mirror of
https://github.com/opnsense/src.git
synced 2026-06-08 16:22:46 -04:00
Merge llvm trunk r351319, resolve conflicts, and update FREEBSD-Xlist.
This commit is contained in:
commit
d9484dd61c
2298 changed files with 193347 additions and 96654 deletions
|
|
@ -2,17 +2,15 @@
|
|||
.arcconfig
|
||||
.clang-format
|
||||
.clang-tidy
|
||||
.gitattributes
|
||||
.gitignore
|
||||
CMakeLists.txt
|
||||
CODE_OWNERS.TXT
|
||||
CREDITS.TXT
|
||||
LLVMBuild.txt
|
||||
Makefile
|
||||
Makefile.common
|
||||
Makefile.config.in
|
||||
Makefile.rules
|
||||
README.txt
|
||||
autoconf/
|
||||
RELEASE_TESTERS.TXT
|
||||
benchmarks/
|
||||
bindings/
|
||||
cmake/
|
||||
configure
|
||||
|
|
@ -21,473 +19,485 @@ examples/
|
|||
include/llvm/CMakeLists.txt
|
||||
include/llvm/Config/
|
||||
include/llvm/IR/CMakeLists.txt
|
||||
include/llvm/Support/DataTypes.h.cmake
|
||||
include/llvm/Support/CMakeLists.txt
|
||||
include/llvm/Support/LICENSE.TXT
|
||||
lib/Analysis/CMakeLists.txt
|
||||
lib/Analysis/IPA/CMakeLists.txt
|
||||
lib/Analysis/IPA/LLVMBuild.txt
|
||||
lib/Analysis/IPA/Makefile
|
||||
lib/Analysis/LLVMBuild.txt
|
||||
lib/Analysis/Makefile
|
||||
lib/Analysis/README.txt
|
||||
lib/AsmParser/CMakeLists.txt
|
||||
lib/AsmParser/LLVMBuild.txt
|
||||
lib/AsmParser/Makefile
|
||||
lib/BinaryFormat/CMakeLists.txt
|
||||
lib/BinaryFormat/LLVMBuild.txt
|
||||
lib/Bitcode/CMakeLists.txt
|
||||
lib/Bitcode/LLVMBuild.txt
|
||||
lib/Bitcode/Makefile
|
||||
lib/Bitcode/Reader/CMakeLists.txt
|
||||
lib/Bitcode/Reader/LLVMBuild.txt
|
||||
lib/Bitcode/Reader/Makefile
|
||||
lib/Bitcode/Writer/CMakeLists.txt
|
||||
lib/Bitcode/Writer/LLVMBuild.txt
|
||||
lib/Bitcode/Writer/Makefile
|
||||
lib/CMakeLists.txt
|
||||
lib/CodeGen/AsmPrinter/CMakeLists.txt
|
||||
lib/CodeGen/AsmPrinter/LLVMBuild.txt
|
||||
lib/CodeGen/AsmPrinter/Makefile
|
||||
lib/CodeGen/CMakeLists.txt
|
||||
lib/CodeGen/GlobalISel/CMakeLists.txt
|
||||
lib/CodeGen/GlobalISel/LLVMBuild.txt
|
||||
lib/CodeGen/LLVMBuild.txt
|
||||
lib/CodeGen/Makefile
|
||||
lib/CodeGen/MIRParser/CMakeLists.txt
|
||||
lib/CodeGen/MIRParser/LLVMBuild.txt
|
||||
lib/CodeGen/README.txt
|
||||
lib/CodeGen/SelectionDAG/CMakeLists.txt
|
||||
lib/CodeGen/SelectionDAG/LLVMBuild.txt
|
||||
lib/CodeGen/SelectionDAG/Makefile
|
||||
lib/DebugInfo/CMakeLists.txt
|
||||
lib/DebugInfo/CodeView/CMakeLists.txt
|
||||
lib/DebugInfo/CodeView/LLVMBuild.txt
|
||||
lib/DebugInfo/DWARF/CMakeLists.txt
|
||||
lib/DebugInfo/DWARF/LLVMBuild.txt
|
||||
lib/DebugInfo/DWARF/Makefile
|
||||
lib/DebugInfo/LLVMBuild.txt
|
||||
lib/DebugInfo/Makefile
|
||||
lib/DebugInfo/MSF/CMakeLists.txt
|
||||
lib/DebugInfo/MSF/LLVMBuild.txt
|
||||
lib/DebugInfo/PDB/CMakeLists.txt
|
||||
lib/DebugInfo/PDB/LLVMBuild.txt
|
||||
lib/DebugInfo/PDB/Makefile
|
||||
lib/DebugInfo/Symbolize/CMakeLists.txt
|
||||
lib/DebugInfo/Symbolize/LLVMBuild.txt
|
||||
lib/Demangle/CMakeLists.txt
|
||||
lib/Demangle/LLVMBuild.txt
|
||||
lib/ExecutionEngine/CMakeLists.txt
|
||||
lib/ExecutionEngine/IntelJITEvents/CMakeLists.txt
|
||||
lib/ExecutionEngine/IntelJITEvents/LLVMBuild.txt
|
||||
lib/ExecutionEngine/IntelJITEvents/Makefile
|
||||
lib/ExecutionEngine/Interpreter/CMakeLists.txt
|
||||
lib/ExecutionEngine/Interpreter/LLVMBuild.txt
|
||||
lib/ExecutionEngine/Interpreter/Makefile
|
||||
lib/ExecutionEngine/LLVMBuild.txt
|
||||
lib/ExecutionEngine/MCJIT/CMakeLists.txt
|
||||
lib/ExecutionEngine/MCJIT/LLVMBuild.txt
|
||||
lib/ExecutionEngine/MCJIT/Makefile
|
||||
lib/ExecutionEngine/Makefile
|
||||
lib/ExecutionEngine/OProfileJIT/CMakeLists.txt
|
||||
lib/ExecutionEngine/OProfileJIT/LLVMBuild.txt
|
||||
lib/ExecutionEngine/OProfileJIT/Makefile
|
||||
lib/ExecutionEngine/Orc/CMakeLists.txt
|
||||
lib/ExecutionEngine/Orc/LLVMBuild.txt
|
||||
lib/ExecutionEngine/Orc/Makefile
|
||||
lib/ExecutionEngine/PerfJITEvents/CMakeLists.txt
|
||||
lib/ExecutionEngine/PerfJITEvents/LLVMBuild.txt
|
||||
lib/ExecutionEngine/RuntimeDyld/CMakeLists.txt
|
||||
lib/ExecutionEngine/RuntimeDyld/LLVMBuild.txt
|
||||
lib/ExecutionEngine/RuntimeDyld/Makefile
|
||||
lib/FuzzMutate/CMakeLists.txt
|
||||
lib/FuzzMutate/LLVMBuild.txt
|
||||
lib/Fuzzer/
|
||||
lib/IR/CMakeLists.txt
|
||||
lib/IR/LLVMBuild.txt
|
||||
lib/IR/Makefile
|
||||
lib/IRReader/CMakeLists.txt
|
||||
lib/IRReader/LLVMBuild.txt
|
||||
lib/IRReader/Makefile
|
||||
lib/LLVMBuild.txt
|
||||
lib/LTO/CMakeLists.txt
|
||||
lib/LTO/LLVMBuild.txt
|
||||
lib/LTO/Makefile
|
||||
lib/LineEditor/CMakeLists.txt
|
||||
lib/LineEditor/LLVMBuild.txt
|
||||
lib/LineEditor/Makefile
|
||||
lib/Linker/CMakeLists.txt
|
||||
lib/Linker/LLVMBuild.txt
|
||||
lib/Linker/Makefile
|
||||
lib/MC/CMakeLists.txt
|
||||
lib/MC/LLVMBuild.txt
|
||||
lib/MC/MCDisassembler/CMakeLists.txt
|
||||
lib/MC/MCDisassembler/LLVMBuild.txt
|
||||
lib/MC/MCDisassembler/Makefile
|
||||
lib/MC/MCParser/CMakeLists.txt
|
||||
lib/MC/MCParser/LLVMBuild.txt
|
||||
lib/MC/MCParser/Makefile
|
||||
lib/MC/Makefile
|
||||
lib/Makefile
|
||||
lib/MCA/CMakeLists.txt
|
||||
lib/MCA/LLVMBuild.txt
|
||||
lib/Object/CMakeLists.txt
|
||||
lib/Object/LLVMBuild.txt
|
||||
lib/Object/Makefile
|
||||
lib/ObjectYAML/CMakeLists.txt
|
||||
lib/ObjectYAML/LLVMBuild.txt
|
||||
lib/OptRemarks/CMakeLists.txt
|
||||
lib/OptRemarks/LLVMBuild.txt
|
||||
lib/Option/CMakeLists.txt
|
||||
lib/Option/LLVMBuild.txt
|
||||
lib/Option/Makefile
|
||||
lib/Passes/CMakeLists.txt
|
||||
lib/Passes/LLVMBuild.txt
|
||||
lib/Passes/Makefile
|
||||
lib/ProfileData/CMakeLists.txt
|
||||
lib/ProfileData/Coverage/CMakeLists.txt
|
||||
lib/ProfileData/Coverage/LLVMBuild.txt
|
||||
lib/ProfileData/LLVMBuild.txt
|
||||
lib/ProfileData/Makefile
|
||||
lib/Support/CMakeLists.txt
|
||||
lib/Support/LLVMBuild.txt
|
||||
lib/Support/Makefile
|
||||
lib/Support/README.txt.system
|
||||
lib/TableGen/CMakeLists.txt
|
||||
lib/TableGen/LLVMBuild.txt
|
||||
lib/TableGen/Makefile
|
||||
lib/Target/AArch64/AsmParser/CMakeLists.txt
|
||||
lib/Target/AArch64/AsmParser/LLVMBuild.txt
|
||||
lib/Target/AArch64/AsmParser/Makefile
|
||||
lib/Target/AArch64/CMakeLists.txt
|
||||
lib/Target/AArch64/Disassembler/CMakeLists.txt
|
||||
lib/Target/AArch64/Disassembler/LLVMBuild.txt
|
||||
lib/Target/AArch64/Disassembler/Makefile
|
||||
lib/Target/AArch64/InstPrinter/CMakeLists.txt
|
||||
lib/Target/AArch64/InstPrinter/LLVMBuild.txt
|
||||
lib/Target/AArch64/InstPrinter/Makefile
|
||||
lib/Target/AArch64/LLVMBuild.txt
|
||||
lib/Target/AArch64/MCTargetDesc/CMakeLists.txt
|
||||
lib/Target/AArch64/MCTargetDesc/LLVMBuild.txt
|
||||
lib/Target/AArch64/MCTargetDesc/Makefile
|
||||
lib/Target/AArch64/Makefile
|
||||
lib/Target/AArch64/TargetInfo/CMakeLists.txt
|
||||
lib/Target/AArch64/TargetInfo/LLVMBuild.txt
|
||||
lib/Target/AArch64/TargetInfo/Makefile
|
||||
lib/Target/AArch64/Utils/CMakeLists.txt
|
||||
lib/Target/AArch64/Utils/LLVMBuild.txt
|
||||
lib/Target/AArch64/Utils/Makefile
|
||||
lib/Target/AMDGPU/AsmParser/CMakeLists.txt
|
||||
lib/Target/AMDGPU/AsmParser/LLVMBuild.txt
|
||||
lib/Target/AMDGPU/CMakeLists.txt
|
||||
lib/Target/AMDGPU/Disassembler/CMakeLists.txt
|
||||
lib/Target/AMDGPU/Disassembler/LLVMBuild.txt
|
||||
lib/Target/AMDGPU/InstPrinter/CMakeLists.txt
|
||||
lib/Target/AMDGPU/InstPrinter/LLVMBuild.txt
|
||||
lib/Target/AMDGPU/LLVMBuild.txt
|
||||
lib/Target/AMDGPU/MCTargetDesc/CMakeLists.txt
|
||||
lib/Target/AMDGPU/MCTargetDesc/LLVMBuild.txt
|
||||
lib/Target/AMDGPU/TargetInfo/CMakeLists.txt
|
||||
lib/Target/AMDGPU/TargetInfo/LLVMBuild.txt
|
||||
lib/Target/AMDGPU/Utils/CMakeLists.txt
|
||||
lib/Target/AMDGPU/Utils/LLVMBuild.txt
|
||||
lib/Target/ARC/CMakeLists.txt
|
||||
lib/Target/ARC/Disassembler/CMakeLists.txt
|
||||
lib/Target/ARC/Disassembler/LLVMBuild.txt
|
||||
lib/Target/ARC/InstPrinter/CMakeLists.txt
|
||||
lib/Target/ARC/InstPrinter/LLVMBuild.txt
|
||||
lib/Target/ARC/LLVMBuild.txt
|
||||
lib/Target/ARC/MCTargetDesc/CMakeLists.txt
|
||||
lib/Target/ARC/MCTargetDesc/LLVMBuild.txt
|
||||
lib/Target/ARC/TargetInfo/CMakeLists.txt
|
||||
lib/Target/ARC/TargetInfo/LLVMBuild.txt
|
||||
lib/Target/ARM/AsmParser/CMakeLists.txt
|
||||
lib/Target/ARM/AsmParser/LLVMBuild.txt
|
||||
lib/Target/ARM/AsmParser/Makefile
|
||||
lib/Target/ARM/CMakeLists.txt
|
||||
lib/Target/ARM/Disassembler/CMakeLists.txt
|
||||
lib/Target/ARM/Disassembler/LLVMBuild.txt
|
||||
lib/Target/ARM/Disassembler/Makefile
|
||||
lib/Target/ARM/InstPrinter/CMakeLists.txt
|
||||
lib/Target/ARM/InstPrinter/LLVMBuild.txt
|
||||
lib/Target/ARM/InstPrinter/Makefile
|
||||
lib/Target/ARM/LLVMBuild.txt
|
||||
lib/Target/ARM/MCTargetDesc/CMakeLists.txt
|
||||
lib/Target/ARM/MCTargetDesc/LLVMBuild.txt
|
||||
lib/Target/ARM/MCTargetDesc/Makefile
|
||||
lib/Target/ARM/Makefile
|
||||
lib/Target/ARM/README-Thumb.txt
|
||||
lib/Target/ARM/README-Thumb2.txt
|
||||
lib/Target/ARM/README.txt
|
||||
lib/Target/ARM/TargetInfo/CMakeLists.txt
|
||||
lib/Target/ARM/TargetInfo/LLVMBuild.txt
|
||||
lib/Target/ARM/TargetInfo/Makefile
|
||||
lib/Target/ARM/Utils/CMakeLists.txt
|
||||
lib/Target/ARM/Utils/LLVMBuild.txt
|
||||
lib/Target/AVR/AsmParser/CMakeLists.txt
|
||||
lib/Target/AVR/AsmParser/LLVMBuild.txt
|
||||
lib/Target/AVR/CMakeLists.txt
|
||||
lib/Target/AVR/Disassembler/CMakeLists.txt
|
||||
lib/Target/AVR/Disassembler/LLVMBuild.txt
|
||||
lib/Target/AVR/InstPrinter/CMakeLists.txt
|
||||
lib/Target/AVR/InstPrinter/LLVMBuild.txt
|
||||
lib/Target/AVR/LLVMBuild.txt
|
||||
lib/Target/AVR/MCTargetDesc/CMakeLists.txt
|
||||
lib/Target/AVR/MCTargetDesc/LLVMBuild.txt
|
||||
lib/Target/AVR/TargetInfo/CMakeLists.txt
|
||||
lib/Target/AVR/TargetInfo/LLVMBuild.txt
|
||||
lib/Target/BPF/AsmParser/CMakeLists.txt
|
||||
lib/Target/BPF/AsmParser/LLVMBuild.txt
|
||||
lib/Target/BPF/CMakeLists.txt
|
||||
lib/Target/BPF/Disassembler/CMakeLists.txt
|
||||
lib/Target/BPF/Disassembler/LLVMBuild.txt
|
||||
lib/Target/BPF/InstPrinter/CMakeLists.txt
|
||||
lib/Target/BPF/InstPrinter/LLVMBuild.txt
|
||||
lib/Target/BPF/InstPrinter/Makefile
|
||||
lib/Target/BPF/LLVMBuild.txt
|
||||
lib/Target/BPF/MCTargetDesc/CMakeLists.txt
|
||||
lib/Target/BPF/MCTargetDesc/LLVMBuild.txt
|
||||
lib/Target/BPF/MCTargetDesc/Makefile
|
||||
lib/Target/BPF/Makefile
|
||||
lib/Target/BPF/TargetInfo/CMakeLists.txt
|
||||
lib/Target/BPF/TargetInfo/LLVMBuild.txt
|
||||
lib/Target/BPF/TargetInfo/Makefile
|
||||
lib/Target/CMakeLists.txt
|
||||
lib/Target/CppBackend/CMakeLists.txt
|
||||
lib/Target/CppBackend/LLVMBuild.txt
|
||||
lib/Target/CppBackend/Makefile
|
||||
lib/Target/CppBackend/TargetInfo/CMakeLists.txt
|
||||
lib/Target/CppBackend/TargetInfo/LLVMBuild.txt
|
||||
lib/Target/CppBackend/TargetInfo/Makefile
|
||||
lib/Target/Hexagon/AsmParser/CMakeLists.txt
|
||||
lib/Target/Hexagon/AsmParser/LLVMBuild.txt
|
||||
lib/Target/Hexagon/CMakeLists.txt
|
||||
lib/Target/Hexagon/Disassembler/CMakeLists.txt
|
||||
lib/Target/Hexagon/Disassembler/LLVMBuild.txt
|
||||
lib/Target/Hexagon/Disassembler/Makefile
|
||||
lib/Target/Hexagon/LLVMBuild.txt
|
||||
lib/Target/Hexagon/MCTargetDesc/CMakeLists.txt
|
||||
lib/Target/Hexagon/MCTargetDesc/LLVMBuild.txt
|
||||
lib/Target/Hexagon/MCTargetDesc/Makefile
|
||||
lib/Target/Hexagon/Makefile
|
||||
lib/Target/Hexagon/TargetInfo/CMakeLists.txt
|
||||
lib/Target/Hexagon/TargetInfo/LLVMBuild.txt
|
||||
lib/Target/Hexagon/TargetInfo/Makefile
|
||||
lib/Target/LLVMBuild.txt
|
||||
lib/Target/Lanai/AsmParser/CMakeLists.txt
|
||||
lib/Target/Lanai/AsmParser/LLVMBuild.txt
|
||||
lib/Target/Lanai/CMakeLists.txt
|
||||
lib/Target/Lanai/Disassembler/CMakeLists.txt
|
||||
lib/Target/Lanai/Disassembler/LLVMBuild.txt
|
||||
lib/Target/Lanai/InstPrinter/CMakeLists.txt
|
||||
lib/Target/Lanai/InstPrinter/LLVMBuild.txt
|
||||
lib/Target/Lanai/LLVMBuild.txt
|
||||
lib/Target/Lanai/MCTargetDesc/CMakeLists.txt
|
||||
lib/Target/Lanai/MCTargetDesc/LLVMBuild.txt
|
||||
lib/Target/Lanai/TargetInfo/CMakeLists.txt
|
||||
lib/Target/Lanai/TargetInfo/LLVMBuild.txt
|
||||
lib/Target/MSP430/AsmParser/CMakeLists.txt
|
||||
lib/Target/MSP430/AsmParser/LLVMBuild.txt
|
||||
lib/Target/MSP430/CMakeLists.txt
|
||||
lib/Target/MSP430/Disassembler/CMakeLists.txt
|
||||
lib/Target/MSP430/Disassembler/LLVMBuild.txt
|
||||
lib/Target/MSP430/InstPrinter/CMakeLists.txt
|
||||
lib/Target/MSP430/InstPrinter/LLVMBuild.txt
|
||||
lib/Target/MSP430/InstPrinter/Makefile
|
||||
lib/Target/MSP430/LLVMBuild.txt
|
||||
lib/Target/MSP430/MCTargetDesc/CMakeLists.txt
|
||||
lib/Target/MSP430/MCTargetDesc/LLVMBuild.txt
|
||||
lib/Target/MSP430/MCTargetDesc/Makefile
|
||||
lib/Target/MSP430/Makefile
|
||||
lib/Target/MSP430/README.txt
|
||||
lib/Target/MSP430/TargetInfo/CMakeLists.txt
|
||||
lib/Target/MSP430/TargetInfo/LLVMBuild.txt
|
||||
lib/Target/MSP430/TargetInfo/Makefile
|
||||
lib/Target/Makefile
|
||||
lib/Target/Mips/AsmParser/CMakeLists.txt
|
||||
lib/Target/Mips/AsmParser/LLVMBuild.txt
|
||||
lib/Target/Mips/AsmParser/Makefile
|
||||
lib/Target/Mips/CMakeLists.txt
|
||||
lib/Target/Mips/Disassembler/CMakeLists.txt
|
||||
lib/Target/Mips/Disassembler/LLVMBuild.txt
|
||||
lib/Target/Mips/Disassembler/Makefile
|
||||
lib/Target/Mips/InstPrinter/CMakeLists.txt
|
||||
lib/Target/Mips/InstPrinter/LLVMBuild.txt
|
||||
lib/Target/Mips/InstPrinter/Makefile
|
||||
lib/Target/Mips/LLVMBuild.txt
|
||||
lib/Target/Mips/MCTargetDesc/CMakeLists.txt
|
||||
lib/Target/Mips/MCTargetDesc/LLVMBuild.txt
|
||||
lib/Target/Mips/MCTargetDesc/Makefile
|
||||
lib/Target/Mips/Makefile
|
||||
lib/Target/Mips/TargetInfo/CMakeLists.txt
|
||||
lib/Target/Mips/TargetInfo/LLVMBuild.txt
|
||||
lib/Target/Mips/TargetInfo/Makefile
|
||||
lib/Target/NVPTX/CMakeLists.txt
|
||||
lib/Target/NVPTX/InstPrinter/CMakeLists.txt
|
||||
lib/Target/NVPTX/InstPrinter/LLVMBuild.txt
|
||||
lib/Target/NVPTX/InstPrinter/Makefile
|
||||
lib/Target/NVPTX/LLVMBuild.txt
|
||||
lib/Target/NVPTX/MCTargetDesc/CMakeLists.txt
|
||||
lib/Target/NVPTX/MCTargetDesc/LLVMBuild.txt
|
||||
lib/Target/NVPTX/MCTargetDesc/Makefile
|
||||
lib/Target/NVPTX/Makefile
|
||||
lib/Target/NVPTX/TargetInfo/CMakeLists.txt
|
||||
lib/Target/NVPTX/TargetInfo/LLVMBuild.txt
|
||||
lib/Target/NVPTX/TargetInfo/Makefile
|
||||
lib/Target/PowerPC/AsmParser/CMakeLists.txt
|
||||
lib/Target/PowerPC/AsmParser/LLVMBuild.txt
|
||||
lib/Target/PowerPC/AsmParser/Makefile
|
||||
lib/Target/PowerPC/CMakeLists.txt
|
||||
lib/Target/PowerPC/Disassembler/CMakeLists.txt
|
||||
lib/Target/PowerPC/Disassembler/LLVMBuild.txt
|
||||
lib/Target/PowerPC/Disassembler/Makefile
|
||||
lib/Target/PowerPC/InstPrinter/CMakeLists.txt
|
||||
lib/Target/PowerPC/InstPrinter/LLVMBuild.txt
|
||||
lib/Target/PowerPC/InstPrinter/Makefile
|
||||
lib/Target/PowerPC/LLVMBuild.txt
|
||||
lib/Target/PowerPC/MCTargetDesc/CMakeLists.txt
|
||||
lib/Target/PowerPC/MCTargetDesc/LLVMBuild.txt
|
||||
lib/Target/PowerPC/MCTargetDesc/Makefile
|
||||
lib/Target/PowerPC/Makefile
|
||||
lib/Target/PowerPC/README.txt
|
||||
lib/Target/PowerPC/README_ALTIVEC.txt
|
||||
lib/Target/PowerPC/TargetInfo/CMakeLists.txt
|
||||
lib/Target/PowerPC/TargetInfo/LLVMBuild.txt
|
||||
lib/Target/PowerPC/TargetInfo/Makefile
|
||||
lib/Target/R600/AsmParser/CMakeLists.txt
|
||||
lib/Target/R600/AsmParser/LLVMBuild.txt
|
||||
lib/Target/R600/AsmParser/Makefile
|
||||
lib/Target/R600/CMakeLists.txt
|
||||
lib/Target/R600/InstPrinter/CMakeLists.txt
|
||||
lib/Target/R600/InstPrinter/LLVMBuild.txt
|
||||
lib/Target/R600/InstPrinter/Makefile
|
||||
lib/Target/R600/LLVMBuild.txt
|
||||
lib/Target/R600/MCTargetDesc/CMakeLists.txt
|
||||
lib/Target/R600/MCTargetDesc/LLVMBuild.txt
|
||||
lib/Target/R600/MCTargetDesc/Makefile
|
||||
lib/Target/R600/Makefile
|
||||
lib/Target/R600/TargetInfo/CMakeLists.txt
|
||||
lib/Target/R600/TargetInfo/LLVMBuild.txt
|
||||
lib/Target/R600/TargetInfo/Makefile
|
||||
lib/Target/README.txt
|
||||
lib/Target/RISCV/AsmParser/CMakeLists.txt
|
||||
lib/Target/RISCV/AsmParser/LLVMBuild.txt
|
||||
lib/Target/RISCV/CMakeLists.txt
|
||||
lib/Target/RISCV/Disassembler/CMakeLists.txt
|
||||
lib/Target/RISCV/Disassembler/LLVMBuild.txt
|
||||
lib/Target/RISCV/InstPrinter/CMakeLists.txt
|
||||
lib/Target/RISCV/InstPrinter/LLVMBuild.txt
|
||||
lib/Target/RISCV/LLVMBuild.txt
|
||||
lib/Target/RISCV/MCTargetDesc/CMakeLists.txt
|
||||
lib/Target/RISCV/MCTargetDesc/LLVMBuild.txt
|
||||
lib/Target/RISCV/TargetInfo/CMakeLists.txt
|
||||
lib/Target/RISCV/TargetInfo/LLVMBuild.txt
|
||||
lib/Target/RISCV/Utils/CMakeLists.txt
|
||||
lib/Target/RISCV/Utils/LLVMBuild.txt
|
||||
lib/Target/Sparc/AsmParser/CMakeLists.txt
|
||||
lib/Target/Sparc/AsmParser/LLVMBuild.txt
|
||||
lib/Target/Sparc/AsmParser/Makefile
|
||||
lib/Target/Sparc/CMakeLists.txt
|
||||
lib/Target/Sparc/Disassembler/CMakeLists.txt
|
||||
lib/Target/Sparc/Disassembler/LLVMBuild.txt
|
||||
lib/Target/Sparc/Disassembler/Makefile
|
||||
lib/Target/Sparc/InstPrinter/CMakeLists.txt
|
||||
lib/Target/Sparc/InstPrinter/LLVMBuild.txt
|
||||
lib/Target/Sparc/InstPrinter/Makefile
|
||||
lib/Target/Sparc/LLVMBuild.txt
|
||||
lib/Target/Sparc/MCTargetDesc/CMakeLists.txt
|
||||
lib/Target/Sparc/MCTargetDesc/LLVMBuild.txt
|
||||
lib/Target/Sparc/MCTargetDesc/Makefile
|
||||
lib/Target/Sparc/Makefile
|
||||
lib/Target/Sparc/README.txt
|
||||
lib/Target/Sparc/TargetInfo/CMakeLists.txt
|
||||
lib/Target/Sparc/TargetInfo/LLVMBuild.txt
|
||||
lib/Target/Sparc/TargetInfo/Makefile
|
||||
lib/Target/SystemZ/AsmParser/CMakeLists.txt
|
||||
lib/Target/SystemZ/AsmParser/LLVMBuild.txt
|
||||
lib/Target/SystemZ/AsmParser/Makefile
|
||||
lib/Target/SystemZ/CMakeLists.txt
|
||||
lib/Target/SystemZ/Disassembler/CMakeLists.txt
|
||||
lib/Target/SystemZ/Disassembler/LLVMBuild.txt
|
||||
lib/Target/SystemZ/Disassembler/Makefile
|
||||
lib/Target/SystemZ/InstPrinter/CMakeLists.txt
|
||||
lib/Target/SystemZ/InstPrinter/LLVMBuild.txt
|
||||
lib/Target/SystemZ/InstPrinter/Makefile
|
||||
lib/Target/SystemZ/LLVMBuild.txt
|
||||
lib/Target/SystemZ/MCTargetDesc/CMakeLists.txt
|
||||
lib/Target/SystemZ/MCTargetDesc/LLVMBuild.txt
|
||||
lib/Target/SystemZ/MCTargetDesc/Makefile
|
||||
lib/Target/SystemZ/Makefile
|
||||
lib/Target/SystemZ/TargetInfo/CMakeLists.txt
|
||||
lib/Target/SystemZ/TargetInfo/LLVMBuild.txt
|
||||
lib/Target/SystemZ/TargetInfo/Makefile
|
||||
lib/Target/WebAssembly/AsmParser/CMakeLists.txt
|
||||
lib/Target/WebAssembly/AsmParser/LLVMBuild.txt
|
||||
lib/Target/WebAssembly/CMakeLists.txt
|
||||
lib/Target/WebAssembly/Disassembler/CMakeLists.txt
|
||||
lib/Target/WebAssembly/Disassembler/LLVMBuild.txt
|
||||
lib/Target/WebAssembly/InstPrinter/CMakeLists.txt
|
||||
lib/Target/WebAssembly/InstPrinter/LLVMBuild.txt
|
||||
lib/Target/WebAssembly/LLVMBuild.txt
|
||||
lib/Target/WebAssembly/MCTargetDesc/CMakeLists.txt
|
||||
lib/Target/WebAssembly/MCTargetDesc/LLVMBuild.txt
|
||||
lib/Target/WebAssembly/TargetInfo/CMakeLists.txt
|
||||
lib/Target/WebAssembly/TargetInfo/LLVMBuild.txt
|
||||
lib/Target/X86/AsmParser/CMakeLists.txt
|
||||
lib/Target/X86/AsmParser/LLVMBuild.txt
|
||||
lib/Target/X86/AsmParser/Makefile
|
||||
lib/Target/X86/CMakeLists.txt
|
||||
lib/Target/X86/Disassembler/CMakeLists.txt
|
||||
lib/Target/X86/Disassembler/LLVMBuild.txt
|
||||
lib/Target/X86/Disassembler/Makefile
|
||||
lib/Target/X86/InstPrinter/CMakeLists.txt
|
||||
lib/Target/X86/InstPrinter/LLVMBuild.txt
|
||||
lib/Target/X86/InstPrinter/Makefile
|
||||
lib/Target/X86/LLVMBuild.txt
|
||||
lib/Target/X86/MCTargetDesc/CMakeLists.txt
|
||||
lib/Target/X86/MCTargetDesc/LLVMBuild.txt
|
||||
lib/Target/X86/MCTargetDesc/Makefile
|
||||
lib/Target/X86/Makefile
|
||||
lib/Target/X86/README-FPStack.txt
|
||||
lib/Target/X86/README-MMX.txt
|
||||
lib/Target/X86/README-SSE.txt
|
||||
lib/Target/X86/README-UNIMPLEMENTED.txt
|
||||
lib/Target/X86/README-X86-64.txt
|
||||
lib/Target/X86/README.txt
|
||||
lib/Target/X86/TargetInfo/CMakeLists.txt
|
||||
lib/Target/X86/TargetInfo/LLVMBuild.txt
|
||||
lib/Target/X86/TargetInfo/Makefile
|
||||
lib/Target/X86/Utils/CMakeLists.txt
|
||||
lib/Target/X86/Utils/LLVMBuild.txt
|
||||
lib/Target/X86/Utils/Makefile
|
||||
lib/Target/X86/X86CompilationCallback_Win64.asm
|
||||
lib/Target/XCore/CMakeLists.txt
|
||||
lib/Target/XCore/Disassembler/CMakeLists.txt
|
||||
lib/Target/XCore/Disassembler/LLVMBuild.txt
|
||||
lib/Target/XCore/Disassembler/Makefile
|
||||
lib/Target/XCore/InstPrinter/CMakeLists.txt
|
||||
lib/Target/XCore/InstPrinter/LLVMBuild.txt
|
||||
lib/Target/XCore/InstPrinter/Makefile
|
||||
lib/Target/XCore/LLVMBuild.txt
|
||||
lib/Target/XCore/MCTargetDesc/CMakeLists.txt
|
||||
lib/Target/XCore/MCTargetDesc/LLVMBuild.txt
|
||||
lib/Target/XCore/MCTargetDesc/Makefile
|
||||
lib/Target/XCore/Makefile
|
||||
lib/Target/XCore/README.txt
|
||||
lib/Target/XCore/TargetInfo/CMakeLists.txt
|
||||
lib/Target/XCore/TargetInfo/LLVMBuild.txt
|
||||
lib/Target/XCore/TargetInfo/Makefile
|
||||
lib/Testing/CMakeLists.txt
|
||||
lib/Testing/LLVMBuild.txt
|
||||
lib/Testing/Support/CMakeLists.txt
|
||||
lib/Testing/Support/LLVMBuild.txt
|
||||
lib/TextAPI/CMakeLists.txt
|
||||
lib/TextAPI/LLVMBuild.txt
|
||||
lib/ToolDrivers/CMakeLists.txt
|
||||
lib/ToolDrivers/LLVMBuild.txt
|
||||
lib/ToolDrivers/llvm-dlltool/CMakeLists.txt
|
||||
lib/ToolDrivers/llvm-dlltool/LLVMBuild.txt
|
||||
lib/ToolDrivers/llvm-lib/CMakeLists.txt
|
||||
lib/ToolDrivers/llvm-lib/LLVMBuild.txt
|
||||
lib/Transforms/AggressiveInstCombine/CMakeLists.txt
|
||||
lib/Transforms/AggressiveInstCombine/LLVMBuild.txt
|
||||
lib/Transforms/CMakeLists.txt
|
||||
lib/Transforms/Coroutines/CMakeLists.txt
|
||||
lib/Transforms/Coroutines/LLVMBuild.txt
|
||||
lib/Transforms/Hello/
|
||||
lib/Transforms/IPO/CMakeLists.txt
|
||||
lib/Transforms/IPO/LLVMBuild.txt
|
||||
lib/Transforms/IPO/Makefile
|
||||
lib/Transforms/InstCombine/CMakeLists.txt
|
||||
lib/Transforms/InstCombine/LLVMBuild.txt
|
||||
lib/Transforms/InstCombine/Makefile
|
||||
lib/Transforms/Instrumentation/CMakeLists.txt
|
||||
lib/Transforms/Instrumentation/LLVMBuild.txt
|
||||
lib/Transforms/Instrumentation/Makefile
|
||||
lib/Transforms/LLVMBuild.txt
|
||||
lib/Transforms/Makefile
|
||||
lib/Transforms/ObjCARC/CMakeLists.txt
|
||||
lib/Transforms/ObjCARC/LLVMBuild.txt
|
||||
lib/Transforms/ObjCARC/Makefile
|
||||
lib/Transforms/Scalar/CMakeLists.txt
|
||||
lib/Transforms/Scalar/LLVMBuild.txt
|
||||
lib/Transforms/Scalar/Makefile
|
||||
lib/Transforms/Utils/CMakeLists.txt
|
||||
lib/Transforms/Utils/LLVMBuild.txt
|
||||
lib/Transforms/Utils/Makefile
|
||||
lib/Transforms/Vectorize/CMakeLists.txt
|
||||
lib/Transforms/Vectorize/LLVMBuild.txt
|
||||
lib/Transforms/Vectorize/Makefile
|
||||
lib/WindowsManifest/CMakeLists.txt
|
||||
lib/WindowsManifest/LLVMBuild.txt
|
||||
lib/XRay/CMakeLists.txt
|
||||
lib/XRay/LLVMBuild.txt
|
||||
llvm.spec.in
|
||||
projects/
|
||||
projects/CMakeLists.txt
|
||||
projects/LLVMBuild.txt
|
||||
resources/
|
||||
runtimes/
|
||||
test/
|
||||
tools/CMakeLists.txt
|
||||
tools/LLVMBuild.txt
|
||||
tools/Makefile
|
||||
tools/bugpoint-passes/
|
||||
tools/bugpoint/CMakeLists.txt
|
||||
tools/bugpoint/LLVMBuild.txt
|
||||
tools/bugpoint/Makefile
|
||||
tools/bugpoint-passes/
|
||||
tools/dsymutil/
|
||||
tools/gold/
|
||||
tools/llc/CMakeLists.txt
|
||||
tools/llc/LLVMBuild.txt
|
||||
tools/llc/Makefile
|
||||
tools/lli/CMakeLists.txt
|
||||
tools/lli/ChildTarget/CMakeLists.txt
|
||||
tools/lli/ChildTarget/LLVMBuild.txt
|
||||
tools/lli/ChildTarget/Makefile
|
||||
tools/lli/LLVMBuild.txt
|
||||
tools/lli/Makefile
|
||||
tools/llvm-ar/CMakeLists.txt
|
||||
tools/llvm-ar/LLVMBuild.txt
|
||||
tools/llvm-ar/Makefile
|
||||
tools/llvm-ar/install_symlink.cmake
|
||||
tools/llvm-as-fuzzer/
|
||||
tools/llvm-as-parasitic-coverage-repro/
|
||||
tools/llvm-as/CMakeLists.txt
|
||||
tools/llvm-as/LLVMBuild.txt
|
||||
tools/llvm-as/Makefile
|
||||
tools/llvm-bcanalyzer/CMakeLists.txt
|
||||
tools/llvm-bcanalyzer/LLVMBuild.txt
|
||||
tools/llvm-bcanalyzer/Makefile
|
||||
tools/llvm-c-test/
|
||||
tools/llvm-cat/
|
||||
tools/llvm-cfi-verify/
|
||||
tools/llvm-config/
|
||||
tools/llvm-cov/CMakeLists.txt
|
||||
tools/llvm-cov/LLVMBuild.txt
|
||||
tools/llvm-cov/Makefile
|
||||
tools/llvm-cvtres/
|
||||
tools/llvm-cxxdump/CMakeLists.txt
|
||||
tools/llvm-cxxdump/LLVMBuild.txt
|
||||
tools/llvm-cxxdump/Makefile
|
||||
tools/llvm-cxxfilt/CMakeLists.txt
|
||||
tools/llvm-cxxmap/CMakeLists.txt
|
||||
tools/llvm-cxxmap/LLVMBuild.txt
|
||||
tools/llvm-diff/CMakeLists.txt
|
||||
tools/llvm-diff/LLVMBuild.txt
|
||||
tools/llvm-diff/Makefile
|
||||
tools/llvm-dis/CMakeLists.txt
|
||||
tools/llvm-dis/LLVMBuild.txt
|
||||
tools/llvm-dis/Makefile
|
||||
tools/llvm-dwarfdump/CMakeLists.txt
|
||||
tools/llvm-dwarfdump/LLVMBuild.txt
|
||||
tools/llvm-dwarfdump/Makefile
|
||||
tools/llvm-dwarfdump/fuzzer/
|
||||
tools/llvm-dwp/
|
||||
tools/llvm-elfabi/
|
||||
tools/llvm-exegesis/
|
||||
tools/llvm-extract/CMakeLists.txt
|
||||
tools/llvm-extract/LLVMBuild.txt
|
||||
tools/llvm-extract/Makefile
|
||||
tools/llvm-go/
|
||||
tools/llvm-isel-fuzzer/
|
||||
tools/llvm-itanium-demangle-fuzzer/
|
||||
tools/llvm-jitlistener/
|
||||
tools/llvm-link/CMakeLists.txt
|
||||
tools/llvm-link/LLVMBuild.txt
|
||||
tools/llvm-link/Makefile
|
||||
tools/llvm-lto/CMakeLists.txt
|
||||
tools/llvm-lto/LLVMBuild.txt
|
||||
tools/llvm-lto/Makefile
|
||||
tools/llvm-lto2/CMakeLists.txt
|
||||
tools/llvm-lto2/LLVMBuild.txt
|
||||
tools/llvm-mc-assemble-fuzzer/
|
||||
tools/llvm-mc-disassemble-fuzzer/
|
||||
tools/llvm-mc/CMakeLists.txt
|
||||
tools/llvm-mc/LLVMBuild.txt
|
||||
tools/llvm-mc/Makefile
|
||||
tools/llvm-mca/CMakeLists.txt
|
||||
tools/llvm-mca/LLVMBuild.txt
|
||||
tools/llvm-mcmarkup/
|
||||
tools/llvm-microsoft-demangle-fuzzer/
|
||||
tools/llvm-modextract/CMakeLists.txt
|
||||
tools/llvm-modextract/LLVMBuild.txt
|
||||
tools/llvm-mt/
|
||||
tools/llvm-nm/CMakeLists.txt
|
||||
tools/llvm-nm/LLVMBuild.txt
|
||||
tools/llvm-nm/Makefile
|
||||
tools/llvm-objcopy/CMakeLists.txt
|
||||
tools/llvm-objcopy/LLVMBuild.txt
|
||||
tools/llvm-objdump/CMakeLists.txt
|
||||
tools/llvm-objdump/LLVMBuild.txt
|
||||
tools/llvm-objdump/Makefile
|
||||
tools/llvm-pdbdump/CMakeLists.txt
|
||||
tools/llvm-pdbdump/LLVMBuild.txt
|
||||
tools/llvm-pdbdump/Makefile
|
||||
tools/llvm-opt-fuzzer/
|
||||
tools/llvm-opt-report/
|
||||
tools/llvm-pdbutil/CMakeLists.txt
|
||||
tools/llvm-pdbutil/LLVMBuild.txt
|
||||
tools/llvm-pdbutil/fuzzer/
|
||||
tools/llvm-profdata/CMakeLists.txt
|
||||
tools/llvm-profdata/LLVMBuild.txt
|
||||
tools/llvm-profdata/Makefile
|
||||
tools/llvm-rc/
|
||||
tools/llvm-readobj/CMakeLists.txt
|
||||
tools/llvm-readobj/LLVMBuild.txt
|
||||
tools/llvm-readobj/Makefile
|
||||
tools/llvm-rtdyld/CMakeLists.txt
|
||||
tools/llvm-rtdyld/LLVMBuild.txt
|
||||
tools/llvm-rtdyld/Makefile
|
||||
tools/llvm-shlib/
|
||||
tools/llvm-size/
|
||||
tools/llvm-special-case-list-fuzzer/
|
||||
tools/llvm-split/
|
||||
tools/llvm-stress/CMakeLists.txt
|
||||
tools/llvm-stress/LLVMBuild.txt
|
||||
tools/llvm-stress/Makefile
|
||||
tools/llvm-strings/
|
||||
tools/llvm-symbolizer/CMakeLists.txt
|
||||
tools/llvm-symbolizer/Makefile
|
||||
tools/llvm-undname/
|
||||
tools/llvm-vtabledump/
|
||||
tools/llvm-xray/CMakeLists.txt
|
||||
tools/llvm-yaml-numeric-parser-fuzzer/
|
||||
tools/lto/
|
||||
tools/macho-dump/CMakeLists.txt
|
||||
tools/macho-dump/LLVMBuild.txt
|
||||
tools/macho-dump/Makefile
|
||||
tools/msbuild/
|
||||
tools/obj2yaml/
|
||||
tools/opt-remarks/
|
||||
tools/opt-viewer/
|
||||
tools/opt/CMakeLists.txt
|
||||
tools/opt/LLVMBuild.txt
|
||||
tools/opt/Makefile
|
||||
tools/sancov/
|
||||
tools/sanstats/
|
||||
tools/verify-uselistorder/
|
||||
tools/xcode-toolchain/
|
||||
tools/yaml2obj/
|
||||
unittests/
|
||||
utils/DSAclean.py
|
||||
|
|
@ -498,33 +508,47 @@ utils/GetRepositoryPath
|
|||
utils/GetSourceVersion
|
||||
utils/KillTheDoctor/
|
||||
utils/LLVMBuild.txt
|
||||
utils/Makefile
|
||||
utils/LLVMVisualizers/
|
||||
utils/Misc/
|
||||
utils/PerfectShuffle/
|
||||
utils/Reviewing/
|
||||
utils/TableGen/CMakeLists.txt
|
||||
utils/TableGen/LLVMBuild.txt
|
||||
utils/TableGen/Makefile
|
||||
utils/TableGen/tdtags
|
||||
utils/Target/
|
||||
utils/UpdateCMakeLists.pl
|
||||
utils/UpdateTestChecks/
|
||||
utils/abtest/
|
||||
utils/abtest.py
|
||||
utils/benchmark/
|
||||
utils/bisect
|
||||
utils/bisect-skip-count
|
||||
utils/bugpoint/
|
||||
utils/bugpoint_gisel_reducer.py
|
||||
utils/buildit/
|
||||
utils/check-each-file
|
||||
utils/clang-parse-diagnostics-file
|
||||
utils/codegen-diff
|
||||
utils/collect_and_build_with_pgo.py
|
||||
utils/count/
|
||||
utils/countloc.sh
|
||||
utils/create_ladder_graph.py
|
||||
utils/crosstool/
|
||||
utils/demangle_tree.py
|
||||
utils/docker/
|
||||
utils/emacs/
|
||||
utils/extract_symbols.py
|
||||
utils/extract_vplan.py
|
||||
utils/findmisopt
|
||||
utils/findoptdiff
|
||||
utils/findsym.pl
|
||||
utils/fpcmp/
|
||||
utils/gdb-scripts/
|
||||
utils/getsrcs.sh
|
||||
utils/git/
|
||||
utils/git-svn/
|
||||
utils/gn/
|
||||
utils/indirect_calls.py
|
||||
utils/jedit/
|
||||
utils/kate/
|
||||
utils/lint/
|
||||
|
|
@ -532,23 +556,33 @@ utils/lit/
|
|||
utils/lldbDataFormatters.py
|
||||
utils/llvm-build/
|
||||
utils/llvm-compilers-check
|
||||
utils/llvm-gisel-cov.py
|
||||
utils/llvm-lit/
|
||||
utils/llvm-native-gxx
|
||||
utils/llvm.grm
|
||||
utils/llvm.natvis
|
||||
utils/llvmdo
|
||||
utils/llvmgrep
|
||||
utils/makellvm
|
||||
utils/not/
|
||||
utils/opt-viewer/
|
||||
utils/prepare-code-coverage-artifact.py
|
||||
utils/release/
|
||||
utils/sanitizers/
|
||||
utils/schedcover.py
|
||||
utils/shuffle_fuzz.py
|
||||
utils/shuffle_select_fuzz_tester.py
|
||||
utils/sort_includes.py
|
||||
utils/test_debuginfo.pl
|
||||
utils/testgen/
|
||||
utils/textmate/
|
||||
utils/unicode-case-fold.py
|
||||
utils/unittest/
|
||||
utils/update_analyze_test_checks.py
|
||||
utils/update_cc_test_checks.py
|
||||
utils/update_llc_test_checks.py
|
||||
utils/update_mca_test_checks.py
|
||||
utils/update_mir_test_checks.py
|
||||
utils/update_test_checks.py
|
||||
utils/valgrind/
|
||||
utils/vim/
|
||||
utils/vscode/
|
||||
utils/wciia.py
|
||||
utils/yaml-bench/
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ LLVM Release License
|
|||
University of Illinois/NCSA
|
||||
Open Source License
|
||||
|
||||
Copyright (c) 2003-2018 University of Illinois at Urbana-Champaign.
|
||||
Copyright (c) 2003-2019 University of Illinois at Urbana-Champaign.
|
||||
All rights reserved.
|
||||
|
||||
Developed by:
|
||||
|
|
|
|||
|
|
@ -54,6 +54,8 @@ extern "C" {
|
|||
* @{
|
||||
*/
|
||||
|
||||
/// External users depend on the following values being stable. It is not safe
|
||||
/// to reorder them.
|
||||
typedef enum {
|
||||
/* Terminator Instructions */
|
||||
LLVMRet = 1,
|
||||
|
|
@ -64,6 +66,9 @@ typedef enum {
|
|||
/* removed 6 due to API changes */
|
||||
LLVMUnreachable = 7,
|
||||
|
||||
/* Standard Unary Operators */
|
||||
LLVMFNeg = 66,
|
||||
|
||||
/* Standard Binary Operators */
|
||||
LLVMAdd = 8,
|
||||
LLVMFAdd = 9,
|
||||
|
|
@ -515,6 +520,23 @@ void *LLVMContextGetDiagnosticContext(LLVMContextRef C);
|
|||
void LLVMContextSetYieldCallback(LLVMContextRef C, LLVMYieldCallback Callback,
|
||||
void *OpaqueHandle);
|
||||
|
||||
/**
|
||||
* Retrieve whether the given context is set to discard all value names.
|
||||
*
|
||||
* @see LLVMContext::shouldDiscardValueNames()
|
||||
*/
|
||||
LLVMBool LLVMContextShouldDiscardValueNames(LLVMContextRef C);
|
||||
|
||||
/**
|
||||
* Set whether the given context discards all value names.
|
||||
*
|
||||
* If true, only the names of GlobalValue objects will be available in the IR.
|
||||
* This can be used to save memory and runtime, especially in release mode.
|
||||
*
|
||||
* @see LLVMContext::setDiscardValueNames()
|
||||
*/
|
||||
void LLVMContextSetDiscardValueNames(LLVMContextRef C, LLVMBool Discard);
|
||||
|
||||
/**
|
||||
* Destroy a context instance.
|
||||
*
|
||||
|
|
@ -842,6 +864,63 @@ LLVMContextRef LLVMGetModuleContext(LLVMModuleRef M);
|
|||
*/
|
||||
LLVMTypeRef LLVMGetTypeByName(LLVMModuleRef M, const char *Name);
|
||||
|
||||
/**
|
||||
* Obtain an iterator to the first NamedMDNode in a Module.
|
||||
*
|
||||
* @see llvm::Module::named_metadata_begin()
|
||||
*/
|
||||
LLVMNamedMDNodeRef LLVMGetFirstNamedMetadata(LLVMModuleRef M);
|
||||
|
||||
/**
|
||||
* Obtain an iterator to the last NamedMDNode in a Module.
|
||||
*
|
||||
* @see llvm::Module::named_metadata_end()
|
||||
*/
|
||||
LLVMNamedMDNodeRef LLVMGetLastNamedMetadata(LLVMModuleRef M);
|
||||
|
||||
/**
|
||||
* Advance a NamedMDNode iterator to the next NamedMDNode.
|
||||
*
|
||||
* Returns NULL if the iterator was already at the end and there are no more
|
||||
* named metadata nodes.
|
||||
*/
|
||||
LLVMNamedMDNodeRef LLVMGetNextNamedMetadata(LLVMNamedMDNodeRef NamedMDNode);
|
||||
|
||||
/**
|
||||
* Decrement a NamedMDNode iterator to the previous NamedMDNode.
|
||||
*
|
||||
* Returns NULL if the iterator was already at the beginning and there are
|
||||
* no previous named metadata nodes.
|
||||
*/
|
||||
LLVMNamedMDNodeRef LLVMGetPreviousNamedMetadata(LLVMNamedMDNodeRef NamedMDNode);
|
||||
|
||||
/**
|
||||
* Retrieve a NamedMDNode with the given name, returning NULL if no such
|
||||
* node exists.
|
||||
*
|
||||
* @see llvm::Module::getNamedMetadata()
|
||||
*/
|
||||
LLVMNamedMDNodeRef LLVMGetNamedMetadata(LLVMModuleRef M,
|
||||
const char *Name, size_t NameLen);
|
||||
|
||||
/**
|
||||
* Retrieve a NamedMDNode with the given name, creating a new node if no such
|
||||
* node exists.
|
||||
*
|
||||
* @see llvm::Module::getOrInsertNamedMetadata()
|
||||
*/
|
||||
LLVMNamedMDNodeRef LLVMGetOrInsertNamedMetadata(LLVMModuleRef M,
|
||||
const char *Name,
|
||||
size_t NameLen);
|
||||
|
||||
/**
|
||||
* Retrieve the name of a NamedMDNode.
|
||||
*
|
||||
* @see llvm::NamedMDNode::getName()
|
||||
*/
|
||||
const char *LLVMGetNamedMetadataName(LLVMNamedMDNodeRef NamedMD,
|
||||
size_t *NameLen);
|
||||
|
||||
/**
|
||||
* Obtain the number of operands for named metadata in a module.
|
||||
*
|
||||
|
|
@ -872,6 +951,44 @@ void LLVMGetNamedMetadataOperands(LLVMModuleRef M, const char *Name,
|
|||
void LLVMAddNamedMetadataOperand(LLVMModuleRef M, const char *Name,
|
||||
LLVMValueRef Val);
|
||||
|
||||
/**
|
||||
* Return the directory of the debug location for this value, which must be
|
||||
* an llvm::Instruction, llvm::GlobalVariable, or llvm::Function.
|
||||
*
|
||||
* @see llvm::Instruction::getDebugLoc()
|
||||
* @see llvm::GlobalVariable::getDebugInfo()
|
||||
* @see llvm::Function::getSubprogram()
|
||||
*/
|
||||
const char *LLVMGetDebugLocDirectory(LLVMValueRef Val, unsigned *Length);
|
||||
|
||||
/**
|
||||
* Return the filename of the debug location for this value, which must be
|
||||
* an llvm::Instruction, llvm::GlobalVariable, or llvm::Function.
|
||||
*
|
||||
* @see llvm::Instruction::getDebugLoc()
|
||||
* @see llvm::GlobalVariable::getDebugInfo()
|
||||
* @see llvm::Function::getSubprogram()
|
||||
*/
|
||||
const char *LLVMGetDebugLocFilename(LLVMValueRef Val, unsigned *Length);
|
||||
|
||||
/**
|
||||
* Return the line number of the debug location for this value, which must be
|
||||
* an llvm::Instruction, llvm::GlobalVariable, or llvm::Function.
|
||||
*
|
||||
* @see llvm::Instruction::getDebugLoc()
|
||||
* @see llvm::GlobalVariable::getDebugInfo()
|
||||
* @see llvm::Function::getSubprogram()
|
||||
*/
|
||||
unsigned LLVMGetDebugLocLine(LLVMValueRef Val);
|
||||
|
||||
/**
|
||||
* Return the column number of the debug location for this value, which must be
|
||||
* an llvm::Instruction.
|
||||
*
|
||||
* @see llvm::Instruction::getDebugLoc()
|
||||
*/
|
||||
unsigned LLVMGetDebugLocColumn(LLVMValueRef Val);
|
||||
|
||||
/**
|
||||
* Add a function to a module under a specified name.
|
||||
*
|
||||
|
|
@ -1221,6 +1338,13 @@ LLVMBool LLVMIsPackedStruct(LLVMTypeRef StructTy);
|
|||
*/
|
||||
LLVMBool LLVMIsOpaqueStruct(LLVMTypeRef StructTy);
|
||||
|
||||
/**
|
||||
* Determine whether a structure is literal.
|
||||
*
|
||||
* @see llvm::StructType::isLiteral()
|
||||
*/
|
||||
LLVMBool LLVMIsLiteralStruct(LLVMTypeRef StructTy);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
|
@ -1408,6 +1532,7 @@ LLVMTypeRef LLVMX86MMXType(void);
|
|||
macro(ConstantVector) \
|
||||
macro(GlobalValue) \
|
||||
macro(GlobalAlias) \
|
||||
macro(GlobalIFunc) \
|
||||
macro(GlobalObject) \
|
||||
macro(Function) \
|
||||
macro(GlobalVariable) \
|
||||
|
|
@ -1417,7 +1542,9 @@ LLVMTypeRef LLVMX86MMXType(void);
|
|||
macro(CallInst) \
|
||||
macro(IntrinsicInst) \
|
||||
macro(DbgInfoIntrinsic) \
|
||||
macro(DbgDeclareInst) \
|
||||
macro(DbgVariableIntrinsic) \
|
||||
macro(DbgDeclareInst) \
|
||||
macro(DbgLabelInst) \
|
||||
macro(MemIntrinsic) \
|
||||
macro(MemCpyInst) \
|
||||
macro(MemMoveInst) \
|
||||
|
|
@ -1434,16 +1561,15 @@ LLVMTypeRef LLVMX86MMXType(void);
|
|||
macro(SelectInst) \
|
||||
macro(ShuffleVectorInst) \
|
||||
macro(StoreInst) \
|
||||
macro(TerminatorInst) \
|
||||
macro(BranchInst) \
|
||||
macro(IndirectBrInst) \
|
||||
macro(InvokeInst) \
|
||||
macro(ReturnInst) \
|
||||
macro(SwitchInst) \
|
||||
macro(UnreachableInst) \
|
||||
macro(ResumeInst) \
|
||||
macro(CleanupReturnInst) \
|
||||
macro(CatchReturnInst) \
|
||||
macro(BranchInst) \
|
||||
macro(IndirectBrInst) \
|
||||
macro(InvokeInst) \
|
||||
macro(ReturnInst) \
|
||||
macro(SwitchInst) \
|
||||
macro(UnreachableInst) \
|
||||
macro(ResumeInst) \
|
||||
macro(CleanupReturnInst) \
|
||||
macro(CatchReturnInst) \
|
||||
macro(FuncletPadInst) \
|
||||
macro(CatchPadInst) \
|
||||
macro(CleanupPadInst) \
|
||||
|
|
@ -1959,9 +2085,14 @@ LLVMValueRef LLVMConstLShr(LLVMValueRef LHSConstant, LLVMValueRef RHSConstant);
|
|||
LLVMValueRef LLVMConstAShr(LLVMValueRef LHSConstant, LLVMValueRef RHSConstant);
|
||||
LLVMValueRef LLVMConstGEP(LLVMValueRef ConstantVal,
|
||||
LLVMValueRef *ConstantIndices, unsigned NumIndices);
|
||||
LLVMValueRef LLVMConstGEP2(LLVMTypeRef Ty, LLVMValueRef ConstantVal,
|
||||
LLVMValueRef *ConstantIndices, unsigned NumIndices);
|
||||
LLVMValueRef LLVMConstInBoundsGEP(LLVMValueRef ConstantVal,
|
||||
LLVMValueRef *ConstantIndices,
|
||||
unsigned NumIndices);
|
||||
LLVMValueRef LLVMConstInBoundsGEP2(LLVMTypeRef Ty, LLVMValueRef ConstantVal,
|
||||
LLVMValueRef *ConstantIndices,
|
||||
unsigned NumIndices);
|
||||
LLVMValueRef LLVMConstTrunc(LLVMValueRef ConstantVal, LLVMTypeRef ToType);
|
||||
LLVMValueRef LLVMConstSExt(LLVMValueRef ConstantVal, LLVMTypeRef ToType);
|
||||
LLVMValueRef LLVMConstZExt(LLVMValueRef ConstantVal, LLVMTypeRef ToType);
|
||||
|
|
@ -2037,6 +2168,14 @@ void LLVMSetDLLStorageClass(LLVMValueRef Global, LLVMDLLStorageClass Class);
|
|||
LLVMUnnamedAddr LLVMGetUnnamedAddress(LLVMValueRef Global);
|
||||
void LLVMSetUnnamedAddress(LLVMValueRef Global, LLVMUnnamedAddr UnnamedAddr);
|
||||
|
||||
/**
|
||||
* Returns the "value type" of a global value. This differs from the formal
|
||||
* type of a global value which is always a pointer type.
|
||||
*
|
||||
* @see llvm::GlobalValue::getValueType()
|
||||
*/
|
||||
LLVMTypeRef LLVMGlobalGetValueType(LLVMValueRef Global);
|
||||
|
||||
/** Deprecated: Use LLVMGetUnnamedAddress instead. */
|
||||
LLVMBool LLVMHasUnnamedAddr(LLVMValueRef Global);
|
||||
/** Deprecated: Use LLVMSetUnnamedAddress instead. */
|
||||
|
|
@ -2067,6 +2206,58 @@ unsigned LLVMGetAlignment(LLVMValueRef V);
|
|||
*/
|
||||
void LLVMSetAlignment(LLVMValueRef V, unsigned Bytes);
|
||||
|
||||
/**
|
||||
* Sets a metadata attachment, erasing the existing metadata attachment if
|
||||
* it already exists for the given kind.
|
||||
*
|
||||
* @see llvm::GlobalObject::setMetadata()
|
||||
*/
|
||||
void LLVMGlobalSetMetadata(LLVMValueRef Global, unsigned Kind,
|
||||
LLVMMetadataRef MD);
|
||||
|
||||
/**
|
||||
* Erases a metadata attachment of the given kind if it exists.
|
||||
*
|
||||
* @see llvm::GlobalObject::eraseMetadata()
|
||||
*/
|
||||
void LLVMGlobalEraseMetadata(LLVMValueRef Global, unsigned Kind);
|
||||
|
||||
/**
|
||||
* Removes all metadata attachments from this value.
|
||||
*
|
||||
* @see llvm::GlobalObject::clearMetadata()
|
||||
*/
|
||||
void LLVMGlobalClearMetadata(LLVMValueRef Global);
|
||||
|
||||
/**
|
||||
* Retrieves an array of metadata entries representing the metadata attached to
|
||||
* this value. The caller is responsible for freeing this array by calling
|
||||
* \c LLVMDisposeValueMetadataEntries.
|
||||
*
|
||||
* @see llvm::GlobalObject::getAllMetadata()
|
||||
*/
|
||||
LLVMValueMetadataEntry *LLVMGlobalCopyAllMetadata(LLVMValueRef Value,
|
||||
size_t *NumEntries);
|
||||
|
||||
/**
|
||||
* Destroys value metadata entries.
|
||||
*/
|
||||
void LLVMDisposeValueMetadataEntries(LLVMValueMetadataEntry *Entries);
|
||||
|
||||
/**
|
||||
* Returns the kind of a value metadata entry at a specific index.
|
||||
*/
|
||||
unsigned LLVMValueMetadataEntriesGetKind(LLVMValueMetadataEntry *Entries,
|
||||
unsigned Index);
|
||||
|
||||
/**
|
||||
* Returns the underlying metadata node of a value metadata entry at a
|
||||
* specific index.
|
||||
*/
|
||||
LLVMMetadataRef
|
||||
LLVMValueMetadataEntriesGetMetadata(LLVMValueMetadataEntry *Entries,
|
||||
unsigned Index);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
|
@ -2217,6 +2408,54 @@ void LLVMSetPersonalityFn(LLVMValueRef Fn, LLVMValueRef PersonalityFn);
|
|||
*/
|
||||
unsigned LLVMGetIntrinsicID(LLVMValueRef Fn);
|
||||
|
||||
/**
|
||||
* Create or insert the declaration of an intrinsic. For overloaded intrinsics,
|
||||
* parameter types must be provided to uniquely identify an overload.
|
||||
*
|
||||
* @see llvm::Intrinsic::getDeclaration()
|
||||
*/
|
||||
LLVMValueRef LLVMGetIntrinsicDeclaration(LLVMModuleRef Mod,
|
||||
unsigned ID,
|
||||
LLVMTypeRef *ParamTypes,
|
||||
size_t ParamCount);
|
||||
|
||||
/**
|
||||
* Retrieves the type of an intrinsic. For overloaded intrinsics, parameter
|
||||
* types must be provided to uniquely identify an overload.
|
||||
*
|
||||
* @see llvm::Intrinsic::getType()
|
||||
*/
|
||||
LLVMTypeRef LLVMIntrinsicGetType(LLVMContextRef Ctx, unsigned ID,
|
||||
LLVMTypeRef *ParamTypes, size_t ParamCount);
|
||||
|
||||
/**
|
||||
* Retrieves the name of an intrinsic.
|
||||
*
|
||||
* @see llvm::Intrinsic::getName()
|
||||
*/
|
||||
const char *LLVMIntrinsicGetName(unsigned ID, size_t *NameLength);
|
||||
|
||||
/**
|
||||
* Copies the name of an overloaded intrinsic identified by a given list of
|
||||
* parameter types.
|
||||
*
|
||||
* Unlike LLVMIntrinsicGetName, the caller is responsible for freeing the
|
||||
* returned string.
|
||||
*
|
||||
* @see llvm::Intrinsic::getName()
|
||||
*/
|
||||
const char *LLVMIntrinsicCopyOverloadedName(unsigned ID,
|
||||
LLVMTypeRef *ParamTypes,
|
||||
size_t ParamCount,
|
||||
size_t *NameLength);
|
||||
|
||||
/**
|
||||
* Obtain if the intrinsic identified by the given ID is overloaded.
|
||||
*
|
||||
* @see llvm::Intrinsic::isOverloaded()
|
||||
*/
|
||||
LLVMBool LLVMIntrinsicIsOverloaded(unsigned ID);
|
||||
|
||||
/**
|
||||
* Obtain the calling function of a function.
|
||||
*
|
||||
|
|
@ -2514,7 +2753,7 @@ LLVMValueRef LLVMGetBasicBlockParent(LLVMBasicBlockRef BB);
|
|||
* If the basic block does not have a terminator (it is not well-formed
|
||||
* if it doesn't), then NULL is returned.
|
||||
*
|
||||
* The returned LLVMValueRef corresponds to a llvm::TerminatorInst.
|
||||
* The returned LLVMValueRef corresponds to an llvm::Instruction.
|
||||
*
|
||||
* @see llvm::BasicBlock::getTerminator()
|
||||
*/
|
||||
|
|
@ -2572,6 +2811,14 @@ LLVMBasicBlockRef LLVMGetPreviousBasicBlock(LLVMBasicBlockRef BB);
|
|||
*/
|
||||
LLVMBasicBlockRef LLVMGetEntryBasicBlock(LLVMValueRef Fn);
|
||||
|
||||
/**
|
||||
* Create a new basic block without inserting it into a function.
|
||||
*
|
||||
* @see llvm::BasicBlock::Create()
|
||||
*/
|
||||
LLVMBasicBlockRef LLVMCreateBasicBlockInContext(LLVMContextRef C,
|
||||
const char *Name);
|
||||
|
||||
/**
|
||||
* Append a basic block to the end of a function.
|
||||
*
|
||||
|
|
@ -2694,6 +2941,16 @@ LLVMValueRef LLVMGetMetadata(LLVMValueRef Val, unsigned KindID);
|
|||
*/
|
||||
void LLVMSetMetadata(LLVMValueRef Val, unsigned KindID, LLVMValueRef Node);
|
||||
|
||||
/**
|
||||
* Returns the metadata associated with an instruction value, but filters out
|
||||
* all the debug locations.
|
||||
*
|
||||
* @see llvm::Instruction::getAllMetadataOtherThanDebugLoc()
|
||||
*/
|
||||
LLVMValueMetadataEntry *
|
||||
LLVMInstructionGetAllMetadataOtherThanDebugLoc(LLVMValueRef Instr,
|
||||
size_t *NumEntries);
|
||||
|
||||
/**
|
||||
* Obtain the basic block to which an instruction belongs.
|
||||
*
|
||||
|
|
@ -2776,6 +3033,15 @@ LLVMRealPredicate LLVMGetFCmpPredicate(LLVMValueRef Inst);
|
|||
*/
|
||||
LLVMValueRef LLVMInstructionClone(LLVMValueRef Inst);
|
||||
|
||||
/**
|
||||
* Determine whether an instruction is a terminator. This routine is named to
|
||||
* be compatible with historical functions that did this by querying the
|
||||
* underlying C++ type.
|
||||
*
|
||||
* @see llvm::Instruction::isTerminator()
|
||||
*/
|
||||
LLVMValueRef LLVMIsATerminatorInst(LLVMValueRef Inst);
|
||||
|
||||
/**
|
||||
* @defgroup LLVMCCoreValueInstructionCall Call Sites and Invocations
|
||||
*
|
||||
|
|
@ -2838,6 +3104,13 @@ void LLVMRemoveCallSiteEnumAttribute(LLVMValueRef C, LLVMAttributeIndex Idx,
|
|||
void LLVMRemoveCallSiteStringAttribute(LLVMValueRef C, LLVMAttributeIndex Idx,
|
||||
const char *K, unsigned KLen);
|
||||
|
||||
/**
|
||||
* Obtain the function type called by this instruction.
|
||||
*
|
||||
* @see llvm::CallBase::getFunctionType()
|
||||
*/
|
||||
LLVMTypeRef LLVMGetCalledFunctionType(LLVMValueRef C);
|
||||
|
||||
/**
|
||||
* Obtain the pointer to the function invoked by this instruction.
|
||||
*
|
||||
|
|
@ -2916,8 +3189,8 @@ void LLVMSetUnwindDest(LLVMValueRef InvokeInst, LLVMBasicBlockRef B);
|
|||
/**
|
||||
* @defgroup LLVMCCoreValueInstructionTerminator Terminators
|
||||
*
|
||||
* Functions in this group only apply to instructions that map to
|
||||
* llvm::TerminatorInst instances.
|
||||
* Functions in this group only apply to instructions for which
|
||||
* LLVMIsATerminatorInst returns true.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
|
@ -2925,21 +3198,21 @@ void LLVMSetUnwindDest(LLVMValueRef InvokeInst, LLVMBasicBlockRef B);
|
|||
/**
|
||||
* Return the number of successors that this terminator has.
|
||||
*
|
||||
* @see llvm::TerminatorInst::getNumSuccessors
|
||||
* @see llvm::Instruction::getNumSuccessors
|
||||
*/
|
||||
unsigned LLVMGetNumSuccessors(LLVMValueRef Term);
|
||||
|
||||
/**
|
||||
* Return the specified successor.
|
||||
*
|
||||
* @see llvm::TerminatorInst::getSuccessor
|
||||
* @see llvm::Instruction::getSuccessor
|
||||
*/
|
||||
LLVMBasicBlockRef LLVMGetSuccessor(LLVMValueRef Term, unsigned i);
|
||||
|
||||
/**
|
||||
* Update the specified successor to point at the provided block.
|
||||
*
|
||||
* @see llvm::TerminatorInst::setSuccessor
|
||||
* @see llvm::Instruction::setSuccessor
|
||||
*/
|
||||
void LLVMSetSuccessor(LLVMValueRef Term, unsigned i, LLVMBasicBlockRef block);
|
||||
|
||||
|
|
@ -3130,10 +3403,16 @@ LLVMValueRef LLVMBuildSwitch(LLVMBuilderRef, LLVMValueRef V,
|
|||
LLVMBasicBlockRef Else, unsigned NumCases);
|
||||
LLVMValueRef LLVMBuildIndirectBr(LLVMBuilderRef B, LLVMValueRef Addr,
|
||||
unsigned NumDests);
|
||||
// LLVMBuildInvoke is deprecated in favor of LLVMBuildInvoke2, in preparation
|
||||
// for opaque pointer types.
|
||||
LLVMValueRef LLVMBuildInvoke(LLVMBuilderRef, LLVMValueRef Fn,
|
||||
LLVMValueRef *Args, unsigned NumArgs,
|
||||
LLVMBasicBlockRef Then, LLVMBasicBlockRef Catch,
|
||||
const char *Name);
|
||||
LLVMValueRef LLVMBuildInvoke2(LLVMBuilderRef, LLVMTypeRef Ty, LLVMValueRef Fn,
|
||||
LLVMValueRef *Args, unsigned NumArgs,
|
||||
LLVMBasicBlockRef Then, LLVMBasicBlockRef Catch,
|
||||
const char *Name);
|
||||
LLVMValueRef LLVMBuildUnreachable(LLVMBuilderRef);
|
||||
|
||||
/* Exception Handling */
|
||||
|
|
@ -3290,13 +3569,48 @@ LLVMValueRef LLVMBuildNot(LLVMBuilderRef, LLVMValueRef V, const char *Name);
|
|||
LLVMValueRef LLVMBuildMalloc(LLVMBuilderRef, LLVMTypeRef Ty, const char *Name);
|
||||
LLVMValueRef LLVMBuildArrayMalloc(LLVMBuilderRef, LLVMTypeRef Ty,
|
||||
LLVMValueRef Val, const char *Name);
|
||||
|
||||
/**
|
||||
* Creates and inserts a memset to the specified pointer and the
|
||||
* specified value.
|
||||
*
|
||||
* @see llvm::IRRBuilder::CreateMemSet()
|
||||
*/
|
||||
LLVMValueRef LLVMBuildMemSet(LLVMBuilderRef B, LLVMValueRef Ptr,
|
||||
LLVMValueRef Val, LLVMValueRef Len,
|
||||
unsigned Align);
|
||||
/**
|
||||
* Creates and inserts a memcpy between the specified pointers.
|
||||
*
|
||||
* @see llvm::IRRBuilder::CreateMemCpy()
|
||||
*/
|
||||
LLVMValueRef LLVMBuildMemCpy(LLVMBuilderRef B,
|
||||
LLVMValueRef Dst, unsigned DstAlign,
|
||||
LLVMValueRef Src, unsigned SrcAlign,
|
||||
LLVMValueRef Size);
|
||||
/**
|
||||
* Creates and inserts a memmove between the specified pointers.
|
||||
*
|
||||
* @see llvm::IRRBuilder::CreateMemMove()
|
||||
*/
|
||||
LLVMValueRef LLVMBuildMemMove(LLVMBuilderRef B,
|
||||
LLVMValueRef Dst, unsigned DstAlign,
|
||||
LLVMValueRef Src, unsigned SrcAlign,
|
||||
LLVMValueRef Size);
|
||||
|
||||
LLVMValueRef LLVMBuildAlloca(LLVMBuilderRef, LLVMTypeRef Ty, const char *Name);
|
||||
LLVMValueRef LLVMBuildArrayAlloca(LLVMBuilderRef, LLVMTypeRef Ty,
|
||||
LLVMValueRef Val, const char *Name);
|
||||
LLVMValueRef LLVMBuildFree(LLVMBuilderRef, LLVMValueRef PointerVal);
|
||||
// LLVMBuildLoad is deprecated in favor of LLVMBuildLoad2, in preparation for
|
||||
// opaque pointer types.
|
||||
LLVMValueRef LLVMBuildLoad(LLVMBuilderRef, LLVMValueRef PointerVal,
|
||||
const char *Name);
|
||||
LLVMValueRef LLVMBuildLoad2(LLVMBuilderRef, LLVMTypeRef Ty,
|
||||
LLVMValueRef PointerVal, const char *Name);
|
||||
LLVMValueRef LLVMBuildStore(LLVMBuilderRef, LLVMValueRef Val, LLVMValueRef Ptr);
|
||||
// LLVMBuildGEP, LLVMBuildInBoundsGEP, and LLVMBuildStructGEP are deprecated in
|
||||
// favor of LLVMBuild*GEP2, in preparation for opaque pointer types.
|
||||
LLVMValueRef LLVMBuildGEP(LLVMBuilderRef B, LLVMValueRef Pointer,
|
||||
LLVMValueRef *Indices, unsigned NumIndices,
|
||||
const char *Name);
|
||||
|
|
@ -3305,6 +3619,15 @@ LLVMValueRef LLVMBuildInBoundsGEP(LLVMBuilderRef B, LLVMValueRef Pointer,
|
|||
const char *Name);
|
||||
LLVMValueRef LLVMBuildStructGEP(LLVMBuilderRef B, LLVMValueRef Pointer,
|
||||
unsigned Idx, const char *Name);
|
||||
LLVMValueRef LLVMBuildGEP2(LLVMBuilderRef B, LLVMTypeRef Ty,
|
||||
LLVMValueRef Pointer, LLVMValueRef *Indices,
|
||||
unsigned NumIndices, const char *Name);
|
||||
LLVMValueRef LLVMBuildInBoundsGEP2(LLVMBuilderRef B, LLVMTypeRef Ty,
|
||||
LLVMValueRef Pointer, LLVMValueRef *Indices,
|
||||
unsigned NumIndices, const char *Name);
|
||||
LLVMValueRef LLVMBuildStructGEP2(LLVMBuilderRef B, LLVMTypeRef Ty,
|
||||
LLVMValueRef Pointer, unsigned Idx,
|
||||
const char *Name);
|
||||
LLVMValueRef LLVMBuildGlobalString(LLVMBuilderRef B, const char *Str,
|
||||
const char *Name);
|
||||
LLVMValueRef LLVMBuildGlobalStringPtr(LLVMBuilderRef B, const char *Str,
|
||||
|
|
@ -3351,11 +3674,16 @@ LLVMValueRef LLVMBuildCast(LLVMBuilderRef B, LLVMOpcode Op, LLVMValueRef Val,
|
|||
LLVMTypeRef DestTy, const char *Name);
|
||||
LLVMValueRef LLVMBuildPointerCast(LLVMBuilderRef, LLVMValueRef Val,
|
||||
LLVMTypeRef DestTy, const char *Name);
|
||||
LLVMValueRef LLVMBuildIntCast(LLVMBuilderRef, LLVMValueRef Val, /*Signed cast!*/
|
||||
LLVMTypeRef DestTy, const char *Name);
|
||||
LLVMValueRef LLVMBuildIntCast2(LLVMBuilderRef, LLVMValueRef Val,
|
||||
LLVMTypeRef DestTy, LLVMBool IsSigned,
|
||||
const char *Name);
|
||||
LLVMValueRef LLVMBuildFPCast(LLVMBuilderRef, LLVMValueRef Val,
|
||||
LLVMTypeRef DestTy, const char *Name);
|
||||
|
||||
/** Deprecated: This cast is always signed. Use LLVMBuildIntCast2 instead. */
|
||||
LLVMValueRef LLVMBuildIntCast(LLVMBuilderRef, LLVMValueRef Val, /*Signed cast!*/
|
||||
LLVMTypeRef DestTy, const char *Name);
|
||||
|
||||
/* Comparisons */
|
||||
LLVMValueRef LLVMBuildICmp(LLVMBuilderRef, LLVMIntPredicate Op,
|
||||
LLVMValueRef LHS, LLVMValueRef RHS,
|
||||
|
|
@ -3366,9 +3694,14 @@ LLVMValueRef LLVMBuildFCmp(LLVMBuilderRef, LLVMRealPredicate Op,
|
|||
|
||||
/* Miscellaneous instructions */
|
||||
LLVMValueRef LLVMBuildPhi(LLVMBuilderRef, LLVMTypeRef Ty, const char *Name);
|
||||
// LLVMBuildCall is deprecated in favor of LLVMBuildCall2, in preparation for
|
||||
// opaque pointer types.
|
||||
LLVMValueRef LLVMBuildCall(LLVMBuilderRef, LLVMValueRef Fn,
|
||||
LLVMValueRef *Args, unsigned NumArgs,
|
||||
const char *Name);
|
||||
LLVMValueRef LLVMBuildCall2(LLVMBuilderRef, LLVMTypeRef, LLVMValueRef Fn,
|
||||
LLVMValueRef *Args, unsigned NumArgs,
|
||||
const char *Name);
|
||||
LLVMValueRef LLVMBuildSelect(LLVMBuilderRef, LLVMValueRef If,
|
||||
LLVMValueRef Then, LLVMValueRef Else,
|
||||
const char *Name);
|
||||
|
|
|
|||
|
|
@ -54,9 +54,12 @@ typedef enum {
|
|||
LLVMDIFlagMainSubprogram = 1 << 21,
|
||||
LLVMDIFlagTypePassByValue = 1 << 22,
|
||||
LLVMDIFlagTypePassByReference = 1 << 23,
|
||||
LLVMDIFlagFixedEnum = 1 << 24,
|
||||
LLVMDIFlagEnumClass = 1 << 24,
|
||||
LLVMDIFlagFixedEnum = LLVMDIFlagEnumClass, // Deprecated.
|
||||
LLVMDIFlagThunk = 1 << 25,
|
||||
LLVMDIFlagTrivial = 1 << 26,
|
||||
LLVMDIFlagBigEndian = 1 << 27,
|
||||
LLVMDIFlagLittleEndian = 1 << 28,
|
||||
LLVMDIFlagIndirectVirtualBase = (1 << 2) | (1 << 5),
|
||||
LLVMDIFlagAccessibility = LLVMDIFlagPrivate | LLVMDIFlagProtected |
|
||||
LLVMDIFlagPublic,
|
||||
|
|
@ -124,6 +127,44 @@ typedef enum {
|
|||
LLVMDWARFEmissionLineTablesOnly
|
||||
} LLVMDWARFEmissionKind;
|
||||
|
||||
/**
|
||||
* The kind of metadata nodes.
|
||||
*/
|
||||
enum {
|
||||
LLVMMDStringMetadataKind,
|
||||
LLVMConstantAsMetadataMetadataKind,
|
||||
LLVMLocalAsMetadataMetadataKind,
|
||||
LLVMDistinctMDOperandPlaceholderMetadataKind,
|
||||
LLVMMDTupleMetadataKind,
|
||||
LLVMDILocationMetadataKind,
|
||||
LLVMDIExpressionMetadataKind,
|
||||
LLVMDIGlobalVariableExpressionMetadataKind,
|
||||
LLVMGenericDINodeMetadataKind,
|
||||
LLVMDISubrangeMetadataKind,
|
||||
LLVMDIEnumeratorMetadataKind,
|
||||
LLVMDIBasicTypeMetadataKind,
|
||||
LLVMDIDerivedTypeMetadataKind,
|
||||
LLVMDICompositeTypeMetadataKind,
|
||||
LLVMDISubroutineTypeMetadataKind,
|
||||
LLVMDIFileMetadataKind,
|
||||
LLVMDICompileUnitMetadataKind,
|
||||
LLVMDISubprogramMetadataKind,
|
||||
LLVMDILexicalBlockMetadataKind,
|
||||
LLVMDILexicalBlockFileMetadataKind,
|
||||
LLVMDINamespaceMetadataKind,
|
||||
LLVMDIModuleMetadataKind,
|
||||
LLVMDITemplateTypeParameterMetadataKind,
|
||||
LLVMDITemplateValueParameterMetadataKind,
|
||||
LLVMDIGlobalVariableMetadataKind,
|
||||
LLVMDILocalVariableMetadataKind,
|
||||
LLVMDILabelMetadataKind,
|
||||
LLVMDIObjCPropertyMetadataKind,
|
||||
LLVMDIImportedEntityMetadataKind,
|
||||
LLVMDIMacroMetadataKind,
|
||||
LLVMDIMacroFileMetadataKind
|
||||
};
|
||||
typedef unsigned LLVMMetadataKind;
|
||||
|
||||
/**
|
||||
* An LLVM DWARF type encoding.
|
||||
*/
|
||||
|
|
@ -531,11 +572,13 @@ LLVMDIBuilderCreateUnspecifiedType(LLVMDIBuilderRef Builder, const char *Name,
|
|||
* \param NameLen Length of type name.
|
||||
* \param SizeInBits Size of the type.
|
||||
* \param Encoding DWARF encoding code, e.g. \c LLVMDWARFTypeEncoding_float.
|
||||
* \param Flags Flags to encode optional attribute like endianity
|
||||
*/
|
||||
LLVMMetadataRef
|
||||
LLVMDIBuilderCreateBasicType(LLVMDIBuilderRef Builder, const char *Name,
|
||||
size_t NameLen, uint64_t SizeInBits,
|
||||
LLVMDWARFTypeEncoding Encoding);
|
||||
LLVMDWARFTypeEncoding Encoding,
|
||||
LLVMDIFlags Flags);
|
||||
|
||||
/**
|
||||
* Create debugging information entry for a pointer.
|
||||
|
|
@ -965,21 +1008,15 @@ LLVMDIBuilderCreateConstantValueExpression(LLVMDIBuilderRef Builder,
|
|||
* \param Expr The location of the global relative to the attached
|
||||
* GlobalVariable.
|
||||
* \param Decl Reference to the corresponding declaration.
|
||||
* variables.
|
||||
* \param AlignInBits Variable alignment(or 0 if no alignment attr was
|
||||
* specified)
|
||||
*/
|
||||
LLVMMetadataRef
|
||||
LLVMDIBuilderCreateGlobalVariableExpression(LLVMDIBuilderRef Builder,
|
||||
LLVMMetadataRef Scope,
|
||||
const char *Name, size_t NameLen,
|
||||
const char *Linkage, size_t LinkLen,
|
||||
LLVMMetadataRef File,
|
||||
unsigned LineNo,
|
||||
LLVMMetadataRef Ty,
|
||||
LLVMBool LocalToUnit,
|
||||
LLVMMetadataRef Expr,
|
||||
LLVMMetadataRef Decl,
|
||||
uint32_t AlignInBits);
|
||||
LLVMMetadataRef LLVMDIBuilderCreateGlobalVariableExpression(
|
||||
LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name,
|
||||
size_t NameLen, const char *Linkage, size_t LinkLen, LLVMMetadataRef File,
|
||||
unsigned LineNo, LLVMMetadataRef Ty, LLVMBool LocalToUnit,
|
||||
LLVMMetadataRef Expr, LLVMMetadataRef Decl, uint32_t AlignInBits);
|
||||
/**
|
||||
* Create a new temporary \c MDNode. Suitable for use in constructing cyclic
|
||||
* \c MDNode structures. A temporary \c MDNode is not uniqued, may be RAUW'd,
|
||||
|
|
@ -1025,17 +1062,11 @@ void LLVMMetadataReplaceAllUsesWith(LLVMMetadataRef TempTargetMetadata,
|
|||
* \param AlignInBits Variable alignment(or 0 if no alignment attr was
|
||||
* specified)
|
||||
*/
|
||||
LLVMMetadataRef
|
||||
LLVMDIBuilderCreateTempGlobalVariableFwdDecl(LLVMDIBuilderRef Builder,
|
||||
LLVMMetadataRef Scope,
|
||||
const char *Name, size_t NameLen,
|
||||
const char *Linkage, size_t LnkLen,
|
||||
LLVMMetadataRef File,
|
||||
unsigned LineNo,
|
||||
LLVMMetadataRef Ty,
|
||||
LLVMBool LocalToUnit,
|
||||
LLVMMetadataRef Decl,
|
||||
uint32_t AlignInBits);
|
||||
LLVMMetadataRef LLVMDIBuilderCreateTempGlobalVariableFwdDecl(
|
||||
LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name,
|
||||
size_t NameLen, const char *Linkage, size_t LnkLen, LLVMMetadataRef File,
|
||||
unsigned LineNo, LLVMMetadataRef Ty, LLVMBool LocalToUnit,
|
||||
LLVMMetadataRef Decl, uint32_t AlignInBits);
|
||||
|
||||
/**
|
||||
* Insert a new llvm.dbg.declare intrinsic call before the given instruction.
|
||||
|
|
@ -1149,6 +1180,13 @@ LLVMMetadataRef LLVMGetSubprogram(LLVMValueRef Func);
|
|||
*/
|
||||
void LLVMSetSubprogram(LLVMValueRef Func, LLVMMetadataRef SP);
|
||||
|
||||
/**
|
||||
* Obtain the enumerated type of a Metadata instance.
|
||||
*
|
||||
* @see llvm::Metadata::getMetadataID()
|
||||
*/
|
||||
LLVMMetadataKind LLVMGetMetadataKind(LLVMMetadataRef Metadata);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* end extern "C" */
|
||||
#endif
|
||||
|
|
|
|||
69
contrib/llvm/include/llvm-c/Error.h
Normal file
69
contrib/llvm/include/llvm-c/Error.h
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
/*===------- llvm-c/Error.h - llvm::Error class C Interface -------*- 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 C interface to LLVM's Error class. *|
|
||||
|* *|
|
||||
\*===----------------------------------------------------------------------===*/
|
||||
|
||||
#ifndef LLVM_C_ERROR_H
|
||||
#define LLVM_C_ERROR_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define LLVMErrorSuccess 0
|
||||
|
||||
/**
|
||||
* Opaque reference to an error instance. Null serves as the 'success' value.
|
||||
*/
|
||||
typedef struct LLVMOpaqueError *LLVMErrorRef;
|
||||
|
||||
/**
|
||||
* Error type identifier.
|
||||
*/
|
||||
typedef const void *LLVMErrorTypeId;
|
||||
|
||||
/**
|
||||
* Returns the type id for the given error instance, which must be a failure
|
||||
* value (i.e. non-null).
|
||||
*/
|
||||
LLVMErrorTypeId LLVMGetErrorTypeId(LLVMErrorRef Err);
|
||||
|
||||
/**
|
||||
* Dispose of the given error without handling it. This operation consumes the
|
||||
* error, and the given LLVMErrorRef value is not usable once this call returns.
|
||||
* Note: This method *only* needs to be called if the error is not being passed
|
||||
* to some other consuming operation, e.g. LLVMGetErrorMessage.
|
||||
*/
|
||||
void LLVMConsumeError(LLVMErrorRef Err);
|
||||
|
||||
/**
|
||||
* Returns the given string's error message. This operation consumes the error,
|
||||
* and the given LLVMErrorRef value is not usable once this call returns.
|
||||
* The caller is responsible for disposing of the string by calling
|
||||
* LLVMDisposeErrorMessage.
|
||||
*/
|
||||
char *LLVMGetErrorMessage(LLVMErrorRef Err);
|
||||
|
||||
/**
|
||||
* Dispose of the given error message.
|
||||
*/
|
||||
void LLVMDisposeErrorMessage(char *ErrMsg);
|
||||
|
||||
/**
|
||||
* Returns the type id for llvm StringError.
|
||||
*/
|
||||
LLVMErrorTypeId LLVMGetStringErrorTypeId();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -186,7 +186,7 @@ void LLVMDisposeMCJITMemoryManager(LLVMMCJITMemoryManagerRef MM);
|
|||
|
||||
LLVMJITEventListenerRef LLVMCreateGDBRegistrationListener(void);
|
||||
LLVMJITEventListenerRef LLVMCreateIntelJITEventListener(void);
|
||||
LLVMJITEventListenerRef LLVMCreateOprofileJITEventListener(void);
|
||||
LLVMJITEventListenerRef LLVMCreateOProfileJITEventListener(void);
|
||||
LLVMJITEventListenerRef LLVMCreatePerfJITEventListener(void);
|
||||
|
||||
/**
|
||||
|
|
|
|||
204
contrib/llvm/include/llvm-c/OptRemarks.h
Normal file
204
contrib/llvm/include/llvm-c/OptRemarks.h
Normal file
|
|
@ -0,0 +1,204 @@
|
|||
/*===-- llvm-c/OptRemarks.h - OptRemarks Public C Interface -------*- C -*-===*\
|
||||
|* *|
|
||||
|* The LLVM Compiler Infrastructure *|
|
||||
|* *|
|
||||
|* This file is distributed under the University of Illinois Open Source *|
|
||||
|* License. See LICENSE.TXT for details. *|
|
||||
|* *|
|
||||
|*===----------------------------------------------------------------------===*|
|
||||
|* *|
|
||||
|* This header provides a public interface to an opt-remark library. *|
|
||||
|* LLVM provides an implementation of this interface. *|
|
||||
|* *|
|
||||
\*===----------------------------------------------------------------------===*/
|
||||
|
||||
#ifndef LLVM_C_OPT_REMARKS_H
|
||||
#define LLVM_C_OPT_REMARKS_H
|
||||
|
||||
#include "llvm-c/Core.h"
|
||||
#include "llvm-c/Types.h"
|
||||
#ifdef __cplusplus
|
||||
#include <cstddef>
|
||||
extern "C" {
|
||||
#else
|
||||
#include <stddef.h>
|
||||
#endif /* !defined(__cplusplus) */
|
||||
|
||||
/**
|
||||
* @defgroup LLVMCOPTREMARKS OptRemarks
|
||||
* @ingroup LLVMC
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
#define OPT_REMARKS_API_VERSION 0
|
||||
|
||||
/**
|
||||
* String containing a buffer and a length. The buffer is not guaranteed to be
|
||||
* zero-terminated.
|
||||
*
|
||||
* \since OPT_REMARKS_API_VERSION=0
|
||||
*/
|
||||
typedef struct {
|
||||
const char *Str;
|
||||
uint32_t Len;
|
||||
} LLVMOptRemarkStringRef;
|
||||
|
||||
/**
|
||||
* DebugLoc containing File, Line and Column.
|
||||
*
|
||||
* \since OPT_REMARKS_API_VERSION=0
|
||||
*/
|
||||
typedef struct {
|
||||
// File:
|
||||
LLVMOptRemarkStringRef SourceFile;
|
||||
// Line:
|
||||
uint32_t SourceLineNumber;
|
||||
// Column:
|
||||
uint32_t SourceColumnNumber;
|
||||
} LLVMOptRemarkDebugLoc;
|
||||
|
||||
/**
|
||||
* Element of the "Args" list. The key might give more information about what
|
||||
* are the semantics of the value, e.g. "Callee" will tell you that the value
|
||||
* is a symbol that names a function.
|
||||
*
|
||||
* \since OPT_REMARKS_API_VERSION=0
|
||||
*/
|
||||
typedef struct {
|
||||
// e.g. "Callee"
|
||||
LLVMOptRemarkStringRef Key;
|
||||
// e.g. "malloc"
|
||||
LLVMOptRemarkStringRef Value;
|
||||
|
||||
// "DebugLoc": Optional
|
||||
LLVMOptRemarkDebugLoc DebugLoc;
|
||||
} LLVMOptRemarkArg;
|
||||
|
||||
/**
|
||||
* One remark entry.
|
||||
*
|
||||
* \since OPT_REMARKS_API_VERSION=0
|
||||
*/
|
||||
typedef struct {
|
||||
// e.g. !Missed, !Passed
|
||||
LLVMOptRemarkStringRef RemarkType;
|
||||
// "Pass": Required
|
||||
LLVMOptRemarkStringRef PassName;
|
||||
// "Name": Required
|
||||
LLVMOptRemarkStringRef RemarkName;
|
||||
// "Function": Required
|
||||
LLVMOptRemarkStringRef FunctionName;
|
||||
|
||||
// "DebugLoc": Optional
|
||||
LLVMOptRemarkDebugLoc DebugLoc;
|
||||
// "Hotness": Optional
|
||||
uint32_t Hotness;
|
||||
// "Args": Optional. It is an array of `num_args` elements.
|
||||
uint32_t NumArgs;
|
||||
LLVMOptRemarkArg *Args;
|
||||
} LLVMOptRemarkEntry;
|
||||
|
||||
typedef struct LLVMOptRemarkOpaqueParser *LLVMOptRemarkParserRef;
|
||||
|
||||
/**
|
||||
* Creates a remark parser that can be used to read and parse the buffer located
|
||||
* in \p Buf of size \p Size.
|
||||
*
|
||||
* \p Buf cannot be NULL.
|
||||
*
|
||||
* This function should be paired with LLVMOptRemarkParserDispose() to avoid
|
||||
* leaking resources.
|
||||
*
|
||||
* \since OPT_REMARKS_API_VERSION=0
|
||||
*/
|
||||
extern LLVMOptRemarkParserRef LLVMOptRemarkParserCreate(const void *Buf,
|
||||
uint64_t Size);
|
||||
|
||||
/**
|
||||
* Returns the next remark in the file.
|
||||
*
|
||||
* The value pointed to by the return value is invalidated by the next call to
|
||||
* LLVMOptRemarkParserGetNext().
|
||||
*
|
||||
* If the parser reaches the end of the buffer, the return value will be NULL.
|
||||
*
|
||||
* In the case of an error, the return value will be NULL, and:
|
||||
*
|
||||
* 1) LLVMOptRemarkParserHasError() will return `1`.
|
||||
*
|
||||
* 2) LLVMOptRemarkParserGetErrorMessage() will return a descriptive error
|
||||
* message.
|
||||
*
|
||||
* An error may occur if:
|
||||
*
|
||||
* 1) An argument is invalid.
|
||||
*
|
||||
* 2) There is a YAML parsing error. This type of error aborts parsing
|
||||
* immediately and returns `1`. It can occur on malformed YAML.
|
||||
*
|
||||
* 3) Remark parsing error. If this type of error occurs, the parser won't call
|
||||
* the handler and will continue to the next one. It can occur on malformed
|
||||
* remarks, like missing or extra fields in the file.
|
||||
*
|
||||
* Here is a quick example of the usage:
|
||||
*
|
||||
* ```
|
||||
* LLVMOptRemarkParserRef Parser = LLVMOptRemarkParserCreate(Buf, Size);
|
||||
* LLVMOptRemarkEntry *Remark = NULL;
|
||||
* while ((Remark == LLVMOptRemarkParserGetNext(Parser))) {
|
||||
* // use Remark
|
||||
* }
|
||||
* bool HasError = LLVMOptRemarkParserHasError(Parser);
|
||||
* LLVMOptRemarkParserDispose(Parser);
|
||||
* ```
|
||||
*
|
||||
* \since OPT_REMARKS_API_VERSION=0
|
||||
*/
|
||||
extern LLVMOptRemarkEntry *
|
||||
LLVMOptRemarkParserGetNext(LLVMOptRemarkParserRef Parser);
|
||||
|
||||
/**
|
||||
* Returns `1` if the parser encountered an error while parsing the buffer.
|
||||
*
|
||||
* \since OPT_REMARKS_API_VERSION=0
|
||||
*/
|
||||
extern LLVMBool LLVMOptRemarkParserHasError(LLVMOptRemarkParserRef Parser);
|
||||
|
||||
/**
|
||||
* Returns a null-terminated string containing an error message.
|
||||
*
|
||||
* In case of no error, the result is `NULL`.
|
||||
*
|
||||
* The memory of the string is bound to the lifetime of \p Parser. If
|
||||
* LLVMOptRemarkParserDispose() is called, the memory of the string will be
|
||||
* released.
|
||||
*
|
||||
* \since OPT_REMARKS_API_VERSION=0
|
||||
*/
|
||||
extern const char *
|
||||
LLVMOptRemarkParserGetErrorMessage(LLVMOptRemarkParserRef Parser);
|
||||
|
||||
/**
|
||||
* Releases all the resources used by \p Parser.
|
||||
*
|
||||
* \since OPT_REMARKS_API_VERSION=0
|
||||
*/
|
||||
extern void LLVMOptRemarkParserDispose(LLVMOptRemarkParserRef Parser);
|
||||
|
||||
/**
|
||||
* Returns the version of the opt-remarks dylib.
|
||||
*
|
||||
* \since OPT_REMARKS_API_VERSION=0
|
||||
*/
|
||||
extern uint32_t LLVMOptRemarkVersion(void);
|
||||
|
||||
/**
|
||||
* @} // endgoup LLVMCOPTREMARKS
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* !defined(__cplusplus) */
|
||||
|
||||
#endif /* LLVM_C_OPT_REMARKS_H */
|
||||
|
|
@ -22,6 +22,7 @@
|
|||
#ifndef LLVM_C_ORCBINDINGS_H
|
||||
#define LLVM_C_ORCBINDINGS_H
|
||||
|
||||
#include "llvm-c/Error.h"
|
||||
#include "llvm-c/Object.h"
|
||||
#include "llvm-c/TargetMachine.h"
|
||||
|
||||
|
|
@ -36,8 +37,6 @@ typedef uint64_t (*LLVMOrcSymbolResolverFn)(const char *Name, void *LookupCtx);
|
|||
typedef uint64_t (*LLVMOrcLazyCompileCallbackFn)(LLVMOrcJITStackRef JITStack,
|
||||
void *CallbackCtx);
|
||||
|
||||
typedef enum { LLVMOrcErrSuccess = 0, LLVMOrcErrGeneric } LLVMOrcErrorCode;
|
||||
|
||||
/**
|
||||
* Create an ORC JIT stack.
|
||||
*
|
||||
|
|
@ -72,43 +71,41 @@ void LLVMOrcDisposeMangledSymbol(char *MangledSymbol);
|
|||
/**
|
||||
* Create a lazy compile callback.
|
||||
*/
|
||||
LLVMOrcErrorCode
|
||||
LLVMOrcCreateLazyCompileCallback(LLVMOrcJITStackRef JITStack,
|
||||
LLVMOrcTargetAddress *RetAddr,
|
||||
LLVMOrcLazyCompileCallbackFn Callback,
|
||||
void *CallbackCtx);
|
||||
LLVMErrorRef LLVMOrcCreateLazyCompileCallback(
|
||||
LLVMOrcJITStackRef JITStack, LLVMOrcTargetAddress *RetAddr,
|
||||
LLVMOrcLazyCompileCallbackFn Callback, void *CallbackCtx);
|
||||
|
||||
/**
|
||||
* Create a named indirect call stub.
|
||||
*/
|
||||
LLVMOrcErrorCode LLVMOrcCreateIndirectStub(LLVMOrcJITStackRef JITStack,
|
||||
const char *StubName,
|
||||
LLVMOrcTargetAddress InitAddr);
|
||||
LLVMErrorRef LLVMOrcCreateIndirectStub(LLVMOrcJITStackRef JITStack,
|
||||
const char *StubName,
|
||||
LLVMOrcTargetAddress InitAddr);
|
||||
|
||||
/**
|
||||
* Set the pointer for the given indirect stub.
|
||||
*/
|
||||
LLVMOrcErrorCode LLVMOrcSetIndirectStubPointer(LLVMOrcJITStackRef JITStack,
|
||||
const char *StubName,
|
||||
LLVMOrcTargetAddress NewAddr);
|
||||
LLVMErrorRef LLVMOrcSetIndirectStubPointer(LLVMOrcJITStackRef JITStack,
|
||||
const char *StubName,
|
||||
LLVMOrcTargetAddress NewAddr);
|
||||
|
||||
/**
|
||||
* Add module to be eagerly compiled.
|
||||
*/
|
||||
LLVMOrcErrorCode
|
||||
LLVMOrcAddEagerlyCompiledIR(LLVMOrcJITStackRef JITStack,
|
||||
LLVMOrcModuleHandle *RetHandle, LLVMModuleRef Mod,
|
||||
LLVMOrcSymbolResolverFn SymbolResolver,
|
||||
void *SymbolResolverCtx);
|
||||
LLVMErrorRef LLVMOrcAddEagerlyCompiledIR(LLVMOrcJITStackRef JITStack,
|
||||
LLVMOrcModuleHandle *RetHandle,
|
||||
LLVMModuleRef Mod,
|
||||
LLVMOrcSymbolResolverFn SymbolResolver,
|
||||
void *SymbolResolverCtx);
|
||||
|
||||
/**
|
||||
* Add module to be lazily compiled one function at a time.
|
||||
*/
|
||||
LLVMOrcErrorCode
|
||||
LLVMOrcAddLazilyCompiledIR(LLVMOrcJITStackRef JITStack,
|
||||
LLVMOrcModuleHandle *RetHandle, LLVMModuleRef Mod,
|
||||
LLVMOrcSymbolResolverFn SymbolResolver,
|
||||
void *SymbolResolverCtx);
|
||||
LLVMErrorRef LLVMOrcAddLazilyCompiledIR(LLVMOrcJITStackRef JITStack,
|
||||
LLVMOrcModuleHandle *RetHandle,
|
||||
LLVMModuleRef Mod,
|
||||
LLVMOrcSymbolResolverFn SymbolResolver,
|
||||
void *SymbolResolverCtx);
|
||||
|
||||
/**
|
||||
* Add an object file.
|
||||
|
|
@ -118,11 +115,11 @@ LLVMOrcAddLazilyCompiledIR(LLVMOrcJITStackRef JITStack,
|
|||
* Clients should *not* dispose of the 'Obj' argument: the JIT will manage it
|
||||
* from this call onwards.
|
||||
*/
|
||||
LLVMOrcErrorCode LLVMOrcAddObjectFile(LLVMOrcJITStackRef JITStack,
|
||||
LLVMOrcModuleHandle *RetHandle,
|
||||
LLVMMemoryBufferRef Obj,
|
||||
LLVMOrcSymbolResolverFn SymbolResolver,
|
||||
void *SymbolResolverCtx);
|
||||
LLVMErrorRef LLVMOrcAddObjectFile(LLVMOrcJITStackRef JITStack,
|
||||
LLVMOrcModuleHandle *RetHandle,
|
||||
LLVMMemoryBufferRef Obj,
|
||||
LLVMOrcSymbolResolverFn SymbolResolver,
|
||||
void *SymbolResolverCtx);
|
||||
|
||||
/**
|
||||
* Remove a module set from the JIT.
|
||||
|
|
@ -130,29 +127,29 @@ LLVMOrcErrorCode LLVMOrcAddObjectFile(LLVMOrcJITStackRef JITStack,
|
|||
* This works for all modules that can be added via OrcAdd*, including object
|
||||
* files.
|
||||
*/
|
||||
LLVMOrcErrorCode LLVMOrcRemoveModule(LLVMOrcJITStackRef JITStack,
|
||||
LLVMOrcModuleHandle H);
|
||||
LLVMErrorRef LLVMOrcRemoveModule(LLVMOrcJITStackRef JITStack,
|
||||
LLVMOrcModuleHandle H);
|
||||
|
||||
/**
|
||||
* Get symbol address from JIT instance.
|
||||
*/
|
||||
LLVMOrcErrorCode LLVMOrcGetSymbolAddress(LLVMOrcJITStackRef JITStack,
|
||||
LLVMOrcTargetAddress *RetAddr,
|
||||
const char *SymbolName);
|
||||
LLVMErrorRef LLVMOrcGetSymbolAddress(LLVMOrcJITStackRef JITStack,
|
||||
LLVMOrcTargetAddress *RetAddr,
|
||||
const char *SymbolName);
|
||||
|
||||
/**
|
||||
* Get symbol address from JIT instance, searching only the specified
|
||||
* handle.
|
||||
*/
|
||||
LLVMOrcErrorCode LLVMOrcGetSymbolAddressIn(LLVMOrcJITStackRef JITStack,
|
||||
LLVMOrcTargetAddress *RetAddr,
|
||||
LLVMOrcModuleHandle H,
|
||||
const char *SymbolName);
|
||||
LLVMErrorRef LLVMOrcGetSymbolAddressIn(LLVMOrcJITStackRef JITStack,
|
||||
LLVMOrcTargetAddress *RetAddr,
|
||||
LLVMOrcModuleHandle H,
|
||||
const char *SymbolName);
|
||||
|
||||
/**
|
||||
* Dispose of an ORC JIT stack.
|
||||
*/
|
||||
LLVMOrcErrorCode LLVMOrcDisposeInstance(LLVMOrcJITStackRef JITStack);
|
||||
LLVMErrorRef LLVMOrcDisposeInstance(LLVMOrcJITStackRef JITStack);
|
||||
|
||||
/**
|
||||
* Register a JIT Event Listener.
|
||||
|
|
|
|||
|
|
@ -39,12 +39,16 @@ typedef enum {
|
|||
LLVMRelocDefault,
|
||||
LLVMRelocStatic,
|
||||
LLVMRelocPIC,
|
||||
LLVMRelocDynamicNoPic
|
||||
LLVMRelocDynamicNoPic,
|
||||
LLVMRelocROPI,
|
||||
LLVMRelocRWPI,
|
||||
LLVMRelocROPI_RWPI
|
||||
} LLVMRelocMode;
|
||||
|
||||
typedef enum {
|
||||
LLVMCodeModelDefault,
|
||||
LLVMCodeModelJITDefault,
|
||||
LLVMCodeModelTiny,
|
||||
LLVMCodeModelSmall,
|
||||
LLVMCodeModelKernel,
|
||||
LLVMCodeModelMedium,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,43 @@
|
|||
/*===-- AggressiveInstCombine.h ---------------------------------*- C++ -*-===*\
|
||||
|* *|
|
||||
|* The LLVM Compiler Infrastructure *|
|
||||
|* *|
|
||||
|* This file is distributed under the University of Illinois Open Source *|
|
||||
|* License. See LICENSE.TXT for details. *|
|
||||
|* *|
|
||||
|*===----------------------------------------------------------------------===*|
|
||||
|* *|
|
||||
|* This header declares the C interface to libLLVMAggressiveInstCombine.a, *|
|
||||
|* which combines instructions to form fewer, simple IR instructions. *|
|
||||
|* *|
|
||||
\*===----------------------------------------------------------------------===*/
|
||||
|
||||
#ifndef LLVM_C_TRANSFORMS_AGGRESSIVEINSTCOMBINE_H
|
||||
#define LLVM_C_TRANSFORMS_AGGRESSIVEINSTCOMBINE_H
|
||||
|
||||
#include "llvm-c/Types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @defgroup LLVMCTransformsAggressiveInstCombine Aggressive Instruction Combining transformations
|
||||
* @ingroup LLVMCTransforms
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** See llvm::createAggressiveInstCombinerPass function. */
|
||||
void LLVMAddAggressiveInstCombinerPass(LLVMPassManagerRef PM);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* defined(__cplusplus) */
|
||||
|
||||
#endif
|
||||
|
||||
55
contrib/llvm/include/llvm-c/Transforms/Coroutines.h
Normal file
55
contrib/llvm/include/llvm-c/Transforms/Coroutines.h
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
/*===-- Coroutines.h - Coroutines Library C Interface -----------*- C++ -*-===*\
|
||||
|* *|
|
||||
|* The LLVM Compiler Infrastructure *|
|
||||
|* *|
|
||||
|* This file is distributed under the University of Illinois Open Source *|
|
||||
|* License. See LICENSE.TXT for details. *|
|
||||
|* *|
|
||||
|*===----------------------------------------------------------------------===*|
|
||||
|* *|
|
||||
|* This header declares the C interface to libLLVMCoroutines.a, which *|
|
||||
|* implements various scalar transformations of the LLVM IR. *|
|
||||
|* *|
|
||||
|* Many exotic languages can interoperate with C code but have a harder time *|
|
||||
|* with C++ due to name mangling. So in addition to C, this interface enables *|
|
||||
|* tools written in such languages. *|
|
||||
|* *|
|
||||
\*===----------------------------------------------------------------------===*/
|
||||
|
||||
#ifndef LLVM_C_TRANSFORMS_COROUTINES_H
|
||||
#define LLVM_C_TRANSFORMS_COROUTINES_H
|
||||
|
||||
#include "llvm-c/Types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @defgroup LLVMCTransformsCoroutines Coroutine transformations
|
||||
* @ingroup LLVMCTransforms
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** See llvm::createCoroEarlyPass function. */
|
||||
void LLVMAddCoroEarlyPass(LLVMPassManagerRef PM);
|
||||
|
||||
/** See llvm::createCoroSplitPass function. */
|
||||
void LLVMAddCoroSplitPass(LLVMPassManagerRef PM);
|
||||
|
||||
/** See llvm::createCoroElidePass function. */
|
||||
void LLVMAddCoroElidePass(LLVMPassManagerRef PM);
|
||||
|
||||
/** See llvm::createCoroCleanupPass function. */
|
||||
void LLVMAddCoroCleanupPass(LLVMPassManagerRef PM);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* defined(__cplusplus) */
|
||||
|
||||
#endif
|
||||
|
|
@ -35,9 +35,6 @@ extern "C" {
|
|||
/** See llvm::createAggressiveDCEPass function. */
|
||||
void LLVMAddAggressiveDCEPass(LLVMPassManagerRef PM);
|
||||
|
||||
/** See llvm::createAggressiveInstCombinerPass function. */
|
||||
void LLVMAddAggressiveInstCombinerPass(LLVMPassManagerRef PM);
|
||||
|
||||
/** See llvm::createBitTrackingDCEPass function. */
|
||||
void LLVMAddBitTrackingDCEPass(LLVMPassManagerRef PM);
|
||||
|
||||
|
|
@ -95,6 +92,9 @@ void LLVMAddLoopUnrollAndJamPass(LLVMPassManagerRef PM);
|
|||
/** See llvm::createLoopUnswitchPass function. */
|
||||
void LLVMAddLoopUnswitchPass(LLVMPassManagerRef PM);
|
||||
|
||||
/** See llvm::createLowerAtomicPass function. */
|
||||
void LLVMAddLowerAtomicPass(LLVMPassManagerRef PM);
|
||||
|
||||
/** See llvm::createMemCpyOptPass function. */
|
||||
void LLVMAddMemCpyOptPass(LLVMPassManagerRef PM);
|
||||
|
||||
|
|
@ -153,6 +153,9 @@ void LLVMAddScopedNoAliasAAPass(LLVMPassManagerRef PM);
|
|||
/** See llvm::createBasicAliasAnalysisPass function */
|
||||
void LLVMAddBasicAliasAnalysisPass(LLVMPassManagerRef PM);
|
||||
|
||||
/** See llvm::createUnifyFunctionExitNodesPass function */
|
||||
void LLVMAddUnifyFunctionExitNodesPass(LLVMPassManagerRef PM);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -89,6 +89,20 @@ typedef struct LLVMOpaqueBasicBlock *LLVMBasicBlockRef;
|
|||
*/
|
||||
typedef struct LLVMOpaqueMetadata *LLVMMetadataRef;
|
||||
|
||||
/**
|
||||
* Represents an LLVM Named Metadata Node.
|
||||
*
|
||||
* This models llvm::NamedMDNode.
|
||||
*/
|
||||
typedef struct LLVMOpaqueNamedMDNode *LLVMNamedMDNodeRef;
|
||||
|
||||
/**
|
||||
* Represents an entry in a Global Object's metadata attachments.
|
||||
*
|
||||
* This models std::pair<unsigned, MDNode *>
|
||||
*/
|
||||
typedef struct LLVMOpaqueValueMetadataEntry LLVMValueMetadataEntry;
|
||||
|
||||
/**
|
||||
* Represents an LLVM basic block builder.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ typedef bool lto_bool_t;
|
|||
* @{
|
||||
*/
|
||||
|
||||
#define LTO_API_VERSION 22
|
||||
#define LTO_API_VERSION 23
|
||||
|
||||
/**
|
||||
* \since prior to LTO_API_VERSION=3
|
||||
|
|
@ -827,6 +827,16 @@ extern void thinlto_codegen_set_cache_entry_expiration(thinlto_code_gen_t cg,
|
|||
extern void thinlto_codegen_set_cache_size_bytes(thinlto_code_gen_t cg,
|
||||
unsigned max_size_bytes);
|
||||
|
||||
/**
|
||||
* Same as thinlto_codegen_set_cache_size_bytes, except the maximum size is in
|
||||
* megabytes (2^20 bytes).
|
||||
*
|
||||
* \since LTO_API_VERSION=23
|
||||
*/
|
||||
extern void
|
||||
thinlto_codegen_set_cache_size_megabytes(thinlto_code_gen_t cg,
|
||||
unsigned max_size_megabytes);
|
||||
|
||||
/**
|
||||
* Sets the maximum number of files in the cache directory. An unspecified
|
||||
* default value will be applied. A value of 0 will be ignored.
|
||||
|
|
|
|||
|
|
@ -870,13 +870,13 @@ public:
|
|||
/// Factory for NaN values.
|
||||
///
|
||||
/// \param Negative - True iff the NaN generated should be negative.
|
||||
/// \param type - The unspecified fill bits for creating the NaN, 0 by
|
||||
/// \param payload - The unspecified fill bits for creating the NaN, 0 by
|
||||
/// default. The value is truncated as necessary.
|
||||
static APFloat getNaN(const fltSemantics &Sem, bool Negative = false,
|
||||
unsigned type = 0) {
|
||||
if (type) {
|
||||
APInt fill(64, type);
|
||||
return getQNaN(Sem, Negative, &fill);
|
||||
uint64_t payload = 0) {
|
||||
if (payload) {
|
||||
APInt intPayload(64, payload);
|
||||
return getQNaN(Sem, Negative, &intPayload);
|
||||
} else {
|
||||
return getQNaN(Sem, Negative, nullptr);
|
||||
}
|
||||
|
|
@ -1243,6 +1243,32 @@ inline APFloat maxnum(const APFloat &A, const APFloat &B) {
|
|||
return (A.compare(B) == APFloat::cmpLessThan) ? B : A;
|
||||
}
|
||||
|
||||
/// Implements IEEE 754-2018 minimum semantics. Returns the smaller of 2
|
||||
/// arguments, propagating NaNs and treating -0 as less than +0.
|
||||
LLVM_READONLY
|
||||
inline APFloat minimum(const APFloat &A, const APFloat &B) {
|
||||
if (A.isNaN())
|
||||
return A;
|
||||
if (B.isNaN())
|
||||
return B;
|
||||
if (A.isZero() && B.isZero() && (A.isNegative() != B.isNegative()))
|
||||
return A.isNegative() ? A : B;
|
||||
return (B.compare(A) == APFloat::cmpLessThan) ? B : A;
|
||||
}
|
||||
|
||||
/// Implements IEEE 754-2018 maximum semantics. Returns the larger of 2
|
||||
/// arguments, propagating NaNs and treating -0 as less than +0.
|
||||
LLVM_READONLY
|
||||
inline APFloat maximum(const APFloat &A, const APFloat &B) {
|
||||
if (A.isNaN())
|
||||
return A;
|
||||
if (B.isNaN())
|
||||
return B;
|
||||
if (A.isZero() && B.isZero() && (A.isNegative() != B.isNegative()))
|
||||
return A.isNegative() ? B : A;
|
||||
return (A.compare(B) == APFloat::cmpLessThan) ? B : A;
|
||||
}
|
||||
|
||||
} // namespace llvm
|
||||
|
||||
#undef APFLOAT_DISPATCH_ON_SEMANTICS
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ class raw_ostream;
|
|||
|
||||
template <typename T> class SmallVectorImpl;
|
||||
template <typename T> class ArrayRef;
|
||||
template <typename T> class Optional;
|
||||
|
||||
class APInt;
|
||||
|
||||
|
|
@ -84,7 +85,7 @@ public:
|
|||
UP,
|
||||
};
|
||||
|
||||
static const WordType WORD_MAX = ~WordType(0);
|
||||
static const WordType WORDTYPE_MAX = ~WordType(0);
|
||||
|
||||
private:
|
||||
/// This union is used to store the integer value. When the
|
||||
|
|
@ -149,7 +150,7 @@ private:
|
|||
unsigned WordBits = ((BitWidth-1) % APINT_BITS_PER_WORD) + 1;
|
||||
|
||||
// Mask out the high bits.
|
||||
uint64_t mask = WORD_MAX >> (APINT_BITS_PER_WORD - WordBits);
|
||||
uint64_t mask = WORDTYPE_MAX >> (APINT_BITS_PER_WORD - WordBits);
|
||||
if (isSingleWord())
|
||||
U.VAL &= mask;
|
||||
else
|
||||
|
|
@ -394,7 +395,7 @@ public:
|
|||
/// This checks to see if the value has all bits of the APInt are set or not.
|
||||
bool isAllOnesValue() const {
|
||||
if (isSingleWord())
|
||||
return U.VAL == WORD_MAX >> (APINT_BITS_PER_WORD - BitWidth);
|
||||
return U.VAL == WORDTYPE_MAX >> (APINT_BITS_PER_WORD - BitWidth);
|
||||
return countTrailingOnesSlowCase() == BitWidth;
|
||||
}
|
||||
|
||||
|
|
@ -495,7 +496,7 @@ public:
|
|||
assert(numBits != 0 && "numBits must be non-zero");
|
||||
assert(numBits <= BitWidth && "numBits out of range");
|
||||
if (isSingleWord())
|
||||
return U.VAL == (WORD_MAX >> (APINT_BITS_PER_WORD - numBits));
|
||||
return U.VAL == (WORDTYPE_MAX >> (APINT_BITS_PER_WORD - numBits));
|
||||
unsigned Ones = countTrailingOnesSlowCase();
|
||||
return (numBits == Ones) &&
|
||||
((Ones + countLeadingZerosSlowCase()) == BitWidth);
|
||||
|
|
@ -559,7 +560,7 @@ public:
|
|||
///
|
||||
/// \returns the all-ones value for an APInt of the specified bit-width.
|
||||
static APInt getAllOnesValue(unsigned numBits) {
|
||||
return APInt(numBits, WORD_MAX, true);
|
||||
return APInt(numBits, WORDTYPE_MAX, true);
|
||||
}
|
||||
|
||||
/// Get the '0' value.
|
||||
|
|
@ -1104,6 +1105,12 @@ public:
|
|||
APInt sshl_ov(const APInt &Amt, bool &Overflow) const;
|
||||
APInt ushl_ov(const APInt &Amt, bool &Overflow) const;
|
||||
|
||||
// Operations that saturate
|
||||
APInt sadd_sat(const APInt &RHS) const;
|
||||
APInt uadd_sat(const APInt &RHS) const;
|
||||
APInt ssub_sat(const APInt &RHS) const;
|
||||
APInt usub_sat(const APInt &RHS) const;
|
||||
|
||||
/// Array-indexing support.
|
||||
///
|
||||
/// \returns the bit value at bitPosition
|
||||
|
|
@ -1382,7 +1389,7 @@ public:
|
|||
/// Set every bit to 1.
|
||||
void setAllBits() {
|
||||
if (isSingleWord())
|
||||
U.VAL = WORD_MAX;
|
||||
U.VAL = WORDTYPE_MAX;
|
||||
else
|
||||
// Set all the bits in all the words.
|
||||
memset(U.pVal, -1, getNumWords() * APINT_WORD_SIZE);
|
||||
|
|
@ -1394,7 +1401,7 @@ public:
|
|||
///
|
||||
/// Set the given bit to 1 whose position is given as "bitPosition".
|
||||
void setBit(unsigned BitPosition) {
|
||||
assert(BitPosition <= BitWidth && "BitPosition out of range");
|
||||
assert(BitPosition < BitWidth && "BitPosition out of range");
|
||||
WordType Mask = maskBit(BitPosition);
|
||||
if (isSingleWord())
|
||||
U.VAL |= Mask;
|
||||
|
|
@ -1415,7 +1422,7 @@ public:
|
|||
if (loBit == hiBit)
|
||||
return;
|
||||
if (loBit < APINT_BITS_PER_WORD && hiBit <= APINT_BITS_PER_WORD) {
|
||||
uint64_t mask = WORD_MAX >> (APINT_BITS_PER_WORD - (hiBit - loBit));
|
||||
uint64_t mask = WORDTYPE_MAX >> (APINT_BITS_PER_WORD - (hiBit - loBit));
|
||||
mask <<= loBit;
|
||||
if (isSingleWord())
|
||||
U.VAL |= mask;
|
||||
|
|
@ -1453,7 +1460,7 @@ public:
|
|||
///
|
||||
/// Set the given bit to 0 whose position is given as "bitPosition".
|
||||
void clearBit(unsigned BitPosition) {
|
||||
assert(BitPosition <= BitWidth && "BitPosition out of range");
|
||||
assert(BitPosition < BitWidth && "BitPosition out of range");
|
||||
WordType Mask = ~maskBit(BitPosition);
|
||||
if (isSingleWord())
|
||||
U.VAL &= Mask;
|
||||
|
|
@ -1469,7 +1476,7 @@ public:
|
|||
/// Toggle every bit to its opposite value.
|
||||
void flipAllBits() {
|
||||
if (isSingleWord()) {
|
||||
U.VAL ^= WORD_MAX;
|
||||
U.VAL ^= WORDTYPE_MAX;
|
||||
clearUnusedBits();
|
||||
} else {
|
||||
flipAllBitsSlowCase();
|
||||
|
|
@ -1758,7 +1765,7 @@ public:
|
|||
/// referencing 2 in a space where 2 does no exist.
|
||||
unsigned nearestLogBase2() const {
|
||||
// Special case when we have a bitwidth of 1. If VAL is 1, then we
|
||||
// get 0. If VAL is 0, we get WORD_MAX which gets truncated to
|
||||
// get 0. If VAL is 0, we get WORDTYPE_MAX which gets truncated to
|
||||
// UINT32_MAX.
|
||||
if (BitWidth == 1)
|
||||
return U.VAL - 1;
|
||||
|
|
@ -2166,6 +2173,41 @@ APInt RoundingUDiv(const APInt &A, const APInt &B, APInt::Rounding RM);
|
|||
/// Return A sign-divided by B, rounded by the given rounding mode.
|
||||
APInt RoundingSDiv(const APInt &A, const APInt &B, APInt::Rounding RM);
|
||||
|
||||
/// Let q(n) = An^2 + Bn + C, and BW = bit width of the value range
|
||||
/// (e.g. 32 for i32).
|
||||
/// This function finds the smallest number n, such that
|
||||
/// (a) n >= 0 and q(n) = 0, or
|
||||
/// (b) n >= 1 and q(n-1) and q(n), when evaluated in the set of all
|
||||
/// integers, belong to two different intervals [Rk, Rk+R),
|
||||
/// where R = 2^BW, and k is an integer.
|
||||
/// The idea here is to find when q(n) "overflows" 2^BW, while at the
|
||||
/// same time "allowing" subtraction. In unsigned modulo arithmetic a
|
||||
/// subtraction (treated as addition of negated numbers) would always
|
||||
/// count as an overflow, but here we want to allow values to decrease
|
||||
/// and increase as long as they are within the same interval.
|
||||
/// Specifically, adding of two negative numbers should not cause an
|
||||
/// overflow (as long as the magnitude does not exceed the bith width).
|
||||
/// On the other hand, given a positive number, adding a negative
|
||||
/// number to it can give a negative result, which would cause the
|
||||
/// value to go from [-2^BW, 0) to [0, 2^BW). In that sense, zero is
|
||||
/// treated as a special case of an overflow.
|
||||
///
|
||||
/// This function returns None if after finding k that minimizes the
|
||||
/// positive solution to q(n) = kR, both solutions are contained between
|
||||
/// two consecutive integers.
|
||||
///
|
||||
/// There are cases where q(n) > T, and q(n+1) < T (assuming evaluation
|
||||
/// in arithmetic modulo 2^BW, and treating the values as signed) by the
|
||||
/// virtue of *signed* overflow. This function will *not* find such an n,
|
||||
/// however it may find a value of n satisfying the inequalities due to
|
||||
/// an *unsigned* overflow (if the values are treated as unsigned).
|
||||
/// To find a solution for a signed overflow, treat it as a problem of
|
||||
/// finding an unsigned overflow with a range with of BW-1.
|
||||
///
|
||||
/// The returned value may have a different bit width from the input
|
||||
/// coefficients.
|
||||
Optional<APInt> SolveQuadraticEquationWrap(APInt A, APInt B, APInt C,
|
||||
unsigned RangeWidth);
|
||||
} // End of APIntOps namespace
|
||||
|
||||
// See friend declaration above. This additional declaration is required in
|
||||
|
|
|
|||
|
|
@ -65,6 +65,16 @@ public:
|
|||
typename std::enable_if<
|
||||
llvm::conjunction<
|
||||
llvm::negation<std::is_same<typename std::decay<T>::type, Any>>,
|
||||
// We also disable this overload when an `Any` object can be
|
||||
// converted to the parameter type because in that case, this
|
||||
// constructor may combine with that conversion during overload
|
||||
// resolution for determining copy constructibility, and then
|
||||
// when we try to determine copy constructibility below we may
|
||||
// infinitely recurse. This is being evaluated by the standards
|
||||
// committee as a potential DR in `std::any` as well, but we're
|
||||
// going ahead and adopting it to work-around usage of `Any` with
|
||||
// types that need to be implicitly convertible from an `Any`.
|
||||
llvm::negation<std::is_convertible<Any, typename std::decay<T>::type>>,
|
||||
std::is_copy_constructible<typename std::decay<T>::type>>::value,
|
||||
int>::type = 0>
|
||||
Any(T &&Value) {
|
||||
|
|
|
|||
|
|
@ -503,6 +503,23 @@ public:
|
|||
return (*this)[Idx];
|
||||
}
|
||||
|
||||
// Push single bit to end of vector.
|
||||
void push_back(bool Val) {
|
||||
unsigned OldSize = Size;
|
||||
unsigned NewSize = Size + 1;
|
||||
|
||||
// Resize, which will insert zeros.
|
||||
// If we already fit then the unused bits will be already zero.
|
||||
if (NewSize > getBitCapacity())
|
||||
resize(NewSize, false);
|
||||
else
|
||||
Size = NewSize;
|
||||
|
||||
// If true, set single bit.
|
||||
if (Val)
|
||||
set(OldSize);
|
||||
}
|
||||
|
||||
/// Test if any common bits are set.
|
||||
bool anyCommon(const BitVector &RHS) const {
|
||||
unsigned ThisWords = NumBitWords(size());
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include <initializer_list>
|
||||
#include <iterator>
|
||||
#include <new>
|
||||
#include <type_traits>
|
||||
|
|
@ -38,6 +39,34 @@ namespace detail {
|
|||
// implementation without requiring two members.
|
||||
template <typename KeyT, typename ValueT>
|
||||
struct DenseMapPair : public std::pair<KeyT, ValueT> {
|
||||
|
||||
// FIXME: Switch to inheriting constructors when we drop support for older
|
||||
// clang versions.
|
||||
// NOTE: This default constructor is declared with '{}' rather than
|
||||
// '= default' to work around a separate bug in clang-3.8. This can
|
||||
// also go when we switch to inheriting constructors.
|
||||
DenseMapPair() {}
|
||||
|
||||
DenseMapPair(const KeyT &Key, const ValueT &Value)
|
||||
: std::pair<KeyT, ValueT>(Key, Value) {}
|
||||
|
||||
DenseMapPair(KeyT &&Key, ValueT &&Value)
|
||||
: std::pair<KeyT, ValueT>(std::move(Key), std::move(Value)) {}
|
||||
|
||||
template <typename AltKeyT, typename AltValueT>
|
||||
DenseMapPair(AltKeyT &&AltKey, AltValueT &&AltValue,
|
||||
typename std::enable_if<
|
||||
std::is_convertible<AltKeyT, KeyT>::value &&
|
||||
std::is_convertible<AltValueT, ValueT>::value>::type * = 0)
|
||||
: std::pair<KeyT, ValueT>(std::forward<AltKeyT>(AltKey),
|
||||
std::forward<AltValueT>(AltValue)) {}
|
||||
|
||||
template <typename AltPairT>
|
||||
DenseMapPair(AltPairT &&AltPair,
|
||||
typename std::enable_if<std::is_convertible<
|
||||
AltPairT, std::pair<KeyT, ValueT>>::value>::type * = 0)
|
||||
: std::pair<KeyT, ValueT>(std::forward<AltPairT>(AltPair)) {}
|
||||
|
||||
KeyT &getFirst() { return std::pair<KeyT, ValueT>::first; }
|
||||
const KeyT &getFirst() const { return std::pair<KeyT, ValueT>::first; }
|
||||
ValueT &getSecond() { return std::pair<KeyT, ValueT>::second; }
|
||||
|
|
@ -46,9 +75,10 @@ struct DenseMapPair : public std::pair<KeyT, ValueT> {
|
|||
|
||||
} // end namespace detail
|
||||
|
||||
template <
|
||||
typename KeyT, typename ValueT, typename KeyInfoT = DenseMapInfo<KeyT>,
|
||||
typename Bucket = detail::DenseMapPair<KeyT, ValueT>, bool IsConst = false>
|
||||
template <typename KeyT, typename ValueT,
|
||||
typename KeyInfoT = DenseMapInfo<KeyT>,
|
||||
typename Bucket = llvm::detail::DenseMapPair<KeyT, ValueT>,
|
||||
bool IsConst = false>
|
||||
class DenseMapIterator;
|
||||
|
||||
template <typename DerivedT, typename KeyT, typename ValueT, typename KeyInfoT,
|
||||
|
|
@ -393,7 +423,7 @@ protected:
|
|||
setNumTombstones(other.getNumTombstones());
|
||||
|
||||
if (isPodLike<KeyT>::value && isPodLike<ValueT>::value)
|
||||
memcpy(getBuckets(), other.getBuckets(),
|
||||
memcpy(reinterpret_cast<void *>(getBuckets()), other.getBuckets(),
|
||||
getNumBuckets() * sizeof(BucketT));
|
||||
else
|
||||
for (size_t i = 0; i < getNumBuckets(); ++i) {
|
||||
|
|
@ -639,9 +669,43 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
/// Equality comparison for DenseMap.
|
||||
///
|
||||
/// Iterates over elements of LHS confirming that each (key, value) pair in LHS
|
||||
/// is also in RHS, and that no additional pairs are in RHS.
|
||||
/// Equivalent to N calls to RHS.find and N value comparisons. Amortized
|
||||
/// complexity is linear, worst case is O(N^2) (if every hash collides).
|
||||
template <typename DerivedT, typename KeyT, typename ValueT, typename KeyInfoT,
|
||||
typename BucketT>
|
||||
bool operator==(
|
||||
const DenseMapBase<DerivedT, KeyT, ValueT, KeyInfoT, BucketT> &LHS,
|
||||
const DenseMapBase<DerivedT, KeyT, ValueT, KeyInfoT, BucketT> &RHS) {
|
||||
if (LHS.size() != RHS.size())
|
||||
return false;
|
||||
|
||||
for (auto &KV : LHS) {
|
||||
auto I = RHS.find(KV.first);
|
||||
if (I == RHS.end() || I->second != KV.second)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Inequality comparison for DenseMap.
|
||||
///
|
||||
/// Equivalent to !(LHS == RHS). See operator== for performance notes.
|
||||
template <typename DerivedT, typename KeyT, typename ValueT, typename KeyInfoT,
|
||||
typename BucketT>
|
||||
bool operator!=(
|
||||
const DenseMapBase<DerivedT, KeyT, ValueT, KeyInfoT, BucketT> &LHS,
|
||||
const DenseMapBase<DerivedT, KeyT, ValueT, KeyInfoT, BucketT> &RHS) {
|
||||
return !(LHS == RHS);
|
||||
}
|
||||
|
||||
template <typename KeyT, typename ValueT,
|
||||
typename KeyInfoT = DenseMapInfo<KeyT>,
|
||||
typename BucketT = detail::DenseMapPair<KeyT, ValueT>>
|
||||
typename BucketT = llvm::detail::DenseMapPair<KeyT, ValueT>>
|
||||
class DenseMap : public DenseMapBase<DenseMap<KeyT, ValueT, KeyInfoT, BucketT>,
|
||||
KeyT, ValueT, KeyInfoT, BucketT> {
|
||||
friend class DenseMapBase<DenseMap, KeyT, ValueT, KeyInfoT, BucketT>;
|
||||
|
|
@ -676,6 +740,11 @@ public:
|
|||
this->insert(I, E);
|
||||
}
|
||||
|
||||
DenseMap(std::initializer_list<typename BaseT::value_type> Vals) {
|
||||
init(Vals.size());
|
||||
this->insert(Vals.begin(), Vals.end());
|
||||
}
|
||||
|
||||
~DenseMap() {
|
||||
this->destroyAll();
|
||||
operator delete(Buckets);
|
||||
|
|
@ -798,7 +867,7 @@ private:
|
|||
|
||||
template <typename KeyT, typename ValueT, unsigned InlineBuckets = 4,
|
||||
typename KeyInfoT = DenseMapInfo<KeyT>,
|
||||
typename BucketT = detail::DenseMapPair<KeyT, ValueT>>
|
||||
typename BucketT = llvm::detail::DenseMapPair<KeyT, ValueT>>
|
||||
class SmallDenseMap
|
||||
: public DenseMapBase<
|
||||
SmallDenseMap<KeyT, ValueT, InlineBuckets, KeyInfoT, BucketT>, KeyT,
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/DenseMapInfo.h"
|
||||
#include "llvm/Support/MathExtras.h"
|
||||
#include "llvm/Support/type_traits.h"
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
|
|
@ -67,7 +68,7 @@ public:
|
|||
explicit DenseSetImpl(unsigned InitialReserve = 0) : TheMap(InitialReserve) {}
|
||||
|
||||
DenseSetImpl(std::initializer_list<ValueT> Elems)
|
||||
: DenseSetImpl(Elems.size()) {
|
||||
: DenseSetImpl(PowerOf2Ceil(Elems.size())) {
|
||||
insert(Elems.begin(), Elems.end());
|
||||
}
|
||||
|
||||
|
|
@ -136,8 +137,8 @@ public:
|
|||
public:
|
||||
using difference_type = typename MapTy::const_iterator::difference_type;
|
||||
using value_type = ValueT;
|
||||
using pointer = value_type *;
|
||||
using reference = value_type &;
|
||||
using pointer = const value_type *;
|
||||
using reference = const value_type &;
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
|
||||
ConstIterator() = default;
|
||||
|
|
@ -214,6 +215,34 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
/// Equality comparison for DenseSet.
|
||||
///
|
||||
/// Iterates over elements of LHS confirming that each element is also a member
|
||||
/// of RHS, and that RHS contains no additional values.
|
||||
/// Equivalent to N calls to RHS.count. Amortized complexity is linear, worst
|
||||
/// case is O(N^2) (if every hash collides).
|
||||
template <typename ValueT, typename MapTy, typename ValueInfoT>
|
||||
bool operator==(const DenseSetImpl<ValueT, MapTy, ValueInfoT> &LHS,
|
||||
const DenseSetImpl<ValueT, MapTy, ValueInfoT> &RHS) {
|
||||
if (LHS.size() != RHS.size())
|
||||
return false;
|
||||
|
||||
for (auto &E : LHS)
|
||||
if (!RHS.count(E))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Inequality comparison for DenseSet.
|
||||
///
|
||||
/// Equivalent to !(LHS == RHS). See operator== for performance notes.
|
||||
template <typename ValueT, typename MapTy, typename ValueInfoT>
|
||||
bool operator!=(const DenseSetImpl<ValueT, MapTy, ValueInfoT> &LHS,
|
||||
const DenseSetImpl<ValueT, MapTy, ValueInfoT> &RHS) {
|
||||
return !(LHS == RHS);
|
||||
}
|
||||
|
||||
} // end namespace detail
|
||||
|
||||
/// Implements a dense probed hash-table based set.
|
||||
|
|
|
|||
|
|
@ -25,6 +25,13 @@ namespace llvm {
|
|||
// GraphTraits - This class should be specialized by different graph types...
|
||||
// which is why the default version is empty.
|
||||
//
|
||||
// This template evolved from supporting `BasicBlock` to also later supporting
|
||||
// more complex types (e.g. CFG and DomTree).
|
||||
//
|
||||
// GraphTraits can be used to create a view over a graph interpreting it
|
||||
// differently without requiring a copy of the original graph. This could
|
||||
// be achieved by carrying more data in NodeRef. See LoopBodyTraits for one
|
||||
// example.
|
||||
template<class GraphType>
|
||||
struct GraphTraits {
|
||||
// Elements to provide:
|
||||
|
|
|
|||
|
|
@ -133,7 +133,7 @@ hash_code hash_value(const std::basic_string<T> &arg);
|
|||
/// undone. This makes it thread-hostile and very hard to use outside of
|
||||
/// immediately on start of a simple program designed for reproducible
|
||||
/// behavior.
|
||||
void set_fixed_execution_hash_seed(size_t fixed_value);
|
||||
void set_fixed_execution_hash_seed(uint64_t fixed_value);
|
||||
|
||||
|
||||
// All of the implementation details of actually computing the various hash
|
||||
|
|
@ -316,9 +316,9 @@ struct hash_state {
|
|||
/// This variable can be set using the \see llvm::set_fixed_execution_seed
|
||||
/// function. See that function for details. Do not, under any circumstances,
|
||||
/// set or read this variable.
|
||||
extern size_t fixed_seed_override;
|
||||
extern uint64_t fixed_seed_override;
|
||||
|
||||
inline size_t get_execution_seed() {
|
||||
inline uint64_t get_execution_seed() {
|
||||
// FIXME: This needs to be a per-execution seed. This is just a placeholder
|
||||
// implementation. Switching to a per-execution seed is likely to flush out
|
||||
// instability bugs and so will happen as its own commit.
|
||||
|
|
@ -326,8 +326,7 @@ inline size_t get_execution_seed() {
|
|||
// However, if there is a fixed seed override set the first time this is
|
||||
// called, return that instead of the per-execution seed.
|
||||
const uint64_t seed_prime = 0xff51afd7ed558ccdULL;
|
||||
static size_t seed = fixed_seed_override ? fixed_seed_override
|
||||
: (size_t)seed_prime;
|
||||
static uint64_t seed = fixed_seed_override ? fixed_seed_override : seed_prime;
|
||||
return seed;
|
||||
}
|
||||
|
||||
|
|
@ -402,7 +401,7 @@ bool store_and_advance(char *&buffer_ptr, char *buffer_end, const T& value,
|
|||
/// combining them, this (as an optimization) directly combines the integers.
|
||||
template <typename InputIteratorT>
|
||||
hash_code hash_combine_range_impl(InputIteratorT first, InputIteratorT last) {
|
||||
const size_t seed = get_execution_seed();
|
||||
const uint64_t seed = get_execution_seed();
|
||||
char buffer[64], *buffer_ptr = buffer;
|
||||
char *const buffer_end = std::end(buffer);
|
||||
while (first != last && store_and_advance(buffer_ptr, buffer_end,
|
||||
|
|
@ -446,7 +445,7 @@ hash_code hash_combine_range_impl(InputIteratorT first, InputIteratorT last) {
|
|||
template <typename ValueT>
|
||||
typename std::enable_if<is_hashable_data<ValueT>::value, hash_code>::type
|
||||
hash_combine_range_impl(ValueT *first, ValueT *last) {
|
||||
const size_t seed = get_execution_seed();
|
||||
const uint64_t seed = get_execution_seed();
|
||||
const char *s_begin = reinterpret_cast<const char *>(first);
|
||||
const char *s_end = reinterpret_cast<const char *>(last);
|
||||
const size_t length = std::distance(s_begin, s_end);
|
||||
|
|
@ -496,7 +495,7 @@ namespace detail {
|
|||
struct hash_combine_recursive_helper {
|
||||
char buffer[64];
|
||||
hash_state state;
|
||||
const size_t seed;
|
||||
const uint64_t seed;
|
||||
|
||||
public:
|
||||
/// Construct a recursive hash combining helper.
|
||||
|
|
|
|||
|
|
@ -31,8 +31,9 @@ class ImmutableListImpl : public FoldingSetNode {
|
|||
T Head;
|
||||
const ImmutableListImpl* Tail;
|
||||
|
||||
ImmutableListImpl(const T& head, const ImmutableListImpl* tail = nullptr)
|
||||
: Head(head), Tail(tail) {}
|
||||
template <typename ElemT>
|
||||
ImmutableListImpl(ElemT &&head, const ImmutableListImpl *tail = nullptr)
|
||||
: Head(std::forward<ElemT>(head)), Tail(tail) {}
|
||||
|
||||
public:
|
||||
ImmutableListImpl(const ImmutableListImpl &) = delete;
|
||||
|
|
@ -66,6 +67,9 @@ public:
|
|||
using value_type = T;
|
||||
using Factory = ImmutableListFactory<T>;
|
||||
|
||||
static_assert(std::is_trivially_destructible<T>::value,
|
||||
"T must be trivially destructible!");
|
||||
|
||||
private:
|
||||
const ImmutableListImpl<T>* X;
|
||||
|
||||
|
|
@ -90,6 +94,9 @@ public:
|
|||
bool operator==(const iterator& I) const { return L == I.L; }
|
||||
bool operator!=(const iterator& I) const { return L != I.L; }
|
||||
const value_type& operator*() const { return L->getHead(); }
|
||||
const typename std::remove_reference<value_type>::type* operator->() const {
|
||||
return &L->getHead();
|
||||
}
|
||||
|
||||
ImmutableList getList() const { return L; }
|
||||
};
|
||||
|
|
@ -123,14 +130,14 @@ public:
|
|||
bool operator==(const ImmutableList& L) const { return isEqual(L); }
|
||||
|
||||
/// getHead - Returns the head of the list.
|
||||
const T& getHead() {
|
||||
const T& getHead() const {
|
||||
assert(!isEmpty() && "Cannot get the head of an empty list.");
|
||||
return X->getHead();
|
||||
}
|
||||
|
||||
/// getTail - Returns the tail of the list, which is another (possibly empty)
|
||||
/// ImmutableList.
|
||||
ImmutableList getTail() {
|
||||
ImmutableList getTail() const {
|
||||
return X ? X->getTail() : nullptr;
|
||||
}
|
||||
|
||||
|
|
@ -166,7 +173,8 @@ public:
|
|||
if (ownsAllocator()) delete &getAllocator();
|
||||
}
|
||||
|
||||
LLVM_NODISCARD ImmutableList<T> concat(const T &Head, ImmutableList<T> Tail) {
|
||||
template <typename ElemT>
|
||||
LLVM_NODISCARD ImmutableList<T> concat(ElemT &&Head, ImmutableList<T> Tail) {
|
||||
// Profile the new list to see if it already exists in our cache.
|
||||
FoldingSetNodeID ID;
|
||||
void* InsertPos;
|
||||
|
|
@ -179,7 +187,7 @@ public:
|
|||
// The list does not exist in our cache. Create it.
|
||||
BumpPtrAllocator& A = getAllocator();
|
||||
L = (ListTy*) A.Allocate<ListTy>();
|
||||
new (L) ListTy(Head, TailImpl);
|
||||
new (L) ListTy(std::forward<ElemT>(Head), TailImpl);
|
||||
|
||||
// Insert the new list into the cache.
|
||||
Cache.InsertNode(L, InsertPos);
|
||||
|
|
@ -188,16 +196,24 @@ public:
|
|||
return L;
|
||||
}
|
||||
|
||||
LLVM_NODISCARD ImmutableList<T> add(const T& D, ImmutableList<T> L) {
|
||||
return concat(D, L);
|
||||
template <typename ElemT>
|
||||
LLVM_NODISCARD ImmutableList<T> add(ElemT &&Data, ImmutableList<T> L) {
|
||||
return concat(std::forward<ElemT>(Data), L);
|
||||
}
|
||||
|
||||
template <typename ...CtorArgs>
|
||||
LLVM_NODISCARD ImmutableList<T> emplace(ImmutableList<T> Tail,
|
||||
CtorArgs &&...Args) {
|
||||
return concat(T(std::forward<CtorArgs>(Args)...), Tail);
|
||||
}
|
||||
|
||||
ImmutableList<T> getEmptyList() const {
|
||||
return ImmutableList<T>(nullptr);
|
||||
}
|
||||
|
||||
ImmutableList<T> create(const T& X) {
|
||||
return Concat(X, getEmptyList());
|
||||
template <typename ElemT>
|
||||
ImmutableList<T> create(ElemT &&Data) {
|
||||
return concat(std::forward<ElemT>(Data), getEmptyList());
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -101,6 +101,7 @@
|
|||
|
||||
#include "llvm/ADT/PointerIntPair.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/bit.h"
|
||||
#include "llvm/Support/AlignOf.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include "llvm/Support/RecyclingAllocator.h"
|
||||
|
|
@ -963,6 +964,7 @@ public:
|
|||
|
||||
private:
|
||||
// The root data is either a RootLeaf or a RootBranchData instance.
|
||||
LLVM_ALIGNAS(RootLeaf) LLVM_ALIGNAS(RootBranchData)
|
||||
AlignedCharArrayUnion<RootLeaf, RootBranchData> data;
|
||||
|
||||
// Tree height.
|
||||
|
|
@ -977,15 +979,10 @@ private:
|
|||
// Allocator used for creating external nodes.
|
||||
Allocator &allocator;
|
||||
|
||||
/// dataAs - Represent data as a node type without breaking aliasing rules.
|
||||
/// Represent data as a node type without breaking aliasing rules.
|
||||
template <typename T>
|
||||
T &dataAs() const {
|
||||
union {
|
||||
const char *d;
|
||||
T *t;
|
||||
} u;
|
||||
u.d = data.buffer;
|
||||
return *u.t;
|
||||
return *bit_cast<T *>(const_cast<char *>(data.buffer));
|
||||
}
|
||||
|
||||
const RootLeaf &rootLeaf() const {
|
||||
|
|
@ -1137,6 +1134,19 @@ public:
|
|||
I.find(x);
|
||||
return I;
|
||||
}
|
||||
|
||||
/// overlaps(a, b) - Return true if the intervals in this map overlap with the
|
||||
/// interval [a;b].
|
||||
bool overlaps(KeyT a, KeyT b) {
|
||||
assert(Traits::nonEmpty(a, b));
|
||||
const_iterator I = find(a);
|
||||
if (!I.valid())
|
||||
return false;
|
||||
// [a;b] and [x;y] overlap iff x<=b and a<=y. The find() call guarantees the
|
||||
// second part (y = find(a).stop()), so it is sufficient to check the first
|
||||
// one.
|
||||
return !Traits::stopLess(b, I.start());
|
||||
}
|
||||
};
|
||||
|
||||
/// treeSafeLookup - Return the mapped value at x or NotFound, assuming a
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ namespace llvm {
|
|||
|
||||
namespace optional_detail {
|
||||
/// Storage for any type.
|
||||
template <typename T, bool IsPodLike> struct OptionalStorage {
|
||||
template <typename T, bool = isPodLike<T>::value> struct OptionalStorage {
|
||||
AlignedCharArrayUnion<T> storage;
|
||||
bool hasVal = false;
|
||||
|
||||
|
|
@ -108,28 +108,10 @@ template <typename T, bool IsPodLike> struct OptionalStorage {
|
|||
}
|
||||
};
|
||||
|
||||
#if !defined(__GNUC__) || defined(__clang__) // GCC up to GCC7 miscompiles this.
|
||||
/// Storage for trivially copyable types only.
|
||||
template <typename T> struct OptionalStorage<T, true> {
|
||||
AlignedCharArrayUnion<T> storage;
|
||||
bool hasVal = false;
|
||||
|
||||
OptionalStorage() = default;
|
||||
|
||||
OptionalStorage(const T &y) : hasVal(true) { new (storage.buffer) T(y); }
|
||||
OptionalStorage &operator=(const T &y) {
|
||||
*reinterpret_cast<T *>(storage.buffer) = y;
|
||||
hasVal = true;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void reset() { hasVal = false; }
|
||||
};
|
||||
#endif
|
||||
} // namespace optional_detail
|
||||
|
||||
template <typename T> class Optional {
|
||||
optional_detail::OptionalStorage<T, isPodLike<T>::value> Storage;
|
||||
optional_detail::OptionalStorage<T> Storage;
|
||||
|
||||
public:
|
||||
using value_type = T;
|
||||
|
|
|
|||
|
|
@ -42,6 +42,8 @@ template <typename PointerTy, unsigned IntBits, typename IntType = unsigned,
|
|||
typename PtrTraits = PointerLikeTypeTraits<PointerTy>,
|
||||
typename Info = PointerIntPairInfo<PointerTy, IntBits, PtrTraits>>
|
||||
class PointerIntPair {
|
||||
// Used by MSVC visualizer and generally helpful for debugging/visualizing.
|
||||
using InfoTy = Info;
|
||||
intptr_t Value = 0;
|
||||
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
#ifndef LLVM_ADT_POINTERSUMTYPE_H
|
||||
#define LLVM_ADT_POINTERSUMTYPE_H
|
||||
|
||||
#include "llvm/ADT/bit.h"
|
||||
#include "llvm/ADT/DenseMapInfo.h"
|
||||
#include "llvm/Support/PointerLikeTypeTraits.h"
|
||||
#include <cassert>
|
||||
|
|
@ -58,56 +59,142 @@ template <typename TagT, typename... MemberTs> struct PointerSumTypeHelper;
|
|||
/// and may be desirable to set to a state that is particularly desirable to
|
||||
/// default construct.
|
||||
///
|
||||
/// Having a supported zero-valued tag also enables getting the address of a
|
||||
/// pointer stored with that tag provided it is stored in its natural bit
|
||||
/// representation. This works because in the case of a zero-valued tag, the
|
||||
/// pointer's value is directly stored into this object and we can expose the
|
||||
/// address of that internal storage. This is especially useful when building an
|
||||
/// `ArrayRef` of a single pointer stored in a sum type.
|
||||
///
|
||||
/// 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 = 0;
|
||||
|
||||
using HelperT = detail::PointerSumTypeHelper<TagT, MemberTs...>;
|
||||
|
||||
// We keep both the raw value and the min tag value's pointer in a union. When
|
||||
// the minimum tag value is zero, this allows code below to cleanly expose the
|
||||
// address of the zero-tag pointer instead of just the zero-tag pointer
|
||||
// itself. This is especially useful when building `ArrayRef`s out of a single
|
||||
// pointer. However, we have to carefully access the union due to the active
|
||||
// member potentially changing. When we *store* a new value, we directly
|
||||
// access the union to allow us to store using the obvious types. However,
|
||||
// when we *read* a value, we copy the underlying storage out to avoid relying
|
||||
// on one member or the other being active.
|
||||
union StorageT {
|
||||
// Ensure we get a null default constructed value. We don't use a member
|
||||
// initializer because some compilers seem to not implement those correctly
|
||||
// for a union.
|
||||
StorageT() : Value(0) {}
|
||||
|
||||
uintptr_t Value;
|
||||
|
||||
typename HelperT::template Lookup<HelperT::MinTag>::PointerT MinTagPointer;
|
||||
};
|
||||
|
||||
StorageT Storage;
|
||||
|
||||
public:
|
||||
constexpr PointerSumType() = default;
|
||||
|
||||
/// A typed setter to a given tagged member of the sum type.
|
||||
template <TagT N>
|
||||
void set(typename HelperT::template Lookup<N>::PointerT Pointer) {
|
||||
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!");
|
||||
Storage.Value = reinterpret_cast<uintptr_t>(V) | N;
|
||||
}
|
||||
|
||||
/// 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;
|
||||
Result.set<N>(Pointer);
|
||||
return Result;
|
||||
}
|
||||
|
||||
TagT getTag() const { return static_cast<TagT>(Value & HelperT::TagMask); }
|
||||
/// Clear the value to null with the min tag type.
|
||||
void clear() { set<HelperT::MinTag>(nullptr); }
|
||||
|
||||
TagT getTag() const {
|
||||
return static_cast<TagT>(getOpaqueValue() & 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;
|
||||
void *P = is<N>() ? getVoidPtr() : 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());
|
||||
return HelperT::template Lookup<N>::TraitsT::getFromVoidPointer(
|
||||
getVoidPtr());
|
||||
}
|
||||
|
||||
explicit 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; }
|
||||
/// If the tag is zero and the pointer's value isn't changed when being
|
||||
/// stored, get the address of the stored value type-punned to the zero-tag's
|
||||
/// pointer type.
|
||||
typename HelperT::template Lookup<HelperT::MinTag>::PointerT const *
|
||||
getAddrOfZeroTagPointer() const {
|
||||
return const_cast<PointerSumType *>(this)->getAddrOfZeroTagPointer();
|
||||
}
|
||||
|
||||
uintptr_t getOpaqueValue() const { return Value; }
|
||||
/// If the tag is zero and the pointer's value isn't changed when being
|
||||
/// stored, get the address of the stored value type-punned to the zero-tag's
|
||||
/// pointer type.
|
||||
typename HelperT::template Lookup<HelperT::MinTag>::PointerT *
|
||||
getAddrOfZeroTagPointer() {
|
||||
static_assert(HelperT::MinTag == 0, "Non-zero minimum tag value!");
|
||||
assert(is<HelperT::MinTag>() && "The active tag is not zero!");
|
||||
// Store the initial value of the pointer when read out of our storage.
|
||||
auto InitialPtr = get<HelperT::MinTag>();
|
||||
// Now update the active member of the union to be the actual pointer-typed
|
||||
// member so that accessing it indirectly through the returned address is
|
||||
// valid.
|
||||
Storage.MinTagPointer = InitialPtr;
|
||||
// Finally, validate that this was a no-op as expected by reading it back
|
||||
// out using the same underlying-storage read as above.
|
||||
assert(InitialPtr == get<HelperT::MinTag>() &&
|
||||
"Switching to typed storage changed the pointer returned!");
|
||||
// Now we can correctly return an address to typed storage.
|
||||
return &Storage.MinTagPointer;
|
||||
}
|
||||
|
||||
explicit operator bool() const {
|
||||
return getOpaqueValue() & HelperT::PointerMask;
|
||||
}
|
||||
bool operator==(const PointerSumType &R) const {
|
||||
return getOpaqueValue() == R.getOpaqueValue();
|
||||
}
|
||||
bool operator!=(const PointerSumType &R) const {
|
||||
return getOpaqueValue() != R.getOpaqueValue();
|
||||
}
|
||||
bool operator<(const PointerSumType &R) const {
|
||||
return getOpaqueValue() < R.getOpaqueValue();
|
||||
}
|
||||
bool operator>(const PointerSumType &R) const {
|
||||
return getOpaqueValue() > R.getOpaqueValue();
|
||||
}
|
||||
bool operator<=(const PointerSumType &R) const {
|
||||
return getOpaqueValue() <= R.getOpaqueValue();
|
||||
}
|
||||
bool operator>=(const PointerSumType &R) const {
|
||||
return getOpaqueValue() >= R.getOpaqueValue();
|
||||
}
|
||||
|
||||
uintptr_t getOpaqueValue() const {
|
||||
// Read the underlying storage of the union, regardless of the active
|
||||
// member.
|
||||
return bit_cast<uintptr_t>(Storage);
|
||||
}
|
||||
|
||||
protected:
|
||||
void *getImpl() const {
|
||||
return reinterpret_cast<void *>(Value & HelperT::PointerMask);
|
||||
void *getVoidPtr() const {
|
||||
return reinterpret_cast<void *>(getOpaqueValue() & HelperT::PointerMask);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -151,8 +238,9 @@ struct PointerSumTypeHelper : MemberTs... {
|
|||
enum { NumTagBits = Min<MemberTs::TraitsT::NumLowBitsAvailable...>::value };
|
||||
|
||||
// Also compute the smallest discriminant and various masks for convenience.
|
||||
constexpr static TagT MinTag =
|
||||
static_cast<TagT>(Min<MemberTs::Tag...>::value);
|
||||
enum : uint64_t {
|
||||
MinTag = Min<MemberTs::Tag...>::value,
|
||||
PointerMask = static_cast<uint64_t>(-1) << NumTagBits,
|
||||
TagMask = ~PointerMask
|
||||
};
|
||||
|
|
|
|||
|
|
@ -296,12 +296,15 @@ class ReversePostOrderTraversal {
|
|||
|
||||
public:
|
||||
using rpo_iterator = typename std::vector<NodeRef>::reverse_iterator;
|
||||
using const_rpo_iterator = typename std::vector<NodeRef>::const_reverse_iterator;
|
||||
|
||||
ReversePostOrderTraversal(GraphT G) { Initialize(GT::getEntryNode(G)); }
|
||||
|
||||
// Because we want a reverse post order, use reverse iterators from the vector
|
||||
rpo_iterator begin() { return Blocks.rbegin(); }
|
||||
const_rpo_iterator begin() const { return Blocks.crbegin(); }
|
||||
rpo_iterator end() { return Blocks.rend(); }
|
||||
const_rpo_iterator end() const { return Blocks.crend(); }
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/iterator.h"
|
||||
#include "llvm/ADT/iterator_range.h"
|
||||
#include "llvm/Config/abi-breaking.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
|
|
@ -70,6 +71,16 @@ template <typename B1, typename... Bn>
|
|||
struct conjunction<B1, Bn...>
|
||||
: std::conditional<bool(B1::value), conjunction<Bn...>, B1>::type {};
|
||||
|
||||
template <typename T> struct make_const_ptr {
|
||||
using type =
|
||||
typename std::add_pointer<typename std::add_const<T>::type>::type;
|
||||
};
|
||||
|
||||
template <typename T> struct make_const_ref {
|
||||
using type = typename std::add_lvalue_reference<
|
||||
typename std::add_const<T>::type>::type;
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Extra additions to <functional>
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
@ -194,6 +205,12 @@ void adl_swap(T &&lhs, T &&rhs) noexcept(
|
|||
adl_detail::adl_swap(std::forward<T>(lhs), std::forward<T>(rhs));
|
||||
}
|
||||
|
||||
/// Test whether \p RangeOrContainer is empty. Similar to C++17 std::empty.
|
||||
template <typename T>
|
||||
constexpr bool empty(const T &RangeOrContainer) {
|
||||
return adl_begin(RangeOrContainer) == adl_end(RangeOrContainer);
|
||||
}
|
||||
|
||||
// mapped_iterator - This is a simple iterator adapter that causes a function to
|
||||
// be applied whenever operator* is invoked on the iterator.
|
||||
|
||||
|
|
@ -418,9 +435,94 @@ make_filter_range(RangeT &&Range, PredicateT Pred) {
|
|||
std::end(std::forward<RangeT>(Range)), Pred));
|
||||
}
|
||||
|
||||
// forward declarations required by zip_shortest/zip_first
|
||||
/// A pseudo-iterator adaptor that is designed to implement "early increment"
|
||||
/// style loops.
|
||||
///
|
||||
/// This is *not a normal iterator* and should almost never be used directly. It
|
||||
/// is intended primarily to be used with range based for loops and some range
|
||||
/// algorithms.
|
||||
///
|
||||
/// The iterator isn't quite an `OutputIterator` or an `InputIterator` but
|
||||
/// somewhere between them. The constraints of these iterators are:
|
||||
///
|
||||
/// - On construction or after being incremented, it is comparable and
|
||||
/// dereferencable. It is *not* incrementable.
|
||||
/// - After being dereferenced, it is neither comparable nor dereferencable, it
|
||||
/// is only incrementable.
|
||||
///
|
||||
/// This means you can only dereference the iterator once, and you can only
|
||||
/// increment it once between dereferences.
|
||||
template <typename WrappedIteratorT>
|
||||
class early_inc_iterator_impl
|
||||
: public iterator_adaptor_base<early_inc_iterator_impl<WrappedIteratorT>,
|
||||
WrappedIteratorT, std::input_iterator_tag> {
|
||||
using BaseT =
|
||||
iterator_adaptor_base<early_inc_iterator_impl<WrappedIteratorT>,
|
||||
WrappedIteratorT, std::input_iterator_tag>;
|
||||
|
||||
using PointerT = typename std::iterator_traits<WrappedIteratorT>::pointer;
|
||||
|
||||
protected:
|
||||
#if LLVM_ENABLE_ABI_BREAKING_CHECKS
|
||||
bool IsEarlyIncremented = false;
|
||||
#endif
|
||||
|
||||
public:
|
||||
early_inc_iterator_impl(WrappedIteratorT I) : BaseT(I) {}
|
||||
|
||||
using BaseT::operator*;
|
||||
typename BaseT::reference operator*() {
|
||||
#if LLVM_ENABLE_ABI_BREAKING_CHECKS
|
||||
assert(!IsEarlyIncremented && "Cannot dereference twice!");
|
||||
IsEarlyIncremented = true;
|
||||
#endif
|
||||
return *(this->I)++;
|
||||
}
|
||||
|
||||
using BaseT::operator++;
|
||||
early_inc_iterator_impl &operator++() {
|
||||
#if LLVM_ENABLE_ABI_BREAKING_CHECKS
|
||||
assert(IsEarlyIncremented && "Cannot increment before dereferencing!");
|
||||
IsEarlyIncremented = false;
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
|
||||
using BaseT::operator==;
|
||||
bool operator==(const early_inc_iterator_impl &RHS) const {
|
||||
#if LLVM_ENABLE_ABI_BREAKING_CHECKS
|
||||
assert(!IsEarlyIncremented && "Cannot compare after dereferencing!");
|
||||
#endif
|
||||
return BaseT::operator==(RHS);
|
||||
}
|
||||
};
|
||||
|
||||
/// Make a range that does early increment to allow mutation of the underlying
|
||||
/// range without disrupting iteration.
|
||||
///
|
||||
/// The underlying iterator will be incremented immediately after it is
|
||||
/// dereferenced, allowing deletion of the current node or insertion of nodes to
|
||||
/// not disrupt iteration provided they do not invalidate the *next* iterator --
|
||||
/// the current iterator can be invalidated.
|
||||
///
|
||||
/// This requires a very exact pattern of use that is only really suitable to
|
||||
/// range based for loops and other range algorithms that explicitly guarantee
|
||||
/// to dereference exactly once each element, and to increment exactly once each
|
||||
/// element.
|
||||
template <typename RangeT>
|
||||
iterator_range<early_inc_iterator_impl<detail::IterOfRange<RangeT>>>
|
||||
make_early_inc_range(RangeT &&Range) {
|
||||
using EarlyIncIteratorT =
|
||||
early_inc_iterator_impl<detail::IterOfRange<RangeT>>;
|
||||
return make_range(EarlyIncIteratorT(std::begin(std::forward<RangeT>(Range))),
|
||||
EarlyIncIteratorT(std::end(std::forward<RangeT>(Range))));
|
||||
}
|
||||
|
||||
// forward declarations required by zip_shortest/zip_first/zip_longest
|
||||
template <typename R, typename UnaryPredicate>
|
||||
bool all_of(R &&range, UnaryPredicate P);
|
||||
template <typename R, typename UnaryPredicate>
|
||||
bool any_of(R &&range, UnaryPredicate P);
|
||||
|
||||
template <size_t... I> struct index_sequence;
|
||||
|
||||
|
|
@ -571,6 +673,132 @@ detail::zippy<detail::zip_first, T, U, Args...> zip_first(T &&t, U &&u,
|
|||
std::forward<T>(t), std::forward<U>(u), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
template <typename Iter>
|
||||
static Iter next_or_end(const Iter &I, const Iter &End) {
|
||||
if (I == End)
|
||||
return End;
|
||||
return std::next(I);
|
||||
}
|
||||
|
||||
template <typename Iter>
|
||||
static auto deref_or_none(const Iter &I, const Iter &End)
|
||||
-> llvm::Optional<typename std::remove_const<
|
||||
typename std::remove_reference<decltype(*I)>::type>::type> {
|
||||
if (I == End)
|
||||
return None;
|
||||
return *I;
|
||||
}
|
||||
|
||||
template <typename Iter> struct ZipLongestItemType {
|
||||
using type =
|
||||
llvm::Optional<typename std::remove_const<typename std::remove_reference<
|
||||
decltype(*std::declval<Iter>())>::type>::type>;
|
||||
};
|
||||
|
||||
template <typename... Iters> struct ZipLongestTupleType {
|
||||
using type = std::tuple<typename ZipLongestItemType<Iters>::type...>;
|
||||
};
|
||||
|
||||
template <typename... Iters>
|
||||
class zip_longest_iterator
|
||||
: public iterator_facade_base<
|
||||
zip_longest_iterator<Iters...>,
|
||||
typename std::common_type<
|
||||
std::forward_iterator_tag,
|
||||
typename std::iterator_traits<Iters>::iterator_category...>::type,
|
||||
typename ZipLongestTupleType<Iters...>::type,
|
||||
typename std::iterator_traits<typename std::tuple_element<
|
||||
0, std::tuple<Iters...>>::type>::difference_type,
|
||||
typename ZipLongestTupleType<Iters...>::type *,
|
||||
typename ZipLongestTupleType<Iters...>::type> {
|
||||
public:
|
||||
using value_type = typename ZipLongestTupleType<Iters...>::type;
|
||||
|
||||
private:
|
||||
std::tuple<Iters...> iterators;
|
||||
std::tuple<Iters...> end_iterators;
|
||||
|
||||
template <size_t... Ns>
|
||||
bool test(const zip_longest_iterator<Iters...> &other,
|
||||
index_sequence<Ns...>) const {
|
||||
return llvm::any_of(
|
||||
std::initializer_list<bool>{std::get<Ns>(this->iterators) !=
|
||||
std::get<Ns>(other.iterators)...},
|
||||
identity<bool>{});
|
||||
}
|
||||
|
||||
template <size_t... Ns> value_type deref(index_sequence<Ns...>) const {
|
||||
return value_type(
|
||||
deref_or_none(std::get<Ns>(iterators), std::get<Ns>(end_iterators))...);
|
||||
}
|
||||
|
||||
template <size_t... Ns>
|
||||
decltype(iterators) tup_inc(index_sequence<Ns...>) const {
|
||||
return std::tuple<Iters...>(
|
||||
next_or_end(std::get<Ns>(iterators), std::get<Ns>(end_iterators))...);
|
||||
}
|
||||
|
||||
public:
|
||||
zip_longest_iterator(std::pair<Iters &&, Iters &&>... ts)
|
||||
: iterators(std::forward<Iters>(ts.first)...),
|
||||
end_iterators(std::forward<Iters>(ts.second)...) {}
|
||||
|
||||
value_type operator*() { return deref(index_sequence_for<Iters...>{}); }
|
||||
|
||||
value_type operator*() const { return deref(index_sequence_for<Iters...>{}); }
|
||||
|
||||
zip_longest_iterator<Iters...> &operator++() {
|
||||
iterators = tup_inc(index_sequence_for<Iters...>{});
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(const zip_longest_iterator<Iters...> &other) const {
|
||||
return !test(other, index_sequence_for<Iters...>{});
|
||||
}
|
||||
};
|
||||
|
||||
template <typename... Args> class zip_longest_range {
|
||||
public:
|
||||
using iterator =
|
||||
zip_longest_iterator<decltype(adl_begin(std::declval<Args>()))...>;
|
||||
using iterator_category = typename iterator::iterator_category;
|
||||
using value_type = typename iterator::value_type;
|
||||
using difference_type = typename iterator::difference_type;
|
||||
using pointer = typename iterator::pointer;
|
||||
using reference = typename iterator::reference;
|
||||
|
||||
private:
|
||||
std::tuple<Args...> ts;
|
||||
|
||||
template <size_t... Ns> iterator begin_impl(index_sequence<Ns...>) const {
|
||||
return iterator(std::make_pair(adl_begin(std::get<Ns>(ts)),
|
||||
adl_end(std::get<Ns>(ts)))...);
|
||||
}
|
||||
|
||||
template <size_t... Ns> iterator end_impl(index_sequence<Ns...>) const {
|
||||
return iterator(std::make_pair(adl_end(std::get<Ns>(ts)),
|
||||
adl_end(std::get<Ns>(ts)))...);
|
||||
}
|
||||
|
||||
public:
|
||||
zip_longest_range(Args &&... ts_) : ts(std::forward<Args>(ts_)...) {}
|
||||
|
||||
iterator begin() const { return begin_impl(index_sequence_for<Args...>{}); }
|
||||
iterator end() const { return end_impl(index_sequence_for<Args...>{}); }
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
/// Iterate over two or more iterators at the same time. Iteration continues
|
||||
/// until all iterators reach the end. The llvm::Optional only contains a value
|
||||
/// if the iterator has not reached the end.
|
||||
template <typename T, typename U, typename... Args>
|
||||
detail::zip_longest_range<T, U, Args...> zip_longest(T &&t, U &&u,
|
||||
Args &&... args) {
|
||||
return detail::zip_longest_range<T, U, Args...>(
|
||||
std::forward<T>(t), std::forward<U>(u), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/// Iterator wrapper that concatenates sequences together.
|
||||
///
|
||||
/// This can concatenate different iterators, even with different types, into
|
||||
|
|
@ -593,18 +821,20 @@ class concat_iterator
|
|||
/// Note that something like iterator_range seems nice at first here, but the
|
||||
/// range properties are of little benefit and end up getting in the way
|
||||
/// because we need to do mutation on the current iterators.
|
||||
std::tuple<std::pair<IterTs, IterTs>...> IterPairs;
|
||||
std::tuple<IterTs...> Begins;
|
||||
std::tuple<IterTs...> Ends;
|
||||
|
||||
/// Attempts to increment a specific iterator.
|
||||
///
|
||||
/// Returns true if it was able to increment the iterator. Returns false if
|
||||
/// the iterator is already at the end iterator.
|
||||
template <size_t Index> bool incrementHelper() {
|
||||
auto &IterPair = std::get<Index>(IterPairs);
|
||||
if (IterPair.first == IterPair.second)
|
||||
auto &Begin = std::get<Index>(Begins);
|
||||
auto &End = std::get<Index>(Ends);
|
||||
if (Begin == End)
|
||||
return false;
|
||||
|
||||
++IterPair.first;
|
||||
++Begin;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -628,11 +858,12 @@ class concat_iterator
|
|||
/// dereferences the iterator and returns the address of the resulting
|
||||
/// reference.
|
||||
template <size_t Index> ValueT *getHelper() const {
|
||||
auto &IterPair = std::get<Index>(IterPairs);
|
||||
if (IterPair.first == IterPair.second)
|
||||
auto &Begin = std::get<Index>(Begins);
|
||||
auto &End = std::get<Index>(Ends);
|
||||
if (Begin == End)
|
||||
return nullptr;
|
||||
|
||||
return &*IterPair.first;
|
||||
return &*Begin;
|
||||
}
|
||||
|
||||
/// Finds the first non-end iterator, dereferences, and returns the resulting
|
||||
|
|
@ -659,7 +890,7 @@ public:
|
|||
/// iterators.
|
||||
template <typename... RangeTs>
|
||||
explicit concat_iterator(RangeTs &&... Ranges)
|
||||
: IterPairs({std::begin(Ranges), std::end(Ranges)}...) {}
|
||||
: Begins(std::begin(Ranges)...), Ends(std::end(Ranges)...) {}
|
||||
|
||||
using BaseT::operator++;
|
||||
|
||||
|
|
@ -671,7 +902,7 @@ public:
|
|||
ValueT &operator*() const { return get(index_sequence_for<IterTs...>()); }
|
||||
|
||||
bool operator==(const concat_iterator &RHS) const {
|
||||
return IterPairs == RHS.IterPairs;
|
||||
return Begins == RHS.Begins && Ends == RHS.Ends;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -740,6 +971,19 @@ struct less_second {
|
|||
}
|
||||
};
|
||||
|
||||
/// \brief Function object to apply a binary function to the first component of
|
||||
/// a std::pair.
|
||||
template<typename FuncTy>
|
||||
struct on_first {
|
||||
FuncTy func;
|
||||
|
||||
template <typename T>
|
||||
auto operator()(const T &lhs, const T &rhs) const
|
||||
-> decltype(func(lhs.first, rhs.first)) {
|
||||
return func(lhs.first, rhs.first);
|
||||
}
|
||||
};
|
||||
|
||||
// A subset of N3658. More stuff can be added as-needed.
|
||||
|
||||
/// Represents a compile-time sequence of integers.
|
||||
|
|
@ -877,6 +1121,10 @@ inline void sort(IteratorTy Start, IteratorTy End) {
|
|||
std::sort(Start, End);
|
||||
}
|
||||
|
||||
template <typename Container> inline void sort(Container &&C) {
|
||||
llvm::sort(adl_begin(C), adl_end(C));
|
||||
}
|
||||
|
||||
template <typename IteratorTy, typename Compare>
|
||||
inline void sort(IteratorTy Start, IteratorTy End, Compare Comp) {
|
||||
#ifdef EXPENSIVE_CHECKS
|
||||
|
|
@ -886,6 +1134,11 @@ inline void sort(IteratorTy Start, IteratorTy End, Compare Comp) {
|
|||
std::sort(Start, End, Comp);
|
||||
}
|
||||
|
||||
template <typename Container, typename Compare>
|
||||
inline void sort(Container &&C, Compare Comp) {
|
||||
llvm::sort(adl_begin(C), adl_end(C), Comp);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Extra additions to <algorithm>
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
@ -908,6 +1161,18 @@ void DeleteContainerSeconds(Container &C) {
|
|||
C.clear();
|
||||
}
|
||||
|
||||
/// Get the size of a range. This is a wrapper function around std::distance
|
||||
/// which is only enabled when the operation is O(1).
|
||||
template <typename R>
|
||||
auto size(R &&Range, typename std::enable_if<
|
||||
std::is_same<typename std::iterator_traits<decltype(
|
||||
Range.begin())>::iterator_category,
|
||||
std::random_access_iterator_tag>::value,
|
||||
void>::type * = nullptr)
|
||||
-> decltype(std::distance(Range.begin(), Range.end())) {
|
||||
return std::distance(Range.begin(), Range.end());
|
||||
}
|
||||
|
||||
/// Provide wrappers to std::for_each which take ranges instead of having to
|
||||
/// pass begin/end explicitly.
|
||||
template <typename R, typename UnaryPredicate>
|
||||
|
|
@ -1018,6 +1283,33 @@ auto lower_bound(R &&Range, ForwardIt I) -> decltype(adl_begin(Range)) {
|
|||
return std::lower_bound(adl_begin(Range), adl_end(Range), I);
|
||||
}
|
||||
|
||||
template <typename R, typename ForwardIt, typename Compare>
|
||||
auto lower_bound(R &&Range, ForwardIt I, Compare C)
|
||||
-> decltype(adl_begin(Range)) {
|
||||
return std::lower_bound(adl_begin(Range), adl_end(Range), I, C);
|
||||
}
|
||||
|
||||
/// Provide wrappers to std::upper_bound which take ranges instead of having to
|
||||
/// pass begin/end explicitly.
|
||||
template <typename R, typename ForwardIt>
|
||||
auto upper_bound(R &&Range, ForwardIt I) -> decltype(adl_begin(Range)) {
|
||||
return std::upper_bound(adl_begin(Range), adl_end(Range), I);
|
||||
}
|
||||
|
||||
template <typename R, typename ForwardIt, typename Compare>
|
||||
auto upper_bound(R &&Range, ForwardIt I, Compare C)
|
||||
-> decltype(adl_begin(Range)) {
|
||||
return std::upper_bound(adl_begin(Range), adl_end(Range), I, C);
|
||||
}
|
||||
/// Wrapper function around std::equal to detect if all elements
|
||||
/// in a container are same.
|
||||
template <typename R>
|
||||
bool is_splat(R &&Range) {
|
||||
size_t range_size = size(Range);
|
||||
return range_size != 0 && (range_size == 1 ||
|
||||
std::equal(adl_begin(Range) + 1, adl_end(Range), adl_begin(Range)));
|
||||
}
|
||||
|
||||
/// Given a range of type R, iterate the entire range and return a
|
||||
/// SmallVector with elements of the vector. This is useful, for example,
|
||||
/// when you want to iterate a range and then sort the results.
|
||||
|
|
@ -1039,18 +1331,6 @@ void erase_if(Container &C, UnaryPredicate P) {
|
|||
C.erase(remove_if(C, P), C.end());
|
||||
}
|
||||
|
||||
/// Get the size of a range. This is a wrapper function around std::distance
|
||||
/// which is only enabled when the operation is O(1).
|
||||
template <typename R>
|
||||
auto size(R &&Range, typename std::enable_if<
|
||||
std::is_same<typename std::iterator_traits<decltype(
|
||||
Range.begin())>::iterator_category,
|
||||
std::random_access_iterator_tag>::value,
|
||||
void>::type * = nullptr)
|
||||
-> decltype(std::distance(Range.begin(), Range.end())) {
|
||||
return std::distance(Range.begin(), Range.end());
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Extra additions to <memory>
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
@ -1263,6 +1543,40 @@ auto apply_tuple(F &&f, Tuple &&t) -> decltype(detail::apply_tuple_impl(
|
|||
Indices{});
|
||||
}
|
||||
|
||||
/// Return true if the sequence [Begin, End) has exactly N items. Runs in O(N)
|
||||
/// time. Not meant for use with random-access iterators.
|
||||
template <typename IterTy>
|
||||
bool hasNItems(
|
||||
IterTy &&Begin, IterTy &&End, unsigned N,
|
||||
typename std::enable_if<
|
||||
!std::is_same<
|
||||
typename std::iterator_traits<typename std::remove_reference<
|
||||
decltype(Begin)>::type>::iterator_category,
|
||||
std::random_access_iterator_tag>::value,
|
||||
void>::type * = nullptr) {
|
||||
for (; N; --N, ++Begin)
|
||||
if (Begin == End)
|
||||
return false; // Too few.
|
||||
return Begin == End;
|
||||
}
|
||||
|
||||
/// Return true if the sequence [Begin, End) has N or more items. Runs in O(N)
|
||||
/// time. Not meant for use with random-access iterators.
|
||||
template <typename IterTy>
|
||||
bool hasNItemsOrMore(
|
||||
IterTy &&Begin, IterTy &&End, unsigned N,
|
||||
typename std::enable_if<
|
||||
!std::is_same<
|
||||
typename std::iterator_traits<typename std::remove_reference<
|
||||
decltype(Begin)>::type>::iterator_category,
|
||||
std::random_access_iterator_tag>::value,
|
||||
void>::type * = nullptr) {
|
||||
for (; N; --N, ++Begin)
|
||||
if (Begin == End)
|
||||
return false; // Too few.
|
||||
return true;
|
||||
}
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_ADT_STLEXTRAS_H
|
||||
|
|
|
|||
|
|
@ -92,10 +92,6 @@ public:
|
|||
};
|
||||
|
||||
private:
|
||||
bool isSmall() const {
|
||||
return X & uintptr_t(1);
|
||||
}
|
||||
|
||||
BitVector *getPointer() const {
|
||||
assert(!isSmall());
|
||||
return reinterpret_cast<BitVector *>(X);
|
||||
|
|
@ -186,6 +182,8 @@ public:
|
|||
return make_range(set_bits_begin(), set_bits_end());
|
||||
}
|
||||
|
||||
bool isSmall() const { return X & uintptr_t(1); }
|
||||
|
||||
/// Tests whether there are no bits in this bitvector.
|
||||
bool empty() const {
|
||||
return isSmall() ? getSmallSize() == 0 : getPointer()->empty();
|
||||
|
|
@ -242,7 +240,7 @@ public:
|
|||
uintptr_t Bits = getSmallBits();
|
||||
if (Bits == 0)
|
||||
return -1;
|
||||
return NumBaseBits - countLeadingZeros(Bits);
|
||||
return NumBaseBits - countLeadingZeros(Bits) - 1;
|
||||
}
|
||||
return getPointer()->find_last();
|
||||
}
|
||||
|
|
@ -265,7 +263,9 @@ public:
|
|||
return -1;
|
||||
|
||||
uintptr_t Bits = getSmallBits();
|
||||
return NumBaseBits - countLeadingOnes(Bits);
|
||||
// Set unused bits.
|
||||
Bits |= ~uintptr_t(0) << getSmallSize();
|
||||
return NumBaseBits - countLeadingOnes(Bits) - 1;
|
||||
}
|
||||
return getPointer()->find_last_unset();
|
||||
}
|
||||
|
|
@ -465,6 +465,11 @@ public:
|
|||
return (*this)[Idx];
|
||||
}
|
||||
|
||||
// Push single bit to end of vector.
|
||||
void push_back(bool Val) {
|
||||
resize(size() + 1, Val);
|
||||
}
|
||||
|
||||
/// Test if any common bits are set.
|
||||
bool anyCommon(const SmallBitVector &RHS) const {
|
||||
if (isSmall() && RHS.isSmall())
|
||||
|
|
@ -482,10 +487,17 @@ public:
|
|||
bool operator==(const SmallBitVector &RHS) const {
|
||||
if (size() != RHS.size())
|
||||
return false;
|
||||
if (isSmall())
|
||||
if (isSmall() && RHS.isSmall())
|
||||
return getSmallBits() == RHS.getSmallBits();
|
||||
else
|
||||
else if (!isSmall() && !RHS.isSmall())
|
||||
return *getPointer() == *RHS.getPointer();
|
||||
else {
|
||||
for (size_t i = 0, e = size(); i != e; ++i) {
|
||||
if ((*this)[i] != RHS[i])
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool operator!=(const SmallBitVector &RHS) const {
|
||||
|
|
@ -493,16 +505,19 @@ public:
|
|||
}
|
||||
|
||||
// Intersection, union, disjoint union.
|
||||
// FIXME BitVector::operator&= does not resize the LHS but this does
|
||||
SmallBitVector &operator&=(const SmallBitVector &RHS) {
|
||||
resize(std::max(size(), RHS.size()));
|
||||
if (isSmall())
|
||||
if (isSmall() && RHS.isSmall())
|
||||
setSmallBits(getSmallBits() & RHS.getSmallBits());
|
||||
else if (!RHS.isSmall())
|
||||
else if (!isSmall() && !RHS.isSmall())
|
||||
getPointer()->operator&=(*RHS.getPointer());
|
||||
else {
|
||||
SmallBitVector Copy = RHS;
|
||||
Copy.resize(size());
|
||||
getPointer()->operator&=(*Copy.getPointer());
|
||||
size_t i, e;
|
||||
for (i = 0, e = std::min(size(), RHS.size()); i != e; ++i)
|
||||
(*this)[i] = test(i) && RHS.test(i);
|
||||
for (e = size(); i != e; ++i)
|
||||
reset(i);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
|
@ -542,28 +557,26 @@ public:
|
|||
|
||||
SmallBitVector &operator|=(const SmallBitVector &RHS) {
|
||||
resize(std::max(size(), RHS.size()));
|
||||
if (isSmall())
|
||||
if (isSmall() && RHS.isSmall())
|
||||
setSmallBits(getSmallBits() | RHS.getSmallBits());
|
||||
else if (!RHS.isSmall())
|
||||
else if (!isSmall() && !RHS.isSmall())
|
||||
getPointer()->operator|=(*RHS.getPointer());
|
||||
else {
|
||||
SmallBitVector Copy = RHS;
|
||||
Copy.resize(size());
|
||||
getPointer()->operator|=(*Copy.getPointer());
|
||||
for (size_t i = 0, e = RHS.size(); i != e; ++i)
|
||||
(*this)[i] = test(i) || RHS.test(i);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
SmallBitVector &operator^=(const SmallBitVector &RHS) {
|
||||
resize(std::max(size(), RHS.size()));
|
||||
if (isSmall())
|
||||
if (isSmall() && RHS.isSmall())
|
||||
setSmallBits(getSmallBits() ^ RHS.getSmallBits());
|
||||
else if (!RHS.isSmall())
|
||||
else if (!isSmall() && !RHS.isSmall())
|
||||
getPointer()->operator^=(*RHS.getPointer());
|
||||
else {
|
||||
SmallBitVector Copy = RHS;
|
||||
Copy.resize(size());
|
||||
getPointer()->operator^=(*Copy.getPointer());
|
||||
for (size_t i = 0, e = RHS.size(); i != e; ++i)
|
||||
(*this)[i] = test(i) != RHS.test(i);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -182,7 +182,7 @@ public:
|
|||
|
||||
/// SmallVectorTemplateBase<isPodLike = false> - This is where we put method
|
||||
/// implementations that are designed to work with non-POD-like T's.
|
||||
template <typename T, bool isPodLike>
|
||||
template <typename T, bool = isPodLike<T>::value>
|
||||
class SmallVectorTemplateBase : public SmallVectorTemplateCommon<T> {
|
||||
protected:
|
||||
SmallVectorTemplateBase(size_t Size) : SmallVectorTemplateCommon<T>(Size) {}
|
||||
|
|
@ -299,7 +299,7 @@ protected:
|
|||
// use memcpy here. Note that I and E are iterators and thus might be
|
||||
// invalid for memcpy if they are equal.
|
||||
if (I != E)
|
||||
memcpy(Dest, I, (E - I) * sizeof(T));
|
||||
memcpy(reinterpret_cast<void *>(Dest), I, (E - I) * sizeof(T));
|
||||
}
|
||||
|
||||
/// Double the size of the allocated memory, guaranteeing space for at
|
||||
|
|
@ -310,7 +310,7 @@ public:
|
|||
void push_back(const T &Elt) {
|
||||
if (LLVM_UNLIKELY(this->size() >= this->capacity()))
|
||||
this->grow();
|
||||
memcpy(this->end(), &Elt, sizeof(T));
|
||||
memcpy(reinterpret_cast<void *>(this->end()), &Elt, sizeof(T));
|
||||
this->set_size(this->size() + 1);
|
||||
}
|
||||
|
||||
|
|
@ -320,8 +320,8 @@ public:
|
|||
/// This class consists of common code factored out of the SmallVector class to
|
||||
/// reduce code duplication based on the SmallVector 'N' template parameter.
|
||||
template <typename T>
|
||||
class SmallVectorImpl : public SmallVectorTemplateBase<T, isPodLike<T>::value> {
|
||||
using SuperClass = SmallVectorTemplateBase<T, isPodLike<T>::value>;
|
||||
class SmallVectorImpl : public SmallVectorTemplateBase<T> {
|
||||
using SuperClass = SmallVectorTemplateBase<T>;
|
||||
|
||||
public:
|
||||
using iterator = typename SuperClass::iterator;
|
||||
|
|
|
|||
|
|
@ -261,21 +261,33 @@ class SparseBitVector {
|
|||
BITWORD_SIZE = SparseBitVectorElement<ElementSize>::BITWORD_SIZE
|
||||
};
|
||||
|
||||
// Pointer to our current Element.
|
||||
ElementListIter CurrElementIter;
|
||||
ElementList Elements;
|
||||
// Pointer to our current Element. This has no visible effect on the external
|
||||
// state of a SparseBitVector, it's just used to improve performance in the
|
||||
// common case of testing/modifying bits with similar indices.
|
||||
mutable ElementListIter CurrElementIter;
|
||||
|
||||
// This is like std::lower_bound, except we do linear searching from the
|
||||
// current position.
|
||||
ElementListIter FindLowerBound(unsigned ElementIndex) {
|
||||
ElementListIter FindLowerBoundImpl(unsigned ElementIndex) const {
|
||||
|
||||
// We cache a non-const iterator so we're forced to resort to const_cast to
|
||||
// get the begin/end in the case where 'this' is const. To avoid duplication
|
||||
// of code with the only difference being whether the const cast is present
|
||||
// 'this' is always const in this particular function and we sort out the
|
||||
// difference in FindLowerBound and FindLowerBoundConst.
|
||||
ElementListIter Begin =
|
||||
const_cast<SparseBitVector<ElementSize> *>(this)->Elements.begin();
|
||||
ElementListIter End =
|
||||
const_cast<SparseBitVector<ElementSize> *>(this)->Elements.end();
|
||||
|
||||
if (Elements.empty()) {
|
||||
CurrElementIter = Elements.begin();
|
||||
return Elements.begin();
|
||||
CurrElementIter = Begin;
|
||||
return CurrElementIter;
|
||||
}
|
||||
|
||||
// Make sure our current iterator is valid.
|
||||
if (CurrElementIter == Elements.end())
|
||||
if (CurrElementIter == End)
|
||||
--CurrElementIter;
|
||||
|
||||
// Search from our current iterator, either backwards or forwards,
|
||||
|
|
@ -284,17 +296,23 @@ class SparseBitVector {
|
|||
if (CurrElementIter->index() == ElementIndex) {
|
||||
return ElementIter;
|
||||
} else if (CurrElementIter->index() > ElementIndex) {
|
||||
while (ElementIter != Elements.begin()
|
||||
while (ElementIter != Begin
|
||||
&& ElementIter->index() > ElementIndex)
|
||||
--ElementIter;
|
||||
} else {
|
||||
while (ElementIter != Elements.end() &&
|
||||
while (ElementIter != End &&
|
||||
ElementIter->index() < ElementIndex)
|
||||
++ElementIter;
|
||||
}
|
||||
CurrElementIter = ElementIter;
|
||||
return ElementIter;
|
||||
}
|
||||
ElementListConstIter FindLowerBoundConst(unsigned ElementIndex) const {
|
||||
return FindLowerBoundImpl(ElementIndex);
|
||||
}
|
||||
ElementListIter FindLowerBound(unsigned ElementIndex) {
|
||||
return FindLowerBoundImpl(ElementIndex);
|
||||
}
|
||||
|
||||
// Iterator to walk set bits in the bitmap. This iterator is a lot uglier
|
||||
// than it would be, in order to be efficient.
|
||||
|
|
@ -423,22 +441,12 @@ class SparseBitVector {
|
|||
public:
|
||||
using iterator = SparseBitVectorIterator;
|
||||
|
||||
SparseBitVector() {
|
||||
CurrElementIter = Elements.begin();
|
||||
}
|
||||
SparseBitVector() : Elements(), CurrElementIter(Elements.begin()) {}
|
||||
|
||||
// SparseBitVector copy ctor.
|
||||
SparseBitVector(const SparseBitVector &RHS) {
|
||||
ElementListConstIter ElementIter = RHS.Elements.begin();
|
||||
while (ElementIter != RHS.Elements.end()) {
|
||||
Elements.push_back(SparseBitVectorElement<ElementSize>(*ElementIter));
|
||||
++ElementIter;
|
||||
}
|
||||
|
||||
CurrElementIter = Elements.begin ();
|
||||
}
|
||||
|
||||
~SparseBitVector() = default;
|
||||
SparseBitVector(const SparseBitVector &RHS)
|
||||
: Elements(RHS.Elements), CurrElementIter(Elements.begin()) {}
|
||||
SparseBitVector(SparseBitVector &&RHS)
|
||||
: Elements(std::move(RHS.Elements)), CurrElementIter(Elements.begin()) {}
|
||||
|
||||
// Clear.
|
||||
void clear() {
|
||||
|
|
@ -450,26 +458,23 @@ public:
|
|||
if (this == &RHS)
|
||||
return *this;
|
||||
|
||||
Elements.clear();
|
||||
|
||||
ElementListConstIter ElementIter = RHS.Elements.begin();
|
||||
while (ElementIter != RHS.Elements.end()) {
|
||||
Elements.push_back(SparseBitVectorElement<ElementSize>(*ElementIter));
|
||||
++ElementIter;
|
||||
}
|
||||
|
||||
CurrElementIter = Elements.begin ();
|
||||
|
||||
Elements = RHS.Elements;
|
||||
CurrElementIter = Elements.begin();
|
||||
return *this;
|
||||
}
|
||||
SparseBitVector &operator=(SparseBitVector &&RHS) {
|
||||
Elements = std::move(RHS.Elements);
|
||||
CurrElementIter = Elements.begin();
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Test, Reset, and Set a bit in the bitmap.
|
||||
bool test(unsigned Idx) {
|
||||
bool test(unsigned Idx) const {
|
||||
if (Elements.empty())
|
||||
return false;
|
||||
|
||||
unsigned ElementIndex = Idx / ElementSize;
|
||||
ElementListIter ElementIter = FindLowerBound(ElementIndex);
|
||||
ElementListConstIter ElementIter = FindLowerBoundConst(ElementIndex);
|
||||
|
||||
// If we can't find an element that is supposed to contain this bit, there
|
||||
// is nothing more to do.
|
||||
|
|
|
|||
|
|
@ -139,22 +139,23 @@ inline std::string utohexstr(uint64_t X, bool LowerCase = false) {
|
|||
|
||||
/// Convert buffer \p Input to its hexadecimal representation.
|
||||
/// The returned string is double the size of \p Input.
|
||||
inline std::string toHex(StringRef Input) {
|
||||
inline std::string toHex(StringRef Input, bool LowerCase = false) {
|
||||
static const char *const LUT = "0123456789ABCDEF";
|
||||
const uint8_t Offset = LowerCase ? 32 : 0;
|
||||
size_t Length = Input.size();
|
||||
|
||||
std::string Output;
|
||||
Output.reserve(2 * Length);
|
||||
for (size_t i = 0; i < Length; ++i) {
|
||||
const unsigned char c = Input[i];
|
||||
Output.push_back(LUT[c >> 4]);
|
||||
Output.push_back(LUT[c & 15]);
|
||||
Output.push_back(LUT[c >> 4] | Offset);
|
||||
Output.push_back(LUT[c & 15] | Offset);
|
||||
}
|
||||
return Output;
|
||||
}
|
||||
|
||||
inline std::string toHex(ArrayRef<uint8_t> Input) {
|
||||
return toHex(toStringRef(Input));
|
||||
inline std::string toHex(ArrayRef<uint8_t> Input, bool LowerCase = false) {
|
||||
return toHex(toStringRef(Input), LowerCase);
|
||||
}
|
||||
|
||||
inline uint8_t hexFromNibbles(char MSB, char LSB) {
|
||||
|
|
|
|||
|
|
@ -55,12 +55,11 @@ public:
|
|||
bpfel, // eBPF or extended BPF or 64-bit BPF (little endian)
|
||||
bpfeb, // eBPF or extended BPF or 64-bit BPF (big endian)
|
||||
hexagon, // Hexagon: hexagon
|
||||
mips, // MIPS: mips, mipsallegrex
|
||||
mipsel, // MIPSEL: mipsel, mipsallegrexel
|
||||
mips64, // MIPS64: mips64
|
||||
mips64el, // MIPS64EL: mips64el
|
||||
mips, // MIPS: mips, mipsallegrex, mipsr6
|
||||
mipsel, // MIPSEL: mipsel, mipsallegrexe, mipsr6el
|
||||
mips64, // MIPS64: mips64, mips64r6, mipsn32, mipsn32r6
|
||||
mips64el, // MIPS64EL: mips64el, mips64r6el, mipsn32el, mipsn32r6el
|
||||
msp430, // MSP430: msp430
|
||||
nios2, // NIOSII: nios2
|
||||
ppc, // PPC: powerpc
|
||||
ppc64, // PPC64: powerpc64, ppu
|
||||
ppc64le, // PPC64LE: powerpc64le
|
||||
|
|
@ -101,6 +100,7 @@ public:
|
|||
enum SubArchType {
|
||||
NoSubArch,
|
||||
|
||||
ARMSubArch_v8_5a,
|
||||
ARMSubArch_v8_4a,
|
||||
ARMSubArch_v8_3a,
|
||||
ARMSubArch_v8_2a,
|
||||
|
|
@ -125,7 +125,9 @@ public:
|
|||
|
||||
KalimbaSubArch_v3,
|
||||
KalimbaSubArch_v4,
|
||||
KalimbaSubArch_v5
|
||||
KalimbaSubArch_v5,
|
||||
|
||||
MipsSubArch_r6
|
||||
};
|
||||
enum VendorType {
|
||||
UnknownVendor,
|
||||
|
|
@ -182,7 +184,10 @@ public:
|
|||
Mesa3D,
|
||||
Contiki,
|
||||
AMDPAL, // AMD PAL Runtime
|
||||
LastOSType = AMDPAL
|
||||
HermitCore, // HermitCore Unikernel/Multikernel
|
||||
Hurd, // GNU/Hurd
|
||||
WASI, // Experimental WebAssembly OS
|
||||
LastOSType = WASI
|
||||
};
|
||||
enum EnvironmentType {
|
||||
UnknownEnvironment,
|
||||
|
|
@ -578,9 +583,20 @@ public:
|
|||
return getOS() == Triple::KFreeBSD;
|
||||
}
|
||||
|
||||
/// Tests whether the OS is Hurd.
|
||||
bool isOSHurd() const {
|
||||
return getOS() == Triple::Hurd;
|
||||
}
|
||||
|
||||
/// Tests whether the OS is WASI.
|
||||
bool isOSWASI() const {
|
||||
return getOS() == Triple::WASI;
|
||||
}
|
||||
|
||||
/// Tests whether the OS uses glibc.
|
||||
bool isOSGlibc() const {
|
||||
return (getOS() == Triple::Linux || getOS() == Triple::KFreeBSD) &&
|
||||
return (getOS() == Triple::Linux || getOS() == Triple::KFreeBSD ||
|
||||
getOS() == Triple::Hurd) &&
|
||||
!isAndroid();
|
||||
}
|
||||
|
||||
|
|
|
|||
59
contrib/llvm/include/llvm/ADT/bit.h
Normal file
59
contrib/llvm/include/llvm/ADT/bit.h
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
//===-- llvm/ADT/bit.h - C++20 <bit> ----------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the C++20 <bit> header.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ADT_BIT_H
|
||||
#define LLVM_ADT_BIT_H
|
||||
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include <cstring>
|
||||
#include <type_traits>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
// This implementation of bit_cast is different from the C++17 one in two ways:
|
||||
// - It isn't constexpr because that requires compiler support.
|
||||
// - It requires trivially-constructible To, to avoid UB in the implementation.
|
||||
template <typename To, typename From
|
||||
, typename = typename std::enable_if<sizeof(To) == sizeof(From)>::type
|
||||
#if (__has_feature(is_trivially_constructible) && defined(_LIBCPP_VERSION)) || \
|
||||
(defined(__GNUC__) && __GNUC__ >= 5)
|
||||
, typename = typename std::is_trivially_constructible<To>::type
|
||||
#elif __has_feature(is_trivially_constructible)
|
||||
, typename = typename std::enable_if<__is_trivially_constructible(To)>::type
|
||||
#else
|
||||
// See comment below.
|
||||
#endif
|
||||
#if (__has_feature(is_trivially_copyable) && defined(_LIBCPP_VERSION)) || \
|
||||
(defined(__GNUC__) && __GNUC__ >= 5)
|
||||
, typename = typename std::enable_if<std::is_trivially_copyable<To>::value>::type
|
||||
, typename = typename std::enable_if<std::is_trivially_copyable<From>::value>::type
|
||||
#elif __has_feature(is_trivially_copyable)
|
||||
, typename = typename std::enable_if<__is_trivially_copyable(To)>::type
|
||||
, typename = typename std::enable_if<__is_trivially_copyable(From)>::type
|
||||
#else
|
||||
// This case is GCC 4.x. clang with libc++ or libstdc++ never get here. Unlike
|
||||
// llvm/Support/type_traits.h's isPodLike we don't want to provide a
|
||||
// good-enough answer here: developers in that configuration will hit
|
||||
// compilation failures on the bots instead of locally. That's acceptable
|
||||
// because it's very few developers, and only until we move past C++11.
|
||||
#endif
|
||||
>
|
||||
inline To bit_cast(const From &from) noexcept {
|
||||
To to;
|
||||
std::memcpy(&to, &from, sizeof(To));
|
||||
return to;
|
||||
}
|
||||
|
||||
} // namespace llvm
|
||||
|
||||
#endif
|
||||
|
|
@ -202,9 +202,7 @@ template <
|
|||
typename ReferenceT = typename std::conditional<
|
||||
std::is_same<T, typename std::iterator_traits<
|
||||
WrappedIteratorT>::value_type>::value,
|
||||
typename std::iterator_traits<WrappedIteratorT>::reference, T &>::type,
|
||||
// Don't provide these, they are mostly to act as aliases below.
|
||||
typename WrappedTraitsT = std::iterator_traits<WrappedIteratorT>>
|
||||
typename std::iterator_traits<WrappedIteratorT>::reference, T &>::type>
|
||||
class iterator_adaptor_base
|
||||
: public iterator_facade_base<DerivedT, IteratorCategoryT, T,
|
||||
DifferenceTypeT, PointerT, ReferenceT> {
|
||||
|
|
@ -311,8 +309,10 @@ make_pointee_range(RangeT &&Range) {
|
|||
template <typename WrappedIteratorT,
|
||||
typename T = decltype(&*std::declval<WrappedIteratorT>())>
|
||||
class pointer_iterator
|
||||
: public iterator_adaptor_base<pointer_iterator<WrappedIteratorT, T>,
|
||||
WrappedIteratorT, T> {
|
||||
: public iterator_adaptor_base<
|
||||
pointer_iterator<WrappedIteratorT, T>, WrappedIteratorT,
|
||||
typename std::iterator_traits<WrappedIteratorT>::iterator_category,
|
||||
T> {
|
||||
mutable T Ptr;
|
||||
|
||||
public:
|
||||
|
|
@ -334,6 +334,34 @@ make_pointer_range(RangeT &&Range) {
|
|||
PointerIteratorT(std::end(std::forward<RangeT>(Range))));
|
||||
}
|
||||
|
||||
// Wrapper iterator over iterator ItType, adding DataRef to the type of ItType,
|
||||
// to create NodeRef = std::pair<InnerTypeOfItType, DataRef>.
|
||||
template <typename ItType, typename NodeRef, typename DataRef>
|
||||
class WrappedPairNodeDataIterator
|
||||
: public iterator_adaptor_base<
|
||||
WrappedPairNodeDataIterator<ItType, NodeRef, DataRef>, ItType,
|
||||
typename std::iterator_traits<ItType>::iterator_category, NodeRef,
|
||||
std::ptrdiff_t, NodeRef *, NodeRef &> {
|
||||
using BaseT = iterator_adaptor_base<
|
||||
WrappedPairNodeDataIterator, ItType,
|
||||
typename std::iterator_traits<ItType>::iterator_category, NodeRef,
|
||||
std::ptrdiff_t, NodeRef *, NodeRef &>;
|
||||
|
||||
const DataRef DR;
|
||||
mutable NodeRef NR;
|
||||
|
||||
public:
|
||||
WrappedPairNodeDataIterator(ItType Begin, const DataRef DR)
|
||||
: BaseT(Begin), DR(DR) {
|
||||
NR.first = DR;
|
||||
}
|
||||
|
||||
NodeRef &operator*() const {
|
||||
NR.second = *this->I;
|
||||
return NR;
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_ADT_ITERATOR_H
|
||||
|
|
|
|||
|
|
@ -43,7 +43,6 @@
|
|||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/Analysis/MemoryLocation.h"
|
||||
#include "llvm/Analysis/TargetLibraryInfo.h"
|
||||
#include "llvm/IR/CallSite.h"
|
||||
#include "llvm/IR/Function.h"
|
||||
#include "llvm/IR/Instruction.h"
|
||||
#include "llvm/IR/Instructions.h"
|
||||
|
|
@ -335,8 +334,7 @@ public:
|
|||
|
||||
/// A convenience wrapper around the primary \c alias interface.
|
||||
AliasResult alias(const Value *V1, const Value *V2) {
|
||||
return alias(V1, MemoryLocation::UnknownSize, V2,
|
||||
MemoryLocation::UnknownSize);
|
||||
return alias(V1, LocationSize::unknown(), V2, LocationSize::unknown());
|
||||
}
|
||||
|
||||
/// A trivial helper function to check to see if the specified pointers are
|
||||
|
|
@ -364,7 +362,8 @@ public:
|
|||
|
||||
/// A convenience wrapper around the \c isMustAlias helper interface.
|
||||
bool isMustAlias(const Value *V1, const Value *V2) {
|
||||
return alias(V1, 1, V2, 1) == MustAlias;
|
||||
return alias(V1, LocationSize::precise(1), V2, LocationSize::precise(1)) ==
|
||||
MustAlias;
|
||||
}
|
||||
|
||||
/// Checks whether the given location points to constant memory, or if
|
||||
|
|
@ -382,15 +381,15 @@ public:
|
|||
/// \name Simple mod/ref information
|
||||
/// @{
|
||||
|
||||
/// Get the ModRef info associated with a pointer argument of a callsite. The
|
||||
/// Get the ModRef info associated with a pointer argument of a call. The
|
||||
/// result's bits are set to indicate the allowed aliasing ModRef kinds. Note
|
||||
/// that these bits do not necessarily account for the overall behavior of
|
||||
/// the function, but rather only provide additional per-argument
|
||||
/// information. This never sets ModRefInfo::Must.
|
||||
ModRefInfo getArgModRefInfo(ImmutableCallSite CS, unsigned ArgIdx);
|
||||
ModRefInfo getArgModRefInfo(const CallBase *Call, unsigned ArgIdx);
|
||||
|
||||
/// Return the behavior of the given call site.
|
||||
FunctionModRefBehavior getModRefBehavior(ImmutableCallSite CS);
|
||||
FunctionModRefBehavior getModRefBehavior(const CallBase *Call);
|
||||
|
||||
/// Return the behavior when calling the given function.
|
||||
FunctionModRefBehavior getModRefBehavior(const Function *F);
|
||||
|
|
@ -406,8 +405,8 @@ public:
|
|||
/// property (e.g. calls to 'sin' and 'cos').
|
||||
///
|
||||
/// This property corresponds to the GCC 'const' attribute.
|
||||
bool doesNotAccessMemory(ImmutableCallSite CS) {
|
||||
return getModRefBehavior(CS) == FMRB_DoesNotAccessMemory;
|
||||
bool doesNotAccessMemory(const CallBase *Call) {
|
||||
return getModRefBehavior(Call) == FMRB_DoesNotAccessMemory;
|
||||
}
|
||||
|
||||
/// Checks if the specified function is known to never read or write memory.
|
||||
|
|
@ -434,8 +433,8 @@ public:
|
|||
/// absence of interfering store instructions, such as CSE of strlen calls.
|
||||
///
|
||||
/// This property corresponds to the GCC 'pure' attribute.
|
||||
bool onlyReadsMemory(ImmutableCallSite CS) {
|
||||
return onlyReadsMemory(getModRefBehavior(CS));
|
||||
bool onlyReadsMemory(const CallBase *Call) {
|
||||
return onlyReadsMemory(getModRefBehavior(Call));
|
||||
}
|
||||
|
||||
/// Checks if the specified function is known to only read from non-volatile
|
||||
|
|
@ -500,36 +499,12 @@ public:
|
|||
|
||||
/// getModRefInfo (for call sites) - Return information about whether
|
||||
/// a particular call site modifies or reads the specified memory location.
|
||||
ModRefInfo getModRefInfo(ImmutableCallSite CS, const MemoryLocation &Loc);
|
||||
ModRefInfo getModRefInfo(const CallBase *Call, const MemoryLocation &Loc);
|
||||
|
||||
/// getModRefInfo (for call sites) - A convenience wrapper.
|
||||
ModRefInfo getModRefInfo(ImmutableCallSite CS, const Value *P,
|
||||
ModRefInfo getModRefInfo(const CallBase *Call, const Value *P,
|
||||
LocationSize Size) {
|
||||
return getModRefInfo(CS, MemoryLocation(P, Size));
|
||||
}
|
||||
|
||||
/// getModRefInfo (for calls) - Return information about whether
|
||||
/// a particular call modifies or reads the specified memory location.
|
||||
ModRefInfo getModRefInfo(const CallInst *C, const MemoryLocation &Loc) {
|
||||
return getModRefInfo(ImmutableCallSite(C), Loc);
|
||||
}
|
||||
|
||||
/// getModRefInfo (for calls) - A convenience wrapper.
|
||||
ModRefInfo getModRefInfo(const CallInst *C, const Value *P,
|
||||
LocationSize Size) {
|
||||
return getModRefInfo(C, MemoryLocation(P, Size));
|
||||
}
|
||||
|
||||
/// getModRefInfo (for invokes) - Return information about whether
|
||||
/// a particular invoke modifies or reads the specified memory location.
|
||||
ModRefInfo getModRefInfo(const InvokeInst *I, const MemoryLocation &Loc) {
|
||||
return getModRefInfo(ImmutableCallSite(I), Loc);
|
||||
}
|
||||
|
||||
/// getModRefInfo (for invokes) - A convenience wrapper.
|
||||
ModRefInfo getModRefInfo(const InvokeInst *I, const Value *P,
|
||||
LocationSize Size) {
|
||||
return getModRefInfo(I, MemoryLocation(P, Size));
|
||||
return getModRefInfo(Call, MemoryLocation(P, Size));
|
||||
}
|
||||
|
||||
/// getModRefInfo (for loads) - Return information about whether
|
||||
|
|
@ -569,7 +544,7 @@ public:
|
|||
|
||||
/// getModRefInfo (for cmpxchges) - A convenience wrapper.
|
||||
ModRefInfo getModRefInfo(const AtomicCmpXchgInst *CX, const Value *P,
|
||||
unsigned Size) {
|
||||
LocationSize Size) {
|
||||
return getModRefInfo(CX, MemoryLocation(P, Size));
|
||||
}
|
||||
|
||||
|
|
@ -579,7 +554,7 @@ public:
|
|||
|
||||
/// getModRefInfo (for atomicrmws) - A convenience wrapper.
|
||||
ModRefInfo getModRefInfo(const AtomicRMWInst *RMW, const Value *P,
|
||||
unsigned Size) {
|
||||
LocationSize Size) {
|
||||
return getModRefInfo(RMW, MemoryLocation(P, Size));
|
||||
}
|
||||
|
||||
|
|
@ -626,8 +601,8 @@ public:
|
|||
ModRefInfo getModRefInfo(const Instruction *I,
|
||||
const Optional<MemoryLocation> &OptLoc) {
|
||||
if (OptLoc == None) {
|
||||
if (auto CS = ImmutableCallSite(I)) {
|
||||
return createModRefInfo(getModRefBehavior(CS));
|
||||
if (const auto *Call = dyn_cast<CallBase>(I)) {
|
||||
return createModRefInfo(getModRefBehavior(Call));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -661,12 +636,12 @@ public:
|
|||
|
||||
/// Return information about whether a call and an instruction may refer to
|
||||
/// the same memory locations.
|
||||
ModRefInfo getModRefInfo(Instruction *I, ImmutableCallSite Call);
|
||||
ModRefInfo getModRefInfo(Instruction *I, const CallBase *Call);
|
||||
|
||||
/// Return information about whether two call sites may refer to the same set
|
||||
/// of memory locations. See the AA documentation for details:
|
||||
/// http://llvm.org/docs/AliasAnalysis.html#ModRefInfo
|
||||
ModRefInfo getModRefInfo(ImmutableCallSite CS1, ImmutableCallSite CS2);
|
||||
ModRefInfo getModRefInfo(const CallBase *Call1, const CallBase *Call2);
|
||||
|
||||
/// Return information about whether a particular call site modifies
|
||||
/// or reads the specified memory location \p MemLoc before instruction \p I
|
||||
|
|
@ -777,25 +752,25 @@ public:
|
|||
/// that these bits do not necessarily account for the overall behavior of
|
||||
/// the function, but rather only provide additional per-argument
|
||||
/// information.
|
||||
virtual ModRefInfo getArgModRefInfo(ImmutableCallSite CS,
|
||||
virtual ModRefInfo getArgModRefInfo(const CallBase *Call,
|
||||
unsigned ArgIdx) = 0;
|
||||
|
||||
/// Return the behavior of the given call site.
|
||||
virtual FunctionModRefBehavior getModRefBehavior(ImmutableCallSite CS) = 0;
|
||||
virtual FunctionModRefBehavior getModRefBehavior(const CallBase *Call) = 0;
|
||||
|
||||
/// Return the behavior when calling the given function.
|
||||
virtual FunctionModRefBehavior getModRefBehavior(const Function *F) = 0;
|
||||
|
||||
/// getModRefInfo (for call sites) - Return information about whether
|
||||
/// a particular call site modifies or reads the specified memory location.
|
||||
virtual ModRefInfo getModRefInfo(ImmutableCallSite CS,
|
||||
virtual ModRefInfo getModRefInfo(const CallBase *Call,
|
||||
const MemoryLocation &Loc) = 0;
|
||||
|
||||
/// Return information about whether two call sites may refer to the same set
|
||||
/// of memory locations. See the AA documentation for details:
|
||||
/// http://llvm.org/docs/AliasAnalysis.html#ModRefInfo
|
||||
virtual ModRefInfo getModRefInfo(ImmutableCallSite CS1,
|
||||
ImmutableCallSite CS2) = 0;
|
||||
virtual ModRefInfo getModRefInfo(const CallBase *Call1,
|
||||
const CallBase *Call2) = 0;
|
||||
|
||||
/// @}
|
||||
};
|
||||
|
|
@ -827,26 +802,26 @@ public:
|
|||
return Result.pointsToConstantMemory(Loc, OrLocal);
|
||||
}
|
||||
|
||||
ModRefInfo getArgModRefInfo(ImmutableCallSite CS, unsigned ArgIdx) override {
|
||||
return Result.getArgModRefInfo(CS, ArgIdx);
|
||||
ModRefInfo getArgModRefInfo(const CallBase *Call, unsigned ArgIdx) override {
|
||||
return Result.getArgModRefInfo(Call, ArgIdx);
|
||||
}
|
||||
|
||||
FunctionModRefBehavior getModRefBehavior(ImmutableCallSite CS) override {
|
||||
return Result.getModRefBehavior(CS);
|
||||
FunctionModRefBehavior getModRefBehavior(const CallBase *Call) override {
|
||||
return Result.getModRefBehavior(Call);
|
||||
}
|
||||
|
||||
FunctionModRefBehavior getModRefBehavior(const Function *F) override {
|
||||
return Result.getModRefBehavior(F);
|
||||
}
|
||||
|
||||
ModRefInfo getModRefInfo(ImmutableCallSite CS,
|
||||
ModRefInfo getModRefInfo(const CallBase *Call,
|
||||
const MemoryLocation &Loc) override {
|
||||
return Result.getModRefInfo(CS, Loc);
|
||||
return Result.getModRefInfo(Call, Loc);
|
||||
}
|
||||
|
||||
ModRefInfo getModRefInfo(ImmutableCallSite CS1,
|
||||
ImmutableCallSite CS2) override {
|
||||
return Result.getModRefInfo(CS1, CS2);
|
||||
ModRefInfo getModRefInfo(const CallBase *Call1,
|
||||
const CallBase *Call2) override {
|
||||
return Result.getModRefInfo(Call1, Call2);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -901,25 +876,28 @@ protected:
|
|||
: CurrentResult.pointsToConstantMemory(Loc, OrLocal);
|
||||
}
|
||||
|
||||
ModRefInfo getArgModRefInfo(ImmutableCallSite CS, unsigned ArgIdx) {
|
||||
return AAR ? AAR->getArgModRefInfo(CS, ArgIdx) : CurrentResult.getArgModRefInfo(CS, ArgIdx);
|
||||
ModRefInfo getArgModRefInfo(const CallBase *Call, unsigned ArgIdx) {
|
||||
return AAR ? AAR->getArgModRefInfo(Call, ArgIdx)
|
||||
: CurrentResult.getArgModRefInfo(Call, ArgIdx);
|
||||
}
|
||||
|
||||
FunctionModRefBehavior getModRefBehavior(ImmutableCallSite CS) {
|
||||
return AAR ? AAR->getModRefBehavior(CS) : CurrentResult.getModRefBehavior(CS);
|
||||
FunctionModRefBehavior getModRefBehavior(const CallBase *Call) {
|
||||
return AAR ? AAR->getModRefBehavior(Call)
|
||||
: CurrentResult.getModRefBehavior(Call);
|
||||
}
|
||||
|
||||
FunctionModRefBehavior getModRefBehavior(const Function *F) {
|
||||
return AAR ? AAR->getModRefBehavior(F) : CurrentResult.getModRefBehavior(F);
|
||||
}
|
||||
|
||||
ModRefInfo getModRefInfo(ImmutableCallSite CS, const MemoryLocation &Loc) {
|
||||
return AAR ? AAR->getModRefInfo(CS, Loc)
|
||||
: CurrentResult.getModRefInfo(CS, Loc);
|
||||
ModRefInfo getModRefInfo(const CallBase *Call, const MemoryLocation &Loc) {
|
||||
return AAR ? AAR->getModRefInfo(Call, Loc)
|
||||
: CurrentResult.getModRefInfo(Call, Loc);
|
||||
}
|
||||
|
||||
ModRefInfo getModRefInfo(ImmutableCallSite CS1, ImmutableCallSite CS2) {
|
||||
return AAR ? AAR->getModRefInfo(CS1, CS2) : CurrentResult.getModRefInfo(CS1, CS2);
|
||||
ModRefInfo getModRefInfo(const CallBase *Call1, const CallBase *Call2) {
|
||||
return AAR ? AAR->getModRefInfo(Call1, Call2)
|
||||
: CurrentResult.getModRefInfo(Call1, Call2);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -951,11 +929,11 @@ public:
|
|||
return false;
|
||||
}
|
||||
|
||||
ModRefInfo getArgModRefInfo(ImmutableCallSite CS, unsigned ArgIdx) {
|
||||
ModRefInfo getArgModRefInfo(const CallBase *Call, unsigned ArgIdx) {
|
||||
return ModRefInfo::ModRef;
|
||||
}
|
||||
|
||||
FunctionModRefBehavior getModRefBehavior(ImmutableCallSite CS) {
|
||||
FunctionModRefBehavior getModRefBehavior(const CallBase *Call) {
|
||||
return FMRB_UnknownModRefBehavior;
|
||||
}
|
||||
|
||||
|
|
@ -963,11 +941,11 @@ public:
|
|||
return FMRB_UnknownModRefBehavior;
|
||||
}
|
||||
|
||||
ModRefInfo getModRefInfo(ImmutableCallSite CS, const MemoryLocation &Loc) {
|
||||
ModRefInfo getModRefInfo(const CallBase *Call, const MemoryLocation &Loc) {
|
||||
return ModRefInfo::ModRef;
|
||||
}
|
||||
|
||||
ModRefInfo getModRefInfo(ImmutableCallSite CS1, ImmutableCallSite CS2) {
|
||||
ModRefInfo getModRefInfo(const CallBase *Call1, const CallBase *Call2) {
|
||||
return ModRefInfo::ModRef;
|
||||
}
|
||||
};
|
||||
|
|
@ -1075,6 +1053,29 @@ public:
|
|||
void getAnalysisUsage(AnalysisUsage &AU) const override;
|
||||
};
|
||||
|
||||
/// A wrapper pass for external alias analyses. This just squirrels away the
|
||||
/// callback used to run any analyses and register their results.
|
||||
struct ExternalAAWrapperPass : ImmutablePass {
|
||||
using CallbackT = std::function<void(Pass &, Function &, AAResults &)>;
|
||||
|
||||
CallbackT CB;
|
||||
|
||||
static char ID;
|
||||
|
||||
ExternalAAWrapperPass() : ImmutablePass(ID) {
|
||||
initializeExternalAAWrapperPassPass(*PassRegistry::getPassRegistry());
|
||||
}
|
||||
|
||||
explicit ExternalAAWrapperPass(CallbackT CB)
|
||||
: ImmutablePass(ID), CB(std::move(CB)) {
|
||||
initializeExternalAAWrapperPassPass(*PassRegistry::getPassRegistry());
|
||||
}
|
||||
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
||||
AU.setPreservesAll();
|
||||
}
|
||||
};
|
||||
|
||||
FunctionPass *createAAResultsWrapperPass();
|
||||
|
||||
/// A wrapper pass around a callback which can be used to populate the
|
||||
|
|
|
|||
|
|
@ -52,9 +52,13 @@ class AliasSet : public ilist_node<AliasSet> {
|
|||
PointerRec **PrevInList = nullptr;
|
||||
PointerRec *NextInList = nullptr;
|
||||
AliasSet *AS = nullptr;
|
||||
LocationSize Size = 0;
|
||||
LocationSize Size = LocationSize::mapEmpty();
|
||||
AAMDNodes AAInfo;
|
||||
|
||||
// Whether the size for this record has been set at all. This makes no
|
||||
// guarantees about the size being known.
|
||||
bool isSizeSet() const { return Size != LocationSize::mapEmpty(); }
|
||||
|
||||
public:
|
||||
PointerRec(Value *V)
|
||||
: Val(V), AAInfo(DenseMapInfo<AAMDNodes>::getEmptyKey()) {}
|
||||
|
|
@ -71,9 +75,10 @@ class AliasSet : public ilist_node<AliasSet> {
|
|||
|
||||
bool updateSizeAndAAInfo(LocationSize NewSize, const AAMDNodes &NewAAInfo) {
|
||||
bool SizeChanged = false;
|
||||
if (NewSize > Size) {
|
||||
Size = NewSize;
|
||||
SizeChanged = true;
|
||||
if (NewSize != Size) {
|
||||
LocationSize OldSize = Size;
|
||||
Size = isSizeSet() ? Size.unionWith(NewSize) : NewSize;
|
||||
SizeChanged = OldSize != Size;
|
||||
}
|
||||
|
||||
if (AAInfo == DenseMapInfo<AAMDNodes>::getEmptyKey())
|
||||
|
|
@ -91,7 +96,10 @@ class AliasSet : public ilist_node<AliasSet> {
|
|||
return SizeChanged;
|
||||
}
|
||||
|
||||
LocationSize getSize() const { return Size; }
|
||||
LocationSize getSize() const {
|
||||
assert(isSizeSet() && "Getting an unset size!");
|
||||
return Size;
|
||||
}
|
||||
|
||||
/// Return the AAInfo, or null if there is no information or conflicting
|
||||
/// information.
|
||||
|
|
@ -175,9 +183,6 @@ class AliasSet : public ilist_node<AliasSet> {
|
|||
};
|
||||
unsigned Alias : 1;
|
||||
|
||||
/// True if this alias set contains volatile loads or stores.
|
||||
unsigned Volatile : 1;
|
||||
|
||||
unsigned SetSize = 0;
|
||||
|
||||
void addRef() { ++RefCount; }
|
||||
|
|
@ -203,9 +208,6 @@ public:
|
|||
bool isMustAlias() const { return Alias == SetMustAlias; }
|
||||
bool isMayAlias() const { return Alias == SetMayAlias; }
|
||||
|
||||
/// Return true if this alias set contains volatile loads or stores.
|
||||
bool isVolatile() const { return Volatile; }
|
||||
|
||||
/// Return true if this alias set should be ignored as part of the
|
||||
/// AliasSetTracker object.
|
||||
bool isForwardingAliasSet() const { return Forward; }
|
||||
|
|
@ -224,6 +226,10 @@ public:
|
|||
// track of the list's exact size.
|
||||
unsigned size() { return SetSize; }
|
||||
|
||||
/// If this alias set is known to contain a single instruction and *only* a
|
||||
/// single unique instruction, return it. Otherwise, return nullptr.
|
||||
Instruction* getUniqueInstruction();
|
||||
|
||||
void print(raw_ostream &OS) const;
|
||||
void dump() const;
|
||||
|
||||
|
|
@ -264,7 +270,7 @@ private:
|
|||
// Can only be created by AliasSetTracker.
|
||||
AliasSet()
|
||||
: PtrListEnd(&PtrList), RefCount(0), AliasAny(false), Access(NoAccess),
|
||||
Alias(SetMustAlias), Volatile(false) {}
|
||||
Alias(SetMustAlias) {}
|
||||
|
||||
PointerRec *getSomePointer() const {
|
||||
return PtrList;
|
||||
|
|
@ -303,8 +309,6 @@ private:
|
|||
dropRef(AST);
|
||||
}
|
||||
|
||||
void setVolatile() { Volatile = true; }
|
||||
|
||||
public:
|
||||
/// Return true if the specified pointer "may" (or must) alias one of the
|
||||
/// members in the set.
|
||||
|
|
@ -379,23 +383,11 @@ public:
|
|||
/// Return the alias sets that are active.
|
||||
const ilist<AliasSet> &getAliasSets() const { return AliasSets; }
|
||||
|
||||
/// Return the alias set that the specified pointer lives in. If the New
|
||||
/// argument is non-null, this method sets the value to true if a new alias
|
||||
/// set is created to contain the pointer (because the pointer didn't alias
|
||||
/// anything).
|
||||
AliasSet &getAliasSetForPointer(Value *P, LocationSize Size,
|
||||
const AAMDNodes &AAInfo);
|
||||
|
||||
/// Return the alias set containing the location specified if one exists,
|
||||
/// otherwise return null.
|
||||
AliasSet *getAliasSetForPointerIfExists(const Value *P, LocationSize Size,
|
||||
const AAMDNodes &AAInfo) {
|
||||
return mergeAliasSetsForPointer(P, Size, AAInfo);
|
||||
}
|
||||
|
||||
/// Return true if the specified instruction "may" (or must) alias one of the
|
||||
/// members in any of the sets.
|
||||
bool containsUnknown(const Instruction *I) const;
|
||||
/// Return the alias set which contains the specified memory location. If
|
||||
/// the memory location aliases two or more existing alias sets, will have
|
||||
/// the effect of merging those alias sets before the single resulting alias
|
||||
/// set is returned.
|
||||
AliasSet &getAliasSetFor(const MemoryLocation &MemLoc);
|
||||
|
||||
/// Return the underlying alias analysis object used by this tracker.
|
||||
AliasAnalysis &getAliasAnalysis() const { return AA; }
|
||||
|
|
@ -445,8 +437,7 @@ private:
|
|||
return *Entry;
|
||||
}
|
||||
|
||||
AliasSet &addPointer(Value *P, LocationSize Size, const AAMDNodes &AAInfo,
|
||||
AliasSet::AccessLattice E);
|
||||
AliasSet &addPointer(MemoryLocation Loc, AliasSet::AccessLattice E);
|
||||
AliasSet *mergeAliasSetsForPointer(const Value *Ptr, LocationSize Size,
|
||||
const AAMDNodes &AAInfo);
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@
|
|||
#include "llvm/Analysis/AliasAnalysis.h"
|
||||
#include "llvm/Analysis/AssumptionCache.h"
|
||||
#include "llvm/Analysis/MemoryLocation.h"
|
||||
#include "llvm/IR/CallSite.h"
|
||||
#include "llvm/IR/InstrTypes.h"
|
||||
#include "llvm/IR/PassManager.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include <algorithm>
|
||||
|
|
@ -84,18 +84,18 @@ public:
|
|||
|
||||
AliasResult alias(const MemoryLocation &LocA, const MemoryLocation &LocB);
|
||||
|
||||
ModRefInfo getModRefInfo(ImmutableCallSite CS, const MemoryLocation &Loc);
|
||||
ModRefInfo getModRefInfo(const CallBase *Call, const MemoryLocation &Loc);
|
||||
|
||||
ModRefInfo getModRefInfo(ImmutableCallSite CS1, ImmutableCallSite CS2);
|
||||
ModRefInfo getModRefInfo(const CallBase *Call1, const CallBase *Call2);
|
||||
|
||||
/// Chases pointers until we find a (constant global) or not.
|
||||
bool pointsToConstantMemory(const MemoryLocation &Loc, bool OrLocal);
|
||||
|
||||
/// Get the location associated with a pointer argument of a callsite.
|
||||
ModRefInfo getArgModRefInfo(ImmutableCallSite CS, unsigned ArgIdx);
|
||||
ModRefInfo getArgModRefInfo(const CallBase *Call, unsigned ArgIdx);
|
||||
|
||||
/// Returns the behavior when calling the given call site.
|
||||
FunctionModRefBehavior getModRefBehavior(ImmutableCallSite CS);
|
||||
FunctionModRefBehavior getModRefBehavior(const CallBase *Call);
|
||||
|
||||
/// Returns the behavior when calling the given function. For use when the
|
||||
/// call site is not known.
|
||||
|
|
@ -115,7 +115,7 @@ private:
|
|||
unsigned ZExtBits;
|
||||
unsigned SExtBits;
|
||||
|
||||
int64_t Scale;
|
||||
APInt Scale;
|
||||
|
||||
bool operator==(const VariableGEPIndex &Other) const {
|
||||
return V == Other.V && ZExtBits == Other.ZExtBits &&
|
||||
|
|
@ -133,10 +133,10 @@ private:
|
|||
// Base pointer of the GEP
|
||||
const Value *Base;
|
||||
// Total constant offset w.r.t the base from indexing into structs
|
||||
int64_t StructOffset;
|
||||
APInt StructOffset;
|
||||
// Total constant offset w.r.t the base from indexing through
|
||||
// pointers/arrays/vectors
|
||||
int64_t OtherOffset;
|
||||
APInt OtherOffset;
|
||||
// Scaled variable (non-constant) indices.
|
||||
SmallVector<VariableGEPIndex, 4> VarIndices;
|
||||
};
|
||||
|
|
@ -189,7 +189,7 @@ private:
|
|||
bool
|
||||
constantOffsetHeuristic(const SmallVectorImpl<VariableGEPIndex> &VarIndices,
|
||||
LocationSize V1Size, LocationSize V2Size,
|
||||
int64_t BaseOffset, AssumptionCache *AC,
|
||||
APInt BaseOffset, AssumptionCache *AC,
|
||||
DominatorTree *DT);
|
||||
|
||||
bool isValueEqualInPotentialCycles(const Value *V1, const Value *V2);
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ public:
|
|||
|
||||
const Function *getFunction() const;
|
||||
const BranchProbabilityInfo *getBPI() const;
|
||||
void view() const;
|
||||
void view(StringRef = "BlockFrequencyDAGs") const;
|
||||
|
||||
/// getblockFreq - Return block frequency. Return 0 if we don't have the
|
||||
/// information. Please note that initial frequency is equal to ENTRY_FREQ. It
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@ class DominatorTree;
|
|||
class Function;
|
||||
class Instruction;
|
||||
class LoopInfo;
|
||||
class TerminatorInst;
|
||||
|
||||
/// Analyze the specified function to find all of the loop backedges in the
|
||||
/// function and return them. This is a relatively cheap (compared to
|
||||
|
|
@ -46,7 +45,7 @@ unsigned GetSuccessorNumber(const BasicBlock *BB, const BasicBlock *Succ);
|
|||
/// edges from a block with multiple successors to a block with multiple
|
||||
/// predecessors.
|
||||
///
|
||||
bool isCriticalEdge(const TerminatorInst *TI, unsigned SuccNum,
|
||||
bool isCriticalEdge(const Instruction *TI, unsigned SuccNum,
|
||||
bool AllowIdenticalEdges = false);
|
||||
|
||||
/// Determine whether instruction 'To' is reachable from 'From',
|
||||
|
|
|
|||
|
|
@ -150,7 +150,7 @@ struct DOTGraphTraits<const Function*> : public DefaultDOTGraphTraits {
|
|||
/// Display the raw branch weights from PGO.
|
||||
std::string getEdgeAttributes(const BasicBlock *Node, succ_const_iterator I,
|
||||
const Function *F) {
|
||||
const TerminatorInst *TI = Node->getTerminator();
|
||||
const Instruction *TI = Node->getTerminator();
|
||||
if (TI->getNumSuccessors() == 1)
|
||||
return "";
|
||||
|
||||
|
|
@ -172,8 +172,7 @@ struct DOTGraphTraits<const Function*> : public DefaultDOTGraphTraits {
|
|||
|
||||
// Prepend a 'W' to indicate that this is a weight rather than the actual
|
||||
// profile count (due to scaling).
|
||||
Twine Attrs = "label=\"W:" + Twine(Weight->getZExtValue()) + "\"";
|
||||
return Attrs.str();
|
||||
return ("label=\"W:" + Twine(Weight->getZExtValue()) + "\"").str();
|
||||
}
|
||||
};
|
||||
} // End llvm namespace
|
||||
|
|
|
|||
|
|
@ -364,6 +364,10 @@ public:
|
|||
InvalidSCCSet, nullptr, nullptr,
|
||||
InlinedInternalEdges};
|
||||
|
||||
// Request PassInstrumentation from analysis manager, will use it to run
|
||||
// instrumenting callbacks for the passes later.
|
||||
PassInstrumentation PI = AM.getResult<PassInstrumentationAnalysis>(M);
|
||||
|
||||
PreservedAnalyses PA = PreservedAnalyses::all();
|
||||
CG.buildRefSCCs();
|
||||
for (auto RCI = CG.postorder_ref_scc_begin(),
|
||||
|
|
@ -428,8 +432,20 @@ public:
|
|||
|
||||
UR.UpdatedRC = nullptr;
|
||||
UR.UpdatedC = nullptr;
|
||||
|
||||
// Check the PassInstrumentation's BeforePass callbacks before
|
||||
// running the pass, skip its execution completely if asked to
|
||||
// (callback returns false).
|
||||
if (!PI.runBeforePass<LazyCallGraph::SCC>(Pass, *C))
|
||||
continue;
|
||||
|
||||
PreservedAnalyses PassPA = Pass.run(*C, CGAM, CG, UR);
|
||||
|
||||
if (UR.InvalidatedSCCs.count(C))
|
||||
PI.runAfterPassInvalidated<LazyCallGraph::SCC>(Pass);
|
||||
else
|
||||
PI.runAfterPass<LazyCallGraph::SCC>(Pass, *C);
|
||||
|
||||
// Update the SCC and RefSCC if necessary.
|
||||
C = UR.UpdatedC ? UR.UpdatedC : C;
|
||||
RC = UR.UpdatedRC ? UR.UpdatedRC : RC;
|
||||
|
|
@ -615,12 +631,20 @@ public:
|
|||
if (CG.lookupSCC(*N) != CurrentC)
|
||||
continue;
|
||||
|
||||
PreservedAnalyses PassPA = Pass.run(N->getFunction(), FAM);
|
||||
Function &F = N->getFunction();
|
||||
|
||||
PassInstrumentation PI = FAM.getResult<PassInstrumentationAnalysis>(F);
|
||||
if (!PI.runBeforePass<Function>(Pass, F))
|
||||
continue;
|
||||
|
||||
PreservedAnalyses PassPA = Pass.run(F, FAM);
|
||||
|
||||
PI.runAfterPass<Function>(Pass, F);
|
||||
|
||||
// We know that the function pass couldn't have invalidated any other
|
||||
// function's analyses (that's the contract of a function pass), so
|
||||
// directly handle the function analysis manager's invalidation here.
|
||||
FAM.invalidate(N->getFunction(), PassPA);
|
||||
FAM.invalidate(F, PassPA);
|
||||
|
||||
// Then intersect the preserved set so that invalidation of module
|
||||
// analyses will eventually occur when the module pass completes.
|
||||
|
|
@ -690,6 +714,8 @@ public:
|
|||
PreservedAnalyses run(LazyCallGraph::SCC &InitialC, CGSCCAnalysisManager &AM,
|
||||
LazyCallGraph &CG, CGSCCUpdateResult &UR) {
|
||||
PreservedAnalyses PA = PreservedAnalyses::all();
|
||||
PassInstrumentation PI =
|
||||
AM.getResult<PassInstrumentationAnalysis>(InitialC, CG);
|
||||
|
||||
// The SCC may be refined while we are running passes over it, so set up
|
||||
// a pointer that we can update.
|
||||
|
|
@ -733,8 +759,17 @@ public:
|
|||
auto CallCounts = ScanSCC(*C, CallHandles);
|
||||
|
||||
for (int Iteration = 0;; ++Iteration) {
|
||||
|
||||
if (!PI.runBeforePass<LazyCallGraph::SCC>(Pass, *C))
|
||||
continue;
|
||||
|
||||
PreservedAnalyses PassPA = Pass.run(*C, AM, CG, UR);
|
||||
|
||||
if (UR.InvalidatedSCCs.count(C))
|
||||
PI.runAfterPassInvalidated<LazyCallGraph::SCC>(Pass);
|
||||
else
|
||||
PI.runAfterPass<LazyCallGraph::SCC>(Pass, *C);
|
||||
|
||||
// If the SCC structure has changed, bail immediately and let the outer
|
||||
// CGSCC layer handle any iteration to reflect the refined structure.
|
||||
if (UR.UpdatedC && UR.UpdatedC != C) {
|
||||
|
|
|
|||
|
|
@ -22,6 +22,14 @@ namespace llvm {
|
|||
class DominatorTree;
|
||||
class OrderedBasicBlock;
|
||||
|
||||
/// The default value for MaxUsesToExplore argument. It's relatively small to
|
||||
/// keep the cost of analysis reasonable for clients like BasicAliasAnalysis,
|
||||
/// where the results can't be cached.
|
||||
/// TODO: we should probably introduce a caching CaptureTracking analysis and
|
||||
/// use it where possible. The caching version can use much higher limit or
|
||||
/// don't have this cap at all.
|
||||
unsigned constexpr DefaultMaxUsesToExplore = 20;
|
||||
|
||||
/// PointerMayBeCaptured - Return true if this pointer value may be captured
|
||||
/// by the enclosing function (which is required to exist). This routine can
|
||||
/// be expensive, so consider caching the results. The boolean ReturnCaptures
|
||||
|
|
@ -29,9 +37,12 @@ namespace llvm {
|
|||
/// counts as capturing it or not. The boolean StoreCaptures specified
|
||||
/// whether storing the value (or part of it) into memory anywhere
|
||||
/// automatically counts as capturing it or not.
|
||||
/// MaxUsesToExplore specifies how many uses should the analysis explore for
|
||||
/// one value before giving up due too "too many uses".
|
||||
bool PointerMayBeCaptured(const Value *V,
|
||||
bool ReturnCaptures,
|
||||
bool StoreCaptures);
|
||||
bool StoreCaptures,
|
||||
unsigned MaxUsesToExplore = DefaultMaxUsesToExplore);
|
||||
|
||||
/// PointerMayBeCapturedBefore - Return true if this pointer value may be
|
||||
/// captured by the enclosing function (which is required to exist). If a
|
||||
|
|
@ -44,10 +55,13 @@ namespace llvm {
|
|||
/// or not. Captures by the provided instruction are considered if the
|
||||
/// final parameter is true. An ordered basic block in \p OBB could be used
|
||||
/// to speed up capture-tracker queries.
|
||||
/// MaxUsesToExplore specifies how many uses should the analysis explore for
|
||||
/// one value before giving up due too "too many uses".
|
||||
bool PointerMayBeCapturedBefore(const Value *V, bool ReturnCaptures,
|
||||
bool StoreCaptures, const Instruction *I,
|
||||
const DominatorTree *DT, bool IncludeI = false,
|
||||
OrderedBasicBlock *OBB = nullptr);
|
||||
OrderedBasicBlock *OBB = nullptr,
|
||||
unsigned MaxUsesToExplore = DefaultMaxUsesToExplore);
|
||||
|
||||
/// This callback is used in conjunction with PointerMayBeCaptured. In
|
||||
/// addition to the interface here, you'll need to provide your own getters
|
||||
|
|
@ -75,7 +89,10 @@ namespace llvm {
|
|||
/// PointerMayBeCaptured - Visit the value and the values derived from it and
|
||||
/// find values which appear to be capturing the pointer value. This feeds
|
||||
/// results into and is controlled by the CaptureTracker object.
|
||||
void PointerMayBeCaptured(const Value *V, CaptureTracker *Tracker);
|
||||
/// MaxUsesToExplore specifies how many uses should the analysis explore for
|
||||
/// one value before giving up due too "too many uses".
|
||||
void PointerMayBeCaptured(const Value *V, CaptureTracker *Tracker,
|
||||
unsigned MaxUsesToExplore = DefaultMaxUsesToExplore);
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -46,19 +46,18 @@ namespace llvm {
|
|||
///
|
||||
unsigned getICmpCode(const ICmpInst *ICI, bool InvertPred = false);
|
||||
|
||||
/// This is the complement of getICmpCode, which turns an opcode and two
|
||||
/// operands into either a constant true or false, or the predicate for a new
|
||||
/// ICmp instruction. The sign is passed in to determine which kind of
|
||||
/// predicate to use in the new icmp instruction.
|
||||
/// This is the complement of getICmpCode. It turns a predicate code into
|
||||
/// either a constant true or false or the predicate for a new ICmp.
|
||||
/// The sign is passed in to determine which kind of predicate to use in the
|
||||
/// new ICmp instruction.
|
||||
/// Non-NULL return value will be a true or false constant.
|
||||
/// NULL return means a new ICmp is needed. The predicate for which is output
|
||||
/// in NewICmpPred.
|
||||
Value *getICmpValue(bool Sign, unsigned Code, Value *LHS, Value *RHS,
|
||||
CmpInst::Predicate &NewICmpPred);
|
||||
/// NULL return means a new ICmp is needed. The predicate is output in Pred.
|
||||
Constant *getPredForICmpCode(unsigned Code, bool Sign, Type *OpTy,
|
||||
CmpInst::Predicate &Pred);
|
||||
|
||||
/// Return true if both predicates match sign or if at least one of them is an
|
||||
/// equality comparison (which is signless).
|
||||
bool PredicatesFoldable(CmpInst::Predicate p1, CmpInst::Predicate p2);
|
||||
bool predicatesFoldable(CmpInst::Predicate P1, CmpInst::Predicate P2);
|
||||
|
||||
/// Decompose an icmp into the form ((X & Mask) pred 0) if possible. The
|
||||
/// returned predicate is either == or !=. Returns false if decomposition
|
||||
|
|
|
|||
|
|
@ -44,19 +44,30 @@ public:
|
|||
F(F), AC(AC), DT(DT) {}
|
||||
|
||||
/// Return the bits demanded from instruction I.
|
||||
///
|
||||
/// For vector instructions individual vector elements are not distinguished:
|
||||
/// A bit is demanded if it is demanded for any of the vector elements. The
|
||||
/// size of the return value corresponds to the type size in bits of the
|
||||
/// scalar type.
|
||||
///
|
||||
/// Instructions that do not have integer or vector of integer type are
|
||||
/// accepted, but will always produce a mask with all bits set.
|
||||
APInt getDemandedBits(Instruction *I);
|
||||
|
||||
/// Return true if, during analysis, I could not be reached.
|
||||
bool isInstructionDead(Instruction *I);
|
||||
|
||||
/// Return whether this use is dead by means of not having any demanded bits.
|
||||
bool isUseDead(Use *U);
|
||||
|
||||
void print(raw_ostream &OS);
|
||||
|
||||
private:
|
||||
void performAnalysis();
|
||||
void determineLiveOperandBits(const Instruction *UserI,
|
||||
const Instruction *I, unsigned OperandNo,
|
||||
const Value *Val, unsigned OperandNo,
|
||||
const APInt &AOut, APInt &AB,
|
||||
KnownBits &Known, KnownBits &Known2);
|
||||
KnownBits &Known, KnownBits &Known2, bool &KnownBitsComputed);
|
||||
|
||||
Function &F;
|
||||
AssumptionCache &AC;
|
||||
|
|
@ -67,6 +78,9 @@ private:
|
|||
// The set of visited instructions (non-integer-typed only).
|
||||
SmallPtrSet<Instruction*, 32> Visited;
|
||||
DenseMap<Instruction *, APInt> AliveBits;
|
||||
// Uses with no demanded bits. If the user also has no demanded bits, the use
|
||||
// might not be stored explicitly in this map, to save memory during analysis.
|
||||
SmallPtrSet<Use *, 16> DeadUses;
|
||||
};
|
||||
|
||||
class DemandedBitsWrapperPass : public FunctionPass {
|
||||
|
|
|
|||
|
|
@ -936,6 +936,17 @@ template <typename T> class ArrayRef;
|
|||
friend struct AnalysisInfoMixin<DependenceAnalysis>;
|
||||
}; // class DependenceAnalysis
|
||||
|
||||
/// Printer pass to dump DA results.
|
||||
struct DependenceAnalysisPrinterPass
|
||||
: public PassInfoMixin<DependenceAnalysisPrinterPass> {
|
||||
DependenceAnalysisPrinterPass(raw_ostream &OS) : OS(OS) {}
|
||||
|
||||
PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM);
|
||||
|
||||
private:
|
||||
raw_ostream &OS;
|
||||
}; // class DependenceAnalysisPrinterPass
|
||||
|
||||
/// Legacy pass manager pass to access dependence information
|
||||
class DependenceAnalysisWrapperPass : public FunctionPass {
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -7,55 +7,199 @@
|
|||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The divergence analysis is an LLVM pass which can be used to find out
|
||||
// if a branch instruction in a GPU program is divergent or not. It can help
|
||||
// branch optimizations such as jump threading and loop unswitching to make
|
||||
// better decisions.
|
||||
// \file
|
||||
// The divergence analysis determines which instructions and branches are
|
||||
// divergent given a set of divergent source instructions.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ANALYSIS_DIVERGENCE_ANALYSIS_H
|
||||
#define LLVM_ANALYSIS_DIVERGENCE_ANALYSIS_H
|
||||
|
||||
#include "llvm/ADT/DenseSet.h"
|
||||
#include "llvm/Analysis/SyncDependenceAnalysis.h"
|
||||
#include "llvm/IR/Function.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
class Module;
|
||||
class Value;
|
||||
class DivergenceAnalysis : public FunctionPass {
|
||||
class Instruction;
|
||||
class Loop;
|
||||
class raw_ostream;
|
||||
class TargetTransformInfo;
|
||||
|
||||
/// \brief Generic divergence analysis for reducible CFGs.
|
||||
///
|
||||
/// This analysis propagates divergence in a data-parallel context from sources
|
||||
/// of divergence to all users. It requires reducible CFGs. All assignments
|
||||
/// should be in SSA form.
|
||||
class DivergenceAnalysis {
|
||||
public:
|
||||
static char ID;
|
||||
/// \brief This instance will analyze the whole function \p F or the loop \p
|
||||
/// RegionLoop.
|
||||
///
|
||||
/// \param RegionLoop if non-null the analysis is restricted to \p RegionLoop.
|
||||
/// Otherwise the whole function is analyzed.
|
||||
/// \param IsLCSSAForm whether the analysis may assume that the IR in the
|
||||
/// region in in LCSSA form.
|
||||
DivergenceAnalysis(const Function &F, const Loop *RegionLoop,
|
||||
const DominatorTree &DT, const LoopInfo &LI,
|
||||
SyncDependenceAnalysis &SDA, bool IsLCSSAForm);
|
||||
|
||||
DivergenceAnalysis() : FunctionPass(ID) {
|
||||
initializeDivergenceAnalysisPass(*PassRegistry::getPassRegistry());
|
||||
}
|
||||
/// \brief The loop that defines the analyzed region (if any).
|
||||
const Loop *getRegionLoop() const { return RegionLoop; }
|
||||
const Function &getFunction() const { return F; }
|
||||
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override;
|
||||
/// \brief Whether \p BB is part of the region.
|
||||
bool inRegion(const BasicBlock &BB) const;
|
||||
/// \brief Whether \p I is part of the region.
|
||||
bool inRegion(const Instruction &I) const;
|
||||
|
||||
bool runOnFunction(Function &F) override;
|
||||
/// \brief Mark \p UniVal as a value that is always uniform.
|
||||
void addUniformOverride(const Value &UniVal);
|
||||
|
||||
// Print all divergent branches in the function.
|
||||
void print(raw_ostream &OS, const Module *) const override;
|
||||
/// \brief Mark \p DivVal as a value that is always divergent.
|
||||
void markDivergent(const Value &DivVal);
|
||||
|
||||
// Returns true if V is divergent at its definition.
|
||||
//
|
||||
// Even if this function returns false, V may still be divergent when used
|
||||
// in a different basic block.
|
||||
bool isDivergent(const Value *V) const { return DivergentValues.count(V); }
|
||||
/// \brief Propagate divergence to all instructions in the region.
|
||||
/// Divergence is seeded by calls to \p markDivergent.
|
||||
void compute();
|
||||
|
||||
// Returns true if V is uniform/non-divergent.
|
||||
//
|
||||
// Even if this function returns true, V may still be divergent when used
|
||||
// in a different basic block.
|
||||
bool isUniform(const Value *V) const { return !isDivergent(V); }
|
||||
/// \brief Whether any value was marked or analyzed to be divergent.
|
||||
bool hasDetectedDivergence() const { return !DivergentValues.empty(); }
|
||||
|
||||
// Keep the analysis results uptodate by removing an erased value.
|
||||
void removeValue(const Value *V) { DivergentValues.erase(V); }
|
||||
/// \brief Whether \p Val will always return a uniform value regardless of its
|
||||
/// operands
|
||||
bool isAlwaysUniform(const Value &Val) const;
|
||||
|
||||
/// \brief Whether \p Val is a divergent value
|
||||
bool isDivergent(const Value &Val) const;
|
||||
|
||||
void print(raw_ostream &OS, const Module *) const;
|
||||
|
||||
private:
|
||||
// Stores all divergent values.
|
||||
DenseSet<const Value *> DivergentValues;
|
||||
};
|
||||
} // End llvm namespace
|
||||
bool updateTerminator(const Instruction &Term) const;
|
||||
bool updatePHINode(const PHINode &Phi) const;
|
||||
|
||||
#endif //LLVM_ANALYSIS_DIVERGENCE_ANALYSIS_H
|
||||
/// \brief Computes whether \p Inst is divergent based on the
|
||||
/// divergence of its operands.
|
||||
///
|
||||
/// \returns Whether \p Inst is divergent.
|
||||
///
|
||||
/// This should only be called for non-phi, non-terminator instructions.
|
||||
bool updateNormalInstruction(const Instruction &Inst) const;
|
||||
|
||||
/// \brief Mark users of live-out users as divergent.
|
||||
///
|
||||
/// \param LoopHeader the header of the divergent loop.
|
||||
///
|
||||
/// Marks all users of live-out values of the loop headed by \p LoopHeader
|
||||
/// as divergent and puts them on the worklist.
|
||||
void taintLoopLiveOuts(const BasicBlock &LoopHeader);
|
||||
|
||||
/// \brief Push all users of \p Val (in the region) to the worklist
|
||||
void pushUsers(const Value &I);
|
||||
|
||||
/// \brief Push all phi nodes in @block to the worklist
|
||||
void pushPHINodes(const BasicBlock &Block);
|
||||
|
||||
/// \brief Mark \p Block as join divergent
|
||||
///
|
||||
/// A block is join divergent if two threads may reach it from different
|
||||
/// incoming blocks at the same time.
|
||||
void markBlockJoinDivergent(const BasicBlock &Block) {
|
||||
DivergentJoinBlocks.insert(&Block);
|
||||
}
|
||||
|
||||
/// \brief Whether \p Val is divergent when read in \p ObservingBlock.
|
||||
bool isTemporalDivergent(const BasicBlock &ObservingBlock,
|
||||
const Value &Val) const;
|
||||
|
||||
/// \brief Whether \p Block is join divergent
|
||||
///
|
||||
/// (see markBlockJoinDivergent).
|
||||
bool isJoinDivergent(const BasicBlock &Block) const {
|
||||
return DivergentJoinBlocks.find(&Block) != DivergentJoinBlocks.end();
|
||||
}
|
||||
|
||||
/// \brief Propagate control-induced divergence to users (phi nodes and
|
||||
/// instructions).
|
||||
//
|
||||
// \param JoinBlock is a divergent loop exit or join point of two disjoint
|
||||
// paths.
|
||||
// \returns Whether \p JoinBlock is a divergent loop exit of \p TermLoop.
|
||||
bool propagateJoinDivergence(const BasicBlock &JoinBlock,
|
||||
const Loop *TermLoop);
|
||||
|
||||
/// \brief Propagate induced value divergence due to control divergence in \p
|
||||
/// Term.
|
||||
void propagateBranchDivergence(const Instruction &Term);
|
||||
|
||||
/// \brief Propagate divergent caused by a divergent loop exit.
|
||||
///
|
||||
/// \param ExitingLoop is a divergent loop.
|
||||
void propagateLoopDivergence(const Loop &ExitingLoop);
|
||||
|
||||
private:
|
||||
const Function &F;
|
||||
// If regionLoop != nullptr, analysis is only performed within \p RegionLoop.
|
||||
// Otw, analyze the whole function
|
||||
const Loop *RegionLoop;
|
||||
|
||||
const DominatorTree &DT;
|
||||
const LoopInfo &LI;
|
||||
|
||||
// Recognized divergent loops
|
||||
DenseSet<const Loop *> DivergentLoops;
|
||||
|
||||
// The SDA links divergent branches to divergent control-flow joins.
|
||||
SyncDependenceAnalysis &SDA;
|
||||
|
||||
// Use simplified code path for LCSSA form.
|
||||
bool IsLCSSAForm;
|
||||
|
||||
// Set of known-uniform values.
|
||||
DenseSet<const Value *> UniformOverrides;
|
||||
|
||||
// Blocks with joining divergent control from different predecessors.
|
||||
DenseSet<const BasicBlock *> DivergentJoinBlocks;
|
||||
|
||||
// Detected/marked divergent values.
|
||||
DenseSet<const Value *> DivergentValues;
|
||||
|
||||
// Internal worklist for divergence propagation.
|
||||
std::vector<const Instruction *> Worklist;
|
||||
};
|
||||
|
||||
/// \brief Divergence analysis frontend for GPU kernels.
|
||||
class GPUDivergenceAnalysis {
|
||||
SyncDependenceAnalysis SDA;
|
||||
DivergenceAnalysis DA;
|
||||
|
||||
public:
|
||||
/// Runs the divergence analysis on @F, a GPU kernel
|
||||
GPUDivergenceAnalysis(Function &F, const DominatorTree &DT,
|
||||
const PostDominatorTree &PDT, const LoopInfo &LI,
|
||||
const TargetTransformInfo &TTI);
|
||||
|
||||
/// Whether any divergence was detected.
|
||||
bool hasDivergence() const { return DA.hasDetectedDivergence(); }
|
||||
|
||||
/// The GPU kernel this analysis result is for
|
||||
const Function &getFunction() const { return DA.getFunction(); }
|
||||
|
||||
/// Whether \p V is divergent.
|
||||
bool isDivergent(const Value &V) const;
|
||||
|
||||
/// Whether \p V is uniform/non-divergent
|
||||
bool isUniform(const Value &V) const { return !isDivergent(V); }
|
||||
|
||||
/// Print all divergent values in the kernel.
|
||||
void print(raw_ostream &OS, const Module *) const;
|
||||
};
|
||||
|
||||
} // namespace llvm
|
||||
|
||||
#endif // LLVM_ANALYSIS_DIVERGENCE_ANALYSIS_H
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ public:
|
|||
AliasResult alias(const MemoryLocation &LocA, const MemoryLocation &LocB);
|
||||
|
||||
using AAResultBase::getModRefInfo;
|
||||
ModRefInfo getModRefInfo(ImmutableCallSite CS, const MemoryLocation &Loc);
|
||||
ModRefInfo getModRefInfo(const CallBase *Call, const MemoryLocation &Loc);
|
||||
|
||||
/// getModRefBehavior - Return the behavior of the specified function if
|
||||
/// called from the specified call site. The call site may be null in which
|
||||
|
|
@ -98,7 +98,7 @@ public:
|
|||
/// getModRefBehavior - Return the behavior of the specified function if
|
||||
/// called from the specified call site. The call site may be null in which
|
||||
/// case the most generic behavior of this function should be returned.
|
||||
FunctionModRefBehavior getModRefBehavior(ImmutableCallSite CS);
|
||||
FunctionModRefBehavior getModRefBehavior(const CallBase *Call);
|
||||
|
||||
private:
|
||||
FunctionInfo *getFunctionInfo(const Function *F);
|
||||
|
|
@ -113,7 +113,7 @@ private:
|
|||
void CollectSCCMembership(CallGraph &CG);
|
||||
|
||||
bool isNonEscapingGlobalNoAlias(const GlobalValue *GV, const Value *V);
|
||||
ModRefInfo getModRefInfoForArgument(ImmutableCallSite CS,
|
||||
ModRefInfo getModRefInfoForArgument(const CallBase *Call,
|
||||
const GlobalValue *GV);
|
||||
};
|
||||
|
||||
|
|
|
|||
26
contrib/llvm/include/llvm/Analysis/GuardUtils.h
Normal file
26
contrib/llvm/include/llvm/Analysis/GuardUtils.h
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
//===-- GuardUtils.h - Utils for work with guards ---------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Utils that are used to perform analyzes related to guards and their
|
||||
// conditions.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ANALYSIS_GUARDUTILS_H
|
||||
#define LLVM_ANALYSIS_GUARDUTILS_H
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class User;
|
||||
|
||||
/// Returns true iff \p U has semantics of a guard.
|
||||
bool isGuard(const User *U);
|
||||
|
||||
} // llvm
|
||||
|
||||
#endif // LLVM_ANALYSIS_GUARDUTILS_H
|
||||
|
||||
357
contrib/llvm/include/llvm/Analysis/IVDescriptors.h
Normal file
357
contrib/llvm/include/llvm/Analysis/IVDescriptors.h
Normal file
|
|
@ -0,0 +1,357 @@
|
|||
//===- llvm/Analysis/IVDescriptors.h - IndVar Descriptors -------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file "describes" induction and recurrence variables.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ANALYSIS_IVDESCRIPTORS_H
|
||||
#define LLVM_ANALYSIS_IVDESCRIPTORS_H
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/ADT/SetVector.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Analysis/AliasAnalysis.h"
|
||||
#include "llvm/Analysis/DemandedBits.h"
|
||||
#include "llvm/Analysis/EHPersonalities.h"
|
||||
#include "llvm/Analysis/MustExecute.h"
|
||||
#include "llvm/Analysis/TargetTransformInfo.h"
|
||||
#include "llvm/IR/Dominators.h"
|
||||
#include "llvm/IR/IRBuilder.h"
|
||||
#include "llvm/IR/InstrTypes.h"
|
||||
#include "llvm/IR/Operator.h"
|
||||
#include "llvm/IR/ValueHandle.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class AliasSet;
|
||||
class AliasSetTracker;
|
||||
class BasicBlock;
|
||||
class DataLayout;
|
||||
class Loop;
|
||||
class LoopInfo;
|
||||
class OptimizationRemarkEmitter;
|
||||
class PredicatedScalarEvolution;
|
||||
class PredIteratorCache;
|
||||
class ScalarEvolution;
|
||||
class SCEV;
|
||||
class TargetLibraryInfo;
|
||||
class TargetTransformInfo;
|
||||
|
||||
/// The RecurrenceDescriptor is used to identify recurrences variables in a
|
||||
/// loop. Reduction is a special case of recurrence that has uses of the
|
||||
/// recurrence variable outside the loop. The method isReductionPHI identifies
|
||||
/// reductions that are basic recurrences.
|
||||
///
|
||||
/// Basic recurrences are defined as the summation, product, OR, AND, XOR, min,
|
||||
/// or max of a set of terms. For example: for(i=0; i<n; i++) { total +=
|
||||
/// array[i]; } is a summation of array elements. Basic recurrences are a
|
||||
/// special case of chains of recurrences (CR). See ScalarEvolution for CR
|
||||
/// references.
|
||||
|
||||
/// This struct holds information about recurrence variables.
|
||||
class RecurrenceDescriptor {
|
||||
public:
|
||||
/// This enum represents the kinds of recurrences that we support.
|
||||
enum RecurrenceKind {
|
||||
RK_NoRecurrence, ///< Not a recurrence.
|
||||
RK_IntegerAdd, ///< Sum of integers.
|
||||
RK_IntegerMult, ///< Product of integers.
|
||||
RK_IntegerOr, ///< Bitwise or logical OR of numbers.
|
||||
RK_IntegerAnd, ///< Bitwise or logical AND of numbers.
|
||||
RK_IntegerXor, ///< Bitwise or logical XOR of numbers.
|
||||
RK_IntegerMinMax, ///< Min/max implemented in terms of select(cmp()).
|
||||
RK_FloatAdd, ///< Sum of floats.
|
||||
RK_FloatMult, ///< Product of floats.
|
||||
RK_FloatMinMax ///< Min/max implemented in terms of select(cmp()).
|
||||
};
|
||||
|
||||
// This enum represents the kind of minmax recurrence.
|
||||
enum MinMaxRecurrenceKind {
|
||||
MRK_Invalid,
|
||||
MRK_UIntMin,
|
||||
MRK_UIntMax,
|
||||
MRK_SIntMin,
|
||||
MRK_SIntMax,
|
||||
MRK_FloatMin,
|
||||
MRK_FloatMax
|
||||
};
|
||||
|
||||
RecurrenceDescriptor() = default;
|
||||
|
||||
RecurrenceDescriptor(Value *Start, Instruction *Exit, RecurrenceKind K,
|
||||
MinMaxRecurrenceKind MK, Instruction *UAI, Type *RT,
|
||||
bool Signed, SmallPtrSetImpl<Instruction *> &CI)
|
||||
: StartValue(Start), LoopExitInstr(Exit), Kind(K), MinMaxKind(MK),
|
||||
UnsafeAlgebraInst(UAI), RecurrenceType(RT), IsSigned(Signed) {
|
||||
CastInsts.insert(CI.begin(), CI.end());
|
||||
}
|
||||
|
||||
/// This POD struct holds information about a potential recurrence operation.
|
||||
class InstDesc {
|
||||
public:
|
||||
InstDesc(bool IsRecur, Instruction *I, Instruction *UAI = nullptr)
|
||||
: IsRecurrence(IsRecur), PatternLastInst(I), MinMaxKind(MRK_Invalid),
|
||||
UnsafeAlgebraInst(UAI) {}
|
||||
|
||||
InstDesc(Instruction *I, MinMaxRecurrenceKind K, Instruction *UAI = nullptr)
|
||||
: IsRecurrence(true), PatternLastInst(I), MinMaxKind(K),
|
||||
UnsafeAlgebraInst(UAI) {}
|
||||
|
||||
bool isRecurrence() { return IsRecurrence; }
|
||||
|
||||
bool hasUnsafeAlgebra() { return UnsafeAlgebraInst != nullptr; }
|
||||
|
||||
Instruction *getUnsafeAlgebraInst() { return UnsafeAlgebraInst; }
|
||||
|
||||
MinMaxRecurrenceKind getMinMaxKind() { return MinMaxKind; }
|
||||
|
||||
Instruction *getPatternInst() { return PatternLastInst; }
|
||||
|
||||
private:
|
||||
// Is this instruction a recurrence candidate.
|
||||
bool IsRecurrence;
|
||||
// The last instruction in a min/max pattern (select of the select(icmp())
|
||||
// pattern), or the current recurrence instruction otherwise.
|
||||
Instruction *PatternLastInst;
|
||||
// If this is a min/max pattern the comparison predicate.
|
||||
MinMaxRecurrenceKind MinMaxKind;
|
||||
// Recurrence has unsafe algebra.
|
||||
Instruction *UnsafeAlgebraInst;
|
||||
};
|
||||
|
||||
/// Returns a struct describing if the instruction 'I' can be a recurrence
|
||||
/// variable of type 'Kind'. If the recurrence is a min/max pattern of
|
||||
/// select(icmp()) this function advances the instruction pointer 'I' from the
|
||||
/// compare instruction to the select instruction and stores this pointer in
|
||||
/// 'PatternLastInst' member of the returned struct.
|
||||
static InstDesc isRecurrenceInstr(Instruction *I, RecurrenceKind Kind,
|
||||
InstDesc &Prev, bool HasFunNoNaNAttr);
|
||||
|
||||
/// Returns true if instruction I has multiple uses in Insts
|
||||
static bool hasMultipleUsesOf(Instruction *I,
|
||||
SmallPtrSetImpl<Instruction *> &Insts,
|
||||
unsigned MaxNumUses);
|
||||
|
||||
/// Returns true if all uses of the instruction I is within the Set.
|
||||
static bool areAllUsesIn(Instruction *I, SmallPtrSetImpl<Instruction *> &Set);
|
||||
|
||||
/// Returns a struct describing if the instruction if the instruction is a
|
||||
/// Select(ICmp(X, Y), X, Y) instruction pattern corresponding to a min(X, Y)
|
||||
/// or max(X, Y).
|
||||
static InstDesc isMinMaxSelectCmpPattern(Instruction *I, InstDesc &Prev);
|
||||
|
||||
/// Returns a struct describing if the instruction is a
|
||||
/// Select(FCmp(X, Y), (Z = X op PHINode), PHINode) instruction pattern.
|
||||
static InstDesc isConditionalRdxPattern(RecurrenceKind Kind, Instruction *I);
|
||||
|
||||
/// Returns identity corresponding to the RecurrenceKind.
|
||||
static Constant *getRecurrenceIdentity(RecurrenceKind K, Type *Tp);
|
||||
|
||||
/// Returns the opcode of binary operation corresponding to the
|
||||
/// RecurrenceKind.
|
||||
static unsigned getRecurrenceBinOp(RecurrenceKind Kind);
|
||||
|
||||
/// Returns true if Phi is a reduction of type Kind and adds it to the
|
||||
/// RecurrenceDescriptor. If either \p DB is non-null or \p AC and \p DT are
|
||||
/// non-null, the minimal bit width needed to compute the reduction will be
|
||||
/// computed.
|
||||
static bool AddReductionVar(PHINode *Phi, RecurrenceKind Kind, Loop *TheLoop,
|
||||
bool HasFunNoNaNAttr,
|
||||
RecurrenceDescriptor &RedDes,
|
||||
DemandedBits *DB = nullptr,
|
||||
AssumptionCache *AC = nullptr,
|
||||
DominatorTree *DT = nullptr);
|
||||
|
||||
/// Returns true if Phi is a reduction in TheLoop. The RecurrenceDescriptor
|
||||
/// is returned in RedDes. If either \p DB is non-null or \p AC and \p DT are
|
||||
/// non-null, the minimal bit width needed to compute the reduction will be
|
||||
/// computed.
|
||||
static bool isReductionPHI(PHINode *Phi, Loop *TheLoop,
|
||||
RecurrenceDescriptor &RedDes,
|
||||
DemandedBits *DB = nullptr,
|
||||
AssumptionCache *AC = nullptr,
|
||||
DominatorTree *DT = nullptr);
|
||||
|
||||
/// Returns true if Phi is a first-order recurrence. A first-order recurrence
|
||||
/// is a non-reduction recurrence relation in which the value of the
|
||||
/// recurrence in the current loop iteration equals a value defined in the
|
||||
/// previous iteration. \p SinkAfter includes pairs of instructions where the
|
||||
/// first will be rescheduled to appear after the second if/when the loop is
|
||||
/// vectorized. It may be augmented with additional pairs if needed in order
|
||||
/// to handle Phi as a first-order recurrence.
|
||||
static bool
|
||||
isFirstOrderRecurrence(PHINode *Phi, Loop *TheLoop,
|
||||
DenseMap<Instruction *, Instruction *> &SinkAfter,
|
||||
DominatorTree *DT);
|
||||
|
||||
RecurrenceKind getRecurrenceKind() { return Kind; }
|
||||
|
||||
MinMaxRecurrenceKind getMinMaxRecurrenceKind() { return MinMaxKind; }
|
||||
|
||||
TrackingVH<Value> getRecurrenceStartValue() { return StartValue; }
|
||||
|
||||
Instruction *getLoopExitInstr() { return LoopExitInstr; }
|
||||
|
||||
/// Returns true if the recurrence has unsafe algebra which requires a relaxed
|
||||
/// floating-point model.
|
||||
bool hasUnsafeAlgebra() { return UnsafeAlgebraInst != nullptr; }
|
||||
|
||||
/// Returns first unsafe algebra instruction in the PHI node's use-chain.
|
||||
Instruction *getUnsafeAlgebraInst() { return UnsafeAlgebraInst; }
|
||||
|
||||
/// Returns true if the recurrence kind is an integer kind.
|
||||
static bool isIntegerRecurrenceKind(RecurrenceKind Kind);
|
||||
|
||||
/// Returns true if the recurrence kind is a floating point kind.
|
||||
static bool isFloatingPointRecurrenceKind(RecurrenceKind Kind);
|
||||
|
||||
/// Returns true if the recurrence kind is an arithmetic kind.
|
||||
static bool isArithmeticRecurrenceKind(RecurrenceKind Kind);
|
||||
|
||||
/// Returns the type of the recurrence. This type can be narrower than the
|
||||
/// actual type of the Phi if the recurrence has been type-promoted.
|
||||
Type *getRecurrenceType() { return RecurrenceType; }
|
||||
|
||||
/// Returns a reference to the instructions used for type-promoting the
|
||||
/// recurrence.
|
||||
SmallPtrSet<Instruction *, 8> &getCastInsts() { return CastInsts; }
|
||||
|
||||
/// Returns true if all source operands of the recurrence are SExtInsts.
|
||||
bool isSigned() { return IsSigned; }
|
||||
|
||||
private:
|
||||
// The starting value of the recurrence.
|
||||
// It does not have to be zero!
|
||||
TrackingVH<Value> StartValue;
|
||||
// The instruction who's value is used outside the loop.
|
||||
Instruction *LoopExitInstr = nullptr;
|
||||
// The kind of the recurrence.
|
||||
RecurrenceKind Kind = RK_NoRecurrence;
|
||||
// If this a min/max recurrence the kind of recurrence.
|
||||
MinMaxRecurrenceKind MinMaxKind = MRK_Invalid;
|
||||
// First occurrence of unasfe algebra in the PHI's use-chain.
|
||||
Instruction *UnsafeAlgebraInst = nullptr;
|
||||
// The type of the recurrence.
|
||||
Type *RecurrenceType = nullptr;
|
||||
// True if all source operands of the recurrence are SExtInsts.
|
||||
bool IsSigned = false;
|
||||
// Instructions used for type-promoting the recurrence.
|
||||
SmallPtrSet<Instruction *, 8> CastInsts;
|
||||
};
|
||||
|
||||
/// A struct for saving information about induction variables.
|
||||
class InductionDescriptor {
|
||||
public:
|
||||
/// This enum represents the kinds of inductions that we support.
|
||||
enum InductionKind {
|
||||
IK_NoInduction, ///< Not an induction variable.
|
||||
IK_IntInduction, ///< Integer induction variable. Step = C.
|
||||
IK_PtrInduction, ///< Pointer induction var. Step = C / sizeof(elem).
|
||||
IK_FpInduction ///< Floating point induction variable.
|
||||
};
|
||||
|
||||
public:
|
||||
/// Default constructor - creates an invalid induction.
|
||||
InductionDescriptor() = default;
|
||||
|
||||
/// Get the consecutive direction. Returns:
|
||||
/// 0 - unknown or non-consecutive.
|
||||
/// 1 - consecutive and increasing.
|
||||
/// -1 - consecutive and decreasing.
|
||||
int getConsecutiveDirection() const;
|
||||
|
||||
Value *getStartValue() const { return StartValue; }
|
||||
InductionKind getKind() const { return IK; }
|
||||
const SCEV *getStep() const { return Step; }
|
||||
BinaryOperator *getInductionBinOp() const { return InductionBinOp; }
|
||||
ConstantInt *getConstIntStepValue() const;
|
||||
|
||||
/// Returns true if \p Phi is an induction in the loop \p L. If \p Phi is an
|
||||
/// induction, the induction descriptor \p D will contain the data describing
|
||||
/// this induction. If by some other means the caller has a better SCEV
|
||||
/// expression for \p Phi than the one returned by the ScalarEvolution
|
||||
/// analysis, it can be passed through \p Expr. If the def-use chain
|
||||
/// associated with the phi includes casts (that we know we can ignore
|
||||
/// under proper runtime checks), they are passed through \p CastsToIgnore.
|
||||
static bool
|
||||
isInductionPHI(PHINode *Phi, const Loop *L, ScalarEvolution *SE,
|
||||
InductionDescriptor &D, const SCEV *Expr = nullptr,
|
||||
SmallVectorImpl<Instruction *> *CastsToIgnore = nullptr);
|
||||
|
||||
/// Returns true if \p Phi is a floating point induction in the loop \p L.
|
||||
/// If \p Phi is an induction, the induction descriptor \p D will contain
|
||||
/// the data describing this induction.
|
||||
static bool isFPInductionPHI(PHINode *Phi, const Loop *L, ScalarEvolution *SE,
|
||||
InductionDescriptor &D);
|
||||
|
||||
/// Returns true if \p Phi is a loop \p L induction, in the context associated
|
||||
/// with the run-time predicate of PSE. If \p Assume is true, this can add
|
||||
/// further SCEV predicates to \p PSE in order to prove that \p Phi is an
|
||||
/// induction.
|
||||
/// If \p Phi is an induction, \p D will contain the data describing this
|
||||
/// induction.
|
||||
static bool isInductionPHI(PHINode *Phi, const Loop *L,
|
||||
PredicatedScalarEvolution &PSE,
|
||||
InductionDescriptor &D, bool Assume = false);
|
||||
|
||||
/// Returns true if the induction type is FP and the binary operator does
|
||||
/// not have the "fast-math" property. Such operation requires a relaxed FP
|
||||
/// mode.
|
||||
bool hasUnsafeAlgebra() {
|
||||
return InductionBinOp && !cast<FPMathOperator>(InductionBinOp)->isFast();
|
||||
}
|
||||
|
||||
/// Returns induction operator that does not have "fast-math" property
|
||||
/// and requires FP unsafe mode.
|
||||
Instruction *getUnsafeAlgebraInst() {
|
||||
if (!InductionBinOp || cast<FPMathOperator>(InductionBinOp)->isFast())
|
||||
return nullptr;
|
||||
return InductionBinOp;
|
||||
}
|
||||
|
||||
/// Returns binary opcode of the induction operator.
|
||||
Instruction::BinaryOps getInductionOpcode() const {
|
||||
return InductionBinOp ? InductionBinOp->getOpcode()
|
||||
: Instruction::BinaryOpsEnd;
|
||||
}
|
||||
|
||||
/// Returns a reference to the type cast instructions in the induction
|
||||
/// update chain, that are redundant when guarded with a runtime
|
||||
/// SCEV overflow check.
|
||||
const SmallVectorImpl<Instruction *> &getCastInsts() const {
|
||||
return RedundantCasts;
|
||||
}
|
||||
|
||||
private:
|
||||
/// Private constructor - used by \c isInductionPHI.
|
||||
InductionDescriptor(Value *Start, InductionKind K, const SCEV *Step,
|
||||
BinaryOperator *InductionBinOp = nullptr,
|
||||
SmallVectorImpl<Instruction *> *Casts = nullptr);
|
||||
|
||||
/// Start value.
|
||||
TrackingVH<Value> StartValue;
|
||||
/// Induction kind.
|
||||
InductionKind IK = IK_NoInduction;
|
||||
/// Step value.
|
||||
const SCEV *Step = nullptr;
|
||||
// Instruction that advances induction variable.
|
||||
BinaryOperator *InductionBinOp = nullptr;
|
||||
// Instructions used for type-casts of the induction variable,
|
||||
// that are redundant when guarded with a runtime SCEV overflow check.
|
||||
SmallVector<Instruction *, 2> RedundantCasts;
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_ANALYSIS_IVDESCRIPTORS_H
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
//===-- IndirectCallSiteVisitor.h - indirect call-sites visitor -----------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements defines a visitor class and a helper function that find
|
||||
// all indirect call-sites in a function.
|
||||
|
||||
#include "llvm/IR/InstVisitor.h"
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
// Visitor class that finds all indirect call sites.
|
||||
struct PGOIndirectCallSiteVisitor
|
||||
: public InstVisitor<PGOIndirectCallSiteVisitor> {
|
||||
std::vector<Instruction *> IndirectCallInsts;
|
||||
PGOIndirectCallSiteVisitor() {}
|
||||
|
||||
void visitCallSite(CallSite CS) {
|
||||
if (CS.isIndirectCall())
|
||||
IndirectCallInsts.push_back(CS.getInstruction());
|
||||
}
|
||||
};
|
||||
|
||||
// Helper function that finds all indirect call sites.
|
||||
inline std::vector<Instruction *> findIndirectCallSites(Function &F) {
|
||||
PGOIndirectCallSiteVisitor ICV;
|
||||
ICV.visit(F);
|
||||
return ICV.IndirectCallInsts;
|
||||
}
|
||||
}
|
||||
39
contrib/llvm/include/llvm/Analysis/IndirectCallVisitor.h
Normal file
39
contrib/llvm/include/llvm/Analysis/IndirectCallVisitor.h
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
//===-- IndirectCallVisitor.h - indirect call visitor ---------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements defines a visitor class and a helper function that find
|
||||
// all indirect call-sites in a function.
|
||||
|
||||
#ifndef LLVM_ANALYSIS_INDIRECTCALLVISITOR_H
|
||||
#define LLVM_ANALYSIS_INDIRECTCALLVISITOR_H
|
||||
|
||||
#include "llvm/IR/InstVisitor.h"
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
// Visitor class that finds all indirect call.
|
||||
struct PGOIndirectCallVisitor : public InstVisitor<PGOIndirectCallVisitor> {
|
||||
std::vector<Instruction *> IndirectCalls;
|
||||
PGOIndirectCallVisitor() {}
|
||||
|
||||
void visitCallBase(CallBase &Call) {
|
||||
if (Call.isIndirectCall())
|
||||
IndirectCalls.push_back(&Call);
|
||||
}
|
||||
};
|
||||
|
||||
// Helper function that finds all indirect call sites.
|
||||
inline std::vector<Instruction *> findIndirectCalls(Function &F) {
|
||||
PGOIndirectCallVisitor ICV;
|
||||
ICV.visit(F);
|
||||
return ICV.IndirectCalls;
|
||||
}
|
||||
} // namespace llvm
|
||||
|
||||
#endif
|
||||
|
|
@ -46,7 +46,6 @@ const int IndirectCallThreshold = 100;
|
|||
const int CallPenalty = 25;
|
||||
const int LastCallToStaticBonus = 15000;
|
||||
const int ColdccPenalty = 2000;
|
||||
const int NoreturnPenalty = 10000;
|
||||
/// Do not inline functions which allocate this many bytes on the stack
|
||||
/// when the caller is recursive.
|
||||
const unsigned TotalAllocaSizeRecursiveCaller = 1024;
|
||||
|
|
@ -74,8 +73,15 @@ class InlineCost {
|
|||
/// The adjusted threshold against which this cost was computed.
|
||||
const int Threshold;
|
||||
|
||||
/// Must be set for Always and Never instances.
|
||||
const char *Reason = nullptr;
|
||||
|
||||
// Trivial constructor, interesting logic in the factory functions below.
|
||||
InlineCost(int Cost, int Threshold) : Cost(Cost), Threshold(Threshold) {}
|
||||
InlineCost(int Cost, int Threshold, const char *Reason = nullptr)
|
||||
: Cost(Cost), Threshold(Threshold), Reason(Reason) {
|
||||
assert((isVariable() || Reason) &&
|
||||
"Reason must be provided for Never or Always");
|
||||
}
|
||||
|
||||
public:
|
||||
static InlineCost get(int Cost, int Threshold) {
|
||||
|
|
@ -83,11 +89,11 @@ public:
|
|||
assert(Cost < NeverInlineCost && "Cost crosses sentinel value");
|
||||
return InlineCost(Cost, Threshold);
|
||||
}
|
||||
static InlineCost getAlways() {
|
||||
return InlineCost(AlwaysInlineCost, 0);
|
||||
static InlineCost getAlways(const char *Reason) {
|
||||
return InlineCost(AlwaysInlineCost, 0, Reason);
|
||||
}
|
||||
static InlineCost getNever() {
|
||||
return InlineCost(NeverInlineCost, 0);
|
||||
static InlineCost getNever(const char *Reason) {
|
||||
return InlineCost(NeverInlineCost, 0, Reason);
|
||||
}
|
||||
|
||||
/// Test whether the inline cost is low enough for inlining.
|
||||
|
|
@ -112,12 +118,30 @@ public:
|
|||
return Threshold;
|
||||
}
|
||||
|
||||
/// Get the reason of Always or Never.
|
||||
const char *getReason() const {
|
||||
assert((Reason || isVariable()) &&
|
||||
"InlineCost reason must be set for Always or Never");
|
||||
return Reason;
|
||||
}
|
||||
|
||||
/// Get the cost delta from the threshold for inlining.
|
||||
/// Only valid if the cost is of the variable kind. Returns a negative
|
||||
/// value if the cost is too high to inline.
|
||||
int getCostDelta() const { return Threshold - getCost(); }
|
||||
};
|
||||
|
||||
/// InlineResult is basically true or false. For false results the message
|
||||
/// describes a reason why it is decided not to inline.
|
||||
struct InlineResult {
|
||||
const char *message = nullptr;
|
||||
InlineResult(bool result, const char *message = nullptr)
|
||||
: message(result ? nullptr : (message ? message : "cost > threshold")) {}
|
||||
InlineResult(const char *message = nullptr) : message(message) {}
|
||||
operator bool() const { return !message; }
|
||||
operator const char *() const { return message; }
|
||||
};
|
||||
|
||||
/// Thresholds to tune inline cost analysis. The inline cost analysis decides
|
||||
/// the condition to apply a threshold and applies it. Otherwise,
|
||||
/// DefaultThreshold is used. If a threshold is Optional, it is applied only
|
||||
|
|
|
|||
|
|
@ -0,0 +1,150 @@
|
|||
//===-- InstructionPrecedenceTracking.h -------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Implements a class that is able to define some instructions as "special"
|
||||
// (e.g. as having implicit control flow, or writing memory, or having another
|
||||
// interesting property) and then efficiently answers queries of the types:
|
||||
// 1. Are there any special instructions in the block of interest?
|
||||
// 2. Return first of the special instructions in the given block;
|
||||
// 3. Check if the given instruction is preceeded by the first special
|
||||
// instruction in the same block.
|
||||
// The class provides caching that allows to answer these queries quickly. The
|
||||
// user must make sure that the cached data is invalidated properly whenever
|
||||
// a content of some tracked block is changed.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ANALYSIS_INSTRUCTIONPRECEDENCETRACKING_H
|
||||
#define LLVM_ANALYSIS_INSTRUCTIONPRECEDENCETRACKING_H
|
||||
|
||||
#include "llvm/IR/Dominators.h"
|
||||
#include "llvm/Analysis/OrderedInstructions.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class InstructionPrecedenceTracking {
|
||||
// Maps a block to the topmost special instruction in it. If the value is
|
||||
// nullptr, it means that it is known that this block does not contain any
|
||||
// special instructions.
|
||||
DenseMap<const BasicBlock *, const Instruction *> FirstSpecialInsts;
|
||||
// Allows to answer queries about precedence of instructions within one block.
|
||||
OrderedInstructions OI;
|
||||
|
||||
// Fills information about the given block's special instructions.
|
||||
void fill(const BasicBlock *BB);
|
||||
|
||||
#ifndef NDEBUG
|
||||
/// Asserts that the cached info for \p BB is up-to-date. This helps to catch
|
||||
/// the usage error of accessing a block without properly invalidating after a
|
||||
/// previous transform.
|
||||
void validate(const BasicBlock *BB) const;
|
||||
|
||||
/// Asserts whether or not the contents of this tracking is up-to-date. This
|
||||
/// helps to catch the usage error of accessing a block without properly
|
||||
/// invalidating after a previous transform.
|
||||
void validateAll() const;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
InstructionPrecedenceTracking(DominatorTree *DT)
|
||||
: OI(OrderedInstructions(DT)) {}
|
||||
|
||||
/// Returns the topmost special instruction from the block \p BB. Returns
|
||||
/// nullptr if there is no special instructions in the block.
|
||||
const Instruction *getFirstSpecialInstruction(const BasicBlock *BB);
|
||||
|
||||
/// Returns true iff at least one instruction from the basic block \p BB is
|
||||
/// special.
|
||||
bool hasSpecialInstructions(const BasicBlock *BB);
|
||||
|
||||
/// Returns true iff the first special instruction of \p Insn's block exists
|
||||
/// and dominates \p Insn.
|
||||
bool isPreceededBySpecialInstruction(const Instruction *Insn);
|
||||
|
||||
/// A predicate that defines whether or not the instruction \p Insn is
|
||||
/// considered special and needs to be tracked. Implementing this method in
|
||||
/// children classes allows to implement tracking of implicit control flow,
|
||||
/// memory writing instructions or any other kinds of instructions we might
|
||||
/// be interested in.
|
||||
virtual bool isSpecialInstruction(const Instruction *Insn) const = 0;
|
||||
|
||||
virtual ~InstructionPrecedenceTracking() = default;
|
||||
|
||||
public:
|
||||
/// Notifies this tracking that we are going to insert a new instruction \p
|
||||
/// Inst to the basic block \p BB. It makes all necessary updates to internal
|
||||
/// caches to keep them consistent.
|
||||
void insertInstructionTo(const Instruction *Inst, const BasicBlock *BB);
|
||||
|
||||
/// Notifies this tracking that we are going to remove the instruction \p Inst
|
||||
/// It makes all necessary updates to internal caches to keep them consistent.
|
||||
void removeInstruction(const Instruction *Inst);
|
||||
|
||||
/// Invalidates all information from this tracking.
|
||||
void clear();
|
||||
};
|
||||
|
||||
/// This class allows to keep track on instructions with implicit control flow.
|
||||
/// These are instructions that may not pass execution to their successors. For
|
||||
/// example, throwing calls and guards do not always do this. If we need to know
|
||||
/// for sure that some instruction is guaranteed to execute if the given block
|
||||
/// is reached, then we need to make sure that there is no implicit control flow
|
||||
/// instruction (ICFI) preceeding it. For example, this check is required if we
|
||||
/// perform PRE moving non-speculable instruction to other place.
|
||||
class ImplicitControlFlowTracking : public InstructionPrecedenceTracking {
|
||||
public:
|
||||
ImplicitControlFlowTracking(DominatorTree *DT)
|
||||
: InstructionPrecedenceTracking(DT) {}
|
||||
|
||||
/// Returns the topmost instruction with implicit control flow from the given
|
||||
/// basic block. Returns nullptr if there is no such instructions in the block.
|
||||
const Instruction *getFirstICFI(const BasicBlock *BB) {
|
||||
return getFirstSpecialInstruction(BB);
|
||||
}
|
||||
|
||||
/// Returns true if at least one instruction from the given basic block has
|
||||
/// implicit control flow.
|
||||
bool hasICF(const BasicBlock *BB) {
|
||||
return hasSpecialInstructions(BB);
|
||||
}
|
||||
|
||||
/// Returns true if the first ICFI of Insn's block exists and dominates Insn.
|
||||
bool isDominatedByICFIFromSameBlock(const Instruction *Insn) {
|
||||
return isPreceededBySpecialInstruction(Insn);
|
||||
}
|
||||
|
||||
virtual bool isSpecialInstruction(const Instruction *Insn) const;
|
||||
};
|
||||
|
||||
class MemoryWriteTracking : public InstructionPrecedenceTracking {
|
||||
public:
|
||||
MemoryWriteTracking(DominatorTree *DT) : InstructionPrecedenceTracking(DT) {}
|
||||
|
||||
/// Returns the topmost instruction that may write memory from the given
|
||||
/// basic block. Returns nullptr if there is no such instructions in the block.
|
||||
const Instruction *getFirstMemoryWrite(const BasicBlock *BB) {
|
||||
return getFirstSpecialInstruction(BB);
|
||||
}
|
||||
|
||||
/// Returns true if at least one instruction from the given basic block may
|
||||
/// write memory.
|
||||
bool mayWriteToMemory(const BasicBlock *BB) {
|
||||
return hasSpecialInstructions(BB);
|
||||
}
|
||||
|
||||
/// Returns true if the first memory writing instruction of Insn's block
|
||||
/// exists and dominates Insn.
|
||||
bool isDominatedByMemoryWriteFromSameBlock(const Instruction *Insn) {
|
||||
return isPreceededBySpecialInstruction(Insn);
|
||||
}
|
||||
|
||||
virtual bool isSpecialInstruction(const Instruction *Insn) const;
|
||||
};
|
||||
|
||||
} // llvm
|
||||
|
||||
#endif // LLVM_ANALYSIS_INSTRUCTIONPRECEDENCETRACKING_H
|
||||
|
|
@ -32,6 +32,8 @@
|
|||
#ifndef LLVM_ANALYSIS_INSTRUCTIONSIMPLIFY_H
|
||||
#define LLVM_ANALYSIS_INSTRUCTIONSIMPLIFY_H
|
||||
|
||||
#include "llvm/IR/Instruction.h"
|
||||
#include "llvm/IR/Operator.h"
|
||||
#include "llvm/IR/User.h"
|
||||
|
||||
namespace llvm {
|
||||
|
|
@ -40,7 +42,6 @@ template <typename T, typename... TArgs> class AnalysisManager;
|
|||
template <class T> class ArrayRef;
|
||||
class AssumptionCache;
|
||||
class DominatorTree;
|
||||
class Instruction;
|
||||
class ImmutableCallSite;
|
||||
class DataLayout;
|
||||
class FastMathFlags;
|
||||
|
|
@ -50,6 +51,41 @@ class Pass;
|
|||
class TargetLibraryInfo;
|
||||
class Type;
|
||||
class Value;
|
||||
class MDNode;
|
||||
class BinaryOperator;
|
||||
|
||||
/// InstrInfoQuery provides an interface to query additional information for
|
||||
/// instructions like metadata or keywords like nsw, which provides conservative
|
||||
/// results if the users specified it is safe to use.
|
||||
struct InstrInfoQuery {
|
||||
InstrInfoQuery(bool UMD) : UseInstrInfo(UMD) {}
|
||||
InstrInfoQuery() : UseInstrInfo(true) {}
|
||||
bool UseInstrInfo = true;
|
||||
|
||||
MDNode *getMetadata(const Instruction *I, unsigned KindID) const {
|
||||
if (UseInstrInfo)
|
||||
return I->getMetadata(KindID);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <class InstT> bool hasNoUnsignedWrap(const InstT *Op) const {
|
||||
if (UseInstrInfo)
|
||||
return Op->hasNoUnsignedWrap();
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class InstT> bool hasNoSignedWrap(const InstT *Op) const {
|
||||
if (UseInstrInfo)
|
||||
return Op->hasNoSignedWrap();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isExact(const BinaryOperator *Op) const {
|
||||
if (UseInstrInfo && isa<PossiblyExactOperator>(Op))
|
||||
return cast<PossiblyExactOperator>(Op)->isExact();
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
struct SimplifyQuery {
|
||||
const DataLayout &DL;
|
||||
|
|
@ -58,14 +94,19 @@ struct SimplifyQuery {
|
|||
AssumptionCache *AC = nullptr;
|
||||
const Instruction *CxtI = nullptr;
|
||||
|
||||
// Wrapper to query additional information for instructions like metadata or
|
||||
// keywords like nsw, which provides conservative results if those cannot
|
||||
// be safely used.
|
||||
const InstrInfoQuery IIQ;
|
||||
|
||||
SimplifyQuery(const DataLayout &DL, const Instruction *CXTI = nullptr)
|
||||
: DL(DL), CxtI(CXTI) {}
|
||||
|
||||
SimplifyQuery(const DataLayout &DL, const TargetLibraryInfo *TLI,
|
||||
const DominatorTree *DT = nullptr,
|
||||
AssumptionCache *AC = nullptr,
|
||||
const Instruction *CXTI = nullptr)
|
||||
: DL(DL), TLI(TLI), DT(DT), AC(AC), CxtI(CXTI) {}
|
||||
const Instruction *CXTI = nullptr, bool UseInstrInfo = true)
|
||||
: DL(DL), TLI(TLI), DT(DT), AC(AC), CxtI(CXTI), IIQ(UseInstrInfo) {}
|
||||
SimplifyQuery getWithInstruction(Instruction *I) const {
|
||||
SimplifyQuery Copy(*this);
|
||||
Copy.CxtI = I;
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
/// \file
|
||||
/// Compute iterated dominance frontiers using a linear time algorithm.
|
||||
///
|
||||
/// The algorithm used here is based on:
|
||||
|
|
@ -28,6 +28,7 @@
|
|||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/IR/BasicBlock.h"
|
||||
#include "llvm/IR/CFGDiff.h"
|
||||
#include "llvm/IR/Dominators.h"
|
||||
|
||||
namespace llvm {
|
||||
|
|
@ -45,17 +46,21 @@ namespace llvm {
|
|||
template <class NodeTy, bool IsPostDom>
|
||||
class IDFCalculator {
|
||||
public:
|
||||
IDFCalculator(DominatorTreeBase<BasicBlock, IsPostDom> &DT)
|
||||
: DT(DT), useLiveIn(false) {}
|
||||
IDFCalculator(DominatorTreeBase<BasicBlock, IsPostDom> &DT)
|
||||
: DT(DT), GD(nullptr), useLiveIn(false) {}
|
||||
|
||||
/// Give the IDF calculator the set of blocks in which the value is
|
||||
/// defined. This is equivalent to the set of starting blocks it should be
|
||||
/// calculating the IDF for (though later gets pruned based on liveness).
|
||||
///
|
||||
/// Note: This set *must* live for the entire lifetime of the IDF calculator.
|
||||
void setDefiningBlocks(const SmallPtrSetImpl<BasicBlock *> &Blocks) {
|
||||
DefBlocks = &Blocks;
|
||||
}
|
||||
IDFCalculator(DominatorTreeBase<BasicBlock, IsPostDom> &DT,
|
||||
const GraphDiff<BasicBlock *, IsPostDom> *GD)
|
||||
: DT(DT), GD(GD), useLiveIn(false) {}
|
||||
|
||||
/// Give the IDF calculator the set of blocks in which the value is
|
||||
/// defined. This is equivalent to the set of starting blocks it should be
|
||||
/// calculating the IDF for (though later gets pruned based on liveness).
|
||||
///
|
||||
/// Note: This set *must* live for the entire lifetime of the IDF calculator.
|
||||
void setDefiningBlocks(const SmallPtrSetImpl<BasicBlock *> &Blocks) {
|
||||
DefBlocks = &Blocks;
|
||||
}
|
||||
|
||||
/// Give the IDF calculator the set of blocks in which the value is
|
||||
/// live on entry to the block. This is used to prune the IDF calculation to
|
||||
|
|
@ -85,6 +90,7 @@ class IDFCalculator {
|
|||
|
||||
private:
|
||||
DominatorTreeBase<BasicBlock, IsPostDom> &DT;
|
||||
const GraphDiff<BasicBlock *, IsPostDom> *GD;
|
||||
bool useLiveIn;
|
||||
const SmallPtrSetImpl<BasicBlock *> *LiveInBlocks;
|
||||
const SmallPtrSetImpl<BasicBlock *> *DefBlocks;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,69 @@
|
|||
//===- llvm/Analysis/LegacyDivergenceAnalysis.h - KernelDivergence Analysis -*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The kernel divergence analysis is an LLVM pass which can be used to find out
|
||||
// if a branch instruction in a GPU program (kernel) is divergent or not. It can help
|
||||
// branch optimizations such as jump threading and loop unswitching to make
|
||||
// better decisions.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef LLVM_ANALYSIS_LEGACY_DIVERGENCE_ANALYSIS_H
|
||||
#define LLVM_ANALYSIS_LEGACY_DIVERGENCE_ANALYSIS_H
|
||||
|
||||
#include "llvm/ADT/DenseSet.h"
|
||||
#include "llvm/IR/Function.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/Analysis/DivergenceAnalysis.h"
|
||||
|
||||
namespace llvm {
|
||||
class Value;
|
||||
class GPUDivergenceAnalysis;
|
||||
class LegacyDivergenceAnalysis : public FunctionPass {
|
||||
public:
|
||||
static char ID;
|
||||
|
||||
LegacyDivergenceAnalysis() : FunctionPass(ID) {
|
||||
initializeLegacyDivergenceAnalysisPass(*PassRegistry::getPassRegistry());
|
||||
}
|
||||
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override;
|
||||
|
||||
bool runOnFunction(Function &F) override;
|
||||
|
||||
// Print all divergent branches in the function.
|
||||
void print(raw_ostream &OS, const Module *) const override;
|
||||
|
||||
// Returns true if V is divergent at its definition.
|
||||
//
|
||||
// Even if this function returns false, V may still be divergent when used
|
||||
// in a different basic block.
|
||||
bool isDivergent(const Value *V) const;
|
||||
|
||||
// Returns true if V is uniform/non-divergent.
|
||||
//
|
||||
// Even if this function returns true, V may still be divergent when used
|
||||
// in a different basic block.
|
||||
bool isUniform(const Value *V) const { return !isDivergent(V); }
|
||||
|
||||
// Keep the analysis results uptodate by removing an erased value.
|
||||
void removeValue(const Value *V) { DivergentValues.erase(V); }
|
||||
|
||||
private:
|
||||
// Whether analysis should be performed by GPUDivergenceAnalysis.
|
||||
bool shouldUseGPUDivergenceAnalysis(const Function &F) const;
|
||||
|
||||
// (optional) handle to new DivergenceAnalysis
|
||||
std::unique_ptr<GPUDivergenceAnalysis> gpuDA;
|
||||
|
||||
// Stores all divergent values.
|
||||
DenseSet<const Value *> DivergentValues;
|
||||
};
|
||||
} // End llvm namespace
|
||||
|
||||
#endif //LLVM_ANALYSIS_LEGACY_DIVERGENCE_ANALYSIS_H
|
||||
|
|
@ -97,6 +97,19 @@ public:
|
|||
/// Set of potential dependent memory accesses.
|
||||
typedef EquivalenceClasses<MemAccessInfo> DepCandidates;
|
||||
|
||||
/// Type to keep track of the status of the dependence check. The order of
|
||||
/// the elements is important and has to be from most permissive to least
|
||||
/// permissive.
|
||||
enum class VectorizationSafetyStatus {
|
||||
// Can vectorize safely without RT checks. All dependences are known to be
|
||||
// safe.
|
||||
Safe,
|
||||
// Can possibly vectorize with RT checks to overcome unknown dependencies.
|
||||
PossiblySafeWithRtChecks,
|
||||
// Cannot vectorize due to known unsafe dependencies.
|
||||
Unsafe,
|
||||
};
|
||||
|
||||
/// Dependece between memory access instructions.
|
||||
struct Dependence {
|
||||
/// The type of the dependence.
|
||||
|
|
@ -146,7 +159,7 @@ public:
|
|||
Instruction *getDestination(const LoopAccessInfo &LAI) const;
|
||||
|
||||
/// Dependence types that don't prevent vectorization.
|
||||
static bool isSafeForVectorization(DepType Type);
|
||||
static VectorizationSafetyStatus isSafeForVectorization(DepType Type);
|
||||
|
||||
/// Lexically forward dependence.
|
||||
bool isForward() const;
|
||||
|
|
@ -164,8 +177,8 @@ public:
|
|||
|
||||
MemoryDepChecker(PredicatedScalarEvolution &PSE, const Loop *L)
|
||||
: PSE(PSE), InnermostLoop(L), AccessIdx(0), MaxSafeRegisterWidth(-1U),
|
||||
ShouldRetryWithRuntimeCheck(false), SafeForVectorization(true),
|
||||
RecordDependences(true) {}
|
||||
FoundNonConstantDistanceDependence(false),
|
||||
Status(VectorizationSafetyStatus::Safe), RecordDependences(true) {}
|
||||
|
||||
/// Register the location (instructions are given increasing numbers)
|
||||
/// of a write access.
|
||||
|
|
@ -193,7 +206,9 @@ public:
|
|||
|
||||
/// No memory dependence was encountered that would inhibit
|
||||
/// vectorization.
|
||||
bool isSafeForVectorization() const { return SafeForVectorization; }
|
||||
bool isSafeForVectorization() const {
|
||||
return Status == VectorizationSafetyStatus::Safe;
|
||||
}
|
||||
|
||||
/// The maximum number of bytes of a vector register we can vectorize
|
||||
/// the accesses safely with.
|
||||
|
|
@ -205,7 +220,10 @@ public:
|
|||
|
||||
/// In same cases when the dependency check fails we can still
|
||||
/// vectorize the loop with a dynamic array access check.
|
||||
bool shouldRetryWithRuntimeCheck() { return ShouldRetryWithRuntimeCheck; }
|
||||
bool shouldRetryWithRuntimeCheck() const {
|
||||
return FoundNonConstantDistanceDependence &&
|
||||
Status == VectorizationSafetyStatus::PossiblySafeWithRtChecks;
|
||||
}
|
||||
|
||||
/// Returns the memory dependences. If null is returned we exceeded
|
||||
/// the MaxDependences threshold and this information is not
|
||||
|
|
@ -267,11 +285,12 @@ private:
|
|||
|
||||
/// If we see a non-constant dependence distance we can still try to
|
||||
/// vectorize this loop with runtime checks.
|
||||
bool ShouldRetryWithRuntimeCheck;
|
||||
bool FoundNonConstantDistanceDependence;
|
||||
|
||||
/// No memory dependence was encountered that would inhibit
|
||||
/// vectorization.
|
||||
bool SafeForVectorization;
|
||||
/// Result of the dependence checks, indicating whether the checked
|
||||
/// dependences are safe for vectorization, require RT checks or are known to
|
||||
/// be unsafe.
|
||||
VectorizationSafetyStatus Status;
|
||||
|
||||
//// True if Dependences reflects the dependences in the
|
||||
//// loop. If false we exceeded MaxDependences and
|
||||
|
|
@ -304,6 +323,11 @@ private:
|
|||
/// \return false if we shouldn't vectorize at all or avoid larger
|
||||
/// vectorization factors by limiting MaxSafeDepDistBytes.
|
||||
bool couldPreventStoreLoadForward(uint64_t Distance, uint64_t TypeByteSize);
|
||||
|
||||
/// Updates the current safety status with \p S. We can go from Safe to
|
||||
/// either PossiblySafeWithRtChecks or Unsafe and from
|
||||
/// PossiblySafeWithRtChecks to Unsafe.
|
||||
void mergeInStatus(VectorizationSafetyStatus S);
|
||||
};
|
||||
|
||||
/// Holds information about the memory runtime legality checks to verify
|
||||
|
|
@ -564,11 +588,10 @@ public:
|
|||
/// Print the information about the memory accesses in the loop.
|
||||
void print(raw_ostream &OS, unsigned Depth = 0) const;
|
||||
|
||||
/// Checks existence of store to invariant address inside loop.
|
||||
/// If the loop has any store to invariant address, then it returns true,
|
||||
/// else returns false.
|
||||
bool hasStoreToLoopInvariantAddress() const {
|
||||
return StoreToLoopInvariantAddress;
|
||||
/// If the loop has memory dependence involving an invariant address, i.e. two
|
||||
/// stores or a store and a load, then return true, else return false.
|
||||
bool hasDependenceInvolvingLoopInvariantAddress() const {
|
||||
return HasDependenceInvolvingLoopInvariantAddress;
|
||||
}
|
||||
|
||||
/// Used to add runtime SCEV checks. Simplifies SCEV expressions and converts
|
||||
|
|
@ -621,9 +644,8 @@ private:
|
|||
/// Cache the result of analyzeLoop.
|
||||
bool CanVecMem;
|
||||
|
||||
/// Indicator for storing to uniform addresses.
|
||||
/// If a loop has write to a loop invariant address then it should be true.
|
||||
bool StoreToLoopInvariantAddress;
|
||||
/// Indicator that there are non vectorizable stores to a uniform address.
|
||||
bool HasDependenceInvolvingLoopInvariantAddress;
|
||||
|
||||
/// The diagnostics report generated for the analysis. E.g. why we
|
||||
/// couldn't analyze the loop.
|
||||
|
|
|
|||
|
|
@ -408,6 +408,12 @@ public:
|
|||
/// Verify loop structure of this loop and all nested loops.
|
||||
void verifyLoopNest(DenseSet<const LoopT *> *Loops) const;
|
||||
|
||||
/// Returns true if the loop is annotated parallel.
|
||||
///
|
||||
/// Derived classes can override this method using static template
|
||||
/// polymorphism.
|
||||
bool isAnnotatedParallel() const { return false; }
|
||||
|
||||
/// Print loop with all the BBs inside it.
|
||||
void print(raw_ostream &OS, unsigned Depth = 0, bool Verbose = false) const;
|
||||
|
||||
|
|
@ -989,6 +995,26 @@ public:
|
|||
/// Function to print a loop's contents as LLVM's text IR assembly.
|
||||
void printLoop(Loop &L, raw_ostream &OS, const std::string &Banner = "");
|
||||
|
||||
/// Find and return the loop attribute node for the attribute @p Name in
|
||||
/// @p LoopID. Return nullptr if there is no such attribute.
|
||||
MDNode *findOptionMDForLoopID(MDNode *LoopID, StringRef Name);
|
||||
|
||||
/// Find string metadata for a loop.
|
||||
///
|
||||
/// Returns the MDNode where the first operand is the metadata's name. The
|
||||
/// following operands are the metadata's values. If no metadata with @p Name is
|
||||
/// found, return nullptr.
|
||||
MDNode *findOptionMDForLoop(const Loop *TheLoop, StringRef Name);
|
||||
|
||||
/// Return whether an MDNode might represent an access group.
|
||||
///
|
||||
/// Access group metadata nodes have to be distinct and empty. Being
|
||||
/// always-empty ensures that it never needs to be changed (which -- because
|
||||
/// MDNodes are designed immutable -- would require creating a new MDNode). Note
|
||||
/// that this is not a sufficient condition: not every distinct and empty NDNode
|
||||
/// is representing an access group.
|
||||
bool isValidAsAccessGroup(MDNode *AccGroup);
|
||||
|
||||
} // End llvm namespace
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -392,7 +392,10 @@ void LoopBase<BlockT, LoopT>::verifyLoopNest(
|
|||
template <class BlockT, class LoopT>
|
||||
void LoopBase<BlockT, LoopT>::print(raw_ostream &OS, unsigned Depth,
|
||||
bool Verbose) const {
|
||||
OS.indent(Depth * 2) << "Loop at depth " << getLoopDepth() << " containing: ";
|
||||
OS.indent(Depth * 2);
|
||||
if (static_cast<const LoopT *>(this)->isAnnotatedParallel())
|
||||
OS << "Parallel ";
|
||||
OS << "Loop at depth " << getLoopDepth() << " containing: ";
|
||||
|
||||
BlockT *H = getHeader();
|
||||
for (unsigned i = 0; i < getBlocks().size(); ++i) {
|
||||
|
|
@ -640,8 +643,8 @@ void LoopInfoBase<BlockT, LoopT>::print(raw_ostream &OS) const {
|
|||
|
||||
template <typename T>
|
||||
bool compareVectors(std::vector<T> &BB1, std::vector<T> &BB2) {
|
||||
llvm::sort(BB1.begin(), BB1.end());
|
||||
llvm::sort(BB2.begin(), BB2.end());
|
||||
llvm::sort(BB1);
|
||||
llvm::sort(BB2);
|
||||
return BB1 == BB2;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -37,7 +37,6 @@
|
|||
namespace llvm {
|
||||
|
||||
class AssumptionCache;
|
||||
class CallSite;
|
||||
class DominatorTree;
|
||||
class Function;
|
||||
class Instruction;
|
||||
|
|
@ -304,7 +303,7 @@ private:
|
|||
/// The maximum size of the dereferences of the pointer.
|
||||
///
|
||||
/// May be UnknownSize if the sizes are unknown.
|
||||
LocationSize Size = MemoryLocation::UnknownSize;
|
||||
LocationSize Size = LocationSize::unknown();
|
||||
/// The AA tags associated with dereferences of the pointer.
|
||||
///
|
||||
/// The members may be null if there are no tags or conflicting tags.
|
||||
|
|
@ -398,7 +397,7 @@ public:
|
|||
/// invalidated on the next non-local query or when an instruction is
|
||||
/// removed. Clients must copy this data if they want it around longer than
|
||||
/// that.
|
||||
const NonLocalDepInfo &getNonLocalCallDependency(CallSite QueryCS);
|
||||
const NonLocalDepInfo &getNonLocalCallDependency(CallBase *QueryCall);
|
||||
|
||||
/// Perform a full dependency query for an access to the QueryInst's
|
||||
/// specified memory location, returning the set of instructions that either
|
||||
|
|
@ -482,9 +481,9 @@ public:
|
|||
void releaseMemory();
|
||||
|
||||
private:
|
||||
MemDepResult getCallSiteDependencyFrom(CallSite C, bool isReadOnlyCall,
|
||||
BasicBlock::iterator ScanIt,
|
||||
BasicBlock *BB);
|
||||
MemDepResult getCallDependencyFrom(CallBase *Call, bool isReadOnlyCall,
|
||||
BasicBlock::iterator ScanIt,
|
||||
BasicBlock *BB);
|
||||
bool getNonLocalPointerDepFromBB(Instruction *QueryInst,
|
||||
const PHITransAddr &Pointer,
|
||||
const MemoryLocation &Loc, bool isLoad,
|
||||
|
|
|
|||
|
|
@ -16,9 +16,9 @@
|
|||
#ifndef LLVM_ANALYSIS_MEMORYLOCATION_H
|
||||
#define LLVM_ANALYSIS_MEMORYLOCATION_H
|
||||
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/ADT/DenseMapInfo.h"
|
||||
#include "llvm/IR/CallSite.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/IR/Instructions.h"
|
||||
#include "llvm/IR/Metadata.h"
|
||||
|
||||
namespace llvm {
|
||||
|
|
@ -34,8 +34,134 @@ class AnyMemIntrinsic;
|
|||
class TargetLibraryInfo;
|
||||
|
||||
// Represents the size of a MemoryLocation. Logically, it's an
|
||||
// Optional<uint64_t>, with a special UnknownSize value from `MemoryLocation`.
|
||||
using LocationSize = uint64_t;
|
||||
// Optional<uint63_t> that also carries a bit to represent whether the integer
|
||||
// it contains, N, is 'precise'. Precise, in this context, means that we know
|
||||
// that the area of storage referenced by the given MemoryLocation must be
|
||||
// precisely N bytes. An imprecise value is formed as the union of two or more
|
||||
// precise values, and can conservatively represent all of the values unioned
|
||||
// into it. Importantly, imprecise values are an *upper-bound* on the size of a
|
||||
// MemoryLocation.
|
||||
//
|
||||
// Concretely, a precise MemoryLocation is (%p, 4) in
|
||||
// store i32 0, i32* %p
|
||||
//
|
||||
// Since we know that %p must be at least 4 bytes large at this point.
|
||||
// Otherwise, we have UB. An example of an imprecise MemoryLocation is (%p, 4)
|
||||
// at the memcpy in
|
||||
//
|
||||
// %n = select i1 %foo, i64 1, i64 4
|
||||
// call void @llvm.memcpy.p0i8.p0i8.i64(i8* %p, i8* %baz, i64 %n, i32 1,
|
||||
// i1 false)
|
||||
//
|
||||
// ...Since we'll copy *up to* 4 bytes into %p, but we can't guarantee that
|
||||
// we'll ever actually do so.
|
||||
//
|
||||
// If asked to represent a pathologically large value, this will degrade to
|
||||
// None.
|
||||
class LocationSize {
|
||||
enum : uint64_t {
|
||||
Unknown = ~uint64_t(0),
|
||||
ImpreciseBit = uint64_t(1) << 63,
|
||||
MapEmpty = Unknown - 1,
|
||||
MapTombstone = Unknown - 2,
|
||||
|
||||
// The maximum value we can represent without falling back to 'unknown'.
|
||||
MaxValue = (MapTombstone - 1) & ~ImpreciseBit,
|
||||
};
|
||||
|
||||
uint64_t Value;
|
||||
|
||||
// Hack to support implicit construction. This should disappear when the
|
||||
// public LocationSize ctor goes away.
|
||||
enum DirectConstruction { Direct };
|
||||
|
||||
constexpr LocationSize(uint64_t Raw, DirectConstruction): Value(Raw) {}
|
||||
|
||||
static_assert(Unknown & ImpreciseBit, "Unknown is imprecise by definition.");
|
||||
public:
|
||||
// FIXME: Migrate all users to construct via either `precise` or `upperBound`,
|
||||
// to make it more obvious at the callsite the kind of size that they're
|
||||
// providing.
|
||||
//
|
||||
// Since the overwhelming majority of users of this provide precise values,
|
||||
// this assumes the provided value is precise.
|
||||
constexpr LocationSize(uint64_t Raw)
|
||||
: Value(Raw > MaxValue ? Unknown : Raw) {}
|
||||
|
||||
static LocationSize precise(uint64_t Value) { return LocationSize(Value); }
|
||||
|
||||
static LocationSize upperBound(uint64_t Value) {
|
||||
// You can't go lower than 0, so give a precise result.
|
||||
if (LLVM_UNLIKELY(Value == 0))
|
||||
return precise(0);
|
||||
if (LLVM_UNLIKELY(Value > MaxValue))
|
||||
return unknown();
|
||||
return LocationSize(Value | ImpreciseBit, Direct);
|
||||
}
|
||||
|
||||
constexpr static LocationSize unknown() {
|
||||
return LocationSize(Unknown, Direct);
|
||||
}
|
||||
|
||||
// Sentinel values, generally used for maps.
|
||||
constexpr static LocationSize mapTombstone() {
|
||||
return LocationSize(MapTombstone, Direct);
|
||||
}
|
||||
constexpr static LocationSize mapEmpty() {
|
||||
return LocationSize(MapEmpty, Direct);
|
||||
}
|
||||
|
||||
// Returns a LocationSize that can correctly represent either `*this` or
|
||||
// `Other`.
|
||||
LocationSize unionWith(LocationSize Other) const {
|
||||
if (Other == *this)
|
||||
return *this;
|
||||
|
||||
if (!hasValue() || !Other.hasValue())
|
||||
return unknown();
|
||||
|
||||
return upperBound(std::max(getValue(), Other.getValue()));
|
||||
}
|
||||
|
||||
bool hasValue() const { return Value != Unknown; }
|
||||
uint64_t getValue() const {
|
||||
assert(hasValue() && "Getting value from an unknown LocationSize!");
|
||||
return Value & ~ImpreciseBit;
|
||||
}
|
||||
|
||||
// Returns whether or not this value is precise. Note that if a value is
|
||||
// precise, it's guaranteed to not be `unknown()`.
|
||||
bool isPrecise() const {
|
||||
return (Value & ImpreciseBit) == 0;
|
||||
}
|
||||
|
||||
// Convenience method to check if this LocationSize's value is 0.
|
||||
bool isZero() const { return hasValue() && getValue() == 0; }
|
||||
|
||||
bool operator==(const LocationSize &Other) const {
|
||||
return Value == Other.Value;
|
||||
}
|
||||
|
||||
bool operator!=(const LocationSize &Other) const {
|
||||
return !(*this == Other);
|
||||
}
|
||||
|
||||
// Ordering operators are not provided, since it's unclear if there's only one
|
||||
// reasonable way to compare:
|
||||
// - values that don't exist against values that do, and
|
||||
// - precise values to imprecise values
|
||||
|
||||
void print(raw_ostream &OS) const;
|
||||
|
||||
// Returns an opaque value that represents this LocationSize. Cannot be
|
||||
// reliably converted back into a LocationSize.
|
||||
uint64_t toRaw() const { return Value; }
|
||||
};
|
||||
|
||||
inline raw_ostream &operator<<(raw_ostream &OS, LocationSize Size) {
|
||||
Size.print(OS);
|
||||
return OS;
|
||||
}
|
||||
|
||||
/// Representation for a specific memory location.
|
||||
///
|
||||
|
|
@ -108,11 +234,15 @@ public:
|
|||
static MemoryLocation getForDest(const AnyMemIntrinsic *MI);
|
||||
|
||||
/// Return a location representing a particular argument of a call.
|
||||
static MemoryLocation getForArgument(ImmutableCallSite CS, unsigned ArgIdx,
|
||||
const TargetLibraryInfo &TLI);
|
||||
static MemoryLocation getForArgument(const CallBase *Call, unsigned ArgIdx,
|
||||
const TargetLibraryInfo *TLI);
|
||||
static MemoryLocation getForArgument(const CallBase *Call, unsigned ArgIdx,
|
||||
const TargetLibraryInfo &TLI) {
|
||||
return getForArgument(Call, ArgIdx, &TLI);
|
||||
}
|
||||
|
||||
explicit MemoryLocation(const Value *Ptr = nullptr,
|
||||
LocationSize Size = UnknownSize,
|
||||
LocationSize Size = LocationSize::unknown(),
|
||||
const AAMDNodes &AATags = AAMDNodes())
|
||||
: Ptr(Ptr), Size(Size), AATags(AATags) {}
|
||||
|
||||
|
|
@ -139,13 +269,30 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
// Specialize DenseMapInfo for MemoryLocation.
|
||||
// Specialize DenseMapInfo.
|
||||
template <> struct DenseMapInfo<LocationSize> {
|
||||
static inline LocationSize getEmptyKey() {
|
||||
return LocationSize::mapEmpty();
|
||||
}
|
||||
static inline LocationSize getTombstoneKey() {
|
||||
return LocationSize::mapTombstone();
|
||||
}
|
||||
static unsigned getHashValue(const LocationSize &Val) {
|
||||
return DenseMapInfo<uint64_t>::getHashValue(Val.toRaw());
|
||||
}
|
||||
static bool isEqual(const LocationSize &LHS, const LocationSize &RHS) {
|
||||
return LHS == RHS;
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct DenseMapInfo<MemoryLocation> {
|
||||
static inline MemoryLocation getEmptyKey() {
|
||||
return MemoryLocation(DenseMapInfo<const Value *>::getEmptyKey(), 0);
|
||||
return MemoryLocation(DenseMapInfo<const Value *>::getEmptyKey(),
|
||||
DenseMapInfo<LocationSize>::getEmptyKey());
|
||||
}
|
||||
static inline MemoryLocation getTombstoneKey() {
|
||||
return MemoryLocation(DenseMapInfo<const Value *>::getTombstoneKey(), 0);
|
||||
return MemoryLocation(DenseMapInfo<const Value *>::getTombstoneKey(),
|
||||
DenseMapInfo<LocationSize>::getTombstoneKey());
|
||||
}
|
||||
static unsigned getHashValue(const MemoryLocation &Val) {
|
||||
return DenseMapInfo<const Value *>::getHashValue(Val.Ptr) ^
|
||||
|
|
|
|||
|
|
@ -280,9 +280,10 @@ protected:
|
|||
friend class MemorySSAUpdater;
|
||||
|
||||
MemoryUseOrDef(LLVMContext &C, MemoryAccess *DMA, unsigned Vty,
|
||||
DeleteValueTy DeleteValue, Instruction *MI, BasicBlock *BB)
|
||||
: MemoryAccess(C, Vty, DeleteValue, BB, 1), MemoryInstruction(MI),
|
||||
OptimizedAccessAlias(MayAlias) {
|
||||
DeleteValueTy DeleteValue, Instruction *MI, BasicBlock *BB,
|
||||
unsigned NumOperands)
|
||||
: MemoryAccess(C, Vty, DeleteValue, BB, NumOperands),
|
||||
MemoryInstruction(MI), OptimizedAccessAlias(MayAlias) {
|
||||
setDefiningAccess(DMA);
|
||||
}
|
||||
|
||||
|
|
@ -308,11 +309,6 @@ private:
|
|||
Optional<AliasResult> OptimizedAccessAlias;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct OperandTraits<MemoryUseOrDef>
|
||||
: public FixedNumOperandTraits<MemoryUseOrDef, 1> {};
|
||||
DEFINE_TRANSPARENT_OPERAND_ACCESSORS(MemoryUseOrDef, MemoryAccess)
|
||||
|
||||
/// Represents read-only accesses to memory
|
||||
///
|
||||
/// In particular, the set of Instructions that will be represented by
|
||||
|
|
@ -323,7 +319,8 @@ public:
|
|||
DECLARE_TRANSPARENT_OPERAND_ACCESSORS(MemoryAccess);
|
||||
|
||||
MemoryUse(LLVMContext &C, MemoryAccess *DMA, Instruction *MI, BasicBlock *BB)
|
||||
: MemoryUseOrDef(C, DMA, MemoryUseVal, deleteMe, MI, BB) {}
|
||||
: MemoryUseOrDef(C, DMA, MemoryUseVal, deleteMe, MI, BB,
|
||||
/*NumOperands=*/1) {}
|
||||
|
||||
// allocate space for exactly one operand
|
||||
void *operator new(size_t s) { return User::operator new(s, 1); }
|
||||
|
|
@ -381,31 +378,33 @@ public:
|
|||
|
||||
MemoryDef(LLVMContext &C, MemoryAccess *DMA, Instruction *MI, BasicBlock *BB,
|
||||
unsigned Ver)
|
||||
: MemoryUseOrDef(C, DMA, MemoryDefVal, deleteMe, MI, BB), ID(Ver) {}
|
||||
: MemoryUseOrDef(C, DMA, MemoryDefVal, deleteMe, MI, BB,
|
||||
/*NumOperands=*/2),
|
||||
ID(Ver) {}
|
||||
|
||||
// allocate space for exactly one operand
|
||||
void *operator new(size_t s) { return User::operator new(s, 1); }
|
||||
// allocate space for exactly two operands
|
||||
void *operator new(size_t s) { return User::operator new(s, 2); }
|
||||
|
||||
static bool classof(const Value *MA) {
|
||||
return MA->getValueID() == MemoryDefVal;
|
||||
}
|
||||
|
||||
void setOptimized(MemoryAccess *MA) {
|
||||
Optimized = MA;
|
||||
OptimizedID = getDefiningAccess()->getID();
|
||||
setOperand(1, MA);
|
||||
OptimizedID = MA->getID();
|
||||
}
|
||||
|
||||
MemoryAccess *getOptimized() const {
|
||||
return cast_or_null<MemoryAccess>(Optimized);
|
||||
return cast_or_null<MemoryAccess>(getOperand(1));
|
||||
}
|
||||
|
||||
bool isOptimized() const {
|
||||
return getOptimized() && getDefiningAccess() &&
|
||||
OptimizedID == getDefiningAccess()->getID();
|
||||
return getOptimized() && OptimizedID == getOptimized()->getID();
|
||||
}
|
||||
|
||||
void resetOptimized() {
|
||||
OptimizedID = INVALID_MEMORYACCESS_ID;
|
||||
setOperand(1, nullptr);
|
||||
}
|
||||
|
||||
void print(raw_ostream &OS) const;
|
||||
|
|
@ -417,13 +416,34 @@ private:
|
|||
|
||||
const unsigned ID;
|
||||
unsigned OptimizedID = INVALID_MEMORYACCESS_ID;
|
||||
WeakVH Optimized;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct OperandTraits<MemoryDef> : public FixedNumOperandTraits<MemoryDef, 1> {};
|
||||
struct OperandTraits<MemoryDef> : public FixedNumOperandTraits<MemoryDef, 2> {};
|
||||
DEFINE_TRANSPARENT_OPERAND_ACCESSORS(MemoryDef, MemoryAccess)
|
||||
|
||||
template <>
|
||||
struct OperandTraits<MemoryUseOrDef> {
|
||||
static Use *op_begin(MemoryUseOrDef *MUD) {
|
||||
if (auto *MU = dyn_cast<MemoryUse>(MUD))
|
||||
return OperandTraits<MemoryUse>::op_begin(MU);
|
||||
return OperandTraits<MemoryDef>::op_begin(cast<MemoryDef>(MUD));
|
||||
}
|
||||
|
||||
static Use *op_end(MemoryUseOrDef *MUD) {
|
||||
if (auto *MU = dyn_cast<MemoryUse>(MUD))
|
||||
return OperandTraits<MemoryUse>::op_end(MU);
|
||||
return OperandTraits<MemoryDef>::op_end(cast<MemoryDef>(MUD));
|
||||
}
|
||||
|
||||
static unsigned operands(const MemoryUseOrDef *MUD) {
|
||||
if (const auto *MU = dyn_cast<MemoryUse>(MUD))
|
||||
return OperandTraits<MemoryUse>::operands(MU);
|
||||
return OperandTraits<MemoryDef>::operands(cast<MemoryDef>(MUD));
|
||||
}
|
||||
};
|
||||
DEFINE_TRANSPARENT_OPERAND_ACCESSORS(MemoryUseOrDef, MemoryAccess)
|
||||
|
||||
/// Represents phi nodes for memory accesses.
|
||||
///
|
||||
/// These have the same semantic as regular phi nodes, with the exception that
|
||||
|
|
@ -684,13 +704,19 @@ public:
|
|||
~MemorySSA();
|
||||
|
||||
MemorySSAWalker *getWalker();
|
||||
MemorySSAWalker *getSkipSelfWalker();
|
||||
|
||||
/// Given a memory Mod/Ref'ing instruction, get the MemorySSA
|
||||
/// access associated with it. If passed a basic block gets the memory phi
|
||||
/// node that exists for that block, if there is one. Otherwise, this will get
|
||||
/// a MemoryUseOrDef.
|
||||
MemoryUseOrDef *getMemoryAccess(const Instruction *) const;
|
||||
MemoryPhi *getMemoryAccess(const BasicBlock *BB) const;
|
||||
MemoryUseOrDef *getMemoryAccess(const Instruction *I) const {
|
||||
return cast_or_null<MemoryUseOrDef>(ValueToMemoryAccess.lookup(I));
|
||||
}
|
||||
|
||||
MemoryPhi *getMemoryAccess(const BasicBlock *BB) const {
|
||||
return cast_or_null<MemoryPhi>(ValueToMemoryAccess.lookup(cast<Value>(BB)));
|
||||
}
|
||||
|
||||
void dump() const;
|
||||
void print(raw_ostream &) const;
|
||||
|
|
@ -750,6 +776,9 @@ public:
|
|||
/// all uses, uses appear in the right places). This is used by unit tests.
|
||||
void verifyMemorySSA() const;
|
||||
|
||||
/// Check clobber sanity for an access.
|
||||
void checkClobberSanityAccess(const MemoryAccess *MA) const;
|
||||
|
||||
/// Used in various insertion functions to specify whether we are talking
|
||||
/// about the beginning or end of a block.
|
||||
enum InsertionPlace { Beginning, End };
|
||||
|
|
@ -764,6 +793,7 @@ protected:
|
|||
void verifyDomination(Function &F) const;
|
||||
void verifyOrdering(Function &F) const;
|
||||
void verifyDominationNumbers(const Function &F) const;
|
||||
void verifyClobberSanity(const Function &F) const;
|
||||
|
||||
// This is used by the use optimizer and updater.
|
||||
AccessList *getWritableBlockAccesses(const BasicBlock *BB) const {
|
||||
|
|
@ -796,16 +826,20 @@ protected:
|
|||
InsertionPlace);
|
||||
void insertIntoListsBefore(MemoryAccess *, const BasicBlock *,
|
||||
AccessList::iterator);
|
||||
MemoryUseOrDef *createDefinedAccess(Instruction *, MemoryAccess *);
|
||||
MemoryUseOrDef *createDefinedAccess(Instruction *, MemoryAccess *,
|
||||
const MemoryUseOrDef *Template = nullptr);
|
||||
|
||||
private:
|
||||
class ClobberWalkerBase;
|
||||
class CachingWalker;
|
||||
class SkipSelfWalker;
|
||||
class OptimizeUses;
|
||||
|
||||
CachingWalker *getWalkerImpl();
|
||||
void buildMemorySSA();
|
||||
void optimizeUses();
|
||||
|
||||
void prepareForMoveTo(MemoryAccess *, BasicBlock *);
|
||||
void verifyUseInDefs(MemoryAccess *, MemoryAccess *) const;
|
||||
|
||||
using AccessMap = DenseMap<const BasicBlock *, std::unique_ptr<AccessList>>;
|
||||
|
|
@ -816,7 +850,8 @@ private:
|
|||
void markUnreachableAsLiveOnEntry(BasicBlock *BB);
|
||||
bool dominatesUse(const MemoryAccess *, const MemoryAccess *) const;
|
||||
MemoryPhi *createMemoryPhi(BasicBlock *BB);
|
||||
MemoryUseOrDef *createNewAccess(Instruction *);
|
||||
MemoryUseOrDef *createNewAccess(Instruction *,
|
||||
const MemoryUseOrDef *Template = nullptr);
|
||||
MemoryAccess *findDominatingDef(BasicBlock *, enum InsertionPlace);
|
||||
void placePHINodes(const SmallPtrSetImpl<BasicBlock *> &);
|
||||
MemoryAccess *renameBlock(BasicBlock *, MemoryAccess *, bool);
|
||||
|
|
@ -851,7 +886,9 @@ private:
|
|||
mutable DenseMap<const MemoryAccess *, unsigned long> BlockNumbering;
|
||||
|
||||
// Memory SSA building info
|
||||
std::unique_ptr<ClobberWalkerBase> WalkerBase;
|
||||
std::unique_ptr<CachingWalker> Walker;
|
||||
std::unique_ptr<SkipSelfWalker> SkipWalker;
|
||||
unsigned NextID;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -35,8 +35,11 @@
|
|||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/ADT/SmallSet.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/Analysis/LoopInfo.h"
|
||||
#include "llvm/Analysis/LoopIterator.h"
|
||||
#include "llvm/Analysis/MemorySSA.h"
|
||||
#include "llvm/IR/BasicBlock.h"
|
||||
#include "llvm/IR/CFGDiff.h"
|
||||
#include "llvm/IR/Dominators.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/IR/OperandTraits.h"
|
||||
|
|
@ -45,6 +48,7 @@
|
|||
#include "llvm/IR/User.h"
|
||||
#include "llvm/IR/Value.h"
|
||||
#include "llvm/IR/ValueHandle.h"
|
||||
#include "llvm/IR/ValueMap.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
|
|
@ -57,6 +61,12 @@ class MemoryAccess;
|
|||
class LLVMContext;
|
||||
class raw_ostream;
|
||||
|
||||
using ValueToValueMapTy = ValueMap<const Value *, WeakTrackingVH>;
|
||||
using PhiToDefMap = SmallDenseMap<MemoryPhi *, MemoryAccess *>;
|
||||
using CFGUpdate = cfg::Update<BasicBlock *>;
|
||||
using GraphDiffInvBBPair =
|
||||
std::pair<const GraphDiff<BasicBlock *> *, Inverse<BasicBlock *>>;
|
||||
|
||||
class MemorySSAUpdater {
|
||||
private:
|
||||
MemorySSA *MSSA;
|
||||
|
|
@ -70,6 +80,7 @@ private:
|
|||
|
||||
public:
|
||||
MemorySSAUpdater(MemorySSA *MSSA) : MSSA(MSSA) {}
|
||||
|
||||
/// Insert a definition into the MemorySSA IR. RenameUses will rename any use
|
||||
/// below the new def block (and any inserted phis). RenameUses should be set
|
||||
/// to true if the definition may cause new aliases for loads below it. This
|
||||
|
|
@ -89,15 +100,48 @@ public:
|
|||
/// Where a mayalias b, *does* require RenameUses be set to true.
|
||||
void insertDef(MemoryDef *Def, bool RenameUses = false);
|
||||
void insertUse(MemoryUse *Use);
|
||||
/// Update the MemoryPhi in `To` following an edge deletion between `From` and
|
||||
/// `To`. If `To` becomes unreachable, a call to removeBlocks should be made.
|
||||
void removeEdge(BasicBlock *From, BasicBlock *To);
|
||||
/// Update the MemoryPhi in `To` to have a single incoming edge from `From`,
|
||||
/// following a CFG change that replaced multiple edges (switch) with a direct
|
||||
/// branch.
|
||||
void removeDuplicatePhiEdgesBetween(BasicBlock *From, BasicBlock *To);
|
||||
/// Update MemorySSA after a loop was cloned, given the blocks in RPO order,
|
||||
/// the exit blocks and a 1:1 mapping of all blocks and instructions
|
||||
/// cloned. This involves duplicating all defs and uses in the cloned blocks
|
||||
/// Updating phi nodes in exit block successors is done separately.
|
||||
void updateForClonedLoop(const LoopBlocksRPO &LoopBlocks,
|
||||
ArrayRef<BasicBlock *> ExitBlocks,
|
||||
const ValueToValueMapTy &VM,
|
||||
bool IgnoreIncomingWithNoClones = false);
|
||||
// Block BB was fully or partially cloned into its predecessor P1. Map
|
||||
// contains the 1:1 mapping of instructions cloned and VM[BB]=P1.
|
||||
void updateForClonedBlockIntoPred(BasicBlock *BB, BasicBlock *P1,
|
||||
const ValueToValueMapTy &VM);
|
||||
/// Update phi nodes in exit block successors following cloning. Exit blocks
|
||||
/// that were not cloned don't have additional predecessors added.
|
||||
void updateExitBlocksForClonedLoop(ArrayRef<BasicBlock *> ExitBlocks,
|
||||
const ValueToValueMapTy &VMap,
|
||||
DominatorTree &DT);
|
||||
void updateExitBlocksForClonedLoop(
|
||||
ArrayRef<BasicBlock *> ExitBlocks,
|
||||
ArrayRef<std::unique_ptr<ValueToValueMapTy>> VMaps, DominatorTree &DT);
|
||||
|
||||
/// Apply CFG updates, analogous with the DT edge updates.
|
||||
void applyUpdates(ArrayRef<CFGUpdate> Updates, DominatorTree &DT);
|
||||
/// Apply CFG insert updates, analogous with the DT edge updates.
|
||||
void applyInsertUpdates(ArrayRef<CFGUpdate> Updates, DominatorTree &DT);
|
||||
|
||||
void moveBefore(MemoryUseOrDef *What, MemoryUseOrDef *Where);
|
||||
void moveAfter(MemoryUseOrDef *What, MemoryUseOrDef *Where);
|
||||
void moveToPlace(MemoryUseOrDef *What, BasicBlock *BB,
|
||||
MemorySSA::InsertionPlace Where);
|
||||
/// `From` block was spliced into `From` and `To`.
|
||||
/// Move all accesses from `From` to `To` starting at instruction `Start`.
|
||||
/// `To` is newly created BB, so empty of MemorySSA::MemoryAccesses.
|
||||
/// Edges are already updated, so successors of `To` with MPhi nodes need to
|
||||
/// update incoming block.
|
||||
/// `From` block was spliced into `From` and `To`. There is a CFG edge from
|
||||
/// `From` to `To`. Move all accesses from `From` to `To` starting at
|
||||
/// instruction `Start`. `To` is newly created BB, so empty of
|
||||
/// MemorySSA::MemoryAccesses. Edges are already updated, so successors of
|
||||
/// `To` with MPhi nodes need to update incoming block.
|
||||
/// |------| |------|
|
||||
/// | From | | From |
|
||||
/// | | |------|
|
||||
|
|
@ -108,12 +152,12 @@ public:
|
|||
/// |------| |------|
|
||||
void moveAllAfterSpliceBlocks(BasicBlock *From, BasicBlock *To,
|
||||
Instruction *Start);
|
||||
/// `From` block was merged into `To`. All instructions were moved and
|
||||
/// `From` is an empty block with successor edges; `From` is about to be
|
||||
/// deleted. Move all accesses from `From` to `To` starting at instruction
|
||||
/// `Start`. `To` may have multiple successors, `From` has a single
|
||||
/// predecessor. `From` may have successors with MPhi nodes, replace their
|
||||
/// incoming block with `To`.
|
||||
/// `From` block was merged into `To`. There is a CFG edge from `To` to
|
||||
/// `From`.`To` still branches to `From`, but all instructions were moved and
|
||||
/// `From` is now an empty block; `From` is about to be deleted. Move all
|
||||
/// accesses from `From` to `To` starting at instruction `Start`. `To` may
|
||||
/// have multiple successors, `From` has a single predecessor. `From` may have
|
||||
/// successors with MPhi nodes, replace their incoming block with `To`.
|
||||
/// |------| |------|
|
||||
/// | To | | To |
|
||||
/// |------| | |
|
||||
|
|
@ -124,15 +168,14 @@ public:
|
|||
/// |------| |------|
|
||||
void moveAllAfterMergeBlocks(BasicBlock *From, BasicBlock *To,
|
||||
Instruction *Start);
|
||||
/// BasicBlock Old had New, an empty BasicBlock, added directly before it,
|
||||
/// and the predecessors in Preds that used to point to Old, now point to
|
||||
/// New. If New is the only predecessor, move Old's Phi, if present, to New.
|
||||
/// A new empty BasicBlock (New) now branches directly to Old. Some of
|
||||
/// Old's predecessors (Preds) are now branching to New instead of Old.
|
||||
/// If New is the only predecessor, move Old's Phi, if present, to New.
|
||||
/// Otherwise, add a new Phi in New with appropriate incoming values, and
|
||||
/// update the incoming values in Old's Phi node too, if present.
|
||||
void
|
||||
wireOldPredecessorsToNewImmediatePredecessor(BasicBlock *Old, BasicBlock *New,
|
||||
ArrayRef<BasicBlock *> Preds);
|
||||
|
||||
void wireOldPredecessorsToNewImmediatePredecessor(
|
||||
BasicBlock *Old, BasicBlock *New, ArrayRef<BasicBlock *> Preds,
|
||||
bool IdenticalEdgesWereMerged = true);
|
||||
// The below are utility functions. Other than creation of accesses to pass
|
||||
// to insertDef, and removeAccess to remove accesses, you should generally
|
||||
// not attempt to update memoryssa yourself. It is very non-trivial to get
|
||||
|
|
@ -220,6 +263,23 @@ private:
|
|||
template <class RangeType>
|
||||
MemoryAccess *tryRemoveTrivialPhi(MemoryPhi *Phi, RangeType &Operands);
|
||||
void fixupDefs(const SmallVectorImpl<WeakVH> &);
|
||||
// Clone all uses and defs from BB to NewBB given a 1:1 map of all
|
||||
// instructions and blocks cloned, and a map of MemoryPhi : Definition
|
||||
// (MemoryAccess Phi or Def). VMap maps old instructions to cloned
|
||||
// instructions and old blocks to cloned blocks. MPhiMap, is created in the
|
||||
// caller of this private method, and maps existing MemoryPhis to new
|
||||
// definitions that new MemoryAccesses must point to. These definitions may
|
||||
// not necessarily be MemoryPhis themselves, they may be MemoryDefs. As such,
|
||||
// the map is between MemoryPhis and MemoryAccesses, where the MemoryAccesses
|
||||
// may be MemoryPhis or MemoryDefs and not MemoryUses.
|
||||
void cloneUsesAndDefs(BasicBlock *BB, BasicBlock *NewBB,
|
||||
const ValueToValueMapTy &VMap, PhiToDefMap &MPhiMap);
|
||||
template <typename Iter>
|
||||
void privateUpdateExitBlocksForClonedLoop(ArrayRef<BasicBlock *> ExitBlocks,
|
||||
Iter ValuesBegin, Iter ValuesEnd,
|
||||
DominatorTree &DT);
|
||||
void applyInsertUpdates(ArrayRef<CFGUpdate>, DominatorTree &DT,
|
||||
const GraphDiff<BasicBlock *> *GD);
|
||||
};
|
||||
} // end namespace llvm
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/Analysis/EHPersonalities.h"
|
||||
#include "llvm/Analysis/InstructionPrecedenceTracking.h"
|
||||
#include "llvm/Analysis/LoopInfo.h"
|
||||
#include "llvm/IR/BasicBlock.h"
|
||||
#include "llvm/IR/Dominators.h"
|
||||
|
|
@ -31,33 +32,138 @@ class DominatorTree;
|
|||
class Loop;
|
||||
|
||||
/// Captures loop safety information.
|
||||
/// It keep information for loop & its header may throw exception or otherwise
|
||||
/// It keep information for loop blocks may throw exception or otherwise
|
||||
/// exit abnormaly on any iteration of the loop which might actually execute
|
||||
/// at runtime. The primary way to consume this infromation is via
|
||||
/// isGuaranteedToExecute below, but some callers bailout or fallback to
|
||||
/// alternate reasoning if a loop contains any implicit control flow.
|
||||
struct LoopSafetyInfo {
|
||||
bool MayThrow = false; // The current loop contains an instruction which
|
||||
// may throw.
|
||||
bool HeaderMayThrow = false; // Same as previous, but specific to loop header
|
||||
/// NOTE: LoopSafetyInfo contains cached information regarding loops and their
|
||||
/// particular blocks. This information is only dropped on invocation of
|
||||
/// computeLoopSafetyInfo. If the loop or any of its block is deleted, or if
|
||||
/// any thrower instructions have been added or removed from them, or if the
|
||||
/// control flow has changed, or in case of other meaningful modifications, the
|
||||
/// LoopSafetyInfo needs to be recomputed. If a meaningful modifications to the
|
||||
/// loop were made and the info wasn't recomputed properly, the behavior of all
|
||||
/// methods except for computeLoopSafetyInfo is undefined.
|
||||
class LoopSafetyInfo {
|
||||
// Used to update funclet bundle operands.
|
||||
DenseMap<BasicBlock *, ColorVector> BlockColors;
|
||||
|
||||
protected:
|
||||
/// Computes block colors.
|
||||
void computeBlockColors(const Loop *CurLoop);
|
||||
|
||||
public:
|
||||
/// Returns block colors map that is used to update funclet operand bundles.
|
||||
const DenseMap<BasicBlock *, ColorVector> &getBlockColors() const;
|
||||
|
||||
/// Copy colors of block \p Old into the block \p New.
|
||||
void copyColors(BasicBlock *New, BasicBlock *Old);
|
||||
|
||||
/// Returns true iff the block \p BB potentially may throw exception. It can
|
||||
/// be false-positive in cases when we want to avoid complex analysis.
|
||||
virtual bool blockMayThrow(const BasicBlock *BB) const = 0;
|
||||
|
||||
/// Returns true iff any block of the loop for which this info is contains an
|
||||
/// instruction that may throw or otherwise exit abnormally.
|
||||
virtual bool anyBlockMayThrow() const = 0;
|
||||
|
||||
/// Return true if we must reach the block \p BB under assumption that the
|
||||
/// loop \p CurLoop is entered.
|
||||
bool allLoopPathsLeadToBlock(const Loop *CurLoop, const BasicBlock *BB,
|
||||
const DominatorTree *DT) const;
|
||||
|
||||
/// Computes safety information for a loop checks loop body & header for
|
||||
/// the possibility of may throw exception, it takes LoopSafetyInfo and loop
|
||||
/// as argument. Updates safety information in LoopSafetyInfo argument.
|
||||
/// Note: This is defined to clear and reinitialize an already initialized
|
||||
/// LoopSafetyInfo. Some callers rely on this fact.
|
||||
virtual void computeLoopSafetyInfo(const Loop *CurLoop) = 0;
|
||||
|
||||
/// Returns true if the instruction in a loop is guaranteed to execute at
|
||||
/// least once (under the assumption that the loop is entered).
|
||||
virtual bool isGuaranteedToExecute(const Instruction &Inst,
|
||||
const DominatorTree *DT,
|
||||
const Loop *CurLoop) const = 0;
|
||||
|
||||
LoopSafetyInfo() = default;
|
||||
|
||||
virtual ~LoopSafetyInfo() = default;
|
||||
};
|
||||
|
||||
/// Computes safety information for a loop checks loop body & header for
|
||||
/// the possibility of may throw exception, it takes LoopSafetyInfo and loop as
|
||||
/// argument. Updates safety information in LoopSafetyInfo argument.
|
||||
/// Note: This is defined to clear and reinitialize an already initialized
|
||||
/// LoopSafetyInfo. Some callers rely on this fact.
|
||||
void computeLoopSafetyInfo(LoopSafetyInfo *, Loop *);
|
||||
|
||||
/// Returns true if the instruction in a loop is guaranteed to execute at least
|
||||
/// once (under the assumption that the loop is entered).
|
||||
bool isGuaranteedToExecute(const Instruction &Inst, const DominatorTree *DT,
|
||||
const Loop *CurLoop,
|
||||
const LoopSafetyInfo *SafetyInfo);
|
||||
/// Simple and conservative implementation of LoopSafetyInfo that can give
|
||||
/// false-positive answers to its queries in order to avoid complicated
|
||||
/// analysis.
|
||||
class SimpleLoopSafetyInfo: public LoopSafetyInfo {
|
||||
bool MayThrow = false; // The current loop contains an instruction which
|
||||
// may throw.
|
||||
bool HeaderMayThrow = false; // Same as previous, but specific to loop header
|
||||
|
||||
public:
|
||||
virtual bool blockMayThrow(const BasicBlock *BB) const;
|
||||
|
||||
virtual bool anyBlockMayThrow() const;
|
||||
|
||||
virtual void computeLoopSafetyInfo(const Loop *CurLoop);
|
||||
|
||||
virtual bool isGuaranteedToExecute(const Instruction &Inst,
|
||||
const DominatorTree *DT,
|
||||
const Loop *CurLoop) const;
|
||||
|
||||
SimpleLoopSafetyInfo() : LoopSafetyInfo() {};
|
||||
|
||||
virtual ~SimpleLoopSafetyInfo() {};
|
||||
};
|
||||
|
||||
/// This implementation of LoopSafetyInfo use ImplicitControlFlowTracking to
|
||||
/// give precise answers on "may throw" queries. This implementation uses cache
|
||||
/// that should be invalidated by calling the methods insertInstructionTo and
|
||||
/// removeInstruction whenever we modify a basic block's contents by adding or
|
||||
/// removing instructions.
|
||||
class ICFLoopSafetyInfo: public LoopSafetyInfo {
|
||||
bool MayThrow = false; // The current loop contains an instruction which
|
||||
// may throw.
|
||||
// Contains information about implicit control flow in this loop's blocks.
|
||||
mutable ImplicitControlFlowTracking ICF;
|
||||
// Contains information about instruction that may possibly write memory.
|
||||
mutable MemoryWriteTracking MW;
|
||||
|
||||
public:
|
||||
virtual bool blockMayThrow(const BasicBlock *BB) const;
|
||||
|
||||
virtual bool anyBlockMayThrow() const;
|
||||
|
||||
virtual void computeLoopSafetyInfo(const Loop *CurLoop);
|
||||
|
||||
virtual bool isGuaranteedToExecute(const Instruction &Inst,
|
||||
const DominatorTree *DT,
|
||||
const Loop *CurLoop) const;
|
||||
|
||||
/// Returns true if we could not execute a memory-modifying instruction before
|
||||
/// we enter \p BB under assumption that \p CurLoop is entered.
|
||||
bool doesNotWriteMemoryBefore(const BasicBlock *BB, const Loop *CurLoop)
|
||||
const;
|
||||
|
||||
/// Returns true if we could not execute a memory-modifying instruction before
|
||||
/// we execute \p I under assumption that \p CurLoop is entered.
|
||||
bool doesNotWriteMemoryBefore(const Instruction &I, const Loop *CurLoop)
|
||||
const;
|
||||
|
||||
/// Inform the safety info that we are planning to insert a new instruction
|
||||
/// \p Inst into the basic block \p BB. It will make all cache updates to keep
|
||||
/// it correct after this insertion.
|
||||
void insertInstructionTo(const Instruction *Inst, const BasicBlock *BB);
|
||||
|
||||
/// Inform safety info that we are planning to remove the instruction \p Inst
|
||||
/// from its block. It will make all cache updates to keep it correct after
|
||||
/// this removal.
|
||||
void removeInstruction(const Instruction *Inst);
|
||||
|
||||
ICFLoopSafetyInfo(DominatorTree *DT) : LoopSafetyInfo(), ICF(DT), MW(DT) {};
|
||||
|
||||
virtual ~ICFLoopSafetyInfo() {};
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ public:
|
|||
FunctionModRefBehavior getModRefBehavior(const Function *F);
|
||||
|
||||
using AAResultBase::getModRefInfo;
|
||||
ModRefInfo getModRefInfo(ImmutableCallSite CS, const MemoryLocation &Loc);
|
||||
ModRefInfo getModRefInfo(const CallBase *Call, const MemoryLocation &Loc);
|
||||
};
|
||||
|
||||
/// Analysis pass providing a never-invalidated alias analysis result.
|
||||
|
|
|
|||
|
|
@ -51,25 +51,25 @@ extern bool EnableARCOpts;
|
|||
/// on.
|
||||
inline bool ModuleHasARC(const Module &M) {
|
||||
return
|
||||
M.getNamedValue("objc_retain") ||
|
||||
M.getNamedValue("objc_release") ||
|
||||
M.getNamedValue("objc_autorelease") ||
|
||||
M.getNamedValue("objc_retainAutoreleasedReturnValue") ||
|
||||
M.getNamedValue("objc_unsafeClaimAutoreleasedReturnValue") ||
|
||||
M.getNamedValue("objc_retainBlock") ||
|
||||
M.getNamedValue("objc_autoreleaseReturnValue") ||
|
||||
M.getNamedValue("objc_autoreleasePoolPush") ||
|
||||
M.getNamedValue("objc_loadWeakRetained") ||
|
||||
M.getNamedValue("objc_loadWeak") ||
|
||||
M.getNamedValue("objc_destroyWeak") ||
|
||||
M.getNamedValue("objc_storeWeak") ||
|
||||
M.getNamedValue("objc_initWeak") ||
|
||||
M.getNamedValue("objc_moveWeak") ||
|
||||
M.getNamedValue("objc_copyWeak") ||
|
||||
M.getNamedValue("objc_retainedObject") ||
|
||||
M.getNamedValue("objc_unretainedObject") ||
|
||||
M.getNamedValue("objc_unretainedPointer") ||
|
||||
M.getNamedValue("clang.arc.use");
|
||||
M.getNamedValue("llvm.objc.retain") ||
|
||||
M.getNamedValue("llvm.objc.release") ||
|
||||
M.getNamedValue("llvm.objc.autorelease") ||
|
||||
M.getNamedValue("llvm.objc.retainAutoreleasedReturnValue") ||
|
||||
M.getNamedValue("llvm.objc.unsafeClaimAutoreleasedReturnValue") ||
|
||||
M.getNamedValue("llvm.objc.retainBlock") ||
|
||||
M.getNamedValue("llvm.objc.autoreleaseReturnValue") ||
|
||||
M.getNamedValue("llvm.objc.autoreleasePoolPush") ||
|
||||
M.getNamedValue("llvm.objc.loadWeakRetained") ||
|
||||
M.getNamedValue("llvm.objc.loadWeak") ||
|
||||
M.getNamedValue("llvm.objc.destroyWeak") ||
|
||||
M.getNamedValue("llvm.objc.storeWeak") ||
|
||||
M.getNamedValue("llvm.objc.initWeak") ||
|
||||
M.getNamedValue("llvm.objc.moveWeak") ||
|
||||
M.getNamedValue("llvm.objc.copyWeak") ||
|
||||
M.getNamedValue("llvm.objc.retainedObject") ||
|
||||
M.getNamedValue("llvm.objc.unretainedObject") ||
|
||||
M.getNamedValue("llvm.objc.unretainedPointer") ||
|
||||
M.getNamedValue("llvm.objc.clang.arc.use");
|
||||
}
|
||||
|
||||
/// This is a wrapper around getUnderlyingObject which also knows how to
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#define LLVM_ANALYSIS_OBJCARCINSTKIND_H
|
||||
|
||||
#include "llvm/IR/Function.h"
|
||||
#include "llvm/IR/Intrinsics.h"
|
||||
#include "llvm/IR/Instructions.h"
|
||||
|
||||
namespace llvm {
|
||||
|
|
@ -48,7 +49,7 @@ enum class ARCInstKind {
|
|||
CopyWeak, ///< objc_copyWeak (derived)
|
||||
DestroyWeak, ///< objc_destroyWeak (derived)
|
||||
StoreStrong, ///< objc_storeStrong (derived)
|
||||
IntrinsicUser, ///< clang.arc.use
|
||||
IntrinsicUser, ///< llvm.objc.clang.arc.use
|
||||
CallOrUser, ///< could call objc_release and/or "use" pointers
|
||||
Call, ///< could call objc_release
|
||||
User, ///< could "use" a pointer
|
||||
|
|
|
|||
|
|
@ -17,8 +17,8 @@
|
|||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_TRANSFORMS_UTILS_ORDEREDINSTRUCTIONS_H
|
||||
#define LLVM_TRANSFORMS_UTILS_ORDEREDINSTRUCTIONS_H
|
||||
#ifndef LLVM_ANALYSIS_ORDEREDINSTRUCTIONS_H
|
||||
#define LLVM_ANALYSIS_ORDEREDINSTRUCTIONS_H
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/Analysis/OrderedBasicBlock.h"
|
||||
|
|
@ -62,4 +62,4 @@ public:
|
|||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_TRANSFORMS_UTILS_ORDEREDINSTRUCTIONS_H
|
||||
#endif // LLVM_ANALYSIS_ORDEREDINSTRUCTIONS_H
|
||||
|
|
@ -61,10 +61,10 @@ namespace llvm {
|
|||
|
||||
//===--------------------------------------------------------------------===//
|
||||
//
|
||||
// createDivergenceAnalysisPass - This pass determines which branches in a GPU
|
||||
// createLegacyDivergenceAnalysisPass - This pass determines which branches in a GPU
|
||||
// program are divergent.
|
||||
//
|
||||
FunctionPass *createDivergenceAnalysisPass();
|
||||
FunctionPass *createLegacyDivergenceAnalysisPass();
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
//
|
||||
|
|
|
|||
|
|
@ -88,6 +88,22 @@ private:
|
|||
/// All values reachable from each component.
|
||||
DenseMap<unsigned int, ConstValueSet> ReachableMap;
|
||||
|
||||
/// A CallbackVH to notify PhiValues when a value is deleted or replaced, so
|
||||
/// that the cached information for that value can be cleared to avoid
|
||||
/// dangling pointers to invalid values.
|
||||
class PhiValuesCallbackVH final : public CallbackVH {
|
||||
PhiValues *PV;
|
||||
void deleted() override;
|
||||
void allUsesReplacedWith(Value *New) override;
|
||||
|
||||
public:
|
||||
PhiValuesCallbackVH(Value *V, PhiValues *PV = nullptr)
|
||||
: CallbackVH(V), PV(PV) {}
|
||||
};
|
||||
|
||||
/// A set of callbacks to the values that processPhi has seen.
|
||||
DenseSet<PhiValuesCallbackVH, DenseMapInfo<Value *>> TrackedValues;
|
||||
|
||||
/// The function that the PhiValues is for.
|
||||
const Function &F;
|
||||
|
||||
|
|
|
|||
|
|
@ -98,14 +98,14 @@ public:
|
|||
bool isFunctionEntryCold(const Function *F);
|
||||
/// Returns true if \p F contains only cold code.
|
||||
bool isFunctionColdInCallGraph(const Function *F, BlockFrequencyInfo &BFI);
|
||||
/// Returns true if \p F is a hot function.
|
||||
/// Returns true if count \p C is considered hot.
|
||||
bool isHotCount(uint64_t C);
|
||||
/// Returns true if count \p C is considered cold.
|
||||
bool isColdCount(uint64_t C);
|
||||
/// Returns true if BasicBlock \p B is considered hot.
|
||||
bool isHotBB(const BasicBlock *B, BlockFrequencyInfo *BFI);
|
||||
/// Returns true if BasicBlock \p B is considered cold.
|
||||
bool isColdBB(const BasicBlock *B, BlockFrequencyInfo *BFI);
|
||||
/// Returns true if BasicBlock \p BB is considered hot.
|
||||
bool isHotBlock(const BasicBlock *BB, BlockFrequencyInfo *BFI);
|
||||
/// Returns true if BasicBlock \p BB is considered cold.
|
||||
bool isColdBlock(const BasicBlock *BB, BlockFrequencyInfo *BFI);
|
||||
/// Returns true if CallSite \p CS is considered hot.
|
||||
bool isHotCallSite(const CallSite &CS, BlockFrequencyInfo *BFI);
|
||||
/// Returns true if Callsite \p CS is considered cold.
|
||||
|
|
@ -134,9 +134,8 @@ public:
|
|||
static char ID;
|
||||
ProfileSummaryInfoWrapperPass();
|
||||
|
||||
ProfileSummaryInfo *getPSI() {
|
||||
return &*PSI;
|
||||
}
|
||||
ProfileSummaryInfo &getPSI() { return *PSI; }
|
||||
const ProfileSummaryInfo &getPSI() const { return *PSI; }
|
||||
|
||||
bool doInitialization(Module &M) override;
|
||||
bool doFinalization(Module &M) override;
|
||||
|
|
|
|||
|
|
@ -1833,6 +1833,10 @@ private:
|
|||
const SCEV *getOrCreateMulExpr(SmallVectorImpl<const SCEV *> &Ops,
|
||||
SCEV::NoWrapFlags Flags);
|
||||
|
||||
// Get addrec expr already created or create a new one.
|
||||
const SCEV *getOrCreateAddRecExpr(SmallVectorImpl<const SCEV *> &Ops,
|
||||
const Loop *L, SCEV::NoWrapFlags Flags);
|
||||
|
||||
/// Return x if \p Val is f(x) where f is a 1-1 function.
|
||||
const SCEV *stripInjectiveFunctions(const SCEV *Val) const;
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
#define LLVM_ANALYSIS_SCOPEDNOALIASAA_H
|
||||
|
||||
#include "llvm/Analysis/AliasAnalysis.h"
|
||||
#include "llvm/IR/CallSite.h"
|
||||
#include "llvm/IR/InstrTypes.h"
|
||||
#include "llvm/IR/PassManager.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include <memory>
|
||||
|
|
@ -41,8 +41,8 @@ public:
|
|||
}
|
||||
|
||||
AliasResult alias(const MemoryLocation &LocA, const MemoryLocation &LocB);
|
||||
ModRefInfo getModRefInfo(ImmutableCallSite CS, const MemoryLocation &Loc);
|
||||
ModRefInfo getModRefInfo(ImmutableCallSite CS1, ImmutableCallSite CS2);
|
||||
ModRefInfo getModRefInfo(const CallBase *Call, const MemoryLocation &Loc);
|
||||
ModRefInfo getModRefInfo(const CallBase *Call1, const CallBase *Call2);
|
||||
|
||||
private:
|
||||
bool mayAliasInScopes(const MDNode *Scopes, const MDNode *NoAlias) const;
|
||||
|
|
|
|||
|
|
@ -189,12 +189,12 @@ private:
|
|||
|
||||
/// getFeasibleSuccessors - Return a vector of booleans to indicate which
|
||||
/// successors are reachable from a given terminator instruction.
|
||||
void getFeasibleSuccessors(TerminatorInst &TI, SmallVectorImpl<bool> &Succs,
|
||||
void getFeasibleSuccessors(Instruction &TI, SmallVectorImpl<bool> &Succs,
|
||||
bool AggressiveUndef);
|
||||
|
||||
void visitInst(Instruction &I);
|
||||
void visitPHINode(PHINode &I);
|
||||
void visitTerminatorInst(TerminatorInst &TI);
|
||||
void visitTerminator(Instruction &TI);
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
@ -286,7 +286,7 @@ void SparseSolver<LatticeKey, LatticeVal, KeyInfo>::markEdgeExecutable(
|
|||
|
||||
template <class LatticeKey, class LatticeVal, class KeyInfo>
|
||||
void SparseSolver<LatticeKey, LatticeVal, KeyInfo>::getFeasibleSuccessors(
|
||||
TerminatorInst &TI, SmallVectorImpl<bool> &Succs, bool AggressiveUndef) {
|
||||
Instruction &TI, SmallVectorImpl<bool> &Succs, bool AggressiveUndef) {
|
||||
Succs.resize(TI.getNumSuccessors());
|
||||
if (TI.getNumSuccessors() == 0)
|
||||
return;
|
||||
|
|
@ -330,7 +330,7 @@ void SparseSolver<LatticeKey, LatticeVal, KeyInfo>::getFeasibleSuccessors(
|
|||
return;
|
||||
}
|
||||
|
||||
if (TI.isExceptional()) {
|
||||
if (TI.isExceptionalTerminator()) {
|
||||
Succs.assign(Succs.size(), true);
|
||||
return;
|
||||
}
|
||||
|
|
@ -374,7 +374,7 @@ template <class LatticeKey, class LatticeVal, class KeyInfo>
|
|||
bool SparseSolver<LatticeKey, LatticeVal, KeyInfo>::isEdgeFeasible(
|
||||
BasicBlock *From, BasicBlock *To, bool AggressiveUndef) {
|
||||
SmallVector<bool, 16> SuccFeasible;
|
||||
TerminatorInst *TI = From->getTerminator();
|
||||
Instruction *TI = From->getTerminator();
|
||||
getFeasibleSuccessors(*TI, SuccFeasible, AggressiveUndef);
|
||||
|
||||
for (unsigned i = 0, e = TI->getNumSuccessors(); i != e; ++i)
|
||||
|
|
@ -385,8 +385,8 @@ bool SparseSolver<LatticeKey, LatticeVal, KeyInfo>::isEdgeFeasible(
|
|||
}
|
||||
|
||||
template <class LatticeKey, class LatticeVal, class KeyInfo>
|
||||
void SparseSolver<LatticeKey, LatticeVal, KeyInfo>::visitTerminatorInst(
|
||||
TerminatorInst &TI) {
|
||||
void SparseSolver<LatticeKey, LatticeVal, KeyInfo>::visitTerminator(
|
||||
Instruction &TI) {
|
||||
SmallVector<bool, 16> SuccFeasible;
|
||||
getFeasibleSuccessors(TI, SuccFeasible, true);
|
||||
|
||||
|
|
@ -465,8 +465,8 @@ void SparseSolver<LatticeKey, LatticeVal, KeyInfo>::visitInst(Instruction &I) {
|
|||
if (ChangedValue.second != LatticeFunc->getUntrackedVal())
|
||||
UpdateState(ChangedValue.first, ChangedValue.second);
|
||||
|
||||
if (TerminatorInst *TI = dyn_cast<TerminatorInst>(&I))
|
||||
visitTerminatorInst(*TI);
|
||||
if (I.isTerminator())
|
||||
visitTerminator(I);
|
||||
}
|
||||
|
||||
template <class LatticeKey, class LatticeVal, class KeyInfo>
|
||||
|
|
|
|||
120
contrib/llvm/include/llvm/Analysis/StackSafetyAnalysis.h
Normal file
120
contrib/llvm/include/llvm/Analysis/StackSafetyAnalysis.h
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
//===- StackSafetyAnalysis.h - Stack memory safety analysis -----*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Stack Safety Analysis detects allocas and arguments with safe access.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ANALYSIS_STACKSAFETYANALYSIS_H
|
||||
#define LLVM_ANALYSIS_STACKSAFETYANALYSIS_H
|
||||
|
||||
#include "llvm/IR/PassManager.h"
|
||||
#include "llvm/Pass.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
/// Interface to access stack safety analysis results for single function.
|
||||
class StackSafetyInfo {
|
||||
public:
|
||||
struct FunctionInfo;
|
||||
|
||||
private:
|
||||
std::unique_ptr<FunctionInfo> Info;
|
||||
|
||||
public:
|
||||
StackSafetyInfo();
|
||||
StackSafetyInfo(FunctionInfo &&Info);
|
||||
StackSafetyInfo(StackSafetyInfo &&);
|
||||
StackSafetyInfo &operator=(StackSafetyInfo &&);
|
||||
~StackSafetyInfo();
|
||||
|
||||
// TODO: Add useful for client methods.
|
||||
void print(raw_ostream &O) const;
|
||||
};
|
||||
|
||||
/// StackSafetyInfo wrapper for the new pass manager.
|
||||
class StackSafetyAnalysis : public AnalysisInfoMixin<StackSafetyAnalysis> {
|
||||
friend AnalysisInfoMixin<StackSafetyAnalysis>;
|
||||
static AnalysisKey Key;
|
||||
|
||||
public:
|
||||
using Result = StackSafetyInfo;
|
||||
StackSafetyInfo run(Function &F, FunctionAnalysisManager &AM);
|
||||
};
|
||||
|
||||
/// Printer pass for the \c StackSafetyAnalysis results.
|
||||
class StackSafetyPrinterPass : public PassInfoMixin<StackSafetyPrinterPass> {
|
||||
raw_ostream &OS;
|
||||
|
||||
public:
|
||||
explicit StackSafetyPrinterPass(raw_ostream &OS) : OS(OS) {}
|
||||
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
|
||||
};
|
||||
|
||||
/// StackSafetyInfo wrapper for the legacy pass manager
|
||||
class StackSafetyInfoWrapperPass : public FunctionPass {
|
||||
StackSafetyInfo SSI;
|
||||
|
||||
public:
|
||||
static char ID;
|
||||
StackSafetyInfoWrapperPass();
|
||||
|
||||
const StackSafetyInfo &getResult() const { return SSI; }
|
||||
|
||||
void print(raw_ostream &O, const Module *M) const override;
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override;
|
||||
|
||||
bool runOnFunction(Function &F) override;
|
||||
};
|
||||
|
||||
using StackSafetyGlobalInfo = std::map<const GlobalValue *, StackSafetyInfo>;
|
||||
|
||||
/// This pass performs the global (interprocedural) stack safety analysis (new
|
||||
/// pass manager).
|
||||
class StackSafetyGlobalAnalysis
|
||||
: public AnalysisInfoMixin<StackSafetyGlobalAnalysis> {
|
||||
friend AnalysisInfoMixin<StackSafetyGlobalAnalysis>;
|
||||
static AnalysisKey Key;
|
||||
|
||||
public:
|
||||
using Result = StackSafetyGlobalInfo;
|
||||
Result run(Module &M, ModuleAnalysisManager &AM);
|
||||
};
|
||||
|
||||
/// Printer pass for the \c StackSafetyGlobalAnalysis results.
|
||||
class StackSafetyGlobalPrinterPass
|
||||
: public PassInfoMixin<StackSafetyGlobalPrinterPass> {
|
||||
raw_ostream &OS;
|
||||
|
||||
public:
|
||||
explicit StackSafetyGlobalPrinterPass(raw_ostream &OS) : OS(OS) {}
|
||||
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM);
|
||||
};
|
||||
|
||||
/// This pass performs the global (interprocedural) stack safety analysis
|
||||
/// (legacy pass manager).
|
||||
class StackSafetyGlobalInfoWrapperPass : public ModulePass {
|
||||
StackSafetyGlobalInfo SSI;
|
||||
|
||||
public:
|
||||
static char ID;
|
||||
|
||||
StackSafetyGlobalInfoWrapperPass();
|
||||
|
||||
const StackSafetyGlobalInfo &getResult() const { return SSI; }
|
||||
|
||||
void print(raw_ostream &O, const Module *M) const override;
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override;
|
||||
|
||||
bool runOnModule(Module &M) override;
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_ANALYSIS_STACKSAFETYANALYSIS_H
|
||||
86
contrib/llvm/include/llvm/Analysis/SyncDependenceAnalysis.h
Normal file
86
contrib/llvm/include/llvm/Analysis/SyncDependenceAnalysis.h
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
//===- SyncDependenceAnalysis.h - Divergent Branch Dependence -*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// \file
|
||||
// This file defines the SyncDependenceAnalysis class, which computes for
|
||||
// every divergent branch the set of phi nodes that the branch will make
|
||||
// divergent.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ANALYSIS_SYNC_DEPENDENCE_ANALYSIS_H
|
||||
#define LLVM_ANALYSIS_SYNC_DEPENDENCE_ANALYSIS_H
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/PostOrderIterator.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/Analysis/LoopInfo.h"
|
||||
#include <memory>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class BasicBlock;
|
||||
class DominatorTree;
|
||||
class Loop;
|
||||
class PostDominatorTree;
|
||||
|
||||
using ConstBlockSet = SmallPtrSet<const BasicBlock *, 4>;
|
||||
|
||||
/// \brief Relates points of divergent control to join points in
|
||||
/// reducible CFGs.
|
||||
///
|
||||
/// This analysis relates points of divergent control to points of converging
|
||||
/// divergent control. The analysis requires all loops to be reducible.
|
||||
class SyncDependenceAnalysis {
|
||||
void visitSuccessor(const BasicBlock &succBlock, const Loop *termLoop,
|
||||
const BasicBlock *defBlock);
|
||||
|
||||
public:
|
||||
bool inRegion(const BasicBlock &BB) const;
|
||||
|
||||
~SyncDependenceAnalysis();
|
||||
SyncDependenceAnalysis(const DominatorTree &DT, const PostDominatorTree &PDT,
|
||||
const LoopInfo &LI);
|
||||
|
||||
/// \brief Computes divergent join points and loop exits caused by branch
|
||||
/// divergence in \p Term.
|
||||
///
|
||||
/// The set of blocks which are reachable by disjoint paths from \p Term.
|
||||
/// The set also contains loop exits if there two disjoint paths:
|
||||
/// one from \p Term to the loop exit and another from \p Term to the loop
|
||||
/// header. Those exit blocks are added to the returned set.
|
||||
/// If L is the parent loop of \p Term and an exit of L is in the returned
|
||||
/// set then L is a divergent loop.
|
||||
const ConstBlockSet &join_blocks(const Instruction &Term);
|
||||
|
||||
/// \brief Computes divergent join points and loop exits (in the surrounding
|
||||
/// loop) caused by the divergent loop exits of\p Loop.
|
||||
///
|
||||
/// The set of blocks which are reachable by disjoint paths from the
|
||||
/// loop exits of \p Loop.
|
||||
/// This treats the loop as a single node in \p Loop's parent loop.
|
||||
/// The returned set has the same properties as for join_blocks(TermInst&).
|
||||
const ConstBlockSet &join_blocks(const Loop &Loop);
|
||||
|
||||
private:
|
||||
static ConstBlockSet EmptyBlockSet;
|
||||
|
||||
ReversePostOrderTraversal<const Function *> FuncRPOT;
|
||||
const DominatorTree &DT;
|
||||
const PostDominatorTree &PDT;
|
||||
const LoopInfo &LI;
|
||||
|
||||
std::map<const Loop *, std::unique_ptr<ConstBlockSet>> CachedLoopExitJoins;
|
||||
std::map<const Instruction *, std::unique_ptr<ConstBlockSet>>
|
||||
CachedBranchJoins;
|
||||
};
|
||||
|
||||
} // namespace llvm
|
||||
|
||||
#endif // LLVM_ANALYSIS_SYNC_DEPENDENCE_ANALYSIS_H
|
||||
|
|
@ -36,16 +36,17 @@ public:
|
|||
using EdgeRef = typename CGT::EdgeRef;
|
||||
using SccTy = std::vector<NodeRef>;
|
||||
|
||||
using GetRelBBFreqTy = function_ref<Optional<Scaled64>(EdgeRef)>;
|
||||
using GetCountTy = function_ref<uint64_t(NodeRef)>;
|
||||
using AddCountTy = function_ref<void(NodeRef, uint64_t)>;
|
||||
// Not all EdgeRef have information about the source of the edge. Hence
|
||||
// NodeRef corresponding to the source of the EdgeRef is explicitly passed.
|
||||
using GetProfCountTy = function_ref<Optional<Scaled64>(NodeRef, EdgeRef)>;
|
||||
using AddCountTy = function_ref<void(NodeRef, Scaled64)>;
|
||||
|
||||
static void propagate(const CallGraphType &CG, GetRelBBFreqTy GetRelBBFreq,
|
||||
GetCountTy GetCount, AddCountTy AddCount);
|
||||
static void propagate(const CallGraphType &CG, GetProfCountTy GetProfCount,
|
||||
AddCountTy AddCount);
|
||||
|
||||
private:
|
||||
static void propagateFromSCC(const SccTy &SCC, GetRelBBFreqTy GetRelBBFreq,
|
||||
GetCountTy GetCount, AddCountTy AddCount);
|
||||
static void propagateFromSCC(const SccTy &SCC, GetProfCountTy GetProfCount,
|
||||
AddCountTy AddCount);
|
||||
};
|
||||
} // namespace llvm
|
||||
|
||||
|
|
|
|||
|
|
@ -565,6 +565,30 @@ TLI_DEFINE_STRING_INTERNAL("cosl")
|
|||
/// char *ctermid(char *s);
|
||||
TLI_DEFINE_ENUM_INTERNAL(ctermid)
|
||||
TLI_DEFINE_STRING_INTERNAL("ctermid")
|
||||
/// int execl(const char *path, const char *arg, ...);
|
||||
TLI_DEFINE_ENUM_INTERNAL(execl)
|
||||
TLI_DEFINE_STRING_INTERNAL("execl")
|
||||
/// int execle(const char *file, const char *arg, ..., char * const envp[]);
|
||||
TLI_DEFINE_ENUM_INTERNAL(execle)
|
||||
TLI_DEFINE_STRING_INTERNAL("execle")
|
||||
/// int execlp(const char *file, const char *arg, ...);
|
||||
TLI_DEFINE_ENUM_INTERNAL(execlp)
|
||||
TLI_DEFINE_STRING_INTERNAL("execlp")
|
||||
/// int execv(const char *path, char *const argv[]);
|
||||
TLI_DEFINE_ENUM_INTERNAL(execv)
|
||||
TLI_DEFINE_STRING_INTERNAL("execv")
|
||||
/// int execvP(const char *file, const char *search_path, char *const argv[]);
|
||||
TLI_DEFINE_ENUM_INTERNAL(execvP)
|
||||
TLI_DEFINE_STRING_INTERNAL("execvP")
|
||||
/// int execve(const char *filename, char *const argv[], char *const envp[]);
|
||||
TLI_DEFINE_ENUM_INTERNAL(execve)
|
||||
TLI_DEFINE_STRING_INTERNAL("execve")
|
||||
/// int execvp(const char *file, char *const argv[]);
|
||||
TLI_DEFINE_ENUM_INTERNAL(execvp)
|
||||
TLI_DEFINE_STRING_INTERNAL("execvp")
|
||||
/// int execvpe(const char *file, char *const argv[], char *const envp[]);
|
||||
TLI_DEFINE_ENUM_INTERNAL(execvpe)
|
||||
TLI_DEFINE_STRING_INTERNAL("execvpe")
|
||||
/// double exp(double x);
|
||||
TLI_DEFINE_ENUM_INTERNAL(exp)
|
||||
TLI_DEFINE_STRING_INTERNAL("exp")
|
||||
|
|
@ -709,6 +733,9 @@ TLI_DEFINE_STRING_INTERNAL("fopen")
|
|||
/// FILE *fopen64(const char *filename, const char *opentype)
|
||||
TLI_DEFINE_ENUM_INTERNAL(fopen64)
|
||||
TLI_DEFINE_STRING_INTERNAL("fopen64")
|
||||
/// int fork();
|
||||
TLI_DEFINE_ENUM_INTERNAL(fork)
|
||||
TLI_DEFINE_STRING_INTERNAL("fork")
|
||||
/// int fprintf(FILE *stream, const char *format, ...);
|
||||
TLI_DEFINE_ENUM_INTERNAL(fprintf)
|
||||
TLI_DEFINE_STRING_INTERNAL("fprintf")
|
||||
|
|
|
|||
|
|
@ -289,7 +289,7 @@ public:
|
|||
/// Returns whether V is a source of divergence.
|
||||
///
|
||||
/// This function provides the target-dependent information for
|
||||
/// the target-independent DivergenceAnalysis. DivergenceAnalysis first
|
||||
/// the target-independent LegacyDivergenceAnalysis. LegacyDivergenceAnalysis first
|
||||
/// builds the dependency graph, and then runs the reachability algorithm
|
||||
/// starting with the sources of divergence.
|
||||
bool isSourceOfDivergence(const Value *V) const;
|
||||
|
|
@ -581,12 +581,21 @@ public:
|
|||
struct MemCmpExpansionOptions {
|
||||
// The list of available load sizes (in bytes), sorted in decreasing order.
|
||||
SmallVector<unsigned, 8> LoadSizes;
|
||||
// Set to true to allow overlapping loads. For example, 7-byte compares can
|
||||
// be done with two 4-byte compares instead of 4+2+1-byte compares. This
|
||||
// requires all loads in LoadSizes to be doable in an unaligned way.
|
||||
bool AllowOverlappingLoads = false;
|
||||
};
|
||||
const MemCmpExpansionOptions *enableMemCmpExpansion(bool IsZeroCmp) const;
|
||||
|
||||
/// Enable matching of interleaved access groups.
|
||||
bool enableInterleavedAccessVectorization() const;
|
||||
|
||||
/// Enable matching of interleaved access groups that contain predicated
|
||||
/// accesses or gaps and therefore vectorized using masked
|
||||
/// vector loads/stores.
|
||||
bool enableMaskedInterleavedAccessVectorization() const;
|
||||
|
||||
/// Indicate that it is potentially unsafe to automatically vectorize
|
||||
/// floating-point operations because the semantics of vector and scalar
|
||||
/// floating-point semantics may differ. For example, ARM NEON v7 SIMD math
|
||||
|
|
@ -739,6 +748,10 @@ public:
|
|||
/// and the number of execution units in the CPU.
|
||||
unsigned getMaxInterleaveFactor(unsigned VF) const;
|
||||
|
||||
/// Collect properties of V used in cost analysis, e.g. OP_PowerOf2.
|
||||
static OperandValueKind getOperandInfo(Value *V,
|
||||
OperandValueProperties &OpProps);
|
||||
|
||||
/// This is an approximation of reciprocal throughput of a math/logic op.
|
||||
/// A higher cost indicates less expected throughput.
|
||||
/// From Agner Fog's guides, reciprocal throughput is "the average number of
|
||||
|
|
@ -762,7 +775,9 @@ public:
|
|||
|
||||
/// \return The cost of a shuffle instruction of kind Kind and of type Tp.
|
||||
/// The index and subtype parameters are used by the subvector insertion and
|
||||
/// extraction shuffle kinds.
|
||||
/// extraction shuffle kinds to show the insert/extract point and the type of
|
||||
/// the subvector being inserted/extracted.
|
||||
/// NOTE: For subvector extractions Tp represents the source type.
|
||||
int getShuffleCost(ShuffleKind Kind, Type *Tp, int Index = 0,
|
||||
Type *SubTp = nullptr) const;
|
||||
|
||||
|
|
@ -817,9 +832,13 @@ public:
|
|||
/// load allows gaps)
|
||||
/// \p Alignment is the alignment of the memory operation
|
||||
/// \p AddressSpace is address space of the pointer.
|
||||
/// \p UseMaskForCond indicates if the memory access is predicated.
|
||||
/// \p UseMaskForGaps indicates if gaps should be masked.
|
||||
int getInterleavedMemoryOpCost(unsigned Opcode, Type *VecTy, unsigned Factor,
|
||||
ArrayRef<unsigned> Indices, unsigned Alignment,
|
||||
unsigned AddressSpace) const;
|
||||
unsigned AddressSpace,
|
||||
bool UseMaskForCond = false,
|
||||
bool UseMaskForGaps = false) const;
|
||||
|
||||
/// Calculate the cost of performing a vector reduction.
|
||||
///
|
||||
|
|
@ -915,6 +934,14 @@ public:
|
|||
bool areInlineCompatible(const Function *Caller,
|
||||
const Function *Callee) const;
|
||||
|
||||
/// \returns True if the caller and callee agree on how \p Args will be passed
|
||||
/// to the callee.
|
||||
/// \param[out] Args The list of compatible arguments. The implementation may
|
||||
/// filter out any incompatible args from this list.
|
||||
bool areFunctionArgsABICompatible(const Function *Caller,
|
||||
const Function *Callee,
|
||||
SmallPtrSetImpl<Argument *> &Args) const;
|
||||
|
||||
/// The type of load/store indexing.
|
||||
enum MemIndexedMode {
|
||||
MIM_Unindexed, ///< No indexing.
|
||||
|
|
@ -1068,6 +1095,7 @@ public:
|
|||
virtual const MemCmpExpansionOptions *enableMemCmpExpansion(
|
||||
bool IsZeroCmp) const = 0;
|
||||
virtual bool enableInterleavedAccessVectorization() = 0;
|
||||
virtual bool enableMaskedInterleavedAccessVectorization() = 0;
|
||||
virtual bool isFPVectorizationPotentiallyUnsafe() = 0;
|
||||
virtual bool allowsMisalignedMemoryAccesses(LLVMContext &Context,
|
||||
unsigned BitWidth,
|
||||
|
|
@ -1128,7 +1156,9 @@ public:
|
|||
unsigned Factor,
|
||||
ArrayRef<unsigned> Indices,
|
||||
unsigned Alignment,
|
||||
unsigned AddressSpace) = 0;
|
||||
unsigned AddressSpace,
|
||||
bool UseMaskForCond = false,
|
||||
bool UseMaskForGaps = false) = 0;
|
||||
virtual int getArithmeticReductionCost(unsigned Opcode, Type *Ty,
|
||||
bool IsPairwiseForm) = 0;
|
||||
virtual int getMinMaxReductionCost(Type *Ty, Type *CondTy,
|
||||
|
|
@ -1157,6 +1187,9 @@ public:
|
|||
unsigned RemainingBytes, unsigned SrcAlign, unsigned DestAlign) const = 0;
|
||||
virtual bool areInlineCompatible(const Function *Caller,
|
||||
const Function *Callee) const = 0;
|
||||
virtual bool
|
||||
areFunctionArgsABICompatible(const Function *Caller, const Function *Callee,
|
||||
SmallPtrSetImpl<Argument *> &Args) const = 0;
|
||||
virtual bool isIndexedLoadLegal(MemIndexedMode Mode, Type *Ty) const = 0;
|
||||
virtual bool isIndexedStoreLegal(MemIndexedMode Mode,Type *Ty) const = 0;
|
||||
virtual unsigned getLoadStoreVecRegBitWidth(unsigned AddrSpace) const = 0;
|
||||
|
|
@ -1342,6 +1375,9 @@ public:
|
|||
bool enableInterleavedAccessVectorization() override {
|
||||
return Impl.enableInterleavedAccessVectorization();
|
||||
}
|
||||
bool enableMaskedInterleavedAccessVectorization() override {
|
||||
return Impl.enableMaskedInterleavedAccessVectorization();
|
||||
}
|
||||
bool isFPVectorizationPotentiallyUnsafe() override {
|
||||
return Impl.isFPVectorizationPotentiallyUnsafe();
|
||||
}
|
||||
|
|
@ -1467,9 +1503,11 @@ public:
|
|||
}
|
||||
int getInterleavedMemoryOpCost(unsigned Opcode, Type *VecTy, unsigned Factor,
|
||||
ArrayRef<unsigned> Indices, unsigned Alignment,
|
||||
unsigned AddressSpace) override {
|
||||
unsigned AddressSpace, bool UseMaskForCond,
|
||||
bool UseMaskForGaps) override {
|
||||
return Impl.getInterleavedMemoryOpCost(Opcode, VecTy, Factor, Indices,
|
||||
Alignment, AddressSpace);
|
||||
Alignment, AddressSpace,
|
||||
UseMaskForCond, UseMaskForGaps);
|
||||
}
|
||||
int getArithmeticReductionCost(unsigned Opcode, Type *Ty,
|
||||
bool IsPairwiseForm) override {
|
||||
|
|
@ -1530,6 +1568,11 @@ public:
|
|||
const Function *Callee) const override {
|
||||
return Impl.areInlineCompatible(Caller, Callee);
|
||||
}
|
||||
bool areFunctionArgsABICompatible(
|
||||
const Function *Caller, const Function *Callee,
|
||||
SmallPtrSetImpl<Argument *> &Args) const override {
|
||||
return Impl.areFunctionArgsABICompatible(Caller, Callee, Args);
|
||||
}
|
||||
bool isIndexedLoadLegal(MemIndexedMode Mode, Type *Ty) const override {
|
||||
return Impl.isIndexedLoadLegal(Mode, Ty, getDataLayout());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -158,6 +158,9 @@ public:
|
|||
case Intrinsic::dbg_label:
|
||||
case Intrinsic::invariant_start:
|
||||
case Intrinsic::invariant_end:
|
||||
case Intrinsic::launder_invariant_group:
|
||||
case Intrinsic::strip_invariant_group:
|
||||
case Intrinsic::is_constant:
|
||||
case Intrinsic::lifetime_start:
|
||||
case Intrinsic::lifetime_end:
|
||||
case Intrinsic::objectsize:
|
||||
|
|
@ -311,6 +314,8 @@ public:
|
|||
|
||||
bool enableInterleavedAccessVectorization() { return false; }
|
||||
|
||||
bool enableMaskedInterleavedAccessVectorization() { return false; }
|
||||
|
||||
bool isFPVectorizationPotentiallyUnsafe() { return false; }
|
||||
|
||||
bool allowsMisalignedMemoryAccesses(LLVMContext &Context,
|
||||
|
|
@ -448,8 +453,9 @@ public:
|
|||
unsigned getInterleavedMemoryOpCost(unsigned Opcode, Type *VecTy,
|
||||
unsigned Factor,
|
||||
ArrayRef<unsigned> Indices,
|
||||
unsigned Alignment,
|
||||
unsigned AddressSpace) {
|
||||
unsigned Alignment, unsigned AddressSpace,
|
||||
bool UseMaskForCond = false,
|
||||
bool UseMaskForGaps = false) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
@ -520,6 +526,14 @@ public:
|
|||
Callee->getFnAttribute("target-features"));
|
||||
}
|
||||
|
||||
bool areFunctionArgsABICompatible(const Function *Caller, const Function *Callee,
|
||||
SmallPtrSetImpl<Argument *> &Args) const {
|
||||
return (Caller->getFnAttribute("target-cpu") ==
|
||||
Callee->getFnAttribute("target-cpu")) &&
|
||||
(Caller->getFnAttribute("target-features") ==
|
||||
Callee->getFnAttribute("target-features"));
|
||||
}
|
||||
|
||||
bool isIndexedLoadLegal(TTI::MemIndexedMode Mode, Type *Ty,
|
||||
const DataLayout &DL) const {
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
#define LLVM_ANALYSIS_TYPEBASEDALIASANALYSIS_H
|
||||
|
||||
#include "llvm/Analysis/AliasAnalysis.h"
|
||||
#include "llvm/IR/CallSite.h"
|
||||
#include "llvm/IR/InstrTypes.h"
|
||||
#include "llvm/IR/PassManager.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include <memory>
|
||||
|
|
@ -43,10 +43,10 @@ public:
|
|||
|
||||
AliasResult alias(const MemoryLocation &LocA, const MemoryLocation &LocB);
|
||||
bool pointsToConstantMemory(const MemoryLocation &Loc, bool OrLocal);
|
||||
FunctionModRefBehavior getModRefBehavior(ImmutableCallSite CS);
|
||||
FunctionModRefBehavior getModRefBehavior(const CallBase *Call);
|
||||
FunctionModRefBehavior getModRefBehavior(const Function *F);
|
||||
ModRefInfo getModRefInfo(ImmutableCallSite CS, const MemoryLocation &Loc);
|
||||
ModRefInfo getModRefInfo(ImmutableCallSite CS1, ImmutableCallSite CS2);
|
||||
ModRefInfo getModRefInfo(const CallBase *Call, const MemoryLocation &Loc);
|
||||
ModRefInfo getModRefInfo(const CallBase *Call1, const CallBase *Call2);
|
||||
|
||||
private:
|
||||
bool Aliases(const MDNode *A, const MDNode *B) const;
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@
|
|||
|
||||
namespace llvm {
|
||||
|
||||
class DominatorTree;
|
||||
|
||||
/// The type of CFI jumptable needed for a function.
|
||||
enum CfiFunctionLinkage {
|
||||
CFL_Definition = 0,
|
||||
|
|
@ -39,7 +41,8 @@ struct DevirtCallSite {
|
|||
/// call sites based on the call and return them in DevirtCalls.
|
||||
void findDevirtualizableCallsForTypeTest(
|
||||
SmallVectorImpl<DevirtCallSite> &DevirtCalls,
|
||||
SmallVectorImpl<CallInst *> &Assumes, const CallInst *CI);
|
||||
SmallVectorImpl<CallInst *> &Assumes, const CallInst *CI,
|
||||
DominatorTree &DT);
|
||||
|
||||
/// Given a call to the intrinsic \@llvm.type.checked.load, find all
|
||||
/// devirtualizable call sites based on the call and return them in DevirtCalls.
|
||||
|
|
@ -47,7 +50,7 @@ void findDevirtualizableCallsForTypeCheckedLoad(
|
|||
SmallVectorImpl<DevirtCallSite> &DevirtCalls,
|
||||
SmallVectorImpl<Instruction *> &LoadedPtrs,
|
||||
SmallVectorImpl<Instruction *> &Preds, bool &HasNonCallUses,
|
||||
const CallInst *CI);
|
||||
const CallInst *CI, DominatorTree &DT);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -55,14 +55,16 @@ class Value;
|
|||
AssumptionCache *AC = nullptr,
|
||||
const Instruction *CxtI = nullptr,
|
||||
const DominatorTree *DT = nullptr,
|
||||
OptimizationRemarkEmitter *ORE = nullptr);
|
||||
OptimizationRemarkEmitter *ORE = nullptr,
|
||||
bool UseInstrInfo = true);
|
||||
|
||||
/// Returns the known bits rather than passing by reference.
|
||||
KnownBits computeKnownBits(const Value *V, const DataLayout &DL,
|
||||
unsigned Depth = 0, AssumptionCache *AC = nullptr,
|
||||
const Instruction *CxtI = nullptr,
|
||||
const DominatorTree *DT = nullptr,
|
||||
OptimizationRemarkEmitter *ORE = nullptr);
|
||||
OptimizationRemarkEmitter *ORE = nullptr,
|
||||
bool UseInstrInfo = true);
|
||||
|
||||
/// Compute known bits from the range metadata.
|
||||
/// \p KnownZero the set of bits that are known to be zero
|
||||
|
|
@ -75,7 +77,8 @@ class Value;
|
|||
const DataLayout &DL,
|
||||
AssumptionCache *AC = nullptr,
|
||||
const Instruction *CxtI = nullptr,
|
||||
const DominatorTree *DT = nullptr);
|
||||
const DominatorTree *DT = nullptr,
|
||||
bool UseInstrInfo = true);
|
||||
|
||||
/// Return true if the given value is known to have exactly one bit set when
|
||||
/// defined. For vectors return true if every element is known to be a power
|
||||
|
|
@ -86,7 +89,8 @@ class Value;
|
|||
bool OrZero = false, unsigned Depth = 0,
|
||||
AssumptionCache *AC = nullptr,
|
||||
const Instruction *CxtI = nullptr,
|
||||
const DominatorTree *DT = nullptr);
|
||||
const DominatorTree *DT = nullptr,
|
||||
bool UseInstrInfo = true);
|
||||
|
||||
bool isOnlyUsedInZeroEqualityComparison(const Instruction *CxtI);
|
||||
|
||||
|
|
@ -99,7 +103,8 @@ class Value;
|
|||
bool isKnownNonZero(const Value *V, const DataLayout &DL, unsigned Depth = 0,
|
||||
AssumptionCache *AC = nullptr,
|
||||
const Instruction *CxtI = nullptr,
|
||||
const DominatorTree *DT = nullptr);
|
||||
const DominatorTree *DT = nullptr,
|
||||
bool UseInstrInfo = true);
|
||||
|
||||
/// Return true if the two given values are negation.
|
||||
/// Currently can recoginze Value pair:
|
||||
|
|
@ -112,28 +117,32 @@ class Value;
|
|||
unsigned Depth = 0,
|
||||
AssumptionCache *AC = nullptr,
|
||||
const Instruction *CxtI = nullptr,
|
||||
const DominatorTree *DT = nullptr);
|
||||
const DominatorTree *DT = nullptr,
|
||||
bool UseInstrInfo = true);
|
||||
|
||||
/// Returns true if the given value is known be positive (i.e. non-negative
|
||||
/// and non-zero).
|
||||
bool isKnownPositive(const Value *V, const DataLayout &DL, unsigned Depth = 0,
|
||||
AssumptionCache *AC = nullptr,
|
||||
const Instruction *CxtI = nullptr,
|
||||
const DominatorTree *DT = nullptr);
|
||||
const DominatorTree *DT = nullptr,
|
||||
bool UseInstrInfo = true);
|
||||
|
||||
/// Returns true if the given value is known be negative (i.e. non-positive
|
||||
/// and non-zero).
|
||||
bool isKnownNegative(const Value *V, const DataLayout &DL, unsigned Depth = 0,
|
||||
AssumptionCache *AC = nullptr,
|
||||
const Instruction *CxtI = nullptr,
|
||||
const DominatorTree *DT = nullptr);
|
||||
const DominatorTree *DT = nullptr,
|
||||
bool UseInstrInfo = true);
|
||||
|
||||
/// Return true if the given values are known to be non-equal when defined.
|
||||
/// Supports scalar integer types only.
|
||||
bool isKnownNonEqual(const Value *V1, const Value *V2, const DataLayout &DL,
|
||||
AssumptionCache *AC = nullptr,
|
||||
const Instruction *CxtI = nullptr,
|
||||
const DominatorTree *DT = nullptr);
|
||||
AssumptionCache *AC = nullptr,
|
||||
const Instruction *CxtI = nullptr,
|
||||
const DominatorTree *DT = nullptr,
|
||||
bool UseInstrInfo = true);
|
||||
|
||||
/// Return true if 'V & Mask' is known to be zero. We use this predicate to
|
||||
/// simplify operations downstream. Mask is known to be zero for bits that V
|
||||
|
|
@ -148,7 +157,8 @@ class Value;
|
|||
const DataLayout &DL,
|
||||
unsigned Depth = 0, AssumptionCache *AC = nullptr,
|
||||
const Instruction *CxtI = nullptr,
|
||||
const DominatorTree *DT = nullptr);
|
||||
const DominatorTree *DT = nullptr,
|
||||
bool UseInstrInfo = true);
|
||||
|
||||
/// Return the number of times the sign bit of the register is replicated into
|
||||
/// the other bits. We know that at least 1 bit is always equal to the sign
|
||||
|
|
@ -160,7 +170,8 @@ class Value;
|
|||
unsigned ComputeNumSignBits(const Value *Op, const DataLayout &DL,
|
||||
unsigned Depth = 0, AssumptionCache *AC = nullptr,
|
||||
const Instruction *CxtI = nullptr,
|
||||
const DominatorTree *DT = nullptr);
|
||||
const DominatorTree *DT = nullptr,
|
||||
bool UseInstrInfo = true);
|
||||
|
||||
/// This function computes the integer multiple of Base that equals V. If
|
||||
/// successful, it returns true and returns the multiple in Multiple. If
|
||||
|
|
@ -194,7 +205,8 @@ class Value;
|
|||
/// Return true if the floating-point scalar value is not a NaN or if the
|
||||
/// floating-point vector value has no NaN elements. Return false if a value
|
||||
/// could ever be NaN.
|
||||
bool isKnownNeverNaN(const Value *V);
|
||||
bool isKnownNeverNaN(const Value *V, const TargetLibraryInfo *TLI,
|
||||
unsigned Depth = 0);
|
||||
|
||||
/// Return true if we can prove that the specified FP value's sign bit is 0.
|
||||
///
|
||||
|
|
@ -209,7 +221,8 @@ class Value;
|
|||
/// return the i8 value that it is represented with. This is true for all i8
|
||||
/// values obviously, but is also true for i32 0, i32 -1, i16 0xF0F0, double
|
||||
/// 0.0 etc. If the value can't be handled with a repeated byte store (e.g.
|
||||
/// i16 0x1234), return null.
|
||||
/// i16 0x1234), return null. If the value is entirely undef and padding,
|
||||
/// return undef.
|
||||
Value *isBytewiseValue(Value *V);
|
||||
|
||||
/// Given an aggregrate and an sequence of indices, see if the scalar value
|
||||
|
|
@ -284,10 +297,10 @@ class Value;
|
|||
|
||||
/// This function returns call pointer argument that is considered the same by
|
||||
/// aliasing rules. You CAN'T use it to replace one value with another.
|
||||
const Value *getArgumentAliasingToReturnedPointer(ImmutableCallSite CS);
|
||||
inline Value *getArgumentAliasingToReturnedPointer(CallSite CS) {
|
||||
return const_cast<Value *>(
|
||||
getArgumentAliasingToReturnedPointer(ImmutableCallSite(CS)));
|
||||
const Value *getArgumentAliasingToReturnedPointer(const CallBase *Call);
|
||||
inline Value *getArgumentAliasingToReturnedPointer(CallBase *Call) {
|
||||
return const_cast<Value *>(getArgumentAliasingToReturnedPointer(
|
||||
const_cast<const CallBase *>(Call)));
|
||||
}
|
||||
|
||||
// {launder,strip}.invariant.group returns pointer that aliases its argument,
|
||||
|
|
@ -296,7 +309,7 @@ class Value;
|
|||
// considered as capture. The arguments are not marked as returned neither,
|
||||
// because it would make it useless.
|
||||
bool isIntrinsicReturningPointerAliasingArgumentWithoutCapturing(
|
||||
ImmutableCallSite CS);
|
||||
const CallBase *Call);
|
||||
|
||||
/// This method strips off any GEP address adjustments and pointer casts from
|
||||
/// the specified value, returning the original object being addressed. Note
|
||||
|
|
@ -405,18 +418,21 @@ class Value;
|
|||
const DataLayout &DL,
|
||||
AssumptionCache *AC,
|
||||
const Instruction *CxtI,
|
||||
const DominatorTree *DT);
|
||||
const DominatorTree *DT,
|
||||
bool UseInstrInfo = true);
|
||||
OverflowResult computeOverflowForSignedMul(const Value *LHS, const Value *RHS,
|
||||
const DataLayout &DL,
|
||||
AssumptionCache *AC,
|
||||
const Instruction *CxtI,
|
||||
const DominatorTree *DT);
|
||||
const DominatorTree *DT,
|
||||
bool UseInstrInfo = true);
|
||||
OverflowResult computeOverflowForUnsignedAdd(const Value *LHS,
|
||||
const Value *RHS,
|
||||
const DataLayout &DL,
|
||||
AssumptionCache *AC,
|
||||
const Instruction *CxtI,
|
||||
const DominatorTree *DT);
|
||||
const DominatorTree *DT,
|
||||
bool UseInstrInfo = true);
|
||||
OverflowResult computeOverflowForSignedAdd(const Value *LHS, const Value *RHS,
|
||||
const DataLayout &DL,
|
||||
AssumptionCache *AC = nullptr,
|
||||
|
|
@ -594,6 +610,12 @@ class Value;
|
|||
Optional<bool> isImpliedCondition(const Value *LHS, const Value *RHS,
|
||||
const DataLayout &DL, bool LHSIsTrue = true,
|
||||
unsigned Depth = 0);
|
||||
|
||||
/// Return the boolean condition value in the context of the given instruction
|
||||
/// if it is known based on dominating conditions.
|
||||
Optional<bool> isImpliedByDomCondition(const Value *Cond,
|
||||
const Instruction *ContextI,
|
||||
const DataLayout &DL);
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_ANALYSIS_VALUETRACKING_H
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
#define LLVM_ANALYSIS_VECTORUTILS_H
|
||||
|
||||
#include "llvm/ADT/MapVector.h"
|
||||
#include "llvm/Analysis/LoopAccessAnalysis.h"
|
||||
#include "llvm/Analysis/TargetLibraryInfo.h"
|
||||
#include "llvm/IR/IRBuilder.h"
|
||||
|
||||
|
|
@ -23,6 +24,7 @@ namespace llvm {
|
|||
template <typename T> class ArrayRef;
|
||||
class DemandedBits;
|
||||
class GetElementPtrInst;
|
||||
template <typename InstTy> class InterleaveGroup;
|
||||
class Loop;
|
||||
class ScalarEvolution;
|
||||
class TargetTransformInfo;
|
||||
|
|
@ -115,8 +117,24 @@ computeMinimumValueSizes(ArrayRef<BasicBlock*> Blocks,
|
|||
DemandedBits &DB,
|
||||
const TargetTransformInfo *TTI=nullptr);
|
||||
|
||||
/// Compute the union of two access-group lists.
|
||||
///
|
||||
/// If the list contains just one access group, it is returned directly. If the
|
||||
/// list is empty, returns nullptr.
|
||||
MDNode *uniteAccessGroups(MDNode *AccGroups1, MDNode *AccGroups2);
|
||||
|
||||
/// Compute the access-group list of access groups that @p Inst1 and @p Inst2
|
||||
/// are both in. If either instruction does not access memory at all, it is
|
||||
/// considered to be in every list.
|
||||
///
|
||||
/// If the list contains just one access group, it is returned directly. If the
|
||||
/// list is empty, returns nullptr.
|
||||
MDNode *intersectAccessGroups(const Instruction *Inst1,
|
||||
const Instruction *Inst2);
|
||||
|
||||
/// Specifically, let Kinds = [MD_tbaa, MD_alias_scope, MD_noalias, MD_fpmath,
|
||||
/// MD_nontemporal]. For K in Kinds, we get the MDNode for K from each of the
|
||||
/// MD_nontemporal, MD_access_group].
|
||||
/// For K in Kinds, we get the MDNode for K from each of the
|
||||
/// elements of VL, compute their "intersection" (i.e., the most generic
|
||||
/// metadata value that covers all of the individual values), and set I's
|
||||
/// metadata for M equal to the intersection value.
|
||||
|
|
@ -124,6 +142,35 @@ computeMinimumValueSizes(ArrayRef<BasicBlock*> Blocks,
|
|||
/// This function always sets a (possibly null) value for each K in Kinds.
|
||||
Instruction *propagateMetadata(Instruction *I, ArrayRef<Value *> VL);
|
||||
|
||||
/// Create a mask that filters the members of an interleave group where there
|
||||
/// are gaps.
|
||||
///
|
||||
/// For example, the mask for \p Group with interleave-factor 3
|
||||
/// and \p VF 4, that has only its first member present is:
|
||||
///
|
||||
/// <1,0,0,1,0,0,1,0,0,1,0,0>
|
||||
///
|
||||
/// Note: The result is a mask of 0's and 1's, as opposed to the other
|
||||
/// create[*]Mask() utilities which create a shuffle mask (mask that
|
||||
/// consists of indices).
|
||||
Constant *createBitMaskForGaps(IRBuilder<> &Builder, unsigned VF,
|
||||
const InterleaveGroup<Instruction> &Group);
|
||||
|
||||
/// Create a mask with replicated elements.
|
||||
///
|
||||
/// This function creates a shuffle mask for replicating each of the \p VF
|
||||
/// elements in a vector \p ReplicationFactor times. It can be used to
|
||||
/// transform a mask of \p VF elements into a mask of
|
||||
/// \p VF * \p ReplicationFactor elements used by a predicated
|
||||
/// interleaved-group of loads/stores whose Interleaved-factor ==
|
||||
/// \p ReplicationFactor.
|
||||
///
|
||||
/// For example, the mask for \p ReplicationFactor=3 and \p VF=4 is:
|
||||
///
|
||||
/// <0,0,0,1,1,1,2,2,2,3,3,3>
|
||||
Constant *createReplicatedMask(IRBuilder<> &Builder, unsigned ReplicationFactor,
|
||||
unsigned VF);
|
||||
|
||||
/// Create an interleave shuffle mask.
|
||||
///
|
||||
/// This function creates a shuffle mask for interleaving \p NumVecs vectors of
|
||||
|
|
@ -176,6 +223,381 @@ Constant *createSequentialMask(IRBuilder<> &Builder, unsigned Start,
|
|||
/// elements, it will be padded with undefs.
|
||||
Value *concatenateVectors(IRBuilder<> &Builder, ArrayRef<Value *> Vecs);
|
||||
|
||||
/// The group of interleaved loads/stores sharing the same stride and
|
||||
/// close to each other.
|
||||
///
|
||||
/// Each member in this group has an index starting from 0, and the largest
|
||||
/// index should be less than interleaved factor, which is equal to the absolute
|
||||
/// value of the access's stride.
|
||||
///
|
||||
/// E.g. An interleaved load group of factor 4:
|
||||
/// for (unsigned i = 0; i < 1024; i+=4) {
|
||||
/// a = A[i]; // Member of index 0
|
||||
/// b = A[i+1]; // Member of index 1
|
||||
/// d = A[i+3]; // Member of index 3
|
||||
/// ...
|
||||
/// }
|
||||
///
|
||||
/// An interleaved store group of factor 4:
|
||||
/// for (unsigned i = 0; i < 1024; i+=4) {
|
||||
/// ...
|
||||
/// A[i] = a; // Member of index 0
|
||||
/// A[i+1] = b; // Member of index 1
|
||||
/// A[i+2] = c; // Member of index 2
|
||||
/// A[i+3] = d; // Member of index 3
|
||||
/// }
|
||||
///
|
||||
/// Note: the interleaved load group could have gaps (missing members), but
|
||||
/// the interleaved store group doesn't allow gaps.
|
||||
template <typename InstTy> class InterleaveGroup {
|
||||
public:
|
||||
InterleaveGroup(unsigned Factor, bool Reverse, unsigned Align)
|
||||
: Factor(Factor), Reverse(Reverse), Align(Align), InsertPos(nullptr) {}
|
||||
|
||||
InterleaveGroup(InstTy *Instr, int Stride, unsigned Align)
|
||||
: Align(Align), InsertPos(Instr) {
|
||||
assert(Align && "The alignment should be non-zero");
|
||||
|
||||
Factor = std::abs(Stride);
|
||||
assert(Factor > 1 && "Invalid interleave factor");
|
||||
|
||||
Reverse = Stride < 0;
|
||||
Members[0] = Instr;
|
||||
}
|
||||
|
||||
bool isReverse() const { return Reverse; }
|
||||
unsigned getFactor() const { return Factor; }
|
||||
unsigned getAlignment() const { return Align; }
|
||||
unsigned getNumMembers() const { return Members.size(); }
|
||||
|
||||
/// Try to insert a new member \p Instr with index \p Index and
|
||||
/// alignment \p NewAlign. The index is related to the leader and it could be
|
||||
/// negative if it is the new leader.
|
||||
///
|
||||
/// \returns false if the instruction doesn't belong to the group.
|
||||
bool insertMember(InstTy *Instr, int Index, unsigned NewAlign) {
|
||||
assert(NewAlign && "The new member's alignment should be non-zero");
|
||||
|
||||
int Key = Index + SmallestKey;
|
||||
|
||||
// Skip if there is already a member with the same index.
|
||||
if (Members.find(Key) != Members.end())
|
||||
return false;
|
||||
|
||||
if (Key > LargestKey) {
|
||||
// The largest index is always less than the interleave factor.
|
||||
if (Index >= static_cast<int>(Factor))
|
||||
return false;
|
||||
|
||||
LargestKey = Key;
|
||||
} else if (Key < SmallestKey) {
|
||||
// The largest index is always less than the interleave factor.
|
||||
if (LargestKey - Key >= static_cast<int>(Factor))
|
||||
return false;
|
||||
|
||||
SmallestKey = Key;
|
||||
}
|
||||
|
||||
// It's always safe to select the minimum alignment.
|
||||
Align = std::min(Align, NewAlign);
|
||||
Members[Key] = Instr;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Get the member with the given index \p Index
|
||||
///
|
||||
/// \returns nullptr if contains no such member.
|
||||
InstTy *getMember(unsigned Index) const {
|
||||
int Key = SmallestKey + Index;
|
||||
auto Member = Members.find(Key);
|
||||
if (Member == Members.end())
|
||||
return nullptr;
|
||||
|
||||
return Member->second;
|
||||
}
|
||||
|
||||
/// Get the index for the given member. Unlike the key in the member
|
||||
/// map, the index starts from 0.
|
||||
unsigned getIndex(const InstTy *Instr) const {
|
||||
for (auto I : Members) {
|
||||
if (I.second == Instr)
|
||||
return I.first - SmallestKey;
|
||||
}
|
||||
|
||||
llvm_unreachable("InterleaveGroup contains no such member");
|
||||
}
|
||||
|
||||
InstTy *getInsertPos() const { return InsertPos; }
|
||||
void setInsertPos(InstTy *Inst) { InsertPos = Inst; }
|
||||
|
||||
/// Add metadata (e.g. alias info) from the instructions in this group to \p
|
||||
/// NewInst.
|
||||
///
|
||||
/// FIXME: this function currently does not add noalias metadata a'la
|
||||
/// addNewMedata. To do that we need to compute the intersection of the
|
||||
/// noalias info from all members.
|
||||
void addMetadata(InstTy *NewInst) const;
|
||||
|
||||
/// Returns true if this Group requires a scalar iteration to handle gaps.
|
||||
bool requiresScalarEpilogue() const {
|
||||
// If the last member of the Group exists, then a scalar epilog is not
|
||||
// needed for this group.
|
||||
if (getMember(getFactor() - 1))
|
||||
return false;
|
||||
|
||||
// We have a group with gaps. It therefore cannot be a group of stores,
|
||||
// and it can't be a reversed access, because such groups get invalidated.
|
||||
assert(!getMember(0)->mayWriteToMemory() &&
|
||||
"Group should have been invalidated");
|
||||
assert(!isReverse() && "Group should have been invalidated");
|
||||
|
||||
// This is a group of loads, with gaps, and without a last-member
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned Factor; // Interleave Factor.
|
||||
bool Reverse;
|
||||
unsigned Align;
|
||||
DenseMap<int, InstTy *> Members;
|
||||
int SmallestKey = 0;
|
||||
int LargestKey = 0;
|
||||
|
||||
// To avoid breaking dependences, vectorized instructions of an interleave
|
||||
// group should be inserted at either the first load or the last store in
|
||||
// program order.
|
||||
//
|
||||
// E.g. %even = load i32 // Insert Position
|
||||
// %add = add i32 %even // Use of %even
|
||||
// %odd = load i32
|
||||
//
|
||||
// store i32 %even
|
||||
// %odd = add i32 // Def of %odd
|
||||
// store i32 %odd // Insert Position
|
||||
InstTy *InsertPos;
|
||||
};
|
||||
|
||||
/// Drive the analysis of interleaved memory accesses in the loop.
|
||||
///
|
||||
/// Use this class to analyze interleaved accesses only when we can vectorize
|
||||
/// a loop. Otherwise it's meaningless to do analysis as the vectorization
|
||||
/// on interleaved accesses is unsafe.
|
||||
///
|
||||
/// The analysis collects interleave groups and records the relationships
|
||||
/// between the member and the group in a map.
|
||||
class InterleavedAccessInfo {
|
||||
public:
|
||||
InterleavedAccessInfo(PredicatedScalarEvolution &PSE, Loop *L,
|
||||
DominatorTree *DT, LoopInfo *LI,
|
||||
const LoopAccessInfo *LAI)
|
||||
: PSE(PSE), TheLoop(L), DT(DT), LI(LI), LAI(LAI) {}
|
||||
|
||||
~InterleavedAccessInfo() { reset(); }
|
||||
|
||||
/// Analyze the interleaved accesses and collect them in interleave
|
||||
/// groups. Substitute symbolic strides using \p Strides.
|
||||
/// Consider also predicated loads/stores in the analysis if
|
||||
/// \p EnableMaskedInterleavedGroup is true.
|
||||
void analyzeInterleaving(bool EnableMaskedInterleavedGroup);
|
||||
|
||||
/// Invalidate groups, e.g., in case all blocks in loop will be predicated
|
||||
/// contrary to original assumption. Although we currently prevent group
|
||||
/// formation for predicated accesses, we may be able to relax this limitation
|
||||
/// in the future once we handle more complicated blocks.
|
||||
void reset() {
|
||||
SmallPtrSet<InterleaveGroup<Instruction> *, 4> DelSet;
|
||||
// Avoid releasing a pointer twice.
|
||||
for (auto &I : InterleaveGroupMap)
|
||||
DelSet.insert(I.second);
|
||||
for (auto *Ptr : DelSet)
|
||||
delete Ptr;
|
||||
InterleaveGroupMap.clear();
|
||||
RequiresScalarEpilogue = false;
|
||||
}
|
||||
|
||||
|
||||
/// Check if \p Instr belongs to any interleave group.
|
||||
bool isInterleaved(Instruction *Instr) const {
|
||||
return InterleaveGroupMap.find(Instr) != InterleaveGroupMap.end();
|
||||
}
|
||||
|
||||
/// Get the interleave group that \p Instr belongs to.
|
||||
///
|
||||
/// \returns nullptr if doesn't have such group.
|
||||
InterleaveGroup<Instruction> *
|
||||
getInterleaveGroup(const Instruction *Instr) const {
|
||||
if (InterleaveGroupMap.count(Instr))
|
||||
return InterleaveGroupMap.find(Instr)->second;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
iterator_range<SmallPtrSetIterator<llvm::InterleaveGroup<Instruction> *>>
|
||||
getInterleaveGroups() {
|
||||
return make_range(InterleaveGroups.begin(), InterleaveGroups.end());
|
||||
}
|
||||
|
||||
/// Returns true if an interleaved group that may access memory
|
||||
/// out-of-bounds requires a scalar epilogue iteration for correctness.
|
||||
bool requiresScalarEpilogue() const { return RequiresScalarEpilogue; }
|
||||
|
||||
/// Invalidate groups that require a scalar epilogue (due to gaps). This can
|
||||
/// happen when optimizing for size forbids a scalar epilogue, and the gap
|
||||
/// cannot be filtered by masking the load/store.
|
||||
void invalidateGroupsRequiringScalarEpilogue();
|
||||
|
||||
private:
|
||||
/// A wrapper around ScalarEvolution, used to add runtime SCEV checks.
|
||||
/// Simplifies SCEV expressions in the context of existing SCEV assumptions.
|
||||
/// The interleaved access analysis can also add new predicates (for example
|
||||
/// by versioning strides of pointers).
|
||||
PredicatedScalarEvolution &PSE;
|
||||
|
||||
Loop *TheLoop;
|
||||
DominatorTree *DT;
|
||||
LoopInfo *LI;
|
||||
const LoopAccessInfo *LAI;
|
||||
|
||||
/// True if the loop may contain non-reversed interleaved groups with
|
||||
/// out-of-bounds accesses. We ensure we don't speculatively access memory
|
||||
/// out-of-bounds by executing at least one scalar epilogue iteration.
|
||||
bool RequiresScalarEpilogue = false;
|
||||
|
||||
/// Holds the relationships between the members and the interleave group.
|
||||
DenseMap<Instruction *, InterleaveGroup<Instruction> *> InterleaveGroupMap;
|
||||
|
||||
SmallPtrSet<InterleaveGroup<Instruction> *, 4> InterleaveGroups;
|
||||
|
||||
/// Holds dependences among the memory accesses in the loop. It maps a source
|
||||
/// access to a set of dependent sink accesses.
|
||||
DenseMap<Instruction *, SmallPtrSet<Instruction *, 2>> Dependences;
|
||||
|
||||
/// The descriptor for a strided memory access.
|
||||
struct StrideDescriptor {
|
||||
StrideDescriptor() = default;
|
||||
StrideDescriptor(int64_t Stride, const SCEV *Scev, uint64_t Size,
|
||||
unsigned Align)
|
||||
: Stride(Stride), Scev(Scev), Size(Size), Align(Align) {}
|
||||
|
||||
// The access's stride. It is negative for a reverse access.
|
||||
int64_t Stride = 0;
|
||||
|
||||
// The scalar expression of this access.
|
||||
const SCEV *Scev = nullptr;
|
||||
|
||||
// The size of the memory object.
|
||||
uint64_t Size = 0;
|
||||
|
||||
// The alignment of this access.
|
||||
unsigned Align = 0;
|
||||
};
|
||||
|
||||
/// A type for holding instructions and their stride descriptors.
|
||||
using StrideEntry = std::pair<Instruction *, StrideDescriptor>;
|
||||
|
||||
/// Create a new interleave group with the given instruction \p Instr,
|
||||
/// stride \p Stride and alignment \p Align.
|
||||
///
|
||||
/// \returns the newly created interleave group.
|
||||
InterleaveGroup<Instruction> *
|
||||
createInterleaveGroup(Instruction *Instr, int Stride, unsigned Align) {
|
||||
assert(!InterleaveGroupMap.count(Instr) &&
|
||||
"Already in an interleaved access group");
|
||||
InterleaveGroupMap[Instr] =
|
||||
new InterleaveGroup<Instruction>(Instr, Stride, Align);
|
||||
InterleaveGroups.insert(InterleaveGroupMap[Instr]);
|
||||
return InterleaveGroupMap[Instr];
|
||||
}
|
||||
|
||||
/// Release the group and remove all the relationships.
|
||||
void releaseGroup(InterleaveGroup<Instruction> *Group) {
|
||||
for (unsigned i = 0; i < Group->getFactor(); i++)
|
||||
if (Instruction *Member = Group->getMember(i))
|
||||
InterleaveGroupMap.erase(Member);
|
||||
|
||||
InterleaveGroups.erase(Group);
|
||||
delete Group;
|
||||
}
|
||||
|
||||
/// Collect all the accesses with a constant stride in program order.
|
||||
void collectConstStrideAccesses(
|
||||
MapVector<Instruction *, StrideDescriptor> &AccessStrideInfo,
|
||||
const ValueToValueMap &Strides);
|
||||
|
||||
/// Returns true if \p Stride is allowed in an interleaved group.
|
||||
static bool isStrided(int Stride);
|
||||
|
||||
/// Returns true if \p BB is a predicated block.
|
||||
bool isPredicated(BasicBlock *BB) const {
|
||||
return LoopAccessInfo::blockNeedsPredication(BB, TheLoop, DT);
|
||||
}
|
||||
|
||||
/// Returns true if LoopAccessInfo can be used for dependence queries.
|
||||
bool areDependencesValid() const {
|
||||
return LAI && LAI->getDepChecker().getDependences();
|
||||
}
|
||||
|
||||
/// Returns true if memory accesses \p A and \p B can be reordered, if
|
||||
/// necessary, when constructing interleaved groups.
|
||||
///
|
||||
/// \p A must precede \p B in program order. We return false if reordering is
|
||||
/// not necessary or is prevented because \p A and \p B may be dependent.
|
||||
bool canReorderMemAccessesForInterleavedGroups(StrideEntry *A,
|
||||
StrideEntry *B) const {
|
||||
// Code motion for interleaved accesses can potentially hoist strided loads
|
||||
// and sink strided stores. The code below checks the legality of the
|
||||
// following two conditions:
|
||||
//
|
||||
// 1. Potentially moving a strided load (B) before any store (A) that
|
||||
// precedes B, or
|
||||
//
|
||||
// 2. Potentially moving a strided store (A) after any load or store (B)
|
||||
// that A precedes.
|
||||
//
|
||||
// It's legal to reorder A and B if we know there isn't a dependence from A
|
||||
// to B. Note that this determination is conservative since some
|
||||
// dependences could potentially be reordered safely.
|
||||
|
||||
// A is potentially the source of a dependence.
|
||||
auto *Src = A->first;
|
||||
auto SrcDes = A->second;
|
||||
|
||||
// B is potentially the sink of a dependence.
|
||||
auto *Sink = B->first;
|
||||
auto SinkDes = B->second;
|
||||
|
||||
// Code motion for interleaved accesses can't violate WAR dependences.
|
||||
// Thus, reordering is legal if the source isn't a write.
|
||||
if (!Src->mayWriteToMemory())
|
||||
return true;
|
||||
|
||||
// At least one of the accesses must be strided.
|
||||
if (!isStrided(SrcDes.Stride) && !isStrided(SinkDes.Stride))
|
||||
return true;
|
||||
|
||||
// If dependence information is not available from LoopAccessInfo,
|
||||
// conservatively assume the instructions can't be reordered.
|
||||
if (!areDependencesValid())
|
||||
return false;
|
||||
|
||||
// If we know there is a dependence from source to sink, assume the
|
||||
// instructions can't be reordered. Otherwise, reordering is legal.
|
||||
return Dependences.find(Src) == Dependences.end() ||
|
||||
!Dependences.lookup(Src).count(Sink);
|
||||
}
|
||||
|
||||
/// Collect the dependences from LoopAccessInfo.
|
||||
///
|
||||
/// We process the dependences once during the interleaved access analysis to
|
||||
/// enable constant-time dependence queries.
|
||||
void collectDependences() {
|
||||
if (!areDependencesValid())
|
||||
return;
|
||||
auto *Deps = LAI->getDepChecker().getDependences();
|
||||
for (auto Dep : *Deps)
|
||||
Dependences[Dep.getSource(*LAI)].insert(Dep.getDestination(*LAI));
|
||||
}
|
||||
};
|
||||
|
||||
} // llvm namespace
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -0,0 +1,70 @@
|
|||
//===- AMDGPUMetadataVerifier.h - MsgPack Types -----------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
/// \file
|
||||
/// This is a verifier for AMDGPU HSA metadata, which can verify both
|
||||
/// well-typed metadata and untyped metadata. When verifying in the non-strict
|
||||
/// mode, untyped metadata is coerced into the correct type if possible.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_BINARYFORMAT_AMDGPUMETADATAVERIFIER_H
|
||||
#define LLVM_BINARYFORMAT_AMDGPUMETADATAVERIFIER_H
|
||||
|
||||
#include "llvm/BinaryFormat/MsgPackTypes.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace AMDGPU {
|
||||
namespace HSAMD {
|
||||
namespace V3 {
|
||||
|
||||
/// Verifier for AMDGPU HSA metadata.
|
||||
///
|
||||
/// Operates in two modes:
|
||||
///
|
||||
/// In strict mode, metadata must already be well-typed.
|
||||
///
|
||||
/// In non-strict mode, metadata is coerced into expected types when possible.
|
||||
class MetadataVerifier {
|
||||
bool Strict;
|
||||
|
||||
bool verifyScalar(msgpack::Node &Node, msgpack::ScalarNode::ScalarKind SKind,
|
||||
function_ref<bool(msgpack::ScalarNode &)> verifyValue = {});
|
||||
bool verifyInteger(msgpack::Node &Node);
|
||||
bool verifyArray(msgpack::Node &Node,
|
||||
function_ref<bool(msgpack::Node &)> verifyNode,
|
||||
Optional<size_t> Size = None);
|
||||
bool verifyEntry(msgpack::MapNode &MapNode, StringRef Key, bool Required,
|
||||
function_ref<bool(msgpack::Node &)> verifyNode);
|
||||
bool
|
||||
verifyScalarEntry(msgpack::MapNode &MapNode, StringRef Key, bool Required,
|
||||
msgpack::ScalarNode::ScalarKind SKind,
|
||||
function_ref<bool(msgpack::ScalarNode &)> verifyValue = {});
|
||||
bool verifyIntegerEntry(msgpack::MapNode &MapNode, StringRef Key,
|
||||
bool Required);
|
||||
bool verifyKernelArgs(msgpack::Node &Node);
|
||||
bool verifyKernel(msgpack::Node &Node);
|
||||
|
||||
public:
|
||||
/// Construct a MetadataVerifier, specifying whether it will operate in \p
|
||||
/// Strict mode.
|
||||
MetadataVerifier(bool Strict) : Strict(Strict) {}
|
||||
|
||||
/// Verify given HSA metadata.
|
||||
///
|
||||
/// \returns True when successful, false when metadata is invalid.
|
||||
bool verify(msgpack::Node &HSAMetadataRoot);
|
||||
};
|
||||
|
||||
} // end namespace V3
|
||||
} // end namespace HSAMD
|
||||
} // end namespace AMDGPU
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_BINARYFORMAT_AMDGPUMETADATAVERIFIER_H
|
||||
|
|
@ -18,9 +18,11 @@
|
|||
defined HANDLE_DW_VIRTUALITY || defined HANDLE_DW_DEFAULTED || \
|
||||
defined HANDLE_DW_CC || defined HANDLE_DW_LNS || defined HANDLE_DW_LNE || \
|
||||
defined HANDLE_DW_LNCT || defined HANDLE_DW_MACRO || \
|
||||
defined HANDLE_DW_RLE || defined HANDLE_DW_CFA || \
|
||||
defined HANDLE_DW_RLE || \
|
||||
(defined HANDLE_DW_CFA && defined HANDLE_DW_CFA_PRED) || \
|
||||
defined HANDLE_DW_APPLE_PROPERTY || defined HANDLE_DW_UT || \
|
||||
defined HANDLE_DWARF_SECTION || defined HANDLE_DW_IDX)
|
||||
defined HANDLE_DWARF_SECTION || defined HANDLE_DW_IDX || \
|
||||
defined HANDLE_DW_END)
|
||||
#error "Missing macro definition of HANDLE_DW*"
|
||||
#endif
|
||||
|
||||
|
|
@ -41,7 +43,7 @@
|
|||
#endif
|
||||
|
||||
#ifndef HANDLE_DW_LANG
|
||||
#define HANDLE_DW_LANG(ID, NAME, VERSION, VENDOR)
|
||||
#define HANDLE_DW_LANG(ID, NAME, LOWER_BOUND, VERSION, VENDOR)
|
||||
#endif
|
||||
|
||||
#ifndef HANDLE_DW_ATE
|
||||
|
|
@ -84,6 +86,10 @@
|
|||
#define HANDLE_DW_CFA(ID, NAME)
|
||||
#endif
|
||||
|
||||
#ifndef HANDLE_DW_CFA_PRED
|
||||
#define HANDLE_DW_CFA_PRED(ID, NAME, PRED)
|
||||
#endif
|
||||
|
||||
#ifndef HANDLE_DW_APPLE_PROPERTY
|
||||
#define HANDLE_DW_APPLE_PROPERTY(ID, NAME)
|
||||
#endif
|
||||
|
|
@ -100,6 +106,10 @@
|
|||
#define HANDLE_DW_IDX(ID, NAME)
|
||||
#endif
|
||||
|
||||
#ifndef HANDLE_DW_END
|
||||
#define HANDLE_DW_END(ID, NAME)
|
||||
#endif
|
||||
|
||||
HANDLE_DW_TAG(0x0000, null, 2, DWARF)
|
||||
HANDLE_DW_TAG(0x0001, array_type, 2, DWARF)
|
||||
HANDLE_DW_TAG(0x0002, class_type, 2, DWARF)
|
||||
|
|
@ -622,50 +632,50 @@ HANDLE_DW_OP(0xfb, GNU_addr_index, 0, GNU)
|
|||
HANDLE_DW_OP(0xfc, GNU_const_index, 0, GNU)
|
||||
|
||||
// DWARF languages.
|
||||
HANDLE_DW_LANG(0x0001, C89, 2, DWARF)
|
||||
HANDLE_DW_LANG(0x0002, C, 2, DWARF)
|
||||
HANDLE_DW_LANG(0x0003, Ada83, 2, DWARF)
|
||||
HANDLE_DW_LANG(0x0004, C_plus_plus, 2, DWARF)
|
||||
HANDLE_DW_LANG(0x0005, Cobol74, 2, DWARF)
|
||||
HANDLE_DW_LANG(0x0006, Cobol85, 2, DWARF)
|
||||
HANDLE_DW_LANG(0x0007, Fortran77, 2, DWARF)
|
||||
HANDLE_DW_LANG(0x0008, Fortran90, 2, DWARF)
|
||||
HANDLE_DW_LANG(0x0009, Pascal83, 2, DWARF)
|
||||
HANDLE_DW_LANG(0x000a, Modula2, 2, DWARF)
|
||||
HANDLE_DW_LANG(0x0001, C89, 0, 2, DWARF)
|
||||
HANDLE_DW_LANG(0x0002, C, 0, 2, DWARF)
|
||||
HANDLE_DW_LANG(0x0003, Ada83, 1, 2, DWARF)
|
||||
HANDLE_DW_LANG(0x0004, C_plus_plus, 0, 2, DWARF)
|
||||
HANDLE_DW_LANG(0x0005, Cobol74, 1, 2, DWARF)
|
||||
HANDLE_DW_LANG(0x0006, Cobol85, 1, 2, DWARF)
|
||||
HANDLE_DW_LANG(0x0007, Fortran77, 1, 2, DWARF)
|
||||
HANDLE_DW_LANG(0x0008, Fortran90, 1, 2, DWARF)
|
||||
HANDLE_DW_LANG(0x0009, Pascal83, 1, 2, DWARF)
|
||||
HANDLE_DW_LANG(0x000a, Modula2, 1, 2, DWARF)
|
||||
// New in DWARF v3:
|
||||
HANDLE_DW_LANG(0x000b, Java, 3, DWARF)
|
||||
HANDLE_DW_LANG(0x000c, C99, 3, DWARF)
|
||||
HANDLE_DW_LANG(0x000d, Ada95, 3, DWARF)
|
||||
HANDLE_DW_LANG(0x000e, Fortran95, 3, DWARF)
|
||||
HANDLE_DW_LANG(0x000f, PLI, 3, DWARF)
|
||||
HANDLE_DW_LANG(0x0010, ObjC, 3, DWARF)
|
||||
HANDLE_DW_LANG(0x0011, ObjC_plus_plus, 3, DWARF)
|
||||
HANDLE_DW_LANG(0x0012, UPC, 3, DWARF)
|
||||
HANDLE_DW_LANG(0x0013, D, 3, DWARF)
|
||||
HANDLE_DW_LANG(0x000b, Java, 0, 3, DWARF)
|
||||
HANDLE_DW_LANG(0x000c, C99, 0, 3, DWARF)
|
||||
HANDLE_DW_LANG(0x000d, Ada95, 1, 3, DWARF)
|
||||
HANDLE_DW_LANG(0x000e, Fortran95, 1, 3, DWARF)
|
||||
HANDLE_DW_LANG(0x000f, PLI, 1, 3, DWARF)
|
||||
HANDLE_DW_LANG(0x0010, ObjC, 0, 3, DWARF)
|
||||
HANDLE_DW_LANG(0x0011, ObjC_plus_plus, 0, 3, DWARF)
|
||||
HANDLE_DW_LANG(0x0012, UPC, 0, 3, DWARF)
|
||||
HANDLE_DW_LANG(0x0013, D, 0, 3, DWARF)
|
||||
// New in DWARF v4:
|
||||
HANDLE_DW_LANG(0x0014, Python, 4, DWARF)
|
||||
HANDLE_DW_LANG(0x0014, Python, 0, 4, DWARF)
|
||||
// New in DWARF v5:
|
||||
HANDLE_DW_LANG(0x0015, OpenCL, 5, DWARF)
|
||||
HANDLE_DW_LANG(0x0016, Go, 5, DWARF)
|
||||
HANDLE_DW_LANG(0x0017, Modula3, 5, DWARF)
|
||||
HANDLE_DW_LANG(0x0018, Haskell, 5, DWARF)
|
||||
HANDLE_DW_LANG(0x0019, C_plus_plus_03, 5, DWARF)
|
||||
HANDLE_DW_LANG(0x001a, C_plus_plus_11, 5, DWARF)
|
||||
HANDLE_DW_LANG(0x001b, OCaml, 5, DWARF)
|
||||
HANDLE_DW_LANG(0x001c, Rust, 5, DWARF)
|
||||
HANDLE_DW_LANG(0x001d, C11, 5, DWARF)
|
||||
HANDLE_DW_LANG(0x001e, Swift, 5, DWARF)
|
||||
HANDLE_DW_LANG(0x001f, Julia, 5, DWARF)
|
||||
HANDLE_DW_LANG(0x0020, Dylan, 5, DWARF)
|
||||
HANDLE_DW_LANG(0x0021, C_plus_plus_14, 5, DWARF)
|
||||
HANDLE_DW_LANG(0x0022, Fortran03, 5, DWARF)
|
||||
HANDLE_DW_LANG(0x0023, Fortran08, 5, DWARF)
|
||||
HANDLE_DW_LANG(0x0024, RenderScript, 5, DWARF)
|
||||
HANDLE_DW_LANG(0x0025, BLISS, 5, DWARF)
|
||||
HANDLE_DW_LANG(0x0015, OpenCL, 0, 5, DWARF)
|
||||
HANDLE_DW_LANG(0x0016, Go, 0, 5, DWARF)
|
||||
HANDLE_DW_LANG(0x0017, Modula3, 1, 5, DWARF)
|
||||
HANDLE_DW_LANG(0x0018, Haskell, 0, 5, DWARF)
|
||||
HANDLE_DW_LANG(0x0019, C_plus_plus_03, 0, 5, DWARF)
|
||||
HANDLE_DW_LANG(0x001a, C_plus_plus_11, 0, 5, DWARF)
|
||||
HANDLE_DW_LANG(0x001b, OCaml, 0, 5, DWARF)
|
||||
HANDLE_DW_LANG(0x001c, Rust, 0, 5, DWARF)
|
||||
HANDLE_DW_LANG(0x001d, C11, 0, 5, DWARF)
|
||||
HANDLE_DW_LANG(0x001e, Swift, 0, 5, DWARF)
|
||||
HANDLE_DW_LANG(0x001f, Julia, 1, 5, DWARF)
|
||||
HANDLE_DW_LANG(0x0020, Dylan, 0, 5, DWARF)
|
||||
HANDLE_DW_LANG(0x0021, C_plus_plus_14, 0, 5, DWARF)
|
||||
HANDLE_DW_LANG(0x0022, Fortran03, 1, 5, DWARF)
|
||||
HANDLE_DW_LANG(0x0023, Fortran08, 1, 5, DWARF)
|
||||
HANDLE_DW_LANG(0x0024, RenderScript, 0, 5, DWARF)
|
||||
HANDLE_DW_LANG(0x0025, BLISS, 0, 5, DWARF)
|
||||
// Vendor extensions:
|
||||
HANDLE_DW_LANG(0x8001, Mips_Assembler, 0, MIPS)
|
||||
HANDLE_DW_LANG(0x8e57, GOOGLE_RenderScript, 0, GOOGLE)
|
||||
HANDLE_DW_LANG(0xb000, BORLAND_Delphi, 0, BORLAND)
|
||||
HANDLE_DW_LANG(0x8001, Mips_Assembler, None, 0, MIPS)
|
||||
HANDLE_DW_LANG(0x8e57, GOOGLE_RenderScript, 0, 0, GOOGLE)
|
||||
HANDLE_DW_LANG(0xb000, BORLAND_Delphi, 0, 0, BORLAND)
|
||||
|
||||
// DWARF attribute type encodings.
|
||||
HANDLE_DW_ATE(0x01, address, 2, DWARF)
|
||||
|
|
@ -690,6 +700,11 @@ HANDLE_DW_ATE(0x10, UTF, 4, DWARF)
|
|||
HANDLE_DW_ATE(0x11, UCS, 5, DWARF)
|
||||
HANDLE_DW_ATE(0x12, ASCII, 5, DWARF)
|
||||
|
||||
// DWARF attribute endianity
|
||||
HANDLE_DW_END(0x00, default)
|
||||
HANDLE_DW_END(0x01, big)
|
||||
HANDLE_DW_END(0x02, little)
|
||||
|
||||
// DWARF virtuality codes.
|
||||
HANDLE_DW_VIRTUALITY(0x00, none)
|
||||
HANDLE_DW_VIRTUALITY(0x01, virtual)
|
||||
|
|
@ -821,9 +836,10 @@ HANDLE_DW_CFA(0x14, val_offset)
|
|||
HANDLE_DW_CFA(0x15, val_offset_sf)
|
||||
HANDLE_DW_CFA(0x16, val_expression)
|
||||
// Vendor extensions:
|
||||
HANDLE_DW_CFA(0x1d, MIPS_advance_loc8)
|
||||
HANDLE_DW_CFA(0x2d, GNU_window_save)
|
||||
HANDLE_DW_CFA(0x2e, GNU_args_size)
|
||||
HANDLE_DW_CFA_PRED(0x1d, MIPS_advance_loc8, SELECT_MIPS64)
|
||||
HANDLE_DW_CFA_PRED(0x2d, GNU_window_save, SELECT_SPARC)
|
||||
HANDLE_DW_CFA_PRED(0x2d, AARCH64_negate_ra_state, SELECT_AARCH64)
|
||||
HANDLE_DW_CFA_PRED(0x2e, GNU_args_size, SELECT_X86)
|
||||
|
||||
// Apple Objective-C Property Attributes.
|
||||
// Keep this list in sync with clang's DeclSpec.h ObjCPropertyAttributeKind!
|
||||
|
|
@ -863,6 +879,7 @@ HANDLE_DWARF_SECTION(DebugTypes, ".debug_types", "debug-types")
|
|||
HANDLE_DWARF_SECTION(DebugLine, ".debug_line", "debug-line")
|
||||
HANDLE_DWARF_SECTION(DebugLineStr, ".debug_line_str", "debug-line-str")
|
||||
HANDLE_DWARF_SECTION(DebugLoc, ".debug_loc", "debug-loc")
|
||||
HANDLE_DWARF_SECTION(DebugLoclists, ".debug_loclists", "debug-loclists")
|
||||
HANDLE_DWARF_SECTION(DebugFrame, ".debug_frame", "debug-frame")
|
||||
HANDLE_DWARF_SECTION(DebugMacro, ".debug_macro", "debug-macro")
|
||||
HANDLE_DWARF_SECTION(DebugNames, ".debug_names", "debug-names")
|
||||
|
|
@ -905,7 +922,9 @@ HANDLE_DW_IDX(0x05, type_hash)
|
|||
#undef HANDLE_DW_MACRO
|
||||
#undef HANDLE_DW_RLE
|
||||
#undef HANDLE_DW_CFA
|
||||
#undef HANDLE_DW_CFA_PRED
|
||||
#undef HANDLE_DW_APPLE_PROPERTY
|
||||
#undef HANDLE_DW_UT
|
||||
#undef HANDLE_DWARF_SECTION
|
||||
#undef HANDLE_DW_IDX
|
||||
#undef HANDLE_DW_END
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/Format.h"
|
||||
#include "llvm/Support/FormatVariadicDetails.h"
|
||||
#include "llvm/ADT/Triple.h"
|
||||
|
||||
namespace llvm {
|
||||
class StringRef;
|
||||
|
|
@ -150,9 +151,8 @@ enum DecimalSignEncoding {
|
|||
|
||||
enum EndianityEncoding {
|
||||
// Endianity attribute values
|
||||
DW_END_default = 0x00,
|
||||
DW_END_big = 0x01,
|
||||
DW_END_little = 0x02,
|
||||
#define HANDLE_DW_END(ID, NAME) DW_END_##NAME = ID,
|
||||
#include "llvm/BinaryFormat/Dwarf.def"
|
||||
DW_END_lo_user = 0x40,
|
||||
DW_END_hi_user = 0xff
|
||||
};
|
||||
|
|
@ -184,7 +184,8 @@ enum DefaultedMemberAttribute {
|
|||
};
|
||||
|
||||
enum SourceLanguage {
|
||||
#define HANDLE_DW_LANG(ID, NAME, VERSION, VENDOR) DW_LANG_##NAME = ID,
|
||||
#define HANDLE_DW_LANG(ID, NAME, LOWER_BOUND, VERSION, VENDOR) \
|
||||
DW_LANG_##NAME = ID,
|
||||
#include "llvm/BinaryFormat/Dwarf.def"
|
||||
DW_LANG_lo_user = 0x8000,
|
||||
DW_LANG_hi_user = 0xffff
|
||||
|
|
@ -273,6 +274,7 @@ enum RangeListEntries {
|
|||
/// Call frame instruction encodings.
|
||||
enum CallFrameInfo {
|
||||
#define HANDLE_DW_CFA(ID, NAME) DW_CFA_##NAME = ID,
|
||||
#define HANDLE_DW_CFA_PRED(ID, NAME, ARCH) DW_CFA_##NAME = ID,
|
||||
#include "llvm/BinaryFormat/Dwarf.def"
|
||||
DW_CFA_extended = 0x00,
|
||||
|
||||
|
|
@ -431,7 +433,7 @@ StringRef LNStandardString(unsigned Standard);
|
|||
StringRef LNExtendedString(unsigned Encoding);
|
||||
StringRef MacinfoString(unsigned Encoding);
|
||||
StringRef RangeListEncodingString(unsigned Encoding);
|
||||
StringRef CallFrameString(unsigned Encoding);
|
||||
StringRef CallFrameString(unsigned Encoding, Triple::ArchType Arch);
|
||||
StringRef ApplePropertyString(unsigned);
|
||||
StringRef UnitTypeString(unsigned);
|
||||
StringRef AtomTypeString(unsigned Atom);
|
||||
|
|
@ -489,6 +491,8 @@ unsigned AttributeEncodingVendor(TypeKind E);
|
|||
unsigned LanguageVendor(SourceLanguage L);
|
||||
/// @}
|
||||
|
||||
Optional<unsigned> LanguageLowerBound(SourceLanguage L);
|
||||
|
||||
/// A helper struct providing information about the byte size of DW_FORM
|
||||
/// values that vary in size depending on the DWARF version, address byte
|
||||
/// size, or DWARF32/DWARF64.
|
||||
|
|
|
|||
|
|
@ -582,6 +582,7 @@ enum {
|
|||
EF_HEXAGON_MACH_V60 = 0x00000060, // Hexagon V60
|
||||
EF_HEXAGON_MACH_V62 = 0x00000062, // Hexagon V62
|
||||
EF_HEXAGON_MACH_V65 = 0x00000065, // Hexagon V65
|
||||
EF_HEXAGON_MACH_V66 = 0x00000066, // Hexagon V66
|
||||
|
||||
// Highest ISA version flags
|
||||
EF_HEXAGON_ISA_MACH = 0x00000000, // Same as specified in bits[11:0]
|
||||
|
|
@ -594,6 +595,7 @@ enum {
|
|||
EF_HEXAGON_ISA_V60 = 0x00000060, // Hexagon V60 ISA
|
||||
EF_HEXAGON_ISA_V62 = 0x00000062, // Hexagon V62 ISA
|
||||
EF_HEXAGON_ISA_V65 = 0x00000065, // Hexagon V65 ISA
|
||||
EF_HEXAGON_ISA_V66 = 0x00000066, // Hexagon V66 ISA
|
||||
};
|
||||
|
||||
// Hexagon-specific section indexes for common small data
|
||||
|
|
@ -701,6 +703,7 @@ enum : unsigned {
|
|||
EF_AMDGPU_MACH_AMDGCN_GFX902 = 0x02d,
|
||||
EF_AMDGPU_MACH_AMDGCN_GFX904 = 0x02e,
|
||||
EF_AMDGPU_MACH_AMDGCN_GFX906 = 0x02f,
|
||||
EF_AMDGPU_MACH_AMDGCN_GFX909 = 0x031,
|
||||
|
||||
// Reserved for AMDGCN-based processors.
|
||||
EF_AMDGPU_MACH_AMDGCN_RESERVED0 = 0x027,
|
||||
|
|
@ -708,11 +711,14 @@ enum : unsigned {
|
|||
|
||||
// First/last AMDGCN-based processors.
|
||||
EF_AMDGPU_MACH_AMDGCN_FIRST = EF_AMDGPU_MACH_AMDGCN_GFX600,
|
||||
EF_AMDGPU_MACH_AMDGCN_LAST = EF_AMDGPU_MACH_AMDGCN_GFX906,
|
||||
EF_AMDGPU_MACH_AMDGCN_LAST = EF_AMDGPU_MACH_AMDGCN_GFX909,
|
||||
|
||||
// Indicates if the xnack target feature is enabled for all code contained in
|
||||
// the object.
|
||||
// Indicates if the "xnack" target feature is enabled for all code contained
|
||||
// in the object.
|
||||
EF_AMDGPU_XNACK = 0x100,
|
||||
// Indicates if the "sram-ecc" target feature is enabled for all code
|
||||
// contained in the object.
|
||||
EF_AMDGPU_SRAM_ECC = 0x200,
|
||||
};
|
||||
|
||||
// ELF Relocation types for AMDGPU
|
||||
|
|
@ -725,6 +731,38 @@ enum {
|
|||
#include "ELFRelocs/BPF.def"
|
||||
};
|
||||
|
||||
// MSP430 specific e_flags
|
||||
enum : unsigned {
|
||||
EF_MSP430_MACH_MSP430x11 = 11,
|
||||
EF_MSP430_MACH_MSP430x11x1 = 110,
|
||||
EF_MSP430_MACH_MSP430x12 = 12,
|
||||
EF_MSP430_MACH_MSP430x13 = 13,
|
||||
EF_MSP430_MACH_MSP430x14 = 14,
|
||||
EF_MSP430_MACH_MSP430x15 = 15,
|
||||
EF_MSP430_MACH_MSP430x16 = 16,
|
||||
EF_MSP430_MACH_MSP430x20 = 20,
|
||||
EF_MSP430_MACH_MSP430x22 = 22,
|
||||
EF_MSP430_MACH_MSP430x23 = 23,
|
||||
EF_MSP430_MACH_MSP430x24 = 24,
|
||||
EF_MSP430_MACH_MSP430x26 = 26,
|
||||
EF_MSP430_MACH_MSP430x31 = 31,
|
||||
EF_MSP430_MACH_MSP430x32 = 32,
|
||||
EF_MSP430_MACH_MSP430x33 = 33,
|
||||
EF_MSP430_MACH_MSP430x41 = 41,
|
||||
EF_MSP430_MACH_MSP430x42 = 42,
|
||||
EF_MSP430_MACH_MSP430x43 = 43,
|
||||
EF_MSP430_MACH_MSP430x44 = 44,
|
||||
EF_MSP430_MACH_MSP430X = 45,
|
||||
EF_MSP430_MACH_MSP430x46 = 46,
|
||||
EF_MSP430_MACH_MSP430x47 = 47,
|
||||
EF_MSP430_MACH_MSP430x54 = 54,
|
||||
};
|
||||
|
||||
// ELF Relocation types for MSP430
|
||||
enum {
|
||||
#include "ELFRelocs/MSP430.def"
|
||||
};
|
||||
|
||||
#undef ELF_RELOC
|
||||
|
||||
// Section header.
|
||||
|
|
@ -829,6 +867,8 @@ enum : unsigned {
|
|||
SHT_MIPS_DWARF = 0x7000001e, // DWARF debugging section.
|
||||
SHT_MIPS_ABIFLAGS = 0x7000002a, // ABI information.
|
||||
|
||||
SHT_MSP430_ATTRIBUTES = 0x70000003U,
|
||||
|
||||
SHT_HIPROC = 0x7fffffff, // Highest processor arch-specific type.
|
||||
SHT_LOUSER = 0x80000000, // Lowest type reserved for applications.
|
||||
SHT_HIUSER = 0xffffffff // Highest type reserved for applications.
|
||||
|
|
@ -1321,7 +1361,7 @@ enum {
|
|||
GNU_PROPERTY_X86_FEATURE_1_SHSTK = 1 << 1
|
||||
};
|
||||
|
||||
// AMDGPU specific notes.
|
||||
// AMD specific notes. (Code Object V2)
|
||||
enum {
|
||||
// Note types with values between 0 and 9 (inclusive) are reserved.
|
||||
NT_AMD_AMDGPU_HSA_METADATA = 10,
|
||||
|
|
@ -1329,6 +1369,12 @@ enum {
|
|||
NT_AMD_AMDGPU_PAL_METADATA = 12
|
||||
};
|
||||
|
||||
// AMDGPU specific notes. (Code Object V3)
|
||||
enum {
|
||||
// Note types with values between 0 and 31 (inclusive) are reserved.
|
||||
NT_AMDGPU_METADATA = 32
|
||||
};
|
||||
|
||||
enum {
|
||||
GNU_ABI_TAG_LINUX = 0,
|
||||
GNU_ABI_TAG_HURD = 1,
|
||||
|
|
@ -1339,6 +1385,8 @@ enum {
|
|||
GNU_ABI_TAG_NACL = 6,
|
||||
};
|
||||
|
||||
constexpr const char *ELF_NOTE_GNU = "GNU";
|
||||
|
||||
// Android packed relocation group flags.
|
||||
enum {
|
||||
RELOCATION_GROUPED_BY_INFO_FLAG = 1,
|
||||
|
|
|
|||
16
contrib/llvm/include/llvm/BinaryFormat/ELFRelocs/MSP430.def
Normal file
16
contrib/llvm/include/llvm/BinaryFormat/ELFRelocs/MSP430.def
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
|
||||
#ifndef ELF_RELOC
|
||||
#error "ELF_RELOC must be defined"
|
||||
#endif
|
||||
|
||||
ELF_RELOC(R_MSP430_NONE, 0)
|
||||
ELF_RELOC(R_MSP430_32, 1)
|
||||
ELF_RELOC(R_MSP430_10_PCREL, 2)
|
||||
ELF_RELOC(R_MSP430_16, 3)
|
||||
ELF_RELOC(R_MSP430_16_PCREL, 4)
|
||||
ELF_RELOC(R_MSP430_16_BYTE, 5)
|
||||
ELF_RELOC(R_MSP430_16_PCREL_BYTE, 6)
|
||||
ELF_RELOC(R_MSP430_2X_PCREL, 7)
|
||||
ELF_RELOC(R_MSP430_RL_PCREL, 8)
|
||||
ELF_RELOC(R_MSP430_8, 9)
|
||||
ELF_RELOC(R_MSP430_SYM_DIFF, 10)
|
||||
|
|
@ -486,7 +486,10 @@ enum PlatformType {
|
|||
PLATFORM_IOS = 2,
|
||||
PLATFORM_TVOS = 3,
|
||||
PLATFORM_WATCHOS = 4,
|
||||
PLATFORM_BRIDGEOS = 5
|
||||
PLATFORM_BRIDGEOS = 5,
|
||||
PLATFORM_IOSSIMULATOR = 7,
|
||||
PLATFORM_TVOSSIMULATOR = 8,
|
||||
PLATFORM_WATCHOSSIMULATOR = 9
|
||||
};
|
||||
|
||||
// Values for tools enum in build_tool_version.
|
||||
|
|
|
|||
108
contrib/llvm/include/llvm/BinaryFormat/MsgPack.def
Normal file
108
contrib/llvm/include/llvm/BinaryFormat/MsgPack.def
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
//===- MsgPack.def - MessagePack definitions --------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file
|
||||
/// Macros for running through MessagePack enumerators.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#if !( \
|
||||
defined HANDLE_MP_FIRST_BYTE || defined HANDLE_MP_FIX_BITS || \
|
||||
defined HANDLE_MP_FIX_BITS_MASK || defined HANDLE_MP_FIX_MAX || \
|
||||
defined HANDLE_MP_FIX_LEN || defined HANDLE_MP_FIX_MIN)
|
||||
#error "Missing macro definition of HANDLE_MP*"
|
||||
#endif
|
||||
|
||||
#ifndef HANDLE_MP_FIRST_BYTE
|
||||
#define HANDLE_MP_FIRST_BYTE(ID, NAME)
|
||||
#endif
|
||||
|
||||
#ifndef HANDLE_MP_FIX_BITS
|
||||
#define HANDLE_MP_FIX_BITS(ID, NAME)
|
||||
#endif
|
||||
|
||||
#ifndef HANDLE_MP_FIX_BITS_MASK
|
||||
#define HANDLE_MP_FIX_BITS_MASK(ID, NAME)
|
||||
#endif
|
||||
|
||||
#ifndef HANDLE_MP_FIX_MAX
|
||||
#define HANDLE_MP_FIX_MAX(ID, NAME)
|
||||
#endif
|
||||
|
||||
#ifndef HANDLE_MP_FIX_LEN
|
||||
#define HANDLE_MP_FIX_LEN(ID, NAME)
|
||||
#endif
|
||||
|
||||
#ifndef HANDLE_MP_FIX_MIN
|
||||
#define HANDLE_MP_FIX_MIN(ID, NAME)
|
||||
#endif
|
||||
|
||||
HANDLE_MP_FIRST_BYTE(0xc0, Nil)
|
||||
HANDLE_MP_FIRST_BYTE(0xc2, False)
|
||||
HANDLE_MP_FIRST_BYTE(0xc3, True)
|
||||
HANDLE_MP_FIRST_BYTE(0xc4, Bin8)
|
||||
HANDLE_MP_FIRST_BYTE(0xc5, Bin16)
|
||||
HANDLE_MP_FIRST_BYTE(0xc6, Bin32)
|
||||
HANDLE_MP_FIRST_BYTE(0xc7, Ext8)
|
||||
HANDLE_MP_FIRST_BYTE(0xc8, Ext16)
|
||||
HANDLE_MP_FIRST_BYTE(0xc9, Ext32)
|
||||
HANDLE_MP_FIRST_BYTE(0xca, Float32)
|
||||
HANDLE_MP_FIRST_BYTE(0xcb, Float64)
|
||||
HANDLE_MP_FIRST_BYTE(0xcc, UInt8)
|
||||
HANDLE_MP_FIRST_BYTE(0xcd, UInt16)
|
||||
HANDLE_MP_FIRST_BYTE(0xce, UInt32)
|
||||
HANDLE_MP_FIRST_BYTE(0xcf, UInt64)
|
||||
HANDLE_MP_FIRST_BYTE(0xd0, Int8)
|
||||
HANDLE_MP_FIRST_BYTE(0xd1, Int16)
|
||||
HANDLE_MP_FIRST_BYTE(0xd2, Int32)
|
||||
HANDLE_MP_FIRST_BYTE(0xd3, Int64)
|
||||
HANDLE_MP_FIRST_BYTE(0xd4, FixExt1)
|
||||
HANDLE_MP_FIRST_BYTE(0xd5, FixExt2)
|
||||
HANDLE_MP_FIRST_BYTE(0xd6, FixExt4)
|
||||
HANDLE_MP_FIRST_BYTE(0xd7, FixExt8)
|
||||
HANDLE_MP_FIRST_BYTE(0xd8, FixExt16)
|
||||
HANDLE_MP_FIRST_BYTE(0xd9, Str8)
|
||||
HANDLE_MP_FIRST_BYTE(0xda, Str16)
|
||||
HANDLE_MP_FIRST_BYTE(0xdb, Str32)
|
||||
HANDLE_MP_FIRST_BYTE(0xdc, Array16)
|
||||
HANDLE_MP_FIRST_BYTE(0xdd, Array32)
|
||||
HANDLE_MP_FIRST_BYTE(0xde, Map16)
|
||||
HANDLE_MP_FIRST_BYTE(0xdf, Map32)
|
||||
|
||||
HANDLE_MP_FIX_BITS(0x00, PositiveInt)
|
||||
HANDLE_MP_FIX_BITS(0x80, Map)
|
||||
HANDLE_MP_FIX_BITS(0x90, Array)
|
||||
HANDLE_MP_FIX_BITS(0xa0, String)
|
||||
HANDLE_MP_FIX_BITS(0xe0, NegativeInt)
|
||||
|
||||
HANDLE_MP_FIX_BITS_MASK(0x80, PositiveInt)
|
||||
HANDLE_MP_FIX_BITS_MASK(0xf0, Map)
|
||||
HANDLE_MP_FIX_BITS_MASK(0xf0, Array)
|
||||
HANDLE_MP_FIX_BITS_MASK(0xe0, String)
|
||||
HANDLE_MP_FIX_BITS_MASK(0xe0, NegativeInt)
|
||||
|
||||
HANDLE_MP_FIX_MAX(0x7f, PositiveInt)
|
||||
HANDLE_MP_FIX_MAX(0x0f, Map)
|
||||
HANDLE_MP_FIX_MAX(0x0f, Array)
|
||||
HANDLE_MP_FIX_MAX(0x1f, String)
|
||||
|
||||
HANDLE_MP_FIX_LEN(0x01, Ext1)
|
||||
HANDLE_MP_FIX_LEN(0x02, Ext2)
|
||||
HANDLE_MP_FIX_LEN(0x04, Ext4)
|
||||
HANDLE_MP_FIX_LEN(0x08, Ext8)
|
||||
HANDLE_MP_FIX_LEN(0x10, Ext16)
|
||||
|
||||
HANDLE_MP_FIX_MIN(-0x20, NegativeInt)
|
||||
|
||||
#undef HANDLE_MP_FIRST_BYTE
|
||||
#undef HANDLE_MP_FIX_BITS
|
||||
#undef HANDLE_MP_FIX_BITS_MASK
|
||||
#undef HANDLE_MP_FIX_MAX
|
||||
#undef HANDLE_MP_FIX_LEN
|
||||
#undef HANDLE_MP_FIX_MIN
|
||||
93
contrib/llvm/include/llvm/BinaryFormat/MsgPack.h
Normal file
93
contrib/llvm/include/llvm/BinaryFormat/MsgPack.h
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
//===-- MsgPack.h - MessagePack Constants -----------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file
|
||||
/// This file contains constants used for implementing MessagePack support.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_BINARYFORMAT_MSGPACK_H
|
||||
#define LLVM_BINARYFORMAT_MSGPACK_H
|
||||
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
#include "llvm/Support/Endian.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace msgpack {
|
||||
|
||||
/// The endianness of all multi-byte encoded values in MessagePack.
|
||||
constexpr support::endianness Endianness = support::big;
|
||||
|
||||
/// The first byte identifiers of MessagePack object formats.
|
||||
namespace FirstByte {
|
||||
#define HANDLE_MP_FIRST_BYTE(ID, NAME) constexpr uint8_t NAME = ID;
|
||||
#include "llvm/BinaryFormat/MsgPack.def"
|
||||
}
|
||||
|
||||
/// Most significant bits used to identify "Fix" variants in MessagePack.
|
||||
///
|
||||
/// For example, FixStr objects encode their size in the five least significant
|
||||
/// bits of their first byte, which is identified by the bit pattern "101" in
|
||||
/// the three most significant bits. So FixBits::String contains 0b10100000.
|
||||
///
|
||||
/// A corresponding mask of the bit pattern is found in \c FixBitsMask.
|
||||
namespace FixBits {
|
||||
#define HANDLE_MP_FIX_BITS(ID, NAME) constexpr uint8_t NAME = ID;
|
||||
#include "llvm/BinaryFormat/MsgPack.def"
|
||||
}
|
||||
|
||||
/// Mask of bits used to identify "Fix" variants in MessagePack.
|
||||
///
|
||||
/// For example, FixStr objects encode their size in the five least significant
|
||||
/// bits of their first byte, which is identified by the bit pattern "101" in
|
||||
/// the three most significant bits. So FixBitsMask::String contains
|
||||
/// 0b11100000.
|
||||
///
|
||||
/// The corresponding bit pattern to mask for is found in FixBits.
|
||||
namespace FixBitsMask {
|
||||
#define HANDLE_MP_FIX_BITS_MASK(ID, NAME) constexpr uint8_t NAME = ID;
|
||||
#include "llvm/BinaryFormat/MsgPack.def"
|
||||
}
|
||||
|
||||
/// The maximum value or size encodable in "Fix" variants of formats.
|
||||
///
|
||||
/// For example, FixStr objects encode their size in the five least significant
|
||||
/// bits of their first byte, so the largest encodable size is 0b00011111.
|
||||
namespace FixMax {
|
||||
#define HANDLE_MP_FIX_MAX(ID, NAME) constexpr uint8_t NAME = ID;
|
||||
#include "llvm/BinaryFormat/MsgPack.def"
|
||||
}
|
||||
|
||||
/// The exact size encodable in "Fix" variants of formats.
|
||||
///
|
||||
/// The only objects for which an exact size makes sense are of Extension type.
|
||||
///
|
||||
/// For example, FixExt4 stores an extension type containing exactly four bytes.
|
||||
namespace FixLen {
|
||||
#define HANDLE_MP_FIX_LEN(ID, NAME) constexpr uint8_t NAME = ID;
|
||||
#include "llvm/BinaryFormat/MsgPack.def"
|
||||
}
|
||||
|
||||
/// The minimum value or size encodable in "Fix" variants of formats.
|
||||
///
|
||||
/// The only object for which a minimum makes sense is a negative FixNum.
|
||||
///
|
||||
/// Negative FixNum objects encode their signed integer value in one byte, but
|
||||
/// they must have the pattern "111" as their three most significant bits. This
|
||||
/// means all values are negative, and the smallest representable value is
|
||||
/// 0b11100000.
|
||||
namespace FixMin {
|
||||
#define HANDLE_MP_FIX_MIN(ID, NAME) constexpr int8_t NAME = ID;
|
||||
#include "llvm/BinaryFormat/MsgPack.def"
|
||||
}
|
||||
|
||||
} // end namespace msgpack
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_BINARYFORMAT_MSGPACK_H
|
||||
148
contrib/llvm/include/llvm/BinaryFormat/MsgPackReader.h
Normal file
148
contrib/llvm/include/llvm/BinaryFormat/MsgPackReader.h
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
//===- MsgPackReader.h - Simple MsgPack reader ------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file
|
||||
/// This is a MessagePack reader.
|
||||
///
|
||||
/// See https://github.com/msgpack/msgpack/blob/master/spec.md for the full
|
||||
/// standard.
|
||||
///
|
||||
/// Typical usage:
|
||||
/// \code
|
||||
/// StringRef input = GetInput();
|
||||
/// msgpack::Reader MPReader(input);
|
||||
/// msgpack::Object Obj;
|
||||
///
|
||||
/// while (MPReader.read(Obj)) {
|
||||
/// switch (Obj.Kind) {
|
||||
/// case msgpack::Type::Int:
|
||||
// // Use Obj.Int
|
||||
/// break;
|
||||
/// // ...
|
||||
/// }
|
||||
/// }
|
||||
/// \endcode
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_SUPPORT_MSGPACKREADER_H
|
||||
#define LLVM_SUPPORT_MSGPACKREADER_H
|
||||
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <cstdint>
|
||||
|
||||
namespace llvm {
|
||||
namespace msgpack {
|
||||
|
||||
/// MessagePack types as defined in the standard, with the exception of Integer
|
||||
/// being divided into a signed Int and unsigned UInt variant in order to map
|
||||
/// directly to C++ types.
|
||||
///
|
||||
/// The types map onto corresponding union members of the \c Object struct.
|
||||
enum class Type : uint8_t {
|
||||
Int,
|
||||
UInt,
|
||||
Nil,
|
||||
Boolean,
|
||||
Float,
|
||||
String,
|
||||
Binary,
|
||||
Array,
|
||||
Map,
|
||||
Extension,
|
||||
};
|
||||
|
||||
/// Extension types are composed of a user-defined type ID and an uninterpreted
|
||||
/// sequence of bytes.
|
||||
struct ExtensionType {
|
||||
/// User-defined extension type.
|
||||
int8_t Type;
|
||||
/// Raw bytes of the extension object.
|
||||
StringRef Bytes;
|
||||
};
|
||||
|
||||
/// MessagePack object, represented as a tagged union of C++ types.
|
||||
///
|
||||
/// All types except \c Type::Nil (which has only one value, and so is
|
||||
/// completely represented by the \c Kind itself) map to a exactly one union
|
||||
/// member.
|
||||
struct Object {
|
||||
Type Kind;
|
||||
union {
|
||||
/// Value for \c Type::Int.
|
||||
int64_t Int;
|
||||
/// Value for \c Type::Uint.
|
||||
uint64_t UInt;
|
||||
/// Value for \c Type::Boolean.
|
||||
bool Bool;
|
||||
/// Value for \c Type::Float.
|
||||
double Float;
|
||||
/// Value for \c Type::String and \c Type::Binary.
|
||||
StringRef Raw;
|
||||
/// Value for \c Type::Array and \c Type::Map.
|
||||
size_t Length;
|
||||
/// Value for \c Type::Extension.
|
||||
ExtensionType Extension;
|
||||
};
|
||||
|
||||
Object() : Kind(Type::Int), Int(0) {}
|
||||
};
|
||||
|
||||
/// Reads MessagePack objects from memory, one at a time.
|
||||
class Reader {
|
||||
public:
|
||||
/// Construct a reader, keeping a reference to the \p InputBuffer.
|
||||
Reader(MemoryBufferRef InputBuffer);
|
||||
/// Construct a reader, keeping a reference to the \p Input.
|
||||
Reader(StringRef Input);
|
||||
|
||||
Reader(const Reader &) = delete;
|
||||
Reader &operator=(const Reader &) = delete;
|
||||
|
||||
/// Read one object from the input buffer, advancing past it.
|
||||
///
|
||||
/// The \p Obj is updated with the kind of the object read, and the
|
||||
/// corresponding union member is updated.
|
||||
///
|
||||
/// For the collection objects (Array and Map), only the length is read, and
|
||||
/// the caller must make and additional \c N calls (in the case of Array) or
|
||||
/// \c N*2 calls (in the case of Map) to \c Read to retrieve the collection
|
||||
/// elements.
|
||||
///
|
||||
/// \param [out] Obj filled with next object on success.
|
||||
///
|
||||
/// \returns true when object successfully read, false when at end of
|
||||
/// input (and so \p Obj was not updated), otherwise an error.
|
||||
Expected<bool> read(Object &Obj);
|
||||
|
||||
private:
|
||||
MemoryBufferRef InputBuffer;
|
||||
StringRef::iterator Current;
|
||||
StringRef::iterator End;
|
||||
|
||||
size_t remainingSpace() {
|
||||
// The rest of the code maintains the invariant that End >= Current, so
|
||||
// that this cast is always defined behavior.
|
||||
return static_cast<size_t>(End - Current);
|
||||
}
|
||||
|
||||
template <class T> Expected<bool> readRaw(Object &Obj);
|
||||
template <class T> Expected<bool> readInt(Object &Obj);
|
||||
template <class T> Expected<bool> readUInt(Object &Obj);
|
||||
template <class T> Expected<bool> readLength(Object &Obj);
|
||||
template <class T> Expected<bool> readExt(Object &Obj);
|
||||
Expected<bool> createRaw(Object &Obj, uint32_t Size);
|
||||
Expected<bool> createExt(Object &Obj, uint32_t Size);
|
||||
};
|
||||
|
||||
} // end namespace msgpack
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_SUPPORT_MSGPACKREADER_H
|
||||
372
contrib/llvm/include/llvm/BinaryFormat/MsgPackTypes.h
Normal file
372
contrib/llvm/include/llvm/BinaryFormat/MsgPackTypes.h
Normal file
|
|
@ -0,0 +1,372 @@
|
|||
//===- MsgPackTypes.h - MsgPack Types ---------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
/// \file
|
||||
/// This is a data structure for representing MessagePack "documents", with
|
||||
/// methods to go to and from MessagePack. The types also specialize YAMLIO
|
||||
/// traits in order to go to and from YAML.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/BinaryFormat/MsgPackReader.h"
|
||||
#include "llvm/BinaryFormat/MsgPackWriter.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/Support/YAMLTraits.h"
|
||||
#include <vector>
|
||||
|
||||
#ifndef LLVM_BINARYFORMAT_MSGPACKTYPES_H
|
||||
#define LLVM_BINARYFORMAT_MSGPACKTYPES_H
|
||||
|
||||
namespace llvm {
|
||||
namespace msgpack {
|
||||
|
||||
class Node;
|
||||
|
||||
/// Short-hand for a Node pointer.
|
||||
using NodePtr = std::shared_ptr<Node>;
|
||||
|
||||
/// Short-hand for an Optional Node pointer.
|
||||
using OptNodePtr = Optional<NodePtr>;
|
||||
|
||||
/// Abstract base-class which can be any MessagePack type.
|
||||
class Node {
|
||||
public:
|
||||
enum NodeKind {
|
||||
NK_Scalar,
|
||||
NK_Array,
|
||||
NK_Map,
|
||||
};
|
||||
|
||||
private:
|
||||
virtual void anchor() = 0;
|
||||
const NodeKind Kind;
|
||||
|
||||
static Expected<OptNodePtr> readArray(Reader &MPReader, size_t Length);
|
||||
static Expected<OptNodePtr> readMap(Reader &MPReader, size_t Length);
|
||||
|
||||
public:
|
||||
NodeKind getKind() const { return Kind; }
|
||||
|
||||
/// Construct a Node. Used by derived classes to track kind information.
|
||||
Node(NodeKind Kind) : Kind(Kind) {}
|
||||
|
||||
virtual ~Node() = default;
|
||||
|
||||
/// Read from a MessagePack reader \p MPReader, returning an error if one is
|
||||
/// encountered, or None if \p MPReader is at the end of stream, or some Node
|
||||
/// pointer if some type is read.
|
||||
static Expected<OptNodePtr> read(Reader &MPReader);
|
||||
|
||||
/// Write to a MessagePack writer \p MPWriter.
|
||||
virtual void write(Writer &MPWriter) = 0;
|
||||
};
|
||||
|
||||
/// A MessagePack scalar.
|
||||
class ScalarNode : public Node {
|
||||
public:
|
||||
enum ScalarKind {
|
||||
SK_Int,
|
||||
SK_UInt,
|
||||
SK_Nil,
|
||||
SK_Boolean,
|
||||
SK_Float,
|
||||
SK_String,
|
||||
SK_Binary,
|
||||
};
|
||||
|
||||
private:
|
||||
void anchor() override;
|
||||
|
||||
void destroy();
|
||||
|
||||
ScalarKind SKind;
|
||||
|
||||
union {
|
||||
int64_t IntValue;
|
||||
uint64_t UIntValue;
|
||||
bool BoolValue;
|
||||
double FloatValue;
|
||||
std::string StringValue;
|
||||
};
|
||||
|
||||
public:
|
||||
/// Construct an Int ScalarNode.
|
||||
ScalarNode(int64_t IntValue);
|
||||
/// Construct an Int ScalarNode.
|
||||
ScalarNode(int32_t IntValue);
|
||||
/// Construct an UInt ScalarNode.
|
||||
ScalarNode(uint64_t UIntValue);
|
||||
/// Construct an UInt ScalarNode.
|
||||
ScalarNode(uint32_t UIntValue);
|
||||
/// Construct a Nil ScalarNode.
|
||||
ScalarNode();
|
||||
/// Construct a Boolean ScalarNode.
|
||||
ScalarNode(bool BoolValue);
|
||||
/// Construct a Float ScalarNode.
|
||||
ScalarNode(double FloatValue);
|
||||
/// Construct a String ScalarNode.
|
||||
ScalarNode(StringRef StringValue);
|
||||
/// Construct a String ScalarNode.
|
||||
ScalarNode(const char *StringValue);
|
||||
/// Construct a String ScalarNode.
|
||||
ScalarNode(std::string &&StringValue);
|
||||
/// Construct a Binary ScalarNode.
|
||||
ScalarNode(MemoryBufferRef BinaryValue);
|
||||
|
||||
~ScalarNode();
|
||||
|
||||
ScalarNode &operator=(const ScalarNode &RHS) = delete;
|
||||
/// A ScalarNode can only be move assigned.
|
||||
ScalarNode &operator=(ScalarNode &&RHS);
|
||||
|
||||
/// Change the kind of this ScalarNode, zero initializing it to the new type.
|
||||
void setScalarKind(ScalarKind SKind) {
|
||||
switch (SKind) {
|
||||
case SK_Int:
|
||||
*this = int64_t(0);
|
||||
break;
|
||||
case SK_UInt:
|
||||
*this = uint64_t(0);
|
||||
break;
|
||||
case SK_Boolean:
|
||||
*this = false;
|
||||
break;
|
||||
case SK_Float:
|
||||
*this = 0.0;
|
||||
break;
|
||||
case SK_String:
|
||||
*this = StringRef();
|
||||
break;
|
||||
case SK_Binary:
|
||||
*this = MemoryBufferRef("", "");
|
||||
break;
|
||||
case SK_Nil:
|
||||
*this = ScalarNode();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the current kind of ScalarNode.
|
||||
ScalarKind getScalarKind() { return SKind; }
|
||||
|
||||
/// Get the value of an Int scalar.
|
||||
///
|
||||
/// \warning Assumes getScalarKind() == SK_Int
|
||||
int64_t getInt() {
|
||||
assert(SKind == SK_Int);
|
||||
return IntValue;
|
||||
}
|
||||
|
||||
/// Get the value of a UInt scalar.
|
||||
///
|
||||
/// \warning Assumes getScalarKind() == SK_UInt
|
||||
uint64_t getUInt() {
|
||||
assert(SKind == SK_UInt);
|
||||
return UIntValue;
|
||||
}
|
||||
|
||||
/// Get the value of an Boolean scalar.
|
||||
///
|
||||
/// \warning Assumes getScalarKind() == SK_Boolean
|
||||
bool getBool() {
|
||||
assert(SKind == SK_Boolean);
|
||||
return BoolValue;
|
||||
}
|
||||
|
||||
/// Get the value of an Float scalar.
|
||||
///
|
||||
/// \warning Assumes getScalarKind() == SK_Float
|
||||
double getFloat() {
|
||||
assert(SKind == SK_Float);
|
||||
return FloatValue;
|
||||
}
|
||||
|
||||
/// Get the value of a String scalar.
|
||||
///
|
||||
/// \warning Assumes getScalarKind() == SK_String
|
||||
StringRef getString() {
|
||||
assert(SKind == SK_String);
|
||||
return StringValue;
|
||||
}
|
||||
|
||||
/// Get the value of a Binary scalar.
|
||||
///
|
||||
/// \warning Assumes getScalarKind() == SK_Binary
|
||||
StringRef getBinary() {
|
||||
assert(SKind == SK_Binary);
|
||||
return StringValue;
|
||||
}
|
||||
|
||||
static bool classof(const Node *N) { return N->getKind() == NK_Scalar; }
|
||||
|
||||
void write(Writer &MPWriter) override;
|
||||
|
||||
/// Parse a YAML scalar of the current ScalarKind from \p ScalarStr.
|
||||
///
|
||||
/// \returns An empty string on success, otherwise an error message.
|
||||
StringRef inputYAML(StringRef ScalarStr);
|
||||
|
||||
/// Output a YAML scalar of the current ScalarKind into \p OS.
|
||||
void outputYAML(raw_ostream &OS) const;
|
||||
|
||||
/// Determine which YAML quoting type the current value would need when
|
||||
/// output.
|
||||
yaml::QuotingType mustQuoteYAML(StringRef ScalarStr) const;
|
||||
|
||||
/// Get the YAML tag for the current ScalarKind.
|
||||
StringRef getYAMLTag() const;
|
||||
|
||||
/// Flag which affects how the type handles YAML tags when reading and
|
||||
/// writing.
|
||||
///
|
||||
/// When false, tags are used when reading and writing. When reading, the tag
|
||||
/// is used to decide the ScalarKind before parsing. When writing, the tag is
|
||||
/// output along with the value.
|
||||
///
|
||||
/// When true, tags are ignored when reading and writing. When reading, the
|
||||
/// ScalarKind is always assumed to be String. When writing, the tag is not
|
||||
/// output.
|
||||
bool IgnoreTag = false;
|
||||
|
||||
static const char *IntTag;
|
||||
static const char *NilTag;
|
||||
static const char *BooleanTag;
|
||||
static const char *FloatTag;
|
||||
static const char *StringTag;
|
||||
static const char *BinaryTag;
|
||||
};
|
||||
|
||||
class ArrayNode : public Node, public std::vector<NodePtr> {
|
||||
void anchor() override;
|
||||
|
||||
public:
|
||||
ArrayNode() : Node(NK_Array) {}
|
||||
static bool classof(const Node *N) { return N->getKind() == NK_Array; }
|
||||
|
||||
void write(Writer &MPWriter) override {
|
||||
MPWriter.writeArraySize(this->size());
|
||||
for (auto &N : *this)
|
||||
N->write(MPWriter);
|
||||
}
|
||||
};
|
||||
|
||||
class MapNode : public Node, public StringMap<NodePtr> {
|
||||
void anchor() override;
|
||||
|
||||
public:
|
||||
MapNode() : Node(NK_Map) {}
|
||||
static bool classof(const Node *N) { return N->getKind() == NK_Map; }
|
||||
|
||||
void write(Writer &MPWriter) override {
|
||||
MPWriter.writeMapSize(this->size());
|
||||
for (auto &N : *this) {
|
||||
MPWriter.write(N.first());
|
||||
N.second->write(MPWriter);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace msgpack
|
||||
|
||||
namespace yaml {
|
||||
|
||||
template <> struct PolymorphicTraits<msgpack::NodePtr> {
|
||||
static NodeKind getKind(const msgpack::NodePtr &N) {
|
||||
if (isa<msgpack::ScalarNode>(*N))
|
||||
return NodeKind::Scalar;
|
||||
if (isa<msgpack::MapNode>(*N))
|
||||
return NodeKind::Map;
|
||||
if (isa<msgpack::ArrayNode>(*N))
|
||||
return NodeKind::Sequence;
|
||||
llvm_unreachable("NodeKind not supported");
|
||||
}
|
||||
static msgpack::ScalarNode &getAsScalar(msgpack::NodePtr &N) {
|
||||
if (!N || !isa<msgpack::ScalarNode>(*N))
|
||||
N.reset(new msgpack::ScalarNode());
|
||||
return *cast<msgpack::ScalarNode>(N.get());
|
||||
}
|
||||
static msgpack::MapNode &getAsMap(msgpack::NodePtr &N) {
|
||||
if (!N || !isa<msgpack::MapNode>(*N))
|
||||
N.reset(new msgpack::MapNode());
|
||||
return *cast<msgpack::MapNode>(N.get());
|
||||
}
|
||||
static msgpack::ArrayNode &getAsSequence(msgpack::NodePtr &N) {
|
||||
if (!N || !isa<msgpack::ArrayNode>(*N))
|
||||
N.reset(new msgpack::ArrayNode());
|
||||
return *cast<msgpack::ArrayNode>(N.get());
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct TaggedScalarTraits<msgpack::ScalarNode> {
|
||||
static void output(const msgpack::ScalarNode &S, void *Ctxt,
|
||||
raw_ostream &ScalarOS, raw_ostream &TagOS) {
|
||||
if (!S.IgnoreTag)
|
||||
TagOS << S.getYAMLTag();
|
||||
S.outputYAML(ScalarOS);
|
||||
}
|
||||
|
||||
static StringRef input(StringRef ScalarStr, StringRef Tag, void *Ctxt,
|
||||
msgpack::ScalarNode &S) {
|
||||
if (Tag == msgpack::ScalarNode::IntTag) {
|
||||
S.setScalarKind(msgpack::ScalarNode::SK_UInt);
|
||||
if (S.inputYAML(ScalarStr) == StringRef())
|
||||
return StringRef();
|
||||
S.setScalarKind(msgpack::ScalarNode::SK_Int);
|
||||
return S.inputYAML(ScalarStr);
|
||||
}
|
||||
|
||||
if (S.IgnoreTag || Tag == msgpack::ScalarNode::StringTag ||
|
||||
Tag == "tag:yaml.org,2002:str")
|
||||
S.setScalarKind(msgpack::ScalarNode::SK_String);
|
||||
else if (Tag == msgpack::ScalarNode::NilTag)
|
||||
S.setScalarKind(msgpack::ScalarNode::SK_Nil);
|
||||
else if (Tag == msgpack::ScalarNode::BooleanTag)
|
||||
S.setScalarKind(msgpack::ScalarNode::SK_Boolean);
|
||||
else if (Tag == msgpack::ScalarNode::FloatTag)
|
||||
S.setScalarKind(msgpack::ScalarNode::SK_Float);
|
||||
else if (Tag == msgpack::ScalarNode::StringTag)
|
||||
S.setScalarKind(msgpack::ScalarNode::SK_String);
|
||||
else if (Tag == msgpack::ScalarNode::BinaryTag)
|
||||
S.setScalarKind(msgpack::ScalarNode::SK_Binary);
|
||||
else
|
||||
return "Unsupported messagepack tag";
|
||||
|
||||
return S.inputYAML(ScalarStr);
|
||||
}
|
||||
|
||||
static QuotingType mustQuote(const msgpack::ScalarNode &S, StringRef Str) {
|
||||
return S.mustQuoteYAML(Str);
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct CustomMappingTraits<msgpack::MapNode> {
|
||||
static void inputOne(IO &IO, StringRef Key, msgpack::MapNode &M) {
|
||||
IO.mapRequired(Key.str().c_str(), M[Key]);
|
||||
}
|
||||
static void output(IO &IO, msgpack::MapNode &M) {
|
||||
for (auto &N : M)
|
||||
IO.mapRequired(N.getKey().str().c_str(), N.getValue());
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct SequenceTraits<msgpack::ArrayNode> {
|
||||
static size_t size(IO &IO, msgpack::ArrayNode &A) { return A.size(); }
|
||||
static msgpack::NodePtr &element(IO &IO, msgpack::ArrayNode &A,
|
||||
size_t Index) {
|
||||
if (Index >= A.size())
|
||||
A.resize(Index + 1);
|
||||
return A[Index];
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace yaml
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_BINARYFORMAT_MSGPACKTYPES_H
|
||||
131
contrib/llvm/include/llvm/BinaryFormat/MsgPackWriter.h
Normal file
131
contrib/llvm/include/llvm/BinaryFormat/MsgPackWriter.h
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
//===- MsgPackWriter.h - Simple MsgPack writer ------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file
|
||||
/// This file contains a MessagePack writer.
|
||||
///
|
||||
/// See https://github.com/msgpack/msgpack/blob/master/spec.md for the full
|
||||
/// specification.
|
||||
///
|
||||
/// Typical usage:
|
||||
/// \code
|
||||
/// raw_ostream output = GetOutputStream();
|
||||
/// msgpack::Writer MPWriter(output);
|
||||
/// MPWriter.writeNil();
|
||||
/// MPWriter.write(false);
|
||||
/// MPWriter.write("string");
|
||||
/// // ...
|
||||
/// \endcode
|
||||
///
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_SUPPORT_MSGPACKPARSER_H
|
||||
#define LLVM_SUPPORT_MSGPACKPARSER_H
|
||||
|
||||
#include "llvm/BinaryFormat/MsgPack.h"
|
||||
#include "llvm/Support/EndianStream.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace msgpack {
|
||||
|
||||
/// Writes MessagePack objects to an output stream, one at a time.
|
||||
class Writer {
|
||||
public:
|
||||
/// Construct a writer, optionally enabling "Compatibility Mode" as defined
|
||||
/// in the MessagePack specification.
|
||||
///
|
||||
/// When in \p Compatible mode, the writer will write \c Str16 formats
|
||||
/// instead of \c Str8 formats, and will refuse to write any \c Bin formats.
|
||||
///
|
||||
/// \param OS stream to output MessagePack objects to.
|
||||
/// \param Compatible when set, write in "Compatibility Mode".
|
||||
Writer(raw_ostream &OS, bool Compatible = false);
|
||||
|
||||
Writer(const Writer &) = delete;
|
||||
Writer &operator=(const Writer &) = delete;
|
||||
|
||||
/// Write a \em Nil to the output stream.
|
||||
///
|
||||
/// The output will be the \em nil format.
|
||||
void writeNil();
|
||||
|
||||
/// Write a \em Boolean to the output stream.
|
||||
///
|
||||
/// The output will be a \em bool format.
|
||||
void write(bool b);
|
||||
|
||||
/// Write a signed integer to the output stream.
|
||||
///
|
||||
/// The output will be in the smallest possible \em int format.
|
||||
///
|
||||
/// The format chosen may be for an unsigned integer.
|
||||
void write(int64_t i);
|
||||
|
||||
/// Write an unsigned integer to the output stream.
|
||||
///
|
||||
/// The output will be in the smallest possible \em int format.
|
||||
void write(uint64_t u);
|
||||
|
||||
/// Write a floating point number to the output stream.
|
||||
///
|
||||
/// The output will be in the smallest possible \em float format.
|
||||
void write(double d);
|
||||
|
||||
/// Write a string to the output stream.
|
||||
///
|
||||
/// The output will be in the smallest possible \em str format.
|
||||
void write(StringRef s);
|
||||
|
||||
/// Write a memory buffer to the output stream.
|
||||
///
|
||||
/// The output will be in the smallest possible \em bin format.
|
||||
///
|
||||
/// \warning Do not use this overload if in \c Compatible mode.
|
||||
void write(MemoryBufferRef Buffer);
|
||||
|
||||
/// Write the header for an \em Array of the given size.
|
||||
///
|
||||
/// The output will be in the smallest possible \em array format.
|
||||
//
|
||||
/// The header contains an identifier for the \em array format used, as well
|
||||
/// as an encoding of the size of the array.
|
||||
///
|
||||
/// N.B. The caller must subsequently call \c Write an additional \p Size
|
||||
/// times to complete the array.
|
||||
void writeArraySize(uint32_t Size);
|
||||
|
||||
/// Write the header for a \em Map of the given size.
|
||||
///
|
||||
/// The output will be in the smallest possible \em map format.
|
||||
//
|
||||
/// The header contains an identifier for the \em map format used, as well
|
||||
/// as an encoding of the size of the map.
|
||||
///
|
||||
/// N.B. The caller must subsequently call \c Write and additional \c Size*2
|
||||
/// times to complete the map. Each even numbered call to \c Write defines a
|
||||
/// new key, and each odd numbered call defines the previous key's value.
|
||||
void writeMapSize(uint32_t Size);
|
||||
|
||||
/// Write a typed memory buffer (an extension type) to the output stream.
|
||||
///
|
||||
/// The output will be in the smallest possible \em ext format.
|
||||
void writeExt(int8_t Type, MemoryBufferRef Buffer);
|
||||
|
||||
private:
|
||||
support::endian::Writer EW;
|
||||
bool Compatible;
|
||||
};
|
||||
|
||||
} // end namespace msgpack
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_SUPPORT_MSGPACKPARSER_H
|
||||
|
|
@ -16,6 +16,7 @@
|
|||
#define LLVM_BINARYFORMAT_WASM_H
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace wasm {
|
||||
|
|
@ -25,7 +26,7 @@ const char WasmMagic[] = {'\0', 'a', 's', 'm'};
|
|||
// Wasm binary format version
|
||||
const uint32_t WasmVersion = 0x1;
|
||||
// Wasm linking metadata version
|
||||
const uint32_t WasmMetadataVersion = 0x1;
|
||||
const uint32_t WasmMetadataVersion = 0x2;
|
||||
// Wasm uses a 64k page size
|
||||
const uint32_t WasmPageSize = 65536;
|
||||
|
||||
|
|
@ -34,9 +35,12 @@ struct WasmObjectHeader {
|
|||
uint32_t Version;
|
||||
};
|
||||
|
||||
struct WasmSignature {
|
||||
std::vector<uint8_t> ParamTypes;
|
||||
uint8_t ReturnType;
|
||||
struct WasmDylinkInfo {
|
||||
uint32_t MemorySize; // Memory size in bytes
|
||||
uint32_t MemoryAlignment; // P2 alignment of memory
|
||||
uint32_t TableSize; // Table size in elements
|
||||
uint32_t TableAlignment; // P2 alignment of table
|
||||
std::vector<StringRef> Needed; // Shared library depenedencies
|
||||
};
|
||||
|
||||
struct WasmExport {
|
||||
|
|
@ -79,6 +83,18 @@ struct WasmGlobal {
|
|||
StringRef SymbolName; // from the "linking" section
|
||||
};
|
||||
|
||||
struct WasmEventType {
|
||||
// Kind of event. Currently only WASM_EVENT_ATTRIBUTE_EXCEPTION is possible.
|
||||
uint32_t Attribute;
|
||||
uint32_t SigIndex;
|
||||
};
|
||||
|
||||
struct WasmEvent {
|
||||
uint32_t Index;
|
||||
WasmEventType Type;
|
||||
StringRef SymbolName; // from the "linking" section
|
||||
};
|
||||
|
||||
struct WasmImport {
|
||||
StringRef Module;
|
||||
StringRef Field;
|
||||
|
|
@ -88,6 +104,7 @@ struct WasmImport {
|
|||
WasmGlobalType Global;
|
||||
WasmTable Table;
|
||||
WasmLimits Memory;
|
||||
WasmEventType Event;
|
||||
};
|
||||
};
|
||||
|
||||
|
|
@ -104,8 +121,8 @@ struct WasmFunction {
|
|||
uint32_t Size;
|
||||
uint32_t CodeOffset; // start of Locals and Body
|
||||
StringRef SymbolName; // from the "linking" section
|
||||
StringRef DebugName; // from the "name" section
|
||||
uint32_t Comdat; // from the "comdat info" section
|
||||
StringRef DebugName; // from the "name" section
|
||||
uint32_t Comdat; // from the "comdat info" section
|
||||
};
|
||||
|
||||
struct WasmDataSegment {
|
||||
|
|
@ -171,18 +188,20 @@ struct WasmLinkingData {
|
|||
};
|
||||
|
||||
enum : unsigned {
|
||||
WASM_SEC_CUSTOM = 0, // Custom / User-defined section
|
||||
WASM_SEC_TYPE = 1, // Function signature declarations
|
||||
WASM_SEC_IMPORT = 2, // Import declarations
|
||||
WASM_SEC_FUNCTION = 3, // Function declarations
|
||||
WASM_SEC_TABLE = 4, // Indirect function table and other tables
|
||||
WASM_SEC_MEMORY = 5, // Memory attributes
|
||||
WASM_SEC_GLOBAL = 6, // Global declarations
|
||||
WASM_SEC_EXPORT = 7, // Exports
|
||||
WASM_SEC_START = 8, // Start function declaration
|
||||
WASM_SEC_ELEM = 9, // Elements section
|
||||
WASM_SEC_CODE = 10, // Function bodies (code)
|
||||
WASM_SEC_DATA = 11 // Data segments
|
||||
WASM_SEC_CUSTOM = 0, // Custom / User-defined section
|
||||
WASM_SEC_TYPE = 1, // Function signature declarations
|
||||
WASM_SEC_IMPORT = 2, // Import declarations
|
||||
WASM_SEC_FUNCTION = 3, // Function declarations
|
||||
WASM_SEC_TABLE = 4, // Indirect function table and other tables
|
||||
WASM_SEC_MEMORY = 5, // Memory attributes
|
||||
WASM_SEC_GLOBAL = 6, // Global declarations
|
||||
WASM_SEC_EXPORT = 7, // Exports
|
||||
WASM_SEC_START = 8, // Start function declaration
|
||||
WASM_SEC_ELEM = 9, // Elements section
|
||||
WASM_SEC_CODE = 10, // Function bodies (code)
|
||||
WASM_SEC_DATA = 11, // Data segments
|
||||
WASM_SEC_DATACOUNT = 12, // Data segment count
|
||||
WASM_SEC_EVENT = 13 // Event declarations
|
||||
};
|
||||
|
||||
// Type immediate encodings used in various contexts.
|
||||
|
|
@ -191,7 +210,8 @@ enum : unsigned {
|
|||
WASM_TYPE_I64 = 0x7E,
|
||||
WASM_TYPE_F32 = 0x7D,
|
||||
WASM_TYPE_F64 = 0x7C,
|
||||
WASM_TYPE_ANYFUNC = 0x70,
|
||||
WASM_TYPE_V128 = 0x7B,
|
||||
WASM_TYPE_FUNCREF = 0x70,
|
||||
WASM_TYPE_EXCEPT_REF = 0x68,
|
||||
WASM_TYPE_FUNC = 0x60,
|
||||
WASM_TYPE_NORESULT = 0x40, // for blocks with no result values
|
||||
|
|
@ -203,12 +223,13 @@ enum : unsigned {
|
|||
WASM_EXTERNAL_TABLE = 0x1,
|
||||
WASM_EXTERNAL_MEMORY = 0x2,
|
||||
WASM_EXTERNAL_GLOBAL = 0x3,
|
||||
WASM_EXTERNAL_EVENT = 0x4,
|
||||
};
|
||||
|
||||
// Opcodes used in initializer expressions.
|
||||
enum : unsigned {
|
||||
WASM_OPCODE_END = 0x0b,
|
||||
WASM_OPCODE_GET_GLOBAL = 0x23,
|
||||
WASM_OPCODE_GLOBAL_GET = 0x23,
|
||||
WASM_OPCODE_I32_CONST = 0x41,
|
||||
WASM_OPCODE_I64_CONST = 0x42,
|
||||
WASM_OPCODE_F32_CONST = 0x43,
|
||||
|
|
@ -217,35 +238,27 @@ enum : unsigned {
|
|||
|
||||
enum : unsigned {
|
||||
WASM_LIMITS_FLAG_HAS_MAX = 0x1,
|
||||
};
|
||||
|
||||
// Subset of types that a value can have
|
||||
enum class ValType {
|
||||
I32 = WASM_TYPE_I32,
|
||||
I64 = WASM_TYPE_I64,
|
||||
F32 = WASM_TYPE_F32,
|
||||
F64 = WASM_TYPE_F64,
|
||||
EXCEPT_REF = WASM_TYPE_EXCEPT_REF,
|
||||
WASM_LIMITS_FLAG_IS_SHARED = 0x2,
|
||||
};
|
||||
|
||||
// Kind codes used in the custom "name" section
|
||||
enum : unsigned {
|
||||
WASM_NAMES_FUNCTION = 0x1,
|
||||
WASM_NAMES_LOCAL = 0x2,
|
||||
WASM_NAMES_LOCAL = 0x2,
|
||||
};
|
||||
|
||||
// Kind codes used in the custom "linking" section
|
||||
enum : unsigned {
|
||||
WASM_SEGMENT_INFO = 0x5,
|
||||
WASM_INIT_FUNCS = 0x6,
|
||||
WASM_COMDAT_INFO = 0x7,
|
||||
WASM_SYMBOL_TABLE = 0x8,
|
||||
WASM_SEGMENT_INFO = 0x5,
|
||||
WASM_INIT_FUNCS = 0x6,
|
||||
WASM_COMDAT_INFO = 0x7,
|
||||
WASM_SYMBOL_TABLE = 0x8,
|
||||
};
|
||||
|
||||
// Kind codes used in the custom "linking" section in the WASM_COMDAT_INFO
|
||||
enum : unsigned {
|
||||
WASM_COMDAT_DATA = 0x0,
|
||||
WASM_COMDAT_FUNCTION = 0x1,
|
||||
WASM_COMDAT_DATA = 0x0,
|
||||
WASM_COMDAT_FUNCTION = 0x1,
|
||||
};
|
||||
|
||||
// Kind codes used in the custom "linking" section in the WASM_SYMBOL_TABLE
|
||||
|
|
@ -254,17 +267,23 @@ enum WasmSymbolType : unsigned {
|
|||
WASM_SYMBOL_TYPE_DATA = 0x1,
|
||||
WASM_SYMBOL_TYPE_GLOBAL = 0x2,
|
||||
WASM_SYMBOL_TYPE_SECTION = 0x3,
|
||||
WASM_SYMBOL_TYPE_EVENT = 0x4,
|
||||
};
|
||||
|
||||
const unsigned WASM_SYMBOL_BINDING_MASK = 0x3;
|
||||
const unsigned WASM_SYMBOL_VISIBILITY_MASK = 0xc;
|
||||
// Kinds of event attributes.
|
||||
enum WasmEventAttribute : unsigned {
|
||||
WASM_EVENT_ATTRIBUTE_EXCEPTION = 0x0,
|
||||
};
|
||||
|
||||
const unsigned WASM_SYMBOL_BINDING_GLOBAL = 0x0;
|
||||
const unsigned WASM_SYMBOL_BINDING_WEAK = 0x1;
|
||||
const unsigned WASM_SYMBOL_BINDING_LOCAL = 0x2;
|
||||
const unsigned WASM_SYMBOL_BINDING_MASK = 0x3;
|
||||
const unsigned WASM_SYMBOL_VISIBILITY_MASK = 0xc;
|
||||
|
||||
const unsigned WASM_SYMBOL_BINDING_GLOBAL = 0x0;
|
||||
const unsigned WASM_SYMBOL_BINDING_WEAK = 0x1;
|
||||
const unsigned WASM_SYMBOL_BINDING_LOCAL = 0x2;
|
||||
const unsigned WASM_SYMBOL_VISIBILITY_DEFAULT = 0x0;
|
||||
const unsigned WASM_SYMBOL_VISIBILITY_HIDDEN = 0x4;
|
||||
const unsigned WASM_SYMBOL_UNDEFINED = 0x10;
|
||||
const unsigned WASM_SYMBOL_VISIBILITY_HIDDEN = 0x4;
|
||||
const unsigned WASM_SYMBOL_UNDEFINED = 0x10;
|
||||
|
||||
#define WASM_RELOC(name, value) name = value,
|
||||
|
||||
|
|
@ -274,9 +293,32 @@ enum : unsigned {
|
|||
|
||||
#undef WASM_RELOC
|
||||
|
||||
// Subset of types that a value can have
|
||||
enum class ValType {
|
||||
I32 = WASM_TYPE_I32,
|
||||
I64 = WASM_TYPE_I64,
|
||||
F32 = WASM_TYPE_F32,
|
||||
F64 = WASM_TYPE_F64,
|
||||
V128 = WASM_TYPE_V128,
|
||||
EXCEPT_REF = WASM_TYPE_EXCEPT_REF,
|
||||
};
|
||||
|
||||
struct WasmSignature {
|
||||
SmallVector<wasm::ValType, 1> Returns;
|
||||
SmallVector<wasm::ValType, 4> Params;
|
||||
// Support empty and tombstone instances, needed by DenseMap.
|
||||
enum { Plain, Empty, Tombstone } State = Plain;
|
||||
|
||||
WasmSignature(SmallVector<wasm::ValType, 1> &&InReturns,
|
||||
SmallVector<wasm::ValType, 4> &&InParams)
|
||||
: Returns(InReturns), Params(InParams) {}
|
||||
WasmSignature() = default;
|
||||
};
|
||||
|
||||
// Useful comparison operators
|
||||
inline bool operator==(const WasmSignature &LHS, const WasmSignature &RHS) {
|
||||
return LHS.ReturnType == RHS.ReturnType && LHS.ParamTypes == RHS.ParamTypes;
|
||||
return LHS.State == RHS.State && LHS.Returns == RHS.Returns &&
|
||||
LHS.Params == RHS.Params;
|
||||
}
|
||||
|
||||
inline bool operator!=(const WasmSignature &LHS, const WasmSignature &RHS) {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
#ifndef WASM_RELOC
|
||||
#error "WASM_RELOC must be defined"
|
||||
#endif
|
||||
|
|
@ -13,3 +12,4 @@ WASM_RELOC(R_WEBASSEMBLY_TYPE_INDEX_LEB, 6)
|
|||
WASM_RELOC(R_WEBASSEMBLY_GLOBAL_INDEX_LEB, 7)
|
||||
WASM_RELOC(R_WEBASSEMBLY_FUNCTION_OFFSET_I32, 8)
|
||||
WASM_RELOC(R_WEBASSEMBLY_SECTION_OFFSET_I32, 9)
|
||||
WASM_RELOC(R_WEBASSEMBLY_EVENT_INDEX_LEB, 10)
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ class Module;
|
|||
struct BitcodeLTOInfo {
|
||||
bool IsThinLTO;
|
||||
bool HasSummary;
|
||||
bool EnableSplitLTOUnit;
|
||||
};
|
||||
|
||||
/// Represents a module in a bitcode file.
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue