Reactor: Implement debug info generation
Currently only works on Linux + GDB.
See docs/ReactorDebugInfo.md for details.
Change-Id: I73d47d0492f6ccfc07eec4d4084332b4991fd515
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/27949
Presubmit-Ready: Ben Clayton <bclayton@google.com>
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
Tested-by: Ben Clayton <bclayton@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
diff --git a/CMakeLists.txt b/CMakeLists.txt
index a07454a..9bd3a17 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -81,6 +81,7 @@
option (UBSAN "Build with undefined behavior sanitizer" 0)
option (WARNINGS_AS_ERRORS "Treat all warnings as errors" 1)
option (DCHECK_ALWAYS_ON "Check validation macros even in release builds" 0)
+option (REACTOR_EMIT_DEBUG_INFO "Emit debug info for JIT functions" 0)
if(ARCH STREQUAL "arm")
set(DEFAULT_REACTOR_BACKEND "Subzero")
@@ -205,6 +206,9 @@
set(LLVM_DIR ${CMAKE_CURRENT_SOURCE_DIR}/third_party/llvm-7.0/llvm)
set(LLVM_CONFIG_DIR ${CMAKE_CURRENT_SOURCE_DIR}/third_party/llvm-7.0/configs)
endif()
+set(LIBBACKTRACE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/third_party/libbacktrace/src)
+set(LIBBACKTRACE_CONFIG_DIR ${CMAKE_CURRENT_SOURCE_DIR}/third_party/libbacktrace/config)
+set(LIBBACKTRACE_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/third_party/libbacktrace/src)
set(SUBZERO_DIR ${CMAKE_CURRENT_SOURCE_DIR}/third_party/subzero)
set(SUBZERO_LLVM_DIR ${CMAKE_CURRENT_SOURCE_DIR}/third_party/llvm-subzero)
set(TESTS_DIR ${CMAKE_CURRENT_SOURCE_DIR}/tests)
@@ -293,6 +297,10 @@
set_cpp_flag("-DDCHECK_ALWAYS_ON")
endif()
+ if(REACTOR_EMIT_DEBUG_INFO)
+ set_cpp_flag("-DENABLE_RR_DEBUG_INFO")
+ endif()
+
# Disable pedanitc warnings
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
set_cpp_flag("-Wno-ignored-attributes") # ignoring attributes on template argument 'X'
@@ -1762,18 +1770,28 @@
${LLVM_DIR}/lib/Target/ARM/ARMLegalizerInfo.cpp
${LLVM_DIR}/lib/Target/ARM/ARMOptimizeBarriersPass.cpp
)
- endif()
+endif()
+
+if(REACTOR_EMIT_DEBUG_INFO)
+ list(APPEND LLVM_LIST
+ ${LLVM_DIR}/lib/Demangle/ItaniumDemangle.cpp
+ )
+endif(REACTOR_EMIT_DEBUG_INFO)
set(LLVM_INCLUDE_DIR "")
if(WIN32)
list(APPEND LLVM_INCLUDE_DIR ${LLVM_CONFIG_DIR}/windows/include)
+ list(APPEND LIBBACKTRACE_INCLUDE_DIR ${LIBBACKTRACE_CONFIG_DIR}/windows/include)
elseif(LINUX)
list(APPEND LLVM_INCLUDE_DIR ${LLVM_CONFIG_DIR}/linux/include)
+ list(APPEND LIBBACKTRACE_INCLUDE_DIR ${LIBBACKTRACE_CONFIG_DIR}/linux/include)
elseif(APPLE)
list(APPEND LLVM_INCLUDE_DIR ${LLVM_CONFIG_DIR}/darwin/include)
+ list(APPEND LIBBACKTRACE_INCLUDE_DIR ${LIBBACKTRACE_CONFIG_DIR}/darwin/include)
elseif(ANDROID)
list(APPEND LLVM_INCLUDE_DIR ${LLVM_CONFIG_DIR}/android/include)
+ list(APPEND LIBBACKTRACE_INCLUDE_DIR ${LIBBACKTRACE_CONFIG_DIR}/android/include)
endif()
list(APPEND LLVM_INCLUDE_DIR
@@ -1962,6 +1980,7 @@
${SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/include
${LLVM_INCLUDE_DIR}
+ ${LIBBACKTRACE_INCLUDE_DIR}
)
set(OPENGL_INCLUDE_DIR
${OPENGL_DIR}
@@ -2002,9 +2021,41 @@
${SOURCE_DIR}/Common/GrallocAndroid.hpp
)
+if(REACTOR_EMIT_DEBUG_INFO)
+ set(LIBBACKTRACE_LIST
+ ${LIBBACKTRACE_DIR}/atomic.c
+ ${LIBBACKTRACE_DIR}/backtrace.c
+ ${LIBBACKTRACE_DIR}/backtrace.h
+ ${LIBBACKTRACE_DIR}/dwarf.c
+ ${LIBBACKTRACE_DIR}/fileline.c
+ ${LIBBACKTRACE_DIR}/filenames.h
+ ${LIBBACKTRACE_DIR}/internal.h
+ ${LIBBACKTRACE_DIR}/mmap.c
+ ${LIBBACKTRACE_DIR}/mmapio.c
+ ${LIBBACKTRACE_DIR}/posix.c
+ ${LIBBACKTRACE_DIR}/print.c
+ ${LIBBACKTRACE_DIR}/simple.c
+ ${LIBBACKTRACE_DIR}/sort.c
+ ${LIBBACKTRACE_DIR}/state.c
+ ${LIBBACKTRACE_INCLUDE_DIR}/backtrace-supported.h
+ ${LIBBACKTRACE_INCLUDE_DIR}/config.h
+ )
+
+ if(WIN32)
+ list(APPEND LIBBACKTRACE_LIST ${LIBBACKTRACE_DIR}/pecoff.c)
+ elseif(LINUX)
+ list(APPEND LIBBACKTRACE_LIST ${LIBBACKTRACE_DIR}/elf.c)
+ elseif(APPLE)
+ message(FATAL_ERROR "libbacktrace does not support mach-o yet")
+ endif()
+endif(REACTOR_EMIT_DEBUG_INFO)
+
set(REACTOR_LLVM_LIST
${SOURCE_DIR}/Reactor/Reactor.cpp
${SOURCE_DIR}/Reactor/LLVMReactor.cpp
+ ${SOURCE_DIR}/Reactor/LLVMReactor.hpp
+ ${SOURCE_DIR}/Reactor/LLVMReactorDebugInfo.cpp
+ ${SOURCE_DIR}/Reactor/LLVMReactorDebugInfo.hpp
${SOURCE_DIR}/Reactor/Nucleus.hpp
${SOURCE_DIR}/Reactor/Routine.cpp
${SOURCE_DIR}/Reactor/Routine.hpp
@@ -2202,6 +2253,17 @@
)
target_link_libraries(ReactorLLVM llvm ${OS_LIBS})
+if(REACTOR_EMIT_DEBUG_INFO)
+ add_library(Libbacktrace STATIC ${LIBBACKTRACE_LIST})
+ set_target_properties(Libbacktrace PROPERTIES
+ INCLUDE_DIRECTORIES "${LIBBACKTRACE_INCLUDE_DIR}"
+ POSITION_INDEPENDENT_CODE 1
+ FOLDER "Core"
+ )
+ target_link_libraries(Libbacktrace ${OS_LIBS})
+ target_link_libraries(ReactorLLVM Libbacktrace)
+endif(REACTOR_EMIT_DEBUG_INFO)
+
if(${REACTOR_BACKEND} STREQUAL "LLVM")
set(Reactor ReactorLLVM)
elseif(${REACTOR_BACKEND} STREQUAL "Subzero")
diff --git a/build/Visual Studio 15 2017 Win64/ReactorLLVM.vcxproj b/build/Visual Studio 15 2017 Win64/ReactorLLVM.vcxproj
index 839919d..5371a2e 100644
--- a/build/Visual Studio 15 2017 Win64/ReactorLLVM.vcxproj
+++ b/build/Visual Studio 15 2017 Win64/ReactorLLVM.vcxproj
@@ -122,7 +122,10 @@
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="$(SolutionDir)src\Reactor\Reactor.cpp" />
- <ClCompile Include="$(SolutionDir)src\Reactor\LLVMReactor.cpp" />
+ <ClCompile Include="$(SolutionDir)src\Reactor\LLVMReactor.cpp" />
+ <ClInclude Include="$(SolutionDir)src\Reactor\LLVMReactor.hpp" />
+ <ClCompile Include="$(SolutionDir)src\Reactor\LLVMReactorDebugInfo.cpp" />
+ <ClInclude Include="$(SolutionDir)src\Reactor\LLVMReactorDebugInfo.hpp" />
<ClInclude Include="$(SolutionDir)src\Reactor\Nucleus.hpp" />
<ClCompile Include="$(SolutionDir)src\Reactor\Routine.cpp" />
<ClInclude Include="$(SolutionDir)src\Reactor\Routine.hpp" />
diff --git a/build/Visual Studio 15 2017 Win64/ReactorLLVM.vcxproj.filters b/build/Visual Studio 15 2017 Win64/ReactorLLVM.vcxproj.filters
index 8848ab0..cdd429e 100644
--- a/build/Visual Studio 15 2017 Win64/ReactorLLVM.vcxproj.filters
+++ b/build/Visual Studio 15 2017 Win64/ReactorLLVM.vcxproj.filters
@@ -7,6 +7,9 @@
<ClCompile Include="$(SolutionDir)src\Reactor\LLVMReactor.cpp">
<Filter>src\Reactor</Filter>
</ClCompile>
+ <ClCompile Include="$(SolutionDir)src\Reactor\LLVMReactorDebugInfo.cpp">
+ <Filter>src\Reactor</Filter>
+ </ClCompile>
<ClCompile Include="$(SolutionDir)src\Reactor\Routine.cpp">
<Filter>src\Reactor</Filter>
</ClCompile>
@@ -33,6 +36,12 @@
<ClInclude Include="$(SolutionDir)src\Reactor\Routine.hpp">
<Filter>src\Reactor</Filter>
</ClInclude>
+ <ClInclude Include="$(SolutionDir)src\Reactor\LLVMReactor.hpp">
+ <Filter>src\Reactor</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)src\Reactor\LLVMReactorDebugInfo.hpp">
+ <Filter>src\Reactor</Filter>
+ </ClInclude>
<ClInclude Include="$(SolutionDir)src\Reactor\LLVMRoutine.hpp">
<Filter>src\Reactor</Filter>
</ClInclude>
diff --git a/docs/ReactorDebugInfo.md b/docs/ReactorDebugInfo.md
new file mode 100644
index 0000000..3b612d4
--- /dev/null
+++ b/docs/ReactorDebugInfo.md
@@ -0,0 +1,237 @@
+# Reactor Debug Info Generation
+
+## Introduction
+
+Reactor produces Just In Time compiled dynamic executable code and can be used to JIT high performance functions specialized for runtime
+configurations, or to even build a compiler.
+
+In order to debug executable code at a higher level than disassembly, source code files are required.
+
+Reactor has two potential sources of source code:
+
+1. The C++ source code of the program that calls into Reactor.
+2. External source files read by the program and passed to Reactor.
+
+While case (2) is preferable for implementing a compiler, this is currently not
+implemented.
+
+Reactor implements case (1) and this can be used by GDB to single line step and
+inspect variables.
+
+## Supported Platforms
+
+Currently:
+
+* Debug info generation is only supported on Linux with the LLVM 7
+backend.
+* GDB is the only supported debugger.
+* The program must be compiled with debug info iteself.
+
+## Enabling
+
+Debug generation is enabled with `REACTOR_EMIT_DEBUG_INFO` CMake flag (defaults
+to disabled).
+
+## Implementation details
+
+### Source Location
+
+All Reactor functions begin with a call to `RR_DEBUG_INFO_UPDATE_LOC()`, which calls into `rr::DebugInfo::EmitLocation()`.
+
+`rr::DebugInfo::EmitLocation()` calls `rr::DebugInfo::getCallerBacktrace()`,
+which in turn uses [`libbacktrace`](https://github.com/ianlancetaylor/libbacktrace)
+to unwind the stack and find the file, function and line of the caller.
+
+This information is passed to `llvm::IRBuilder<>::SetCurrentDebugLocation`
+to emit source line information for the next LLVM instructions to be built.
+
+### Variables
+
+There are 3 aspects to generating variable debug information:
+
+#### 1. Variable names
+
+Constructing a Reactor `LValue`:
+
+```C++
+rr::Int a = 1;
+```
+
+Will emit an LLVM `alloca` instruction to allocate the storage of the variable,
+and emit another to initialize it to the constant `1`. While fluent, none of the
+Reactor calls see the name of the C++ local variable "`a`", and the LLVM `alloca`
+value gets a meaningless numerical value.
+
+There are two potential ways that Reactor can obtain the variable name:
+
+1. Use the running executable's own debug information to examine the local
+ declaration and extract the local variable's name.
+2. Use the backtrace information to parse the name from the source file.
+
+While (1) is arguably a cleaner and more robust solution, (2) is
+easier to implement and can work for the majority of use cases.
+
+(2) is the current solution implemented.
+
+`rr::DebugInfo::getOrParseFileTokens()` scans a source file line by line, and
+uses a regular expression to look for patterns of `<type> <name>`. Matching is not
+precise, but is adequate to find locals constructed with and without assignment.
+
+#### 2. Variable binding
+
+Given that we can find a variable name for a given source line, we need a way of
+binding the LLVM values to the name.
+
+Given our trivial example:
+
+```C++
+rr::Int a = 1
+```
+
+The `rr::Int` constructor calls `RR_DEBUG_INFO_EMIT_VAR()` passing the storage
+value as single argument. `RR_DEBUG_INFO_EMIT_VAR()` performs the backtrace
+to find the source file and line and uses the token information produced by
+`rr::DebugInfo::getOrParseFileTokens()` to identify the variable name.
+
+However, things get a bit more complicated when there are multiple variables
+being constructed on the same line.
+
+Take for example:
+
+```C++
+rr::Int a = rr::Int(1) + rr::Int(2)
+```
+
+Here we have 3 calls to the `rr::Int` constructor, each calling down
+to `RR_DEBUG_INFO_EMIT_VAR()`.
+
+To disambiguate which of these should be bound to the variable name "`a`",
+`rr::DebugInfo::EmitVariable()` buffers the binding into
+`scope.pending` and the last binding for a given line is used by
+`DebugInfo::emitPending()`. For variable construction and assignment, C++
+guarantees that the LHS is the last value to be constructed.
+
+This solution is not perfect.
+
+Multi-line expressions, multiple assignments on a single line, macro obfuscation
+can all break variable bindings - however the majority of typical cases work.
+
+#### 3. Variable scope
+
+`rr::DebugInfo` maintains a stack of `llvm::DIScope`s and `llvm::DILocation`s
+that mirrors the current backtrace for function being called.
+
+A synthetic call stack is produced by chaining `llvm::DILocation`s with
+`InlinedAt`s.
+
+For example, at the declaration of `i`:
+
+```C++
+void B()
+{
+ rr::Int i; // <- here
+}
+
+void A()
+{
+ B();
+}
+
+int main(int argc, const char* argv[])
+{
+ A();
+}
+```
+
+The `DIScope` hierarchy would be:
+
+```C++
+ DIFile: "foo.cpp"
+rr::DebugInfo::diScope[0].di: ↳ DISubprogram: "main"
+rr::DebugInfo::diScope[1].di: ↳ DISubprogram: "A"
+rr::DebugInfo::diScope[2].di: ↳ DISubprogram: "B"
+```
+
+The `DILocation` hierarchy would be:
+
+```C++
+rr::DebugInfo::diRootLocation: DILocation(DISubprogram: "ReactorFunction")
+rr::DebugInfo::diScope[0].location: ↳ DILocation(DISubprogram: "main")
+rr::DebugInfo::diScope[1].location: ↳ DILocation(DISubprogram: "A")
+rr::DebugInfo::diScope[2].location: ↳ DILocation(DISubprogram: "B")
+```
+
+Where '↳' represents an `InlinedAt`.
+
+
+`rr::DebugInfo::diScope` is updated by `rr::DebugInfo::syncScope()`.
+
+`llvm::DIScope`s typically do not nest - there is usually a separate
+`llvm::DISubprogram` for each function in the callstack. All local variables
+within a function will typically share the same scope, regardless of whether
+they are declared within a sub-block.
+
+Loops and jumps within a function add complexity. Consider:
+
+```C++
+void B()
+{
+ rr::Int i = 0;
+}
+
+void A()
+{
+ for (int i = 0; i < 3; i++)
+ {
+ rr::Int x = 0;
+ }
+ B();
+}
+
+int main(int argc, const char* argv[])
+{
+ A();
+}
+```
+
+In this particular example Reactor will not be aware of the `for` loop, and will
+attempt to create three variables called "`x`" in the same function scope for `A()`.
+Duplicate symbols in the same `llvm::DIScope` result in undefined behavior.
+
+To solve this, `rr::DebugInfo::syncScope()` observes when a function jumps
+backwards, and forks the current `llvm::DILexicalBlock` for the function. This
+results in a number of `llvm::DILexicalBlock` chains, each declaring variables
+that shadow the previous block.
+
+At the declaration of `i`, the `DIScope` hierarchy would be:
+
+```C++
+ DIFile: "foo.cpp"
+rr::DebugInfo::diScope[0].di: ↳ DISubprogram: "main"
+ ↳ DISubprogram: "A"
+ | ↳ DILexicalBlock: "A".1
+rr::DebugInfo::diScope[1].di: | ↳ DILexicalBlock: "A".2
+rr::DebugInfo::diScope[2].di: ↳ DISubprogram: "B"
+```
+
+The `DILocation` hierarchy would be:
+
+```C++
+rr::DebugInfo::diRootLocation: DILocation(DISubprogram: "ReactorFunction")
+rr::DebugInfo::diScope[0].location: ↳ DILocation(DISubprogram: "main")
+rr::DebugInfo::diScope[1].location: ↳ DILocation(DILexicalBlock: "A".2)
+rr::DebugInfo::diScope[2].location: ↳ DILocation(DISubprogram: "B")
+```
+
+### Debugger integration
+
+Once the debug information has been generated, it needs to be handed to the
+debugger.
+
+Reactor uses [`llvm::JITEventListener::createGDBRegistrationListener()`](http://llvm.org/doxygen/classllvm_1_1JITEventListener.html#a004abbb5a0d48ac376dfbe3e3c97c306)
+to inform GDB of the JIT'd program and its debugging information.
+More information [can be found here](https://llvm.org/docs/DebuggingJITedCode.html).
+
+LLDB should be able to support this same mechanism, but at the time of writing
+this does not appear to work.
+
diff --git a/src/Reactor/LLVMReactor.cpp b/src/Reactor/LLVMReactor.cpp
index 9c453b7..6c30207 100644
--- a/src/Reactor/LLVMReactor.cpp
+++ b/src/Reactor/LLVMReactor.cpp
@@ -14,6 +14,8 @@
#include "Reactor.hpp"
#include "Debug.hpp"
+#include "LLVMReactor.hpp"
+#include "LLVMReactorDebugInfo.hpp"
#include "x86.hpp"
#include "CPUID.hpp"
@@ -117,6 +119,10 @@
llvm::Module *module = nullptr;
llvm::Function *function = nullptr;
+#ifdef ENABLE_RR_DEBUG_INFO
+ std::unique_ptr<rr::DebugInfo> debugInfo;
+#endif
+
rr::MutexLock codegenMutex;
#ifdef ENABLE_RR_PRINT
@@ -555,6 +561,9 @@
public:
ExternalFunctionSymbolResolver()
{
+ struct F { static void nop() {} };
+ func_.emplace("nop", reinterpret_cast<void*>(F::nop));
+
func_.emplace("floorf", reinterpret_cast<void*>(floorf));
func_.emplace("nearbyintf", reinterpret_cast<void*>(nearbyintf));
func_.emplace("truncf", reinterpret_cast<void*>(truncf));
@@ -639,6 +648,9 @@
}
})),
targetMachine(llvm::EngineBuilder()
+#ifdef ENABLE_RR_DEBUG_INFO
+ .setOptLevel(llvm::CodeGenOpt::None)
+#endif // ENABLE_RR_DEBUG_INFO
.setMArch(arch)
.setMAttrs(mattrs)
.setTargetOptions(targetOpts)
@@ -650,7 +662,25 @@
return ObjLayer::Resources{
std::make_shared<llvm::SectionMemoryManager>(),
resolver};
- }),
+ },
+ ObjLayer::NotifyLoadedFtor(),
+ [](llvm::orc::VModuleKey, const llvm::object::ObjectFile &Obj, const llvm::RuntimeDyld::LoadedObjectInfo &L) {
+#ifdef ENABLE_RR_DEBUG_INFO
+ if (debugInfo != nullptr)
+ {
+ debugInfo->NotifyObjectEmitted(Obj, L);
+ }
+#endif // ENABLE_RR_DEBUG_INFO
+ },
+ [](llvm::orc::VModuleKey, const llvm::object::ObjectFile &Obj) {
+#ifdef ENABLE_RR_DEBUG_INFO
+ if (debugInfo != nullptr)
+ {
+ debugInfo->NotifyFreeingObject(Obj);
+ }
+#endif // ENABLE_RR_DEBUG_INFO
+ }
+ ),
compileLayer(objLayer, llvm::orc::SimpleCompiler(*targetMachine)),
emittedFunctionsNum(0)
{
@@ -701,6 +731,13 @@
void optimize(llvm::Module *module)
{
+#ifdef ENABLE_RR_DEBUG_INFO
+ if (debugInfo != nullptr)
+ {
+ return; // Don't optimize if we're generating debug info.
+ }
+#endif // ENABLE_RR_DEBUG_INFO
+
std::unique_ptr<llvm::legacy::PassManager> passManager(
new llvm::legacy::PassManager());
@@ -787,26 +824,11 @@
}
}
- inline Type *T(llvm::Type *t)
- {
- return reinterpret_cast<Type*>(t);
- }
-
Type *T(InternalType t)
{
return reinterpret_cast<Type*>(t);
}
- inline llvm::Value *V(Value *t)
- {
- return reinterpret_cast<llvm::Value*>(t);
- }
-
- inline Value *V(llvm::Value *t)
- {
- return reinterpret_cast<Value*>(t);
- }
-
inline std::vector<llvm::Type*> &T(std::vector<Type*> &t)
{
return reinterpret_cast<std::vector<llvm::Type*>&>(t);
@@ -1038,6 +1060,13 @@
::module->print(file, 0);
}
+#ifdef ENABLE_RR_DEBUG_INFO
+ if (debugInfo != nullptr)
+ {
+ debugInfo->Finalize();
+ }
+#endif // ENABLE_RR_DEBUG_INFO
+
LLVMRoutine *routine = ::reactorJIT->acquireRoutine(::function);
return routine;
@@ -1113,6 +1142,10 @@
::function->addFnAttr("stack-probe-size", "1048576");
#endif
+#ifdef ENABLE_RR_DEBUG_INFO
+ ::debugInfo = std::unique_ptr<DebugInfo>(new DebugInfo(::builder, ::context, ::module, ::function));
+#endif // ENABLE_RR_DEBUG_INFO
+
::builder->SetInsertPoint(llvm::BasicBlock::Create(*::context, "", ::function));
}
@@ -1131,6 +1164,8 @@
void Nucleus::createRetVoid()
{
+ RR_DEBUG_INFO_UPDATE_LOC();
+
// Code generated after this point is unreachable, so any variables
// being read can safely return an undefined value. We have to avoid
// materializing variables after the terminator ret instruction.
@@ -1141,6 +1176,8 @@
void Nucleus::createRet(Value *v)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
+
// Code generated after this point is unreachable, so any variables
// being read can safely return an undefined value. We have to avoid
// materializing variables after the terminator ret instruction.
@@ -1151,6 +1188,7 @@
void Nucleus::createBr(BasicBlock *dest)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
Variable::materializeAll();
::builder->CreateBr(B(dest));
@@ -1158,118 +1196,140 @@
void Nucleus::createCondBr(Value *cond, BasicBlock *ifTrue, BasicBlock *ifFalse)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
Variable::materializeAll();
-
::builder->CreateCondBr(V(cond), B(ifTrue), B(ifFalse));
}
Value *Nucleus::createAdd(Value *lhs, Value *rhs)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return V(::builder->CreateAdd(V(lhs), V(rhs)));
}
Value *Nucleus::createSub(Value *lhs, Value *rhs)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return V(::builder->CreateSub(V(lhs), V(rhs)));
}
Value *Nucleus::createMul(Value *lhs, Value *rhs)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return V(::builder->CreateMul(V(lhs), V(rhs)));
}
Value *Nucleus::createUDiv(Value *lhs, Value *rhs)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return V(::builder->CreateUDiv(V(lhs), V(rhs)));
}
Value *Nucleus::createSDiv(Value *lhs, Value *rhs)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return V(::builder->CreateSDiv(V(lhs), V(rhs)));
}
Value *Nucleus::createFAdd(Value *lhs, Value *rhs)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return V(::builder->CreateFAdd(V(lhs), V(rhs)));
}
Value *Nucleus::createFSub(Value *lhs, Value *rhs)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return V(::builder->CreateFSub(V(lhs), V(rhs)));
}
Value *Nucleus::createFMul(Value *lhs, Value *rhs)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return V(::builder->CreateFMul(V(lhs), V(rhs)));
}
Value *Nucleus::createFDiv(Value *lhs, Value *rhs)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return V(::builder->CreateFDiv(V(lhs), V(rhs)));
}
Value *Nucleus::createURem(Value *lhs, Value *rhs)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return V(::builder->CreateURem(V(lhs), V(rhs)));
}
Value *Nucleus::createSRem(Value *lhs, Value *rhs)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return V(::builder->CreateSRem(V(lhs), V(rhs)));
}
Value *Nucleus::createFRem(Value *lhs, Value *rhs)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return V(::builder->CreateFRem(V(lhs), V(rhs)));
}
Value *Nucleus::createShl(Value *lhs, Value *rhs)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return V(::builder->CreateShl(V(lhs), V(rhs)));
}
Value *Nucleus::createLShr(Value *lhs, Value *rhs)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return V(::builder->CreateLShr(V(lhs), V(rhs)));
}
Value *Nucleus::createAShr(Value *lhs, Value *rhs)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return V(::builder->CreateAShr(V(lhs), V(rhs)));
}
Value *Nucleus::createAnd(Value *lhs, Value *rhs)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return V(::builder->CreateAnd(V(lhs), V(rhs)));
}
Value *Nucleus::createOr(Value *lhs, Value *rhs)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return V(::builder->CreateOr(V(lhs), V(rhs)));
}
Value *Nucleus::createXor(Value *lhs, Value *rhs)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return V(::builder->CreateXor(V(lhs), V(rhs)));
}
Value *Nucleus::createNeg(Value *v)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return V(::builder->CreateNeg(V(v)));
}
Value *Nucleus::createFNeg(Value *v)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return V(::builder->CreateFNeg(V(v)));
}
Value *Nucleus::createNot(Value *v)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return V(::builder->CreateNot(V(v)));
}
Value *Nucleus::createLoad(Value *ptr, Type *type, bool isVolatile, unsigned int alignment, bool atomic, std::memory_order memoryOrder)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
switch(asInternalType(type))
{
case Type_v2i32:
@@ -1309,6 +1369,7 @@
Value *Nucleus::createStore(Value *value, Value *ptr, Type *type, bool isVolatile, unsigned int alignment, bool atomic, std::memory_order memoryOrder)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
switch(asInternalType(type))
{
case Type_v2i32:
@@ -1348,8 +1409,8 @@
Value *Nucleus::createGEP(Value *ptr, Type *type, Value *index, bool unsignedIndex)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
ASSERT(V(ptr)->getType()->getContainedType(0) == T(type));
-
if(sizeof(void*) == 8)
{
// LLVM manual: "When indexing into an array, pointer or vector,
@@ -1392,46 +1453,55 @@
Value *Nucleus::createAtomicAdd(Value *ptr, Value *value)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return V(::builder->CreateAtomicRMW(llvm::AtomicRMWInst::Add, V(ptr), V(value), llvm::AtomicOrdering::SequentiallyConsistent));
}
Value *Nucleus::createTrunc(Value *v, Type *destType)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return V(::builder->CreateTrunc(V(v), T(destType)));
}
Value *Nucleus::createZExt(Value *v, Type *destType)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return V(::builder->CreateZExt(V(v), T(destType)));
}
Value *Nucleus::createSExt(Value *v, Type *destType)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return V(::builder->CreateSExt(V(v), T(destType)));
}
Value *Nucleus::createFPToSI(Value *v, Type *destType)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return V(::builder->CreateFPToSI(V(v), T(destType)));
}
Value *Nucleus::createSIToFP(Value *v, Type *destType)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return V(::builder->CreateSIToFP(V(v), T(destType)));
}
Value *Nucleus::createFPTrunc(Value *v, Type *destType)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return V(::builder->CreateFPTrunc(V(v), T(destType)));
}
Value *Nucleus::createFPExt(Value *v, Type *destType)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return V(::builder->CreateFPExt(V(v), T(destType)));
}
Value *Nucleus::createBitCast(Value *v, Type *destType)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
// Bitcasts must be between types of the same logical size. But with emulated narrow vectors we need
// support for casting between scalars and wide vectors. Emulate them by writing to the stack and
// reading back as the destination type.
@@ -1455,137 +1525,165 @@
Value *Nucleus::createICmpEQ(Value *lhs, Value *rhs)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return V(::builder->CreateICmpEQ(V(lhs), V(rhs)));
}
Value *Nucleus::createICmpNE(Value *lhs, Value *rhs)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return V(::builder->CreateICmpNE(V(lhs), V(rhs)));
}
Value *Nucleus::createICmpUGT(Value *lhs, Value *rhs)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return V(::builder->CreateICmpUGT(V(lhs), V(rhs)));
}
Value *Nucleus::createICmpUGE(Value *lhs, Value *rhs)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return V(::builder->CreateICmpUGE(V(lhs), V(rhs)));
}
Value *Nucleus::createICmpULT(Value *lhs, Value *rhs)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return V(::builder->CreateICmpULT(V(lhs), V(rhs)));
}
Value *Nucleus::createICmpULE(Value *lhs, Value *rhs)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return V(::builder->CreateICmpULE(V(lhs), V(rhs)));
}
Value *Nucleus::createICmpSGT(Value *lhs, Value *rhs)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return V(::builder->CreateICmpSGT(V(lhs), V(rhs)));
}
Value *Nucleus::createICmpSGE(Value *lhs, Value *rhs)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return V(::builder->CreateICmpSGE(V(lhs), V(rhs)));
}
Value *Nucleus::createICmpSLT(Value *lhs, Value *rhs)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return V(::builder->CreateICmpSLT(V(lhs), V(rhs)));
}
Value *Nucleus::createICmpSLE(Value *lhs, Value *rhs)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return V(::builder->CreateICmpSLE(V(lhs), V(rhs)));
}
Value *Nucleus::createFCmpOEQ(Value *lhs, Value *rhs)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return V(::builder->CreateFCmpOEQ(V(lhs), V(rhs)));
}
Value *Nucleus::createFCmpOGT(Value *lhs, Value *rhs)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return V(::builder->CreateFCmpOGT(V(lhs), V(rhs)));
}
Value *Nucleus::createFCmpOGE(Value *lhs, Value *rhs)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return V(::builder->CreateFCmpOGE(V(lhs), V(rhs)));
}
Value *Nucleus::createFCmpOLT(Value *lhs, Value *rhs)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return V(::builder->CreateFCmpOLT(V(lhs), V(rhs)));
}
Value *Nucleus::createFCmpOLE(Value *lhs, Value *rhs)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return V(::builder->CreateFCmpOLE(V(lhs), V(rhs)));
}
Value *Nucleus::createFCmpONE(Value *lhs, Value *rhs)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return V(::builder->CreateFCmpONE(V(lhs), V(rhs)));
}
Value *Nucleus::createFCmpORD(Value *lhs, Value *rhs)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return V(::builder->CreateFCmpORD(V(lhs), V(rhs)));
}
Value *Nucleus::createFCmpUNO(Value *lhs, Value *rhs)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return V(::builder->CreateFCmpUNO(V(lhs), V(rhs)));
}
Value *Nucleus::createFCmpUEQ(Value *lhs, Value *rhs)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return V(::builder->CreateFCmpUEQ(V(lhs), V(rhs)));
}
Value *Nucleus::createFCmpUGT(Value *lhs, Value *rhs)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return V(::builder->CreateFCmpUGT(V(lhs), V(rhs)));
}
Value *Nucleus::createFCmpUGE(Value *lhs, Value *rhs)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return V(::builder->CreateFCmpUGE(V(lhs), V(rhs)));
}
Value *Nucleus::createFCmpULT(Value *lhs, Value *rhs)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return V(::builder->CreateFCmpULT(V(lhs), V(rhs)));
}
Value *Nucleus::createFCmpULE(Value *lhs, Value *rhs)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return V(::builder->CreateFCmpULE(V(lhs), V(rhs)));
}
Value *Nucleus::createFCmpUNE(Value *lhs, Value *rhs)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return V(::builder->CreateFCmpUNE(V(lhs), V(rhs)));
}
Value *Nucleus::createExtractElement(Value *vector, Type *type, int index)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
ASSERT(V(vector)->getType()->getContainedType(0) == T(type));
return V(::builder->CreateExtractElement(V(vector), V(createConstantInt(index))));
}
Value *Nucleus::createInsertElement(Value *vector, Value *element, int index)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return V(::builder->CreateInsertElement(V(vector), V(element), V(createConstantInt(index))));
}
Value *Nucleus::createShuffleVector(Value *v1, Value *v2, const int *select)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
+
int size = llvm::cast<llvm::VectorType>(V(v1)->getType())->getNumElements();
const int maxSize = 16;
llvm::Constant *swizzle[maxSize];
@@ -1603,22 +1701,26 @@
Value *Nucleus::createSelect(Value *c, Value *ifTrue, Value *ifFalse)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return V(::builder->CreateSelect(V(c), V(ifTrue), V(ifFalse)));
}
SwitchCases *Nucleus::createSwitch(Value *control, BasicBlock *defaultBranch, unsigned numCases)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return reinterpret_cast<SwitchCases*>(::builder->CreateSwitch(V(control), B(defaultBranch), numCases));
}
void Nucleus::addSwitchCase(SwitchCases *switchCases, int label, BasicBlock *branch)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
llvm::SwitchInst *sw = reinterpret_cast<llvm::SwitchInst *>(switchCases);
sw->addCase(llvm::ConstantInt::get(llvm::Type::getInt32Ty(*::context), label, true), B(branch));
}
void Nucleus::createUnreachable()
{
+ RR_DEBUG_INFO_UPDATE_LOC();
::builder->CreateUnreachable();
}
@@ -1629,56 +1731,67 @@
Value *Nucleus::createNullValue(Type *Ty)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return V(llvm::Constant::getNullValue(T(Ty)));
}
Value *Nucleus::createConstantLong(int64_t i)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return V(llvm::ConstantInt::get(llvm::Type::getInt64Ty(*::context), i, true));
}
Value *Nucleus::createConstantInt(int i)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return V(llvm::ConstantInt::get(llvm::Type::getInt32Ty(*::context), i, true));
}
Value *Nucleus::createConstantInt(unsigned int i)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return V(llvm::ConstantInt::get(llvm::Type::getInt32Ty(*::context), i, false));
}
Value *Nucleus::createConstantBool(bool b)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return V(llvm::ConstantInt::get(llvm::Type::getInt1Ty(*::context), b));
}
Value *Nucleus::createConstantByte(signed char i)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return V(llvm::ConstantInt::get(llvm::Type::getInt8Ty(*::context), i, true));
}
Value *Nucleus::createConstantByte(unsigned char i)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return V(llvm::ConstantInt::get(llvm::Type::getInt8Ty(*::context), i, false));
}
Value *Nucleus::createConstantShort(short i)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return V(llvm::ConstantInt::get(llvm::Type::getInt16Ty(*::context), i, true));
}
Value *Nucleus::createConstantShort(unsigned short i)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return V(llvm::ConstantInt::get(llvm::Type::getInt16Ty(*::context), i, false));
}
Value *Nucleus::createConstantFloat(float x)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return V(llvm::ConstantFP::get(T(Float::getType()), x));
}
Value *Nucleus::createNullPointer(Type *Ty)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return V(llvm::ConstantPointerNull::get(llvm::PointerType::get(T(Ty), 0)));
}
@@ -1756,6 +1869,7 @@
RValue<Byte8> AddSat(RValue<Byte8> x, RValue<Byte8> y)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
#if defined(__i386__) || defined(__x86_64__)
return x86::paddusb(x, y);
#else
@@ -1765,6 +1879,7 @@
RValue<Byte8> SubSat(RValue<Byte8> x, RValue<Byte8> y)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
#if defined(__i386__) || defined(__x86_64__)
return x86::psubusb(x, y);
#else
@@ -1774,6 +1889,7 @@
RValue<Int> SignMask(RValue<Byte8> x)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
#if defined(__i386__) || defined(__x86_64__)
return x86::pmovmskb(x);
#else
@@ -1792,6 +1908,7 @@
RValue<Byte8> CmpEQ(RValue<Byte8> x, RValue<Byte8> y)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
#if defined(__i386__) || defined(__x86_64__)
return x86::pcmpeqb(x, y);
#else
@@ -1806,6 +1923,7 @@
RValue<SByte8> AddSat(RValue<SByte8> x, RValue<SByte8> y)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
#if defined(__i386__) || defined(__x86_64__)
return x86::paddsb(x, y);
#else
@@ -1815,6 +1933,7 @@
RValue<SByte8> SubSat(RValue<SByte8> x, RValue<SByte8> y)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
#if defined(__i386__) || defined(__x86_64__)
return x86::psubsb(x, y);
#else
@@ -1824,6 +1943,7 @@
RValue<Int> SignMask(RValue<SByte8> x)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
#if defined(__i386__) || defined(__x86_64__)
return x86::pmovmskb(As<Byte8>(x));
#else
@@ -1833,6 +1953,7 @@
RValue<Byte8> CmpGT(RValue<SByte8> x, RValue<SByte8> y)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
#if defined(__i386__) || defined(__x86_64__)
return x86::pcmpgtb(x, y);
#else
@@ -1842,6 +1963,7 @@
RValue<Byte8> CmpEQ(RValue<SByte8> x, RValue<SByte8> y)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
#if defined(__i386__) || defined(__x86_64__)
return x86::pcmpeqb(As<Byte8>(x), As<Byte8>(y));
#else
@@ -1876,6 +1998,7 @@
Short4::Short4(RValue<Int4> cast)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
int select[8] = {0, 2, 4, 6, 0, 2, 4, 6};
Value *short8 = Nucleus::createBitCast(cast.value, Short8::getType());
@@ -1891,6 +2014,7 @@
Short4::Short4(RValue<Float4> cast)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
Int4 v4i32 = Int4(cast);
#if defined(__i386__) || defined(__x86_64__)
v4i32 = As<Int4>(x86::packssdw(v4i32, v4i32));
@@ -1904,6 +2028,7 @@
RValue<Short4> operator<<(RValue<Short4> lhs, unsigned char rhs)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
#if defined(__i386__) || defined(__x86_64__)
// return RValue<Short4>(Nucleus::createShl(lhs.value, rhs.value));
@@ -1915,6 +2040,7 @@
RValue<Short4> operator>>(RValue<Short4> lhs, unsigned char rhs)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
#if defined(__i386__) || defined(__x86_64__)
return x86::psraw(lhs, rhs);
#else
@@ -1924,6 +2050,7 @@
RValue<Short4> Max(RValue<Short4> x, RValue<Short4> y)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
#if defined(__i386__) || defined(__x86_64__)
return x86::pmaxsw(x, y);
#else
@@ -1933,6 +2060,7 @@
RValue<Short4> Min(RValue<Short4> x, RValue<Short4> y)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
#if defined(__i386__) || defined(__x86_64__)
return x86::pminsw(x, y);
#else
@@ -1942,6 +2070,7 @@
RValue<Short4> AddSat(RValue<Short4> x, RValue<Short4> y)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
#if defined(__i386__) || defined(__x86_64__)
return x86::paddsw(x, y);
#else
@@ -1951,6 +2080,7 @@
RValue<Short4> SubSat(RValue<Short4> x, RValue<Short4> y)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
#if defined(__i386__) || defined(__x86_64__)
return x86::psubsw(x, y);
#else
@@ -1960,6 +2090,7 @@
RValue<Short4> MulHigh(RValue<Short4> x, RValue<Short4> y)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
#if defined(__i386__) || defined(__x86_64__)
return x86::pmulhw(x, y);
#else
@@ -1969,6 +2100,7 @@
RValue<Int2> MulAdd(RValue<Short4> x, RValue<Short4> y)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
#if defined(__i386__) || defined(__x86_64__)
return x86::pmaddwd(x, y);
#else
@@ -1978,6 +2110,7 @@
RValue<SByte8> PackSigned(RValue<Short4> x, RValue<Short4> y)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
#if defined(__i386__) || defined(__x86_64__)
auto result = x86::packsswb(x, y);
#else
@@ -1988,6 +2121,7 @@
RValue<Byte8> PackUnsigned(RValue<Short4> x, RValue<Short4> y)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
#if defined(__i386__) || defined(__x86_64__)
auto result = x86::packuswb(x, y);
#else
@@ -1998,6 +2132,7 @@
RValue<Short4> CmpGT(RValue<Short4> x, RValue<Short4> y)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
#if defined(__i386__) || defined(__x86_64__)
return x86::pcmpgtw(x, y);
#else
@@ -2007,6 +2142,7 @@
RValue<Short4> CmpEQ(RValue<Short4> x, RValue<Short4> y)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
#if defined(__i386__) || defined(__x86_64__)
return x86::pcmpeqw(x, y);
#else
@@ -2021,6 +2157,7 @@
UShort4::UShort4(RValue<Float4> cast, bool saturate)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
if(saturate)
{
#if defined(__i386__) || defined(__x86_64__)
@@ -2043,6 +2180,7 @@
RValue<UShort4> operator<<(RValue<UShort4> lhs, unsigned char rhs)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
#if defined(__i386__) || defined(__x86_64__)
// return RValue<Short4>(Nucleus::createShl(lhs.value, rhs.value));
@@ -2054,6 +2192,7 @@
RValue<UShort4> operator>>(RValue<UShort4> lhs, unsigned char rhs)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
#if defined(__i386__) || defined(__x86_64__)
// return RValue<Short4>(Nucleus::createLShr(lhs.value, rhs.value));
@@ -2065,16 +2204,19 @@
RValue<UShort4> Max(RValue<UShort4> x, RValue<UShort4> y)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return RValue<UShort4>(Max(As<Short4>(x) - Short4(0x8000u, 0x8000u, 0x8000u, 0x8000u), As<Short4>(y) - Short4(0x8000u, 0x8000u, 0x8000u, 0x8000u)) + Short4(0x8000u, 0x8000u, 0x8000u, 0x8000u));
}
RValue<UShort4> Min(RValue<UShort4> x, RValue<UShort4> y)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return RValue<UShort4>(Min(As<Short4>(x) - Short4(0x8000u, 0x8000u, 0x8000u, 0x8000u), As<Short4>(y) - Short4(0x8000u, 0x8000u, 0x8000u, 0x8000u)) + Short4(0x8000u, 0x8000u, 0x8000u, 0x8000u));
}
RValue<UShort4> AddSat(RValue<UShort4> x, RValue<UShort4> y)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
#if defined(__i386__) || defined(__x86_64__)
return x86::paddusw(x, y);
#else
@@ -2084,6 +2226,7 @@
RValue<UShort4> SubSat(RValue<UShort4> x, RValue<UShort4> y)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
#if defined(__i386__) || defined(__x86_64__)
return x86::psubusw(x, y);
#else
@@ -2093,6 +2236,7 @@
RValue<UShort4> MulHigh(RValue<UShort4> x, RValue<UShort4> y)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
#if defined(__i386__) || defined(__x86_64__)
return x86::pmulhuw(x, y);
#else
@@ -2102,6 +2246,7 @@
RValue<UShort4> Average(RValue<UShort4> x, RValue<UShort4> y)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
#if defined(__i386__) || defined(__x86_64__)
return x86::pavgw(x, y);
#else
@@ -2116,6 +2261,7 @@
RValue<Short8> operator<<(RValue<Short8> lhs, unsigned char rhs)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
#if defined(__i386__) || defined(__x86_64__)
return x86::psllw(lhs, rhs);
#else
@@ -2125,6 +2271,7 @@
RValue<Short8> operator>>(RValue<Short8> lhs, unsigned char rhs)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
#if defined(__i386__) || defined(__x86_64__)
return x86::psraw(lhs, rhs);
#else
@@ -2134,6 +2281,7 @@
RValue<Int4> MulAdd(RValue<Short8> x, RValue<Short8> y)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
#if defined(__i386__) || defined(__x86_64__)
return x86::pmaddwd(x, y);
#else
@@ -2143,6 +2291,7 @@
RValue<Short8> MulHigh(RValue<Short8> x, RValue<Short8> y)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
#if defined(__i386__) || defined(__x86_64__)
return x86::pmulhw(x, y);
#else
@@ -2157,6 +2306,7 @@
RValue<UShort8> operator<<(RValue<UShort8> lhs, unsigned char rhs)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
#if defined(__i386__) || defined(__x86_64__)
return As<UShort8>(x86::psllw(As<Short8>(lhs), rhs));
#else
@@ -2166,6 +2316,7 @@
RValue<UShort8> operator>>(RValue<UShort8> lhs, unsigned char rhs)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
#if defined(__i386__) || defined(__x86_64__)
return x86::psrlw(lhs, rhs); // FIXME: Fallback required
#else
@@ -2175,6 +2326,7 @@
RValue<UShort8> Swizzle(RValue<UShort8> x, char select0, char select1, char select2, char select3, char select4, char select5, char select6, char select7)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
int pshufb[16] =
{
select0 + 0,
@@ -2204,6 +2356,7 @@
RValue<UShort8> MulHigh(RValue<UShort8> x, RValue<UShort8> y)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
#if defined(__i386__) || defined(__x86_64__)
return x86::pmulhuw(x, y);
#else
@@ -2218,6 +2371,7 @@
RValue<Int> operator++(Int &val, int) // Post-increment
{
+ RR_DEBUG_INFO_UPDATE_LOC();
RValue<Int> res = val;
Value *inc = Nucleus::createAdd(res.value, Nucleus::createConstantInt(1));
@@ -2228,6 +2382,7 @@
const Int &operator++(Int &val) // Pre-increment
{
+ RR_DEBUG_INFO_UPDATE_LOC();
Value *inc = Nucleus::createAdd(val.loadValue(), Nucleus::createConstantInt(1));
val.storeValue(inc);
@@ -2236,6 +2391,7 @@
RValue<Int> operator--(Int &val, int) // Post-decrement
{
+ RR_DEBUG_INFO_UPDATE_LOC();
RValue<Int> res = val;
Value *inc = Nucleus::createSub(res.value, Nucleus::createConstantInt(1));
@@ -2246,6 +2402,7 @@
const Int &operator--(Int &val) // Pre-decrement
{
+ RR_DEBUG_INFO_UPDATE_LOC();
Value *inc = Nucleus::createSub(val.loadValue(), Nucleus::createConstantInt(1));
val.storeValue(inc);
@@ -2254,6 +2411,7 @@
RValue<Int> RoundInt(RValue<Float> cast)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
#if defined(__i386__) || defined(__x86_64__)
return x86::cvtss2si(cast);
#else
@@ -2273,6 +2431,7 @@
UInt::UInt(RValue<Float> cast)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
// Note: createFPToUI is broken, must perform conversion using createFPtoSI
// Value *integer = Nucleus::createFPToUI(cast.value, UInt::getType());
@@ -2292,6 +2451,7 @@
RValue<UInt> operator++(UInt &val, int) // Post-increment
{
+ RR_DEBUG_INFO_UPDATE_LOC();
RValue<UInt> res = val;
Value *inc = Nucleus::createAdd(res.value, Nucleus::createConstantInt(1));
@@ -2302,6 +2462,7 @@
const UInt &operator++(UInt &val) // Pre-increment
{
+ RR_DEBUG_INFO_UPDATE_LOC();
Value *inc = Nucleus::createAdd(val.loadValue(), Nucleus::createConstantInt(1));
val.storeValue(inc);
@@ -2310,6 +2471,7 @@
RValue<UInt> operator--(UInt &val, int) // Post-decrement
{
+ RR_DEBUG_INFO_UPDATE_LOC();
RValue<UInt> res = val;
Value *inc = Nucleus::createSub(res.value, Nucleus::createConstantInt(1));
@@ -2320,6 +2482,7 @@
const UInt &operator--(UInt &val) // Pre-decrement
{
+ RR_DEBUG_INFO_UPDATE_LOC();
Value *inc = Nucleus::createSub(val.loadValue(), Nucleus::createConstantInt(1));
val.storeValue(inc);
@@ -2353,6 +2516,7 @@
RValue<Int2> operator<<(RValue<Int2> lhs, unsigned char rhs)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
#if defined(__i386__) || defined(__x86_64__)
// return RValue<Int2>(Nucleus::createShl(lhs.value, rhs.value));
@@ -2364,6 +2528,7 @@
RValue<Int2> operator>>(RValue<Int2> lhs, unsigned char rhs)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
#if defined(__i386__) || defined(__x86_64__)
// return RValue<Int2>(Nucleus::createAShr(lhs.value, rhs.value));
@@ -2380,6 +2545,7 @@
RValue<UInt2> operator<<(RValue<UInt2> lhs, unsigned char rhs)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
#if defined(__i386__) || defined(__x86_64__)
// return RValue<UInt2>(Nucleus::createShl(lhs.value, rhs.value));
@@ -2391,6 +2557,7 @@
RValue<UInt2> operator>>(RValue<UInt2> lhs, unsigned char rhs)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
#if defined(__i386__) || defined(__x86_64__)
// return RValue<UInt2>(Nucleus::createLShr(lhs.value, rhs.value));
@@ -2407,6 +2574,7 @@
Int4::Int4(RValue<Byte4> cast) : XYZW(this)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
#if defined(__i386__) || defined(__x86_64__)
if(CPUID::supportsSSE4_1())
{
@@ -2429,6 +2597,7 @@
Int4::Int4(RValue<SByte4> cast) : XYZW(this)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
#if defined(__i386__) || defined(__x86_64__)
if(CPUID::supportsSSE4_1())
{
@@ -2451,6 +2620,7 @@
Int4::Int4(RValue<Short4> cast) : XYZW(this)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
#if defined(__i386__) || defined(__x86_64__)
if(CPUID::supportsSSE4_1())
{
@@ -2467,6 +2637,7 @@
Int4::Int4(RValue<UShort4> cast) : XYZW(this)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
#if defined(__i386__) || defined(__x86_64__)
if(CPUID::supportsSSE4_1())
{
@@ -2483,6 +2654,7 @@
Int4::Int4(RValue<Int> rhs) : XYZW(this)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
Value *vector = loadValue();
Value *insert = Nucleus::createInsertElement(vector, rhs.value, 0);
@@ -2494,6 +2666,7 @@
RValue<Int4> operator<<(RValue<Int4> lhs, unsigned char rhs)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
#if defined(__i386__) || defined(__x86_64__)
return x86::pslld(lhs, rhs);
#else
@@ -2503,6 +2676,7 @@
RValue<Int4> operator>>(RValue<Int4> lhs, unsigned char rhs)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
#if defined(__i386__) || defined(__x86_64__)
return x86::psrad(lhs, rhs);
#else
@@ -2512,6 +2686,7 @@
RValue<Int4> CmpEQ(RValue<Int4> x, RValue<Int4> y)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
// FIXME: An LLVM bug causes SExt(ICmpCC()) to produce 0 or 1 instead of 0 or ~0
// Restore the following line when LLVM is updated to a version where this issue is fixed.
// return RValue<Int4>(Nucleus::createSExt(Nucleus::createICmpEQ(x.value, y.value), Int4::getType()));
@@ -2520,6 +2695,7 @@
RValue<Int4> CmpLT(RValue<Int4> x, RValue<Int4> y)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
// FIXME: An LLVM bug causes SExt(ICmpCC()) to produce 0 or 1 instead of 0 or ~0
// Restore the following line when LLVM is updated to a version where this issue is fixed.
// return RValue<Int4>(Nucleus::createSExt(Nucleus::createICmpSLT(x.value, y.value), Int4::getType()));
@@ -2528,6 +2704,7 @@
RValue<Int4> CmpLE(RValue<Int4> x, RValue<Int4> y)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
// FIXME: An LLVM bug causes SExt(ICmpCC()) to produce 0 or 1 instead of 0 or ~0
// Restore the following line when LLVM is updated to a version where this issue is fixed.
// return RValue<Int4>(Nucleus::createSExt(Nucleus::createICmpSLE(x.value, y.value), Int4::getType()));
@@ -2536,6 +2713,7 @@
RValue<Int4> CmpNEQ(RValue<Int4> x, RValue<Int4> y)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
// FIXME: An LLVM bug causes SExt(ICmpCC()) to produce 0 or 1 instead of 0 or ~0
// Restore the following line when LLVM is updated to a version where this issue is fixed.
// return RValue<Int4>(Nucleus::createSExt(Nucleus::createICmpNE(x.value, y.value), Int4::getType()));
@@ -2544,6 +2722,7 @@
RValue<Int4> CmpNLT(RValue<Int4> x, RValue<Int4> y)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
// FIXME: An LLVM bug causes SExt(ICmpCC()) to produce 0 or 1 instead of 0 or ~0
// Restore the following line when LLVM is updated to a version where this issue is fixed.
// return RValue<Int4>(Nucleus::createSExt(Nucleus::createICmpSGE(x.value, y.value), Int4::getType()));
@@ -2552,6 +2731,7 @@
RValue<Int4> CmpNLE(RValue<Int4> x, RValue<Int4> y)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
// FIXME: An LLVM bug causes SExt(ICmpCC()) to produce 0 or 1 instead of 0 or ~0
// Restore the following line when LLVM is updated to a version where this issue is fixed.
// return RValue<Int4>(Nucleus::createSExt(Nucleus::createICmpSGT(x.value, y.value), Int4::getType()));
@@ -2560,6 +2740,7 @@
RValue<Int4> Max(RValue<Int4> x, RValue<Int4> y)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
#if defined(__i386__) || defined(__x86_64__)
if(CPUID::supportsSSE4_1())
{
@@ -2575,6 +2756,7 @@
RValue<Int4> Min(RValue<Int4> x, RValue<Int4> y)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
#if defined(__i386__) || defined(__x86_64__)
if(CPUID::supportsSSE4_1())
{
@@ -2590,6 +2772,7 @@
RValue<Int4> RoundInt(RValue<Float4> cast)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
#if defined(__i386__) || defined(__x86_64__)
return x86::cvtps2dq(cast);
#else
@@ -2599,18 +2782,21 @@
RValue<Int4> MulHigh(RValue<Int4> x, RValue<Int4> y)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
// TODO: For x86, build an intrinsics version of this which uses shuffles + pmuludq.
return As<Int4>(V(lowerMulHigh(V(x.value), V(y.value), true)));
}
RValue<UInt4> MulHigh(RValue<UInt4> x, RValue<UInt4> y)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
// TODO: For x86, build an intrinsics version of this which uses shuffles + pmuludq.
return As<UInt4>(V(lowerMulHigh(V(x.value), V(y.value), false)));
}
RValue<Short8> PackSigned(RValue<Int4> x, RValue<Int4> y)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
#if defined(__i386__) || defined(__x86_64__)
return x86::packssdw(x, y);
#else
@@ -2620,6 +2806,7 @@
RValue<UShort8> PackUnsigned(RValue<Int4> x, RValue<Int4> y)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
#if defined(__i386__) || defined(__x86_64__)
return x86::packusdw(x, y);
#else
@@ -2629,6 +2816,7 @@
RValue<Int> SignMask(RValue<Int4> x)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
#if defined(__i386__) || defined(__x86_64__)
return x86::movmskps(As<Float4>(x));
#else
@@ -2643,6 +2831,7 @@
UInt4::UInt4(RValue<Float4> cast) : XYZW(this)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
// Note: createFPToUI is broken, must perform conversion using createFPtoSI
// Value *xyzw = Nucleus::createFPToUI(cast.value, UInt4::getType());
@@ -2662,6 +2851,7 @@
RValue<UInt4> operator<<(RValue<UInt4> lhs, unsigned char rhs)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
#if defined(__i386__) || defined(__x86_64__)
return As<UInt4>(x86::pslld(As<Int4>(lhs), rhs));
#else
@@ -2671,6 +2861,7 @@
RValue<UInt4> operator>>(RValue<UInt4> lhs, unsigned char rhs)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
#if defined(__i386__) || defined(__x86_64__)
return x86::psrld(lhs, rhs);
#else
@@ -2680,6 +2871,7 @@
RValue<UInt4> CmpEQ(RValue<UInt4> x, RValue<UInt4> y)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
// FIXME: An LLVM bug causes SExt(ICmpCC()) to produce 0 or 1 instead of 0 or ~0
// Restore the following line when LLVM is updated to a version where this issue is fixed.
// return RValue<UInt4>(Nucleus::createSExt(Nucleus::createICmpEQ(x.value, y.value), Int4::getType()));
@@ -2688,11 +2880,13 @@
RValue<UInt4> CmpLT(RValue<UInt4> x, RValue<UInt4> y)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return RValue<UInt4>(Nucleus::createSExt(Nucleus::createICmpULT(x.value, y.value), Int4::getType()));
}
RValue<UInt4> CmpLE(RValue<UInt4> x, RValue<UInt4> y)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
// FIXME: An LLVM bug causes SExt(ICmpCC()) to produce 0 or 1 instead of 0 or ~0
// Restore the following line when LLVM is updated to a version where this issue is fixed.
// return RValue<UInt4>(Nucleus::createSExt(Nucleus::createICmpULE(x.value, y.value), Int4::getType()));
@@ -2701,11 +2895,13 @@
RValue<UInt4> CmpNEQ(RValue<UInt4> x, RValue<UInt4> y)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return RValue<UInt4>(Nucleus::createSExt(Nucleus::createICmpNE(x.value, y.value), Int4::getType()));
}
RValue<UInt4> CmpNLT(RValue<UInt4> x, RValue<UInt4> y)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
// FIXME: An LLVM bug causes SExt(ICmpCC()) to produce 0 or 1 instead of 0 or ~0
// Restore the following line when LLVM is updated to a version where this issue is fixed.
// return RValue<UInt4>(Nucleus::createSExt(Nucleus::createICmpUGE(x.value, y.value), Int4::getType()));
@@ -2714,11 +2910,13 @@
RValue<UInt4> CmpNLE(RValue<UInt4> x, RValue<UInt4> y)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return RValue<UInt4>(Nucleus::createSExt(Nucleus::createICmpUGT(x.value, y.value), Int4::getType()));
}
RValue<UInt4> Max(RValue<UInt4> x, RValue<UInt4> y)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
#if defined(__i386__) || defined(__x86_64__)
if(CPUID::supportsSSE4_1())
{
@@ -2734,6 +2932,7 @@
RValue<UInt4> Min(RValue<UInt4> x, RValue<UInt4> y)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
#if defined(__i386__) || defined(__x86_64__)
if(CPUID::supportsSSE4_1())
{
@@ -2759,6 +2958,7 @@
RValue<Float> Rcp_pp(RValue<Float> x, bool exactAtPow2)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
#if defined(__i386__) || defined(__x86_64__)
if(exactAtPow2)
{
@@ -2774,6 +2974,7 @@
RValue<Float> RcpSqrt_pp(RValue<Float> x)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
#if defined(__i386__) || defined(__x86_64__)
return x86::rsqrtss(x);
#else
@@ -2783,6 +2984,7 @@
RValue<Float> Sqrt(RValue<Float> x)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
#if defined(__i386__) || defined(__x86_64__)
return x86::sqrtss(x);
#else
@@ -2792,6 +2994,7 @@
RValue<Float> Round(RValue<Float> x)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
#if defined(__i386__) || defined(__x86_64__)
if(CPUID::supportsSSE4_1())
{
@@ -2808,6 +3011,7 @@
RValue<Float> Trunc(RValue<Float> x)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
#if defined(__i386__) || defined(__x86_64__)
if(CPUID::supportsSSE4_1())
{
@@ -2824,6 +3028,7 @@
RValue<Float> Frac(RValue<Float> x)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
#if defined(__i386__) || defined(__x86_64__)
if(CPUID::supportsSSE4_1())
{
@@ -2842,6 +3047,7 @@
RValue<Float> Floor(RValue<Float> x)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
#if defined(__i386__) || defined(__x86_64__)
if(CPUID::supportsSSE4_1())
{
@@ -2858,6 +3064,7 @@
RValue<Float> Ceil(RValue<Float> x)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
#if defined(__i386__) || defined(__x86_64__)
if(CPUID::supportsSSE4_1())
{
@@ -2882,6 +3089,7 @@
Float4::Float4(RValue<Float> rhs) : XYZW(this)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
Value *vector = loadValue();
Value *insert = Nucleus::createInsertElement(vector, rhs.value, 0);
@@ -2893,6 +3101,7 @@
RValue<Float4> Max(RValue<Float4> x, RValue<Float4> y)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
#if defined(__i386__) || defined(__x86_64__)
return x86::maxps(x, y);
#else
@@ -2902,6 +3111,7 @@
RValue<Float4> Min(RValue<Float4> x, RValue<Float4> y)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
#if defined(__i386__) || defined(__x86_64__)
return x86::minps(x, y);
#else
@@ -2911,6 +3121,7 @@
RValue<Float4> Rcp_pp(RValue<Float4> x, bool exactAtPow2)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
#if defined(__i386__) || defined(__x86_64__)
if(exactAtPow2)
{
@@ -2926,6 +3137,7 @@
RValue<Float4> RcpSqrt_pp(RValue<Float4> x)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
#if defined(__i386__) || defined(__x86_64__)
return x86::rsqrtps(x);
#else
@@ -2935,6 +3147,7 @@
RValue<Float4> Sqrt(RValue<Float4> x)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
#if defined(__i386__) || defined(__x86_64__)
return x86::sqrtps(x);
#else
@@ -2944,6 +3157,7 @@
RValue<Int> SignMask(RValue<Float4> x)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
#if defined(__i386__) || defined(__x86_64__)
return x86::movmskps(x);
#else
@@ -2953,72 +3167,85 @@
RValue<Int4> CmpEQ(RValue<Float4> x, RValue<Float4> y)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
// return As<Int4>(x86::cmpeqps(x, y));
return RValue<Int4>(Nucleus::createSExt(Nucleus::createFCmpOEQ(x.value, y.value), Int4::getType()));
}
RValue<Int4> CmpLT(RValue<Float4> x, RValue<Float4> y)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
// return As<Int4>(x86::cmpltps(x, y));
return RValue<Int4>(Nucleus::createSExt(Nucleus::createFCmpOLT(x.value, y.value), Int4::getType()));
}
RValue<Int4> CmpLE(RValue<Float4> x, RValue<Float4> y)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
// return As<Int4>(x86::cmpleps(x, y));
return RValue<Int4>(Nucleus::createSExt(Nucleus::createFCmpOLE(x.value, y.value), Int4::getType()));
}
RValue<Int4> CmpNEQ(RValue<Float4> x, RValue<Float4> y)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
// return As<Int4>(x86::cmpneqps(x, y));
return RValue<Int4>(Nucleus::createSExt(Nucleus::createFCmpONE(x.value, y.value), Int4::getType()));
}
RValue<Int4> CmpNLT(RValue<Float4> x, RValue<Float4> y)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
// return As<Int4>(x86::cmpnltps(x, y));
return RValue<Int4>(Nucleus::createSExt(Nucleus::createFCmpOGE(x.value, y.value), Int4::getType()));
}
RValue<Int4> CmpNLE(RValue<Float4> x, RValue<Float4> y)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
// return As<Int4>(x86::cmpnleps(x, y));
return RValue<Int4>(Nucleus::createSExt(Nucleus::createFCmpOGT(x.value, y.value), Int4::getType()));
}
RValue<Int4> CmpUEQ(RValue<Float4> x, RValue<Float4> y)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return RValue<Int4>(Nucleus::createSExt(Nucleus::createFCmpUEQ(x.value, y.value), Int4::getType()));
}
RValue<Int4> CmpULT(RValue<Float4> x, RValue<Float4> y)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return RValue<Int4>(Nucleus::createSExt(Nucleus::createFCmpULT(x.value, y.value), Int4::getType()));
}
RValue<Int4> CmpULE(RValue<Float4> x, RValue<Float4> y)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return RValue<Int4>(Nucleus::createSExt(Nucleus::createFCmpULE(x.value, y.value), Int4::getType()));
}
RValue<Int4> CmpUNEQ(RValue<Float4> x, RValue<Float4> y)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return RValue<Int4>(Nucleus::createSExt(Nucleus::createFCmpUNE(x.value, y.value), Int4::getType()));
}
RValue<Int4> CmpUNLT(RValue<Float4> x, RValue<Float4> y)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return RValue<Int4>(Nucleus::createSExt(Nucleus::createFCmpUGE(x.value, y.value), Int4::getType()));
}
RValue<Int4> CmpUNLE(RValue<Float4> x, RValue<Float4> y)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return RValue<Int4>(Nucleus::createSExt(Nucleus::createFCmpUGT(x.value, y.value), Int4::getType()));
}
RValue<Float4> Round(RValue<Float4> x)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
#if defined(__i386__) || defined(__x86_64__)
if(CPUID::supportsSSE4_1())
{
@@ -3035,6 +3262,7 @@
RValue<Float4> Trunc(RValue<Float4> x)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
#if defined(__i386__) || defined(__x86_64__)
if(CPUID::supportsSSE4_1())
{
@@ -3051,6 +3279,7 @@
RValue<Float4> Frac(RValue<Float4> x)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
Float4 frc;
#if defined(__i386__) || defined(__x86_64__)
@@ -3075,6 +3304,7 @@
RValue<Float4> Floor(RValue<Float4> x)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
#if defined(__i386__) || defined(__x86_64__)
if(CPUID::supportsSSE4_1())
{
@@ -3091,6 +3321,7 @@
RValue<Float4> Ceil(RValue<Float4> x)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
#if defined(__i386__) || defined(__x86_64__)
if(CPUID::supportsSSE4_1())
{
@@ -3267,6 +3498,7 @@
RValue<Long> Ticks()
{
+ RR_DEBUG_INFO_UPDATE_LOC();
llvm::Function *rdtsc = llvm::Intrinsic::getDeclaration(::module, llvm::Intrinsic::readcyclecounter);
return RValue<Long>(V(::builder->CreateCall(rdtsc)));
@@ -3935,4 +4167,48 @@
}
#endif // ENABLE_RR_PRINT
+ void Break()
+ {
+ auto trap = ::llvm::Intrinsic::getDeclaration(module, llvm::Intrinsic::trap);
+ builder->CreateCall(trap);
+ }
+
+ void Nop()
+ {
+ auto voidTy = ::llvm::Type::getVoidTy(*context);
+ auto funcTy = ::llvm::FunctionType::get(voidTy, {}, false);
+ auto func = ::module->getOrInsertFunction("nop", funcTy);
+ builder->CreateCall(func);
+ }
+
+ void EmitDebugLocation()
+ {
+#ifdef ENABLE_RR_DEBUG_INFO
+ if (debugInfo != nullptr)
+ {
+ debugInfo->EmitLocation();
+ }
+#endif // ENABLE_RR_DEBUG_INFO
+ }
+
+ void EmitDebugVariable(Value* value)
+ {
+#ifdef ENABLE_RR_DEBUG_INFO
+ if (debugInfo != nullptr)
+ {
+ debugInfo->EmitVariable(value);
+ }
+#endif // ENABLE_RR_DEBUG_INFO
+ }
+
+ void FlushDebug()
+ {
+#ifdef ENABLE_RR_DEBUG_INFO
+ if (debugInfo != nullptr)
+ {
+ debugInfo->Flush();
+ }
+#endif // ENABLE_RR_DEBUG_INFO
+ }
+
}
diff --git a/src/Reactor/LLVMReactor.hpp b/src/Reactor/LLVMReactor.hpp
new file mode 100644
index 0000000..4ff5274
--- /dev/null
+++ b/src/Reactor/LLVMReactor.hpp
@@ -0,0 +1,52 @@
+// Copyright 2019 The SwiftShader Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef rr_LLVMReactor_hpp
+#define rr_LLVMReactor_hpp
+
+namespace llvm
+{
+ class Type;
+ class Value;
+}
+
+namespace rr
+{
+ class Type;
+ class Value;
+
+ llvm::Type *T(Type *t);
+
+ inline Type *T(llvm::Type *t)
+ {
+ return reinterpret_cast<Type*>(t);
+ }
+
+ inline llvm::Value *V(Value *t)
+ {
+ return reinterpret_cast<llvm::Value*>(t);
+ }
+
+ inline Value *V(llvm::Value *t)
+ {
+ return reinterpret_cast<Value*>(t);
+ }
+
+ // Emits a no-op instruction that will not be optimized away.
+ // Useful for emitting something that can have a source location without
+ // effect.
+ void Nop();
+}
+
+#endif // rr_LLVMReactor_hpp
diff --git a/src/Reactor/LLVMReactorDebugInfo.cpp b/src/Reactor/LLVMReactorDebugInfo.cpp
new file mode 100644
index 0000000..75b4a03
--- /dev/null
+++ b/src/Reactor/LLVMReactorDebugInfo.cpp
@@ -0,0 +1,543 @@
+// Copyright 2019 The SwiftShader Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "LLVMReactorDebugInfo.hpp"
+
+#ifdef ENABLE_RR_DEBUG_INFO
+
+#include "Reactor.hpp"
+#include "LLVMReactor.hpp"
+
+#if REACTOR_LLVM_VERSION < 7
+#error "ENABLE_RR_DEBUG_INFO can currently only be used with LLVM 7+"
+#endif
+
+#include "backtrace.h"
+
+#include "llvm/Demangle/Demangle.h"
+#include "llvm/ExecutionEngine/JITEventListener.h"
+#include "llvm/IR/DIBuilder.h"
+#include "llvm/IR/Intrinsics.h"
+#include "llvm/IR/IRBuilder.h"
+
+#include <cctype>
+#include <fstream>
+#include <regex>
+#include <sstream>
+#include <string>
+
+#if 0
+#define LOG(msg, ...) printf(msg "\n", ##__VA_ARGS__)
+#else
+#define LOG(msg, ...)
+#endif
+
+namespace
+{
+ std::pair<llvm::StringRef, llvm::StringRef> splitPath(const char* path)
+ {
+ return llvm::StringRef(path).rsplit('/');
+ }
+} // anonymous namespaces
+
+namespace rr
+{
+ DebugInfo::DebugInfo(
+ llvm::IRBuilder<> *builder,
+ llvm::LLVMContext *context,
+ llvm::Module *module,
+ llvm::Function *function)
+ : builder(builder), context(context), module(module), function(function)
+ {
+ using namespace ::llvm;
+
+ auto location = getCallerLocation();
+
+ auto fileAndDir = splitPath(location.function.file.c_str());
+ diBuilder = new llvm::DIBuilder(*module);
+ diCU = diBuilder->createCompileUnit(
+ llvm::dwarf::DW_LANG_C,
+ diBuilder->createFile(fileAndDir.first, fileAndDir.second),
+ "Reactor",
+ 0, "", 0);
+
+ jitEventListener = llvm::JITEventListener::createGDBRegistrationListener();
+ registerBasicTypes();
+
+ SmallVector<Metadata *, 8> EltTys;
+ auto funcTy = diBuilder->createSubroutineType(diBuilder->getOrCreateTypeArray(EltTys));
+
+ auto file = getOrCreateFile(location.function.file.c_str());
+ auto sp = diBuilder->createFunction(
+ file, // scope
+ "ReactorFunction", // function name
+ "ReactorFunction", // linkage
+ file, // file
+ location.line, // line
+ funcTy, // type
+ false, // internal linkage
+ true, // definition
+ location.line, // scope line
+ DINode::FlagPrototyped, // flags
+ false // is optimized
+ );
+ diSubprogram = sp;
+ function->setSubprogram(sp);
+ diRootLocation = DILocation::get(*context, location.line, 0, sp);
+ builder->SetCurrentDebugLocation(diRootLocation);
+ }
+
+ void DebugInfo::Finalize()
+ {
+ while (diScope.size() > 0)
+ {
+ emitPending(diScope.back(), builder, diBuilder);
+ diScope.pop_back();
+ }
+ diBuilder->finalize();
+ }
+
+ void DebugInfo::EmitLocation()
+ {
+ auto const& backtrace = getCallerBacktrace();
+ syncScope(backtrace);
+ builder->SetCurrentDebugLocation(getLocation(backtrace, backtrace.size() - 1));
+ }
+
+ void DebugInfo::Flush()
+ {
+ emitPending(diScope.back(), builder, diBuilder);
+ }
+
+ void DebugInfo::syncScope(Backtrace const& backtrace)
+ {
+ auto shrink = [this](size_t newsize)
+ {
+ while (diScope.size() > newsize)
+ {
+ auto &scope = diScope.back();
+ LOG("- STACK(%d): di: %p, location: %s:%d",
+ int(diScope.size() - 1), scope.di,
+ scope.location.function.file.c_str(),
+ int(scope.location.line));
+ emitPending(scope, builder, diBuilder);
+ diScope.pop_back();
+ }
+ };
+
+ if (backtrace.size() < diScope.size())
+ {
+ shrink(backtrace.size());
+ }
+
+ for (size_t i = 0; i < diScope.size(); i++)
+ {
+ auto &scope = diScope[i];
+ auto const &oldLocation = scope.location;
+ auto const &newLocation = backtrace[i];
+
+ if (oldLocation.function != newLocation.function)
+ {
+ LOG(" STACK(%d): Changed function %s -> %s", int(i),
+ oldLocation.function.name.c_str(), newLocation.function.name.c_str());
+ shrink(i);
+ break;
+ }
+
+ if (oldLocation.line > newLocation.line)
+ {
+ // Create a new di block to shadow all the variables in the loop.
+ auto file = getOrCreateFile(newLocation.function.file.c_str());
+ auto di = diBuilder->createLexicalBlock(scope.di, file, newLocation.line, 0);
+ LOG(" STACK(%d): Jumped backwards %d -> %d. di: %p -> %p", int(i),
+ oldLocation.line, newLocation.line, scope.di, di);
+ emitPending(scope, builder, diBuilder);
+ scope = {newLocation, di};
+ shrink(i+1);
+ break;
+ }
+
+ scope.location = newLocation;
+ }
+
+ while (backtrace.size() > diScope.size())
+ {
+ auto i = diScope.size();
+ auto location = backtrace[i];
+ auto file = getOrCreateFile(location.function.file.c_str());
+ auto funcTy = diBuilder->createSubroutineType(diBuilder->getOrCreateTypeArray({}));
+
+ char buf[1024];
+ size_t size = sizeof(buf);
+ int status = 0;
+ llvm::itaniumDemangle(location.function.name.c_str(), buf, &size, &status);
+ auto name = status == 0 ? buf : location.function.name.c_str();
+
+ auto func = diBuilder->createFunction(
+ file, // scope
+ name, // function name
+ "", // linkage
+ file, // file
+ location.line, // line
+ funcTy, // type
+ false, // internal linkage
+ true, // definition
+ location.line, // scope line
+ llvm::DINode::FlagPrototyped, // flags
+ false // is optimized
+ );
+ diScope.push_back({location, func});
+ LOG("+ STACK(%d): di: %p, location: %s:%d", int(i), di,
+ location.function.file.c_str(), int(location.line));
+ }
+ }
+
+ llvm::DILocation* DebugInfo::getLocation(const Backtrace &backtrace, size_t i)
+ {
+ if (backtrace.size() == 0) { return nullptr; }
+ assert(backtrace.size() == diScope.size());
+ return llvm::DILocation::get(
+ *context,
+ backtrace[i].line,
+ 0,
+ diScope[i].di,
+ i > 0 ? getLocation(backtrace, i - 1) : diRootLocation
+ );
+ }
+
+ void DebugInfo::EmitVariable(Value *variable)
+ {
+ auto const& backtrace = getCallerBacktrace();
+ syncScope(backtrace);
+
+ for (int i = backtrace.size() - 1; i >= 0; i--)
+ {
+ auto const &location = backtrace[i];
+ auto tokens = getOrParseFileTokens(location.function.file.c_str());
+ auto tokIt = tokens->find(location.line);
+ if (tokIt == tokens->end())
+ {
+ break;
+ }
+ auto token = tokIt->second;
+ auto name = token.identifier;
+ if (token.kind == Token::Return)
+ {
+ // This is a:
+ //
+ // return <expr>;
+ //
+ // Emit this expression as two variables -
+ // Once as a synthetic 'return_value' variable at this scope.
+ // Again by bubbling the expression value up the callstack as
+ // Return Value Optimizations (RVOs) are likely to carry across
+ // the value to a local without calling a constructor in
+ // statements like:
+ //
+ // auto val = foo();
+ //
+ name = "return_value";
+ }
+
+ auto &scope = diScope[i];
+ if (scope.pending.location != location)
+ {
+ emitPending(scope, builder, diBuilder);
+ }
+
+ auto value = V(variable);
+ auto block = builder->GetInsertBlock();
+
+ auto insertAfter = block->size() > 0 ? &block->back() : nullptr;
+ while (insertAfter != nullptr && insertAfter->isTerminator())
+ {
+ insertAfter = insertAfter->getPrevNode();
+ }
+
+ scope.pending = Pending{};
+ scope.pending.name = name;
+ scope.pending.location = location;
+ scope.pending.diLocation = getLocation(backtrace, i);
+ scope.pending.value = value;
+ scope.pending.block = block;
+ scope.pending.insertAfter = insertAfter;
+ scope.pending.scope = scope.di;
+
+ if (token.kind == Token::Return)
+ {
+ // Insert a noop instruction so the debugger can inspect the
+ // return value before the function scope closes.
+ scope.pending.addNopOnNextLine = true;
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+
+ void DebugInfo::emitPending(Scope &scope, IRBuilder *builder, llvm::DIBuilder *diBuilder)
+ {
+ auto const &pending = scope.pending;
+ if (pending.value == nullptr)
+ {
+ return;
+ }
+
+ if (!scope.symbols.emplace(pending.name).second)
+ {
+ return;
+ }
+
+ bool isAlloca = llvm::isa<llvm::AllocaInst>(pending.value);
+
+ LOG(" EMIT(%s): di: %p, location: %s:%d, isAlloca: %s", pending.name.c_str(), scope.di,
+ pending.location.function.file.c_str(), pending.location.line, isAlloca ? "true" : "false");
+
+ auto value = pending.value;
+
+ IRBuilder::InsertPointGuard guard(*builder);
+ if (pending.insertAfter != nullptr)
+ {
+ builder->SetInsertPoint(pending.block, ++pending.insertAfter->getIterator());
+ }
+ else
+ {
+ builder->SetInsertPoint(pending.block);
+ }
+ builder->SetCurrentDebugLocation(pending.diLocation);
+
+ if (!isAlloca)
+ {
+ // While insertDbgValueIntrinsic should be enough to declare a
+ // variable with no storage, variables of RValues can share the same
+ // llvm::Value, and only one can be named. Take for example:
+ //
+ // Int a = 42;
+ // RValue<Int> b = a;
+ // RValue<Int> c = b;
+ //
+ // To handle this, always promote named RValues to an alloca.
+
+ llvm::BasicBlock &entryBlock = function->getEntryBlock();
+ auto alloca = new llvm::AllocaInst(value->getType(), 0, pending.name);
+ entryBlock.getInstList().push_front(alloca);
+ builder->CreateStore(value, alloca);
+ value = alloca;
+ }
+
+ value->setName(pending.name);
+
+ auto diFile = getOrCreateFile(pending.location.function.file.c_str());
+ auto diType = getOrCreateType(value->getType()->getPointerElementType());
+ auto diVar = diBuilder->createAutoVariable(scope.di, pending.name, diFile, pending.location.line, diType);
+
+ auto di = diBuilder->insertDeclare(value, diVar, diBuilder->createExpression(), pending.diLocation, pending.block);
+ if (pending.insertAfter != nullptr) { di->moveAfter(pending.insertAfter); }
+
+ if (pending.addNopOnNextLine)
+ {
+ builder->SetCurrentDebugLocation(llvm::DILocation::get(
+ *context,
+ pending.diLocation->getLine() + 1,
+ 0,
+ pending.diLocation->getScope(),
+ pending.diLocation->getInlinedAt()
+ ));
+ Nop();
+ }
+
+ scope.pending = Pending{};
+ }
+
+ void DebugInfo::NotifyObjectEmitted(const llvm::object::ObjectFile &Obj, const llvm::LoadedObjectInfo &L)
+ {
+ jitEventListener->NotifyObjectEmitted(Obj, static_cast<const llvm::RuntimeDyld::LoadedObjectInfo&>(L));
+ }
+
+ void DebugInfo::NotifyFreeingObject(const llvm::object::ObjectFile &Obj)
+ {
+ jitEventListener->NotifyFreeingObject(Obj);
+ }
+
+ void DebugInfo::registerBasicTypes()
+ {
+ using namespace rr;
+ using namespace llvm;
+
+ auto vec4 = diBuilder->getOrCreateArray(diBuilder->getOrCreateSubrange(0, 4));
+ auto vec8 = diBuilder->getOrCreateArray(diBuilder->getOrCreateSubrange(0, 8));
+ auto vec16 = diBuilder->getOrCreateArray(diBuilder->getOrCreateSubrange(0, 16));
+
+ diTypes.emplace(T(Bool::getType()), diBuilder->createBasicType("Bool", sizeof(bool), dwarf::DW_ATE_boolean));
+ diTypes.emplace(T(Byte::getType()), diBuilder->createBasicType("Byte", 8, dwarf::DW_ATE_unsigned_char));
+ diTypes.emplace(T(SByte::getType()), diBuilder->createBasicType("SByte", 8, dwarf::DW_ATE_signed_char));
+ diTypes.emplace(T(Short::getType()), diBuilder->createBasicType("Short", 16, dwarf::DW_ATE_signed));
+ diTypes.emplace(T(UShort::getType()), diBuilder->createBasicType("UShort", 16, dwarf::DW_ATE_unsigned));
+ diTypes.emplace(T(Int::getType()), diBuilder->createBasicType("Int", 32, dwarf::DW_ATE_signed));
+ diTypes.emplace(T(UInt::getType()), diBuilder->createBasicType("UInt", 32, dwarf::DW_ATE_unsigned));
+ diTypes.emplace(T(Long::getType()), diBuilder->createBasicType("Long", 64, dwarf::DW_ATE_signed));
+ diTypes.emplace(T(Half::getType()), diBuilder->createBasicType("Half", 16, dwarf::DW_ATE_float));
+ diTypes.emplace(T(Float::getType()), diBuilder->createBasicType("Float", 32, dwarf::DW_ATE_float));
+
+ diTypes.emplace(T(Byte4::getType()), diBuilder->createVectorType(128, 128, diTypes[T(Byte::getType())], {vec16}));
+ diTypes.emplace(T(SByte4::getType()), diBuilder->createVectorType(128, 128, diTypes[T(SByte::getType())], {vec16}));
+ diTypes.emplace(T(Byte8::getType()), diBuilder->createVectorType(128, 128, diTypes[T(Byte::getType())], {vec16}));
+ diTypes.emplace(T(SByte8::getType()), diBuilder->createVectorType(128, 128, diTypes[T(SByte::getType())], {vec16}));
+ diTypes.emplace(T(Byte16::getType()), diBuilder->createVectorType(128, 128, diTypes[T(Byte::getType())], {vec16}));
+ diTypes.emplace(T(SByte16::getType()), diBuilder->createVectorType(128, 128, diTypes[T(SByte::getType())], {vec16}));
+ diTypes.emplace(T(Short2::getType()), diBuilder->createVectorType(128, 128, diTypes[T(Short::getType())], {vec8}));
+ diTypes.emplace(T(UShort2::getType()), diBuilder->createVectorType(128, 128, diTypes[T(UShort::getType())], {vec8}));
+ diTypes.emplace(T(Short4::getType()), diBuilder->createVectorType(128, 128, diTypes[T(Short::getType())], {vec8}));
+ diTypes.emplace(T(UShort4::getType()), diBuilder->createVectorType(128, 128, diTypes[T(UShort::getType())], {vec8}));
+ diTypes.emplace(T(Short8::getType()), diBuilder->createVectorType(128, 128, diTypes[T(Short::getType())], {vec8}));
+ diTypes.emplace(T(UShort8::getType()), diBuilder->createVectorType(128, 128, diTypes[T(UShort::getType())], {vec8}));
+ diTypes.emplace(T(Int2::getType()), diBuilder->createVectorType(128, 128, diTypes[T(Int::getType())], {vec4}));
+ diTypes.emplace(T(UInt2::getType()), diBuilder->createVectorType(128, 128, diTypes[T(UInt::getType())], {vec4}));
+ diTypes.emplace(T(Int4::getType()), diBuilder->createVectorType(128, 128, diTypes[T(Int::getType())], {vec4}));
+ diTypes.emplace(T(UInt4::getType()), diBuilder->createVectorType(128, 128, diTypes[T(UInt::getType())], {vec4}));
+ diTypes.emplace(T(Float2::getType()), diBuilder->createVectorType(128, 128, diTypes[T(Float::getType())], {vec4}));
+ diTypes.emplace(T(Float4::getType()), diBuilder->createVectorType(128, 128, diTypes[T(Float::getType())], {vec4}));
+ }
+
+ DebugInfo::Location DebugInfo::getCallerLocation() const
+ {
+ return getCallerBacktrace(1)[0];
+ }
+
+ DebugInfo::Backtrace DebugInfo::getCallerBacktrace(size_t limit /* = 0 */) const
+ {
+ struct callbacks
+ {
+ static void onError(void *data, const char *msg, int errnum)
+ {
+ fprintf(stderr, "BACKTRACE ERROR %d: %s\n", errnum, msg);
+ }
+
+ static int onPCInfo(void *data, uintptr_t pc, const char *file, int line, const char *function)
+ {
+ if (file == nullptr) { return 0; }
+
+ auto const &fileSR = llvm::StringRef(file);
+ if (fileSR.endswith("ReactorDebugInfo.cpp") ||
+ fileSR.endswith("Reactor.cpp") ||
+ fileSR.endswith("Reactor.hpp"))
+ {
+ return 0;
+ }
+
+ auto cb = reinterpret_cast<callbacks*>(data);
+
+ Location location;
+ location.function.file = file;
+ location.function.name = function;
+ location.line = line;
+
+ cb->locations.push_back(location);
+ return (cb->limit == 0 || sizeof(cb->locations) < cb->limit) ? 0 : 1;
+ }
+
+ size_t limit;
+ std::vector<DebugInfo::Location> locations;
+ };
+
+ callbacks callbacks;
+ callbacks.limit = limit;
+ static auto state = backtrace_create_state(nullptr, 0, &callbacks::onError, nullptr);
+ backtrace_full(state, 1, &callbacks::onPCInfo, &callbacks::onError, &callbacks);
+
+ std::reverse(callbacks.locations.begin(), callbacks.locations.end());
+
+ return callbacks.locations;
+ }
+
+ llvm::DIType *DebugInfo::getOrCreateType(llvm::Type* type)
+ {
+ auto it = diTypes.find(type);
+ if (it != diTypes.end()) { return it->second; }
+
+ if(type->isPointerTy())
+ {
+ auto dbgTy = diBuilder->createPointerType(
+ getOrCreateType(type->getPointerElementType()),
+ sizeof(void*)*8, alignof(void*)*8);
+ diTypes.emplace(type, dbgTy);
+ return dbgTy;
+ }
+ llvm::errs() << "Unimplemented debug type: " << type << "\n";
+ assert(false);
+ }
+
+ llvm::DIFile *DebugInfo::getOrCreateFile(const char* path)
+ {
+ auto it = diFiles.find(path);
+ if (it != diFiles.end()) { return it->second; }
+ auto dirAndName = splitPath(path);
+ auto file = diBuilder->createFile(dirAndName.second, dirAndName.first);
+ diFiles.emplace(path, file);
+ return file;
+ }
+
+ DebugInfo::LineTokens const *DebugInfo::getOrParseFileTokens(const char* path)
+ {
+ static std::regex reLocalDecl(
+ "^" // line start
+ "\\s*" // initial whitespace
+ "(?:For\\s*\\(\\s*)?" // optional 'For ('
+ "((?:\\w+(?:<[^>]+>)?)(?:::\\w+(?:<[^>]+>)?)*)" // type (match group 1)
+ "\\s+" // whitespace between type and name
+ "(\\w+)" // identifier (match group 2)
+ "\\s*" // whitespace after identifier
+ "(\\[.*\\])?"); // optional array suffix (match group 3)
+
+ auto it = fileTokens.find(path);
+ if (it != fileTokens.end())
+ {
+ return it->second.get();
+ }
+
+ auto tokens = std::unique_ptr<LineTokens>(new LineTokens());
+
+ std::ifstream file(path);
+ std::string line;
+ int lineCount = 0;
+ while (std::getline(file, line))
+ {
+ lineCount++;
+ std::smatch match;
+ if (std::regex_search(line, match, reLocalDecl) && match.size() > 3)
+ {
+ bool isArray = match.str(3) != "";
+ if (!isArray) // Cannot deal with C-arrays of values.
+ {
+ if (match.str(1) == "return")
+ {
+ (*tokens)[lineCount] = Token{Token::Return};
+ }
+ else
+ {
+ (*tokens)[lineCount] = Token{Token::Identifier, match.str(2)};
+ }
+ }
+ }
+ }
+
+ auto out = tokens.get();
+ fileTokens.emplace(path, std::move(tokens));
+ return out;
+ }
+
+} // namespace rr
+
+#endif // ENABLE_RR_DEBUG_INFO
diff --git a/src/Reactor/LLVMReactorDebugInfo.hpp b/src/Reactor/LLVMReactorDebugInfo.hpp
new file mode 100644
index 0000000..d8c83de
--- /dev/null
+++ b/src/Reactor/LLVMReactorDebugInfo.hpp
@@ -0,0 +1,211 @@
+// Copyright 2019 The SwiftShader Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef rr_LLVMReactorDebugInfo_hpp
+#define rr_LLVMReactorDebugInfo_hpp
+
+#include "Reactor.hpp"
+
+#ifdef ENABLE_RR_DEBUG_INFO
+
+#include <unordered_set>
+#include <unordered_map>
+#include <vector>
+#include <memory>
+
+// Forward declarations
+namespace llvm
+{
+ class BasicBlock;
+ class ConstantFolder;
+ class DIBuilder;
+ class DICompileUnit;
+ class DIFile;
+ class DILocation;
+ class DIScope;
+ class DISubprogram;
+ class DIType;
+ class Function;
+ class Instruction;
+ class IRBuilderDefaultInserter;
+ class JITEventListener;
+ class LLVMContext;
+ class LoadedObjectInfo;
+ class Module;
+ class Type;
+ class Value;
+
+ namespace object
+ {
+ class ObjectFile;
+ }
+
+ template <typename T, typename Inserter> class IRBuilder;
+} // namespace llvm
+
+namespace rr
+{
+ class Type;
+ class Value;
+
+ // DebugInfo generates LLVM DebugInfo IR from the C++ source that calls
+ // into Reactor functions. See docs/ReactorDebugInfo.mk for more information.
+ class DebugInfo
+ {
+ public:
+ using IRBuilder = llvm::IRBuilder<llvm::ConstantFolder, llvm::IRBuilderDefaultInserter>;
+
+ DebugInfo(IRBuilder *builder,
+ llvm::LLVMContext *context,
+ llvm::Module *module,
+ llvm::Function *function);
+
+ // Finalize debug info generation. Must be called before the LLVM module
+ // is built.
+ void Finalize();
+
+ // Updates the current source location.
+ void EmitLocation();
+
+ // Binds the value to its symbol in the source file.
+ // See docs/ReactorDebugInfo.mk for more information.
+ void EmitVariable(Value *value);
+
+ // Forcefully flush the binding of the last variable name.
+ // Used for binding the initializer of `For` loops.
+ void Flush();
+
+ // NotifyObjectEmitted informs any attached debuggers of the JIT'd
+ // object.
+ void NotifyObjectEmitted(const llvm::object::ObjectFile &Obj, const llvm::LoadedObjectInfo &L);
+
+ // NotifyFreeingObject informs any attached debuggers that the JIT'd
+ // object is now invalid.
+ void NotifyFreeingObject(const llvm::object::ObjectFile &Obj);
+
+ private:
+ struct Token
+ {
+ enum Kind
+ {
+ Identifier,
+ Return
+ };
+ Kind kind;
+ std::string identifier;
+ };
+
+ using LineTokens = std::unordered_map<unsigned int, Token>;
+
+ struct FunctionLocation
+ {
+ std::string name;
+ std::string file;
+
+ bool operator == (const FunctionLocation &rhs) const { return name == rhs.name && file == rhs.file; }
+ bool operator != (const FunctionLocation &rhs) const { return !(*this == rhs); }
+
+ struct Hash
+ {
+ std::size_t operator()(const FunctionLocation &l) const noexcept
+ {
+ return std::hash<std::string>()(l.file) * 31 +
+ std::hash<std::string>()(l.name);
+ }
+ };
+ };
+
+ struct Location
+ {
+ FunctionLocation function;
+ unsigned int line = 0;
+
+ bool operator == (const Location &rhs) const { return function == rhs.function && line == rhs.line; }
+ bool operator != (const Location &rhs) const { return !(*this == rhs); }
+
+ struct Hash
+ {
+ std::size_t operator()(const Location &l) const noexcept
+ {
+ return FunctionLocation::Hash()(l.function) * 31 +
+ std::hash<unsigned int>()(l.line);
+ }
+ };
+ };
+
+ using Backtrace = std::vector<Location>;
+
+ struct Pending
+ {
+ std::string name;
+ Location location;
+ llvm::DILocation *diLocation = nullptr;
+ llvm::Value *value = nullptr;
+ llvm::Instruction *insertAfter = nullptr;
+ llvm::BasicBlock *block = nullptr;
+ llvm::DIScope *scope = nullptr;
+ bool addNopOnNextLine = false;
+ };
+
+ struct Scope
+ {
+ Location location;
+ llvm::DIScope *di;
+ std::unordered_set<std::string> symbols;
+ Pending pending;
+ };
+
+ void registerBasicTypes();
+
+ void emitPending(Scope &scope, IRBuilder *builder, llvm::DIBuilder *diBuilder);
+
+ // Returns the source location of the non-Reactor calling function.
+ Location getCallerLocation() const;
+
+ // Returns the backtrace for the callstack, starting at the first
+ // non-Reactor file. If limit is non-zero, then a maximum of limit
+ // frames will be returned.
+ Backtrace getCallerBacktrace(size_t limit = 0) const;
+
+ llvm::DILocation* getLocation(const Backtrace &backtrace, size_t i);
+
+ llvm::DIType *getOrCreateType(llvm::Type* type);
+ llvm::DIFile *getOrCreateFile(const char* path);
+ LineTokens const *getOrParseFileTokens(const char* path);
+
+ // Synchronizes diScope with the current backtrace.
+ void syncScope(Backtrace const& backtrace);
+
+ IRBuilder *builder;
+ llvm::LLVMContext *context;
+ llvm::Module *module;
+ llvm::Function *function;
+
+ llvm::DIBuilder *diBuilder;
+ llvm::DICompileUnit *diCU;
+ llvm::DISubprogram *diSubprogram;
+ llvm::DILocation *diRootLocation;
+ std::vector<Scope> diScope;
+ std::unordered_map<std::string, llvm::DIFile*> diFiles;
+ std::unordered_map<llvm::Type*, llvm::DIType*> diTypes;
+ std::unordered_map<std::string, std::unique_ptr<LineTokens>> fileTokens;
+ llvm::JITEventListener *jitEventListener;
+ std::vector<void const*> pushed;
+ };
+
+} // namespace rr
+
+#endif // ENABLE_RR_DEBUG_INFO
+
+#endif // rr_LLVMReactorDebugInfo_hpp
diff --git a/src/Reactor/Reactor.hpp b/src/Reactor/Reactor.hpp
index b7dcaf3..4e95806 100644
--- a/src/Reactor/Reactor.hpp
+++ b/src/Reactor/Reactor.hpp
@@ -32,6 +32,27 @@
#define ENABLE_RR_PRINT 1 // Enables RR_PRINT(), RR_WATCH()
#endif // !defined(NDEBUG) && (REACTOR_LLVM_VERSION >= 7)
+#ifdef ENABLE_RR_DEBUG_INFO
+ // Functions used for generating JIT debug info.
+ // See docs/ReactorDebugInfo.md for more information.
+ namespace rr
+ {
+ // Update the current source location for debug.
+ void EmitDebugLocation();
+ // Bind value to its symbolic name taken from the backtrace.
+ void EmitDebugVariable(class Value* value);
+ // Flush any pending variable bindings before the line ends.
+ void FlushDebug();
+ }
+ #define RR_DEBUG_INFO_UPDATE_LOC() rr::EmitDebugLocation()
+ #define RR_DEBUG_INFO_EMIT_VAR(value) rr::EmitDebugVariable(value)
+ #define RR_DEBUG_INFO_FLUSH() rr::FlushDebug()
+#else
+ #define RR_DEBUG_INFO_UPDATE_LOC()
+ #define RR_DEBUG_INFO_EMIT_VAR(value)
+ #define RR_DEBUG_INFO_FLUSH()
+#endif // ENABLE_RR_DEBUG_INFO
+
namespace rr
{
struct Capabilities
@@ -211,6 +232,10 @@
public:
explicit RValue(Value *rvalue);
+#ifdef ENABLE_RR_DEBUG_INFO
+ RValue(const RValue<T> &rvalue);
+#endif // ENABLE_RR_DEBUG_INFO
+
RValue(const T &lvalue);
RValue(typename BoolLiteral<T>::type i);
RValue(typename IntLiteral<T>::type i);
@@ -2385,6 +2410,9 @@
template<class T>
LValue<T>::LValue(int arraySize) : Variable(T::getType(), arraySize)
{
+#ifdef ENABLE_RR_DEBUG_INFO
+ materialize();
+#endif // ENABLE_RR_DEBUG_INFO
}
inline void Variable::materialize() const
@@ -2392,6 +2420,7 @@
if(!address)
{
address = Nucleus::allocateStackVariable(type, arraySize);
+ RR_DEBUG_INFO_EMIT_VAR(address);
if(rvalue)
{
@@ -2488,47 +2517,62 @@
return alignment;
}
+#ifdef ENABLE_RR_DEBUG_INFO
+ template<class T>
+ RValue<T>::RValue(const RValue<T> &rvalue) : value(rvalue.value)
+ {
+ RR_DEBUG_INFO_EMIT_VAR(value);
+ }
+#endif // ENABLE_RR_DEBUG_INFO
+
template<class T>
RValue<T>::RValue(Value *rvalue)
{
assert(Nucleus::createBitCast(rvalue, T::getType()) == rvalue); // Run-time type should match T, so bitcast is no-op.
value = rvalue;
+ RR_DEBUG_INFO_EMIT_VAR(value);
}
template<class T>
RValue<T>::RValue(const T &lvalue)
{
value = lvalue.loadValue();
+ RR_DEBUG_INFO_EMIT_VAR(value);
}
template<class T>
RValue<T>::RValue(typename BoolLiteral<T>::type i)
{
value = Nucleus::createConstantBool(i);
+ RR_DEBUG_INFO_EMIT_VAR(value);
}
template<class T>
RValue<T>::RValue(typename IntLiteral<T>::type i)
{
value = Nucleus::createConstantInt(i);
+ RR_DEBUG_INFO_EMIT_VAR(value);
}
template<class T>
RValue<T>::RValue(typename FloatLiteral<T>::type f)
{
value = Nucleus::createConstantFloat(f);
+ RR_DEBUG_INFO_EMIT_VAR(value);
}
template<class T>
RValue<T>::RValue(const Reference<T> &ref)
{
value = ref.loadValue();
+ RR_DEBUG_INFO_EMIT_VAR(value);
}
template<class Vector4, int T>
Swizzle2<Vector4, T>::operator RValue<Vector4>() const
{
+ RR_DEBUG_INFO_UPDATE_LOC();
Value *vector = parent->loadValue();
return Swizzle(RValue<Vector4>(vector), T);
@@ -2537,6 +2581,7 @@
template<class Vector4, int T>
Swizzle4<Vector4, T>::operator RValue<Vector4>() const
{
+ RR_DEBUG_INFO_UPDATE_LOC();
Value *vector = parent->loadValue();
return Swizzle(RValue<Vector4>(vector), T);
@@ -2545,6 +2590,7 @@
template<class Vector4, int T>
SwizzleMask4<Vector4, T>::operator RValue<Vector4>() const
{
+ RR_DEBUG_INFO_UPDATE_LOC();
Value *vector = parent->loadValue();
return Swizzle(RValue<Vector4>(vector), T);
@@ -2553,24 +2599,28 @@
template<class Vector4, int T>
RValue<Vector4> SwizzleMask4<Vector4, T>::operator=(RValue<Vector4> rhs)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return Mask(*parent, rhs, T);
}
template<class Vector4, int T>
RValue<Vector4> SwizzleMask4<Vector4, T>::operator=(RValue<typename Scalar<Vector4>::Type> rhs)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return Mask(*parent, Vector4(rhs), T);
}
template<class Vector4, int T>
SwizzleMask1<Vector4, T>::operator RValue<typename Scalar<Vector4>::Type>() const // FIXME: Call a non-template function
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return Extract(*parent, T & 0x3);
}
template<class Vector4, int T>
SwizzleMask1<Vector4, T>::operator RValue<Vector4>() const
{
+ RR_DEBUG_INFO_UPDATE_LOC();
Value *vector = parent->loadValue();
return Swizzle(RValue<Vector4>(vector), T);
@@ -2579,24 +2629,28 @@
template<class Vector4, int T>
RValue<Vector4> SwizzleMask1<Vector4, T>::operator=(float x)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return *parent = Insert(*parent, Float(x), T & 0x3);
}
template<class Vector4, int T>
RValue<Vector4> SwizzleMask1<Vector4, T>::operator=(RValue<Vector4> rhs)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return Mask(*parent, Float4(rhs), T);
}
template<class Vector4, int T>
RValue<Vector4> SwizzleMask1<Vector4, T>::operator=(RValue<typename Scalar<Vector4>::Type> rhs) // FIXME: Call a non-template function
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return *parent = Insert(*parent, rhs, T & 0x3);
}
template<class Vector4, int T>
SwizzleMask2<Vector4, T>::operator RValue<Vector4>() const
{
+ RR_DEBUG_INFO_UPDATE_LOC();
Value *vector = parent->loadValue();
return Swizzle(RValue<Float4>(vector), T);
@@ -2605,6 +2659,7 @@
template<class Vector4, int T>
RValue<Vector4> SwizzleMask2<Vector4, T>::operator=(RValue<Vector4> rhs)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return Mask(*parent, Float4(rhs), T);
}
@@ -2635,24 +2690,28 @@
template<int X, int Y>
Float4::Float4(const Swizzle2<Float4, X> &x, const Swizzle2<Float4, Y> &y) : XYZW(this)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
*this = ShuffleLowHigh(*x.parent, *y.parent, (X & 0xF) | (Y & 0xF) << 4);
}
template<int X, int Y>
Float4::Float4(const SwizzleMask2<Float4, X> &x, const Swizzle2<Float4, Y> &y) : XYZW(this)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
*this = ShuffleLowHigh(*x.parent, *y.parent, (X & 0xF) | (Y & 0xF) << 4);
}
template<int X, int Y>
Float4::Float4(const Swizzle2<Float4, X> &x, const SwizzleMask2<Float4, Y> &y) : XYZW(this)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
*this = ShuffleLowHigh(*x.parent, *y.parent, (X & 0xF) | (Y & 0xF) << 4);
}
template<int X, int Y>
Float4::Float4(const SwizzleMask2<Float4, X> &x, const SwizzleMask2<Float4, Y> &y) : XYZW(this)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
*this = ShuffleLowHigh(*x.parent, *y.parent, (X & 0xF) | (Y & 0xF) << 4);
}
@@ -2736,6 +2795,7 @@
template<class T>
Reference<T> Pointer<T>::operator[](int index)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
Value *element = Nucleus::createGEP(LValue<Pointer<T>>::loadValue(), T::getType(), Nucleus::createConstantInt(index), false);
return Reference<T>(element, alignment);
@@ -2744,6 +2804,7 @@
template<class T>
Reference<T> Pointer<T>::operator[](unsigned int index)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
Value *element = Nucleus::createGEP(LValue<Pointer<T>>::loadValue(), T::getType(), Nucleus::createConstantInt(index), true);
return Reference<T>(element, alignment);
@@ -2752,6 +2813,7 @@
template<class T>
Reference<T> Pointer<T>::operator[](RValue<Int> index)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
Value *element = Nucleus::createGEP(LValue<Pointer<T>>::loadValue(), T::getType(), index.value, false);
return Reference<T>(element, alignment);
@@ -2760,6 +2822,7 @@
template<class T>
Reference<T> Pointer<T>::operator[](RValue<UInt> index)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
Value *element = Nucleus::createGEP(LValue<Pointer<T>>::loadValue(), T::getType(), index.value, true);
return Reference<T>(element, alignment);
@@ -2835,12 +2898,14 @@
template<class T>
RValue<T> IfThenElse(RValue<Bool> condition, RValue<T> ifTrue, RValue<T> ifFalse)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return RValue<T>(Nucleus::createSelect(condition.value, ifTrue.value, ifFalse.value));
}
template<class T>
RValue<T> IfThenElse(RValue<Bool> condition, const T &ifTrue, RValue<T> ifFalse)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
Value *trueValue = ifTrue.loadValue();
return RValue<T>(Nucleus::createSelect(condition.value, trueValue, ifFalse.value));
@@ -2849,6 +2914,7 @@
template<class T>
RValue<T> IfThenElse(RValue<Bool> condition, RValue<T> ifTrue, const T &ifFalse)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
Value *falseValue = ifFalse.loadValue();
return RValue<T>(Nucleus::createSelect(condition.value, ifTrue.value, falseValue));
@@ -2857,6 +2923,7 @@
template<class T>
RValue<T> IfThenElse(RValue<Bool> condition, const T &ifTrue, const T &ifFalse)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
Value *trueValue = ifTrue.loadValue();
Value *falseValue = ifFalse.loadValue();
@@ -2866,6 +2933,7 @@
template<class T>
void Return(const Pointer<T> &ret)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
Nucleus::createRet(Nucleus::createLoad(ret.address, Pointer<T>::getType()));
Nucleus::setInsertBlock(Nucleus::createBasicBlock());
Nucleus::createUnreachable();
@@ -2874,6 +2942,7 @@
template<class T>
void Return(RValue<Pointer<T>> ret)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
Nucleus::createRet(ret.value);
Nucleus::setInsertBlock(Nucleus::createBasicBlock());
Nucleus::createUnreachable();
@@ -2918,12 +2987,14 @@
template<class T, class S>
RValue<T> ReinterpretCast(RValue<S> val)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return RValue<T>(Nucleus::createBitCast(val.value, T::getType()));
}
template<class T, class S>
RValue<T> ReinterpretCast(const LValue<S> &var)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
Value *val = var.loadValue();
return RValue<T>(Nucleus::createBitCast(val, T::getType()));
@@ -2938,6 +3009,7 @@
template<class T>
RValue<T> As(Value *val)
{
+ RR_DEBUG_INFO_UPDATE_LOC();
return RValue<T>(Nucleus::createBitCast(val, T::getType()));
}
@@ -3050,6 +3122,10 @@
CallHelper<FUNCTION_SIGNATURE>::Call(fptr, args...);
}
+ // Breakpoint emits an instruction that will cause the application to trap.
+ // This can be used to stop an attached debugger at the given call.
+ void Breakpoint();
+
#ifdef ENABLE_RR_PRINT
// PrintValue holds the printf format and value(s) for a single argument
// to Print(). A single argument can be expanded into multiple printf
@@ -3387,6 +3463,7 @@
bool setup()
{
+ RR_DEBUG_INFO_FLUSH();
if(Nucleus::getInsertBlock() != endBB)
{
testBB = Nucleus::createBasicBlock();
diff --git a/src/Reactor/Reactor.vcxproj b/src/Reactor/Reactor.vcxproj
index ee0825e..ab5b1ec 100644
--- a/src/Reactor/Reactor.vcxproj
+++ b/src/Reactor/Reactor.vcxproj
@@ -289,6 +289,7 @@
<ClCompile Include="LLVMRoutine.cpp" />
<ClCompile Include="LLVMRoutineManager.cpp" />
<ClCompile Include="LLVMReactor.cpp" />
+ <ClCompile Include="LLVMReactorDebugInfo.cpp" />
<ClCompile Include="ExecutableMemory.cpp" />
<ClCompile Include="Reactor.cpp" />
<ClCompile Include="Routine.cpp" />
@@ -297,6 +298,8 @@
<ItemGroup>
<ClInclude Include="CPUID.hpp" />
<ClInclude Include="Debug.hpp" />
+ <ClInclude Include="LLVMReactor.hpp" />
+ <ClInclude Include="LLVMReactorDebugInfo.hpp" />
<ClInclude Include="LLVMRoutine.hpp" />
<ClInclude Include="LLVMRoutineManager.hpp" />
<ClInclude Include="ExecutableMemory.hpp" />
diff --git a/src/Reactor/Reactor.vcxproj.filters b/src/Reactor/Reactor.vcxproj.filters
index 30d695f..c8a2c50 100644
--- a/src/Reactor/Reactor.vcxproj.filters
+++ b/src/Reactor/Reactor.vcxproj.filters
@@ -27,6 +27,9 @@
<ClCompile Include="LLVMReactor.cpp">
<Filter>Source Files</Filter>
</ClCompile>
+ <ClCompile Include="LLVMReactorDebugInfo.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
<ClCompile Include="CPUID.cpp">
<Filter>Source Files</Filter>
</ClCompile>
@@ -56,6 +59,12 @@
<ClInclude Include="Routine.hpp">
<Filter>Header Files</Filter>
</ClInclude>
+ <ClInclude Include="LLVMReactor.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="LLVMReactorDebugInfo.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
<ClInclude Include="LLVMRoutineManager.hpp">
<Filter>Header Files</Filter>
</ClInclude>
diff --git a/src/Reactor/SubzeroReactor.cpp b/src/Reactor/SubzeroReactor.cpp
index 731e682..3afed7b 100644
--- a/src/Reactor/SubzeroReactor.cpp
+++ b/src/Reactor/SubzeroReactor.cpp
@@ -3425,4 +3425,8 @@
RValue<Float4> Log2(RValue<Float4> x) { UNIMPLEMENTED("Subzero Log2()"); return Float4(0); }
RValue<UInt4> Ctlz(RValue<UInt4> x, bool isZeroUndef) { UNIMPLEMENTED("Subzero Ctlz()"); return UInt4(0); }
RValue<UInt4> Cttz(RValue<UInt4> x, bool isZeroUndef) { UNIMPLEMENTED("Subzero Cttz()"); return UInt4(0); }
+
+ void EmitDebugLocation() {}
+ void EmitDebugVariable(Value* value) {}
+ void FlushDebug() {}
}
diff --git a/third_party/libbacktrace/config/darwin/include/backtrace-supported.h b/third_party/libbacktrace/config/darwin/include/backtrace-supported.h
new file mode 100644
index 0000000..7709fca
--- /dev/null
+++ b/third_party/libbacktrace/config/darwin/include/backtrace-supported.h
@@ -0,0 +1,66 @@
+/* backtrace-supported.h.in -- Whether stack backtrace is supported.
+ Copyright (C) 2012-2016 Free Software Foundation, Inc.
+ Written by Ian Lance Taylor, Google.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ (1) Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ (2) Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+ (3) The name of the author may not be used to
+ endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE. */
+
+/* The file backtrace-supported.h.in is used by configure to generate
+ the file backtrace-supported.h. The file backtrace-supported.h may
+ be #include'd to see whether the backtrace library will be able to
+ get a backtrace and produce symbolic information. */
+
+
+/* BACKTRACE_SUPPORTED will be #define'd as 1 if the backtrace library
+ should work, 0 if it will not. Libraries may #include this to make
+ other arrangements. */
+
+#define BACKTRACE_SUPPORTED 1
+
+/* BACKTRACE_USES_MALLOC will be #define'd as 1 if the backtrace
+ library will call malloc as it works, 0 if it will call mmap
+ instead. This may be used to determine whether it is safe to call
+ the backtrace functions from a signal handler. In general this
+ only applies to calls like backtrace and backtrace_pcinfo. It does
+ not apply to backtrace_simple, which never calls malloc. It does
+ not apply to backtrace_print, which always calls fprintf and
+ therefore malloc. */
+
+#define BACKTRACE_USES_MALLOC 0
+
+/* BACKTRACE_SUPPORTS_THREADS will be #define'd as 1 if the backtrace
+ library is configured with threading support, 0 if not. If this is
+ 0, the threaded parameter to backtrace_create_state must be passed
+ as 0. */
+
+#define BACKTRACE_SUPPORTS_THREADS 1
+
+/* BACKTRACE_SUPPORTS_DATA will be #defined'd as 1 if the backtrace_syminfo
+ will work for variables. It will always work for functions. */
+
+#define BACKTRACE_SUPPORTS_DATA 1
diff --git a/third_party/libbacktrace/config/darwin/include/config.h b/third_party/libbacktrace/config/darwin/include/config.h
new file mode 100644
index 0000000..ee92775
--- /dev/null
+++ b/third_party/libbacktrace/config/darwin/include/config.h
@@ -0,0 +1,150 @@
+/* config.h. Generated from config.h.in by configure. */
+/* config.h.in. Generated from configure.ac by autoheader. */
+
+/* ELF size: 32 or 64 */
+#define BACKTRACE_ELF_SIZE 64
+
+/* XCOFF size: 32 or 64 */
+#define BACKTRACE_XCOFF_SIZE unused
+
+/* Define to 1 if you have the __atomic functions */
+#define HAVE_ATOMIC_FUNCTIONS 1
+
+/* Define to 1 if you have the `clock_gettime' function. */
+#define HAVE_CLOCK_GETTIME 1
+
+/* Define to 1 if you have the declaration of `strnlen', and to 0 if you
+ don't. */
+#define HAVE_DECL_STRNLEN 1
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define if dl_iterate_phdr is available. */
+/* #undef HAVE_DL_ITERATE_PHDR */
+
+/* Define to 1 if you have the fcntl function */
+#define HAVE_FCNTL 1
+
+/* Define if getexecname is available. */
+/* #undef HAVE_GETEXECNAME */
+
+/* Define if _Unwind_GetIPInfo is available. */
+#define HAVE_GETIPINFO 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `z' library (-lz). */
+#define HAVE_LIBZ 1
+
+/* Define to 1 if you have the <link.h> header file. */
+/* #undef HAVE_LINK_H */
+
+/* Define if AIX loadquery is available. */
+/* #undef HAVE_LOADQUERY */
+
+/* Define to 1 if you have the `lstat' function. */
+#define HAVE_LSTAT 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the `readlink' function. */
+#define HAVE_READLINK 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the __sync functions */
+#define HAVE_SYNC_FUNCTIONS 1
+
+/* Define to 1 if you have the <sys/ldr.h> header file. */
+/* #undef HAVE_SYS_LDR_H */
+
+/* Define to 1 if you have the <sys/mman.h> header file. */
+#define HAVE_SYS_MMAN_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define if -lz is available. */
+#define HAVE_ZLIB 1
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+ */
+#define LT_OBJDIR ".libs/"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT ""
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "package-unused"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "package-unused version-unused"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "libbacktrace"
+
+/* Define to the home page for this package. */
+#define PACKAGE_URL ""
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "version-unused"
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Enable extensions on AIX 3, Interix. */
+#ifndef _ALL_SOURCE
+# define _ALL_SOURCE 1
+#endif
+/* Enable GNU extensions on systems that have them. */
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE 1
+#endif
+/* Enable threading extensions on Solaris. */
+#ifndef _POSIX_PTHREAD_SEMANTICS
+# define _POSIX_PTHREAD_SEMANTICS 1
+#endif
+/* Enable extensions on HP NonStop. */
+#ifndef _TANDEM_SOURCE
+# define _TANDEM_SOURCE 1
+#endif
+/* Enable general extensions on Solaris. */
+#ifndef __EXTENSIONS__
+# define __EXTENSIONS__ 1
+#endif
+
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+/* #undef _FILE_OFFSET_BITS */
+
+/* Define for large files, on AIX-style hosts. */
+/* #undef _LARGE_FILES */
+
+/* Define to 1 if on MINIX. */
+/* #undef _MINIX */
+
+/* Define to 2 if the system does not provide POSIX.1 features except with
+ this defined. */
+/* #undef _POSIX_1_SOURCE */
+
+/* Define to 1 if you need to in order for `stat' and other things to work. */
+/* #undef _POSIX_SOURCE */
diff --git a/third_party/libbacktrace/config/linux/include/backtrace-supported.h b/third_party/libbacktrace/config/linux/include/backtrace-supported.h
new file mode 100644
index 0000000..7709fca
--- /dev/null
+++ b/third_party/libbacktrace/config/linux/include/backtrace-supported.h
@@ -0,0 +1,66 @@
+/* backtrace-supported.h.in -- Whether stack backtrace is supported.
+ Copyright (C) 2012-2016 Free Software Foundation, Inc.
+ Written by Ian Lance Taylor, Google.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ (1) Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ (2) Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+ (3) The name of the author may not be used to
+ endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE. */
+
+/* The file backtrace-supported.h.in is used by configure to generate
+ the file backtrace-supported.h. The file backtrace-supported.h may
+ be #include'd to see whether the backtrace library will be able to
+ get a backtrace and produce symbolic information. */
+
+
+/* BACKTRACE_SUPPORTED will be #define'd as 1 if the backtrace library
+ should work, 0 if it will not. Libraries may #include this to make
+ other arrangements. */
+
+#define BACKTRACE_SUPPORTED 1
+
+/* BACKTRACE_USES_MALLOC will be #define'd as 1 if the backtrace
+ library will call malloc as it works, 0 if it will call mmap
+ instead. This may be used to determine whether it is safe to call
+ the backtrace functions from a signal handler. In general this
+ only applies to calls like backtrace and backtrace_pcinfo. It does
+ not apply to backtrace_simple, which never calls malloc. It does
+ not apply to backtrace_print, which always calls fprintf and
+ therefore malloc. */
+
+#define BACKTRACE_USES_MALLOC 0
+
+/* BACKTRACE_SUPPORTS_THREADS will be #define'd as 1 if the backtrace
+ library is configured with threading support, 0 if not. If this is
+ 0, the threaded parameter to backtrace_create_state must be passed
+ as 0. */
+
+#define BACKTRACE_SUPPORTS_THREADS 1
+
+/* BACKTRACE_SUPPORTS_DATA will be #defined'd as 1 if the backtrace_syminfo
+ will work for variables. It will always work for functions. */
+
+#define BACKTRACE_SUPPORTS_DATA 1
diff --git a/third_party/libbacktrace/config/linux/include/config.h b/third_party/libbacktrace/config/linux/include/config.h
new file mode 100644
index 0000000..7333eca
--- /dev/null
+++ b/third_party/libbacktrace/config/linux/include/config.h
@@ -0,0 +1,150 @@
+/* config.h. Generated from config.h.in by configure. */
+/* config.h.in. Generated from configure.ac by autoheader. */
+
+/* ELF size: 32 or 64 */
+#define BACKTRACE_ELF_SIZE 64
+
+/* XCOFF size: 32 or 64 */
+#define BACKTRACE_XCOFF_SIZE unused
+
+/* Define to 1 if you have the __atomic functions */
+#define HAVE_ATOMIC_FUNCTIONS 1
+
+/* Define to 1 if you have the `clock_gettime' function. */
+#define HAVE_CLOCK_GETTIME 1
+
+/* Define to 1 if you have the declaration of `strnlen', and to 0 if you
+ don't. */
+#define HAVE_DECL_STRNLEN 1
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define if dl_iterate_phdr is available. */
+#define HAVE_DL_ITERATE_PHDR 1
+
+/* Define to 1 if you have the fcntl function */
+#define HAVE_FCNTL 1
+
+/* Define if getexecname is available. */
+/* #undef HAVE_GETEXECNAME */
+
+/* Define if _Unwind_GetIPInfo is available. */
+#define HAVE_GETIPINFO 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `z' library (-lz). */
+#define HAVE_LIBZ 1
+
+/* Define to 1 if you have the <link.h> header file. */
+#define HAVE_LINK_H 1
+
+/* Define if AIX loadquery is available. */
+/* #undef HAVE_LOADQUERY */
+
+/* Define to 1 if you have the `lstat' function. */
+#define HAVE_LSTAT 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the `readlink' function. */
+#define HAVE_READLINK 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the __sync functions */
+#define HAVE_SYNC_FUNCTIONS 1
+
+/* Define to 1 if you have the <sys/ldr.h> header file. */
+/* #undef HAVE_SYS_LDR_H */
+
+/* Define to 1 if you have the <sys/mman.h> header file. */
+#define HAVE_SYS_MMAN_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define if -lz is available. */
+#define HAVE_ZLIB 1
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+ */
+#define LT_OBJDIR ".libs/"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT ""
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "package-unused"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "package-unused version-unused"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "libbacktrace"
+
+/* Define to the home page for this package. */
+#define PACKAGE_URL ""
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "version-unused"
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Enable extensions on AIX 3, Interix. */
+#ifndef _ALL_SOURCE
+# define _ALL_SOURCE 1
+#endif
+/* Enable GNU extensions on systems that have them. */
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE 1
+#endif
+/* Enable threading extensions on Solaris. */
+#ifndef _POSIX_PTHREAD_SEMANTICS
+# define _POSIX_PTHREAD_SEMANTICS 1
+#endif
+/* Enable extensions on HP NonStop. */
+#ifndef _TANDEM_SOURCE
+# define _TANDEM_SOURCE 1
+#endif
+/* Enable general extensions on Solaris. */
+#ifndef __EXTENSIONS__
+# define __EXTENSIONS__ 1
+#endif
+
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+/* #undef _FILE_OFFSET_BITS */
+
+/* Define for large files, on AIX-style hosts. */
+/* #undef _LARGE_FILES */
+
+/* Define to 1 if on MINIX. */
+/* #undef _MINIX */
+
+/* Define to 2 if the system does not provide POSIX.1 features except with
+ this defined. */
+/* #undef _POSIX_1_SOURCE */
+
+/* Define to 1 if you need to in order for `stat' and other things to work. */
+/* #undef _POSIX_SOURCE */