aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2016-01-13 19:58:01 +0000
committerDimitry Andric <dim@FreeBSD.org>2016-01-13 19:58:01 +0000
commit050e163ae8b4bb6eb252b59e2f8f36e68ae9239d (patch)
tree7376a0c71aad05d327e5b1dcbceb3311a10f9f29
parent8a6c1c25bce0267ee4072bd7b786b921e8a66a35 (diff)
downloadsrc-050e163ae8b4bb6eb252b59e2f8f36e68ae9239d.tar.gz
src-050e163ae8b4bb6eb252b59e2f8f36e68ae9239d.zip
Vendor import of llvm trunk r257626:vendor/llvm/llvm-trunk-r257626
Notes
Notes: svn path=/vendor/llvm/dist/; revision=293838 svn path=/vendor/llvm/llvm-trunk-r257626/; revision=293839; tag=vendor/llvm/llvm-trunk-r257626
-rwxr-xr-xcmake/modules/AddLLVM.cmake6
-rw-r--r--cmake/modules/HandleLLVMOptions.cmake30
-rw-r--r--docs/AliasAnalysis.rst4
-rw-r--r--docs/CommandGuide/llvm-symbolizer.rst6
-rw-r--r--docs/ExceptionHandling.rst64
-rw-r--r--docs/GettingStartedVS.rst34
-rw-r--r--docs/LangRef.rst214
-rw-r--r--docs/Phabricator.rst8
-rw-r--r--docs/ProgrammersManual.rst6
-rw-r--r--examples/Kaleidoscope/Orc/fully_lazy/toy.cpp2
-rw-r--r--include/llvm/ADT/IntEqClasses.h8
-rw-r--r--include/llvm/ADT/PointerEmbeddedInt.h103
-rw-r--r--include/llvm/ADT/PointerIntPair.h11
-rw-r--r--include/llvm/ADT/PointerSumType.h205
-rw-r--r--include/llvm/ADT/Twine.h8
-rw-r--r--include/llvm/Analysis/LazyCallGraph.h91
-rw-r--r--include/llvm/Analysis/LoopInfo.h250
-rw-r--r--include/llvm/CodeGen/AsmPrinter.h2
-rw-r--r--include/llvm/CodeGen/DIE.h42
-rw-r--r--include/llvm/CodeGen/LiveInterval.h6
-rw-r--r--include/llvm/CodeGen/RegisterPressure.h39
-rw-r--r--include/llvm/CodeGen/WinEHFuncInfo.h5
-rw-r--r--include/llvm/DebugInfo/Symbolize/DIPrinter.h9
-rw-r--r--include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h106
-rw-r--r--include/llvm/ExecutionEngine/Orc/IndirectionUtils.h10
-rw-r--r--include/llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h4
-rw-r--r--include/llvm/ExecutionEngine/Orc/OrcArchitectureSupport.h (renamed from include/llvm/ExecutionEngine/Orc/OrcTargetSupport.h)77
-rw-r--r--include/llvm/ExecutionEngine/Orc/OrcError.h37
-rw-r--r--include/llvm/ExecutionEngine/Orc/OrcRemoteTargetClient.h784
-rw-r--r--include/llvm/ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.h185
-rw-r--r--include/llvm/ExecutionEngine/Orc/OrcRemoteTargetServer.h432
-rw-r--r--include/llvm/ExecutionEngine/Orc/RPCChannel.h179
-rw-r--r--include/llvm/ExecutionEngine/Orc/RPCUtils.h266
-rw-r--r--include/llvm/ExecutionEngine/RTDyldMemoryManager.h4
-rw-r--r--include/llvm/ExecutionEngine/RuntimeDyld.h44
-rw-r--r--include/llvm/IR/Attributes.td5
-rw-r--r--include/llvm/IR/Function.h11
-rw-r--r--include/llvm/IR/IRBuilder.h4
-rw-r--r--include/llvm/IR/Intrinsics.td2
-rw-r--r--include/llvm/IR/IntrinsicsX86.td384
-rw-r--r--include/llvm/IR/LLVMContext.h11
-rw-r--r--include/llvm/IR/Metadata.h21
-rw-r--r--include/llvm/InitializePasses.h3
-rw-r--r--include/llvm/LinkAllPasses.h3
-rw-r--r--include/llvm/Linker/Linker.h7
-rw-r--r--include/llvm/MC/MCExpr.h3
-rw-r--r--include/llvm/MC/MCObjectFileInfo.h2
-rw-r--r--include/llvm/MC/MCStreamer.h4
-rw-r--r--include/llvm/Object/COFF.h3
-rw-r--r--include/llvm/Object/ELFObjectFile.h10
-rw-r--r--include/llvm/Pass.h4
-rw-r--r--include/llvm/ProfileData/CoverageMapping.h113
-rw-r--r--include/llvm/ProfileData/InstrProf.h78
-rw-r--r--include/llvm/ProfileData/InstrProfData.inc67
-rw-r--r--include/llvm/ProfileData/SampleProf.h55
-rw-r--r--include/llvm/Support/ARMTargetParser.def2
-rw-r--r--include/llvm/Support/Allocator.h3
-rw-r--r--include/llvm/Support/COFF.h9
-rw-r--r--include/llvm/Support/ELF.h17
-rw-r--r--include/llvm/Support/ELFRelocs/WebAssembly.def8
-rw-r--r--include/llvm/Support/GenericDomTree.h12
-rw-r--r--include/llvm/Support/MathExtras.h19
-rw-r--r--include/llvm/Transforms/IPO.h18
-rw-r--r--include/llvm/Transforms/Utils/Cloning.h36
-rw-r--r--include/llvm/Transforms/Utils/Local.h3
-rw-r--r--include/llvm/module.modulemap1
-rw-r--r--lib/Analysis/BasicAliasAnalysis.cpp30
-rw-r--r--lib/Analysis/CallGraphSCCPass.cpp7
-rw-r--r--lib/Analysis/GlobalsModRef.cpp15
-rw-r--r--lib/Analysis/InstructionSimplify.cpp199
-rw-r--r--lib/Analysis/LoopAccessAnalysis.cpp1
-rw-r--r--lib/Analysis/LoopInfo.cpp6
-rw-r--r--lib/Analysis/LoopPass.cpp27
-rw-r--r--lib/Analysis/ScopedNoAliasAA.cpp2
-rw-r--r--lib/Analysis/TypeBasedAliasAnalysis.cpp2
-rw-r--r--lib/Analysis/ValueTracking.cpp12
-rw-r--r--lib/Bitcode/Reader/BitcodeReader.cpp23
-rw-r--r--lib/Bitcode/Writer/BitcodeWriter.cpp15
-rw-r--r--lib/CodeGen/AsmPrinter/AsmPrinter.cpp32
-rw-r--r--lib/CodeGen/AsmPrinter/DIE.cpp33
-rw-r--r--lib/CodeGen/AsmPrinter/DwarfDebug.cpp80
-rw-r--r--lib/CodeGen/AsmPrinter/DwarfDebug.h16
-rw-r--r--lib/CodeGen/AsmPrinter/WinCodeViewLineTables.cpp23
-rw-r--r--lib/CodeGen/BranchFolding.cpp15
-rw-r--r--lib/CodeGen/CodeGenPrepare.cpp16
-rw-r--r--lib/CodeGen/LiveDebugValues.cpp151
-rw-r--r--lib/CodeGen/LiveInterval.cpp10
-rw-r--r--lib/CodeGen/LiveIntervalAnalysis.cpp2
-rw-r--r--lib/CodeGen/MachineBasicBlock.cpp2
-rw-r--r--lib/CodeGen/MachineFunctionPrinterPass.cpp4
-rw-r--r--lib/CodeGen/MachineInstr.cpp38
-rw-r--r--lib/CodeGen/MachineLICM.cpp87
-rw-r--r--lib/CodeGen/MachineVerifier.cpp2
-rw-r--r--lib/CodeGen/RegisterCoalescer.cpp2
-rw-r--r--lib/CodeGen/RegisterPressure.cpp117
-rw-r--r--lib/CodeGen/ScheduleDAGInstrs.cpp28
-rw-r--r--lib/CodeGen/SelectionDAG/DAGCombiner.cpp26
-rw-r--r--lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp2
-rw-r--r--lib/CodeGen/SelectionDAG/LegalizeDAG.cpp14
-rw-r--r--lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp8
-rw-r--r--lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp9
-rw-r--r--lib/CodeGen/SelectionDAG/StatepointLowering.cpp18
-rw-r--r--lib/CodeGen/ShrinkWrap.cpp57
-rw-r--r--lib/CodeGen/StackColoring.cpp9
-rw-r--r--lib/CodeGen/WinEHPrepare.cpp25
-rw-r--r--lib/DebugInfo/Symbolize/DIPrinter.cpp40
-rw-r--r--lib/ExecutionEngine/Orc/CMakeLists.txt4
-rw-r--r--lib/ExecutionEngine/Orc/OrcArchitectureSupport.cpp (renamed from lib/ExecutionEngine/Orc/OrcTargetSupport.cpp)4
-rw-r--r--lib/ExecutionEngine/Orc/OrcCBindingsStack.cpp2
-rw-r--r--lib/ExecutionEngine/Orc/OrcCBindingsStack.h3
-rw-r--r--lib/ExecutionEngine/Orc/OrcError.cpp57
-rw-r--r--lib/ExecutionEngine/Orc/OrcMCJITReplacement.h16
-rw-r--r--lib/ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.cpp83
-rw-r--r--lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp46
-rw-r--r--lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h6
-rw-r--r--lib/ExecutionEngine/SectionMemoryManager.cpp3
-rw-r--r--lib/Fuzzer/FuzzerDriver.cpp4
-rw-r--r--lib/Fuzzer/FuzzerFlags.def4
-rw-r--r--lib/Fuzzer/FuzzerInterface.h17
-rw-r--r--lib/Fuzzer/FuzzerInternal.h9
-rw-r--r--lib/Fuzzer/FuzzerLoop.cpp23
-rw-r--r--lib/Fuzzer/FuzzerMutate.cpp90
-rw-r--r--lib/Fuzzer/FuzzerTraceState.cpp244
-rw-r--r--lib/Fuzzer/FuzzerUtil.cpp25
-rw-r--r--lib/Fuzzer/test/FuzzerUnittest.cpp35
-rw-r--r--lib/Fuzzer/test/MemcmpTest.cpp12
-rw-r--r--lib/Fuzzer/test/fuzzer-dfsan.test7
-rw-r--r--lib/Fuzzer/test/fuzzer-dict.test6
-rw-r--r--lib/Fuzzer/test/fuzzer-traces.test7
-rw-r--r--lib/Fuzzer/test/fuzzer.test6
-rw-r--r--lib/IR/AsmWriter.cpp2
-rw-r--r--lib/IR/Core.cpp2
-rw-r--r--lib/IR/Function.cpp44
-rw-r--r--lib/IR/IRPrintingPasses.cpp11
-rw-r--r--lib/IR/LLVMContext.cpp16
-rw-r--r--lib/IR/LLVMContextImpl.h7
-rw-r--r--lib/IR/LegacyPassManager.cpp13
-rw-r--r--lib/IR/Metadata.cpp2
-rw-r--r--lib/IR/Verifier.cpp317
-rw-r--r--lib/LTO/LTOCodeGenerator.cpp3
-rw-r--r--lib/Linker/IRMover.cpp24
-rw-r--r--lib/Linker/LinkModules.cpp157
-rw-r--r--lib/MC/MCExpr.cpp1
-rw-r--r--lib/MC/MCObjectFileInfo.cpp10
-rw-r--r--lib/MC/MCObjectStreamer.cpp2
-rw-r--r--lib/MC/WinCOFFObjectWriter.cpp8
-rw-r--r--lib/Object/COFFObjectFile.cpp24
-rw-r--r--lib/Object/ELF.cpp7
-rw-r--r--lib/ProfileData/CoverageMapping.cpp2
-rw-r--r--lib/ProfileData/CoverageMappingReader.cpp36
-rw-r--r--lib/ProfileData/InstrProf.cpp62
-rw-r--r--lib/ProfileData/InstrProfWriter.cpp16
-rw-r--r--lib/Support/Debug.cpp8
-rw-r--r--lib/Support/IntEqClasses.cpp4
-rw-r--r--lib/Support/Triple.cpp56
-rw-r--r--lib/Support/Windows/Path.inc1
-rw-r--r--lib/Support/Windows/Signals.inc5
-rw-r--r--lib/Support/Windows/WindowsSupport.h31
-rw-r--r--lib/Support/raw_ostream.cpp2
-rw-r--r--lib/Target/AArch64/AArch64InstrInfo.cpp57
-rw-r--r--lib/Target/AArch64/AArch64InstrInfo.h4
-rw-r--r--lib/Target/AMDGPU/AMDGPU.h4
-rw-r--r--lib/Target/AMDGPU/AMDGPUAsmPrinter.cpp54
-rw-r--r--lib/Target/AMDGPU/AMDGPUAsmPrinter.h2
-rw-r--r--lib/Target/AMDGPU/AMDGPUCallingConv.td67
-rw-r--r--lib/Target/AMDGPU/AMDGPUISelLowering.cpp300
-rw-r--r--lib/Target/AMDGPU/AMDGPUISelLowering.h9
-rw-r--r--lib/Target/AMDGPU/AMDGPUInstrInfo.td4
-rw-r--r--lib/Target/AMDGPU/AMDGPUTargetMachine.cpp8
-rw-r--r--lib/Target/AMDGPU/CMakeLists.txt1
-rw-r--r--lib/Target/AMDGPU/EvergreenInstructions.td2
-rw-r--r--lib/Target/AMDGPU/MCTargetDesc/AMDGPUMCAsmInfo.cpp1
-rw-r--r--lib/Target/AMDGPU/SIDefines.h2
-rw-r--r--lib/Target/AMDGPU/SIFixSGPRCopies.cpp2
-rw-r--r--lib/Target/AMDGPU/SIFoldOperands.cpp14
-rw-r--r--lib/Target/AMDGPU/SIISelLowering.cpp132
-rw-r--r--lib/Target/AMDGPU/SIISelLowering.h7
-rw-r--r--lib/Target/AMDGPU/SIInsertWaits.cpp16
-rw-r--r--lib/Target/AMDGPU/SIInstrInfo.cpp16
-rw-r--r--lib/Target/AMDGPU/SIInstrInfo.h3
-rw-r--r--lib/Target/AMDGPU/SIInstructions.td2
-rw-r--r--lib/Target/AMDGPU/SIMachineFunctionInfo.cpp6
-rw-r--r--lib/Target/AMDGPU/SIMachineFunctionInfo.h26
-rw-r--r--lib/Target/AMDGPU/SIMachineScheduler.cpp1968
-rw-r--r--lib/Target/AMDGPU/SIMachineScheduler.h489
-rw-r--r--lib/Target/AMDGPU/SIRegisterInfo.cpp96
-rw-r--r--lib/Target/AMDGPU/SIRegisterInfo.h6
-rw-r--r--lib/Target/AMDGPU/SITypeRewriter.cpp3
-rw-r--r--lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.cpp21
-rw-r--r--lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.h2
-rw-r--r--lib/Target/ARM/ARMBaseRegisterInfo.cpp23
-rw-r--r--lib/Target/ARM/ARMBaseRegisterInfo.h9
-rw-r--r--lib/Target/ARM/ARMCallingConv.td15
-rw-r--r--lib/Target/ARM/ARMFastISel.cpp5
-rw-r--r--lib/Target/ARM/ARMISelDAGToDAG.cpp15
-rw-r--r--lib/Target/ARM/ARMISelLowering.cpp138
-rw-r--r--lib/Target/ARM/ARMISelLowering.h11
-rw-r--r--lib/Target/ARM/ARMInstrInfo.td21
-rw-r--r--lib/Target/ARM/ARMInstrNEON.td7
-rw-r--r--lib/Target/ARM/ARMInstrThumb.td8
-rw-r--r--lib/Target/ARM/ARMInstrThumb2.td7
-rw-r--r--lib/Target/ARM/ARMInstrVFP.td4
-rw-r--r--lib/Target/ARM/ARMMachineFunctionInfo.cpp3
-rw-r--r--lib/Target/ARM/ARMMachineFunctionInfo.h9
-rw-r--r--lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp28
-rw-r--r--lib/Target/ARM/MCTargetDesc/ARMTargetStreamer.cpp3
-rw-r--r--lib/Target/ARM/Thumb1FrameLowering.h5
-rw-r--r--lib/Target/AVR/AVR.h54
-rw-r--r--lib/Target/AVR/AVRSelectionDAGInfo.h29
-rw-r--r--lib/Target/AVR/AVRTargetObjectFile.cpp40
-rw-r--r--lib/Target/AVR/AVRTargetObjectFile.h35
-rw-r--r--lib/Target/AVR/CMakeLists.txt1
-rw-r--r--lib/Target/Hexagon/CMakeLists.txt6
-rw-r--r--lib/Target/Hexagon/HexagonAsmPrinter.cpp6
-rw-r--r--lib/Target/Hexagon/HexagonBitSimplify.cpp26
-rw-r--r--lib/Target/Hexagon/HexagonInstrInfoV4.td4
-rw-r--r--lib/Target/Hexagon/HexagonRDF.cpp60
-rw-r--r--lib/Target/Hexagon/HexagonRDF.h28
-rw-r--r--lib/Target/Hexagon/HexagonRDFOpt.cpp272
-rw-r--r--lib/Target/Hexagon/HexagonRegisterInfo.cpp2
-rw-r--r--lib/Target/Hexagon/HexagonTargetMachine.cpp12
-rw-r--r--lib/Target/Hexagon/MCTargetDesc/HexagonMCCodeEmitter.cpp30
-rw-r--r--lib/Target/Hexagon/MCTargetDesc/HexagonShuffler.cpp19
-rw-r--r--lib/Target/Hexagon/MCTargetDesc/HexagonShuffler.h20
-rw-r--r--lib/Target/Hexagon/RDFCopy.cpp180
-rw-r--r--lib/Target/Hexagon/RDFCopy.h48
-rw-r--r--lib/Target/Hexagon/RDFDeadCode.cpp204
-rw-r--r--lib/Target/Hexagon/RDFDeadCode.h65
-rw-r--r--lib/Target/Hexagon/RDFGraph.cpp1716
-rw-r--r--lib/Target/Hexagon/RDFGraph.h841
-rw-r--r--lib/Target/Hexagon/RDFLiveness.cpp848
-rw-r--r--lib/Target/Hexagon/RDFLiveness.h106
-rw-r--r--lib/Target/Mips/MipsISelLowering.cpp19
-rw-r--r--lib/Target/Mips/MipsISelLowering.h1
-rw-r--r--lib/Target/Mips/MipsInstrInfo.td4
-rw-r--r--lib/Target/Mips/MipsSEInstrInfo.cpp5
-rw-r--r--lib/Target/NVPTX/NVPTXISelLowering.cpp1
-rw-r--r--lib/Target/NVPTX/NVPTXTargetObjectFile.h3
-rw-r--r--lib/Target/PowerPC/PPCAsmPrinter.cpp100
-rw-r--r--lib/Target/PowerPC/PPCInstr64Bit.td15
-rw-r--r--lib/Target/PowerPC/PPCInstrInfo.cpp43
-rw-r--r--lib/Target/PowerPC/PPCInstrInfo.td15
-rw-r--r--lib/Target/PowerPC/PPCMachineFunctionInfo.cpp21
-rw-r--r--lib/Target/PowerPC/PPCMachineFunctionInfo.h4
-rw-r--r--lib/Target/PowerPC/PPCTLSDynamicCall.cpp7
-rw-r--r--lib/Target/Sparc/SparcInstrInfo.cpp182
-rw-r--r--lib/Target/Sparc/SparcInstrInfo.h3
-rw-r--r--lib/Target/SystemZ/SystemZInstrInfo.td3
-rw-r--r--lib/Target/WebAssembly/CMakeLists.txt3
-rw-r--r--lib/Target/WebAssembly/Disassembler/CMakeLists.txt3
-rw-r--r--lib/Target/WebAssembly/Disassembler/LLVMBuild.txt23
-rw-r--r--lib/Target/WebAssembly/Disassembler/Makefile16
-rw-r--r--lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp148
-rw-r--r--lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.cpp85
-rw-r--r--lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.h3
-rw-r--r--lib/Target/WebAssembly/LLVMBuild.txt3
-rw-r--r--lib/Target/WebAssembly/MCTargetDesc/CMakeLists.txt1
-rw-r--r--lib/Target/WebAssembly/MCTargetDesc/WebAssemblyAsmBackend.cpp5
-rw-r--r--lib/Target/WebAssembly/MCTargetDesc/WebAssemblyELFObjectWriter.cpp26
-rw-r--r--lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCAsmInfo.cpp7
-rw-r--r--lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp90
-rw-r--r--lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.cpp83
-rw-r--r--lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h42
-rw-r--r--lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp94
-rw-r--r--lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h68
-rw-r--r--lib/Target/WebAssembly/Makefile2
-rw-r--r--lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp63
-rw-r--r--lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp153
-rw-r--r--lib/Target/WebAssembly/WebAssemblyISelLowering.cpp14
-rw-r--r--lib/Target/WebAssembly/WebAssemblyInstrControl.td25
-rw-r--r--lib/Target/WebAssembly/WebAssemblyInstrInfo.cpp9
-rw-r--r--lib/Target/WebAssembly/WebAssemblyInstrInfo.td33
-rw-r--r--lib/Target/WebAssembly/WebAssemblyInstrMemory.td246
-rw-r--r--lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp35
-rw-r--r--lib/Target/WebAssembly/WebAssemblyMCInstLower.h3
-rw-r--r--lib/Target/WebAssembly/WebAssemblyRegStackify.cpp8
-rw-r--r--lib/Target/WebAssembly/WebAssemblyRegisterInfo.cpp18
-rw-r--r--lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp5
-rw-r--r--lib/Target/WebAssembly/known_gcc_test_failures.txt19
-rw-r--r--lib/Target/X86/X86.h7
-rw-r--r--lib/Target/X86/X86CallingConv.td6
-rw-r--r--lib/Target/X86/X86FastISel.cpp3
-rw-r--r--lib/Target/X86/X86ISelLowering.cpp298
-rw-r--r--lib/Target/X86/X86ISelLowering.h19
-rw-r--r--lib/Target/X86/X86InstrAVX512.td114
-rw-r--r--lib/Target/X86/X86InstrExtension.td36
-rw-r--r--lib/Target/X86/X86InstrFragmentsSIMD.td3
-rw-r--r--lib/Target/X86/X86InstrInfo.td160
-rw-r--r--lib/Target/X86/X86InstrMPX.td28
-rw-r--r--lib/Target/X86/X86InstrSSE.td11
-rw-r--r--lib/Target/X86/X86IntrinsicsInfo.h148
-rw-r--r--lib/Target/X86/X86MachineFunctionInfo.h7
-rw-r--r--lib/Target/X86/X86OptimizeLEAs.cpp195
-rw-r--r--lib/Target/X86/X86RegisterInfo.cpp12
-rw-r--r--lib/Target/X86/X86RegisterInfo.h2
-rw-r--r--lib/Transforms/IPO/ForceFunctionAttrs.cpp2
-rw-r--r--lib/Transforms/IPO/FunctionAttrs.cpp166
-rw-r--r--lib/Transforms/IPO/FunctionImport.cpp24
-rw-r--r--lib/Transforms/IPO/IPO.cpp5
-rw-r--r--lib/Transforms/IPO/LoopExtractor.cpp4
-rw-r--r--lib/Transforms/IPO/PassManagerBuilder.cpp10
-rw-r--r--lib/Transforms/InstCombine/InstCombineMulDivRem.cpp6
-rw-r--r--lib/Transforms/InstCombine/InstCombineSelect.cpp6
-rw-r--r--lib/Transforms/InstCombine/InstCombineVectorOps.cpp17
-rw-r--r--lib/Transforms/Instrumentation/InstrProfiling.cpp34
-rw-r--r--lib/Transforms/Instrumentation/MemorySanitizer.cpp2
-rw-r--r--lib/Transforms/Scalar/JumpThreading.cpp218
-rw-r--r--lib/Transforms/Scalar/LICM.cpp46
-rw-r--r--lib/Transforms/Scalar/LoopDeletion.cpp2
-rw-r--r--lib/Transforms/Scalar/LoopUnrollPass.cpp488
-rw-r--r--lib/Transforms/Scalar/MemCpyOptimizer.cpp35
-rw-r--r--lib/Transforms/Scalar/PlaceSafepoints.cpp2
-rw-r--r--lib/Transforms/Scalar/Reassociate.cpp3
-rw-r--r--lib/Transforms/Scalar/RewriteStatepointsForGC.cpp102
-rw-r--r--lib/Transforms/Scalar/SCCP.cpp61
-rw-r--r--lib/Transforms/Scalar/TailRecursionElimination.cpp9
-rw-r--r--lib/Transforms/Utils/BasicBlockUtils.cpp16
-rw-r--r--lib/Transforms/Utils/CloneFunction.cpp72
-rw-r--r--lib/Transforms/Utils/Local.cpp31
-rw-r--r--lib/Transforms/Utils/LoopUnroll.cpp4
-rw-r--r--lib/Transforms/Utils/LoopUtils.cpp2
-rw-r--r--lib/Transforms/Utils/SimplifyCFG.cpp101
-rw-r--r--lib/Transforms/Utils/SimplifyLibCalls.cpp165
-rw-r--r--lib/Transforms/Utils/ValueMapper.cpp13
-rw-r--r--lib/Transforms/Vectorize/SLPVectorizer.cpp44
-rw-r--r--test/Analysis/GlobalsModRef/nocapture.ll57
-rw-r--r--test/Analysis/LoopAccessAnalysis/interleave-innermost.ll29
-rw-r--r--test/Bitcode/compatibility.ll37
-rw-r--r--test/CodeGen/AArch64/arm64-misched-memdep-bug.ll22
-rw-r--r--test/CodeGen/AArch64/branch-folder-merge-mmos.ll33
-rw-r--r--test/CodeGen/AArch64/machine-combiner.ll258
-rw-r--r--test/CodeGen/AMDGPU/ctlz.ll269
-rw-r--r--test/CodeGen/AMDGPU/ctlz_zero_undef.ll197
-rw-r--r--test/CodeGen/AMDGPU/flat-scratch-reg.ll8
-rw-r--r--test/CodeGen/AMDGPU/fmin_legacy.ll4
-rw-r--r--test/CodeGen/AMDGPU/fsub.ll15
-rw-r--r--test/CodeGen/AMDGPU/hsa-globals.ll16
-rw-r--r--test/CodeGen/AMDGPU/hsa-note-no-func.ll6
-rw-r--r--test/CodeGen/AMDGPU/hsa.ll4
-rw-r--r--test/CodeGen/AMDGPU/inline-asm.ll11
-rw-r--r--test/CodeGen/AMDGPU/llvm.amdgcn.dispatch.ptr.ll3
-rw-r--r--test/CodeGen/AMDGPU/llvm.round.f64.ll2
-rw-r--r--test/CodeGen/AMDGPU/ret.ll245
-rw-r--r--test/CodeGen/AMDGPU/si-scheduler.ll55
-rw-r--r--test/CodeGen/AMDGPU/sint_to_fp.i64.ll62
-rw-r--r--test/CodeGen/AMDGPU/sint_to_fp.ll91
-rw-r--r--test/CodeGen/AMDGPU/udiv.ll89
-rw-r--r--test/CodeGen/AMDGPU/uint_to_fp.i64.ll57
-rw-r--r--test/CodeGen/AMDGPU/uint_to_fp.ll123
-rw-r--r--test/CodeGen/ARM/bit-reverse-to-rbit.ll34
-rw-r--r--test/CodeGen/ARM/cxx-tlscc.ll46
-rw-r--r--test/CodeGen/ARM/darwin-tls.ll165
-rw-r--r--test/CodeGen/ARM/fabs-to-bfc.ll14
-rw-r--r--test/CodeGen/ARM/fp16-args.ll7
-rw-r--r--test/CodeGen/ARM/fp16-v3.ll28
-rw-r--r--test/CodeGen/ARM/inlineasm-imm-thumb.ll20
-rw-r--r--test/CodeGen/ARM/inlineasm-imm-thumb2.ll31
-rw-r--r--test/CodeGen/ARM/zero-cycle-zero.ll58
-rw-r--r--test/CodeGen/Hexagon/bit-phi.ll58
-rw-r--r--test/CodeGen/Hexagon/postinc-offset.ll3
-rw-r--r--test/CodeGen/Hexagon/rdf-copy.ll54
-rw-r--r--test/CodeGen/Hexagon/rdf-dead-loop.ll31
-rw-r--r--test/CodeGen/Mips/llvm-ir/call.ll15
-rw-r--r--test/CodeGen/Mips/madd-msub.ll14
-rw-r--r--test/CodeGen/PowerPC/2016-01-07-BranchWeightCrash.ll35
-rw-r--r--test/CodeGen/PowerPC/ppc64le-localentry-large.ll27
-rw-r--r--test/CodeGen/PowerPC/ppc64le-localentry.ll20
-rw-r--r--test/CodeGen/PowerPC/pr25802.ll52
-rw-r--r--test/CodeGen/PowerPC/tls_get_addr_clobbers.ll54
-rw-r--r--test/CodeGen/PowerPC/tls_get_addr_stackframe.ll32
-rw-r--r--test/CodeGen/SPARC/2011-01-19-DelaySlot.ll2
-rw-r--r--test/CodeGen/SPARC/analyze-branch.ll58
-rw-r--r--test/CodeGen/WebAssembly/call.ll22
-rw-r--r--test/CodeGen/WebAssembly/cfg-stackify.ll817
-rw-r--r--test/CodeGen/WebAssembly/comparisons_f32.ll2
-rw-r--r--test/CodeGen/WebAssembly/comparisons_f64.ll2
-rw-r--r--test/CodeGen/WebAssembly/comparisons_i32.ll2
-rw-r--r--test/CodeGen/WebAssembly/comparisons_i64.ll2
-rw-r--r--test/CodeGen/WebAssembly/conv.ll2
-rw-r--r--test/CodeGen/WebAssembly/copysign-casts.ll2
-rw-r--r--test/CodeGen/WebAssembly/cpus.ll16
-rw-r--r--test/CodeGen/WebAssembly/dead-vreg.ll2
-rw-r--r--test/CodeGen/WebAssembly/f32.ll4
-rw-r--r--test/CodeGen/WebAssembly/f64.ll4
-rw-r--r--test/CodeGen/WebAssembly/fast-isel.ll2
-rw-r--r--test/CodeGen/WebAssembly/frem.ll6
-rw-r--r--test/CodeGen/WebAssembly/func.ll3
-rw-r--r--test/CodeGen/WebAssembly/global.ll20
-rw-r--r--test/CodeGen/WebAssembly/globl.ll2
-rw-r--r--test/CodeGen/WebAssembly/i32.ll2
-rw-r--r--test/CodeGen/WebAssembly/i64.ll2
-rw-r--r--test/CodeGen/WebAssembly/ident.ll2
-rw-r--r--test/CodeGen/WebAssembly/immediates.ll2
-rw-r--r--test/CodeGen/WebAssembly/inline-asm.ll7
-rw-r--r--test/CodeGen/WebAssembly/legalize.ll2
-rw-r--r--test/CodeGen/WebAssembly/load-ext.ll2
-rw-r--r--test/CodeGen/WebAssembly/load-store-i1.ll2
-rw-r--r--test/CodeGen/WebAssembly/load.ll2
-rw-r--r--test/CodeGen/WebAssembly/loop-idiom.ll2
-rw-r--r--test/CodeGen/WebAssembly/memory-addr32.ll2
-rw-r--r--test/CodeGen/WebAssembly/memory-addr64.ll2
-rw-r--r--test/CodeGen/WebAssembly/offset-folding.ll2
-rw-r--r--test/CodeGen/WebAssembly/offset.ll2
-rw-r--r--test/CodeGen/WebAssembly/phi.ll4
-rw-r--r--test/CodeGen/WebAssembly/reg-stackify.ll22
-rw-r--r--test/CodeGen/WebAssembly/return-int32.ll2
-rw-r--r--test/CodeGen/WebAssembly/return-void.ll2
-rw-r--r--test/CodeGen/WebAssembly/returned.ll10
-rw-r--r--test/CodeGen/WebAssembly/select.ll2
-rw-r--r--test/CodeGen/WebAssembly/signext-zeroext.ll6
-rw-r--r--test/CodeGen/WebAssembly/store-results.ll2
-rw-r--r--test/CodeGen/WebAssembly/store-trunc.ll2
-rw-r--r--test/CodeGen/WebAssembly/store.ll2
-rw-r--r--test/CodeGen/WebAssembly/switch.ll86
-rw-r--r--test/CodeGen/WebAssembly/unreachable.ll4
-rw-r--r--test/CodeGen/WebAssembly/unused-argument.ll4
-rw-r--r--test/CodeGen/WebAssembly/userstack.ll23
-rw-r--r--test/CodeGen/WebAssembly/varargs.ll4
-rw-r--r--test/CodeGen/WebAssembly/vtable.ll2
-rw-r--r--test/CodeGen/WinEH/wineh-cloning.ll42
-rw-r--r--test/CodeGen/WinEH/wineh-no-demotion.ll4
-rw-r--r--test/CodeGen/WinEH/wineh-statenumbering.ll2
-rw-r--r--test/CodeGen/X86/2008-11-03-F80VAARG.ll4
-rw-r--r--test/CodeGen/X86/2012-01-12-extract-sv.ll4
-rw-r--r--test/CodeGen/X86/avx-vbroadcast.ll431
-rw-r--r--test/CodeGen/X86/avx2-vbroadcast.ll763
-rw-r--r--test/CodeGen/X86/avx512-intrinsics.ll395
-rw-r--r--test/CodeGen/X86/avx512bw-intrinsics.ll215
-rw-r--r--test/CodeGen/X86/avx512bwvl-intrinsics.ll421
-rw-r--r--test/CodeGen/X86/avx512vl-intrinsics.ll1033
-rw-r--r--test/CodeGen/X86/catchpad-lifetime.ll91
-rw-r--r--test/CodeGen/X86/cxx_tlscc64.ll63
-rw-r--r--test/CodeGen/X86/dagcombine-cse.ll2
-rw-r--r--test/CodeGen/X86/f16c-intrinsics.ll12
-rw-r--r--test/CodeGen/X86/insertps-combine.ll33
-rw-r--r--test/CodeGen/X86/lea-opt.ll38
-rw-r--r--test/CodeGen/X86/pr13577.ll16
-rw-r--r--test/CodeGen/X86/scalar-int-to-fp.ll43
-rw-r--r--test/CodeGen/X86/shrinkwrap-hang.ll32
-rw-r--r--test/CodeGen/X86/stack-folding-fp-sse42.ll2
-rw-r--r--test/CodeGen/X86/statepoint-vector.ll162
-rw-r--r--test/CodeGen/X86/vec_uint_to_fp-fastmath.ll24
-rw-r--r--test/CodeGen/X86/version_directive.ll4
-rw-r--r--test/CodeGen/X86/x86-shrink-wrapping.ll105
-rw-r--r--test/DebugInfo/COFF/asm.ll73
-rw-r--r--test/DebugInfo/COFF/multifile.ll108
-rw-r--r--test/DebugInfo/COFF/multifunction.ll271
-rw-r--r--test/DebugInfo/COFF/simple.ll60
-rw-r--r--test/DebugInfo/COFF/tail-call-without-lexical-scopes.ll2
-rw-r--r--test/DebugInfo/X86/debug-macro.ll67
-rw-r--r--test/DebugInfo/X86/debugger-tune.ll2
-rw-r--r--test/DebugInfo/X86/tls.ll2
-rw-r--r--test/ExecutionEngine/MCJIT/remote/cross-module-a.ll1
-rw-r--r--test/ExecutionEngine/MCJIT/remote/cross-module-sm-pic-a.ll14
-rw-r--r--test/ExecutionEngine/MCJIT/remote/multi-module-a.ll1
-rw-r--r--test/ExecutionEngine/MCJIT/remote/multi-module-sm-pic-a.ll10
-rw-r--r--test/ExecutionEngine/MCJIT/remote/simpletest-remote.ll1
-rw-r--r--test/ExecutionEngine/MCJIT/remote/stubs-remote.ll2
-rw-r--r--test/ExecutionEngine/MCJIT/remote/test-common-symbols-remote.ll1
-rw-r--r--test/ExecutionEngine/MCJIT/remote/test-data-align-remote.ll1
-rw-r--r--test/ExecutionEngine/MCJIT/remote/test-fp-no-external-funcs-remote.ll1
-rw-r--r--test/ExecutionEngine/MCJIT/remote/test-global-init-nonzero-remote.ll1
-rw-r--r--test/ExecutionEngine/MCJIT/remote/test-global-init-nonzero-sm-pic.ll5
-rw-r--r--test/ExecutionEngine/MCJIT/remote/test-ptr-reloc-remote.ll1
-rw-r--r--test/ExecutionEngine/MCJIT/remote/test-ptr-reloc-sm-pic.ll5
-rw-r--r--test/ExecutionEngine/OrcMCJIT/remote/cross-module-a.ll1
-rw-r--r--test/ExecutionEngine/OrcMCJIT/remote/cross-module-sm-pic-a.ll14
-rw-r--r--test/ExecutionEngine/OrcMCJIT/remote/multi-module-a.ll1
-rw-r--r--test/ExecutionEngine/OrcMCJIT/remote/multi-module-sm-pic-a.ll10
-rw-r--r--test/ExecutionEngine/OrcMCJIT/remote/simpletest-remote.ll1
-rw-r--r--test/ExecutionEngine/OrcMCJIT/remote/stubs-remote.ll2
-rw-r--r--test/ExecutionEngine/OrcMCJIT/remote/test-common-symbols-remote.ll1
-rw-r--r--test/ExecutionEngine/OrcMCJIT/remote/test-data-align-remote.ll1
-rw-r--r--test/ExecutionEngine/OrcMCJIT/remote/test-fp-no-external-funcs-remote.ll1
-rw-r--r--test/ExecutionEngine/OrcMCJIT/remote/test-global-init-nonzero-remote.ll1
-rw-r--r--test/ExecutionEngine/OrcMCJIT/remote/test-global-init-nonzero-sm-pic.ll5
-rw-r--r--test/ExecutionEngine/OrcMCJIT/remote/test-ptr-reloc-remote.ll1
-rw-r--r--test/ExecutionEngine/OrcMCJIT/remote/test-ptr-reloc-sm-pic.ll5
-rw-r--r--test/Feature/exception.ll4
-rw-r--r--test/Instrumentation/MemorySanitizer/origin-array.ll23
-rw-r--r--test/Linker/Inputs/pr26037.ll23
-rw-r--r--test/Linker/pr26037.ll38
-rw-r--r--test/MC/ARM/twice.ll9
-rw-r--r--test/MC/COFF/timestamp.s1
-rw-r--r--test/MC/Disassembler/Mips/mips2/valid-mips2.txt1
-rw-r--r--test/MC/Disassembler/Mips/mips3/valid-mips3.txt1
-rw-r--r--test/MC/Disassembler/Mips/mips4/valid-mips4.txt1
-rw-r--r--test/MC/Disassembler/X86/avx-512.txt2
-rw-r--r--test/MC/Mips/mips1/valid.s1
-rw-r--r--test/MC/Mips/mips2/valid.s1
-rw-r--r--test/MC/Mips/mips3/valid.s1
-rw-r--r--test/MC/Mips/mips32/valid.s1
-rw-r--r--test/MC/Mips/mips32r2/valid.s1
-rw-r--r--test/MC/Mips/mips32r3/valid.s1
-rw-r--r--test/MC/Mips/mips32r5/valid.s1
-rw-r--r--test/MC/Mips/mips32r6/valid.s1
-rw-r--r--test/MC/Mips/mips4/valid.s1
-rw-r--r--test/MC/Mips/mips5/valid.s1
-rw-r--r--test/MC/Mips/mips64/valid.s1
-rw-r--r--test/MC/Mips/mips64r2/valid.s1
-rw-r--r--test/MC/Mips/mips64r3/valid.s1
-rw-r--r--test/MC/Mips/mips64r5/valid.s1
-rw-r--r--test/MC/Mips/mips64r6/valid.s1
-rw-r--r--test/MC/X86/avx512-encodings.s56
-rw-r--r--test/MC/X86/intel-syntax-avx512.s124
-rw-r--r--test/MC/X86/intel-syntax-x86-64-avx512f_vl.s104
-rw-r--r--test/MC/X86/x86-64-avx512dq.s48
-rw-r--r--test/Other/2010-05-06-Printer.ll14
-rw-r--r--test/TableGen/TwoLevelName.td24
-rw-r--r--test/Transforms/FunctionAttrs/norecurse.ll2
-rw-r--r--test/Transforms/FunctionImport/Inputs/funcimport.ll15
-rw-r--r--test/Transforms/FunctionImport/Inputs/funcimport_alias.ll7
-rw-r--r--test/Transforms/FunctionImport/funcimport.ll2
-rw-r--r--test/Transforms/FunctionImport/funcimport_alias.ll25
-rw-r--r--test/Transforms/FunctionImport/funcimport_debug.ll14
-rw-r--r--test/Transforms/IPConstantProp/PR16052.ll26
-rw-r--r--test/Transforms/IPConstantProp/PR26044.ll31
-rw-r--r--test/Transforms/Inline/attributes.ll84
-rw-r--r--test/Transforms/InstCombine/fast-math.ll69
-rw-r--r--test/Transforms/InstCombine/inline-intrinsic-assert.ll12
-rw-r--r--test/Transforms/InstCombine/insert-extract-shuffle.ll50
-rw-r--r--test/Transforms/InstCombine/log-pow.ll64
-rw-r--r--test/Transforms/InstCombine/no_cgscc_assert.ll5
-rw-r--r--test/Transforms/InstCombine/pow-exp.ll53
-rw-r--r--test/Transforms/InstCombine/pow-exp2.ll19
-rw-r--r--test/Transforms/InstCombine/pow-sqrt.ll14
-rw-r--r--test/Transforms/InstCombine/printf-3.ll39
-rw-r--r--test/Transforms/InstCombine/tan.ll19
-rw-r--r--test/Transforms/InstSimplify/floating-point-compare.ll41
-rw-r--r--test/Transforms/JumpThreading/pr26096.ll68
-rw-r--r--test/Transforms/JumpThreading/select.ll37
-rw-r--r--test/Transforms/LoopUnroll/partial-unroll-optsize.ll3
-rw-r--r--test/Transforms/LoopUnroll/unloop.ll2
-rw-r--r--test/Transforms/MemCpyOpt/fca2memcpy.ll24
-rw-r--r--test/Transforms/Reassociate/add_across_block_crash.ll20
-rw-r--r--test/Transforms/RewriteStatepointsForGC/constants.ll11
-rw-r--r--test/Transforms/RewriteStatepointsForGC/deopt-bundles/live-vector-nosplit.ll112
-rw-r--r--test/Transforms/RewriteStatepointsForGC/deopt-bundles/live-vector.ll2
-rw-r--r--test/Transforms/RewriteStatepointsForGC/live-vector.ll2
-rw-r--r--test/Transforms/RewriteStatepointsForGC/two-invokes-one-landingpad.ll33
-rw-r--r--test/Transforms/SimplifyCFG/bug-25299.ll40
-rw-r--r--test/Transforms/SimplifyCFG/invoke_unwind.ll42
-rw-r--r--test/Transforms/Util/split-bit-piece.ll45
-rw-r--r--test/Verifier/gc_relocate_return.ll5
-rw-r--r--test/Verifier/invalid-eh.ll274
-rw-r--r--test/lit.cfg6
-rw-r--r--test/lit.site.cfg.in1
-rw-r--r--test/tools/llvm-lto/error.ll2
-rw-r--r--test/tools/llvm-objdump/Inputs/malformed-macho.binbin0 -> 843 bytes
-rw-r--r--test/tools/llvm-objdump/X86/macho-private-header.test6
-rw-r--r--test/tools/llvm-objdump/malformed-archives.test2
-rw-r--r--test/tools/llvm-objdump/malformed-macho.test2
-rw-r--r--test/tools/llvm-profdata/value-prof.proftext10
-rw-r--r--test/tools/llvm-readobj/codeview-linetables.test309
-rw-r--r--test/tools/llvm-symbolizer/Inputs/addr.inp2
-rw-r--r--test/tools/llvm-symbolizer/print_context.c22
-rw-r--r--test/tools/llvm-symbolizer/sym.test4
-rw-r--r--tools/lli/CMakeLists.txt3
-rw-r--r--tools/lli/ChildTarget/CMakeLists.txt7
-rw-r--r--tools/lli/ChildTarget/ChildTarget.cpp285
-rw-r--r--tools/lli/ChildTarget/Makefile4
-rw-r--r--tools/lli/OrcLazyJIT.cpp2
-rw-r--r--tools/lli/OrcLazyJIT.h4
-rw-r--r--tools/lli/RPCChannel.h49
-rw-r--r--tools/lli/RemoteJITUtils.h131
-rw-r--r--tools/lli/RemoteMemoryManager.cpp174
-rw-r--r--tools/lli/RemoteMemoryManager.h101
-rw-r--r--tools/lli/RemoteTarget.cpp71
-rw-r--r--tools/lli/RemoteTarget.h122
-rw-r--r--tools/lli/RemoteTargetExternal.cpp327
-rw-r--r--tools/lli/RemoteTargetExternal.h143
-rw-r--r--tools/lli/RemoteTargetMessage.h85
-rw-r--r--tools/lli/Unix/RPCChannel.inc122
-rw-r--r--tools/lli/Windows/RPCChannel.inc29
-rw-r--r--tools/lli/lli.cpp179
-rw-r--r--tools/llvm-lto/llvm-lto.cpp1
-rw-r--r--tools/llvm-objdump/COFFDump.cpp19
-rw-r--r--tools/llvm-objdump/MachODump.cpp42
-rw-r--r--tools/llvm-objdump/llvm-objdump.cpp41
-rw-r--r--tools/llvm-objdump/llvm-objdump.h2
-rw-r--r--tools/llvm-readobj/COFFDumper.cpp42
-rw-r--r--tools/llvm-readobj/ELFDumper.cpp3
-rw-r--r--tools/llvm-symbolizer/llvm-symbolizer.cpp40
-rw-r--r--unittests/ADT/CMakeLists.txt2
-rw-r--r--unittests/ADT/PointerEmbeddedIntTest.cpp46
-rw-r--r--unittests/ADT/PointerIntPairTest.cpp27
-rw-r--r--unittests/ADT/PointerSumTypeTest.cpp113
-rw-r--r--unittests/ExecutionEngine/MCJIT/MCJITCAPITest.cpp5
-rw-r--r--unittests/ExecutionEngine/Orc/CMakeLists.txt1
-rw-r--r--unittests/ExecutionEngine/Orc/ObjectLinkingLayerTest.cpp82
-rw-r--r--unittests/ExecutionEngine/Orc/OrcTestCommon.cpp6
-rw-r--r--unittests/ExecutionEngine/Orc/OrcTestCommon.h2
-rw-r--r--unittests/ExecutionEngine/Orc/RPCUtilsTest.cpp147
-rw-r--r--unittests/IR/AsmWriterTest.cpp37
-rw-r--r--unittests/IR/CMakeLists.txt1
-rw-r--r--unittests/IR/IRBuilderTest.cpp16
-rw-r--r--unittests/ProfileData/InstrProfTest.cpp140
-rw-r--r--unittests/Support/MathExtrasTest.cpp54
-rw-r--r--utils/KillTheDoctor/KillTheDoctor.cpp6
-rw-r--r--utils/TableGen/AsmWriterEmitter.cpp163
-rw-r--r--utils/TableGen/AsmWriterInst.cpp6
-rw-r--r--utils/lit/lit/util.py9
602 files changed, 26329 insertions, 6787 deletions
diff --git a/cmake/modules/AddLLVM.cmake b/cmake/modules/AddLLVM.cmake
index bed81b28426e..b06e434a2487 100755
--- a/cmake/modules/AddLLVM.cmake
+++ b/cmake/modules/AddLLVM.cmake
@@ -308,6 +308,8 @@ endfunction(set_windows_version_resource_properties)
# SHARED;STATIC
# STATIC by default w/o BUILD_SHARED_LIBS.
# SHARED by default w/ BUILD_SHARED_LIBS.
+# OBJECT
+# Also create an OBJECT library target. Default if STATIC && SHARED.
# MODULE
# Target ${name} might not be created on unsupported platforms.
# Check with "if(TARGET ${name})".
@@ -329,7 +331,7 @@ endfunction(set_windows_version_resource_properties)
# )
function(llvm_add_library name)
cmake_parse_arguments(ARG
- "MODULE;SHARED;STATIC;DISABLE_LLVM_LINK_LLVM_DYLIB;SONAME"
+ "MODULE;SHARED;STATIC;OBJECT;DISABLE_LLVM_LINK_LLVM_DYLIB;SONAME"
"OUTPUT_NAME"
"ADDITIONAL_HEADERS;DEPENDS;LINK_COMPONENTS;LINK_LIBS;OBJLIBS"
${ARGN})
@@ -362,7 +364,7 @@ function(llvm_add_library name)
endif()
# Generate objlib
- if(ARG_SHARED AND ARG_STATIC)
+ if((ARG_SHARED AND ARG_STATIC) OR ARG_OBJECT)
# Generate an obj library for both targets.
set(obj_name "obj.${name}")
add_library(${obj_name} OBJECT EXCLUDE_FROM_ALL
diff --git a/cmake/modules/HandleLLVMOptions.cmake b/cmake/modules/HandleLLVMOptions.cmake
index 4c5ffe2f7b28..6db258ff66a1 100644
--- a/cmake/modules/HandleLLVMOptions.cmake
+++ b/cmake/modules/HandleLLVMOptions.cmake
@@ -363,6 +363,36 @@ if( MSVC )
append("/Zc:inline" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
+ if (NOT LLVM_ENABLE_TIMESTAMPS AND CMAKE_CXX_COMPILER_ID MATCHES "Clang")
+ # clang-cl and cl by default produce non-deterministic binaries because
+ # link.exe /incremental requires a timestamp in the .obj file. clang-cl
+ # has the flag /Brepro to force deterministic binaries, so pass that when
+ # LLVM_ENABLE_TIMESTAMPS is turned off.
+ # This checks CMAKE_CXX_COMPILER_ID in addition to check_cxx_compiler_flag()
+ # because cl.exe does not emit an error on flags it doesn't understand,
+ # letting check_cxx_compiler_flag() claim it understands all flags.
+ check_cxx_compiler_flag("/Brepro" SUPPORTS_BREPRO)
+ append_if(SUPPORTS_BREPRO "/Brepro" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
+
+ if (SUPPORTS_BREPRO)
+ # Check if /INCREMENTAL is passed to the linker and complain that it
+ # won't work with /Brepro.
+ string(TOUPPER "${CMAKE_EXE_LINKER_FLAGS}" upper_exe_flags)
+ string(TOUPPER "${CMAKE_MODULE_LINKER_FLAGS}" upper_module_flags)
+ string(TOUPPER "${CMAKE_SHARED_LINKER_FLAGS}" upper_shared_flags)
+
+ string(FIND "${upper_exe_flags}" "/INCREMENTAL" exe_index)
+ string(FIND "${upper_module_flags}" "/INCREMENTAL" module_index)
+ string(FIND "${upper_shared_flags}" "/INCREMENTAL" shared_index)
+
+ if (${exe_index} GREATER -1 OR
+ ${module_index} GREATER -1 OR
+ ${shared_index} GREATER -1)
+ message(FATAL_ERROR "LLVM_ENABLE_TIMESTAMPS not compatible with /INCREMENTAL linking")
+ endif()
+ endif()
+ endif()
+
# Disable sized deallocation if the flag is supported. MSVC fails to compile
# the operator new overload in User otherwise.
check_c_compiler_flag("/WX /Zc:sizedDealloc-" SUPPORTS_SIZED_DEALLOC)
diff --git a/docs/AliasAnalysis.rst b/docs/AliasAnalysis.rst
index fe7fcbd4bc50..e055b4e1afbc 100644
--- a/docs/AliasAnalysis.rst
+++ b/docs/AliasAnalysis.rst
@@ -190,7 +190,7 @@ this property are side-effect free, only depending on their input arguments and
the state of memory when they are called. This property allows calls to these
functions to be eliminated and moved around, as long as there is no store
instruction that changes the contents of memory. Note that all functions that
-satisfy the ``doesNotAccessMemory`` method also satisfies ``onlyReadsMemory``.
+satisfy the ``doesNotAccessMemory`` method also satisfy ``onlyReadsMemory``.
Writing a new ``AliasAnalysis`` Implementation
==============================================
@@ -634,7 +634,7 @@ transformations:
* It uses mod/ref information to hoist function calls out of loops that do not
write to memory and are loop-invariant.
-* If uses alias information to promote memory objects that are loaded and stored
+* It uses alias information to promote memory objects that are loaded and stored
to in loops to live in a register instead. It can do this if there are no may
aliases to the loaded/stored memory location.
diff --git a/docs/CommandGuide/llvm-symbolizer.rst b/docs/CommandGuide/llvm-symbolizer.rst
index ec4178e4e7ab..7bcad1c12f11 100644
--- a/docs/CommandGuide/llvm-symbolizer.rst
+++ b/docs/CommandGuide/llvm-symbolizer.rst
@@ -11,9 +11,9 @@ DESCRIPTION
:program:`llvm-symbolizer` reads object file names and addresses from standard
input and prints corresponding source code locations to standard output.
-If object file is specified in command line, :program:`llvm-symbolizer` reads
-only addresses from standard input. This
-program uses debug info sections and symbol table in the object files.
+If object file is specified in command line, :program:`llvm-symbolizer`
+processes only addresses from standard input, the rest is output verbatim.
+This program uses debug info sections and symbol table in the object files.
EXAMPLE
--------
diff --git a/docs/ExceptionHandling.rst b/docs/ExceptionHandling.rst
index 74827c02a272..41dd4b606b15 100644
--- a/docs/ExceptionHandling.rst
+++ b/docs/ExceptionHandling.rst
@@ -775,3 +775,67 @@ C++ code:
The "inner" ``catchswitch`` consumes ``%1`` which is produced by the outer
catchswitch.
+
+.. _wineh-constraints:
+
+Funclet transitions
+-----------------------
+
+The EH tables for personalities that use funclets make implicit use of the
+funclet nesting relationship to encode unwind destinations, and so are
+constrained in the set of funclet transitions they can represent. The related
+LLVM IR instructions accordingly have constraints that ensure encodability of
+the EH edges in the flow graph.
+
+A ``catchswitch``, ``catchpad``, or ``cleanuppad`` is said to be "entered"
+when it executes. It may subsequently be "exited" by any of the following
+means:
+
+* A ``catchswitch`` is immediately exited when none of its constituent
+ ``catchpad``\ s are appropriate for the in-flight exception and it unwinds
+ to its unwind destination or the caller.
+* A ``catchpad`` and its parent ``catchswitch`` are both exited when a
+ ``catchret`` from the ``catchpad`` is executed.
+* A ``cleanuppad`` is exited when a ``cleanupret`` from it is executed.
+* Any of these pads is exited when control unwinds to the function's caller,
+ either by a ``call`` which unwinds all the way to the function's caller,
+ a nested ``catchswitch`` marked "``unwinds to caller``", or a nested
+ ``cleanuppad``\ 's ``cleanupret`` marked "``unwinds to caller"``.
+* Any of these pads is exited when an unwind edge (from an ``invoke``,
+ nested ``catchswitch``, or nested ``cleanuppad``\ 's ``cleanupret``)
+ unwinds to a destination pad that is not a descendant of the given pad.
+
+Note that the ``ret`` instruction is *not* a valid way to exit a funclet pad;
+it is undefined behavior to execute a ``ret`` when a pad has been entered but
+not exited.
+
+A single unwind edge may exit any number of pads (with the restrictions that
+the edge from a ``catchswitch`` must exit at least itself, and the edge from
+a ``cleanupret`` must exit at least its ``cleanuppad``), and then must enter
+exactly one pad, which must be distinct from all the exited pads. The parent
+of the pad that an unwind edge enters must be the most-recently-entered
+not-yet-exited pad (after exiting from any pads that the unwind edge exits),
+or "none" if there is no such pad. This ensures that the stack of executing
+funclets at run-time always corresponds to some path in the funclet pad tree
+that the parent tokens encode.
+
+All unwind edges which exit any given funclet pad (including ``cleanupret``
+edges exiting their ``cleanuppad`` and ``catchswitch`` edges exiting their
+``catchswitch``) must share the same unwind destination. Similarly, any
+funclet pad which may be exited by unwind to caller must not be exited by
+any exception edges which unwind anywhere other than the caller. This
+ensures that each funclet as a whole has only one unwind destination, which
+EH tables for funclet personalities may require. Note that any unwind edge
+which exits a ``catchpad`` also exits its parent ``catchswitch``, so this
+implies that for any given ``catchswitch``, its unwind destination must also
+be the unwind destination of any unwind edge that exits any of its constituent
+``catchpad``\s. Because ``catchswitch`` has no ``nounwind`` variant, and
+because IR producers are not *required* to annotate calls which will not
+unwind as ``nounwind``, it is legal to nest a ``call`` or an "``unwind to
+caller``\ " ``catchswitch`` within a funclet pad that has an unwind
+destination other than caller; it is undefined behavior for such a ``call``
+or ``catchswitch`` to unwind.
+
+Finally, the funclet pads' unwind destinations cannot form a cycle. This
+ensures that EH lowering can construct "try regions" with a tree-like
+structure, which funclet-based personalities may require.
diff --git a/docs/GettingStartedVS.rst b/docs/GettingStartedVS.rst
index 63e81f5165df..0ca50904ce44 100644
--- a/docs/GettingStartedVS.rst
+++ b/docs/GettingStartedVS.rst
@@ -12,26 +12,20 @@ Welcome to LLVM on Windows! This document only covers LLVM on Windows using
Visual Studio, not mingw or cygwin. In order to get started, you first need to
know some basic information.
-There are many different projects that compose LLVM. The first is the LLVM
-suite. This contains all of the tools, libraries, and header files needed to
-use LLVM. It contains an assembler, disassembler,
-bitcode analyzer and bitcode optimizer. It also contains a test suite that can
-be used to test the LLVM tools.
-
-Another useful project on Windows is `Clang <http://clang.llvm.org/>`_.
-Clang is a C family ([Objective]C/C++) compiler. Clang mostly works on
-Windows, but does not currently understand all of the Microsoft extensions
-to C and C++. Because of this, clang cannot parse the C++ standard library
-included with Visual Studio, nor parts of the Windows Platform SDK. However,
-most standard C programs do compile. Clang can be used to emit bitcode,
-directly emit object files or even linked executables using Visual Studio's
-``link.exe``.
-
-The large LLVM test suite cannot be run on the Visual Studio port at this
-time.
-
-Most of the tools build and work. ``bugpoint`` does build, but does
-not work.
+There are many different projects that compose LLVM. The first piece is the
+LLVM suite. This contains all of the tools, libraries, and header files needed
+to use LLVM. It contains an assembler, disassembler, bitcode analyzer and
+bitcode optimizer. It also contains basic regression tests that can be used to
+test the LLVM tools and the Clang front end.
+
+The second piece is the `Clang <http://clang.llvm.org/>`_ front end. This
+component compiles C, C++, Objective C, and Objective C++ code into LLVM
+bitcode. Clang typically uses LLVM libraries to optimize the bitcode and emit
+machine code. LLVM fully supports the COFF object file format, which is
+compatible with all other existing Windows toolchains.
+
+The last major part of LLVM, the execution Test Suite, does not run on Windows,
+and this document does not discuss it.
Additional information about the LLVM directory structure and tool chain
can be found on the main :doc:`GettingStarted` page.
diff --git a/docs/LangRef.rst b/docs/LangRef.rst
index 103d876b3cef..5f8a3a5a4a98 100644
--- a/docs/LangRef.rst
+++ b/docs/LangRef.rst
@@ -1579,6 +1579,8 @@ caller's deoptimization state to the callee's deoptimization state is
semantically equivalent to composing the caller's deoptimization
continuation after the callee's deoptimization continuation.
+.. _ob_funclet:
+
Funclet Operand Bundles
^^^^^^^^^^^^^^^^^^^^^^^
@@ -1588,6 +1590,18 @@ is within a particular funclet. There can be at most one
``"funclet"`` operand bundle attached to a call site and it must have
exactly one bundle operand.
+If any funclet EH pads have been "entered" but not "exited" (per the
+`description in the EH doc\ <ExceptionHandling.html#wineh-constraints>`_),
+it is undefined behavior to execute a ``call`` or ``invoke`` which:
+
+* does not have a ``"funclet"`` bundle and is not a ``call`` to a nounwind
+ intrinsic, or
+* has a ``"funclet"`` bundle whose operand is not the most-recently-entered
+ not-yet-exited funclet EH pad.
+
+Similarly, if no funclet EH pads have been entered-but-not-yet-exited,
+executing a ``call`` or ``invoke`` with a ``"funclet"`` bundle is undefined behavior.
+
.. _moduleasm:
Module-Level Inline Assembly
@@ -5404,10 +5418,12 @@ The ``parent`` argument is the token of the funclet that contains the
``catchswitch`` instruction. If the ``catchswitch`` is not inside a funclet,
this operand may be the token ``none``.
-The ``default`` argument is the label of another basic block beginning with a
-"pad" instruction, one of ``cleanuppad`` or ``catchswitch``.
+The ``default`` argument is the label of another basic block beginning with
+either a ``cleanuppad`` or ``catchswitch`` instruction. This unwind destination
+must be a legal target with respect to the ``parent`` links, as described in
+the `exception handling documentation\ <ExceptionHandling.html#wineh-constraints>`_.
-The ``handlers`` are a list of successor blocks that each begin with a
+The ``handlers`` are a nonempty list of successor blocks that each begin with a
:ref:`catchpad <i_catchpad>` instruction.
Semantics:
@@ -5431,82 +5447,6 @@ Example:
dispatch2:
%cs2 = catchswitch within %parenthandler [label %handler0] unwind label %cleanup
-.. _i_catchpad:
-
-'``catchpad``' Instruction
-^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Syntax:
-"""""""
-
-::
-
- <resultval> = catchpad within <catchswitch> [<args>*]
-
-Overview:
-"""""""""
-
-The '``catchpad``' instruction is used by `LLVM's exception handling
-system <ExceptionHandling.html#overview>`_ to specify that a basic block
-begins a catch handler --- one where a personality routine attempts to transfer
-control to catch an exception.
-
-Arguments:
-""""""""""
-
-The ``catchswitch`` operand must always be a token produced by a
-:ref:`catchswitch <i_catchswitch>` instruction in a predecessor block. This
-ensures that each ``catchpad`` has exactly one predecessor block, and it always
-terminates in a ``catchswitch``.
-
-The ``args`` correspond to whatever information the personality routine
-requires to know if this is an appropriate handler for the exception. Control
-will transfer to the ``catchpad`` if this is the first appropriate handler for
-the exception.
-
-The ``resultval`` has the type :ref:`token <t_token>` and is used to match the
-``catchpad`` to corresponding :ref:`catchrets <i_catchret>` and other nested EH
-pads.
-
-Semantics:
-""""""""""
-
-When the call stack is being unwound due to an exception being thrown, the
-exception is compared against the ``args``. If it doesn't match, control will
-not reach the ``catchpad`` instruction. The representation of ``args`` is
-entirely target and personality function-specific.
-
-Like the :ref:`landingpad <i_landingpad>` instruction, the ``catchpad``
-instruction must be the first non-phi of its parent basic block.
-
-The meaning of the tokens produced and consumed by ``catchpad`` and other "pad"
-instructions is described in the
-`Windows exception handling documentation <ExceptionHandling.html#wineh>`.
-
-Executing a ``catchpad`` instruction constitutes "entering" that pad.
-The pad may then be "exited" in one of three ways:
-
-1) explicitly via a ``catchret`` that consumes it. Executing such a ``catchret``
- is undefined behavior if any descendant pads have been entered but not yet
- exited.
-2) implicitly via a call (which unwinds all the way to the current function's caller),
- or via a ``catchswitch`` or a ``cleanupret`` that unwinds to caller.
-3) implicitly via an unwind edge whose destination EH pad isn't a descendant of
- the ``catchpad``. When the ``catchpad`` is exited in this manner, it is
- undefined behavior if the destination EH pad has a parent which is not an
- ancestor of the ``catchpad`` being exited.
-
-Example:
-""""""""
-
-.. code-block:: llvm
-
- dispatch:
- %cs = catchswitch within none [label %handler0] unwind to caller
- ;; A catch block which can catch an integer.
- handler0:
- %tok = catchpad within %cs [i8** @_ZTIi]
-
.. _i_catchret:
'``catchret``' Instruction
@@ -5543,11 +5483,10 @@ unwinding was interrupted with a :ref:`catchpad <i_catchpad>` instruction. The
code to, for example, destroy the active exception. Control then transfers to
``normal``.
-The ``token`` argument must be a token produced by a dominating ``catchpad``
-instruction. The ``catchret`` destroys the physical frame established by
-``catchpad``, so executing multiple returns on the same token without
-re-executing the ``catchpad`` will result in undefined behavior.
-See :ref:`catchpad <i_catchpad>` for more details.
+The ``token`` argument must be a token produced by a ``catchpad`` instruction.
+If the specified ``catchpad`` is not the most-recently-entered not-yet-exited
+funclet pad (as described in the `EH documentation\ <ExceptionHandling.html#wineh-constraints>`_),
+the ``catchret``'s behavior is undefined.
Example:
""""""""
@@ -5581,7 +5520,15 @@ Arguments:
The '``cleanupret``' instruction requires one argument, which indicates
which ``cleanuppad`` it exits, and must be a :ref:`cleanuppad <i_cleanuppad>`.
-It also has an optional successor, ``continue``.
+If the specified ``cleanuppad`` is not the most-recently-entered not-yet-exited
+funclet pad (as described in the `EH documentation\ <ExceptionHandling.html#wineh-constraints>`_),
+the ``cleanupret``'s behavior is undefined.
+
+The '``cleanupret``' instruction also has an optional successor, ``continue``,
+which must be the label of another basic block beginning with either a
+``cleanuppad`` or ``catchswitch`` instruction. This unwind destination must
+be a legal target with respect to the ``parent`` links, as described in the
+`exception handling documentation\ <ExceptionHandling.html#wineh-constraints>`_.
Semantics:
""""""""""
@@ -5591,13 +5538,6 @@ The '``cleanupret``' instruction indicates to the
:ref:`cleanuppad <i_cleanuppad>` it transferred control to has ended.
It transfers control to ``continue`` or unwinds out of the function.
-The unwind destination ``continue``, if present, must be an EH pad
-whose parent is either ``none`` or an ancestor of the ``cleanuppad``
-being returned from. This constitutes an exceptional exit from all
-ancestors of the completed ``cleanuppad``, up to but not including
-the parent of ``continue``.
-See :ref:`cleanuppad <i_cleanuppad>` for more details.
-
Example:
""""""""
@@ -6996,7 +6936,7 @@ name ``<index>`` corresponding to a metadata node with one ``i32`` entry of
value 1. The existence of the ``!nontemporal`` metadata on the instruction
tells the optimizer and code generator that this load is not expected to
be reused in the cache. The code generator may select special
-instructions to save cache bandwidth, such as the MOVNT instruction on
+instructions to save cache bandwidth, such as the ``MOVNT`` instruction on
x86.
The optional ``!invariant.group`` metadata must reference a
@@ -8590,6 +8530,74 @@ Example:
catch i8** @_ZTIi
filter [1 x i8**] [@_ZTId]
+.. _i_catchpad:
+
+'``catchpad``' Instruction
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Syntax:
+"""""""
+
+::
+
+ <resultval> = catchpad within <catchswitch> [<args>*]
+
+Overview:
+"""""""""
+
+The '``catchpad``' instruction is used by `LLVM's exception handling
+system <ExceptionHandling.html#overview>`_ to specify that a basic block
+begins a catch handler --- one where a personality routine attempts to transfer
+control to catch an exception.
+
+Arguments:
+""""""""""
+
+The ``catchswitch`` operand must always be a token produced by a
+:ref:`catchswitch <i_catchswitch>` instruction in a predecessor block. This
+ensures that each ``catchpad`` has exactly one predecessor block, and it always
+terminates in a ``catchswitch``.
+
+The ``args`` correspond to whatever information the personality routine
+requires to know if this is an appropriate handler for the exception. Control
+will transfer to the ``catchpad`` if this is the first appropriate handler for
+the exception.
+
+The ``resultval`` has the type :ref:`token <t_token>` and is used to match the
+``catchpad`` to corresponding :ref:`catchrets <i_catchret>` and other nested EH
+pads.
+
+Semantics:
+""""""""""
+
+When the call stack is being unwound due to an exception being thrown, the
+exception is compared against the ``args``. If it doesn't match, control will
+not reach the ``catchpad`` instruction. The representation of ``args`` is
+entirely target and personality function-specific.
+
+Like the :ref:`landingpad <i_landingpad>` instruction, the ``catchpad``
+instruction must be the first non-phi of its parent basic block.
+
+The meaning of the tokens produced and consumed by ``catchpad`` and other "pad"
+instructions is described in the
+`Windows exception handling documentation\ <ExceptionHandling.html#wineh>`_.
+
+When a ``catchpad`` has been "entered" but not yet "exited" (as
+described in the `EH documentation\ <ExceptionHandling.html#wineh-constraints>`_),
+it is undefined behavior to execute a :ref:`call <i_call>` or :ref:`invoke <i_invoke>`
+that does not carry an appropriate :ref:`"funclet" bundle <ob_funclet>`.
+
+Example:
+""""""""
+
+.. code-block:: llvm
+
+ dispatch:
+ %cs = catchswitch within none [label %handler0] unwind to caller
+ ;; A catch block which can catch an integer.
+ handler0:
+ %tok = catchpad within %cs [i8** @_ZTIi]
+
.. _i_cleanuppad:
'``cleanuppad``' Instruction
@@ -8644,22 +8652,10 @@ The ``cleanuppad`` instruction has several restrictions:
- A basic block that is not a cleanup block may not include a
'``cleanuppad``' instruction.
-Executing a ``cleanuppad`` instruction constitutes "entering" that pad.
-The pad may then be "exited" in one of three ways:
-
-1) explicitly via a ``cleanupret`` that consumes it. Executing such a ``cleanupret``
- is undefined behavior if any descendant pads have been entered but not yet
- exited.
-2) implicitly via a call (which unwinds all the way to the current function's caller),
- or via a ``catchswitch`` or a ``cleanupret`` that unwinds to caller.
-3) implicitly via an unwind edge whose destination EH pad isn't a descendant of
- the ``cleanuppad``. When the ``cleanuppad`` is exited in this manner, it is
- undefined behavior if the destination EH pad has a parent which is not an
- ancestor of the ``cleanuppad`` being exited.
-
-It is undefined behavior for the ``cleanuppad`` to exit via an unwind edge which
-does not transitively unwind to the same destination as a constituent
-``cleanupret``.
+When a ``cleanuppad`` has been "entered" but not yet "exited" (as
+described in the `EH documentation\ <ExceptionHandling.html#wineh-constraints>`_),
+it is undefined behavior to execute a :ref:`call <i_call>` or :ref:`invoke <i_invoke>`
+that does not carry an appropriate :ref:`"funclet" bundle <ob_funclet>`.
Example:
""""""""
diff --git a/docs/Phabricator.rst b/docs/Phabricator.rst
index 73704d9b17d7..af1e4429fda9 100644
--- a/docs/Phabricator.rst
+++ b/docs/Phabricator.rst
@@ -136,7 +136,7 @@ reviewers, the ``Differential Revision``, etc from the review and commit it to t
arc commit --revision D<Revision>
-When committing an LLVM change that has been reviewed using
+When committing a change that has been reviewed using
Phabricator, the convention is for the commit message to end with the
line:
@@ -153,6 +153,12 @@ This allows people reading the version history to see the review for
context. This also allows Phabricator to detect the commit, close the
review, and add a link from the review to the commit.
+If you use ``git`` or ``svn`` to commit the change and forget to add the line
+to your commit message, you should close the review manually. In the web UI,
+under "Leap Into Action" put the SVN revision number in the Comment, set the
+Action to "Close Revision" and click Submit. Note the review must have been
+Accepted first.
+
Abandoning a change
-------------------
diff --git a/docs/ProgrammersManual.rst b/docs/ProgrammersManual.rst
index 44f76fef8f1f..665e30aeb676 100644
--- a/docs/ProgrammersManual.rst
+++ b/docs/ProgrammersManual.rst
@@ -408,6 +408,9 @@ Then you can run your pass like this:
'foo' debug type
$ opt < a.bc > /dev/null -mypass -debug-only=bar
'bar' debug type
+ $ opt < a.bc > /dev/null -mypass -debug-only=foo,bar
+ 'foo' debug type
+ 'bar' debug type
Of course, in practice, you should only set ``DEBUG_TYPE`` at the top of a file,
to specify the debug type for the entire module. Be careful that you only do
@@ -417,7 +420,8 @@ system in place to ensure that names do not conflict. If two different modules
use the same string, they will all be turned on when the name is specified.
This allows, for example, all debug information for instruction scheduling to be
enabled with ``-debug-only=InstrSched``, even if the source lives in multiple
-files.
+files. The name must not include a comma (,) as that is used to seperate the
+arguments of the ``-debug-only`` option.
For performance reasons, -debug-only is not available in optimized build
(``--enable-optimized``) of LLVM.
diff --git a/examples/Kaleidoscope/Orc/fully_lazy/toy.cpp b/examples/Kaleidoscope/Orc/fully_lazy/toy.cpp
index 78184f5d32cd..0371a3f76f69 100644
--- a/examples/Kaleidoscope/Orc/fully_lazy/toy.cpp
+++ b/examples/Kaleidoscope/Orc/fully_lazy/toy.cpp
@@ -4,7 +4,7 @@
#include "llvm/ExecutionEngine/Orc/LambdaResolver.h"
#include "llvm/ExecutionEngine/Orc/LazyEmittingLayer.h"
#include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h"
-#include "llvm/ExecutionEngine/Orc/OrcTargetSupport.h"
+#include "llvm/ExecutionEngine/Orc/OrcArchitectureSupport.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/IRBuilder.h"
diff --git a/include/llvm/ADT/IntEqClasses.h b/include/llvm/ADT/IntEqClasses.h
index 8e75c48e3764..0baee2f11a79 100644
--- a/include/llvm/ADT/IntEqClasses.h
+++ b/include/llvm/ADT/IntEqClasses.h
@@ -53,10 +53,10 @@ public:
NumClasses = 0;
}
- /// join - Join the equivalence classes of a and b. After joining classes,
- /// findLeader(a) == findLeader(b).
- /// This requires an uncompressed map.
- void join(unsigned a, unsigned b);
+ /// Join the equivalence classes of a and b. After joining classes,
+ /// findLeader(a) == findLeader(b). This requires an uncompressed map.
+ /// Returns the new leader.
+ unsigned join(unsigned a, unsigned b);
/// findLeader - Compute the leader of a's equivalence class. This is the
/// smallest member of the class.
diff --git a/include/llvm/ADT/PointerEmbeddedInt.h b/include/llvm/ADT/PointerEmbeddedInt.h
new file mode 100644
index 000000000000..8781d1803ac7
--- /dev/null
+++ b/include/llvm/ADT/PointerEmbeddedInt.h
@@ -0,0 +1,103 @@
+//===- llvm/ADT/PointerEmbeddedInt.h ----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_ADT_POINTEREMBEDDEDINT_H
+#define LLVM_ADT_POINTEREMBEDDEDINT_H
+
+#include "llvm/ADT/DenseMapInfo.h"
+#include "llvm/Support/PointerLikeTypeTraits.h"
+#include <climits>
+
+namespace llvm {
+
+/// Utility to embed an integer into a pointer-like type. This is specifically
+/// intended to allow embedding integers where fewer bits are required than
+/// exist in a pointer, and the integer can participate in abstractions along
+/// side other pointer-like types. For example it can be placed into a \c
+/// PointerSumType or \c PointerUnion.
+///
+/// Note that much like pointers, an integer value of zero has special utility
+/// due to boolean conversions. For example, a non-null value can be tested for
+/// in the above abstractions without testing the particular active member.
+/// Also, the default constructed value zero initializes the integer.
+template <typename IntT, int Bits = sizeof(IntT) * CHAR_BIT>
+class PointerEmbeddedInt {
+ uintptr_t Value;
+
+ static_assert(Bits < sizeof(uintptr_t) * CHAR_BIT,
+ "Cannot embed more bits than we have in a pointer!");
+
+ enum : uintptr_t {
+ // We shift as many zeros into the value as we can while preserving the
+ // number of bits desired for the integer.
+ Shift = sizeof(uintptr_t) * CHAR_BIT - Bits,
+
+ // We also want to be able to mask out the preserved bits for asserts.
+ Mask = static_cast<uintptr_t>(-1) << Bits
+ };
+
+ friend class PointerLikeTypeTraits<PointerEmbeddedInt>;
+
+ explicit PointerEmbeddedInt(uintptr_t Value) : Value(Value) {}
+
+public:
+ PointerEmbeddedInt() : Value(0) {}
+
+ PointerEmbeddedInt(IntT I) : Value(static_cast<uintptr_t>(I) << Shift) {
+ assert((I & Mask) == 0 && "Integer has bits outside those preserved!");
+ }
+
+ PointerEmbeddedInt &operator=(IntT I) {
+ assert((I & Mask) == 0 && "Integer has bits outside those preserved!");
+ Value = static_cast<uintptr_t>(I) << Shift;
+ }
+
+ // Note that this imilict conversion additionally allows all of the basic
+ // comparison operators to work transparently, etc.
+ operator IntT() const { return static_cast<IntT>(Value >> Shift); }
+};
+
+// Provide pointer like traits to support use with pointer unions and sum
+// types.
+template <typename IntT, int Bits>
+class PointerLikeTypeTraits<PointerEmbeddedInt<IntT, Bits>> {
+ typedef PointerEmbeddedInt<IntT, Bits> T;
+
+public:
+ static inline void *getAsVoidPointer(const T &P) {
+ return reinterpret_cast<void *>(P.Value);
+ }
+ static inline T getFromVoidPointer(void *P) {
+ return T(reinterpret_cast<uintptr_t>(P));
+ }
+ static inline T getFromVoidPointer(const void *P) {
+ return T(reinterpret_cast<uintptr_t>(P));
+ }
+
+ enum { NumLowBitsAvailable = T::Shift };
+};
+
+// Teach DenseMap how to use PointerEmbeddedInt objects as keys if the Int type
+// itself can be a key.
+template <typename IntT, int Bits>
+struct DenseMapInfo<PointerEmbeddedInt<IntT, Bits>> {
+ typedef PointerEmbeddedInt<IntT, Bits> T;
+
+ typedef DenseMapInfo<IntT> IntInfo;
+
+ static inline T getEmptyKey() { return IntInfo::getEmptyKey(); }
+ static inline T getTombstoneKey() { return IntInfo::getTombstoneKey(); }
+ static unsigned getHashValue(const T &Arg) {
+ return IntInfo::getHashValue(Arg);
+ }
+ static bool isEqual(const T &LHS, const T &RHS) { return LHS == RHS; }
+};
+}
+
+#endif
diff --git a/include/llvm/ADT/PointerIntPair.h b/include/llvm/ADT/PointerIntPair.h
index 0058d85d1ae4..83fbf127e6da 100644
--- a/include/llvm/ADT/PointerIntPair.h
+++ b/include/llvm/ADT/PointerIntPair.h
@@ -55,20 +55,25 @@ public:
PointerTy getPointer() const { return Info::getPointer(Value); }
- IntType getInt() const { return (IntType)Info::getInt(Value); }
+ IntType getInt() const {
+ return (IntType)Info::getInt(Value);
+ }
void setPointer(PointerTy PtrVal) {
Value = Info::updatePointer(Value, PtrVal);
}
- void setInt(IntType IntVal) { Value = Info::updateInt(Value, IntVal); }
+ void setInt(IntType IntVal) {
+ Value = Info::updateInt(Value, static_cast<intptr_t>(IntVal));
+ }
void initWithPointer(PointerTy PtrVal) {
Value = Info::updatePointer(0, PtrVal);
}
void setPointerAndInt(PointerTy PtrVal, IntType IntVal) {
- Value = Info::updateInt(Info::updatePointer(0, PtrVal), IntVal);
+ Value = Info::updateInt(Info::updatePointer(0, PtrVal),
+ static_cast<intptr_t>(IntVal));
}
PointerTy const *getAddrOfPointer() const {
diff --git a/include/llvm/ADT/PointerSumType.h b/include/llvm/ADT/PointerSumType.h
new file mode 100644
index 000000000000..6b8618fc5a17
--- /dev/null
+++ b/include/llvm/ADT/PointerSumType.h
@@ -0,0 +1,205 @@
+//===- llvm/ADT/PointerSumType.h --------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_ADT_POINTERSUMTYPE_H
+#define LLVM_ADT_POINTERSUMTYPE_H
+
+#include "llvm/ADT/DenseMapInfo.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/PointerLikeTypeTraits.h"
+
+namespace llvm {
+
+/// A compile time pair of an integer tag and the pointer-like type which it
+/// indexes within a sum type. Also allows the user to specify a particular
+/// traits class for pointer types with custom behavior such as over-aligned
+/// allocation.
+template <uintptr_t N, typename PointerArgT,
+ typename TraitsArgT = PointerLikeTypeTraits<PointerArgT>>
+struct PointerSumTypeMember {
+ enum { Tag = N };
+ typedef PointerArgT PointerT;
+ typedef TraitsArgT TraitsT;
+};
+
+namespace detail {
+
+template <typename TagT, typename... MemberTs>
+struct PointerSumTypeHelper;
+
+}
+
+/// A sum type over pointer-like types.
+///
+/// This is a normal tagged union across pointer-like types that uses the low
+/// bits of the pointers to store the tag.
+///
+/// Each member of the sum type is specified by passing a \c
+/// PointerSumTypeMember specialization in the variadic member argument list.
+/// This allows the user to control the particular tag value associated with
+/// a particular type, use the same type for multiple different tags, and
+/// customize the pointer-like traits used for a particular member. Note that
+/// these *must* be specializations of \c PointerSumTypeMember, no other type
+/// will suffice, even if it provides a compatible interface.
+///
+/// This type implements all of the comparison operators and even hash table
+/// support by comparing the underlying storage of the pointer values. It
+/// doesn't support delegating to particular members for comparisons.
+///
+/// It also default constructs to a zero tag with a null pointer, whatever that
+/// would be. This means that the zero value for the tag type is significant
+/// and may be desireable to set to a state that is particularly desirable to
+/// default construct.
+///
+/// There is no support for constructing or accessing with a dynamic tag as
+/// that would fundamentally violate the type safety provided by the sum type.
+template <typename TagT, typename... MemberTs> class PointerSumType {
+ uintptr_t Value;
+
+ typedef detail::PointerSumTypeHelper<TagT, MemberTs...> HelperT;
+
+public:
+ PointerSumType() : Value(0) {}
+
+ /// A typed constructor for a specific tagged member of the sum type.
+ template <TagT N>
+ static PointerSumType
+ create(typename HelperT::template Lookup<N>::PointerT Pointer) {
+ PointerSumType Result;
+ void *V = HelperT::template Lookup<N>::TraitsT::getAsVoidPointer(Pointer);
+ assert((reinterpret_cast<uintptr_t>(V) & HelperT::TagMask) == 0 &&
+ "Pointer is insufficiently aligned to store the discriminant!");
+ Result.Value = reinterpret_cast<uintptr_t>(V) | N;
+ return Result;
+ }
+
+ TagT getTag() const { return static_cast<TagT>(Value & HelperT::TagMask); }
+
+ template <TagT N> bool is() const { return N == getTag(); }
+
+ template <TagT N> typename HelperT::template Lookup<N>::PointerT get() const {
+ void *P = is<N>() ? getImpl() : nullptr;
+ return HelperT::template Lookup<N>::TraitsT::getFromVoidPointer(P);
+ }
+
+ template <TagT N>
+ typename HelperT::template Lookup<N>::PointerT cast() const {
+ assert(is<N>() && "This instance has a different active member.");
+ return HelperT::template Lookup<N>::TraitsT::getFromVoidPointer(getImpl());
+ }
+
+ operator bool() const { return Value & HelperT::PointerMask; }
+ bool operator==(const PointerSumType &R) const { return Value == R.Value; }
+ bool operator!=(const PointerSumType &R) const { return Value != R.Value; }
+ bool operator<(const PointerSumType &R) const { return Value < R.Value; }
+ bool operator>(const PointerSumType &R) const { return Value > R.Value; }
+ bool operator<=(const PointerSumType &R) const { return Value <= R.Value; }
+ bool operator>=(const PointerSumType &R) const { return Value >= R.Value; }
+
+ uintptr_t getOpaqueValue() const { return Value; }
+
+protected:
+ void *getImpl() const {
+ return reinterpret_cast<void *>(Value & HelperT::PointerMask);
+ }
+};
+
+namespace detail {
+
+/// A helper template for implementing \c PointerSumType. It provides fast
+/// compile-time lookup of the member from a particular tag value, along with
+/// useful constants and compile time checking infrastructure..
+template <typename TagT, typename... MemberTs>
+struct PointerSumTypeHelper : MemberTs... {
+ // First we use a trick to allow quickly looking up information about
+ // a particular member of the sum type. This works because we arranged to
+ // have this type derive from all of the member type templates. We can select
+ // the matching member for a tag using type deduction during overload
+ // resolution.
+ template <TagT N, typename PointerT, typename TraitsT>
+ static PointerSumTypeMember<N, PointerT, TraitsT>
+ LookupOverload(PointerSumTypeMember<N, PointerT, TraitsT> *);
+ template <TagT N> static void LookupOverload(...);
+ template <TagT N> struct Lookup {
+ // Compute a particular member type by resolving the lookup helper ovorload.
+ typedef decltype(LookupOverload<N>(
+ static_cast<PointerSumTypeHelper *>(nullptr))) MemberT;
+
+ /// The Nth member's pointer type.
+ typedef typename MemberT::PointerT PointerT;
+
+ /// The Nth member's traits type.
+ typedef typename MemberT::TraitsT TraitsT;
+ };
+
+ // Next we need to compute the number of bits available for the discriminant
+ // by taking the min of the bits available for each member. Much of this
+ // would be amazingly easier with good constexpr support.
+ template <uintptr_t V, uintptr_t... Vs>
+ struct Min : std::integral_constant<
+ uintptr_t, (V < Min<Vs...>::value ? V : Min<Vs...>::value)> {
+ };
+ template <uintptr_t V>
+ struct Min<V> : std::integral_constant<uintptr_t, V> {};
+ enum { NumTagBits = Min<MemberTs::TraitsT::NumLowBitsAvailable...>::value };
+
+ // Also compute the smallest discriminant and various masks for convenience.
+ enum : uint64_t {
+ MinTag = Min<MemberTs::Tag...>::value,
+ PointerMask = static_cast<uint64_t>(-1) << NumTagBits,
+ TagMask = ~PointerMask
+ };
+
+ // Finally we need a recursive template to do static checks of each
+ // member.
+ template <typename MemberT, typename... InnerMemberTs>
+ struct Checker : Checker<InnerMemberTs...> {
+ static_assert(MemberT::Tag < (1 << NumTagBits),
+ "This discriminant value requires too many bits!");
+ };
+ template <typename MemberT> struct Checker<MemberT> : std::true_type {
+ static_assert(MemberT::Tag < (1 << NumTagBits),
+ "This discriminant value requires too many bits!");
+ };
+ static_assert(Checker<MemberTs...>::value,
+ "Each member must pass the checker.");
+};
+
+}
+
+// Teach DenseMap how to use PointerSumTypes as keys.
+template <typename TagT, typename... MemberTs>
+struct DenseMapInfo<PointerSumType<TagT, MemberTs...>> {
+ typedef PointerSumType<TagT, MemberTs...> SumType;
+
+ typedef detail::PointerSumTypeHelper<TagT, MemberTs...> HelperT;
+ enum { SomeTag = HelperT::MinTag };
+ typedef typename HelperT::template Lookup<HelperT::MinTag>::PointerT
+ SomePointerT;
+ typedef DenseMapInfo<SomePointerT> SomePointerInfo;
+
+ static inline SumType getEmptyKey() {
+ return SumType::create<SomeTag>(SomePointerInfo::getEmptyKey());
+ }
+ static inline SumType getTombstoneKey() {
+ return SumType::create<SomeTag>(
+ SomePointerInfo::getTombstoneKey());
+ }
+ static unsigned getHashValue(const SumType &Arg) {
+ uintptr_t OpaqueValue = Arg.getOpaqueValue();
+ return DenseMapInfo<uintptr_t>::getHashValue(OpaqueValue);
+ }
+ static bool isEqual(const SumType &LHS, const SumType &RHS) {
+ return LHS == RHS;
+ }
+};
+
+}
+
+#endif
diff --git a/include/llvm/ADT/Twine.h b/include/llvm/ADT/Twine.h
index db0bf4b68de8..81b1a6d946fc 100644
--- a/include/llvm/ADT/Twine.h
+++ b/include/llvm/ADT/Twine.h
@@ -101,15 +101,13 @@ namespace llvm {
/// A pointer to a SmallString instance.
SmallStringKind,
- /// A char value reinterpreted as a pointer, to render as a character.
+ /// A char value, to render as a character.
CharKind,
- /// An unsigned int value reinterpreted as a pointer, to render as an
- /// unsigned decimal integer.
+ /// An unsigned int value, to render as an unsigned decimal integer.
DecUIKind,
- /// An int value reinterpreted as a pointer, to render as a signed
- /// decimal integer.
+ /// An int value, to render as a signed decimal integer.
DecIKind,
/// A pointer to an unsigned long value, to render as an unsigned decimal
diff --git a/include/llvm/Analysis/LazyCallGraph.h b/include/llvm/Analysis/LazyCallGraph.h
index ef3d5e8fe3df..e02f3ab2de1f 100644
--- a/include/llvm/Analysis/LazyCallGraph.h
+++ b/include/llvm/Analysis/LazyCallGraph.h
@@ -104,54 +104,10 @@ class LazyCallGraph {
public:
class Node;
class SCC;
+ class iterator;
typedef SmallVector<PointerUnion<Function *, Node *>, 4> NodeVectorT;
typedef SmallVectorImpl<PointerUnion<Function *, Node *>> NodeVectorImplT;
- /// A lazy iterator used for both the entry nodes and child nodes.
- ///
- /// When this iterator is dereferenced, if not yet available, a function will
- /// be scanned for "calls" or uses of functions and its child information
- /// will be constructed. All of these results are accumulated and cached in
- /// the graph.
- class iterator
- : public iterator_adaptor_base<iterator, NodeVectorImplT::iterator,
- std::forward_iterator_tag, Node> {
- friend class LazyCallGraph;
- friend class LazyCallGraph::Node;
-
- LazyCallGraph *G;
- NodeVectorImplT::iterator E;
-
- // Build the iterator for a specific position in a node list.
- iterator(LazyCallGraph &G, NodeVectorImplT::iterator NI,
- NodeVectorImplT::iterator E)
- : iterator_adaptor_base(NI), G(&G), E(E) {
- while (I != E && I->isNull())
- ++I;
- }
-
- public:
- iterator() {}
-
- using iterator_adaptor_base::operator++;
- iterator &operator++() {
- do {
- ++I;
- } while (I != E && I->isNull());
- return *this;
- }
-
- reference operator*() const {
- if (I->is<Node *>())
- return *I->get<Node *>();
-
- Function *F = I->get<Function *>();
- Node &ChildN = G->get(*F);
- *I = &ChildN;
- return ChildN;
- }
- };
-
/// A node in the call graph.
///
/// This represents a single node. It's primary roles are to cache the list of
@@ -200,6 +156,51 @@ public:
bool operator!=(const Node &N) const { return !operator==(N); }
};
+ /// A lazy iterator used for both the entry nodes and child nodes.
+ ///
+ /// When this iterator is dereferenced, if not yet available, a function will
+ /// be scanned for "calls" or uses of functions and its child information
+ /// will be constructed. All of these results are accumulated and cached in
+ /// the graph.
+ class iterator
+ : public iterator_adaptor_base<iterator, NodeVectorImplT::iterator,
+ std::forward_iterator_tag, Node> {
+ friend class LazyCallGraph;
+ friend class LazyCallGraph::Node;
+
+ LazyCallGraph *G;
+ NodeVectorImplT::iterator E;
+
+ // Build the iterator for a specific position in a node list.
+ iterator(LazyCallGraph &G, NodeVectorImplT::iterator NI,
+ NodeVectorImplT::iterator E)
+ : iterator_adaptor_base(NI), G(&G), E(E) {
+ while (I != E && I->isNull())
+ ++I;
+ }
+
+ public:
+ iterator() {}
+
+ using iterator_adaptor_base::operator++;
+ iterator &operator++() {
+ do {
+ ++I;
+ } while (I != E && I->isNull());
+ return *this;
+ }
+
+ reference operator*() const {
+ if (I->is<Node *>())
+ return *I->get<Node *>();
+
+ Function *F = I->get<Function *>();
+ Node &ChildN = G->get(*F);
+ *I = &ChildN;
+ return ChildN;
+ }
+ };
+
/// An SCC of the call graph.
///
/// This represents a Strongly Connected Component of the call graph as
diff --git a/include/llvm/Analysis/LoopInfo.h b/include/llvm/Analysis/LoopInfo.h
index c219bd85a48a..70e636ce1f3d 100644
--- a/include/llvm/Analysis/LoopInfo.h
+++ b/include/llvm/Analysis/LoopInfo.h
@@ -59,38 +59,37 @@ template<class N, class M> class LoopInfoBase;
template<class N, class M> class LoopBase;
//===----------------------------------------------------------------------===//
-/// LoopBase class - Instances of this class are used to represent loops that
-/// are detected in the flow graph
+/// Instances of this class are used to represent loops that are detected in the
+/// flow graph.
///
template<class BlockT, class LoopT>
class LoopBase {
LoopT *ParentLoop;
- // SubLoops - Loops contained entirely within this one.
+ // Loops contained entirely within this one.
std::vector<LoopT *> SubLoops;
- // Blocks - The list of blocks in this loop. First entry is the header node.
+ // The list of blocks in this loop. First entry is the header node.
std::vector<BlockT*> Blocks;
SmallPtrSet<const BlockT*, 8> DenseBlockSet;
- /// Indicator that this loops has been "unlooped", so there's no loop here
- /// anymore.
- bool IsUnloop = false;
+ /// Indicator that this loop is no longer a valid loop.
+ bool IsInvalid = false;
LoopBase(const LoopBase<BlockT, LoopT> &) = delete;
const LoopBase<BlockT, LoopT>&
operator=(const LoopBase<BlockT, LoopT> &) = delete;
public:
- /// Loop ctor - This creates an empty loop.
+ /// This creates an empty loop.
LoopBase() : ParentLoop(nullptr) {}
~LoopBase() {
for (size_t i = 0, e = SubLoops.size(); i != e; ++i)
delete SubLoops[i];
}
- /// getLoopDepth - Return the nesting level of this loop. An outer-most
- /// loop has depth 1, for consistency with loop depth values used for basic
- /// blocks, where depth 0 is used for blocks not inside any loops.
+ /// Return the nesting level of this loop. An outer-most loop has depth 1,
+ /// for consistency with loop depth values used for basic blocks, where depth
+ /// 0 is used for blocks not inside any loops.
unsigned getLoopDepth() const {
unsigned D = 1;
for (const LoopT *CurLoop = ParentLoop; CurLoop;
@@ -101,33 +100,28 @@ public:
BlockT *getHeader() const { return Blocks.front(); }
LoopT *getParentLoop() const { return ParentLoop; }
- /// setParentLoop is a raw interface for bypassing addChildLoop.
+ /// This is a raw interface for bypassing addChildLoop.
void setParentLoop(LoopT *L) { ParentLoop = L; }
- /// contains - Return true if the specified loop is contained within in
- /// this loop.
- ///
+ /// Return true if the specified loop is contained within in this loop.
bool contains(const LoopT *L) const {
if (L == this) return true;
if (!L) return false;
return contains(L->getParentLoop());
}
- /// contains - Return true if the specified basic block is in this loop.
- ///
+ /// Return true if the specified basic block is in this loop.
bool contains(const BlockT *BB) const {
return DenseBlockSet.count(BB);
}
- /// contains - Return true if the specified instruction is in this loop.
- ///
+ /// Return true if the specified instruction is in this loop.
template<class InstT>
bool contains(const InstT *Inst) const {
return contains(Inst->getParent());
}
- /// iterator/begin/end - Return the loops contained entirely within this loop.
- ///
+ /// Return the loops contained entirely within this loop.
const std::vector<LoopT *> &getSubLoops() const { return SubLoops; }
std::vector<LoopT *> &getSubLoopsVector() { return SubLoops; }
typedef typename std::vector<LoopT *>::const_iterator iterator;
@@ -139,8 +133,7 @@ public:
reverse_iterator rend() const { return SubLoops.rend(); }
bool empty() const { return SubLoops.empty(); }
- /// getBlocks - Get a list of the basic blocks which make up this loop.
- ///
+ /// Get a list of the basic blocks which make up this loop.
const std::vector<BlockT*> &getBlocks() const { return Blocks; }
typedef typename std::vector<BlockT*>::const_iterator block_iterator;
block_iterator block_begin() const { return Blocks.begin(); }
@@ -149,21 +142,19 @@ public:
return make_range(block_begin(), block_end());
}
- /// getNumBlocks - Get the number of blocks in this loop in constant time.
+ /// Get the number of blocks in this loop in constant time.
unsigned getNumBlocks() const {
return Blocks.size();
}
- /// Mark this loop as having been unlooped - the last backedge was removed and
- /// we no longer have a loop.
- void markUnlooped() { IsUnloop = true; }
+ /// Invalidate the loop, indicating that it is no longer a loop.
+ void invalidate() { IsInvalid = true; }
- /// Return true if this no longer represents a loop.
- bool isUnloop() const { return IsUnloop; }
+ /// Return true if this loop is no longer valid.
+ bool isInvalid() { return IsInvalid; }
- /// isLoopExiting - True if terminator in the block can branch to another
- /// block that is outside of the current loop.
- ///
+ /// True if terminator in the block can branch to another block that is
+ /// outside of the current loop.
bool isLoopExiting(const BlockT *BB) const {
typedef GraphTraits<const BlockT*> BlockTraits;
for (typename BlockTraits::ChildIteratorType SI =
@@ -175,8 +166,7 @@ public:
return false;
}
- /// getNumBackEdges - Calculate the number of back edges to the loop header
- ///
+ /// Calculate the number of back edges to the loop header.
unsigned getNumBackEdges() const {
unsigned NumBackEdges = 0;
BlockT *H = getHeader();
@@ -199,53 +189,49 @@ public:
// induction variable canonicalization pass should be used to normalize loops
// for easy analysis. These methods assume canonical loops.
- /// getExitingBlocks - Return all blocks inside the loop that have successors
- /// outside of the loop. These are the blocks _inside of the current loop_
- /// which branch out. The returned list is always unique.
- ///
+ /// Return all blocks inside the loop that have successors outside of the
+ /// loop. These are the blocks _inside of the current loop_ which branch out.
+ /// The returned list is always unique.
void getExitingBlocks(SmallVectorImpl<BlockT *> &ExitingBlocks) const;
- /// getExitingBlock - If getExitingBlocks would return exactly one block,
- /// return that block. Otherwise return null.
+ /// If getExitingBlocks would return exactly one block, return that block.
+ /// Otherwise return null.
BlockT *getExitingBlock() const;
- /// getExitBlocks - Return all of the successor blocks of this loop. These
- /// are the blocks _outside of the current loop_ which are branched to.
- ///
+ /// Return all of the successor blocks of this loop. These are the blocks
+ /// _outside of the current loop_ which are branched to.
void getExitBlocks(SmallVectorImpl<BlockT*> &ExitBlocks) const;
- /// getExitBlock - If getExitBlocks would return exactly one block,
- /// return that block. Otherwise return null.
+ /// If getExitBlocks would return exactly one block, return that block.
+ /// Otherwise return null.
BlockT *getExitBlock() const;
/// Edge type.
typedef std::pair<const BlockT*, const BlockT*> Edge;
- /// getExitEdges - Return all pairs of (_inside_block_,_outside_block_).
+ /// Return all pairs of (_inside_block_,_outside_block_).
void getExitEdges(SmallVectorImpl<Edge> &ExitEdges) const;
- /// getLoopPreheader - If there is a preheader for this loop, return it. A
- /// loop has a preheader if there is only one edge to the header of the loop
- /// from outside of the loop. If this is the case, the block branching to the
- /// header of the loop is the preheader node.
+ /// If there is a preheader for this loop, return it. A loop has a preheader
+ /// if there is only one edge to the header of the loop from outside of the
+ /// loop. If this is the case, the block branching to the header of the loop
+ /// is the preheader node.
///
/// This method returns null if there is no preheader for the loop.
- ///
BlockT *getLoopPreheader() const;
- /// getLoopPredecessor - If the given loop's header has exactly one unique
- /// predecessor outside the loop, return it. Otherwise return null.
- /// This is less strict that the loop "preheader" concept, which requires
+ /// If the given loop's header has exactly one unique predecessor outside the
+ /// loop, return it. Otherwise return null.
+ /// This is less strict that the loop "preheader" concept, which requires
/// the predecessor to have exactly one successor.
- ///
BlockT *getLoopPredecessor() const;
- /// getLoopLatch - If there is a single latch block for this loop, return it.
+ /// If there is a single latch block for this loop, return it.
/// A latch block is a block that contains a branch back to the header.
BlockT *getLoopLatch() const;
- /// getLoopLatches - Return all loop latch blocks of this loop. A latch block
- /// is a block that contains a branch back to the header.
+ /// Return all loop latch blocks of this loop. A latch block is a block that
+ /// contains a branch back to the header.
void getLoopLatches(SmallVectorImpl<BlockT *> &LoopLatches) const {
BlockT *H = getHeader();
typedef GraphTraits<Inverse<BlockT*> > InvBlockTraits;
@@ -260,32 +246,29 @@ public:
// APIs for updating loop information after changing the CFG
//
- /// addBasicBlockToLoop - This method is used by other analyses to update loop
- /// information. NewBB is set to be a new member of the current loop.
+ /// This method is used by other analyses to update loop information.
+ /// NewBB is set to be a new member of the current loop.
/// Because of this, it is added as a member of all parent loops, and is added
/// to the specified LoopInfo object as being in the current basic block. It
/// is not valid to replace the loop header with this method.
- ///
void addBasicBlockToLoop(BlockT *NewBB, LoopInfoBase<BlockT, LoopT> &LI);
- /// replaceChildLoopWith - This is used when splitting loops up. It replaces
- /// the OldChild entry in our children list with NewChild, and updates the
- /// parent pointer of OldChild to be null and the NewChild to be this loop.
+ /// This is used when splitting loops up. It replaces the OldChild entry in
+ /// our children list with NewChild, and updates the parent pointer of
+ /// OldChild to be null and the NewChild to be this loop.
/// This updates the loop depth of the new child.
void replaceChildLoopWith(LoopT *OldChild, LoopT *NewChild);
- /// addChildLoop - Add the specified loop to be a child of this loop. This
- /// updates the loop depth of the new child.
- ///
+ /// Add the specified loop to be a child of this loop.
+ /// This updates the loop depth of the new child.
void addChildLoop(LoopT *NewChild) {
assert(!NewChild->ParentLoop && "NewChild already has a parent!");
NewChild->ParentLoop = static_cast<LoopT *>(this);
SubLoops.push_back(NewChild);
}
- /// removeChildLoop - This removes the specified child from being a subloop of
- /// this loop. The loop is not deleted, as it will presumably be inserted
- /// into another loop.
+ /// This removes the specified child from being a subloop of this loop. The
+ /// loop is not deleted, as it will presumably be inserted into another loop.
LoopT *removeChildLoop(iterator I) {
assert(I != SubLoops.end() && "Cannot remove end iterator!");
LoopT *Child = *I;
@@ -295,7 +278,7 @@ public:
return Child;
}
- /// addBlockEntry - This adds a basic block directly to the basic block list.
+ /// This adds a basic block directly to the basic block list.
/// This should only be used by transformations that create new loops. Other
/// transformations should use addBasicBlockToLoop.
void addBlockEntry(BlockT *BB) {
@@ -303,19 +286,18 @@ public:
DenseBlockSet.insert(BB);
}
- /// reverseBlocks - interface to reverse Blocks[from, end of loop] in this loop
+ /// interface to reverse Blocks[from, end of loop] in this loop
void reverseBlock(unsigned from) {
std::reverse(Blocks.begin() + from, Blocks.end());
}
- /// reserveBlocks- interface to do reserve() for Blocks
+ /// interface to do reserve() for Blocks
void reserveBlocks(unsigned size) {
Blocks.reserve(size);
}
- /// moveToHeader - This method is used to move BB (which must be part of this
- /// loop) to be the loop header of the loop (the block that dominates all
- /// others).
+ /// This method is used to move BB (which must be part of this loop) to be the
+ /// loop header of the loop (the block that dominates all others).
void moveToHeader(BlockT *BB) {
if (Blocks[0] == BB) return;
for (unsigned i = 0; ; ++i) {
@@ -328,9 +310,9 @@ public:
}
}
- /// removeBlockFromLoop - This removes the specified basic block from the
- /// current loop, updating the Blocks as appropriate. This does not update
- /// the mapping in the LoopInfo class.
+ /// This removes the specified basic block from the current loop, updating the
+ /// Blocks as appropriate. This does not update the mapping in the LoopInfo
+ /// class.
void removeBlockFromLoop(BlockT *BB) {
auto I = std::find(Blocks.begin(), Blocks.end(), BB);
assert(I != Blocks.end() && "N is not in this list!");
@@ -339,10 +321,10 @@ public:
DenseBlockSet.erase(BB);
}
- /// verifyLoop - Verify loop structure
+ /// Verify loop structure
void verifyLoop() const;
- /// verifyLoop - Verify loop structure of this loop and all nested loops.
+ /// Verify loop structure of this loop and all nested loops.
void verifyLoopNest(DenseSet<const LoopT*> *Loops) const;
void print(raw_ostream &OS, unsigned Depth = 0) const;
@@ -368,28 +350,26 @@ class Loop : public LoopBase<BasicBlock, Loop> {
public:
Loop() {}
- /// isLoopInvariant - Return true if the specified value is loop invariant
- ///
+ /// Return true if the specified value is loop invariant.
bool isLoopInvariant(const Value *V) const;
- /// hasLoopInvariantOperands - Return true if all the operands of the
- /// specified instruction are loop invariant.
+ /// Return true if all the operands of the specified instruction are loop
+ /// invariant.
bool hasLoopInvariantOperands(const Instruction *I) const;
- /// makeLoopInvariant - If the given value is an instruction inside of the
- /// loop and it can be hoisted, do so to make it trivially loop-invariant.
+ /// If the given value is an instruction inside of the loop and it can be
+ /// hoisted, do so to make it trivially loop-invariant.
/// Return true if the value after any hoisting is loop invariant. This
/// function can be used as a slightly more aggressive replacement for
/// isLoopInvariant.
///
/// If InsertPt is specified, it is the point to hoist instructions to.
/// If null, the terminator of the loop preheader is used.
- ///
bool makeLoopInvariant(Value *V, bool &Changed,
Instruction *InsertPt = nullptr) const;
- /// makeLoopInvariant - If the given instruction is inside of the
- /// loop and it can be hoisted, do so to make it trivially loop-invariant.
+ /// If the given instruction is inside of the loop and it can be hoisted, do
+ /// so to make it trivially loop-invariant.
/// Return true if the instruction after any hoisting is loop invariant. This
/// function can be used as a slightly more aggressive replacement for
/// isLoopInvariant.
@@ -400,28 +380,26 @@ public:
bool makeLoopInvariant(Instruction *I, bool &Changed,
Instruction *InsertPt = nullptr) const;
- /// getCanonicalInductionVariable - Check to see if the loop has a canonical
- /// induction variable: an integer recurrence that starts at 0 and increments
- /// by one each time through the loop. If so, return the phi node that
- /// corresponds to it.
+ /// Check to see if the loop has a canonical induction variable: an integer
+ /// recurrence that starts at 0 and increments by one each time through the
+ /// loop. If so, return the phi node that corresponds to it.
///
/// The IndVarSimplify pass transforms loops to have a canonical induction
/// variable.
///
PHINode *getCanonicalInductionVariable() const;
- /// isLCSSAForm - Return true if the Loop is in LCSSA form
+ /// Return true if the Loop is in LCSSA form.
bool isLCSSAForm(DominatorTree &DT) const;
- /// \brief Return true if this Loop and all inner subloops are in LCSSA form.
+ /// Return true if this Loop and all inner subloops are in LCSSA form.
bool isRecursivelyLCSSAForm(DominatorTree &DT) const;
- /// isLoopSimplifyForm - Return true if the Loop is in the form that
- /// the LoopSimplify form transforms loops to, which is sometimes called
- /// normal form.
+ /// Return true if the Loop is in the form that the LoopSimplify form
+ /// transforms loops to, which is sometimes called normal form.
bool isLoopSimplifyForm() const;
- /// isSafeToClone - Return true if the loop body is safe to clone in practice.
+ /// Return true if the loop body is safe to clone in practice.
bool isSafeToClone() const;
/// Returns true if the loop is annotated parallel.
@@ -454,23 +432,22 @@ public:
/// operand should should be the node itself.
void setLoopID(MDNode *LoopID) const;
- /// hasDedicatedExits - Return true if no exit block for the loop
- /// has a predecessor that is outside the loop.
+ /// Return true if no exit block for the loop has a predecessor that is
+ /// outside the loop.
bool hasDedicatedExits() const;
- /// getUniqueExitBlocks - Return all unique successor blocks of this loop.
+ /// Return all unique successor blocks of this loop.
/// These are the blocks _outside of the current loop_ which are branched to.
/// This assumes that loop exits are in canonical form.
- ///
void getUniqueExitBlocks(SmallVectorImpl<BasicBlock *> &ExitBlocks) const;
- /// getUniqueExitBlock - If getUniqueExitBlocks would return exactly one
- /// block, return that block. Otherwise return null.
+ /// If getUniqueExitBlocks would return exactly one block, return that block.
+ /// Otherwise return null.
BasicBlock *getUniqueExitBlock() const;
void dump() const;
- /// \brief Return the debug location of the start of this loop.
+ /// Return the debug location of the start of this loop.
/// This looks for a BB terminating instruction with a known debug
/// location by looking at the preheader and header blocks. If it
/// cannot find a terminating instruction with location information,
@@ -498,7 +475,7 @@ private:
};
//===----------------------------------------------------------------------===//
-/// LoopInfo - This class builds and contains all of the top level loop
+/// This class builds and contains all of the top-level loop
/// structures in the specified function.
///
@@ -507,6 +484,8 @@ class LoopInfoBase {
// BBMap - Mapping of basic blocks to the inner most loop they occur in
DenseMap<const BlockT *, LoopT *> BBMap;
std::vector<LoopT *> TopLevelLoops;
+ std::vector<LoopT *> RemovedLoops;
+
friend class LoopBase<BlockT, LoopT>;
friend class LoopInfo;
@@ -538,6 +517,9 @@ public:
for (auto *L : TopLevelLoops)
delete L;
TopLevelLoops.clear();
+ for (auto *L : RemovedLoops)
+ delete L;
+ RemovedLoops.clear();
}
/// iterator/begin/end - The interface to the top-level loops in the current
@@ -552,33 +534,30 @@ public:
reverse_iterator rend() const { return TopLevelLoops.rend(); }
bool empty() const { return TopLevelLoops.empty(); }
- /// getLoopFor - Return the inner most loop that BB lives in. If a basic
- /// block is in no loop (for example the entry node), null is returned.
- ///
+ /// Return the inner most loop that BB lives in. If a basic block is in no
+ /// loop (for example the entry node), null is returned.
LoopT *getLoopFor(const BlockT *BB) const { return BBMap.lookup(BB); }
- /// operator[] - same as getLoopFor...
- ///
+ /// Same as getLoopFor.
const LoopT *operator[](const BlockT *BB) const {
return getLoopFor(BB);
}
- /// getLoopDepth - Return the loop nesting level of the specified block. A
- /// depth of 0 means the block is not inside any loop.
- ///
+ /// Return the loop nesting level of the specified block. A depth of 0 means
+ /// the block is not inside any loop.
unsigned getLoopDepth(const BlockT *BB) const {
const LoopT *L = getLoopFor(BB);
return L ? L->getLoopDepth() : 0;
}
- // isLoopHeader - True if the block is a loop header node
+ // True if the block is a loop header node
bool isLoopHeader(const BlockT *BB) const {
const LoopT *L = getLoopFor(BB);
return L && L->getHeader() == BB;
}
- /// removeLoop - This removes the specified top-level loop from this loop info
- /// object. The loop is not deleted, as it will presumably be inserted into
+ /// This removes the specified top-level loop from this loop info object.
+ /// The loop is not deleted, as it will presumably be inserted into
/// another loop.
LoopT *removeLoop(iterator I) {
assert(I != end() && "Cannot remove end iterator!");
@@ -588,9 +567,9 @@ public:
return L;
}
- /// changeLoopFor - Change the top-level loop that contains BB to the
- /// specified loop. This should be used by transformations that restructure
- /// the loop hierarchy tree.
+ /// Change the top-level loop that contains BB to the specified loop.
+ /// This should be used by transformations that restructure the loop hierarchy
+ /// tree.
void changeLoopFor(BlockT *BB, LoopT *L) {
if (!L) {
BBMap.erase(BB);
@@ -599,8 +578,8 @@ public:
BBMap[BB] = L;
}
- /// changeTopLevelLoop - Replace the specified loop in the top-level loops
- /// list with the indicated loop.
+ /// Replace the specified loop in the top-level loops list with the indicated
+ /// loop.
void changeTopLevelLoop(LoopT *OldLoop,
LoopT *NewLoop) {
auto I = std::find(TopLevelLoops.begin(), TopLevelLoops.end(), OldLoop);
@@ -610,14 +589,13 @@ public:
"Loops already embedded into a subloop!");
}
- /// addTopLevelLoop - This adds the specified loop to the collection of
- /// top-level loops.
+ /// This adds the specified loop to the collection of top-level loops.
void addTopLevelLoop(LoopT *New) {
assert(!New->getParentLoop() && "Loop already in subloop!");
TopLevelLoops.push_back(New);
}
- /// removeBlock - This method completely removes BB from all data structures,
+ /// This method completely removes BB from all data structures,
/// including all of the Loop objects it is nested in and our mapping from
/// BasicBlocks to loops.
void removeBlock(BlockT *BB) {
@@ -670,15 +648,14 @@ public:
// Most of the public interface is provided via LoopInfoBase.
- /// updateUnloop - Update LoopInfo after removing the last backedge from a
- /// loop--now the "unloop". This updates the loop forest and parent loops for
- /// each block so that Unloop is no longer referenced, but does not actually
- /// delete the Unloop object. Generally, the loop pass manager should manage
- /// deleting the Unloop.
- void updateUnloop(Loop *Unloop);
+ /// Update LoopInfo after removing the last backedge from a loop. This updates
+ /// the loop forest and parent loops for each block so that \c L is no longer
+ /// referenced, but does not actually delete \c L immediately. The pointer
+ /// will remain valid until this LoopInfo's memory is released.
+ void markAsRemoved(Loop *L);
- /// replacementPreservesLCSSAForm - Returns true if replacing From with To
- /// everywhere is guaranteed to preserve LCSSA form.
+ /// Returns true if replacing From with To everywhere is guaranteed to
+ /// preserve LCSSA form.
bool replacementPreservesLCSSAForm(Instruction *From, Value *To) {
// Preserving LCSSA form is only problematic if the replacing value is an
// instruction.
@@ -698,8 +675,7 @@ public:
return ToLoop->contains(getLoopFor(From->getParent()));
}
- /// \brief Checks if moving a specific instruction can break LCSSA in any
- /// loop.
+ /// Checks if moving a specific instruction can break LCSSA in any loop.
///
/// Return true if moving \p Inst to before \p NewLoc will break LCSSA,
/// assuming that the function containing \p Inst and \p NewLoc is currently
diff --git a/include/llvm/CodeGen/AsmPrinter.h b/include/llvm/CodeGen/AsmPrinter.h
index f5e778b2f262..cf29fc9ef889 100644
--- a/include/llvm/CodeGen/AsmPrinter.h
+++ b/include/llvm/CodeGen/AsmPrinter.h
@@ -259,7 +259,7 @@ public:
void EmitAlignment(unsigned NumBits, const GlobalObject *GO = nullptr) const;
/// Lower the specified LLVM Constant to an MCExpr.
- const MCExpr *lowerConstant(const Constant *CV);
+ virtual const MCExpr *lowerConstant(const Constant *CV);
/// \brief Print a general LLVM constant to the .s file.
void EmitGlobalConstant(const DataLayout &DL, const Constant *CV);
diff --git a/include/llvm/CodeGen/DIE.h b/include/llvm/CodeGen/DIE.h
index fa612d981dec..72b3adc7de99 100644
--- a/include/llvm/CodeGen/DIE.h
+++ b/include/llvm/CodeGen/DIE.h
@@ -29,6 +29,48 @@ class MCSymbol;
class raw_ostream;
class DwarfTypeUnit;
+// AsmStreamerBase - A base abstract interface class defines methods that
+// can be implemented to stream objects or can be implemented to
+// calculate the size of the streamed objects.
+// The derived classes will use an AsmPrinter to implement the methods.
+//
+// TODO: complete this interface and use it to merge EmitValue and SizeOf
+// methods in the DIE classes below.
+class AsmStreamerBase {
+protected:
+ const AsmPrinter *AP;
+ AsmStreamerBase(const AsmPrinter *AP) : AP(AP) {}
+
+public:
+ virtual ~AsmStreamerBase() {}
+ virtual unsigned emitULEB128(uint64_t Value, const char *Desc = nullptr,
+ unsigned PadTo = 0) = 0;
+ virtual unsigned emitInt8(unsigned char Value) = 0;
+ virtual unsigned emitBytes(StringRef Data) = 0;
+};
+
+/// EmittingAsmStreamer - Implements AbstractAsmStreamer to stream objects.
+/// Notice that the return value is not the actual size of the streamed object.
+/// For size calculation use SizeReporterAsmStreamer.
+class EmittingAsmStreamer : public AsmStreamerBase {
+public:
+ EmittingAsmStreamer(const AsmPrinter *AP) : AsmStreamerBase(AP) {}
+ unsigned emitULEB128(uint64_t Value, const char *Desc = nullptr,
+ unsigned PadTo = 0) override;
+ unsigned emitInt8(unsigned char Value) override;
+ unsigned emitBytes(StringRef Data) override;
+};
+
+/// SizeReporterAsmStreamer - Only reports the size of the streamed objects.
+class SizeReporterAsmStreamer : public AsmStreamerBase {
+public:
+ SizeReporterAsmStreamer(const AsmPrinter *AP) : AsmStreamerBase(AP) {}
+ unsigned emitULEB128(uint64_t Value, const char *Desc = nullptr,
+ unsigned PadTo = 0) override;
+ unsigned emitInt8(unsigned char Value) override;
+ unsigned emitBytes(StringRef Data) override;
+};
+
//===--------------------------------------------------------------------===//
/// DIEAbbrevData - Dwarf abbreviation data, describes one attribute of a
/// Dwarf abbreviation.
diff --git a/include/llvm/CodeGen/LiveInterval.h b/include/llvm/CodeGen/LiveInterval.h
index 0157bf9117e5..edade3164a3c 100644
--- a/include/llvm/CodeGen/LiveInterval.h
+++ b/include/llvm/CodeGen/LiveInterval.h
@@ -848,9 +848,9 @@ namespace llvm {
public:
explicit ConnectedVNInfoEqClasses(LiveIntervals &lis) : LIS(lis) {}
- /// Classify - Classify the values in LI into connected components.
- /// Return the number of connected components.
- unsigned Classify(const LiveInterval *LI);
+ /// Classify the values in \p LR into connected components.
+ /// Returns the number of connected components.
+ unsigned Classify(const LiveRange &LR);
/// getEqClass - Classify creates equivalence classes numbered 0..N. Return
/// the equivalence class assigned the VNI.
diff --git a/include/llvm/CodeGen/RegisterPressure.h b/include/llvm/CodeGen/RegisterPressure.h
index 987634fb36c3..9bbdf3e071bd 100644
--- a/include/llvm/CodeGen/RegisterPressure.h
+++ b/include/llvm/CodeGen/RegisterPressure.h
@@ -141,6 +141,28 @@ public:
LLVM_DUMP_METHOD void dump(const TargetRegisterInfo &TRI) const;
};
+/// List of registers defined and used by a machine instruction.
+class RegisterOperands {
+public:
+ /// List of virtual regiserts and register units read by the instruction.
+ SmallVector<unsigned, 8> Uses;
+ /// \brief List of virtual registers and register units defined by the
+ /// instruction which are not dead.
+ SmallVector<unsigned, 8> Defs;
+ /// \brief List of virtual registers and register units defined by the
+ /// instruction but dead.
+ SmallVector<unsigned, 8> DeadDefs;
+
+ /// Analyze the given instruction \p MI and fill in the Uses, Defs and
+ /// DeadDefs list based on the MachineOperand flags.
+ void collect(const MachineInstr &MI, const TargetRegisterInfo &TRI,
+ const MachineRegisterInfo &MRI, bool IgnoreDead = false);
+
+ /// Use liveness information to find dead defs not marked with a dead flag
+ /// and move them to the DeadDefs vector.
+ void detectDeadDefs(const MachineInstr &MI, const LiveIntervals &LIS);
+};
+
/// Array of PressureDiffs.
class PressureDiffs {
PressureDiff *PDiffArray;
@@ -161,6 +183,10 @@ public:
const PressureDiff &operator[](unsigned Idx) const {
return const_cast<PressureDiffs*>(this)->operator[](Idx);
}
+ /// \brief Record pressure difference induced by the given operand list to
+ /// node with index \p Idx.
+ void addInstruction(unsigned Idx, const RegisterOperands &RegOpers,
+ const MachineRegisterInfo &MRI);
};
/// Store the effects of a change in pressure on things that MI scheduler cares
@@ -329,8 +355,17 @@ public:
void setPos(MachineBasicBlock::const_iterator Pos) { CurrPos = Pos; }
/// Recede across the previous instruction.
- void recede(SmallVectorImpl<unsigned> *LiveUses = nullptr,
- PressureDiff *PDiff = nullptr);
+ void recede(SmallVectorImpl<unsigned> *LiveUses = nullptr);
+
+ /// Recede across the previous instruction.
+ /// This "low-level" variant assumes that recedeSkipDebugValues() was
+ /// called previously and takes precomputed RegisterOperands for the
+ /// instruction.
+ void recede(const RegisterOperands &RegOpers,
+ SmallVectorImpl<unsigned> *LiveUses = nullptr);
+
+ /// Recede until we find an instruction which is not a DebugValue.
+ void recedeSkipDebugValues();
/// Advance across the current instruction.
void advance();
diff --git a/include/llvm/CodeGen/WinEHFuncInfo.h b/include/llvm/CodeGen/WinEHFuncInfo.h
index f6ad7a8572ab..46c1029f62cf 100644
--- a/include/llvm/CodeGen/WinEHFuncInfo.h
+++ b/include/llvm/CodeGen/WinEHFuncInfo.h
@@ -93,8 +93,6 @@ struct WinEHFuncInfo {
DenseMap<const Instruction *, int> EHPadStateMap;
DenseMap<const FuncletPadInst *, int> FuncletBaseStateMap;
DenseMap<const InvokeInst *, int> InvokeStateMap;
- DenseMap<const CatchReturnInst *, const BasicBlock *>
- CatchRetSuccessorColorMap;
DenseMap<MCSymbol *, std::pair<int, MCSymbol *>> LabelToStateMap;
SmallVector<CxxUnwindMapEntry, 4> CxxUnwindMap;
SmallVector<WinEHTryBlockMapEntry, 4> TryBlockMap;
@@ -125,8 +123,5 @@ void calculateSEHStateNumbers(const Function *ParentFn,
WinEHFuncInfo &FuncInfo);
void calculateClrEHStateNumbers(const Function *Fn, WinEHFuncInfo &FuncInfo);
-
-void calculateCatchReturnSuccessorColors(const Function *Fn,
- WinEHFuncInfo &FuncInfo);
}
#endif // LLVM_CODEGEN_WINEHFUNCINFO_H
diff --git a/include/llvm/DebugInfo/Symbolize/DIPrinter.h b/include/llvm/DebugInfo/Symbolize/DIPrinter.h
index 0703fb14da61..3098199bb4da 100644
--- a/include/llvm/DebugInfo/Symbolize/DIPrinter.h
+++ b/include/llvm/DebugInfo/Symbolize/DIPrinter.h
@@ -28,13 +28,16 @@ class DIPrinter {
raw_ostream &OS;
bool PrintFunctionNames;
bool PrintPretty;
- void printName(const DILineInfo &Info, bool Inlined);
+ int PrintSourceContext;
+
+ void print(const DILineInfo &Info, bool Inlined);
+ void printContext(std::string FileName, int64_t Line);
public:
DIPrinter(raw_ostream &OS, bool PrintFunctionNames = true,
- bool PrintPretty = false)
+ bool PrintPretty = false, int PrintSourceContext = 0)
: OS(OS), PrintFunctionNames(PrintFunctionNames),
- PrintPretty(PrintPretty) {}
+ PrintPretty(PrintPretty), PrintSourceContext(PrintSourceContext) {}
DIPrinter &operator<<(const DILineInfo &Info);
DIPrinter &operator<<(const DIInliningInfo &Info);
diff --git a/include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h b/include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h
index 7dab5d1bc67f..84af4728b350 100644
--- a/include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h
+++ b/include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h
@@ -19,7 +19,6 @@
#include "LambdaResolver.h"
#include "LogicalDylib.h"
#include "llvm/ADT/STLExtras.h"
-#include "llvm/ExecutionEngine/SectionMemoryManager.h"
#include "llvm/Transforms/Utils/Cloning.h"
#include <list>
#include <memory>
@@ -61,31 +60,36 @@ private:
typedef typename BaseLayerT::ModuleSetHandleT BaseLayerModuleSetHandleT;
- class ModuleOwner {
+ // Provide type-erasure for the Modules and MemoryManagers.
+ template <typename ResourceT>
+ class ResourceOwner {
public:
- ModuleOwner() = default;
- ModuleOwner(const ModuleOwner&) = delete;
- ModuleOwner& operator=(const ModuleOwner&) = delete;
- virtual ~ModuleOwner() { }
- virtual Module& getModule() const = 0;
+ ResourceOwner() = default;
+ ResourceOwner(const ResourceOwner&) = delete;
+ ResourceOwner& operator=(const ResourceOwner&) = delete;
+ virtual ~ResourceOwner() { }
+ virtual ResourceT& getResource() const = 0;
};
- template <typename ModulePtrT>
- class ModuleOwnerImpl : public ModuleOwner {
+ template <typename ResourceT, typename ResourcePtrT>
+ class ResourceOwnerImpl : public ResourceOwner<ResourceT> {
public:
- ModuleOwnerImpl(ModulePtrT ModulePtr) : ModulePtr(std::move(ModulePtr)) {}
- Module& getModule() const override { return *ModulePtr; }
+ ResourceOwnerImpl(ResourcePtrT ResourcePtr)
+ : ResourcePtr(std::move(ResourcePtr)) {}
+ ResourceT& getResource() const override { return *ResourcePtr; }
private:
- ModulePtrT ModulePtr;
+ ResourcePtrT ResourcePtr;
};
- template <typename ModulePtrT>
- std::unique_ptr<ModuleOwner> wrapOwnership(ModulePtrT ModulePtr) {
- return llvm::make_unique<ModuleOwnerImpl<ModulePtrT>>(std::move(ModulePtr));
+ template <typename ResourceT, typename ResourcePtrT>
+ std::unique_ptr<ResourceOwner<ResourceT>>
+ wrapOwnership(ResourcePtrT ResourcePtr) {
+ typedef ResourceOwnerImpl<ResourceT, ResourcePtrT> RO;
+ return llvm::make_unique<RO>(std::move(ResourcePtr));
}
struct LogicalModuleResources {
- std::unique_ptr<ModuleOwner> SourceModuleOwner;
+ std::unique_ptr<ResourceOwner<Module>> SourceModule;
std::set<const Function*> StubsToClone;
std::unique_ptr<IndirectStubsMgrT> StubsMgr;
@@ -93,15 +97,16 @@ private:
// Explicit move constructor to make MSVC happy.
LogicalModuleResources(LogicalModuleResources &&Other)
- : SourceModuleOwner(std::move(Other.SourceModuleOwner)),
+ : SourceModule(std::move(Other.SourceModule)),
StubsToClone(std::move(Other.StubsToClone)),
StubsMgr(std::move(Other.StubsMgr)) {}
// Explicit move assignment to make MSVC happy.
LogicalModuleResources& operator=(LogicalModuleResources &&Other) {
- SourceModuleOwner = std::move(Other.SourceModuleOwner);
+ SourceModule = std::move(Other.SourceModule);
StubsToClone = std::move(Other.StubsToClone);
StubsMgr = std::move(Other.StubsMgr);
+ return *this;
}
JITSymbol findSymbol(StringRef Name, bool ExportedSymbolsOnly) {
@@ -114,12 +119,35 @@ private:
};
-
-
struct LogicalDylibResources {
typedef std::function<RuntimeDyld::SymbolInfo(const std::string&)>
SymbolResolverFtor;
+
+ typedef std::function<typename BaseLayerT::ModuleSetHandleT(
+ BaseLayerT&,
+ std::unique_ptr<Module>,
+ std::unique_ptr<RuntimeDyld::SymbolResolver>)>
+ ModuleAdderFtor;
+
+ LogicalDylibResources() = default;
+
+ // Explicit move constructor to make MSVC happy.
+ LogicalDylibResources(LogicalDylibResources &&Other)
+ : ExternalSymbolResolver(std::move(Other.ExternalSymbolResolver)),
+ MemMgr(std::move(Other.MemMgr)),
+ ModuleAdder(std::move(Other.ModuleAdder)) {}
+
+ // Explicit move assignment operator to make MSVC happy.
+ LogicalDylibResources& operator=(LogicalDylibResources &&Other) {
+ ExternalSymbolResolver = std::move(Other.ExternalSymbolResolver);
+ MemMgr = std::move(Other.MemMgr);
+ ModuleAdder = std::move(Other.ModuleAdder);
+ return *this;
+ }
+
SymbolResolverFtor ExternalSymbolResolver;
+ std::unique_ptr<ResourceOwner<RuntimeDyld::MemoryManager>> MemMgr;
+ ModuleAdderFtor ModuleAdder;
};
typedef LogicalDylib<BaseLayerT, LogicalModuleResources,
@@ -157,9 +185,6 @@ public:
MemoryManagerPtrT MemMgr,
SymbolResolverPtrT Resolver) {
- assert(MemMgr == nullptr &&
- "User supplied memory managers not supported with COD yet.");
-
LogicalDylibs.push_back(CODLogicalDylib(BaseLayer));
auto &LDResources = LogicalDylibs.back().getDylibResources();
@@ -168,6 +193,18 @@ public:
return Resolver->findSymbol(Name);
};
+ auto &MemMgrRef = *MemMgr;
+ LDResources.MemMgr =
+ wrapOwnership<RuntimeDyld::MemoryManager>(std::move(MemMgr));
+
+ LDResources.ModuleAdder =
+ [&MemMgrRef](BaseLayerT &B, std::unique_ptr<Module> M,
+ std::unique_ptr<RuntimeDyld::SymbolResolver> R) {
+ std::vector<std::unique_ptr<Module>> Ms;
+ Ms.push_back(std::move(M));
+ return B.addModuleSet(std::move(Ms), &MemMgrRef, std::move(R));
+ };
+
// Process each of the modules in this module set.
for (auto &M : Ms)
addLogicalModule(LogicalDylibs.back(), std::move(M));
@@ -215,9 +252,9 @@ private:
auto LMH = LD.createLogicalModule();
auto &LMResources = LD.getLogicalModuleResources(LMH);
- LMResources.SourceModuleOwner = wrapOwnership(std::move(SrcMPtr));
+ LMResources.SourceModule = wrapOwnership<Module>(std::move(SrcMPtr));
- Module &SrcM = LMResources.SourceModuleOwner->getModule();
+ Module &SrcM = LMResources.SourceModule->getResource();
// Create the GlobalValues module.
const DataLayout &DL = SrcM.getDataLayout();
@@ -326,12 +363,9 @@ private:
return RuntimeDyld::SymbolInfo(nullptr);
});
- std::vector<std::unique_ptr<Module>> GVsMSet;
- GVsMSet.push_back(std::move(GVsM));
auto GVsH =
- BaseLayer.addModuleSet(std::move(GVsMSet),
- llvm::make_unique<SectionMemoryManager>(),
- std::move(GVsResolver));
+ LD.getDylibResources().ModuleAdder(BaseLayer, std::move(GVsM),
+ std::move(GVsResolver));
LD.addToLogicalModule(LMH, GVsH);
}
@@ -348,7 +382,7 @@ private:
LogicalModuleHandle LMH,
Function &F) {
auto &LMResources = LD.getLogicalModuleResources(LMH);
- Module &SrcM = LMResources.SourceModuleOwner->getModule();
+ Module &SrcM = LMResources.SourceModule->getResource();
// If F is a declaration we must already have compiled it.
if (F.isDeclaration())
@@ -386,7 +420,7 @@ private:
LogicalModuleHandle LMH,
const PartitionT &Part) {
auto &LMResources = LD.getLogicalModuleResources(LMH);
- Module &SrcM = LMResources.SourceModuleOwner->getModule();
+ Module &SrcM = LMResources.SourceModule->getResource();
// Create the module.
std::string NewName = SrcM.getName();
@@ -445,7 +479,6 @@ private:
moveFunctionBody(*F, VMap, &Materializer);
// Create memory manager and symbol resolver.
- auto MemMgr = llvm::make_unique<SectionMemoryManager>();
auto Resolver = createLambdaResolver(
[this, &LD, LMH](const std::string &Name) {
if (auto Symbol = LD.findSymbolInternally(LMH, Name))
@@ -459,10 +492,9 @@ private:
Symbol.getFlags());
return RuntimeDyld::SymbolInfo(nullptr);
});
- std::vector<std::unique_ptr<Module>> PartMSet;
- PartMSet.push_back(std::move(M));
- return BaseLayer.addModuleSet(std::move(PartMSet), std::move(MemMgr),
- std::move(Resolver));
+
+ return LD.getDylibResources().ModuleAdder(BaseLayer, std::move(M),
+ std::move(Resolver));
}
BaseLayerT &BaseLayer;
diff --git a/include/llvm/ExecutionEngine/Orc/IndirectionUtils.h b/include/llvm/ExecutionEngine/Orc/IndirectionUtils.h
index d6ee3a846b04..e17630fa05ff 100644
--- a/include/llvm/ExecutionEngine/Orc/IndirectionUtils.h
+++ b/include/llvm/ExecutionEngine/Orc/IndirectionUtils.h
@@ -22,6 +22,7 @@
#include "llvm/IR/Mangler.h"
#include "llvm/IR/Module.h"
#include "llvm/Transforms/Utils/ValueMapper.h"
+#include "llvm/Support/Process.h"
#include <sstream>
namespace llvm {
@@ -179,14 +180,15 @@ private:
std::error_code EC;
auto TrampolineBlock =
sys::OwningMemoryBlock(
- sys::Memory::allocateMappedMemory(TargetT::PageSize, nullptr,
+ sys::Memory::allocateMappedMemory(sys::Process::getPageSize(), nullptr,
sys::Memory::MF_READ |
sys::Memory::MF_WRITE, EC));
assert(!EC && "Failed to allocate trampoline block");
unsigned NumTrampolines =
- (TargetT::PageSize - TargetT::PointerSize) / TargetT::TrampolineSize;
+ (sys::Process::getPageSize() - TargetT::PointerSize) /
+ TargetT::TrampolineSize;
uint8_t *TrampolineMem = static_cast<uint8_t*>(TrampolineBlock.base());
TargetT::writeTrampolines(TrampolineMem, ResolverBlock.base(),
@@ -240,8 +242,8 @@ private:
virtual void anchor();
};
-/// @brief IndirectStubsManager implementation for a concrete target, e.g.
-/// OrcX86_64. (See OrcTargetSupport.h).
+/// @brief IndirectStubsManager implementation for the host architecture, e.g.
+/// OrcX86_64. (See OrcArchitectureSupport.h).
template <typename TargetT>
class LocalIndirectStubsManager : public IndirectStubsManager {
public:
diff --git a/include/llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h b/include/llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h
index 2acfecfb94dc..4dc48f114883 100644
--- a/include/llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h
+++ b/include/llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h
@@ -108,9 +108,7 @@ private:
void Finalize() override {
State = Finalizing;
- RTDyld->resolveRelocations();
- RTDyld->registerEHFrames();
- MemMgr->finalizeMemory();
+ RTDyld->finalizeWithMemoryManagerLocking();
State = Finalized;
}
diff --git a/include/llvm/ExecutionEngine/Orc/OrcTargetSupport.h b/include/llvm/ExecutionEngine/Orc/OrcArchitectureSupport.h
index 246d3e0a9fc6..1b0488bcf00d 100644
--- a/include/llvm/ExecutionEngine/Orc/OrcTargetSupport.h
+++ b/include/llvm/ExecutionEngine/Orc/OrcArchitectureSupport.h
@@ -1,4 +1,4 @@
-//===-- OrcTargetSupport.h - Code to support specific targets --*- C++ -*-===//
+//===-- OrcArchitectureSupport.h - Architecture support code ---*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -7,32 +7,76 @@
//
//===----------------------------------------------------------------------===//
//
-// Target specific code for Orc, e.g. callback assembly.
+// Architecture specific code for Orc, e.g. callback assembly.
//
-// Target classes should be part of the JIT *target* process, not the host
+// Architecture classes should be part of the JIT *target* process, not the host
// process (except where you're doing hosted JITing and the two are one and the
// same).
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_EXECUTIONENGINE_ORC_ORCTARGETSUPPORT_H
-#define LLVM_EXECUTIONENGINE_ORC_ORCTARGETSUPPORT_H
+#ifndef LLVM_EXECUTIONENGINE_ORC_ORCARCHITECTURESUPPORT_H
+#define LLVM_EXECUTIONENGINE_ORC_ORCARCHITECTURESUPPORT_H
#include "IndirectionUtils.h"
#include "llvm/Support/Memory.h"
+#include "llvm/Support/Process.h"
namespace llvm {
namespace orc {
+/// Generic ORC Architecture support.
+///
+/// This class can be substituted as the target architecure support class for
+/// ORC templates that require one (e.g. IndirectStubsManagers). It does not
+/// support lazy JITing however, and any attempt to use that functionality
+/// will result in execution of an llvm_unreachable.
+class OrcGenericArchitecture {
+public:
+ static const unsigned PointerSize = sizeof(uintptr_t);
+ static const unsigned TrampolineSize = 1;
+ static const unsigned ResolverCodeSize = 1;
+
+ typedef TargetAddress (*JITReentryFn)(void *CallbackMgr, void *TrampolineId);
+
+ static void writeResolverCode(uint8_t *ResolveMem, JITReentryFn Reentry,
+ void *CallbackMgr) {
+ llvm_unreachable("writeResolverCode is not supported by the generic host "
+ "support class");
+ }
+
+ static void writeTrampolines(uint8_t *TrampolineMem, void *ResolverAddr,
+ unsigned NumTrampolines) {
+ llvm_unreachable("writeTrampolines is not supported by the generic host "
+ "support class");
+ }
+
+ class IndirectStubsInfo {
+ public:
+ const static unsigned StubSize = 1;
+ unsigned getNumStubs() const { llvm_unreachable("Not supported"); }
+ void *getStub(unsigned Idx) const { llvm_unreachable("Not supported"); }
+ void **getPtr(unsigned Idx) const { llvm_unreachable("Not supported"); }
+ };
+
+ static std::error_code emitIndirectStubsBlock(IndirectStubsInfo &StubsInfo,
+ unsigned MinStubs,
+ void *InitialPtrVal) {
+ llvm_unreachable("emitIndirectStubsBlock is not supported by the generic "
+ "host support class");
+ }
+};
+
+/// @brief X86_64 support.
+///
+/// X86_64 supports lazy JITing.
class OrcX86_64 {
public:
- static const unsigned PageSize = 4096;
static const unsigned PointerSize = 8;
static const unsigned TrampolineSize = 8;
static const unsigned ResolverCodeSize = 0x78;
- typedef TargetAddress (*JITReentryFn)(void *CallbackMgr,
- void *TrampolineId);
+ typedef TargetAddress (*JITReentryFn)(void *CallbackMgr, void *TrampolineId);
/// @brief Write the resolver code into the given memory. The user is be
/// responsible for allocating the memory and setting permissions.
@@ -49,16 +93,16 @@ public:
/// makeIndirectStubsBlock function.
class IndirectStubsInfo {
friend class OrcX86_64;
+
public:
const static unsigned StubSize = 8;
- const static unsigned PtrSize = 8;
IndirectStubsInfo() : NumStubs(0) {}
IndirectStubsInfo(IndirectStubsInfo &&Other)
: NumStubs(Other.NumStubs), StubsMem(std::move(Other.StubsMem)) {
Other.NumStubs = 0;
}
- IndirectStubsInfo& operator=(IndirectStubsInfo &&Other) {
+ IndirectStubsInfo &operator=(IndirectStubsInfo &&Other) {
NumStubs = Other.NumStubs;
Other.NumStubs = 0;
StubsMem = std::move(Other.StubsMem);
@@ -70,17 +114,18 @@ public:
/// @brief Get a pointer to the stub at the given index, which must be in
/// the range 0 .. getNumStubs() - 1.
- void* getStub(unsigned Idx) const {
- return static_cast<uint64_t*>(StubsMem.base()) + Idx;
+ void *getStub(unsigned Idx) const {
+ return static_cast<uint64_t *>(StubsMem.base()) + Idx;
}
/// @brief Get a pointer to the implementation-pointer at the given index,
/// which must be in the range 0 .. getNumStubs() - 1.
- void** getPtr(unsigned Idx) const {
+ void **getPtr(unsigned Idx) const {
char *PtrsBase =
- static_cast<char*>(StubsMem.base()) + NumStubs * StubSize;
- return reinterpret_cast<void**>(PtrsBase) + Idx;
+ static_cast<char *>(StubsMem.base()) + NumStubs * StubSize;
+ return reinterpret_cast<void **>(PtrsBase) + Idx;
}
+
private:
unsigned NumStubs;
sys::OwningMemoryBlock StubsMem;
@@ -100,4 +145,4 @@ public:
} // End namespace orc.
} // End namespace llvm.
-#endif // LLVM_EXECUTIONENGINE_ORC_ORCTARGETSUPPORT_H
+#endif // LLVM_EXECUTIONENGINE_ORC_ORCARCHITECTURESUPPORT_H
diff --git a/include/llvm/ExecutionEngine/Orc/OrcError.h b/include/llvm/ExecutionEngine/Orc/OrcError.h
new file mode 100644
index 000000000000..48f35d6b39be
--- /dev/null
+++ b/include/llvm/ExecutionEngine/Orc/OrcError.h
@@ -0,0 +1,37 @@
+//===------ OrcError.h - Reject symbol lookup requests ------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Define an error category, error codes, and helper utilities for Orc.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_EXECUTIONENGINE_ORC_ORCERROR_H
+#define LLVM_EXECUTIONENGINE_ORC_ORCERROR_H
+
+#include <system_error>
+
+namespace llvm {
+namespace orc {
+
+enum class OrcErrorCode : int {
+ // RPC Errors
+ RemoteAllocatorDoesNotExist = 1,
+ RemoteAllocatorIdAlreadyInUse,
+ RemoteMProtectAddrUnrecognized,
+ RemoteIndirectStubsOwnerDoesNotExist,
+ RemoteIndirectStubsOwnerIdAlreadyInUse,
+ UnexpectedRPCCall
+};
+
+std::error_code orcError(OrcErrorCode ErrCode);
+
+} // End namespace orc.
+} // End namespace llvm.
+
+#endif // LLVM_EXECUTIONENGINE_ORC_ORCERROR_H
diff --git a/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetClient.h b/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetClient.h
new file mode 100644
index 000000000000..d7640b8e8b5f
--- /dev/null
+++ b/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetClient.h
@@ -0,0 +1,784 @@
+//===---- OrcRemoteTargetClient.h - Orc Remote-target Client ----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the OrcRemoteTargetClient class and helpers. This class
+// can be used to communicate over an RPCChannel with an OrcRemoteTargetServer
+// instance to support remote-JITing.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_EXECUTIONENGINE_ORC_ORCREMOTETARGETCLIENT_H
+#define LLVM_EXECUTIONENGINE_ORC_ORCREMOTETARGETCLIENT_H
+
+#include "IndirectionUtils.h"
+#include "OrcRemoteTargetRPCAPI.h"
+#include <system_error>
+
+#define DEBUG_TYPE "orc-remote"
+
+namespace llvm {
+namespace orc {
+namespace remote {
+
+/// This class provides utilities (including memory manager, indirect stubs
+/// manager, and compile callback manager types) that support remote JITing
+/// in ORC.
+///
+/// Each of the utility classes talks to a JIT server (an instance of the
+/// OrcRemoteTargetServer class) via an RPC system (see RPCUtils.h) to carry out
+/// its actions.
+template <typename ChannelT>
+class OrcRemoteTargetClient : public OrcRemoteTargetRPCAPI {
+public:
+ /// Remote memory manager.
+ class RCMemoryManager : public RuntimeDyld::MemoryManager {
+ public:
+ RCMemoryManager(OrcRemoteTargetClient &Client, ResourceIdMgr::ResourceId Id)
+ : Client(Client), Id(Id) {
+ DEBUG(dbgs() << "Created remote allocator " << Id << "\n");
+ }
+
+ RCMemoryManager(RCMemoryManager &&Other)
+ : Client(std::move(Other.Client)), Id(std::move(Other.Id)),
+ Unmapped(std::move(Other.Unmapped)),
+ Unfinalized(std::move(Other.Unfinalized)) {}
+
+ RCMemoryManager operator=(RCMemoryManager &&Other) {
+ Client = std::move(Other.Client);
+ Id = std::move(Other.Id);
+ Unmapped = std::move(Other.Unmapped);
+ Unfinalized = std::move(Other.Unfinalized);
+ return *this;
+ }
+
+ ~RCMemoryManager() {
+ Client.destroyRemoteAllocator(Id);
+ DEBUG(dbgs() << "Destroyed remote allocator " << Id << "\n");
+ }
+
+ uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment,
+ unsigned SectionID,
+ StringRef SectionName) override {
+ Unmapped.back().CodeAllocs.emplace_back(Size, Alignment);
+ uint8_t *Alloc = reinterpret_cast<uint8_t *>(
+ Unmapped.back().CodeAllocs.back().getLocalAddress());
+ DEBUG(dbgs() << "Allocator " << Id << " allocated code for "
+ << SectionName << ": " << Alloc << " (" << Size
+ << " bytes, alignment " << Alignment << ")\n");
+ return Alloc;
+ }
+
+ uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
+ unsigned SectionID, StringRef SectionName,
+ bool IsReadOnly) override {
+ if (IsReadOnly) {
+ Unmapped.back().RODataAllocs.emplace_back(Size, Alignment);
+ uint8_t *Alloc = reinterpret_cast<uint8_t *>(
+ Unmapped.back().RODataAllocs.back().getLocalAddress());
+ DEBUG(dbgs() << "Allocator " << Id << " allocated ro-data for "
+ << SectionName << ": " << Alloc << " (" << Size
+ << " bytes, alignment " << Alignment << ")\n");
+ return Alloc;
+ } // else...
+
+ Unmapped.back().RWDataAllocs.emplace_back(Size, Alignment);
+ uint8_t *Alloc = reinterpret_cast<uint8_t *>(
+ Unmapped.back().RWDataAllocs.back().getLocalAddress());
+ DEBUG(dbgs() << "Allocator " << Id << " allocated rw-data for "
+ << SectionName << ": " << Alloc << " (" << Size
+ << " bytes, alignment " << Alignment << ")\n");
+ return Alloc;
+ }
+
+ void reserveAllocationSpace(uintptr_t CodeSize, uint32_t CodeAlign,
+ uintptr_t RODataSize, uint32_t RODataAlign,
+ uintptr_t RWDataSize,
+ uint32_t RWDataAlign) override {
+ Unmapped.push_back(ObjectAllocs());
+
+ DEBUG(dbgs() << "Allocator " << Id << " reserved:\n");
+
+ if (CodeSize != 0) {
+ std::error_code EC = Client.reserveMem(Unmapped.back().RemoteCodeAddr,
+ Id, CodeSize, CodeAlign);
+ // FIXME; Add error to poll.
+ assert(!EC && "Failed reserving remote memory.");
+ (void)EC;
+ DEBUG(dbgs() << " code: "
+ << format("0x%016x", Unmapped.back().RemoteCodeAddr)
+ << " (" << CodeSize << " bytes, alignment " << CodeAlign
+ << ")\n");
+ }
+
+ if (RODataSize != 0) {
+ std::error_code EC = Client.reserveMem(Unmapped.back().RemoteRODataAddr,
+ Id, RODataSize, RODataAlign);
+ // FIXME; Add error to poll.
+ assert(!EC && "Failed reserving remote memory.");
+ (void)EC;
+ DEBUG(dbgs() << " ro-data: "
+ << format("0x%016x", Unmapped.back().RemoteRODataAddr)
+ << " (" << RODataSize << " bytes, alignment "
+ << RODataAlign << ")\n");
+ }
+
+ if (RWDataSize != 0) {
+ std::error_code EC = Client.reserveMem(Unmapped.back().RemoteRWDataAddr,
+ Id, RWDataSize, RWDataAlign);
+ // FIXME; Add error to poll.
+ assert(!EC && "Failed reserving remote memory.");
+ (void)EC;
+ DEBUG(dbgs() << " rw-data: "
+ << format("0x%016x", Unmapped.back().RemoteRWDataAddr)
+ << " (" << RWDataSize << " bytes, alignment "
+ << RWDataAlign << ")\n");
+ }
+ }
+
+ bool needsToReserveAllocationSpace() override { return true; }
+
+ void registerEHFrames(uint8_t *Addr, uint64_t LoadAddr,
+ size_t Size) override {}
+
+ void deregisterEHFrames(uint8_t *addr, uint64_t LoadAddr,
+ size_t Size) override {}
+
+ void notifyObjectLoaded(RuntimeDyld &Dyld,
+ const object::ObjectFile &Obj) override {
+ DEBUG(dbgs() << "Allocator " << Id << " applied mappings:\n");
+ for (auto &ObjAllocs : Unmapped) {
+ {
+ TargetAddress NextCodeAddr = ObjAllocs.RemoteCodeAddr;
+ for (auto &Alloc : ObjAllocs.CodeAllocs) {
+ NextCodeAddr = RoundUpToAlignment(NextCodeAddr, Alloc.getAlign());
+ Dyld.mapSectionAddress(Alloc.getLocalAddress(), NextCodeAddr);
+ DEBUG(dbgs() << " code: "
+ << static_cast<void *>(Alloc.getLocalAddress())
+ << " -> " << format("0x%016x", NextCodeAddr) << "\n");
+ Alloc.setRemoteAddress(NextCodeAddr);
+ NextCodeAddr += Alloc.getSize();
+ }
+ }
+ {
+ TargetAddress NextRODataAddr = ObjAllocs.RemoteRODataAddr;
+ for (auto &Alloc : ObjAllocs.RODataAllocs) {
+ NextRODataAddr =
+ RoundUpToAlignment(NextRODataAddr, Alloc.getAlign());
+ Dyld.mapSectionAddress(Alloc.getLocalAddress(), NextRODataAddr);
+ DEBUG(dbgs() << " ro-data: "
+ << static_cast<void *>(Alloc.getLocalAddress())
+ << " -> " << format("0x%016x", NextRODataAddr)
+ << "\n");
+ Alloc.setRemoteAddress(NextRODataAddr);
+ NextRODataAddr += Alloc.getSize();
+ }
+ }
+ {
+ TargetAddress NextRWDataAddr = ObjAllocs.RemoteRWDataAddr;
+ for (auto &Alloc : ObjAllocs.RWDataAllocs) {
+ NextRWDataAddr =
+ RoundUpToAlignment(NextRWDataAddr, Alloc.getAlign());
+ Dyld.mapSectionAddress(Alloc.getLocalAddress(), NextRWDataAddr);
+ DEBUG(dbgs() << " rw-data: "
+ << static_cast<void *>(Alloc.getLocalAddress())
+ << " -> " << format("0x%016x", NextRWDataAddr)
+ << "\n");
+ Alloc.setRemoteAddress(NextRWDataAddr);
+ NextRWDataAddr += Alloc.getSize();
+ }
+ }
+ Unfinalized.push_back(std::move(ObjAllocs));
+ }
+ Unmapped.clear();
+ }
+
+ bool finalizeMemory(std::string *ErrMsg = nullptr) override {
+ DEBUG(dbgs() << "Allocator " << Id << " finalizing:\n");
+
+ for (auto &ObjAllocs : Unfinalized) {
+
+ for (auto &Alloc : ObjAllocs.CodeAllocs) {
+ DEBUG(dbgs() << " copying code: "
+ << static_cast<void *>(Alloc.getLocalAddress()) << " -> "
+ << format("0x%016x", Alloc.getRemoteAddress()) << " ("
+ << Alloc.getSize() << " bytes)\n");
+ Client.writeMem(Alloc.getRemoteAddress(), Alloc.getLocalAddress(),
+ Alloc.getSize());
+ }
+
+ if (ObjAllocs.RemoteCodeAddr) {
+ DEBUG(dbgs() << " setting R-X permissions on code block: "
+ << format("0x%016x", ObjAllocs.RemoteCodeAddr) << "\n");
+ Client.setProtections(Id, ObjAllocs.RemoteCodeAddr,
+ sys::Memory::MF_READ | sys::Memory::MF_EXEC);
+ }
+
+ for (auto &Alloc : ObjAllocs.RODataAllocs) {
+ DEBUG(dbgs() << " copying ro-data: "
+ << static_cast<void *>(Alloc.getLocalAddress()) << " -> "
+ << format("0x%016x", Alloc.getRemoteAddress()) << " ("
+ << Alloc.getSize() << " bytes)\n");
+ Client.writeMem(Alloc.getRemoteAddress(), Alloc.getLocalAddress(),
+ Alloc.getSize());
+ }
+
+ if (ObjAllocs.RemoteRODataAddr) {
+ DEBUG(dbgs() << " setting R-- permissions on ro-data block: "
+ << format("0x%016x", ObjAllocs.RemoteRODataAddr)
+ << "\n");
+ Client.setProtections(Id, ObjAllocs.RemoteRODataAddr,
+ sys::Memory::MF_READ);
+ }
+
+ for (auto &Alloc : ObjAllocs.RWDataAllocs) {
+ DEBUG(dbgs() << " copying rw-data: "
+ << static_cast<void *>(Alloc.getLocalAddress()) << " -> "
+ << format("0x%016x", Alloc.getRemoteAddress()) << " ("
+ << Alloc.getSize() << " bytes)\n");
+ Client.writeMem(Alloc.getRemoteAddress(), Alloc.getLocalAddress(),
+ Alloc.getSize());
+ }
+
+ if (ObjAllocs.RemoteRWDataAddr) {
+ DEBUG(dbgs() << " setting RW- permissions on rw-data block: "
+ << format("0x%016x", ObjAllocs.RemoteRWDataAddr)
+ << "\n");
+ Client.setProtections(Id, ObjAllocs.RemoteRWDataAddr,
+ sys::Memory::MF_READ | sys::Memory::MF_WRITE);
+ }
+ }
+ Unfinalized.clear();
+
+ return false;
+ }
+
+ private:
+ class Alloc {
+ public:
+ Alloc(uint64_t Size, unsigned Align)
+ : Size(Size), Align(Align), Contents(new char[Size + Align - 1]),
+ RemoteAddr(0) {}
+
+ Alloc(Alloc &&Other)
+ : Size(std::move(Other.Size)), Align(std::move(Other.Align)),
+ Contents(std::move(Other.Contents)),
+ RemoteAddr(std::move(Other.RemoteAddr)) {}
+
+ Alloc &operator=(Alloc &&Other) {
+ Size = std::move(Other.Size);
+ Align = std::move(Other.Align);
+ Contents = std::move(Other.Contents);
+ RemoteAddr = std::move(Other.RemoteAddr);
+ return *this;
+ }
+
+ uint64_t getSize() const { return Size; }
+
+ unsigned getAlign() const { return Align; }
+
+ char *getLocalAddress() const {
+ uintptr_t LocalAddr = reinterpret_cast<uintptr_t>(Contents.get());
+ LocalAddr = RoundUpToAlignment(LocalAddr, Align);
+ return reinterpret_cast<char *>(LocalAddr);
+ }
+
+ void setRemoteAddress(TargetAddress RemoteAddr) {
+ this->RemoteAddr = RemoteAddr;
+ }
+
+ TargetAddress getRemoteAddress() const { return RemoteAddr; }
+
+ private:
+ uint64_t Size;
+ unsigned Align;
+ std::unique_ptr<char[]> Contents;
+ TargetAddress RemoteAddr;
+ };
+
+ struct ObjectAllocs {
+ ObjectAllocs()
+ : RemoteCodeAddr(0), RemoteRODataAddr(0), RemoteRWDataAddr(0) {}
+
+ ObjectAllocs(ObjectAllocs &&Other)
+ : RemoteCodeAddr(std::move(Other.RemoteCodeAddr)),
+ RemoteRODataAddr(std::move(Other.RemoteRODataAddr)),
+ RemoteRWDataAddr(std::move(Other.RemoteRWDataAddr)),
+ CodeAllocs(std::move(Other.CodeAllocs)),
+ RODataAllocs(std::move(Other.RODataAllocs)),
+ RWDataAllocs(std::move(Other.RWDataAllocs)) {}
+
+ ObjectAllocs &operator=(ObjectAllocs &&Other) {
+ RemoteCodeAddr = std::move(Other.RemoteCodeAddr);
+ RemoteRODataAddr = std::move(Other.RemoteRODataAddr);
+ RemoteRWDataAddr = std::move(Other.RemoteRWDataAddr);
+ CodeAllocs = std::move(Other.CodeAllocs);
+ RODataAllocs = std::move(Other.RODataAllocs);
+ RWDataAllocs = std::move(Other.RWDataAllocs);
+ return *this;
+ }
+
+ TargetAddress RemoteCodeAddr;
+ TargetAddress RemoteRODataAddr;
+ TargetAddress RemoteRWDataAddr;
+ std::vector<Alloc> CodeAllocs, RODataAllocs, RWDataAllocs;
+ };
+
+ OrcRemoteTargetClient &Client;
+ ResourceIdMgr::ResourceId Id;
+ std::vector<ObjectAllocs> Unmapped;
+ std::vector<ObjectAllocs> Unfinalized;
+ };
+
+ /// Remote indirect stubs manager.
+ class RCIndirectStubsManager : public IndirectStubsManager {
+ public:
+ RCIndirectStubsManager(OrcRemoteTargetClient &Remote,
+ ResourceIdMgr::ResourceId Id)
+ : Remote(Remote), Id(Id) {}
+
+ ~RCIndirectStubsManager() { Remote.destroyIndirectStubsManager(Id); }
+
+ std::error_code createStub(StringRef StubName, TargetAddress StubAddr,
+ JITSymbolFlags StubFlags) override {
+ if (auto EC = reserveStubs(1))
+ return EC;
+
+ return createStubInternal(StubName, StubAddr, StubFlags);
+ }
+
+ std::error_code createStubs(const StubInitsMap &StubInits) override {
+ if (auto EC = reserveStubs(StubInits.size()))
+ return EC;
+
+ for (auto &Entry : StubInits)
+ if (auto EC = createStubInternal(Entry.first(), Entry.second.first,
+ Entry.second.second))
+ return EC;
+
+ return std::error_code();
+ }
+
+ JITSymbol findStub(StringRef Name, bool ExportedStubsOnly) override {
+ auto I = StubIndexes.find(Name);
+ if (I == StubIndexes.end())
+ return nullptr;
+ auto Key = I->second.first;
+ auto Flags = I->second.second;
+ auto StubSymbol = JITSymbol(getStubAddr(Key), Flags);
+ if (ExportedStubsOnly && !StubSymbol.isExported())
+ return nullptr;
+ return StubSymbol;
+ }
+
+ JITSymbol findPointer(StringRef Name) override {
+ auto I = StubIndexes.find(Name);
+ if (I == StubIndexes.end())
+ return nullptr;
+ auto Key = I->second.first;
+ auto Flags = I->second.second;
+ return JITSymbol(getPtrAddr(Key), Flags);
+ }
+
+ std::error_code updatePointer(StringRef Name,
+ TargetAddress NewAddr) override {
+ auto I = StubIndexes.find(Name);
+ assert(I != StubIndexes.end() && "No stub pointer for symbol");
+ auto Key = I->second.first;
+ return Remote.writePointer(getPtrAddr(Key), NewAddr);
+ }
+
+ private:
+ struct RemoteIndirectStubsInfo {
+ RemoteIndirectStubsInfo(TargetAddress StubBase, TargetAddress PtrBase,
+ unsigned NumStubs)
+ : StubBase(StubBase), PtrBase(PtrBase), NumStubs(NumStubs) {}
+ TargetAddress StubBase;
+ TargetAddress PtrBase;
+ unsigned NumStubs;
+ };
+
+ OrcRemoteTargetClient &Remote;
+ ResourceIdMgr::ResourceId Id;
+ std::vector<RemoteIndirectStubsInfo> RemoteIndirectStubsInfos;
+ typedef std::pair<uint16_t, uint16_t> StubKey;
+ std::vector<StubKey> FreeStubs;
+ StringMap<std::pair<StubKey, JITSymbolFlags>> StubIndexes;
+
+ std::error_code reserveStubs(unsigned NumStubs) {
+ if (NumStubs <= FreeStubs.size())
+ return std::error_code();
+
+ unsigned NewStubsRequired = NumStubs - FreeStubs.size();
+ TargetAddress StubBase;
+ TargetAddress PtrBase;
+ unsigned NumStubsEmitted;
+
+ Remote.emitIndirectStubs(StubBase, PtrBase, NumStubsEmitted, Id,
+ NewStubsRequired);
+
+ unsigned NewBlockId = RemoteIndirectStubsInfos.size();
+ RemoteIndirectStubsInfos.push_back(
+ RemoteIndirectStubsInfo(StubBase, PtrBase, NumStubsEmitted));
+
+ for (unsigned I = 0; I < NumStubsEmitted; ++I)
+ FreeStubs.push_back(std::make_pair(NewBlockId, I));
+
+ return std::error_code();
+ }
+
+ std::error_code createStubInternal(StringRef StubName,
+ TargetAddress InitAddr,
+ JITSymbolFlags StubFlags) {
+ auto Key = FreeStubs.back();
+ FreeStubs.pop_back();
+ StubIndexes[StubName] = std::make_pair(Key, StubFlags);
+ return Remote.writePointer(getPtrAddr(Key), InitAddr);
+ }
+
+ TargetAddress getStubAddr(StubKey K) {
+ assert(RemoteIndirectStubsInfos[K.first].StubBase != 0 &&
+ "Missing stub address");
+ return RemoteIndirectStubsInfos[K.first].StubBase +
+ K.second * Remote.getIndirectStubSize();
+ }
+
+ TargetAddress getPtrAddr(StubKey K) {
+ assert(RemoteIndirectStubsInfos[K.first].PtrBase != 0 &&
+ "Missing pointer address");
+ return RemoteIndirectStubsInfos[K.first].PtrBase +
+ K.second * Remote.getPointerSize();
+ }
+ };
+
+ /// Remote compile callback manager.
+ class RCCompileCallbackManager : public JITCompileCallbackManager {
+ public:
+ RCCompileCallbackManager(TargetAddress ErrorHandlerAddress,
+ OrcRemoteTargetClient &Remote)
+ : JITCompileCallbackManager(ErrorHandlerAddress), Remote(Remote) {
+ assert(!Remote.CompileCallback && "Compile callback already set");
+ Remote.CompileCallback = [this](TargetAddress TrampolineAddr) {
+ return executeCompileCallback(TrampolineAddr);
+ };
+ Remote.emitResolverBlock();
+ }
+
+ private:
+ void grow() {
+ TargetAddress BlockAddr = 0;
+ uint32_t NumTrampolines = 0;
+ auto EC = Remote.emitTrampolineBlock(BlockAddr, NumTrampolines);
+ assert(!EC && "Failed to create trampolines");
+
+ uint32_t TrampolineSize = Remote.getTrampolineSize();
+ for (unsigned I = 0; I < NumTrampolines; ++I)
+ this->AvailableTrampolines.push_back(BlockAddr + (I * TrampolineSize));
+ }
+
+ OrcRemoteTargetClient &Remote;
+ };
+
+ /// Create an OrcRemoteTargetClient.
+ /// Channel is the ChannelT instance to communicate on. It is assumed that
+ /// the channel is ready to be read from and written to.
+ static ErrorOr<OrcRemoteTargetClient> Create(ChannelT &Channel) {
+ std::error_code EC;
+ OrcRemoteTargetClient H(Channel, EC);
+ if (EC)
+ return EC;
+ return H;
+ }
+
+ /// Call the int(void) function at the given address in the target and return
+ /// its result.
+ std::error_code callIntVoid(int &Result, TargetAddress Addr) {
+ DEBUG(dbgs() << "Calling int(*)(void) " << format("0x%016x", Addr) << "\n");
+
+ if (auto EC = call<CallIntVoid>(Channel, Addr))
+ return EC;
+
+ unsigned NextProcId;
+ if (auto EC = listenForCompileRequests(NextProcId))
+ return EC;
+
+ if (NextProcId != CallIntVoidResponseId)
+ return orcError(OrcErrorCode::UnexpectedRPCCall);
+
+ return handle<CallIntVoidResponse>(Channel, [&](int R) {
+ Result = R;
+ DEBUG(dbgs() << "Result: " << R << "\n");
+ return std::error_code();
+ });
+ }
+
+ /// Call the int(int, char*[]) function at the given address in the target and
+ /// return its result.
+ std::error_code callMain(int &Result, TargetAddress Addr,
+ const std::vector<std::string> &Args) {
+ DEBUG(dbgs() << "Calling int(*)(int, char*[]) " << format("0x%016x", Addr)
+ << "\n");
+
+ if (auto EC = call<CallMain>(Channel, Addr, Args))
+ return EC;
+
+ unsigned NextProcId;
+ if (auto EC = listenForCompileRequests(NextProcId))
+ return EC;
+
+ if (NextProcId != CallMainResponseId)
+ return orcError(OrcErrorCode::UnexpectedRPCCall);
+
+ return handle<CallMainResponse>(Channel, [&](int R) {
+ Result = R;
+ DEBUG(dbgs() << "Result: " << R << "\n");
+ return std::error_code();
+ });
+ }
+
+ /// Call the void() function at the given address in the target and wait for
+ /// it to finish.
+ std::error_code callVoidVoid(TargetAddress Addr) {
+ DEBUG(dbgs() << "Calling void(*)(void) " << format("0x%016x", Addr)
+ << "\n");
+
+ if (auto EC = call<CallVoidVoid>(Channel, Addr))
+ return EC;
+
+ unsigned NextProcId;
+ if (auto EC = listenForCompileRequests(NextProcId))
+ return EC;
+
+ if (NextProcId != CallVoidVoidResponseId)
+ return orcError(OrcErrorCode::UnexpectedRPCCall);
+
+ return handle<CallVoidVoidResponse>(Channel, doNothing);
+ }
+
+ /// Create an RCMemoryManager which will allocate its memory on the remote
+ /// target.
+ std::error_code
+ createRemoteMemoryManager(std::unique_ptr<RCMemoryManager> &MM) {
+ assert(!MM && "MemoryManager should be null before creation.");
+
+ auto Id = AllocatorIds.getNext();
+ if (auto EC = call<CreateRemoteAllocator>(Channel, Id))
+ return EC;
+ MM = llvm::make_unique<RCMemoryManager>(*this, Id);
+ return std::error_code();
+ }
+
+ /// Create an RCIndirectStubsManager that will allocate stubs on the remote
+ /// target.
+ std::error_code
+ createIndirectStubsManager(std::unique_ptr<RCIndirectStubsManager> &I) {
+ assert(!I && "Indirect stubs manager should be null before creation.");
+ auto Id = IndirectStubOwnerIds.getNext();
+ if (auto EC = call<CreateIndirectStubsOwner>(Channel, Id))
+ return EC;
+ I = llvm::make_unique<RCIndirectStubsManager>(*this, Id);
+ return std::error_code();
+ }
+
+ /// Search for symbols in the remote process. Note: This should be used by
+ /// symbol resolvers *after* they've searched the local symbol table in the
+ /// JIT stack.
+ std::error_code getSymbolAddress(TargetAddress &Addr, StringRef Name) {
+ // Check for an 'out-of-band' error, e.g. from an MM destructor.
+ if (ExistingError)
+ return ExistingError;
+
+ // Request remote symbol address.
+ if (auto EC = call<GetSymbolAddress>(Channel, Name))
+ return EC;
+
+ return expect<GetSymbolAddressResponse>(Channel, [&](TargetAddress &A) {
+ Addr = A;
+ DEBUG(dbgs() << "Remote address lookup " << Name << " = "
+ << format("0x%016x", Addr) << "\n");
+ return std::error_code();
+ });
+ }
+
+ /// Get the triple for the remote target.
+ const std::string &getTargetTriple() const { return RemoteTargetTriple; }
+
+ std::error_code terminateSession() { return call<TerminateSession>(Channel); }
+
+private:
+ OrcRemoteTargetClient(ChannelT &Channel, std::error_code &EC)
+ : Channel(Channel), RemotePointerSize(0), RemotePageSize(0),
+ RemoteTrampolineSize(0), RemoteIndirectStubSize(0) {
+ if ((EC = call<GetRemoteInfo>(Channel)))
+ return;
+
+ EC = expect<GetRemoteInfoResponse>(
+ Channel, readArgs(RemoteTargetTriple, RemotePointerSize, RemotePageSize,
+ RemoteTrampolineSize, RemoteIndirectStubSize));
+ }
+
+ void destroyRemoteAllocator(ResourceIdMgr::ResourceId Id) {
+ if (auto EC = call<DestroyRemoteAllocator>(Channel, Id)) {
+ // FIXME: This will be triggered by a removeModuleSet call: Propagate
+ // error return up through that.
+ llvm_unreachable("Failed to destroy remote allocator.");
+ AllocatorIds.release(Id);
+ }
+ }
+
+ std::error_code destroyIndirectStubsManager(ResourceIdMgr::ResourceId Id) {
+ IndirectStubOwnerIds.release(Id);
+ return call<DestroyIndirectStubsOwner>(Channel, Id);
+ }
+
+ std::error_code emitIndirectStubs(TargetAddress &StubBase,
+ TargetAddress &PtrBase,
+ uint32_t &NumStubsEmitted,
+ ResourceIdMgr::ResourceId Id,
+ uint32_t NumStubsRequired) {
+ if (auto EC = call<EmitIndirectStubs>(Channel, Id, NumStubsRequired))
+ return EC;
+
+ return expect<EmitIndirectStubsResponse>(
+ Channel, readArgs(StubBase, PtrBase, NumStubsEmitted));
+ }
+
+ std::error_code emitResolverBlock() {
+ // Check for an 'out-of-band' error, e.g. from an MM destructor.
+ if (ExistingError)
+ return ExistingError;
+
+ return call<EmitResolverBlock>(Channel);
+ }
+
+ std::error_code emitTrampolineBlock(TargetAddress &BlockAddr,
+ uint32_t &NumTrampolines) {
+ // Check for an 'out-of-band' error, e.g. from an MM destructor.
+ if (ExistingError)
+ return ExistingError;
+
+ if (auto EC = call<EmitTrampolineBlock>(Channel))
+ return EC;
+
+ return expect<EmitTrampolineBlockResponse>(
+ Channel, [&](TargetAddress BAddr, uint32_t NTrampolines) {
+ BlockAddr = BAddr;
+ NumTrampolines = NTrampolines;
+ return std::error_code();
+ });
+ }
+
+ uint32_t getIndirectStubSize() const { return RemoteIndirectStubSize; }
+ uint32_t getPageSize() const { return RemotePageSize; }
+ uint32_t getPointerSize() const { return RemotePointerSize; }
+
+ uint32_t getTrampolineSize() const { return RemoteTrampolineSize; }
+
+ std::error_code listenForCompileRequests(uint32_t &NextId) {
+ // Check for an 'out-of-band' error, e.g. from an MM destructor.
+ if (ExistingError)
+ return ExistingError;
+
+ if (auto EC = getNextProcId(Channel, NextId))
+ return EC;
+
+ while (NextId == RequestCompileId) {
+ TargetAddress TrampolineAddr = 0;
+ if (auto EC = handle<RequestCompile>(Channel, readArgs(TrampolineAddr)))
+ return EC;
+
+ TargetAddress ImplAddr = CompileCallback(TrampolineAddr);
+ if (auto EC = call<RequestCompileResponse>(Channel, ImplAddr))
+ return EC;
+
+ if (auto EC = getNextProcId(Channel, NextId))
+ return EC;
+ }
+
+ return std::error_code();
+ }
+
+ std::error_code readMem(char *Dst, TargetAddress Src, uint64_t Size) {
+ // Check for an 'out-of-band' error, e.g. from an MM destructor.
+ if (ExistingError)
+ return ExistingError;
+
+ if (auto EC = call<ReadMem>(Channel, Src, Size))
+ return EC;
+
+ if (auto EC = expect<ReadMemResponse>(
+ Channel, [&]() { return Channel.readBytes(Dst, Size); }))
+ return EC;
+
+ return std::error_code();
+ }
+
+ std::error_code reserveMem(TargetAddress &RemoteAddr,
+ ResourceIdMgr::ResourceId Id, uint64_t Size,
+ uint32_t Align) {
+
+ // Check for an 'out-of-band' error, e.g. from an MM destructor.
+ if (ExistingError)
+ return ExistingError;
+
+ if (std::error_code EC = call<ReserveMem>(Channel, Id, Size, Align))
+ return EC;
+
+ return expect<ReserveMemResponse>(Channel, readArgs(RemoteAddr));
+ }
+
+ std::error_code setProtections(ResourceIdMgr::ResourceId Id,
+ TargetAddress RemoteSegAddr,
+ unsigned ProtFlags) {
+ return call<SetProtections>(Channel, Id, RemoteSegAddr, ProtFlags);
+ }
+
+ std::error_code writeMem(TargetAddress Addr, const char *Src, uint64_t Size) {
+ // Check for an 'out-of-band' error, e.g. from an MM destructor.
+ if (ExistingError)
+ return ExistingError;
+
+ // Make the send call.
+ if (auto EC = call<WriteMem>(Channel, Addr, Size))
+ return EC;
+
+ // Follow this up with the section contents.
+ if (auto EC = Channel.appendBytes(Src, Size))
+ return EC;
+
+ return Channel.send();
+ }
+
+ std::error_code writePointer(TargetAddress Addr, TargetAddress PtrVal) {
+ // Check for an 'out-of-band' error, e.g. from an MM destructor.
+ if (ExistingError)
+ return ExistingError;
+
+ return call<WritePtr>(Channel, Addr, PtrVal);
+ }
+
+ static std::error_code doNothing() { return std::error_code(); }
+
+ ChannelT &Channel;
+ std::error_code ExistingError;
+ std::string RemoteTargetTriple;
+ uint32_t RemotePointerSize;
+ uint32_t RemotePageSize;
+ uint32_t RemoteTrampolineSize;
+ uint32_t RemoteIndirectStubSize;
+ ResourceIdMgr AllocatorIds, IndirectStubOwnerIds;
+ std::function<TargetAddress(TargetAddress)> CompileCallback;
+};
+
+} // end namespace remote
+} // end namespace orc
+} // end namespace llvm
+
+#undef DEBUG_TYPE
+
+#endif
diff --git a/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.h b/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.h
new file mode 100644
index 000000000000..96dc24251026
--- /dev/null
+++ b/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.h
@@ -0,0 +1,185 @@
+//===--- OrcRemoteTargetRPCAPI.h - Orc Remote-target RPC API ----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the Orc remote-target RPC API. It should not be used
+// directly, but is used by the RemoteTargetClient and RemoteTargetServer
+// classes.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_EXECUTIONENGINE_ORC_ORCREMOTETARGETRPCAPI_H
+#define LLVM_EXECUTIONENGINE_ORC_ORCREMOTETARGETRPCAPI_H
+
+#include "JITSymbol.h"
+#include "RPCChannel.h"
+#include "RPCUtils.h"
+
+namespace llvm {
+namespace orc {
+namespace remote {
+
+class OrcRemoteTargetRPCAPI : public RPC<RPCChannel> {
+protected:
+ class ResourceIdMgr {
+ public:
+ typedef uint64_t ResourceId;
+ ResourceIdMgr() : NextId(0) {}
+ ResourceId getNext() {
+ if (!FreeIds.empty()) {
+ ResourceId I = FreeIds.back();
+ FreeIds.pop_back();
+ return I;
+ }
+ return NextId++;
+ }
+ void release(ResourceId I) { FreeIds.push_back(I); }
+
+ private:
+ ResourceId NextId;
+ std::vector<ResourceId> FreeIds;
+ };
+
+public:
+ enum JITProcId : uint32_t {
+ InvalidId = 0,
+ CallIntVoidId,
+ CallIntVoidResponseId,
+ CallMainId,
+ CallMainResponseId,
+ CallVoidVoidId,
+ CallVoidVoidResponseId,
+ CreateRemoteAllocatorId,
+ CreateIndirectStubsOwnerId,
+ DestroyRemoteAllocatorId,
+ DestroyIndirectStubsOwnerId,
+ EmitIndirectStubsId,
+ EmitIndirectStubsResponseId,
+ EmitResolverBlockId,
+ EmitTrampolineBlockId,
+ EmitTrampolineBlockResponseId,
+ GetSymbolAddressId,
+ GetSymbolAddressResponseId,
+ GetRemoteInfoId,
+ GetRemoteInfoResponseId,
+ ReadMemId,
+ ReadMemResponseId,
+ ReserveMemId,
+ ReserveMemResponseId,
+ RequestCompileId,
+ RequestCompileResponseId,
+ SetProtectionsId,
+ TerminateSessionId,
+ WriteMemId,
+ WritePtrId
+ };
+
+ static const char *getJITProcIdName(JITProcId Id);
+
+ typedef Procedure<CallIntVoidId, TargetAddress /* FnAddr */> CallIntVoid;
+
+ typedef Procedure<CallIntVoidResponseId, int /* Result */>
+ CallIntVoidResponse;
+
+ typedef Procedure<CallMainId, TargetAddress /* FnAddr */,
+ std::vector<std::string> /* Args */>
+ CallMain;
+
+ typedef Procedure<CallMainResponseId, int /* Result */> CallMainResponse;
+
+ typedef Procedure<CallVoidVoidId, TargetAddress /* FnAddr */> CallVoidVoid;
+
+ typedef Procedure<CallVoidVoidResponseId> CallVoidVoidResponse;
+
+ typedef Procedure<CreateRemoteAllocatorId,
+ ResourceIdMgr::ResourceId /* Allocator ID */>
+ CreateRemoteAllocator;
+
+ typedef Procedure<CreateIndirectStubsOwnerId,
+ ResourceIdMgr::ResourceId /* StubsOwner ID */>
+ CreateIndirectStubsOwner;
+
+ typedef Procedure<DestroyRemoteAllocatorId,
+ ResourceIdMgr::ResourceId /* Allocator ID */>
+ DestroyRemoteAllocator;
+
+ typedef Procedure<DestroyIndirectStubsOwnerId,
+ ResourceIdMgr::ResourceId /* StubsOwner ID */>
+ DestroyIndirectStubsOwner;
+
+ typedef Procedure<EmitIndirectStubsId,
+ ResourceIdMgr::ResourceId /* StubsOwner ID */,
+ uint32_t /* NumStubsRequired */>
+ EmitIndirectStubs;
+
+ typedef Procedure<
+ EmitIndirectStubsResponseId, TargetAddress /* StubsBaseAddr */,
+ TargetAddress /* PtrsBaseAddr */, uint32_t /* NumStubsEmitted */>
+ EmitIndirectStubsResponse;
+
+ typedef Procedure<EmitResolverBlockId> EmitResolverBlock;
+
+ typedef Procedure<EmitTrampolineBlockId> EmitTrampolineBlock;
+
+ typedef Procedure<EmitTrampolineBlockResponseId,
+ TargetAddress /* BlockAddr */,
+ uint32_t /* NumTrampolines */>
+ EmitTrampolineBlockResponse;
+
+ typedef Procedure<GetSymbolAddressId, std::string /*SymbolName*/>
+ GetSymbolAddress;
+
+ typedef Procedure<GetSymbolAddressResponseId, uint64_t /* SymbolAddr */>
+ GetSymbolAddressResponse;
+
+ typedef Procedure<GetRemoteInfoId> GetRemoteInfo;
+
+ typedef Procedure<GetRemoteInfoResponseId, std::string /* Triple */,
+ uint32_t /* PointerSize */, uint32_t /* PageSize */,
+ uint32_t /* TrampolineSize */,
+ uint32_t /* IndirectStubSize */>
+ GetRemoteInfoResponse;
+
+ typedef Procedure<ReadMemId, TargetAddress /* Src */, uint64_t /* Size */>
+ ReadMem;
+
+ typedef Procedure<ReadMemResponseId> ReadMemResponse;
+
+ typedef Procedure<ReserveMemId, ResourceIdMgr::ResourceId /* Id */,
+ uint64_t /* Size */, uint32_t /* Align */>
+ ReserveMem;
+
+ typedef Procedure<ReserveMemResponseId, TargetAddress /* Addr */>
+ ReserveMemResponse;
+
+ typedef Procedure<RequestCompileId, TargetAddress /* TrampolineAddr */>
+ RequestCompile;
+
+ typedef Procedure<RequestCompileResponseId, TargetAddress /* ImplAddr */>
+ RequestCompileResponse;
+
+ typedef Procedure<SetProtectionsId, ResourceIdMgr::ResourceId /* Id */,
+ TargetAddress /* Dst */, uint32_t /* ProtFlags */>
+ SetProtections;
+
+ typedef Procedure<TerminateSessionId> TerminateSession;
+
+ typedef Procedure<WriteMemId, TargetAddress /* Dst */, uint64_t /* Size */
+ /* Data should follow */>
+ WriteMem;
+
+ typedef Procedure<WritePtrId, TargetAddress /* Dst */,
+ TargetAddress /* Val */>
+ WritePtr;
+};
+
+} // end namespace remote
+} // end namespace orc
+} // end namespace llvm
+
+#endif
diff --git a/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetServer.h b/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetServer.h
new file mode 100644
index 000000000000..5247661e49ce
--- /dev/null
+++ b/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetServer.h
@@ -0,0 +1,432 @@
+//===---- OrcRemoteTargetServer.h - Orc Remote-target Server ----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the OrcRemoteTargetServer class. It can be used to build a
+// JIT server that can execute code sent from an OrcRemoteTargetClient.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_EXECUTIONENGINE_ORC_ORCREMOTETARGETSERVER_H
+#define LLVM_EXECUTIONENGINE_ORC_ORCREMOTETARGETSERVER_H
+
+#include "OrcRemoteTargetRPCAPI.h"
+#include "llvm/ExecutionEngine/RTDyldMemoryManager.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/Process.h"
+#include "llvm/Support/raw_ostream.h"
+#include <map>
+
+#define DEBUG_TYPE "orc-remote"
+
+namespace llvm {
+namespace orc {
+namespace remote {
+
+template <typename ChannelT, typename TargetT>
+class OrcRemoteTargetServer : public OrcRemoteTargetRPCAPI {
+public:
+ typedef std::function<TargetAddress(const std::string &Name)>
+ SymbolLookupFtor;
+
+ OrcRemoteTargetServer(ChannelT &Channel, SymbolLookupFtor SymbolLookup)
+ : Channel(Channel), SymbolLookup(std::move(SymbolLookup)) {}
+
+ std::error_code getNextProcId(JITProcId &Id) {
+ return deserialize(Channel, Id);
+ }
+
+ std::error_code handleKnownProcedure(JITProcId Id) {
+ typedef OrcRemoteTargetServer ThisT;
+
+ DEBUG(dbgs() << "Handling known proc: " << getJITProcIdName(Id) << "\n");
+
+ switch (Id) {
+ case CallIntVoidId:
+ return handle<CallIntVoid>(Channel, *this, &ThisT::handleCallIntVoid);
+ case CallMainId:
+ return handle<CallMain>(Channel, *this, &ThisT::handleCallMain);
+ case CallVoidVoidId:
+ return handle<CallVoidVoid>(Channel, *this, &ThisT::handleCallVoidVoid);
+ case CreateRemoteAllocatorId:
+ return handle<CreateRemoteAllocator>(Channel, *this,
+ &ThisT::handleCreateRemoteAllocator);
+ case CreateIndirectStubsOwnerId:
+ return handle<CreateIndirectStubsOwner>(
+ Channel, *this, &ThisT::handleCreateIndirectStubsOwner);
+ case DestroyRemoteAllocatorId:
+ return handle<DestroyRemoteAllocator>(
+ Channel, *this, &ThisT::handleDestroyRemoteAllocator);
+ case DestroyIndirectStubsOwnerId:
+ return handle<DestroyIndirectStubsOwner>(
+ Channel, *this, &ThisT::handleDestroyIndirectStubsOwner);
+ case EmitIndirectStubsId:
+ return handle<EmitIndirectStubs>(Channel, *this,
+ &ThisT::handleEmitIndirectStubs);
+ case EmitResolverBlockId:
+ return handle<EmitResolverBlock>(Channel, *this,
+ &ThisT::handleEmitResolverBlock);
+ case EmitTrampolineBlockId:
+ return handle<EmitTrampolineBlock>(Channel, *this,
+ &ThisT::handleEmitTrampolineBlock);
+ case GetSymbolAddressId:
+ return handle<GetSymbolAddress>(Channel, *this,
+ &ThisT::handleGetSymbolAddress);
+ case GetRemoteInfoId:
+ return handle<GetRemoteInfo>(Channel, *this, &ThisT::handleGetRemoteInfo);
+ case ReadMemId:
+ return handle<ReadMem>(Channel, *this, &ThisT::handleReadMem);
+ case ReserveMemId:
+ return handle<ReserveMem>(Channel, *this, &ThisT::handleReserveMem);
+ case SetProtectionsId:
+ return handle<SetProtections>(Channel, *this,
+ &ThisT::handleSetProtections);
+ case WriteMemId:
+ return handle<WriteMem>(Channel, *this, &ThisT::handleWriteMem);
+ case WritePtrId:
+ return handle<WritePtr>(Channel, *this, &ThisT::handleWritePtr);
+ default:
+ return orcError(OrcErrorCode::UnexpectedRPCCall);
+ }
+
+ llvm_unreachable("Unhandled JIT RPC procedure Id.");
+ }
+
+ std::error_code requestCompile(TargetAddress &CompiledFnAddr,
+ TargetAddress TrampolineAddr) {
+ if (auto EC = call<RequestCompile>(Channel, TrampolineAddr))
+ return EC;
+
+ while (1) {
+ JITProcId Id = InvalidId;
+ if (auto EC = getNextProcId(Id))
+ return EC;
+
+ switch (Id) {
+ case RequestCompileResponseId:
+ return handle<RequestCompileResponse>(Channel,
+ readArgs(CompiledFnAddr));
+ default:
+ if (auto EC = handleKnownProcedure(Id))
+ return EC;
+ }
+ }
+
+ llvm_unreachable("Fell through request-compile command loop.");
+ }
+
+private:
+ struct Allocator {
+ Allocator() = default;
+ Allocator(Allocator &&Other) : Allocs(std::move(Other.Allocs)) {}
+ Allocator &operator=(Allocator &&Other) {
+ Allocs = std::move(Other.Allocs);
+ return *this;
+ }
+
+ ~Allocator() {
+ for (auto &Alloc : Allocs)
+ sys::Memory::releaseMappedMemory(Alloc.second);
+ }
+
+ std::error_code allocate(void *&Addr, size_t Size, uint32_t Align) {
+ std::error_code EC;
+ sys::MemoryBlock MB = sys::Memory::allocateMappedMemory(
+ Size, nullptr, sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC);
+ if (EC)
+ return EC;
+
+ Addr = MB.base();
+ assert(Allocs.find(MB.base()) == Allocs.end() && "Duplicate alloc");
+ Allocs[MB.base()] = std::move(MB);
+ return std::error_code();
+ }
+
+ std::error_code setProtections(void *block, unsigned Flags) {
+ auto I = Allocs.find(block);
+ if (I == Allocs.end())
+ return orcError(OrcErrorCode::RemoteMProtectAddrUnrecognized);
+ return sys::Memory::protectMappedMemory(I->second, Flags);
+ }
+
+ private:
+ std::map<void *, sys::MemoryBlock> Allocs;
+ };
+
+ static std::error_code doNothing() { return std::error_code(); }
+
+ static TargetAddress reenter(void *JITTargetAddr, void *TrampolineAddr) {
+ TargetAddress CompiledFnAddr = 0;
+
+ auto T = static_cast<OrcRemoteTargetServer *>(JITTargetAddr);
+ auto EC = T->requestCompile(
+ CompiledFnAddr, static_cast<TargetAddress>(
+ reinterpret_cast<uintptr_t>(TrampolineAddr)));
+ assert(!EC && "Compile request failed");
+ (void)EC;
+ return CompiledFnAddr;
+ }
+
+ std::error_code handleCallIntVoid(TargetAddress Addr) {
+ typedef int (*IntVoidFnTy)();
+ IntVoidFnTy Fn =
+ reinterpret_cast<IntVoidFnTy>(static_cast<uintptr_t>(Addr));
+
+ DEBUG(dbgs() << " Calling "
+ << reinterpret_cast<void *>(reinterpret_cast<intptr_t>(Fn))
+ << "\n");
+ int Result = Fn();
+ DEBUG(dbgs() << " Result = " << Result << "\n");
+
+ return call<CallIntVoidResponse>(Channel, Result);
+ }
+
+ std::error_code handleCallMain(TargetAddress Addr,
+ std::vector<std::string> Args) {
+ typedef int (*MainFnTy)(int, const char *[]);
+
+ MainFnTy Fn = reinterpret_cast<MainFnTy>(static_cast<uintptr_t>(Addr));
+ int ArgC = Args.size() + 1;
+ int Idx = 1;
+ std::unique_ptr<const char *[]> ArgV(new const char *[ArgC + 1]);
+ ArgV[0] = "<jit process>";
+ for (auto &Arg : Args)
+ ArgV[Idx++] = Arg.c_str();
+
+ DEBUG(dbgs() << " Calling " << reinterpret_cast<void *>(Fn) << "\n");
+ int Result = Fn(ArgC, ArgV.get());
+ DEBUG(dbgs() << " Result = " << Result << "\n");
+
+ return call<CallMainResponse>(Channel, Result);
+ }
+
+ std::error_code handleCallVoidVoid(TargetAddress Addr) {
+ typedef void (*VoidVoidFnTy)();
+ VoidVoidFnTy Fn =
+ reinterpret_cast<VoidVoidFnTy>(static_cast<uintptr_t>(Addr));
+
+ DEBUG(dbgs() << " Calling " << reinterpret_cast<void *>(Fn) << "\n");
+ Fn();
+ DEBUG(dbgs() << " Complete.\n");
+
+ return call<CallVoidVoidResponse>(Channel);
+ }
+
+ std::error_code handleCreateRemoteAllocator(ResourceIdMgr::ResourceId Id) {
+ auto I = Allocators.find(Id);
+ if (I != Allocators.end())
+ return orcError(OrcErrorCode::RemoteAllocatorIdAlreadyInUse);
+ DEBUG(dbgs() << " Created allocator " << Id << "\n");
+ Allocators[Id] = Allocator();
+ return std::error_code();
+ }
+
+ std::error_code handleCreateIndirectStubsOwner(ResourceIdMgr::ResourceId Id) {
+ auto I = IndirectStubsOwners.find(Id);
+ if (I != IndirectStubsOwners.end())
+ return orcError(OrcErrorCode::RemoteIndirectStubsOwnerIdAlreadyInUse);
+ DEBUG(dbgs() << " Create indirect stubs owner " << Id << "\n");
+ IndirectStubsOwners[Id] = ISBlockOwnerList();
+ return std::error_code();
+ }
+
+ std::error_code handleDestroyRemoteAllocator(ResourceIdMgr::ResourceId Id) {
+ auto I = Allocators.find(Id);
+ if (I == Allocators.end())
+ return orcError(OrcErrorCode::RemoteAllocatorDoesNotExist);
+ Allocators.erase(I);
+ DEBUG(dbgs() << " Destroyed allocator " << Id << "\n");
+ return std::error_code();
+ }
+
+ std::error_code
+ handleDestroyIndirectStubsOwner(ResourceIdMgr::ResourceId Id) {
+ auto I = IndirectStubsOwners.find(Id);
+ if (I == IndirectStubsOwners.end())
+ return orcError(OrcErrorCode::RemoteIndirectStubsOwnerDoesNotExist);
+ IndirectStubsOwners.erase(I);
+ return std::error_code();
+ }
+
+ std::error_code handleEmitIndirectStubs(ResourceIdMgr::ResourceId Id,
+ uint32_t NumStubsRequired) {
+ DEBUG(dbgs() << " ISMgr " << Id << " request " << NumStubsRequired
+ << " stubs.\n");
+
+ auto StubOwnerItr = IndirectStubsOwners.find(Id);
+ if (StubOwnerItr == IndirectStubsOwners.end())
+ return orcError(OrcErrorCode::RemoteIndirectStubsOwnerDoesNotExist);
+
+ typename TargetT::IndirectStubsInfo IS;
+ if (auto EC =
+ TargetT::emitIndirectStubsBlock(IS, NumStubsRequired, nullptr))
+ return EC;
+
+ TargetAddress StubsBase =
+ static_cast<TargetAddress>(reinterpret_cast<uintptr_t>(IS.getStub(0)));
+ TargetAddress PtrsBase =
+ static_cast<TargetAddress>(reinterpret_cast<uintptr_t>(IS.getPtr(0)));
+ uint32_t NumStubsEmitted = IS.getNumStubs();
+
+ auto &BlockList = StubOwnerItr->second;
+ BlockList.push_back(std::move(IS));
+
+ return call<EmitIndirectStubsResponse>(Channel, StubsBase, PtrsBase,
+ NumStubsEmitted);
+ }
+
+ std::error_code handleEmitResolverBlock() {
+ std::error_code EC;
+ ResolverBlock = sys::OwningMemoryBlock(sys::Memory::allocateMappedMemory(
+ TargetT::ResolverCodeSize, nullptr,
+ sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC));
+ if (EC)
+ return EC;
+
+ TargetT::writeResolverCode(static_cast<uint8_t *>(ResolverBlock.base()),
+ &reenter, this);
+
+ return sys::Memory::protectMappedMemory(ResolverBlock.getMemoryBlock(),
+ sys::Memory::MF_READ |
+ sys::Memory::MF_EXEC);
+ }
+
+ std::error_code handleEmitTrampolineBlock() {
+ std::error_code EC;
+ auto TrampolineBlock =
+ sys::OwningMemoryBlock(sys::Memory::allocateMappedMemory(
+ sys::Process::getPageSize(), nullptr,
+ sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC));
+ if (EC)
+ return EC;
+
+ unsigned NumTrampolines =
+ (sys::Process::getPageSize() - TargetT::PointerSize) /
+ TargetT::TrampolineSize;
+
+ uint8_t *TrampolineMem = static_cast<uint8_t *>(TrampolineBlock.base());
+ TargetT::writeTrampolines(TrampolineMem, ResolverBlock.base(),
+ NumTrampolines);
+
+ EC = sys::Memory::protectMappedMemory(TrampolineBlock.getMemoryBlock(),
+ sys::Memory::MF_READ |
+ sys::Memory::MF_EXEC);
+
+ TrampolineBlocks.push_back(std::move(TrampolineBlock));
+
+ return call<EmitTrampolineBlockResponse>(
+ Channel,
+ static_cast<TargetAddress>(reinterpret_cast<uintptr_t>(TrampolineMem)),
+ NumTrampolines);
+ }
+
+ std::error_code handleGetSymbolAddress(const std::string &Name) {
+ TargetAddress Addr = SymbolLookup(Name);
+ DEBUG(dbgs() << " Symbol '" << Name << "' = " << format("0x%016x", Addr)
+ << "\n");
+ return call<GetSymbolAddressResponse>(Channel, Addr);
+ }
+
+ std::error_code handleGetRemoteInfo() {
+ std::string ProcessTriple = sys::getProcessTriple();
+ uint32_t PointerSize = TargetT::PointerSize;
+ uint32_t PageSize = sys::Process::getPageSize();
+ uint32_t TrampolineSize = TargetT::TrampolineSize;
+ uint32_t IndirectStubSize = TargetT::IndirectStubsInfo::StubSize;
+ DEBUG(dbgs() << " Remote info:\n"
+ << " triple = '" << ProcessTriple << "'\n"
+ << " pointer size = " << PointerSize << "\n"
+ << " page size = " << PageSize << "\n"
+ << " trampoline size = " << TrampolineSize << "\n"
+ << " indirect stub size = " << IndirectStubSize << "\n");
+ return call<GetRemoteInfoResponse>(Channel, ProcessTriple, PointerSize,
+ PageSize, TrampolineSize,
+ IndirectStubSize);
+ }
+
+ std::error_code handleReadMem(TargetAddress RSrc, uint64_t Size) {
+ char *Src = reinterpret_cast<char *>(static_cast<uintptr_t>(RSrc));
+
+ DEBUG(dbgs() << " Reading " << Size << " bytes from "
+ << static_cast<void *>(Src) << "\n");
+
+ if (auto EC = call<ReadMemResponse>(Channel))
+ return EC;
+
+ if (auto EC = Channel.appendBytes(Src, Size))
+ return EC;
+
+ return Channel.send();
+ }
+
+ std::error_code handleReserveMem(ResourceIdMgr::ResourceId Id, uint64_t Size,
+ uint32_t Align) {
+ auto I = Allocators.find(Id);
+ if (I == Allocators.end())
+ return orcError(OrcErrorCode::RemoteAllocatorDoesNotExist);
+ auto &Allocator = I->second;
+ void *LocalAllocAddr = nullptr;
+ if (auto EC = Allocator.allocate(LocalAllocAddr, Size, Align))
+ return EC;
+
+ DEBUG(dbgs() << " Allocator " << Id << " reserved " << LocalAllocAddr
+ << " (" << Size << " bytes, alignment " << Align << ")\n");
+
+ TargetAddress AllocAddr =
+ static_cast<TargetAddress>(reinterpret_cast<uintptr_t>(LocalAllocAddr));
+
+ return call<ReserveMemResponse>(Channel, AllocAddr);
+ }
+
+ std::error_code handleSetProtections(ResourceIdMgr::ResourceId Id,
+ TargetAddress Addr, uint32_t Flags) {
+ auto I = Allocators.find(Id);
+ if (I == Allocators.end())
+ return orcError(OrcErrorCode::RemoteAllocatorDoesNotExist);
+ auto &Allocator = I->second;
+ void *LocalAddr = reinterpret_cast<void *>(static_cast<uintptr_t>(Addr));
+ DEBUG(dbgs() << " Allocator " << Id << " set permissions on " << LocalAddr
+ << " to " << (Flags & sys::Memory::MF_READ ? 'R' : '-')
+ << (Flags & sys::Memory::MF_WRITE ? 'W' : '-')
+ << (Flags & sys::Memory::MF_EXEC ? 'X' : '-') << "\n");
+ return Allocator.setProtections(LocalAddr, Flags);
+ }
+
+ std::error_code handleWriteMem(TargetAddress RDst, uint64_t Size) {
+ char *Dst = reinterpret_cast<char *>(static_cast<uintptr_t>(RDst));
+ DEBUG(dbgs() << " Writing " << Size << " bytes to "
+ << format("0x%016x", RDst) << "\n");
+ return Channel.readBytes(Dst, Size);
+ }
+
+ std::error_code handleWritePtr(TargetAddress Addr, TargetAddress PtrVal) {
+ DEBUG(dbgs() << " Writing pointer *" << format("0x%016x", Addr) << " = "
+ << format("0x%016x", PtrVal) << "\n");
+ uintptr_t *Ptr =
+ reinterpret_cast<uintptr_t *>(static_cast<uintptr_t>(Addr));
+ *Ptr = static_cast<uintptr_t>(PtrVal);
+ return std::error_code();
+ }
+
+ ChannelT &Channel;
+ SymbolLookupFtor SymbolLookup;
+ std::map<ResourceIdMgr::ResourceId, Allocator> Allocators;
+ typedef std::vector<typename TargetT::IndirectStubsInfo> ISBlockOwnerList;
+ std::map<ResourceIdMgr::ResourceId, ISBlockOwnerList> IndirectStubsOwners;
+ sys::OwningMemoryBlock ResolverBlock;
+ std::vector<sys::OwningMemoryBlock> TrampolineBlocks;
+};
+
+} // end namespace remote
+} // end namespace orc
+} // end namespace llvm
+
+#undef DEBUG_TYPE
+
+#endif
diff --git a/include/llvm/ExecutionEngine/Orc/RPCChannel.h b/include/llvm/ExecutionEngine/Orc/RPCChannel.h
new file mode 100644
index 000000000000..b97b6daf5864
--- /dev/null
+++ b/include/llvm/ExecutionEngine/Orc/RPCChannel.h
@@ -0,0 +1,179 @@
+// -*- c++ -*-
+
+#ifndef LLVM_EXECUTIONENGINE_ORC_RPCCHANNEL_H
+#define LLVM_EXECUTIONENGINE_ORC_RPCCHANNEL_H
+
+#include "OrcError.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/Support/Endian.h"
+
+#include <system_error>
+
+namespace llvm {
+namespace orc {
+namespace remote {
+
+/// Interface for byte-streams to be used with RPC.
+class RPCChannel {
+public:
+ virtual ~RPCChannel() {}
+
+ /// Read Size bytes from the stream into *Dst.
+ virtual std::error_code readBytes(char *Dst, unsigned Size) = 0;
+
+ /// Read size bytes from *Src and append them to the stream.
+ virtual std::error_code appendBytes(const char *Src, unsigned Size) = 0;
+
+ /// Flush the stream if possible.
+ virtual std::error_code send() = 0;
+};
+
+/// RPC channel serialization for a variadic list of arguments.
+template <typename T, typename... Ts>
+std::error_code serialize_seq(RPCChannel &C, const T &Arg, const Ts &... Args) {
+ if (auto EC = serialize(C, Arg))
+ return EC;
+ return serialize_seq(C, Args...);
+}
+
+/// RPC channel serialization for an (empty) variadic list of arguments.
+inline std::error_code serialize_seq(RPCChannel &C) {
+ return std::error_code();
+}
+
+/// RPC channel deserialization for a variadic list of arguments.
+template <typename T, typename... Ts>
+std::error_code deserialize_seq(RPCChannel &C, T &Arg, Ts &... Args) {
+ if (auto EC = deserialize(C, Arg))
+ return EC;
+ return deserialize_seq(C, Args...);
+}
+
+/// RPC channel serialization for an (empty) variadic list of arguments.
+inline std::error_code deserialize_seq(RPCChannel &C) {
+ return std::error_code();
+}
+
+/// RPC channel serialization for integer primitives.
+template <typename T>
+typename std::enable_if<
+ std::is_same<T, uint64_t>::value || std::is_same<T, int64_t>::value ||
+ std::is_same<T, uint32_t>::value || std::is_same<T, int32_t>::value ||
+ std::is_same<T, uint16_t>::value || std::is_same<T, int16_t>::value ||
+ std::is_same<T, uint8_t>::value || std::is_same<T, int8_t>::value,
+ std::error_code>::type
+serialize(RPCChannel &C, T V) {
+ support::endian::byte_swap<T, support::big>(V);
+ return C.appendBytes(reinterpret_cast<const char *>(&V), sizeof(T));
+}
+
+/// RPC channel deserialization for integer primitives.
+template <typename T>
+typename std::enable_if<
+ std::is_same<T, uint64_t>::value || std::is_same<T, int64_t>::value ||
+ std::is_same<T, uint32_t>::value || std::is_same<T, int32_t>::value ||
+ std::is_same<T, uint16_t>::value || std::is_same<T, int16_t>::value ||
+ std::is_same<T, uint8_t>::value || std::is_same<T, int8_t>::value,
+ std::error_code>::type
+deserialize(RPCChannel &C, T &V) {
+ if (auto EC = C.readBytes(reinterpret_cast<char *>(&V), sizeof(T)))
+ return EC;
+ support::endian::byte_swap<T, support::big>(V);
+ return std::error_code();
+}
+
+/// RPC channel serialization for enums.
+template <typename T>
+typename std::enable_if<std::is_enum<T>::value, std::error_code>::type
+serialize(RPCChannel &C, T V) {
+ return serialize(C, static_cast<typename std::underlying_type<T>::type>(V));
+}
+
+/// RPC channel deserialization for enums.
+template <typename T>
+typename std::enable_if<std::is_enum<T>::value, std::error_code>::type
+deserialize(RPCChannel &C, T &V) {
+ typename std::underlying_type<T>::type Tmp;
+ std::error_code EC = deserialize(C, Tmp);
+ V = static_cast<T>(Tmp);
+ return EC;
+}
+
+/// RPC channel serialization for bools.
+inline std::error_code serialize(RPCChannel &C, bool V) {
+ uint8_t VN = V ? 1 : 0;
+ return C.appendBytes(reinterpret_cast<const char *>(&VN), 1);
+}
+
+/// RPC channel deserialization for bools.
+inline std::error_code deserialize(RPCChannel &C, bool &V) {
+ uint8_t VN = 0;
+ if (auto EC = C.readBytes(reinterpret_cast<char *>(&VN), 1))
+ return EC;
+
+ V = (VN != 0) ? true : false;
+ return std::error_code();
+}
+
+/// RPC channel serialization for StringRefs.
+/// Note: There is no corresponding deseralization for this, as StringRef
+/// doesn't own its memory and so can't hold the deserialized data.
+inline std::error_code serialize(RPCChannel &C, StringRef S) {
+ if (auto EC = serialize(C, static_cast<uint64_t>(S.size())))
+ return EC;
+ return C.appendBytes((const char *)S.bytes_begin(), S.size());
+}
+
+/// RPC channel serialization for std::strings.
+inline std::error_code serialize(RPCChannel &C, const std::string &S) {
+ return serialize(C, StringRef(S));
+}
+
+/// RPC channel deserialization for std::strings.
+inline std::error_code deserialize(RPCChannel &C, std::string &S) {
+ uint64_t Count;
+ if (auto EC = deserialize(C, Count))
+ return EC;
+ S.resize(Count);
+ return C.readBytes(&S[0], Count);
+}
+
+/// RPC channel serialization for ArrayRef<T>.
+template <typename T>
+std::error_code serialize(RPCChannel &C, const ArrayRef<T> &A) {
+ if (auto EC = serialize(C, static_cast<uint64_t>(A.size())))
+ return EC;
+
+ for (const auto &E : A)
+ if (auto EC = serialize(C, E))
+ return EC;
+
+ return std::error_code();
+}
+
+/// RPC channel serialization for std::array<T>.
+template <typename T>
+std::error_code serialize(RPCChannel &C, const std::vector<T> &V) {
+ return serialize(C, ArrayRef<T>(V));
+}
+
+/// RPC channel deserialization for std::array<T>.
+template <typename T>
+std::error_code deserialize(RPCChannel &C, std::vector<T> &V) {
+ uint64_t Count = 0;
+ if (auto EC = deserialize(C, Count))
+ return EC;
+
+ V.resize(Count);
+ for (auto &E : V)
+ if (auto EC = deserialize(C, E))
+ return EC;
+
+ return std::error_code();
+}
+
+} // end namespace remote
+} // end namespace orc
+} // end namespace llvm
+
+#endif
diff --git a/include/llvm/ExecutionEngine/Orc/RPCUtils.h b/include/llvm/ExecutionEngine/Orc/RPCUtils.h
new file mode 100644
index 000000000000..0bd5cbc0cdde
--- /dev/null
+++ b/include/llvm/ExecutionEngine/Orc/RPCUtils.h
@@ -0,0 +1,266 @@
+//===----- RPCUTils.h - Basic tilities for building RPC APIs ----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Basic utilities for building RPC APIs.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_EXECUTIONENGINE_ORC_RPCUTILS_H
+#define LLVM_EXECUTIONENGINE_ORC_RPCUTILS_H
+
+#include "llvm/ADT/STLExtras.h"
+
+namespace llvm {
+namespace orc {
+namespace remote {
+
+// Base class containing utilities that require partial specialization.
+// These cannot be included in RPC, as template class members cannot be
+// partially specialized.
+class RPCBase {
+protected:
+ template <typename ProcedureIdT, ProcedureIdT ProcId, typename... Ts>
+ class ProcedureHelper {
+ public:
+ static const ProcedureIdT Id = ProcId;
+ };
+
+ template <typename ChannelT, typename Proc> class CallHelper;
+
+ template <typename ChannelT, typename ProcedureIdT, ProcedureIdT ProcId,
+ typename... ArgTs>
+ class CallHelper<ChannelT, ProcedureHelper<ProcedureIdT, ProcId, ArgTs...>> {
+ public:
+ static std::error_code call(ChannelT &C, const ArgTs &... Args) {
+ if (auto EC = serialize(C, ProcId))
+ return EC;
+ // If you see a compile-error on this line you're probably calling a
+ // function with the wrong signature.
+ return serialize_seq(C, Args...);
+ }
+ };
+
+ template <typename ChannelT, typename Proc> class HandlerHelper;
+
+ template <typename ChannelT, typename ProcedureIdT, ProcedureIdT ProcId,
+ typename... ArgTs>
+ class HandlerHelper<ChannelT,
+ ProcedureHelper<ProcedureIdT, ProcId, ArgTs...>> {
+ public:
+ template <typename HandlerT>
+ static std::error_code handle(ChannelT &C, HandlerT Handler) {
+ return readAndHandle(C, Handler, llvm::index_sequence_for<ArgTs...>());
+ }
+
+ private:
+ template <typename HandlerT, size_t... Is>
+ static std::error_code readAndHandle(ChannelT &C, HandlerT Handler,
+ llvm::index_sequence<Is...> _) {
+ std::tuple<ArgTs...> RPCArgs;
+ if (auto EC = deserialize_seq(C, std::get<Is>(RPCArgs)...))
+ return EC;
+ return Handler(std::get<Is>(RPCArgs)...);
+ }
+ };
+
+ template <typename ClassT, typename... ArgTs> class MemberFnWrapper {
+ public:
+ typedef std::error_code (ClassT::*MethodT)(ArgTs...);
+ MemberFnWrapper(ClassT &Instance, MethodT Method)
+ : Instance(Instance), Method(Method) {}
+ std::error_code operator()(ArgTs &... Args) {
+ return (Instance.*Method)(Args...);
+ }
+
+ private:
+ ClassT &Instance;
+ MethodT Method;
+ };
+
+ template <typename... ArgTs> class ReadArgs {
+ public:
+ std::error_code operator()() { return std::error_code(); }
+ };
+
+ template <typename ArgT, typename... ArgTs>
+ class ReadArgs<ArgT, ArgTs...> : public ReadArgs<ArgTs...> {
+ public:
+ ReadArgs(ArgT &Arg, ArgTs &... Args)
+ : ReadArgs<ArgTs...>(Args...), Arg(Arg) {}
+
+ std::error_code operator()(ArgT &ArgVal, ArgTs &... ArgVals) {
+ this->Arg = std::move(ArgVal);
+ return ReadArgs<ArgTs...>::operator()(ArgVals...);
+ }
+
+ private:
+ ArgT &Arg;
+ };
+};
+
+/// Contains primitive utilities for defining, calling and handling calls to
+/// remote procedures. ChannelT is a bidirectional stream conforming to the
+/// RPCChannel interface (see RPCChannel.h), and ProcedureIdT is a procedure
+/// identifier type that must be serializable on ChannelT.
+///
+/// These utilities support the construction of very primitive RPC utilities.
+/// Their intent is to ensure correct serialization and deserialization of
+/// procedure arguments, and to keep the client and server's view of the API in
+/// sync.
+///
+/// These utilities do not support return values. These can be handled by
+/// declaring a corresponding '.*Response' procedure and expecting it after a
+/// call). They also do not support versioning: the client and server *must* be
+/// compiled with the same procedure definitions.
+///
+///
+///
+/// Overview (see comments individual types/methods for details):
+///
+/// Procedure<Id, Args...> :
+///
+/// associates a unique serializable id with an argument list.
+///
+///
+/// call<Proc>(Channel, Args...) :
+///
+/// Calls the remote procedure 'Proc' by serializing Proc's id followed by its
+/// arguments and sending the resulting bytes to 'Channel'.
+///
+///
+/// handle<Proc>(Channel, <functor matching std::error_code(Args...)> :
+///
+/// Handles a call to 'Proc' by deserializing its arguments and calling the
+/// given functor. This assumes that the id for 'Proc' has already been
+/// deserialized.
+///
+/// expect<Proc>(Channel, <functor matching std::error_code(Args...)> :
+///
+/// The same as 'handle', except that the procedure id should not have been
+/// read yet. Expect will deserialize the id and assert that it matches Proc's
+/// id. If it does not, and unexpected RPC call error is returned.
+
+template <typename ChannelT, typename ProcedureIdT = uint32_t>
+class RPC : public RPCBase {
+public:
+ /// Utility class for defining/referring to RPC procedures.
+ ///
+ /// Typedefs of this utility are used when calling/handling remote procedures.
+ ///
+ /// ProcId should be a unique value of ProcedureIdT (i.e. not used with any
+ /// other Procedure typedef in the RPC API being defined.
+ ///
+ /// the template argument Ts... gives the argument list for the remote
+ /// procedure.
+ ///
+ /// E.g.
+ ///
+ /// typedef Procedure<0, bool> Proc1;
+ /// typedef Procedure<1, std::string, std::vector<int>> Proc2;
+ ///
+ /// if (auto EC = call<Proc1>(Channel, true))
+ /// /* handle EC */;
+ ///
+ /// if (auto EC = expect<Proc2>(Channel,
+ /// [](std::string &S, std::vector<int> &V) {
+ /// // Stuff.
+ /// return std::error_code();
+ /// })
+ /// /* handle EC */;
+ ///
+ template <ProcedureIdT ProcId, typename... Ts>
+ using Procedure = ProcedureHelper<ProcedureIdT, ProcId, Ts...>;
+
+ /// Serialize Args... to channel C, but do not call C.send().
+ ///
+ /// For buffered channels, this can be used to queue up several calls before
+ /// flushing the channel.
+ template <typename Proc, typename... ArgTs>
+ static std::error_code appendCall(ChannelT &C, const ArgTs &... Args) {
+ return CallHelper<ChannelT, Proc>::call(C, Args...);
+ }
+
+ /// Serialize Args... to channel C and call C.send().
+ template <typename Proc, typename... ArgTs>
+ static std::error_code call(ChannelT &C, const ArgTs &... Args) {
+ if (auto EC = appendCall<Proc>(C, Args...))
+ return EC;
+ return C.send();
+ }
+
+ /// Deserialize and return an enum whose underlying type is ProcedureIdT.
+ static std::error_code getNextProcId(ChannelT &C, ProcedureIdT &Id) {
+ return deserialize(C, Id);
+ }
+
+ /// Deserialize args for Proc from C and call Handler. The signature of
+ /// handler must conform to 'std::error_code(Args...)' where Args... matches
+ /// the arguments used in the Proc typedef.
+ template <typename Proc, typename HandlerT>
+ static std::error_code handle(ChannelT &C, HandlerT Handler) {
+ return HandlerHelper<ChannelT, Proc>::handle(C, Handler);
+ }
+
+ /// Helper version of 'handle' for calling member functions.
+ template <typename Proc, typename ClassT, typename... ArgTs>
+ static std::error_code
+ handle(ChannelT &C, ClassT &Instance,
+ std::error_code (ClassT::*HandlerMethod)(ArgTs...)) {
+ return handle<Proc>(
+ C, MemberFnWrapper<ClassT, ArgTs...>(Instance, HandlerMethod));
+ }
+
+ /// Deserialize a ProcedureIdT from C and verify it matches the id for Proc.
+ /// If the id does match, deserialize the arguments and call the handler
+ /// (similarly to handle).
+ /// If the id does not match, return an unexpect RPC call error and do not
+ /// deserialize any further bytes.
+ template <typename Proc, typename HandlerT>
+ static std::error_code expect(ChannelT &C, HandlerT Handler) {
+ ProcedureIdT ProcId;
+ if (auto EC = getNextProcId(C, ProcId))
+ return EC;
+ if (ProcId != Proc::Id)
+ return orcError(OrcErrorCode::UnexpectedRPCCall);
+ return handle<Proc>(C, Handler);
+ }
+
+ /// Helper version of expect for calling member functions.
+ template <typename Proc, typename ClassT, typename... ArgTs>
+ static std::error_code
+ expect(ChannelT &C, ClassT &Instance,
+ std::error_code (ClassT::*HandlerMethod)(ArgTs...)) {
+ return expect<Proc>(
+ C, MemberFnWrapper<ClassT, ArgTs...>(Instance, HandlerMethod));
+ }
+
+ /// Helper for handling setter procedures - this method returns a functor that
+ /// sets the variables referred to by Args... to values deserialized from the
+ /// channel.
+ /// E.g.
+ ///
+ /// typedef Procedure<0, bool, int> Proc1;
+ ///
+ /// ...
+ /// bool B;
+ /// int I;
+ /// if (auto EC = expect<Proc1>(Channel, readArgs(B, I)))
+ /// /* Handle Args */ ;
+ ///
+ template <typename... ArgTs>
+ static ReadArgs<ArgTs...> readArgs(ArgTs &... Args) {
+ return ReadArgs<ArgTs...>(Args...);
+ }
+};
+
+} // end namespace remote
+} // end namespace orc
+} // end namespace llvm
+
+#endif
diff --git a/include/llvm/ExecutionEngine/RTDyldMemoryManager.h b/include/llvm/ExecutionEngine/RTDyldMemoryManager.h
index 207bad06c239..c5006962550e 100644
--- a/include/llvm/ExecutionEngine/RTDyldMemoryManager.h
+++ b/include/llvm/ExecutionEngine/RTDyldMemoryManager.h
@@ -30,6 +30,10 @@ class ExecutionEngine;
class MCJITMemoryManager : public RuntimeDyld::MemoryManager {
public:
+
+ // Don't hide the notifyObjectLoaded method from RuntimeDyld::MemoryManager.
+ using RuntimeDyld::MemoryManager::notifyObjectLoaded;
+
/// This method is called after an object has been loaded into memory but
/// before relocations are applied to the loaded sections. The object load
/// may have been initiated by MCJIT to resolve an external symbol for another
diff --git a/include/llvm/ExecutionEngine/RuntimeDyld.h b/include/llvm/ExecutionEngine/RuntimeDyld.h
index 385b8d0a30b1..100e97b8b3d9 100644
--- a/include/llvm/ExecutionEngine/RuntimeDyld.h
+++ b/include/llvm/ExecutionEngine/RuntimeDyld.h
@@ -95,7 +95,9 @@ public:
/// \brief Memory Management.
class MemoryManager {
+ friend class RuntimeDyld;
public:
+ MemoryManager() : FinalizationLocked(false) {}
virtual ~MemoryManager() {}
/// Allocate a memory block of (at least) the given size suitable for
@@ -122,9 +124,11 @@ public:
///
/// Note that by default the callback is disabled. To enable it
/// redefine the method needsToReserveAllocationSpace to return true.
- virtual void reserveAllocationSpace(uintptr_t CodeSize,
- uintptr_t DataSizeRO,
- uintptr_t DataSizeRW) {}
+ virtual void reserveAllocationSpace(uintptr_t CodeSize, uint32_t CodeAlign,
+ uintptr_t RODataSize,
+ uint32_t RODataAlign,
+ uintptr_t RWDataSize,
+ uint32_t RWDataAlign) {}
/// Override to return true to enable the reserveAllocationSpace callback.
virtual bool needsToReserveAllocationSpace() { return false; }
@@ -151,8 +155,23 @@ public:
/// Returns true if an error occurred, false otherwise.
virtual bool finalizeMemory(std::string *ErrMsg = nullptr) = 0;
+ /// This method is called after an object has been loaded into memory but
+ /// before relocations are applied to the loaded sections.
+ ///
+ /// Memory managers which are preparing code for execution in an external
+ /// address space can use this call to remap the section addresses for the
+ /// newly loaded object.
+ ///
+ /// For clients that do not need access to an ExecutionEngine instance this
+ /// method should be preferred to its cousin
+ /// MCJITMemoryManager::notifyObjectLoaded as this method is compatible with
+ /// ORC JIT stacks.
+ virtual void notifyObjectLoaded(RuntimeDyld &RTDyld,
+ const object::ObjectFile &Obj) {}
+
private:
virtual void anchor();
+ bool FinalizationLocked;
};
/// \brief Symbol resolution.
@@ -241,6 +260,25 @@ public:
this->ProcessAllSections = ProcessAllSections;
}
+ /// Perform all actions needed to make the code owned by this RuntimeDyld
+ /// instance executable:
+ ///
+ /// 1) Apply relocations.
+ /// 2) Register EH frames.
+ /// 3) Update memory permissions*.
+ ///
+ /// * Finalization is potentially recursive**, and the 3rd step will only be
+ /// applied by the outermost call to finalize. This allows different
+ /// RuntimeDyld instances to share a memory manager without the innermost
+ /// finalization locking the memory and causing relocation fixup errors in
+ /// outer instances.
+ ///
+ /// ** Recursive finalization occurs when one RuntimeDyld instances needs the
+ /// address of a symbol owned by some other instance in order to apply
+ /// relocations.
+ ///
+ void finalizeWithMemoryManagerLocking();
+
private:
// RuntimeDyldImpl is the actual class. RuntimeDyld is just the public
// interface.
diff --git a/include/llvm/IR/Attributes.td b/include/llvm/IR/Attributes.td
index 797cd55427b3..30249bbd8fab 100644
--- a/include/llvm/IR/Attributes.td
+++ b/include/llvm/IR/Attributes.td
@@ -189,4 +189,9 @@ class MergeRule<string F> {
string MergeFunc = F;
}
+def : MergeRule<"setAND<LessPreciseFPMADAttr>">;
+def : MergeRule<"setAND<NoInfsFPMathAttr>">;
+def : MergeRule<"setAND<NoNansFPMathAttr>">;
+def : MergeRule<"setAND<UnsafeFPMathAttr>">;
+def : MergeRule<"setOR<NoImplicitFloatAttr>">;
def : MergeRule<"adjustCallerSSPLevel">;
diff --git a/include/llvm/IR/Function.h b/include/llvm/IR/Function.h
index 2a983930bf4d..4f64caeade20 100644
--- a/include/llvm/IR/Function.h
+++ b/include/llvm/IR/Function.h
@@ -66,7 +66,8 @@ private:
* bit 2 : HasPrologueData
* bit 3 : HasPersonalityFn
* bits 4-13 : CallingConvention
- * bits 14-15 : [reserved]
+ * bits 14 : HasGC
+ * bits 15 : [reserved]
*/
/// Bits from GlobalObject::GlobalObjectSubclassData.
@@ -220,9 +221,11 @@ public:
/// hasGC/getGC/setGC/clearGC - The name of the garbage collection algorithm
/// to use during code generation.
- bool hasGC() const;
- const char *getGC() const;
- void setGC(const char *Str);
+ bool hasGC() const {
+ return getSubclassDataFromValue() & (1<<14);
+ }
+ const std::string &getGC() const;
+ void setGC(const std::string Str);
void clearGC();
/// @brief adds the attribute to the list of attributes.
diff --git a/include/llvm/IR/IRBuilder.h b/include/llvm/IR/IRBuilder.h
index a30505471aac..1b75c60631b0 100644
--- a/include/llvm/IR/IRBuilder.h
+++ b/include/llvm/IR/IRBuilder.h
@@ -178,10 +178,10 @@ public:
void clearFastMathFlags() { FMF.clear(); }
/// \brief Set the floating point math metadata to be used.
- void SetDefaultFPMathTag(MDNode *FPMathTag) { DefaultFPMathTag = FPMathTag; }
+ void setDefaultFPMathTag(MDNode *FPMathTag) { DefaultFPMathTag = FPMathTag; }
/// \brief Set the fast-math flags to be used with generated fp-math operators
- void SetFastMathFlags(FastMathFlags NewFMF) { FMF = NewFMF; }
+ void setFastMathFlags(FastMathFlags NewFMF) { FMF = NewFMF; }
//===--------------------------------------------------------------------===//
// RAII helpers.
diff --git a/include/llvm/IR/Intrinsics.td b/include/llvm/IR/Intrinsics.td
index 5a95ddced538..f67029ab56e3 100644
--- a/include/llvm/IR/Intrinsics.td
+++ b/include/llvm/IR/Intrinsics.td
@@ -575,7 +575,7 @@ def int_experimental_gc_statepoint : Intrinsic<[llvm_token_ty],
def int_experimental_gc_result : Intrinsic<[llvm_any_ty], [llvm_token_ty],
[IntrReadMem]>;
-def int_experimental_gc_relocate : Intrinsic<[llvm_anyptr_ty],
+def int_experimental_gc_relocate : Intrinsic<[llvm_any_ty],
[llvm_token_ty, llvm_i32_ty, llvm_i32_ty],
[IntrReadMem]>;
diff --git a/include/llvm/IR/IntrinsicsX86.td b/include/llvm/IR/IntrinsicsX86.td
index 54bcbd8da509..8023a9f6e8e9 100644
--- a/include/llvm/IR/IntrinsicsX86.td
+++ b/include/llvm/IR/IntrinsicsX86.td
@@ -1507,6 +1507,60 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.".
[llvm_v64i8_ty, llvm_v64i8_ty, llvm_v64i8_ty, llvm_i64_ty],
[IntrNoMem]>;
+ def int_x86_avx512_mask_pshuf_d_128 :
+ GCCBuiltin<"__builtin_ia32_pshufd128_mask">,
+ Intrinsic<[llvm_v4i32_ty],
+ [llvm_v4i32_ty, llvm_i16_ty, llvm_v4i32_ty, llvm_i8_ty],
+ [IntrNoMem]>;
+
+ def int_x86_avx512_mask_pshuf_d_256 :
+ GCCBuiltin<"__builtin_ia32_pshufd256_mask">,
+ Intrinsic<[llvm_v8i32_ty],
+ [llvm_v8i32_ty, llvm_i16_ty, llvm_v8i32_ty, llvm_i8_ty],
+ [IntrNoMem]>;
+
+ def int_x86_avx512_mask_pshuf_d_512 :
+ GCCBuiltin<"__builtin_ia32_pshufd512_mask">,
+ Intrinsic<[llvm_v16i32_ty],
+ [llvm_v16i32_ty, llvm_i16_ty, llvm_v16i32_ty, llvm_i8_ty],
+ [IntrNoMem]>;
+
+ def int_x86_avx512_mask_pshufh_w_128 :
+ GCCBuiltin<"__builtin_ia32_pshufhw128_mask">,
+ Intrinsic<[llvm_v8i16_ty],
+ [llvm_v8i16_ty, llvm_i8_ty, llvm_v8i16_ty, llvm_i8_ty],
+ [IntrNoMem]>;
+
+ def int_x86_avx512_mask_pshufh_w_256 :
+ GCCBuiltin<"__builtin_ia32_pshufhw256_mask">,
+ Intrinsic<[llvm_v16i16_ty],
+ [llvm_v16i16_ty, llvm_i8_ty, llvm_v16i16_ty, llvm_i16_ty],
+ [IntrNoMem]>;
+
+ def int_x86_avx512_mask_pshufh_w_512 :
+ GCCBuiltin<"__builtin_ia32_pshufhw512_mask">,
+ Intrinsic<[llvm_v32i16_ty],
+ [llvm_v32i16_ty, llvm_i8_ty, llvm_v32i16_ty, llvm_i32_ty],
+ [IntrNoMem]>;
+
+ def int_x86_avx512_mask_pshufl_w_128 :
+ GCCBuiltin<"__builtin_ia32_pshuflw128_mask">,
+ Intrinsic<[llvm_v8i16_ty],
+ [llvm_v8i16_ty, llvm_i8_ty, llvm_v8i16_ty, llvm_i8_ty],
+ [IntrNoMem]>;
+
+ def int_x86_avx512_mask_pshufl_w_256 :
+ GCCBuiltin<"__builtin_ia32_pshuflw256_mask">,
+ Intrinsic<[llvm_v16i16_ty],
+ [llvm_v16i16_ty, llvm_i8_ty, llvm_v16i16_ty, llvm_i16_ty],
+ [IntrNoMem]>;
+
+ def int_x86_avx512_mask_pshufl_w_512 :
+ GCCBuiltin<"__builtin_ia32_pshuflw512_mask">,
+ Intrinsic<[llvm_v32i16_ty],
+ [llvm_v32i16_ty, llvm_i8_ty, llvm_v32i16_ty, llvm_i32_ty],
+ [IntrNoMem]>;
+
def int_x86_avx512_mask_shuf_f32x4_256 :
GCCBuiltin<"__builtin_ia32_shuf_f32x4_256_mask">,
Intrinsic<[llvm_v8f32_ty],
@@ -1836,25 +1890,69 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.".
def int_x86_avx_maskload_ps_256 : GCCBuiltin<"__builtin_ia32_maskloadps256">,
Intrinsic<[llvm_v8f32_ty], [llvm_ptr_ty, llvm_v8i32_ty],
[IntrReadArgMem]>;
- def int_x86_avx512_mask_loadu_ps_512 : GCCBuiltin<"__builtin_ia32_loadups512_mask">,
- Intrinsic<[llvm_v16f32_ty], [llvm_ptr_ty, llvm_v16f32_ty, llvm_i16_ty],
- [IntrReadArgMem]>;
- def int_x86_avx512_mask_loadu_pd_512 : GCCBuiltin<"__builtin_ia32_loadupd512_mask">,
- Intrinsic<[llvm_v8f64_ty], [llvm_ptr_ty, llvm_v8f64_ty, llvm_i8_ty],
- [IntrReadArgMem]>;
- def int_x86_avx512_mask_load_ps_512 : GCCBuiltin<"__builtin_ia32_loadaps512_mask">,
- Intrinsic<[llvm_v16f32_ty], [llvm_ptr_ty, llvm_v16f32_ty, llvm_i16_ty],
- [IntrReadArgMem]>;
- def int_x86_avx512_mask_load_pd_512 : GCCBuiltin<"__builtin_ia32_loadapd512_mask">,
- Intrinsic<[llvm_v8f64_ty], [llvm_ptr_ty, llvm_v8f64_ty, llvm_i8_ty],
- [IntrReadArgMem]>;
- def int_x86_avx512_mask_move_ss : GCCBuiltin<"__builtin_ia32_movss_mask">,
- Intrinsic<[llvm_v4f32_ty], [llvm_v4f32_ty, llvm_v4f32_ty, llvm_v4f32_ty, llvm_i8_ty],
- [IntrNoMem]>;
- def int_x86_avx512_mask_move_sd : GCCBuiltin<"__builtin_ia32_movsd_mask">,
- Intrinsic<[llvm_v2f64_ty], [llvm_v2f64_ty, llvm_v2f64_ty, llvm_v2f64_ty, llvm_i8_ty],
- [IntrNoMem]>;
+ def int_x86_avx512_mask_loadu_ps_128 :
+ GCCBuiltin<"__builtin_ia32_loadups128_mask">,
+ Intrinsic<[llvm_v4f32_ty],
+ [llvm_ptr_ty, llvm_v4f32_ty, llvm_i8_ty], [IntrReadArgMem]>;
+ def int_x86_avx512_mask_loadu_ps_256 :
+ GCCBuiltin<"__builtin_ia32_loadups256_mask">,
+ Intrinsic<[llvm_v8f32_ty],
+ [llvm_ptr_ty, llvm_v8f32_ty, llvm_i8_ty], [IntrReadArgMem]>;
+ def int_x86_avx512_mask_loadu_ps_512 :
+ GCCBuiltin<"__builtin_ia32_loadups512_mask">,
+ Intrinsic<[llvm_v16f32_ty],
+ [llvm_ptr_ty, llvm_v16f32_ty, llvm_i16_ty], [IntrReadArgMem]>;
+
+ def int_x86_avx512_mask_loadu_pd_128 :
+ GCCBuiltin<"__builtin_ia32_loadupd128_mask">,
+ Intrinsic<[llvm_v2f64_ty],
+ [llvm_ptr_ty, llvm_v2f64_ty, llvm_i8_ty], [IntrReadArgMem]>;
+ def int_x86_avx512_mask_loadu_pd_256 :
+ GCCBuiltin<"__builtin_ia32_loadupd256_mask">,
+ Intrinsic<[llvm_v4f64_ty],
+ [llvm_ptr_ty, llvm_v4f64_ty, llvm_i8_ty], [IntrReadArgMem]>;
+ def int_x86_avx512_mask_loadu_pd_512 :
+ GCCBuiltin<"__builtin_ia32_loadupd512_mask">,
+ Intrinsic<[llvm_v8f64_ty],
+ [llvm_ptr_ty, llvm_v8f64_ty, llvm_i8_ty], [IntrReadArgMem]>;
+
+ def int_x86_avx512_mask_load_ps_128 :
+ GCCBuiltin<"__builtin_ia32_loadaps128_mask">,
+ Intrinsic<[llvm_v4f32_ty],
+ [llvm_ptr_ty, llvm_v4f32_ty, llvm_i8_ty], [IntrReadArgMem]>;
+ def int_x86_avx512_mask_load_ps_256 :
+ GCCBuiltin<"__builtin_ia32_loadaps256_mask">,
+ Intrinsic<[llvm_v8f32_ty],
+ [llvm_ptr_ty, llvm_v8f32_ty, llvm_i8_ty], [IntrReadArgMem]>;
+ def int_x86_avx512_mask_load_ps_512 :
+ GCCBuiltin<"__builtin_ia32_loadaps512_mask">,
+ Intrinsic<[llvm_v16f32_ty],
+ [llvm_ptr_ty, llvm_v16f32_ty, llvm_i16_ty], [IntrReadArgMem]>;
+
+ def int_x86_avx512_mask_load_pd_128 :
+ GCCBuiltin<"__builtin_ia32_loadapd128_mask">,
+ Intrinsic<[llvm_v2f64_ty],
+ [llvm_ptr_ty, llvm_v2f64_ty, llvm_i8_ty], [IntrReadArgMem]>;
+ def int_x86_avx512_mask_load_pd_256 :
+ GCCBuiltin<"__builtin_ia32_loadapd256_mask">,
+ Intrinsic<[llvm_v4f64_ty],
+ [llvm_ptr_ty, llvm_v4f64_ty, llvm_i8_ty], [IntrReadArgMem]>;
+ def int_x86_avx512_mask_load_pd_512 :
+ GCCBuiltin<"__builtin_ia32_loadapd512_mask">,
+ Intrinsic<[llvm_v8f64_ty],
+ [llvm_ptr_ty, llvm_v8f64_ty, llvm_i8_ty], [IntrReadArgMem]>;
+
+ def int_x86_avx512_mask_move_ss :
+ GCCBuiltin<"__builtin_ia32_movss_mask">,
+ Intrinsic<[llvm_v4f32_ty],
+ [llvm_v4f32_ty, llvm_v4f32_ty, llvm_v4f32_ty, llvm_i8_ty],
+ [IntrNoMem]>;
+ def int_x86_avx512_mask_move_sd :
+ GCCBuiltin<"__builtin_ia32_movsd_mask">,
+ Intrinsic<[llvm_v2f64_ty],
+ [llvm_v2f64_ty, llvm_v2f64_ty, llvm_v2f64_ty, llvm_i8_ty],
+ [IntrNoMem]>;
}
// Conditional store ops
@@ -2262,6 +2360,46 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.".
Intrinsic<[llvm_v8i64_ty], [llvm_v8i64_ty,
llvm_v2i64_ty, llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>;
+ def int_x86_avx512_mask_psll_w_128 : GCCBuiltin<"__builtin_ia32_psllw128_mask">,
+ Intrinsic<[llvm_v8i16_ty], [llvm_v8i16_ty,
+ llvm_v8i16_ty, llvm_v8i16_ty, llvm_i8_ty], [IntrNoMem]>;
+ def int_x86_avx512_mask_psll_w_256 : GCCBuiltin<"__builtin_ia32_psllw256_mask">,
+ Intrinsic<[llvm_v16i16_ty], [llvm_v16i16_ty,
+ llvm_v8i16_ty, llvm_v16i16_ty, llvm_i16_ty], [IntrNoMem]>;
+ def int_x86_avx512_mask_psll_w_512 : GCCBuiltin<"__builtin_ia32_psllw512_mask">,
+ Intrinsic<[llvm_v32i16_ty], [llvm_v32i16_ty,
+ llvm_v8i16_ty, llvm_v32i16_ty, llvm_i32_ty], [IntrNoMem]>;
+ def int_x86_avx512_mask_psll_wi_128 : GCCBuiltin<"__builtin_ia32_psllwi128_mask">,
+ Intrinsic<[llvm_v8i16_ty], [llvm_v8i16_ty,
+ llvm_i8_ty, llvm_v8i16_ty, llvm_i8_ty], [IntrNoMem]>;
+ def int_x86_avx512_mask_psll_wi_256 : GCCBuiltin<"__builtin_ia32_psllwi256_mask">,
+ Intrinsic<[llvm_v16i16_ty], [llvm_v16i16_ty,
+ llvm_i8_ty, llvm_v16i16_ty, llvm_i16_ty], [IntrNoMem]>;
+ def int_x86_avx512_mask_psll_wi_512 : GCCBuiltin<"__builtin_ia32_psllwi512_mask">,
+ Intrinsic<[llvm_v32i16_ty], [llvm_v32i16_ty,
+ llvm_i8_ty, llvm_v32i16_ty, llvm_i32_ty], [IntrNoMem]>;
+ def int_x86_avx512_mask_psllv16_hi : GCCBuiltin<"__builtin_ia32_psllv16hi_mask">,
+ Intrinsic<[llvm_v16i16_ty], [llvm_v16i16_ty,
+ llvm_v16i16_ty, llvm_v16i16_ty, llvm_i16_ty], [IntrNoMem]>;
+ def int_x86_avx512_mask_psllv2_di : GCCBuiltin<"__builtin_ia32_psllv2di_mask">,
+ Intrinsic<[llvm_v2i64_ty], [llvm_v2i64_ty,
+ llvm_v2i64_ty, llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>;
+ def int_x86_avx512_mask_psllv32hi : GCCBuiltin<"__builtin_ia32_psllv32hi_mask">,
+ Intrinsic<[llvm_v32i16_ty], [llvm_v32i16_ty,
+ llvm_v32i16_ty, llvm_v32i16_ty, llvm_i32_ty], [IntrNoMem]>;
+ def int_x86_avx512_mask_psllv4_di : GCCBuiltin<"__builtin_ia32_psllv4di_mask">,
+ Intrinsic<[llvm_v4i64_ty], [llvm_v4i64_ty,
+ llvm_v4i64_ty, llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>;
+ def int_x86_avx512_mask_psllv4_si : GCCBuiltin<"__builtin_ia32_psllv4si_mask">,
+ Intrinsic<[llvm_v4i32_ty], [llvm_v4i32_ty,
+ llvm_v4i32_ty, llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>;
+ def int_x86_avx512_mask_psllv8_hi : GCCBuiltin<"__builtin_ia32_psllv8hi_mask">,
+ Intrinsic<[llvm_v8i16_ty], [llvm_v8i16_ty,
+ llvm_v8i16_ty, llvm_v8i16_ty, llvm_i8_ty], [IntrNoMem]>;
+ def int_x86_avx512_mask_psllv8_si : GCCBuiltin<"__builtin_ia32_psllv8si_mask">,
+ Intrinsic<[llvm_v8i32_ty], [llvm_v8i32_ty,
+ llvm_v8i32_ty, llvm_v8i32_ty, llvm_i8_ty], [IntrNoMem]>;
+
def int_x86_avx512_mask_psra_d_128 : GCCBuiltin<"__builtin_ia32_psrad128_mask">,
Intrinsic<[llvm_v4i32_ty], [llvm_v4i32_ty,
llvm_v4i32_ty, llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>;
@@ -2823,6 +2961,28 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.".
Intrinsic<[llvm_v8i64_ty], [llvm_v8i64_ty,
llvm_i8_ty, llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>;
+ def int_x86_avx512_mask_psrav16_hi : GCCBuiltin<"__builtin_ia32_psrav16hi_mask">,
+ Intrinsic<[llvm_v16i16_ty], [llvm_v16i16_ty,
+ llvm_v16i16_ty, llvm_v16i16_ty, llvm_i16_ty], [IntrNoMem]>;
+ def int_x86_avx512_mask_psrav32_hi : GCCBuiltin<"__builtin_ia32_psrav32hi_mask">,
+ Intrinsic<[llvm_v32i16_ty], [llvm_v32i16_ty,
+ llvm_v32i16_ty, llvm_v32i16_ty, llvm_i32_ty], [IntrNoMem]>;
+ def int_x86_avx512_mask_psrav4_si : GCCBuiltin<"__builtin_ia32_psrav4si_mask">,
+ Intrinsic<[llvm_v4i32_ty], [llvm_v4i32_ty,
+ llvm_v4i32_ty, llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>;
+ def int_x86_avx512_mask_psrav8_hi : GCCBuiltin<"__builtin_ia32_psrav8hi_mask">,
+ Intrinsic<[llvm_v8i16_ty], [llvm_v8i16_ty,
+ llvm_v8i16_ty, llvm_v8i16_ty, llvm_i8_ty], [IntrNoMem]>;
+ def int_x86_avx512_mask_psrav8_si : GCCBuiltin<"__builtin_ia32_psrav8si_mask">,
+ Intrinsic<[llvm_v8i32_ty], [llvm_v8i32_ty,
+ llvm_v8i32_ty, llvm_v8i32_ty, llvm_i8_ty], [IntrNoMem]>;
+ def int_x86_avx512_mask_psrav_q_128 : GCCBuiltin<"__builtin_ia32_psravq128_mask">,
+ Intrinsic<[llvm_v2i64_ty], [llvm_v2i64_ty,
+ llvm_v2i64_ty, llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>;
+ def int_x86_avx512_mask_psrav_q_256 : GCCBuiltin<"__builtin_ia32_psravq256_mask">,
+ Intrinsic<[llvm_v4i64_ty], [llvm_v4i64_ty,
+ llvm_v4i64_ty, llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>;
+
def int_x86_avx512_mask_psrlv16_hi : GCCBuiltin<"__builtin_ia32_psrlv16hi_mask">,
Intrinsic<[llvm_v16i16_ty], [llvm_v16i16_ty,
llvm_v16i16_ty, llvm_v16i16_ty, llvm_i16_ty], [IntrNoMem]>;
@@ -2844,6 +3004,83 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.".
def int_x86_avx512_mask_psrlv8_si : GCCBuiltin<"__builtin_ia32_psrlv8si_mask">,
Intrinsic<[llvm_v8i32_ty], [llvm_v8i32_ty,
llvm_v8i32_ty, llvm_v8i32_ty, llvm_i8_ty], [IntrNoMem]>;
+
+ def int_x86_avx512_mask_prorv_d_128 : GCCBuiltin<"__builtin_ia32_prorvd128_mask">,
+ Intrinsic<[llvm_v4i32_ty], [llvm_v4i32_ty,
+ llvm_v4i32_ty, llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>;
+ def int_x86_avx512_mask_prorv_d_256 : GCCBuiltin<"__builtin_ia32_prorvd256_mask">,
+ Intrinsic<[llvm_v8i32_ty], [llvm_v8i32_ty,
+ llvm_v8i32_ty, llvm_v8i32_ty, llvm_i8_ty], [IntrNoMem]>;
+ def int_x86_avx512_mask_prorv_d_512 : GCCBuiltin<"__builtin_ia32_prorvd512_mask">,
+ Intrinsic<[llvm_v16i32_ty], [llvm_v16i32_ty,
+ llvm_v16i32_ty, llvm_v16i32_ty, llvm_i16_ty], [IntrNoMem]>;
+ def int_x86_avx512_mask_prorv_q_128 : GCCBuiltin<"__builtin_ia32_prorvq128_mask">,
+ Intrinsic<[llvm_v2i64_ty], [llvm_v2i64_ty,
+ llvm_v2i64_ty, llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>;
+ def int_x86_avx512_mask_prorv_q_256 : GCCBuiltin<"__builtin_ia32_prorvq256_mask">,
+ Intrinsic<[llvm_v4i64_ty], [llvm_v4i64_ty,
+ llvm_v4i64_ty, llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>;
+ def int_x86_avx512_mask_prorv_q_512 : GCCBuiltin<"__builtin_ia32_prorvq512_mask">,
+ Intrinsic<[llvm_v8i64_ty], [llvm_v8i64_ty,
+ llvm_v8i64_ty, llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>;
+
+ def int_x86_avx512_mask_prol_d_128 : GCCBuiltin<"__builtin_ia32_prold128_mask">,
+ Intrinsic<[llvm_v4i32_ty] , [llvm_v4i32_ty,
+ llvm_i8_ty, llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>;
+ def int_x86_avx512_mask_prol_d_256 : GCCBuiltin<"__builtin_ia32_prold256_mask">,
+ Intrinsic<[llvm_v8i32_ty] , [llvm_v8i32_ty,
+ llvm_i8_ty, llvm_v8i32_ty, llvm_i8_ty], [IntrNoMem]>;
+ def int_x86_avx512_mask_prol_d_512 : GCCBuiltin<"__builtin_ia32_prold512_mask">,
+ Intrinsic<[llvm_v16i32_ty] , [llvm_v16i32_ty,
+ llvm_i8_ty, llvm_v16i32_ty, llvm_i16_ty], [IntrNoMem]>;
+ def int_x86_avx512_mask_prol_q_128 : GCCBuiltin<"__builtin_ia32_prolq128_mask">,
+ Intrinsic<[llvm_v2i64_ty] , [llvm_v2i64_ty,
+ llvm_i8_ty, llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>;
+ def int_x86_avx512_mask_prol_q_256 : GCCBuiltin<"__builtin_ia32_prolq256_mask">,
+ Intrinsic<[llvm_v4i64_ty] , [llvm_v4i64_ty,
+ llvm_i8_ty, llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>;
+ def int_x86_avx512_mask_prol_q_512 : GCCBuiltin<"__builtin_ia32_prolq512_mask">,
+ Intrinsic<[llvm_v8i64_ty] , [llvm_v8i64_ty,
+ llvm_i8_ty, llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>;
+
+
+ def int_x86_avx512_mask_prolv_d_128 : GCCBuiltin<"__builtin_ia32_prolvd128_mask">,
+ Intrinsic<[llvm_v4i32_ty], [llvm_v4i32_ty,
+ llvm_v4i32_ty, llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>;
+ def int_x86_avx512_mask_prolv_d_256 : GCCBuiltin<"__builtin_ia32_prolvd256_mask">,
+ Intrinsic<[llvm_v8i32_ty], [llvm_v8i32_ty,
+ llvm_v8i32_ty, llvm_v8i32_ty, llvm_i8_ty], [IntrNoMem]>;
+ def int_x86_avx512_mask_prolv_d_512 : GCCBuiltin<"__builtin_ia32_prolvd512_mask">,
+ Intrinsic<[llvm_v16i32_ty], [llvm_v16i32_ty,
+ llvm_v16i32_ty, llvm_v16i32_ty, llvm_i16_ty], [IntrNoMem]>;
+ def int_x86_avx512_mask_prolv_q_128 : GCCBuiltin<"__builtin_ia32_prolvq128_mask">,
+ Intrinsic<[llvm_v2i64_ty], [llvm_v2i64_ty,
+ llvm_v2i64_ty, llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>;
+ def int_x86_avx512_mask_prolv_q_256 : GCCBuiltin<"__builtin_ia32_prolvq256_mask">,
+ Intrinsic<[llvm_v4i64_ty], [llvm_v4i64_ty,
+ llvm_v4i64_ty, llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>;
+ def int_x86_avx512_mask_prolv_q_512 : GCCBuiltin<"__builtin_ia32_prolvq512_mask">,
+ Intrinsic<[llvm_v8i64_ty], [llvm_v8i64_ty,
+ llvm_v8i64_ty, llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>;
+ def int_x86_avx512_mask_pror_d_128 : GCCBuiltin<"__builtin_ia32_prord128_mask">,
+ Intrinsic<[llvm_v4i32_ty], [llvm_v4i32_ty,
+ llvm_i8_ty, llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>;
+ def int_x86_avx512_mask_pror_d_256 : GCCBuiltin<"__builtin_ia32_prord256_mask">,
+ Intrinsic<[llvm_v8i32_ty], [llvm_v8i32_ty,
+ llvm_i8_ty, llvm_v8i32_ty, llvm_i8_ty], [IntrNoMem]>;
+ def int_x86_avx512_mask_pror_d_512 : GCCBuiltin<"__builtin_ia32_prord512_mask">,
+ Intrinsic<[llvm_v16i32_ty], [llvm_v16i32_ty,
+ llvm_i8_ty, llvm_v16i32_ty, llvm_i16_ty], [IntrNoMem]>;
+ def int_x86_avx512_mask_pror_q_128 : GCCBuiltin<"__builtin_ia32_prorq128_mask">,
+ Intrinsic<[llvm_v2i64_ty], [llvm_v2i64_ty,
+ llvm_i8_ty, llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>;
+ def int_x86_avx512_mask_pror_q_256 : GCCBuiltin<"__builtin_ia32_prorq256_mask">,
+ Intrinsic<[llvm_v4i64_ty], [llvm_v4i64_ty,
+ llvm_i8_ty, llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>;
+ def int_x86_avx512_mask_pror_q_512 : GCCBuiltin<"__builtin_ia32_prorq512_mask">,
+ Intrinsic<[llvm_v8i64_ty], [llvm_v8i64_ty,
+ llvm_i8_ty, llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>;
+
}
// Gather ops
@@ -4208,6 +4445,61 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.".
def int_x86_avx512_kortestc_w : GCCBuiltin<"__builtin_ia32_kortestchi">,
Intrinsic<[llvm_i32_ty], [llvm_i16_ty, llvm_i16_ty],
[IntrNoMem]>;
+
+ def int_x86_avx512_mask_pmovsxb_d_128 : GCCBuiltin<"__builtin_ia32_pmovsxbd128_mask">,
+ Intrinsic<[llvm_v4i32_ty], [llvm_v16i8_ty,
+ llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>;
+ def int_x86_avx512_mask_pmovsxb_d_256 : GCCBuiltin<"__builtin_ia32_pmovsxbd256_mask">,
+ Intrinsic<[llvm_v8i32_ty], [llvm_v16i8_ty,
+ llvm_v8i32_ty, llvm_i8_ty], [IntrNoMem]>;
+ def int_x86_avx512_mask_pmovsxb_d_512 : GCCBuiltin<"__builtin_ia32_pmovsxbd512_mask">,
+ Intrinsic<[llvm_v16i32_ty], [llvm_v16i8_ty,
+ llvm_v16i32_ty, llvm_i16_ty], [IntrNoMem]>;
+ def int_x86_avx512_mask_pmovsxb_q_128 : GCCBuiltin<"__builtin_ia32_pmovsxbq128_mask">,
+ Intrinsic<[llvm_v2i64_ty], [llvm_v16i8_ty,
+ llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>;
+ def int_x86_avx512_mask_pmovsxb_q_256 : GCCBuiltin<"__builtin_ia32_pmovsxbq256_mask">,
+ Intrinsic<[llvm_v4i64_ty], [llvm_v16i8_ty,
+ llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>;
+ def int_x86_avx512_mask_pmovsxb_q_512 : GCCBuiltin<"__builtin_ia32_pmovsxbq512_mask">,
+ Intrinsic<[llvm_v8i64_ty], [llvm_v16i8_ty,
+ llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>;
+ def int_x86_avx512_mask_pmovsxb_w_128 : GCCBuiltin<"__builtin_ia32_pmovsxbw128_mask">,
+ Intrinsic<[llvm_v8i16_ty], [llvm_v16i8_ty,
+ llvm_v8i16_ty, llvm_i8_ty], [IntrNoMem]>;
+ def int_x86_avx512_mask_pmovsxb_w_256 : GCCBuiltin<"__builtin_ia32_pmovsxbw256_mask">,
+ Intrinsic<[llvm_v16i16_ty], [llvm_v16i8_ty,
+ llvm_v16i16_ty, llvm_i16_ty], [IntrNoMem]>;
+ def int_x86_avx512_mask_pmovsxb_w_512 : GCCBuiltin<"__builtin_ia32_pmovsxbw512_mask">,
+ Intrinsic<[llvm_v32i16_ty], [llvm_v32i8_ty,
+ llvm_v32i16_ty, llvm_i32_ty], [IntrNoMem]>;
+ def int_x86_avx512_mask_pmovsxd_q_128 : GCCBuiltin<"__builtin_ia32_pmovsxdq128_mask">,
+ Intrinsic<[llvm_v2i64_ty], [llvm_v4i32_ty,
+ llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>;
+ def int_x86_avx512_mask_pmovsxd_q_256 : GCCBuiltin<"__builtin_ia32_pmovsxdq256_mask">,
+ Intrinsic<[llvm_v4i64_ty], [llvm_v4i32_ty,
+ llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>;
+ def int_x86_avx512_mask_pmovsxd_q_512 : GCCBuiltin<"__builtin_ia32_pmovsxdq512_mask">,
+ Intrinsic<[llvm_v8i64_ty], [llvm_v8i32_ty,
+ llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>;
+ def int_x86_avx512_mask_pmovsxw_d_128 : GCCBuiltin<"__builtin_ia32_pmovsxwd128_mask">,
+ Intrinsic<[llvm_v4i32_ty], [llvm_v8i16_ty,
+ llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>;
+ def int_x86_avx512_mask_pmovsxw_d_256 : GCCBuiltin<"__builtin_ia32_pmovsxwd256_mask">,
+ Intrinsic<[llvm_v8i32_ty], [llvm_v8i16_ty,
+ llvm_v8i32_ty, llvm_i8_ty], [IntrNoMem]>;
+ def int_x86_avx512_mask_pmovsxw_d_512 : GCCBuiltin<"__builtin_ia32_pmovsxwd512_mask">,
+ Intrinsic<[llvm_v16i32_ty], [llvm_v16i16_ty,
+ llvm_v16i32_ty, llvm_i16_ty], [IntrNoMem]>;
+ def int_x86_avx512_mask_pmovsxw_q_128 : GCCBuiltin<"__builtin_ia32_pmovsxwq128_mask">,
+ Intrinsic<[llvm_v2i64_ty], [llvm_v8i16_ty,
+ llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>;
+ def int_x86_avx512_mask_pmovsxw_q_256 : GCCBuiltin<"__builtin_ia32_pmovsxwq256_mask">,
+ Intrinsic<[llvm_v4i64_ty], [llvm_v8i16_ty,
+ llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>;
+ def int_x86_avx512_mask_pmovsxw_q_512 : GCCBuiltin<"__builtin_ia32_pmovsxwq512_mask">,
+ Intrinsic<[llvm_v8i64_ty], [llvm_v8i16_ty,
+ llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>;
}
// Conversion ops
@@ -5319,6 +5611,62 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.".
def int_x86_avx512_pmovzxdq : GCCBuiltin<"__builtin_ia32_pmovzxdq512">,
Intrinsic<[llvm_v8i64_ty], [llvm_v8i32_ty],
[IntrNoMem]>;
+
+ def int_x86_avx512_mask_pmovzxb_d_128 : GCCBuiltin<"__builtin_ia32_pmovzxbd128_mask">,
+ Intrinsic<[llvm_v4i32_ty], [llvm_v16i8_ty,
+ llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>;
+ def int_x86_avx512_mask_pmovzxb_d_256 : GCCBuiltin<"__builtin_ia32_pmovzxbd256_mask">,
+ Intrinsic<[llvm_v8i32_ty], [llvm_v16i8_ty,
+ llvm_v8i32_ty, llvm_i8_ty], [IntrNoMem]>;
+ def int_x86_avx512_mask_pmovzxb_d_512 : GCCBuiltin<"__builtin_ia32_pmovzxbd512_mask">,
+ Intrinsic<[llvm_v16i32_ty], [llvm_v16i8_ty,
+ llvm_v16i32_ty, llvm_i16_ty], [IntrNoMem]>;
+ def int_x86_avx512_mask_pmovzxb_q_128 : GCCBuiltin<"__builtin_ia32_pmovzxbq128_mask">,
+ Intrinsic<[llvm_v2i64_ty], [llvm_v16i8_ty,
+ llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>;
+ def int_x86_avx512_mask_pmovzxb_q_256 : GCCBuiltin<"__builtin_ia32_pmovzxbq256_mask">,
+ Intrinsic<[llvm_v4i64_ty], [llvm_v16i8_ty,
+ llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>;
+ def int_x86_avx512_mask_pmovzxb_q_512 : GCCBuiltin<"__builtin_ia32_pmovzxbq512_mask">,
+ Intrinsic<[llvm_v8i64_ty], [llvm_v16i8_ty,
+ llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>;
+ def int_x86_avx512_mask_pmovzxb_w_128 : GCCBuiltin<"__builtin_ia32_pmovzxbw128_mask">,
+ Intrinsic<[llvm_v8i16_ty], [llvm_v16i8_ty,
+ llvm_v8i16_ty, llvm_i8_ty], [IntrNoMem]>;
+ def int_x86_avx512_mask_pmovzxb_w_256 : GCCBuiltin<"__builtin_ia32_pmovzxbw256_mask">,
+ Intrinsic<[llvm_v16i16_ty], [llvm_v16i8_ty,
+ llvm_v16i16_ty, llvm_i16_ty], [IntrNoMem]>;
+ def int_x86_avx512_mask_pmovzxb_w_512 : GCCBuiltin<"__builtin_ia32_pmovzxbw512_mask">,
+ Intrinsic<[llvm_v32i16_ty], [llvm_v32i8_ty,
+ llvm_v32i16_ty, llvm_i32_ty], [IntrNoMem]>;
+ def int_x86_avx512_mask_pmovzxd_q_128 : GCCBuiltin<"__builtin_ia32_pmovzxdq128_mask">,
+ Intrinsic<[llvm_v2i64_ty], [llvm_v4i32_ty,
+ llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>;
+ def int_x86_avx512_mask_pmovzxd_q_256 : GCCBuiltin<"__builtin_ia32_pmovzxdq256_mask">,
+ Intrinsic<[llvm_v4i64_ty], [llvm_v4i32_ty,
+ llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>;
+ def int_x86_avx512_mask_pmovzxd_q_512 : GCCBuiltin<"__builtin_ia32_pmovzxdq512_mask">,
+ Intrinsic<[llvm_v8i64_ty], [llvm_v8i32_ty,
+ llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>;
+ def int_x86_avx512_mask_pmovzxw_d_128 : GCCBuiltin<"__builtin_ia32_pmovzxwd128_mask">,
+ Intrinsic<[llvm_v4i32_ty], [llvm_v8i16_ty,
+ llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>;
+ def int_x86_avx512_mask_pmovzxw_d_256 : GCCBuiltin<"__builtin_ia32_pmovzxwd256_mask">,
+ Intrinsic<[llvm_v8i32_ty], [llvm_v8i16_ty,
+ llvm_v8i32_ty, llvm_i8_ty], [IntrNoMem]>;
+ def int_x86_avx512_mask_pmovzxw_d_512 : GCCBuiltin<"__builtin_ia32_pmovzxwd512_mask">,
+ Intrinsic<[llvm_v16i32_ty], [llvm_v16i16_ty,
+ llvm_v16i32_ty, llvm_i16_ty], [IntrNoMem]>;
+ def int_x86_avx512_mask_pmovzxw_q_128 : GCCBuiltin<"__builtin_ia32_pmovzxwq128_mask">,
+ Intrinsic<[llvm_v2i64_ty], [llvm_v8i16_ty,
+ llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>;
+ def int_x86_avx512_mask_pmovzxw_q_256 : GCCBuiltin<"__builtin_ia32_pmovzxwq256_mask">,
+ Intrinsic<[llvm_v4i64_ty], [llvm_v8i16_ty,
+ llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>;
+ def int_x86_avx512_mask_pmovzxw_q_512 : GCCBuiltin<"__builtin_ia32_pmovzxwq512_mask">,
+ Intrinsic<[llvm_v8i64_ty], [llvm_v8i16_ty,
+ llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>;
+
}
//Bitwise Ops
let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.".
diff --git a/include/llvm/IR/LLVMContext.h b/include/llvm/IR/LLVMContext.h
index c546fc3d1ee0..56aa3010d925 100644
--- a/include/llvm/IR/LLVMContext.h
+++ b/include/llvm/IR/LLVMContext.h
@@ -93,6 +93,17 @@ public:
/// tag registered with an LLVMContext has an unique ID.
uint32_t getOperandBundleTagID(StringRef Tag) const;
+
+ /// Define the GC for a function
+ void setGC(const Function &Fn, std::string GCName);
+
+ /// Return the GC for a function
+ const std::string &getGC(const Function &Fn);
+
+ /// Remove the GC for a function
+ void deleteGC(const Function &Fn);
+
+
typedef void (*InlineAsmDiagHandlerTy)(const SMDiagnostic&, void *Context,
unsigned LocCookie);
diff --git a/include/llvm/IR/Metadata.h b/include/llvm/IR/Metadata.h
index 4a8557d074f0..df8ce354bb7f 100644
--- a/include/llvm/IR/Metadata.h
+++ b/include/llvm/IR/Metadata.h
@@ -915,11 +915,21 @@ public:
/// \brief Resolve cycles.
///
/// Once all forward declarations have been resolved, force cycles to be
- /// resolved. If \p AllowTemps is true, then any temporary metadata
- /// is ignored, otherwise it asserts when encountering temporary metadata.
+ /// resolved. This interface is used when there are no more temporaries,
+ /// and thus unresolved nodes are part of cycles and no longer need RAUW
+ /// support.
///
/// \pre No operands (or operands' operands, etc.) have \a isTemporary().
- void resolveCycles(bool AllowTemps = false);
+ void resolveCycles() { resolveRecursivelyImpl(/* AllowTemps */ false); }
+
+ /// \brief Resolve cycles while ignoring temporaries.
+ ///
+ /// This drops RAUW support for any temporaries, which can no longer
+ /// be uniqued.
+ ///
+ void resolveNonTemporaries() {
+ resolveRecursivelyImpl(/* AllowTemps */ true);
+ }
/// \brief Replace a temporary node with a permanent one.
///
@@ -977,6 +987,11 @@ private:
void decrementUnresolvedOperandCount();
unsigned countUnresolvedOperands();
+ /// Resolve cycles recursively. If \p AllowTemps is true, then any temporary
+ /// metadata is ignored, otherwise it asserts when encountering temporary
+ /// metadata.
+ void resolveRecursivelyImpl(bool AllowTemps);
+
/// \brief Mutate this to be "uniqued".
///
/// Mutate this so that \a isUniqued().
diff --git a/include/llvm/InitializePasses.h b/include/llvm/InitializePasses.h
index cb2b1394e92b..90fbc1d891b7 100644
--- a/include/llvm/InitializePasses.h
+++ b/include/llvm/InitializePasses.h
@@ -132,7 +132,6 @@ void initializeEarlyCSELegacyPassPass(PassRegistry &);
void initializeEliminateAvailableExternallyPass(PassRegistry&);
void initializeExpandISelPseudosPass(PassRegistry&);
void initializeForceFunctionAttrsLegacyPassPass(PassRegistry&);
-void initializeFunctionAttrsPass(PassRegistry&);
void initializeGCMachineCodeAnalysisPass(PassRegistry&);
void initializeGCModuleInfoPass(PassRegistry&);
void initializeGVNPass(PassRegistry&);
@@ -227,6 +226,7 @@ void initializePostDomOnlyViewerPass(PassRegistry&);
void initializePostDomPrinterPass(PassRegistry&);
void initializePostDomViewerPass(PassRegistry&);
void initializePostDominatorTreePass(PassRegistry&);
+void initializePostOrderFunctionAttrsPass(PassRegistry&);
void initializePostRASchedulerPass(PassRegistry&);
void initializePostMachineSchedulerPass(PassRegistry&);
void initializePrintFunctionPassWrapperPass(PassRegistry&);
@@ -242,6 +242,7 @@ void initializeRegionOnlyPrinterPass(PassRegistry&);
void initializeRegionOnlyViewerPass(PassRegistry&);
void initializeRegionPrinterPass(PassRegistry&);
void initializeRegionViewerPass(PassRegistry&);
+void initializeReversePostOrderFunctionAttrsPass(PassRegistry&);
void initializeRewriteStatepointsForGCPass(PassRegistry&);
void initializeSafeStackPass(PassRegistry&);
void initializeSCCPPass(PassRegistry&);
diff --git a/include/llvm/LinkAllPasses.h b/include/llvm/LinkAllPasses.h
index 29fcd93a2a1c..d695d11a6369 100644
--- a/include/llvm/LinkAllPasses.h
+++ b/include/llvm/LinkAllPasses.h
@@ -157,7 +157,8 @@ namespace {
(void) llvm::createPostDomTree();
(void) llvm::createInstructionNamerPass();
(void) llvm::createMetaRenamerPass();
- (void) llvm::createFunctionAttrsPass();
+ (void) llvm::createPostOrderFunctionAttrsPass();
+ (void) llvm::createReversePostOrderFunctionAttrsPass();
(void) llvm::createMergeFunctionsPass();
(void) llvm::createPrintModulePass(*(llvm::raw_ostream*)nullptr);
(void) llvm::createPrintFunctionPass(*(llvm::raw_ostream*)nullptr);
diff --git a/include/llvm/Linker/Linker.h b/include/llvm/Linker/Linker.h
index dde3f73883ca..2b051e6d15c9 100644
--- a/include/llvm/Linker/Linker.h
+++ b/include/llvm/Linker/Linker.h
@@ -67,10 +67,9 @@ public:
DenseMap<unsigned, MDNode *> *ValIDToTempMDMap);
};
-/// Create a new module with exported local functions renamed and promoted
-/// for ThinLTO.
-std::unique_ptr<Module> renameModuleForThinLTO(std::unique_ptr<Module> M,
- const FunctionInfoIndex *Index);
+/// Perform in-place global value handling on the given Module for
+/// exported local functions renamed and promoted for ThinLTO.
+bool renameModuleForThinLTO(Module &M, const FunctionInfoIndex *Index);
} // End llvm namespace
diff --git a/include/llvm/MC/MCExpr.h b/include/llvm/MC/MCExpr.h
index 1d6bdef0af27..f6ccdc095551 100644
--- a/include/llvm/MC/MCExpr.h
+++ b/include/llvm/MC/MCExpr.h
@@ -290,6 +290,9 @@ public:
VK_Hexagon_LD_PLT,
VK_Hexagon_IE,
VK_Hexagon_IE_GOT,
+
+ VK_WebAssembly_FUNCTION, // Function table index, rather than virtual addr
+
VK_TPREL,
VK_DTPREL
};
diff --git a/include/llvm/MC/MCObjectFileInfo.h b/include/llvm/MC/MCObjectFileInfo.h
index cf2c3f12bb6b..8a3a6af3bf79 100644
--- a/include/llvm/MC/MCObjectFileInfo.h
+++ b/include/llvm/MC/MCObjectFileInfo.h
@@ -92,6 +92,7 @@ protected:
MCSection *DwarfLocSection;
MCSection *DwarfARangesSection;
MCSection *DwarfRangesSection;
+ MCSection *DwarfMacinfoSection;
// The pubnames section is no longer generated by default. The generation
// can be enabled by a compiler flag.
MCSection *DwarfPubNamesSection;
@@ -245,6 +246,7 @@ public:
MCSection *getDwarfLocSection() const { return DwarfLocSection; }
MCSection *getDwarfARangesSection() const { return DwarfARangesSection; }
MCSection *getDwarfRangesSection() const { return DwarfRangesSection; }
+ MCSection *getDwarfMacinfoSection() const { return DwarfMacinfoSection; }
// DWARF5 Experimental Debug Info Sections
MCSection *getDwarfAccelNamesSection() const {
diff --git a/include/llvm/MC/MCStreamer.h b/include/llvm/MC/MCStreamer.h
index 494f02dfad3e..04d143ffef66 100644
--- a/include/llvm/MC/MCStreamer.h
+++ b/include/llvm/MC/MCStreamer.h
@@ -131,6 +131,10 @@ public:
void finish() override;
+ /// Reset any state between object emissions, i.e. the equivalent of
+ /// MCStreamer's reset method.
+ virtual void reset();
+
/// Callback used to implement the ldr= pseudo.
/// Add a new entry to the constant pool for the current section and return an
/// MCExpr that can be used to refer to the constant pool location.
diff --git a/include/llvm/Object/COFF.h b/include/llvm/Object/COFF.h
index 1b0e2e36bd5e..3e69c3e6e5d4 100644
--- a/include/llvm/Object/COFF.h
+++ b/include/llvm/Object/COFF.h
@@ -858,6 +858,9 @@ public:
std::error_code getExportRVA(uint32_t &Result) const;
std::error_code getSymbolName(StringRef &Result) const;
+ std::error_code isForwarder(bool &Result) const;
+ std::error_code getForwardTo(StringRef &Result) const;
+
private:
const export_directory_table_entry *ExportTable;
uint32_t Index;
diff --git a/include/llvm/Object/ELFObjectFile.h b/include/llvm/Object/ELFObjectFile.h
index 5823848aaacb..5d826da4c2fc 100644
--- a/include/llvm/Object/ELFObjectFile.h
+++ b/include/llvm/Object/ELFObjectFile.h
@@ -842,6 +842,8 @@ StringRef ELFObjectFile<ELFT>::getFileFormatName() const {
case ELF::EM_SPARC:
case ELF::EM_SPARC32PLUS:
return "ELF32-sparc";
+ case ELF::EM_WEBASSEMBLY:
+ return "ELF32-wasm";
default:
return "ELF32-unknown";
}
@@ -861,6 +863,8 @@ StringRef ELFObjectFile<ELFT>::getFileFormatName() const {
return "ELF64-sparc";
case ELF::EM_MIPS:
return "ELF64-mips";
+ case ELF::EM_WEBASSEMBLY:
+ return "ELF64-wasm";
default:
return "ELF64-unknown";
}
@@ -908,6 +912,12 @@ unsigned ELFObjectFile<ELFT>::getArch() const {
return IsLittleEndian ? Triple::sparcel : Triple::sparc;
case ELF::EM_SPARCV9:
return Triple::sparcv9;
+ case ELF::EM_WEBASSEMBLY:
+ switch (EF.getHeader()->e_ident[ELF::EI_CLASS]) {
+ case ELF::ELFCLASS32: return Triple::wasm32;
+ case ELF::ELFCLASS64: return Triple::wasm64;
+ default: return Triple::UnknownArch;
+ }
default:
return Triple::UnknownArch;
diff --git a/include/llvm/Pass.h b/include/llvm/Pass.h
index 3c4d838a4652..99604cdbc9ca 100644
--- a/include/llvm/Pass.h
+++ b/include/llvm/Pass.h
@@ -369,6 +369,10 @@ protected:
/// @brief This is the storage for the -time-passes option.
extern bool TimePassesIsEnabled;
+/// isFunctionInPrintList - returns true if a function should be printed via
+// debugging options like -print-after-all/-print-before-all.
+// @brief Tells if the function IR should be printed by PrinterPass.
+extern bool isFunctionInPrintList(StringRef FunctionName);
} // End llvm namespace
// Include support files that contain important APIs commonly used by Passes,
diff --git a/include/llvm/ProfileData/CoverageMapping.h b/include/llvm/ProfileData/CoverageMapping.h
index 3790e1358449..92a991eb39ba 100644
--- a/include/llvm/ProfileData/CoverageMapping.h
+++ b/include/llvm/ProfileData/CoverageMapping.h
@@ -20,13 +20,34 @@
#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/Triple.h"
#include "llvm/ADT/iterator.h"
+#include "llvm/ProfileData/InstrProf.h"
#include "llvm/Support/Debug.h"
+#include "llvm/Support/Endian.h"
#include "llvm/Support/ErrorOr.h"
#include "llvm/Support/raw_ostream.h"
#include <system_error>
#include <tuple>
namespace llvm {
+namespace coverage {
+enum class coveragemap_error {
+ success = 0,
+ eof,
+ no_data_found,
+ unsupported_version,
+ truncated,
+ malformed
+};
+} // end of coverage namespace.
+}
+
+namespace std {
+template <>
+struct is_error_code_enum<llvm::coverage::coveragemap_error> : std::true_type {
+};
+}
+
+namespace llvm {
class IndexedInstrProfReader;
namespace coverage {
@@ -35,8 +56,6 @@ class CoverageMappingReader;
class CoverageMapping;
struct CounterExpressions;
-enum CoverageMappingVersion { CoverageMappingVersion1 };
-
/// \brief A Counter is an abstract value that describes how to compute the
/// execution count for a region of code using the collected profile count data.
struct Counter {
@@ -454,6 +473,76 @@ public:
CoverageData getCoverageForExpansion(const ExpansionRecord &Expansion);
};
+const std::error_category &coveragemap_category();
+
+inline std::error_code make_error_code(coveragemap_error E) {
+ return std::error_code(static_cast<int>(E), coveragemap_category());
+}
+
+// Profile coverage map has the following layout:
+// [CoverageMapFileHeader]
+// [ArrayStart]
+// [CovMapFunctionRecord]
+// [CovMapFunctionRecord]
+// ...
+// [ArrayEnd]
+// [Encoded Region Mapping Data]
+LLVM_PACKED_START
+template <class IntPtrT> struct CovMapFunctionRecord {
+#define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Init) Type Name;
+#include "llvm/ProfileData/InstrProfData.inc"
+
+ // Return the structural hash associated with the function.
+ template <support::endianness Endian> uint64_t getFuncHash() const {
+ return support::endian::byte_swap<uint64_t, Endian>(FuncHash);
+ }
+ // Return the coverage map data size for the funciton.
+ template <support::endianness Endian> uint32_t getDataSize() const {
+ return support::endian::byte_swap<uint32_t, Endian>(DataSize);
+ }
+ // Return function lookup key. The value is consider opaque.
+ template <support::endianness Endian> IntPtrT getFuncNameRef() const {
+ return support::endian::byte_swap<IntPtrT, Endian>(NamePtr);
+ }
+ // Return the PGO name of the function */
+ template <support::endianness Endian>
+ std::error_code getFuncName(InstrProfSymtab &ProfileNames,
+ StringRef &FuncName) const {
+ IntPtrT NameRef = getFuncNameRef<Endian>();
+ uint32_t NameS = support::endian::byte_swap<uint32_t, Endian>(NameSize);
+ FuncName = ProfileNames.getFuncName(NameRef, NameS);
+ if (NameS && FuncName.empty())
+ return coveragemap_error::malformed;
+ return std::error_code();
+ }
+};
+// Per module coverage mapping data header, i.e. CoverageMapFileHeader
+// documented above.
+struct CovMapHeader {
+#define COVMAP_HEADER(Type, LLVMType, Name, Init) Type Name;
+#include "llvm/ProfileData/InstrProfData.inc"
+ template <support::endianness Endian> uint32_t getNRecords() const {
+ return support::endian::byte_swap<uint32_t, Endian>(NRecords);
+ }
+ template <support::endianness Endian> uint32_t getFilenamesSize() const {
+ return support::endian::byte_swap<uint32_t, Endian>(FilenamesSize);
+ }
+ template <support::endianness Endian> uint32_t getCoverageSize() const {
+ return support::endian::byte_swap<uint32_t, Endian>(CoverageSize);
+ }
+ template <support::endianness Endian> uint32_t getVersion() const {
+ return support::endian::byte_swap<uint32_t, Endian>(Version);
+ }
+};
+
+LLVM_PACKED_END
+
+enum CoverageMappingVersion {
+ CoverageMappingVersion1 = 0,
+ // The current versin is Version1
+ CoverageMappingCurrentVersion = INSTR_PROF_COVMAP_VERSION
+};
+
} // end namespace coverage
/// \brief Provide DenseMapInfo for CounterExpression
@@ -484,26 +573,6 @@ template<> struct DenseMapInfo<coverage::CounterExpression> {
}
};
-const std::error_category &coveragemap_category();
-
-enum class coveragemap_error {
- success = 0,
- eof,
- no_data_found,
- unsupported_version,
- truncated,
- malformed
-};
-
-inline std::error_code make_error_code(coveragemap_error E) {
- return std::error_code(static_cast<int>(E), coveragemap_category());
-}
-
} // end namespace llvm
-namespace std {
-template <>
-struct is_error_code_enum<llvm::coveragemap_error> : std::true_type {};
-}
-
#endif // LLVM_PROFILEDATA_COVERAGEMAPPING_H_
diff --git a/include/llvm/ProfileData/InstrProf.h b/include/llvm/ProfileData/InstrProf.h
index 49569d89507b..c84d8d24f206 100644
--- a/include/llvm/ProfileData/InstrProf.h
+++ b/include/llvm/ProfileData/InstrProf.h
@@ -30,7 +30,6 @@
#include <system_error>
#include <vector>
-#define INSTR_PROF_INDEX_VERSION 3
namespace llvm {
class Function;
@@ -66,7 +65,8 @@ inline StringRef getInstrProfValueProfFuncName() {
/// Return the name of the section containing function coverage mapping
/// data.
inline StringRef getInstrProfCoverageSectionName(bool AddSegment) {
- return AddSegment ? "__DATA,__llvm_covmap" : "__llvm_covmap";
+ return AddSegment ? "__DATA," INSTR_PROF_COVMAP_SECT_NAME_STR
+ : INSTR_PROF_COVMAP_SECT_NAME_STR;
}
/// Return the name prefix of variables containing instrumented function names.
@@ -89,6 +89,12 @@ inline StringRef getCoverageMappingVarName() {
return "__llvm_coverage_mapping";
}
+/// Return the name of the internal variable recording the array
+/// of PGO name vars referenced by the coverage mapping, The owning
+/// functions of those names are not emitted by FE (e.g, unused inline
+/// functions.)
+inline StringRef getCoverageNamesVarName() { return "__llvm_coverage_names"; }
+
/// Return the name of function that registers all the per-function control
/// data at program startup time by calling __llvm_register_function. This
/// function has internal linkage and is called by __llvm_profile_init
@@ -349,11 +355,14 @@ struct InstrProfValueSiteRecord {
return left.Value < right.Value;
});
}
+ /// Sort ValueData Descending by Count
+ inline void sortByCount();
/// Merge data from another InstrProfValueSiteRecord
/// Optionally scale merged counts by \p Weight.
- instrprof_error mergeValueData(InstrProfValueSiteRecord &Input,
- uint64_t Weight = 1);
+ instrprof_error merge(InstrProfValueSiteRecord &Input, uint64_t Weight = 1);
+ /// Scale up value profile data counts.
+ instrprof_error scale(uint64_t Weight);
};
/// Profiling information for a single function.
@@ -396,6 +405,19 @@ struct InstrProfRecord {
/// Optionally scale merged counts by \p Weight.
instrprof_error merge(InstrProfRecord &Other, uint64_t Weight = 1);
+ /// Scale up profile counts (including value profile data) by
+ /// \p Weight.
+ instrprof_error scale(uint64_t Weight);
+
+ /// Sort value profile data (per site) by count.
+ void sortValueData() {
+ for (uint32_t Kind = IPVK_First; Kind <= IPVK_Last; ++Kind) {
+ std::vector<InstrProfValueSiteRecord> &SiteRecords =
+ getValueSitesForKind(Kind);
+ for (auto &SR : SiteRecords)
+ SR.sortByCount();
+ }
+ }
/// Clear value data entries
void clearValueData() {
for (uint32_t Kind = IPVK_First; Kind <= IPVK_Last; ++Kind)
@@ -430,6 +452,8 @@ private:
// Scale merged value counts by \p Weight.
instrprof_error mergeValueProfData(uint32_t ValueKind, InstrProfRecord &Src,
uint64_t Weight);
+ // Scale up value profile data count.
+ instrprof_error scaleValueProfData(uint32_t ValueKind, uint64_t Weight);
};
uint32_t InstrProfRecord::getNumValueKinds() const {
@@ -497,11 +521,22 @@ inline support::endianness getHostEndianness() {
#define INSTR_PROF_VALUE_PROF_DATA
#include "llvm/ProfileData/InstrProfData.inc"
- /*
- * Initialize the record for runtime value profile data.
- * Return 0 if the initialization is successful, otherwise
- * return 1.
- */
+void InstrProfValueSiteRecord::sortByCount() {
+ ValueData.sort(
+ [](const InstrProfValueData &left, const InstrProfValueData &right) {
+ return left.Count > right.Count;
+ });
+ // Now truncate
+ size_t max_s = INSTR_PROF_MAX_NUM_VAL_PER_SITE;
+ if (ValueData.size() > max_s)
+ ValueData.resize(max_s);
+}
+
+/*
+* Initialize the record for runtime value profile data.
+* Return 0 if the initialization is successful, otherwise
+* return 1.
+*/
int initializeValueProfRuntimeRecord(ValueProfRuntimeRecord *RuntimeRecord,
const uint16_t *NumValueSites,
ValueProfNode **Nodes);
@@ -597,31 +632,6 @@ struct Header {
} // end namespace RawInstrProf
-namespace coverage {
-
-// Profile coverage map has the following layout:
-// [CoverageMapFileHeader]
-// [ArrayStart]
-// [CovMapFunctionRecord]
-// [CovMapFunctionRecord]
-// ...
-// [ArrayEnd]
-// [Encoded Region Mapping Data]
-LLVM_PACKED_START
-template <class IntPtrT> struct CovMapFunctionRecord {
- #define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Init) Type Name;
- #include "llvm/ProfileData/InstrProfData.inc"
-};
-// Per module coverage mapping data header, i.e. CoverageMapFileHeader
-// documented above.
-struct CovMapHeader {
-#define COVMAP_HEADER(Type, LLVMType, Name, Init) Type Name;
-#include "llvm/ProfileData/InstrProfData.inc"
-};
-
-LLVM_PACKED_END
-}
-
} // end namespace llvm
namespace std {
diff --git a/include/llvm/ProfileData/InstrProfData.inc b/include/llvm/ProfileData/InstrProfData.inc
index 3a7c0c5f2773..33c7d94aea2a 100644
--- a/include/llvm/ProfileData/InstrProfData.inc
+++ b/include/llvm/ProfileData/InstrProfData.inc
@@ -28,7 +28,7 @@
*
* Examples of how the template is used to instantiate structure definition:
* 1. To declare a structure:
- *
+ *
* struct ProfData {
* #define INSTR_PROF_DATA(Type, LLVMType, Name, Initializer) \
* Type Name;
@@ -155,7 +155,7 @@ VALUE_PROF_KIND(IPVK_Last, IPVK_IndirectCallTarget)
#endif
COVMAP_FUNC_RECORD(const IntPtrT, llvm::Type::getInt8PtrTy(Ctx), \
NamePtr, llvm::ConstantExpr::getBitCast(NamePtr, \
- llvm::Type::getInt8PtrTy(Ctx)))
+ llvm::Type::getInt8PtrTy(Ctx)))
COVMAP_FUNC_RECORD(const uint32_t, llvm::Type::getInt32Ty(Ctx), NameSize, \
llvm::ConstantInt::get(llvm::Type::getInt32Ty(Ctx),\
NameValue.size()))
@@ -182,7 +182,7 @@ COVMAP_HEADER(uint32_t, Int32Ty, FilenamesSize, \
COVMAP_HEADER(uint32_t, Int32Ty, CoverageSize, \
llvm::ConstantInt::get(Int32Ty, CoverageMappingSize))
COVMAP_HEADER(uint32_t, Int32Ty, Version, \
- llvm::ConstantInt::get(Int32Ty, CoverageMappingVersion1))
+ llvm::ConstantInt::get(Int32Ty, CoverageMappingCurrentVersion))
#undef COVMAP_HEADER
/* COVMAP_HEADER end. */
@@ -190,7 +190,8 @@ COVMAP_HEADER(uint32_t, Int32Ty, Version, \
#ifdef INSTR_PROF_VALUE_PROF_DATA
#define INSTR_PROF_DATA_DEFINED
-/*!
+#define INSTR_PROF_MAX_NUM_VAL_PER_SITE 255
+/*!
* This is the header of the data structure that defines the on-disk
* layout of the value profile data of a particular kind for one function.
*/
@@ -202,7 +203,7 @@ typedef struct ValueProfRecord {
* otherwise the record for this kind won't be emitted.
*/
uint32_t NumValueSites;
- /*
+ /*
* The first element of the array that stores the number of profiled
* values for each value site. The size of the array is NumValueSites.
* Since NumValueSites is greater than zero, there is at least one
@@ -226,7 +227,7 @@ typedef struct ValueProfRecord {
* \brief Return the number of value sites.
*/
uint32_t getNumValueSites() const { return NumValueSites; }
- /*!
+ /*!
* \brief Read data from this record and save it to Record.
*/
void deserializeTo(InstrProfRecord &Record,
@@ -247,10 +248,10 @@ typedef struct ValueProfRecord {
typedef struct ValueProfData {
/*
* Total size in bytes including this field. It must be a multiple
- * of sizeof(uint64_t).
+ * of sizeof(uint64_t).
*/
uint32_t TotalSize;
- /*
+ /*
*The number of value profile kinds that has value profile data.
* In this implementation, a value profile kind is considered to
* have profile data if the number of value profile sites for the
@@ -260,7 +261,7 @@ typedef struct ValueProfData {
*/
uint32_t NumValueKinds;
- /*
+ /*
* Following are a sequence of variable length records. The prefix/header
* of each record is defined by ValueProfRecord type. The number of
* records is NumValueKinds.
@@ -314,7 +315,7 @@ typedef struct ValueProfData {
#endif
} ValueProfData;
-/*
+/*
* The closure is designed to abstact away two types of value profile data:
* - InstrProfRecord which is the primary data structure used to
* represent profile data in host tools (reader, writer, and profile-use)
@@ -335,7 +336,7 @@ typedef struct ValueProfRecordClosure {
uint32_t (*GetNumValueData)(const void *Record, uint32_t VKind);
uint32_t (*GetNumValueDataForSite)(const void *R, uint32_t VK, uint32_t S);
- /*
+ /*
* After extracting the value profile data from the value profile record,
* this method is used to map the in-memory value to on-disk value. If
* the method is null, value will be written out untranslated.
@@ -346,7 +347,7 @@ typedef struct ValueProfRecordClosure {
ValueProfData *(*AllocValueProfData)(size_t TotalSizeInBytes);
} ValueProfRecordClosure;
-/*
+/*
* A wrapper struct that represents value profile runtime data.
* Like InstrProfRecord class which is used by profiling host tools,
* ValueProfRuntimeRecord also implements the abstract intefaces defined in
@@ -384,7 +385,7 @@ serializeValueProfDataFromRT(const ValueProfRuntimeRecord *Record,
uint32_t getNumValueKindsRT(const void *R);
#undef INSTR_PROF_VALUE_PROF_DATA
-#endif /* INSTR_PROF_VALUE_PROF_DATA */
+#endif /* INSTR_PROF_VALUE_PROF_DATA */
#ifdef INSTR_PROF_COMMON_API_IMPL
@@ -412,7 +413,7 @@ uint32_t getValueProfRecordHeaderSize(uint32_t NumValueSites) {
return Size;
}
-/*!
+/*!
* \brief Return the total size of the value profile record including the
* header and the value data.
*/
@@ -432,7 +433,7 @@ InstrProfValueData *getValueProfRecordValueData(ValueProfRecord *This) {
This->NumValueSites));
}
-/*!
+/*!
* \brief Return the total number of value data for \c This record.
*/
INSTR_PROF_INLINE
@@ -444,7 +445,7 @@ uint32_t getValueProfRecordNumValueData(ValueProfRecord *This) {
return NumValueData;
}
-/*!
+/*!
* \brief Use this method to advance to the next \c This \c ValueProfRecord.
*/
INSTR_PROF_INLINE
@@ -465,7 +466,7 @@ ValueProfRecord *getFirstValueProfRecord(ValueProfData *This) {
/* Closure based interfaces. */
-/*!
+/*!
* Return the total size in bytes of the on-disk value profile data
* given the data stored in Record.
*/
@@ -535,7 +536,7 @@ ValueProfData *serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
return VPD;
}
-/*
+/*
* The value profiler runtime library stores the value profile data
* for a given function in \c NumValueSites and \c Nodes structures.
* \c ValueProfRuntimeRecord class is used to encapsulate the runtime
@@ -639,7 +640,7 @@ static ValueProfRecordClosure RTRecordClosure = {0,
getValueForSiteRT,
allocValueProfDataRT};
-/*
+/*
* Return the size of ValueProfData structure to store data
* recorded in the runtime record.
*/
@@ -648,7 +649,7 @@ uint32_t getValueProfDataSizeRT(const ValueProfRuntimeRecord *Record) {
return getValueProfDataSize(&RTRecordClosure);
}
-/*
+/*
* Return a ValueProfData instance that stores the data collected
* from runtime. If \c DstData is provided by the caller, the value
* profile data will be store in *DstData and DstData is returned,
@@ -696,18 +697,31 @@ serializeValueProfDataFromRT(const ValueProfRuntimeRecord *Record,
/* Raw profile format version. */
#define INSTR_PROF_RAW_VERSION 2
+#define INSTR_PROF_INDEX_VERSION 3
+#define INSTR_PROF_COVMAP_VERSION 0
+
+/* Profile version is always of type uint_64_t. Reserve the upper 8 bits in the
+ * version for other variants of profile. We set the lowest bit of the upper 8
+ * bits (i.e. bit 56) to 1 to indicate if this is an IR-level instrumentaiton
+ * generated profile, and 0 if this is a Clang FE generated profile.
+*/
+#define VARIANT_MASKS_ALL 0xff00000000000000ULL
+#define GET_VERSION(V) ((V) & ~VARIANT_MASKS_ALL)
/* Runtime section names and name strings. */
#define INSTR_PROF_DATA_SECT_NAME __llvm_prf_data
#define INSTR_PROF_NAME_SECT_NAME __llvm_prf_names
#define INSTR_PROF_CNTS_SECT_NAME __llvm_prf_cnts
+#define INSTR_PROF_COVMAP_SECT_NAME __llvm_covmap
-#define INSTR_PROF_DATA_SECT_NAME_STR \
- INSTR_PROF_QUOTE(INSTR_PROF_DATA_SECT_NAME)
-#define INSTR_PROF_NAME_SECT_NAME_STR \
- INSTR_PROF_QUOTE(INSTR_PROF_NAME_SECT_NAME)
-#define INSTR_PROF_CNTS_SECT_NAME_STR \
- INSTR_PROF_QUOTE(INSTR_PROF_CNTS_SECT_NAME)
+#define INSTR_PROF_DATA_SECT_NAME_STR \
+ INSTR_PROF_QUOTE(INSTR_PROF_DATA_SECT_NAME)
+#define INSTR_PROF_NAME_SECT_NAME_STR \
+ INSTR_PROF_QUOTE(INSTR_PROF_NAME_SECT_NAME)
+#define INSTR_PROF_CNTS_SECT_NAME_STR \
+ INSTR_PROF_QUOTE(INSTR_PROF_CNTS_SECT_NAME)
+#define INSTR_PROF_COVMAP_SECT_NAME_STR \
+ INSTR_PROF_QUOTE(INSTR_PROF_COVMAP_SECT_NAME)
/* Macros to define start/stop section symbol for a given
* section on Linux. For instance
@@ -751,4 +765,3 @@ typedef struct ValueProfNode {
#else
#undef INSTR_PROF_DATA_DEFINED
#endif
-
diff --git a/include/llvm/ProfileData/SampleProf.h b/include/llvm/ProfileData/SampleProf.h
index 8df3fe803209..6c39cf9458dc 100644
--- a/include/llvm/ProfileData/SampleProf.h
+++ b/include/llvm/ProfileData/SampleProf.h
@@ -140,16 +140,9 @@ public:
/// around unsigned integers.
sampleprof_error addSamples(uint64_t S, uint64_t Weight = 1) {
bool Overflowed;
- if (Weight > 1) {
- S = SaturatingMultiply(S, Weight, &Overflowed);
- if (Overflowed)
- return sampleprof_error::counter_overflow;
- }
- NumSamples = SaturatingAdd(NumSamples, S, &Overflowed);
- if (Overflowed)
- return sampleprof_error::counter_overflow;
-
- return sampleprof_error::success;
+ NumSamples = SaturatingMultiplyAdd(S, Weight, NumSamples, &Overflowed);
+ return Overflowed ? sampleprof_error::counter_overflow
+ : sampleprof_error::success;
}
/// Add called function \p F with samples \p S.
@@ -161,16 +154,10 @@ public:
uint64_t Weight = 1) {
uint64_t &TargetSamples = CallTargets[F];
bool Overflowed;
- if (Weight > 1) {
- S = SaturatingMultiply(S, Weight, &Overflowed);
- if (Overflowed)
- return sampleprof_error::counter_overflow;
- }
- TargetSamples = SaturatingAdd(TargetSamples, S, &Overflowed);
- if (Overflowed)
- return sampleprof_error::counter_overflow;
-
- return sampleprof_error::success;
+ TargetSamples =
+ SaturatingMultiplyAdd(S, Weight, TargetSamples, &Overflowed);
+ return Overflowed ? sampleprof_error::counter_overflow
+ : sampleprof_error::success;
}
/// Return true if this sample record contains function calls.
@@ -215,29 +202,17 @@ public:
void dump() const;
sampleprof_error addTotalSamples(uint64_t Num, uint64_t Weight = 1) {
bool Overflowed;
- if (Weight > 1) {
- Num = SaturatingMultiply(Num, Weight, &Overflowed);
- if (Overflowed)
- return sampleprof_error::counter_overflow;
- }
- TotalSamples = SaturatingAdd(TotalSamples, Num, &Overflowed);
- if (Overflowed)
- return sampleprof_error::counter_overflow;
-
- return sampleprof_error::success;
+ TotalSamples =
+ SaturatingMultiplyAdd(Num, Weight, TotalSamples, &Overflowed);
+ return Overflowed ? sampleprof_error::counter_overflow
+ : sampleprof_error::success;
}
sampleprof_error addHeadSamples(uint64_t Num, uint64_t Weight = 1) {
bool Overflowed;
- if (Weight > 1) {
- Num = SaturatingMultiply(Num, Weight, &Overflowed);
- if (Overflowed)
- return sampleprof_error::counter_overflow;
- }
- TotalHeadSamples = SaturatingAdd(TotalHeadSamples, Num, &Overflowed);
- if (Overflowed)
- return sampleprof_error::counter_overflow;
-
- return sampleprof_error::success;
+ TotalHeadSamples =
+ SaturatingMultiplyAdd(Num, Weight, TotalHeadSamples, &Overflowed);
+ return Overflowed ? sampleprof_error::counter_overflow
+ : sampleprof_error::success;
}
sampleprof_error addBodySamples(uint32_t LineOffset, uint32_t Discriminator,
uint64_t Num, uint64_t Weight = 1) {
diff --git a/include/llvm/Support/ARMTargetParser.def b/include/llvm/Support/ARMTargetParser.def
index c895b095bc5b..d94a51b8bcf9 100644
--- a/include/llvm/Support/ARMTargetParser.def
+++ b/include/llvm/Support/ARMTargetParser.def
@@ -96,7 +96,7 @@ ARM_ARCH("iwmmxt", AK_IWMMXT, "iwmmxt", "", ARMBuildAttrs::CPUArch::v5TE,
FK_NONE, AEK_NONE)
ARM_ARCH("iwmmxt2", AK_IWMMXT2, "iwmmxt2", "", ARMBuildAttrs::CPUArch::v5TE,
FK_NONE, AEK_NONE)
-ARM_ARCH("xscale", AK_XSCALE, "xscale", "", ARMBuildAttrs::CPUArch::v5TE,
+ARM_ARCH("xscale", AK_XSCALE, "xscale", "v5e", ARMBuildAttrs::CPUArch::v5TE,
FK_NONE, AEK_NONE)
ARM_ARCH("armv7s", AK_ARMV7S, "7-S", "v7s", ARMBuildAttrs::CPUArch::v7,
FK_NEON_VFPV4, AEK_DSP)
diff --git a/include/llvm/Support/Allocator.h b/include/llvm/Support/Allocator.h
index c608736fa956..043d82314609 100644
--- a/include/llvm/Support/Allocator.h
+++ b/include/llvm/Support/Allocator.h
@@ -187,6 +187,7 @@ public:
/// \brief Deallocate all but the current slab and reset the current pointer
/// to the beginning of it, freeing all memory allocated so far.
void Reset() {
+ // Deallocate all but the first slab, and deallocate all custom-sized slabs.
DeallocateCustomSizedSlabs();
CustomSizedSlabs.clear();
@@ -198,7 +199,7 @@ public:
CurPtr = (char *)Slabs.front();
End = CurPtr + SlabSize;
- // Deallocate all but the first slab, and deallocate all custom-sized slabs.
+ __asan_poison_memory_region(*Slabs.begin(), computeSlabSize(0));
DeallocateSlabs(std::next(Slabs.begin()), Slabs.end());
Slabs.erase(std::next(Slabs.begin()), Slabs.end());
}
diff --git a/include/llvm/Support/COFF.h b/include/llvm/Support/COFF.h
index 0162175efe3e..0245632c96a0 100644
--- a/include/llvm/Support/COFF.h
+++ b/include/llvm/Support/COFF.h
@@ -656,6 +656,15 @@ namespace COFF {
}
};
+ enum CodeViewLine : unsigned {
+ CVL_LineNumberStartBits = 24,
+ CVL_LineNumberEndDeltaBits = 7,
+ CVL_LineNumberEndDeltaMask = (1U << CVL_LineNumberEndDeltaBits) - 1,
+ CVL_MaxLineNumber = (1U << CVL_LineNumberStartBits) - 1,
+ CVL_IsStatement = 1U << 31,
+ CVL_MaxColumnNumber = UINT16_MAX,
+ };
+
enum CodeViewIdentifiers {
DEBUG_LINE_TABLES_HAVE_COLUMN_RECORDS = 0x1,
DEBUG_SECTION_MAGIC = 0x4,
diff --git a/include/llvm/Support/ELF.h b/include/llvm/Support/ELF.h
index 97708a7cdd63..e24420fc1fe4 100644
--- a/include/llvm/Support/ELF.h
+++ b/include/llvm/Support/ELF.h
@@ -309,7 +309,12 @@ enum {
EM_COOL = 217, // iCelero CoolEngine
EM_NORC = 218, // Nanoradio Optimized RISC
EM_CSR_KALIMBA = 219, // CSR Kalimba architecture family
- EM_AMDGPU = 224 // AMD GPU architecture
+ EM_AMDGPU = 224, // AMD GPU architecture
+
+ // A request has been made to the maintainer of the official registry for
+ // such numbers for an official value for WebAssembly. As soon as one is
+ // allocated, this enum will be updated to use it.
+ EM_WEBASSEMBLY = 0x4157, // WebAssembly architecture
};
// Object file classes.
@@ -594,6 +599,11 @@ enum {
#include "ELFRelocs/Sparc.def"
};
+// ELF Relocation types for WebAssembly
+enum {
+#include "ELFRelocs/WebAssembly.def"
+};
+
#undef ELF_RELOC
// Section header.
@@ -1024,7 +1034,10 @@ enum {
PT_AMDGPU_HSA_LOAD_GLOBAL_PROGRAM = 0x60000000,
PT_AMDGPU_HSA_LOAD_GLOBAL_AGENT = 0x60000001,
PT_AMDGPU_HSA_LOAD_READONLY_AGENT = 0x60000002,
- PT_AMDGPU_HSA_LOAD_CODE_AGENT = 0x60000003
+ PT_AMDGPU_HSA_LOAD_CODE_AGENT = 0x60000003,
+
+ // WebAssembly program header types.
+ PT_WEBASSEMBLY_FUNCTIONS = PT_LOPROC + 0, // Function definitions.
};
// Segment flag bits.
diff --git a/include/llvm/Support/ELFRelocs/WebAssembly.def b/include/llvm/Support/ELFRelocs/WebAssembly.def
new file mode 100644
index 000000000000..9a34349efb96
--- /dev/null
+++ b/include/llvm/Support/ELFRelocs/WebAssembly.def
@@ -0,0 +1,8 @@
+
+#ifndef ELF_RELOC
+#error "ELF_RELOC must be defined"
+#endif
+
+ELF_RELOC(R_WEBASSEMBLY_NONE, 0)
+ELF_RELOC(R_WEBASSEMBLY_DATA, 1)
+ELF_RELOC(R_WEBASSEMBLY_FUNCTION, 2)
diff --git a/include/llvm/Support/GenericDomTree.h b/include/llvm/Support/GenericDomTree.h
index 8751f272cd29..8bae582d18c7 100644
--- a/include/llvm/Support/GenericDomTree.h
+++ b/include/llvm/Support/GenericDomTree.h
@@ -724,25 +724,17 @@ public:
if (!this->IsPostDominators) {
// Initialize root
NodeT *entry = TraitsTy::getEntryNode(&F);
- this->Roots.push_back(entry);
- this->IDoms[entry] = nullptr;
- this->DomTreeNodes[entry] = nullptr;
+ addRoot(entry);
Calculate<FT, NodeT *>(*this, F);
} else {
// Initialize the roots list
for (typename TraitsTy::nodes_iterator I = TraitsTy::nodes_begin(&F),
E = TraitsTy::nodes_end(&F);
- I != E; ++I) {
+ I != E; ++I)
if (TraitsTy::child_begin(&*I) == TraitsTy::child_end(&*I))
addRoot(&*I);
- // Prepopulate maps so that we don't get iterator invalidation issues
- // later.
- this->IDoms[&*I] = nullptr;
- this->DomTreeNodes[&*I] = nullptr;
- }
-
Calculate<FT, Inverse<NodeT *>>(*this, F);
}
}
diff --git a/include/llvm/Support/MathExtras.h b/include/llvm/Support/MathExtras.h
index 8111aeebe6ee..408ae3c339a2 100644
--- a/include/llvm/Support/MathExtras.h
+++ b/include/llvm/Support/MathExtras.h
@@ -717,6 +717,25 @@ SaturatingMultiply(T X, T Y, bool *ResultOverflowed = nullptr) {
return Z;
}
+/// \brief Multiply two unsigned integers, X and Y, and add the unsigned
+/// integer, A to the product. Clamp the result to the maximum representable
+/// value of T on overflow. ResultOverflowed indicates if the result is larger
+/// than the maximum representable value of type T.
+/// Note that this is purely a convenience function as there is no distinction
+/// where overflow occurred in a 'fused' multiply-add for unsigned numbers.
+template <typename T>
+typename std::enable_if<std::is_unsigned<T>::value, T>::type
+SaturatingMultiplyAdd(T X, T Y, T A, bool *ResultOverflowed = nullptr) {
+ bool Dummy;
+ bool &Overflowed = ResultOverflowed ? *ResultOverflowed : Dummy;
+
+ T Product = SaturatingMultiply(X, Y, &Overflowed);
+ if (Overflowed)
+ return Product;
+
+ return SaturatingAdd(A, Product, &Overflowed);
+}
+
extern const float huge_valf;
} // End llvm namespace
diff --git a/include/llvm/Transforms/IPO.h b/include/llvm/Transforms/IPO.h
index 0c374a070ce8..78d2fadc5190 100644
--- a/include/llvm/Transforms/IPO.h
+++ b/include/llvm/Transforms/IPO.h
@@ -183,12 +183,20 @@ ModulePass *createBlockExtractorPass();
ModulePass *createStripDeadPrototypesPass();
//===----------------------------------------------------------------------===//
-/// createFunctionAttrsPass - This pass discovers functions that do not access
-/// memory, or only read memory, and gives them the readnone/readonly attribute.
-/// It also discovers function arguments that are not captured by the function
-/// and marks them with the nocapture attribute.
+/// createPostOrderFunctionAttrsPass - This pass walks SCCs of the call graph
+/// in post-order to deduce and propagate function attributes. It can discover
+/// functions that do not access memory, or only read memory, and give them the
+/// readnone/readonly attribute. It also discovers function arguments that are
+/// not captured by the function and marks them with the nocapture attribute.
///
-Pass *createFunctionAttrsPass();
+Pass *createPostOrderFunctionAttrsPass();
+
+//===----------------------------------------------------------------------===//
+/// createReversePostOrderFunctionAttrsPass - This pass walks SCCs of the call
+/// graph in RPO to deduce and propagate function attributes. Currently it
+/// only handles synthesizing norecurse attributes.
+///
+Pass *createReversePostOrderFunctionAttrsPass();
//===----------------------------------------------------------------------===//
/// createMergeFunctionsPass - This pass discovers identical functions and
diff --git a/include/llvm/Transforms/Utils/Cloning.h b/include/llvm/Transforms/Utils/Cloning.h
index 92a1d52f1011..4f006f2adeef 100644
--- a/include/llvm/Transforms/Utils/Cloning.h
+++ b/include/llvm/Transforms/Utils/Cloning.h
@@ -147,42 +147,12 @@ void CloneFunctionInto(Function *NewFunc, const Function *OldFunc,
ValueMapTypeRemapper *TypeMapper = nullptr,
ValueMaterializer *Materializer = nullptr);
-/// A helper class used with CloneAndPruneIntoFromInst to change the default
-/// behavior while instructions are being cloned.
-class CloningDirector {
-public:
- /// This enumeration describes the way CloneAndPruneIntoFromInst should
- /// proceed after the CloningDirector has examined an instruction.
- enum CloningAction {
- ///< Continue cloning the instruction (default behavior).
- CloneInstruction,
- ///< Skip this instruction but continue cloning the current basic block.
- SkipInstruction,
- ///< Skip this instruction and stop cloning the current basic block.
- StopCloningBB,
- ///< Don't clone the terminator but clone the current block's successors.
- CloneSuccessors
- };
-
- virtual ~CloningDirector() {}
-
- /// Subclasses must override this function to customize cloning behavior.
- virtual CloningAction handleInstruction(ValueToValueMapTy &VMap,
- const Instruction *Inst,
- BasicBlock *NewBB) = 0;
-
- virtual ValueMapTypeRemapper *getTypeRemapper() { return nullptr; }
- virtual ValueMaterializer *getValueMaterializer() { return nullptr; }
-};
-
void CloneAndPruneIntoFromInst(Function *NewFunc, const Function *OldFunc,
const Instruction *StartingInst,
ValueToValueMapTy &VMap, bool ModuleLevelChanges,
- SmallVectorImpl<ReturnInst*> &Returns,
- const char *NameSuffix = "",
- ClonedCodeInfo *CodeInfo = nullptr,
- CloningDirector *Director = nullptr);
-
+ SmallVectorImpl<ReturnInst *> &Returns,
+ const char *NameSuffix = "",
+ ClonedCodeInfo *CodeInfo = nullptr);
/// CloneAndPruneFunctionInto - This works exactly like CloneFunctionInto,
/// except that it does some simple constant prop and DCE on the fly. The
diff --git a/include/llvm/Transforms/Utils/Local.h b/include/llvm/Transforms/Utils/Local.h
index 81b376f0c212..911c6f14da0b 100644
--- a/include/llvm/Transforms/Utils/Local.h
+++ b/include/llvm/Transforms/Utils/Local.h
@@ -42,6 +42,7 @@ class TargetLibraryInfo;
class TargetTransformInfo;
class DIBuilder;
class DominatorTree;
+class LazyValueInfo;
template<typename T> class SmallVectorImpl;
@@ -303,7 +304,7 @@ void removeUnwindEdge(BasicBlock *BB);
/// \brief Remove all blocks that can not be reached from the function's entry.
///
/// Returns true if any basic block was removed.
-bool removeUnreachableBlocks(Function &F);
+bool removeUnreachableBlocks(Function &F, LazyValueInfo *LVI = nullptr);
/// \brief Combine the metadata of two instructions so that K can replace J
///
diff --git a/include/llvm/module.modulemap b/include/llvm/module.modulemap
index 0adce0c9602d..d74ada6faa61 100644
--- a/include/llvm/module.modulemap
+++ b/include/llvm/module.modulemap
@@ -207,6 +207,7 @@ module LLVM_Utils {
textual header "Support/ELFRelocs/Sparc.def"
textual header "Support/ELFRelocs/SystemZ.def"
textual header "Support/ELFRelocs/x86_64.def"
+ textual header "Support/ELFRelocs/WebAssembly.def"
}
// This part of the module is usable from both C and C++ code.
diff --git a/lib/Analysis/BasicAliasAnalysis.cpp b/lib/Analysis/BasicAliasAnalysis.cpp
index 85404d87a611..c3d280350b90 100644
--- a/lib/Analysis/BasicAliasAnalysis.cpp
+++ b/lib/Analysis/BasicAliasAnalysis.cpp
@@ -586,8 +586,13 @@ FunctionModRefBehavior BasicAAResult::getModRefBehavior(const Function *F) {
return FunctionModRefBehavior(AAResultBase::getModRefBehavior(F) & Min);
}
-ModRefInfo BasicAAResult::getArgModRefInfo(ImmutableCallSite CS,
- unsigned ArgIdx) {
+/// Returns true if this is a writeonly (i.e Mod only) parameter. Currently,
+/// we don't have a writeonly attribute, so this only knows about builtin
+/// intrinsics and target library functions. We could consider adding a
+/// writeonly attribute in the future and moving all of these facts to either
+/// Intrinsics.td or InferFunctionAttr.cpp
+static bool isWriteOnlyParam(ImmutableCallSite CS, unsigned ArgIdx,
+ const TargetLibraryInfo &TLI) {
if (const IntrinsicInst *II = dyn_cast<IntrinsicInst>(CS.getInstruction()))
switch (II->getIntrinsicID()) {
default:
@@ -597,9 +602,9 @@ ModRefInfo BasicAAResult::getArgModRefInfo(ImmutableCallSite CS,
case Intrinsic::memmove:
// We don't currently have a writeonly attribute. All other properties
// of these intrinsics are nicely described via attributes in
- // Intrinsics.td and handled generically below.
+ // Intrinsics.td and handled generically.
if (ArgIdx == 0)
- return MRI_Mod;
+ return true;
}
// We can bound the aliasing properties of memset_pattern16 just as we can
@@ -609,7 +614,22 @@ ModRefInfo BasicAAResult::getArgModRefInfo(ImmutableCallSite CS,
// handled via InferFunctionAttr.
if (CS.getCalledFunction() && isMemsetPattern16(CS.getCalledFunction(), TLI))
if (ArgIdx == 0)
- return MRI_Mod;
+ return true;
+
+ // TODO: memset_pattern4, memset_pattern8
+ // TODO: _chk variants
+ // TODO: strcmp, strcpy
+
+ return false;
+}
+
+ModRefInfo BasicAAResult::getArgModRefInfo(ImmutableCallSite CS,
+ unsigned ArgIdx) {
+
+ // Emulate the missing writeonly attribute by checking for known builtin
+ // intrinsics and target library functions.
+ if (isWriteOnlyParam(CS, ArgIdx, TLI))
+ return MRI_Mod;
if (CS.paramHasAttr(ArgIdx + 1, Attribute::ReadOnly))
return MRI_Ref;
diff --git a/lib/Analysis/CallGraphSCCPass.cpp b/lib/Analysis/CallGraphSCCPass.cpp
index 07b389a2a139..6dd1d0a066b6 100644
--- a/lib/Analysis/CallGraphSCCPass.cpp
+++ b/lib/Analysis/CallGraphSCCPass.cpp
@@ -612,9 +612,10 @@ namespace {
bool runOnSCC(CallGraphSCC &SCC) override {
Out << Banner;
for (CallGraphNode *CGN : SCC) {
- if (CGN->getFunction())
- CGN->getFunction()->print(Out);
- else
+ if (CGN->getFunction()) {
+ if (isFunctionInPrintList(CGN->getFunction()->getName()))
+ CGN->getFunction()->print(Out);
+ } else
Out << "\nPrinting <null> Function\n";
}
return false;
diff --git a/lib/Analysis/GlobalsModRef.cpp b/lib/Analysis/GlobalsModRef.cpp
index 249f3954d554..1babb822074b 100644
--- a/lib/Analysis/GlobalsModRef.cpp
+++ b/lib/Analysis/GlobalsModRef.cpp
@@ -358,21 +358,6 @@ bool GlobalsAAResult::AnalyzeUsesOfPointer(Value *V,
if (CS.isArgOperand(&U) && isFreeCall(I, &TLI)) {
if (Writers)
Writers->insert(CS->getParent()->getParent());
- } else if (CS.doesNotCapture(CS.getDataOperandNo(&U))) {
- Function *ParentF = CS->getParent()->getParent();
- // A nocapture argument may be read from or written to, but does not
- // escape unless the call can somehow recurse.
- //
- // nocapture "indicates that the callee does not make any copies of
- // the pointer that outlive itself". Therefore if we directly or
- // indirectly recurse, we must treat the pointer as escaping.
- if (FunctionToSCCMap[ParentF] ==
- FunctionToSCCMap[CS.getCalledFunction()])
- return true;
- if (Readers)
- Readers->insert(ParentF);
- if (Writers)
- Writers->insert(ParentF);
} else {
return true; // Argument of an unknown call.
}
diff --git a/lib/Analysis/InstructionSimplify.cpp b/lib/Analysis/InstructionSimplify.cpp
index b89ff268d11e..6dfe62596275 100644
--- a/lib/Analysis/InstructionSimplify.cpp
+++ b/lib/Analysis/InstructionSimplify.cpp
@@ -70,7 +70,7 @@ static Value *SimplifyOrInst(Value *, Value *, const Query &, unsigned);
static Value *SimplifyXorInst(Value *, Value *, const Query &, unsigned);
static Value *SimplifyTruncInst(Value *, Type *, const Query &, unsigned);
-/// getFalse - For a boolean type, or a vector of boolean type, return false, or
+/// For a boolean type, or a vector of boolean type, return false, or
/// a vector with every element false, as appropriate for the type.
static Constant *getFalse(Type *Ty) {
assert(Ty->getScalarType()->isIntegerTy(1) &&
@@ -78,7 +78,7 @@ static Constant *getFalse(Type *Ty) {
return Constant::getNullValue(Ty);
}
-/// getTrue - For a boolean type, or a vector of boolean type, return true, or
+/// For a boolean type, or a vector of boolean type, return true, or
/// a vector with every element true, as appropriate for the type.
static Constant *getTrue(Type *Ty) {
assert(Ty->getScalarType()->isIntegerTy(1) &&
@@ -100,7 +100,7 @@ static bool isSameCompare(Value *V, CmpInst::Predicate Pred, Value *LHS,
CRHS == LHS;
}
-/// ValueDominatesPHI - Does the given value dominate the specified phi node?
+/// Does the given value dominate the specified phi node?
static bool ValueDominatesPHI(Value *V, PHINode *P, const DominatorTree *DT) {
Instruction *I = dyn_cast<Instruction>(V);
if (!I)
@@ -131,8 +131,8 @@ static bool ValueDominatesPHI(Value *V, PHINode *P, const DominatorTree *DT) {
return false;
}
-/// ExpandBinOp - Simplify "A op (B op' C)" by distributing op over op', turning
-/// it into "(A op B) op' (A op C)". Here "op" is given by Opcode and "op'" is
+/// Simplify "A op (B op' C)" by distributing op over op', turning it into
+/// "(A op B) op' (A op C)". Here "op" is given by Opcode and "op'" is
/// given by OpcodeToExpand, while "A" corresponds to LHS and "B op' C" to RHS.
/// Also performs the transform "(A op' B) op C" -> "(A op C) op' (B op C)".
/// Returns the simplified value, or null if no simplification was performed.
@@ -193,8 +193,8 @@ static Value *ExpandBinOp(unsigned Opcode, Value *LHS, Value *RHS,
return nullptr;
}
-/// SimplifyAssociativeBinOp - Generic simplifications for associative binary
-/// operations. Returns the simpler value, or null if none was found.
+/// Generic simplifications for associative binary operations.
+/// Returns the simpler value, or null if none was found.
static Value *SimplifyAssociativeBinOp(unsigned Opc, Value *LHS, Value *RHS,
const Query &Q, unsigned MaxRecurse) {
Instruction::BinaryOps Opcode = (Instruction::BinaryOps)Opc;
@@ -290,10 +290,10 @@ static Value *SimplifyAssociativeBinOp(unsigned Opc, Value *LHS, Value *RHS,
return nullptr;
}
-/// ThreadBinOpOverSelect - In the case of a binary operation with a select
-/// instruction as an operand, try to simplify the binop by seeing whether
-/// evaluating it on both branches of the select results in the same value.
-/// Returns the common value if so, otherwise returns null.
+/// In the case of a binary operation with a select instruction as an operand,
+/// try to simplify the binop by seeing whether evaluating it on both branches
+/// of the select results in the same value. Returns the common value if so,
+/// otherwise returns null.
static Value *ThreadBinOpOverSelect(unsigned Opcode, Value *LHS, Value *RHS,
const Query &Q, unsigned MaxRecurse) {
// Recursion is always used, so bail out at once if we already hit the limit.
@@ -362,10 +362,9 @@ static Value *ThreadBinOpOverSelect(unsigned Opcode, Value *LHS, Value *RHS,
return nullptr;
}
-/// ThreadCmpOverSelect - In the case of a comparison with a select instruction,
-/// try to simplify the comparison by seeing whether both branches of the select
-/// result in the same value. Returns the common value if so, otherwise returns
-/// null.
+/// In the case of a comparison with a select instruction, try to simplify the
+/// comparison by seeing whether both branches of the select result in the same
+/// value. Returns the common value if so, otherwise returns null.
static Value *ThreadCmpOverSelect(CmpInst::Predicate Pred, Value *LHS,
Value *RHS, const Query &Q,
unsigned MaxRecurse) {
@@ -444,10 +443,10 @@ static Value *ThreadCmpOverSelect(CmpInst::Predicate Pred, Value *LHS,
return nullptr;
}
-/// ThreadBinOpOverPHI - In the case of a binary operation with an operand that
-/// is a PHI instruction, try to simplify the binop by seeing whether evaluating
-/// it on the incoming phi values yields the same result for every value. If so
-/// returns the common value, otherwise returns null.
+/// In the case of a binary operation with an operand that is a PHI instruction,
+/// try to simplify the binop by seeing whether evaluating it on the incoming
+/// phi values yields the same result for every value. If so returns the common
+/// value, otherwise returns null.
static Value *ThreadBinOpOverPHI(unsigned Opcode, Value *LHS, Value *RHS,
const Query &Q, unsigned MaxRecurse) {
// Recursion is always used, so bail out at once if we already hit the limit.
@@ -486,10 +485,10 @@ static Value *ThreadBinOpOverPHI(unsigned Opcode, Value *LHS, Value *RHS,
return CommonValue;
}
-/// ThreadCmpOverPHI - In the case of a comparison with a PHI instruction, try
-/// try to simplify the comparison by seeing whether comparing with all of the
-/// incoming phi values yields the same result every time. If so returns the
-/// common result, otherwise returns null.
+/// In the case of a comparison with a PHI instruction, try to simplify the
+/// comparison by seeing whether comparing with all of the incoming phi values
+/// yields the same result every time. If so returns the common result,
+/// otherwise returns null.
static Value *ThreadCmpOverPHI(CmpInst::Predicate Pred, Value *LHS, Value *RHS,
const Query &Q, unsigned MaxRecurse) {
// Recursion is always used, so bail out at once if we already hit the limit.
@@ -524,8 +523,8 @@ static Value *ThreadCmpOverPHI(CmpInst::Predicate Pred, Value *LHS, Value *RHS,
return CommonValue;
}
-/// SimplifyAddInst - Given operands for an Add, see if we can
-/// fold the result. If not, this returns null.
+/// Given operands for an Add, see if we can fold the result.
+/// If not, this returns null.
static Value *SimplifyAddInst(Value *Op0, Value *Op1, bool isNSW, bool isNUW,
const Query &Q, unsigned MaxRecurse) {
if (Constant *CLHS = dyn_cast<Constant>(Op0)) {
@@ -656,8 +655,8 @@ static Constant *computePointerDifference(const DataLayout &DL, Value *LHS,
return ConstantExpr::getSub(LHSOffset, RHSOffset);
}
-/// SimplifySubInst - Given operands for a Sub, see if we can
-/// fold the result. If not, this returns null.
+/// Given operands for a Sub, see if we can fold the result.
+/// If not, this returns null.
static Value *SimplifySubInst(Value *Op0, Value *Op1, bool isNSW, bool isNUW,
const Query &Q, unsigned MaxRecurse) {
if (Constant *CLHS = dyn_cast<Constant>(Op0))
@@ -889,8 +888,8 @@ static Value *SimplifyFMulInst(Value *Op0, Value *Op1,
return nullptr;
}
-/// SimplifyMulInst - Given operands for a Mul, see if we can
-/// fold the result. If not, this returns null.
+/// Given operands for a Mul, see if we can fold the result.
+/// If not, this returns null.
static Value *SimplifyMulInst(Value *Op0, Value *Op1, const Query &Q,
unsigned MaxRecurse) {
if (Constant *CLHS = dyn_cast<Constant>(Op0)) {
@@ -989,8 +988,8 @@ Value *llvm::SimplifyMulInst(Value *Op0, Value *Op1, const DataLayout &DL,
RecursionLimit);
}
-/// SimplifyDiv - Given operands for an SDiv or UDiv, see if we can
-/// fold the result. If not, this returns null.
+/// Given operands for an SDiv or UDiv, see if we can fold the result.
+/// If not, this returns null.
static Value *SimplifyDiv(Instruction::BinaryOps Opcode, Value *Op0, Value *Op1,
const Query &Q, unsigned MaxRecurse) {
if (Constant *C0 = dyn_cast<Constant>(Op0)) {
@@ -1075,8 +1074,8 @@ static Value *SimplifyDiv(Instruction::BinaryOps Opcode, Value *Op0, Value *Op1,
return nullptr;
}
-/// SimplifySDivInst - Given operands for an SDiv, see if we can
-/// fold the result. If not, this returns null.
+/// Given operands for an SDiv, see if we can fold the result.
+/// If not, this returns null.
static Value *SimplifySDivInst(Value *Op0, Value *Op1, const Query &Q,
unsigned MaxRecurse) {
if (Value *V = SimplifyDiv(Instruction::SDiv, Op0, Op1, Q, MaxRecurse))
@@ -1093,8 +1092,8 @@ Value *llvm::SimplifySDivInst(Value *Op0, Value *Op1, const DataLayout &DL,
RecursionLimit);
}
-/// SimplifyUDivInst - Given operands for a UDiv, see if we can
-/// fold the result. If not, this returns null.
+/// Given operands for a UDiv, see if we can fold the result.
+/// If not, this returns null.
static Value *SimplifyUDivInst(Value *Op0, Value *Op1, const Query &Q,
unsigned MaxRecurse) {
if (Value *V = SimplifyDiv(Instruction::UDiv, Op0, Op1, Q, MaxRecurse))
@@ -1154,8 +1153,8 @@ Value *llvm::SimplifyFDivInst(Value *Op0, Value *Op1, FastMathFlags FMF,
RecursionLimit);
}
-/// SimplifyRem - Given operands for an SRem or URem, see if we can
-/// fold the result. If not, this returns null.
+/// Given operands for an SRem or URem, see if we can fold the result.
+/// If not, this returns null.
static Value *SimplifyRem(Instruction::BinaryOps Opcode, Value *Op0, Value *Op1,
const Query &Q, unsigned MaxRecurse) {
if (Constant *C0 = dyn_cast<Constant>(Op0)) {
@@ -1215,8 +1214,8 @@ static Value *SimplifyRem(Instruction::BinaryOps Opcode, Value *Op0, Value *Op1,
return nullptr;
}
-/// SimplifySRemInst - Given operands for an SRem, see if we can
-/// fold the result. If not, this returns null.
+/// Given operands for an SRem, see if we can fold the result.
+/// If not, this returns null.
static Value *SimplifySRemInst(Value *Op0, Value *Op1, const Query &Q,
unsigned MaxRecurse) {
if (Value *V = SimplifyRem(Instruction::SRem, Op0, Op1, Q, MaxRecurse))
@@ -1233,8 +1232,8 @@ Value *llvm::SimplifySRemInst(Value *Op0, Value *Op1, const DataLayout &DL,
RecursionLimit);
}
-/// SimplifyURemInst - Given operands for a URem, see if we can
-/// fold the result. If not, this returns null.
+/// Given operands for a URem, see if we can fold the result.
+/// If not, this returns null.
static Value *SimplifyURemInst(Value *Op0, Value *Op1, const Query &Q,
unsigned MaxRecurse) {
if (Value *V = SimplifyRem(Instruction::URem, Op0, Op1, Q, MaxRecurse))
@@ -1279,7 +1278,7 @@ Value *llvm::SimplifyFRemInst(Value *Op0, Value *Op1, FastMathFlags FMF,
RecursionLimit);
}
-/// isUndefShift - Returns true if a shift by \c Amount always yields undef.
+/// Returns true if a shift by \c Amount always yields undef.
static bool isUndefShift(Value *Amount) {
Constant *C = dyn_cast<Constant>(Amount);
if (!C)
@@ -1306,8 +1305,8 @@ static bool isUndefShift(Value *Amount) {
return false;
}
-/// SimplifyShift - Given operands for an Shl, LShr or AShr, see if we can
-/// fold the result. If not, this returns null.
+/// Given operands for an Shl, LShr or AShr, see if we can fold the result.
+/// If not, this returns null.
static Value *SimplifyShift(unsigned Opcode, Value *Op0, Value *Op1,
const Query &Q, unsigned MaxRecurse) {
if (Constant *C0 = dyn_cast<Constant>(Op0)) {
@@ -1375,8 +1374,8 @@ static Value *SimplifyRightShift(unsigned Opcode, Value *Op0, Value *Op1,
return nullptr;
}
-/// SimplifyShlInst - Given operands for an Shl, see if we can
-/// fold the result. If not, this returns null.
+/// Given operands for an Shl, see if we can fold the result.
+/// If not, this returns null.
static Value *SimplifyShlInst(Value *Op0, Value *Op1, bool isNSW, bool isNUW,
const Query &Q, unsigned MaxRecurse) {
if (Value *V = SimplifyShift(Instruction::Shl, Op0, Op1, Q, MaxRecurse))
@@ -1402,8 +1401,8 @@ Value *llvm::SimplifyShlInst(Value *Op0, Value *Op1, bool isNSW, bool isNUW,
RecursionLimit);
}
-/// SimplifyLShrInst - Given operands for an LShr, see if we can
-/// fold the result. If not, this returns null.
+/// Given operands for an LShr, see if we can fold the result.
+/// If not, this returns null.
static Value *SimplifyLShrInst(Value *Op0, Value *Op1, bool isExact,
const Query &Q, unsigned MaxRecurse) {
if (Value *V = SimplifyRightShift(Instruction::LShr, Op0, Op1, isExact, Q,
@@ -1427,8 +1426,8 @@ Value *llvm::SimplifyLShrInst(Value *Op0, Value *Op1, bool isExact,
RecursionLimit);
}
-/// SimplifyAShrInst - Given operands for an AShr, see if we can
-/// fold the result. If not, this returns null.
+/// Given operands for an AShr, see if we can fold the result.
+/// If not, this returns null.
static Value *SimplifyAShrInst(Value *Op0, Value *Op1, bool isExact,
const Query &Q, unsigned MaxRecurse) {
if (Value *V = SimplifyRightShift(Instruction::AShr, Op0, Op1, isExact, Q,
@@ -1502,8 +1501,8 @@ static Value *simplifyUnsignedRangeCheck(ICmpInst *ZeroICmp,
return nullptr;
}
-// Simplify (and (icmp ...) (icmp ...)) to true when we can tell that the range
-// of possible values cannot be satisfied.
+/// Simplify (and (icmp ...) (icmp ...)) to true when we can tell that the range
+/// of possible values cannot be satisfied.
static Value *SimplifyAndOfICmps(ICmpInst *Op0, ICmpInst *Op1) {
ICmpInst::Predicate Pred0, Pred1;
ConstantInt *CI1, *CI2;
@@ -1554,8 +1553,8 @@ static Value *SimplifyAndOfICmps(ICmpInst *Op0, ICmpInst *Op1) {
return nullptr;
}
-/// SimplifyAndInst - Given operands for an And, see if we can
-/// fold the result. If not, this returns null.
+/// Given operands for an And, see if we can fold the result.
+/// If not, this returns null.
static Value *SimplifyAndInst(Value *Op0, Value *Op1, const Query &Q,
unsigned MaxRecurse) {
if (Constant *CLHS = dyn_cast<Constant>(Op0)) {
@@ -1661,8 +1660,8 @@ Value *llvm::SimplifyAndInst(Value *Op0, Value *Op1, const DataLayout &DL,
RecursionLimit);
}
-// Simplify (or (icmp ...) (icmp ...)) to true when we can tell that the union
-// contains all possible values.
+/// Simplify (or (icmp ...) (icmp ...)) to true when we can tell that the union
+/// contains all possible values.
static Value *SimplifyOrOfICmps(ICmpInst *Op0, ICmpInst *Op1) {
ICmpInst::Predicate Pred0, Pred1;
ConstantInt *CI1, *CI2;
@@ -1713,8 +1712,8 @@ static Value *SimplifyOrOfICmps(ICmpInst *Op0, ICmpInst *Op1) {
return nullptr;
}
-/// SimplifyOrInst - Given operands for an Or, see if we can
-/// fold the result. If not, this returns null.
+/// Given operands for an Or, see if we can fold the result.
+/// If not, this returns null.
static Value *SimplifyOrInst(Value *Op0, Value *Op1, const Query &Q,
unsigned MaxRecurse) {
if (Constant *CLHS = dyn_cast<Constant>(Op0)) {
@@ -1849,8 +1848,8 @@ Value *llvm::SimplifyOrInst(Value *Op0, Value *Op1, const DataLayout &DL,
RecursionLimit);
}
-/// SimplifyXorInst - Given operands for a Xor, see if we can
-/// fold the result. If not, this returns null.
+/// Given operands for a Xor, see if we can fold the result.
+/// If not, this returns null.
static Value *SimplifyXorInst(Value *Op0, Value *Op1, const Query &Q,
unsigned MaxRecurse) {
if (Constant *CLHS = dyn_cast<Constant>(Op0)) {
@@ -1910,9 +1909,9 @@ static Type *GetCompareTy(Value *Op) {
return CmpInst::makeCmpResultType(Op->getType());
}
-/// ExtractEquivalentCondition - Rummage around inside V looking for something
-/// equivalent to the comparison "LHS Pred RHS". Return such a value if found,
-/// otherwise return null. Helper function for analyzing max/min idioms.
+/// Rummage around inside V looking for something equivalent to the comparison
+/// "LHS Pred RHS". Return such a value if found, otherwise return null.
+/// Helper function for analyzing max/min idioms.
static Value *ExtractEquivalentCondition(Value *V, CmpInst::Predicate Pred,
Value *LHS, Value *RHS) {
SelectInst *SI = dyn_cast<SelectInst>(V);
@@ -2100,21 +2099,17 @@ static Constant *computePointerICmp(const DataLayout &DL,
// that might be resolve lazily to symbols in another dynamically-loaded
// library (and, thus, could be malloc'ed by the implementation).
auto IsAllocDisjoint = [](SmallVectorImpl<Value *> &Objects) {
- return std::all_of(Objects.begin(), Objects.end(),
- [](Value *V){
- if (const AllocaInst *AI = dyn_cast<AllocaInst>(V))
- return AI->getParent() && AI->getParent()->getParent() &&
- AI->isStaticAlloca();
- if (const GlobalValue *GV = dyn_cast<GlobalValue>(V))
- return (GV->hasLocalLinkage() ||
- GV->hasHiddenVisibility() ||
- GV->hasProtectedVisibility() ||
- GV->hasUnnamedAddr()) &&
- !GV->isThreadLocal();
- if (const Argument *A = dyn_cast<Argument>(V))
- return A->hasByValAttr();
- return false;
- });
+ return std::all_of(Objects.begin(), Objects.end(), [](Value *V) {
+ if (const AllocaInst *AI = dyn_cast<AllocaInst>(V))
+ return AI->getParent() && AI->getFunction() && AI->isStaticAlloca();
+ if (const GlobalValue *GV = dyn_cast<GlobalValue>(V))
+ return (GV->hasLocalLinkage() || GV->hasHiddenVisibility() ||
+ GV->hasProtectedVisibility() || GV->hasUnnamedAddr()) &&
+ !GV->isThreadLocal();
+ if (const Argument *A = dyn_cast<Argument>(V))
+ return A->hasByValAttr();
+ return false;
+ });
};
if ((IsNAC(LHSUObjs) && IsAllocDisjoint(RHSUObjs)) ||
@@ -2127,8 +2122,8 @@ static Constant *computePointerICmp(const DataLayout &DL,
return nullptr;
}
-/// SimplifyICmpInst - Given operands for an ICmpInst, see if we can
-/// fold the result. If not, this returns null.
+/// Given operands for an ICmpInst, see if we can fold the result.
+/// If not, this returns null.
static Value *SimplifyICmpInst(unsigned Predicate, Value *LHS, Value *RHS,
const Query &Q, unsigned MaxRecurse) {
CmpInst::Predicate Pred = (CmpInst::Predicate)Predicate;
@@ -3102,8 +3097,8 @@ Value *llvm::SimplifyICmpInst(unsigned Predicate, Value *LHS, Value *RHS,
RecursionLimit);
}
-/// SimplifyFCmpInst - Given operands for an FCmpInst, see if we can
-/// fold the result. If not, this returns null.
+/// Given operands for an FCmpInst, see if we can fold the result.
+/// If not, this returns null.
static Value *SimplifyFCmpInst(unsigned Predicate, Value *LHS, Value *RHS,
FastMathFlags FMF, const Query &Q,
unsigned MaxRecurse) {
@@ -3227,8 +3222,7 @@ Value *llvm::SimplifyFCmpInst(unsigned Predicate, Value *LHS, Value *RHS,
Query(DL, TLI, DT, AC, CxtI), RecursionLimit);
}
-/// SimplifyWithOpReplaced - See if V simplifies when its operand Op is
-/// replaced with RepOp.
+/// See if V simplifies when its operand Op is replaced with RepOp.
static const Value *SimplifyWithOpReplaced(Value *V, Value *Op, Value *RepOp,
const Query &Q,
unsigned MaxRecurse) {
@@ -3311,8 +3305,8 @@ static const Value *SimplifyWithOpReplaced(Value *V, Value *Op, Value *RepOp,
return nullptr;
}
-/// SimplifySelectInst - Given operands for a SelectInst, see if we can fold
-/// the result. If not, this returns null.
+/// Given operands for a SelectInst, see if we can fold the result.
+/// If not, this returns null.
static Value *SimplifySelectInst(Value *CondVal, Value *TrueVal,
Value *FalseVal, const Query &Q,
unsigned MaxRecurse) {
@@ -3449,8 +3443,8 @@ Value *llvm::SimplifySelectInst(Value *Cond, Value *TrueVal, Value *FalseVal,
Query(DL, TLI, DT, AC, CxtI), RecursionLimit);
}
-/// SimplifyGEPInst - Given operands for an GetElementPtrInst, see if we can
-/// fold the result. If not, this returns null.
+/// Given operands for an GetElementPtrInst, see if we can fold the result.
+/// If not, this returns null.
static Value *SimplifyGEPInst(Type *SrcTy, ArrayRef<Value *> Ops,
const Query &Q, unsigned) {
// The type of the GEP pointer operand.
@@ -3542,8 +3536,8 @@ Value *llvm::SimplifyGEPInst(ArrayRef<Value *> Ops, const DataLayout &DL,
Ops, Query(DL, TLI, DT, AC, CxtI), RecursionLimit);
}
-/// SimplifyInsertValueInst - Given operands for an InsertValueInst, see if we
-/// can fold the result. If not, this returns null.
+/// Given operands for an InsertValueInst, see if we can fold the result.
+/// If not, this returns null.
static Value *SimplifyInsertValueInst(Value *Agg, Value *Val,
ArrayRef<unsigned> Idxs, const Query &Q,
unsigned) {
@@ -3579,8 +3573,8 @@ Value *llvm::SimplifyInsertValueInst(
RecursionLimit);
}
-/// SimplifyExtractValueInst - Given operands for an ExtractValueInst, see if we
-/// can fold the result. If not, this returns null.
+/// Given operands for an ExtractValueInst, see if we can fold the result.
+/// If not, this returns null.
static Value *SimplifyExtractValueInst(Value *Agg, ArrayRef<unsigned> Idxs,
const Query &, unsigned) {
if (auto *CAgg = dyn_cast<Constant>(Agg))
@@ -3614,8 +3608,8 @@ Value *llvm::SimplifyExtractValueInst(Value *Agg, ArrayRef<unsigned> Idxs,
RecursionLimit);
}
-/// SimplifyExtractElementInst - Given operands for an ExtractElementInst, see if we
-/// can fold the result. If not, this returns null.
+/// Given operands for an ExtractElementInst, see if we can fold the result.
+/// If not, this returns null.
static Value *SimplifyExtractElementInst(Value *Vec, Value *Idx, const Query &,
unsigned) {
if (auto *CVec = dyn_cast<Constant>(Vec)) {
@@ -3646,7 +3640,7 @@ Value *llvm::SimplifyExtractElementInst(
RecursionLimit);
}
-/// SimplifyPHINode - See if we can fold the given phi. If not, returns null.
+/// See if we can fold the given phi. If not, returns null.
static Value *SimplifyPHINode(PHINode *PN, const Query &Q) {
// If all of the PHI's incoming values are the same then replace the PHI node
// with the common value.
@@ -3696,8 +3690,8 @@ Value *llvm::SimplifyTruncInst(Value *Op, Type *Ty, const DataLayout &DL,
//=== Helper functions for higher up the class hierarchy.
-/// SimplifyBinOp - Given operands for a BinaryOperator, see if we can
-/// fold the result. If not, this returns null.
+/// Given operands for a BinaryOperator, see if we can fold the result.
+/// If not, this returns null.
static Value *SimplifyBinOp(unsigned Opcode, Value *LHS, Value *RHS,
const Query &Q, unsigned MaxRecurse) {
switch (Opcode) {
@@ -3763,8 +3757,8 @@ static Value *SimplifyBinOp(unsigned Opcode, Value *LHS, Value *RHS,
}
}
-/// SimplifyFPBinOp - Given operands for a BinaryOperator, see if we can
-/// fold the result. If not, this returns null.
+/// Given operands for a BinaryOperator, see if we can fold the result.
+/// If not, this returns null.
/// In contrast to SimplifyBinOp, try to use FastMathFlag when folding the
/// result. In case we don't need FastMathFlags, simply fall to SimplifyBinOp.
static Value *SimplifyFPBinOp(unsigned Opcode, Value *LHS, Value *RHS,
@@ -3799,8 +3793,7 @@ Value *llvm::SimplifyFPBinOp(unsigned Opcode, Value *LHS, Value *RHS,
RecursionLimit);
}
-/// SimplifyCmpInst - Given operands for a CmpInst, see if we can
-/// fold the result.
+/// Given operands for a CmpInst, see if we can fold the result.
static Value *SimplifyCmpInst(unsigned Predicate, Value *LHS, Value *RHS,
const Query &Q, unsigned MaxRecurse) {
if (CmpInst::isIntPredicate((CmpInst::Predicate)Predicate))
@@ -3938,8 +3931,8 @@ Value *llvm::SimplifyCall(Value *V, ArrayRef<Value *> Args,
Query(DL, TLI, DT, AC, CxtI), RecursionLimit);
}
-/// SimplifyInstruction - See if we can compute a simplified version of this
-/// instruction. If not, this returns null.
+/// See if we can compute a simplified version of this instruction.
+/// If not, this returns null.
Value *llvm::SimplifyInstruction(Instruction *I, const DataLayout &DL,
const TargetLibraryInfo *TLI,
const DominatorTree *DT, AssumptionCache *AC) {
diff --git a/lib/Analysis/LoopAccessAnalysis.cpp b/lib/Analysis/LoopAccessAnalysis.cpp
index d7896ade3543..8bcdcb862014 100644
--- a/lib/Analysis/LoopAccessAnalysis.cpp
+++ b/lib/Analysis/LoopAccessAnalysis.cpp
@@ -845,6 +845,7 @@ int llvm::isStridedPtr(PredicatedScalarEvolution &PSE, Value *Ptr,
if (Lp != AR->getLoop()) {
DEBUG(dbgs() << "LAA: Bad stride - Not striding over innermost loop " <<
*Ptr << " SCEV: " << *PtrScev << "\n");
+ return 0;
}
// The address calculation must not wrap. Otherwise, a dependence could be
diff --git a/lib/Analysis/LoopInfo.cpp b/lib/Analysis/LoopInfo.cpp
index 9ab9eead584f..0c725fcadff7 100644
--- a/lib/Analysis/LoopInfo.cpp
+++ b/lib/Analysis/LoopInfo.cpp
@@ -637,8 +637,10 @@ LoopInfo::LoopInfo(const DominatorTreeBase<BasicBlock> &DomTree) {
analyze(DomTree);
}
-void LoopInfo::updateUnloop(Loop *Unloop) {
- Unloop->markUnlooped();
+void LoopInfo::markAsRemoved(Loop *Unloop) {
+ assert(!Unloop->isInvalid() && "Loop has already been removed");
+ Unloop->invalidate();
+ RemovedLoops.push_back(Unloop);
// First handle the special case of no parent loop to simplify the algorithm.
if (!Unloop->getParentLoop()) {
diff --git a/lib/Analysis/LoopPass.cpp b/lib/Analysis/LoopPass.cpp
index dc424734dd56..8163231c3323 100644
--- a/lib/Analysis/LoopPass.cpp
+++ b/lib/Analysis/LoopPass.cpp
@@ -42,7 +42,11 @@ public:
}
bool runOnLoop(Loop *L, LPPassManager &) override {
- P.run(*L);
+ auto BBI = find_if(L->blocks().begin(), L->blocks().end(),
+ [](BasicBlock *BB) { return BB; });
+ if (BBI != L->blocks().end() &&
+ isFunctionInPrintList((*BBI)->getParent()->getName()))
+ P.run(*L);
return false;
}
};
@@ -174,8 +178,9 @@ bool LPPassManager::runOnFunction(Function &F) {
// Walk Loops
while (!LQ.empty()) {
-
+ bool LoopWasDeleted = false;
CurrentLoop = LQ.back();
+
// Run all passes on the current Loop.
for (unsigned Index = 0; Index < getNumContainedPasses(); ++Index) {
LoopPass *P = getContainedPass(Index);
@@ -192,15 +197,15 @@ bool LPPassManager::runOnFunction(Function &F) {
Changed |= P->runOnLoop(CurrentLoop, *this);
}
+ LoopWasDeleted = CurrentLoop->isInvalid();
if (Changed)
dumpPassInfo(P, MODIFICATION_MSG, ON_LOOP_MSG,
- CurrentLoop->isUnloop()
- ? "<deleted>"
- : CurrentLoop->getHeader()->getName());
+ LoopWasDeleted ? "<deleted>"
+ : CurrentLoop->getHeader()->getName());
dumpPreservedSet(P);
- if (CurrentLoop->isUnloop()) {
+ if (LoopWasDeleted) {
// Notify passes that the loop is being deleted.
deleteSimpleAnalysisLoop(CurrentLoop);
} else {
@@ -222,12 +227,11 @@ bool LPPassManager::runOnFunction(Function &F) {
removeNotPreservedAnalysis(P);
recordAvailableAnalysis(P);
- removeDeadPasses(P, CurrentLoop->isUnloop()
- ? "<deleted>"
- : CurrentLoop->getHeader()->getName(),
+ removeDeadPasses(P, LoopWasDeleted ? "<deleted>"
+ : CurrentLoop->getHeader()->getName(),
ON_LOOP_MSG);
- if (CurrentLoop->isUnloop())
+ if (LoopWasDeleted)
// Do not run other passes on this loop.
break;
}
@@ -235,12 +239,11 @@ bool LPPassManager::runOnFunction(Function &F) {
// If the loop was deleted, release all the loop passes. This frees up
// some memory, and avoids trouble with the pass manager trying to call
// verifyAnalysis on them.
- if (CurrentLoop->isUnloop()) {
+ if (LoopWasDeleted) {
for (unsigned Index = 0; Index < getNumContainedPasses(); ++Index) {
Pass *P = getContainedPass(Index);
freePass(P, "<deleted>", ON_LOOP_MSG);
}
- delete CurrentLoop;
}
// Pop the loop from queue after running all passes.
diff --git a/lib/Analysis/ScopedNoAliasAA.cpp b/lib/Analysis/ScopedNoAliasAA.cpp
index 029997adab9e..486f3a583284 100644
--- a/lib/Analysis/ScopedNoAliasAA.cpp
+++ b/lib/Analysis/ScopedNoAliasAA.cpp
@@ -26,7 +26,7 @@
// ... = load %ptr2, !alias.scope !{ !scope1, !scope2 }, !noalias !{ !scope1 }
//
// When evaluating an aliasing query, if one of the instructions is associated
-// has a set of noalias scopes in some domain that is superset of the alias
+// has a set of noalias scopes in some domain that is a superset of the alias
// scopes in that domain of some other instruction, then the two memory
// accesses are assumed not to alias.
//
diff --git a/lib/Analysis/TypeBasedAliasAnalysis.cpp b/lib/Analysis/TypeBasedAliasAnalysis.cpp
index 805f3efb0814..9f923913ca27 100644
--- a/lib/Analysis/TypeBasedAliasAnalysis.cpp
+++ b/lib/Analysis/TypeBasedAliasAnalysis.cpp
@@ -70,7 +70,7 @@
// A a;
// } B;
//
-// For an acess to B.a.s, we attach !5 (a path tag node) to the load/store
+// For an access to B.a.s, we attach !5 (a path tag node) to the load/store
// instruction. The base type is !4 (struct B), the access type is !2 (scalar
// type short) and the offset is 4.
//
diff --git a/lib/Analysis/ValueTracking.cpp b/lib/Analysis/ValueTracking.cpp
index abc57ed8bca0..a83e207bd265 100644
--- a/lib/Analysis/ValueTracking.cpp
+++ b/lib/Analysis/ValueTracking.cpp
@@ -2556,6 +2556,9 @@ bool llvm::CannotBeOrderedLessThanZero(const Value *V, unsigned Depth) {
switch (I->getOpcode()) {
default: break;
+ // Unsigned integers are always nonnegative.
+ case Instruction::UIToFP:
+ return true;
case Instruction::FMul:
// x*x is always non-negative or a NaN.
if (I->getOperand(0) == I->getOperand(1))
@@ -2566,6 +2569,9 @@ bool llvm::CannotBeOrderedLessThanZero(const Value *V, unsigned Depth) {
case Instruction::FRem:
return CannotBeOrderedLessThanZero(I->getOperand(0), Depth+1) &&
CannotBeOrderedLessThanZero(I->getOperand(1), Depth+1);
+ case Instruction::Select:
+ return CannotBeOrderedLessThanZero(I->getOperand(1), Depth+1) &&
+ CannotBeOrderedLessThanZero(I->getOperand(2), Depth+1);
case Instruction::FPExt:
case Instruction::FPTrunc:
// Widening/narrowing never change sign.
@@ -2574,6 +2580,12 @@ bool llvm::CannotBeOrderedLessThanZero(const Value *V, unsigned Depth) {
if (const IntrinsicInst *II = dyn_cast<IntrinsicInst>(I))
switch (II->getIntrinsicID()) {
default: break;
+ case Intrinsic::maxnum:
+ return CannotBeOrderedLessThanZero(I->getOperand(0), Depth+1) ||
+ CannotBeOrderedLessThanZero(I->getOperand(1), Depth+1);
+ case Intrinsic::minnum:
+ return CannotBeOrderedLessThanZero(I->getOperand(0), Depth+1) &&
+ CannotBeOrderedLessThanZero(I->getOperand(1), Depth+1);
case Intrinsic::exp:
case Intrinsic::exp2:
case Intrinsic::fabs:
diff --git a/lib/Bitcode/Reader/BitcodeReader.cpp b/lib/Bitcode/Reader/BitcodeReader.cpp
index c7606fd488a0..2ad4b32e3157 100644
--- a/lib/Bitcode/Reader/BitcodeReader.cpp
+++ b/lib/Bitcode/Reader/BitcodeReader.cpp
@@ -2654,8 +2654,6 @@ std::error_code BitcodeReader::parseConstants() {
return error("Invalid record");
Type *EltTy = cast<SequentialType>(CurTy)->getElementType();
- unsigned Size = Record.size();
-
if (EltTy->isIntegerTy(8)) {
SmallVector<uint8_t, 16> Elts(Record.begin(), Record.end());
if (isa<VectorType>(CurTy))
@@ -2680,21 +2678,24 @@ std::error_code BitcodeReader::parseConstants() {
V = ConstantDataVector::get(Context, Elts);
else
V = ConstantDataArray::get(Context, Elts);
+ } else if (EltTy->isHalfTy()) {
+ SmallVector<uint16_t, 16> Elts(Record.begin(), Record.end());
+ if (isa<VectorType>(CurTy))
+ V = ConstantDataVector::getFP(Context, Elts);
+ else
+ V = ConstantDataArray::getFP(Context, Elts);
} else if (EltTy->isFloatTy()) {
- SmallVector<float, 16> Elts(Size);
- std::transform(Record.begin(), Record.end(), Elts.begin(), BitsToFloat);
+ SmallVector<uint32_t, 16> Elts(Record.begin(), Record.end());
if (isa<VectorType>(CurTy))
- V = ConstantDataVector::get(Context, Elts);
+ V = ConstantDataVector::getFP(Context, Elts);
else
- V = ConstantDataArray::get(Context, Elts);
+ V = ConstantDataArray::getFP(Context, Elts);
} else if (EltTy->isDoubleTy()) {
- SmallVector<double, 16> Elts(Size);
- std::transform(Record.begin(), Record.end(), Elts.begin(),
- BitsToDouble);
+ SmallVector<uint64_t, 16> Elts(Record.begin(), Record.end());
if (isa<VectorType>(CurTy))
- V = ConstantDataVector::get(Context, Elts);
+ V = ConstantDataVector::getFP(Context, Elts);
else
- V = ConstantDataArray::get(Context, Elts);
+ V = ConstantDataArray::getFP(Context, Elts);
} else {
return error("Invalid type for value");
}
diff --git a/lib/Bitcode/Writer/BitcodeWriter.cpp b/lib/Bitcode/Writer/BitcodeWriter.cpp
index a1f87863757b..a899a0cc3ee4 100644
--- a/lib/Bitcode/Writer/BitcodeWriter.cpp
+++ b/lib/Bitcode/Writer/BitcodeWriter.cpp
@@ -1630,19 +1630,10 @@ static void WriteConstants(unsigned FirstVal, unsigned LastVal,
if (isa<IntegerType>(EltTy)) {
for (unsigned i = 0, e = CDS->getNumElements(); i != e; ++i)
Record.push_back(CDS->getElementAsInteger(i));
- } else if (EltTy->isFloatTy()) {
- for (unsigned i = 0, e = CDS->getNumElements(); i != e; ++i) {
- union { float F; uint32_t I; };
- F = CDS->getElementAsFloat(i);
- Record.push_back(I);
- }
} else {
- assert(EltTy->isDoubleTy() && "Unknown ConstantData element type");
- for (unsigned i = 0, e = CDS->getNumElements(); i != e; ++i) {
- union { double F; uint64_t I; };
- F = CDS->getElementAsDouble(i);
- Record.push_back(I);
- }
+ for (unsigned i = 0, e = CDS->getNumElements(); i != e; ++i)
+ Record.push_back(
+ CDS->getElementAsAPFloat(i).bitcastToAPInt().getLimitedValue());
}
} else if (isa<ConstantArray>(C) || isa<ConstantStruct>(C) ||
isa<ConstantVector>(C)) {
diff --git a/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
index be7eafbeb83d..5f67d3daa97f 100644
--- a/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
+++ b/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
@@ -192,22 +192,26 @@ bool AsmPrinter::doInitialization(Module &M) {
// use the directive, where it would need the same conditionalization
// anyway.
Triple TT(getTargetTriple());
- if (TT.isOSDarwin()) {
+ // If there is a version specified, Major will be non-zero.
+ if (TT.isOSDarwin() && TT.getOSMajorVersion() != 0) {
unsigned Major, Minor, Update;
- TT.getOSVersion(Major, Minor, Update);
- // If there is a version specified, Major will be non-zero.
- if (Major) {
- MCVersionMinType VersionType;
- if (TT.isWatchOS())
- VersionType = MCVM_WatchOSVersionMin;
- else if (TT.isTvOS())
- VersionType = MCVM_TvOSVersionMin;
- else if (TT.isMacOSX())
- VersionType = MCVM_OSXVersionMin;
- else
- VersionType = MCVM_IOSVersionMin;
- OutStreamer->EmitVersionMin(VersionType, Major, Minor, Update);
+ MCVersionMinType VersionType;
+ if (TT.isWatchOS()) {
+ VersionType = MCVM_WatchOSVersionMin;
+ TT.getWatchOSVersion(Major, Minor, Update);
+ } else if (TT.isTvOS()) {
+ VersionType = MCVM_TvOSVersionMin;
+ TT.getiOSVersion(Major, Minor, Update);
+ } else if (TT.isMacOSX()) {
+ VersionType = MCVM_OSXVersionMin;
+ if (!TT.getMacOSXVersion(Major, Minor, Update))
+ Major = 0;
+ } else {
+ VersionType = MCVM_IOSVersionMin;
+ TT.getiOSVersion(Major, Minor, Update);
}
+ if (Major != 0)
+ OutStreamer->EmitVersionMin(VersionType, Major, Minor, Update);
}
// Allow the target to emit any magic that it wants at the start of the file.
diff --git a/lib/CodeGen/AsmPrinter/DIE.cpp b/lib/CodeGen/AsmPrinter/DIE.cpp
index bf794f7f70f6..7b0cdbde3791 100644
--- a/lib/CodeGen/AsmPrinter/DIE.cpp
+++ b/lib/CodeGen/AsmPrinter/DIE.cpp
@@ -32,6 +32,39 @@
using namespace llvm;
//===----------------------------------------------------------------------===//
+// EmittingAsmStreamer Implementation
+//===----------------------------------------------------------------------===//
+unsigned EmittingAsmStreamer::emitULEB128(uint64_t Value, const char *Desc,
+ unsigned PadTo) {
+ AP->EmitULEB128(Value, Desc, PadTo);
+ return 0;
+}
+
+unsigned EmittingAsmStreamer::emitInt8(unsigned char Value) {
+ AP->EmitInt8(Value);
+ return 0;
+}
+
+unsigned EmittingAsmStreamer::emitBytes(StringRef Data) {
+ AP->OutStreamer->EmitBytes(Data);
+ return 0;
+}
+
+//===----------------------------------------------------------------------===//
+// SizeReporterAsmStreamer Implementation
+//===----------------------------------------------------------------------===//
+unsigned SizeReporterAsmStreamer::emitULEB128(uint64_t Value, const char *Desc,
+ unsigned PadTo) {
+ return getULEB128Size(Value);
+}
+
+unsigned SizeReporterAsmStreamer::emitInt8(unsigned char Value) { return 1; }
+
+unsigned SizeReporterAsmStreamer::emitBytes(StringRef Data) {
+ return Data.size();
+}
+
+//===----------------------------------------------------------------------===//
// DIEAbbrevData Implementation
//===----------------------------------------------------------------------===//
diff --git a/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
index 3466f3469f1c..a4fb07eacb3b 100644
--- a/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
+++ b/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
@@ -221,7 +221,7 @@ DwarfDebug::DwarfDebug(AsmPrinter *A, Module *M)
// precedence; fall back to triple-based defaults.
if (Asm->TM.Options.DebuggerTuning != DebuggerKind::Default)
DebuggerTuning = Asm->TM.Options.DebuggerTuning;
- else if (IsDarwin || TT.isOSFreeBSD())
+ else if (IsDarwin)
DebuggerTuning = DebuggerKind::LLDB;
else if (TT.isPS4CPU())
DebuggerTuning = DebuggerKind::SCE;
@@ -561,6 +561,8 @@ void DwarfDebug::finalizeModuleInfo() {
// Collect info for variables that were optimized out.
collectDeadVariables();
+ unsigned MacroOffset = 0;
+ std::unique_ptr<AsmStreamerBase> AS(new SizeReporterAsmStreamer(Asm));
// Handle anything that needs to be done on a per-unit basis after
// all other generation.
for (const auto &P : CUMap) {
@@ -613,6 +615,15 @@ void DwarfDebug::finalizeModuleInfo() {
U.setBaseAddress(TheCU.getRanges().front().getStart());
U.attachRangesOrLowHighPC(U.getUnitDie(), TheCU.takeRanges());
}
+
+ auto *CUNode = cast<DICompileUnit>(P.first);
+ if (CUNode->getMacros()) {
+ // Compile Unit has macros, emit "DW_AT_macro_info" attribute.
+ U.addUInt(U.getUnitDie(), dwarf::DW_AT_macro_info,
+ dwarf::DW_FORM_sec_offset, MacroOffset);
+ // Update macro section offset
+ MacroOffset += handleMacroNodes(AS.get(), CUNode->getMacros(), U);
+ }
}
// Compute DIE offsets and sizes.
@@ -656,6 +667,9 @@ void DwarfDebug::endModule() {
// Emit info into a debug ranges section.
emitDebugRanges();
+ // Emit info into a debug macinfo section.
+ emitDebugMacinfo();
+
if (useSplitDwarf()) {
emitDebugStrDWO();
emitDebugInfoDWO();
@@ -1833,6 +1847,70 @@ void DwarfDebug::emitDebugRanges() {
}
}
+unsigned DwarfDebug::handleMacroNodes(AsmStreamerBase *AS,
+ DIMacroNodeArray Nodes,
+ DwarfCompileUnit &U) {
+ unsigned Size = 0;
+ for (auto *MN : Nodes) {
+ if (auto *M = dyn_cast<DIMacro>(MN))
+ Size += emitMacro(AS, *M);
+ else if (auto *F = dyn_cast<DIMacroFile>(MN))
+ Size += emitMacroFile(AS, *F, U);
+ else
+ llvm_unreachable("Unexpected DI type!");
+ }
+ return Size;
+}
+
+unsigned DwarfDebug::emitMacro(AsmStreamerBase *AS, DIMacro &M) {
+ int Size = 0;
+ Size += AS->emitULEB128(M.getMacinfoType());
+ Size += AS->emitULEB128(M.getLine());
+ StringRef Name = M.getName();
+ StringRef Value = M.getValue();
+ Size += AS->emitBytes(Name);
+ if (!Value.empty()) {
+ // There should be one space between macro name and macro value.
+ Size += AS->emitInt8(' ');
+ Size += AS->emitBytes(Value);
+ }
+ Size += AS->emitInt8('\0');
+ return Size;
+}
+
+unsigned DwarfDebug::emitMacroFile(AsmStreamerBase *AS, DIMacroFile &F,
+ DwarfCompileUnit &U) {
+ int Size = 0;
+ assert(F.getMacinfoType() == dwarf::DW_MACINFO_start_file);
+ Size += AS->emitULEB128(dwarf::DW_MACINFO_start_file);
+ Size += AS->emitULEB128(F.getLine());
+ DIFile *File = F.getFile();
+ unsigned FID =
+ U.getOrCreateSourceID(File->getFilename(), File->getDirectory());
+ Size += AS->emitULEB128(FID);
+ Size += handleMacroNodes(AS, F.getElements(), U);
+ Size += AS->emitULEB128(dwarf::DW_MACINFO_end_file);
+ return Size;
+}
+
+// Emit visible names into a debug macinfo section.
+void DwarfDebug::emitDebugMacinfo() {
+ if (MCSection *Macinfo = Asm->getObjFileLowering().getDwarfMacinfoSection()) {
+ // Start the dwarf macinfo section.
+ Asm->OutStreamer->SwitchSection(Macinfo);
+ }
+ std::unique_ptr<AsmStreamerBase> AS(new EmittingAsmStreamer(Asm));
+ for (const auto &P : CUMap) {
+ auto &TheCU = *P.second;
+ auto *SkCU = TheCU.getSkeleton();
+ DwarfCompileUnit &U = SkCU ? *SkCU : TheCU;
+ auto *CUNode = cast<DICompileUnit>(P.first);
+ handleMacroNodes(AS.get(), CUNode->getMacros(), U);
+ }
+ Asm->OutStreamer->AddComment("End Of Macro List Mark");
+ Asm->EmitInt8(0);
+}
+
// DWARF5 Experimental Separate Dwarf emitters.
void DwarfDebug::initSkeletonUnit(const DwarfUnit &U, DIE &Die,
diff --git a/lib/CodeGen/AsmPrinter/DwarfDebug.h b/lib/CodeGen/AsmPrinter/DwarfDebug.h
index 4c613a905450..460c186683fc 100644
--- a/lib/CodeGen/AsmPrinter/DwarfDebug.h
+++ b/lib/CodeGen/AsmPrinter/DwarfDebug.h
@@ -400,18 +400,26 @@ class DwarfDebug : public AsmPrinterHandler {
/// Emit visible names into a debug str section.
void emitDebugStr();
- /// Emit visible names into a debug loc section.
+ /// Emit variable locations into a debug loc section.
void emitDebugLoc();
- /// Emit visible names into a debug loc dwo section.
+ /// Emit variable locations into a debug loc dwo section.
void emitDebugLocDWO();
- /// Emit visible names into a debug aranges section.
+ /// Emit address ranges into a debug aranges section.
void emitDebugARanges();
- /// Emit visible names into a debug ranges section.
+ /// Emit address ranges into a debug ranges section.
void emitDebugRanges();
+ /// Emit macros into a debug macinfo section.
+ void emitDebugMacinfo();
+ unsigned emitMacro(AsmStreamerBase *AS, DIMacro &M);
+ unsigned emitMacroFile(AsmStreamerBase *AS, DIMacroFile &F,
+ DwarfCompileUnit &U);
+ unsigned handleMacroNodes(AsmStreamerBase *AS, DIMacroNodeArray Nodes,
+ DwarfCompileUnit &U);
+
/// DWARF 5 Experimental Split Dwarf Emitters
/// Initialize common features of skeleton units.
diff --git a/lib/CodeGen/AsmPrinter/WinCodeViewLineTables.cpp b/lib/CodeGen/AsmPrinter/WinCodeViewLineTables.cpp
index c2c0f84e5c92..1e2f55b71151 100644
--- a/lib/CodeGen/AsmPrinter/WinCodeViewLineTables.cpp
+++ b/lib/CodeGen/AsmPrinter/WinCodeViewLineTables.cpp
@@ -82,13 +82,24 @@ void WinCodeViewLineTables::maybeRecordLocation(DebugLoc DL,
const MDNode *Scope = DL.getScope();
if (!Scope)
return;
+ unsigned LineNumber = DL.getLine();
+ // Skip this line if it is longer than the maximum we can record.
+ if (LineNumber > COFF::CVL_MaxLineNumber)
+ return;
+
+ unsigned ColumnNumber = DL.getCol();
+ // Truncate the column number if it is longer than the maximum we can record.
+ if (ColumnNumber > COFF::CVL_MaxColumnNumber)
+ ColumnNumber = 0;
+
StringRef Filename = getFullFilepath(Scope);
// Skip this instruction if it has the same file:line as the previous one.
assert(CurFn);
if (!CurFn->Instrs.empty()) {
const InstrInfoTy &LastInstr = InstrInfo[CurFn->Instrs.back()];
- if (LastInstr.Filename == Filename && LastInstr.LineNumber == DL.getLine())
+ if (LastInstr.Filename == Filename && LastInstr.LineNumber == LineNumber &&
+ LastInstr.ColumnNumber == ColumnNumber)
return;
}
FileNameRegistry.add(Filename);
@@ -96,7 +107,7 @@ void WinCodeViewLineTables::maybeRecordLocation(DebugLoc DL,
MCSymbol *MCL = Asm->MMI->getContext().createTempSymbol();
Asm->OutStreamer->EmitLabel(MCL);
CurFn->Instrs.push_back(MCL);
- InstrInfo[MCL] = InstrInfoTy(Filename, DL.getLine(), DL.getCol());
+ InstrInfo[MCL] = InstrInfoTy(Filename, LineNumber, ColumnNumber);
}
WinCodeViewLineTables::WinCodeViewLineTables(AsmPrinter *AP)
@@ -282,8 +293,9 @@ void WinCodeViewLineTables::emitDebugInfoForFunction(const Function *GV) {
ColSegEnd = ColSegI + FilenameSegmentLengths[LastSegmentStart];
ColSegI != ColSegEnd; ++ColSegI) {
unsigned ColumnNumber = InstrInfo[FI.Instrs[ColSegI]].ColumnNumber;
+ assert(ColumnNumber <= COFF::CVL_MaxColumnNumber);
Asm->EmitInt16(ColumnNumber); // Start column
- Asm->EmitInt16(ColumnNumber); // End column
+ Asm->EmitInt16(0); // End column
}
Asm->OutStreamer->EmitLabel(FileSegmentEnd);
};
@@ -320,7 +332,10 @@ void WinCodeViewLineTables::emitDebugInfoForFunction(const Function *GV) {
// The first PC with the given linenumber and the linenumber itself.
EmitLabelDiff(*Asm->OutStreamer, Fn, Instr);
- Asm->EmitInt32(InstrInfo[Instr].LineNumber);
+ uint32_t LineNumber = InstrInfo[Instr].LineNumber;
+ assert(LineNumber <= COFF::CVL_MaxLineNumber);
+ uint32_t LineData = LineNumber | COFF::CVL_IsStatement;
+ Asm->EmitInt32(LineData);
}
FinishPreviousChunk();
diff --git a/lib/CodeGen/BranchFolding.cpp b/lib/CodeGen/BranchFolding.cpp
index 604feeddd355..df5cac5a9f7a 100644
--- a/lib/CodeGen/BranchFolding.cpp
+++ b/lib/CodeGen/BranchFolding.cpp
@@ -744,18 +744,6 @@ bool BranchFolder::CreateCommonTailOnlyBlock(MachineBasicBlock *&PredBB,
return true;
}
-static bool hasIdenticalMMOs(const MachineInstr *MI1, const MachineInstr *MI2) {
- auto I1 = MI1->memoperands_begin(), E1 = MI1->memoperands_end();
- auto I2 = MI2->memoperands_begin(), E2 = MI2->memoperands_end();
- if ((E1 - I1) != (E2 - I2))
- return false;
- for (; I1 != E1; ++I1, ++I2) {
- if (**I1 != **I2)
- return false;
- }
- return true;
-}
-
static void
removeMMOsFromMemoryOperations(MachineBasicBlock::iterator MBBIStartPos,
MachineBasicBlock &MBBCommon) {
@@ -792,8 +780,7 @@ removeMMOsFromMemoryOperations(MachineBasicBlock::iterator MBBIStartPos,
assert(MBBICommon->isIdenticalTo(&*MBBI) && "Expected matching MIIs!");
if (MBBICommon->mayLoad() || MBBICommon->mayStore())
- if (!hasIdenticalMMOs(&*MBBI, &*MBBICommon))
- MBBICommon->dropMemRefs();
+ MBBICommon->setMemRefs(MBBICommon->mergeMemRefsWith(*MBBI));
++MBBI;
++MBBICommon;
diff --git a/lib/CodeGen/CodeGenPrepare.cpp b/lib/CodeGen/CodeGenPrepare.cpp
index 6fbdea84c10f..03e57787307a 100644
--- a/lib/CodeGen/CodeGenPrepare.cpp
+++ b/lib/CodeGen/CodeGenPrepare.cpp
@@ -1108,7 +1108,7 @@ static bool OptimizeExtractBits(BinaryOperator *ShiftI, ConstantInt *CI,
// <16 x i1> %mask, <16 x i32> %passthru)
// to a chain of basic blocks, with loading element one-by-one if
// the appropriate mask bit is set
-//
+//
// %1 = bitcast i8* %addr to i32*
// %2 = extractelement <16 x i1> %mask, i32 0
// %3 = icmp eq i1 %2, true
@@ -1272,12 +1272,12 @@ static void ScalarizeMaskedLoad(CallInst *CI) {
// %5 = getelementptr i32* %1, i32 0
// store i32 %4, i32* %5
// br label %else
-//
+//
// else: ; preds = %0, %cond.store
// %6 = extractelement <16 x i1> %mask, i32 1
// %7 = icmp eq i1 %6, true
// br i1 %7, label %cond.store1, label %else2
-//
+//
// cond.store1: ; preds = %else
// %8 = extractelement <16 x i32> %val, i32 1
// %9 = getelementptr i32* %1, i32 1
@@ -1377,24 +1377,24 @@ static void ScalarizeMaskedStore(CallInst *CI) {
// <16 x i1> %Mask, <16 x i32> %Src)
// to a chain of basic blocks, with loading element one-by-one if
// the appropriate mask bit is set
-//
+//
// % Ptrs = getelementptr i32, i32* %base, <16 x i64> %ind
// % Mask0 = extractelement <16 x i1> %Mask, i32 0
// % ToLoad0 = icmp eq i1 % Mask0, true
// br i1 % ToLoad0, label %cond.load, label %else
-//
+//
// cond.load:
// % Ptr0 = extractelement <16 x i32*> %Ptrs, i32 0
// % Load0 = load i32, i32* % Ptr0, align 4
// % Res0 = insertelement <16 x i32> undef, i32 % Load0, i32 0
// br label %else
-//
+//
// else:
// %res.phi.else = phi <16 x i32>[% Res0, %cond.load], [undef, % 0]
// % Mask1 = extractelement <16 x i1> %Mask, i32 1
// % ToLoad1 = icmp eq i1 % Mask1, true
// br i1 % ToLoad1, label %cond.load1, label %else2
-//
+//
// cond.load1:
// % Ptr1 = extractelement <16 x i32*> %Ptrs, i32 1
// % Load1 = load i32, i32* % Ptr1, align 4
@@ -1526,7 +1526,7 @@ static void ScalarizeMaskedGather(CallInst *CI) {
// % Ptr0 = extractelement <16 x i32*> %Ptrs, i32 0
// store i32 %Elt0, i32* % Ptr0, align 4
// br label %else
-//
+//
// else:
// % Mask1 = extractelement <16 x i1> % Mask, i32 1
// % ToStore1 = icmp eq i1 % Mask1, true
diff --git a/lib/CodeGen/LiveDebugValues.cpp b/lib/CodeGen/LiveDebugValues.cpp
index 98d30b95dd2d..b9937e5570d4 100644
--- a/lib/CodeGen/LiveDebugValues.cpp
+++ b/lib/CodeGen/LiveDebugValues.cpp
@@ -19,6 +19,8 @@
//===----------------------------------------------------------------------===//
#include "llvm/ADT/Statistic.h"
+#include "llvm/ADT/PostOrderIterator.h"
+#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
@@ -30,7 +32,7 @@
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetRegisterInfo.h"
#include "llvm/Target/TargetSubtargetInfo.h"
-#include <deque>
+#include <queue>
#include <list>
using namespace llvm;
@@ -76,16 +78,13 @@ private:
typedef std::list<VarLoc> VarLocList;
typedef SmallDenseMap<const MachineBasicBlock *, VarLocList> VarLocInMBB;
- bool OLChanged; // OutgoingLocs got changed for this bb.
- bool MBBJoined; // The MBB was joined.
-
void transferDebugValue(MachineInstr &MI, VarLocList &OpenRanges);
void transferRegisterDef(MachineInstr &MI, VarLocList &OpenRanges);
- void transferTerminatorInst(MachineInstr &MI, VarLocList &OpenRanges,
+ bool transferTerminatorInst(MachineInstr &MI, VarLocList &OpenRanges,
VarLocInMBB &OutLocs);
- void transfer(MachineInstr &MI, VarLocList &OpenRanges, VarLocInMBB &OutLocs);
+ bool transfer(MachineInstr &MI, VarLocList &OpenRanges, VarLocInMBB &OutLocs);
- void join(MachineBasicBlock &MBB, VarLocInMBB &OutLocs, VarLocInMBB &InLocs);
+ bool join(MachineBasicBlock &MBB, VarLocInMBB &OutLocs, VarLocInMBB &InLocs);
bool ExtendRanges(MachineFunction &MF);
@@ -225,24 +224,18 @@ void LiveDebugValues::transferRegisterDef(MachineInstr &MI,
}
/// Terminate all open ranges at the end of the current basic block.
-void LiveDebugValues::transferTerminatorInst(MachineInstr &MI,
+bool LiveDebugValues::transferTerminatorInst(MachineInstr &MI,
VarLocList &OpenRanges,
VarLocInMBB &OutLocs) {
+ bool Changed = false;
const MachineBasicBlock *CurMBB = MI.getParent();
if (!(MI.isTerminator() || (&MI == &CurMBB->instr_back())))
- return;
+ return false;
if (OpenRanges.empty())
- return;
+ return false;
- if (OutLocs.find(CurMBB) == OutLocs.end()) {
- // Create space for new Outgoing locs entries.
- VarLocList VLL;
- OutLocs.insert(std::make_pair(CurMBB, std::move(VLL)));
- }
- auto OL = OutLocs.find(CurMBB);
- assert(OL != OutLocs.end());
- VarLocList &VLL = OL->second;
+ VarLocList &VLL = OutLocs[CurMBB];
for (auto OR : OpenRanges) {
// Copy OpenRanges to OutLocs, if not already present.
@@ -251,28 +244,30 @@ void LiveDebugValues::transferTerminatorInst(MachineInstr &MI,
if (std::find_if(VLL.begin(), VLL.end(),
[&](const VarLoc &V) { return (OR == V); }) == VLL.end()) {
VLL.push_back(std::move(OR));
- OLChanged = true;
+ Changed = true;
}
}
OpenRanges.clear();
+ return Changed;
}
/// This routine creates OpenRanges and OutLocs.
-void LiveDebugValues::transfer(MachineInstr &MI, VarLocList &OpenRanges,
+bool LiveDebugValues::transfer(MachineInstr &MI, VarLocList &OpenRanges,
VarLocInMBB &OutLocs) {
+ bool Changed = false;
transferDebugValue(MI, OpenRanges);
transferRegisterDef(MI, OpenRanges);
- transferTerminatorInst(MI, OpenRanges, OutLocs);
+ Changed = transferTerminatorInst(MI, OpenRanges, OutLocs);
+ return Changed;
}
/// This routine joins the analysis results of all incoming edges in @MBB by
/// inserting a new DBG_VALUE instruction at the start of the @MBB - if the same
/// source variable in all the predecessors of @MBB reside in the same location.
-void LiveDebugValues::join(MachineBasicBlock &MBB, VarLocInMBB &OutLocs,
+bool LiveDebugValues::join(MachineBasicBlock &MBB, VarLocInMBB &OutLocs,
VarLocInMBB &InLocs) {
DEBUG(dbgs() << "join MBB: " << MBB.getName() << "\n");
-
- MBBJoined = false;
+ bool Changed = false;
VarLocList InLocsT; // Temporary incoming locations.
@@ -282,7 +277,7 @@ void LiveDebugValues::join(MachineBasicBlock &MBB, VarLocInMBB &OutLocs,
auto OL = OutLocs.find(p);
// Join is null in case of empty OutLocs from any of the pred.
if (OL == OutLocs.end())
- return;
+ return false;
// Just copy over the Out locs to incoming locs for the first predecessor.
if (p == *MBB.pred_begin()) {
@@ -292,27 +287,18 @@ void LiveDebugValues::join(MachineBasicBlock &MBB, VarLocInMBB &OutLocs,
// Join with this predecessor.
VarLocList &VLL = OL->second;
- InLocsT.erase(std::remove_if(InLocsT.begin(), InLocsT.end(),
- [&](VarLoc &ILT) {
- return (std::find_if(VLL.begin(), VLL.end(),
- [&](const VarLoc &V) {
- return (ILT == V);
- }) == VLL.end());
- }),
- InLocsT.end());
+ InLocsT.erase(
+ std::remove_if(InLocsT.begin(), InLocsT.end(), [&](VarLoc &ILT) {
+ return (std::find_if(VLL.begin(), VLL.end(), [&](const VarLoc &V) {
+ return (ILT == V);
+ }) == VLL.end());
+ }), InLocsT.end());
}
if (InLocsT.empty())
- return;
+ return false;
- if (InLocs.find(&MBB) == InLocs.end()) {
- // Create space for new Incoming locs entries.
- VarLocList VLL;
- InLocs.insert(std::make_pair(&MBB, std::move(VLL)));
- }
- auto IL = InLocs.find(&MBB);
- assert(IL != InLocs.end());
- VarLocList &ILL = IL->second;
+ VarLocList &ILL = InLocs[&MBB];
// Insert DBG_VALUE instructions, if not already inserted.
for (auto ILT : InLocsT) {
@@ -331,12 +317,13 @@ void LiveDebugValues::join(MachineBasicBlock &MBB, VarLocInMBB &OutLocs,
MI->getOperand(1).setImm(DMI->getOperand(1).getImm());
DEBUG(dbgs() << "Inserted: "; MI->dump(););
++NumInserted;
- MBBJoined = true; // rerun transfer().
+ Changed = true;
VarLoc V(ILT.Var, MI);
ILL.push_back(std::move(V));
}
}
+ return Changed;
}
/// Calculate the liveness information for the given machine function and
@@ -346,48 +333,72 @@ bool LiveDebugValues::ExtendRanges(MachineFunction &MF) {
DEBUG(dbgs() << "\nDebug Range Extension\n");
bool Changed = false;
- OLChanged = MBBJoined = false;
+ bool OLChanged = false;
+ bool MBBJoined = false;
VarLocList OpenRanges; // Ranges that are open until end of bb.
VarLocInMBB OutLocs; // Ranges that exist beyond bb.
VarLocInMBB InLocs; // Ranges that are incoming after joining.
- std::deque<MachineBasicBlock *> BBWorklist;
-
+ DenseMap<unsigned int, MachineBasicBlock *> OrderToBB;
+ DenseMap<MachineBasicBlock *, unsigned int> BBToOrder;
+ std::priority_queue<unsigned int, std::vector<unsigned int>,
+ std::greater<unsigned int>> Worklist;
+ std::priority_queue<unsigned int, std::vector<unsigned int>,
+ std::greater<unsigned int>> Pending;
// Initialize every mbb with OutLocs.
for (auto &MBB : MF)
for (auto &MI : MBB)
transfer(MI, OpenRanges, OutLocs);
DEBUG(printVarLocInMBB(OutLocs, "OutLocs after initialization", dbgs()));
- // Construct a worklist of MBBs.
- for (auto &MBB : MF)
- BBWorklist.push_back(&MBB);
-
- // Perform join() and transfer() using the worklist until the ranges converge
- // Ranges have converged when the worklist is empty.
- while (!BBWorklist.empty()) {
- MachineBasicBlock *MBB = BBWorklist.front();
- BBWorklist.pop_front();
-
- join(*MBB, OutLocs, InLocs);
+ ReversePostOrderTraversal<MachineFunction *> RPOT(&MF);
+ unsigned int RPONumber = 0;
+ for (auto RI = RPOT.begin(), RE = RPOT.end(); RI != RE; ++RI) {
+ OrderToBB[RPONumber] = *RI;
+ BBToOrder[*RI] = RPONumber;
+ Worklist.push(RPONumber);
+ ++RPONumber;
+ }
- if (MBBJoined) {
- Changed = true;
- for (auto &MI : *MBB)
- transfer(MI, OpenRanges, OutLocs);
- DEBUG(printVarLocInMBB(OutLocs, "OutLocs after propagating", dbgs()));
- DEBUG(printVarLocInMBB(InLocs, "InLocs after propagating", dbgs()));
-
- if (OLChanged) {
- OLChanged = false;
- for (auto s : MBB->successors())
- if (std::find(BBWorklist.begin(), BBWorklist.end(), s) ==
- BBWorklist.end()) // add if not already present.
- BBWorklist.push_back(s);
+ // This is a standard "union of predecessor outs" dataflow problem.
+ // To solve it, we perform join() and transfer() using the two worklist method
+ // until the ranges converge.
+ // Ranges have converged when both worklists are empty.
+ while (!Worklist.empty() || !Pending.empty()) {
+ // We track what is on the pending worklist to avoid inserting the same
+ // thing twice. We could avoid this with a custom priority queue, but this
+ // is probably not worth it.
+ SmallPtrSet<MachineBasicBlock *, 16> OnPending;
+ while (!Worklist.empty()) {
+ MachineBasicBlock *MBB = OrderToBB[Worklist.top()];
+ Worklist.pop();
+ MBBJoined = join(*MBB, OutLocs, InLocs);
+
+ if (MBBJoined) {
+ MBBJoined = false;
+ Changed = true;
+ for (auto &MI : *MBB)
+ OLChanged |= transfer(MI, OpenRanges, OutLocs);
+ DEBUG(printVarLocInMBB(OutLocs, "OutLocs after propagating", dbgs()));
+ DEBUG(printVarLocInMBB(InLocs, "InLocs after propagating", dbgs()));
+
+ if (OLChanged) {
+ OLChanged = false;
+ for (auto s : MBB->successors())
+ if (!OnPending.count(s)) {
+ OnPending.insert(s);
+ Pending.push(BBToOrder[s]);
+ }
+ }
}
}
+ Worklist.swap(Pending);
+ // At this point, pending must be empty, since it was just the empty
+ // worklist
+ assert(Pending.empty() && "Pending should be empty");
}
+
DEBUG(printVarLocInMBB(OutLocs, "Final OutLocs", dbgs()));
DEBUG(printVarLocInMBB(InLocs, "Final InLocs", dbgs()));
return Changed;
diff --git a/lib/CodeGen/LiveInterval.cpp b/lib/CodeGen/LiveInterval.cpp
index efad36ffa3f1..bb3488348f24 100644
--- a/lib/CodeGen/LiveInterval.cpp
+++ b/lib/CodeGen/LiveInterval.cpp
@@ -1328,15 +1328,15 @@ void LiveRangeUpdater::flush() {
LR->verify();
}
-unsigned ConnectedVNInfoEqClasses::Classify(const LiveInterval *LI) {
+unsigned ConnectedVNInfoEqClasses::Classify(const LiveRange &LR) {
// Create initial equivalence classes.
EqClass.clear();
- EqClass.grow(LI->getNumValNums());
+ EqClass.grow(LR.getNumValNums());
const VNInfo *used = nullptr, *unused = nullptr;
// Determine connections.
- for (const VNInfo *VNI : LI->valnos) {
+ for (const VNInfo *VNI : LR.valnos) {
// Group all unused values into one class.
if (VNI->isUnused()) {
if (unused)
@@ -1351,14 +1351,14 @@ unsigned ConnectedVNInfoEqClasses::Classify(const LiveInterval *LI) {
// Connect to values live out of predecessors.
for (MachineBasicBlock::const_pred_iterator PI = MBB->pred_begin(),
PE = MBB->pred_end(); PI != PE; ++PI)
- if (const VNInfo *PVNI = LI->getVNInfoBefore(LIS.getMBBEndIdx(*PI)))
+ if (const VNInfo *PVNI = LR.getVNInfoBefore(LIS.getMBBEndIdx(*PI)))
EqClass.join(VNI->id, PVNI->id);
} else {
// Normal value defined by an instruction. Check for two-addr redef.
// FIXME: This could be coincidental. Should we really check for a tied
// operand constraint?
// Note that VNI->def may be a use slot for an early clobber def.
- if (const VNInfo *UVNI = LI->getVNInfoBefore(VNI->def))
+ if (const VNInfo *UVNI = LR.getVNInfoBefore(VNI->def))
EqClass.join(VNI->id, UVNI->id);
}
}
diff --git a/lib/CodeGen/LiveIntervalAnalysis.cpp b/lib/CodeGen/LiveIntervalAnalysis.cpp
index 9451d92bd7ae..a506e0571c09 100644
--- a/lib/CodeGen/LiveIntervalAnalysis.cpp
+++ b/lib/CodeGen/LiveIntervalAnalysis.cpp
@@ -1446,7 +1446,7 @@ void LiveIntervals::removeVRegDefAt(LiveInterval &LI, SlotIndex Pos) {
void LiveIntervals::splitSeparateComponents(LiveInterval &LI,
SmallVectorImpl<LiveInterval*> &SplitLIs) {
ConnectedVNInfoEqClasses ConEQ(*this);
- unsigned NumComp = ConEQ.Classify(&LI);
+ unsigned NumComp = ConEQ.Classify(LI);
if (NumComp <= 1)
return;
DEBUG(dbgs() << " Split " << NumComp << " components: " << LI << '\n');
diff --git a/lib/CodeGen/MachineBasicBlock.cpp b/lib/CodeGen/MachineBasicBlock.cpp
index 76099f28499b..85d544d94984 100644
--- a/lib/CodeGen/MachineBasicBlock.cpp
+++ b/lib/CodeGen/MachineBasicBlock.cpp
@@ -1182,7 +1182,7 @@ MachineBasicBlock::getProbabilityIterator(MachineBasicBlock::succ_iterator I) {
/// Return whether (physical) register "Reg" has been <def>ined and not <kill>ed
/// as of just before "MI".
-///
+///
/// Search is localised to a neighborhood of
/// Neighborhood instructions before (searching for defs or kills) and N
/// instructions after (searching just for defs) MI.
diff --git a/lib/CodeGen/MachineFunctionPrinterPass.cpp b/lib/CodeGen/MachineFunctionPrinterPass.cpp
index 790f5accdb26..4f424ff292cc 100644
--- a/lib/CodeGen/MachineFunctionPrinterPass.cpp
+++ b/lib/CodeGen/MachineFunctionPrinterPass.cpp
@@ -31,7 +31,7 @@ struct MachineFunctionPrinterPass : public MachineFunctionPass {
const std::string Banner;
MachineFunctionPrinterPass() : MachineFunctionPass(ID), OS(dbgs()) { }
- MachineFunctionPrinterPass(raw_ostream &os, const std::string &banner)
+ MachineFunctionPrinterPass(raw_ostream &os, const std::string &banner)
: MachineFunctionPass(ID), OS(os), Banner(banner) {}
const char *getPassName() const override { return "MachineFunction Printer"; }
@@ -42,6 +42,8 @@ struct MachineFunctionPrinterPass : public MachineFunctionPass {
}
bool runOnMachineFunction(MachineFunction &MF) override {
+ if (!llvm::isFunctionInPrintList(MF.getName()))
+ return false;
OS << "# " << Banner << ":\n";
MF.print(OS, getAnalysisIfAvailable<SlotIndexes>());
return false;
diff --git a/lib/CodeGen/MachineInstr.cpp b/lib/CodeGen/MachineInstr.cpp
index 6b8eeccd173d..6dca74d60026 100644
--- a/lib/CodeGen/MachineInstr.cpp
+++ b/lib/CodeGen/MachineInstr.cpp
@@ -866,14 +866,44 @@ void MachineInstr::addMemOperand(MachineFunction &MF,
setMemRefs(NewMemRefs, NewMemRefs + NewNum);
}
+/// Check to see if the MMOs pointed to by the two MemRefs arrays are
+/// identical.
+static bool hasIdenticalMMOs(const MachineInstr &MI1, const MachineInstr &MI2) {
+ auto I1 = MI1.memoperands_begin(), E1 = MI1.memoperands_end();
+ auto I2 = MI2.memoperands_begin(), E2 = MI2.memoperands_end();
+ if ((E1 - I1) != (E2 - I2))
+ return false;
+ for (; I1 != E1; ++I1, ++I2) {
+ if (**I1 != **I2)
+ return false;
+ }
+ return true;
+}
+
std::pair<MachineInstr::mmo_iterator, unsigned>
MachineInstr::mergeMemRefsWith(const MachineInstr& Other) {
- // TODO: If we end up with too many memory operands, return the empty
- // conservative set rather than failing asserts.
+
+ // If either of the incoming memrefs are empty, we must be conservative and
+ // treat this as if we've exhausted our space for memrefs and dropped them.
+ if (memoperands_empty() || Other.memoperands_empty())
+ return std::make_pair(nullptr, 0);
+
+ // If both instructions have identical memrefs, we don't need to merge them.
+ // Since many instructions have a single memref, and we tend to merge things
+ // like pairs of loads from the same location, this catches a large number of
+ // cases in practice.
+ if (hasIdenticalMMOs(*this, Other))
+ return std::make_pair(MemRefs, NumMemRefs);
+
// TODO: consider uniquing elements within the operand lists to reduce
// space usage and fall back to conservative information less often.
- size_t CombinedNumMemRefs = (memoperands_end() - memoperands_begin())
- + (Other.memoperands_end() - Other.memoperands_begin());
+ size_t CombinedNumMemRefs = NumMemRefs + Other.NumMemRefs;
+
+ // If we don't have enough room to store this many memrefs, be conservative
+ // and drop them. Otherwise, we'd fail asserts when trying to add them to
+ // the new instruction.
+ if (CombinedNumMemRefs != uint8_t(CombinedNumMemRefs))
+ return std::make_pair(nullptr, 0);
MachineFunction *MF = getParent()->getParent();
mmo_iterator MemBegin = MF->allocateMemRefsArray(CombinedNumMemRefs);
diff --git a/lib/CodeGen/MachineLICM.cpp b/lib/CodeGen/MachineLICM.cpp
index a8368e9c80d6..99a97d2dbd74 100644
--- a/lib/CodeGen/MachineLICM.cpp
+++ b/lib/CodeGen/MachineLICM.cpp
@@ -334,12 +334,11 @@ static bool InstructionStoresToFI(const MachineInstr *MI, int FI) {
// writes to all slots.
if (MI->memoperands_empty())
return true;
- for (MachineInstr::mmo_iterator o = MI->memoperands_begin(),
- oe = MI->memoperands_end(); o != oe; ++o) {
- if (!(*o)->isStore() || !(*o)->getPseudoValue())
+ for (const MachineMemOperand *MemOp : MI->memoperands()) {
+ if (!MemOp->isStore() || !MemOp->getPseudoValue())
continue;
if (const FixedStackPseudoSourceValue *Value =
- dyn_cast<FixedStackPseudoSourceValue>((*o)->getPseudoValue())) {
+ dyn_cast<FixedStackPseudoSourceValue>(MemOp->getPseudoValue())) {
if (Value->getFrameIndex() == FI)
return true;
}
@@ -357,8 +356,7 @@ void MachineLICM::ProcessMI(MachineInstr *MI,
bool RuledOut = false;
bool HasNonInvariantUse = false;
unsigned Def = 0;
- for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
- const MachineOperand &MO = MI->getOperand(i);
+ for (const MachineOperand &MO : MI->operands()) {
if (MO.isFI()) {
// Remember if the instruction stores to the frame index.
int FI = MO.getIndex();
@@ -452,9 +450,7 @@ void MachineLICM::HoistRegionPostRA() {
// Walk the entire region, count number of defs for each register, and
// collect potential LICM candidates.
const std::vector<MachineBasicBlock *> &Blocks = CurLoop->getBlocks();
- for (unsigned i = 0, e = Blocks.size(); i != e; ++i) {
- MachineBasicBlock *BB = Blocks[i];
-
+ for (MachineBasicBlock *BB : Blocks) {
// If the header of the loop containing this basic block is a landing pad,
// then don't try to hoist instructions out of this loop.
const MachineLoop *ML = MLI->getLoopFor(BB);
@@ -469,19 +465,15 @@ void MachineLICM::HoistRegionPostRA() {
}
SpeculationState = SpeculateUnknown;
- for (MachineBasicBlock::iterator
- MII = BB->begin(), E = BB->end(); MII != E; ++MII) {
- MachineInstr *MI = &*MII;
- ProcessMI(MI, PhysRegDefs, PhysRegClobbers, StoredFIs, Candidates);
- }
+ for (MachineInstr &MI : *BB)
+ ProcessMI(&MI, PhysRegDefs, PhysRegClobbers, StoredFIs, Candidates);
}
// Gather the registers read / clobbered by the terminator.
BitVector TermRegs(NumRegs);
MachineBasicBlock::iterator TI = Preheader->getFirstTerminator();
if (TI != Preheader->end()) {
- for (unsigned i = 0, e = TI->getNumOperands(); i != e; ++i) {
- const MachineOperand &MO = TI->getOperand(i);
+ for (const MachineOperand &MO : TI->operands()) {
if (!MO.isReg())
continue;
unsigned Reg = MO.getReg();
@@ -500,17 +492,16 @@ void MachineLICM::HoistRegionPostRA() {
// 3. Make sure candidate def should not clobber
// registers read by the terminator. Similarly its def should not be
// clobbered by the terminator.
- for (unsigned i = 0, e = Candidates.size(); i != e; ++i) {
- if (Candidates[i].FI != INT_MIN &&
- StoredFIs.count(Candidates[i].FI))
+ for (CandidateInfo &Candidate : Candidates) {
+ if (Candidate.FI != INT_MIN &&
+ StoredFIs.count(Candidate.FI))
continue;
- unsigned Def = Candidates[i].Def;
+ unsigned Def = Candidate.Def;
if (!PhysRegClobbers.test(Def) && !TermRegs.test(Def)) {
bool Safe = true;
- MachineInstr *MI = Candidates[i].MI;
- for (unsigned j = 0, ee = MI->getNumOperands(); j != ee; ++j) {
- const MachineOperand &MO = MI->getOperand(j);
+ MachineInstr *MI = Candidate.MI;
+ for (const MachineOperand &MO : MI->operands()) {
if (!MO.isReg() || MO.isDef() || !MO.getReg())
continue;
unsigned Reg = MO.getReg();
@@ -523,7 +514,7 @@ void MachineLICM::HoistRegionPostRA() {
}
}
if (Safe)
- HoistPostRA(MI, Candidates[i].Def);
+ HoistPostRA(MI, Candidate.Def);
}
}
}
@@ -532,15 +523,11 @@ void MachineLICM::HoistRegionPostRA() {
/// sure it is not killed by any instructions in the loop.
void MachineLICM::AddToLiveIns(unsigned Reg) {
const std::vector<MachineBasicBlock *> &Blocks = CurLoop->getBlocks();
- for (unsigned i = 0, e = Blocks.size(); i != e; ++i) {
- MachineBasicBlock *BB = Blocks[i];
+ for (MachineBasicBlock *BB : Blocks) {
if (!BB->isLiveIn(Reg))
BB->addLiveIn(Reg);
- for (MachineBasicBlock::iterator
- MII = BB->begin(), E = BB->end(); MII != E; ++MII) {
- MachineInstr *MI = &*MII;
- for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
- MachineOperand &MO = MI->getOperand(i);
+ for (MachineInstr &MI : *BB) {
+ for (MachineOperand &MO : MI.operands()) {
if (!MO.isReg() || !MO.getReg() || MO.isDef()) continue;
if (MO.getReg() == Reg || TRI->isSuperRegister(Reg, MO.getReg()))
MO.setIsKill(false);
@@ -582,8 +569,8 @@ bool MachineLICM::IsGuaranteedToExecute(MachineBasicBlock *BB) {
// Check loop exiting blocks.
SmallVector<MachineBasicBlock*, 8> CurrentLoopExitingBlocks;
CurLoop->getExitingBlocks(CurrentLoopExitingBlocks);
- for (unsigned i = 0, e = CurrentLoopExitingBlocks.size(); i != e; ++i)
- if (!DT->dominates(BB, CurrentLoopExitingBlocks[i])) {
+ for (MachineBasicBlock *CurrentLoopExitingBlock : CurrentLoopExitingBlocks)
+ if (!DT->dominates(BB, CurrentLoopExitingBlock)) {
SpeculationState = SpeculateTrue;
return false;
}
@@ -689,8 +676,7 @@ void MachineLICM::HoistOutOfLoop(MachineDomTreeNode *HeaderN) {
InitRegPressure(Preheader);
// Now perform LICM.
- for (unsigned i = 0, e = Scopes.size(); i != e; ++i) {
- MachineDomTreeNode *Node = Scopes[i];
+ for (MachineDomTreeNode *Node : Scopes) {
MachineBasicBlock *MBB = Node->getBlock();
EnterScope(MBB);
@@ -858,13 +844,11 @@ static bool mayLoadFromGOTOrConstantPool(MachineInstr &MI) {
if (MI.memoperands_empty())
return true;
- for (MachineInstr::mmo_iterator I = MI.memoperands_begin(),
- E = MI.memoperands_end(); I != E; ++I) {
- if (const PseudoSourceValue *PSV = (*I)->getPseudoValue()) {
+ for (MachineMemOperand *MemOp : MI.memoperands())
+ if (const PseudoSourceValue *PSV = MemOp->getPseudoValue())
if (PSV->isGOT() || PSV->isConstantPool())
return true;
- }
- }
+
return false;
}
@@ -899,9 +883,7 @@ bool MachineLICM::IsLoopInvariantInst(MachineInstr &I) {
return false;
// The instruction is loop invariant if all of its operands are.
- for (unsigned i = 0, e = I.getNumOperands(); i != e; ++i) {
- const MachineOperand &MO = I.getOperand(i);
-
+ for (const MachineOperand &MO : I.operands()) {
if (!MO.isReg())
continue;
@@ -1230,11 +1212,8 @@ MachineInstr *MachineLICM::ExtractHoistableLoad(MachineInstr *MI) {
/// preheader that may become duplicates of instructions that are hoisted
/// out of the loop.
void MachineLICM::InitCSEMap(MachineBasicBlock *BB) {
- for (MachineBasicBlock::iterator I = BB->begin(),E = BB->end(); I != E; ++I) {
- const MachineInstr *MI = &*I;
- unsigned Opcode = MI->getOpcode();
- CSEMap[Opcode].push_back(MI);
- }
+ for (MachineInstr &MI : *BB)
+ CSEMap[MI.getOpcode()].push_back(&MI);
}
/// Find an instruction amount PrevMIs that is a duplicate of MI.
@@ -1242,11 +1221,10 @@ void MachineLICM::InitCSEMap(MachineBasicBlock *BB) {
const MachineInstr*
MachineLICM::LookForDuplicate(const MachineInstr *MI,
std::vector<const MachineInstr*> &PrevMIs) {
- for (unsigned i = 0, e = PrevMIs.size(); i != e; ++i) {
- const MachineInstr *PrevMI = PrevMIs[i];
+ for (const MachineInstr *PrevMI : PrevMIs)
if (TII->produceSameValue(MI, PrevMI, (PreRegAlloc ? MRI : nullptr)))
return PrevMI;
- }
+
return nullptr;
}
@@ -1296,8 +1274,7 @@ bool MachineLICM::EliminateCSE(MachineInstr *MI,
}
}
- for (unsigned i = 0, e = Defs.size(); i != e; ++i) {
- unsigned Idx = Defs[i];
+ for (unsigned Idx : Defs) {
unsigned Reg = MI->getOperand(Idx).getReg();
unsigned DupReg = Dup->getOperand(Idx).getReg();
MRI->replaceRegWith(Reg, DupReg);
@@ -1370,11 +1347,9 @@ bool MachineLICM::Hoist(MachineInstr *MI, MachineBasicBlock *Preheader) {
// Clear the kill flags of any register this instruction defines,
// since they may need to be live throughout the entire loop
// rather than just live for part of it.
- for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
- MachineOperand &MO = MI->getOperand(i);
+ for (MachineOperand &MO : MI->operands())
if (MO.isReg() && MO.isDef() && !MO.isDead())
MRI->clearKillFlags(MO.getReg());
- }
// Add to the CSE map.
if (CI != CSEMap.end())
diff --git a/lib/CodeGen/MachineVerifier.cpp b/lib/CodeGen/MachineVerifier.cpp
index cdcd8eb4fbdf..428295ec2cc6 100644
--- a/lib/CodeGen/MachineVerifier.cpp
+++ b/lib/CodeGen/MachineVerifier.cpp
@@ -1736,7 +1736,7 @@ void MachineVerifier::verifyLiveInterval(const LiveInterval &LI) {
// Check the LI only has one connected component.
ConnectedVNInfoEqClasses ConEQ(*LiveInts);
- unsigned NumComp = ConEQ.Classify(&LI);
+ unsigned NumComp = ConEQ.Classify(LI);
if (NumComp > 1) {
report("Multiple connected components in live interval", MF);
report_context(LI);
diff --git a/lib/CodeGen/RegisterCoalescer.cpp b/lib/CodeGen/RegisterCoalescer.cpp
index e7b32179bde5..c1ff13ec7ca0 100644
--- a/lib/CodeGen/RegisterCoalescer.cpp
+++ b/lib/CodeGen/RegisterCoalescer.cpp
@@ -2874,7 +2874,7 @@ void RegisterCoalescer::joinAllIntervals() {
std::vector<MBBPriorityInfo> MBBs;
MBBs.reserve(MF->size());
- for (MachineFunction::iterator I = MF->begin(), E = MF->end();I != E;++I){
+ for (MachineFunction::iterator I = MF->begin(), E = MF->end(); I != E; ++I) {
MachineBasicBlock *MBB = &*I;
MBBs.push_back(MBBPriorityInfo(MBB, Loops->getLoopDepth(MBB),
JoinSplitEdges && isSplitEdge(MBB)));
diff --git a/lib/CodeGen/RegisterPressure.cpp b/lib/CodeGen/RegisterPressure.cpp
index 3749b1dd217a..f33dc3e10492 100644
--- a/lib/CodeGen/RegisterPressure.cpp
+++ b/lib/CodeGen/RegisterPressure.cpp
@@ -313,21 +313,6 @@ static bool containsReg(ArrayRef<unsigned> RegUnits, unsigned RegUnit) {
namespace {
-/// List of register defined and used by a machine instruction.
-class RegisterOperands {
-public:
- SmallVector<unsigned, 8> Uses;
- SmallVector<unsigned, 8> Defs;
- SmallVector<unsigned, 8> DeadDefs;
-
- void collect(const MachineInstr &MI, const TargetRegisterInfo &TRI,
- const MachineRegisterInfo &MRI, bool IgnoreDead = false);
-
- /// Use liveness information to find dead defs not marked with a dead flag
- /// and move them to the DeadDefs vector.
- void detectDeadDefs(const MachineInstr &MI, const LiveIntervals &LIS);
-};
-
/// Collect this instruction's unique uses and defs into SmallVectors for
/// processing defs and uses in order.
///
@@ -385,9 +370,11 @@ class RegisterOperandsCollector {
}
}
- friend class RegisterOperands;
+ friend class llvm::RegisterOperands;
};
+} // namespace
+
void RegisterOperands::collect(const MachineInstr &MI,
const TargetRegisterInfo &TRI,
const MachineRegisterInfo &MRI,
@@ -417,8 +404,6 @@ void RegisterOperands::detectDeadDefs(const MachineInstr &MI,
}
}
-} // namespace
-
/// Initialize an array of N PressureDiffs.
void PressureDiffs::init(unsigned N) {
Size = N;
@@ -431,6 +416,18 @@ void PressureDiffs::init(unsigned N) {
PDiffArray = reinterpret_cast<PressureDiff*>(calloc(N, sizeof(PressureDiff)));
}
+void PressureDiffs::addInstruction(unsigned Idx,
+ const RegisterOperands &RegOpers,
+ const MachineRegisterInfo &MRI) {
+ PressureDiff &PDiff = (*this)[Idx];
+ assert(!PDiff.begin()->isValid() && "stale PDiff");
+ for (unsigned Reg : RegOpers.Defs)
+ PDiff.addPressureChange(Reg, true, &MRI);
+
+ for (unsigned Reg : RegOpers.Uses)
+ PDiff.addPressureChange(Reg, false, &MRI);
+}
+
/// Add a change in pressure to the pressure diff of a given instruction.
void PressureDiff::addPressureChange(unsigned RegUnit, bool IsDec,
const MachineRegisterInfo *MRI) {
@@ -467,18 +464,6 @@ void PressureDiff::addPressureChange(unsigned RegUnit, bool IsDec,
}
}
-/// Record the pressure difference induced by the given operand list.
-static void collectPDiff(PressureDiff &PDiff, RegisterOperands &RegOpers,
- const MachineRegisterInfo *MRI) {
- assert(!PDiff.begin()->isValid() && "stale PDiff");
-
- for (unsigned Reg : RegOpers.Defs)
- PDiff.addPressureChange(Reg, true, MRI);
-
- for (unsigned Reg : RegOpers.Uses)
- PDiff.addPressureChange(Reg, false, MRI);
-}
-
/// Force liveness of registers.
void RegPressureTracker::addLiveRegs(ArrayRef<unsigned> Regs) {
for (unsigned Reg : Regs) {
@@ -514,39 +499,10 @@ void RegPressureTracker::discoverLiveOut(unsigned Reg) {
/// registers that are both defined and used by the instruction. If a pressure
/// difference pointer is provided record the changes is pressure caused by this
/// instruction independent of liveness.
-void RegPressureTracker::recede(SmallVectorImpl<unsigned> *LiveUses,
- PressureDiff *PDiff) {
- assert(CurrPos != MBB->begin());
- if (!isBottomClosed())
- closeBottom();
-
- // Open the top of the region using block iterators.
- if (!RequireIntervals && isTopClosed())
- static_cast<RegionPressure&>(P).openTop(CurrPos);
-
- // Find the previous instruction.
- do
- --CurrPos;
- while (CurrPos != MBB->begin() && CurrPos->isDebugValue());
+void RegPressureTracker::recede(const RegisterOperands &RegOpers,
+ SmallVectorImpl<unsigned> *LiveUses) {
assert(!CurrPos->isDebugValue());
- SlotIndex SlotIdx;
- if (RequireIntervals)
- SlotIdx = LIS->getInstructionIndex(CurrPos).getRegSlot();
-
- // Open the top of the region using slot indexes.
- if (RequireIntervals && isTopClosed())
- static_cast<IntervalPressure&>(P).openTop(SlotIdx);
-
- const MachineInstr &MI = *CurrPos;
- RegisterOperands RegOpers;
- RegOpers.collect(MI, *TRI, *MRI);
- if (RequireIntervals)
- RegOpers.detectDeadDefs(MI, *LIS);
-
- if (PDiff)
- collectPDiff(*PDiff, RegOpers, MRI);
-
// Boost pressure for all dead defs together.
increaseRegPressure(RegOpers.DeadDefs);
decreaseRegPressure(RegOpers.DeadDefs);
@@ -560,6 +516,10 @@ void RegPressureTracker::recede(SmallVectorImpl<unsigned> *LiveUses,
discoverLiveOut(Reg);
}
+ SlotIndex SlotIdx;
+ if (RequireIntervals)
+ SlotIdx = LIS->getInstructionIndex(CurrPos).getRegSlot();
+
// Generate liveness for uses.
for (unsigned Reg : RegOpers.Uses) {
if (!LiveRegs.contains(Reg)) {
@@ -586,6 +546,41 @@ void RegPressureTracker::recede(SmallVectorImpl<unsigned> *LiveUses,
}
}
+void RegPressureTracker::recedeSkipDebugValues() {
+ assert(CurrPos != MBB->begin());
+ if (!isBottomClosed())
+ closeBottom();
+
+ // Open the top of the region using block iterators.
+ if (!RequireIntervals && isTopClosed())
+ static_cast<RegionPressure&>(P).openTop(CurrPos);
+
+ // Find the previous instruction.
+ do
+ --CurrPos;
+ while (CurrPos != MBB->begin() && CurrPos->isDebugValue());
+
+ SlotIndex SlotIdx;
+ if (RequireIntervals)
+ SlotIdx = LIS->getInstructionIndex(CurrPos).getRegSlot();
+
+ // Open the top of the region using slot indexes.
+ if (RequireIntervals && isTopClosed())
+ static_cast<IntervalPressure&>(P).openTop(SlotIdx);
+}
+
+void RegPressureTracker::recede(SmallVectorImpl<unsigned> *LiveUses) {
+ recedeSkipDebugValues();
+
+ const MachineInstr &MI = *CurrPos;
+ RegisterOperands RegOpers;
+ RegOpers.collect(MI, *TRI, *MRI);
+ if (RequireIntervals)
+ RegOpers.detectDeadDefs(MI, *LIS);
+
+ recede(RegOpers, LiveUses);
+}
+
/// Advance across the current instruction.
void RegPressureTracker::advance() {
assert(!TrackUntiedDefs && "unsupported mode");
diff --git a/lib/CodeGen/ScheduleDAGInstrs.cpp b/lib/CodeGen/ScheduleDAGInstrs.cpp
index fb82ab7a5555..11b246a8de25 100644
--- a/lib/CodeGen/ScheduleDAGInstrs.cpp
+++ b/lib/CodeGen/ScheduleDAGInstrs.cpp
@@ -896,11 +896,16 @@ void ScheduleDAGInstrs::buildSchedGraph(AliasAnalysis *AA,
assert(SU && "No SUnit mapped to this MI");
if (RPTracker) {
- PressureDiff *PDiff = PDiffs ? &(*PDiffs)[SU->NodeNum] : nullptr;
- RPTracker->recede(/*LiveUses=*/nullptr, PDiff);
- assert(RPTracker->getPos() == std::prev(MII) &&
- "RPTracker can't find MI");
collectVRegUses(SU);
+
+ RegisterOperands RegOpers;
+ RegOpers.collect(*MI, *TRI, MRI);
+ if (PDiffs != nullptr)
+ PDiffs->addInstruction(SU->NodeNum, RegOpers, MRI);
+
+ RPTracker->recedeSkipDebugValues();
+ assert(&*RPTracker->getPos() == MI && "RPTracker in sync");
+ RPTracker->recede(RegOpers);
}
assert(
@@ -1005,6 +1010,9 @@ void ScheduleDAGInstrs::buildSchedGraph(AliasAnalysis *AA,
addChainDependency(AAForDep, MFI, MF.getDataLayout(), SU,
I->second[i], RejectMemNodes, TrueMemOrderLatency);
}
+ // This call must come after calls to addChainDependency() since it
+ // consumes the 'RejectMemNodes' list that addChainDependency() possibly
+ // adds to.
adjustChainDeps(AA, MFI, MF.getDataLayout(), SU, &ExitSU, RejectMemNodes,
TrueMemOrderLatency);
PendingLoads.clear();
@@ -1086,6 +1094,9 @@ void ScheduleDAGInstrs::buildSchedGraph(AliasAnalysis *AA,
addChainDependency(AAForDep, MFI, MF.getDataLayout(), SU, AliasChain,
RejectMemNodes);
}
+ // This call must come after calls to addChainDependency() since it
+ // consumes the 'RejectMemNodes' list that addChainDependency() possibly
+ // adds to.
adjustChainDeps(AA, MFI, MF.getDataLayout(), SU, &ExitSU, RejectMemNodes,
TrueMemOrderLatency);
} else if (MI->mayLoad()) {
@@ -1133,13 +1144,16 @@ void ScheduleDAGInstrs::buildSchedGraph(AliasAnalysis *AA,
else
NonAliasMemUses[V].push_back(SU);
}
- if (MayAlias)
- adjustChainDeps(AA, MFI, MF.getDataLayout(), SU, &ExitSU,
- RejectMemNodes, /*Latency=*/0);
// Add dependencies on alias and barrier chains, if needed.
if (MayAlias && AliasChain)
addChainDependency(AAForDep, MFI, MF.getDataLayout(), SU, AliasChain,
RejectMemNodes);
+ if (MayAlias)
+ // This call must come after calls to addChainDependency() since it
+ // consumes the 'RejectMemNodes' list that addChainDependency()
+ // possibly adds to.
+ adjustChainDeps(AA, MFI, MF.getDataLayout(), SU, &ExitSU,
+ RejectMemNodes, /*Latency=*/0);
if (BarrierChain)
BarrierChain->addPred(SDep(SU, SDep::Barrier));
}
diff --git a/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index bc2405b952a6..c741982bc08d 100644
--- a/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -7325,6 +7325,7 @@ SDValue DAGCombiner::visitBITCAST(SDNode *N) {
// fold (bitcast (fneg x)) ->
// flipbit = signbit
// (xor (bitcast x) (build_pair flipbit, flipbit))
+ //
// fold (bitcast (fabs x)) ->
// flipbit = (and (extract_element (bitcast x), 0), signbit)
// (xor (bitcast x) (build_pair flipbit, flipbit))
@@ -8794,20 +8795,21 @@ SDValue DAGCombiner::visitFSQRT(SDNode *N) {
ZeroCmp, Zero, RV);
}
+/// copysign(x, fp_extend(y)) -> copysign(x, y)
+/// copysign(x, fp_round(y)) -> copysign(x, y)
static inline bool CanCombineFCOPYSIGN_EXTEND_ROUND(SDNode *N) {
- // copysign(x, fp_extend(y)) -> copysign(x, y)
- // copysign(x, fp_round(y)) -> copysign(x, y)
- // Do not optimize out type conversion of f128 type yet.
- // For some target like x86_64, configuration is changed
- // to keep one f128 value in one SSE register, but
- // instruction selection cannot handle FCOPYSIGN on
- // SSE registers yet.
SDValue N1 = N->getOperand(1);
- EVT N1VT = N1->getValueType(0);
- EVT N1Op0VT = N1->getOperand(0)->getValueType(0);
- return (N1.getOpcode() == ISD::FP_EXTEND ||
- N1.getOpcode() == ISD::FP_ROUND) &&
- (N1VT == N1Op0VT || N1Op0VT != MVT::f128);
+ if ((N1.getOpcode() == ISD::FP_EXTEND ||
+ N1.getOpcode() == ISD::FP_ROUND)) {
+ // Do not optimize out type conversion of f128 type yet.
+ // For some targets like x86_64, configuration is changed to keep one f128
+ // value in one SSE register, but instruction selection cannot handle
+ // FCOPYSIGN on SSE registers yet.
+ EVT N1VT = N1->getValueType(0);
+ EVT N1Op0VT = N1->getOperand(0)->getValueType(0);
+ return (N1VT == N1Op0VT || N1Op0VT != MVT::f128);
+ }
+ return false;
}
SDValue DAGCombiner::visitFCOPYSIGN(SDNode *N) {
diff --git a/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp b/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp
index b62bd2bd63ee..08815ed787dc 100644
--- a/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp
+++ b/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp
@@ -297,8 +297,6 @@ void FunctionLoweringInfo::set(const Function &fn, MachineFunction &mf,
else if (Personality == EHPersonality::CoreCLR)
calculateClrEHStateNumbers(&fn, EHInfo);
- calculateCatchReturnSuccessorColors(&fn, EHInfo);
-
// Map all BB references in the WinEH data to MBBs.
for (WinEHTryBlockMapEntry &TBME : EHInfo.TryBlockMap) {
for (WinEHHandlerType &H : TBME.HandlerArray) {
diff --git a/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp b/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
index f46767f6c4a1..5d572c4c2b02 100644
--- a/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
+++ b/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
@@ -2941,6 +2941,18 @@ SDValue SelectionDAGLegalize::ExpandBitCount(unsigned Opc, SDValue Op,
// This trivially expands to CTLZ.
return DAG.getNode(ISD::CTLZ, dl, Op.getValueType(), Op);
case ISD::CTLZ: {
+ EVT VT = Op.getValueType();
+ unsigned len = VT.getSizeInBits();
+
+ if (TLI.isOperationLegalOrCustom(ISD::CTLZ_ZERO_UNDEF, VT)) {
+ EVT SetCCVT = getSetCCResultType(VT);
+ SDValue CTLZ = DAG.getNode(ISD::CTLZ_ZERO_UNDEF, dl, VT, Op);
+ SDValue Zero = DAG.getConstant(0, dl, VT);
+ SDValue SrcIsZero = DAG.getSetCC(dl, SetCCVT, Op, Zero, ISD::SETEQ);
+ return DAG.getNode(ISD::SELECT, dl, VT, SrcIsZero,
+ DAG.getConstant(len, dl, VT), CTLZ);
+ }
+
// for now, we do this:
// x = x | (x >> 1);
// x = x | (x >> 2);
@@ -2950,9 +2962,7 @@ SDValue SelectionDAGLegalize::ExpandBitCount(unsigned Opc, SDValue Op,
// return popcount(~x);
//
// Ref: "Hacker's Delight" by Henry Warren
- EVT VT = Op.getValueType();
EVT ShVT = TLI.getShiftAmountTy(VT, DAG.getDataLayout());
- unsigned len = VT.getSizeInBits();
for (unsigned i = 0; (1U << i) <= (len / 2); ++i) {
SDValue Tmp3 = DAG.getConstant(1ULL << i, dl, ShVT);
Op = DAG.getNode(ISD::OR, dl, VT, Op,
diff --git a/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp b/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp
index cd114d668e20..74f80db6d01b 100644
--- a/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp
+++ b/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp
@@ -262,12 +262,8 @@ SDValue DAGTypeLegalizer::PromoteIntRes_BITCAST(SDNode *N) {
return DAG.getNode(ISD::ANY_EXTEND, dl, NOutVT, GetSoftenedFloat(InOp));
case TargetLowering::TypePromoteFloat: {
// Convert the promoted float by hand.
- if (NOutVT.bitsEq(NInVT)) {
- SDValue PromotedOp = GetPromotedFloat(InOp);
- SDValue Trunc = DAG.getNode(ISD::FP_TO_FP16, dl, NOutVT, PromotedOp);
- return DAG.getNode(ISD::AssertZext, dl, NOutVT, Trunc,
- DAG.getValueType(OutVT));
- }
+ SDValue PromotedOp = GetPromotedFloat(InOp);
+ return DAG.getNode(ISD::FP_TO_FP16, dl, NOutVT, PromotedOp);
break;
}
case TargetLowering::TypeExpandInteger:
diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index e446a934554e..45ae39af7600 100644
--- a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -1205,8 +1205,13 @@ void SelectionDAGBuilder::visitCatchRet(const CatchReturnInst &I) {
// Figure out the funclet membership for the catchret's successor.
// This will be used by the FuncletLayout pass to determine how to order the
// BB's.
- WinEHFuncInfo *EHInfo = DAG.getMachineFunction().getWinEHFuncInfo();
- const BasicBlock *SuccessorColor = EHInfo->CatchRetSuccessorColorMap[&I];
+ // A 'catchret' returns to the outer scope's color.
+ Value *ParentPad = I.getParentPad();
+ const BasicBlock *SuccessorColor;
+ if (isa<ConstantTokenNone>(ParentPad))
+ SuccessorColor = &FuncInfo.Fn->getEntryBlock();
+ else
+ SuccessorColor = cast<Instruction>(ParentPad)->getParent();
assert(SuccessorColor && "No parent funclet for catchret!");
MachineBasicBlock *SuccessorColorMBB = FuncInfo.MBBMap[SuccessorColor];
assert(SuccessorColorMBB && "No MBB for SuccessorColor!");
diff --git a/lib/CodeGen/SelectionDAG/StatepointLowering.cpp b/lib/CodeGen/SelectionDAG/StatepointLowering.cpp
index 6547a62d0778..02545a730656 100644
--- a/lib/CodeGen/SelectionDAG/StatepointLowering.cpp
+++ b/lib/CodeGen/SelectionDAG/StatepointLowering.cpp
@@ -461,7 +461,9 @@ static void lowerIncomingStatepointValue(SDValue Incoming,
// If the original value was a constant, make sure it gets recorded as
// such in the stackmap. This is required so that the consumer can
// parse any internal format to the deopt state. It also handles null
- // pointers and other constant pointers in GC states
+ // pointers and other constant pointers in GC states. Note the constant
+ // vectors do not appear to actually hit this path and that anything larger
+ // than an i64 value (not type!) will fail asserts here.
pushStackMapConstant(Ops, Builder, C->getSExtValue());
} else if (FrameIndexSDNode *FI = dyn_cast<FrameIndexSDNode>(Incoming)) {
// This handles allocas as arguments to the statepoint (this is only
@@ -505,27 +507,27 @@ static void lowerStatepointMetaArgs(SmallVectorImpl<SDValue> &Ops,
#ifndef NDEBUG
// Check that each of the gc pointer and bases we've gotten out of the
- // safepoint is something the strategy thinks might be a pointer into the GC
- // heap. This is basically just here to help catch errors during statepoint
- // insertion. TODO: This should actually be in the Verifier, but we can't get
- // to the GCStrategy from there (yet).
+ // safepoint is something the strategy thinks might be a pointer (or vector
+ // of pointers) into the GC heap. This is basically just here to help catch
+ // errors during statepoint insertion. TODO: This should actually be in the
+ // Verifier, but we can't get to the GCStrategy from there (yet).
GCStrategy &S = Builder.GFI->getStrategy();
for (const Value *V : Bases) {
- auto Opt = S.isGCManagedPointer(V->getType());
+ auto Opt = S.isGCManagedPointer(V->getType()->getScalarType());
if (Opt.hasValue()) {
assert(Opt.getValue() &&
"non gc managed base pointer found in statepoint");
}
}
for (const Value *V : Ptrs) {
- auto Opt = S.isGCManagedPointer(V->getType());
+ auto Opt = S.isGCManagedPointer(V->getType()->getScalarType());
if (Opt.hasValue()) {
assert(Opt.getValue() &&
"non gc managed derived pointer found in statepoint");
}
}
for (const Value *V : Relocations) {
- auto Opt = S.isGCManagedPointer(V->getType());
+ auto Opt = S.isGCManagedPointer(V->getType()->getScalarType());
if (Opt.hasValue()) {
assert(Opt.getValue() && "non gc managed pointer relocated");
}
diff --git a/lib/CodeGen/ShrinkWrap.cpp b/lib/CodeGen/ShrinkWrap.cpp
index f8aa1e2b0b9a..d361a6c4ad06 100644
--- a/lib/CodeGen/ShrinkWrap.cpp
+++ b/lib/CodeGen/ShrinkWrap.cpp
@@ -47,6 +47,7 @@
// MachineFrameInfo is updated with this information.
//===----------------------------------------------------------------------===//
#include "llvm/ADT/BitVector.h"
+#include "llvm/ADT/PostOrderIterator.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/Statistic.h"
// To check for profitability.
@@ -263,6 +264,8 @@ MachineBasicBlock *FindIDom(MachineBasicBlock &Block, ListOfBBs BBs,
if (!IDom)
break;
}
+ if (IDom == &Block)
+ return nullptr;
return IDom;
}
@@ -352,13 +355,9 @@ void ShrinkWrap::updateSaveRestorePoints(MachineBasicBlock &MBB,
if (MLI->getLoopDepth(Save) > MLI->getLoopDepth(Restore)) {
// Push Save outside of this loop if immediate dominator is different
// from save block. If immediate dominator is not different, bail out.
- MachineBasicBlock *IDom = FindIDom<>(*Save, Save->predecessors(), *MDT);
- if (IDom != Save)
- Save = IDom;
- else {
- Save = nullptr;
+ Save = FindIDom<>(*Save, Save->predecessors(), *MDT);
+ if (!Save)
break;
- }
} else {
// If the loop does not exit, there is no point in looking
// for a post-dominator outside the loop.
@@ -386,6 +385,41 @@ void ShrinkWrap::updateSaveRestorePoints(MachineBasicBlock &MBB,
}
}
+/// Check whether the edge (\p SrcBB, \p DestBB) is a backedge according to MLI.
+/// I.e., check if it exists a loop that contains SrcBB and where DestBB is the
+/// loop header.
+static bool isProperBackedge(const MachineLoopInfo &MLI,
+ const MachineBasicBlock *SrcBB,
+ const MachineBasicBlock *DestBB) {
+ for (const MachineLoop *Loop = MLI.getLoopFor(SrcBB); Loop;
+ Loop = Loop->getParentLoop()) {
+ if (Loop->getHeader() == DestBB)
+ return true;
+ }
+ return false;
+}
+
+/// Check if the CFG of \p MF is irreducible.
+static bool isIrreducibleCFG(const MachineFunction &MF,
+ const MachineLoopInfo &MLI) {
+ const MachineBasicBlock *Entry = &*MF.begin();
+ ReversePostOrderTraversal<const MachineBasicBlock *> RPOT(Entry);
+ BitVector VisitedBB(MF.getNumBlockIDs());
+ for (const MachineBasicBlock *MBB : RPOT) {
+ VisitedBB.set(MBB->getNumber());
+ for (const MachineBasicBlock *SuccBB : MBB->successors()) {
+ if (!VisitedBB.test(SuccBB->getNumber()))
+ continue;
+ // We already visited SuccBB, thus MBB->SuccBB must be a backedge.
+ // Check that the head matches what we have in the loop information.
+ // Otherwise, we have an irreducible graph.
+ if (!isProperBackedge(MLI, MBB, SuccBB))
+ return true;
+ }
+ }
+ return false;
+}
+
bool ShrinkWrap::runOnMachineFunction(MachineFunction &MF) {
if (MF.empty() || !isShrinkWrapEnabled(MF))
return false;
@@ -394,6 +428,17 @@ bool ShrinkWrap::runOnMachineFunction(MachineFunction &MF) {
init(MF);
+ if (isIrreducibleCFG(MF, *MLI)) {
+ // If MF is irreducible, a block may be in a loop without
+ // MachineLoopInfo reporting it. I.e., we may use the
+ // post-dominance property in loops, which lead to incorrect
+ // results. Moreover, we may miss that the prologue and
+ // epilogue are not in the same loop, leading to unbalanced
+ // construction/deconstruction of the stack frame.
+ DEBUG(dbgs() << "Irreducible CFGs are not supported yet\n");
+ return false;
+ }
+
const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo();
std::unique_ptr<RegScavenger> RS(
TRI->requiresRegisterScavenging(MF) ? new RegScavenger() : nullptr);
diff --git a/lib/CodeGen/StackColoring.cpp b/lib/CodeGen/StackColoring.cpp
index 3541b33a8441..7b5203815172 100644
--- a/lib/CodeGen/StackColoring.cpp
+++ b/lib/CodeGen/StackColoring.cpp
@@ -43,6 +43,7 @@
#include "llvm/CodeGen/PseudoSourceValue.h"
#include "llvm/CodeGen/SlotIndexes.h"
#include "llvm/CodeGen/StackProtector.h"
+#include "llvm/CodeGen/WinEHFuncInfo.h"
#include "llvm/IR/DebugInfo.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/Function.h"
@@ -570,6 +571,14 @@ void StackColoring::remapInstructions(DenseMap<int, int> &SlotRemap) {
}
}
+ // Update the location of C++ catch objects for the MSVC personality routine.
+ if (WinEHFuncInfo *EHInfo = MF->getWinEHFuncInfo())
+ for (WinEHTryBlockMapEntry &TBME : EHInfo->TryBlockMap)
+ for (WinEHHandlerType &H : TBME.HandlerArray)
+ if (H.CatchObj.FrameIndex != INT_MAX &&
+ SlotRemap.count(H.CatchObj.FrameIndex))
+ H.CatchObj.FrameIndex = SlotRemap[H.CatchObj.FrameIndex];
+
DEBUG(dbgs()<<"Fixed "<<FixedMemOp<<" machine memory operands.\n");
DEBUG(dbgs()<<"Fixed "<<FixedDbg<<" debug locations.\n");
DEBUG(dbgs()<<"Fixed "<<FixedInstr<<" machine instructions.\n");
diff --git a/lib/CodeGen/WinEHPrepare.cpp b/lib/CodeGen/WinEHPrepare.cpp
index 2426c27d43dc..886c5f6070c1 100644
--- a/lib/CodeGen/WinEHPrepare.cpp
+++ b/lib/CodeGen/WinEHPrepare.cpp
@@ -144,10 +144,11 @@ static void addTryBlockMapEntry(WinEHFuncInfo &FuncInfo, int TryLow,
HT.TypeDescriptor = cast<GlobalVariable>(TypeInfo->stripPointerCasts());
HT.Adjectives = cast<ConstantInt>(CPI->getArgOperand(1))->getZExtValue();
HT.Handler = CPI->getParent();
- if (isa<ConstantPointerNull>(CPI->getArgOperand(2)))
- HT.CatchObj.Alloca = nullptr;
+ if (auto *AI =
+ dyn_cast<AllocaInst>(CPI->getArgOperand(2)->stripPointerCasts()))
+ HT.CatchObj.Alloca = AI;
else
- HT.CatchObj.Alloca = cast<AllocaInst>(CPI->getArgOperand(2));
+ HT.CatchObj.Alloca = nullptr;
TBME.HandlerArray.push_back(HT);
}
FuncInfo.TryBlockMap.push_back(TBME);
@@ -664,24 +665,6 @@ void WinEHPrepare::colorFunclets(Function &F) {
}
}
-void llvm::calculateCatchReturnSuccessorColors(const Function *Fn,
- WinEHFuncInfo &FuncInfo) {
- for (const BasicBlock &BB : *Fn) {
- const auto *CatchRet = dyn_cast<CatchReturnInst>(BB.getTerminator());
- if (!CatchRet)
- continue;
- // A 'catchret' returns to the outer scope's color.
- Value *ParentPad = CatchRet->getParentPad();
- const BasicBlock *Color;
- if (isa<ConstantTokenNone>(ParentPad))
- Color = &Fn->getEntryBlock();
- else
- Color = cast<Instruction>(ParentPad)->getParent();
- // Record the catchret successor's funclet membership.
- FuncInfo.CatchRetSuccessorColorMap[CatchRet] = Color;
- }
-}
-
void WinEHPrepare::demotePHIsOnFunclets(Function &F) {
// Strip PHI nodes off of EH pads.
SmallVector<PHINode *, 16> PHINodes;
diff --git a/lib/DebugInfo/Symbolize/DIPrinter.cpp b/lib/DebugInfo/Symbolize/DIPrinter.cpp
index c6bfbc07dcf3..a9dee7abeed1 100644
--- a/lib/DebugInfo/Symbolize/DIPrinter.cpp
+++ b/lib/DebugInfo/Symbolize/DIPrinter.cpp
@@ -15,6 +15,7 @@
#include "llvm/DebugInfo/Symbolize/DIPrinter.h"
#include "llvm/DebugInfo/DIContext.h"
+#include "llvm/Support/LineIterator.h"
namespace llvm {
namespace symbolize {
@@ -24,7 +25,37 @@ namespace symbolize {
static const char kDILineInfoBadString[] = "<invalid>";
static const char kBadString[] = "??";
-void DIPrinter::printName(const DILineInfo &Info, bool Inlined) {
+// Prints source code around in the FileName the Line.
+void DIPrinter::printContext(std::string FileName, int64_t Line) {
+ if (PrintSourceContext <= 0)
+ return;
+
+ ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
+ MemoryBuffer::getFile(FileName);
+ if (!BufOrErr)
+ return;
+
+ std::unique_ptr<MemoryBuffer> Buf = std::move(BufOrErr.get());
+ int64_t FirstLine =
+ std::max(static_cast<int64_t>(1), Line - PrintSourceContext / 2);
+ int64_t LastLine = FirstLine + PrintSourceContext;
+ size_t MaxLineNumberWidth = std::ceil(std::log10(LastLine));
+
+ for (line_iterator I = line_iterator(*Buf, false);
+ !I.is_at_eof() && I.line_number() <= LastLine; ++I) {
+ int64_t L = I.line_number();
+ if (L >= FirstLine && L <= LastLine) {
+ OS << format_decimal(L, MaxLineNumberWidth);
+ if (L == Line)
+ OS << " >: ";
+ else
+ OS << " : ";
+ OS << *I << "\n";
+ }
+ }
+}
+
+void DIPrinter::print(const DILineInfo &Info, bool Inlined) {
if (PrintFunctionNames) {
std::string FunctionName = Info.FunctionName;
if (FunctionName == kDILineInfoBadString)
@@ -38,21 +69,22 @@ void DIPrinter::printName(const DILineInfo &Info, bool Inlined) {
if (Filename == kDILineInfoBadString)
Filename = kBadString;
OS << Filename << ":" << Info.Line << ":" << Info.Column << "\n";
+ printContext(Filename, Info.Line);
}
DIPrinter &DIPrinter::operator<<(const DILineInfo &Info) {
- printName(Info, false);
+ print(Info, false);
return *this;
}
DIPrinter &DIPrinter::operator<<(const DIInliningInfo &Info) {
uint32_t FramesNum = Info.getNumberOfFrames();
if (FramesNum == 0) {
- printName(DILineInfo(), false);
+ print(DILineInfo(), false);
return *this;
}
for (uint32_t i = 0; i < FramesNum; i++)
- printName(Info.getFrame(i), i > 0);
+ print(Info.getFrame(i), i > 0);
return *this;
}
diff --git a/lib/ExecutionEngine/Orc/CMakeLists.txt b/lib/ExecutionEngine/Orc/CMakeLists.txt
index a17f52e322e8..d26f212e00c9 100644
--- a/lib/ExecutionEngine/Orc/CMakeLists.txt
+++ b/lib/ExecutionEngine/Orc/CMakeLists.txt
@@ -2,10 +2,12 @@ add_llvm_library(LLVMOrcJIT
ExecutionUtils.cpp
IndirectionUtils.cpp
NullResolver.cpp
+ OrcArchitectureSupport.cpp
OrcCBindings.cpp
OrcCBindingsStack.cpp
+ OrcError.cpp
OrcMCJITReplacement.cpp
- OrcTargetSupport.cpp
+ OrcRemoteTargetRPCAPI.cpp
ADDITIONAL_HEADER_DIRS
${LLVM_MAIN_INCLUDE_DIR}/llvm/ExecutionEngine/Orc
diff --git a/lib/ExecutionEngine/Orc/OrcTargetSupport.cpp b/lib/ExecutionEngine/Orc/OrcArchitectureSupport.cpp
index b931f10b9d78..01e829f7909e 100644
--- a/lib/ExecutionEngine/Orc/OrcTargetSupport.cpp
+++ b/lib/ExecutionEngine/Orc/OrcArchitectureSupport.cpp
@@ -1,4 +1,4 @@
-//===------- OrcTargetSupport.cpp - Target support utilities for Orc ------===//
+//===------ OrcArchSupport.cpp - Architecture specific support code -------===//
//
// The LLVM Compiler Infrastructure
//
@@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/ADT/Triple.h"
-#include "llvm/ExecutionEngine/Orc/OrcTargetSupport.h"
+#include "llvm/ExecutionEngine/Orc/OrcArchitectureSupport.h"
#include "llvm/Support/Process.h"
#include <array>
diff --git a/lib/ExecutionEngine/Orc/OrcCBindingsStack.cpp b/lib/ExecutionEngine/Orc/OrcCBindingsStack.cpp
index e519c7f30920..956daae372da 100644
--- a/lib/ExecutionEngine/Orc/OrcCBindingsStack.cpp
+++ b/lib/ExecutionEngine/Orc/OrcCBindingsStack.cpp
@@ -9,7 +9,7 @@
#include "OrcCBindingsStack.h"
-#include "llvm/ExecutionEngine/Orc/OrcTargetSupport.h"
+#include "llvm/ExecutionEngine/Orc/OrcArchitectureSupport.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/DynamicLibrary.h"
#include <cstdio>
diff --git a/lib/ExecutionEngine/Orc/OrcCBindingsStack.h b/lib/ExecutionEngine/Orc/OrcCBindingsStack.h
index 2e17624ff474..aae6a99432bc 100644
--- a/lib/ExecutionEngine/Orc/OrcCBindingsStack.h
+++ b/lib/ExecutionEngine/Orc/OrcCBindingsStack.h
@@ -221,7 +221,8 @@ public:
ModuleHandleT addIRModuleLazy(Module* M,
LLVMOrcSymbolResolverFn ExternalResolver,
void *ExternalResolverCtx) {
- return addIRModule(CODLayer, std::move(M), nullptr,
+ return addIRModule(CODLayer, std::move(M),
+ llvm::make_unique<SectionMemoryManager>(),
std::move(ExternalResolver), ExternalResolverCtx);
}
diff --git a/lib/ExecutionEngine/Orc/OrcError.cpp b/lib/ExecutionEngine/Orc/OrcError.cpp
new file mode 100644
index 000000000000..e95115ec6fed
--- /dev/null
+++ b/lib/ExecutionEngine/Orc/OrcError.cpp
@@ -0,0 +1,57 @@
+//===---------------- OrcError.cpp - Error codes for ORC ------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Error codes for ORC.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ExecutionEngine/Orc/OrcError.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/ManagedStatic.h"
+
+using namespace llvm;
+using namespace llvm::orc;
+
+namespace {
+
+class OrcErrorCategory : public std::error_category {
+public:
+ const char *name() const LLVM_NOEXCEPT override { return "orc"; }
+
+ std::string message(int condition) const override {
+ switch (static_cast<OrcErrorCode>(condition)) {
+ case OrcErrorCode::RemoteAllocatorDoesNotExist:
+ return "Remote allocator does not exist";
+ case OrcErrorCode::RemoteAllocatorIdAlreadyInUse:
+ return "Remote allocator Id already in use";
+ case OrcErrorCode::RemoteMProtectAddrUnrecognized:
+ return "Remote mprotect call references unallocated memory";
+ case OrcErrorCode::RemoteIndirectStubsOwnerDoesNotExist:
+ return "Remote indirect stubs owner does not exist";
+ case OrcErrorCode::RemoteIndirectStubsOwnerIdAlreadyInUse:
+ return "Remote indirect stubs owner Id already in use";
+ case OrcErrorCode::UnexpectedRPCCall:
+ return "Unexpected RPC call";
+ }
+ llvm_unreachable("Unhandled error code");
+ }
+};
+
+static ManagedStatic<OrcErrorCategory> OrcErrCat;
+}
+
+namespace llvm {
+namespace orc {
+
+std::error_code orcError(OrcErrorCode ErrCode) {
+ typedef std::underlying_type<OrcErrorCode>::type UT;
+ return std::error_code(static_cast<UT>(ErrCode), *OrcErrCat);
+}
+}
+}
diff --git a/lib/ExecutionEngine/Orc/OrcMCJITReplacement.h b/lib/ExecutionEngine/Orc/OrcMCJITReplacement.h
index 38a27cff5b2f..2ab70a9fee86 100644
--- a/lib/ExecutionEngine/Orc/OrcMCJITReplacement.h
+++ b/lib/ExecutionEngine/Orc/OrcMCJITReplacement.h
@@ -54,10 +54,13 @@ class OrcMCJITReplacement : public ExecutionEngine {
return Addr;
}
- void reserveAllocationSpace(uintptr_t CodeSize, uintptr_t DataSizeRO,
- uintptr_t DataSizeRW) override {
- return ClientMM->reserveAllocationSpace(CodeSize, DataSizeRO,
- DataSizeRW);
+ void reserveAllocationSpace(uintptr_t CodeSize, uint32_t CodeAlign,
+ uintptr_t RODataSize, uint32_t RODataAlign,
+ uintptr_t RWDataSize,
+ uint32_t RWDataAlign) override {
+ return ClientMM->reserveAllocationSpace(CodeSize, CodeAlign,
+ RODataSize, RODataAlign,
+ RWDataSize, RWDataAlign);
}
bool needsToReserveAllocationSpace() override {
@@ -74,6 +77,11 @@ class OrcMCJITReplacement : public ExecutionEngine {
return ClientMM->deregisterEHFrames(Addr, LoadAddr, Size);
}
+ void notifyObjectLoaded(RuntimeDyld &RTDyld,
+ const object::ObjectFile &O) override {
+ return ClientMM->notifyObjectLoaded(RTDyld, O);
+ }
+
void notifyObjectLoaded(ExecutionEngine *EE,
const object::ObjectFile &O) override {
return ClientMM->notifyObjectLoaded(EE, O);
diff --git a/lib/ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.cpp b/lib/ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.cpp
new file mode 100644
index 000000000000..064633b4e490
--- /dev/null
+++ b/lib/ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.cpp
@@ -0,0 +1,83 @@
+//===------- OrcRemoteTargetRPCAPI.cpp - ORC Remote API utilities ---------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.h"
+
+namespace llvm {
+namespace orc {
+namespace remote {
+
+const char *OrcRemoteTargetRPCAPI::getJITProcIdName(JITProcId Id) {
+ switch (Id) {
+ case InvalidId:
+ return "*** Invalid JITProcId ***";
+ case CallIntVoidId:
+ return "CallIntVoid";
+ case CallIntVoidResponseId:
+ return "CallIntVoidResponse";
+ case CallMainId:
+ return "CallMain";
+ case CallMainResponseId:
+ return "CallMainResponse";
+ case CallVoidVoidId:
+ return "CallVoidVoid";
+ case CallVoidVoidResponseId:
+ return "CallVoidVoidResponse";
+ case CreateRemoteAllocatorId:
+ return "CreateRemoteAllocator";
+ case CreateIndirectStubsOwnerId:
+ return "CreateIndirectStubsOwner";
+ case DestroyRemoteAllocatorId:
+ return "DestroyRemoteAllocator";
+ case DestroyIndirectStubsOwnerId:
+ return "DestroyIndirectStubsOwner";
+ case EmitIndirectStubsId:
+ return "EmitIndirectStubs";
+ case EmitIndirectStubsResponseId:
+ return "EmitIndirectStubsResponse";
+ case EmitResolverBlockId:
+ return "EmitResolverBlock";
+ case EmitTrampolineBlockId:
+ return "EmitTrampolineBlock";
+ case EmitTrampolineBlockResponseId:
+ return "EmitTrampolineBlockResponse";
+ case GetSymbolAddressId:
+ return "GetSymbolAddress";
+ case GetSymbolAddressResponseId:
+ return "GetSymbolAddressResponse";
+ case GetRemoteInfoId:
+ return "GetRemoteInfo";
+ case GetRemoteInfoResponseId:
+ return "GetRemoteInfoResponse";
+ case ReadMemId:
+ return "ReadMem";
+ case ReadMemResponseId:
+ return "ReadMemResponse";
+ case ReserveMemId:
+ return "ReserveMem";
+ case ReserveMemResponseId:
+ return "ReserveMemResponse";
+ case RequestCompileId:
+ return "RequestCompile";
+ case RequestCompileResponseId:
+ return "RequestCompileResponse";
+ case SetProtectionsId:
+ return "SetProtections";
+ case TerminateSessionId:
+ return "TerminateSession";
+ case WriteMemId:
+ return "WriteMem";
+ case WritePtrId:
+ return "WritePtr";
+ };
+ return nullptr;
+}
+}
+}
+}
diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp
index a95f3bbe4179..d16b2db24e1a 100644
--- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp
+++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp
@@ -146,9 +146,12 @@ RuntimeDyldImpl::loadObjectImpl(const object::ObjectFile &Obj) {
// Compute the memory size required to load all sections to be loaded
// and pass this information to the memory manager
if (MemMgr.needsToReserveAllocationSpace()) {
- uint64_t CodeSize = 0, DataSizeRO = 0, DataSizeRW = 0;
- computeTotalAllocSize(Obj, CodeSize, DataSizeRO, DataSizeRW);
- MemMgr.reserveAllocationSpace(CodeSize, DataSizeRO, DataSizeRW);
+ uint64_t CodeSize = 0, RODataSize = 0, RWDataSize = 0;
+ uint32_t CodeAlign = 1, RODataAlign = 1, RWDataAlign = 1;
+ computeTotalAllocSize(Obj, CodeSize, CodeAlign, RODataSize, RODataAlign,
+ RWDataSize, RWDataAlign);
+ MemMgr.reserveAllocationSpace(CodeSize, CodeAlign, RODataSize, RODataAlign,
+ RWDataSize, RWDataAlign);
}
// Used sections from the object file
@@ -335,13 +338,15 @@ static bool isZeroInit(const SectionRef Section) {
// sections
void RuntimeDyldImpl::computeTotalAllocSize(const ObjectFile &Obj,
uint64_t &CodeSize,
- uint64_t &DataSizeRO,
- uint64_t &DataSizeRW) {
+ uint32_t &CodeAlign,
+ uint64_t &RODataSize,
+ uint32_t &RODataAlign,
+ uint64_t &RWDataSize,
+ uint32_t &RWDataAlign) {
// Compute the size of all sections required for execution
std::vector<uint64_t> CodeSectionSizes;
std::vector<uint64_t> ROSectionSizes;
std::vector<uint64_t> RWSectionSizes;
- uint64_t MaxAlignment = sizeof(void *);
// Collect sizes of all sections to be loaded;
// also determine the max alignment of all sections
@@ -376,17 +381,15 @@ void RuntimeDyldImpl::computeTotalAllocSize(const ObjectFile &Obj,
SectionSize = 1;
if (IsCode) {
+ CodeAlign = std::max(CodeAlign, Alignment);
CodeSectionSizes.push_back(SectionSize);
} else if (IsReadOnly) {
+ RODataAlign = std::max(RODataAlign, Alignment);
ROSectionSizes.push_back(SectionSize);
} else {
+ RWDataAlign = std::max(RWDataAlign, Alignment);
RWSectionSizes.push_back(SectionSize);
}
-
- // update the max alignment
- if (Alignment > MaxAlignment) {
- MaxAlignment = Alignment;
- }
}
}
@@ -410,9 +413,9 @@ void RuntimeDyldImpl::computeTotalAllocSize(const ObjectFile &Obj,
// allocated with the max alignment. Note that we cannot compute with the
// individual alignments of the sections, because then the required size
// depends on the order, in which the sections are allocated.
- CodeSize = computeAllocationSizeForSections(CodeSectionSizes, MaxAlignment);
- DataSizeRO = computeAllocationSizeForSections(ROSectionSizes, MaxAlignment);
- DataSizeRW = computeAllocationSizeForSections(RWSectionSizes, MaxAlignment);
+ CodeSize = computeAllocationSizeForSections(CodeSectionSizes, CodeAlign);
+ RODataSize = computeAllocationSizeForSections(ROSectionSizes, RODataAlign);
+ RWDataSize = computeAllocationSizeForSections(RWSectionSizes, RWDataAlign);
}
// compute stub buffer size for the given section
@@ -937,7 +940,9 @@ RuntimeDyld::loadObject(const ObjectFile &Obj) {
if (!Dyld->isCompatibleFile(Obj))
report_fatal_error("Incompatible object format!");
- return Dyld->loadObject(Obj);
+ auto LoadedObjInfo = Dyld->loadObject(Obj);
+ MemMgr.notifyObjectLoaded(*this, Obj);
+ return LoadedObjInfo;
}
void *RuntimeDyld::getSymbolLocalAddress(StringRef Name) const {
@@ -967,6 +972,17 @@ bool RuntimeDyld::hasError() { return Dyld->hasError(); }
StringRef RuntimeDyld::getErrorString() { return Dyld->getErrorString(); }
+void RuntimeDyld::finalizeWithMemoryManagerLocking() {
+ bool MemoryFinalizationLocked = MemMgr.FinalizationLocked;
+ MemMgr.FinalizationLocked = true;
+ resolveRelocations();
+ registerEHFrames();
+ if (!MemoryFinalizationLocked) {
+ MemMgr.finalizeMemory();
+ MemMgr.FinalizationLocked = false;
+ }
+}
+
void RuntimeDyld::registerEHFrames() {
if (Dyld)
Dyld->registerEHFrames();
diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h
index dafd3c8793c3..ab732c69ee2f 100644
--- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h
+++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h
@@ -411,8 +411,10 @@ protected:
// \brief Compute an upper bound of the memory that is required to load all
// sections
- void computeTotalAllocSize(const ObjectFile &Obj, uint64_t &CodeSize,
- uint64_t &DataSizeRO, uint64_t &DataSizeRW);
+ void computeTotalAllocSize(const ObjectFile &Obj,
+ uint64_t &CodeSize, uint32_t &CodeAlign,
+ uint64_t &RODataSize, uint32_t &RODataAlign,
+ uint64_t &RWDataSize, uint32_t &RWDataAlign);
// \brief Compute the stub buffer size required for a section
unsigned computeSectionStubBufSize(const ObjectFile &Obj,
diff --git a/lib/ExecutionEngine/SectionMemoryManager.cpp b/lib/ExecutionEngine/SectionMemoryManager.cpp
index e2f220862cf7..1ad5f1740115 100644
--- a/lib/ExecutionEngine/SectionMemoryManager.cpp
+++ b/lib/ExecutionEngine/SectionMemoryManager.cpp
@@ -137,9 +137,6 @@ bool SectionMemoryManager::finalizeMemory(std::string *ErrMsg)
return true;
}
- // Don't allow free memory blocks to be used after setting protection flags.
- RODataMem.FreeMem.clear();
-
// Make read-only data memory read-only.
ec = applyMemoryGroupPermissions(RODataMem,
sys::Memory::MF_READ | sys::Memory::MF_EXEC);
diff --git a/lib/Fuzzer/FuzzerDriver.cpp b/lib/Fuzzer/FuzzerDriver.cpp
index e8c117ef6087..66e46dbf3aad 100644
--- a/lib/Fuzzer/FuzzerDriver.cpp
+++ b/lib/Fuzzer/FuzzerDriver.cpp
@@ -259,8 +259,6 @@ int FuzzerDriver(const std::vector<std::string> &Args,
Flags.prefer_small_during_initial_shuffle;
Options.Reload = Flags.reload;
Options.OnlyASCII = Flags.only_ascii;
- Options.TBMDepth = Flags.tbm_depth;
- Options.TBMWidth = Flags.tbm_width;
Options.OutputCSV = Flags.output_csv;
if (Flags.runs >= 0)
Options.MaxNumberOfRuns = Flags.runs;
@@ -286,7 +284,7 @@ int FuzzerDriver(const std::vector<std::string> &Args,
Fuzzer F(USF, Options);
for (auto &U: Dictionary)
- USF.GetMD().AddWordToDictionary(U.data(), U.size());
+ USF.GetMD().AddWordToManualDictionary(U);
// Timer
if (Flags.timeout > 0)
diff --git a/lib/Fuzzer/FuzzerFlags.def b/lib/Fuzzer/FuzzerFlags.def
index 6d98f66ef9c1..977efb76922b 100644
--- a/lib/Fuzzer/FuzzerFlags.def
+++ b/lib/Fuzzer/FuzzerFlags.def
@@ -56,10 +56,6 @@ FUZZER_FLAG_INT(report_slow_units, 10,
FUZZER_FLAG_INT(only_ascii, 0,
"If 1, generate only ASCII (isprint+isspace) inputs.")
FUZZER_FLAG_STRING(dict, "Experimental. Use the dictionary file.")
-FUZZER_FLAG_INT(tbm_depth, 5, "Apply at most this number of consecutive"
- "trace-based-mutations (tbm).")
-FUZZER_FLAG_INT(tbm_width, 5, "Apply at most this number of independent"
- "trace-based-mutations (tbm)")
FUZZER_FLAG_STRING(test_single_input, "Use specified file as test input.")
FUZZER_FLAG_STRING(artifact_prefix, "Write fuzzing artifacts (crash, "
"timeout, or slow inputs) as "
diff --git a/lib/Fuzzer/FuzzerInterface.h b/lib/Fuzzer/FuzzerInterface.h
index 65f1707ba922..e22b27a3dd2b 100644
--- a/lib/Fuzzer/FuzzerInterface.h
+++ b/lib/Fuzzer/FuzzerInterface.h
@@ -16,6 +16,7 @@
#ifndef LLVM_FUZZER_INTERFACE_H
#define LLVM_FUZZER_INTERFACE_H
+#include <limits>
#include <cstddef>
#include <cstdint>
#include <vector>
@@ -86,9 +87,13 @@ class MutationDispatcher {
/// Mutates data by chanding one bit.
size_t Mutate_ChangeBit(uint8_t *Data, size_t Size, size_t MaxSize);
- /// Mutates data by adding a word from the dictionary.
- size_t Mutate_AddWordFromDictionary(uint8_t *Data, size_t Size,
- size_t MaxSize);
+ /// Mutates data by adding a word from the manual dictionary.
+ size_t Mutate_AddWordFromManualDictionary(uint8_t *Data, size_t Size,
+ size_t MaxSize);
+
+ /// Mutates data by adding a word from the automatic dictionary.
+ size_t Mutate_AddWordFromAutoDictionary(uint8_t *Data, size_t Size,
+ size_t MaxSize);
/// Tries to find an ASCII integer in Data, changes it to another ASCII int.
size_t Mutate_ChangeASCIIInteger(uint8_t *Data, size_t Size, size_t MaxSize);
@@ -104,7 +109,11 @@ class MutationDispatcher {
size_t CrossOver(const uint8_t *Data1, size_t Size1, const uint8_t *Data2,
size_t Size2, uint8_t *Out, size_t MaxOutSize);
- void AddWordToDictionary(const uint8_t *Word, size_t Size);
+ void AddWordToManualDictionary(const Unit &Word);
+
+ void AddWordToAutoDictionary(const Unit &Word, size_t PositionHint);
+ void ClearAutoDictionary();
+
void SetCorpus(const std::vector<Unit> *Corpus);
private:
diff --git a/lib/Fuzzer/FuzzerInternal.h b/lib/Fuzzer/FuzzerInternal.h
index 17a2cae94a58..c1e9daac9808 100644
--- a/lib/Fuzzer/FuzzerInternal.h
+++ b/lib/Fuzzer/FuzzerInternal.h
@@ -38,6 +38,7 @@ std::string DirPlusFile(const std::string &DirPath,
void Printf(const char *Fmt, ...);
void Print(const Unit &U, const char *PrintAfter = "");
+void PrintASCII(const uint8_t *Data, size_t Size, const char *PrintAfter = "");
void PrintASCII(const Unit &U, const char *PrintAfter = "");
std::string Hash(const Unit &U);
void SetTimer(int Seconds);
@@ -88,8 +89,6 @@ class Fuzzer {
int SyncTimeout = 600;
int ReportSlowUnits = 10;
bool OnlyASCII = false;
- int TBMDepth = 10;
- int TBMWidth = 10;
std::string OutputCorpus;
std::string SyncCommand;
std::string ArtifactPrefix = "./";
@@ -156,10 +155,8 @@ class Fuzzer {
// Start tracing; forget all previously proposed mutations.
void StartTraceRecording();
- // Stop tracing and return the number of proposed mutations.
- size_t StopTraceRecording();
- // Apply Idx-th trace-based mutation to U.
- void ApplyTraceBasedMutation(size_t Idx, Unit *U);
+ // Stop tracing.
+ void StopTraceRecording();
void SetDeathCallback();
static void StaticDeathCallback();
diff --git a/lib/Fuzzer/FuzzerLoop.cpp b/lib/Fuzzer/FuzzerLoop.cpp
index 0b1d9d9686a2..5237682ff24d 100644
--- a/lib/Fuzzer/FuzzerLoop.cpp
+++ b/lib/Fuzzer/FuzzerLoop.cpp
@@ -390,7 +390,6 @@ void Fuzzer::MutateAndTestOne() {
U = ChooseUnitToMutate();
for (int i = 0; i < Options.MutateDepth; i++) {
- StartTraceRecording();
size_t Size = U.size();
U.resize(Options.MaxLen);
size_t NewSize = USF.Mutate(U.data(), Size, U.size());
@@ -398,21 +397,10 @@ void Fuzzer::MutateAndTestOne() {
assert(NewSize <= (size_t)Options.MaxLen &&
"Mutator return overisized unit");
U.resize(NewSize);
+ if (i == 0)
+ StartTraceRecording();
RunOneAndUpdateCorpus(U);
- size_t NumTraceBasedMutations = StopTraceRecording();
- size_t TBMWidth =
- std::min((size_t)Options.TBMWidth, NumTraceBasedMutations);
- size_t TBMDepth =
- std::min((size_t)Options.TBMDepth, NumTraceBasedMutations);
- Unit BackUp = U;
- for (size_t w = 0; w < TBMWidth; w++) {
- U = BackUp;
- for (size_t d = 0; d < TBMDepth; d++) {
- TotalNumberOfExecutedTraceBasedMutations++;
- ApplyTraceBasedMutation(USF.GetRand()(NumTraceBasedMutations), &U);
- RunOneAndUpdateCorpus(U);
- }
- }
+ StopTraceRecording();
}
}
@@ -467,12 +455,15 @@ void Fuzzer::Drill() {
PrintStats("REINIT");
SavedOutputCorpusPath.swap(Options.OutputCorpus);
- for (auto &U : SavedCorpus)
+ for (auto &U : SavedCorpus) {
+ CurrentUnit = U;
RunOne(U);
+ }
PrintStats("MERGE ");
Options.PrintNEW = true;
size_t NumMerged = 0;
for (auto &U : Corpus) {
+ CurrentUnit = U;
if (RunOne(U)) {
PrintStatusForNewUnit(U);
NumMerged++;
diff --git a/lib/Fuzzer/FuzzerMutate.cpp b/lib/Fuzzer/FuzzerMutate.cpp
index 84ee18e69fb0..30e5b43c0839 100644
--- a/lib/Fuzzer/FuzzerMutate.cpp
+++ b/lib/Fuzzer/FuzzerMutate.cpp
@@ -22,14 +22,22 @@ struct Mutator {
const char *Name;
};
+struct DictionaryEntry {
+ Unit Word;
+ size_t PositionHint;
+};
+
struct MutationDispatcher::Impl {
- std::vector<Unit> Dictionary;
+ std::vector<DictionaryEntry> ManualDictionary;
+ std::vector<DictionaryEntry> AutoDictionary;
std::vector<Mutator> Mutators;
std::vector<Mutator> CurrentMutatorSequence;
+ std::vector<DictionaryEntry> CurrentDictionaryEntrySequence;
const std::vector<Unit> *Corpus = nullptr;
+ FuzzerRandomBase &Rand;
void Add(Mutator M) { Mutators.push_back(M); }
- Impl() {
+ Impl(FuzzerRandomBase &Rand) : Rand(Rand) {
Add({&MutationDispatcher::Mutate_EraseByte, "EraseByte"});
Add({&MutationDispatcher::Mutate_InsertByte, "InsertByte"});
Add({&MutationDispatcher::Mutate_ChangeByte, "ChangeByte"});
@@ -37,14 +45,14 @@ struct MutationDispatcher::Impl {
Add({&MutationDispatcher::Mutate_ShuffleBytes, "ShuffleBytes"});
Add({&MutationDispatcher::Mutate_ChangeASCIIInteger, "ChangeASCIIInt"});
Add({&MutationDispatcher::Mutate_CrossOver, "CrossOver"});
- }
- void AddWordToDictionary(const uint8_t *Word, size_t Size) {
- if (Dictionary.empty()) {
- Add({&MutationDispatcher::Mutate_AddWordFromDictionary, "AddFromDict"});
- }
- Dictionary.push_back(Unit(Word, Word + Size));
+ Add({&MutationDispatcher::Mutate_AddWordFromManualDictionary,
+ "AddFromManualDict"});
+ Add({&MutationDispatcher::Mutate_AddWordFromAutoDictionary,
+ "AddFromAutoDict"});
}
void SetCorpus(const std::vector<Unit> *Corpus) { this->Corpus = Corpus; }
+ size_t AddWordFromDictionary(const std::vector<DictionaryEntry> &D,
+ uint8_t *Data, size_t Size, size_t MaxSize);
};
static char FlipRandomBit(char X, FuzzerRandomBase &Rand) {
@@ -68,7 +76,8 @@ static char RandCh(FuzzerRandomBase &Rand) {
size_t MutationDispatcher::Mutate_ShuffleBytes(uint8_t *Data, size_t Size,
size_t MaxSize) {
assert(Size);
- size_t ShuffleAmount = Rand(std::min(Size, (size_t)8)) + 1; // [1,8] and <= Size.
+ size_t ShuffleAmount =
+ Rand(std::min(Size, (size_t)8)) + 1; // [1,8] and <= Size.
size_t ShuffleStart = Rand(Size - ShuffleAmount);
assert(ShuffleStart + ShuffleAmount <= Size);
std::random_shuffle(Data + ShuffleStart, Data + ShuffleStart + ShuffleAmount,
@@ -110,25 +119,42 @@ size_t MutationDispatcher::Mutate_ChangeBit(uint8_t *Data, size_t Size,
return Size;
}
-size_t MutationDispatcher::Mutate_AddWordFromDictionary(uint8_t *Data,
- size_t Size,
- size_t MaxSize) {
- auto &D = MDImpl->Dictionary;
- assert(!D.empty());
+size_t MutationDispatcher::Mutate_AddWordFromManualDictionary(uint8_t *Data,
+ size_t Size,
+ size_t MaxSize) {
+ return MDImpl->AddWordFromDictionary(MDImpl->ManualDictionary, Data, Size,
+ MaxSize);
+}
+
+size_t MutationDispatcher::Mutate_AddWordFromAutoDictionary(uint8_t *Data,
+ size_t Size,
+ size_t MaxSize) {
+ return MDImpl->AddWordFromDictionary(MDImpl->AutoDictionary, Data, Size,
+ MaxSize);
+}
+
+size_t MutationDispatcher::Impl::AddWordFromDictionary(
+ const std::vector<DictionaryEntry> &D, uint8_t *Data, size_t Size,
+ size_t MaxSize) {
if (D.empty()) return 0;
- const Unit &Word = D[Rand(D.size())];
+ const DictionaryEntry &DE = D[Rand(D.size())];
+ const Unit &Word = DE.Word;
+ size_t PositionHint = DE.PositionHint;
+ bool UsePositionHint = PositionHint != std::numeric_limits<size_t>::max() &&
+ PositionHint + Word.size() < Size && Rand.RandBool();
if (Rand.RandBool()) { // Insert Word.
if (Size + Word.size() > MaxSize) return 0;
- size_t Idx = Rand(Size + 1);
+ size_t Idx = UsePositionHint ? PositionHint : Rand(Size + 1);
memmove(Data + Idx + Word.size(), Data + Idx, Size - Idx);
memcpy(Data + Idx, Word.data(), Word.size());
- return Size + Word.size();
+ Size += Word.size();
} else { // Overwrite some bytes with Word.
if (Word.size() > Size) return 0;
- size_t Idx = Rand(Size - Word.size());
+ size_t Idx = UsePositionHint ? PositionHint : Rand(Size - Word.size());
memcpy(Data + Idx, Word.data(), Word.size());
- return Size;
}
+ CurrentDictionaryEntrySequence.push_back(DE);
+ return Size;
}
size_t MutationDispatcher::Mutate_ChangeASCIIInteger(uint8_t *Data, size_t Size,
@@ -182,12 +208,20 @@ size_t MutationDispatcher::Mutate_CrossOver(uint8_t *Data, size_t Size,
void MutationDispatcher::StartMutationSequence() {
MDImpl->CurrentMutatorSequence.clear();
+ MDImpl->CurrentDictionaryEntrySequence.clear();
}
void MutationDispatcher::PrintMutationSequence() {
Printf("MS: %zd ", MDImpl->CurrentMutatorSequence.size());
for (auto M : MDImpl->CurrentMutatorSequence)
Printf("%s-", M.Name);
+ if (!MDImpl->CurrentDictionaryEntrySequence.empty()) {
+ Printf(" DE: ");
+ for (auto DE : MDImpl->CurrentDictionaryEntrySequence) {
+ Printf("\"");
+ PrintASCII(DE.Word, "\"-");
+ }
+ }
}
// Mutates Data in place, returns new size.
@@ -219,12 +253,24 @@ void MutationDispatcher::SetCorpus(const std::vector<Unit> *Corpus) {
MDImpl->SetCorpus(Corpus);
}
-void MutationDispatcher::AddWordToDictionary(const uint8_t *Word, size_t Size) {
- MDImpl->AddWordToDictionary(Word, Size);
+void MutationDispatcher::AddWordToManualDictionary(const Unit &Word) {
+ MDImpl->ManualDictionary.push_back(
+ {Word, std::numeric_limits<size_t>::max()});
+}
+
+void MutationDispatcher::AddWordToAutoDictionary(const Unit &Word,
+ size_t PositionHint) {
+ static const size_t kMaxAutoDictSize = 1 << 14;
+ if (MDImpl->AutoDictionary.size() >= kMaxAutoDictSize) return;
+ MDImpl->AutoDictionary.push_back({Word, PositionHint});
+}
+
+void MutationDispatcher::ClearAutoDictionary() {
+ MDImpl->AutoDictionary.clear();
}
MutationDispatcher::MutationDispatcher(FuzzerRandomBase &Rand) : Rand(Rand) {
- MDImpl = new Impl;
+ MDImpl = new Impl(Rand);
}
MutationDispatcher::~MutationDispatcher() { delete MDImpl; }
diff --git a/lib/Fuzzer/FuzzerTraceState.cpp b/lib/Fuzzer/FuzzerTraceState.cpp
index 241c2f0ce590..b2006fa3aa4d 100644
--- a/lib/Fuzzer/FuzzerTraceState.cpp
+++ b/lib/Fuzzer/FuzzerTraceState.cpp
@@ -46,8 +46,6 @@
// * The __dfsw_* functions (implemented in this file) record the
// parameters (i.e. the application data and the corresponding taint labels)
// in a global state.
-// * Fuzzer::ApplyTraceBasedMutation() tries to use the data recorded
-// by __dfsw_* hooks to guide the fuzzing towards new application states.
//
// Parts of this code will not function when DFSan is not linked in.
// Instead of using ifdefs and thus requiring a separate build of lib/Fuzzer
@@ -78,7 +76,7 @@
#include <algorithm>
#include <cstring>
#include <thread>
-#include <unordered_map>
+#include <map>
#if !LLVM_FUZZER_SUPPORTS_DFSAN
// Stubs for dfsan for platforms where dfsan does not exist and weak
@@ -166,15 +164,19 @@ struct LabelRange {
// For now, very simple: put Size bytes of Data at position Pos.
struct TraceBasedMutation {
- size_t Pos;
- size_t Size;
- uint64_t Data;
+ static const size_t kMaxSize = 28;
+ uint32_t Pos : 24;
+ uint32_t Size : 8;
+ uint8_t Data[kMaxSize];
};
+const size_t TraceBasedMutation::kMaxSize;
+
class TraceState {
public:
- TraceState(const Fuzzer::FuzzingOptions &Options, const Unit &CurrentUnit)
- : Options(Options), CurrentUnit(CurrentUnit) {
+ TraceState(UserSuppliedFuzzer &USF,
+ const Fuzzer::FuzzingOptions &Options, const Unit &CurrentUnit)
+ : USF(USF), Options(Options), CurrentUnit(CurrentUnit) {
// Current trace collection is not thread-friendly and it probably
// does not have to be such, but at least we should not crash in presence
// of threads. So, just ignore all traces coming from all threads but one.
@@ -185,28 +187,71 @@ class TraceState {
void DFSanCmpCallback(uintptr_t PC, size_t CmpSize, size_t CmpType,
uint64_t Arg1, uint64_t Arg2, dfsan_label L1,
dfsan_label L2);
+ void DFSanMemcmpCallback(size_t CmpSize, const uint8_t *Data1,
+ const uint8_t *Data2, dfsan_label L1,
+ dfsan_label L2);
void DFSanSwitchCallback(uint64_t PC, size_t ValSizeInBits, uint64_t Val,
size_t NumCases, uint64_t *Cases, dfsan_label L);
void TraceCmpCallback(uintptr_t PC, size_t CmpSize, size_t CmpType,
uint64_t Arg1, uint64_t Arg2);
+ void TraceMemcmpCallback(size_t CmpSize, const uint8_t *Data1,
+ const uint8_t *Data2);
void TraceSwitchCallback(uintptr_t PC, size_t ValSizeInBits, uint64_t Val,
size_t NumCases, uint64_t *Cases);
int TryToAddDesiredData(uint64_t PresentData, uint64_t DesiredData,
size_t DataSize);
+ int TryToAddDesiredData(const uint8_t *PresentData,
+ const uint8_t *DesiredData, size_t DataSize);
void StartTraceRecording() {
if (!Options.UseTraces) return;
RecordingTraces = true;
- Mutations.clear();
+ NumMutations = 0;
+ USF.GetMD().ClearAutoDictionary();
}
- size_t StopTraceRecording(FuzzerRandomBase &Rand) {
+ void StopTraceRecording() {
+ if (!RecordingTraces) return;
RecordingTraces = false;
- return Mutations.size();
+ for (size_t i = 0; i < NumMutations; i++) {
+ auto &M = Mutations[i];
+ Unit U(M.Data, M.Data + M.Size);
+ if (Options.Verbosity >= 2) {
+ AutoDictUnitCounts[U]++;
+ AutoDictAdds++;
+ if ((AutoDictAdds & (AutoDictAdds - 1)) == 0) {
+ typedef std::pair<size_t, Unit> CU;
+ std::vector<CU> CountedUnits;
+ for (auto &I : AutoDictUnitCounts)
+ CountedUnits.push_back(std::make_pair(I.second, I.first));
+ std::sort(CountedUnits.begin(), CountedUnits.end(),
+ [](const CU &a, const CU &b) { return a.first > b.first; });
+ Printf("AutoDict:\n");
+ for (auto &I : CountedUnits) {
+ Printf(" %zd ", I.first);
+ PrintASCII(I.second);
+ Printf("\n");
+ }
+ }
+ }
+ USF.GetMD().AddWordToAutoDictionary(U, M.Pos);
+ }
}
- void ApplyTraceBasedMutation(size_t Idx, fuzzer::Unit *U);
+ void AddMutation(uint32_t Pos, uint32_t Size, const uint8_t *Data) {
+ if (NumMutations >= kMaxMutations) return;
+ assert(Size <= TraceBasedMutation::kMaxSize);
+ auto &M = Mutations[NumMutations++];
+ M.Pos = Pos;
+ M.Size = Size;
+ memcpy(M.Data, Data, Size);
+ }
+
+ void AddMutation(uint32_t Pos, uint32_t Size, uint64_t Data) {
+ assert(Size <= sizeof(Data));
+ AddMutation(Pos, Size, reinterpret_cast<uint8_t*>(&Data));
+ }
private:
bool IsTwoByteData(uint64_t Data) {
@@ -215,10 +260,15 @@ class TraceState {
return Signed == 0 || Signed == -1L;
}
bool RecordingTraces = false;
- std::vector<TraceBasedMutation> Mutations;
+ static const size_t kMaxMutations = 1 << 16;
+ size_t NumMutations;
+ TraceBasedMutation Mutations[kMaxMutations];
LabelRange LabelRanges[1 << (sizeof(dfsan_label) * 8)];
+ UserSuppliedFuzzer &USF;
const Fuzzer::FuzzingOptions &Options;
const Unit &CurrentUnit;
+ std::map<Unit, size_t> AutoDictUnitCounts;
+ size_t AutoDictAdds = 0;
static thread_local bool IsMyThread;
};
@@ -234,15 +284,6 @@ LabelRange TraceState::GetLabelRange(dfsan_label L) {
return LR = LabelRange::Singleton(LI);
}
-void TraceState::ApplyTraceBasedMutation(size_t Idx, fuzzer::Unit *U) {
- assert(Idx < Mutations.size());
- auto &M = Mutations[Idx];
- if (Options.Verbosity >= 3)
- Printf("TBM %zd %zd %zd\n", M.Pos, M.Size, M.Data);
- if (M.Pos + M.Size > U->size()) return;
- memcpy(U->data() + M.Pos, &M.Data, M.Size);
-}
-
void TraceState::DFSanCmpCallback(uintptr_t PC, size_t CmpSize, size_t CmpType,
uint64_t Arg1, uint64_t Arg2, dfsan_label L1,
dfsan_label L2) {
@@ -257,19 +298,39 @@ void TraceState::DFSanCmpCallback(uintptr_t PC, size_t CmpSize, size_t CmpType,
LabelRange LR = L1 ? GetLabelRange(L1) : GetLabelRange(L2);
for (size_t Pos = LR.Beg; Pos + CmpSize <= LR.End; Pos++) {
- Mutations.push_back({Pos, CmpSize, Data});
- Mutations.push_back({Pos, CmpSize, Data + 1});
- Mutations.push_back({Pos, CmpSize, Data - 1});
+ AddMutation(Pos, CmpSize, Data);
+ AddMutation(Pos, CmpSize, Data + 1);
+ AddMutation(Pos, CmpSize, Data - 1);
}
if (CmpSize > LR.End - LR.Beg)
- Mutations.push_back({LR.Beg, (unsigned)(LR.End - LR.Beg), Data});
+ AddMutation(LR.Beg, (unsigned)(LR.End - LR.Beg), Data);
if (Options.Verbosity >= 3)
Printf("DFSanCmpCallback: PC %lx S %zd T %zd A1 %llx A2 %llx R %d L1 %d L2 "
"%d MU %zd\n",
- PC, CmpSize, CmpType, Arg1, Arg2, Res, L1, L2, Mutations.size());
+ PC, CmpSize, CmpType, Arg1, Arg2, Res, L1, L2, NumMutations);
+}
+
+void TraceState::DFSanMemcmpCallback(size_t CmpSize, const uint8_t *Data1,
+ const uint8_t *Data2, dfsan_label L1,
+ dfsan_label L2) {
+
+ assert(ReallyHaveDFSan());
+ if (!RecordingTraces || !IsMyThread) return;
+ if (L1 == 0 && L2 == 0)
+ return; // Not actionable.
+ if (L1 != 0 && L2 != 0)
+ return; // Probably still actionable.
+
+ const uint8_t *Data = L1 ? Data2 : Data1;
+ LabelRange LR = L1 ? GetLabelRange(L1) : GetLabelRange(L2);
+ for (size_t Pos = LR.Beg; Pos + CmpSize <= LR.End; Pos++) {
+ AddMutation(Pos, CmpSize, Data);
+ if (Options.Verbosity >= 3)
+ Printf("DFSanMemcmpCallback: Pos %d Size %d\n", Pos, CmpSize);
+ }
}
void TraceState::DFSanSwitchCallback(uint64_t PC, size_t ValSizeInBits,
@@ -286,12 +347,12 @@ void TraceState::DFSanSwitchCallback(uint64_t PC, size_t ValSizeInBits,
for (size_t Pos = LR.Beg; Pos + ValSize <= LR.End; Pos++)
for (size_t i = 0; i < NumCases; i++)
- Mutations.push_back({Pos, ValSize, Cases[i]});
+ AddMutation(Pos, ValSize, Cases[i]);
if (TryShort)
for (size_t Pos = LR.Beg; Pos + 2 <= LR.End; Pos++)
for (size_t i = 0; i < NumCases; i++)
- Mutations.push_back({Pos, 2, Cases[i]});
+ AddMutation(Pos, 2, Cases[i]);
if (Options.Verbosity >= 3)
Printf("DFSanSwitchCallback: PC %lx Val %zd SZ %zd # %zd L %d: {%d, %d} "
@@ -310,10 +371,27 @@ int TraceState::TryToAddDesiredData(uint64_t PresentData, uint64_t DesiredData,
break;
size_t Pos = Cur - Beg;
assert(Pos < CurrentUnit.size());
- if (Mutations.size() > 100000U) return Res; // Just in case.
- Mutations.push_back({Pos, DataSize, DesiredData});
- Mutations.push_back({Pos, DataSize, DesiredData + 1});
- Mutations.push_back({Pos, DataSize, DesiredData - 1});
+ AddMutation(Pos, DataSize, DesiredData);
+ AddMutation(Pos, DataSize, DesiredData + 1);
+ AddMutation(Pos, DataSize, DesiredData - 1);
+ Res++;
+ }
+ return Res;
+}
+
+int TraceState::TryToAddDesiredData(const uint8_t *PresentData,
+ const uint8_t *DesiredData,
+ size_t DataSize) {
+ int Res = 0;
+ const uint8_t *Beg = CurrentUnit.data();
+ const uint8_t *End = Beg + CurrentUnit.size();
+ for (const uint8_t *Cur = Beg; Cur < End; Cur++) {
+ Cur = (uint8_t *)memmem(Cur, End - Cur, PresentData, DataSize);
+ if (!Cur)
+ break;
+ size_t Pos = Cur - Beg;
+ assert(Pos < CurrentUnit.size());
+ AddMutation(Pos, DataSize, DesiredData);
Res++;
}
return Res;
@@ -322,15 +400,31 @@ int TraceState::TryToAddDesiredData(uint64_t PresentData, uint64_t DesiredData,
void TraceState::TraceCmpCallback(uintptr_t PC, size_t CmpSize, size_t CmpType,
uint64_t Arg1, uint64_t Arg2) {
if (!RecordingTraces || !IsMyThread) return;
+ if ((CmpType == ICMP_EQ || CmpType == ICMP_NE) && Arg1 == Arg2)
+ return; // No reason to mutate.
int Added = 0;
- if (Options.Verbosity >= 3)
- Printf("TraceCmp %zd/%zd: %p %zd %zd\n", CmpSize, CmpType, PC, Arg1, Arg2);
Added += TryToAddDesiredData(Arg1, Arg2, CmpSize);
Added += TryToAddDesiredData(Arg2, Arg1, CmpSize);
if (!Added && CmpSize == 4 && IsTwoByteData(Arg1) && IsTwoByteData(Arg2)) {
Added += TryToAddDesiredData(Arg1, Arg2, 2);
Added += TryToAddDesiredData(Arg2, Arg1, 2);
}
+ if (Options.Verbosity >= 3 && Added)
+ Printf("TraceCmp %zd/%zd: %p %zd %zd\n", CmpSize, CmpType, PC, Arg1, Arg2);
+}
+
+void TraceState::TraceMemcmpCallback(size_t CmpSize, const uint8_t *Data1,
+ const uint8_t *Data2) {
+ if (!RecordingTraces || !IsMyThread) return;
+ CmpSize = std::min(CmpSize, TraceBasedMutation::kMaxSize);
+ int Added2 = TryToAddDesiredData(Data1, Data2, CmpSize);
+ int Added1 = TryToAddDesiredData(Data2, Data1, CmpSize);
+ if ((Added1 || Added2) && Options.Verbosity >= 3) {
+ Printf("MemCmp Added %d%d: ", Added1, Added2);
+ if (Added1) PrintASCII(Data1, CmpSize);
+ if (Added2) PrintASCII(Data2, CmpSize);
+ Printf("\n");
+ }
}
void TraceState::TraceSwitchCallback(uintptr_t PC, size_t ValSizeInBits,
@@ -351,7 +445,6 @@ void TraceState::TraceSwitchCallback(uintptr_t PC, size_t ValSizeInBits,
if (TryShort)
TryToAddDesiredData(Val, Cases[i], 2);
}
-
}
static TraceState *TS;
@@ -364,19 +457,14 @@ void Fuzzer::StartTraceRecording() {
TS->StartTraceRecording();
}
-size_t Fuzzer::StopTraceRecording() {
- if (!TS) return 0;
- return TS->StopTraceRecording(USF.GetRand());
-}
-
-void Fuzzer::ApplyTraceBasedMutation(size_t Idx, Unit *U) {
- assert(TS);
- TS->ApplyTraceBasedMutation(Idx, U);
+void Fuzzer::StopTraceRecording() {
+ if (!TS) return;
+ TS->StopTraceRecording();
}
void Fuzzer::InitializeTraceState() {
if (!Options.UseTraces) return;
- TS = new TraceState(Options, CurrentUnit);
+ TS = new TraceState(USF, Options, CurrentUnit);
CurrentUnit.resize(Options.MaxLen);
// The rest really requires DFSan.
if (!ReallyHaveDFSan()) return;
@@ -423,91 +511,79 @@ void dfsan_weak_hook_memcmp(void *caller_pc, const void *s1, const void *s2,
size_t n, dfsan_label s1_label,
dfsan_label s2_label, dfsan_label n_label) {
if (!TS) return;
- uintptr_t PC = reinterpret_cast<uintptr_t>(caller_pc);
- uint64_t S1 = 0, S2 = 0;
- // Simplification: handle only first 8 bytes.
- memcpy(&S1, s1, std::min(n, sizeof(S1)));
- memcpy(&S2, s2, std::min(n, sizeof(S2)));
dfsan_label L1 = dfsan_read_label(s1, n);
dfsan_label L2 = dfsan_read_label(s2, n);
- TS->DFSanCmpCallback(PC, n, fuzzer::ICMP_EQ, S1, S2, L1, L2);
+ TS->DFSanMemcmpCallback(n, reinterpret_cast<const uint8_t *>(s1),
+ reinterpret_cast<const uint8_t *>(s2), L1, L2);
}
void dfsan_weak_hook_strncmp(void *caller_pc, const char *s1, const char *s2,
size_t n, dfsan_label s1_label,
dfsan_label s2_label, dfsan_label n_label) {
if (!TS) return;
- uintptr_t PC = reinterpret_cast<uintptr_t>(caller_pc);
- uint64_t S1 = 0, S2 = 0;
n = std::min(n, fuzzer::InternalStrnlen(s1, n));
n = std::min(n, fuzzer::InternalStrnlen(s2, n));
- // Simplification: handle only first 8 bytes.
- memcpy(&S1, s1, std::min(n, sizeof(S1)));
- memcpy(&S2, s2, std::min(n, sizeof(S2)));
dfsan_label L1 = dfsan_read_label(s1, n);
dfsan_label L2 = dfsan_read_label(s2, n);
- TS->DFSanCmpCallback(PC, n, fuzzer::ICMP_EQ, S1, S2, L1, L2);
+ TS->DFSanMemcmpCallback(n, reinterpret_cast<const uint8_t *>(s1),
+ reinterpret_cast<const uint8_t *>(s2), L1, L2);
}
void dfsan_weak_hook_strcmp(void *caller_pc, const char *s1, const char *s2,
dfsan_label s1_label, dfsan_label s2_label) {
if (!TS) return;
- uintptr_t PC = reinterpret_cast<uintptr_t>(caller_pc);
- uint64_t S1 = 0, S2 = 0;
size_t Len1 = strlen(s1);
size_t Len2 = strlen(s2);
size_t N = std::min(Len1, Len2);
if (N <= 1) return; // Not interesting.
- // Simplification: handle only first 8 bytes.
- memcpy(&S1, s1, std::min(N, sizeof(S1)));
- memcpy(&S2, s2, std::min(N, sizeof(S2)));
dfsan_label L1 = dfsan_read_label(s1, Len1);
dfsan_label L2 = dfsan_read_label(s2, Len2);
- TS->DFSanCmpCallback(PC, N, fuzzer::ICMP_EQ, S1, S2, L1, L2);
+ TS->DFSanMemcmpCallback(N, reinterpret_cast<const uint8_t *>(s1),
+ reinterpret_cast<const uint8_t *>(s2), L1, L2);
}
+// We may need to avoid defining weak hooks to stay compatible with older clang.
+#ifndef LLVM_FUZZER_DEFINES_SANITIZER_WEAK_HOOOKS
+# define LLVM_FUZZER_DEFINES_SANITIZER_WEAK_HOOOKS 1
+#endif
+
+#if LLVM_FUZZER_DEFINES_SANITIZER_WEAK_HOOOKS
void __sanitizer_weak_hook_memcmp(void *caller_pc, const void *s1,
- const void *s2, size_t n) {
+ const void *s2, size_t n, int result) {
if (!TS) return;
- uintptr_t PC = reinterpret_cast<uintptr_t>(caller_pc);
- uint64_t S1 = 0, S2 = 0;
- // Simplification: handle only first 8 bytes.
- memcpy(&S1, s1, std::min(n, sizeof(S1)));
- memcpy(&S2, s2, std::min(n, sizeof(S2)));
- TS->TraceCmpCallback(PC, n, fuzzer::ICMP_EQ, S1, S2);
+ if (result == 0) return; // No reason to mutate.
+ if (n <= 1) return; // Not interesting.
+ TS->TraceMemcmpCallback(n, reinterpret_cast<const uint8_t *>(s1),
+ reinterpret_cast<const uint8_t *>(s2));
}
void __sanitizer_weak_hook_strncmp(void *caller_pc, const char *s1,
- const char *s2, size_t n) {
+ const char *s2, size_t n, int result) {
if (!TS) return;
- uintptr_t PC = reinterpret_cast<uintptr_t>(caller_pc);
- uint64_t S1 = 0, S2 = 0;
+ if (result == 0) return; // No reason to mutate.
size_t Len1 = fuzzer::InternalStrnlen(s1, n);
size_t Len2 = fuzzer::InternalStrnlen(s2, n);
n = std::min(n, Len1);
n = std::min(n, Len2);
if (n <= 1) return; // Not interesting.
- // Simplification: handle only first 8 bytes.
- memcpy(&S1, s1, std::min(n, sizeof(S1)));
- memcpy(&S2, s2, std::min(n, sizeof(S2)));
- TS->TraceCmpCallback(PC, n, fuzzer::ICMP_EQ, S1, S2);
+ TS->TraceMemcmpCallback(n, reinterpret_cast<const uint8_t *>(s1),
+ reinterpret_cast<const uint8_t *>(s2));
}
void __sanitizer_weak_hook_strcmp(void *caller_pc, const char *s1,
- const char *s2) {
+ const char *s2, int result) {
if (!TS) return;
- uintptr_t PC = reinterpret_cast<uintptr_t>(caller_pc);
- uint64_t S1 = 0, S2 = 0;
+ if (result == 0) return; // No reason to mutate.
size_t Len1 = strlen(s1);
size_t Len2 = strlen(s2);
size_t N = std::min(Len1, Len2);
if (N <= 1) return; // Not interesting.
- // Simplification: handle only first 8 bytes.
- memcpy(&S1, s1, std::min(N, sizeof(S1)));
- memcpy(&S2, s2, std::min(N, sizeof(S2)));
- TS->TraceCmpCallback(PC, N, fuzzer::ICMP_EQ, S1, S2);
+ TS->TraceMemcmpCallback(N, reinterpret_cast<const uint8_t *>(s1),
+ reinterpret_cast<const uint8_t *>(s2));
}
+#endif // LLVM_FUZZER_DEFINES_SANITIZER_WEAK_HOOOKS
+
__attribute__((visibility("default")))
void __sanitizer_cov_trace_cmp(uint64_t SizeAndType, uint64_t Arg1,
uint64_t Arg2) {
diff --git a/lib/Fuzzer/FuzzerUtil.cpp b/lib/Fuzzer/FuzzerUtil.cpp
index 6c1133fffd37..d7226cfce966 100644
--- a/lib/Fuzzer/FuzzerUtil.cpp
+++ b/lib/Fuzzer/FuzzerUtil.cpp
@@ -27,13 +27,26 @@ void Print(const Unit &v, const char *PrintAfter) {
Printf("%s", PrintAfter);
}
+void PrintASCIIByte(uint8_t Byte) {
+ if (Byte == '\\')
+ Printf("\\\\");
+ else if (Byte == '"')
+ Printf("\\\"");
+ else if (Byte >= 32 && Byte < 127)
+ Printf("%c", Byte);
+ else
+ Printf("\\x%02x", Byte);
+}
+
+void PrintASCII(const uint8_t *Data, size_t Size, const char *PrintAfter) {
+ for (size_t i = 0; i < Size; i++)
+ PrintASCIIByte(Data[i]);
+ Printf("%s", PrintAfter);
+}
+
void PrintASCII(const Unit &U, const char *PrintAfter) {
- for (auto X : U) {
- if (isprint(X))
- Printf("%c", X);
- else
- Printf("\\x%x", (unsigned)X);
- }
+ for (auto X : U)
+ PrintASCIIByte(X);
Printf("%s", PrintAfter);
}
diff --git a/lib/Fuzzer/test/FuzzerUnittest.cpp b/lib/Fuzzer/test/FuzzerUnittest.cpp
index 8c0012708afc..b33e0c961455 100644
--- a/lib/Fuzzer/test/FuzzerUnittest.cpp
+++ b/lib/Fuzzer/test/FuzzerUnittest.cpp
@@ -247,8 +247,8 @@ void TestAddWordFromDictionary(Mutator M, int NumIter) {
MutationDispatcher MD(Rand);
uint8_t Word1[4] = {0xAA, 0xBB, 0xCC, 0xDD};
uint8_t Word2[3] = {0xFF, 0xEE, 0xEF};
- MD.AddWordToDictionary(Word1, sizeof(Word1));
- MD.AddWordToDictionary(Word2, sizeof(Word2));
+ MD.AddWordToManualDictionary(Unit(Word1, Word1 + sizeof(Word1)));
+ MD.AddWordToManualDictionary(Unit(Word2, Word2 + sizeof(Word2)));
int FoundMask = 0;
uint8_t CH0[7] = {0x00, 0x11, 0x22, 0xAA, 0xBB, 0xCC, 0xDD};
uint8_t CH1[7] = {0x00, 0x11, 0xAA, 0xBB, 0xCC, 0xDD, 0x22};
@@ -274,14 +274,41 @@ void TestAddWordFromDictionary(Mutator M, int NumIter) {
}
TEST(FuzzerMutate, AddWordFromDictionary1) {
- TestAddWordFromDictionary(&MutationDispatcher::Mutate_AddWordFromDictionary,
- 1 << 15);
+ TestAddWordFromDictionary(
+ &MutationDispatcher::Mutate_AddWordFromManualDictionary, 1 << 15);
}
TEST(FuzzerMutate, AddWordFromDictionary2) {
TestAddWordFromDictionary(&MutationDispatcher::Mutate, 1 << 15);
}
+void TestAddWordFromDictionaryWithHint(Mutator M, int NumIter) {
+ FuzzerRandomLibc Rand(0);
+ MutationDispatcher MD(Rand);
+ uint8_t Word[] = {0xAA, 0xBB, 0xCC, 0xDD, 0xFF, 0xEE, 0xEF};
+ size_t PosHint = 7777;
+ MD.AddWordToAutoDictionary(Unit(Word, Word + sizeof(Word)), PosHint);
+ int FoundMask = 0;
+ for (int i = 0; i < NumIter; i++) {
+ uint8_t T[10000];
+ memset(T, 0, sizeof(T));
+ size_t NewSize = (MD.*M)(T, 9000, 10000);
+ if (NewSize >= PosHint + sizeof(Word) &&
+ !memcmp(Word, T + PosHint, sizeof(Word)))
+ FoundMask = 1;
+ }
+ EXPECT_EQ(FoundMask, 1);
+}
+
+TEST(FuzzerMutate, AddWordFromDictionaryWithHint1) {
+ TestAddWordFromDictionaryWithHint(
+ &MutationDispatcher::Mutate_AddWordFromAutoDictionary, 1 << 5);
+}
+
+TEST(FuzzerMutate, AddWordFromDictionaryWithHint2) {
+ TestAddWordFromDictionaryWithHint(&MutationDispatcher::Mutate, 1 << 10);
+}
+
void TestChangeASCIIInteger(Mutator M, int NumIter) {
FuzzerRandomLibc Rand(0);
MutationDispatcher MD(Rand);
diff --git a/lib/Fuzzer/test/MemcmpTest.cpp b/lib/Fuzzer/test/MemcmpTest.cpp
index 47ce59e0d8f5..c19c95717bbb 100644
--- a/lib/Fuzzer/test/MemcmpTest.cpp
+++ b/lib/Fuzzer/test/MemcmpTest.cpp
@@ -10,8 +10,16 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
if (Size >= 12 && memcmp(Data + 8, "ABCD", 4) == 0) {
if (Size >= 14 && memcmp(Data + 12, "XY", 2) == 0) {
if (Size >= 16 && memcmp(Data + 14, "KLM", 3) == 0) {
- fprintf(stderr, "BINGO\n");
- exit(1);
+ if (Size >= 27 && memcmp(Data + 17, "ABCDE-GHIJ", 10) == 0){
+ fprintf(stderr, "BINGO %zd\n", Size);
+ for (size_t i = 0; i < Size; i++) {
+ uint8_t C = Data[i];
+ if (C >= 32 && C < 127)
+ fprintf(stderr, "%c", C);
+ }
+ fprintf(stderr, "\n");
+ exit(1);
+ }
}
}
}
diff --git a/lib/Fuzzer/test/fuzzer-dfsan.test b/lib/Fuzzer/test/fuzzer-dfsan.test
index 982f143669d0..567086ed65af 100644
--- a/lib/Fuzzer/test/fuzzer-dfsan.test
+++ b/lib/Fuzzer/test/fuzzer-dfsan.test
@@ -5,18 +5,19 @@ CHECK4: BINGO
CHECK_DFSanCmpCallback: DFSanCmpCallback: PC
CHECK_DFSanSwitchCallback: DFSanSwitchCallback: PC
+CHECK_DFSanMemcmpCallback: DFSanMemcmpCallback: Pos
RUN: not LLVMFuzzer-SimpleCmpTest-DFSan -use_traces=1 -seed=1 -runs=1000000 -timeout=5 2>&1 | FileCheck %s --check-prefix=CHECK1
RUN: LLVMFuzzer-SimpleCmpTest-DFSan -use_traces=1 -seed=1 -runs=100 -timeout=5 -verbosity=3 2>&1 | FileCheck %s -check-prefix=CHECK_DFSanCmpCallback
RUN: not LLVMFuzzer-MemcmpTest-DFSan -use_traces=1 -seed=1 -runs=10000 -timeout=5 2>&1 | FileCheck %s --check-prefix=CHECK2
-RUN: LLVMFuzzer-MemcmpTest-DFSan -use_traces=1 -seed=1 -runs=2 -timeout=5 -verbosity=3 2>&1 | FileCheck %s -check-prefix=CHECK_DFSanCmpCallback
+RUN: LLVMFuzzer-MemcmpTest-DFSan -use_traces=1 -seed=1 -runs=2 -timeout=5 -verbosity=3 2>&1 | FileCheck %s -check-prefix=CHECK_DFSanMemcmpCallback
RUN: not LLVMFuzzer-StrncmpTest-DFSan -use_traces=1 -seed=1 -runs=10000 -timeout=5 2>&1 | FileCheck %s --check-prefix=CHECK3
-RUN: LLVMFuzzer-StrncmpTest-DFSan -use_traces=1 -seed=1 -runs=2 -timeout=5 -verbosity=3 2>&1 | FileCheck %s -check-prefix=CHECK_DFSanCmpCallback
+RUN: LLVMFuzzer-StrncmpTest-DFSan -use_traces=1 -seed=1 -runs=2 -timeout=5 -verbosity=3 2>&1 | FileCheck %s -check-prefix=CHECK_DFSanMemcmpCallback
RUN: not LLVMFuzzer-StrcmpTest-DFSan -use_traces=1 -seed=1 -runs=10000 -timeout=5 2>&1 | FileCheck %s --check-prefix=CHECK3
-RUN: LLVMFuzzer-StrcmpTest-DFSan -use_traces=1 -seed=1 -runs=2 -timeout=5 -verbosity=3 2>&1 | FileCheck %s -check-prefix=CHECK_DFSanCmpCallback
+RUN: LLVMFuzzer-StrcmpTest-DFSan -use_traces=1 -seed=1 -runs=2 -timeout=5 -verbosity=3 2>&1 | FileCheck %s -check-prefix=CHECK_DFSanMemcmpCallback
RUN: not LLVMFuzzer-SwitchTest-DFSan -use_traces=1 -seed=1 -runs=100000 -timeout=5 2>&1 | FileCheck %s --check-prefix=CHECK4
RUN: LLVMFuzzer-SwitchTest-DFSan -use_traces=1 -seed=1 -runs=2 -timeout=5 -verbosity=3 2>&1 | FileCheck %s -check-prefix=CHECK_DFSanSwitchCallback
diff --git a/lib/Fuzzer/test/fuzzer-dict.test b/lib/Fuzzer/test/fuzzer-dict.test
new file mode 100644
index 000000000000..dec002f6a377
--- /dev/null
+++ b/lib/Fuzzer/test/fuzzer-dict.test
@@ -0,0 +1,6 @@
+CHECK: BINGO
+Done1000000: Done 1000000 runs in
+
+RUN: not LLVMFuzzer-SimpleDictionaryTest -dict=%S/dict1.txt -seed=1 -runs=1000003 2>&1 | FileCheck %s
+RUN: LLVMFuzzer-SimpleDictionaryTest -seed=1 -runs=1000000 2>&1 | FileCheck %s --check-prefix=Done1000000
+
diff --git a/lib/Fuzzer/test/fuzzer-traces.test b/lib/Fuzzer/test/fuzzer-traces.test
index 084cf30d6982..3b8639b8e941 100644
--- a/lib/Fuzzer/test/fuzzer-traces.test
+++ b/lib/Fuzzer/test/fuzzer-traces.test
@@ -1,7 +1,8 @@
CHECK: BINGO
Done1000000: Done 1000000 runs in
+Done10000000: Done 10000000 runs in
-RUN: not LLVMFuzzer-SimpleCmpTest -use_traces=1 -seed=1 -runs=1000001 2>&1 | FileCheck %s
+RUN: not LLVMFuzzer-SimpleCmpTest -use_traces=1 -seed=1 -runs=10000001 2>&1 | FileCheck %s
RUN: not LLVMFuzzer-MemcmpTest -use_traces=1 -seed=4294967295 -runs=100000 2>&1 | FileCheck %s
RUN: LLVMFuzzer-MemcmpTest -seed=4294967295 -runs=1000000 2>&1 | FileCheck %s --check-prefix=Done1000000
@@ -15,5 +16,5 @@ RUN: LLVMFuzzer-StrcmpTest -seed=1 -runs=1000000 2>&1 | FileC
RUN: not LLVMFuzzer-SwitchTest -use_traces=1 -seed=1 -runs=1000002 2>&1 | FileCheck %s
RUN: LLVMFuzzer-SwitchTest -seed=1 -runs=1000000 2>&1 | FileCheck %s --check-prefix=Done1000000
-RUN: not LLVMFuzzer-SimpleHashTest -use_traces=1 -seed=1 -runs=100000 2>&1 | FileCheck %s
-RUN: LLVMFuzzer-SimpleHashTest -seed=1 -runs=1000000 2>&1 | FileCheck %s --check-prefix=Done1000000
+RUN: not LLVMFuzzer-SimpleHashTest -use_traces=1 -seed=1 -runs=10000000 2>&1 | FileCheck %s
+RUN: LLVMFuzzer-SimpleHashTest -seed=1 -runs=10000000 2>&1 | FileCheck %s --check-prefix=Done10000000
diff --git a/lib/Fuzzer/test/fuzzer.test b/lib/Fuzzer/test/fuzzer.test
index 150fc7202b00..c63014f59d62 100644
--- a/lib/Fuzzer/test/fuzzer.test
+++ b/lib/Fuzzer/test/fuzzer.test
@@ -20,14 +20,12 @@ NullDerefTestExactPath: Test unit written to FOOBAR
RUN: not LLVMFuzzer-CounterTest -use_counters=1 -max_len=6 -seed=1 -timeout=15 2>&1 | FileCheck %s
RUN: not LLVMFuzzer-CallerCalleeTest -cross_over=0 -max_len=6 -seed=1 -timeout=15 2>&1 | FileCheck %s
-RUN: LLVMFuzzer-CallerCalleeTest -use_indir_calls=0 -cross_over=0 -max_len=6 -seed=1 -runs=1000000 2>&1 | FileCheck %s --check-prefix=Done1000000
+# This one is flaky, may actually find the goal even w/o use_indir_calls.
+# LLVMFuzzer-CallerCalleeTest -use_indir_calls=0 -cross_over=0 -max_len=6 -seed=1 -runs=1000000 2>&1 | FileCheck %s --check-prefix=Done1000000
RUN: not LLVMFuzzer-UserSuppliedFuzzerTest -seed=1 -timeout=15 2>&1 | FileCheck %s
-RUN: not LLVMFuzzer-SimpleDictionaryTest -dict=%S/dict1.txt -seed=1 -runs=1000003 2>&1 | FileCheck %s
-RUN: LLVMFuzzer-SimpleDictionaryTest -seed=1 -runs=1000000 2>&1 | FileCheck %s --check-prefix=Done1000000
-
RUN: not LLVMFuzzer-UninstrumentedTest-Uninstrumented 2>&1 | FileCheck %s --check-prefix=UNINSTRUMENTED
UNINSTRUMENTED: ERROR: __sanitizer_set_death_callback is not defined. Exiting.
diff --git a/lib/IR/AsmWriter.cpp b/lib/IR/AsmWriter.cpp
index 1ebe9b7ee5bc..0ce44e105cc3 100644
--- a/lib/IR/AsmWriter.cpp
+++ b/lib/IR/AsmWriter.cpp
@@ -3121,7 +3121,7 @@ void AssemblyWriter::printMetadataAttachments(
return;
if (MDNames.empty())
- TheModule->getMDKindNames(MDNames);
+ MDs[0].second->getContext().getMDKindNames(MDNames);
for (const auto &I : MDs) {
unsigned Kind = I.first;
diff --git a/lib/IR/Core.cpp b/lib/IR/Core.cpp
index 7f39c8085a69..591dafa22a4b 100644
--- a/lib/IR/Core.cpp
+++ b/lib/IR/Core.cpp
@@ -1722,7 +1722,7 @@ void LLVMSetFunctionCallConv(LLVMValueRef Fn, unsigned CC) {
const char *LLVMGetGC(LLVMValueRef Fn) {
Function *F = unwrap<Function>(Fn);
- return F->hasGC()? F->getGC() : nullptr;
+ return F->hasGC()? F->getGC().c_str() : nullptr;
}
void LLVMSetGC(LLVMValueRef Fn, const char *GC) {
diff --git a/lib/IR/Function.cpp b/lib/IR/Function.cpp
index cfb40b19c733..cfdfc40cd8aa 100644
--- a/lib/IR/Function.cpp
+++ b/lib/IR/Function.cpp
@@ -366,47 +366,21 @@ void Function::addDereferenceableOrNullAttr(unsigned i, uint64_t Bytes) {
setAttributes(PAL);
}
-// Maintain the GC name for each function in an on-the-side table. This saves
-// allocating an additional word in Function for programs which do not use GC
-// (i.e., most programs) at the cost of increased overhead for clients which do
-// use GC.
-static DenseMap<const Function*,PooledStringPtr> *GCNames;
-static StringPool *GCNamePool;
-static ManagedStatic<sys::SmartRWMutex<true> > GCLock;
-
-bool Function::hasGC() const {
- sys::SmartScopedReader<true> Reader(*GCLock);
- return GCNames && GCNames->count(this);
-}
-
-const char *Function::getGC() const {
+const std::string &Function::getGC() const {
assert(hasGC() && "Function has no collector");
- sys::SmartScopedReader<true> Reader(*GCLock);
- return *(*GCNames)[this];
+ return getContext().getGC(*this);
}
-void Function::setGC(const char *Str) {
- sys::SmartScopedWriter<true> Writer(*GCLock);
- if (!GCNamePool)
- GCNamePool = new StringPool();
- if (!GCNames)
- GCNames = new DenseMap<const Function*,PooledStringPtr>();
- (*GCNames)[this] = GCNamePool->intern(Str);
+void Function::setGC(const std::string Str) {
+ setValueSubclassDataBit(14, !Str.empty());
+ getContext().setGC(*this, std::move(Str));
}
void Function::clearGC() {
- sys::SmartScopedWriter<true> Writer(*GCLock);
- if (GCNames) {
- GCNames->erase(this);
- if (GCNames->empty()) {
- delete GCNames;
- GCNames = nullptr;
- if (GCNamePool->empty()) {
- delete GCNamePool;
- GCNamePool = nullptr;
- }
- }
- }
+ if (!hasGC())
+ return;
+ getContext().deleteGC(*this);
+ setValueSubclassDataBit(14, false);
}
/// Copy all additional attributes (those not needed to create a Function) from
diff --git a/lib/IR/IRPrintingPasses.cpp b/lib/IR/IRPrintingPasses.cpp
index c1ac336c1fbf..822dbeb08b33 100644
--- a/lib/IR/IRPrintingPasses.cpp
+++ b/lib/IR/IRPrintingPasses.cpp
@@ -28,7 +28,13 @@ PrintModulePass::PrintModulePass(raw_ostream &OS, const std::string &Banner,
PreservedAnalyses PrintModulePass::run(Module &M) {
OS << Banner;
- M.print(OS, nullptr, ShouldPreserveUseListOrder);
+ if (llvm::isFunctionInPrintList("*"))
+ M.print(OS, nullptr, ShouldPreserveUseListOrder);
+ else {
+ for(const auto &F : M.functions())
+ if (llvm::isFunctionInPrintList(F.getName()))
+ F.print(OS);
+ }
return PreservedAnalyses::all();
}
@@ -37,7 +43,8 @@ PrintFunctionPass::PrintFunctionPass(raw_ostream &OS, const std::string &Banner)
: OS(OS), Banner(Banner) {}
PreservedAnalyses PrintFunctionPass::run(Function &F) {
- OS << Banner << static_cast<Value &>(F);
+ if (isFunctionInPrintList(F.getName()))
+ OS << Banner << static_cast<Value &>(F);
return PreservedAnalyses::all();
}
diff --git a/lib/IR/LLVMContext.cpp b/lib/IR/LLVMContext.cpp
index 8848bcb71477..48b53b0f532a 100644
--- a/lib/IR/LLVMContext.cpp
+++ b/lib/IR/LLVMContext.cpp
@@ -304,3 +304,19 @@ void LLVMContext::getOperandBundleTags(SmallVectorImpl<StringRef> &Tags) const {
uint32_t LLVMContext::getOperandBundleTagID(StringRef Tag) const {
return pImpl->getOperandBundleTagID(Tag);
}
+
+void LLVMContext::setGC(const Function &Fn, std::string GCName) {
+ auto It = pImpl->GCNames.find(&Fn);
+
+ if (It == pImpl->GCNames.end()) {
+ pImpl->GCNames.insert(std::make_pair(&Fn, std::move(GCName)));
+ return;
+ }
+ It->second = std::move(GCName);
+}
+const std::string &LLVMContext::getGC(const Function &Fn) {
+ return pImpl->GCNames[&Fn];
+}
+void LLVMContext::deleteGC(const Function &Fn) {
+ pImpl->GCNames.erase(&Fn);
+}
diff --git a/lib/IR/LLVMContextImpl.h b/lib/IR/LLVMContextImpl.h
index a24114d0a0ae..d42047d4e775 100644
--- a/lib/IR/LLVMContextImpl.h
+++ b/lib/IR/LLVMContextImpl.h
@@ -1027,6 +1027,13 @@ public:
void getOperandBundleTags(SmallVectorImpl<StringRef> &Tags) const;
uint32_t getOperandBundleTagID(StringRef Tag) const;
+ /// Maintain the GC name for each function.
+ ///
+ /// This saves allocating an additional word in Function for programs which
+ /// do not use GC (i.e., most programs) at the cost of increased overhead for
+ /// clients which do use GC.
+ DenseMap<const Function*, std::string> GCNames;
+
LLVMContextImpl(LLVMContext &C);
~LLVMContextImpl();
diff --git a/lib/IR/LegacyPassManager.cpp b/lib/IR/LegacyPassManager.cpp
index f2e0c7d32c02..63d89f21b350 100644
--- a/lib/IR/LegacyPassManager.cpp
+++ b/lib/IR/LegacyPassManager.cpp
@@ -28,6 +28,7 @@
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <map>
+#include <unordered_set>
using namespace llvm;
using namespace llvm::legacy;
@@ -83,6 +84,13 @@ PrintAfterAll("print-after-all",
llvm::cl::desc("Print IR after each pass"),
cl::init(false));
+static cl::list<std::string>
+ PrintFuncsList("filter-print-funcs", cl::value_desc("function names"),
+ cl::desc("Only print IR for functions whose name "
+ "match this for all print-[before|after][-all] "
+ "options"),
+ cl::CommaSeparated);
+
/// This is a helper to determine whether to print IR before or
/// after a pass.
@@ -109,6 +117,11 @@ static bool ShouldPrintAfterPass(const PassInfo *PI) {
return PrintAfterAll || ShouldPrintBeforeOrAfterPass(PI, PrintAfter);
}
+bool llvm::isFunctionInPrintList(StringRef FunctionName) {
+ static std::unordered_set<std::string> PrintFuncNames(PrintFuncsList.begin(),
+ PrintFuncsList.end());
+ return PrintFuncNames.empty() || PrintFuncNames.count(FunctionName);
+}
/// isPassDebuggingExecutionsOrMore - Return true if -debug-pass=Executions
/// or higher is specified.
bool PMDataManager::isPassDebuggingExecutionsOrMore() const {
diff --git a/lib/IR/Metadata.cpp b/lib/IR/Metadata.cpp
index d8eaceb9ea2b..9a9a5017841c 100644
--- a/lib/IR/Metadata.cpp
+++ b/lib/IR/Metadata.cpp
@@ -557,7 +557,7 @@ void MDNode::decrementUnresolvedOperandCount() {
resolve();
}
-void MDNode::resolveCycles(bool AllowTemps) {
+void MDNode::resolveRecursivelyImpl(bool AllowTemps) {
if (isResolved())
return;
diff --git a/lib/IR/Verifier.cpp b/lib/IR/Verifier.cpp
index 6dfb05d94491..9198b0e1fb58 100644
--- a/lib/IR/Verifier.cpp
+++ b/lib/IR/Verifier.cpp
@@ -45,6 +45,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/IR/Verifier.h"
+#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallPtrSet.h"
@@ -145,6 +146,11 @@ private:
OS << *C;
}
+ template <typename T> void Write(ArrayRef<T> Vs) {
+ for (const T &V : Vs)
+ Write(V);
+ }
+
template <typename T1, typename... Ts>
void WriteTs(const T1 &V1, const Ts &... Vs) {
Write(V1);
@@ -204,6 +210,10 @@ class Verifier : public InstVisitor<Verifier>, VerifierSupport {
/// given function and the largest index passed to llvm.localrecover.
DenseMap<Function *, std::pair<unsigned, unsigned>> FrameEscapeInfo;
+ // Maps catchswitches and cleanuppads that unwind to siblings to the
+ // terminators that indicate the unwind, used to detect cycles therein.
+ MapVector<Instruction *, TerminatorInst *> SiblingFuncletInfo;
+
/// Cache of constants visited in search of ConstantExprs.
SmallPtrSet<const Constant *, 32> ConstantExprVisited;
@@ -245,9 +255,11 @@ public:
Broken = false;
// FIXME: We strip const here because the inst visitor strips const.
visit(const_cast<Function &>(F));
+ verifySiblingFuncletUnwinds();
InstsInThisBlock.clear();
LandingPadResultTy = nullptr;
SawFrameEscape = false;
+ SiblingFuncletInfo.clear();
return !Broken;
}
@@ -403,6 +415,7 @@ private:
void visitCatchPadInst(CatchPadInst &CPI);
void visitCatchReturnInst(CatchReturnInst &CatchReturn);
void visitCleanupPadInst(CleanupPadInst &CPI);
+ void visitFuncletPadInst(FuncletPadInst &FPI);
void visitCatchSwitchInst(CatchSwitchInst &CatchSwitch);
void visitCleanupReturnInst(CleanupReturnInst &CRI);
@@ -428,6 +441,7 @@ private:
void visitConstantExpr(const ConstantExpr *CE);
void VerifyStatepoint(ImmutableCallSite CS);
void verifyFrameRecoverIndices();
+ void verifySiblingFuncletUnwinds();
// Module-level debug info verification...
void verifyTypeRefs();
@@ -984,6 +998,9 @@ void Verifier::visitDIMacro(const DIMacro &N) {
N.getMacinfoType() == dwarf::DW_MACINFO_undef,
"invalid macinfo type", &N);
Assert(!N.getName().empty(), "anonymous macro", &N);
+ if (!N.getValue().empty()) {
+ assert(N.getValue().data()[0] != ' ' && "Macro value has a space prefix");
+ }
}
void Verifier::visitDIMacroFile(const DIMacroFile &N) {
@@ -1693,6 +1710,59 @@ void Verifier::verifyFrameRecoverIndices() {
}
}
+static Instruction *getSuccPad(TerminatorInst *Terminator) {
+ BasicBlock *UnwindDest;
+ if (auto *II = dyn_cast<InvokeInst>(Terminator))
+ UnwindDest = II->getUnwindDest();
+ else if (auto *CSI = dyn_cast<CatchSwitchInst>(Terminator))
+ UnwindDest = CSI->getUnwindDest();
+ else
+ UnwindDest = cast<CleanupReturnInst>(Terminator)->getUnwindDest();
+ return UnwindDest->getFirstNonPHI();
+}
+
+void Verifier::verifySiblingFuncletUnwinds() {
+ SmallPtrSet<Instruction *, 8> Visited;
+ SmallPtrSet<Instruction *, 8> Active;
+ for (const auto &Pair : SiblingFuncletInfo) {
+ Instruction *PredPad = Pair.first;
+ if (Visited.count(PredPad))
+ continue;
+ Active.insert(PredPad);
+ TerminatorInst *Terminator = Pair.second;
+ do {
+ Instruction *SuccPad = getSuccPad(Terminator);
+ if (Active.count(SuccPad)) {
+ // Found a cycle; report error
+ Instruction *CyclePad = SuccPad;
+ SmallVector<Instruction *, 8> CycleNodes;
+ do {
+ CycleNodes.push_back(CyclePad);
+ TerminatorInst *CycleTerminator = SiblingFuncletInfo[CyclePad];
+ if (CycleTerminator != CyclePad)
+ CycleNodes.push_back(CycleTerminator);
+ CyclePad = getSuccPad(CycleTerminator);
+ } while (CyclePad != SuccPad);
+ Assert(false, "EH pads can't handle each other's exceptions",
+ ArrayRef<Instruction *>(CycleNodes));
+ }
+ // Don't re-walk a node we've already checked
+ if (!Visited.insert(SuccPad).second)
+ break;
+ // Walk to this successor if it has a map entry.
+ PredPad = SuccPad;
+ auto TermI = SiblingFuncletInfo.find(PredPad);
+ if (TermI == SiblingFuncletInfo.end())
+ break;
+ Terminator = TermI->second;
+ Active.insert(PredPad);
+ } while (true);
+ // Each node only has one successor, so we've walked all the active
+ // nodes' successors.
+ Active.clear();
+ }
+}
+
// visitFunction - Verify that a function is ok.
//
void Verifier::visitFunction(const Function &F) {
@@ -2892,6 +2962,13 @@ void Verifier::visitInsertValueInst(InsertValueInst &IVI) {
visitInstruction(IVI);
}
+static Value *getParentPad(Value *EHPad) {
+ if (auto *FPI = dyn_cast<FuncletPadInst>(EHPad))
+ return FPI->getParentPad();
+
+ return cast<CatchSwitchInst>(EHPad)->getParentPad();
+}
+
void Verifier::visitEHPadPredecessors(Instruction &I) {
assert(I.isEHPad());
@@ -2919,16 +2996,45 @@ void Verifier::visitEHPadPredecessors(Instruction &I) {
"Block containg CatchPadInst must be jumped to "
"only by its catchswitch.",
CPI);
+ Assert(BB != CPI->getCatchSwitch()->getUnwindDest(),
+ "Catchswitch cannot unwind to one of its catchpads",
+ CPI->getCatchSwitch(), CPI);
return;
}
+ // Verify that each pred has a legal terminator with a legal to/from EH
+ // pad relationship.
+ Instruction *ToPad = &I;
+ Value *ToPadParent = getParentPad(ToPad);
for (BasicBlock *PredBB : predecessors(BB)) {
TerminatorInst *TI = PredBB->getTerminator();
+ Value *FromPad;
if (auto *II = dyn_cast<InvokeInst>(TI)) {
Assert(II->getUnwindDest() == BB && II->getNormalDest() != BB,
- "EH pad must be jumped to via an unwind edge", &I, II);
- } else if (!isa<CleanupReturnInst>(TI) && !isa<CatchSwitchInst>(TI)) {
- Assert(false, "EH pad must be jumped to via an unwind edge", &I, TI);
+ "EH pad must be jumped to via an unwind edge", ToPad, II);
+ if (auto Bundle = II->getOperandBundle(LLVMContext::OB_funclet))
+ FromPad = Bundle->Inputs[0];
+ else
+ FromPad = ConstantTokenNone::get(II->getContext());
+ } else if (auto *CRI = dyn_cast<CleanupReturnInst>(TI)) {
+ FromPad = CRI->getCleanupPad();
+ Assert(FromPad != ToPadParent, "A cleanupret must exit its cleanup", CRI);
+ } else if (auto *CSI = dyn_cast<CatchSwitchInst>(TI)) {
+ FromPad = CSI;
+ } else {
+ Assert(false, "EH pad must be jumped to via an unwind edge", ToPad, TI);
+ }
+
+ // The edge may exit from zero or more nested pads.
+ for (;; FromPad = getParentPad(FromPad)) {
+ Assert(FromPad != ToPad,
+ "EH pad cannot handle exceptions raised within it", FromPad, TI);
+ if (FromPad == ToPadParent) {
+ // This is a legal unwind edge.
+ break;
+ }
+ Assert(!isa<ConstantTokenNone>(FromPad),
+ "A single unwind edge may only enter one EH pad", TI);
}
}
}
@@ -2992,7 +3098,7 @@ void Verifier::visitCatchPadInst(CatchPadInst &CPI) {
Assert(BB->getFirstNonPHI() == &CPI,
"CatchPadInst not the first non-PHI instruction in the block.", &CPI);
- visitInstruction(CPI);
+ visitFuncletPadInst(CPI);
}
void Verifier::visitCatchReturnInst(CatchReturnInst &CatchReturn) {
@@ -3022,33 +3128,160 @@ void Verifier::visitCleanupPadInst(CleanupPadInst &CPI) {
Assert(isa<ConstantTokenNone>(ParentPad) || isa<FuncletPadInst>(ParentPad),
"CleanupPadInst has an invalid parent.", &CPI);
+ visitFuncletPadInst(CPI);
+}
+
+void Verifier::visitFuncletPadInst(FuncletPadInst &FPI) {
User *FirstUser = nullptr;
- BasicBlock *FirstUnwindDest = nullptr;
- for (User *U : CPI.users()) {
- BasicBlock *UnwindDest;
- if (CleanupReturnInst *CRI = dyn_cast<CleanupReturnInst>(U)) {
- UnwindDest = CRI->getUnwindDest();
- } else if (isa<CleanupPadInst>(U) || isa<CatchSwitchInst>(U)) {
- continue;
- } else if (CallSite(U)) {
- continue;
- } else {
- Assert(false, "bogus cleanuppad use", &CPI);
+ Value *FirstUnwindPad = nullptr;
+ SmallVector<FuncletPadInst *, 8> Worklist({&FPI});
+ while (!Worklist.empty()) {
+ FuncletPadInst *CurrentPad = Worklist.pop_back_val();
+ Value *UnresolvedAncestorPad = nullptr;
+ for (User *U : CurrentPad->users()) {
+ BasicBlock *UnwindDest;
+ if (auto *CRI = dyn_cast<CleanupReturnInst>(U)) {
+ UnwindDest = CRI->getUnwindDest();
+ } else if (auto *CSI = dyn_cast<CatchSwitchInst>(U)) {
+ // We allow catchswitch unwind to caller to nest
+ // within an outer pad that unwinds somewhere else,
+ // because catchswitch doesn't have a nounwind variant.
+ // See e.g. SimplifyCFGOpt::SimplifyUnreachable.
+ if (CSI->unwindsToCaller())
+ continue;
+ UnwindDest = CSI->getUnwindDest();
+ } else if (auto *II = dyn_cast<InvokeInst>(U)) {
+ UnwindDest = II->getUnwindDest();
+ } else if (isa<CallInst>(U)) {
+ // Calls which don't unwind may be found inside funclet
+ // pads that unwind somewhere else. We don't *require*
+ // such calls to be annotated nounwind.
+ continue;
+ } else if (auto *CPI = dyn_cast<CleanupPadInst>(U)) {
+ // The unwind dest for a cleanup can only be found by
+ // recursive search. Add it to the worklist, and we'll
+ // search for its first use that determines where it unwinds.
+ Worklist.push_back(CPI);
+ continue;
+ } else {
+ Assert(isa<CatchReturnInst>(U), "Bogus funclet pad use", U);
+ continue;
+ }
+
+ Value *UnwindPad;
+ bool ExitsFPI;
+ if (UnwindDest) {
+ UnwindPad = UnwindDest->getFirstNonPHI();
+ Value *UnwindParent = getParentPad(UnwindPad);
+ // Ignore unwind edges that don't exit CurrentPad.
+ if (UnwindParent == CurrentPad)
+ continue;
+ // Determine whether the original funclet pad is exited,
+ // and if we are scanning nested pads determine how many
+ // of them are exited so we can stop searching their
+ // children.
+ Value *ExitedPad = CurrentPad;
+ ExitsFPI = false;
+ do {
+ if (ExitedPad == &FPI) {
+ ExitsFPI = true;
+ // Now we can resolve any ancestors of CurrentPad up to
+ // FPI, but not including FPI since we need to make sure
+ // to check all direct users of FPI for consistency.
+ UnresolvedAncestorPad = &FPI;
+ break;
+ }
+ Value *ExitedParent = getParentPad(ExitedPad);
+ if (ExitedParent == UnwindParent) {
+ // ExitedPad is the ancestor-most pad which this unwind
+ // edge exits, so we can resolve up to it, meaning that
+ // ExitedParent is the first ancestor still unresolved.
+ UnresolvedAncestorPad = ExitedParent;
+ break;
+ }
+ ExitedPad = ExitedParent;
+ } while (!isa<ConstantTokenNone>(ExitedPad));
+ } else {
+ // Unwinding to caller exits all pads.
+ UnwindPad = ConstantTokenNone::get(FPI.getContext());
+ ExitsFPI = true;
+ UnresolvedAncestorPad = &FPI;
+ }
+
+ if (ExitsFPI) {
+ // This unwind edge exits FPI. Make sure it agrees with other
+ // such edges.
+ if (FirstUser) {
+ Assert(UnwindPad == FirstUnwindPad, "Unwind edges out of a funclet "
+ "pad must have the same unwind "
+ "dest",
+ &FPI, U, FirstUser);
+ } else {
+ FirstUser = U;
+ FirstUnwindPad = UnwindPad;
+ // Record cleanup sibling unwinds for verifySiblingFuncletUnwinds
+ if (isa<CleanupPadInst>(&FPI) && !isa<ConstantTokenNone>(UnwindPad) &&
+ getParentPad(UnwindPad) == getParentPad(&FPI))
+ SiblingFuncletInfo[&FPI] = cast<TerminatorInst>(U);
+ }
+ }
+ // Make sure we visit all uses of FPI, but for nested pads stop as
+ // soon as we know where they unwind to.
+ if (CurrentPad != &FPI)
+ break;
}
+ if (UnresolvedAncestorPad) {
+ if (CurrentPad == UnresolvedAncestorPad) {
+ // When CurrentPad is FPI itself, we don't mark it as resolved even if
+ // we've found an unwind edge that exits it, because we need to verify
+ // all direct uses of FPI.
+ assert(CurrentPad == &FPI);
+ continue;
+ }
+ // Pop off the worklist any nested pads that we've found an unwind
+ // destination for. The pads on the worklist are the uncles,
+ // great-uncles, etc. of CurrentPad. We've found an unwind destination
+ // for all ancestors of CurrentPad up to but not including
+ // UnresolvedAncestorPad.
+ Value *ResolvedPad = CurrentPad;
+ while (!Worklist.empty()) {
+ Value *UnclePad = Worklist.back();
+ Value *AncestorPad = getParentPad(UnclePad);
+ // Walk ResolvedPad up the ancestor list until we either find the
+ // uncle's parent or the last resolved ancestor.
+ while (ResolvedPad != AncestorPad) {
+ Value *ResolvedParent = getParentPad(ResolvedPad);
+ if (ResolvedParent == UnresolvedAncestorPad) {
+ break;
+ }
+ ResolvedPad = ResolvedParent;
+ }
+ // If the resolved ancestor search didn't find the uncle's parent,
+ // then the uncle is not yet resolved.
+ if (ResolvedPad != AncestorPad)
+ break;
+ // This uncle is resolved, so pop it from the worklist.
+ Worklist.pop_back();
+ }
+ }
+ }
- if (!FirstUser) {
- FirstUser = U;
- FirstUnwindDest = UnwindDest;
- } else {
- Assert(
- UnwindDest == FirstUnwindDest,
- "cleanupret instructions from the same cleanuppad must have the same "
- "unwind destination",
- FirstUser, U);
+ if (FirstUnwindPad) {
+ if (auto *CatchSwitch = dyn_cast<CatchSwitchInst>(FPI.getParentPad())) {
+ BasicBlock *SwitchUnwindDest = CatchSwitch->getUnwindDest();
+ Value *SwitchUnwindPad;
+ if (SwitchUnwindDest)
+ SwitchUnwindPad = SwitchUnwindDest->getFirstNonPHI();
+ else
+ SwitchUnwindPad = ConstantTokenNone::get(FPI.getContext());
+ Assert(SwitchUnwindPad == FirstUnwindPad,
+ "Unwind edges out of a catch must have the same unwind dest as "
+ "the parent catchswitch",
+ &FPI, FirstUser, CatchSwitch);
}
}
- visitInstruction(CPI);
+ visitInstruction(FPI);
}
void Verifier::visitCatchSwitchInst(CatchSwitchInst &CatchSwitch) {
@@ -3067,17 +3300,21 @@ void Verifier::visitCatchSwitchInst(CatchSwitchInst &CatchSwitch) {
"CatchSwitchInst not the first non-PHI instruction in the block.",
&CatchSwitch);
+ auto *ParentPad = CatchSwitch.getParentPad();
+ Assert(isa<ConstantTokenNone>(ParentPad) || isa<FuncletPadInst>(ParentPad),
+ "CatchSwitchInst has an invalid parent.", ParentPad);
+
if (BasicBlock *UnwindDest = CatchSwitch.getUnwindDest()) {
Instruction *I = UnwindDest->getFirstNonPHI();
Assert(I->isEHPad() && !isa<LandingPadInst>(I),
"CatchSwitchInst must unwind to an EH block which is not a "
"landingpad.",
&CatchSwitch);
- }
- auto *ParentPad = CatchSwitch.getParentPad();
- Assert(isa<ConstantTokenNone>(ParentPad) || isa<FuncletPadInst>(ParentPad),
- "CatchSwitchInst has an invalid parent.", ParentPad);
+ // Record catchswitch sibling unwinds for verifySiblingFuncletUnwinds
+ if (getParentPad(I) == ParentPad)
+ SiblingFuncletInfo[&CatchSwitch] = &CatchSwitch;
+ }
Assert(CatchSwitch.getNumHandlers() != 0,
"CatchSwitchInst cannot have empty handler list", &CatchSwitch);
@@ -3652,6 +3889,9 @@ void Verifier::visitIntrinsicCallSite(Intrinsic::ID ID, CallSite CS) {
case Intrinsic::experimental_gc_relocate: {
Assert(CS.getNumArgOperands() == 3, "wrong number of arguments", CS);
+ Assert(isa<PointerType>(CS.getType()->getScalarType()),
+ "gc.relocate must return a pointer or a vector of pointers", CS);
+
// Check that this relocate is correctly tied to the statepoint
// This is case for relocate on the unwinding path of an invoke statepoint
@@ -3734,17 +3974,20 @@ void Verifier::visitIntrinsicCallSite(Intrinsic::ID ID, CallSite CS) {
"'gc parameters' section of the statepoint call",
CS);
- // Relocated value must be a pointer type, but gc_relocate does not need to return the
- // same pointer type as the relocated pointer. It can be casted to the correct type later
- // if it's desired. However, they must have the same address space.
+ // Relocated value must be either a pointer type or vector-of-pointer type,
+ // but gc_relocate does not need to return the same pointer type as the
+ // relocated pointer. It can be casted to the correct type later if it's
+ // desired. However, they must have the same address space and 'vectorness'
GCRelocateInst &Relocate = cast<GCRelocateInst>(*CS.getInstruction());
- Assert(Relocate.getDerivedPtr()->getType()->isPointerTy(),
+ Assert(Relocate.getDerivedPtr()->getType()->getScalarType()->isPointerTy(),
"gc.relocate: relocated value must be a gc pointer", CS);
- // gc_relocate return type must be a pointer type, and is verified earlier in
- // VerifyIntrinsicType().
- Assert(cast<PointerType>(CS.getType())->getAddressSpace() ==
- cast<PointerType>(Relocate.getDerivedPtr()->getType())->getAddressSpace(),
+ auto ResultType = CS.getType();
+ auto DerivedType = Relocate.getDerivedPtr()->getType();
+ Assert(ResultType->isVectorTy() == DerivedType->isVectorTy(),
+ "gc.relocate: vector relocates to vector and pointer to pointer", CS);
+ Assert(ResultType->getPointerAddressSpace() ==
+ DerivedType->getPointerAddressSpace(),
"gc.relocate: relocating a pointer shouldn't change its address space", CS);
break;
}
diff --git a/lib/LTO/LTOCodeGenerator.cpp b/lib/LTO/LTOCodeGenerator.cpp
index 6baaaa4b1395..66df23bab1b5 100644
--- a/lib/LTO/LTOCodeGenerator.cpp
+++ b/lib/LTO/LTOCodeGenerator.cpp
@@ -92,7 +92,8 @@ void LTOCodeGenerator::initializeLTOPasses() {
initializeSROALegacyPassPass(R);
initializeSROA_DTPass(R);
initializeSROA_SSAUpPass(R);
- initializeFunctionAttrsPass(R);
+ initializePostOrderFunctionAttrsPass(R);
+ initializeReversePostOrderFunctionAttrsPass(R);
initializeGlobalsAAWrapperPassPass(R);
initializeLICMPass(R);
initializeMergedLoadStoreMotionPass(R);
diff --git a/lib/Linker/IRMover.cpp b/lib/Linker/IRMover.cpp
index 309690f61d74..8dd59f9e0e3e 100644
--- a/lib/Linker/IRMover.cpp
+++ b/lib/Linker/IRMover.cpp
@@ -773,6 +773,16 @@ GlobalValue *IRLinker::copyGlobalValueProto(const GlobalValue *SGV,
NewGV->setLinkage(GlobalValue::ExternalWeakLinkage);
NewGV->copyAttributesFrom(SGV);
+
+ // Remove these copied constants in case this stays a declaration, since
+ // they point to the source module. If the def is linked the values will
+ // be mapped in during linkFunctionBody.
+ if (auto *NewF = dyn_cast<Function>(NewGV)) {
+ NewF->setPersonalityFn(nullptr);
+ NewF->setPrefixData(nullptr);
+ NewF->setPrologueData(nullptr);
+ }
+
return NewGV;
}
@@ -1211,6 +1221,18 @@ void IRLinker::findNeededSubprograms(ValueToValueMapTy &ValueMap) {
for (unsigned I = 0, E = CompileUnits->getNumOperands(); I != E; ++I) {
auto *CU = cast<DICompileUnit>(CompileUnits->getOperand(I));
assert(CU && "Expected valid compile unit");
+ // Ensure that we don't remove subprograms referenced by DIImportedEntity.
+ // It is not legal to have a DIImportedEntity with a null entity or scope.
+ // FIXME: The DISubprogram for functions not linked in but kept due to
+ // being referenced by a DIImportedEntity should also get their
+ // IsDefinition flag is unset.
+ SmallPtrSet<DISubprogram *, 8> ImportedEntitySPs;
+ for (auto *IE : CU->getImportedEntities()) {
+ if (auto *SP = dyn_cast<DISubprogram>(IE->getEntity()))
+ ImportedEntitySPs.insert(SP);
+ if (auto *SP = dyn_cast<DISubprogram>(IE->getScope()))
+ ImportedEntitySPs.insert(SP);
+ }
for (auto *Op : CU->getSubprograms()) {
// Unless we were doing function importing and deferred metadata linking,
// any needed SPs should have been mapped as they would be reached
@@ -1218,7 +1240,7 @@ void IRLinker::findNeededSubprograms(ValueToValueMapTy &ValueMap) {
// function bodies, or from DILocation on inlined instructions).
assert(!(ValueMap.MD()[Op] && IsMetadataLinkingPostpass) &&
"DISubprogram shouldn't be mapped yet");
- if (!ValueMap.MD()[Op])
+ if (!ValueMap.MD()[Op] && !ImportedEntitySPs.count(Op))
UnneededSubprograms.insert(Op);
}
}
diff --git a/lib/Linker/LinkModules.cpp b/lib/Linker/LinkModules.cpp
index 9de3be412d75..6ffa71e14779 100644
--- a/lib/Linker/LinkModules.cpp
+++ b/lib/Linker/LinkModules.cpp
@@ -65,9 +65,6 @@ class ModuleLinker {
return Flags & Linker::InternalizeLinkedSymbols;
}
- /// Check if we should promote the given local value to global scope.
- bool doPromoteLocalToGlobal(const GlobalValue *SGV);
-
bool shouldLinkFromSource(bool &LinkFromSrc, const GlobalValue &Dest,
const GlobalValue &Src);
@@ -97,11 +94,11 @@ class ModuleLinker {
Module &DstM = Mover.getModule();
// If the source has no name it can't link. If it has local linkage,
// there is no name match-up going on.
- if (!SrcGV->hasName() || GlobalValue::isLocalLinkage(getLinkage(SrcGV)))
+ if (!SrcGV->hasName() || GlobalValue::isLocalLinkage(SrcGV->getLinkage()))
return nullptr;
// Otherwise see if we have a match in the destination module's symtab.
- GlobalValue *DGV = DstM.getNamedValue(getName(SrcGV));
+ GlobalValue *DGV = DstM.getNamedValue(SrcGV->getName());
if (!DGV)
return nullptr;
@@ -116,6 +113,64 @@ class ModuleLinker {
bool linkIfNeeded(GlobalValue &GV);
+ /// Helper method to check if we are importing from the current source
+ /// module.
+ bool isPerformingImport() const { return FunctionsToImport != nullptr; }
+
+ /// If we are importing from the source module, checks if we should
+ /// import SGV as a definition, otherwise import as a declaration.
+ bool doImportAsDefinition(const GlobalValue *SGV);
+
+public:
+ ModuleLinker(IRMover &Mover, Module &SrcM, unsigned Flags,
+ const FunctionInfoIndex *Index = nullptr,
+ DenseSet<const GlobalValue *> *FunctionsToImport = nullptr,
+ DenseMap<unsigned, MDNode *> *ValIDToTempMDMap = nullptr)
+ : Mover(Mover), SrcM(SrcM), Flags(Flags), ImportIndex(Index),
+ FunctionsToImport(FunctionsToImport),
+ ValIDToTempMDMap(ValIDToTempMDMap) {
+ assert((ImportIndex || !FunctionsToImport) &&
+ "Expect a FunctionInfoIndex when importing");
+ // If we have a FunctionInfoIndex but no function to import,
+ // then this is the primary module being compiled in a ThinLTO
+ // backend compilation, and we need to see if it has functions that
+ // may be exported to another backend compilation.
+ if (ImportIndex && !FunctionsToImport)
+ HasExportedFunctions = ImportIndex->hasExportedFunctions(SrcM);
+ assert((ValIDToTempMDMap || !FunctionsToImport) &&
+ "Function importing must provide a ValIDToTempMDMap");
+ }
+
+ bool run();
+};
+
+/// Class to handle necessary GlobalValue changes required by ThinLTO including
+/// linkage changes and any necessary renaming.
+class ThinLTOGlobalProcessing {
+ /// The Module which we are exporting or importing functions from.
+ Module &M;
+
+ /// Function index passed in for function importing/exporting handling.
+ const FunctionInfoIndex *ImportIndex;
+
+ /// Functions to import from this module, all other functions will be
+ /// imported as declarations instead of definitions.
+ DenseSet<const GlobalValue *> *FunctionsToImport;
+
+ /// Set to true if the given FunctionInfoIndex contains any functions
+ /// from this source module, in which case we must conservatively assume
+ /// that any of its functions may be imported into another module
+ /// as part of a different backend compilation process.
+ bool HasExportedFunctions = false;
+
+ /// Populated during ThinLTO global processing with locals promoted
+ /// to global scope in an exporting module, which now need to be linked
+ /// in if calling from the ModuleLinker.
+ SetVector<GlobalValue *> NewExportedValues;
+
+ /// Check if we should promote the given local value to global scope.
+ bool doPromoteLocalToGlobal(const GlobalValue *SGV);
+
/// Helper methods to check if we are importing from or potentially
/// exporting from the current source module.
bool isPerformingImport() const { return FunctionsToImport != nullptr; }
@@ -143,32 +198,30 @@ class ModuleLinker {
GlobalValue::LinkageTypes getLinkage(const GlobalValue *SGV);
public:
- ModuleLinker(IRMover &Mover, Module &SrcM, unsigned Flags,
- const FunctionInfoIndex *Index = nullptr,
- DenseSet<const GlobalValue *> *FunctionsToImport = nullptr,
- DenseMap<unsigned, MDNode *> *ValIDToTempMDMap = nullptr)
- : Mover(Mover), SrcM(SrcM), Flags(Flags), ImportIndex(Index),
- FunctionsToImport(FunctionsToImport),
- ValIDToTempMDMap(ValIDToTempMDMap) {
- assert((ImportIndex || !FunctionsToImport) &&
- "Expect a FunctionInfoIndex when importing");
+ ThinLTOGlobalProcessing(
+ Module &M, const FunctionInfoIndex *Index,
+ DenseSet<const GlobalValue *> *FunctionsToImport = nullptr)
+ : M(M), ImportIndex(Index), FunctionsToImport(FunctionsToImport) {
// If we have a FunctionInfoIndex but no function to import,
// then this is the primary module being compiled in a ThinLTO
// backend compilation, and we need to see if it has functions that
// may be exported to another backend compilation.
- if (ImportIndex && !FunctionsToImport)
- HasExportedFunctions = ImportIndex->hasExportedFunctions(SrcM);
- assert((ValIDToTempMDMap || !FunctionsToImport) &&
- "Function importing must provide a ValIDToTempMDMap");
+ if (!FunctionsToImport)
+ HasExportedFunctions = ImportIndex->hasExportedFunctions(M);
}
bool run();
+
+ /// Access the promoted globals that are now exported and need to be linked.
+ SetVector<GlobalValue *> &getNewExportedValues() { return NewExportedValues; }
};
}
-bool ModuleLinker::doImportAsDefinition(const GlobalValue *SGV) {
- if (!isPerformingImport())
- return false;
+/// Checks if we should import SGV as a definition, otherwise import as a
+/// declaration.
+static bool
+doImportAsDefinitionImpl(const GlobalValue *SGV,
+ DenseSet<const GlobalValue *> *FunctionsToImport) {
auto *GA = dyn_cast<GlobalAlias>(SGV);
if (GA) {
if (GA->hasWeakAnyLinkage())
@@ -176,7 +229,7 @@ bool ModuleLinker::doImportAsDefinition(const GlobalValue *SGV) {
const GlobalObject *GO = GA->getBaseObject();
if (!GO->hasLinkOnceODRLinkage())
return false;
- return doImportAsDefinition(GO);
+ return doImportAsDefinitionImpl(GO, FunctionsToImport);
}
// Always import GlobalVariable definitions, except for the special
// case of WeakAny which are imported as ExternalWeak declarations
@@ -196,7 +249,19 @@ bool ModuleLinker::doImportAsDefinition(const GlobalValue *SGV) {
return false;
}
-bool ModuleLinker::doPromoteLocalToGlobal(const GlobalValue *SGV) {
+bool ThinLTOGlobalProcessing::doImportAsDefinition(const GlobalValue *SGV) {
+ if (!isPerformingImport())
+ return false;
+ return doImportAsDefinitionImpl(SGV, FunctionsToImport);
+}
+
+bool ModuleLinker::doImportAsDefinition(const GlobalValue *SGV) {
+ if (!isPerformingImport())
+ return false;
+ return doImportAsDefinitionImpl(SGV, FunctionsToImport);
+}
+
+bool ThinLTOGlobalProcessing::doPromoteLocalToGlobal(const GlobalValue *SGV) {
assert(SGV->hasLocalLinkage());
// Both the imported references and the original local variable must
// be promoted.
@@ -220,7 +285,7 @@ bool ModuleLinker::doPromoteLocalToGlobal(const GlobalValue *SGV) {
return true;
}
-std::string ModuleLinker::getName(const GlobalValue *SGV) {
+std::string ThinLTOGlobalProcessing::getName(const GlobalValue *SGV) {
// For locals that must be promoted to global scope, ensure that
// the promoted name uniquely identifies the copy in the original module,
// using the ID assigned during combined index creation. When importing,
@@ -234,7 +299,8 @@ std::string ModuleLinker::getName(const GlobalValue *SGV) {
return SGV->getName();
}
-GlobalValue::LinkageTypes ModuleLinker::getLinkage(const GlobalValue *SGV) {
+GlobalValue::LinkageTypes
+ThinLTOGlobalProcessing::getLinkage(const GlobalValue *SGV) {
// Any local variable that is referenced by an exported function needs
// to be promoted to global scope. Since we don't currently know which
// functions reference which local variables/functions, we must treat
@@ -298,8 +364,7 @@ GlobalValue::LinkageTypes ModuleLinker::getLinkage(const GlobalValue *SGV) {
// since it would cause global constructors/destructors to be
// executed multiple times. This should have already been handled
// by linkIfNeeded, and we will assert in shouldLinkFromSource
- // if we try to import, so we simply return AppendingLinkage here
- // as this helper is called more widely in getLinkedToGlobal.
+ // if we try to import, so we simply return AppendingLinkage.
return GlobalValue::AppendingLinkage;
case GlobalValue::InternalLinkage:
@@ -652,7 +717,7 @@ void ModuleLinker::addLazyFor(GlobalValue &GV, IRMover::ValueAdder Add) {
}
}
-void ModuleLinker::processGlobalForThinLTO(GlobalValue &GV) {
+void ThinLTOGlobalProcessing::processGlobalForThinLTO(GlobalValue &GV) {
if (GV.hasLocalLinkage() &&
(doPromoteLocalToGlobal(&GV) || isPerformingImport())) {
GV.setName(getName(&GV));
@@ -660,21 +725,26 @@ void ModuleLinker::processGlobalForThinLTO(GlobalValue &GV) {
if (!GV.hasLocalLinkage())
GV.setVisibility(GlobalValue::HiddenVisibility);
if (isModuleExporting())
- ValuesToLink.insert(&GV);
+ NewExportedValues.insert(&GV);
return;
}
GV.setLinkage(getLinkage(&GV));
}
-void ModuleLinker::processGlobalsForThinLTO() {
- for (GlobalVariable &GV : SrcM.globals())
+void ThinLTOGlobalProcessing::processGlobalsForThinLTO() {
+ for (GlobalVariable &GV : M.globals())
processGlobalForThinLTO(GV);
- for (Function &SF : SrcM)
+ for (Function &SF : M)
processGlobalForThinLTO(SF);
- for (GlobalAlias &GA : SrcM.aliases())
+ for (GlobalAlias &GA : M.aliases())
processGlobalForThinLTO(GA);
}
+bool ThinLTOGlobalProcessing::run() {
+ processGlobalsForThinLTO();
+ return false;
+}
+
bool ModuleLinker::run() {
for (const auto &SMEC : SrcM.getComdatSymbolTable()) {
const Comdat &C = SMEC.getValue();
@@ -713,7 +783,14 @@ bool ModuleLinker::run() {
if (linkIfNeeded(GA))
return true;
- processGlobalsForThinLTO();
+ if (ImportIndex) {
+ ThinLTOGlobalProcessing ThinLTOProcessing(SrcM, ImportIndex,
+ FunctionsToImport);
+ if (ThinLTOProcessing.run())
+ return true;
+ for (auto *GV : ThinLTOProcessing.getNewExportedValues())
+ ValuesToLink.insert(GV);
+ }
for (unsigned I = 0; I < ValuesToLink.size(); ++I) {
GlobalValue *GV = ValuesToLink[I];
@@ -786,15 +863,9 @@ bool Linker::linkModules(Module &Dest, std::unique_ptr<Module> Src,
return L.linkInModule(std::move(Src), Flags);
}
-std::unique_ptr<Module>
-llvm::renameModuleForThinLTO(std::unique_ptr<Module> M,
- const FunctionInfoIndex *Index) {
- std::unique_ptr<llvm::Module> RenamedModule(
- new llvm::Module(M->getModuleIdentifier(), M->getContext()));
- Linker L(*RenamedModule.get());
- if (L.linkInModule(std::move(M), llvm::Linker::Flags::None, Index))
- return nullptr;
- return RenamedModule;
+bool llvm::renameModuleForThinLTO(Module &M, const FunctionInfoIndex *Index) {
+ ThinLTOGlobalProcessing ThinLTOProcessing(M, Index);
+ return ThinLTOProcessing.run();
}
//===----------------------------------------------------------------------===//
diff --git a/lib/MC/MCExpr.cpp b/lib/MC/MCExpr.cpp
index 0f26b38c29d7..748644bd9c8f 100644
--- a/lib/MC/MCExpr.cpp
+++ b/lib/MC/MCExpr.cpp
@@ -300,6 +300,7 @@ StringRef MCSymbolRefExpr::getVariantKindName(VariantKind Kind) {
case VK_Hexagon_LD_PLT: return "LDPLT";
case VK_Hexagon_IE: return "IE";
case VK_Hexagon_IE_GOT: return "IEGOT";
+ case VK_WebAssembly_FUNCTION: return "FUNCTION";
case VK_TPREL: return "tprel";
case VK_DTPREL: return "dtprel";
}
diff --git a/lib/MC/MCObjectFileInfo.cpp b/lib/MC/MCObjectFileInfo.cpp
index 34f49cac1628..f86f7e40acb4 100644
--- a/lib/MC/MCObjectFileInfo.cpp
+++ b/lib/MC/MCObjectFileInfo.cpp
@@ -256,6 +256,9 @@ void MCObjectFileInfo::initMachOMCObjectFileInfo(Triple T) {
DwarfRangesSection =
Ctx->getMachOSection("__DWARF", "__debug_ranges", MachO::S_ATTR_DEBUG,
SectionKind::getMetadata(), "debug_range");
+ DwarfMacinfoSection =
+ Ctx->getMachOSection("__DWARF", "__debug_macinfo", MachO::S_ATTR_DEBUG,
+ SectionKind::getMetadata());
DwarfDebugInlineSection =
Ctx->getMachOSection("__DWARF", "__debug_inlined", MachO::S_ATTR_DEBUG,
SectionKind::getMetadata());
@@ -505,6 +508,8 @@ void MCObjectFileInfo::initELFMCObjectFileInfo(Triple T) {
Ctx->getELFSection(".debug_aranges", ELF::SHT_PROGBITS, 0);
DwarfRangesSection =
Ctx->getELFSection(".debug_ranges", ELF::SHT_PROGBITS, 0, "debug_range");
+ DwarfMacinfoSection =
+ Ctx->getELFSection(".debug_macinfo", ELF::SHT_PROGBITS, 0);
// DWARF5 Experimental Debug Info
@@ -684,6 +689,11 @@ void MCObjectFileInfo::initCOFFMCObjectFileInfo(Triple T) {
COFF::IMAGE_SCN_MEM_DISCARDABLE | COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
COFF::IMAGE_SCN_MEM_READ,
SectionKind::getMetadata(), "debug_range");
+ DwarfMacinfoSection = Ctx->getCOFFSection(
+ ".debug_macinfo",
+ COFF::IMAGE_SCN_MEM_DISCARDABLE | COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
+ COFF::IMAGE_SCN_MEM_READ,
+ SectionKind::getMetadata());
DwarfInfoDWOSection = Ctx->getCOFFSection(
".debug_info.dwo",
COFF::IMAGE_SCN_MEM_DISCARDABLE | COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
diff --git a/lib/MC/MCObjectStreamer.cpp b/lib/MC/MCObjectStreamer.cpp
index d0a7dafa15b8..972610ac8d6e 100644
--- a/lib/MC/MCObjectStreamer.cpp
+++ b/lib/MC/MCObjectStreamer.cpp
@@ -64,8 +64,6 @@ void MCObjectStreamer::emitAbsoluteSymbolDiff(const MCSymbol *Hi,
return;
}
- assert(Hi->getOffset() >= Lo->getOffset() &&
- "Expected Hi to be greater than Lo");
EmitIntValue(Hi->getOffset() - Lo->getOffset(), Size);
}
diff --git a/lib/MC/WinCOFFObjectWriter.cpp b/lib/MC/WinCOFFObjectWriter.cpp
index a3820906b76b..a76cbdbd5447 100644
--- a/lib/MC/WinCOFFObjectWriter.cpp
+++ b/lib/MC/WinCOFFObjectWriter.cpp
@@ -969,9 +969,6 @@ void WinCOFFObjectWriter::writeObject(MCAssembler &Asm,
Header.PointerToSymbolTable = offset;
- // FIXME: Remove the #else branch and make the #if branch unconditional once
- // LLVM's self host configuration is aware of /Brepro.
-#if (ENABLE_TIMESTAMPS == 1)
// MS LINK expects to be able to use this timestamp to implement their
// /INCREMENTAL feature.
if (Asm.isIncrementalLinkerCompatible()) {
@@ -980,12 +977,9 @@ void WinCOFFObjectWriter::writeObject(MCAssembler &Asm,
Now = UINT32_MAX;
Header.TimeDateStamp = Now;
} else {
+ // Have deterministic output if /INCREMENTAL isn't needed. Also matches GNU.
Header.TimeDateStamp = 0;
}
-#else
- // We want a deterministic output. It looks like GNU as also writes 0 in here.
- Header.TimeDateStamp = 0;
-#endif
// Write it all to disk...
WriteFileHeader(Header);
diff --git a/lib/Object/COFFObjectFile.cpp b/lib/Object/COFFObjectFile.cpp
index 1f2111759a0e..4cd6aff5f17c 100644
--- a/lib/Object/COFFObjectFile.cpp
+++ b/lib/Object/COFFObjectFile.cpp
@@ -1336,6 +1336,30 @@ ExportDirectoryEntryRef::getSymbolName(StringRef &Result) const {
return std::error_code();
}
+std::error_code ExportDirectoryEntryRef::isForwarder(bool &Result) const {
+ const data_directory *DataEntry;
+ if (auto EC = OwningObject->getDataDirectory(COFF::EXPORT_TABLE, DataEntry))
+ return EC;
+ uint32_t RVA;
+ if (auto EC = getExportRVA(RVA))
+ return EC;
+ uint32_t Begin = DataEntry->RelativeVirtualAddress;
+ uint32_t End = DataEntry->RelativeVirtualAddress + DataEntry->Size;
+ Result = (Begin <= RVA && RVA < End);
+ return std::error_code();
+}
+
+std::error_code ExportDirectoryEntryRef::getForwardTo(StringRef &Result) const {
+ uint32_t RVA;
+ if (auto EC = getExportRVA(RVA))
+ return EC;
+ uintptr_t IntPtr = 0;
+ if (auto EC = OwningObject->getRvaPtr(RVA, IntPtr))
+ return EC;
+ Result = StringRef(reinterpret_cast<const char *>(IntPtr));
+ return std::error_code();
+}
+
bool ImportedSymbolRef::
operator==(const ImportedSymbolRef &Other) const {
return Entry32 == Other.Entry32 && Entry64 == Other.Entry64
diff --git a/lib/Object/ELF.cpp b/lib/Object/ELF.cpp
index 62c27cc427a6..12b772d930ba 100644
--- a/lib/Object/ELF.cpp
+++ b/lib/Object/ELF.cpp
@@ -91,6 +91,13 @@ StringRef getELFRelocationTypeName(uint32_t Machine, uint32_t Type) {
break;
}
break;
+ case ELF::EM_WEBASSEMBLY:
+ switch (Type) {
+#include "llvm/Support/ELFRelocs/WebAssembly.def"
+ default:
+ break;
+ }
+ break;
default:
break;
}
diff --git a/lib/ProfileData/CoverageMapping.cpp b/lib/ProfileData/CoverageMapping.cpp
index 55c0fb4792ef..f5d477bd139a 100644
--- a/lib/ProfileData/CoverageMapping.cpp
+++ b/