Commit Graph

706 Commits

Author SHA1 Message Date
alan-baker
354205b3dc
Don't merge unreachable blocks (#2375)
Fixes #2374

* Block merging no longer merges unreachable blocks into their
successors
 * added a test
2019-02-12 09:24:01 -05:00
Ryan Harrison
12b3d7e9d6 Add strip-debug to webgpu-mode passes (#2368)
Fixes #2366
2019-02-08 14:26:17 -05:00
greg-lunarg
cf21146137 Expand bindless bounds checking to runtime-sized descriptor arrays (#2316) 2019-02-07 14:00:36 -05:00
Ryan Harrison
0f4bf0720a
Add flatten-decorations flag to webgpu-mode flags (#2348)
Fixes #2272
2019-02-05 14:07:53 -05:00
Alastair Donaldson
3b6fee3dae Fixes #2338. Added functionality to remove OpPhi instructions (replacing their uses) when merging blocks (#2339)
* Fixes #2338.  Added check for phi node before merging blocks.

* Added functionality to merge blocks A and B even when B starts with OpPhi instructions, by replacing uses of the OpPhi results with the definitions coming from A.  Added some tests for this.

* Fixed assertion.
2019-01-31 09:36:05 -05:00
Steven Perron
464111eaef
Remove use of deprecated googletest macro (#2286)
* Remove use of deprecated googletest macro

INSTANTIATE_TEST_CASE_P has been deprecated.  We need to use
INSTANTIATE_TEST_SUITE_P instead.

* Remove extra commas from test suites.
2019-01-29 18:56:52 -05:00
Steven Perron
8df947d2d6
Handle instructions not in blocks in code sinking. (#2308)
When looking at the uses of the result of an instruction, code sinking
assumes that all uses are in a basic block.  However, this is not true
if there is a decoration or name for the result of that insturction.
This commit checks for this.

Fixes https://crbug.com/923243.
2019-01-21 12:09:56 -05:00
Steven Perron
d6c067630d Handle extract with no index in VDCE. (#2305)
It is legal, but not generated by any SPIR-V producer: an OpCompositeExtract
with no indexes.  This is essentially just a copy of the object, so we
treat them that way.  We simply propagate the live variables of the
result to the operand.

Fixes https://crbug.com/919181.
2019-01-18 15:43:36 -05:00
Steven Perron
81fb2649bf
Handle access chain with no index in SROA. (#2304)
It is legal, but not generated by any SPIR-V producer: an OpAccessChain
with no indexes.  This is essentially just a copy of the pointer.

I have decided to treat it like an OpCopyObject.  In CheckUses, we
return that it is not okay.

When looking at this I realized that we had code in GetUsedComponents
that cannot be reached.  If there is a use in an OpCopyObject the it
will not call GetUsedComponents.  I removed that dead code.

Fixes https://crbug.com/918311.
2019-01-18 14:19:43 -05:00
Steven Perron
213e15e100
Fix overflow when negating INT_MIN. (#2293)
When doing (-INT_MIN) is considered overflow, so we cannot fold it by
actually performing the negation.

Fixes https://crbug.com/917991
2019-01-17 17:01:55 -05:00
Steven Perron
99c2c21cf4
Fix memory leak in unrolling. (#2301)
During unrolling a new loop is created, but its ownership is not clear
as it gets passed through the code. Changed something to unique_ptr to
make that clearer.

Fixes #2299.

Fixing other memory leaks at the same time.

Fixes #2296
Fixes #2297
2019-01-17 16:02:43 -05:00
Steven Perron
dd4157dcee
Sink (#2284)
Add code sinking pass. It will move OpLoad and OpAccessChain instructions as close as possible to their uses.

Part of #1611.
2019-01-17 15:56:36 -05:00
greg-lunarg
8d2d66f30c Fix vertex instrumentation to use VertexIndex and InstanceIndex (#2294)
...instead of VertexId and InstanceId
2019-01-16 18:02:07 -05:00
Steven Perron
49b5b0abc6
Fix up bit shifts by 32. (#2292)
In C++, a bit shift of the same size as the type is undefined, but it is
defined in spir-v.  When folding those cases, we have to be careful.  We
cannot simply do the shift in C++.

Fixes https://crbug.com/917697.
2019-01-16 15:52:23 -05:00
greg-lunarg
83bfdc976a Instrumentation: Add ArrayStride decoration to debug output buffer array (#2290) 2019-01-16 10:01:40 -05:00
alan-baker
06c9dc07bd
Upgrade modf and frexp (#2266)
Fixes #2138

* Modf and frexp are upgraded to use the struct version of the
instruction and generate an explicit store whose flags can be upgraded
separately
* Fixed major bug where availability and visibility were reversed for
non-copy memory instructions
* Fixed bug where availability and visibility scope operands were reversed for copy memory
* Upgraded all opt tests to use SPV_ENV_UNIVERSAL_1_3
* Upgrade tests moved into unified tests and removed standalone test
2019-01-07 12:36:38 -05:00
Steven Perron
241644a5a3
Have replace load size handle extact with no index. (#2261)
Fixes https://crbug.com/917774
2019-01-03 13:02:10 -05:00
Steven Perron
9f36c8bb72
Handle CompositeInsert with no indices in VDCE (#2258)
* Handle CompositeInsert with no indices in VDCE

In the spec, there it nothing that forces an OpCompositeInsert to have
an index, but VDCE assumes there is at least 1 in a couple places.

This commit updates VDCE to handle these cases.
2019-01-02 14:00:04 -05:00
Steven Perron
bdc2ab9356
In LICM don't place code between merge instruction and branch. (#2252)
Fixes #2210.
2018-12-20 18:33:52 -05:00
kholtnv
e49bd96f2c Added additional changes for the new AccelerationStructureNV type. (#2218)
* Added additional changes for the new AccelerationStructureNV type.

* Added additional changes for the new AccelerationStructureNV type.  Change tabs to space...

* Added additional changes for the new accelerationStructureNV type -- add proper type name.

Fix TypeManager.TypeStrings test:
[----------] 29 tests from TypeManager
[ RUN      ] TypeManager.TypeStrings
[       OK ] TypeManager.TypeStrings (7 ms)
2018-12-19 21:42:39 +00:00
Steven Perron
68b69e16aa
Update the continue target in merge return. (#2249)
When we are predicating the continue target for a loop, it can no longer
be the continue target because it will have a branch that exits the loop
and is not the bach edge.  The continue target will have to be the
target of that branch that is still in the loop.

Fixes #2211.
2018-12-19 21:24:49 +00:00
Steven Perron
ac7feace90
Fix missing OpPhi after merge return. (#2248)
The function `UpdatePhiNodes` was being called inconsistently.  In one
case, the cfg had already been updated to include the new edge, and in
another place the cfg was not updated.  This caused the function to
miss flagging a block as needing new phi nodes.  I picked that the cfg
should not be updated before making the call.  I documented it, and
change the call sites to match.

Fixes #2207.
2018-12-19 18:17:42 +00:00
Steven Perron
9d04f82bef
Ensure SROA gets the correct pointer type. (#2247)
We initially assumed that if the type manager returned the correct id
for the pointee type, that we would get the correct pointer type back,
but that is not true.  See the unit test added with this commit.  We
need to fall back to the linear search any time we are looking for a
pointer to a type that may not be unique.

At the same time, SROA considered an OpName on a variable to be a use of
the entire variable.  That has been fixed.

Fixes #2209.
2018-12-19 17:07:29 +00:00
Steven Perron
9e81c337f9
Place load after OpPhi instructions in block. (#2246)
We currently place the load instructions at the start of the basic block
that dominates all of the loads.  If that basic block contains OpPhi
instructions, then this will generate invalid code.  We just need to
search for a location that comes after all of the OpPhi instructions.

Fixes #2204.
2018-12-19 15:18:22 +00:00
Steven Perron
5ec2d1a8cd
Don't fold specialized branches in loop unswitch (#2245)
* Don't fold specialized branchs in loop unswitch

Folding branches can have a lot of special cases, and can be a little
error prone.  So I only want it in one place.  That will be in dead
branch elimination.  I will change loop unswitching to set the branches
that were being folded to have a constant condition.  Then subsequent
pass of dead branch elimination will be able to remove the code.

At the same time, I added a check that loop unswitching will not
unswitch a branch with a constant condition.  It is not useful to do it
because dead branch elimination will simple fold the branch anyway.
Also it avoid an infinite loop that would other wise be introduced by my
first change.

Fixes #2203.
2018-12-19 04:40:30 +00:00
Steven Perron
1254335d13
Don't unswitch the latch block. (#2205)
Loop unswitching is unswitching the conditional branch that creates the
back-edge. In the version of the loop, where the bachedge is not taken,
there is no back-edge. This is what causes the validator to complain.

The solution I will go with will be to now unswitch a condition with a
back-edge. At this time we do not now if loop unswitching is used. We do
not include it in the optimization sets provided, nor is it used in
glslang's set. When there are opportunities and no breaks from the loop,
the loop with either be a single iteration loop, or an infinite loop.
There is no performance advantage to performing loop unswitching in
either of those cases. If there is a break, maintaining structured
control flow will be tricky. Unless we see a clear advantage to handling
these case, I would go with the safer simpler solution.

Fixes #2201.
2018-12-18 18:15:00 +00:00
Steven Perron
ff07c6df83
SSA-rewriter: make sure phi entries are unique. (#2206)
If there are multiple edges to a basic block, then the ssa rewriter will
create OpPhi instructions with duplicate entries.  This is invalid, and
it is fixed in this commit.

Fixes #2202.
2018-12-18 18:14:27 +00:00
Jeff Bolz
24328a0554 Recognize OpTypeAccelerationStructureNV as a type instruction (#2190) 2018-12-11 19:03:55 -05:00
Steven Perron
e07dabc25f
Invalidate the decoration manager at the start of ADCE. (#2189)
* Invalidate the decoration manager at the start of ADCE.

If the decoration manager is kept live the the contex will try to keep
it up to date.  ADCE deals with group decorations by changing the
operands in |OpGroupDecorate| instructions directly without informing
the decoration manager.  This puts it in an invalid state, which will
cause an error when the context tries to update it.  To Avoid this
problem, we will invalidate the decoration manager upfront.

At the same time, the decoration manager is now considered when checking
the consistency of the decoration manager.
2018-12-10 13:24:33 -05:00
Jeff Bolz
8fc8dfe4a5 Add PCH_FILE for upgrade_memory_model target. MSVC doesn't like building pass_utils.cpp twice in the same folder with different PCH settings. (#2186) 2018-12-10 10:54:19 -05:00
Steven Perron
0bc66a8ba9
Fix invalid OpPhi generated by merge-return. (#2172)
* Fix invalid OpPhi generated by merge-return.

When we create a new phi node for a value say %10, we have to replace
all of the uses of %10 that are no longer dominated by the def of %10
by the result id of the new phi.  However, if the use is in a phi node,
it is possible that the bb contains the use is not dominated by either.
In this case, needs to be handled differently.

* Split loop headers before add a new branch to them.

In merge return, Phi node in loop header that are also merges for loop
do not get updated correctly.  Those cases do not fit in with our
current analysis.  Doing this will simplify the code by reducing the
number of cases that have to be handled.
2018-12-07 14:10:30 -05:00
David Neto
6df6194db8
Validate Uniform decoration (#2181) 2018-12-07 09:32:57 -05:00
Steven Perron
2e4563d94f
Document in the context what happens with id overflow. (#2159)
Added documentation to the ir context to indicates that TakeNextId()
returns 0 when the max id is reached.  TODOs were added to each call
sight so that we know where we have to start to handle this case.

Handle id overflow in |SplitLoopHeader|.

Handle id overflow in |GetOrCreatePreHeaderBlock|.

Handle failure to create preheader in LICM.

Part of https://github.com/KhronosGroup/SPIRV-Tools/issues/1841.
2018-12-06 09:07:00 -05:00
Steven Perron
17cba4695c
Remove undefined behaviour when folding shifts. (#2157)
We currently simulate all shift operations when the two operand are
constants.  The problem is that if the shift amount is larger than
32, the result is undefined.

I'm changing the folder to return 0 if the shift value is too high.
That way, we will have defined behaviour.

https://crbug.com/910937.
2018-12-04 10:04:02 -05:00
alan-baker
e510b1bac5
Update memory model (#1904)
Upgrade to VulkanKHR memory model

* Converts Logical GLSL450 memory model to Logical VulkanKHR
* Adds extension and capability
* Removes deprecated decorations and replaces them with appropriate
flags on downstream instructions
* Support for Workgroup upgrades
* Support for copy memory
* Adding support for image functions
* Adding barrier upgrades and tests
* Use QueueFamilyKHR scope instead of device
2018-11-30 14:15:51 -05:00
Steven Perron
2d2a512691
Don't inline recursive functions. (#2130)
* Move ProcessFunction* function from pass to the context.

There are a few functions that are used to traverse the call tree.
They currently live in the Pass class, but they have nothing to do with
a pass, and may be needed outside of a pass.  They would be better in
the ir context, or in a specific call tree class if we ever have a need
for it.

* Don't inline recursive functions.

Inlining does not check if a function is recursive or not.  This has
been fine as long as the shader was a Vulkan shader, which forbid
recursive functions.  However, not all shaders are vulkan, so either
we limit inlining to Vulkan shaders or we teach it to look for recursive
functions.

I prefer to keep the passes as general as is reasonable.  The change
does not require much new code in inlining and gives a reason to refactor
some other code.

The changes are to add a member function to the Function class that
checks if that function is recursive or not.

Then this is used in inlining to not inlining a function call if it calls
a recursive function.

* Add id to function analysis

There are a few places that build a map from ids to Function whose
result is that id.  I decided to add an analysis to the context for this
to reduce that code, and simplify some of the functions.

* Add missing file.
2018-11-29 14:24:58 -05:00
alan-baker
3d56cddb75
Validate pointer variables (#2111)
Fixes #2104

* Checks the rules for logical addressing and variable pointers
 * Has an out for relaxed logical pointers
* Updated PassFixture to expose validator options
 * enabled relaxed logical pointers for some tests
* New validator tests
2018-11-27 16:47:10 -05:00
Ryan Harrison
d7cd1203a4 Ensure for OpVariable that result type and storage class operand agree (#2052)
From SPIR-V spec, section 3.32.8 on OpVariable:
  Its Storage Class operand must be the same as the Storage Class
  operand of the result type.

Fixes #941
2018-11-16 11:22:11 -05:00
greg-lunarg
c37388f1ad Add passes to propagate and eliminate redundant line instructions (#2027). (#2039)
These are bookend passes designed to help preserve line information
across passes which delete, move and clone instructions. The propagation
pass attaches a debug line instruction to every instruction based on
SPIR-V line propagation rules. It should be performed before optimization.
The redundant line elimination pass eliminates all line instructions
which match the previous line instruction. This pass should be performed
at the end of optimization to reduce physical SPIR-V file size.

Fixes #2027.
2018-11-15 14:06:17 -05:00
Steven Perron
dc9d155d62
Fix folding of volatile store. (#2048)
When looking for the Volatile mask on a store, the instruction folder
accesses an out-of-bounds element.  We fix that up.

Fixes crbug.com/903530.
2018-11-14 13:52:18 -05:00
Steven Perron
ec5574a9c6
Instruction::GetBaseAddress to handle OpPtrAccessChain (#2050)
That function currently only handled OpPtrAccessChain if it was in the
middle of the chain, but not at the start.  Fixing that up.

Fixes crbug.com/905271.
2018-11-14 12:42:25 -05:00
greg-lunarg
1e9fc1aac1 Add base and core bindless validation instrumentation classes (#2014)
* Add base and core bindless validation instrumentation classes

* Fix formatting.

* Few more formatting fixes

* Fix build failure

* More build fixes

* Need to call non-const functions in order.

Specifically, these are functions which call TakeNextId(). These need to
be called in a specific order to guarantee that tests which do exact
compares will work across all platforms. c++ pretty much does not
guarantee order of evaluation of operands, so any such functions need to
be called separately in individual statements to guarantee order.

* More ordering.

* And more ordering.

* And more formatting.

* Attempt to fix NDK build

* Another attempt to address NDK build problem.

* One more attempt at NDK build failure

* Add instrument.hpp to BUILD.gn

* Some name improvement in instrument.hpp

* Change all types in instrument.hpp to int.

* Improve documentation in instrument.hpp

* Format fixes

* Comment clean up in instrument.hpp

* imageInst -> image_inst

* Fix GetLabel() issue.
2018-11-08 13:54:54 -05:00
greg-lunarg
6721478ef1 Don't assume one return means function can be inlined. (#2018) (#2025)
If there is only 1 return and it is in a loop, then the function cannot be inlined.

Fix condition when inlined code needs one-trip loop wrapper.  The dummy loop is needed when there is a return inside a selection construct.  Even if there is only 1 return.
2018-11-08 09:11:20 -05:00
Jeff Bolz
c06a35b902 Rename PCH macro to spvtools_pch to avoid conflicts with other projects. Also add pch to test/opt. (#2034) 2018-11-07 09:15:04 -05:00
Jeff Bolz
60fac96c6b Enable precompiled headers for spirv-tools(-shared) and some unit tests (#2026) 2018-11-06 09:26:23 -05:00
Steven Perron
f2cc71e5cb
Handle OpMemberDecorateStringGOOGLE in ACDE (#2029)
Add missing case to the switch statement for the annotation
instructions.

See https://github.com/KhronosGroup/glslang/issues/1561.
2018-11-02 13:42:45 -04:00
dan sinclair
9e6f5134d1
Reduce number of test targets (#2024)
This CL takes the various opt unit tests and makes a single executable
instead of one per test. This reduces the number of build targets by
~125 when building with ninja.
2018-11-01 10:19:37 -04:00
Steven Perron
6647884a13
Remove MemberDecorateStringGOOGLE during stript-refect. (#2021)
The strip-reflect pass is not removing the reflection decorations that
are decorating members.  With this commit, they will now be removed.

Fixes #2019.
2018-10-30 16:17:35 -04:00
Steven Perron
18fe6d59e5
Fix dead branch elim infinite loop. (#2009)
When looking for a break from a selection construct, we do not realize
that a jump to the continue target of a loop containing the selection
is a break.  This causes and infinit loop, or possibly other failures.

Fixes #2004.
2018-10-24 09:10:30 -04:00
Steven Perron
0ba35798c3
Fix dead branch elim infinite loop. (#1997)
When looking for a break from a selection construct, we do not need to
look inside nested constructs.  However, if a loop header has an
unconditional branch, then we enter the loop.  Entering the loop causes
an infinite loop because we keep going through the loop.

The solution is to look for a merge block, if one exsits, even for block
terminated by an OpBranch.

Fixes #1979.
2018-10-22 13:59:20 -04:00
alan-baker
6e85d1a6fc
Fix restrictions in if conversion (#1998)
Fixes #1991

* Improved identification of potential conditional branches
* Pass changed to only work for shaders
* added a test to catch the bug
2018-10-19 15:16:46 -04:00
Steven Perron
715afb0cea
Add a nullptr check to array copy propagation. (#1987)
We are missing a check for a nullptr that is causing things to fail.

Added an extra test case, and fixed up others.

This is the fix for https://github.com/Microsoft/DirectXShaderCompiler/issues/1598.
2018-10-19 12:53:40 -04:00
greg-lunarg
c4687889b7 Fix ADCE to treat OpUnreachable correctly during liveness analysis (#1984)
ADCE liveness algorithm should treat OpUnreachable at least like other
branch instructions. It was being treated as always live which was
preventing useless structured constructs from being eliminated.
OpUnreachable is generated by dead branch elimination which is now
being required by merge return, so this fix should accompany that
change.
2018-10-19 10:16:35 -04:00
Steven Perron
0e68bb3632
Only run merge-returnon reachable functions. (#1983)
We currently run merge-return on all functions, but
dead-branch-elimination only runs on function reachable from an entry
point or exported function.  Since dead-branch-elimination is needed for
merge-return, they have to match.

Fixes #1976.
2018-10-18 08:48:27 -04:00
greg-lunarg
ab45d69154 Fix ADCE liveness to include all enclosing control structures. (#1975)
Was removing control structures which didn't have data dependency
with enclosed live loop and otherwise did not contain live code.
An example is a counting loop around a live loop.

Fixes #1967.
2018-10-16 08:00:07 -04:00
Nuno Subtil
5bc30788fd Fix gtest.h include in test/opt/pass_utils.h
Fixes builds where googletest is outside the SPIRV-Tools tree.
2018-10-12 10:22:25 -04:00
Steven Perron
82663f34c9
Check for unreachable blocks in merge-return. (#1966)
Merge return assumes that the only unreachable blocks are those needed
to keep the structured cfg valid.  Even those must be essentially empty
blocks.

If this is not the case, we get unpredictable behaviour.  This commit
add a check in merge return, and emits an error if it is not the case.

Added a pass of dead branch elimination before merge return in both the
performance and size passes.  It is a precondition of merge return.

Fixes #1962.
2018-10-10 15:18:15 -04:00
Steven Perron
4e266f775a
Fold divisions by 0. (#1963)
The current implementation in the folder when seeing a division by zero
is to assert.  In the release build, the compiler will attempt to
compute the value, which causes its own problems.

The solution I will go with is to fold the division, and just give it
the value of 0.  The same goes for remainder and mod operations.

Fixes #1961.
2018-10-10 11:17:26 -04:00
alan-baker
fae1e61ab8
Fix bug in construct block calculation (#1964)
Fixes #1960

* Only allows blocks that are dominated by the header
* Fixed a bad loop fusion test
* Added a test derived from the reported bug
2018-10-10 11:14:01 -04:00
Steven Perron
497958d899 Removing HLSLCounterBuffer decorations when not needed. (#1954)
The HlslCounterBufferGOOGLE that was introduced changed the OpDecorateId
so that is can now reference an id other than the target.  If that other
id is used only in the decoration, then the definition of the id will be
removed because decoration do not count as real uses.

However, if the target of the decoration is still live the decoration
will not be removed.  This leaves a reference to an id that is not
defined.

There are two solutions to consider.  The first is that is the decoration
is kept, then the definition of the id should be kept live.  Implementing
this change would be involved because the way ADCE handles decorations
will have to be reimplemented.

The other solution is to remove the decoration the id is otherwise dead.
This works for this specific case.  Also this is the more desirable
behaviour in this case.  The id will always be the id of a variable that
belongs to a descriptor set.  If that variable is not bound and we do
not remove it, the driver will complain.

I chose to implement the second solution.  The first will be left to when
a case for it comes up.

Fixes https://github.com/KhronosGroup/SPIRV-Tools/issues/1885.
2018-10-05 08:23:09 -04:00
Jaebaek Seo
ebcc58b5f8 Validator: function scope variable at start of entry block #1923
All OpVariable instructions in a function must be the first
instructions in the first block.
2018-10-04 15:05:47 -04:00
Alan Baker
3b5960174f Don't scalarize spec constant sized arrays
Fixes #1952

* Prevent scalarization of arrays that are sized by a specialization
constant
2018-10-04 11:58:23 -04:00
Steven Perron
c4c68712c4
Make EFFCEE required (#1943)
Fixes #1912.

Remove the non-effcee build as EFFCEE is now required.
2018-10-04 10:00:11 -04:00
Alan Baker
a77bb2e54b Add validation for execution modes
* Check rules from Execution Mode tables, 2.16.2 and the Vulkan
environment spec

* Allows MeshNV execution model with the following execution modes
 * LocalSize, LocalSizeId, OutputPoints and OutputVertices
 * Done to not break their validation
2018-10-02 10:22:23 -04:00
Steven Perron
146eb3bdcf
Fix erroneous uses of the type manager in copy-prop-arrays. (#1942)
There are a few spots where copy propagate arrays is trying
to go from a Type to an id, but the type is not unique.  When generating
code this pass needs specific ids, otherwise we get type mismatches.
However, the ambigous types means we can sometimes get the wrong type
and generate invalid code.

That code has been rewritten to not rely on the type manager, and just
look at the instructions instead.

I have opened https://github.com/KhronosGroup/SPIRV-Tools/issues/1939 to
try to get a way to make this more robust.
2018-10-01 14:45:44 -04:00
Steven Perron
32381e30ef
Handle decoration groups with no decorations. (#1921)
In DecorationManager::RemoveDecorationsFrom, we do not remove the id
from a decoration group if the group has no decorations.  This causes
problems because KillNamesAndDecorates is suppose to remove all
references to the id, but in this case, there is still a reference.

This is fixed by adding a special case.

Also, there is the possibility of a double free because
RemoveDecorationsFrom will delete the instructions defining |id| when
|id| is a decoration group.  Later, KillInst would later write to memory
that has been deleted when trying to turn it into a Nop.  To fix this,
we will only remove the decorations that use |id| and not its definition
in RemoveDecorationsFrom.
2018-09-28 14:16:04 -04:00
Steven Perron
b85fb4a300
Get KillNameAndDecorates to handle group decorations. (#1919)
It seems like the current implementation of KillNameAndDecorates does
not handle group decorations correctly.  The id being removed is not
removed from the OpGroupDecorate instructions.  Even worst, any
decorations that apply to that group are removed.

The solution is to use the function in the decoration manager that will
remove the decorations and update the instructions instead of doing the
work itself.
2018-09-25 12:57:44 -04:00
Lei Zhang
9bfe0eb25e Wrap tests needing effcee inside SPIRV_EFFCEE 2018-09-20 11:51:40 -04:00
Steven Perron
9fbcce4ca1
Add unrolling to the legalization passes (#1903)
Adds unrolling to the legalization passes.

After enabling unrolling I found a bug when there is a self-referencing
phi node.  That has been fixed.

The test that checks for that the order of optimizations is correct also
needed to be updated.
2018-09-19 16:40:09 -04:00
Steven Perron
7075c49923
Add dummy loop in merge-return. (#1896)
The current implementation of merge return can create bad, but correct,
code.  When it is not in a loop construct, it will insert a lot of
extra branch around code.  The potentially large number of branches are
bad.  At the same time, it can separate code store to variables from
its uses hiding the fact that the store dominates the load.

This hurts the later analysis because the compiler thinks that multiple
values can reach a load, when there is really only 1.  This poorer
analysis leads to missed optimizations.

The solution is to create a dummy loop around the entire body of the
function, then we can break from that loop with a single branch.  Also
only new merge nodes would be those at the end of loops meaning that
most analysies will not be hurt.

Remove dead code for cases that are no longer possible.

It seems like some drivers expect there the be an OpSelectionMerge
before conditional branches, even if they are not strictly needed.
So we add them.
2018-09-18 08:52:47 -04:00
Steven Perron
5f599e700e
Fix infinite loop in dead-branch-elimination (#1891)
* Create structed cfg analysis.

There are lots of optimization that have to traverse the CFG in a
structured order just because it wants to know which constructs a
basic block in contained in.  This adds extra complexity to these
optimizations, for causes too much refactoring of older optimizations.

To help with this problem, I have written an analysis that can give this
information.

* Identify branches breaking from loops.

Dead branch elimination does a search for a conditional branch to the
end of the current selection construct.  This search assumes that the
only way to leave the construct is through the merge node.  But that is
not true.  The code can jump to the merge node of a loop that contains
the construct.

The search needs to take this into consideration.
2018-09-17 13:00:24 -04:00
Steven Perron
6d5f1bc2e8
Allow merge blocks to merge two header blocks in some cases. (#1890)
In merge blocks, we do not allow the merging of two blocks with merge
instructions.  This is because if the two block are merged only 1 of
those instructions can exists.  However, if the successor block is the
merge block of the predecessor, then we can delete the merge instruction
in the predecessor.  In this case, we are able to merge the blocks.
2018-09-14 13:37:18 -04:00
Steven Perron
75c1bf2843
Add option for the max id bound. (#1870)
* Create a new entry point for the optimizer

Creates a new struct to hold the options for the optimizer, and creates
an entry point that take the optimizer options as a parameter.

The old entry point that takes validator options are now deprecated.
The validator options will be one of the optimizer options.

Part of the optimizer options will also be the upper bound on the id bound.

* Add a command line option to set the max value for the id bound.  The default is 0x3FFFFF.

* Modify `TakeNextIdBound` to return 0 when the limit is reached.
2018-09-10 11:49:41 -04:00
Steven Perron
d746681fe9
Copy decorations when creating new ids. (#1843)
* Copy decorations when creating new ids.

When creating a new value based on an old value, we need to copy the
decorations to the new id.  This change does this in 3 places:

1) The variable holding the return value of the function generated by
merge return should get decorations from the function.

2) The results of the OpPhi instructions should get decorations from the
variable they are replacing in the ssa writer.

3) In local access chain convert the intermediate struct (result of
OpCompositeInsert) generated for the store replacement should get its
decorations from the variable being stored to.

Fixes #1787.
2018-08-24 11:55:39 -04:00
Steven Perron
b4d3618f77
Don't "break" from selection constructs. (#1862)
If seems like at least 1 driver does not like a condition jump to the end
of a selection construct.  We are generating these in the merge return
pass.  This change stops merge return from generating this sequence.

Part of #1861.
2018-08-23 14:38:25 -04:00
Steven Perron
6c73b1fb70
Update the order when predicating blocks. (#1859)
When doing predicate blocks, we need to traverse every block in
structured order in order to keep track of which construct a block is
contained in.  The standard way of traversing code in structured order
is to create a list with all of the nodes in order.  However, when
predicating blocks, new blocks are created, and those blocks are missed.
This causes branches that go too far.

The solution is to update the order as new blocks are created.  Since
we are using an std::list, we do not have to worry about invalidation of
iterators when changing the list.
2018-08-23 12:59:31 -04:00
Steven Perron
19264ef42c
Have PredicateBlocks jump the existing merge blocks. (#1849)
* Refactor PredicateBlocks

Refactor PredicateBlocks so that we know which constructs a return
is contained in.  Will be used later.

* Have PredicateBlocks jump the existing merge blocks.

In PredicateBlocks, we currently skip instructions with side effects,
but it still follows the same control flow (sort-of).  This causes a
problem, when we are trying to predicate code in a loop.  We skip all
of the code with side effects (IV increment), but still follow the
same control flow (jump back the start of the loop).  This creates an
infinite loop because the code will keep jumping back to the start of
the loop without changing the values that effect the exit condition.

This is a large change to merge-return.  When predicating a block that
is in a loop or merge construct, it will jump to the merge block of the
construct.  Once out of all constructs we will generate code as we did
before.
2018-08-21 12:04:08 -04:00
Steven Perron
d693a83e36
Handle breaks from structured-ifs in DCE. (#1848)
* Handle breaks from structured-ifs in DCE.

dead code elimination assumes that are conditional branches except for
breaks and continues in loops will have an OpSelectionMerge before them.
That is not true when breaking out of a selection construct.

The fix is to look for breaks in selection constructs in the same place
we look for breaks and continues for loops.
2018-08-21 11:54:44 -04:00
Steven Perron
45c235d41f
Have dead-branch-elim handle conditional exits from selections. (#1850)
When dead-branch-elim folds a conditional branch, it also deletes the
OpSelectionMerge instruction.  If that construct contains a
conditional branch to the merge node, it will not have its own
OpSelectionMerge.  When the headers merge instruction is deleted, the
the inner conditional branch will no longer be legal.  It will be a
selection to a node that is not a merge node.

We fix this up by moving the OpSelectionMerge to a new location if it is
still needed.
2018-08-21 11:49:56 -04:00
Steven Perron
e065cc208f
Keep decorations when replacing loads in access-chain-convert. (#1829)
In local-access-chain-convert, we replace loads by load the entire
variable, then doing the extract.  The extract will have the same value
as the load.  However, if the load has a decoration on it, the
decoration is lost because we do not copy any them to the new id.

This is fixed by rewritting the load into the extract and keeping the
same result id.

This change has the effect that we do not call DCEInst on the loads
because the load is not being deleted, but replaced.  This could leave
OpAccessChain instructions around that are not used.  This is not a
problem for -O and -Os.  They run local_single_*_elim passes and then
dead code elimination.  The dce will remove the unused access chains,
and the load elimination passes work even if there are unused access
chains.  I have added test to them to ensure they will not loss
opportunities.

Fixes #1787.
2018-08-15 09:14:21 -04:00
dan sinclair
ef678672fb
Remove source/message.h (#1838)
The code in source/message was only used in a single set of tests to
format the output results. This CL changes the test to verify the
message instead of all the error values and removes the source/message
code.
2018-08-14 15:41:21 -04:00
dan sinclair
1963a2dbda
Use MakeUnique. (#1837)
This CL replaces instances of reset(new ..) with MakeUnique.
2018-08-14 15:01:50 -04:00
dan sinclair
1553025f4c
Move make_unique to source/util. (#1836)
This MakeUnique code is used in places other then source/opt so move it
to source/utils.
2018-08-14 12:44:54 -04:00
Steven Perron
5c8b4f5a1c
Validate the input to Optimizer::Run (#1799)
* Run the validator in the optimization fuzzers.

The optimizers assumes that the input to the optimizer is valid.  Since
the fuzzers do not check that the input is valid before passing the
spir-v to the optimizer, we are getting a few errors.

The solution is to run the validator in the optimizer to validate the
input.

For the legalization passes, we need to add an extra option to the
validator to accept certain types of variable pointers, even if the
capability is not given.  At the same time, we changed the option
"--legalize-hlsl" to relax the validator in the same way instead of
turning it off.
2018-08-08 11:16:19 -04:00
dan sinclair
05057c9846
Fixup readabilty/inheritance warnings (#1805)
This CL removes the un-needed virtual qualifiers from methods already
marked as override.
2018-08-07 09:10:03 -04:00
dan sinclair
eda2cfbe12
Cleanup includes. (#1795)
This Cl cleans up the include paths to be relative to the top level
directory. Various include-what-you-use fixes have been added.
2018-08-03 15:06:09 -04:00
dan sinclair
7861df9bb3
Remove using namespace commands. (#1794)
This CL removes the last two 'using namespace' commands.
2018-08-03 08:05:52 -04:00
dan sinclair
58a6876cee
Rewrite include guards (#1793)
This CL rewrites the include guards to make PRESUBMIT.py include guard
check happy.
2018-08-03 08:05:33 -04:00
Steven Perron
ce644d4a24
Update OpPhi instructions after splitting block. (#1783)
In the merge return pass, we will split a block, but not update the phi
instructions that reference the block.  Since the branch in the original
block is now part of the block with the new id, the phi nodes must be
updated.

This commit will change this.

I have also considered other places where an id of a basic block could
be referenced, and I don't think any of them need to change.

1) Branch and merge instructions: These jump to the start of the
original block, and so we want them to jump to the block that uses the
original id.  Nothing needs to change.

2) Names and decorations: I don't think it matters with block keeps the
name, and there are no decorations that apply to basic blocks.

Fixes #1736.
2018-08-02 11:02:50 -04:00
Steven Perron
c8c724cba7
Don't change decorations and names in merge return. (#1777)
When creating a new phi for a value in the function, merge return will
rewrite all uses of an id that are no longer dominated by its
definition.  Uses that are not in a basic block, like OpName or
decorations, are not dominated, but they should not be replaced.

Fixes #1736.
2018-08-01 13:47:09 -04:00
Alan Baker
755e5c9420 Transform to combine consecutive access chains
* Combines OpAccessChain, OpInBoundsAccessChain, OpPtrAccessChain and
OpInBoundsPtrAccessChain
* New folding rule to fold add with 0 for integers
 * Converts to a bitcast if the result type does not match the operand
 type
V
2018-07-31 13:42:47 -04:00
Diego Novillo
99fe61e724 Add API to create passes out of a list of command-line flags.
This re-implements the -Oconfig=<file> flag to use a new API that takes
a list of command-line flags representing optimization passes.

This moves the processing of flags that create new optimization passes
out of spirv-opt and into the library API.  Useful for other tools that
want to incorporate a facility similar to -Oconfig.

The main changes are:

1- Add a new public function Optimizer::RegisterPassesFromFlags. This
   takes a vector of strings.  Each string is assumed to have the form
   '--pass_name[=pass_args]'.  It creates and registers into the pass
   manager all the passes specified in the vector.  Each pass is
   validated internally.  Failure to create a pass instance causes the
   function to return false and a diagnostic is emitted to the
   registered message consumer.

2- Re-implements -Oconfig in spirv-opt to use the new API.
2018-07-27 15:10:08 -04:00
Alan Baker
b49f76fd62 Handle undef literal value in vector shuffle
Fixes #1731

* Updated folding rules related to vector shuffle to account for the
undef literal value:
 * FoldVectorShuffleFeedingShuffle
 * FoldVectorShuffleFeedingExtract
 * FoldVectorShuffleWithConstants
* These rules would commit memory violations due to treating the undef
literal value as an accessible composite component
2018-07-20 11:32:43 -04:00
Alan Baker
3c19651733 Add variable pointer support to IsValidBasePointer
Fixes #1729

* Adds supported opcodes to IsValidBasePointer() enable by
VariablePointers and VariablePointersStorageBuffer capabilities
 * Added tests
2018-07-19 14:43:59 -04:00
Alan Baker
28199b80b7 Fix block ordering in dead branch elim
Fixes #1727

* If the pass finds any dead branches it can optimize then at the end of
the pass it reorders basic blocks to ensure they satisfy block ordering
requirements
 * Added some new tests
* While investigating this issue, found and fixed a non-deterministic
ordering of dominators
 * Now the edges used to construct the dominator tree are sorted
 according to posorder traversal indices
2018-07-19 11:17:57 -04:00
Steven Perron
208921efe8 Fix finding constant with particular type. (#1724)
With current implementation, the constant manager does not keep around
two constant with the same value but different types when the types
hash to the same value. So when you start looking for that constant you
will get a constant with the wrong type back.

I've made a few changes to the constant manager to fix this.  First off,
I have changed the map from constant to ids to be an std::multimap.
This way a single constant can be mapped to mutiple ids each
representing a different type.

Then when asking for an id of a constant, we can search all of the ids
associated with that constant in order to find the one with the correct
type.
2018-07-16 12:36:53 -04:00
Steven Perron
95b4d47e34 Fix infinite loop while folding OpVectorShuffle (#1722)
When folding an OpVectorShuffle where the first operand is defined by
an OpVectorShuffle, is unused, and is equal to the second, we end up
with an infinite loop.  This is because we think we change the
instruction, but it does not actually change.  So we keep trying to
folding the same instruction.

This commit fixes up that specific issue.  When the operand is unused,
we replace it with Null.
2018-07-13 12:43:00 -04:00
Steven Perron
63c1d8fb15
Fix size error when folding vector shuffle. (#1721)
When folding a vector shuffle that feeds another vector shuffle causes
the size of the first operand to change, when other indices have to be
adjusted reletive to the new size.
2018-07-13 11:20:02 -04:00
dan sinclair
e477e7573e
Remove the module from opt::Function. (#1717)
The function class provides a {Set|Get}Parent call in order to provide
the context to the LoopDescriptor methods. This CL removes the module
from Function and provides the needed context directly to LoopDescriptor
on creation.
2018-07-12 14:42:05 -04:00
dan sinclair
a5e4a53217
Remove context() method from opt::Function (#1700)
This CL removes the context() method from opt::Function. In the places
where the context() was used we can retrieve, or provide, the context in
another fashion.
2018-07-12 10:16:15 -04:00
dan sinclair
f96b7f1cb9
use Pass::Run to set the context on each pass. (#1708)
Currently the IRContext is passed into the Pass::Process method. It is
then up to the individual pass to store the context into the context_
variable. This CL changes the Run method to store the context before
calling Process which no-longer receives the context as a parameter.
2018-07-12 09:08:45 -04:00
Steven Perron
e63551deac Add folding rule to merge a vector shuffle feeding another one. 2018-07-11 14:44:46 -04:00
dan sinclair
2cce2c5b97
Move tests into namespaces (#1689)
This CL moves the test into namespaces based on their directories.
2018-07-11 09:24:49 -04:00
dan sinclair
84846b7e76
Cleanup whitespace lint warnings. (#1690)
This CL cleans up the whitespace warnings and enables the check when
running 'git cl presubmit --all -uf'.
2018-07-10 13:09:46 -04:00
Sean Purcell
9532aede29 Fix unused param errors when Effcee not present 2018-07-10 11:57:42 -04:00
dan sinclair
a3e3869540
Convert validation to use libspriv::Instruction where possible. (#1663)
For the instructions which execute after the IdPass check we can provide
the Instruction instead of the spv_parsed_instruction_t. This
Instruction class provides a bit more context (like the source line)
that is not available from spv_parsed_instruction_t.
2018-07-10 10:57:52 -04:00
dan sinclair
e6b953361d
Move the ir namespace to opt. (#1680)
This CL moves the files in opt/ to consistenly be under the opt::
namespace. This frees up the ir:: namespace so it can be used to make a
shared ir represenation.
2018-07-09 11:32:29 -04:00
dan sinclair
3dad1cda11
Change libspirv to spvtools namespace (#1678)
This CL changes all of the libspirv namespace code to spvtools to match
the rest of the code base.
2018-07-07 09:38:00 -04:00
Steven Perron
a45d4cac61 Move folding routines into a class
The folding routines are currently global functions.  They also rely on
data in an std::map that holds the folding rules for each opcode.  This
causes that map to not have a clear owner, and therefore never gets
deleted.

There has been a request to delete this map.  To implement this, we will
create a InstructionFolder class that owns the maps.  The IRContext will
own the InstructionFolder instance.  Then the global functions will
become public memeber functions of the InstructionFolder.

Fixes https://github.com/KhronosGroup/SPIRV-Tools/issues/1659.
2018-07-05 17:52:43 -04:00
Steven Perron
9ecbcf5fc8 Make sure the constant folder get the correct type.
There are a few locations where we need to handle duplicate types.  We
cannot merge them because they may be needed for reflection.  When this
happens we need do some extra lookups in the type manager.

The specific fixes are:

1) When generating a constant through `GetDefiningInstruction` accept
and use an id for the desired type of the constant.  This will make sure
you get the type that is needed.

2) In Private-to-local, make sure we to update the def-use chains when a
new pointer type is created.

3) In the type manager, make sure that `FindPointerToType` returns a
pointer that points to the given type and not a duplicate type.

4) In scalar replacment, make sure the null constants that are created
are the correct type.
2018-07-05 14:34:30 -04:00
Steven Perron
465f2815cb Revert change and stop running remove duplicates.
Revert "Don't merge types of resources"

This reverts commit f393b0e480, but leaves
the tests that were added.  Added new test. These test are the so that,
if someone tries the same change I made, they will see the test that
they need to handle.

Don't run remove duplicates in -O and -Os

Romve duplicates was run to help reduce compile time when looking for
types in the type manager.  I've run compile time test on three sets
of shaders, and the compile time does not seem to change.

It should be safe to remove it.
2018-06-29 14:09:44 -04:00
Steven Perron
2eb9bfb5b6 Remove stores of undef.
When storing an undef, any value is valid, including the one already in
that memory location.  So we can avoid the store.
2018-06-29 09:49:19 -04:00
Greg Roth
7cc9f36283 Add test for CFG alteration by compact IDs
The Compact IDs pass can corrupt the CFG, but first the CFG has to
be setup. To do this, a test that builds the CFG, then performs the
compact IDs pass, then checks context consistency.

Fixes https://github.com/KhronosGroup/SPIRV-Tools/issues/1648
2018-06-28 08:48:34 -06:00
Steven Perron
f393b0e480 Don't merge types of resources
When doing reflection users care about the names of the variable, the
name of the type, and the name of the members.  Remove duplicates breaks
this because it removes the names one of the types when merging.

To fix this we have to keep the different types around for each
resource.  This commit adds code to remove duplicates to look for the
types uses to describe resources, and make sure they do not get merged.

However, allow merging of a type used in a resource with something not
used in a resource.  Was done when the non resource type came second.

This could have a negative effect on compile time, but it was not
expected to be much.

Fixes https://github.com/KhronosGroup/SPIRV-Tools/issues/1372.
2018-06-27 13:57:07 -04:00
Alan Baker
0d43e10b4a Use type id when looking up vector type
Fixes #1634

* Vector components of composite constructs used wrong accessor
2018-06-25 09:47:29 -04:00
Corentin Wallez
ba602c9059 Add a WIP WebGPU environment. It disallows OpUndef
Add SPV_ENV_WEBGPU_0 for work-in-progress WebGPU.

val: Disallow OpUndef in WebGPU env

Silence unused variable warnings when !defined(SPIRV_EFFCE)

Limit visibility of validate_instruction.cpp's symbols
  Only InstructionPass needs to be visible so all other functions are put
  in an anonymous namespace inside the libspirv namespace.
2018-06-21 15:53:15 -04:00
Alan Baker
4f866abfd8 Validate static uses of interfaces
Fixes #1120

Checks that all static uses of the Input and Output variables are listed
as interfaces in each corresponding entry point declaration.
 * Changed validation state to track interface lists
 * updated many tests
* Modified validation state to store entry point names
 * Combined with interface list and called EntryPointDescription
 * Updated uses
* Changed interface validation error messages to output entry point name
in addtion to ID
2018-06-13 10:56:14 -04:00
David Neto
700ebd3442 Make fewer test executables
Try to reduce the amount of disk space used by especially by debug builds,
which may be contributing to AppVeyor failures.

Collapses tests in categories:
- validator
- loop optimizations
- dominator analysis
- linker

Contributes to #1615
2018-06-12 09:48:42 -04:00
Alan Baker
06de86863b Check for invalid branches into construct body.
Fixes #1281

* New structured cfg check: all non-construct header blocks'
predecessors must come from within the construct
* New function to calculate blocks in a construct

* Fixed a bug in BasicBlock type bitset

Relaxing check to not consider unreachable predecessors

* Fixing broken common uniform elim test
2018-06-11 19:23:44 -04:00
Steven Perron
fe2fbee294 Delete the insert-extract-elim pass.
Replaces anything that creates an insert-extract-elim pass and create
a simplifiation pass instead.  Then delete the implementation of the
pass.

Fixes https://github.com/KhronosGroup/SPIRV-Tools/issues/1570.
2018-06-01 10:13:39 -04:00
Steven Perron
9a008835f4 Add store for var initializer in inlining.
Fixes https://github.com/KhronosGroup/SPIRV-Tools/issues/1591.
2018-06-01 09:44:42 -04:00
Steven Perron
93c4c184d5 Handle types with self references.
By using forward pointers, we are able to define a struct that has a
pointer to itself.  This could be directly or indirectly.  The current
implementation of the type manager did not handle this case.  There are
three changes that are made in this commit inorder to handle this case:

1) Change the handling of OpTypeForwardPointer

The current handling of OpTypeForwardsPointer is broken if there is a
reference to the pointer before the real definition.  When build the
type that contain the forward delared pointer, the type manager will ask
for the type for that ID, and will get a nullptr because it does not
exists.  This nullptr is not handleded very well.

The change is to keep track of the incomplete types the first time
through all of the types.  An incomplete type is a ForwardPointer or any
type that references an incomplete type.

Then we implement a second pass through the incomplete types that will
complete them.

2) Hashing types.

When hashing a type, we want to uses all of the subtypes as part of the
hash.  However, with types that reference them selves, this creates an
infinite recursion.  To get around this, we keep track of which types
have been seen on the path from the root type.  If we have see the
current type already then we can stop the recursion.

3) Comparing types.

In order to check if two types are the same, we must check that all of
their subtypes are the same as well.  This also causes an infinit
recursion.  The solution is to stop comparing the subtypes if we are
trying to compare two pointer types that we are already in the middle of
comparing.  The ideas is that if the two pointer are different, then in
progress compare will return false itself.

Fixes https://github.com/KhronosGroup/SPIRV-Tools/issues/1578.
2018-05-30 15:48:38 -04:00
Steven Perron
745dd00af9 Fold FMix feeding Extract, and use the simplification pass.
We add a new rule to the folding rules to fold an FMix feeding an
extract when the alpha value for the element being extracted is either
0 or 1.  In those case, we can simple extract from one of the operands
to the FMix.

With that change the simplification pass completely subsumes the
insert-extract elimination pass.  So we remove the insert-extract
elimination passes and replce them with calls to the simplification
pass.

In a follow up PR, we should delete the insert-extract elimination pass.

Contributes to https://github.com/KhronosGroup/SPIRV-Tools/issues/1570.
2018-05-25 14:42:59 -04:00
Steven Perron
a579e720a8 Remove the limit on struct size in SROA.
Removes the limit on scalar replacement for the lagalization passes.
This is done by adding an option to the pass (and command line option)
to set the limit on maximum size of the composite that scalar
replacement is willing to divide.

Fixes #1494.
2018-05-18 10:03:46 -04:00
Steven Perron
f1f7cc870e Get ADCE to handle OpCopyMemory
ADCE does not treat OpCopyMemory as an instruction that references
memory.  Because of that stores are removed that should not be.

This change teaches ADCE that OpCopyMemory and OpCopyMemorySize both
loads from and stores to memory.  This will keep other stores live when
needed, and will allows ADCE to remove OpCopyMemory instructions as
well.

Fixes https://github.com/KhronosGroup/SPIRV-Tools/issues/1556.
2018-05-16 13:50:47 -04:00
Steven Perron
9b1a938ea1 SROA: Only create symbols that are loaded.
Currently in scalar replacement, we create a new variable for every
memeber of the composite being divided.  It is often overkill, because
not all of those members will be used.  This change will check which
elements are used and only create variable for the members that are
used.

This reduces the compile time for one set of shader from 248s to 165s.

Part of https://github.com/KhronosGroup/SPIRV-Tools/issues/1494.
2018-05-16 10:48:25 -04:00
Steven Perron
0e1b7e5aef Fix getting operand without checking opcode.
Fixes https://github.com/KhronosGhttps://github.com/KhronosGroup/SPIRV-Tools/issues/1559roup/SPIRV-Tools/issues/1559.

There is an load of an operand of an instruction that was suppose to be
only for the OpCompositeExtract case.  However, an error caused it to
be loaded for every opcode, even those that do not have an operand in
that position.

We fix up that bug, and a couple other things noticed that the same
time.
2018-05-16 09:34:43 -04:00
alan-baker
18ad1be7f9 Fixing MacOS compiler error 2018-05-15 12:23:27 -04:00
Steven Perron
f46f2d3e5d Remove redundant stores.
The code patterns generated by DXC around function calls can cause many
store to be storing the same value that was just loaded from the same
location:

```
%10 = OpLoad %type %var
OpStore %var %10
```

We want to clean these up very early on because they can cause other
transformations to do a lot of work.  For the cases I see, they can be
removed during local-single-block-elim.

For one set of shaders the compile time goes from 248s to 182s.  A 26%
improvement.

Part of https://github.com/KhronosGroup/SPIRV-Tools/issues/1494.
2018-05-15 10:24:05 -04:00
Steven Perron
af430ec822 Add pass to fold a load feeding an extract.
We have already disabled common uniform elimination because it created
sequences of loads an entire uniform object, then we extract just a
single element.  This caused problems in some drivers, and is just
generally slow because it loads more memory than needed.

However, there are other way to get into this situation, so I've added
a pass that looks specifically for this pattern and removes it when only
a portion of the load is used.

Fixes #1547.
2018-05-14 15:40:34 -04:00
Steven Perron
804e8884c4 Fold fclamp feeding compare.
An FClamp instruction forces a values to be within a certain interval.
When the upper or lower bound of the FClamp is a constant and the value
being compared with is a constant, then in some case we can fold the
compared because the entire range is say less than the value.

Fixes https://github.com/KhronosGroup/SPIRV-Tools/issues/1549.
2018-05-14 10:27:49 -04:00
Steven Perron
9ec3f81e5c Remove dead Workgroup variables in ADCE.
If there is a shader with a variable in the workgroup storage class that
is stored to, but not loadeds, then we know nothing will read those
loads.  It should be safe to remove them.

This is implemented in ADCE by treating workgroup variables the same
way that private variables are treated.

Fixes https://github.com/KhronosGroup/SPIRV-Tools/issues/1550.
2018-05-09 16:07:26 -04:00
Steven Perron
7d01643132 Allow hoisting code in if-conversion.
When doing if-conversion, we do not currently move code out of the side
nodes.  The reason for this is that it can increase the number of
instructions that get executed because both side nods will have to be
executed now.

In this commit, we add code to move an instruction, and all of the
instructions it depends on, out of a side node and into the header of
the selection construct.  However to keep the cost down, we only do it
when the two values in the OpPhi node compute the same value.  This way
we have to move only one of the instructions and the other becomes
unused most of the time.  So no real extra cost.

Makes the value number table an alalysis in the ir context.

Added more opcodes to list of code motion safe opcodes.

Fixes #1526.
2018-05-04 12:56:29 -04:00
Stephen McGroarty
1c2cbaf569 Add GetContinueBlock to loop class.
Previously, the loop class used the terms latch and continue block
interchangeably. This patch splits the two and corrects and tests some
uses of the old uses of GetLatchBlock.
2018-05-03 14:30:41 -04:00
Steven Perron
70bb3c1cc2 Fold divide and multiply by same value.
We want to fold code like (x*y)/x and other permutations of this.

Fixes #1531.
2018-05-02 10:18:37 -04:00
Toomas Remmelg
1dc2458060 Add a loop fusion pass.
This pass will look for adjacent loops that are compatible and legal to
be fused.

Loops are compatible if:

- they both have one induction variable
- they have the same upper and lower bounds
    - same initial value
    - same condition
- they have the same update step
- they are adjacent
- there are no break/continue in either of them

Fusion is legal if:

- fused loops do not have any dependencies with dependence distance
  greater than 0 that did not exist in the original loops.
- there are no function calls in the loops (could have side-effects)
- there are no barriers in the loops

It will fuse all such loops as long as the number of registers used for
the fused loop stays under the threshold defined by
max_registers_per_loop.
2018-05-01 15:40:37 -04:00
Stephen McGroarty
9a5dd6fe88 Support loop fission.
Adds support for spliting loops whose register pressure exceeds a user
provided level. This pass will split a loop into two or more loops given
that the loop is a top level loop and that spliting the loop is legal.
Control flow is left intact for dead code elimination to remove.

This pass is enabled with the --loop-fission flag to spirv-opt.
2018-05-01 15:15:10 -04:00
Steven Perron
9ba0879ddf Improve Vector DCE
Track live scalars in VDCE as if they were single element vectors.

Handle the extended instructions for GLSL in VDCE.

Handle composite construct instructions in VDCE.
2018-04-30 11:55:50 -04:00
Steven Perron
a00a0a09ae Revert "Improvements to vector dce."
This reverts commit 2813722993.

A regression was found.  Undoing the change until it is fixed.
2018-04-27 10:33:19 -04:00
Alan Baker
4246abdc74 Fixes handling of kill and unreachable ops in inlining.
Fixes #1527

* Adds handling for copying OpKill and OpUnreachable and forces the
generation of a new basic block
* Adds tests to check
2018-04-27 09:42:37 -04:00
Steven Perron
e1bcd2b2d8 Fold OpVectorTimesScalar and OpPhi better.
If one of the operands to an OpVectorTimesScalar instruction is zero,
then the result will be the 0 vector. Currently we do not fold the
insturction unless both operands are constants. This change fixes that.

We also allow folding of OpPhi instructions where the incoming values
are either an OpUndef or the OpPhi instruction itself. As with other
cases, this can be simplified to the OpUndef.
2018-04-26 12:41:16 -04:00
Steven Perron
2813722993 Improvements to vector dce.
Track live scalars in VDCE as if they were single element vectors.

Handle the extended instructions for GLSL in VDCE.

Handle composite construct instructions in VDCE.

Fixes #1511.
2018-04-26 11:07:48 -04:00
Greg Fischer
268be6143d LocalSingleBlockElim: Add store-store elimination
Eliminate unused store to variable if followed by store to same
variable in same block.

Most significantly, this cleans up stores made unused by this pass.
These useless stores can inhibit subsequent optimizations, specifically
LocalSingleStoreElim. Eliminating them makes subsequent optimization more
effective.

The main effect of this pass is to simplify the work done by the SSA
rewriter.  It catches many local loads/stores that help speeding up the
work done by the main rewriter.
2018-04-25 10:30:18 -04:00
Steven Perron
2c0ce87210
Vector DCE (#1512)
Introduce a pass that does a DCE type analysis for vector elements
instead of the whole vector as a single element.

It will then rewrite instructions that are not used with something else.
For example, an instruction whose value are not used, even though it is
referenced, is replaced with an OpUndef.
2018-04-23 11:13:07 -04:00
David Neto
7a59283587 Another fix for old XCode: std::set explicit ctor in test code 2018-04-20 15:58:01 -04:00
Victor Lomuller
efc5061929 Dominator analysis interface clean.
Remove the CFG requirement when querying a dominator/post-dominator from an IRContext.

Updated all uses of the function and tests.
2018-04-20 15:41:59 -04:00
Jaebaek Seo
48802bad72 Constant folding for OpVectorTimesScalar 2018-04-20 13:43:04 -04:00
Victor Lomuller
0ec08c28c1 Add register liveness analysis.
For each function, the analysis determine which SSA registers are live
at the beginning of each basic block and which one are killed at
the end of the basic block.

It also includes utilities to simulate the register pressure for loop
fusion and fission.

The implementation is based on the paper "A non-iterative data-flow
algorithm for computing liveness sets in strict ssa programs" from
Boissinot et al.
2018-04-20 09:45:15 -04:00
GregF
1c89da46ff Test/DependencyAnalysis: Fix uninitialized variables 2018-04-19 15:34:15 -04:00
Jaebaek Seo
430a29335e Fix broken pointer of CommonUniformElimPass 2018-04-19 09:36:10 -04:00
Steven Perron
c20a718e00 Rewrite local-single-store-elim to not create large data structures.
The local-single-store-elim algorithm is not fundamentally bad.
However, when there are a large number of variables, some of the
maps that are used can become very large.  These large data structures
then take a very long time to be destroyed.  I've seen cases around 40%
if the time.

I've rewritten that algorithm to not use as much memory.  This give a
significant improvement when running a large number of shader through
DXC.

I've also made a small change to local-single-block-elim to delete the
loads that is has replaced.  That way local-single-store-elim will not
have to look at those.  local-single-store-elim now does the same thing.

The time for one set goes from 309s down to 126s.  For another set, the
time goes from 102s down to 88s.
2018-04-18 16:38:18 -04:00
Jaebaek Seo
0fa42996b5
Merge pull request #1461 from jaebaek/fnegate
Add constant folding for OpFNegate

Contributes to #709
2018-04-18 13:46:10 -04:00
Jaebaek Seo
3c5bd26668 Typo 2018-04-17 14:13:19 -04:00
Toomas Remmelg
0f335cf87e Add support for MIV and Delta test dependence analysis.
GCD MIV test as described in Chapter 3 of "Optimizing Compilers for
Modern Architectures: A Dependence-Based Approach" by Randy Allen, and
Ken Kennedy.

Delta test as described in Figure 3 of "Practical Dependence Testing" by
Gina Goff, Ken Kennedy, and Chau-Wen Tseng from PLDI '91.
2018-04-17 13:57:02 -04:00
Jaebaek Seo
ff92339fff Format 2018-04-17 12:12:48 -04:00
Jaebaek Seo
d8b9306a4f Add more unit tests 2018-04-17 12:08:45 -04:00
Jaebaek Seo
79491259e0 Add constant folding for FNegate 2018-04-17 12:08:45 -04:00
David Neto
152b9a681e ADCE: Remove OpDecorateStringGOOGLE
Also fix a few failures to set "modified" status when removing
global values.

Add OpDecorateStringGOOGLE to decoration ordering

Fixes #1492
2018-04-17 10:24:30 -04:00
Victor Lomuller
10e5d7cf13 Add a loop peeling pass.
For each loop in a function, the pass walks the loops from inner to outer most loop
and tries to peel loop for which a certain amount of iteration can be done before or after the loop.

To limit code growth, peeling will not happen if the growth in code size goes above a configurable threshold.
2018-04-11 15:41:29 +01:00
Alexander Johnston
61b50b3bfa ZIV and SIV loop dependence analysis.
Provides functionality to perform ZIV and SIV dependency analysis tests
between a load and store within the same loop.

Dependency tests rely on scalar analysis to prove and disprove dependencies
with regard to the loop being analysed.

Based on the 1990 paper Practical Dependence Testing by Goff, Kennedy, Tseng

Adds support for marking loops in the loop nest as IRRELEVANT.
Loops are marked IRRELEVANT if the analysed instructions contain
no induction variables for the loops, i.e. the loops induction
variable is not relevent to the dependence of the store and load.
2018-04-11 09:32:42 -04:00
Steven Perron
53bc1623ec Fold OpDot
Adding three rules to fold OpDot (implemented as two).

- When an OpDot has two constants, then fold to the resulting const.

- When one of the inputs is the 0 vector, then fold to zero.

- When one of the inputs is a single 1 with 0s, then rewrite to an
OpCompositeExtract of the appropriate element.  This will help find
even more folding opportunities.

Contributes to #709.
2018-04-10 13:09:37 -04:00
GregF
6fbfe1c016 Fix SSA rewrite for nested loops.
From the test case, the slice of the CFG that is interesting for the bug
is

25
|
v
30
|
v
31<-+
|   |
v   |
34--+

1. In block 25, we have a Phi candidate for %f with arguments
   %47 = Phi[%float_0, %0]. This merges %float_0 and a yet unknown
   argument from the external loop backedge.
2. We are now processing block 34:
   i. The load %35 = OpLoad %f triggers a Phi candidate to be placed in
      block 31.
  ii. The Phi candidate %50 = Phi needs two arguments. The one coming
      from block 30 is %47. But the one coming from block 34 (which we
      are now processing and have marked sealed), finds %50 itself as
      the reaching def for %f.
3. This wrongfully marks %50 as a copy-of Phi, which ultimately makes
   both %47 and %50 copy-of Phis that get eliminated.
2018-04-06 15:17:52 -04:00
Steven Perron
742454968d OpName and decorations should not stop array copy prop. 2018-04-04 22:24:10 -04:00
Steven Perron
7c5d49bf2a Teach ADCE about OpImageTexelPointer
Currently OpImageTexelPointer operations are treat like a use of the
pointer, but it does
not look for the memory being referenced to make sure stores are not
removed.

This change teaches it so identify the memory being accessed, and
treats it as if that memory is loaded.

Fixes to #1445.
2018-04-04 13:45:29 -04:00
Steven Perron
c33af63264 Teach array copy propagation about OpImageTexelPointer.
OpImageTexelPointer acts like a special kind of load.  It is not an
array load, but it also cannot be removed the same way a regular
load can.  The type of propagation that needs to be done is similar
to what we do for arrays, so I want to merge that code into that
optmization.

Contributers to #1445.
2018-04-04 13:42:51 -04:00
Steven Perron
e64a4656b3 Teach the private to local about OpImageTexelPointer.
OpImageTexelPointer acts like a special kind of load.  It is still
safe to change the storage class of a variable used in a
OpImageTexalPointer instruction.

Contributes to #1445.
2018-04-04 13:42:35 -04:00
Neil Roberts
57a2441791 hex_float: Use max_digits10 for the float precision
CPPreference.com has this description of digits10:

“The value of std::numeric_limits<T>::digits10 is the number of
 base-10 digits that can be represented by the type T without change,
 that is, any number with this many significant decimal digits can be
 converted to a value of type T and back to decimal form, without
 change due to rounding or overflow.”

This means that any number with this many digits can be represented
accurately in the corresponding type. A change in any digit in a
number after that may or may not cause it a different bitwise
representation. Therefore this isn’t necessarily enough precision to
accurately represent the value in text. Instead we need max_digits10
which has the following description:

“The value of std::numeric_limits<T>::max_digits10 is the number of
 base-10 digits that are necessary to uniquely represent all distinct
 values of the type T, such as necessary for
 serialization/deserialization to text.”

The patch includes a test case in hex_float_test which tries to do a
round-robin conversion of a number that requires more than 6 decimal
places to be accurately represented. This would fail without the
patch.

Sadly this also breaks a bunch of other tests. Some of the tests in
hex_float_test use ldexp and then compare it with a value which is not
the same as the one returned by ldexp but instead is the value rounded
to 6 decimals. Others use values that are not evenly representable as
a binary floating fraction but then happened to generate the same
value when rounded to 6 decimals. Where the actual value didn’t seem
to matter these have been changed with different values that can be
represented as a binary fraction.
2018-04-03 12:53:10 -04:00
Lei Zhang
fc9f621e8b Add missing <iterator> header for std::back_inserter 2018-03-30 11:30:25 -04:00
Steven Perron
cbceeceab4 In copy-prop-arrays, indentify copies via OpCompositeInsert
When the original code copies an entire array or struct one element at a
time, this turns into a series of OpCompositeInsert instruction followed
by a store of the whole array.  We currently miss opportunities in copy
propagate arrays because we do not recognize this as a copy.

This commit adds code to copy propagate arrays to identify this code
pattern.

Also updates the performance passed to run array copy propagation.
2018-03-29 09:39:55 -04:00
Steven Perron
d8ca09821d Handle non-constant accesses in memory objects (copy prop arrays)
The first implementation of MemroyObject, which is used in copy
propagate arrays, forced the access chain to be like the access chains
in OpCompositeExtract.  This excluded the possibility of the memory
object from representing an array element that was extracted with a
variable index.   Looking at the code, that restriction is not
neccessary.  I also see some opportunities for doing this in some real
shaders.

Contributes to #1430.
2018-03-28 20:23:47 -04:00
Stephen McGroarty
ad7e4b8401 Initial patch for scalar evolution analysis
This patch adds support for the analysis of scalars in loops. It works
by traversing the defuse chain to build a DAG of scalar operations and
then simplifies the DAG by folding constants and grouping like terms.
It represents induction variables as recurrent expressions with respect
to a given loop and can simplify DAGs containing recurrent expression by
rewritting the entire DAG to be a recurrent expression with respect to
the same loop.
2018-03-28 16:34:23 -04:00
Alan Baker
97c8fdccd2 Adding OpPhi validation rules.
* Added tests
* Fixes SSA check for unreachable phi parents
* Fixes invalid cfg cleanup test
2018-03-27 17:26:26 -04:00
Steven Perron
5e07ab1358 Handle more cases in copy propagate arrays.
When we change the type of an object that gets stored, we do not want to
change the type of the memory location being stored to.  In order to
still be able to do the rewrite, we will decompose and rebuild the
object so it is the type that can be stored.

Fixes #1416.
2018-03-27 11:04:49 -04:00
Steven Perron
c4dc046399 Copy propagate arrays
The sprir-v generated from HLSL code contain many copyies of very large
arrays.  Not only are these time consumming, but they also cause
problems for drivers because they require too much space.

To work around this, we will implement an array copy propagation.  Note
that we will not implement a complete array data flow analysis in order
to implement this.  We will be looking for very simple cases:

1) The source must never be stored to.
2) The target must be stored to exactly once.
3) The store to the target must be a store to the entire array, and be a
copy of the entire source.
4) All loads of the target must be dominated by the store.

The hard part is keeping all of the types correct.  We do not want to
have to do too large a search to update everything, which may not be
possible, do we give up if we see any instruction that might be hard to
update.

Also in types.h, the element decorations are not stored in an std::map.
This change was done so the hashing algorithm for a Struct is
consistent.  With the std::unordered_map, the traversal order was
non-deterministic leading to the same type getting hashed to different
values.  See |Struct::GetExtraHashWords|.

Contributes to #1416.
2018-03-26 14:44:41 -04:00
Diego Novillo
735d8a579e SSA rewrite pass.
This pass replaces the load/store elimination passes.  It implements the
SSA re-writing algorithm proposed in

     Simple and Efficient Construction of Static Single Assignment Form.
     Braun M., Buchwald S., Hack S., Leißa R., Mallon C., Zwinkau A. (2013)
     In: Jhala R., De Bosschere K. (eds)
     Compiler Construction. CC 2013.
     Lecture Notes in Computer Science, vol 7791.
     Springer, Berlin, Heidelberg

     https://link.springer.com/chapter/10.1007/978-3-642-37051-9_6

In contrast to common eager algorithms based on dominance and dominance
frontier information, this algorithm works backwards from load operations.

When a target variable is loaded, it queries the variable's reaching
definition.  If the reaching definition is unknown at the current location,
it searches backwards in the CFG, inserting Phi instructions at join points
in the CFG along the way until it finds the desired store instruction.

The algorithm avoids repeated lookups using memoization.

For reducible CFGs, which are a superset of the structured CFGs in SPIRV,
this algorithm is proven to produce minimal SSA.  That is, it inserts the
minimal number of Phi instructions required to ensure the SSA property, but
some Phi instructions may be dead
(https://en.wikipedia.org/wiki/Static_single_assignment_form).
2018-03-20 20:56:55 -04:00
Victor Lomuller
bdf421cf40 Add loop peeling utility
The loop peeler util takes a loop as input and create a new one before.
The iterator of the duplicated loop then set to accommodate the number
of iteration required for the peeling.

The loop peeling pass that decided to do the peeling and profitability
analysis is left for a follow-up PR.
2018-03-20 10:21:10 -04:00
Steven Perron
b3daa93b46 Change merge return pass to handle structured cfg.
We are seeing shaders that have multiple returns in a functions.  These
functions must get inlined for legalization purposes; however, the
inliner does not know how to inline functions that have multiple
returns.

The solution we will go with it to improve the merge return pass to
handle structured control flow.

Note that the merge return pass will assume the cfg has been cleanedup
by dead branch elimination.

Fixes #857.
2018-03-19 13:49:04 -04:00
David Neto
844e186cf7 Add --strip-reflect pass
Strips reflection info. This is limited to decorations and
decoration instructions related to the SPV_GOOGLE_hlsl_functionality1
extension.
It will remove the OpExtension for SPV_GOOGLE_hlsl_functionality1.
It will also remove the OpExtension for SPV_GOOGLE_decorate_string
if there are no further remaining uses of OpDecorateStringGOOGLE.

Fixes https://github.com/KhronosGroup/SPIRV-Tools/issues/1398
2018-03-15 21:20:42 -04:00
David Neto
884933366b Teach DecorationManager about OpDecorateStringGOOGLE
Also add more decoration manager test coverage for OpDecorateId.

Fixes #1396
2018-03-13 22:18:33 -04:00
Alan Baker
7e03e76a5f Fixes #1402. Don't merge non-branch terminators into loop header.
Added tests
2018-03-13 22:16:17 -04:00
Alan Baker
43d1609183 Fixes #1407. Removing assertion against void pointer
Added test
2018-03-13 19:45:20 -04:00
Alan Baker
4065adf05d Fixes #1404. Don't DCE workgroup size
Added test.
2018-03-13 19:38:31 -04:00
Pierre Moreau
5bd55f10cd Reimplement the DecorationManager
This reimplementation fixes several issues when removing decorations associated
to an ID (partially addresses #1174 and gives tools for fixing #898), as well
as making it easier to remove groups; a few additional tests have been added.

DecorationManager::RemoveDecoration() will still not delete dead decorations it
created, but I do not think it is its job either; given the following input

```
OpCapability Shader
OpCapability Linkage
OpMemoryModel Logical GLSL450
OpDecorate %2 Restrict
%2      = OpDecorationGroup
OpGroupDecorate %2 %1 %3
OpDecorate %4 Invariant
%4      = OpDecorationGroup
OpGroupDecorate %4 %2
%uint   = OpTypeInt 32 0
%1      = OpVariable %uint Uniform
%3      = OpVariable %uint Uniform
```

which of the following two outputs would you expect RemoveDecoration(2) to produce:

```
OpCapability Shader
OpCapability Linkage
OpMemoryModel Logical GLSL450
%uint = OpTypeInt 32 0
%1 = OpVariable %uint Uniform
%3 = OpVariable %uint Uniform
```

or

```
OpCapability Shader
OpCapability Linkage
OpMemoryModel Logical GLSL450
OpDecorate %4 Invariant
%4      = OpDecorationGroup
%uint   = OpTypeInt 32 0
%1      = OpVariable %uint Uniform
%3      = OpVariable %uint Uniform
```

Fixes https://github.com/KhronosGroup/SPIRV-Tools/issues/924
Fixes https://github.com/KhronosGroup/SPIRV-Tools/issues/1174
2018-03-12 09:56:14 -04:00
Alan Baker
bc9cfee6fa Fixes #1385. Grab correct input to calculate indices.
* Added tests to catch the bug
2018-03-07 16:07:40 -05:00
Alan Baker
5f50e6209c Fixes #1376. Don't handle half folding gracefully.
* Added early returns to folding rules to prevent half attempts
* Added some tests
2018-03-06 14:00:02 -05:00
Steven Perron
9ba50e34f2 Avoid generating duplicate names when merging types
The merging types we do not remove other information related to the
types.  We simply leave it duplicated, and hope it is removed later.
This is what happens with decorations.  They are removed in the next
phase of remove duplicates.  However, for OpNames that is not the case.
We end up with two different names for the same id, which does not make
sense.

The solution is to remove the names and decorations for the type being
removed instead of rewriting them to refer to the other type.

Note that it is possible that if the first type does not have a name,
then the types will end up with no name.  That is fine because the names
should not have any semantic significance anyway.

The was identified in issue #1372, but this does not fix that issue.
2018-03-05 12:02:50 -05:00
Pierre Moreau
6cd6e5ebef Define Disassemble only when Effcee is used in fold_test 2018-03-02 16:40:52 -05:00
Alan Baker
52bceb3569 Handles more cases of redundant selects
* Handles OpConstantNull and vector types
 * vector selects (except against a null) are converted to vector
 shuffles
* Added tests
2018-03-02 14:28:08 -05:00
Alan Baker
824625760b Fixes #1361. Mark all non-constant global values as varying in CCP
* Also mark function parameters as varying
* Conservatively mark assignment instructions as varying if any input is
varying after attempting to fold
* Added a test to catch this case
2018-03-01 15:24:41 -05:00
Alan Baker
ce5941a642 Fixes #1357. Support null constants better in folding
* getFloatConstantKind() now handles OpConstantNull
* PerformOperation() now handles OpConstantNull for vectors
* Fixed some instances where we would attempt to merge a division by 0
* added tests
2018-02-28 23:12:27 -05:00
GregF
bdaf8d56fb Opt: Add constant folding for FToI and IToF 2018-02-28 23:08:52 -05:00
Alan Baker
9457cabbce Fixes #1354. Do not merge integer division.
* Removes merging of div with a div or mul for integers
* Updated tests
2018-02-28 13:33:21 -05:00
Steven Perron
588f4fcc95 Add more folding rules for vector shuffle.
Adds rule to fold OpVectorShuffle with constant inputs.

Adds rules to fold OpCompositeExtrac being fed by an OpVectorShuffle.
2018-02-27 21:20:22 -05:00
Steven Perron
2cb589cc14 Remove uses DCEInst and call ADCE
The algorithm used in DCEInst to remove dead code is very slow.  It is
fine if you only want to remove a small number of instructions, but, if
you need to remove a large number of instructions, then the algorithm in
ADCE is much faster.

This PR removes the calls to DCEInst in the load-store removal passes
and adds a pass of ADCE afterwards.

A number of different iterations of the order of optimization, and I
believe this is the best I could find.

The results I have on 3 sets of shaders are:

Legalization:

Set 1: 5.39 -> 5.01
Set 2: 13.98 -> 8.38
Set 3: 98.00 -> 96.26

Performance passes:

Set 1: 6.90 -> 5.23
Set 2: 10.11 -> 6.62
Set 3: 253.69 -> 253.74

Size reduction passes:

Set 1: 7.16 -> 7.25
Set 2: 17.17 -> 16.81
Set 3: 112.06 -> 107.71

Note that the third set's compile time is large because of the large
number of basic blocks, not so much because of the number of
instructions.  That is why we don't see much gain there.
2018-02-27 21:06:08 -05:00
Alan Baker
802cf053c7 Merge arithmetic with non-trivial constant operands
Adding basis of arithmetic merging

* Refactored constant collection in ConstantManager
* New rules:
 * consecutive negates
 * negate of arithmetic op with a constant
 * consecutive muls
 * reciprocal of div

* Removed IRContext::CanFoldFloatingPoint
 * replaced by Instruction::IsFloatingPointFoldingAllowed
* Fixed some bad tests
* added some header comments

Added PerformIntegerOperation

* minor fixes to constants and tests
* fixed IntMultiplyBy1 to work with 64 bit ints
* added tests for integer mul merging

Adding test for vector integer multiply merging

Adding support for merging integer add and sub through negate

* Added tests

Adding rules to merge mult with preceding divide

* Has a couple tests, but needs more
* Added more comments

Fixed bug in integer division folding

* Will no longer merge through integer division if there would be a
remainder in the division
* Added a bunch more tests

Adding rules to merge divide and multiply through divide

* Improved comments
* Added tests

Adding rules to handle mul or div of a negation

* Added tests

Changes for review

* Early exit if no constants are involved in more functions
* fixed some comments
* removed unused declaration
* clarified some logic

Adding new rules for add and subtract

* Fold adds of adds, subtracts or negates
* Fold subtracts of adds, subtracts or negates
* Added tests
2018-02-27 13:02:13 -05:00
Stephen McGroarty
20b8cdb7c6 Make IR builder use the type manager for constants
This change makes the IR builder use the type manager to generate
OpTypeInts when creating OpConstants. This avoids dangling references
being stored by the created OpConstants.
2018-02-27 12:59:26 -05:00
Victor Lomuller
3497a94460 Add loop unswitch pass.
It moves all conditional branching and switch whose conditions are loop
invariant and uniform. Before performing the loop unswitch we check that
the loop does not contain any instruction that would prevent it
(barriers, group instructions etc.).
2018-02-27 08:52:46 -05:00
Stephen McGroarty
e354984b09 Unroller support for multiple induction variables
Support for multiple induction variables within a loop and support for
loop condition operands <= and >=.
2018-02-27 11:50:08 +00:00
Steven Perron
3f19c2031a Preserve analysies in the simplification pass
Fixes a bug at the same time.  In `UpdateDefUse`, if the definition
already exists, we are not suppose to analyse it again.  When you do
the entries for the definition are deleted, and we don't want that.
The check for this was wrong.
2018-02-22 16:06:30 -05:00
GregF
46a9ec9d23 Opt: Check for side-effects in DCEInst()
This function now checks for side-effects before adding operand
instructions to the dead instruction work list.

Because this fix puts more pressure on IsCombinatorInstruction() to
be correct, this commit adds all OpConstant* and OpType* instructions
to combinator_ops_ set.

Fixes #1341.
2018-02-22 12:24:13 -05:00
Alan Baker
01760d2f0f Fixes #1338. Handle OpConstantNull in branch/switch conditions
* No longer assume the branch/switch condition must be bool or int
constants (respectively)
* Added a couple unit tests for each case
2018-02-21 10:22:39 -05:00
Arseny Kapoulkine
309be423cc Add folding for redundant add/sub/mul/div/mix operations
This change implements instruction folding for arithmetic operations
that are redundant, specifically:

  x + 0 = 0 + x = x
  x - 0 = x
  0 - x = -x
  x * 0 = 0 * x = 0
  x * 1 = 1 * x = x
  0 / x = 0
  x / 1 = x
  mix(a, b, 0) = a
  mix(a, b, 1) = b

Cache ExtInst import id in feature manager

This allows us to avoid string lookups during optimization; for now we
just cache GLSL std450 import id but I can imagine caching more sets as
they become utilized by the optimizer.

Add tests for add/sub/mul/div/mix folding

The tests cover scalar float/double cases, and some vector cases.

Since most of the code for floating point folding is shared, the tests
for vector folding are not as exhaustive as scalar.

To test sub->negate folding I had to implement a custom fixture.
2018-02-20 18:29:27 -05:00
Steven Perron
9d95a91a9f Fix folding insert feeding extract
I mixed up two cases when folding an OpCompositeExtract that is feed by
and OpCompositeInsert.  The specific cases are demonstracted in the new
test.  I mixed up the conditions for the cases, and treated one like the
other.

Fixes #1323.
2018-02-20 11:22:51 -05:00
Alan Baker
c3f34d8bf3 Fixes #1300. Adding checks for bad CCP transitions and unsettled values
* Now track propagation status and assert on bad statuses
 * Added helper methods to access instruction propagation status
* Modified the phi meet operator to properly reflect the paper it is
based on
* Modified SSA edge addition so that all edge are added, but only on
state changes
* Fixed a bug in instruction simulation where interesting conditional
branches would not mark the interesting edge as executed
 * Added a test to catch this bug
* Added an ostream operator for SSAPropagator::PropStatus
2018-02-18 19:41:34 -05:00
Arseny Kapoulkine
1054413600 Add constant folding rules for floating-point comparison
This change handles all 6 regular comparison types in two variations,
ordered (true if values are ordered *and* comparison is true) and
unordered (true if values are unordered *or* comparison is true).

Ordered comparison matches the default floating-point behavior on host
but we use std::isnan to check ordering explicitly anyway.

This change also slightly reworks the floating-point folding support
code to make it possible to define a folding operation that returns
boolean instead of floating point.

These tests exhaustively test ordered/unordered comparisons for
float/double.

Since for NaN inputs the comparison result doesn't depend on the
comparison function, we just test == and !=; NaN inputs result in true
unordered comparisons and false ordered comparisons.
2018-02-16 20:41:22 -05:00
Steven Perron
50f307f889 Simplify OpPhi instructions referencing unreachable continues
In dead branch elimination, we already recognize unreachable continue
blocks, and update OpPhi instruction accordingly.  This change adds an
extra check: if the head block has exactly 1 other incoming edge, then
replace the OpPhi with the value from that edge.

Fixes #1314.
2018-02-16 18:58:03 -05:00
Steven Perron
3756b387f3 Get CCP to use the constant floating point rules.
Fixes #1311
2018-02-16 13:49:47 -05:00
Arseny Kapoulkine
32a8e04c7d Add folding of redundant OpSelect insns
We can fold OpSelect into one of the operands in two cases:

- condition is constant
- both results are the same

Even if the original shader doesn't have either of these, if-conversion
pass sometimes ends up generating instructions like

   %7127 = OpSelect %int %3220 %7058 %7058

And this optimization cleans them up.
2018-02-15 10:03:22 -05:00
Steven Perron
6669d8163d Fold binary floating point operators.
Adds the floating rules for FAdd, FDiv, FMul, and FSub.

Contributes to #1164.
2018-02-14 15:48:15 -05:00
Stephen McGroarty
dd8400e150 Initial support for loop unrolling.
This patch adds initial support for loop unrolling in the form of a
series of utility classes which perform the unrolling. The pass can
be run with the command spirv-opt --loop-unroll. This will unroll
loops within the module which have the unroll hint set. The unroller
imposes a number of requirements on the loops it can unroll. These are
documented in the comments for the LoopUtils::CanPerformUnroll method in
loop_utils.h. Some of the restrictions will be lifted in future patches.
2018-02-14 15:44:38 -05:00
Alan Baker
229ebc0665 Fixes #1295. Mark undef values as varying in ccp.
* Undef now marked as varying in ccp
 * this prevents incorrect meet operations since phis were always not
 interesting
* added a test to catch the bug
2018-02-14 10:21:26 -05:00
Steven Perron
1d7b1423f9 Add folding of OpCompositeExtract and OpConstantComposite constant instructions.
Create files for constant folding rules.

Add the rules for OpConstantComposite and OpCompositeExtract.
2018-02-09 17:52:33 -05:00
Alexander Johnston
84ccd0b9ae Loop invariant code motion initial implementation 2018-02-08 22:55:47 -05:00
GregF
ca4457b4b6 SROA: Do replacement on structs with no partial references. 2018-02-08 15:20:02 -05:00
Steven Perron
06cdb96984 Make use of the instruction folder.
Implementation of the simplification pass.

- Create pass that calls the instruction folder on each instruction and
  propagate instructions that fold to a copy.  This will do copy
  propagation as well.

- Did not use the propagator engine because I want to modify the instruction
  as we go along.

- Change folding to not allocate new instructions, but make changes in
  place.  This change had a big impact on compile time.

- Add simplification pass to the legalization passes in place of
  insert-extract elimination.

- Added test cases for new folding rules.

- Added tests for the simplification pass

- Added a method to the CFG to apply a function to the basic blocks in
  reverse post order.

Contributes to #1164.
2018-02-07 23:01:47 -05:00
David Neto
e7fafdaa68 Fix test inclusion when Effcee is absent 2018-02-06 12:10:50 -05:00
Alan Baker
871022772e Registering a type now rebuilds it out of memory owned by the manager.
* Added TypeManager::RebuildType
 * rebuilds the type and its constituent types in terms of memory owned
 by the manager.
 * Used by TypeManager::RegisterType to properly allocate memory
* Adding an unit test to expose the issue
* Added some tests to provide coverage of RebuildType
* Added an accessor to the target pointer for a forward pointer
2018-02-06 10:17:56 -05:00
Steven Perron
bc1ec9418b Add general folding infrastructure.
Create the folding engine that will

1) attempt to fold an instruction.
2) iterates on the folding so small folding rules can be easily combined.
3) insert new instructions when needed.

I've added the minimum number of rules needed to test the features above.
2018-02-02 12:24:11 -05:00
Victor Lomuller
50e85c865c Add LoopUtils class to gather some loop transformation support.
This patch adds LoopUtils class to handle some loop related transformations. For now it has 2 transformations that simplifies other transformations such as loop unroll or unswitch:
 - Dedicate exit blocks: this ensure that all exit basic block
   (out-of-loop basic blocks that have a predecessor in the loop)
   have all their predecessors in the loop;
 - Loop Closed SSA (LCSSA): this ensure that all definitions in a loop are used inside the loop
   or in a phi instruction in an exit basic block.

It also adds the following capabilities:
 - Loop::IsLCSSA to test if the loop is in a LCSSA form
 - Loop::GetOrCreatePreHeaderBlock that can build a loop preheader if required;
 - New methods to allow on the fly updates of the loop descriptors.
 - New methods to allow on the fly updates of the CFG analysis.
 - Instruction::SetOperand to allow expression of the index relative to Instruction::NumOperands (to be compatible with the index returned by DefUseManager::ForEachUse)
2018-02-01 15:35:09 -05:00
Steven Perron
61d8c0384b Add pass to reaplce invalid opcodes
Creates a pass that will remove instructions that are invalid for the
current shader stage.  For the instruction to be considered for replacement

1) The opcode must be valid for a shader modules.
2) The opcode must be invalid for the current shader stage.
3) All entry points to the module must be for the same shader stage.
4) The function containing the instruction must be reachable from an entry point.

Fixes #1247.
2018-02-01 15:25:09 -05:00
Jeremy Hayes
cd68f2b176 Add adjacency validation pass
Validate OpPhi predecessors.
Validate OpLoopMerge successors.
Validate OpSelectionMerge successors.
Fix collateral damage to existing tests.
Remove ValidateIdWithMessage.OpSampledImageUsedInOpPhiBad.
2018-02-01 14:10:55 -05:00
Alan Baker
2735e0851e Remove constexpr from Analysis operators
* Had to remove templating from InstructionBuilder as a result
 * now preserved analyses are specified as a constructor argument
* updated tests and uses
* changed static_assert to a runtime assert
 * this should probably get further changes in the future
2018-01-31 14:44:43 -05:00
Alan Baker
16949236fe Prevent unnecessary changes to the IR in dead branch elim
* When handling unreachable merges and continues, do not optimize to the
same IR
 * pass did not check whether the unreachable blocks were in the
 optimized form before transforming them
* added a test to catch this issue
2018-01-30 16:51:58 -05:00
Alan Baker
e661da7941 Enhancements to block merging
* Should handle all possibilities
 * Stricter checks for what is disallowed:
  * header and header
  * merge and merge
 * Allow header and merge blocks to be merged
  * Erases the structured control declaration if merging header and
    merge blocks together.
2018-01-30 16:05:51 -05:00
Alan Baker
6704233d39 Fix dereference of possibly nullptr
* If the dead branch elim is performed on a module without structured
control flow, the OpSelectionMerge may not be present
 * Add a check for pointer validity before dereferencing
* Added a test to catch the bug
2018-01-30 10:15:43 -05:00
GregF
f28b106173 InsertExtractElim: Split out DeadInsertElim as separate pass 2018-01-30 08:52:14 -05:00
Alan Baker
1b46f7ecad Fixes in CCP for #1228
* Forces traversal of phis if the def has changed to varying
* Mark a phi as varying if all incoming values are varying
* added a test to catch the bug
2018-01-29 15:12:05 -05:00
Victor Lomuller
6018de81de Add LoopDescriptor as an IRContext analysis.
Move some function definitions from header to source to avoid circular definition.
2018-01-25 16:12:32 -05:00
Greg Fischer
684997eb72 DeadInsertElim: Detect and DCE dead Inserts
This adds Dead Insert Elimination to the end of the
--eliminate-insert-extract pass. See the new tests for examples of code
that will benefit.

Essentially, this removes OpCompositeInsert instructions which are not
used, either because there is no instruction which uses the value at the
index it is inserted, or because a subsequent insert intercepts any such
use.

This code has been seen to remove significant amounts of dead code from
real-life HLSL shaders being ported to Vulkan. In fact, it is needed to
remove dead texture samples which cause Vulkan validation layer errors
(unbound textures and samplers) if not removed . Such DCE is thus
required for fxc equivalence and legalization.

This analysis operates across "chains" of Inserts which can also contain
Phi instructions.
2018-01-25 16:07:21 -05:00
Alan Baker
2e93e806e4 Initial implementation of if conversion
* Handles simple cases only
* Identifies phis in blocks with two predecessors and attempts to
convert the phi to an select
 * does not perform code motion currently so the converted values must
 dominate the join point (e.g. can't be defined in the branches)
 * limited for now to two predecessors, but can be extended to handle
 more cases
* Adding if conversion to -O and -Os
2018-01-25 09:42:00 -08:00
Steven Perron
c4835e1bd8 Use id_map in Fold*ToConstant
The folding routines are suppose to use the id_map provided to map the
ids in the instruction.  The ones I just added are missing it.
2018-01-22 16:27:31 -05:00
Steven Perron
6c409e30a2 Add generic folding function and use in CCP
The current folding routines have a very cumbersome interface, make them
harder to use, and not a obvious how to extend.

This change is to create a new interface for the folding routines, and
show how it can be used by calling it from CCP.

This does not make a significant change to the behaviour of CCP.  In
general it should produce the same code as before; however it is
possible that an instruction that takes 32-bit integers as inputs and
the result is not a 32-bit integer or bool will not be folded as before.

It seems like andriod has a problem with INT32_MAX and the like.  I'll
explicitly define those if the are not already defined.
2018-01-22 14:26:49 -05:00
Alan Baker
3b780db7f8 Fixes infinite loop in ADCE
* Addresses how breaks are indentified to prevent infinite loops when
back to back loop share a merge and header
* Added test to catch the bug
2018-01-19 11:08:46 -05:00
Victor Lomuller
cf3b2a58c4 Introduce an instruction builder helper class.
The class factorize the instruction building process.
Def-use manager analysis can be updated on the fly to maintain coherency.
To be updated to take into account more analysis.
2018-01-19 10:17:45 -05:00
Alan Baker
73940aba1b Simplifying code for adding instructions to worklist
* AddToWorklist can now be called unconditionally
 * It will only add instructions that have not already been marked as
 live
 * Fixes a case where a merge was not added to the worklist because the
 branch was already marked as live
* Added two similar tests that fail without the fix
2018-01-18 20:36:46 -05:00
Steven Perron
34d4294c2c Create a pass to work around a driver bug related to OpUnreachable.
We have come across a driver bug where and OpUnreachable inside a loop
is causing the shader to go into an infinite loop.  This commit will try
to avoid this bug by turning OpUnreachable instructions that are
contained in a loop into branches to the loop merge block.

This is not added to "-O" and "-Os" because it should only be used if
the driver being targeted has this problem.

Fixes #1209.
2018-01-18 20:31:46 -05:00
Alan Baker
18618061cb Adding testcase for #1210 2018-01-18 12:58:07 -05:00
Alan Baker
80b743a570 Adding support for switch removal in ADCE
* Updated code to handle switches
* Enabled disabled test and added a couple new ones
2018-01-17 11:05:42 -05:00
Alan Baker
5ffe862f28 Fixes missing increment in common uniform elim
* Addresses #1203
* Increments inIdx in IsConstantIndexAccessChain
 * added test to catch the bug
2018-01-16 14:47:35 -05:00
Steven Perron
6cc772c3ce Skip SpecConstants in CCP.
At the moment specialization constants look like constants to ccp.  This
causes a problem because they are handled differently by the constant
manager.

I choose to simply skip over them, and not try to add them to the value
table.  We can do specialization before ccp if we want to be able to
propagate these values.

Fixes #1199.
2018-01-15 09:53:23 -05:00
Steven Perron
24f9947050 Move initialization of the const mgr to the constructor.
The current code expects the users of the constant manager to initialize
it with all of the constants in the module.  The problem is that you do
not want to redo the work multiple times.  So I decided to move that
code to the constructor of the constant manager.  This way it will
always be initialized on first use.

I also removed an assert that expects all constant instructions to be
successfully mapped.  This is because not all OpConstant* instruction
can map to a constant, and neither do the OpSpecConstant* instructions.

The real problem is that an OpConstantComposite can contain a member
that is OpUndef.  I tried to treat OpUndef like OpConstantNull, but this
failed because an OpSpecConstantComposite with an OpUndef cannot be
changed to an OpConstantComposite.  Since I feel this case will not be
common, I decided to not complicate the code.

Fixes #1193.
2018-01-12 13:53:21 -05:00
Alan Baker
672494da13 Adding ostream operators for IR structures
* Added for Instruction, BasicBlock, Function and Module
* Uses new disassembly functionality that can disassemble individual
instructions
 * For debug use only (no caching is done)
 * Each output converts module to binary, parses and outputs an
 individual instruction
* Added a test for whole module output
* Disabling Microsoft checked iterator warnings
* Updated check_copyright.py to accept 2018
2018-01-12 11:19:58 -05:00
Alan Baker
eb0c73dad6 Maintain instruction to block mapping in phi insertion
* Changed MemPass::InsertPhiInstructions to set basic blocks for new
phis
* Local SSA elim now maintains instr to block mapping
 * Added a test and confirmed it fails without the updated phis
* IRContext::set_instr_block no longer builds the map if the analysis is
invalid
* Added instruction to block mapping verification to
IRContext::IsConsistent()
2018-01-12 10:16:53 -05:00
Greg Fischer
5eafc00ad5 InsertExtractElim: Optimize through VectorShuffle, Mix
This improves Extract replacement to continue through VectorShuffle.
It will also handle Mix with 0.0 or 1.0 in the a-value of the desired
component.

To facilitate optimization of VectorShuffle, the algorithm was refactored
to pass around the indices of the extract in a vector rather than pass the
extract instruction itself. This allows the indices to be modified as the
algorithm progresses.
2018-01-12 09:41:45 -05:00
Alan Baker
3a054e1ddc Adding additional functionality to ADCE.
Modified ADCE to remove dead globals.
* Entry point and execution mode instructions are marked as alive
* Reachable functions and their parameters are marked as alive
* Instruction deletion now deferred until the end of the pass
* Eliminated dead insts set, added IsDead to calculate that value
instead
* Ported applicable dead variable elimination tests
* Ported dead constant elim tests

Added dead function elimination to ADCE
* ported dead function elim tests

Added handling of decoration groups in ADCE
* Uses a custom sorter to traverse decorations in a specific order
* Simplifies necessary checks

Updated -O and -Os pass lists.
2018-01-10 08:35:48 -05:00
Alan Baker
1b6cfd3409 Rewriting dead branch elimination.
Pass now paints live blocks and fixes constant branches and switches as
it goes. No longer requires structured control flow. It also removes
unreachable blocks as a side effect. It fixes the IR (phis) before doing
any code removal (other than terminator changes).

Added several unit tests for updated/new functionality.

Does not remove dead edge from a phi node:
* Checks that incoming edges are live in order to retain them
* Added BasicBlock::IsSuccessor
* added test

Fixing phi updates in the presence of extra backedge blocks

* Added tests to catch bug

Reworked how phis are updated

* Instead of creating a new Phi and RAUW'ing the old phi with it, I now
replace the phi operands, but maintain the def/use manager correctly.

For unreachable merge:

* When considering unreachable continue blocks the code now properly
checks whether the incoming edge will continue to be live.

Major refactoring for review

* Broke into 4 major functions
 * marking live blocks
 * marking structured targets
 * fixing phis
 * deleting blocks
2018-01-09 12:21:39 -05:00
Diego Novillo
e5560d64de Fix constant propagation of induction variables.
This fixes https://github.com/KhronosGroup/SPIRV-Tools/issues/1143.
When an instruction transitions from constant to bottom (varying) in the
lattice, we were telling the propagator that the instruction was
varying, but never updating the actual value in the values table.

This led to incorrect value substitutions at the end of propagation.

The patch also re-enables CCP in -O and -Os.
2018-01-08 15:34:35 -05:00
Victor Lomuller
e8ad02f3dd Add loop descriptors and some required dominator tree extensions.
Add post-order tree iterator.

Add DominatorTreeNode extensions:
 - Add begin/end methods to do pre-order and post-order tree traversal from a given DominatorTreeNode

Add DominatorTree extensions:
  - Add begin/end methods to do pre-order and post-order tree traversal
  - Tree traversal ignore by default the pseudo entry block
  - Retrieve a DominatorTreeNode from a basic block

Add loop descriptor:
  - Add a LoopDescriptor class to register all loops in a given function.
  - Add a Loop class to describe a loop:
    - Loop parent
    - Nested loops
    - Loop depth
    - Loop header, merge, continue and preheader
    - Basic blocks that belong to the loop

Correct a bug that forced dominator tree to be constantly rebuilt.
2018-01-08 09:31:13 -05:00
Steven Perron
ccb921dd2b Allow getting the base pointer of an image load/store.
In value numbering, we treat loads and stores of images, ie OpImageLoad,
as a memory operation where it is interested in the "base address" of
the instruction.  In those cases, it is an image instruction.

The problem is that `Instruction::GetBaseAddress()` does not account for
the image instructions, so the assert at the end to make sure it found
a valid base address for its addressing mode fails.

The solution is to look at the load/store instruction to determine how
the assertion should be done.

Fixes #1160.
2018-01-05 13:26:10 -05:00
Diego Novillo
716718a5e9 Fix infinite simulation cycles in SSA propagator.
This fixes https://github.com/KhronosGroup/SPIRV-Tools/issues/1159.  I
had missed a nuance in the original algorithm.  When simulating Phi
instructions, the SSA edges out of a Phi instruction should never be
added to the list of edges to simulate.

Phi instructions can be in SSA def-use cycles with other Phi
instructions.  This was causing the propagator to fall into an infinite
loop when the same def-use edge kept being added to the queue.

The original algorithm in the paper specifically separates the visit of
a Phi instruction vs the visit of a regular instruction.  This fix makes
the implementation match the original algorithm.
2018-01-05 10:29:39 -05:00
Pierre Moreau
702852bd22 Opt: Make DecorationManager::HaveTheSameDecorations symmetric
Fixes https://github.com/KhronosGroup/SPIRV-Tools/issues/1112

Also: Add SpvOpDecorateId to IsAnnotationInst()
2018-01-04 14:07:25 -05:00
Diego Novillo
5f100789fb Handle execution termination instructions when building edges.
This fixes issue https://github.com/KhronosGroup/SPIRV-Tools/issues/1153.

When building CFG edges, edges out of a OpKill and OpUnreachable
instruction should be directed to the CFG's pseudo exit block.
2018-01-03 15:25:03 -05:00
Diego Novillo
135150a1a8 Do not insert Phi nodes in CCP propagator.
In CCP we should not need to insert Phi nodes because CCP never looks at
loads/stores.  This required adjusting two tests that relied on Phi
instructions being inserted.  I changed the tests to have the Phi
instructions pre-inserted.

I also added a new test to make sure that CCP does not try to look
through stores and loads.

Finally, given that CCP does not handle loads/stores, it's better to run
mem2reg before it.  I've changed the -O/-Os schedules to run local
multi-store elimination before CCP.

Although this is just an efficiency fix for CCP, it is
also working around a bug in Phi insertion.  When Phi instructions are
inserted, they are never associated a basic block.  This causes a
segfault when the propagator tries to lookup CFG edges when analyzing
Phi instructions.
2018-01-03 15:12:25 -05:00
GregF
226f263cbc Test: Fix linux/gcc defined-but-not-used warnings/errors 2017-12-29 09:22:36 -05:00
Diego Novillo
4ba9dcc8a0 Implement SSA CCP (SSA Conditional Constant Propagation).
This implements the conditional constant propagation pass proposed in

Constant propagation with conditional branches,
Wegman and Zadeck, ACM TOPLAS 13(2):181-210.

The main logic resides in CCPPass::VisitInstruction.  Instruction that
may produce a constant value are evaluated with the constant folder. If
they produce a new constant, the instruction is considered interesting.
Otherwise, it's considered varying (for unfoldable instructions) or
just not interesting (when not enough operands have a constant value).

The other main piece of logic is in CCPPass::VisitBranch.  This
evaluates the selector of the branch.  When it's found to be a known
value, it computes the destination basic block and sets it.  This tells
the propagator which branches to follow.

The patch required extensions to the constant manager as well. Instead
of hashing the Constant pointers, this patch changes the constant pool
to hash the contents of the Constant.  This allows the lookups to be
done using the actual values of the Constant, preventing duplicate
definitions.
2017-12-21 14:29:45 -05:00
Steven Perron
756b277fb8 Store all enabled capabilities in the feature manger.
In order to keep track of all of the implicit capabilities as well as
the explicit ones, we will add them all to the feature manager.  That is
the object that needs to be queried when checking if a capability is
enabled.

The name of the "HasCapability" function in the module was changed to
make it more obvious that it does not check for implied capabilities.

Keep an spv_context and AssemblyGrammar in IRContext
2017-12-21 11:14:53 -05:00
Alan Baker
1ab8ad654a Fixing bugs in type manager memory management
* changed the way duplicate types are removed to stop copying
instructions
* Reworked RemoveDuplicatesPass::AreTypesSame to use type manager and
type equality
* Reworked TypeManager memory management to store a pool of unique
pointers of types
 * removed unique pointers from id map
 * fixed instances where free'd memory could be accessed
2017-12-21 08:59:06 -05:00
Pierre Moreau
424f744db1 Opt: Fix implementation and comment of AreDecorationsTheSame
Target should not be ignored when comparing decorations in RemoveDuplicates
Opt: Remove unused code in RemoveDuplicateDecorations
2017-12-19 15:36:47 -05:00
Steven Perron
79a00649b4 Allow pointers to pointers in logical addressing mode.
A few optimizations are updates to handle code that is suppose to be
using the logical addressing mode, but still has variables that contain
pointers as long as the pointer are to opaque objects.  This is called
"relaxed logical addressing".

|Instruction::GetBaseAddress| will check that pointers that are use meet
the relaxed logical addressing rules.  Optimization that now handle
relaxed logical addressing instead of logical addressing are:

 - aggressive dead-code elimination
 - local access chain convert
 - local store elimination passes.
2017-12-19 14:29:14 -05:00
Steven Perron
b86eb6842b Convert private variables to function scope.
When a private variable is used in a single function, it can be
converted to a function scope variable in that function.  This adds a
pass that does that.  The pass can be enabled using the option
`--private-to-local`.

This transformation allows other transformations to act on these
variables.

Also moved `FindPointerToType` from the inline class to the type manager.
2017-12-19 14:21:04 -05:00
Alan Baker
616908503d Improving the usability of the type manager. The type manager hashes
types. This allows the lookup of type declaration ids from arbitrarily
constructed types. Users should be cautious when dealing with non-unique
types (structs and potentially pointers) to get the exact id if
necessary.

* Changed the spec composite constant folder to handle ambiguous composites
* Added functionality to create necessary instructions for a type
* Added ability to remove ids from the type manager
2017-12-18 08:20:56 -05:00
GregF
0f80406315 ADCE: Only mark true breaks and continues of live loops
This fixes issue #1075

- Mark continue when conditional branch with merge block.
  Only mark if merge block is not continue block.

- Handle conditional branch break with preceding merge
2017-12-15 11:53:57 -05:00
Greg Fischer
22faa2b083 ADCE: Empty Loop Elimination
This entirely eliminates loops which do not contain live code.
2017-12-12 13:53:15 -05:00
Steven Perron
07ce16d1e7 Set the parent for basic blocks during inlining.
Inlining is not setting the parent (function) for each basic block.
This can cause problems for later optimizations.  The solution is to set
the parent for each new block just before it is linked into the
function.
2017-12-12 13:39:08 -05:00
Alan Baker
867451f49e Add scalar replacement
Adds a scalar replacement pass. The pass considers all function scope
variables of composite type. If there are accesses to individual
elements (and it is legal) the pass replaces the variable with a
variable for each composite element and updates all the uses.

Added the pass to -O
Added NumUses and NumUsers to DefUseManager
Added some helper methods for the inst to block mapping in context
Added some helper methods for specific constant types

No longer generate duplicate pointer types.

* Now searches for an existing pointer of the appropriate type instead
of failing validation
* Fixed spec constant extracts
* Addressed changes for review
* Changed RunSinglePassAndMatch to be able to run validation
 * current users do not enable it

Added handling of acceptable decorations.

* Decorations are also transfered where appropriate

Refactored extension checking into FeatureManager

* Context now owns a feature manager
 * consciously NOT an analysis
 * added some test
* fixed some minor issues related to decorates
* added some decorate related tests for scalar replacement
2017-12-11 10:51:13 -05:00
GregF
78c025abe9 MultiStore: Support OpVariable Initialization
Treat an OpVariable with initialization as if it was an OpStore.
With PR #1073, this completes work for issue #1017.
2017-12-11 10:37:14 -05:00
GregF
c6fdf68c2f SingleStore: Support OpVariable Initialization
Treat an OpVariable with initialization as if it was an OpStore.
This fixes issue #1017.
2017-12-08 16:02:14 -05:00
Steven Perron
5d602abd66 Add global redundancy elimination
Adds a pass that looks for redundant instruction in a function, and
removes them.  The algorithm is a hash table based value numbering
algorithm that traverses the dominator tree.

This pass removes completely redundant instructions, not partially
redundant ones.
2017-12-07 18:35:38 -05:00
Steven Perron
851e1ad985 Kill names and decoration in inlining.
Currently when inlining a call, the name and decorations for the result of the
call is not deleted.  This should be changed.  Added a test for this as well.

This fixes issue #622.
2017-12-07 12:20:45 -05:00
Victor Lomuller
731d1899b1 Add depth first iterator for trees
- Add generic depth first iterator
 - Update the dominator tree to use this iterator instead of "randomly"
   iterate over the nodes
2017-12-07 10:07:56 -05:00
Stephen McGroarty
8ba68fa9b9 Dominator Tree Analysis (#3)
Support for dominator and post dominator analysis on ir::Functions. This patch contains a DominatorTree class for building the tree and DominatorAnalysis and DominatorAnalysisPass classes for interfacing and caching the built trees.
2017-12-05 22:59:43 -05:00
Diego Novillo
e9ecc0cbfd Remove cfg_ field from SSAPropagator class - NFC.
When I moved the CFG into IRContext
(https://github.com/KhronosGroup/SPIRV-Tools/pull/1019), I forgot to
update SSAPropagator to stop requiring one.

Fixed with this patch.
2017-12-04 15:28:21 -05:00
Steven Perron
65046eca7c Change IRContext::KillInst to delete instructions.
The current method of removing an instruction is to call ToNop.  The
problem with this is that it leaves around an instruction that later
passes will look at.  We should just delete the instruction.

In MemPass there is a utility routine called DCEInst.  It can delete
essentially any instruction, which can invalidate pointers now that they
are actually deleted.  The interface was changed to add a call back that
can be used to update any local data structures that contain
ir::Intruction*.
2017-12-04 11:07:45 -05:00
Steven Perron
b35b52f97b Compute value number when the value table is constructed.
Computing the value numbers on demand, as we do now, can lead to
different results depending on the order in which the users asks for
the value numbers.  To make things more stable, we compute them ahead
of time.
2017-12-04 11:02:04 -05:00
GregF
8dd3d93cf6 AggressiveDCE: Add merge and continue branches for live loop.
This ensures that an if-break is not eliminated from a loop.

This fixes issue #989
2017-11-29 09:56:21 -05:00
Diego Novillo
8ffed974ac Fix windows build. unsigned vs signed comparison in EXPECT_EQ. 2017-11-28 09:13:42 -05:00
Diego Novillo
74327845aa Generic value propagation engine.
This class implements a generic value propagation algorithm based on the
conditional constant propagation algorithm proposed in

     Constant propagation with conditional branches,
     Wegman and Zadeck, ACM TOPLAS 13(2):181-210.

The implementation is based on

     A Propagation Engine for GCC
     Diego Novillo, GCC Summit 2005
     http://ols.fedoraproject.org/GCC/Reprints-2005/novillo-Reprint.pdf

The purpose of this implementation is to act as a common framework for any
transformation that needs to propagate values from statements producing new
values to statements using those values.
2017-11-27 23:32:06 -05:00
Diego Novillo
83228137e1 Re-format source tree - NFC.
Re-formatted the source tree with the command:

$ /usr/bin/clang-format -style=file -i \
    $(find include source tools test utils -name '*.cpp' -or -name '*.h')

This required a fix to source/val/decoration.h.  It was not including
spirv.h, which broke builds when the #include headers were re-ordered by
clang-format.
2017-11-27 14:31:49 -05:00
Alan Baker
746bfd210a Adding new def -> use mapping container
Replaced representation of uses

* Changed uses from unordered_map<uint32_t, UseList> to
set<pairInstruction*, Instruction*>>
* Replaced GetUses with ForEachUser and ForEachUse functions
* updated passes to use new functions
* partially updated tests
* lots of cleanup still todo

Adding an unique id to Instruction generated by IRContext

Each instruction is given an unique id that can be used for ordering
purposes. The ids are generated via the IRContext.

Major changes:
* Instructions now contain a uint32_t for unique id and a cached context
pointer
 * Most constructors have been modified to take a context as input
 * unfortunately I cannot remove the default and copy constructors, but
 developers should avoid these
* Added accessors to parents of basic block and function
* Removed the copy constructors for BasicBlock and Function and replaced
them with Clone functions
* Reworked BuildModule to return an IRContext owning the built module
 * Since all instructions require a context, the context now becomes the
basic unit for IR
* Added a constructor to context to create an owned module internally
* Replaced uses of Instruction's copy constructor with Clone whereever I
found them
* Reworked the linker functionality to perform clones into a different
context instead of moves
* Updated many tests to be consistent with the above changes
 * Still need to add new tests to cover added functionality
* Added comparison operators to Instruction

Adding tests for Instruction, IRContext and IR loading

Fixed some header comments for BuildModule

Fixes to get tests passing again

* Reordered two linker steps to avoid use/def problems
* Fixed def/use manager uses in merge return pass
* Added early return for GetAnnotations
* Changed uses of Instruction::ToNop in passes to IRContext::KillInst

Simplifying the uses for some contexts in passes
2017-11-23 16:40:02 -05:00
Lei Zhang
b02c9a5802 Allow derived access chain without uses in access chain conversion 2017-11-23 16:00:28 -05:00
Steven Perron
28c415500d Create a local value numbering pass
Creates a pass that removes redundant instructions within the same basic
block.  This will be implemented using a hash based value numbering
algorithm.

Added a number of functions that check for the Vulkan descriptor types.
These are used to determine if we are variables are read-only or not.

Implemented a function to check if loads and variables are read-only.
Implemented kernel specific and shader specific versions.

A big change is that the Combinator analysis in ADCE is factored out
into the IRContext as an analysis. This was done because it is being
reused in the value number table.
2017-11-23 11:45:09 -05:00
GregF
e28edd458b Optimize loads/stores on nested structs
Also fix LocalAccessChainConvert test: nested structs now convert

Add InsertExtractElim test for nested struct
2017-11-21 17:56:03 -05:00
Alan Baker
a771713e42 Adding an unique id to Instruction generated by IRContext
Each instruction is given an unique id that can be used for ordering
purposes. The ids are generated via the IRContext.

Major changes:
* Instructions now contain a uint32_t for unique id and a cached context
pointer
 * Most constructors have been modified to take a context as input
 * unfortunately I cannot remove the default and copy constructors, but
 developers should avoid these
* Added accessors to parents of basic block and function
* Removed the copy constructors for BasicBlock and Function and replaced
them with Clone functions
* Reworked BuildModule to return an IRContext owning the built module
 * Since all instructions require a context, the context now becomes the
basic unit for IR
* Added a constructor to context to create an owned module internally
* Replaced uses of Instruction's copy constructor with Clone whereever I
found them
* Reworked the linker functionality to perform clones into a different
context instead of moves
* Updated many tests to be consistent with the above changes
 * Still need to add new tests to cover added functionality
* Added comparison operators to Instruction
* Added an internal option to LinkerOptions to verify merged ids are
unique
* Added a test for the linker to verify merged ids are unique

* Updated MergeReturnPass to supply a context
* Updated DecorationManager to supply a context for cloned decorations

* Reworked several portions of the def use tests in anticipation of next
set of changes
2017-11-20 17:49:10 -05:00
Lei Zhang
4019bcfd57 Fix hard-coded header path
If SPIRV-Tools is used as an external project and have
googletest being kept in the same directory as it, we
won't have gmock-matchers.h in external/. This will
result in a compilation error.

Use gmock.h instead.
2017-11-17 19:54:55 -05:00
Steven Perron
eb4653a67f Add the decoration manager to the IRContext.
To make the decoration manger available everywhere, and to reduce the
number of times it needs to be build, I add one the IRContext.

As the same time, I move code that modifies decoration instruction into
the IRContext from mempass and the decoration manager.  This will make
it easier to keep everything up to date.

This should take care of issue #928.
2017-11-15 12:48:03 -05:00
Alan Baker
a92d69b43d Initial implementation of merge return pass.
Works with current DefUseManager infrastructure.

Added merge return to the standard opts.

Added validation to passes.

Disabled pass for shader capabilty.
2017-11-15 10:27:04 -05:00
Diego Novillo
98281ed411 Add analysis to compute mappings between instructions and basic blocks.
This analysis builds a map from instructions to the basic block that
contains them.  It is accessed via get_instr_block().  Once built, it is kept
up-to-date by the IRContext, as long as instructions are removed via
KillInst.

I have not yet marked passes that preserve this analysis. I will do it
in a separate change.

Other changes:

- Add documentation about analysis values requirement to be powers of 2.
- Force a re-build of the def-use manager in tests.
- Fix AllPreserveFirstOnlyAfterPassWithChange to use the
  DummyPassPreservesFirst pass.
- Fix sentinel value for IRContext::Analysis enum.

- Fix logic for checking if the instr<->block mapping is valid in KillInst.
2017-11-13 13:21:48 -05:00
Daniel Schürmann
a76d0977ac Fix decorations of inlined functions.
Fixes issue #728.  Currently the inliner is not generating decorations for
inlined code which corresponds to function code which has decorations. An
example of decorations that are relevant: RelaxedPrecision, NoContraction.

The solution is to replicate the decoration during inlining.
2017-11-13 12:49:25 -05:00
David Neto
76555bd4ba Tests: Add optional dependency on Effcee stateful matcher
Add Effcee as an optional dependency for use in tests.  In future it will
be a required dependency.

Effcee is a stateful pattern matcher that has much of the functionality
of LLVM's FileCheck, except in library form.  Effcee makes it much easier
to write tests for optimization passes.

Demonstrate its use in a test for the strength-reduction pass.

Update README.md with example commands of how to get sources.

Update Appveyor and Travis-CI build rules.

Also: Include test libraries if not SPIRV_SKIP_TESTS
- SPIRV_SKIP_TESTS is implied by SPIRV_SKIP_EXECUTABLES
2017-11-13 11:34:21 -05:00
Steven Perron
f32d11f74b Add the IRContext (part 2): Add def-use manager
This change will move the instances of the def-use manager to the
IRContext.  This allows it to persists across optimization, and does
not have to be rebuilt multiple times.

Added test to ensure that the IRContext is validating and invalidating
the analyses correctly.
2017-11-08 13:35:34 -05:00
GregF
ac04b2faea Opt: Fix HasLoads to not report decoration as load. 2017-11-07 17:39:58 -05:00
Steven Perron
476cae6f7d Add the IRContext (part 1)
This is the first part of adding the IRContext.  This class is meant to
hold the extra data that is build on top of the module that it
owns.

The first part will simply create the IRContext class and get it passed
to the passes in place of the module.  For now it does not have any
functionality of its own, but it acts more as a wrapper for the module.

The functions that I added to the IRContext are those that either
traverse the headers or add to them.  I did this because we may decide
to have other ways of dealing with these sections (for example adding a
type pool, or use the decoration manager).

I also added the function that add to the header because the IRContext
needs to know when an instruction is added to update other data
structures appropriately.

Note that there is still lots of work that needs to be done.  There are
still many places that change the module, and do not inform the context.
That will be the next step.
2017-10-31 13:46:05 -04:00
GregF
94bec26afe ADCE: Dead if elimination
Mark structured conditional branches live only if one or more instructions
in their associated construct is marked live. After closure, replace dead
structured conditional branches with a branch to its merge and remove
dead blocks.

ADCE: Dead If Elim: Remove duplicate StructuredOrder code

Also generalize ComputeStructuredOrder so that the caller can specify the
root block for the order. Phi insertion uses pseudo_entry_block and adce and
dead branch elim use the first block of the function.

ADCE: Dead If Elim: Pull redundant code out of InsertPhiInstructions

ADCE: Dead If Elim: Encapsulate CFG Cleanup Initialization

ADCE: Dead If Elim: Remove redundant code from ADCE initialization

ADCE: Dead If: Use CFGCleanup to eliminate newly dead blocks

Moved bulk of CFG Cleanup code into MemPass.
2017-10-31 11:51:30 -04:00
Steven Perron
94dc66b74d Change the sections in the module to use the InstructionList class.
This change will replace a number of the
std::vector<std::unique_ptr<Instruction>> member of the module to
InstructionList.  This is for consistency and to make it easier to
delete instructions that are no longer needed.
2017-10-25 15:52:06 -04:00
Daniel Schürmann
97990dc907 Fixed --eliminate-common-uniform so that it does not eliminate loads of volatile variables. 2017-10-24 11:17:33 -04:00
Steven Perron
5834719fc1 Add pass to remove dead variables at the module level.
There does not seem to be any pass that remove global variables.  I
think we could use one.  This pass will look specifically for global
variables that are not referenced and are not exported.  Any decoration
associated with the variable will also be removed.  However, this could
cause types or constants to become unreferenced.  They will not be
removed.  Another pass will have to be called to remove those.
2017-10-23 13:57:05 -04:00
David Neto
2436794736 Optimizer: OpModuleProcessed is in its own layout section
This is a recent decision from the SPIR WG.  The spec update
has not yet been published.
Khronos SPIR-V internal issue 199
2017-10-23 10:46:37 -04:00
Steven Perron
bb7802b18c Change BasicBlock to use InstructionList to hold instructions.
This is the first step in replacing the std::vector of Instruction
pointers to using and intrusive linked list.

To this end, we created the InstructionList class.  It inherites from
the IntrusiveList class, but add the extra concept of ownership.  An
InstructionList owns the instruction that are in it.  This is to be
consistent with the current ownership rules where the vector owns the
instruction that are in it.

The other larger change is that the inst_ member of the BasicBlock class
was changed to using the InstructionList class.

Added test for the InsertBefore functions, and making sure that the
InstructionList destructor will delete the elements that it contains.

I've also add extra comments to explain ownership a little better.
2017-10-20 12:37:44 -04:00
David Neto
8ec62deb23 The reviewed cfg_cleanup optimize pass 2017-10-19 15:28:09 -04:00
Diego Novillo
c75704ec08 CFG cleanup pass - Remove unreachable blocks.
- Adds a new pass CFGCleanupPass.  This serves as an umbrella pass to
  remove unnecessary cruft from a CFG.
- Currently, the only cleanup operation done is the removal of
  unreachable basic blocks.
- Adds unit tests.
- Adds a flag to spirvopt to execute the pass (--cfg-cleanup).
2017-10-19 15:16:29 -04:00
GregF
1a9061a2be ADCE: Treat privates like locals in entry point with no calls
This is needed for ongoing legalization of HLSL. It allows removal
of accesses to textures/buffers that are not used.
2017-10-13 15:39:14 -04:00
GregF
63064bd9eb DeadBranchElim: Add dead case elimination
Expands dead branch elimination to eliminate dead switch cases. It also
changes dbe to eliminate orphaned merge blocks and recursively eliminate
any blocks thereby orphaned.
2017-10-12 11:44:05 -04:00
Pierre Moreau
86627f7b3f Implement Linker (module combiner)
Add extra iterators for ir::Module's sections
Add extra getters to ir::Function
Add a const version of BasicBlock::GetLabelInst()

Use the max of all inputs' version as version

Split debug in debug1 and debug2
- Debug1 instructions have to be placed before debug2 instructions.

Error out if different addressing or memory models are found

Exit early if no binaries were given

Error out if entry points are redeclared

Implement copy ctors for Function and BasicBlock
- Visual Studio ends up generating copy constructors that call deleted
  functions while compiling the linker code, while GCC and clang do not.
  So explicitly write those functions to avoid Visual Studio messing up.

Move removing duplicate capabilities to its own pass

Add functions running on all IDs present in an instruction

Remove duplicate SpvOpExtInstImport

Give default options value for link functions

Remove linkage capability if not making a library

Check types before allowing to link

Detect if two types/variables/functions have different decorations

Remove decorations of imported variables/functions and their types

Add a DecorationManager

Add a method for removing all decorations of id

Add methods for removing operands from instructions

Error out if one of the modules has a non-zero schema

Update README.md to talk about the linker

Do not freak out if an imported built-in variable has no export
2017-10-06 18:33:53 -04:00
GregF
da04f5640e AggressiveDCE: Fix to not treat parameter memory refs as local
This fixes a bug that incorrectly deletes stores to parameters, which
can be used to return values from functions.
2017-10-05 10:59:45 -04:00
Pierre Moreau
c87e9671ab Compact-ids pass should update the header ID bound 2017-10-03 11:24:28 -04:00
David Neto
77feb8dd03 Compact-ids pass should update instruction's result_id member
Also update the result type field.

Fixes https://github.com/KhronosGroup/SPIRV-Tools/issues/827
2017-09-27 08:31:05 -04:00
Steven Perron
e43c91046b Create the dead function elimination pass
Creates a pass called eliminate dead functions that looks for functions
that could never be called, and deletes them from the module.

To support this change a new function was added to the Pass class to
traverse the call trees from diffent starting points.

Includes a test to ensure that annotations are removed when deleting a
dead function.  They were not, so fixed that up as well.

Did some cleanup of the assembly for the test in pass_test.cpp.  Trying
to make them smaller and easier to read.
2017-09-26 11:18:06 -04:00
David Neto
33b879c105 elim-multi-store: only patch loop header phis that we created
There can already be OpPhi instructions in a loop header that
are unrelated to the optimization.  We should not be patching those.

Fixes https://github.com/KhronosGroup/SPIRV-Tools/issues/826
2017-09-21 10:01:30 -04:00
Steven Perron
e4c7d8e748 Add strength reduction; for now replace multiply by power of 2
Create a new optimization pass, strength reduction, which will replace
integer multiplication by a constant power of 2 with an equivalent bit
shift.  More changes could be added later.

- Does not duplicate constants

- Adds vector |Concat| utility function to a common test header.
2017-09-18 17:01:36 -04:00
David Neto
25ddfec08e Inliner: Fix LoopMerge when inline into loop header of multi block loop
This adapts the fix for the single-block loop.  Split the loop like
before.  But when we move the OpLoopMerge back to the loop header,
redirect the continue target only when the original loop was a single
block loop.

Fixes https://github.com/KhronosGroup/SPIRV-Tools/issues/800
2017-09-05 19:46:24 -04:00
David Neto
860c4197b0 Inliner: Remap callee entry block id to single-trip loop header
Otherwise cloned phis can be invalid.

Fixes https://github.com/KhronosGroup/SPIRV-Tools/issues/790
2017-09-01 15:56:14 -04:00
David Neto
efff5fabfa Inline: Fix single-block loop caller cases
If the caller block is a single-block loop and inlining will
replace the caller block by several blocks, then:
- The original OpLoopMerge instruction will end up in the *last*
  such block.  That's the wrong place to put it.
- Move it back to the end of the first block.
- Update its Continue Target ID to point to the last block

We also have to take care of cases where the inlined code
begins with a structured header block.  In this case
we need to ensure the restored OpLoopMerge does not appear
in the same block as the merge instruction from the callee's
first block.

Fixes https://github.com/KhronosGroup/SPIRV-Tools/issues/787
2017-09-01 15:47:17 -04:00
GregF
7c3de19ce7 DeadBranchElim: Fix dead block detection to ignore backedges
- DeadBranchElim: Make sure to mark orphan'd merge blocks and continue
targets as live.
- Add test with loop in dead branch
- Add test that orphan'd merge block is handled.

Fixes https://github.com/KhronosGroup/SPIRV-Tools/issues/776
2017-08-30 13:37:46 -04:00
GregF
a699d1ade7 Inline: Fix remapping of non-label forward references in callee phi 2017-08-29 18:35:05 -06:00
GregF
429ca05b3f Opt: Create InlineOpaquePass
Only inline calls to functions with opaque params or return

TODO: Handle parameter type or return type where the opqaue
type is buried within an array.
2017-08-18 18:04:30 -04:00
GregF
c8c86a0d36 Opt: Have "size" passes process full entry point call tree.
Includes code to deal correctly with OpFunctionParameter. This
is needed by opaque propagation which may not exhaustively inline
entry point functions.

Adds ProcessEntryPointCallTree: a method to do work on the
functions in the entry point call trees in a deterministic order.
2017-08-18 10:16:01 -04:00
GregF
1d477b9898 Opt: Add opaque tests 2017-08-15 15:54:41 -06:00
GregF
b0310a4156 ADCE: Add support for function calls
ADCE will now generate correct code in the presence of function calls.
This is needed for opaque type optimization needed by glslang. Currently
all function calls are marked as live. TODO: mark calls live only if they
write a non-local.
2017-08-10 17:30:05 -04:00
David Neto
2a1014be9c Inliner: callee can have early return that isn't multi-return
Avoid generating an invalid OpLabel.
Create the continue target for the single-trip loop only if
you actually created the header for the single-trip loop.

Fixes https://github.com/KhronosGroup/SPIRV-Tools/issues/755
2017-08-10 11:43:44 -04:00
GregF
e28bd39997 Inline: Split out InlineExhaustivePass from InlinePass 2017-08-04 17:56:46 -04:00
GregF
f4b29f3bf7 Add CommonUniformElim pass
- UniformElim: Only process reachable blocks

- UniformElim: Don't reuse loads of samplers and images across blocks.
  Added a second phase which only reuses loads within a block for samplers
  and images.

- UniformElim: Upgrade CopyObject skipping in GetPtr

- UniformElim: Add extensions whitelist
  Currently disallowing SPV_KHR_variable_pointers because it doesn't
  handle extended pointer forms.

- UniformElim: Do not process shaders with GroupDecorate

- UniformElim: Bail on shaders with non-32-bit ints.

- UniformElim: Document support for only single index and add TODO.
2017-08-03 11:34:58 -04:00
GregF
c1b46eedbd Add MemPass, move all shared functions to it. 2017-08-02 14:24:02 -04:00
GregF
7954740d54 Opt: Delete names and decorations of dead instructions 2017-07-26 18:36:41 -04:00
Lei Zhang
9f6efc76c8 Opt: HasOnlySupportedRefs should consider OpCopyObject
This fixes test failure after merging the previous pull request.
2017-07-25 23:22:09 -04:00
GregF
1182415581 Add extension whitelists to size-reduction passes.
Currently only SPV_KHR_variable_pointers is disallowed in passes which
do pointer analysis. Positive and negative tests of the general extensions
mechanism were added to aggressive_dce but cover all passes.
2017-07-25 19:14:02 -04:00
GregF
adb237f3bd Fix handling of CopyObject in GetPtr and its call sites 2017-07-21 18:08:01 -04:00
GregF
9de4e69856 Add AggressiveDCEPass
Create aggressive dead code elimination pass
This pass eliminates unused code from functions. In addition,
it detects and eliminates code which may have spurious uses but which do
not contribute to the output of the function. The most common cause of
such code sequences is summations in loops whose result is no longer used
due to dead code elimination. This optimization has additional compile
time cost over standard dead code elimination.

This pass only processes entry point functions. It also only processes
shaders with logical addressing. It currently will not process functions
with function calls. It currently only supports the GLSL.std.450 extended
instruction set. It currently does not support any extensions.

This pass will be made more effective by first running passes that remove
dead control flow and inlines function calls.

This pass can be especially useful after running Local Access Chain
Conversion, which tends to cause cycles of dead code to be left after
Store/Load elimination passes are completed. These cycles cannot be
eliminated with standard dead code elimination.

Additionally: This transform uses a whitelist of instructions that it
knows do have side effects, (a.k.a. combinators).  It assumes other
instructions have side effects: it will not remove them, and assumes
they have side effects via their ID operands.
2017-07-10 11:30:25 -04:00
GregF
cc8bad3a5b Add LocalMultiStoreElim pass
A SSA local variable load/store elimination pass.
For every entry point function, eliminate all loads and stores of function
scope variables only referenced with non-access-chain loads and stores.
Eliminate the variables as well.

The presence of access chain references and function calls can inhibit
the above optimization.

Only shader modules with logical addressing are currently processed.
Currently modules with any extensions enabled are not processed. This
is left for future work.

This pass is most effective if preceeded by Inlining and
LocalAccessChainConvert. LocalSingleStoreElim and LocalSingleBlockElim
will reduce the work that this pass has to do.
2017-07-07 17:54:21 -04:00
GregF
52e247f221 DeadBranchElim: Add DeadBranchElimPass 2017-07-07 15:16:25 -04:00
David Neto
35a0695844 Include memory and semantics IDs when iterating over inbound IDs
Fixes Instruction::ForEachInId so it covers
SPV_OPERAND_TYPE_MEMORY_SEMANTICS_ID and SPV_OPERAND_TYPE_SCOPE_ID.
Future proof a bit by using the common spvIsIdType routine.

Fixes https://github.com/KhronosGroup/SPIRV-Tools/issues/697
2017-07-05 10:36:57 -04:00
GregF
ad1d0351a0 BlockMerge: Add BlockMergePass
Also, add BasicBlock::tail()
2017-06-27 11:31:33 -04:00
GregF
6136bf9e0b mem2reg: Add InsertExtractElimPass 2017-06-21 08:13:15 -04:00
GregF
0c5722fc01 mem2reg: Add LocalSingleStoreElimPass
Eliminate function scope variables with one store, if possible.
2017-06-19 10:43:02 -04:00
GregF
7c8da66bc2 mem2reg: Add pass to eliminate local loads and stores in single block. 2017-06-12 17:03:47 -04:00
GregF
aa7e687ef0 Mem2Reg: Add Local Access Chain Convert pass
- Supports OpAccessChain and OpInBoundsAccessChain
- Does not process modules with non-32-bit integer types.
2017-06-04 12:49:27 -04:00
Greg Fischer
bba812f4e4 Inline: Inline early return function if no returns in loop. 2017-05-12 17:18:00 -04:00
Mike Lothain
3f90058d2f Update set_spec_const_default_value_test.cpp
Work around warning of dangling else
2017-05-08 10:41:48 -04:00
GregF
a107d349e3 Inline: Do not inline functions with multiple returns (for now) 2017-04-25 16:50:57 -06:00
qining
144f59e451 Add bit pattern interface for setting default value for spec constants 2017-04-21 11:22:47 -04:00
Andrey Tuganov
1e309af80a Added --compact-ids to /tools/opt
The pass remaps ids to a compact set which starts with %1 and
has no gaps.
2017-04-20 10:54:39 -04:00
David Neto
11a867f412 Add FlattenDecoration transform
Add --flatten-decorations to spirv-opt

Flattens decoration groups.  That is, replace OpDecorationGroup
and its uses in OpGroupDecorate and OpGroupMemberDecorate with
ordinary OpDecorate and OpMemberDecorate instructions.

Fixes https://github.com/KhronosGroup/SPIRV-Tools/issues/602
2017-04-06 11:19:56 -04:00
David Neto
afc60bbebf Fix optimizer on when to write the binary
The spvtools::Optimizer::Run method should also write the output binary
if optimization succeeds without changes but the output binary vector
does not have exactly the same contents as the input binary.
We have to check both the base pointer of the storage and the size of
the vector

Added a test for this too.

Fixes https://github.com/KhronosGroup/SPIRV-Tools/issues/611
2017-04-03 15:48:50 -04:00
David Neto
ceb1d4f2fd Avoid inlining calls to external functions
External functions don't have bodies to inline anyway.
Fixes https://github.com/KhronosGroup/SPIRV-Tools/issues/605
2017-03-31 10:36:58 -04:00
David Neto
2410e00851 Add low priority test suggestions for inliner 2017-03-29 18:02:40 -04:00
Greg Fischer
04fcc66743 Add exhaustive function call inlining to spirv-opt
Inlining is done for all functions designated as entry points.

Add optional validation to test fixture method SinglePassRunAndCheck.
2017-03-29 18:02:40 -04:00
David Neto
545a6c1dc3 Provide friendly names for true and false 2017-01-11 16:33:45 -05:00
David Neto
c935253c91 Make friendly number-based names for OpConstant
For example:
  %int_42 = OpConstant %int 42
  %int_n42 = OpConstant %int -42
  %float_3_14 = OpConstant %float 3.14
2016-11-15 14:05:03 -05:00
Lei Zhang
4f57e140bf Renaming test files to comply with Google style guide.
Also posfixing test files with `_test' to make it more clear.
2016-11-07 14:41:51 -05:00
Lei Zhang
c1d5e660ee Add begin() and end() for TypeManager. 2016-09-30 16:56:42 -04:00
Lei Zhang
f9cb7c282c Avoid appending EOL in StringifyMessage().
EOL should be appended when outputing to streams by the tool.
2016-09-23 15:13:24 -04:00