Commit ac07ed82 by Ben Clayton

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: 's avatarBen Clayton <bclayton@google.com> Reviewed-by: 's avatarNicolas Capens <nicolascapens@google.com>
parent 755467c4
......@@ -81,6 +81,7 @@ option (TSAN "Build with thread sanitizer" 0)
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 @@ else()
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 @@ else()
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 @@ elseif(ARCH STREQUAL "arm")
${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 @@ set(COMMON_INCLUDE_DIR
${SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/include
${LLVM_INCLUDE_DIR}
${LIBBACKTRACE_INCLUDE_DIR}
)
set(OPENGL_INCLUDE_DIR
${OPENGL_DIR}
......@@ -2002,9 +2021,41 @@ list(REMOVE_ITEM SWIFTSHADER_LIST
${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 @@ set_target_properties(ReactorLLVM PROPERTIES
)
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")
......
......@@ -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" />
......
......@@ -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>
......
# 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.
......@@ -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 @@ namespace
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 @@ namespace rr
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 @@ namespace rr
}
})),
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
}
}
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 @@ namespace rr
::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 @@ namespace rr
::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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
void Nucleus::createBr(BasicBlock *dest)
{
RR_DEBUG_INFO_UPDATE_LOC();
Variable::materializeAll();
::builder->CreateBr(B(dest));
......@@ -1158,118 +1196,140 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
UShort4::UShort4(RValue<Float4> cast, bool saturate)
{
RR_DEBUG_INFO_UPDATE_LOC();
if(saturate)
{
#if defined(__i386__) || defined(__x86_64__)
......@@ -2043,6 +2180,7 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
RValue<Float4> Frac(RValue<Float4> x)
{
RR_DEBUG_INFO_UPDATE_LOC();
Float4 frc;
#if defined(__i386__) || defined(__x86_64__)
......@@ -3075,6 +3304,7 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
}
#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
}
}
// 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
// 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
// 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
......@@ -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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
if(!address)
{
address = Nucleus::allocateStackVariable(type, arraySize);
RR_DEBUG_INFO_EMIT_VAR(address);
if(rvalue)
{
......@@ -2488,47 +2517,62 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
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 @@ namespace rr
bool setup()
{
RR_DEBUG_INFO_FLUSH();
if(Nucleus::getInsertBlock() != endBB)
{
testBB = Nucleus::createBasicBlock();
......
......@@ -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" />
......
......@@ -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>
......
......@@ -3425,4 +3425,8 @@ namespace rr
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() {}
}
/* 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
/* 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 */
/* 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
/* 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 */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment