* Implement batched loop control flow (including, break, continue) along with early outs (return, exit). Also add batched support for printf and other string operations. Implement batched support for shadingsystem ops like bind_interpolated_param, get_userdata, rangecheck, uninitcheck_values, and nancheck. Implement batched support for negate, min/max, arraycopy, compassign, mxcompref, mxcompassign, .Added BATCHED_REGRESSION tests to the suite to exercise control flow and string ops and compare scaler and batched results. Enabled various tests to also execute in BATCHED mode. Enable unoptimized BATCHED mode testing, as constfolding was avoiding any work in optimized mode for some tests.
Fixed bug in testshaded batched mode that inverted population of x and y shader global values, but only noticed in order of side effects like printf in shaders.
Added buffered file support to ShadingSystem to allow batched fprint to write out to files in the correct order.
Fixed bug in BatchedAnalysis which was not handling unlocked geom correctly by requiring unlocked input parameters be varying inorder to accept Wide results from BatchedRendererServices::get_userdata.
LLVM_Util had previously added support managing masks, and its strategy should
be reviewed before trying to understand this commit's changes:
// Overview of masking strategy
//
// For if/then based on a conditional, the result of the conditional is
// conditionals written to a symbol that is a wide boolean. To handle
// nesting we will keep a stack of conditional masks. When a new
// conditional mask is pushed, it is combined with the previous mask on
// the top of the stack. It is the top of the mask stack that is used
// as the mask for any instructions requiring masking. When a
// conditional scope is exited, we just pop the top of the conditional
// mask stack.
//
// Loops are handled by pushing their conditional result onto the
// conditional mask stack, and popping it back off at the end of the
// loop.
//
// Handling of early outs (exit, return, break, continue) is done by
// storing a mask representing the lanes which are going to be
// deactivated (or continue executing) to an allocated location in the
// stack. We actually have to store these early out masks, so that we
// can apply it to the conditional mask stack. As that stack unwinds,
// any early out masks are applied to the top of the conditional mask
// stack. As there are different types of early outs that apply to
// different control flow scopes and multiple types can be present at
// the same time for different data lanes, we must store these early
// out masks at separate locations on the stack.
//
// To handle 'exit', we allocate a 'shader mask' that is initially
// populated with a startMaskValue representing the active lanes in a
// shader global batch. For example perhaps only 7 of 16 data lanes
// are populated, the startMaskValue would store that value and push it
// onto the conditional mask stack. We require a location on the stack
// for this 'shader mask' in order for an 'exit' statement to modify it
// and cause a subset of the lanes to be deactivated. If an exit was
// processed, the 'shader mask' is where it will be stored and pulled
// from when applying to the unwinding conditional mask stack.
//
// To handle 'return', we allocate a 'function mask' that is initially
// populated with a startMaskValue representing the active lanes when
// an inlined function was called. This startMaskValue should just be
// value at the top of the conditional mask stack. As function calls
// can be nested, we maintain a stack of function masks. We require a
// location on the stack for each 'function mask' in order for a
// 'return' statement to modify it and cause a subset of the lanes to
// be deactivated. If an return was processed, the 'return mask' is
// where it will be stored and pulled from when applying to the
// unwinding conditional mask stack. When a function scope is exited,
// the function mask is popped so any return's processed would apply to
// the outer function mask vs. the one just exited.
//
// To handle 'break', we use the condition symbol's location on the
// stack to directly disable data lanes for the loop execution. As we
// already had a location to store the conditional symbol's mask, no
// need to allocate or store a separate one. However code will need to
// reload the condition's value when a break 'could have been' called
// vs. relying on a conditional result already in a register.
//
// To handle 'continue', we allocate a 'continue mask' that is
// initially populated with a 0 representing the deactived lanes by
// 'continue' operations. We require a location on the stack for each
// 'continue mask' in order for a 'continue' statement to modify it and
// cause a subset of the lanes to be deactivated. If an continue was
// processed, the 'continue mask' is where it will be stored and pulled
// from when applying to the unwinding conditional mask stack. When a
// loop's scope is exited, the continue mask is popped so it would't be
// applied to an outer loop.
//
// The logic of when and how to actually apply these masks is handled
// by the caller, tracking/storing the different stacks and masks is
// handled here. And queries exist to see how many early outs
// operations have been processed, these counts can be used by the
// caller to determine which to generate code to apply each of them.
In our case BatchedBackendLLVM is the caller and during code gen will be calling:
push_shader_instance(llvm::Value* startMaskValue) and pop_shader_instance()
push_function_mask(llvm::Value* startMaskValue) and pop_function_mask()
push_masked_loop(llvm::Value* location_of_control_mask, llvm::Value* location_of_continue_mask) and pop_masked_loop()
And to handle if/then/else be calling
push_mask(llvm::Value *mask, bool negate, bool absolute) and pop_mask()
By checking masked_exit_count(), masked_return_count(), masked_break_count(), and masked_continue_count()
before and after code gen of a function call, then block, else block, loop body, etc.
we can detect if a exit, return, break or continue existed in the generated scope
and then can call apply_exit_to_mask_stack(), apply_return_to_mask_stack(),
apply_break_to_mask_stack(), or apply_continue_to_mask_stack() when needed.
Add utility function "foreach_unique" to provide scalar execution of a Functor
for each unique value in the a Wide data block along with a mask identify which
data lanes match the unique value.
Add utility function "unproxy(const T &elem)" to extract value type from a proxied
element. This is alternative to static_cast<ValueType>(elem), and better self documents.
Fixed compatibility bug where llvm 9+ asserted that bool was not a valid datatype for llvm::ConstantDataVector::getSplat.
Added LLVM_Util::test_mask_lane(llvm::Value *mask, llvm::Value * lane_index) to test a mask with a variable lane index.
* Updated OIIO::vformat calls to OIIO::sprintf.
Conditionally compile buffered_file_output_mutex to avoid unused variable warning when not building with USE_BATCHED.
Ran couple files through clang-format.
* Initialize local variable mask_slot to avoid maybe-uninitialized errors
* Fixed paths to additional oiiodiff that runs when a test fails to find a match to use the /baseline subdir when performing a BATCHED_REGRESSION test.
Improved control-flow-test to use 0.5 default value instead of 0 to tell difference between actual assignment and 0's on the heap.
* Changed some control-flow-reg tests to use non-zero default values to tell difference between uninitialized heap and setting of default values.
Changed order of parameters so that any initops that contain an "exit" are the final parameter so the exit doesn't skip assigning default values. Otherwise those parameters would be uninitialized data and cause intermitent CI failures.
* Deleted extraneious cmakefile settings for clang
Signed-off-by: Alex M. Wells <alex.m.wells@intel.com>
0 lines
0 B
Plaintext
0 lines
0 B
Plaintext
The file is empty.