aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
-rw-r--r--bits.h61
-rw-r--r--lib.h1
-rw-r--r--linearize.c20
-rw-r--r--show-parse.c2
-rw-r--r--simplify.c105
-rw-r--r--symbol.h8
-rw-r--r--validation/check_access-store.c21
-rw-r--r--validation/eval-typeof-vla.c26
-rw-r--r--validation/fp-ops.c2
-rw-r--r--validation/linear/cast-constant-to-float.c6
-rw-r--r--validation/linear/cast-constants.c20
-rw-r--r--validation/optim/bool-context-fp.c16
-rw-r--r--validation/optim/lsr-asr.c42
-rw-r--r--validation/optim/shift-big.c62
-rw-r--r--validation/optim/shift-shift.c149
-rw-r--r--validation/optim/zext-asr.c13
-rw-r--r--validation/shift-negative.c17
-rw-r--r--validation/shift-undef.c24
18 files changed, 529 insertions, 66 deletions
diff --git a/bits.h b/bits.h
new file mode 100644
index 00000000..c0dc952e
--- /dev/null
+++ b/bits.h
@@ -0,0 +1,61 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Helper functions for manipulation & testing of integer values
+ * like zero or sign-extensions.
+ *
+ * Copyright (C) 2017 Luc Van Oostenryck
+ *
+ */
+
+#ifndef BITS_H
+#define BITS_H
+
+static inline unsigned long long sign_bit(unsigned size)
+{
+ return 1ULL << (size - 1);
+}
+
+static inline unsigned long long sign_mask(unsigned size)
+{
+ unsigned long long sbit = sign_bit(size);
+ return sbit - 1;
+}
+
+static inline unsigned long long bits_mask(unsigned size)
+{
+ unsigned long long sbit = sign_bit(size);
+ return sbit | (sbit - 1);
+}
+
+
+static inline long long zero_extend(long long val, unsigned size)
+{
+ return val & bits_mask(size);
+}
+
+static inline long long sign_extend(long long val, unsigned size)
+{
+ if (val & sign_bit(size))
+ val |= ~sign_mask(size);
+ return val;
+}
+
+///
+// sign extend @val but only if exactly representable
+static inline long long sign_extend_safe(long long val, unsigned size)
+{
+ unsigned long long mask = bits_mask(size);
+ if (!(val & ~mask))
+ val = sign_extend(val, size);
+ return val;
+}
+
+static inline long long bits_extend(long long val, unsigned size, int is_signed)
+{
+ val = zero_extend(val, size);
+ if (is_signed)
+ val = sign_extend(val, size);
+ return val;
+}
+
+#endif
diff --git a/lib.h b/lib.h
index 7362111c..3cd8560a 100644
--- a/lib.h
+++ b/lib.h
@@ -34,6 +34,7 @@
#include "compat.h"
#include "ptrlist.h"
#include "utils.h"
+#include "bits.h"
#define DO_STRINGIFY(x) #x
#define STRINGIFY(x) DO_STRINGIFY(x)
diff --git a/linearize.c b/linearize.c
index c1e4498e..016b853b 100644
--- a/linearize.c
+++ b/linearize.c
@@ -368,7 +368,7 @@ const char *show_instruction(struct instruction *insn)
buf += sprintf(buf, "%lld", expr->value);
break;
case EXPR_FVALUE:
- buf += sprintf(buf, "%Lf", expr->fvalue);
+ buf += sprintf(buf, "%Le", expr->fvalue);
break;
case EXPR_STRING:
buf += sprintf(buf, "%.40s", show_string(expr->string));
@@ -386,7 +386,7 @@ const char *show_instruction(struct instruction *insn)
}
case OP_SETFVAL:
buf += sprintf(buf, "%s <- ", show_pseudo(insn->target));
- buf += sprintf(buf, "%Lf", insn->fvalue);
+ buf += sprintf(buf, "%Le", insn->fvalue);
break;
case OP_SWITCH: {
@@ -776,7 +776,6 @@ static void add_branch(struct entrypoint *ep, struct expression *expr, pseudo_t
}
}
-/* Dummy pseudo allocator */
pseudo_t alloc_pseudo(struct instruction *def)
{
static int nr = 0;
@@ -881,13 +880,8 @@ struct access_data {
struct symbol *type; // ctype
pseudo_t address; // pseudo containing address ..
unsigned int offset; // byte offset
- struct position pos;
};
-static void finish_address_gen(struct entrypoint *ep, struct access_data *ad)
-{
-}
-
static int linearize_simple_address(struct entrypoint *ep,
struct expression *addr,
struct access_data *ad)
@@ -930,7 +924,6 @@ static int linearize_address_gen(struct entrypoint *ep,
if (!ctype)
return 0;
- ad->pos = expr->pos;
ad->type = ctype;
if (expr->type == EXPR_PREOP && expr->op == '*')
return linearize_simple_address(ep, expr->unop, ad);
@@ -1105,7 +1098,6 @@ static pseudo_t linearize_access(struct entrypoint *ep, struct expression *expr)
if (!linearize_address_gen(ep, expr, &ad))
return VOID;
value = linearize_load_gen(ep, &ad);
- finish_address_gen(ep, &ad);
return value;
}
@@ -1126,7 +1118,6 @@ static pseudo_t linearize_inc_dec(struct entrypoint *ep, struct expression *expr
one = value_pseudo(expr->op_value);
new = add_binary_op(ep, expr->ctype, op, old, one);
linearize_store_gen(ep, new, &ad);
- finish_address_gen(ep, &ad);
return postop ? old : new;
}
@@ -1444,7 +1435,6 @@ static pseudo_t linearize_assignment(struct entrypoint *ep, struct expression *e
value = cast_pseudo(ep, dst, ctype, expr->ctype);
}
value = linearize_store_gen(ep, value, &ad);
- finish_address_gen(ep, &ad);
return value;
}
@@ -1755,7 +1745,6 @@ static pseudo_t linearize_position(struct entrypoint *ep, struct expression *pos
struct expression *init_expr = pos->init_expr;
ad->offset = pos->init_offset;
- ad->type = init_expr->ctype;
return linearize_initializer(ep, init_expr, ad);
}
@@ -1790,7 +1779,6 @@ static void linearize_argument(struct entrypoint *ep, struct symbol *arg, int nr
ad.type = arg;
ad.address = symbol_pseudo(ep, arg);
linearize_store_gen(ep, argument_pseudo(ep, nr), &ad);
- finish_address_gen(ep, &ad);
}
static pseudo_t linearize_expression(struct entrypoint *ep, struct expression *expr)
@@ -1894,15 +1882,12 @@ static pseudo_t linearize_one_symbol(struct entrypoint *ep, struct symbol *sym)
// only the existing fields need to be initialized.
// FIXME: this init the whole aggregate even if
// all fields arelater explicitely initialized.
- struct expression *expr = sym->initializer;
- ad.pos = expr->pos;
ad.type = sym;
ad.address = symbol_pseudo(ep, sym);
linearize_store_gen(ep, value_pseudo(0), &ad);
}
value = linearize_initializer(ep, sym->initializer, &ad);
- finish_address_gen(ep, &ad);
return value;
}
@@ -2002,7 +1987,6 @@ static void add_asm_output(struct entrypoint *ep, struct instruction *insn, stru
if (!expr || !linearize_address_gen(ep, expr, &ad))
return;
linearize_store_gen(ep, pseudo, &ad);
- finish_address_gen(ep, &ad);
rule = __alloc_asm_constraint(0);
rule->ident = ident;
rule->constraint = constraint;
diff --git a/show-parse.c b/show-parse.c
index 72d3f385..6328439c 100644
--- a/show-parse.c
+++ b/show-parse.c
@@ -987,7 +987,7 @@ static int show_fvalue(struct expression *expr)
int new = new_pseudo();
long double value = expr->fvalue;
- printf("\tmovf.%d\t\tv%d,$%Lf\n", expr->ctype->bit_size, new, value);
+ printf("\tmovf.%d\t\tv%d,$%Le\n", expr->ctype->bit_size, new, value);
return new;
}
diff --git a/simplify.c b/simplify.c
index 65ea87d9..250549da 100644
--- a/simplify.c
+++ b/simplify.c
@@ -546,31 +546,117 @@ undef:
return NULL;
}
+static long long check_shift_count(struct instruction *insn, unsigned long long uval)
+{
+ unsigned int size = insn->size;
+ long long sval = uval;
+
+ if (uval < size)
+ return uval;
+
+ 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;
+}
static int simplify_shift(struct instruction *insn, pseudo_t pseudo, long long value)
{
+ struct instruction *def;
+ unsigned long long nval;
unsigned int size;
+ pseudo_t src2;
if (!value)
return replace_with_pseudo(insn, pseudo);
+ value = check_shift_count(insn, value);
+ if (value < 0)
+ return 0;
size = insn->size;
- if (value >= size && !insn->tainted) {
- if (Wshift_count_overflow)
- warning(insn->pos, "shift by bigger than operand's width");
- insn->tainted = 1;
- }
switch (insn->opcode) {
case OP_ASR:
+ if (value >= size)
+ return 0;
+ if (pseudo->type != PSEUDO_REG)
+ break;
+ def = pseudo->def;
+ switch (def->opcode) {
+ case OP_LSR:
+ case OP_ASR:
+ if (def == insn) // cyclic DAG!
+ break;
+ src2 = def->src2;
+ if (src2->type != PSEUDO_VAL)
+ break;
+ nval = src2->value;
+ if (nval > insn->size || nval == 0)
+ break;
+ value += nval;
+ if (def->opcode == OP_LSR)
+ insn->opcode = OP_LSR;
+ else if (value >= size)
+ value = size - 1;
+ goto new_value;
+
+ case OP_ZEXT:
+ // transform:
+ // zext.N %t <- (O) %a
+ // asr.N %r <- %t, C
+ // into
+ // zext.N %t <- (O) %a
+ // lsr.N %r <- %t, C
+ insn->opcode = OP_LSR;
+ return REPEAT_CSE;
+ }
break;
case OP_LSR:
size = operand_size(insn, pseudo);
/* fall through */
case OP_SHL:
if (value >= size)
- return replace_with_pseudo(insn, value_pseudo(0));
+ goto zero;
+ if (pseudo->type != PSEUDO_REG)
+ break;
+ def = pseudo->def;
+ if (def->opcode == insn->opcode) {
+ if (def == insn) // cyclic DAG!
+ break;
+ src2 = def->src2;
+ if (src2->type != PSEUDO_VAL)
+ break;
+ nval = src2->value;
+ if (nval > insn->size)
+ break;
+ value += nval;
+ goto new_value;
+ }
+ break;
}
return 0;
+
+new_value:
+ if (value < size) {
+ insn->src2 = value_pseudo(value);
+ return replace_pseudo(insn, &insn->src1, pseudo->def->src1);
+ }
+zero:
+ return replace_with_pseudo(insn, value_pseudo(0));
}
static int simplify_mul_div(struct instruction *insn, long long value)
@@ -1363,6 +1449,13 @@ int simplify_instruction(struct instruction *insn)
return simplify_switch(insn);
case OP_RANGE:
return simplify_range(insn);
+ case OP_FADD:
+ case OP_FSUB:
+ case OP_FMUL:
+ case OP_FDIV:
+ if (dead_insn(insn, &insn->src1, &insn->src2, NULL))
+ return REPEAT_CSE;
+ break;
}
return 0;
}
diff --git a/symbol.h b/symbol.h
index 6b891edd..1cad6d05 100644
--- a/symbol.h
+++ b/symbol.h
@@ -453,6 +453,14 @@ static inline int get_sym_type(struct symbol *type)
return type->type;
}
+static inline long long extend_value(long long val, struct symbol *ctype)
+{
+ int is_signed = !(ctype->ctype.modifiers & MOD_UNSIGNED);
+ unsigned size = ctype->bit_size;
+
+ return bits_extend(val, size, is_signed);
+}
+
static inline struct symbol *lookup_keyword(struct ident *ident, enum namespace ns)
{
if (!ident->keyword)
diff --git a/validation/check_access-store.c b/validation/check_access-store.c
new file mode 100644
index 00000000..489507fd
--- /dev/null
+++ b/validation/check_access-store.c
@@ -0,0 +1,21 @@
+extern int a[1];
+
+static int r(void)
+{
+ return a[1];
+}
+
+static void w(void)
+{
+ a[1] = 2;
+}
+
+/*
+ * check-name: check_access-store
+ * check-known-to-fail
+ *
+ * check-error-start
+check_access-store.c:5:17: warning: invalid access past the end of 'a' (4 4)
+check_access-store.c:10:17: warning: invalid access past the end of 'a' (4 4)
+ * check-error-end
+ */
diff --git a/validation/eval-typeof-vla.c b/validation/eval-typeof-vla.c
new file mode 100644
index 00000000..56a9ec20
--- /dev/null
+++ b/validation/eval-typeof-vla.c
@@ -0,0 +1,26 @@
+extern int a[1];
+
+static int foo(int n)
+{
+ int i = 0;
+ int (*p)[1] = (typeof(++i, (int (*)[n])a)) &a;
+
+ (void) p;
+
+ return i;
+}
+
+/*
+ * check-name: eval-typeof-vla
+ * check-command: test-linearize -Wno-vla $file
+ * check-known-to-fail
+ *
+ * check-output-start
+foo:
+.L0:
+ <entry-point>
+ ret.32 $1
+
+
+ * check-output-end
+ */
diff --git a/validation/fp-ops.c b/validation/fp-ops.c
index 81f73384..96c246f8 100644
--- a/validation/fp-ops.c
+++ b/validation/fp-ops.c
@@ -48,7 +48,7 @@ fneg:
ftst:
.L10:
<entry-point>
- setfval.64 %r21 <- 0.000000
+ setfval.64 %r21 <- 0.000000e+00
fcmpoeq.1 %r23 <- %arg1, %r21
ret.1 %r23
diff --git a/validation/linear/cast-constant-to-float.c b/validation/linear/cast-constant-to-float.c
index ef7892f1..ac4eff0f 100644
--- a/validation/linear/cast-constant-to-float.c
+++ b/validation/linear/cast-constant-to-float.c
@@ -13,21 +13,21 @@ double f3(void) { return -1.0; }
f1:
.L0:
<entry-point>
- setfval.64 %r1 <- -1.000000
+ setfval.64 %r1 <- -1.000000e+00
ret.64 %r1
f2:
.L2:
<entry-point>
- setfval.64 %r3 <- -1.000000
+ setfval.64 %r3 <- -1.000000e+00
ret.64 %r3
f3:
.L4:
<entry-point>
- setfval.64 %r5 <- -1.000000
+ setfval.64 %r5 <- -1.000000e+00
ret.64 %r5
diff --git a/validation/linear/cast-constants.c b/validation/linear/cast-constants.c
index 9e200672..c1fdab41 100644
--- a/validation/linear/cast-constants.c
+++ b/validation/linear/cast-constants.c
@@ -286,70 +286,70 @@ vptr_2_iptr:
int_2_float:
.L76:
<entry-point>
- setfval.32 %r39 <- 123.000000
+ setfval.32 %r39 <- 1.230000e+02
ret.32 %r39
uint_2_float:
.L78:
<entry-point>
- setfval.32 %r41 <- 123.000000
+ setfval.32 %r41 <- 1.230000e+02
ret.32 %r41
long_2_float:
.L80:
<entry-point>
- setfval.32 %r43 <- 123.000000
+ setfval.32 %r43 <- 1.230000e+02
ret.32 %r43
ulong_2_float:
.L82:
<entry-point>
- setfval.32 %r45 <- 123.000000
+ setfval.32 %r45 <- 1.230000e+02
ret.32 %r45
double_2_float:
.L84:
<entry-point>
- setfval.32 %r47 <- 1.123000
+ setfval.32 %r47 <- 1.123000e+00
ret.32 %r47
int_2_double:
.L86:
<entry-point>
- setfval.64 %r49 <- 123.000000
+ setfval.64 %r49 <- 1.230000e+02
ret.64 %r49
uint_2_double:
.L88:
<entry-point>
- setfval.64 %r51 <- 123.000000
+ setfval.64 %r51 <- 1.230000e+02
ret.64 %r51
long_2_double:
.L90:
<entry-point>
- setfval.64 %r53 <- 123.000000
+ setfval.64 %r53 <- 1.230000e+02
ret.64 %r53
ulong_2_double:
.L92:
<entry-point>
- setfval.64 %r55 <- 123.000000
+ setfval.64 %r55 <- 1.230000e+02
ret.64 %r55
float_2_double:
.L94:
<entry-point>
- setfval.64 %r57 <- 1.123000
+ setfval.64 %r57 <- 1.123000e+00
ret.64 %r57
diff --git a/validation/optim/bool-context-fp.c b/validation/optim/bool-context-fp.c
index 50e96825..3bfc3343 100644
--- a/validation/optim/bool-context-fp.c
+++ b/validation/optim/bool-context-fp.c
@@ -18,7 +18,7 @@ int ifand(float a, float b) { return a && b; }
bfimp:
.L0:
<entry-point>
- setfval.32 %r2 <- 0.000000
+ setfval.32 %r2 <- 0.000000e+00
fcmpune.1 %r3 <- %arg1, %r2
ret.1 %r3
@@ -26,7 +26,7 @@ bfimp:
bfexp:
.L2:
<entry-point>
- setfval.32 %r6 <- 0.000000
+ setfval.32 %r6 <- 0.000000e+00
fcmpune.1 %r7 <- %arg1, %r6
ret.1 %r7
@@ -34,7 +34,7 @@ bfexp:
bfnot:
.L4:
<entry-point>
- setfval.32 %r10 <- 0.000000
+ setfval.32 %r10 <- 0.000000e+00
fcmpoeq.1 %r12 <- %arg1, %r10
ret.1 %r12
@@ -42,7 +42,7 @@ bfnot:
ifnot:
.L6:
<entry-point>
- setfval.32 %r15 <- 0.000000
+ setfval.32 %r15 <- 0.000000e+00
fcmpoeq.32 %r16 <- %arg1, %r15
ret.32 %r16
@@ -50,7 +50,7 @@ ifnot:
bfior:
.L8:
<entry-point>
- setfval.32 %r19 <- 0.000000
+ setfval.32 %r19 <- 0.000000e+00
fcmpune.1 %r20 <- %arg1, %r19
fcmpune.1 %r23 <- %arg2, %r19
or.1 %r24 <- %r20, %r23
@@ -61,7 +61,7 @@ bfior:
ifior:
.L10:
<entry-point>
- setfval.32 %r29 <- 0.000000
+ setfval.32 %r29 <- 0.000000e+00
fcmpune.1 %r30 <- %arg1, %r29
fcmpune.1 %r33 <- %arg2, %r29
or.1 %r34 <- %r30, %r33
@@ -72,7 +72,7 @@ ifior:
bfand:
.L12:
<entry-point>
- setfval.32 %r38 <- 0.000000
+ setfval.32 %r38 <- 0.000000e+00
fcmpune.1 %r39 <- %arg1, %r38
fcmpune.1 %r42 <- %arg2, %r38
and.1 %r43 <- %r39, %r42
@@ -83,7 +83,7 @@ bfand:
ifand:
.L14:
<entry-point>
- setfval.32 %r48 <- 0.000000
+ setfval.32 %r48 <- 0.000000e+00
fcmpune.1 %r49 <- %arg1, %r48
fcmpune.1 %r52 <- %arg2, %r48
and.1 %r53 <- %r49, %r52
diff --git a/validation/optim/lsr-asr.c b/validation/optim/lsr-asr.c
new file mode 100644
index 00000000..aee46940
--- /dev/null
+++ b/validation/optim/lsr-asr.c
@@ -0,0 +1,42 @@
+int lsrasr0(unsigned int x)
+{
+ return ((int) (x >> 15)) >> 15;
+}
+
+int lsrasr1(unsigned int x)
+{
+ return ((int) (x >> 16)) >> 15;
+}
+
+int lsrasr2(unsigned int x)
+{
+ return ((int) (x >> 16)) >> 16;
+}
+
+/*
+ * check-name: lsr-asr
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-start
+lsrasr0:
+.L0:
+ <entry-point>
+ lsr.32 %r3 <- %arg1, $30
+ ret.32 %r3
+
+
+lsrasr1:
+.L2:
+ <entry-point>
+ lsr.32 %r7 <- %arg1, $31
+ ret.32 %r7
+
+
+lsrasr2:
+.L4:
+ <entry-point>
+ ret.32 $0
+
+
+ * check-output-end
+ */
diff --git a/validation/optim/shift-big.c b/validation/optim/shift-big.c
index da65c5cd..84bcd2ce 100644
--- a/validation/optim/shift-big.c
+++ b/validation/optim/shift-big.c
@@ -1,20 +1,29 @@
typedef unsigned int u32;
typedef int s32;
-static u32 lsr32(u32 a) { return a >> 32; }
-static s32 asr32(s32 a) { return a >> 32; }
-static u32 shl32(u32 a) { return a << 32; }
+s32 asr31(s32 a) { return a >> 31; }
+s32 asr32(s32 a) { return a >> 32; }
+s32 asr33(s32 a) { return a >> 33; }
+
+u32 lsr31(u32 a) { return a >> 31; }
+u32 lsr32(u32 a) { return a >> 32; }
+u32 lsr33(u32 a) { return a >> 33; }
+
+u32 shl31(u32 a) { return a << 31; }
+u32 shl32(u32 a) { return a << 32; }
+u32 shl33(u32 a) { return a << 33; }
/*
* check-name: optim/shift-big.c
- * check-command: test-linearize -fnormalize-pseudos $file
+ * check-command: test-linearize -Wno-decl -m64 $file
*
* check-error-ignore
* check-output-start
-lsr32:
+asr31:
.L0:
<entry-point>
- ret.32 $0
+ asr.32 %r2 <- %arg1, $31
+ ret.32 %r2
asr32:
@@ -24,9 +33,48 @@ asr32:
ret.32 %r5
-shl32:
+asr33:
.L4:
<entry-point>
+ asr.32 %r8 <- %arg1, $33
+ ret.32 %r8
+
+
+lsr31:
+.L6:
+ <entry-point>
+ lsr.32 %r11 <- %arg1, $31
+ ret.32 %r11
+
+
+lsr32:
+.L8:
+ <entry-point>
+ ret.32 $0
+
+
+lsr33:
+.L10:
+ <entry-point>
+ ret.32 $0
+
+
+shl31:
+.L12:
+ <entry-point>
+ shl.32 %r20 <- %arg1, $31
+ ret.32 %r20
+
+
+shl32:
+.L14:
+ <entry-point>
+ ret.32 $0
+
+
+shl33:
+.L16:
+ <entry-point>
ret.32 $0
diff --git a/validation/optim/shift-shift.c b/validation/optim/shift-shift.c
new file mode 100644
index 00000000..12a4b7d4
--- /dev/null
+++ b/validation/optim/shift-shift.c
@@ -0,0 +1,149 @@
+unsigned int shl0(unsigned int x)
+{
+ return x << 15 << 15;
+}
+
+unsigned int shl1(unsigned int x)
+{
+ return x << 16 << 15;
+}
+
+unsigned int shl2(unsigned int x)
+{
+ return x << 16 << 16;
+}
+
+unsigned int shl3(unsigned int x)
+{
+ return x << 12 << 10 << 10;
+}
+
+
+unsigned int lsr0(unsigned int x)
+{
+ return x >> 15 >> 15;
+}
+
+unsigned int lsr1(unsigned int x)
+{
+ return x >> 16 >> 15;
+}
+
+unsigned int lsr2(unsigned int x)
+{
+ return x >> 16 >> 16;
+}
+
+unsigned int lsr3(unsigned int x)
+{
+ return x >> 12 >> 10 >> 10;
+}
+
+
+int asr0(int x)
+{
+ return x >> 15 >> 15;
+}
+
+int asr1(int x)
+{
+ return x >> 16 >> 15;
+}
+
+int asr2(int x)
+{
+ return x >> 16 >> 16;
+}
+
+int asr3(int x)
+{
+ return x >> 12 >> 10 >> 10;
+}
+
+/*
+ * check-name: shift-shift
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-start
+shl0:
+.L0:
+ <entry-point>
+ shl.32 %r3 <- %arg1, $30
+ ret.32 %r3
+
+
+shl1:
+.L2:
+ <entry-point>
+ shl.32 %r7 <- %arg1, $31
+ ret.32 %r7
+
+
+shl2:
+.L4:
+ <entry-point>
+ ret.32 $0
+
+
+shl3:
+.L6:
+ <entry-point>
+ ret.32 $0
+
+
+lsr0:
+.L8:
+ <entry-point>
+ lsr.32 %r20 <- %arg1, $30
+ ret.32 %r20
+
+
+lsr1:
+.L10:
+ <entry-point>
+ lsr.32 %r24 <- %arg1, $31
+ ret.32 %r24
+
+
+lsr2:
+.L12:
+ <entry-point>
+ ret.32 $0
+
+
+lsr3:
+.L14:
+ <entry-point>
+ ret.32 $0
+
+
+asr0:
+.L16:
+ <entry-point>
+ asr.32 %r37 <- %arg1, $30
+ ret.32 %r37
+
+
+asr1:
+.L18:
+ <entry-point>
+ asr.32 %r41 <- %arg1, $31
+ ret.32 %r41
+
+
+asr2:
+.L20:
+ <entry-point>
+ asr.32 %r45 <- %arg1, $31
+ ret.32 %r45
+
+
+asr3:
+.L22:
+ <entry-point>
+ asr.32 %r50 <- %arg1, $31
+ ret.32 %r50
+
+
+ * check-output-end
+ */
diff --git a/validation/optim/zext-asr.c b/validation/optim/zext-asr.c
new file mode 100644
index 00000000..5f235ad8
--- /dev/null
+++ b/validation/optim/zext-asr.c
@@ -0,0 +1,13 @@
+unsigned short foo(unsigned short a)
+{
+ return a >> 16;
+}
+
+/*
+ * check-name: zext-asr
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-contains: ret\\..*\\$0
+ * check-output-excludes: asr\\.
+ */
diff --git a/validation/shift-negative.c b/validation/shift-negative.c
new file mode 100644
index 00000000..fff5cf12
--- /dev/null
+++ b/validation/shift-negative.c
@@ -0,0 +1,17 @@
+unsigned int fn1(unsigned int a) { return a >> -1; }
+unsigned int fn2(unsigned int a) { return a >> ~0; }
+
+unsigned int fo1(unsigned int a) { return a >> ((a & 0) | -1); }
+unsigned int fo2(unsigned int a) { return a >> ((a & 0) ^ ~0); }
+
+/*
+ * check-name: shift-negative
+ * 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: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.c b/validation/shift-undef.c
index 54c8359b..4e94fa23 100644
--- a/validation/shift-undef.c
+++ b/validation/shift-undef.c
@@ -130,12 +130,12 @@ 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:21:29: warning: shift by bigger than operand's width
-shift-undef.c:22:29: warning: shift by bigger than operand's width
-shift-undef.c:23:29: warning: shift by bigger than operand's width
-shift-undef.c:24:29: warning: shift by bigger than operand's width
-shift-undef.c:25:29: warning: shift by bigger than operand's width
-shift-undef.c:26:29: warning: shift by bigger than operand's width
+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
@@ -154,11 +154,11 @@ 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 count is negative (-8)
shift-undef.c:49:30: warning: shift count is negative (-9)
-shift-undef.c:50:26: warning: shift by bigger than operand's width
-shift-undef.c:51:26: warning: shift by bigger than operand's width
-shift-undef.c:52:26: warning: shift by bigger than operand's width
-shift-undef.c:53:26: warning: shift by bigger than operand's width
-shift-undef.c:54:26: warning: shift by bigger than operand's width
-shift-undef.c:55:26: warning: shift by bigger than operand's width
+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 int
+shift-undef.c:52:26: warning: shift too big (111) for type int
+shift-undef.c:53:26: warning: shift count is negative (-10)
+shift-undef.c:54:26: warning: shift count is negative (-11)
+shift-undef.c:55:26: warning: shift count is negative (-12)
* check-error-end
*/