aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/validation
AgeCommit message (Collapse)AuthorFilesLines
2018-12-08add testcase for missing deliminator ' or "Luc Van Oostenryck1-0/+18
Add a testcase for "Newline in string or character constant" vs. "missing delimitator" upcoming change. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-12-01Conditionalize 'warning: non-ANSI function ...'John Levon4-0/+53
Sparse unconditionally issues warnings about non-ANSI function declarations & definitions. However, some environments have large amounts of legacy headers that are pre-ANSI, and can't easily be changed. These generate a lot of useless warnings. Fix this by using the options flags -Wstrict-prototypes & -Wold-style-definition to conditionalize these warnings. Signed-off-by: John Levon <levon@movementarian.org> Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-12-01Use -Wimplicit-int when warning about missing K&R argument typesLuc Van Oostenryck1-0/+15
In legacy environment, a lot of warnings can be issued about arguments without an explicit type. Fix this by contitionalizing such warnings with the flag -Wimplicit-int, reducing the level of noise in such environment. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-12-01fix implicit K&R argument typesLuc Van Oostenryck1-0/+16
In an old-style function definition, if not explicitly specified, the type of an argument defaults to 'int'. Sparse issues an error for such arguments and leaves the type as 'incomplete'. This can then create a cascade of other warnings. Fix this by effectively giving the type 'int' to such arguments. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-11-29Ignore #ident directivesJohn Levon2-0/+24
Legacy code can be littered with the non-standard "#ident" directive; ignore it. Signed-off-by: John Levon <levon@movementarian.org> Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-11-23constant: add -Wconstant-suffix warningRamsay Jones2-0/+30
Currently, when used on the kernel, sparse issues a bunch of warnings like: warning: constant 0x100000000 is so big it is long These warning are issued when there is a discrepancy between the type as indicated by the suffix (or the absence of a suffix) and the real type as selected by the type suffix *and* the value of the constant. Since there is nothing incorrect with this discrepancy, (no bits are lost) these warnings are more annoying than useful. So, make them depending on a new warning flag -Wconstant-suffix and make it off by default. Signed-off-by: Ramsay Jones <ramsay@ramsayjones.plus.com> Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-11-22sparsei: add the --[no-]jit optionsRamsay Jones1-1/+1
On the cygwin platform, a 'sparsei' backend test, which uses the llvm 'lli' tool, fails due to a dynamic linking error: $ make check ... TEST sum from 1 to n (backend/sum.c) error: actual output text does not match expected output text. error: see backend/sum.c.output.* for further investigation. --- backend/sum.c.output.expected 2018-06-03 18:27:11.502760500 +0100 +++ backend/sum.c.output.got 2018-06-03 18:27:11.307670000 +0100 @@ -1,2 +0,0 @@ -15 -5050 error: actual error text does not match expected error text. error: see backend/sum.c.error.* for further investigation. --- backend/sum.c.error.expected 2018-06-03 18:27:11.562997400 +0100 +++ backend/sum.c.error.got 2018-06-03 18:27:11.481038800 +0100 @@ -0,0 +1 @@ +LLVM ERROR: Program used external function 'printf' which could not be resolved! error: Actual exit value does not match the expected one. error: expected 0, got 1. ... Out of 288 tests, 277 passed, 11 failed (10 of them are known to fail) make: *** [Makefile:236: check] Error 1 $ Note the 'LLVM ERROR' about the 'printf' external function which could not be resolved (linked). On Linux, it seems that the 'lli' tool (JIT compiler) can resolve the 'printf' symbol, with the help of the dynamic linker, since the tool itself is linked to the (dynamic) C library. On windows (hence also on cygwin), the 'lli' tool fails to resolve the external symbol, since it is not exported from the '.exe'. The 'lli' tool can be used as an interpreter, so that the JIT compiler is disabled, which also side-steps this external symbol linking problem. Add the --[no-]jit options to the 'sparsei' tool, which in turn uses (or not) the '-force-interpreter' option to 'lli'. In order to fix the failing test-case, simply pass the '--no-jit' option to 'sparsei'. Signed-off-by: Ramsay Jones <ramsay@ramsayjones.plus.com> Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-11-20fix expansion of function designatorLuc Van Oostenryck1-1/+0
The expression corresponding to the function pointer of indirect call can be arbirarily complex. For example, it can contain a statement expression or another call, possibly inlined. These expressions must be expanded to insure that sub-expressions involving 'sizeof()' or other operators taking a type as argument (like __builtin_compatible_types_p()) are no more present (because these expressions always evaluate to a compile-time constant and so are not expected and thus not handled at linearization time). However, this is not currently enforced, possibly causing some failures during linearization with warnings like: warning: unknown expression (4 0) (which correspond to EXPR_TYPE). Fix this, during the expansion of function calls, by also expanding the corresponding designator. References: https://lore.kernel.org/lkml/1542623503-3755-1-git-send-email-yamada.masahiro@socionext.com/ Reported-by: Masahiro Yamada <yamada.masahiro@socionext.com> Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com> Tested-by: Masahiro Yamada <yamada.masahiro@socionext.com>
2018-11-20add testcase for missing function designator expansionLuc Van Oostenryck1-0/+23
Add a testcase showing function designator are not expanded. References: https://lore.kernel.org/lkml/1542623503-3755-1-git-send-email-yamada.masahi> Reported-by: Masahiro Yamada <yamada.masahiro@socionext.com> Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-10-05Merge branch 'fix-enum-type' into tipLuc Van Oostenryck14-3/+305
2018-10-05enum: more specific error message for empty enumLuc Van Oostenryck1-1/+1
Currently, the error message issued for an empty enum is "bad enum definition". This is exactly the same message used when one of the enumerator is invalid. Fix this by using a specific error message. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-10-05enum: default to unsignedLuc Van Oostenryck3-4/+3
GCC uses an unsigned type for enum's basetype unless one of the enumerators is negative. Using 'int' for plain simple enumerators and then using the same rule as for integer constants (int -> unsigned int -> long -> ...) should be more natural but doing so creates useless warnings when using sparse on the kernel code. So, do the same as GCC: * uses the smaller type that fits all enumerators, * uses at least int or unsigned int, * uses an signed type only if one of the enumerators is negative. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-10-05enum: warn when mixing different restricted typesLuc Van Oostenryck1-0/+20
Sparse supports enum initializers with bitwise types but this makes sense only if they are all the same type. Add a check and issue a warning if an enum is initialized with different restricted types. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-10-05enum: only warn (once) when mixing bitwisenessLuc Van Oostenryck1-0/+29
As an extension to the standard C types, parse supports bitwise types (also called 'restricted') which should in no circonstances mix with other types. In the kernel, some enums are defined with such bitwise types as initializers; the goal being to have slightly more strict enums. While the semantic of such enums is not very clear, using a mix of bitwise and not-bitwise initializers completely defeats the desired stricter typing. Attract some attention to such mixed initialization by issuing a single warning for each such declarations. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-10-05enum: use the smallest type that fitLuc Van Oostenryck3-3/+0
The C standard requires that the type of enum constants is 'int' and let the enum base/compatible type be implementation defined. For this base type, instead of 'int', GCC uses the smallest type that can represent all the values of the enum (int, unsigned int, long, ...) Sparse has the same logic as GCC but if all the initializers have the same type, this type is used instead. This is a sensible choice but often gives differents result than GCC. To stay more compatible with GCC, always use the same logic and thus only keep the common type as base type for restricted types. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-10-05enum: fix cast_enum_list()Luc Van Oostenryck1-1/+0
Sparse want that an enum's enumerators have all the same type. This is done by first determining the common type and then calling cast_enum_list() which use cast_value() on each member to cast them to the common type. However, cast_value() doesn't create a new expression and doesn't change the ctype of the target: the target expression is supposed to have already the right type and it's just the value that is transfered from the source expression and size adjusted. It's seems that in cast_enum_list() this has been overlooked with the result that the value is correctly adjusted but keep it's original type. Fix this by updating, for each member, the desired type. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-10-05enum: add testcase for base & enumerator typeLuc Van Oostenryck8-0/+227
Add various testcases for checking enum's base & enumerator type. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-10-05enum: add testcase for type of enum membersLuc Van Oostenryck1-0/+15
Members of an enum should all have the same type but isn't so currently. Add a testcase for it and mark it as 'known-to-fail'. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-10-05enum: fix UB when rshifting by full widthLuc Van Oostenryck1-1/+0
Shifting by an amount greater or equal than the width of the type is Undefined Behaviour. In the present case, when type_is_ok() is called with a type as wide as an ullong (64 bits here), the bounds are shifted by 64 which is UB and at execution (on x86) the value is simply unchanged (since the shift is done with the amount modulo 63). This, of course, doesn't give the expected result and as consequence valid enums can have an invalid base type (bad_ctype). Fix this by doing the shift with a small helper which return 0 if the amount is equal to the maximum width. NB. Doing the shift in two steps could also be a solution, as maybe some clever trick, but since this code is in no way critical performance-wise, the solution here has the merit to be very explicit. Fixes: b598c1d75a9c455c85a894172329941300fcfb9f Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-10-05enum: add testcase for UB in oversized shiftLuc Van Oostenryck1-0/+17
type_is_ok(), used to calculate the base type of enums, has a bug related to UB when doing a full width rshift. Add a testcase for this. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-09-26print address space number for cast-from-AS warningsVincenzo Frascino2-3/+63
This patch prints the address space number when a warning "cast removes address space of expression" is triggered. This makes easier to discriminate in between different address spaces. Signed-off-by: Vincenzo Frascino <vincenzo.frascino@arm.com> Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-09-10ssa: relax what can be promotedLuc Van Oostenryck1-2/+0
During SSA conversion, it is checked what can be promoted and what cannot. Obviously, ints, longs, pointers can be promoted, enums and bitfields can too. Complication arise with unions and structs. Currently union are only accepted if they contains integers of the same size. For structs its even more complicated because we want to convert simple bitfields. What should be accepted is structs containing either: * a single scalar * only bitfields and only if the total size is < long However the test was slightly more strict than that: it dodn't allowed a struct with a total size bigger than a long. As consequence, on IP32, a struct containing a single double wasn't promoted. Fix this by moving the test about the total size and only if some bitfield was present. Reported-by: Ramsay Jones <ramsay@ramsayjones.plus.com> Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-09-10test: make 32-bit version of failed testLuc Van Oostenryck2-2/+31
The test mem2reg/init-local.c succeeds on 64-bit but fails on 32-bit. Duplicate the test, one with -m64 and the other with -m32 and mark this one as known-to-fail. Reported-by: Ramsay Jones <ramsay@ramsayjones.plus.com> Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-09-10test: use integers of different sizes, even on 32-bitLuc Van Oostenryck1-2/+2
The test optim/cse-size fials on 32-bit because it needs two integers of different size but uses int & long. These two types have indeed different sizes on 64-bit (LP64) but not on 32-bit (ILP32). Fix this by using short & int. Reported-by: Ramsay Jones <ramsay@ramsayjones.plus.com> Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-09-10test: make test Waddress-space-strict succeed on 32-bitLuc Van Oostenryck1-26/+7
The test Waddress-space-strict made assumptions about the relative size of integers & pointers. Since this test was crafted on a 64-bit machine, the test was running fine for LP64 but failed on a 32-bit machine (or anything using IP32, like using the -m32 option). However, since the test is about conversion of address-spaces, using integers of different size adds no value, and indeed brings problems. Fix this by limiting the conversions to a single integer type, the one with the same size as pointers on ILP32 & LP64: long. Reported-by: Ramsay Jones <ramsay@ramsayjones.plus.com> Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-09-06Merge branch 'rem-trivial-phi' into tipLuc Van Oostenryck1-0/+14
* remove more complex phi-nodes
2018-09-06Merge branches 'missing-return' and 'fix-logical-phi' into tipLuc Van Oostenryck13-90/+281
* fix linearization/SSA when missing a return * fix linearization/SSA of (nested) logical expressions
2018-09-06fix linearization of nested logical exprLuc Van Oostenryck4-93/+90
The linearization of nested logical expressions is not correct regarding the phi-nodes and their phi-sources. For example, code like: extern int a(void); int b(void); int c(void); static int foo(void) { return (a() && b()) && c(); } gives (optimized) IR like: foo: phisrc.32 %phi1 <- $0 call.32 %r1 <- a cbr %r1, .L4, .L3 .L4: call.32 %r3 <- b cbr %r3, .L2, .L3 .L2: call.32 %r5 <- c setne.32 %r7 <- %r5, $0 phisrc.32 %phi2 <- %r7 br .L3 .L3: phi.32 %r8 <- %phi2, %phi1 ret.32 %r8 The problem can already be seen by the fact that the phi-node in L3 has 2 operands while L3 has 3 parents. There is no phi-value for L4. The code is OK for non-nested logical expressions: linearize_cond_branch() takes the sucess/failure BB as argument, generate the code for those branches and there is a phi-node for each of them. However, with nested logical expressions, one of the BB will be shared between the inner and the outer expression. The phisrc will 'cover' one of the BB but only one of them. The solution is to add the phi-sources not before but after and add one for each of the parent BB. This way, it can be guaranteed that each parent BB has its phisrc, whatever the complexity of the sub- expressions. With this change, the generated IR becomes: foo: call.32 %r2 <- a phisrc.32 %phi1 <- $0 cbr %r2, .L4, .L3 .L4: call.32 %r4 <- b phisrc.32 %phi2 <- $0 cbr %r4, .L2, .L3 .L2: call.32 %r6 <- c setne.32 %r8 <- %r6, $0 phisrc.32 %phi3 <- %r8 br .L3 .L3: phi.32 %r1 <- %phi1, %phi2, %phi3 ret.32 %r1 Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-09-06add tests for nested logical exprLuc Van Oostenryck1-0/+49
Nested logical expressions are not correctly linearized. Add a test for all possible combinations of 2 logical operators. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-09-06fix ordering of phi-node operandLuc Van Oostenryck2-5/+4
The linearization of logical '&&' create a phi-node with its operands in the wrong order relatively to the parent BBs. Switch the order of the operands for logical '&&'. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-09-06add testcases for wrong ordering in phi-nodesLuc Van Oostenryck4-0/+55
In valid SSA there is a 1-to-1 correspondance between each operand of a phi-node and the parents BB. However, currently, this is not always respected. Add testcases for the known problems. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-09-06return nothing only in void functionsLuc Van Oostenryck1-1/+0
Currently, the code for the return is only generated if the effectively return a type or a value with a size greater than 0. But this mean that a non-void function with an error in its return expression is considered as a void function for what the generated IR is concerned, making things incoherent. Fix this by using the declared type instead of the type of the return expression. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-09-06use UNDEF for missing returnsLuc Van Oostenryck5-5/+0
If a return statement is missing in the last block, the generated IR will be invalid because the number of operands in the exit phi-node will not match the number or parent BBs. Detect this situation and insert an UNDEF for the missing value. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-09-06topasm: top-level asm is specialLuc Van Oostenryck1-0/+0
Top-level ASM statements are parsed as fake anonymous functions. Obviously, they have few in common with functions (for example, they don't have a return type) and mixing the two makes things more complicated than needed (for example, to detect a top-level ASM, we had to check that the corresponding symbol (name) had a null ident). Avoid potential problems by special casing them and return early in linearize_fn(). As consequence, they now don't have anymore an OP_ENTRY as first instructions and can be detected by testing ep->entry. Note: It would be more logical to catch them even erlier, in linearize_symbol() but they also need an entrypoint and an active BB so that we can generate the single statement. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-09-05add testcases for missing return in last blockLuc Van Oostenryck6-0/+97
In this case the phi-node created for the return value ends up with a missing operand, violating the semantic of the phi-node: map one value with each predecessor. Add testcases for these missing returns. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-09-01stricter warning for explicit cast to ulongLuc Van Oostenryck1-0/+56
sparse issues a warning when user pointers are casted to integer types except to unsigned longs which are explicitly allowed. However it may happen that we would like to also be warned on casts to unsigned long. Fix this by adding a new warning flag: -Wcast-from-as (to mirrors -Wcast-to-as) which extends -Waddress-space to all casts that remove an address space attribute (without using __force). References: https://lore.kernel.org/lkml/20180628102741.vk6vphfinlj3lvhv@armageddon.cambridge.arm.com/ Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-09-01Merge branch 'dead-switch' into tipLuc Van Oostenryck1-0/+19
* fix linearization of unreachable switch + label
2018-09-01Merge branch 'has-attribute' into tipLuc Van Oostenryck1-0/+56
* add support for __has_attribute()
2018-09-01trivial-phi: remove more complex trivial phi-nodesLuc Van Oostenryck1-1/+0
In a set of related phi-nodes and phi-sources if all phi-sources but one correspond to the target of one of the phi-sources, then no phi-nodes is needed and all %phis can be replaced by the unique source. For example, code like: int test(void); int foo(int a) { while (test()) a ^= 0; return a; } used to produce an IR with a phi-node for 'a', like: foo: phisrc.32 %phi2(a) <- %arg1 br .L4 .L4: phi.32 %r7(a) <- %phi2(a), %phi3(a) call.32 %r1 <- test cbr %r1, .L2, .L5 .L2: phisrc.32 %phi3(a) <- %r7(a) br .L4 .L5: ret.32 %r7(a) but since 'a ^= 0' is a no-op, the value of 'a' is in fact never mofified. This can be seen in the phi-node where its second operand (%phi3) is the same as its target (%r7). So the only possible value for 'a' is the one from the first operand, its initial value (%arg1). Once this trivial phi-nodes is removed, the IR is the expected: foo: br .L4 .L4: call.32 %r1 <- test cbr %r1, .L4, .L5 .L5: ret.32 %arg1 Removing these trivial phi-nodes will usually trigger other simplifications, especially those concerning the CFG. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-09-01trivial-phi: add testcase for unneeded trivial phi-nodesLuc Van Oostenryck1-0/+15
Trivial phi-nodes are phi-nodes having an unique possible outcome. So, there is nothing to join and the phi-node target can be replaced by the unique value. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-09-01fix linearization of unreachable switch (with reachable label).Luc Van Oostenryck1-1/+0
An unreachable/inactive switch statement is currently not linearized. That's nice because it avoids to create useless instructions. However, the body of the statement can contain a label which can be reachable. If so, the resulting IR will contain a branch to an unexisting BB. Bad. For example, code like: int foo(int a) { goto label; switch(a) { default: label: break; } return 0; } (which is just a complicated way to write: int foo(int a) { return 0; }) is linearized as: foo: br .L1 Fix this by linearizing the statement even if not active. Note: it seems that none of the other statements are discarded if inactive. Good. OTOH, statement expressions can also contains (reachable) labels and thus would need the same fix (which will need much more work). Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-09-01add tescase for unreachable label in switchLuc Van Oostenryck1-0/+20
or more exactly, an unreachable switch statement but containing a reachable label. This is valid code but is curently wrongly linearized. So, add a testcase for it. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-09-01has-attr: add support for __has_attribute()Luc Van Oostenryck1-1/+0
Sparse has support for a subset of GCC's large collection of attributes. It's not easy to know which versions support this or that attribute. However, since GCC5 there is a good solution to this problem: the magic macro __has_attribute(<name>) which evaluates to 1 if <name> is an attribute known to the compiler and 0 otherwise. Add support for this __has_attribute() macro by extending the already existing support for __has_builtin(). Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-09-01has-attr: add testcase for __has_attribute()Luc Van Oostenryck1-0/+57
Add a testcase for the incoming support of __has_attribute(). Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-08-30Merge branch 'volatile-bitfield' and 'mode-pointer' into tipLuc Van Oostenryck2-0/+34
* fix: do not optimize away accesses to volatile bitfields * support mode(__pointer__) and mode(__byte__)
2018-08-25fix: do not optimize away accesses to volatile bitfieldsLuc Van Oostenryck1-1/+0
Accesses to volatiles must, of course, not be optimized away. For this, we need to check to type associated to the memory access. Currently this is done by checking if the type of the result of the memops is volatile or not. Usualy, the type of the result is the same as the one of the access so everything is good but for bitfields, the memop is not done with the type of the bitfield itself but to its base type. Since this base type is unrelated to the access type, it is generaly not marked as volatile even when the access to the bitfield is volatile. Fix this by using the true type of the access to set the field struct instruction::is_volatile. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-08-25add testcase for accesses to volatile bitfieldsLuc Van Oostenryck1-0/+17
Accesses to bitfields must, of course, not be optimized away. This is currently not the case. Add a testcase for it. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-08-25Merge branch 'ssa' into tipLuc Van Oostenryck32-71/+301
* do 'classical' SSA conversion (via the iterated dominance frontier). Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-08-25testsuite: remove useless test for loop-linearizationLuc Van Oostenryck1-136/+0
This testcase was added a bit too quickly in order to have minimal testing of loop's linearization. However, such test just comparing the raw output of test-linearize is a big PITA because it's so sensible to things like pseudos' name themselves depending very much on details about the linearization and simplification. Also, this test didn't really tested anything, it only allowed to track changes. Remove it as it has no testing value. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-08-25Merge branch 'kill-dead-stores' into tipLuc Van Oostenryck4-0/+128
* fix buggy recursion in kill_dead_stores() * kill dead stores again after memops simplification is done. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-08-25add a testcase for enum using a modeLuc Van Oostenryck1-0/+18
Sparse can apply a mode on plain integer types. Add a known-to-fail testcase showing the problem. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-08-24Merge branches 'optim-trunc-or' and 'optim-mask-shift-or' into tipLuc Van Oostenryck4-4/+0
* simplify TRUNC((x & M') | y, N) * simplify AND(SHIFT(a | b, S), M) * simplify TRUNC(SHIFT(a | b, S), N)
2018-08-24simplify TRUNC(SHIFT(a | b, S), N)Luc Van Oostenryck2-2/+0
The simplification of TRUNC(SHIFT(a | b, S), N) can be done by combining the effective mask corresponding to TRUNC(_, N) with the one corresponding to SHIFT(_, S). This allows to also simplify signed bitfields. For example, code like: struct s { signed int :2; signed int f:3; }; int bfs(struct s s, int a) { s.f = a; return s.f; } is now simplified into the minimal: bfs: trunc.3 %r4 <- (32) %arg2 sext.32 %r11 <- (3) %r4 ret.32 %r11 The simplification is done by calling simplify_mask_shift() with the mask corresponding to TRUNC(_, N). Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-08-24simplify AND(SHIFT(a | b, S), M)Luc Van Oostenryck2-2/+0
The simplification of AND(SHIFT(a | b, S), M) can be done by combining the mask M with the effective mask corresponding to SHIFT(_, S). This instruction pattern is generated when accessing bitfields, for example, code like: struct u { unsigned int :2; unsigned int f:3; }; int bfu(struct u s, int a) { s.f = a; return s.f; } is now simplified into the minimal: bfu: and.32 %r11 <- %arg2, $7 ret.32 %r11 The simplification is done by introducing a small helper, simplify_mask_shift(), doing the pattern matching and then calling simplify_mask_shift_or() with the mask M. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-08-22simplify TRUNC((x & M') | y, N)Luc Van Oostenryck4-4/+0
A N-bit truncate is not much different than ANDing with a N-bit mask and so some simplifications done for AND can also be done for TRUNC. For example for code like this: char foo(int x, int y) { return (x & 0xffff) | y; } the mask is unneeded and the function should be equivalent to: char foo(int x, int y) { return x | y; } The simplification in this patch does exactly this, giving: foo: or.32 %r4 <- %arg1, %arg2 trunc.8 %r5 <- (32) %r4 ret.8 %r5 while previously the mask was not optimized away: foo: and.32 %r2 <- %arg1, $0xffff or.32 %r4 <- %r2, %arg2 trunc.8 %r5 <- (32) %r4 ret.8 %r5 This simplification is especially important for signed bitfields because the TRUNC+ZEXT of unsigned bitfields is simplified into an OP_AND but this is, of course, not the case for the TRUNC+SEXT of signed bitfields. Do the simplification by calling simplify_mask_or(), initialy used for OP_AND, but with the effective mask corresponding to TRUNC(x, N): $mask(N). Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-08-22Merge branches 'optim-shift-and' and 'optim-bitfield' into tipLuc Van Oostenryck38-0/+628
2018-08-22simplify ((x & M) << S) when (M << S) == (-1 << S)Luc Van Oostenryck1-1/+0
The instructions SHL(AND(x, M), S) can be simplified into SHL(x, S) if (M << S) == (-1 << S). For example, code like: unsigned foo(unsigned x) { return (x & 0x000fffff) << 12; } is now optimized into: foo: shl.32 %r3 <- %arg1, $12 ret.32 %r3 Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-08-22simplify ((x & M) << S) when (M << S) == 0Luc Van Oostenryck1-1/+0
The instructions SHL(AND(x, M), S) can be simplified to 0 if (M << S) == 0. For example code like: unsigned foo(unsigned x) { return (x & 0xfff00000) << 12; } is now simplified into: foo: ret.32 $0 Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-08-22simplify ((x & M) >> S) when (M >> S) == (-1 >> S)Luc Van Oostenryck1-1/+0
The instructions LSR(AND(x, M), S) are already simplified into AND(LSR(x, S), (M >> S)) but only if AND(x, M) has a single user. However, if (M >> S) == (-1 >> S), the AND part is redundant and the whole can always directly be simplified into LSR(x, S). For example, code like: unsigned foo(unsigned x) { unsigned t = (x & 0xfffff000); return ((t >> 12) ^ (x >> 12)) & t; } is now optimized into: foo: ret.32 $0 because (t >> 12) is simplified into (x >> 12). Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-08-22simplify ((x & M) >> S) when (M >> S) == 0Luc Van Oostenryck1-1/+0
The instructions LSR(AND(x, M), S) are already simplified into AND(LSR(x, S), (M >> S)) but only if AND(x, M) has a single user. However, if (M >> S) == 0, they can always directly be simplified to 0. For example code like: unsigned foo(unsigned x) { unsigned t = (x & 0x00000fff); return (t >> 12) & t; } is now simplified into: foo: ret.32 $0 while previously it was: foo: and.32 %r2 <- %arg1, $0xfff lsr.32 %r4 <- %r2, $12 and.32 %r6 <- %r4, %r2 ret.32 %r6 Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-08-22add testcases for {LSR,SHL}(AND(x, M), S) with shared AND(x, M)Luc Van Oostenryck4-0/+66
The pattern LSR(AND(x, M), S) is already generically simplified into ((x >> S) & (M >> S)) but only if the sub-expression AND(x, M) is not shared with some other expressions because the simplification modify it. But for some special cases the expression can be simplified even if the sub-expression is shared because the simplification doesn't need to modify this AND(x, M) part. Add the testcases for LSR and the incoming SHL. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-08-22simplify SHL((x & M') | y, S)Luc Van Oostenryck7-7/+0
The same simplifications done for LSR can be done for SHL (with the appropriate mask). For example, code like: int foo(int a, int b) { return ((a & 0xfff00000) | b) << 12; } is now optimized into: foo: shl.32 %r5 <- %arg2, $12 ret.32 %r5 while previously it was: foo: and.32 %r2 <- %arg1, $0xfff00000 or.32 %r4 <- %r2, %arg2 shl.32 %r5 <- %r4, $12 ret.32 %r5 Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-08-22simplify OP((x | C), K) when (C & M) != CLuc Van Oostenryck1-1/+0
If the effective mask (M) corresponding to OP(_, K) is different than the combined mask (C & M), then the inner mask (C) can be replaced by the smaller (C & M), giving: OP((x | M'), K) with M' == (C & M). For example, code like: int foo(int x) { return (x | 0xfffffff0) & 0xfff; } is now simplified into: foo: or.32 %r2 <- %arg1, $0xff0 and.32 %r3 <- %r2, $0xfff ret.32 %r3 while previously, the constant was not reduced: foo: or.32 %r2 <- %arg1, $0xfffffff0 and.32 %r3 <- %r2, $0xfff ret.32 %r3 Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-08-22simplify OP((x | C), K) when (C & M) == MLuc Van Oostenryck1-1/+0
In an expression like OP((x | C), K), if the effective mask (M) corresponding to OP(_, K) is equal to the combined mask (C & M), then the OR operation is unneeded and can be replaced by M itself, giving: OP(M, K). In mathematical terms: 0) ((x | C) & M) = ((x & M) | (C & M)) 1) (C & M) = M 2) ((x & M) | (C & M)) = ((x & M) | M) = M and so OP((x | C), K) -> OP(M, K). For example, code like: unsigned int foo(int x) { return (x | 7) & 2; } is now simplified into: foo: ret.32 $2 which previously was not optimized foo: or.32 %r2 <- %arg1, $7 and.32 %r3 <- %r2, $2 ret.32 %r3 Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-08-22simplify OP((x | C), K) when (C & M) == 0Luc Van Oostenryck2-2/+0
In an expression like OP((x | C), K), if the inner constant (C) and the effective mask (M) corresponding to OP(_, K) are disjoint ((C & M) == 0), then the OR with the constant is unneeded and can be optimized away since the constant will be 'cleared' by the mask, giving: OP(x, K) For example, code like: int foo(int x) { return (x | 0xfffff000) & 0xfff; } is now optimized into: foo: and.32 %r3 <- %arg1, $0xfff ret.32 %r3 while previously the OR mask was not optimized away: foo: or.32 %r2 <- %arg1, $0xfffff000 and.32 %r3 <- %r2, $0xfff ret.32 %r3 Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-08-22simplify OP(((x & M') | y), K) when (M' & M) != M'Luc Van Oostenryck3-3/+0
Currently, in simplify_mask_or_and(), only the cases where (M' & M) == 0 or (M' & M) == M are simplified. However, if the combined mask (M' & M) is different than the original inner mask (M'), this inner mask can be replaced by the smaller combined one, giving: OP(((x & (M' & M)) | y), K). For example, code like: int foo(int x, int y) { return (((x & 0xfffffff0) | y) & 0xfff); } is now simplified into: foo: and.32 %r2 <- %arg1, $0xff0 or.32 %r4 <- %r2, %arg2 and.32 %r5 <- %r4, $0xfff ret.32 %r5 while previously, the mask was not reduced: foo: and.32 %r2 <- %arg1, $0xfffffff0 ... Note: this is not a very effective simplification like directly removing an instruction, nevertheless the smaller mask can trigger other simplifications and may also be advantageous for a subsequent code generation phase. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-08-22simplify OP(((x & M') | y), K) when (M' & M) == MLuc Van Oostenryck3-3/+0
In an expression like this, if the inner mask (M') 'covers' all the bits of the effective mask (M) corresponding to OP(_, K), IOW if (M' & M) == M, then the inner mask (M') is unneeded and can be optimized away, giving: OP((x | y), K). For example, with this simplification, code like: int foo(int x, int y) { return (((x & 0x0fffffff) | y) & 0xfff); } is now optimized into the minimal: foo: or.32 %r4 <- %arg1, %arg2 and.32 %r5 <- %r4, $0xfff ret.32 %r5 while previously, the inner mask was not optimized away: foo: and.32 %r2 <- %arg1, $0xfffffff or.32 %r4 <- %r2, %arg2 and.32 %r5 <- %r4, $0xfff ret.32 %r5 Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-08-22allow simplification of OP(((x & y) | (a & M')), K)Luc Van Oostenryck3-3/+0
In simplify_mask_or(), two calls to simplify_mask_or_and() are made: one for each operand of the OR instruction. These two calls are guarded by a test checking the presence of the AND instruction. If it is the case for the first operand, the second operand is never considered for simplification, even if no simplifications have been made. Fix this by testing the return value of simplify_and_or_mask() and let's do the second call if no simplifications could be done in the first one. For example, code like: int foo(int x, int y, int a) { return ((a & 0xf000) | (x & y)) & 0x0fff; } was expectedly simplified into: foo: and.32 %r5 <- %arg1, %arg2 and.32 %r7 <- %r5, $0xfff ret.32 %r7 while the same code with the operands of the OR swapped was not: int foo(int x, int y, int a) { return ((x & y) | (a & 0xf000)) & 0x0fff; } resulted in the non-optimized: foo: and.32 %r3 <- %arg1, %arg2 and.32 %r5 <- %arg3, $0xf000 or.32 %r6 <- %r3, %r5 and.32 %r7 <- %r6, $0xfff ret.32 %r7 but now the simplification can also be done: foo: and.32 %r3 <- %arg1, %arg2 and.32 %r7 <- %r3, $0xfff ret.32 %r7 Note: it would be simpler to unconditionally do both calls but this is unsafe because some of the concerned instructions, needed in the second call, could have been simplified away in the first one. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-08-22add testcases for bitfield & AND/OR simplificationLuc Van Oostenryck36-0/+625
The extraction & insertion of bitfields is made of relatively complex combinations of SHL/LSR/AND/OR and TRUNC/ZEXT/SEXT. Add a few testcases showing the effectiveness of their simplification and to catch possible future regressions. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-08-22add testcase for (((x & M') | (y & M'')) & M)Luc Van Oostenryck2-0/+23
There is a potential problem when the second side of the OR is simplified away. Add 2 testcases to catch possible regressions here. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-08-17Merge branches 'optim-shl-lsr' and 'optim-trunc-trunc' into tipLuc Van Oostenryck1-0/+12
* add simplification of TRUNC(TRUNC((x)) * add simplification of SHL(LSR(x), S), S)
2018-08-17simplify TRUNC(TRUNC(x))Luc Van Oostenryck1-1/+0
The simplification of ZEXT(ZEXT(x)) was already added but its dual, TRUNC(TRUNC(x)), was not. Add it now. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-08-17simplify ((x >> S) << S)Luc Van Oostenryck1-1/+0
The simplification of ((x << S) >> S) was already added but its dual was forgotten. Add it now. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-08-16add testcase for TRUNC(TRUNC(x)) simplificationLuc Van Oostenryck1-0/+13
Add the testcase before doing the simplification. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-08-16add testcase for ((x >> S) << S) simplificationLuc Van Oostenryck1-0/+15
Add the testcase before doing the simplification. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-08-16rename testcase for ((x << S) >> S) simplificationLuc Van Oostenryck1-1/+1
The testcase was named with the wrong operation order (inner op first instead of outer-first). Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-08-08Merge branches 'fix-inc-dec-size' and 'optim-mask' into tipLuc Van Oostenryck8-81/+92
* generate integer-wide OP_ADD & OP_SUB in linearize_inc_dec() * simplify mask instructions & bitfield accesses
2018-08-08simplify (x & M) >> S to (x >> S) & (M >> S)Luc Van Oostenryck1-1/+0
This is especially usefull when simplifying code accessing bitfields. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-08-08simplify (x << S) >> S into x & (-1 >> S)Luc Van Oostenryck3-11/+3
This transformation is especially usefull when simplifying code accessing bitfields or for other masking manipulations. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-08-08simplify ((x & M) | y) >> S to (y >> S) when (M >> S) == 0Luc Van Oostenryck1-1/+0
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-08-08simplify ((x & M') | y ) & M into (y & M) when (M' & M) == 0Luc Van Oostenryck1-1/+0
This is a common pattern for bitfield simplification. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-08-07optim: add a few more testcases for shift & maskLuc Van Oostenryck1-0/+15
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-08-07fix instruction size & type in linearize_inc_dec()Luc Van Oostenryck2-68/+75
If the ++ or -- operator is used on a bitfield, the addition or subtraction is done with the size of the bitfield. So code like: struct { int f:3; } s; ... s->f++; will generate intermediate code like: add.3 %r <- %a, $1 This is not incorrect from the IR point of view but CPUs have only register-sized instructions, like 'add.32'. So, these odd-sized instruction have one or two implicit masking/extend that should better make explicit. Fix this by casting to and from the base type when these operators are used on bitfields. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-08-06limit the mask used for bitfield insertionLuc Van Oostenryck1-6/+6
The mask used for bitfield insertion is as big as the integers used internally by sparse. Elsewhere in the code, constants are always truncated to the size of the instructions using them. It's also displaying concerned instructions oddly. For example: and.32 %r2 <- %r1, 0xfffffffffffffff0 Fix this by limiting the mask to the size of the instruction. Fixes: a8e1df573 ("bitfield: extract linearize_bitfield_insert()") Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-08-06cast: fix warning position in cast_pseudo()Luc Van Oostenryck2-4/+4
The function cast_pseudo() can issues warnings about non size-preserving integer <-> pointer casts. The file:line:column position of these warnings is taken from the destination type but this position is the one where the type is declared (or where the symbol associated with this type is defined) which may or may not be related to the position of the cast. Fix this by using the current position instead (which should hold the position of the cast). Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-08-06boolean conversion of boolean value is a no-opLuc Van Oostenryck1-6/+6
If an expression is already a boolean (constant) expression, converting it to a boolean expression is a no-op. In this case, return early, this avoids to create intermediate code that will need to be simplified away at some later stage. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-08-06simplify AND(SETCC(x,y), M)Luc Van Oostenryck1-1/+0
Since the OP_SETCC instructions can only return a 0 or a 1, a subsequent AND mask can often be heavily simplified. Simplify the mask value. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-08-06simplify TRUNC(SETCC(x,y), N)Luc Van Oostenryck1-1/+0
Since the OP_SETCC instructions can only return a 0 or a 1, a truncation won't change the value and the OP_SETCC can be changed to directly return the extended size. Remove the unneeded truncate. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-08-06simplify SEXT(SETCC(x,y), N)Luc Van Oostenryck1-1/+0
Since the OP_SETCC instructions can only return a 0 or a 1, a sign-extension won't change the value if the size is wider than 1. The OP_SETCC can thus be changed to directly return the extended size. Remove the unneeded extension. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-08-06simplify ZEXT(SETCC(x,y), N)Luc Van Oostenryck3-8/+3
Since the OP_SETCC instructions can only return a 0 or a 1, a zero-extension won't change the value and the OP_SETCC can be changed to directly return the extended size. Remove the unneeded extension. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-08-06simplify SETNE(TRUNC(x,N),{0,1})Luc Van Oostenryck1-1/+0
Convert the OP_TRUNC into an OP_AND with the appropriate mask. This a greater chance to simplify with previous instructions and to correspond to a register-size operand. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-08-06simplify SETNE(AND(X,1),0) to AND(X,1)Luc Van Oostenryck1-1/+0
Since the OP_SETCC instructions can only return a 0 or a 1, a compare-not-equal-zero or compare-equal-1 is a no-op if the operand have been masked with 1. Remove the no-op comparison (if the size matches). Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-08-06simplify linearize_logical()Luc Van Oostenryck1-92/+68
The linearized code for logical expressions looks like: .Lc ... condition 1 ... cbr %c, .L1, .L2 .L1 %phisrc %phi1 <- $1 br .Lm .L2 ... condition 2 ... %phisrc %phi2 <- %r br .Lm .Lm %phi %r <- %phi1, %phi2 But .L1 can easily be merged with .Lc: .Lc ... condition 1 ... %phisrc %phi1 <- $1 cbr %c, .Lm, .L2 .L2 ... condition 2 ... %phisrc %phi2 <- %r br .Lm .Lm %phi %r <- %phi1, %phi2 Do this simplification which: * creates less basic blocks & branches * do at linearization time a simplification not done later. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-08-06expand linearize_conditional() into linearize_logical()Luc Van Oostenryck1-127/+111
linearize_logical() call linearize_conditional() but needs additional tests there and generate code more complicated than needed. Change this by expanding the call to linearize_conditional() and make the obvious simplification concerning the shortcut expressions 0 & 1. Also, removes the logical-specific parts in linearize_conditional(), since there are now unneeded. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-08-06fix linearize_conditional() for logical opsLuc Van Oostenryck1-1/+0
The function linearize_conditional(), normaly used for conditionals (c ? a : b) is also used to linearize the logical ops || and &&. For conditionals, the type evaluation ensure that both LHS & RHS have consistent types. However, this is not the case when used for logical ops. This creates 2 separated but related problems: * the operands are not compared with 0 as required by the standard (6.5.13, 6.5.14). * both operands can have different, incompatible types and thus it's possible to have a phi-node with sources of different, incompatible types, which doesn't make sense. Fix this by: * add a flag to linearize_conditional() telling if it's used for a conditional or for a logical op. * when used for logical ops: * first compare the operands againts zero * convert the boolean result to the expression's type. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-08-06conditional branches can't accept arbitrary expressionsLuc Van Oostenryck3-29/+29
Conditional branches, or more exactly OP_CBR, can't accept arbitrary expression as condition. it is required to have an integer value. Fix this by adding a comparison against zero.
2018-08-04add testcase for linearize_logical()Luc Van Oostenryck8-0/+418
Add some tests in preparation of some bug-fixing and simplification in linearize_logical()linearize_conditional(). Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-07-28Merge branch 'optim-setne' into tipLuc Van Oostenryck4-37/+43
* some simplifications of OP_SETNE & OP_SETEQ with 0 and 1 Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-07-28simplify 'x != 0' or 'x == 1' to 'x'Luc Van Oostenryck2-37/+19
These two comparisons are no-ops when the operand is boolean. Simplify them away. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-07-28simplify SET{EQ,NE}(SEXT(x, N),{0,1})Luc Van Oostenryck1-1/+0
A sign-extension has no effect on the result of a comparison with 0 or with 1 when the original size is bigger than 1. Optimize away the extension. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-07-28simplify SET{EQ,NE}(ZEXT(x, N),{0,1})Luc Van Oostenryck1-1/+0
A zero-extension has no effect on the result of a comparison with 0 or 1. Optimize away the extension. Note: this simplification was already done but only when the original size was 1 but it can be done for all sizes. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-07-25testcase for SET{EQ,NE}([SZ]EXT(x, N),{0,1})'s simplificationLuc Van Oostenryck2-0/+26
Add some basic testcase for these relatively common simplification opportunities. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-07-25Merge branch 'optim-cast' into tipLuc Van Oostenryck21-0/+379
* several simplifications involving casts and/or bitfields Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-07-25Merge branch 'optim-shift' into tipLuc Van Oostenryck7-0/+488
* give a correct & sensible warning on negative or over-sized shifts. * add conservative simplification of such shifts. * do not optimize the meaningless shift: * any shift with a negative count * OP_ASRs with an over-sized shift count. * try to give a correct negative/too-big error message during simplification. * simplify chains of shifts. * simplify ZEXT + ASR into ZEXT + LSR Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-07-25shift: simplify ASR(ZEXT(X, N), C)Luc Van Oostenryck1-0/+13
After an OP_ZEXT, it is guaranteed that the sign bit is zero. So, an arithmetic right-shift following an OP_ZEXT gives the same result as an logical right-shift which is simpler to handle and further optimize. So, when preceded by an OP_ZEXT, replace OP_ASR by OP_LSR. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-07-25shift: simplify ASR(LSR(x,N),N')Luc Van Oostenryck1-0/+42
Since an LSR with an in-range shift count will insert a zero in the MSB, a subsequent ASR will be equivalent to an LSR of the same count or equivalently, the combinaison the these two shifts is equivalent to a single LSR with a shift count equal to the sum of the two initial counts. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-07-25shift: simplify LSR(LSR(x,N),N') & friendsLuc Van Oostenryck1-0/+149
A shift of a shift (of the same kind) is equivalent to a single shitf with a count equal to the sum of the two initial counts. In addition: * for LSRs & SHLs, if the sum is >= to the instruction size, then the result is zero. * for ASRs, if the sum is >= to the instruction size, then the result is the same as a shift of a count of size - 1. Implement these simplifications if both shift counts are in range. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-07-25testcases: missing evaluation of side effects in typeof(VLA)Luc Van Oostenryck1-0/+26
The argument of the typeof operator is normally not evaluated but it should be when it involves a VLA. Add a testcase for this. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-07-25testcases: add testcase for missing detection of out-of-bound storesLuc Van Oostenryck1-0/+21
Apparently, only loads are detected, stores are not. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-07-24use "%Le" to display floatsLuc Van Oostenryck4-22/+22
Floating-point values are displayed using the printf format "%Lf" but this is the format without exponent (and with default precision of 6 digit). However, by its nature, this format is very imprecise. For example, *all* values smaller than 0.5e-6 are displayed as "0.000000". Improve this by using the "%Le" format which always use an exponent and thus maximize the precision. Note: ultimately, we should display them exactly, for example by using "%La", but this will requires C99. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-07-23big-shift: fix warning message for negative or over-sized shiftsLuc Van Oostenryck2-13/+12
In order to preserve shifts with negative count and give a proper warning for them, we first need to identify when the shift must be considered as negative. This identification is made complicated by the fact that PSEUDO_VAL are typeless. The solution chosen here is to try to first sign extend the shift count (with the size of an int and the size of the instruction). If after this extension the count appears as negative it is treated as such (and this new value replace the old one to avoid to have to redo this at each simplification run), otherwise it is considered as unsigned. The only case where a negative count could be wrongly interpreted as a big unsigned value would be if: size target int < instruction's size < size host value which can't happen for now since sizeof(int) == 4 on all targets and sizeof(value) is 8. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-07-23big-shift: add testcases for simplification of negative shiftsLuc Van Oostenryck1-0/+18
Like GCC, we don't want to touch shifts with a negative count. Add testcases covering this at expansion and simplification time. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-07-23big-shift: add testcases for simplification of over-sized shiftsLuc Van Oostenryck1-7/+55
Like GCC, we don't want to touch over-sized ASR but over-sized LSRs & SHLs degenerate to 0. Add testcases covering all cases. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-07-23cast: simplify SEXT(ZEXT(x,N),N')Luc Van Oostenryck1-1/+0
A sign-extension following a zero-extension can always be simplified into a single zero-extension since the intermediate value is guaranted to have a zero sign bit. Simplify away such instructions. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-07-23cast: simplify ZEXT(ZEXT(x,N),N')Luc Van Oostenryck1-1/+0
A zero-extension following another zero-extension can always be simplified into a single zero-extension. Simplify away such instructions. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-07-23cast: simplify SEXT(SEXT(x,N),N')Luc Van Oostenryck1-1/+0
A sign-extension following another sign-extension can always be simplified into a single sign-extension. Simplify away such instructions. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-07-23cast: simplify AND(ZEXT(x,M),N)Luc Van Oostenryck2-2/+0
An OP_AND with a constant value following a OP_ZEXT can often be simplified: * the constant mask can be made smaller * the whole masking is redundant and can be removed. Do these two simplifications depending on the initial mask and the sizes of the instructions. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-07-23cast: simplify [ZS]EXT(AND(x,M),N)Luc Van Oostenryck3-3/+0
A OP_AND with a constant value followed by a sign or zero-extension can often be moved after the extension. This is good because it can trigger the cancellation of the OP[ZS]EXT with a preceding OP_TRUNC, a common situation with bitfields. Note: This 'simplification' is less desirable if there is no preceding OP_TRUNC, for example, in a sequence like: and.32 %t <- %a, $mask *ext.64 %r <- %t If needed, this can be filtered out at some later stage. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-07-23cast: preserve the sizes of TRUNC(AND(x,M),N)Luc Van Oostenryck1-1/+0
sparse contains some code to simplify an AND masking followed by a truncating cast. However, this simplification is problematic because it doesn't keep the sizes consistent. For example, code like: and.32 %r3 <- %r2, $0x7fff trunc.16 %r4 <- (32) %r3 will be discarded with %r3 used in place of %r4. This is correct in the mathematical sense but %r4 had a size of 16 while %r3 has a size of 32, so using %r3 in place of %r4 will make the sizes inconsistent with unexpected consequences. We can more or less fix this by using another transformation that preserve the sizes: trunc.16 %r3 <- (32) %r2 and.16 %r4 <- %r3, $0x7fff which in itself doesn't optimize anything but: 1) the mask may be smaller 2) may trigger other simplification with the TRUNC or the AND. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-07-23cast: simplify [SZ]EXT + TRUNC to a smaller/greater sizeLuc Van Oostenryck2-2/+0
An OP_SEXT or a OP_ZEXT followed by a truncate to a size smaller than the original size is unneeded, the same result can be obtained by doing the truncate directly on the original value. Dualy, an OP_SEXT or a OP_ZEXT followed by a truncate to a size greater than the original size doesn't need the truncate, the same result can be obtained by doing the extend directly on the original value. Rearrange the inputs (src & orig_type) to bypass the unneeded operation. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-07-23cast: simplify [SZ]EXT + TRUNC to original sizeLuc Van Oostenryck1-1/+0
An OP_ZEXT/OP_SEXT following by a OP_TRUNC to the original size is a NOP. Simplify away such OP_TRUNC. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-07-23add testcases for casts & bitfield insertion/extractionLuc Van Oostenryck21-0/+391
There is several difficulties some related to unclear semantic of our IR instructions and/or type evaluation. Add testcases trying to cover this area. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-07-23big-shift: do not truncate the count when checking itLuc Van Oostenryck1-1/+0
The function check_shift_count() is used to check the validity of shift counts but the count is truncated to an (host) int. This truncated value can thus miss very large (or very negative) shift count. Fix this by using the full width shift count when doing the check. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-07-23big-shift: fix warning message for negative shift countLuc Van Oostenryck1-18/+18
The diagnostic emitted when shifting by an negative amount is confusing: warning: shift too big (4294967295) for type ... Change the message to the more informative: warning: shift count is negative (-1) Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-07-23big-shift: use the type width for too big shiftLuc Van Oostenryck1-12/+45
Currently, during simplification, when it's checked if the shift amount of a shift instruction is in range, it's not the instruction's size (which is the same as the type's width) that is used but the 'operand size' as returned by operand_size(). operand_size() is a bit like poor man's Value Range Propagation or VRP without Propagation, and use the knowledge of previous instructions to deduce the effective size of the operand. For example, if the operand is the result of a narrowing cast or have been ANDed with a known mask, or was a bitfield, the size returned is the one of the cast or the mask and may be smaller than its type. A priori, using more precise knowledge is a good thing but in the present case it's not because it causes warning for things that are totally legal, meaningfull and used all the time. For example, we don't want to warn in the following code: struct bf { int u:8; }; int bf(struct bf *p) { return p->s << 24; } Another situation where such warnings are not desirable is when the shift instruction 'is far' from the one defining the size, for example when the shift occurs in an inline function and this inline function is called with a smaller type. So, use the instruction size instead of the effective operand size when checking the range of a shift instruction. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-07-23big-shift: simplify over-sized OP_SHLsLuc Van Oostenryck1-0/+7
In the mathematical sense, the result of a left-shift by an amount bigger than the operand size equals zero. Do the corresponding simplification. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-07-23big-shift: simplify over-sized OP_LSRsLuc Van Oostenryck2-10/+37
In the mathematical sense, the result of LSR by an amount bigger than the operand size equals zero. Do the corresponding simplification. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-07-23big-shift: reuse simplify_asr() for LSR & SHLLuc Van Oostenryck1-0/+8
During the simplification phase, ASR instructions are checked and possibly simplified but LSR & SHL are not. Rename simplify_asr() into simplify_shift() and do the check & simplification for LSR & SHL too. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-07-23big-shift: do not simplify over-sized OP_ASR to zeroLuc Van Oostenryck1-0/+2
Currently, arithmetic right shifts with a shift count bigger than the operand size are simplified to zero. While this makes a lot of sense for LSR and SHL, for ASR it's much less so. Remove the simplification and let the back-end generate the code for a non-immediate count (which is what GCC do). Note: Some other options would be: - reduce the shift count modulo the operand size, like it was done previously at expansion time and which correspond to the run-time behaviour of several CPUs families (x86[-64], arm64, mips, ...) but not all of them (arm, ppc, ...). - truncate the count to N-1 Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-07-22big-shift: also check shift count of shift-assignmentLuc Van Oostenryck1-0/+48
At expansion time, a diagnostic is emitted for shift with a bad count in a shift expression but not in a shift-assign. Fix this by calling the checking function also for shift-assigns. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-07-21big-shift: add test for shifts with bad countLuc Van Oostenryck2-0/+95
The following patches change quite a bit of things regarding shifts with bad count. Add testcases to ensure everything is covered and catch possible future regressions. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-07-01ssa: phi worklistLuc Van Oostenryck1-1/+0
This patch optimize the very simple implementation of the phi-node renaming at the end of the SSA conversion. It avoids the need to rescan the whole function to find the phi-nodes by using a worklist to put the phi-nodes during the renaming of non-phi nodes instructions. This optimization avoids O(n^2) behaviour in some pathological cases. Note: A lot of optimizations can be done for the renaming. For the moment, things are kept as simplest as possible, the goal being to have correctness first. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-07-01ssa: activate the new SSA conversionLuc Van Oostenryck10-10/+2
This activate the new SSA conversion that will be used to replace simplify_symbol_usage() which created invalid SSA (phi-nodes were placed where the value was needed instead of where the paths meet, also and partially related, it was possible for a phi-node to have more operands/sources than the BB it was in had parents). Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-07-01testsuite: remove useless test for loop-linearizationLuc Van Oostenryck1-136/+0
This testcase was added a bit too quickly in order to have minimal testing of loop's linearization. However, such test just comparing the raw output of test-linearize is a big PITA because it's so sensible to things like pseudos' name themselves depending very much on details about the linearization and simplification. Also, this test didn't really tested anything, it only allowed to track changes. Remove it as it has no testing value. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-07-01testsuite: improve mem2reg testcasesLuc Van Oostenryck19-18/+178
A few tests are added, some have been renamed to better refect their purposes. Finally, some checks have been added or tweaked. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-07-01testsuite: add a few more tests catching quadratic behaviourLuc Van Oostenryck3-0/+69
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-07-01testsuite: reorganize tests for compound literalsLuc Van Oostenryck3-9/+19
Split the existing test in 2 as it contains 2 different cases. Also move the test to 'linear/' subdir. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-06-30kds: fix recursion in kill_dead_stores_bb()Luc Van Oostenryck1-1/+0
In kill_dead_stores_bb(), after having scanned the current BB, we may recurse into the parent BBs. But we must do this only if we're sure that the store there may not be needed in another BB. In other words, we must do this only if the current BB is the only child of the parent. However, if one of the parent has more than one child, instead of trying the next parent, the function stops there and returns. Furthermore, the check is done with an open loop instead of using the helper bb_list_size(). Fix this by using bb_list_size() to check if the parent has only one child, do the recursion if it is the case and try the next parent if not. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-06-30kds: kill dead stores after memops simplificationLuc Van Oostenryck2-2/+0
Currently, dead stores are removed after the initial promotion of symbols to pseudos (simplify_one_symbol()). But more complex promotions are done later during memops simplification (simplify_loads()) and dead stores should be removed there too but aren't. Fix this by calling kill_dead_stores() after memops simplification. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-06-30kds: add testcases for kill_dead_stores()Luc Van Oostenryck4-0/+131
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-06-30Merge branch 'cse-cast' into tipLuc Van Oostenryck1-0/+15
* cse: try the next pair instead of keeping the first instruction * cse: compare casts only by kind a size, not by C type.
2018-06-30fix killing OP_SWITCHLuc Van Oostenryck1-0/+17
Currently OP_SWITCHes are only handled by default in kill_insn(). In consequence, when killed, OP_SWITCHes leave a fake usage on the condition. Fix this by removing the condition's usage when killing an OP_SWITCH. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-06-30Merge branch 'cast-optim' into tipLuc Van Oostenryck4-61/+38
* optimize away OP_UTPTR & OP_PTRTU which are nops.
2018-06-29cast: optimize away casts to/from pointersLuc Van Oostenryck2-16/+26
Now that all casts to or from a pointer are between a pointer and a pointer-sized unsigned integer, from an optimization PoV, they are all no-ops. So, optimize them away at simplification time. Note: casts between pointers (OP_PTRCAST) should also be optimized away but the original type is used for a number a things (for example in check_access()) and can't be optimized away so simply (yet). Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-06-29cast: reorganize testcases for cast optimizationLuc Van Oostenryck3-45/+12
validation/linear/* should not contain testcases that are optimization dependent and validation/*.c should not contain tests using 'test-linearize', only those using 'sparse'. Move some cast-related testcases accordingly. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-06-28bool: generate plain OP_{AND,OR} instead of OP_{AND,OR}_BOOLLuc Van Oostenryck3-28/+53
Now that OP_AND_BOOL and OP_OR_BOOL are always given boolean operands, they are just a special case of 1 bit OP_AND & OP_OR. To avoid to have to repeat CSE, simplification patterns, ... better to generate plain OP_AND & OP_OR instead. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-06-28bool: fix missing boolean context for floatsLuc Van Oostenryck1-0/+48
The function add_convert_to_bool() was added to give a boolean context to logical expressions but did this onl for integers. Fix this for floating-point expressions by adding the proper comparison to 0.0. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-06-28bool: simplify ZEXT in bool -> int -> boolLuc Van Oostenryck2-33/+29
Because of C's integer promotion, in code like 'a == 0', the operand 'a' must be promoted to int. So, if 'a' is of type 'bool', it results in following linearization: zext.32 %t <- (1) %a setne.32 %r <- %t, $0 While this promotion is required by the standard at C level, here, from an operational PoV, the zero-extension is unneeded since the result will be the same without it. Change this by simplifying away such zero-extensions. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-06-28bool: add testcase for bool simplificationLuc Van Oostenryck1-0/+247
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-06-28simplify 'x ^ ~0' to '~x'Luc Van Oostenryck1-0/+8
This is yet another simple identity with the potential to trigger more simplifications. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-06-28simplify 'x & ~0' to 'x'Luc Van Oostenryck1-0/+7
This is another simple identity with the potential to trigger more simplifications. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-06-28simplify 'x | ~0' to '~0'Luc Van Oostenryck1-0/+15
This is a simple identity with the potential to trigger more simplifications. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-06-26add simple testcases for internal infinite loopsLuc Van Oostenryck1-0/+54
The current SSA conversion kinda ignore undefined variables. Those may then later be detected when they are part of a LOAD + (ADD|SUB) cycle but they can also create other cycles which are not detected. These cycles inhibit (or uselessly complicate) lots of optimizations. For example, code like: and.32 %r2 <- %r1, $1 and.32 %r3 <- %r2, $1 should be simplified into: and.32 %r3 <- %r1, $1 but this simplification would behave horribly with 'cycles' like: and.32 %r1 <- %r1, $1 This patch add a testcase for a number a very simple situations where such cycles can be created. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-06-26cast: simplify TRUNC + ZEXT to ANDLuc Van Oostenryck2-10/+8
A truncation followed by a zero-extension to the original size, which is produced when loading a storing bitfields, is equivalent to a simple AND masking. Often, this AND can then trigger even more optimizations. So, replace TRUNC + ZEXT instructions by the equivalent AND. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-06-26cse: move to next comparable instructionLuc Van Oostenryck1-1/+0
Let's suppose we have a few instructions: A, B, C & D, all congruent insn_compare() The current way the CSE is done is: The first try will be try_to_cse(A,B). If this succeeds, A & B have been merged (AB) and the next try will be done with the next instruction: try_to_cse(AB,C). That's good. However, if it fails, the next try will be: try_to_cse(A,C). If this one also fails, the next one will be: try_to_cse(A,D) And if this one also fails, nothing else is done. In other words, all attempts are done with A. If it happens that A can't be eliminated (because it doesn't dominate B, C & D and is not dominated by them), no eliminations are done because the other pairs, not involving A are never tried. Ideally, we should try all possible pairs: A-B, A-C & A-D but also B-C, B-D & C-D. However this is quadratic and can be a bit costly. An easy & cheap way to improve the current situation is, in case of failure, to not reuse the original first instruction but the other one. So instead of testing: A-B, A-C, A-D, ... we will test: A-B, B-C, C-D, ... with the result that an 'bad' instruction can't block anymore the following pairs. So, when try_to_cse() fails, do not retry by keeping the first instructions, but retry using the second one. In practice, this seems to work fairly well. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-06-23cast: keep instruction sizes consistentLuc Van Oostenryck2-11/+189
The last instruction of linearize_load_gen() ensure that loading a bitfield of size N results in a object of size N. Also, we require that the usual binops & unops use the same type on their operand and result. This means that before anything can be done on the loaded bitfield it must first be sign or zero- extended in order to match the other operand's size. The same situation exists when storing a bitfield but there the extension isn't done. We can thus have some weird code like: trunc.9 %r2 <- (32) %r1 shl.32 %r3 <- %r2, ... where a bitfield of size 9 is mixed with a 32 bit shift. Avoid such mixing of size and always zero extend the bitfield before storing it (since this was the implicitly desired semantic). The combination TRUNC + ZEXT can then be optimised later into a simple masking operation. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-06-23cse: add testcase for missed opportunityLuc Van Oostenryck1-0/+16
In the test the offset is the same for dst & src and thus it's calculation should be CSEed away but it is not (yet). Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-06-23cast: specialize integer castsLuc Van Oostenryck14-156/+151
Casts to integer used to be done with only 2 instructions: OP_CAST & OP_SCAST. Those are not very convenient as they don't reflect the real operations that need to be done. This patch specialize these instructions in: - OP_TRUNC, for casts to a smaller type - OP_ZEXT, for casts that need a zero extension - OP_SEXT, for casts that need a sign extension - Integer-to-integer casts of the same size are considered as a NOPs and are, in fact, never emitted. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-06-23cast: make casts from pointer always size preservingLuc Van Oostenryck2-86/+86
Currently casts from pointers can be done to any integer type. However, casts to (or from) pointers are only meaningful if it preserves the value and thus done between same-sized objects. To avoid to have to worry about sign/zero extension while doing casts to pointers it's good to not have to deal with such casts. Do this by doing first a cast to an unsigned integer of the same size as a pointer and then, if needed, doing to cast to the final type. As such we have only to support pointer casts to unsigned integers of the same size and on the other hand we have the generic integer-to-interger casts we to support anyway. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-06-23cast: add support for -Wpointer-to-int-castLuc Van Oostenryck2-2/+2
It's relatively common to cast a pointer to an unsigned long, for example to make some bit operations. It's much less sensical to cast a pointer to an integer smaller (or bigger) than a pointer is. So, emit a diagnostic for this, under the control of a new warning flag: -Wpointer-to-int-cast. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-06-23cast: specialize cast from pointersLuc Van Oostenryck5-4/+43
Currently all casts to pointers are processed alike. This is simple but rather unconvenient in later phases as this correspond to different operations that obeys to different rules and which later need extra checks. Change this by using a specific instructions (OP_UTPTR) for [unsigned] integer to pointers. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-06-23cast: make pointer casts always size preservingLuc Van Oostenryck2-38/+42
Currently casts to pointers can be done from any integer types. However, casts to (or from) pointers are only meaningful if value preserving and thus between objects of the same size. To avoid to have to worry about sign/zero extension while doing casts to pointers it's good to only have to deal with the value preserving ones. Do this by doing first, if needed, a cast an integer of the same size as a pointer before doing the cast to a pointer. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-06-23cast: specialize casts from unsigned to pointersLuc Van Oostenryck5-6/+58
Currently all casts to pointers are processed alike. This is simple but rather unconvenient as it correspond to different operations that obeys to different rules and which later need extra checks. Change this by using a specific instructions (OP_UTPTR) for unsigned integer to pointers. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-06-23cast: specialize floats to integer conversionLuc Van Oostenryck5-12/+12
Currently, casts from floats to integers are processed like integers (or any other type) to integers. This is simple but rather unconvenient as it correspond to different operations that obeys to different rules and which later need extra checks. Change this by directly using specific instructions: - FCVTU for floats to unsigned integers - FCVTS for floats to signed integers Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-06-23cast: handle NO-OP castsLuc Van Oostenryck1-0/+15
Some casts, the ones which doesn't change the size or the resulting 'machine type', are no-op. Directly simplify away such casts. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-06-23cast: specialize FPCAST into [USF]CVTFLuc Van Oostenryck2-11/+11
Currently, all casts to a floating point type use OP_FPCAST. This is maybe simple but rather uncovenient as it correspond to several quite different operations that later need extra checks. Change this by directly using different instructions for the different cases: - FCVTF for float-float conversions - UCVTF for unsigned integer to floats - SCVTF for signed integer to floats and reject attempts to cast a pointer to a float. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-06-23cast: add tests for warnings issued by sparse -vLuc Van Oostenryck1-0/+27
The sparse command (aka the 'checker') do a number of additional checks when used with the -v flag (I strongly believes that this option is rarely used but let me not disgress about it here). One of these additional checks is about casts. Add some testcases in order to catch any problems here. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-06-23cast: add testcase for cast to bad typeofLuc Van Oostenryck1-0/+13
There are special problems when a typeof() expression can't be evaluated. Catch this here. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-06-23cast: add testcase for bad implicit casts to struct/unionLuc Van Oostenryck1-0/+47
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-06-23cast: reorg testcases related to castsLuc Van Oostenryck9-47/+32
* merge the tests about implicit & explicit casts in a single file as there was a lot of redundancy. * shuffle the tests to linear/ or optim/ Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-06-21fix bad fpcast simplificationLuc Van Oostenryck1-1/+0
A integer-to-float cast of a constant is currently simplified away as if it is an integer-to-integer cast. That's bad. Fix this by refusing to simplify away any integer-to-float casts like already done for float-to-integer casts. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-06-21add testcase for bad fpcast simplificationLuc Van Oostenryck1-0/+14
A integer-to-float cast of a constant is currently simplified away as if it is an integer-to-integer cast. That's bad. Create a testcase for it. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-06-16testsuite: allow extra/default options to test commandsLuc Van Oostenryck1-0/+4
This allow, for example, to simulate running the testsuite on a 32bit machine or running the testsuite with some extra debugging flags. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-06-16testsuite: fix missing returnLuc Van Oostenryck2-8/+9
Some non-void functions in the testcases miss a return. Add the missing return or make the function as returning void. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-06-16add support for -fdiagnostic-prefix[=prefix]Luc Van Oostenryck1-0/+11
When using sparse it's common to compile a file and directly run sparse on the same file, like it is done for the kernel. In this case, error messages from sparse are interspersed with those from the compiler. It's thus not always easy to know from which tools they come. Fix this by allowing to prefix all the diagnostic messages by some configurable string, by default "sparse". More exactly, an error message that was emitted like: file.c:<line>:<col>: error: this is invalid code can now be emitted as: file.c:<line>:<col>: sparse: error: this is invalid code Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com> Reviewed-by: Ramsay Jones <ramsay@ramsayjones.plus.com>
2018-06-12Merge branches 'has-builtin' and 'builtin-predef' into tipLuc Van Oostenryck8-0/+377
This will merge the following topic branches: * builtin-dyn: Expansion of macros like __FILE__, __DATE__, ... must, contrary to usual macros, be done dynamically. This series improves support for them: - consider them as defined (like GCC do) - use table + method for their expansion (avoid useless compares) - add support for __INCLUDE_LEVEL__ & __BASE_FILE__ * builtin-predef: Add a function: predefine() which allow to directly add the definition of a simple macro (without args and with a single number or ident as definition). Also do the conversion of the concerned predefined macros and some cleanups. * builtin-overflow: Add support for builtins doing overflow checking. * has-builtin: Add support for the __has_builtin() macro. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-06-08builtin: add support for __has_builtin()Luc Van Oostenryck1-0/+43
Sparse has support for a subset of GCC's large collection of builtin functions. As for GCC, it's not easy to know which builtins are supported in which versions. clang has a good solution to this problem: it adds the checking macro __has_builtin(<name>) which evaluates to 1 if <name> is a builtin function supported by the compiler and 0 otherwise. It can be used like: #if __has_builtin(__builtin_clz) #define clz(x) __builtin_clz(x) #else ... #endif It's possible or probable that GCC will have this soon too: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66970 Add support for this __has_builtin() macro by extending the evaluation of preprocessor expressions very much like it is done to support defined(). Note: Some function-like builtin features, like __builtin_offset(), are considered as a kind of keyword/operator and processed as such. These are *not* considered as builtins by __has_builtin(). Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-06-08builtin: add support for __builtin_{add,sub,mul}_overflow(), ...Luc Van Oostenryck1-0/+246
It seems they will be used in the kernel so add them. Unlike __builtin_uadd_overflow() and friends, these don't take a fixed type and thus can't simply be declared but need their own evaluate() method to do the type checking. Note: of course, no expansion is done on them. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-06-08builtin: add testcase for builtin macro expansionLuc Van Oostenryck1-0/+17
Add a few silly testcases doing some expansion of a builtin macro. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-06-04dyn-macro: add real support for __BASE_FILE__Luc Van Oostenryck3-0/+23
There was some support for it but it was just a define that expanded to the fixed name "base_file.c". Implement the real thing by saving the input filename and replacing __BASE_FILE__ by it. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-06-04dyn-macro: add support for __INCLUDE_LEVEL__Luc Van Oostenryck3-0/+19
This macro, which is supported by GCC, wasn't yet by sparse. Add support for it. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-06-04dyn-macro: use a table to expand __DATE__, __FILE__, ...Luc Van Oostenryck1-1/+0
GCC consider these macros as being defined, sparse doesn't. Also sparse uses a sequence of comparisons, one for each of __DATE__, __FILE__, ..., which is not ideal. Fix this by defining and using a table to associate to the corresponding symbol a method doing the expansion. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-06-04dyn-macro: add testcase for __LINE__ & friendsLuc Van Oostenryck1-0/+30
GCC considers __LINE__, __FILE__, ... as being defined. Add a testcase for this. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-06-04Merge branches 'label-redef', 'goto-reserved', 'errmsg-builtin-pos', ↵Luc Van Oostenryck13-2/+436
'fix-builtin-expect' and 'int-const-expr' into tip
2018-06-04add test for integer-const-expr-nessLuc Van Oostenryck1-0/+85
This use Martin's awesome macro to test if sparse's notion of integer-const-expr is the same as GCC's. It test also that the result of this macro is itself a constant integer expression. Awesome-macro-by: Martin Uecker <Martin.Uecker@med.uni-goettingen.de> Test-originally-by: Rasmus Villemoes <linux@rasmusvillemoes.dk> Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-06-01give a position to end-of-inputLuc Van Oostenryck2-2/+12
If an error occurs at the end of the input, for example because a missing terminating ';' or '}', the error message is like: builtin:0:0: error: ... IOW, the stream name & position is not displayed because the because the current token is eof_token_entry which has no position. This can be confusing and for sure doesn't point where the error is. Fix this by giving to eof_token_entry the end-of-stream position. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-06-01fix crash on 'goto <reserved word>'Luc Van Oostenryck1-0/+12
On code like 'goto <some reserved code>', bind_symbol() reports an error and doesn't bind the label's ident to the goto's label symbol. However, at evaluation time, the ident is unconditionally dereferenced. Avoid the crash by checking for a null ident before dereferencing it. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-06-01fix typing of __builtin_expect()Luc Van Oostenryck1-0/+101
Typewisely, sparse process __builtin_expect() as: 1) returning 'int' 2) taking any type in first & second arg 3) returning exactly its first argument, silently, even if this conflicts with 1). but this doesn't match with how gcc declare it: long __builtin_expect(long, long); Fix this by giving the proper prototype to this builtin and removing the bogus 'returns an int'. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-05-27Merge branch 'vla-sizeof' into tipLuc Van Oostenryck6-0/+124
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-05-27vla-sizeof: add support for sizeof of VLAsLuc Van Oostenryck5-5/+0
While sparse can parse VLA, their size were left as 'undeterminated' (-1) and trying to use sizeof on VLAs resulted in a warning 'error: cannot size the expression'. Fix this by adding the needing code to evaluate the expressions corresponding to the sizeof of VLAs. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-05-27vla-sizeof: add test casesLuc Van Oostenryck6-0/+129
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-05-26label: avoid multiple definitionsLuc Van Oostenryck1-1/+0
If a label is defined several times, an error is issued about it. Nevertheless, the label is used as is and once the code is linearized several BB are created for the same label and this create inconsistencies. For example, some code will trigger assertion failures in rewrite_parent_branch(). Avoid the consistencies by ignoring redefined labels. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-05-26label: add testcase for label redefinitionLuc Van Oostenryck1-0/+18
Redefined labels create inconsistencies in BB processing. Add a testcase for it. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-05-26context: extra warning for __context__() & friendsLuc Van Oostenryck1-0/+17
Statements with an empty expression, like: __context__(); or __context__(x,); are silently accepted. Worse, since NULL expressions are usually ignored because it is assumed they have already been properly diagnosticated, no warnings of any kind are given at some later stage. Fix this by explicitly checking after empty expressions and emit an error message if needed. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-05-26context: stricter syntax for __context__ statementLuc Van Oostenryck1-3/+22
The expected syntax for the __context__ statement is: __context__(<expression>); or __context__(<context>, <expression>); but originally it was just: __context__ <expression> In other words the parenthesis were not needed and are still not needed when no context is given. One problem with the current way to parse these statements is that very few validation is done. For example, code like: __context__; is silently accepted, as is: __context__ a, b; which is of course not the same as: __context__(a,b); And code like: __context__(,1); results in a confusing error message: error: an expression is expected before ')' error: Expected ) in expression error: got , So, given that: * the kernel has always used the syntax with parenthesis, * the two arguments form requires the parenthesis and thus a function-like syntax use a more direct, robust and simpl parsing which enforce the function-like syntax for both forms. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-05-26context: fix crashes while parsing '__context__;' or '__context__(;'Luc Van Oostenryck1-0/+7
The expected syntax for the __context__ statement is: __context__(<inc/dec value>); or __context__(<context>, <inc/dec value>); The distinction between the two formats is made by checking if the expression is a PREOP with '(' as op and with an comma expression as inner expression. However, code like: __context__; or __context__(; crashes while trying to test the non-existing expression (after PREOP or after the comma expression). Fix this by testing if the expression is non-null before dereferencing it. Note: this fix has the merit to directly address the problem but doesn't let a diagnostic to be issued for the case __context__; which is considered as perfectly valid. The next patch will take care of this. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-05-26context: __context__(...) expect a constant expressionLuc Van Oostenryck1-0/+19
No check are done if the inc/dec value of context statements is effectively a compile-time integer value: '0' is silently used if it is not. Change that by using get_expression_value() when linearizing context statements (which has the added advantage to also slightly simplify the code). Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-05-26context: fix parsing of attribute 'context'Luc Van Oostenryck1-0/+40
Currently the parsing of the attribute 'context' is rather complex and uses a loop which allows 1, 2, 3 or more arguments. But the the real syntax is only correct for 2 or 3 arguments. Furthermore the parsing mixes calls to expect() with its own error reporting. This is a problem because if the error has first been reported by expect(), the returned token is 'bad_token' which has no position so you can have error logs like: test.c:1:43: error: Expected ( after context attribute test.c:1:43: error: got ) builtin:0:0: error: expected context input/output values But the 'builtin:0.0' should really be 'test.c:1.43' or, even better, there shouldn't be a double error reporting. Fix this by simplifying the parsing and only support 2 or 3 args. Also, make the error messages slightly more explicit about the nature of the error. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
2018-05-21Merge branch 'doc-sphinx' into tipLuc Van Oostenryck2-1/+178
2018-05-21autodoc: add autodoc tests in the testsuiteLuc Van Oostenryck2-1/+178
It's certainly worth to have some tests but to not slow down the testsuite and to not create a dependency on python this test need to be run explicitely with: ./test-suite doc/cdoc.cdoc Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>