diff options
author | Luc Van Oostenryck <luc.vanoostenryck@gmail.com> | 2020-06-20 23:52:14 +0200 |
---|---|---|
committer | Luc Van Oostenryck <luc.vanoostenryck@gmail.com> | 2020-08-06 18:30:44 +0200 |
commit | 9aa1c8656be5fee7394cb242a80d7ea8eed32385 (patch) | |
tree | 499fd2c3b3154ac371873dae541798cab2e021c0 | |
parent | c2a5bd264187f42564b7055bce4cf72a7985cbc5 (diff) | |
download | sparse-9aa1c8656be5fee7394cb242a80d7ea8eed32385.tar.gz |
bad-shift: wait dead code elimination to warn about bad shifts
Sparse complains when a shift amount is too big for the size
of its operand or if it's negative.
However, it does this even for expressions that are never evaluated.
It's especially annoying in the kernel for type generic macros,
for example the ones in arch/*/include/asm/cmpxchg.h
So, remove all warnings done at expansion time and avoid any
simplifications of such expressions. Same, at linearization
and optimization time but in this case mark the instructions as
'tainted' to inhibit any further simplifications. Finally, at the
end of the optimization phase, warn for the tainted instructions.
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
-rw-r--r-- | expand.c | 18 | ||||
-rw-r--r-- | linearize.c | 44 | ||||
-rw-r--r-- | simplify.c | 20 | ||||
-rw-r--r-- | validation/expand/bad-shift.c | 8 | ||||
-rw-r--r-- | validation/optim/shift-big.c | 12 | ||||
-rw-r--r-- | validation/shift-negative.c | 4 | ||||
-rw-r--r-- | validation/shift-undef-long.c | 7 | ||||
-rw-r--r-- | validation/shift-undef.c | 48 |
8 files changed, 78 insertions, 83 deletions
@@ -170,22 +170,6 @@ Float: expr->type = EXPR_FVALUE; } -static void warn_shift_count(struct expression *expr, struct symbol *ctype, long long count) -{ - if (count < 0) { - if (!Wshift_count_negative) - return; - warning(expr->pos, "shift count is negative (%lld)", count); - return; - } - if (ctype->type == SYM_NODE) - ctype = ctype->ctype.base_type; - - if (!Wshift_count_overflow) - return; - warning(expr->pos, "shift too big (%llu) for type %s", count, show_typename(ctype)); -} - /* Return true if constant shift size is valid */ static bool check_shift_count(struct expression *expr, struct expression *right) { @@ -194,8 +178,6 @@ static bool check_shift_count(struct expression *expr, struct expression *right) if (count >= 0 && count < ctype->bit_size) return true; - if (!conservative) - warn_shift_count(expr, ctype, count); return false; } diff --git a/linearize.c b/linearize.c index 49274681..5a8e7497 100644 --- a/linearize.c +++ b/linearize.c @@ -2468,6 +2468,49 @@ static pseudo_t linearize_statement(struct entrypoint *ep, struct statement *stm return VOID; } +static void check_tainted_insn(struct instruction *insn) +{ + unsigned long long uval; + long long sval; + pseudo_t src2; + + switch (insn->opcode) { + case OP_DIVU: case OP_DIVS: + case OP_MODU: case OP_MODS: + if (insn->src2 == value_pseudo(0)) + warning(insn->pos, "divide by zero"); + break; + case OP_SHL: case OP_LSR: case OP_ASR: + src2 = insn->src2; + if (src2->type != PSEUDO_VAL) + break; + uval = src2->value; + if (uval < insn->size) + break; + sval = sign_extend(uval, insn->size); + if (Wshift_count_negative && sval < 0) + warning(insn->pos, "shift count is negative (%lld)", sval); + else if (Wshift_count_overflow) + warning(insn->pos, "shift too big (%llu) for type %s", uval, show_typename(insn->type)); + } +} + +/// +// issue warnings after all possible DCE +static void late_warnings(struct entrypoint *ep) +{ + struct basic_block *bb; + FOR_EACH_PTR(ep->bbs, bb) { + struct instruction *insn; + FOR_EACH_PTR(bb->insns, insn) { + if (!insn->bb) + continue; + if (insn->tainted) + check_tainted_insn(insn); + } END_FOR_EACH_PTR(insn); + } END_FOR_EACH_PTR(bb); +} + static struct entrypoint *linearize_fn(struct symbol *sym, struct symbol *base_type) { struct statement *stmt = base_type->stmt; @@ -2514,6 +2557,7 @@ static struct entrypoint *linearize_fn(struct symbol *sym, struct symbol *base_t add_one_insn(ep, ret); optimize(ep); + late_warnings(ep); return ep; } @@ -754,28 +754,18 @@ static long long check_shift_count(struct instruction *insn, unsigned long long unsigned int size = insn->size; long long sval = uval; + if (insn->tainted) + return -1; + if (uval < size) return uval; + insn->tainted = 1; sval = sign_extend_safe(sval, size); sval = sign_extend_safe(sval, bits_in_int); if (sval < 0) insn->src2 = value_pseudo(sval); - if (insn->tainted) - return sval; - - if (sval < 0 && Wshift_count_negative) - warning(insn->pos, "shift count is negative (%lld)", sval); - if (sval > 0 && Wshift_count_overflow) { - struct symbol *ctype = insn->type; - const char *tname; - if (ctype->type == SYM_NODE) - ctype = ctype->ctype.base_type; - tname = show_typename(ctype); - warning(insn->pos, "shift too big (%llu) for type %s", sval, tname); - } - insn->tainted = 1; - return sval; + return -1; } static int simplify_shift(struct instruction *insn, pseudo_t pseudo, long long value) diff --git a/validation/expand/bad-shift.c b/validation/expand/bad-shift.c index 22c4341f..b68866c2 100644 --- a/validation/expand/bad-shift.c +++ b/validation/expand/bad-shift.c @@ -56,9 +56,9 @@ rneg: * check-output-end * * check-error-start -expand/bad-shift.c:5:18: warning: shift too big (32) for type int -expand/bad-shift.c:10:18: warning: shift count is negative (-1) -expand/bad-shift.c:15:18: warning: shift too big (32) for type int -expand/bad-shift.c:20:18: warning: shift count is negative (-1) +expand/bad-shift.c:5:21: warning: shift too big (32) for type int +expand/bad-shift.c:10:21: warning: shift count is negative (-1) +expand/bad-shift.c:15:21: warning: shift too big (32) for type int +expand/bad-shift.c:20:21: warning: shift count is negative (-1) * check-error-end */ diff --git a/validation/optim/shift-big.c b/validation/optim/shift-big.c index 84bcd2ce..e7bf22fe 100644 --- a/validation/optim/shift-big.c +++ b/validation/optim/shift-big.c @@ -50,13 +50,15 @@ lsr31: lsr32: .L8: <entry-point> - ret.32 $0 + lsr.32 %r14 <- %arg1, $32 + ret.32 %r14 lsr33: .L10: <entry-point> - ret.32 $0 + lsr.32 %r17 <- %arg1, $33 + ret.32 %r17 shl31: @@ -69,13 +71,15 @@ shl31: shl32: .L14: <entry-point> - ret.32 $0 + shl.32 %r23 <- %arg1, $32 + ret.32 %r23 shl33: .L16: <entry-point> - ret.32 $0 + shl.32 %r26 <- %arg1, $33 + ret.32 %r26 * check-output-end diff --git a/validation/shift-negative.c b/validation/shift-negative.c index fff5cf12..6df02b18 100644 --- a/validation/shift-negative.c +++ b/validation/shift-negative.c @@ -9,8 +9,8 @@ unsigned int fo2(unsigned int a) { return a >> ((a & 0) ^ ~0); } * check-command: sparse -Wno-decl $file * * check-error-start -shift-negative.c:1:45: warning: shift count is negative (-1) -shift-negative.c:2:45: warning: shift count is negative (-1) +shift-negative.c:1:48: warning: shift count is negative (-1) +shift-negative.c:2:48: warning: shift count is negative (-1) shift-negative.c:4:59: warning: shift count is negative (-1) shift-negative.c:5:59: warning: shift count is negative (-1) * check-error-end diff --git a/validation/shift-undef-long.c b/validation/shift-undef-long.c index 32626743..985fe4c4 100644 --- a/validation/shift-undef-long.c +++ b/validation/shift-undef-long.c @@ -13,9 +13,8 @@ static unsigned very_big_shift(unsigned int a) * check-command: sparse -m64 $file * * check-error-start -shift-undef-long.c:4:16: warning: shift too big (4294967295) for type unsigned int -shift-undef-long.c:5:16: warning: shift too big (4294967296) for type unsigned int -shift-undef-long.c:6:16: warning: shift too big (4294967296) for type unsigned int -shift-undef-long.c:7:16: warning: shift count is negative (-4294967296) +shift-undef-long.c:4:25: warning: shift count is negative (-1) +shift-undef-long.c:5:47: warning: shift too big (4294967296) for type unsigned int +shift-undef-long.c:7:20: warning: shift count is negative (-4294967296) * check-error-end */ diff --git a/validation/shift-undef.c b/validation/shift-undef.c index 613c6b95..0c7541e9 100644 --- a/validation/shift-undef.c +++ b/validation/shift-undef.c @@ -112,48 +112,24 @@ void hw_write(u32 val) * check-command: sparse -Wno-decl $file * * check-error-start -shift-undef.c:3:15: warning: shift too big (100) for type int -shift-undef.c:4:15: warning: shift too big (101) for type unsigned int -shift-undef.c:5:15: warning: shift too big (102) for type unsigned int -shift-undef.c:6:15: warning: shift count is negative (-1) -shift-undef.c:7:15: warning: shift count is negative (-2) -shift-undef.c:8:15: warning: shift count is negative (-3) -shift-undef.c:9:25: warning: shift too big (103) for type int -shift-undef.c:10:25: warning: shift too big (104) for type unsigned int -shift-undef.c:11:25: warning: shift too big (105) for type unsigned int -shift-undef.c:12:25: warning: shift count is negative (-4) -shift-undef.c:13:25: warning: shift count is negative (-5) -shift-undef.c:14:25: warning: shift count is negative (-6) -shift-undef.c:15:30: warning: shift too big (106) for type int -shift-undef.c:16:30: warning: shift too big (107) for type unsigned int -shift-undef.c:17:30: warning: shift too big (108) for type unsigned int -shift-undef.c:18:30: warning: shift count is negative (-7) -shift-undef.c:19:30: warning: shift count is negative (-8) -shift-undef.c:20:30: warning: shift count is negative (-9) +shift-undef.c:3:18: warning: shift too big (100) for type int +shift-undef.c:4:18: warning: shift too big (101) for type unsigned int +shift-undef.c:5:18: warning: shift too big (102) for type unsigned int +shift-undef.c:6:19: warning: shift count is negative (-1) +shift-undef.c:7:19: warning: shift count is negative (-2) +shift-undef.c:8:19: warning: shift count is negative (-3) shift-undef.c:21:29: warning: shift too big (109) for type int shift-undef.c:22:29: warning: shift too big (110) for type unsigned int shift-undef.c:23:29: warning: shift too big (111) for type unsigned int shift-undef.c:24:29: warning: shift count is negative (-10) shift-undef.c:25:29: warning: shift count is negative (-11) shift-undef.c:26:29: warning: shift count is negative (-12) -shift-undef.c:32:11: warning: shift too big (100) for type int -shift-undef.c:33:11: warning: shift too big (101) for type unsigned int -shift-undef.c:34:11: warning: shift too big (102) for type unsigned int -shift-undef.c:35:11: warning: shift count is negative (-1) -shift-undef.c:36:11: warning: shift too big (4294967294) for type unsigned int -shift-undef.c:37:11: warning: shift too big (4294967293) for type unsigned int -shift-undef.c:38:25: warning: shift too big (103) for type int -shift-undef.c:39:25: warning: shift too big (104) for type unsigned int -shift-undef.c:40:25: warning: shift too big (105) for type unsigned int -shift-undef.c:41:25: warning: shift count is negative (-4) -shift-undef.c:42:25: warning: shift too big (4294967291) for type unsigned int -shift-undef.c:43:25: warning: shift too big (4294967290) for type unsigned int -shift-undef.c:44:30: warning: shift too big (106) for type int -shift-undef.c:45:30: warning: shift too big (107) for type unsigned int -shift-undef.c:46:30: warning: shift too big (108) for type unsigned int -shift-undef.c:47:30: warning: shift count is negative (-7) -shift-undef.c:48:30: warning: shift too big (4294967288) for type unsigned int -shift-undef.c:49:30: warning: shift too big (4294967287) for type unsigned int +shift-undef.c:32:15: warning: shift too big (100) for type int +shift-undef.c:33:15: warning: shift too big (101) for type unsigned int +shift-undef.c:34:15: warning: shift too big (102) for type unsigned int +shift-undef.c:35:16: warning: shift count is negative (-1) +shift-undef.c:36:16: warning: shift count is negative (-2) +shift-undef.c:37:16: warning: shift count is negative (-3) shift-undef.c:50:26: warning: shift too big (109) for type int shift-undef.c:51:26: warning: shift too big (110) for type unsigned int shift-undef.c:52:26: warning: shift too big (111) for type unsigned int |