If there is an optimisation opportunity and the function argument hasn’t been added to constraint
system through previous facts we fail to optimise it.
It might be a good idea to start the constraint system with all the function arguments added to the system
Reviewed By: fhahn
Differential Revision: https://reviews.llvm.org/D144879
This reverts commit 2a2a6bfcfe8e62886542cb673ac8df349cf26499.
This causes build failures:
/home/npopov/repos/llvm-project/llvm/lib/Analysis/ConstraintSystem.cpp: In member function ‘llvm::SmallVector<std::__cxx11::basic_string<char> > llvm::ConstraintSystem::getVarNamesList() const’:
/home/npopov/repos/llvm-project/llvm/lib/Analysis/ConstraintSystem.cpp:118:10: error: invalid use of incomplete type ‘class llvm::Value’
118 | if (V->getName().empty())
| ^~
In file included from /home/npopov/repos/llvm-project/llvm/lib/Analysis/ConstraintSystem.cpp:9:
/home/npopov/repos/llvm-project/llvm/include/llvm/Analysis/ConstraintSystem.h:21:7: note: forward declaration of ‘class llvm::Value’
21 | class Value;
| ^~~~~
/home/npopov/repos/llvm-project/llvm/lib/Analysis/ConstraintSystem.cpp:119:22: error: invalid use of incomplete type ‘class llvm::Value’
119 | OperandName = V->getNameOrAsOperand();
| ^~
/home/npopov/repos/llvm-project/llvm/include/llvm/Analysis/ConstraintSystem.h:21:7: note: forward declaration of ‘class llvm::Value’
21 | class Value;
| ^~~~~
/home/npopov/repos/llvm-project/llvm/lib/Analysis/ConstraintSystem.cpp:121:41: error: invalid use of incomplete type ‘class llvm::Value’
121 | OperandName = std::string("%") + V->getName().str();
| ^~
/home/npopov/repos/llvm-project/llvm/include/llvm/Analysis/ConstraintSystem.h:21:7: note: forward declaration of ‘class llvm::Value’
21 | class Value;
| ^~~~~
Previously when constraint system outputs the rows in the system the variables used are x1,2...n making it hard to infer which ones they relate to in the IR
Reviewed By: fhahn
Differential Revision: https://reviews.llvm.org/D142618
This patch adds an optimization remark for each performed optimization
containing a module that can be used to reproduce the transformation.
The reproducer function contains a series of @llvm.assume calls, one for
each condition currently in scope. For each condition, the operand
instruction are cloned until we reach operands that have an entry in the
constraint system. Those will then be added as function arguments.
The reproducer functions are minimal, that is, they only contain the
conditions required for a given simplification. The resulting IR is very
compact and can be used to verify each transformation individually.
It also provides a python script to extract the IR from the remarks and
create LLVM IR files from it.
Reviewed By: paquette
Differential Revision: https://reviews.llvm.org/D143323
This reverts commit 40ffe9c167395256b43846733ab69eec17eead78.
Reverted because some comments where missed in the review https://reviews.llvm.org/D142647
Once the constraint system grows too large in terms of number of rows,
queries can become very slow. This patch adds a new option to limit the
number of rows tracked.
The python script below can be used to generate worst-case IR with a
chain of conditional branches with N branches.
With this limit, we get the following runtimes:
* python3 generate.py 100: 0.1s
* python3 generate.py 1000: 2s
* python3 generate.py 10000: 4s
Without the limit, the case with 1000 chained conditions takes 20+
seconds.
generate.py:
import sys
N = int(sys.argv[1])
args = []
checks = []
for i in range(0, N):
args.append('i32 %l{}'.format(i))
checks.append("""
bb{0}:
%c{0} = icmp uge i32 %l{0}, 100
br i1 %c{0}, label %bb{1}, label %exit
""".format(i, i+1))
print("""
define i1 @foo({0}) {{
{1}
bb{2}:
%c{2} = icmp uge i32 %l0, 100
ret i1 %c{2}
exit:
ret i1 false
}}
""".format(' ,'.join(args), '\n'.join(checks), N))
Reviewed By: nikic
Differential Revision: https://reviews.llvm.org/D140926
Update the sort order to make sure that comesBefore is never used from
conditional facts, which are instructions but may use DFS numbers from
different blocks.
This fixes a crash in the added test on some platforms.
This allows interleaving facts and checks in a single block. In
particular this enables using facts from assumes for conditions in the
same block that come after the assume.
This could be extended to only try to simplify checks at the point where
a condition is used.
Reviewed By: nikic
Differential Revision: https://reviews.llvm.org/D138452
This slightly simplifies the code and addresses a correctness issue
where the index scaling for the precondition was not considered
properly.
Thanks to @nikic for pointing that out in D137840.
Use collectOffset to collect scaled indices and constant offset for GEP
instead of custom code. This simplifies the logic in decomposeGEP and
allows to handle all cases supported by the generic helper.
Replace the vector of DecompEntry with a struct that stores the
constant offset separately. I think this is cleaner than giving the
first element special handling.
This probably also fixes some potential ubsan errors by more
consistently using addWithOverflow/multiplyWithOverflow.
decompose() currently returns a mix of {} and 0 + 1*V on failure.
This changes it to always return the 0 + 1*V form, thus making
decompose() infallible.
This makes the code marginally more powerful, e.g. we now fold
sub_decomp_i80 by treating the constant as a symbolic value.
Differential Revision: https://reviews.llvm.org/D137847
Commit 359bc5c541ae4b02 caused
Assertion `isa<To>(Val) && "cast<Ty>() argument of incompatible type!"'
failures in decomposeGEP when the GEP pointer operand is a vector.
Fix is to use DataLayout::getIndexTypeSizeInBits when fetching the
index size, as it will use the scalar type in case of a ptr vector.
Differential Revision: https://reviews.llvm.org/D137185
At the moment, the implementation requires that the outer GEP has a
single index, the inner GEP can have an arbitrary indices, because the
general `decompose` helper is used.
If the arithmetic for indices of inbounds GEPs overflows, the result is
poison. This means it is also OK for the coefficients to overflow. GEP
decomposition is limited to cases where the index size is <= 64 bit,
which can be represented by int64_t used for the coefficients in the
constraint system.
Instead of duplicating the existing decomposition code for GEP indices
just use the existing code by calling the existing decompose function on
the index expression and multiply the result's coefficients by the scale of
the index.
This both reduces code duplication and generalizes the pattern we can
handle.
If both operands of an `add nsw` are known positive, it can be treated
the same as `add nuw` and added to the unsigned system.
https://alive2.llvm.org/ce/z/6gprff
Support decomposition for `mul/shl nuw` with constant operand for unsigned
queries. Those expressions should not wrap in the unsigned sense and can
be added directly to the unsigned system.
Move logic to check and replace conditions to a helper function. This
isolates the code, allows using early returns, reduces the
indentation and simplifies eliminateConstraints.
Limit pointer decomposition to pointers with index sizes of at most 64
bits. int64_t is used for coefficients, so as long as the index size <=
64 bits we should be able to represent all pointer offsets.
Pointer decomposition is limited to inbounds GEPs, so if a index
computation would overflow the result is poison, so it doesn't matter
that the coefficient overflows.
This allows replacing MulOverflow with regular multiplications.
The current decomposition for GEPs did not correctly handle cases where
GEPs access different source types. Adjust the constraints by including
the indexed type-size as coefficients.
Further generalization to allow GEPs with more than one index is a
needed general follow-up improvement.
Move common logic shared by callers of getConstraint that use the result
to query the constraint system to a new helper getConstraintForSolving.
This includes common legality checks (i.e. not an equality constraint,
no new variables) and the logic to query the unsigned system if possible
for signed predicates.