Add a pragma option to zero-initialize Reactor local variables MemorySanitizer errors in Reactor routines are either caused by uninitialized heap allocations, incorrect instrumentation (false positives), or uninitialized local variables (including shader variables). To help confirm or eliminate the latter as a possible cause, as well as to provide a convenient means to locate the uninitialized variable through a divide-and-conquer strategy, this change provides the `InitializeLocalVariables` pragma. It is only supported by the LLVM backend, since this is also the only backend which supports MemorySanitizer instrumentation. Bug: b/191149148 Change-Id: I2f58c171e20bbcc19afdbc88bf61bf04a5bf477f Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/53688 Tested-by: Nicolas Capens <nicolascapens@google.com> Reviewed-by: Alexis Hétu <sugoi@google.com> Kokoro-Result: kokoro <noreply+kokoro@google.com>
diff --git a/src/Reactor/LLVMReactor.cpp b/src/Reactor/LLVMReactor.cpp index 5538529..6632ffd 100644 --- a/src/Reactor/LLVMReactor.cpp +++ b/src/Reactor/LLVMReactor.cpp
@@ -17,6 +17,7 @@ #include "CPUID.hpp" #include "Debug.hpp" #include "LLVMReactorDebugInfo.hpp" +#include "PragmaInternals.hpp" #include "Print.hpp" #include "Reactor.hpp" #include "x86.hpp" @@ -631,6 +632,18 @@ entryBlock.getInstList().push_front(declaration); + if(getPragmaState(InitializeLocalVariables)) + { + llvm::Type *i8PtrTy = llvm::Type::getInt8Ty(*jit->context)->getPointerTo(); + llvm::Type *i32Ty = llvm::Type::getInt32Ty(*jit->context); + llvm::Function *memset = llvm::Intrinsic::getDeclaration(jit->module.get(), llvm::Intrinsic::memset, { i8PtrTy, i32Ty }); + + jit->builder->CreateCall(memset, { jit->builder->CreatePointerCast(declaration, i8PtrTy), + V(Nucleus::createConstantByte((unsigned char)0)), + V(Nucleus::createConstantInt((int)typeSize(type) * (arraySize ? arraySize : 1))), + V(Nucleus::createConstantBool(false)) }); + } + return V(declaration); }
diff --git a/src/Reactor/Pragma.cpp b/src/Reactor/Pragma.cpp index 38e22ad..1175352 100644 --- a/src/Reactor/Pragma.cpp +++ b/src/Reactor/Pragma.cpp
@@ -31,6 +31,7 @@ struct PragmaState { bool memorySanitizerInstrumentation = true; + bool initializeLocalVariables = false; int optimizationLevel = 2; // Default }; @@ -69,6 +70,9 @@ case MemorySanitizerInstrumentation: state.memorySanitizerInstrumentation = enable; break; + case InitializeLocalVariables: + state.initializeLocalVariables = enable; + break; default: UNSUPPORTED("Unknown Boolean pragma option %d", int(option)); } @@ -96,6 +100,8 @@ { case MemorySanitizerInstrumentation: return state.memorySanitizerInstrumentation; + case InitializeLocalVariables: + return state.initializeLocalVariables; default: UNSUPPORTED("Unknown Boolean pragma option %d", int(option)); return false;
diff --git a/src/Reactor/Pragma.hpp b/src/Reactor/Pragma.hpp index 3b86a03..ff4f00c 100644 --- a/src/Reactor/Pragma.hpp +++ b/src/Reactor/Pragma.hpp
@@ -22,6 +22,7 @@ enum BooleanPragmaOption { MemorySanitizerInstrumentation, + InitializeLocalVariables, }; enum IntegerPragmaOption
diff --git a/src/Reactor/SubzeroReactor.cpp b/src/Reactor/SubzeroReactor.cpp index 5518086..86abd9b 100644 --- a/src/Reactor/SubzeroReactor.cpp +++ b/src/Reactor/SubzeroReactor.cpp
@@ -104,6 +104,8 @@ auto alloca = Ice::InstAlloca::create(function, address, bytes, typeSize); // SRoA depends on the alignment to match the type size. function->getEntryNode()->getInsts().push_front(alloca); + ASSERT(!rr::getPragmaState(rr::InitializeLocalVariables) && "Subzero does not support initializing local variables"); + return address; }