aboutsummaryrefslogtreecommitdiffstatshomepage
AgeCommit message (Collapse)AuthorFilesLines
2020-12-29add testcases for dubious enum valuesLuc Van Oostenryck1-0/+18
sparse accept any type of integral value for enumerators but address constants are also accepted, which is 'strange'. Add a testcase for such 'enums'. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-12-27ptrlist: avoid mixing reverse and non-reverse macrosLuc Van Oostenryck1-12/+17
The macros used to iterate the ptrlists exist in two kinds: those to iterate forward direction and those to iterate in the reverse direction. Those macros must be used in pair: one for the top of the loop and one at the end of the loop. However, if we mix them, for example like: FOR_EACH_PTR(list, var) { ... } FOR_EACH_PTR_REVERSE(var); things will still work for lists with a single block (most of them) but will behave strangely and of course wrongly when reaching the next block. So, to avoid future debugging fun, add a unused variable, discarded at compile time, but with distinct prefix for each direction. This way, mixing the macros will create a warning at compile time. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-12-27shrink struct BBLuc Van Oostenryck2-7/+6
Reorganize the members of struct BB, avoiding padding and making better use of the union, to shrink its size from 104 to 96 bytes. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-12-11Merge branch 'fix-parsing-testsuite-tags'Luc Van Oostenryck3-4/+5
* fix parsing of tags used in the testcases
2020-12-11testsuite: fix parsing of tags used in the testcasesLuc Van Oostenryck3-4/+5
In testcases' tags, if a value contains 'check-' then this value will be used as the tagname instead of the value. Fix this by adding a bit more context in the regexp used for parsing these. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-12-11Merge branches 'kill-asm' and 'next'Luc Van Oostenryck3-3/+37
* fix killing OP_ASM * move check_access() to late_warnings()
2020-12-10move check_access() to late_warnings()Luc Van Oostenryck3-3/+37
check_access() is called at each run of simplify_loads(). However, a bad access can belong to a dead branch and thus a bad access warning can be issued for code that is not executed, maybe specifically excluded. So, move check_access() to late_warnings(), where all optimizations have been done. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-12-04fix killing OP_ASMLuc Van Oostenryck1-0/+15
Currently OP_ASMs are only handled by default in kill_insn(). In consequence, the usage is not removed from their inputs, possibly leaving dead pseudos. Fix this by removing the usage on the input pseudos. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-12-02Merge branch 'kill-replace' into nextLuc Van Oostenryck7-74/+64
* let replace_with_pseudo() use kill_instruction() * move rewrite_load_instruction() to memops.c * replace convert_load_instruction() by replace_with_pseudo()
2020-12-02Merge branches 'fix-kill_dominated_stores' and 'kill-dead-loads' into nextLuc Van Oostenryck2-0/+27
* memops: fix wrong killing of stores partially dominated by a load * memops: kill dead loads before phi-node conversion
2020-11-29memops: kill dead loads before phi-node conversionLuc Van Oostenryck2-0/+27
During load simplification it may happen that a load is unused but if this fact is ignored and the usual conversion to a phi-node is made, then this value may seem to be needed and can't anymore be simplified away. Fix this by removing dead loads during load simplification. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-28fix wrong killing of stores partially dominated by a loadLuc Van Oostenryck2-2/+29
When a partial but overlapping load is followed by a store, this load is not considered as dominating the store. This is a problem for kill_dominated_stores() because the load will be simply ignored. For example, in code like: union { u64 l; int i; } u; int i; u.l = x; i = u.i; u.l = y; The load will be ignored, then the first store can be ignored too and the value of 'i' will be undefined (but actually set to 0). The root of the problem seems to be situated in dominates() where a load is considered as dominating another memop only if both correspond to the same 'access' (address and size). This is probably fine when the other memop is itself a load (because the value of the first load can't be reused for the second one) but it's not when the other memop if a store. So, to be safe, consider different-but-overlapping memops as neither dominated or non-dominated but as "don't know". Note: as explained here above, this can *probably* be relaxed when both memops are loads but it's not 100% clear to me yet and I found no examples where it actually make a difference. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-28replace convert_load_instruction() by replace_with_pseudo()Luc Van Oostenryck4-14/+10
These two functions are now exactly the same, so replace the first one by the second one. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-28memops: move rewrite_load_instruction() hereLuc Van Oostenryck3-42/+41
The function rewrite_load_instruction() is defined in flow.c but: * is not directly related to 'flow' * it's only used in memops.c * needs some change related to simplify_loads(). So, move this code to memops.c Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-28make replace_with_pseudo() externLuc Van Oostenryck2-1/+3
This function can be useful since it can be useful in other files, for example in memops.c So make it extern.. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-28make a header for simplificationLuc Van Oostenryck4-1/+10
The few external functions defined in simplify.h are declared in flow.h (for historical reasons). In preparation for some changes, create a specific headers for these. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-28let replace_with_pseudo() use kill_instruction()Luc Van Oostenryck1-17/+1
In replace_with_pseudo(), the replaced instruction needs to be killed and for this contains ts own code. But this is a duplication of what is already done in kill_instruction(). So, replace this part of the code by a cal to kill_instruction(). Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-28Merge branch 'bit-trans' into nextLuc Van Oostenryck11-17/+504
* factorize (x OP1 z) OP2 (y OP1 z) into (x OP2 y) OP1 z * factorize SHIFT(x, s) OP SHIFT(y, s) into SHIFT((x OP y), s) * factorize SEL(x, OP(y,z), y) into OP(SEL(x, z, 0), y) * convert SEL(x & BIT1, BIT2, 0) into SHIFT(x & BIT1, S)
2020-11-27convert SEL(x & BIT1, BIT2, 0) into SHIFT(x & BIT1, S)Luc Van Oostenryck2-1/+15
Convert an expression like: (x & (1 << A)) ? (1 << B) : 0 into: (x & (1 << A)) << (B - A) or: (x & (1 << A)) >> (A - B) Suggested-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-27add log base 2 function: log2_exact()Luc Van Oostenryck1-0/+7
Add log2_exact() to get the base 2 logarithm of a value known to be a power of 2. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-27add helper is_pow2()Luc Van Oostenryck1-0/+9
Add is_pow2() to test if a pseudo is a power of 2. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-27add helper is_power_of_2()Luc Van Oostenryck1-0/+5
Add is_power_of_2() to test if a value is a power of 2. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-27factorize SEL(x, OP(y,z), y) into OP(SEL(x, z, 0), y)Luc Van Oostenryck2-1/+40
'Factorize' and expression like: x ? (y | z) : y; into (x ? z : 0) | y; and some positional variants as well as replacing '|' by '+' or '^'. Note: it's not very clear if this is really an improvement but it allows some very nice simplification of 'bits translations'. Note: the same can be done for others operations, for example it can be done for '&' if '0' (the neuter value for '|', '+' and '^') by '~0' (same with '*' and '1'). Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-27add testscases for 'bits translation' optimizationLuc Van Oostenryck2-0/+44
Add some testcase related to the simplification of expressions like: if (val1 & BIT1) val2 |= BIT2; into val2 |= (val1 & BIT1) {SHL/LSR} |BIT2-BIT1|; Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-27factorize SHIFT(x, s) OP SHIFT(y, s) into SHIFT((x OP y), s)Luc Van Oostenryck4-3/+27
Factorize bitwise OPs of shifts with identical counts. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-27factorize (x OP1 z) OP2 (y OP1 z) into (x OP2 y) OP1 zLuc Van Oostenryck5-4/+78
Factorize common distributive operations: (x * z) + (y * z) --> (x + y) * z (x | z) & (y | z) --> (x & y) | z (x & z) | (y & z) --> (x | y) & z (x & z) ^ (y & z) --> (x ^ y) & z Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-27refactor simplify_add() to avoid code duplicationLuc Van Oostenryck1-13/+9
Do some refactoring in simplify_add() to avoid some code duplication there and better handle generic transforms that need to be applied on both operands. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-27refactor simplify_add() to avoid code duplication (preparation)Luc Van Oostenryck1-5/+2
Do some refactoring in simplify_add() to prepare the next patch which will avoid some code duplication there. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-27add helper replace_binop()Luc Van Oostenryck1-0/+17
Add an helper to replace a binop OP(a, b) and taking care to drop the usage of the previous operands. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-27add helper make_insn_pair() & swap_insn()Luc Van Oostenryck1-0/+31
Add two helpers to create instruction pair OUT(IN(a, b), c). Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-27reassoc: add helper can_move_to()Luc Van Oostenryck1-0/+37
When transforming IR expressions, it may happen that we want to reuse an instruction and move a pseudo into it but that this pseudo is only defined later. Add a small help to check this: can_move_to(). Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-27add testscases for some factorization of distributive operationsLuc Van Oostenryck7-0/+193
Add some testcases for factorizations of: (x * z) + (y * z) --> (x + y) * z (x | z) & (y | z) --> (x & y) | z (x & z) | (y & z) --> (x | y) & z (x & z) ^ (y & z) --> (x ^ y) & z and (x << s) | (y << s) --> ((x | y) << s) and same for &, ^, LSR and ASR. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-26Merge branch 'fix-trivial-phi' into nextLuc Van Oostenryck2-2/+22
* fix trivial_phi() when the target is before the single value
2020-11-26fix trivial_phi() when the target is before the single valueLuc Van Oostenryck2-2/+22
A phi-node is called 'trivial' if it only reference itself and a single other value. In this case the only possible value for the phi-node is this single other value which can thus replace the phi-node. However, the current code get this slightly wrong when the first referenced value is itself and not the other value. Fix this by moving up the test checking if it references itself. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-26Merge branch 'ir-symaddr' into nextLuc Van Oostenryck1-4/+4
* give a type to OP_SYMADDR
2020-11-24Merge branch 'optim-not' into nextLuc Van Oostenryck11-23/+200
* put PSEUDO_ARGS and PSEUDO_REGs in canonical order too * simplify (~x {&,|,^} x) --> {0,~0,~0} * simplify ((x cmp y) {&,|,^} (x !cmp y)) --> {0,1,1}
2020-11-22symaddr: give a type to OP_SYMADDRLuc Van Oostenryck1-4/+4
Currently, OP_SYMADDRs are given a size but not a type. But the type is needed for several things, the idea being that for each instruction producing a pseudo (PSEUDO_REG) it's possible to: * retrieve its defining instruction * retrieve its type via this defining instruction Fix this by giving to OP_SYMADDRs the type of their symbol. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-22Merge branch 'cleanup' into nextLuc Van Oostenryck3-21/+8
2020-11-22Merge branch 'optim-cgoto' into nextLuc Van Oostenryck12-6/+159
* simplification of computed gotos with 1 or 2 targets
2020-11-22not: simplify ((x cmp y) {&,|,^} (x !cmp y)) --> {0,1,1}Luc Van Oostenryck2-4/+21
Simplify bitwise operations on a compare and its complement into 0 (for &) or 1 for (| and ^). Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-22not: simplify (~x {&,|,^} x) --> {0,~0,~0}Luc Van Oostenryck2-4/+63
Simplify bitwise operations on a pseudo and its complement into 0 (for &) or ~0 for (| and ^). Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-22opcode: add helpers opcode_negate() & opcode_swap()Luc Van Oostenryck1-0/+10
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-22canon: simplify calculation of canonical orderLuc Van Oostenryck2-15/+29
The calculation of the canonical order is currently somehow complicated. Fix this by reordering the definition of the different type of pseudos so that they are already in canonical order and just comparing the types to determine the order. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-22canon: put PSEUDO_REGs in canonical order tooLuc Van Oostenryck2-1/+3
Currently, only binops containing PSEUDO_VAL, SYM or ARG were put in canonical order. This means that binops containing only PSEUDO_REGs are not ordered. This is not directly a problem for CSE because commutativity is taken in account but: * more combination need to be checked during simplification * 'anti-commutative' operations like (a > b) & (b < a) are not recognized as such. So, take PSEUDO_REGs in account when checking if operands are in canonical order. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-22canon: put PSEUDO_ARGs in canonical order tooLuc Van Oostenryck4-12/+14
Currently, only binops containing PSEUDO_VAL or PSEUDO_SYM were put in canonical order. This means that binops containing only PSEUDO_ARGs or PSEUDO_REGs are not ordered. This is not directly a problem for CSE because commutativity is taken in account but: * more combination need to be checked during simplification * 'anti-commutative' operations like (a > b) & (b < a) are not recognized as such. So, as a first step, also take PSEUDO_ARGs in account when checking if operands are in canonical order. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-22not: add testcases for canonicalization & simplification of negationsLuc Van Oostenryck6-0/+73
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-21add a new instruction for label-as-valueLuc Van Oostenryck10-17/+63
Convert OP_SETVAL of a label into a new instruction: OP_LABEL. There is 2 reasons to do this: *) there is slightly less checking to be done in later phases (since OP_SETVAL can be for labels but also strings) *) OP_SETVAL is CSEd but this is largely useless because this instruction is hashed on the expression's address and these are (most) often not shared. With a separate instruction for label expressions, their CSE is now OK because the hashing is done on the BB. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-21simplify CGOTO(SEL(x, L1, L2)) into CBR x, L1, L2Luc Van Oostenryck2-1/+22
A computed goto having as operand a select of 2 statically known addresses (OP_SETVAL/EXPR_LABEL) is equivalent to a simple conditional branch. Simplify such computed goto into the corresponding OP_CBR Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-21simplify OP_COMPUTEDGOTO with unique and known targetLuc Van Oostenryck2-1/+30
If the OP_COMPUTEDGOTO's source pseudo is defined by a single OP_SETVAL/EXPR_LABEL, then the corresponding basic block is the only possible destination and the computed goto can then be simplified into a simple branch. So, convert such computed goto into a simple OP_BR which may then participate in other flow simplifications. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-21simplify kill_insn() of unops and unop-ish instructionsLuc Van Oostenryck1-13/+5
In instructions, the first pseudo operands exist under different names (.src1, .src, .cond, .phi_src) all aliased to each other. Use this to simplify unops and others instructions with a single pseudo operand. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-21remove unneeded REPEAT_SYMBOL_CLEANUPLuc Van Oostenryck3-8/+3
Since simplify_memops() must be called unconditionally (see [1]) it's useless to set REPEAT_SYMBOL_CLEANUP (at the condition that REPEAT_CSE is set instead). So remove it's definition and set REPEAT_CSE instead when needed). [1] 6b5e7cf5ac39 ("cfg: call simplify_memops() unconditionally.") Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-21fix kill_insn(OP_SETVAL)Luc Van Oostenryck1-1/+1
When killing OP_SETVAL's, kill_use(&insn->src1) is called to remove the usage of its first operand but OP_SETVAL has no such operand. Fix this by moving the corresponding entry with OP_SETFVAL and others instruction without operands. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-21add testcases for COMPUTEDGOTO simplificationLuc Van Oostenryck3-0/+57
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-19Merge branches 'cleanup-postop' and 'cleanup-linearize'Luc Van Oostenryck2-6/+1
2020-11-19Merge branch 'diamond'Luc Van Oostenryck2-2/+114
* rebuild dominance tree during CFG cleanup * simplify CBR-CBR on the same condition
2020-11-19simplify unrestricted postopLuc Van Oostenryck1-2/+1
The '++' and '--' operator used in evaluate_postop() are 'restricted' operators. It's thus unneeded to call restricted_unop() on them as it will always return '1'. It's also unneeded to test for TYPE_RESTRICT since it will also be tested in unrestrict(). So, simply call unrestrict() unconditionally. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-19Merge branch 'unqual'Luc Van Oostenryck5-2/+77
* unqual: comma expressions should drop qualifiers * unqual: statement expressions should drop qualifiers
2020-11-18unqual: statement expressions should drop qualifiersLuc Van Oostenryck2-2/+1
Statement expressions should be subjected to lvalue-conversion and thus should drop qualifiers. Fix this by calling unqualify_type() after array-to-pointer conversion. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-18unqual: comma expressions should drop qualifiersLuc Van Oostenryck2-2/+1
Comma expressions should be subjected to lvalue-conversion and thus should drop qualifiers. Fix this by calling unqualify_type() after array-to-pointer conversion. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-18unqual: unqualify_type() should check for null ctypesLuc Van Oostenryck1-0/+2
It's possible that the input type is NULL, so add a check for it. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-18unqual: add testcasesLuc Van Oostenryck4-0/+75
Add some testcases related to qualifier dropping / lvalue conversion. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-18casts should drop qualifiersLuc Van Oostenryck2-0/+27
Casts should drop qualifiers but Sparse doesn't do this yet. The fix seems pretty simple: after having evaluated the type of the cast, if this type is a SYM_NODE and contains qualifiers, make a copy of the type with the qualifiers removed and use this copy as the type. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-17linearize: remove unneeded forward declarationsLuc Van Oostenryck1-4/+0
These declarations are not needed, so remove them. A few of the other ones could/should be removed but it would need to shuffle some code around. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-17Merge branch 'pack-early'Luc Van Oostenryck18-39/+269
* cfg: remove phi-sources when merging BBs * cfg: remove phi-nodes when merging BBs * cfg: add missing REPEAT_CFG_CLEANUP * cfg: call simplify_memops() unconditionally. * cfg: early CFG simplification
2020-11-17simplify CBR-CBR on the same conditionLuc Van Oostenryck1-0/+106
In situations like: ... cbr <cond>, L1, L2 L1: L2: ... ... L3: cbr <cond>, L4, L5 since the conditions are the same and L3 is empty but the CBR, all branches to L3 in L1 can be changed to branches to L4 (idem with L5 in L2). The same can be done in all BB 'in the path between L1 and L3', more exactly in all BB dominated by L1, this guarantee that the changes is only done on the BB where the conditions match. Note: This simplification kinda generalizes the current simplify_branch_branch() but should itself generalized to handle the presence of phi-sources in L3. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-17rebuild dominance tree during CFG cleanupLuc Van Oostenryck1-2/+8
Currently, the dominance tree is build once, just before the SSA conversion. However, changes in the CFG potentially changes the dominance relationships. So, rebuild the dominance tree after changes to the CFG. Note: This doesn't seems to significantly affect the performance (at least when used on the kernel): before after real 4m15.854s real 4m16.95&s user 71m11.390s user 71m29.180s sys 28m45.222s sys 28m46.145s Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-17cfg: early CFG simplificationLuc Van Oostenryck12-11/+102
The linearization step sometimes creates a lot of intermediate basic blocks, often containing just a branch. Their presence often make things more complicated than needed (more work to do in later phases, visual clutter when inspection the IR 'by hand') and they can sometimes, indirectly hinder some optimizations. Happily, most of them can trivially be optimized away. So, add a CFG simplification phase running very early and doing: *) jump threading (eliminate jump to jump) *) merge single-child/sinle-parents basic blocks. These changes slightly decrease the number of 'context imbalance' warnings (32 less on a total of 995 warnings) and the size of the generated IR (only ~0.4% but this is very significant relatively to most other simplifications). They also seem to improve the kernel tests' running time: before after real 4m19.261s real 4m17.548s user 72m03.634s user 71m34.642s sys 29m05.573s sys 29m01.856s but it's probably just noise. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-17cfg: call simplify_memops() unconditionally.Luc Van Oostenryck4-3/+40
Currently, in the main optimization loop, simplify_memops() is only called if REPEAT_SYMBOL_CLEANUP have been set. This has (at least) two problems: 1) simplify_memops() may itself create other 'symbol cleanup' opportunities. That's fine and when it happens REPEAT_SYMBOL_CLEANUP is correctly set but this is directly lost because repeat_phase is cleared just after. So, loads and stores are not always optimized away as they should. 2) Loads & stores are not always done directly on symbols, in fact, it often happens that they are done on some PSEUDO_REG. Here too, loads and stores are not always optimized away as they should. So, call simplify_memops() unconditionally. Note: this have only very small effects on the tests' running time: before after after too real 4m18.001s real 4m18.655s real 4m19.4 user 71m32.911s user 72m02.701s user 72m06.6 sys 29m06.523s sys 29m01.721s sys 29m06.8 which is under the noise I usually have. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-17cfg: add missing REPEAT_CFG_CLEANUPLuc Van Oostenryck2-1/+2
simplify_branch() & insert_branch() convert a conditional branch into an unconditional one, removing a child which may then become unreachable. However, these function doesn't set REPEAT_CFG_CLEANUP and the unreachable child may not be removed. Fix this by setting the missing REPEAT_CFG_CLEANUP in these functions. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-17cfg: remove phi-nodes when merging BBsLuc Van Oostenryck1-0/+23
When merging BBs, it's possible that the top BB feeds one or several phi-nodes in the bottom BB. Since phi-nodes only make sense for values incoming from the parent BBs, these phi-nodes can and should be removed when merging the BBs. So, when merging BBs, remove these related phi-nodes. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-17cfg: remove phi-sources when merging BBsLuc Van Oostenryck2-1/+42
When merging two basic blocks, it may happen that both of theses blocks contain a phi-source for the same phi-node. In this case, only the phi-source from the bottom BB must be taken in account, it kinda overwrites the value from the top BB and the phi-source from the top BB must be ignored, in fact it must be removed. However, it is not the case and this extra phi-source creates different kinds of problems. Among other things, it hinders further simplifications. For example, the following code: extern int array[2]; static inline int stupid_select(int idx) { if (idx) idx = 0; return array[idx]; } int select(void) { int d = stupid_select(-1); return d; } should boil down to a simple dereference of the array with an index of zero, like: select: load.32 %r8 <- 0[array] ret.32 %r8 but currently gives: select: phisrc.32 %phi3(idx) <- $0xffffffff phisrc.32 %phi4(idx) <- $0 phi.32 %r12(idx) <- %phi3(idx), %phi4(idx) sext.64 %r5 <- (32) %r12(idx) mul.64 %r6 <- %r5, $4 add.64 %r7 <- %r6, array load.32 %r8 <- 0[%r7] ret.32 %r8 This patch takes care of the problem by: * when merging 2 BBs, check when reaching a phi-source in the bottom BB * if one is found, look after sibling phi-sources * remove such sibling if belonging to the top BB. With this change, the code above gives: select: phisrc.32 %phi4(idx) <- $0 phi.32 %r12(idx) <- %phi4(idx) sext.64 %r5 <- (32) %r12(idx) mul.64 %r6 <- %r5, $4 add.64 %r7 <- %r6, array load.32 %r8 <- 0[%r7] ret.32 %r8 which can the be simplified into the expected result. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-15cfg: extract merge_bb() from pack_basic_blocks()Luc Van Oostenryck1-23/+35
Extract merge_bb() from pack_basic_blocks() in order to reuse this part of the code in other simplification/finer grained version of pack_basic_blocks(). Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-15cfg: add testcase for phi-adjusting during BB mergeLuc Van Oostenryck1-0/+24
When merging BBs, phi-sources from the bottom BB should 'overwrite' the ones from the top BB which should be ignored. Add a testcase from the incoming fix. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-15testcase: avoid UNDEFLuc Van Oostenryck1-2/+3
Reduced testcases (with creduce, of course) often needlessly have undefined variables. Since these are untouched by the simplification code and should not be present in source code, they should be avoided in optimization testcases. So, defines 'x' to some value other than 0. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-14doc: add header for flow simplification related documentationLuc Van Oostenryck2-3/+5
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-16doc: add header for optimization related documentationLuc Van Oostenryck2-2/+7
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-16doc: add some doc to flowgraph.hLuc Van Oostenryck2-0/+21
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-16doc: fix extracted autodoc when short description ends with a ?Luc Van Oostenryck1-2/+3
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-16doc: add some doc about using NULL or VOID in ptrlistsLuc Van Oostenryck1-0/+12
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-16doc: Sphinx's option ':noindex:' have been renamed into ':noindexentry:'Luc Van Oostenryck1-1/+1
and instead of keeping the old name for compatibility, no it's rejected. But well, purity of language is surely much more important than compatibility. *long deep sigh* So, use the new name (but it will for sure create problems when using an older version of Sphinx). Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-12linearize: fix a couple of 'selfcheck' warningsRamsay Jones1-0/+2
Signed-off-by: Ramsay Jones <ramsay@ramsayjones.plus.com> Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-11Merge branch 'debug'Luc Van Oostenryck3-3/+20
* do not call simplify_instruction() on removed instruction * add debug helpers: show_insn_bb() & show_insn_entry()
2020-11-09Merge branch 'optim-cmp' into nextLuc Van Oostenryck20-237/+582
* simplify & canonicalize compares
2020-11-09Merge branch 'optim-sel' into nextLuc Van Oostenryck9-21/+122
* simplify SEL(SEL(...), ...) * simplify SEL(x == y, x, y) and friends * simplify SEL(x, x, x) and SEL(x, 0, x)
2020-11-09fix linear_isdigit()'s itypeLuc Van Oostenryck1-0/+1
The merge of the branch with the linear_isdigit() experiment and the branch giving a type to OP_SETxx's arguments created a semantic conflict: the compare used for the isidigt() builtin needed the type too. Fix this now. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-08select: simplify select(x, x, 0) --> xLuc Van Oostenryck3-9/+5
The dual simplification select(x, 0, x) --> 0 was already done but this one was forgotten, so add it now. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-08select: simplify handling of select(x, 0, x) --> 0Luc Van Oostenryck2-5/+11
This simplification is already handled but explicitly kills it's 2 operands while this is done automatically when killing the instruction. Also, it uses replace_with_value(0) which needs to recreate the pseudo for 0 while it's already available via its operands. So, changes to use replace_with_pseudo() and without the unneeded kills. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-08cmp: simplify compares and sign/zero extendLuc Van Oostenryck3-12/+42
Compare instructions with both operands sign or zero-extended from the same original size are equivalent to a compare of the original values. If the values were zero-extended, a signed compare becomes an unsigned one. Simplify away the sign/zero-extensions. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-08cmp: simplify zext(x) cmpu CLuc Van Oostenryck2-1/+4
An unsigned compare of a zero-extended value against a constant outside of the original range is statically known. Simplify to the corresponding 0/1. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-08cmp: simplify zext(x) cmps CLuc Van Oostenryck2-1/+14
A signed compare of a zero-extended value against a constant outside of the original range is statically known. Simplify to the corresponding 0/1. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-08cmp: canonicalize sext(x) cmpu C (with C >= SMAX)Luc Van Oostenryck2-1/+12
A unsigned compare of a sign-extended value against a value bigger than the original SMAX is equivalent to a signed compare against 0. Canonicalize to the signed compare against 0. Note: ultimately both forms are just a test of the sign bit. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-08cmp: simplify sext(x) cmps {SMAX,SMIN}Luc Van Oostenryck2-1/+14
A signed compare of a sign-extended value against a constant outside of the original range is statically known. Simplify to the corresponding 0/1. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-08cmp: simplify zext(x) cmp C --> x cmp CLuc Van Oostenryck4-3/+11
When doing a compare of a zero-extended value against a constant, this extension can be dropped and the comparison done on the original type if the constant is within the original range and signed compares become the corresponding unsigned one. Simplify away these sign-extensions. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-08cmp: simplify sext(x) cmp C --> x cmp CLuc Van Oostenryck2-1/+24
When doing a compare of a sign-extended value against a constant the, sign-extension can be dropped and the comparison done on the original type if the constant is within the original range. Simplify away these sign-extensions. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-08cmp: canonicalize unsigned (x {<=,>} SMAX)Luc Van Oostenryck2-1/+4
Unsigned <= or > against SMAX are equivalent to testing if the value is positive or not (when interpreted as a signed number). Canonicalize to this positive/negative test since it only needs the constant 0 which make it easier to handle at later steps. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-08cmp: canonicalize unsigned compare with UMAX or UMAX-1Luc Van Oostenryck2-1/+8
Unsigned compares with UMAX (or UMAX-1) are equivalent to equality tests. These are preferable since it's easier to reason about them in other simplifications. So canonicalize these compares to equality tests. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-08cmp: simplify unsigned (x {<=,>} UMAX) into {1,0}Luc Van Oostenryck2-1/+5
These compares are always true or false, so simplify them. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-08cmp: canonicalize unsigned (x {<,>=} C) --> (x {<=,>} C-1)Luc Van Oostenryck2-2/+7
An unsigned comparison like (x < 3) is equivalent to (x <= 2). Canonicalize '<' & '>=' to '<=' & '>', such that the smallest constant is used. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-08cmp: use a few helpers for the simplification of comparesLuc Van Oostenryck1-20/+32
The current code for the simplification of compares is quite simple but also repetitive because everything must be done 4 times, one for each operations (<,<=,>=,>). So, add 2 helpers to factor out the details of the common parts. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-08cmp: move some code in a separate function: simplify_compare_constant()Luc Van Oostenryck1-31/+43
simplify_constant_rightside() contains a few simplification regarding unsigned compares but much more can be done for unsigned and signed ones. So, move the current simplification in a separate function. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-08cmp: add signed/unsigned to opcode tableLuc Van Oostenryck3-85/+90
The opcode table allows to efficiently store some properties of the IR instructions and the correspondence between some of them. One of these correspondences the 'signed' / 'unsigned' version of otherwise identical instructions. This is useful for some transformation of compare instructions but is not present yet in the table. So, add this now. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-07simplify SEL(x == y, x, y) and friendsLuc Van Oostenryck2-0/+24
If the condition of a select instruction is a equality test of the select's operands, then the result of the select is always the same as its second operand. Same for the first operand with an inequality test. Simplify away these selects. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-07select: simplify handling of constant cond or src1 == src2Luc Van Oostenryck1-8/+6
If the operands of a select instruction are identical, then this select can be replaced by its operand. If the condition of a select is a constant, the this select can be replaced by one of its condition, depending on the truth value of the condition. This simplification is already done but: * when src1 == src2, the condition's value is tested although it may not be a constant. It's kinda OK because in all case one of the operand will be selected and both are identical but it's a bit weird and unclean. * since the instruction will be replaced, the usage of its condition and operands must be removed. This is done here but the kill_instruction() inside replace_with_pseudo() take already care of this. So, separate the two cases and simply use replace_with_pseudo() for both without bothering killing the operands. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-07select: simplify SEL(SEL(x, C1, C2), y, z) --> y (with C1, C2 != 0)Luc Van Oostenryck2-1/+3
If the condition of a select is also a select, with constant but non-zero operands, then the result of this inner select is always true and the outer select can be replaced by its second operand. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-07select: simplify SEL(SEL(x, C, 0), C, 0) --> SEL(x, C, 0) == condLuc Van Oostenryck1-0/+3
If the condition of a select is also a select, both with the same arguments: first a non-zero constant, then a zero constant, then the outer select is equivalent to the inner one and can thus be replaced by the result of the inner select (which is its own condition). Note: this is a special case of: SEL(SEL(x, C, 0), y, z) --> SEL(x, y, z) and without this patch we'll have: t = SEL(x, C, 0) r = SEL(t, C, 0) simplified into: t = SEL(x, C, 0) // possibly unused now r = SEL(x, C, 0) but the present patch do t = SEL(x, C, 0) r = t In other words, functionally, the result is the same but now the result is taken from the first instruction. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-07select: simplify SEL(SEL(x, C, 0), y, z) --> SEL(x, y, z) and its dualLuc Van Oostenryck3-2/+20
If the condition of a select is also a select but with constant operands, some simplification can be done: * if the second operand is 0, the original condition can be used, * idem if the first operand is 0s but the operand must be swapped. Originally-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-07select: add some testcases for select simplificationLuc Van Oostenryck5-0/+54
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-05cmp: add testcases for the simplification of comparesLuc Van Oostenryck15-0/+293
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-02cmp: adapt testcase for compares' canonicalizationLuc Van Oostenryck1-111/+14
The current testcase, because it's just checking test-linearize's output as-is, is very sensitive to small simplification changes. Fix this by changing the tests into equivalent tests and then just checking that these tests return '1'. This allows to test only what really matters for canonicalization and make these tests very robust. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-01Merge branch 'typed-cmp'Luc Van Oostenryck7-5/+75
* give an explicit type to compare's operands
2020-11-01linearize __builtin_isdigit()Luc Van Oostenryck4-0/+65
As an experiment about the linearization of builtins, try this easy one (and statically expand it if the argument is constant). Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-01fix usage count in linearize_fma()Luc Van Oostenryck2-4/+4
When linearizing __builtin_fma(), the arguments were just assigned but the corresponding usage was not tracked. Fix this. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-01fix init_linearized_builtins()Luc Van Oostenryck1-1/+1
Hmmm ... the wrong pointer was updated. Fix this. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-01testsuite: add a new tag: check-output-returnsLuc Van Oostenryck3-0/+33
The current tags check-output-contains/excludes/pattern are quite powerful and the new check-output-match is easy to use but it can be even simpler. Indeed, a lot of IR simplifications/ canonicalizations can be tested by checking that the expression to be tested is equivalent to another one. This is less precise than some more specific tests but: * it's a big advantage because it's less sensitive to 'noise' like the exact number used by the pseudos or to the results of some new simplifications or canonicalizations * very often, this equivalence is what really matters and not the exact transformation. So, add a new utra-simple-to-use tag: just ask that all functions of the tests return the same specified value (usually 1): check-output-returns: <value> Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-01testsuite: add a new tag: check-output-matchLuc Van Oostenryck3-0/+47
The current tags check-output-contains/excludes/pattern are quite powerful, universal, but they often need 'complex' regular expressions with escaping which make them not so nice to read. For testing IR results, a very common pattern is: this instruction must have this (kind of) operand. So, make a new tag for this. It does nothing than can't be done with done with the previous ones, on the contrary, but is much simpler to use: check-output-match(instruction): operand Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-01do not call simplify_instruction() if already removedLuc Van Oostenryck2-3/+2
simplify_instruction() is called on every instructions, even those already removed. It's useless (and annoying when debugging). So, filter out removed instructions before calling simplify_instruction(). Fixes: c5ba883e6ac47381f8112ed33f22a931a79ac517 Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-07add debug helpers: show_insn_bb() & show_insn_entry()Luc Van Oostenryck1-0/+18
These 2 helpers are just small wrappers around show_instruction() and show_entry() but can be called even when the instruction is removed. They're just handy when debugging. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-01eval_insn: give an explicit type to compare's operandsLuc Van Oostenryck6-7/+30
The return type of IR instructions is stored in the field ::type of struct instruction and this struct has no space to hold the type of the operand(s). This is not a problem for most instructions because there is an easy way to get the operands' type. For example, for binops both types must be the same so they are used interchangeably. However, for compare instructions both types can be different and there is no easy way to get the type of the operands. Currently, this is ignored and creates some errors. It also blocks simplifications that need this type information. But compares instructions need only 2 operands, there is thus one 'slot' left. So, use this slot for the operands' type. This solves the current errors, allows new simplifications and has very little impact on existing code. Of course, this type information needs now to be tracked and adjusted whenever the operands change or an instruction is changed into a compare. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-11-01eval_insn: add testcases for incorrect type in OP_SET_*Luc Van Oostenryck3-0/+47
Because of the lack of type information, compare instruction are not always handled correctly. So, add some testcases for this. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-10-27Merge branch 'one_use'Luc Van Oostenryck2-11/+11
* replace nbr_users() & multi_users() by one_use()
2020-10-27replace nbr_users() & multi_users() by one_use()Luc Van Oostenryck2-11/+11
During simplification, we're only interested to know if a pseudo is used only once or more than once. This can be checked quicker than getting the exact number of users. So, replace the last call to nbr_users() and the calls to multi_users() by a call to one_use() which has a slightly clearer name. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-10-27Merge branches 'cleanup-linearize', 'inline-use', 'inline-def', 'pure-call', ↵Luc Van Oostenryck10-70/+71
'old-style' and 'kill-dead' * cleanup linearize_cond_branch() * OP_INLINE should not use the function symbol * add testcase for missing inline definition * fix testing if a OP_CALL's function is pure * warn on all missing parameter types * kill dead instructions before any other simplifications
2020-10-26handle more graciously labels with no statementLuc Van Oostenryck1-0/+5
In C a label must precede a statement. A null statement is OK but a closing braces is not. So, catch this situation, emit a warning and continue as if a null statement was there. This occurs currently on v5.10-rc1 because of some ifdefery. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-10-25fix testing if a OP_CALL's function is pureLuc Van Oostenryck1-3/+3
kill_instruction() will kill an OP_CALL but only if it's a forced kill or if the corresponding function is pure. However, only functions called via a symbol pseudo are so killed. Those called via a function pointer are not because only symbol pseudos contain the function type needed to test the presence of the MOD_PURE modifier. Fix this by using the function type always available in the instruction's ::fntypes member. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-10-25add helper first_symbol()Luc Van Oostenryck1-0/+5
This is just a wrapper around first_ptr_list(). Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-10-25kill dead instructions before any other simplificationsLuc Van Oostenryck1-46/+5
Dead instructions are removed when simplify_instruction() is called but this is done in various places, depending on the kind of instructions, sometimes after other simplifications. Change this by using the instruction's flag OPF_TARGET at the very beginning of simplify_instruction() to test which instructions are dead and thus can be removed. Note: OP_CALLs are special here as they're considered as always returning a value but only calls to pure functions are removed. This is OK since pure functions should always return a value. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-10-25OP_CALL should use the full function typeLuc Van Oostenryck1-2/+0
OP_CALL keep a list with the type of the function itself and of each of its arguments. However, the function type added to the list is not the complete type but its base type. So, we can't use the function's modifiers or contexts. Fix this by storing the complete function type. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-10-25linearize: OP_INLINE should not use the function symbolLuc Van Oostenryck1-1/+1
The instruction OP_INLINE is a kind of note or comment, indicating that the code below it used to be the body of a function which has now been inlined. The symbol of the original function is displayed when this instruction is displayed but this symbol should not be considered as being used by the instruction since there is no dependency or def-use chain between the two. So, replace the use_pseudo() by a simple assignment. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-10-24Merge branches 'optim-setuimm' and 'optim-unop' into nextLuc Van Oostenryck9-5/+163
* simplify and canonicalize unsigned compares * basic unop simplifications
2020-10-24Merge branch 'fix-llvm-11' into nextLuc Van Oostenryck1-46/+29
* llvm: fix crash with llvm-11 / use real phi-nodes
2020-10-24unop: simplify ~(-x) --> x - 1Luc Van Oostenryck2-1/+4
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-10-24unop: simplify ~(x ^ C) --> x ^ ~CLuc Van Oostenryck2-1/+6
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-10-24unop: simplify ~(C - x) --> x + ~CLuc Van Oostenryck2-1/+6
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-10-24unop: simplify ~(x + C) --> ~C - xLuc Van Oostenryck2-1/+7
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-10-24unop: simplify -(~x) --> x + 1Luc Van Oostenryck2-1/+4
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-10-24unop: simplify -(x - y) --> y - xLuc Van Oostenryck2-1/+4
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-10-24unop: simplify -(x + C) --> -C - xLuc Van Oostenryck2-1/+7
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-10-24unop: prepare simplify_unop() to handle more casesLuc Van Oostenryck1-5/+10
Currently, simplify_unop() can only handle the simplification of -(-x) and ~(~x). Prepare it to handle more cases. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-10-23canonicalize unsigned compares against 0 or 1Luc Van Oostenryck2-1/+25
Some unsigned compares against 0 or 1 are equivalent to testing equality with 0 (x <= 0, x > 0, x < 1, x >= 1). Canonicalize them to this later, more common form. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-10-23simplify unsigned compares against 0Luc Van Oostenryck2-0/+20
Some unsigned compares against 0 are always true or always false (x < 0 or x >= 0). Simplify them. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-10-23cleanup linearize_cond_branch()Luc Van Oostenryck1-12/+5
No functional changes here, just some more consistency: * systematically use break instead of 'return VOID' * remove some superfluous curlies * remove some unneeded blank lines Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-10-23unop: add testcases for unop simplificationsLuc Van Oostenryck7-0/+78
Add a few testcases for the simplification of unary operations. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-10-23llvm: fix crash with llvm-11 / use real phi-nodesLuc Van Oostenryck1-46/+29
sparse-llvm crashes with LLVM-11. From what I can see, it's because LLVM-11 doesn't like anymore that an instruction is first created unattached to a basic block (LLVMClearInsertionPosition()) and inserted at some later step (LLVMInsertIntoBuilder()). Since the corresponding function still exist I suppose they're working correctly and sparse-llvm somehow misuse them. I don't know. However, this functionality is only used to create the alloca instructions used to simulate the phi-nodes. So, fix this crash by using real phi instructions for the phi-nodes. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-10-22warn on all missing parameter typesLuc Van Oostenryck6-6/+22
A warning is given for K&R parameters without type declaration and these parameters are given an implicit type of int to avoid several problems with false errors in the next stages. However, this is only done for K&R functions with the optional parameter type declarations. If the parameters has no type declaration at all, no diagnostic is given and the type is left as incomplete. In consequence, a function defined with a typo like 'int foo(oid)' instead of 'int foo(void)' is left undetected (even with -Wold-style-definition and -Wstrict-prototypes enabled). Fix this by: 1) adding the type check to declare_argument() so that all parameters have a real type. 2) downgrade the diagnostic to a warning for K&R functions. Fixes: 6f7aa5e84dacec8e27a8d70090bba26a1a1276de Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-10-22add testcase for missing inline definitionLuc Van Oostenryck1-0/+30
If the address of an inline function is taken, a definition for this function must be emitted. However, sparse only do this if this inline function is defined before it is used. So add a testcase for this. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-10-22memops need long offsetsLuc Van Oostenryck2-4/+4
These days, declaring arrays bigger than 2GB or doing pointer arithmetic with an offset larger than 2^31 is maybe not usual but certainly not outrageous. However, currently Sparse silently truncates 32 bits the offsets of memory accesses. So, fix this by using 64-bit offsets for memory accesses. Also, use a signed type since these offsets can be negative. Note: I had a really nice (real) example for this but the margin of this patch is too small for it (and now I've lost it). Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-10-22Merge branch 'optim-base' into nextLuc Van Oostenryck18-64/+397
* essential OP_ADD & OP_SUB simplifications
2020-10-21optim: fix some testcases related to bitfield manipulationLuc Van Oostenryck2-5/+8
The patterns used here were based on looser semantic for OP_{SEXT,TRUNC}. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-10-20Merge branch 'bf-sign' into nextLuc Van Oostenryck10-22/+60
* teach sparse about -funsigned-bitfields * let plain bitfields default to signed
2020-10-20sub: simplify x + (y - x) --> yLuc Van Oostenryck2-1/+4
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-10-20sub: simplify (x - y) + y --> xLuc Van Oostenryck2-1/+5
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-10-20sub: simplify x - (y + x) --> -yLuc Van Oostenryck2-1/+2
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-10-20sub: simplify x - (x + y) --> -yLuc Van Oostenryck2-1/+4
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-10-20sub: simplify (x + y) - y --> xLuc Van Oostenryck2-1/+2
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-10-20sub: simplify (x + y) - x --> yLuc Van Oostenryck2-1/+8
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-10-20add: simplify (-x + y) --> (y - x)Luc Van Oostenryck2-1/+8
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-10-20add: simplify (x + -y) --> (x - y)Luc Van Oostenryck2-2/+15
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-10-20sub: simplify (x - -y) --> (x + y)Luc Van Oostenryck2-2/+15
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-10-20sub: simplify (C - y) + D --> eval(C+D) - yLuc Van Oostenryck2-1/+20
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-10-20sub: simplify C - (D - z) --> z + eval(C-D)Luc Van Oostenryck2-1/+8
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-10-20sub: simplify C - (y + D) --> eval(C-D) - yLuc Van Oostenryck2-1/+18
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-10-20sub: canonicalize (0 - x) into -xLuc Van Oostenryck2-1/+4
Not really a simplification in itself but it make some other simplification a little easier (already because there is one argument less to be matched). Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-10-20sub: reorganize handling of OP_{ADD,SUB}s with constant rightsideLuc Van Oostenryck1-9/+11
This is a preparatory step for more interesting changes later. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-10-20reassoc: simplify (x # C) # K --> x # eval(C # K)Luc Van Oostenryck2-1/+5
Do this simplification once for all associative binops. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-10-20constants must be truncated to the operation's sizeLuc Van Oostenryck2-2/+1
At expansion phase, when simplified, all constants are truncated to the size of the operations that generate them. This should be done during simplification too because: *) if some constants are sometimes truncated and sometimes sign-extended, CSE will miss some opportunities. *) it's not possible to sign-extend them because it's not always known if the constant is used in a signed context or not. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-10-20add a flag to identify commutative & associative opsLuc Van Oostenryck3-48/+76
The way how the functions doing the simplification of commutative or associative binops are called is simple but complicates the simplification of a specific binop. Fix this by adding a flag to the opcode table to identify the commutative and the associative binops and using this flag to call or not the functions doing the corresponding simplification. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-10-20unop: add helper replace_with_unop()Luc Van Oostenryck1-0/+14
Some simplifications reduce to transforming a binop into an unop. Add an helper for making this change easier and more readable. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-10-20unop: add helper eval_unop()Luc Van Oostenryck1-0/+12
Currently, eval_op() only do the evaluation of binops but unops need sometimes to be evaluated too. So, teach eval_op() about OP_NEG & OP_NOT and add a new helper, eval_unop() for making it easier to use with unops. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-10-20extract eval_op() from eval_insn()Luc Van Oostenryck1-5/+9
eval_insn() can be handy when there is an existing instruction to evaluate but it can happen that there isn't one, only pseudos. Allow to reuse the evaluation code by using a new API: eval_op() extracted from eval_insn() and taking all its input as arguments (opcode, size, src1 & src2). Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-10-20let switch_pseudo() return REPEAT_CSELuc Van Oostenryck1-1/+2
It make some uses easier and more compact. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-10-20add testcases about OP_ADD & OP_SUB simplificationsLuc Van Oostenryck15-0/+171
Add some testcases about basic simplifications of additions and subtractions. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-10-19Merge branch 'builtin-atomic' into nextLuc Van Oostenryck6-32/+136
* fix and complete the evaluation of atomic builtins
2020-10-19builtin: add support for remaining atomic builtinsLuc Van Oostenryck1-0/+5
Nothing special for these ones, just plain functions with fixed types and arity. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-10-19builtin: add support for __atomic_clear()Luc Van Oostenryck2-0/+16
The first argument is supposed to be a pointer to a bool, but of course, a volatile qualified pointer should be accepted too. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-10-19builtin: add builtin type: [volatile] pointer to boolLuc Van Oostenryck2-0/+4
This builtin type is needed for __atomic_clear()'s prototype. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-10-19builtin: add support for others generic atomic builtinsLuc Van Oostenryck1-0/+10
Reuse the generic method for all these builtins. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-10-19builtin: add support for __atomic_add_fetch(), ...Luc Van Oostenryck1-0/+12
Reuse the generic method for all these builtins. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-10-19builtin: add predefines for __ATOMIC_RELAXED & friendsLuc Van Oostenryck1-0/+7
The __atomic_*() builtins take an int argument to specify the desired memory ordering. The different admissible values are predefined by the compiler, so do that too for Sparse. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-10-19builtin: __sync_synchronize() too is variadicLuc Van Oostenryck1-1/+1
This builtin was marked as taking no argument but is in fact variadic (like all the __sync_* builtins). Fix this by marking it as being variadic. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-10-19builtin: fix evaluation of __sync_lock_releaseLuc Van Oostenryck1-1/+1
It must use the generic method too. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-10-19builtin: evaluate __sync_*_fetch*()Luc Van Oostenryck2-13/+37
Reuse the generic method for all these builtins. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-10-19builtin: make eval_sync_compare_and_swap() more genericLuc Van Oostenryck1-17/+32
Most __sync_* or __atomic_* builtin functions have one or more arguments having its real type determined by the first argument: either the same type (a pointer to an integral type) or the type of the object it points to. Currently, only __sync_{bool,val}_compare_and_swap() are handled but lots of very similar variants would be needed for the others. So, make it a generic function, able to handle all these builtins. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-10-19Merge branch 'warn-address-builtin' into nextLuc Van Oostenryck2-10/+19
2020-10-18Sparse v0.6.3v0.6.3Luc Van Oostenryck2-3/+4
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-10-16fix null pointer deref on return expression with invalid typeLuc Van Oostenryck2-1/+10
If the evaluation of the return expression failed a following test can dereference the pointer holding the expression's type ... which is null. Bad. Fix this by adding the missing null pointer test. Fixes: 3bc32d46494c404df7905fceaca9156830ff97f1 Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-10-16warn when taking the address of a built-in functionLuc Van Oostenryck2-10/+19
Built-in functions are meant to be expanded by the compiler. As such, they don't have an address. So, issue an error when trying take the address of a built-in function. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-10-16testsuite: fix location of error messagesLuc Van Oostenryck1-3/+3
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-10-14update TODO listLuc Van Oostenryck1-8/+21
A few things are now done, remove them from the list, and add a few things that should be done. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-10-14flex-array: fix typo in warning messageLuc Van Oostenryck2-3/+3
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-10-14builtin: add builtin type for volatile void *Luc Van Oostenryck2-0/+4
This is the type of most __sync_* or __atomic_* builtins. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-10-14builtin: add generic .args methodLuc Van Oostenryck1-0/+7
The arity of builtin functions can be retrieved from their prototype. So, create a generic .args method, doing the evaluation of all arguments present in the prototype. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-10-12Sparse v0.6.3-rc1v0.6.3-rc1Luc Van Oostenryck2-1/+2
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-10-12doc: add release notes for incoming v0.6.3Luc Van Oostenryck1-4/+54
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-10-11Merge branch 'more-builtin' (early part)Luc Van Oostenryck1-0/+8
* builtin: teach sparse about __builtin_ia32_pause()
2020-10-09builtin: teach sparse about __builtin_ia32_pause()Luc Van Oostenryck1-0/+8
This builtin is used by Open vSwitch, so teach Sparse about it. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-10-09flex-array: fix location for nesting of flexible membersLuc Van Oostenryck2-3/+3
The warning about the nesting of flexible array members is given with the location of the outer struct or union but that is not very interesting. What is needed is the location of the member causing this nesting. So, fix the warning message to use the member's location. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-10-09Merge branch 'misc'Luc Van Oostenryck5-9/+5
2020-10-09Merge branch 'usual-conv'Luc Van Oostenryck3-32/+47
2020-10-09flex-array: allow arrays of unions with flexible members.Ilya Maximets7-1/+44
There is a common pattern on how to allocate memory for a flexible-size structure, e.g. union { struct flex f; /* Structure that contains a flexible array. */ char buf[MAX_SIZE]; /* Memory buffer for structure 'flex' and its flexible array. */ }; There is another example of such thing in CMSG manpage with the alignment purposes: union { /* Ancillary data buffer, wrapped in a union in order to ensure it is suitably aligned */ char buf[CMSG_SPACE(sizeof(myfds))]; struct cmsghdr align; } u; Such unions could form an array in case user wants multiple instances of them. For example, if you want receive up to 32 network packets via recvmmsg(), you will need 32 unions like 'u'. Open vSwitch does exactly that and fails the check. So, add a new option, -W[no-]flex-array-union, to enable or disable any warning concerning flexible arrays and unions. This option needs at least one of -Wflex-array-{array,nested,union} to be enabled in order to have any effect. Signed-off-by: Ilya Maximets <i.maximets@ovn.org> Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2020-10-08fix usual conversion of integersLuc Van Oostenryck2-31/+45
The current implementation of the usual conversion doesn't handle correctly the case of 'long' + 'unsigned int' on a 32-bit arch. The resulting type is 'unsigned int' instead of 'unsigned long'. Fix this by following closely the C99's wording. This now gives the expected result for C89 & C99 on 32 & 64-bit archs (as tested with the GCC testsuite). Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>