aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
-rw-r--r--Documentation/api.rst5
-rwxr-xr-xDocumentation/sphinx/cdoc.py14
-rw-r--r--bits.h61
-rw-r--r--cse.c30
-rw-r--r--evaluate.c5
-rw-r--r--expand.c52
-rw-r--r--flow.c2
-rw-r--r--lib.c4
-rw-r--r--lib.h3
-rw-r--r--linearize.c170
-rw-r--r--linearize.h22
-rw-r--r--liveness.c9
-rw-r--r--ptrlist.c110
-rw-r--r--ptrlist.h5
-rw-r--r--show-parse.c2
-rw-r--r--simplify.c665
-rw-r--r--sparse-llvm.c4
-rw-r--r--sparse.112
-rw-r--r--symbol.h8
-rw-r--r--unssa.c7
-rw-r--r--validation/cast-kinds-check.c22
-rw-r--r--validation/cast-weirds.c39
-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/kill-switch.c17
-rw-r--r--validation/linear/bitfield-inc.c16
-rw-r--r--validation/linear/bitfield-preinc.c18
-rw-r--r--validation/linear/bitfield-size.c142
-rw-r--r--validation/linear/bitfield-store.c22
-rw-r--r--validation/linear/call-complex-pointer.c10
-rw-r--r--validation/linear/cast-constant-to-float.c6
-rw-r--r--validation/linear/cast-constants.c20
-rw-r--r--validation/linear/logical.c259
-rw-r--r--validation/loop-linearization.c44
-rw-r--r--validation/optim/and-extend.c27
-rw-r--r--validation/optim/and-extendx.c24
-rw-r--r--validation/optim/and-lsr.c15
-rw-r--r--validation/optim/and-or-bf0.c24
-rw-r--r--validation/optim/and-or-bf1.c18
-rw-r--r--validation/optim/and-or-bf2.c27
-rw-r--r--validation/optim/and-or-bfs.c23
-rw-r--r--validation/optim/and-or-bfu.c21
-rw-r--r--validation/optim/and-or-bfx.c18
-rw-r--r--validation/optim/and-or-constant0.c12
-rw-r--r--validation/optim/and-or-constant1.c14
-rw-r--r--validation/optim/and-or-constant2.c13
-rw-r--r--validation/optim/and-or-crash.c5
-rw-r--r--validation/optim/and-or-lsr0.c13
-rw-r--r--validation/optim/and-or-lsr1.c13
-rw-r--r--validation/optim/and-or-lsr2.c13
-rw-r--r--validation/optim/and-or-lsrx.c13
-rw-r--r--validation/optim/and-or-mask.c18
-rw-r--r--validation/optim/and-or-mask0.c12
-rw-r--r--validation/optim/and-or-mask1.c13
-rw-r--r--validation/optim/and-or-mask2.c13
-rw-r--r--validation/optim/and-or-mask3s.c25
-rw-r--r--validation/optim/and-or-mask3u.c25
-rw-r--r--validation/optim/and-or-mask4.c25
-rw-r--r--validation/optim/and-or-maskx.c13
-rw-r--r--validation/optim/and-or-shl0.c12
-rw-r--r--validation/optim/and-or-shl1.c13
-rw-r--r--validation/optim/and-or-shl2.c13
-rw-r--r--validation/optim/and-or-shlx.c13
-rw-r--r--validation/optim/and-or-trunc0.c13
-rw-r--r--validation/optim/and-or-trunc1.c12
-rw-r--r--validation/optim/and-or-trunc2.c13
-rw-r--r--validation/optim/and-or-truncx.c13
-rw-r--r--validation/optim/and-trunc.c20
-rw-r--r--validation/optim/bitfield-store-load0.c44
-rw-r--r--validation/optim/bitfield-store-loads.c23
-rw-r--r--validation/optim/bitfield-store-loadu.c21
-rw-r--r--validation/optim/bool-context-fp.c22
-rw-r--r--validation/optim/bool-sext-test.c12
-rw-r--r--validation/optim/bool-simplify.c15
-rw-r--r--validation/optim/bool-simplify2.c50
-rw-r--r--validation/optim/bool-zext-test.c12
-rw-r--r--validation/optim/call-inlined.c4
-rw-r--r--validation/optim/cast-kinds.c (renamed from validation/linear/cast-kinds.c)24
-rw-r--r--validation/optim/cast-nop.c18
-rw-r--r--validation/optim/cse-cmp-next.c15
-rw-r--r--validation/optim/ext-trunc-greater.c17
-rw-r--r--validation/optim/ext-trunc-same.c19
-rw-r--r--validation/optim/ext-trunc-smaller.c18
-rw-r--r--validation/optim/lsr-and0.c13
-rw-r--r--validation/optim/lsr-and1.c18
-rw-r--r--validation/optim/lsr-asr.c42
-rw-r--r--validation/optim/lsr-shl0.c14
-rw-r--r--validation/optim/mask-lsr.c14
-rw-r--r--validation/optim/mask-out.c12
-rw-r--r--validation/optim/mask1-setne0.c28
-rw-r--r--validation/optim/or-and-constant1.c29
-rw-r--r--validation/optim/setcc-mask.c18
-rw-r--r--validation/optim/setne0-sext.c9
-rw-r--r--validation/optim/setne0-trunc.c9
-rw-r--r--validation/optim/setne0-zext.c9
-rw-r--r--validation/optim/sext-sext.c12
-rw-r--r--validation/optim/sext.c15
-rw-r--r--validation/optim/sh-or-and0.c20
-rw-r--r--validation/optim/sh-or-and1.c20
-rw-r--r--validation/optim/sh-or-and2.c21
-rw-r--r--validation/optim/shift-big.c82
-rw-r--r--validation/optim/shift-shift.c149
-rw-r--r--validation/optim/shift-zext.c12
-rw-r--r--validation/optim/shl-and0.c13
-rw-r--r--validation/optim/shl-and1.c18
-rw-r--r--validation/optim/shl-lsr0.c14
-rw-r--r--validation/optim/trunc-mask-zext.c13
-rw-r--r--validation/optim/trunc-or-shl.c13
-rw-r--r--validation/optim/trunc-seteq0.c18
-rw-r--r--validation/optim/trunc-setne0.c20
-rw-r--r--validation/optim/trunc-trunc.c12
-rw-r--r--validation/optim/zext-and.c12
-rw-r--r--validation/optim/zext-and1.c12
-rw-r--r--validation/optim/zext-asr.c13
-rw-r--r--validation/optim/zext-sext.c13
-rw-r--r--validation/optim/zext-zext.c13
-rw-r--r--validation/shift-negative.c17
-rw-r--r--validation/shift-undef-long.c21
-rw-r--r--validation/shift-undef.c164
120 files changed, 3250 insertions, 409 deletions
diff --git a/Documentation/api.rst b/Documentation/api.rst
index 1270551c..cb8a0982 100644
--- a/Documentation/api.rst
+++ b/Documentation/api.rst
@@ -20,3 +20,8 @@ Typing
~~~~~~
.. c:autodoc:: evaluate.h
+
+Optimization
+~~~~~~~~~~~~
+
+.. c:autodoc:: simplify.c
diff --git a/Documentation/sphinx/cdoc.py b/Documentation/sphinx/cdoc.py
index 2718c86a..318e9b23 100755
--- a/Documentation/sphinx/cdoc.py
+++ b/Documentation/sphinx/cdoc.py
@@ -212,12 +212,14 @@ def convert_to_rst(info):
lst.append((n, l))
if 'desc' in info:
desc = info['desc']
- n = desc[0]
- r = ''
- for l in desc[1:]:
- r += l + '\n'
- lst.append((n, r))
- lst.append((n+1, '\n'))
+ n = desc[0] - 1
+ desc.append('')
+ for i in range(1, len(desc)):
+ l = desc[i]
+ lst.append((n+i, l))
+ # auto add a blank line for a list
+ if re.search(r":$", desc[i]) and re.search(r"\S", desc[i+1]):
+ lst.append((n+i, ''))
elif typ == 'func':
(n, l) = info['func']
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/cse.c b/cse.c
index 848ac512..511ac88a 100644
--- a/cse.c
+++ b/cse.c
@@ -94,14 +94,12 @@ void cse_collect(struct instruction *insn)
case OP_TRUNC:
case OP_PTRCAST:
case OP_UTPTR: case OP_PTRTU:
- /*
- * This is crap! Many "orig_types" are the
- * same as far as casts go, we should generate
- * some kind of "type hash" that is identical
- * for identical casts
- */
- hash += hashval(insn->orig_type);
+ if (!insn->orig_type || insn->orig_type->bit_size < 0)
+ return;
hash += hashval(insn->src);
+
+ // Note: see corresponding line in insn_compare()
+ hash += hashval(insn->orig_type->bit_size);
break;
/* Other */
@@ -164,6 +162,7 @@ static int insn_compare(const void *_i1, const void *_i2)
{
const struct instruction *i1 = _i1;
const struct instruction *i2 = _i2;
+ int size1, size2;
int diff;
if (i1->opcode != i2->opcode)
@@ -241,13 +240,18 @@ static int insn_compare(const void *_i1, const void *_i2)
case OP_TRUNC:
case OP_PTRCAST:
case OP_UTPTR: case OP_PTRTU:
- /*
- * This is crap! See the comments on hashing.
- */
- if (i1->orig_type != i2->orig_type)
- return i1->orig_type < i2->orig_type ? -1 : 1;
if (i1->src != i2->src)
return i1->src < i2->src ? -1 : 1;
+
+ // Note: if it can be guaranted that identical ->src
+ // implies identical orig_type->bit_size, then this
+ // test and the hashing of the original size in
+ // cse_collect() are not needed.
+ // It must be generaly true but it isn't guaranted (yet).
+ size1 = i1->orig_type->bit_size;
+ size2 = i2->orig_type->bit_size;
+ if (size1 != size2)
+ return size1 < size2 ? -1 : 1;
break;
default:
@@ -359,6 +363,8 @@ static struct instruction * try_to_cse(struct entrypoint *ep, struct instruction
i1 = cse_one_instruction(i2, i1);
remove_instruction(&b1->insns, i1, 1);
add_instruction_to_end(i1, common);
+ } else {
+ i1 = i2;
}
return i1;
diff --git a/evaluate.c b/evaluate.c
index 194b9721..7ab7db81 100644
--- a/evaluate.c
+++ b/evaluate.c
@@ -1325,6 +1325,11 @@ static int evaluate_assign_op(struct expression *expr)
goto Cast;
if (!restricted_value(expr->right, t))
return 1;
+ } else if (op == SPECIAL_SHR_ASSIGN || op == SPECIAL_SHL_ASSIGN) {
+ // shifts do integer promotions, but that's it.
+ unrestrict(expr->right, sclass, &s);
+ target = integer_promotion(s);
+ goto Cast;
} else if (!(sclass & TYPE_RESTRICT))
goto usual;
/* source and target would better be identical restricted */
diff --git a/expand.c b/expand.c
index cd05ce11..45e6f95e 100644
--- a/expand.c
+++ b/expand.c
@@ -158,11 +158,25 @@ Float:
expr->type = EXPR_FVALUE;
}
-static int check_shift_count(struct expression *expr, struct symbol *ctype, unsigned int count)
+static void check_shift_count(struct expression *expr, struct expression *right)
{
- warning(expr->pos, "shift too big (%u) for type %s", count, show_typename(ctype));
- count &= ctype->bit_size-1;
- return count;
+ struct symbol *ctype = expr->ctype;
+ long long count = get_longlong(right);
+
+ if (count < 0) {
+ if (!Wshift_count_negative)
+ return;
+ warning(expr->pos, "shift count is negative (%lld)", count);
+ return;
+ }
+ if (count < ctype->bit_size)
+ 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));
}
/*
@@ -183,12 +197,9 @@ static int simplify_int_binop(struct expression *expr, struct symbol *ctype)
return 0;
r = right->value;
if (expr->op == SPECIAL_LEFTSHIFT || expr->op == SPECIAL_RIGHTSHIFT) {
- if (r >= ctype->bit_size) {
- if (conservative)
- return 0;
- r = check_shift_count(expr, ctype, r);
- right->value = r;
- }
+ if (conservative)
+ return 0;
+ check_shift_count(expr, right);
}
if (left->type != EXPR_VALUE)
return 0;
@@ -559,11 +570,30 @@ static int expand_conditional(struct expression *expr)
return cost + cond_cost + BRANCH_COST;
}
-
+
+static void check_assignment(struct expression *expr)
+{
+ struct expression *right;
+
+ switch (expr->op) {
+ case SPECIAL_SHL_ASSIGN:
+ case SPECIAL_SHR_ASSIGN:
+ right = expr->right;
+ if (right->type != EXPR_VALUE)
+ break;
+ check_shift_count(expr, right);
+ break;
+ }
+ return;
+}
+
static int expand_assignment(struct expression *expr)
{
expand_expression(expr->left);
expand_expression(expr->right);
+
+ if (!conservative)
+ check_assignment(expr);
return SIDE_EFFECTS;
}
diff --git a/flow.c b/flow.c
index c6d68532..8bdd5984 100644
--- a/flow.c
+++ b/flow.c
@@ -278,7 +278,7 @@ int simplify_flow(struct entrypoint *ep)
static inline void concat_user_list(struct pseudo_user_list *src, struct pseudo_user_list **dst)
{
- concat_ptr_list((struct ptr_list *)src, (struct ptr_list **)dst);
+ copy_ptr_list((struct ptr_list **)dst, (struct ptr_list *)src);
}
void convert_instruction_target(struct instruction *insn, pseudo_t src)
diff --git a/lib.c b/lib.c
index 308f8f69..2d87b567 100644
--- a/lib.c
+++ b/lib.c
@@ -274,6 +274,8 @@ int Wpointer_to_int_cast = 1;
int Wptr_subtraction_blows = 0;
int Wreturn_void = 0;
int Wshadow = 0;
+int Wshift_count_negative = 1;
+int Wshift_count_overflow = 1;
int Wsizeof_bool = 0;
int Wtautological_compare = 0;
int Wtransparent_union = 0;
@@ -701,6 +703,8 @@ static const struct flag warnings[] = {
{ "ptr-subtraction-blows", &Wptr_subtraction_blows },
{ "return-void", &Wreturn_void },
{ "shadow", &Wshadow },
+ { "shift-count-negative", &Wshift_count_negative },
+ { "shift-count-overflow", &Wshift_count_overflow },
{ "sizeof-bool", &Wsizeof_bool },
{ "pointer-arith", &Wpointer_arith },
{ "sparse-error", &Wsparse_error },
diff --git a/lib.h b/lib.h
index b0453bb6..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)
@@ -163,6 +164,8 @@ extern int Wpointer_to_int_cast;
extern int Wptr_subtraction_blows;
extern int Wreturn_void;
extern int Wshadow;
+extern int Wshift_count_negative;
+extern int Wshift_count_overflow;
extern int Wsizeof_bool;
extern int Wtautological_compare;
extern int Wtransparent_union;
diff --git a/linearize.c b/linearize.c
index 194afe66..2e9a5638 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;
@@ -879,15 +878,11 @@ pseudo_t alloc_phi(struct basic_block *source, pseudo_t pseudo, struct symbol *t
*/
struct access_data {
struct symbol *type; // ctype
+ struct symbol *btype; // base type of bitfields
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 +925,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);
@@ -941,14 +935,13 @@ static int linearize_address_gen(struct entrypoint *ep,
static pseudo_t add_load(struct entrypoint *ep, struct access_data *ad)
{
- struct symbol *btype = bitfield_base_type(ad->type);
struct instruction *insn;
pseudo_t new;
if (!ep->active)
return VOID;
- insn = alloc_typed_instruction(OP_LOAD, btype);
+ insn = alloc_typed_instruction(OP_LOAD, ad->btype);
new = alloc_pseudo(insn);
insn->target = new;
@@ -966,42 +959,69 @@ static void add_store(struct entrypoint *ep, struct access_data *ad, pseudo_t va
if (!bb)
return;
- store = alloc_typed_instruction(OP_STORE, bitfield_base_type(ad->type));
+ store = alloc_typed_instruction(OP_STORE, ad->btype);
store->offset = ad->offset;
use_pseudo(store, value, &store->target);
use_pseudo(store, ad->address, &store->src);
add_one_insn(ep, store);
}
+static pseudo_t linearize_bitfield_insert(struct entrypoint *ep,
+ pseudo_t ori, pseudo_t val, struct symbol *ctype, struct symbol *btype)
+{
+ unsigned int shift = ctype->bit_offset;
+ unsigned int size = ctype->bit_size;
+ unsigned long long mask = ((1ULL << size) - 1);
+ unsigned long long smask= bits_mask(btype->bit_size);
+
+ val = add_cast(ep, btype, ctype, OP_ZEXT, val);
+ if (shift) {
+ val = add_binary_op(ep, btype, OP_SHL, val, value_pseudo(shift));
+ mask <<= shift;
+ }
+ ori = add_binary_op(ep, btype, OP_AND, ori, value_pseudo(~mask & smask));
+ val = add_binary_op(ep, btype, OP_OR, ori, val);
+
+ return val;
+}
+
static pseudo_t linearize_store_gen(struct entrypoint *ep,
pseudo_t value,
struct access_data *ad)
{
struct symbol *ctype = ad->type;
- struct symbol *btype = bitfield_base_type(ctype);
+ struct symbol *btype;
pseudo_t store = value;
if (!ep->active)
return VOID;
+ btype = ad->btype = bitfield_base_type(ctype);
if (type_size(btype) != type_size(ctype)) {
- unsigned int shift = ctype->bit_offset;
- unsigned int size = ctype->bit_size;
pseudo_t orig = add_load(ep, ad);
- unsigned long long mask = (1ULL << size) - 1;
-
- store = add_cast(ep, btype, ctype, OP_ZEXT, store);
- if (shift) {
- store = add_binary_op(ep, btype, OP_SHL, store, value_pseudo(shift));
- mask <<= shift;
- }
- orig = add_binary_op(ep, btype, OP_AND, orig, value_pseudo(~mask));
- store = add_binary_op(ep, btype, OP_OR, orig, store);
+ store = linearize_bitfield_insert(ep, orig, value, ctype, btype);
}
add_store(ep, ad, store);
return value;
}
+static void taint_undefined_behaviour(struct instruction *insn)
+{
+ pseudo_t src2;
+
+ switch (insn->opcode) {
+ case OP_LSR:
+ case OP_ASR:
+ case OP_SHL:
+ src2 = insn->src2;
+ if (src2->type != PSEUDO_VAL)
+ break;
+ if ((unsigned long long)src2->value >= insn->size)
+ insn->tainted = 1;
+ break;
+ }
+}
+
static pseudo_t add_binary_op(struct entrypoint *ep, struct symbol *ctype, int op, pseudo_t left, pseudo_t right)
{
struct instruction *insn = alloc_typed_instruction(op, ctype);
@@ -1044,23 +1064,32 @@ static pseudo_t add_symbol_address(struct entrypoint *ep, struct symbol *sym)
return target;
}
+static pseudo_t linearize_bitfield_extract(struct entrypoint *ep,
+ pseudo_t val, struct symbol *ctype, struct symbol *btype)
+{
+ unsigned int off = ctype->bit_offset;
+
+ if (off) {
+ pseudo_t shift = value_pseudo(off);
+ val = add_binary_op(ep, btype, OP_LSR, val, shift);
+ }
+ val = cast_pseudo(ep, val, btype, ctype);
+ return val;
+}
+
static pseudo_t linearize_load_gen(struct entrypoint *ep, struct access_data *ad)
{
struct symbol *ctype = ad->type;
- struct symbol *btype = bitfield_base_type(ctype);
+ struct symbol *btype;
pseudo_t new;
if (!ep->active)
return VOID;
+ btype = ad->btype = bitfield_base_type(ctype);
new = add_load(ep, ad);
- if (ctype->bit_offset) {
- pseudo_t shift = value_pseudo(ctype->bit_offset);
- pseudo_t newval = add_binary_op(ep, btype, OP_LSR, new, shift);
- new = newval;
- }
if (ctype->bit_size != type_size(btype))
- new = cast_pseudo(ep, new, btype, ctype);
+ new = linearize_bitfield_extract(ep, new, ctype, btype);
return new;
}
@@ -1072,14 +1101,13 @@ 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;
}
static pseudo_t linearize_inc_dec(struct entrypoint *ep, struct expression *expr, int postop)
{
struct access_data ad = { NULL, };
- pseudo_t old, new, one;
+ pseudo_t old, new, one;
int op = expr->op == SPECIAL_INCREMENT ? OP_ADD : OP_SUB;
if (!linearize_address_gen(ep, expr->unop, &ad))
@@ -1091,9 +1119,12 @@ static pseudo_t linearize_inc_dec(struct entrypoint *ep, struct expression *expr
one = add_setfval(ep, expr->ctype, expr->op_value);
else
one = value_pseudo(expr->op_value);
- new = add_binary_op(ep, expr->ctype, op, old, one);
+ if (ad.btype != ad.type)
+ old = cast_pseudo(ep, old, ad.type, ad.btype);
+ new = add_binary_op(ep, ad.btype, op, old, one);
+ if (ad.btype != ad.type)
+ new = cast_pseudo(ep, new, ad.btype, ad.type);
linearize_store_gen(ep, new, &ad);
- finish_address_gen(ep, &ad);
return postop ? old : new;
}
@@ -1289,6 +1320,7 @@ static int get_cast_opcode(struct symbol *dst, struct symbol *src)
static pseudo_t cast_pseudo(struct entrypoint *ep, pseudo_t src, struct symbol *from, struct symbol *to)
{
+ const struct position pos = current_pos;
pseudo_t result;
struct instruction *insn;
int opcode;
@@ -1309,7 +1341,7 @@ static pseudo_t cast_pseudo(struct entrypoint *ep, pseudo_t src, struct symbol *
if (src == value_pseudo(0))
break;
if (Wint_to_pointer_cast)
- warning(to->pos, "non size-preserving integer to pointer cast");
+ warning(pos, "non size-preserving integer to pointer cast");
src = cast_pseudo(ep, src, from, size_t_ctype);
from = size_t_ctype;
break;
@@ -1317,7 +1349,7 @@ static pseudo_t cast_pseudo(struct entrypoint *ep, pseudo_t src, struct symbol *
if (from->bit_size == to->bit_size)
break;
if (Wpointer_to_int_cast)
- warning(to->pos, "non size-preserving pointer to integer cast");
+ warning(pos, "non size-preserving pointer to integer cast");
src = cast_pseudo(ep, src, from, size_t_ctype);
return cast_pseudo(ep, src, size_t_ctype, to);
case OP_BADOP:
@@ -1352,8 +1384,12 @@ static inline pseudo_t add_convert_to_bool(struct entrypoint *ep, pseudo_t src,
pseudo_t zero;
int op;
+ if (!type || src == VOID)
+ return VOID;
if (is_bool_type(type))
return src;
+ if (src->type == PSEUDO_VAL && (src->value == 0 || src->value == 1))
+ return src;
if (is_float_type(type)) {
zero = add_setfval(ep, type, 0.0);
op = map_opcode(OP_SET_NE, type);
@@ -1407,10 +1443,10 @@ static pseudo_t linearize_assignment(struct entrypoint *ep, struct expression *e
oldvalue = cast_pseudo(ep, oldvalue, target->ctype, ctype);
opcode = map_opcode(op_trans[expr->op - SPECIAL_BASE], ctype);
dst = add_binary_op(ep, ctype, opcode, oldvalue, value);
+ taint_undefined_behaviour(dst->def);
value = cast_pseudo(ep, dst, ctype, expr->ctype);
}
value = linearize_store_gen(ep, value, &ad);
- finish_address_gen(ep, &ad);
return value;
}
@@ -1512,6 +1548,7 @@ static pseudo_t linearize_binop(struct entrypoint *ep, struct expression *expr)
src2 = linearize_expression(ep, expr->right);
op = map_opcode(opcode[expr->op], expr->ctype);
dst = add_binary_op(ep, expr->ctype, op, src1, src2);
+ taint_undefined_behaviour(dst->def);
return dst;
}
@@ -1617,13 +1654,39 @@ static pseudo_t linearize_conditional(struct entrypoint *ep, struct expression *
static pseudo_t linearize_logical(struct entrypoint *ep, struct expression *expr)
{
- struct expression *shortcut;
+ struct basic_block *other, *merge;
+ pseudo_t phi1, phi2;
- shortcut = alloc_const_expression(expr->pos, expr->op == SPECIAL_LOGICAL_OR);
- shortcut->ctype = expr->ctype;
- if (expr->op == SPECIAL_LOGICAL_OR)
- return linearize_conditional(ep, expr, expr->left, shortcut, expr->right);
- return linearize_conditional(ep, expr, expr->left, expr->right, shortcut);
+ if (!ep->active || !expr->left || !expr->right)
+ return VOID;
+
+ other = alloc_basic_block(ep, expr->right->pos);
+ merge = alloc_basic_block(ep, expr->pos);
+
+ if (expr->op == SPECIAL_LOGICAL_OR) {
+ pseudo_t src2;
+
+ phi1 = alloc_phi(ep->active, value_pseudo(1), expr->ctype);
+ linearize_cond_branch(ep, expr->left, merge, other);
+
+ set_activeblock(ep, other);
+ src2 = linearize_expression_to_bool(ep, expr->right);
+ src2 = cast_pseudo(ep, src2, &bool_ctype, expr->ctype);
+ phi2 = alloc_phi(ep->active, src2, expr->ctype);
+ } else {
+ pseudo_t src1;
+
+ phi2 = alloc_phi(ep->active, value_pseudo(0), expr->ctype);
+ linearize_cond_branch(ep, expr->left, other, merge);
+
+ set_activeblock(ep, other);
+ src1 = linearize_expression_to_bool(ep, expr->right);
+ src1 = cast_pseudo(ep, src1, &bool_ctype, expr->ctype);
+ phi1 = alloc_phi(ep->active, src1, expr->ctype);
+ }
+
+ set_activeblock(ep, merge);
+ return add_join_conditional(ep, expr, phi1, phi2);
}
static pseudo_t linearize_compare(struct entrypoint *ep, struct expression *expr)
@@ -1679,7 +1742,7 @@ static pseudo_t linearize_cond_branch(struct entrypoint *ep, struct expression *
return linearize_cond_branch(ep, expr->unop, bb_false, bb_true);
/* fall through */
default: {
- cond = linearize_expression(ep, expr);
+ cond = linearize_expression_to_bool(ep, expr);
add_branch(ep, expr, cond, bb_true, bb_false);
return VOID;
@@ -1715,15 +1778,6 @@ static pseudo_t linearize_cast(struct entrypoint *ep, struct expression *expr)
return cast_pseudo(ep, src, orig->ctype, expr->ctype);
}
-static pseudo_t linearize_position(struct entrypoint *ep, struct expression *pos, struct access_data *ad)
-{
- struct expression *init_expr = pos->init_expr;
-
- ad->offset = pos->init_offset;
- ad->type = init_expr->ctype;
- return linearize_initializer(ep, init_expr, ad);
-}
-
static pseudo_t linearize_initializer(struct entrypoint *ep, struct expression *initializer, struct access_data *ad)
{
switch (initializer->type) {
@@ -1735,7 +1789,8 @@ static pseudo_t linearize_initializer(struct entrypoint *ep, struct expression *
break;
}
case EXPR_POS:
- linearize_position(ep, initializer, ad);
+ ad->offset = initializer->init_offset;
+ linearize_initializer(ep, initializer->init_expr, ad);
break;
default: {
pseudo_t value = linearize_expression(ep, initializer);
@@ -1755,7 +1810,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)
@@ -1859,15 +1913,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;
}
@@ -1967,7 +2018,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/linearize.h b/linearize.h
index 092e1ac2..1184df98 100644
--- a/linearize.h
+++ b/linearize.h
@@ -303,6 +303,11 @@ static inline int remove_pseudo(struct pseudo_list **list, pseudo_t pseudo)
return delete_ptr_list_entry((struct ptr_list **)list, pseudo, 0) != 0;
}
+static inline int pseudo_in_list(struct pseudo_list *list, pseudo_t pseudo)
+{
+ return lookup_ptr_list_entry((struct ptr_list *)list, pseudo);
+}
+
static inline int bb_terminated(struct basic_block *bb)
{
struct instruction *insn;
@@ -333,9 +338,24 @@ static inline int pseudo_user_list_size(struct pseudo_user_list *list)
return ptr_list_size((struct ptr_list *)list);
}
+static inline bool pseudo_user_list_empty(struct pseudo_user_list *list)
+{
+ return ptr_list_empty((struct ptr_list *)list);
+}
+
static inline int has_users(pseudo_t p)
{
- return pseudo_user_list_size(p->users) != 0;
+ return !pseudo_user_list_empty(p->users);
+}
+
+static inline bool multi_users(pseudo_t p)
+{
+ return ptr_list_multiple((struct ptr_list *)(p->users));
+}
+
+static inline int nbr_users(pseudo_t p)
+{
+ return pseudo_user_list_size(p->users);
}
static inline struct pseudo_user *alloc_pseudo_user(struct instruction *insn, pseudo_t *pp)
diff --git a/liveness.c b/liveness.c
index 4c3339f1..d1968ce4 100644
--- a/liveness.c
+++ b/liveness.c
@@ -139,15 +139,6 @@ static void track_instruction_usage(struct basic_block *bb, struct instruction *
}
}
-int pseudo_in_list(struct pseudo_list *list, pseudo_t pseudo)
-{
- pseudo_t old;
- FOR_EACH_PTR(list,old) {
- if (old == pseudo)
- return 1;
- } END_FOR_EACH_PTR(old);
- return 0;
-}
static int liveness_changed;
diff --git a/ptrlist.c b/ptrlist.c
index c7ebf5a3..3677a347 100644
--- a/ptrlist.c
+++ b/ptrlist.c
@@ -37,6 +37,46 @@ int ptr_list_size(struct ptr_list *head)
}
///
+// test if a list is empty
+// @head: the head of the list
+// @return: ``true`` if the list is empty, ``false`` otherwise.
+bool ptr_list_empty(const struct ptr_list *head)
+{
+ const struct ptr_list *list = head;
+
+ if (!head)
+ return true;
+
+ do {
+ if (list->nr - list->rm)
+ return false;
+ } while ((list = list->next) != head);
+
+ return true;
+}
+
+///
+// test is a list contains more than one element
+// @head: the head of the list
+// @return: ``true`` if the list has more than 1 element, ``false`` otherwise.
+bool ptr_list_multiple(const struct ptr_list *head)
+{
+ const struct ptr_list *list = head;
+ int nr = 0;
+
+ if (!head)
+ return false;
+
+ do {
+ nr += list->nr - list->rm;
+ if (nr > 1)
+ return true;
+ } while ((list = list->next) != head);
+
+ return false;
+}
+
+///
// get the first element of a ptrlist
// @head: the head of the list
// @return: the first element of the list or ``NULL`` if the list is empty
@@ -233,6 +273,27 @@ void **__add_ptr_list_tag(struct ptr_list **listp, void *ptr, unsigned long tag)
}
///
+// test if some entry is already present in a ptrlist
+// @list: the head of the list
+// @entry: the entry to test
+// @return: ``true`` if the entry is already present, ``false`` otherwise.
+bool lookup_ptr_list_entry(const struct ptr_list *head, const void *entry)
+{
+ const struct ptr_list *list = head;
+
+ if (!head)
+ return false;
+ do {
+ int nr = list->nr;
+ int i;
+ for (i = 0; i < nr; i++)
+ if (list->list[i] == entry)
+ return true;
+ } while ((list = list->next) != head);
+ return false;
+}
+
+///
// delete an entry from a ptrlist
// @list: a pointer to the list
// @entry: the item to be deleted
@@ -341,6 +402,55 @@ void concat_ptr_list(struct ptr_list *a, struct ptr_list **b)
}
///
+// copy the elements of a list at the end of another list.
+// @listp: a pointer to the destination list.
+// @src: the head of the source list.
+void copy_ptr_list(struct ptr_list **listp, struct ptr_list *src)
+{
+ struct ptr_list *head, *tail;
+ struct ptr_list *cur = src;
+ int idx;
+
+ if (!src)
+ return;
+ head = *listp;
+ if (!head) {
+ *listp = src;
+ return;
+ }
+
+ tail = head->prev;
+ idx = tail->nr;
+ do {
+ struct ptr_list *next;
+ int nr = cur->nr;
+ int i;
+ for (i = 0; i < nr;) {
+ void *ptr = cur->list[i++];
+ if (!ptr)
+ continue;
+ if (idx >= LIST_NODE_NR) {
+ struct ptr_list *prev = tail;
+ tail = __alloc_ptrlist(0);
+ prev->next = tail;
+ tail->prev = prev;
+ prev->nr = idx;
+ idx = 0;
+ }
+ tail->list[idx++] = ptr;
+ }
+
+ next = cur->next;
+ __free_ptrlist(cur);
+ cur = next;
+ } while (cur != src);
+
+ tail->nr = idx;
+ head->prev = tail;
+ tail->next = head;
+}
+
+///
// free a ptrlist
// @listp: a pointer to the list
// Each blocks of the list are freed (but the entries
diff --git a/ptrlist.h b/ptrlist.h
index e97cdda3..2f023478 100644
--- a/ptrlist.h
+++ b/ptrlist.h
@@ -2,6 +2,7 @@
#define PTR_LIST_H
#include <stdlib.h>
+#include <stdbool.h>
/*
* Generic pointer list manipulation code.
@@ -32,10 +33,14 @@ void * undo_ptr_list_last(struct ptr_list **head);
void * delete_ptr_list_last(struct ptr_list **head);
int delete_ptr_list_entry(struct ptr_list **, void *, int);
int replace_ptr_list_entry(struct ptr_list **, void *old, void *new, int);
+bool lookup_ptr_list_entry(const struct ptr_list *head, const void *entry);
extern void sort_list(struct ptr_list **, int (*)(const void *, const void *));
extern void concat_ptr_list(struct ptr_list *a, struct ptr_list **b);
+extern void copy_ptr_list(struct ptr_list **h, struct ptr_list *t);
extern int ptr_list_size(struct ptr_list *);
+extern bool ptr_list_empty(const struct ptr_list *head);
+extern bool ptr_list_multiple(const struct ptr_list *head);
extern int linearize_ptr_list(struct ptr_list *, void **, int);
extern void *first_ptr_list(struct ptr_list *);
extern void *last_ptr_list(struct ptr_list *);
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 f8531043..52910876 100644
--- a/simplify.c
+++ b/simplify.c
@@ -4,6 +4,41 @@
* Copyright (C) 2004 Linus Torvalds
*/
+///
+// Instruction simplification
+// --------------------------
+//
+// Notation
+// ^^^^^^^^
+// The following conventions are used to describe the simplications:
+// * Uppercase letters are reserved for constants:
+// * `M` for a constant mask,
+// * `S` for a constant shift,
+// * `N` for a constant number of bits (usually other than a shift),
+// * `C` or 'K' for others constants.
+// * Lowercase letters `a`, `b`, `x`, `y`, ... are used for non-constants
+// or when it doesn't matter if the pseudo is a constant or not.
+// * Primes are used if needed to distinguish symbols (`M`, `M'`, ...).
+// * Expressions or sub-expressions involving only constants are
+// understood to be evaluated.
+// * `$mask(N)` is used for `((1 << N) -1)`
+// * `$trunc(x, N)` is used for `(x & $mask(N))`
+// * Expressions like `(-1 << S)`, `(-1 >> S)` and others formulae are
+// understood to be truncated to the size of the current instruction
+// (needed, since in general this size is not the same as the one used
+// by sparse for the evaluation of arithmetic operations).
+// * `TRUNC(x, N)` is used for a truncation *to* a size of `N` bits
+// * `ZEXT(x, N)` is used for a zero-extension *from* a size of `N` bits
+// * `OP(x, C)` is used to represent some generic operation using a constant,
+// including when the constant is implicit (e.g. `TRUNC(x, N)`).
+// * `MASK(x, M)` is used to respresent a 'masking' instruction:
+// - `AND(x, M)`
+// - `LSR(x, S)`, with `M` = (-1 << S)
+// - `SHL(x, S)`, with `M` = (-1 >> S)
+// - `TRUNC(x, N)`, with `M` = $mask(N)
+// - `ZEXT(x, N)`, with `M` = $mask(N)
+// * `SHIFT(x, S)` is used for `LSR(x, S)` or `SHL(x, S)`.
+
#include <assert.h>
#include "parse.h"
@@ -12,7 +47,12 @@
#include "flow.h"
#include "symbol.h"
-/* Find the trivial parent for a phi-source */
+///
+// Utilities
+// ^^^^^^^^^
+
+///
+// find the trivial parent for a phi-source
static struct basic_block *phi_parent(struct basic_block *source, pseudo_t pseudo)
{
/* Can't go upwards if the pseudo is defined in the bb it came from.. */
@@ -26,16 +66,15 @@ static struct basic_block *phi_parent(struct basic_block *source, pseudo_t pseud
return first_basic_block(source->parents);
}
-/*
- * Copy the phi-node's phisrcs into to given array.
- * Returns 0 if the the list contained the expected
- * number of element, a positive number if there was
- * more than expected and a negative one if less.
- *
- * Note: we can't reuse a function like linearize_ptr_list()
- * because any VOIDs in the phi-list must be ignored here
- * as in this context they mean 'entry has been removed'.
- */
+///
+// copy the phi-node's phisrcs into to given array
+// @return: 0 if the the list contained the expected
+// number of element, a positive number if there was
+// more than expected and a negative one if less.
+//
+// :note: we can't reuse a function like linearize_ptr_list()
+// because any VOIDs in the phi-list must be ignored here
+// as in this context they mean 'entry has been removed'.
static int get_phisources(struct instruction *sources[], int nbr, struct instruction *insn)
{
pseudo_t phi;
@@ -179,7 +218,7 @@ static int delete_pseudo_user_list_entry(struct pseudo_user_list **list, pseudo_
} END_FOR_EACH_PTR(pu);
assert(count <= 0);
out:
- if (pseudo_user_list_size(*list) == 0)
+ if (pseudo_user_list_empty(*list))
*list = NULL;
return count;
}
@@ -227,15 +266,16 @@ static void kill_use_list(struct pseudo_list *list)
} END_FOR_EACH_PTR(p);
}
-/*
- * kill an instruction:
- * - remove it from its bb
- * - remove the usage of all its operands
- * If forse is zero, the normal case, the function only for
- * instructions free of (possible) side-effects. Otherwise
- * the function does that unconditionally (must only be used
- * for unreachable instructions.
- */
+///
+// kill an instruction
+// @insn: the instruction to be killed
+// @force: if unset, the normal case, the instruction is not killed
+// if not free of possible side-effect; if set the instruction
+// is unconditionally killed.
+//
+// The killed instruction is removed from its BB and the usage
+// of all its operands are removed. The instruction is also
+// marked as killed by setting its ->bb to NULL.
int kill_insn(struct instruction *insn, int force)
{
if (!insn || !insn->bb)
@@ -270,6 +310,7 @@ int kill_insn(struct instruction *insn, int force)
break;
case OP_CBR:
+ case OP_SWITCH:
case OP_COMPUTEDGOTO:
kill_use(&insn->cond);
break;
@@ -314,9 +355,8 @@ int kill_insn(struct instruction *insn, int force)
return repeat_phase |= REPEAT_CSE;
}
-/*
- * Kill trivially dead instructions
- */
+///
+// kill trivially dead instructions
static int dead_insn(struct instruction *insn, pseudo_t *src1, pseudo_t *src2, pseudo_t *src3)
{
if (has_users(insn->target))
@@ -335,7 +375,7 @@ static inline int constant(pseudo_t pseudo)
}
///
-// replace one operand by a new value
+// replace the operand of an instruction
// @insn: the instruction
// @pp: the address of the instruction's operand
// @new: the new value for the operand
@@ -377,6 +417,13 @@ static inline int def_opcode(pseudo_t p)
return p->def->opcode;
}
+//
+// return the opcode of the instruction defining ``SRC`` if existing
+// and OP_BADOP if not. It also assigns the defining instruction
+// to ``DEF``.
+#define DEF_OPCODE(DEF, SRC) \
+ (((SRC)->type == PSEUDO_REG && (DEF = (SRC)->def)) ? DEF->opcode : OP_BADOP)
+
static unsigned int value_size(long long value)
{
value >>= 8;
@@ -391,12 +438,11 @@ static unsigned int value_size(long long value)
return 64;
}
-/*
- * Try to determine the maximum size of bits in a pseudo.
- *
- * Right now this only follow casts and constant values, but we
- * could look at things like logical 'and' instructions etc.
- */
+///
+// try to determine the maximum size of bits in a pseudo
+//
+// Right now this only follow casts and constant values, but we
+// could look at things like AND instructions, etc.
static unsigned int operand_size(struct instruction *insn, pseudo_t pseudo)
{
unsigned int size = insn->size;
@@ -471,12 +517,18 @@ static pseudo_t eval_insn(struct instruction *insn)
res = left % right;
break;
case OP_SHL:
+ if (ur >= size)
+ goto undef;
res = left << right;
break;
case OP_LSR:
+ if (ur >= size)
+ goto undef;
res = ul >> ur;
break;
case OP_ASR:
+ if (ur >= size)
+ goto undef;
res = left >> right;
break;
/* Logical */
@@ -532,18 +584,296 @@ undef:
return NULL;
}
+///
+// Simplifications
+// ^^^^^^^^^^^^^^^
-static int simplify_asr(struct instruction *insn, pseudo_t pseudo, long long value)
+///
+// try to simplify MASK(OR(AND(x, M'), b), M)
+// @insn: the masking instruction
+// @mask: the associated mask (M)
+// @ora: one of the OR's operands, guaranteed to be PSEUDO_REG
+// @orb: the other OR's operand
+// @return: 0 if no changes have been made, one or more REPEAT_* flags otherwise.
+static int simplify_mask_or_and(struct instruction *insn, unsigned long long mask,
+ pseudo_t ora, pseudo_t orb)
{
- unsigned int size = operand_size(insn, pseudo);
+ unsigned long long omask, nmask;
+ struct instruction *and = ora->def;
+ pseudo_t src2 = and->src2;
- if (value >= size) {
- warning(insn->pos, "right shift by bigger than source value");
- return replace_with_pseudo(insn, value_pseudo(0));
+ if (and->opcode != OP_AND)
+ return 0;
+ if (!constant(src2))
+ return 0;
+ omask = src2->value;
+ nmask = omask & mask;
+ if (nmask == 0) {
+ // if (M' & M) == 0: ((a & M') | b) -> b
+ return replace_pseudo(insn, &insn->src1, orb);
+ }
+ if (multi_users(insn->src1))
+ return 0; // can't modify anything inside the OR
+ if (nmask == mask) {
+ struct instruction *or = insn->src1->def;
+ pseudo_t *arg = (ora == or->src1) ? &or->src1 : &or->src2;
+ // if (M' & M) == M: ((a & M') | b) -> (a | b)
+ return replace_pseudo(or, arg, and->src1);
+ }
+ if (nmask != omask && !multi_users(ora)) {
+ // if (M' & M) != M': AND(a, M') -> AND(a, (M' & M))
+ and->src2 = value_pseudo(nmask);
+ return REPEAT_CSE;
+ }
+ return 0;
+}
+
+///
+// try to simplify MASK(OR(a, b), M)
+// @insn: the masking instruction
+// @mask: the associated mask (M)
+// @or: the OR instruction
+// @return: 0 if no changes have been made, one or more REPEAT_* flags otherwise.
+static int simplify_mask_or(struct instruction *insn, unsigned long long mask, struct instruction *or)
+{
+ pseudo_t src1 = or->src1;
+ pseudo_t src2 = or->src2;
+ int rc;
+
+ if (src1->type == PSEUDO_REG) {
+ if ((rc = simplify_mask_or_and(insn, mask, src1, src2)))
+ return rc;
+ }
+ if (src2->type == PSEUDO_REG) {
+ if ((rc = simplify_mask_or_and(insn, mask, src2, src1)))
+ return rc;
+ } else if (src2->type == PSEUDO_VAL) {
+ unsigned long long oval = src2->value;
+ unsigned long long nval = oval & mask;
+ // Try to simplify:
+ // MASK(OR(x, C), M)
+ if (nval == 0) {
+ // if (C & M) == 0: OR(x, C) -> x
+ return replace_pseudo(insn, &insn->src1, src1);
+ }
+ if (nval == mask) {
+ // if (C & M) == M: OR(x, C) -> M
+ return replace_pseudo(insn, &insn->src1, value_pseudo(mask));
+ }
+ if (nval != oval && !multi_users(or->target)) {
+ // if (C & M) != C: OR(x, C) -> OR(x, (C & M))
+ return replace_pseudo(or, &or->src2, value_pseudo(nval));
+ }
+ }
+ return 0;
+}
+
+///
+// try to simplify MASK(SHIFT(OR(a, b), S), M)
+// @sh: the shift instruction
+// @or: the OR instruction
+// @mask: the mask associated to MASK (M):
+// @return: 0 if no changes have been made, one or more REPEAT_* flags otherwise.
+static int simplify_mask_shift_or(struct instruction *sh, struct instruction *or, unsigned long long mask)
+{
+ unsigned long long smask = bits_mask(sh->size);
+ int shift = sh->src2->value;
+
+ if (sh->opcode == OP_LSR)
+ mask <<= shift;
+ else
+ mask >>= shift;
+ return simplify_mask_or(sh, smask & mask, or);
+}
+
+static int simplify_mask_shift(struct instruction *sh, unsigned long long mask)
+{
+ struct instruction *inner;
+
+ if (!constant(sh->src2) || sh->tainted)
+ return 0;
+ switch (DEF_OPCODE(inner, sh->src1)) {
+ case OP_OR:
+ if (!multi_users(sh->target))
+ return simplify_mask_shift_or(sh, inner, mask);
+ break;
}
+ return 0;
+}
+
+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 mask, omask, nmask;
+ 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;
+ 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);
+ if (value >= size)
+ goto zero;
+ switch(DEF_OPCODE(def, pseudo)) {
+ case OP_AND:
+ // replace (A & M) >> S
+ // by (A >> S) & (M >> S)
+ if (!constant(def->src2))
+ break;
+ mask = bits_mask(insn->size - value) << value;
+ omask = def->src2->value;
+ nmask = omask & mask;
+ if (nmask == 0)
+ return replace_with_pseudo(insn, value_pseudo(0));
+ if (nmask == mask)
+ return replace_pseudo(insn, &insn->src1, def->src1);
+ if (nbr_users(pseudo) > 1)
+ break;
+ def->opcode = OP_LSR;
+ def->src2 = insn->src2;
+ insn->opcode = OP_AND;
+ insn->src2 = value_pseudo(omask >> value);
+ return REPEAT_CSE;
+ case OP_LSR:
+ goto case_shift_shift;
+ case OP_OR:
+ mask = bits_mask(size);
+ return simplify_mask_shift_or(insn, def, mask);
+ case OP_SHL:
+ // replace ((x << S) >> S)
+ // by (x & (-1 >> S))
+ if (def->src2 != insn->src2)
+ break;
+ mask = bits_mask(insn->size - value);
+ goto replace_mask;
+ }
+ break;
+ case OP_SHL:
+ if (value >= size)
+ goto zero;
+ switch(DEF_OPCODE(def, pseudo)) {
+ case OP_AND:
+ // simplify (A & M) << S
+ if (!constant(def->src2))
+ break;
+ mask = bits_mask(insn->size) >> value;
+ omask = def->src2->value;
+ nmask = omask & mask;
+ if (nmask == 0)
+ return replace_with_pseudo(insn, value_pseudo(0));
+ if (nmask == mask)
+ return replace_pseudo(insn, &insn->src1, def->src1);
+ // do not simplify into ((A << S) & (M << S))
+ break;
+ case OP_LSR:
+ // replace ((x >> S) << S)
+ // by (x & (-1 << S))
+ if (def->src2 != insn->src2)
+ break;
+ mask = bits_mask(insn->size - value) << value;
+ goto replace_mask;
+ case OP_OR:
+ mask = bits_mask(size);
+ return simplify_mask_shift_or(insn, def, mask);
+ case OP_SHL:
+ case_shift_shift: // also for LSR - LSR
+ 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));
+replace_mask:
+ insn->opcode = OP_AND;
+ insn->src2 = value_pseudo(mask);
+ return replace_pseudo(insn, &insn->src1, def->src1);
}
static int simplify_mul_div(struct instruction *insn, long long value)
@@ -577,7 +907,7 @@ static int simplify_seteq_setne(struct instruction *insn, long long value)
{
pseudo_t old = insn->src1;
struct instruction *def;
- pseudo_t src1, src2;
+ unsigned osize;
int inverse;
int opcode;
@@ -591,8 +921,26 @@ static int simplify_seteq_setne(struct instruction *insn, long long value)
return 0;
inverse = (insn->opcode == OP_SET_NE) == value;
+ if (!inverse && def->size == 1 && insn->size == 1) {
+ // Replace:
+ // setne %r <- %s, $0
+ // or:
+ // seteq %r <- %s, $1
+ // by %s when boolean
+ return replace_with_pseudo(insn, old);
+ }
opcode = def->opcode;
switch (opcode) {
+ case OP_AND:
+ if (inverse)
+ break;
+ if (def->size != insn->size)
+ break;
+ if (def->src2->type != PSEUDO_VAL)
+ break;
+ if (def->src2->value != 1)
+ break;
+ return replace_with_pseudo(insn, old);
case OP_FPCMP ... OP_BINCMP_END:
// Convert:
// setcc.n %t <- %a, %b
@@ -601,23 +949,74 @@ static int simplify_seteq_setne(struct instruction *insn, long long value)
// setcc.n %t <- %a, %b
// setcc.m %r <- %a, $b
// and similar for setne/eq ... 0/1
- src1 = def->src1;
- src2 = def->src2;
insn->opcode = inverse ? opcode_table[opcode].negate : opcode;
- use_pseudo(insn, src1, &insn->src1);
- use_pseudo(insn, src2, &insn->src2);
+ use_pseudo(insn, def->src1, &insn->src1);
+ use_pseudo(insn, def->src2, &insn->src2);
remove_usage(old, &insn->src1);
return REPEAT_CSE;
+ case OP_SEXT:
+ if (value && (def->orig_type->bit_size == 1))
+ break;
+ /* Fall through */
case OP_ZEXT:
- if (def->orig_type->bit_size == 1) {
- // Convert:
- // zext.m %s <- (1) %a
- // setne.1 %r <- %s, $0
- // into:
- // setne.1 %s <- %a, $0
- // and same for setne/eq ... 0/1
- return replace_pseudo(insn, &insn->src1, def->src1);
+ // Convert:
+ // *ext.m %s <- (1) %a
+ // setne.1 %r <- %s, $0
+ // into:
+ // setne.1 %s <- %a, $0
+ // and same for setne/eq ... 0/1
+ return replace_pseudo(insn, &insn->src1, def->src);
+ case OP_TRUNC:
+ if (multi_users(old))
+ break;
+ // convert
+ // trunc.n %s <- (o) %a
+ // setne.m %r <- %s, $0
+ // into:
+ // and.o %s <- %a, $((1 << o) - 1)
+ // setne.m %r <- %s, $0
+ // and same for setne/eq ... 0/1
+ osize = def->size;
+ def->opcode = OP_AND;
+ def->type = def->orig_type;
+ def->size = def->type->bit_size;
+ def->src2 = value_pseudo(bits_mask(osize));
+ return REPEAT_CSE;
+ }
+ return 0;
+}
+
+static int simplify_constant_mask(struct instruction *insn, unsigned long long mask)
+{
+ pseudo_t old = insn->src1;
+ unsigned long long omask;
+ unsigned long long nmask;
+ struct instruction *def;
+ int osize;
+
+ switch (DEF_OPCODE(def, old)) {
+ case OP_FPCMP ... OP_BINCMP_END:
+ osize = 1;
+ goto oldsize;
+ case OP_OR:
+ return simplify_mask_or(insn, mask, def);
+ case OP_LSR:
+ case OP_SHL:
+ return simplify_mask_shift(def, mask);
+ case OP_ZEXT:
+ osize = def->orig_type->bit_size;
+ /* fall through */
+ oldsize:
+ omask = (1ULL << osize) - 1;
+ nmask = mask & omask;
+ if (nmask == omask)
+ // the AND mask is redundant
+ return replace_with_pseudo(insn, old);
+ if (nmask != mask) {
+ // can use a smaller mask
+ insn->src2 = value_pseudo(nmask);
+ return REPEAT_CSE;
}
break;
}
@@ -651,14 +1050,14 @@ static int simplify_constant_rightside(struct instruction *insn)
}
/* Fall through */
case OP_ADD:
- case OP_SHL:
- case OP_LSR:
case_neutral_zero:
if (!value)
return replace_with_pseudo(insn, insn->src1);
return 0;
case OP_ASR:
- return simplify_asr(insn, insn->src1, value);
+ case OP_SHL:
+ case OP_LSR:
+ return simplify_shift(insn, insn->src1, value);
case OP_MODU: case OP_MODS:
if (value == 1)
@@ -674,7 +1073,7 @@ static int simplify_constant_rightside(struct instruction *insn)
return replace_with_pseudo(insn, insn->src2);
if ((value & bits) == bits)
return replace_with_pseudo(insn, insn->src1);
- return 0;
+ return simplify_constant_mask(insn, value);
case OP_SET_NE:
case OP_SET_EQ:
@@ -823,7 +1222,7 @@ static int simplify_associative_binop(struct instruction *insn)
return 0;
if (!simple_pseudo(def->src2))
return 0;
- if (pseudo_user_list_size(def->target->users) != 1)
+ if (multi_users(def->target))
return 0;
switch_pseudo(def, &def->src1, insn, &insn->src2);
return REPEAT_CSE;
@@ -914,7 +1313,7 @@ static int simplify_one_memop(struct instruction *insn, pseudo_t orig)
offset:
/* Invalid code */
- if (new == orig) {
+ if (new == orig || new == addr) {
if (new == VOID)
return 0;
/*
@@ -926,18 +1325,20 @@ offset:
*/
if (repeat_phase & REPEAT_CFG_CLEANUP)
return 0;
- new = VOID;
warning(insn->pos, "crazy programmer");
+ replace_pseudo(insn, &insn->src, VOID);
+ return 0;
}
insn->offset += off->value;
replace_pseudo(insn, &insn->src, new);
return REPEAT_CSE | REPEAT_SYMBOL_CLEANUP;
}
-/*
- * We walk the whole chain of adds/subs backwards. That's not
- * only more efficient, but it allows us to find loops.
- */
+///
+// simplify memops instructions
+//
+// :note: We walk the whole chain of adds/subs backwards.
+// That's not only more efficient, but it allows us to find loops.
static int simplify_memop(struct instruction *insn)
{
int one, ret = 0;
@@ -952,8 +1353,10 @@ static int simplify_memop(struct instruction *insn)
static int simplify_cast(struct instruction *insn)
{
+ unsigned long long mask;
struct instruction *def;
pseudo_t src;
+ pseudo_t val;
int osize;
int size;
@@ -971,29 +1374,125 @@ static int simplify_cast(struct instruction *insn)
def = src->def;
switch (def_opcode(src)) {
case OP_AND:
+ val = def->src2;
+ if (val->type != PSEUDO_VAL)
+ break;
/* A cast of a AND might be a no-op.. */
- if (def->size >= size) {
- pseudo_t val = def->src2;
- if (val->type == PSEUDO_VAL) {
- if (!(val->value >> (size-1)))
- goto simplify;
- }
+ switch (insn->opcode) {
+ case OP_TRUNC:
+ if (multi_users(src))
+ break;
+ def->opcode = OP_TRUNC;
+ def->orig_type = def->type;
+ def->type = insn->type;
+ def->size = size;
+
+ insn->opcode = OP_AND;
+ mask = val->value;
+ mask &= (1ULL << size) - 1;
+ insn->src2 = value_pseudo(mask);
+ return REPEAT_CSE;
+
+ case OP_SEXT:
+ if (val->value & (1 << (def->size - 1)))
+ break;
+ // OK, sign bit is 0
+ case OP_ZEXT:
+ if (multi_users(src))
+ break;
+ // transform:
+ // and.n %b <- %a, M
+ // *ext.m %c <- (n) %b
+ // into:
+ // zext.m %b <- %a
+ // and.m %c <- %b, M
+ // For ZEXT, the mask will always be small
+ // enough. For SEXT, it can only be done if
+ // the mask force the sign bit to 0.
+ def->opcode = OP_ZEXT;
+ def->orig_type = insn->orig_type;
+ def->type = insn->type;
+ def->size = insn->size;
+ insn->opcode = OP_AND;
+ insn->src2 = val;
+ return REPEAT_CSE;
+ }
+ break;
+ case OP_FPCMP ... OP_BINCMP_END:
+ switch (insn->opcode) {
+ case OP_SEXT:
+ if (insn->size == 1)
+ break;
+ /* fall through */
+ case OP_ZEXT:
+ case OP_TRUNC:
+ // simplify:
+ // setcc.n %t <- %a, %b
+ // zext.m %r <- (n) %t
+ // into:
+ // setcc.m %r <- %a, %b
+ // and same for s/zext/trunc/
+ insn->opcode = def->opcode;
+ use_pseudo(insn, def->src2, &insn->src2);
+ return replace_pseudo(insn, &insn->src1, def->src1);
+ }
+ break;
+ case OP_OR:
+ switch (insn->opcode) {
+ case OP_TRUNC:
+ mask = bits_mask(insn->size);
+ return simplify_mask_or(insn, mask, def);
}
break;
+ case OP_LSR:
+ case OP_SHL:
+ if (insn->opcode != OP_TRUNC)
+ break;
+ mask = bits_mask(insn->size);
+ return simplify_mask_shift(def, mask);
case OP_TRUNC:
- osize = def->orig_type->bit_size;
- if (insn->opcode == OP_ZEXT && size == osize) {
+ switch (insn->opcode) {
+ case OP_TRUNC:
+ insn->orig_type = def->orig_type;
+ return replace_pseudo(insn, &insn->src1, def->src);
+ case OP_ZEXT:
+ if (size != def->orig_type->bit_size)
+ break;
insn->opcode = OP_AND;
insn->src2 = value_pseudo((1ULL << def->size) - 1);
return replace_pseudo(insn, &insn->src1, def->src);
}
break;
+ case OP_ZEXT:
+ switch (insn->opcode) {
+ case OP_SEXT:
+ insn->opcode = OP_ZEXT;
+ /* fall through */
+ case OP_ZEXT:
+ insn->orig_type = def->orig_type;
+ return replace_pseudo(insn, &insn->src, def->src);
+ }
+ /* fall through */
+ case OP_SEXT:
+ switch (insn->opcode) {
+ case OP_TRUNC:
+ osize = def->orig_type->bit_size;
+ if (size == osize)
+ return replace_with_pseudo(insn, def->src);
+ if (size > osize)
+ insn->opcode = def->opcode;
+ insn->orig_type = def->orig_type;
+ return replace_pseudo(insn, &insn->src, def->src);
+ }
+ switch (insn->opcode) {
+ case OP_SEXT:
+ insn->orig_type = def->orig_type;
+ return replace_pseudo(insn, &insn->src, def->src);
+ }
+ break;
}
return 0;
-
-simplify:
- return replace_with_pseudo(insn, src);
}
static int simplify_select(struct instruction *insn)
@@ -1070,9 +1569,8 @@ static int simplify_range(struct instruction *insn)
return 0;
}
-/*
- * Simplify "set_ne/eq $0 + br"
- */
+///
+// simplify SET_NE/EQ $0 + BR
static int simplify_cond_branch(struct instruction *br, struct instruction *def, pseudo_t newcond)
{
replace_pseudo(br, &br->cond, newcond);
@@ -1215,12 +1713,22 @@ int simplify_instruction(struct instruction *insn)
case OP_FCVTU: case OP_FCVTS:
case OP_UCVTF: case OP_SCVTF:
case OP_FCVTF:
+ case OP_PTRCAST:
+ if (dead_insn(insn, &insn->src, NULL, NULL))
+ return REPEAT_CSE;
+ break;
case OP_UTPTR:
case OP_PTRTU:
- case OP_PTRCAST:
+ return replace_with_pseudo(insn, insn->src);
+ case OP_SLICE:
if (dead_insn(insn, &insn->src, NULL, NULL))
return REPEAT_CSE;
break;
+ case OP_SETVAL:
+ case OP_SETFVAL:
+ if (dead_insn(insn, NULL, NULL, NULL))
+ return REPEAT_CSE;
+ break;
case OP_PHI:
if (dead_insn(insn, NULL, NULL, NULL)) {
kill_use_list(insn->phi_list);
@@ -1239,6 +1747,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/sparse-llvm.c b/sparse-llvm.c
index d28eb6e7..58811309 100644
--- a/sparse-llvm.c
+++ b/sparse-llvm.c
@@ -636,6 +636,10 @@ static void output_op_compare(struct function *fn, struct instruction *insn)
case LLVMIntegerTypeKind: {
LLVMIntPredicate op = translate_op(insn->opcode);
+ if (LLVMGetTypeKind(LLVMTypeOf(rhs)) == LLVMPointerTypeKind) {
+ LLVMTypeRef ltype = LLVMTypeOf(lhs);
+ rhs = LLVMBuildPtrToInt(fn->builder, rhs, ltype, "");
+ }
target = LLVMBuildICmp(fn->builder, op, lhs, rhs, target_name);
break;
}
diff --git a/sparse.1 b/sparse.1
index 806fb0cf..8a14a6be 100644
--- a/sparse.1
+++ b/sparse.1
@@ -339,6 +339,18 @@ Such declarations can lead to error-prone code.
Sparse does not issue these warnings by default.
.
.TP
+.B \-Wshift-count-negative
+Warn if a shift count is negative.
+
+Sparse issues these warnings by default.
+.
+.TP
+.B \-Wshift-count-overflow
+Warn if a shift count is bigger than the operand's width.
+
+Sparse issues these warnings by default.
+.
+.TP
.B \-Wsizeof-bool
Warn when checking the sizeof a _Bool.
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/unssa.c b/unssa.c
index e7c9154d..334ffa47 100644
--- a/unssa.c
+++ b/unssa.c
@@ -34,11 +34,6 @@
#include <assert.h>
-static inline int nbr_pseudo_users(pseudo_t p)
-{
- return ptr_list_size((struct ptr_list *)p->users);
-}
-
static int simplify_phi_node(struct instruction *phi, pseudo_t tmp)
{
pseudo_t target = phi->target;
@@ -95,7 +90,7 @@ static void replace_phi_node(struct instruction *phi)
src = def->phi_src;
if (src->type != PSEUDO_REG)
continue;
- switch (nbr_pseudo_users(src)) {
+ switch (nbr_users(src)) {
struct instruction *insn;
case 1:
insn = src->def;
diff --git a/validation/cast-kinds-check.c b/validation/cast-kinds-check.c
index 0fe705f5..7eb1ca1c 100644
--- a/validation/cast-kinds-check.c
+++ b/validation/cast-kinds-check.c
@@ -1,19 +1,19 @@
-#include "linear/cast-kinds.c"
+#include "optim/cast-kinds.c"
/*
* check-name: cast-kinds check
* check-command: sparse -m64 -v -Wno-pointer-to-int-cast $file
*
* check-error-start
-linear/cast-kinds.c:5:45: warning: cast drops bits
-linear/cast-kinds.c:6:47: warning: cast drops bits
-linear/cast-kinds.c:7:46: warning: cast drops bits
-linear/cast-kinds.c:8:45: warning: cast drops bits
-linear/cast-kinds.c:12:48: warning: cast drops bits
-linear/cast-kinds.c:13:50: warning: cast drops bits
-linear/cast-kinds.c:14:49: warning: cast drops bits
-linear/cast-kinds.c:15:48: warning: cast drops bits
-linear/cast-kinds.c:37:42: warning: non size-preserving integer to pointer cast
-linear/cast-kinds.c:38:44: warning: non size-preserving integer to pointer cast
+optim/cast-kinds.c:5:45: warning: cast drops bits
+optim/cast-kinds.c:6:47: warning: cast drops bits
+optim/cast-kinds.c:7:46: warning: cast drops bits
+optim/cast-kinds.c:8:45: warning: cast drops bits
+optim/cast-kinds.c:12:48: warning: cast drops bits
+optim/cast-kinds.c:13:50: warning: cast drops bits
+optim/cast-kinds.c:14:49: warning: cast drops bits
+optim/cast-kinds.c:15:48: warning: cast drops bits
+optim/cast-kinds.c:37:48: warning: non size-preserving integer to pointer cast
+optim/cast-kinds.c:38:50: warning: non size-preserving integer to pointer cast
* check-error-end
*/
diff --git a/validation/cast-weirds.c b/validation/cast-weirds.c
index a99c65d2..7d028882 100644
--- a/validation/cast-weirds.c
+++ b/validation/cast-weirds.c
@@ -9,43 +9,10 @@ static void * uint_2_vptr(uint a) { return (void *)a; }
/*
* check-name: cast-weirds
- * check-command: test-linearize -m64 $file
+ * check-command: sparse -m64 $file
*
* check-error-start
-cast-weirds.c:4:42: warning: non size-preserving integer to pointer cast
-cast-weirds.c:5:44: warning: non size-preserving integer to pointer cast
+cast-weirds.c:4:48: warning: non size-preserving integer to pointer cast
+cast-weirds.c:5:50: warning: non size-preserving integer to pointer cast
* check-error-end
- *
- * check-output-start
-int_2_iptr:
-.L0:
- <entry-point>
- sext.64 %r2 <- (32) %arg1
- utptr.64 %r3 <- (64) %r2
- ret.64 %r3
-
-
-uint_2_iptr:
-.L2:
- <entry-point>
- zext.64 %r6 <- (32) %arg1
- utptr.64 %r7 <- (64) %r6
- ret.64 %r7
-
-
-int_2_vptr:
-.L4:
- <entry-point>
- sext.64 %r10 <- (32) %arg1
- ret.64 %r10
-
-
-uint_2_vptr:
-.L6:
- <entry-point>
- zext.64 %r13 <- (32) %arg1
- ret.64 %r13
-
-
- * check-output-end
*/
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/kill-switch.c b/validation/kill-switch.c
new file mode 100644
index 00000000..1316a775
--- /dev/null
+++ b/validation/kill-switch.c
@@ -0,0 +1,17 @@
+extern int i;
+
+static void foo(void)
+{
+ switch (i) {
+ case 0:
+ ;
+ }
+}
+
+/*
+ * check-name: kill-switch
+ * check-command: test-linearize $file
+ *
+ * check-output-ignore
+ * check-output-excludes: load\\.
+ */
diff --git a/validation/linear/bitfield-inc.c b/validation/linear/bitfield-inc.c
new file mode 100644
index 00000000..56997592
--- /dev/null
+++ b/validation/linear/bitfield-inc.c
@@ -0,0 +1,16 @@
+struct s {
+ int f:5;
+};
+
+void inc(struct s *p)
+{
+ p->f++;
+}
+
+/*
+ * check-name: bitfield-inc
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-excludes: add\\.5
+ */
diff --git a/validation/linear/bitfield-preinc.c b/validation/linear/bitfield-preinc.c
new file mode 100644
index 00000000..783327ae
--- /dev/null
+++ b/validation/linear/bitfield-preinc.c
@@ -0,0 +1,18 @@
+struct s {
+ int f:3;
+};
+
+int preinc(void)
+{
+ struct s s = { 7 };
+ return ++s.f;
+}
+
+/*
+ * check-name: bitfield-preinc
+ * check-description: ++X is equivalent to X+=1
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-contains: ret.32 *\\$0
+ */
diff --git a/validation/linear/bitfield-size.c b/validation/linear/bitfield-size.c
index 963f6e28..841bdd0a 100644
--- a/validation/linear/bitfield-size.c
+++ b/validation/linear/bitfield-size.c
@@ -49,41 +49,45 @@ upostinc:
load.64 %r1 <- 0[x]
load.32 %r2 <- 0[%r1]
trunc.3 %r3 <- (32) %r2
- add.3 %r4 <- %r3, $1
- load.32 %r5 <- 0[%r1]
- zext.32 %r6 <- (3) %r4
- and.32 %r7 <- %r5, $-8
- or.32 %r8 <- %r7, %r6
- store.32 %r8 -> 0[%r1]
- zext.32 %r9 <- (3) %r3
- phisrc.32 %phi1(return) <- %r9
+ zext.32 %r4 <- (3) %r3
+ add.32 %r5 <- %r4, $1
+ trunc.3 %r6 <- (32) %r5
+ load.32 %r7 <- 0[%r1]
+ zext.32 %r8 <- (3) %r6
+ and.32 %r9 <- %r7, $0xfffffff8
+ or.32 %r10 <- %r9, %r8
+ store.32 %r10 -> 0[%r1]
+ zext.32 %r11 <- (3) %r4
+ phisrc.32 %phi1(return) <- %r11
br .L1
.L1:
- phi.32 %r10 <- %phi1(return)
- ret.32 %r10
+ phi.32 %r12 <- %phi1(return)
+ ret.32 %r12
upreinc:
.L2:
<entry-point>
store.64 %arg1 -> 0[x]
- load.64 %r11 <- 0[x]
- load.32 %r12 <- 0[%r11]
- trunc.3 %r13 <- (32) %r12
- add.3 %r14 <- %r13, $1
- load.32 %r15 <- 0[%r11]
- zext.32 %r16 <- (3) %r14
- and.32 %r17 <- %r15, $-8
- or.32 %r18 <- %r17, %r16
- store.32 %r18 -> 0[%r11]
- zext.32 %r19 <- (3) %r14
- phisrc.32 %phi2(return) <- %r19
+ load.64 %r13 <- 0[x]
+ load.32 %r14 <- 0[%r13]
+ trunc.3 %r15 <- (32) %r14
+ zext.32 %r16 <- (3) %r15
+ add.32 %r17 <- %r16, $1
+ trunc.3 %r18 <- (32) %r17
+ load.32 %r19 <- 0[%r13]
+ zext.32 %r20 <- (3) %r18
+ and.32 %r21 <- %r19, $0xfffffff8
+ or.32 %r22 <- %r21, %r20
+ store.32 %r22 -> 0[%r13]
+ zext.32 %r23 <- (3) %r18
+ phisrc.32 %phi2(return) <- %r23
br .L3
.L3:
- phi.32 %r20 <- %phi2(return)
- ret.32 %r20
+ phi.32 %r24 <- %phi2(return)
+ ret.32 %r24
ucpy:
@@ -91,15 +95,15 @@ ucpy:
<entry-point>
store.64 %arg1 -> 0[d]
store.64 %arg2 -> 0[s]
- load.64 %r21 <- 0[s]
- load.32 %r22 <- 0[%r21]
- trunc.3 %r23 <- (32) %r22
- load.64 %r24 <- 0[d]
- load.32 %r25 <- 0[%r24]
- zext.32 %r26 <- (3) %r23
- and.32 %r27 <- %r25, $-8
- or.32 %r28 <- %r27, %r26
- store.32 %r28 -> 0[%r24]
+ load.64 %r25 <- 0[s]
+ load.32 %r26 <- 0[%r25]
+ trunc.3 %r27 <- (32) %r26
+ load.64 %r28 <- 0[d]
+ load.32 %r29 <- 0[%r28]
+ zext.32 %r30 <- (3) %r27
+ and.32 %r31 <- %r29, $0xfffffff8
+ or.32 %r32 <- %r31, %r30
+ store.32 %r32 -> 0[%r28]
br .L5
.L5:
@@ -110,44 +114,48 @@ spostinc:
.L6:
<entry-point>
store.64 %arg1 -> 0[x]
- load.64 %r29 <- 0[x]
- load.32 %r30 <- 0[%r29]
- trunc.3 %r31 <- (32) %r30
- add.3 %r32 <- %r31, $1
- load.32 %r33 <- 0[%r29]
- zext.32 %r34 <- (3) %r32
- and.32 %r35 <- %r33, $-8
- or.32 %r36 <- %r35, %r34
- store.32 %r36 -> 0[%r29]
- zext.32 %r37 <- (3) %r31
- phisrc.32 %phi3(return) <- %r37
+ load.64 %r33 <- 0[x]
+ load.32 %r34 <- 0[%r33]
+ trunc.3 %r35 <- (32) %r34
+ zext.32 %r36 <- (3) %r35
+ add.32 %r37 <- %r36, $1
+ trunc.3 %r38 <- (32) %r37
+ load.32 %r39 <- 0[%r33]
+ zext.32 %r40 <- (3) %r38
+ and.32 %r41 <- %r39, $0xfffffff8
+ or.32 %r42 <- %r41, %r40
+ store.32 %r42 -> 0[%r33]
+ zext.32 %r43 <- (3) %r36
+ phisrc.32 %phi3(return) <- %r43
br .L7
.L7:
- phi.32 %r38 <- %phi3(return)
- ret.32 %r38
+ phi.32 %r44 <- %phi3(return)
+ ret.32 %r44
spreinc:
.L8:
<entry-point>
store.64 %arg1 -> 0[x]
- load.64 %r39 <- 0[x]
- load.32 %r40 <- 0[%r39]
- trunc.3 %r41 <- (32) %r40
- add.3 %r42 <- %r41, $1
- load.32 %r43 <- 0[%r39]
- zext.32 %r44 <- (3) %r42
- and.32 %r45 <- %r43, $-8
- or.32 %r46 <- %r45, %r44
- store.32 %r46 -> 0[%r39]
- zext.32 %r47 <- (3) %r42
- phisrc.32 %phi4(return) <- %r47
+ load.64 %r45 <- 0[x]
+ load.32 %r46 <- 0[%r45]
+ trunc.3 %r47 <- (32) %r46
+ zext.32 %r48 <- (3) %r47
+ add.32 %r49 <- %r48, $1
+ trunc.3 %r50 <- (32) %r49
+ load.32 %r51 <- 0[%r45]
+ zext.32 %r52 <- (3) %r50
+ and.32 %r53 <- %r51, $0xfffffff8
+ or.32 %r54 <- %r53, %r52
+ store.32 %r54 -> 0[%r45]
+ zext.32 %r55 <- (3) %r50
+ phisrc.32 %phi4(return) <- %r55
br .L9
.L9:
- phi.32 %r48 <- %phi4(return)
- ret.32 %r48
+ phi.32 %r56 <- %phi4(return)
+ ret.32 %r56
scpy:
@@ -155,15 +163,15 @@ scpy:
<entry-point>
store.64 %arg1 -> 0[d]
store.64 %arg2 -> 0[s]
- load.64 %r49 <- 0[s]
- load.32 %r50 <- 0[%r49]
- trunc.3 %r51 <- (32) %r50
- load.64 %r52 <- 0[d]
- load.32 %r53 <- 0[%r52]
- zext.32 %r54 <- (3) %r51
- and.32 %r55 <- %r53, $-8
- or.32 %r56 <- %r55, %r54
- store.32 %r56 -> 0[%r52]
+ load.64 %r57 <- 0[s]
+ load.32 %r58 <- 0[%r57]
+ trunc.3 %r59 <- (32) %r58
+ load.64 %r60 <- 0[d]
+ load.32 %r61 <- 0[%r60]
+ zext.32 %r62 <- (3) %r59
+ and.32 %r63 <- %r61, $0xfffffff8
+ or.32 %r64 <- %r63, %r62
+ store.32 %r64 -> 0[%r60]
br .L11
.L11:
diff --git a/validation/linear/bitfield-store.c b/validation/linear/bitfield-store.c
new file mode 100644
index 00000000..3d952c8d
--- /dev/null
+++ b/validation/linear/bitfield-store.c
@@ -0,0 +1,22 @@
+int foo(void)
+{
+ struct {
+ int a:8;
+ int b:16;
+ int c:8;
+ } s = { 0xff, 0x0000, 0xff };
+
+ return s.b = 0x56781234;
+}
+
+/*
+ * check-name: bitfield-store
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-contains: ret\\..*\\$0x1234
+ *
+ * check-error-start
+linear/bitfield-store.c:9:22: warning: cast truncates bits from constant value (56781234 becomes 1234)
+ * check-error-end
+ */
diff --git a/validation/linear/call-complex-pointer.c b/validation/linear/call-complex-pointer.c
index ea8232f1..dc0ab07b 100644
--- a/validation/linear/call-complex-pointer.c
+++ b/validation/linear/call-complex-pointer.c
@@ -18,14 +18,14 @@ foo:
br .L4
.L3:
- ptrcast.64 %r5 <- (64) %arg3
- phisrc.64 %phi2 <- %r5
+ ptrcast.64 %r6 <- (64) %arg3
+ phisrc.64 %phi2 <- %r6
br .L4
.L4:
- phi.64 %r6 <- %phi1, %phi2
- call.32 %r7 <- %r6, %arg4
- ret.32 %r7
+ phi.64 %r7 <- %phi1, %phi2
+ call.32 %r8 <- %r7, %arg4
+ ret.32 %r8
* check-output-end
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/linear/logical.c b/validation/linear/logical.c
new file mode 100644
index 00000000..148ad427
--- /dev/null
+++ b/validation/linear/logical.c
@@ -0,0 +1,259 @@
+struct S {
+ int :1;
+ signed int s:2;
+ unsigned int u:3;
+ long l;
+ double d;
+};
+
+int os(int i, struct S *b) { return i || b->s; }
+int ou(int i, struct S *b) { return i || b->u; }
+int ol(int i, struct S *b) { return i || b->l; }
+int od(int i, struct S *b) { return i || b->d; }
+
+int as(int i, struct S *b) { return i && b->s; }
+int au(int i, struct S *b) { return i && b->u; }
+int al(int i, struct S *b) { return i && b->l; }
+int ad(int i, struct S *b) { return i && b->d; }
+
+/*
+ * check-name: logical
+ * check-command: test-linearize -m64 -fdump-ir -Wno-decl $file
+ *
+ * check-output-start
+os:
+.L0:
+ <entry-point>
+ store.32 %arg1 -> 0[i]
+ store.64 %arg2 -> 0[b]
+ phisrc.32 %phi1 <- $1
+ load.32 %r1 <- 0[i]
+ setne.1 %r2 <- %r1, $0
+ cbr %r2, .L3, .L2
+
+.L2:
+ load.64 %r3 <- 0[b]
+ load.32 %r4 <- 0[%r3]
+ lsr.32 %r5 <- %r4, $1
+ trunc.2 %r6 <- (32) %r5
+ setne.1 %r7 <- %r6, $0
+ zext.32 %r8 <- (1) %r7
+ phisrc.32 %phi2 <- %r8
+ br .L3
+
+.L3:
+ phi.32 %r9 <- %phi1, %phi2
+ phisrc.32 %phi3(return) <- %r9
+ br .L1
+
+.L1:
+ phi.32 %r10 <- %phi3(return)
+ ret.32 %r10
+
+
+ou:
+.L4:
+ <entry-point>
+ store.32 %arg1 -> 0[i]
+ store.64 %arg2 -> 0[b]
+ phisrc.32 %phi5 <- $1
+ load.32 %r11 <- 0[i]
+ setne.1 %r12 <- %r11, $0
+ cbr %r12, .L7, .L6
+
+.L6:
+ load.64 %r13 <- 0[b]
+ load.32 %r14 <- 0[%r13]
+ lsr.32 %r15 <- %r14, $3
+ trunc.3 %r16 <- (32) %r15
+ setne.1 %r17 <- %r16, $0
+ zext.32 %r18 <- (1) %r17
+ phisrc.32 %phi6 <- %r18
+ br .L7
+
+.L7:
+ phi.32 %r19 <- %phi5, %phi6
+ phisrc.32 %phi7(return) <- %r19
+ br .L5
+
+.L5:
+ phi.32 %r20 <- %phi7(return)
+ ret.32 %r20
+
+
+ol:
+.L8:
+ <entry-point>
+ store.32 %arg1 -> 0[i]
+ store.64 %arg2 -> 0[b]
+ phisrc.32 %phi9 <- $1
+ load.32 %r21 <- 0[i]
+ setne.1 %r22 <- %r21, $0
+ cbr %r22, .L11, .L10
+
+.L10:
+ load.64 %r23 <- 0[b]
+ load.64 %r24 <- 8[%r23]
+ setne.1 %r25 <- %r24, $0
+ zext.32 %r26 <- (1) %r25
+ phisrc.32 %phi10 <- %r26
+ br .L11
+
+.L11:
+ phi.32 %r27 <- %phi9, %phi10
+ phisrc.32 %phi11(return) <- %r27
+ br .L9
+
+.L9:
+ phi.32 %r28 <- %phi11(return)
+ ret.32 %r28
+
+
+od:
+.L12:
+ <entry-point>
+ store.32 %arg1 -> 0[i]
+ store.64 %arg2 -> 0[b]
+ phisrc.32 %phi13 <- $1
+ load.32 %r29 <- 0[i]
+ setne.1 %r30 <- %r29, $0
+ cbr %r30, .L15, .L14
+
+.L14:
+ load.64 %r31 <- 0[b]
+ load.64 %r32 <- 16[%r31]
+ setfval.64 %r33 <- 0.000000e+00
+ fcmpune.1 %r34 <- %r32, %r33
+ zext.32 %r35 <- (1) %r34
+ phisrc.32 %phi14 <- %r35
+ br .L15
+
+.L15:
+ phi.32 %r36 <- %phi13, %phi14
+ phisrc.32 %phi15(return) <- %r36
+ br .L13
+
+.L13:
+ phi.32 %r37 <- %phi15(return)
+ ret.32 %r37
+
+
+as:
+.L16:
+ <entry-point>
+ store.32 %arg1 -> 0[i]
+ store.64 %arg2 -> 0[b]
+ phisrc.32 %phi17 <- $0
+ load.32 %r38 <- 0[i]
+ setne.1 %r39 <- %r38, $0
+ cbr %r39, .L18, .L19
+
+.L18:
+ load.64 %r40 <- 0[b]
+ load.32 %r41 <- 0[%r40]
+ lsr.32 %r42 <- %r41, $1
+ trunc.2 %r43 <- (32) %r42
+ setne.1 %r44 <- %r43, $0
+ zext.32 %r45 <- (1) %r44
+ phisrc.32 %phi18 <- %r45
+ br .L19
+
+.L19:
+ phi.32 %r46 <- %phi18, %phi17
+ phisrc.32 %phi19(return) <- %r46
+ br .L17
+
+.L17:
+ phi.32 %r47 <- %phi19(return)
+ ret.32 %r47
+
+
+au:
+.L20:
+ <entry-point>
+ store.32 %arg1 -> 0[i]
+ store.64 %arg2 -> 0[b]
+ phisrc.32 %phi21 <- $0
+ load.32 %r48 <- 0[i]
+ setne.1 %r49 <- %r48, $0
+ cbr %r49, .L22, .L23
+
+.L22:
+ load.64 %r50 <- 0[b]
+ load.32 %r51 <- 0[%r50]
+ lsr.32 %r52 <- %r51, $3
+ trunc.3 %r53 <- (32) %r52
+ setne.1 %r54 <- %r53, $0
+ zext.32 %r55 <- (1) %r54
+ phisrc.32 %phi22 <- %r55
+ br .L23
+
+.L23:
+ phi.32 %r56 <- %phi22, %phi21
+ phisrc.32 %phi23(return) <- %r56
+ br .L21
+
+.L21:
+ phi.32 %r57 <- %phi23(return)
+ ret.32 %r57
+
+
+al:
+.L24:
+ <entry-point>
+ store.32 %arg1 -> 0[i]
+ store.64 %arg2 -> 0[b]
+ phisrc.32 %phi25 <- $0
+ load.32 %r58 <- 0[i]
+ setne.1 %r59 <- %r58, $0
+ cbr %r59, .L26, .L27
+
+.L26:
+ load.64 %r60 <- 0[b]
+ load.64 %r61 <- 8[%r60]
+ setne.1 %r62 <- %r61, $0
+ zext.32 %r63 <- (1) %r62
+ phisrc.32 %phi26 <- %r63
+ br .L27
+
+.L27:
+ phi.32 %r64 <- %phi26, %phi25
+ phisrc.32 %phi27(return) <- %r64
+ br .L25
+
+.L25:
+ phi.32 %r65 <- %phi27(return)
+ ret.32 %r65
+
+
+ad:
+.L28:
+ <entry-point>
+ store.32 %arg1 -> 0[i]
+ store.64 %arg2 -> 0[b]
+ phisrc.32 %phi29 <- $0
+ load.32 %r66 <- 0[i]
+ setne.1 %r67 <- %r66, $0
+ cbr %r67, .L30, .L31
+
+.L30:
+ load.64 %r68 <- 0[b]
+ load.64 %r69 <- 16[%r68]
+ setfval.64 %r70 <- 0.000000e+00
+ fcmpune.1 %r71 <- %r69, %r70
+ zext.32 %r72 <- (1) %r71
+ phisrc.32 %phi30 <- %r72
+ br .L31
+
+.L31:
+ phi.32 %r73 <- %phi30, %phi29
+ phisrc.32 %phi31(return) <- %r73
+ br .L29
+
+.L29:
+ phi.32 %r74 <- %phi31(return)
+ ret.32 %r74
+
+
+ * check-output-end
+ */
diff --git a/validation/loop-linearization.c b/validation/loop-linearization.c
index 25c6dfb8..051e0453 100644
--- a/validation/loop-linearization.c
+++ b/validation/loop-linearization.c
@@ -56,8 +56,8 @@ ffor:
br .L7
.L2:
- add.32 %r7 <- %r1(i), $1
- phisrc.32 %phi6(i) <- %r7
+ add.32 %r8 <- %r1(i), $1
+ phisrc.32 %phi6(i) <- %r8
br .L4
.L3:
@@ -65,8 +65,8 @@ ffor:
br .L7
.L7:
- phi.32 %r5 <- %phi1(return), %phi2(return)
- ret.32 %r5
+ phi.32 %r6 <- %phi1(return), %phi2(return)
+ ret.32 %r6
fwhile:
@@ -76,21 +76,21 @@ fwhile:
br .L12
.L12:
- phi.32 %r8(i) <- %phi11(i), %phi12(i)
- setlt.32 %r9 <- %r8(i), $10
- cbr %r9, .L9, .L11
+ phi.32 %r9(i) <- %phi11(i), %phi12(i)
+ setlt.32 %r10 <- %r9(i), $10
+ cbr %r10, .L9, .L11
.L9:
- call.32 %r11 <- p, %r8(i)
- cbr %r11, .L14, .L13
+ call.32 %r12 <- p, %r9(i)
+ cbr %r12, .L14, .L13
.L13:
phisrc.32 %phi7(return) <- $0
br .L15
.L14:
- add.32 %r14 <- %r8(i), $1
- phisrc.32 %phi12(i) <- %r14
+ add.32 %r16 <- %r9(i), $1
+ phisrc.32 %phi12(i) <- %r16
br .L12
.L11:
@@ -98,8 +98,8 @@ fwhile:
br .L15
.L15:
- phi.32 %r12 <- %phi7(return), %phi8(return)
- ret.32 %r12
+ phi.32 %r14 <- %phi7(return), %phi8(return)
+ ret.32 %r14
fdo:
@@ -109,27 +109,27 @@ fdo:
br .L17
.L17:
- phi.32 %r15(i) <- %phi16(i), %phi17(i)
- call.32 %r16 <- p, %r15(i)
- cbr %r16, .L18, .L20
+ phi.32 %r17(i) <- %phi16(i), %phi17(i)
+ call.32 %r18 <- p, %r17(i)
+ cbr %r18, .L18, .L20
.L20:
phisrc.32 %phi13(return) <- $0
br .L22
.L18:
- add.32 %r19 <- %r15(i), $1
- setlt.32 %r20 <- %r15(i), $10
- phisrc.32 %phi17(i) <- %r19
- cbr %r20, .L17, .L19
+ add.32 %r22 <- %r17(i), $1
+ setlt.32 %r23 <- %r17(i), $10
+ phisrc.32 %phi17(i) <- %r22
+ cbr %r23, .L17, .L19
.L19:
phisrc.32 %phi14(return) <- $1
br .L22
.L22:
- phi.32 %r17 <- %phi13(return), %phi14(return)
- ret.32 %r17
+ phi.32 %r20 <- %phi13(return), %phi14(return)
+ ret.32 %r20
* check-output-end
diff --git a/validation/optim/and-extend.c b/validation/optim/and-extend.c
new file mode 100644
index 00000000..eb589236
--- /dev/null
+++ b/validation/optim/and-extend.c
@@ -0,0 +1,27 @@
+typedef unsigned short u16;
+typedef short s16;
+typedef unsigned int u32;
+typedef int s32;
+
+u32 ufoo(u32 x)
+{
+ u16 i = ((u16)x) & 0x7fffU;
+ return i;
+}
+
+u32 sfoo(u32 x)
+{
+ s16 i = ((s16)x) & 0x7fff;
+ return i;
+}
+
+/*
+ * check-name: and-extend
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-excludes: trunc\\.
+ * check-output-excludes: zext\\.
+ * check-output-excludes: sext\\.
+ * check-output-contains: and\\.32.*0x7fff
+ */
diff --git a/validation/optim/and-extendx.c b/validation/optim/and-extendx.c
new file mode 100644
index 00000000..5c181c93
--- /dev/null
+++ b/validation/optim/and-extendx.c
@@ -0,0 +1,24 @@
+typedef unsigned short u16;
+typedef short s16;
+typedef unsigned int u32;
+typedef int s32;
+typedef unsigned long long u64;
+typedef long long s64;
+
+u64 ufoo(int x)
+{
+ return x & 0x7fff;
+}
+
+u64 sfoo(int x)
+{
+ return x & 0x7fff;
+}
+
+/*
+ * check-name: and-extend
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-contains: and\\.64.*0x7fff
+ */
diff --git a/validation/optim/and-lsr.c b/validation/optim/and-lsr.c
new file mode 100644
index 00000000..439eb822
--- /dev/null
+++ b/validation/optim/and-lsr.c
@@ -0,0 +1,15 @@
+// (x & M) >> S to (x >> S) & (M >> S)
+
+unsigned int foo(unsigned int x)
+{
+ return (x & 0xffff) >> 12;
+}
+
+/*
+ * check-name: and-lsr
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-contains: and\\..*\\$15
+ * check-output-excludes: and\\..*\\$0xffff
+ */
diff --git a/validation/optim/and-or-bf0.c b/validation/optim/and-or-bf0.c
new file mode 100644
index 00000000..cfaff4f2
--- /dev/null
+++ b/validation/optim/and-or-bf0.c
@@ -0,0 +1,24 @@
+struct s {
+ int f:3;
+};
+
+void foo(struct s *p, int a)
+{
+ p->f = 1;
+ p->f = a;
+}
+
+void bar(struct s *p, int a)
+{
+ p->f = a;
+ p->f = 1;
+}
+
+/*
+ * check-name: and-or-bf0
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-pattern(3): and\\.
+ * check-output-pattern(2): or\\.
+ */
diff --git a/validation/optim/and-or-bf1.c b/validation/optim/and-or-bf1.c
new file mode 100644
index 00000000..23477ff3
--- /dev/null
+++ b/validation/optim/and-or-bf1.c
@@ -0,0 +1,18 @@
+struct s {
+ int :2;
+ int f:3;
+};
+
+void foo(struct s *d, const struct s *s, int a)
+{
+ d->f = s->f | a;
+}
+
+/*
+ * check-name: and-or-bf1
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-pattern(2): and\\.
+ * check-output-pattern(2): or\\.
+ */
diff --git a/validation/optim/and-or-bf2.c b/validation/optim/and-or-bf2.c
new file mode 100644
index 00000000..2296da12
--- /dev/null
+++ b/validation/optim/and-or-bf2.c
@@ -0,0 +1,27 @@
+struct s {
+ char a:3;
+ char b:3;
+ char c:2;
+};
+
+void foo(struct s *p)
+{
+ p->a = 1;
+ p->b = 2;
+ p->c = 3;
+}
+
+/*
+ * check-name: and-or-bf2
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-start
+foo:
+.L0:
+ <entry-point>
+ store.8 $209 -> 0[%arg1]
+ ret
+
+
+ * check-output-end
+ */
diff --git a/validation/optim/and-or-bfs.c b/validation/optim/and-or-bfs.c
new file mode 100644
index 00000000..f3f33204
--- /dev/null
+++ b/validation/optim/and-or-bfs.c
@@ -0,0 +1,23 @@
+struct s {
+ signed int :2;
+ signed int f:3;
+};
+
+int bfs(struct s s, int a)
+{
+ s.f = a;
+ return s.f;
+}
+
+/*
+ * check-name: and-or-bfs
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-pattern(1): trunc\\.
+ * check-output-pattern(1): sext\\.
+ * check-output-excludes: and\\.
+ * check-output-excludes: or\\.
+ * check-output-excludes: shl\\.
+ * check-output-excludes: lsr\\.
+ */
diff --git a/validation/optim/and-or-bfu.c b/validation/optim/and-or-bfu.c
new file mode 100644
index 00000000..b6a080bd
--- /dev/null
+++ b/validation/optim/and-or-bfu.c
@@ -0,0 +1,21 @@
+struct u {
+ unsigned int :2;
+ unsigned int f:3;
+};
+
+int bfu(struct u s, int a)
+{
+ s.f = a;
+ return s.f;
+}
+
+/*
+ * check-name: and-or-bfu
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-pattern(1): and\\.
+ * check-output-excludes: or\\.
+ * check-output-excludes: shl\\.
+ * check-output-excludes: lsr\\.
+ */
diff --git a/validation/optim/and-or-bfx.c b/validation/optim/and-or-bfx.c
new file mode 100644
index 00000000..57a54cf5
--- /dev/null
+++ b/validation/optim/and-or-bfx.c
@@ -0,0 +1,18 @@
+struct s {
+ int f:3;
+};
+
+void foo(struct s *p, int a, int b)
+{
+ p->f = a;
+ p->f = b;
+}
+
+/*
+ * check-name: and-or-bfx
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-pattern(2): and\\.
+ * check-output-pattern(1): or\\.
+ */
diff --git a/validation/optim/and-or-constant0.c b/validation/optim/and-or-constant0.c
new file mode 100644
index 00000000..dcf440f3
--- /dev/null
+++ b/validation/optim/and-or-constant0.c
@@ -0,0 +1,12 @@
+int foo(int x)
+{
+ return (x | 0xfffff000) & 0xfff;
+}
+
+/*
+ * check-name: and-or-constant0
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-excludes: or\\.
+ */
diff --git a/validation/optim/and-or-constant1.c b/validation/optim/and-or-constant1.c
new file mode 100644
index 00000000..49823d5c
--- /dev/null
+++ b/validation/optim/and-or-constant1.c
@@ -0,0 +1,14 @@
+int foo(int x)
+{
+ return (x | 0x000fffff) & 0xfff;
+}
+
+/*
+ * check-name: or-and-constant1
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-contains: ret\\..*\\$0xfff
+ * check-output-excludes: and\\.
+ * check-output-excludes: or\\.
+ */
diff --git a/validation/optim/and-or-constant2.c b/validation/optim/and-or-constant2.c
new file mode 100644
index 00000000..d7e66f9c
--- /dev/null
+++ b/validation/optim/and-or-constant2.c
@@ -0,0 +1,13 @@
+int foo(int x)
+{
+ return (x | 0xfffffff0) & 0xfff;
+}
+
+/*
+ * check-name: and-or-constant2
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-contains: or\\..*\\$0xff0
+ * check-output-excludes: or\\..*\\$0xfffffff0
+ */
diff --git a/validation/optim/and-or-crash.c b/validation/optim/and-or-crash.c
new file mode 100644
index 00000000..98a8a9b8
--- /dev/null
+++ b/validation/optim/and-or-crash.c
@@ -0,0 +1,5 @@
+static unsigned a(unsigned b, unsigned c) { (c << 1 | b & 1 << 1) >> 1; }
+
+/*
+ * check-name: catch crashes during AND-OR simplifications
+ */
diff --git a/validation/optim/and-or-lsr0.c b/validation/optim/and-or-lsr0.c
new file mode 100644
index 00000000..227c5aed
--- /dev/null
+++ b/validation/optim/and-or-lsr0.c
@@ -0,0 +1,13 @@
+int foo(int a, int b)
+{
+ return ((a & 0x00000fff) | b) >> 12;
+}
+
+/*
+ * check-name: and-or-lsr0
+ * check-command: test-linearize -Wno-decl $file
+ * check-known-to-fail
+ *
+ * check-output-ignore
+ * check-output-excludes: or\\.
+ */
diff --git a/validation/optim/and-or-lsr1.c b/validation/optim/and-or-lsr1.c
new file mode 100644
index 00000000..bd1dbc8a
--- /dev/null
+++ b/validation/optim/and-or-lsr1.c
@@ -0,0 +1,13 @@
+int foo(int a, int b)
+{
+ return ((a & 0xfffff000) | b) >> 12;
+}
+
+/*
+ * check-name: and-or-lsr1
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-pattern(0): and\\.
+ * check-output-pattern(1): or\\.
+ */
diff --git a/validation/optim/and-or-lsr2.c b/validation/optim/and-or-lsr2.c
new file mode 100644
index 00000000..d1af0135
--- /dev/null
+++ b/validation/optim/and-or-lsr2.c
@@ -0,0 +1,13 @@
+int foo(int x, int y)
+{
+ return ((x & 0xf0ffffff) | y) >> 12;
+}
+
+/*
+ * check-name: and-or-lsr2
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-contains: and\\..*\\$0xf0fff
+ * check-output-excludes: and\\..*\\$0xf0ffffff
+ */
diff --git a/validation/optim/and-or-lsrx.c b/validation/optim/and-or-lsrx.c
new file mode 100644
index 00000000..31adca92
--- /dev/null
+++ b/validation/optim/and-or-lsrx.c
@@ -0,0 +1,13 @@
+unsigned int foo(unsigned int x, unsigned int y, unsigned int a)
+{
+ return ((x & y) | (a & 0x0fff)) >> 12;
+}
+
+/*
+ * check-name: and-or-lsrx
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-pattern(1): and\\.
+ * check-output-excludes: or\\.
+ */
diff --git a/validation/optim/and-or-mask.c b/validation/optim/and-or-mask.c
new file mode 100644
index 00000000..46803789
--- /dev/null
+++ b/validation/optim/and-or-mask.c
@@ -0,0 +1,18 @@
+int foo(int a, int b)
+{
+ return ((a & 7) | (b & 3)) & 8;
+}
+
+/*
+ * check-name: and-or-mask
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-start
+foo:
+.L0:
+ <entry-point>
+ ret.32 $0
+
+
+ * check-output-end
+ */
diff --git a/validation/optim/and-or-mask0.c b/validation/optim/and-or-mask0.c
new file mode 100644
index 00000000..2d2245ea
--- /dev/null
+++ b/validation/optim/and-or-mask0.c
@@ -0,0 +1,12 @@
+int foo(int a, int b)
+{
+ return ((a & 0xfffff000) | b) & 0xfff;
+}
+
+/*
+ * check-name: and-or-mask0
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-excludes: or\\.
+ */
diff --git a/validation/optim/and-or-mask1.c b/validation/optim/and-or-mask1.c
new file mode 100644
index 00000000..bff3a89f
--- /dev/null
+++ b/validation/optim/and-or-mask1.c
@@ -0,0 +1,13 @@
+int foo(int a, int b)
+{
+ return ((a & 0x0fffffff) | b) & 0xfff;
+}
+
+/*
+ * check-name: and-or-mask1
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-pattern(1): and\\.
+ * check-output-pattern(1): or\\.
+ */
diff --git a/validation/optim/and-or-mask2.c b/validation/optim/and-or-mask2.c
new file mode 100644
index 00000000..cab802a6
--- /dev/null
+++ b/validation/optim/and-or-mask2.c
@@ -0,0 +1,13 @@
+int foo(int x, int y)
+{
+ return ((x & 0xffffff0f) | y) & 0xfff;
+}
+
+/*
+ * check-name: and-or-mask2
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-contains: and\\..*\\$0xf0f
+ * check-output-excludes: and\\..*\\$0xffffff0f
+ */
diff --git a/validation/optim/and-or-mask3s.c b/validation/optim/and-or-mask3s.c
new file mode 100644
index 00000000..cf264723
--- /dev/null
+++ b/validation/optim/and-or-mask3s.c
@@ -0,0 +1,25 @@
+#define W 3
+#define S 8
+#define M (W << S)
+
+static inline int fun(unsigned int x, unsigned int y)
+{
+ return ((x & M) | (y << S)) >> S;
+}
+
+short foo(unsigned int x, unsigned int y)
+{
+ return fun(x, y) & W;
+}
+
+/*
+ * check-name: and-or-mask3s
+ * check-command: test-linearize -Wno-decl $file
+ * check-known-to-fail
+ *
+ * check-output-ignore
+ * check-output-pattern(1): lsr\\.
+ * check-output-pattern(1): or\\.
+ * check-output-pattern(1): and\\.
+ * check-output-excludes: shl\\.
+ */
diff --git a/validation/optim/and-or-mask3u.c b/validation/optim/and-or-mask3u.c
new file mode 100644
index 00000000..c5b6c5fa
--- /dev/null
+++ b/validation/optim/and-or-mask3u.c
@@ -0,0 +1,25 @@
+#define W 3
+#define S 8
+#define M (W << S)
+
+static inline int fun(unsigned int x, unsigned int y)
+{
+ return ((x & M) | (y << S)) >> S;
+}
+
+int foo(unsigned int x, unsigned int y)
+{
+ return fun(x, y) & W;
+}
+
+/*
+ * check-name: and-or-mask3u
+ * check-command: test-linearize -Wno-decl $file
+ * check-known-to-fail
+ *
+ * check-output-ignore
+ * check-output-pattern(1): lsr\\.
+ * check-output-pattern(1): or\\.
+ * check-output-pattern(1): and\\.
+ * check-output-excludes: shl\\.
+ */
diff --git a/validation/optim/and-or-mask4.c b/validation/optim/and-or-mask4.c
new file mode 100644
index 00000000..1c4bc01a
--- /dev/null
+++ b/validation/optim/and-or-mask4.c
@@ -0,0 +1,25 @@
+#define W 3
+#define S 8
+#define M (W << S)
+
+static inline int fun(unsigned int x, unsigned int y)
+{
+ return ((x & W) | (y >> S)) << S;
+}
+
+int foo(unsigned int x, unsigned int y)
+{
+ return fun(x, y) & M;
+}
+
+/*
+ * check-name: and-or-mask4
+ * check-command: test-linearize -Wno-decl $file
+ * check-known-to-fail
+ *
+ * check-output-ignore
+ * check-output-pattern(1): shl\\.
+ * check-output-pattern(1): or\\.
+ * check-output-pattern(1): and\\.
+ * check-output-excludes: lsr\\.
+ */
diff --git a/validation/optim/and-or-maskx.c b/validation/optim/and-or-maskx.c
new file mode 100644
index 00000000..21d44e8d
--- /dev/null
+++ b/validation/optim/and-or-maskx.c
@@ -0,0 +1,13 @@
+int foo(int x, int y, int a)
+{
+ return ((x & y) | (a & 0xf000)) & 0x0fff;
+}
+
+/*
+ * check-name: and-or-maskx
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-pattern(2): and\\.
+ * check-output-excludes: or\\.
+ */
diff --git a/validation/optim/and-or-shl0.c b/validation/optim/and-or-shl0.c
new file mode 100644
index 00000000..4850b326
--- /dev/null
+++ b/validation/optim/and-or-shl0.c
@@ -0,0 +1,12 @@
+int foo(int a, int b)
+{
+ return ((a & 0xfff00000) | b) << 12;
+}
+
+/*
+ * check-name: and-or-shl0
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-excludes: or\\.
+ */
diff --git a/validation/optim/and-or-shl1.c b/validation/optim/and-or-shl1.c
new file mode 100644
index 00000000..bea22245
--- /dev/null
+++ b/validation/optim/and-or-shl1.c
@@ -0,0 +1,13 @@
+int foo(int a, int b)
+{
+ return ((a & 0x000fffff) | b) << 12;
+}
+
+/*
+ * check-name: and-or-shl1
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-pattern(0): and\\.
+ * check-output-pattern(1): or\\.
+ */
diff --git a/validation/optim/and-or-shl2.c b/validation/optim/and-or-shl2.c
new file mode 100644
index 00000000..f5f62758
--- /dev/null
+++ b/validation/optim/and-or-shl2.c
@@ -0,0 +1,13 @@
+int foo(int x, int y)
+{
+ return ((x & 0xffffff0f) | y) << 12;
+}
+
+/*
+ * check-name: and-or-shl2
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-contains: and\\..*\\$0xfff0f
+ * check-output-excludes: and\\..*\\$0xffffff0f
+ */
diff --git a/validation/optim/and-or-shlx.c b/validation/optim/and-or-shlx.c
new file mode 100644
index 00000000..ec2a2ced
--- /dev/null
+++ b/validation/optim/and-or-shlx.c
@@ -0,0 +1,13 @@
+unsigned int foo(unsigned int x, unsigned int y, unsigned int a)
+{
+ return ((x & y) | (a & 0xfff00000)) << 12;
+}
+
+/*
+ * check-name: and-or-shlx
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-pattern(1): and\\.
+ * check-output-excludes: or\\.
+ */
diff --git a/validation/optim/and-or-trunc0.c b/validation/optim/and-or-trunc0.c
new file mode 100644
index 00000000..3d326b6a
--- /dev/null
+++ b/validation/optim/and-or-trunc0.c
@@ -0,0 +1,13 @@
+char foo(int x, int y)
+{
+ return (x & 0xff00) | y;
+}
+
+/*
+ * check-name: and-or-trunc0
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-excludes: and\\.
+ * check-output-excludes: or\\.
+ */
diff --git a/validation/optim/and-or-trunc1.c b/validation/optim/and-or-trunc1.c
new file mode 100644
index 00000000..6bbe8a8c
--- /dev/null
+++ b/validation/optim/and-or-trunc1.c
@@ -0,0 +1,12 @@
+char foo(int x, int y)
+{
+ return (x & 0xffff) | y;
+}
+
+/*
+ * check-name: and-or-trunc1
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-excludes: and\\.
+ */
diff --git a/validation/optim/and-or-trunc2.c b/validation/optim/and-or-trunc2.c
new file mode 100644
index 00000000..e66c1f14
--- /dev/null
+++ b/validation/optim/and-or-trunc2.c
@@ -0,0 +1,13 @@
+char foo(int x, int y)
+{
+ return (x & 0xff07) | y;
+}
+
+/*
+ * check-name: and-or-trunc2
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-pattern(1): and\\.
+ * check-output-pattern(1): and\\..*\\$7
+ */
diff --git a/validation/optim/and-or-truncx.c b/validation/optim/and-or-truncx.c
new file mode 100644
index 00000000..ef8249a1
--- /dev/null
+++ b/validation/optim/and-or-truncx.c
@@ -0,0 +1,13 @@
+char foo(int x, int y, int b)
+{
+ return (x & y) | (b & 0xff00);
+}
+
+/*
+ * check-name: and-or-truncx
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-pattern(1): and\\.
+ * check-output-excludes: or\\.
+ */
diff --git a/validation/optim/and-trunc.c b/validation/optim/and-trunc.c
new file mode 100644
index 00000000..df1e4d03
--- /dev/null
+++ b/validation/optim/and-trunc.c
@@ -0,0 +1,20 @@
+short smask(short x)
+{
+ return x & (short) 0x7fff;
+}
+
+short umask(unsigned short x)
+{
+ return x & (unsigned short) 0x7fff;
+}
+
+/*
+ * check-name: and-trunc
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-excludes: sext\\.
+ * check-output-excludes: zext\\.
+ * check-output-excludes: trunc\\.
+ * check-output-contains: and\\.16
+ */
diff --git a/validation/optim/bitfield-store-load0.c b/validation/optim/bitfield-store-load0.c
new file mode 100644
index 00000000..f68cb600
--- /dev/null
+++ b/validation/optim/bitfield-store-load0.c
@@ -0,0 +1,44 @@
+int ufoo(unsigned int a)
+{
+ struct u {
+ unsigned int :2;
+ unsigned int a:3;
+ } bf;
+
+ bf.a = a;
+ return bf.a;
+}
+
+int sfoo(int a)
+{
+ struct s {
+ signed int :2;
+ signed int a:3;
+ } bf;
+
+ bf.a = a;
+ return bf.a;
+}
+
+/*
+ * check-name: optim store/load bitfields
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-start
+ufoo:
+.L0:
+ <entry-point>
+ and.32 %r11 <- %arg1, $7
+ ret.32 %r11
+
+
+sfoo:
+.L2:
+ <entry-point>
+ trunc.3 %r16 <- (32) %arg1
+ sext.32 %r23 <- (3) %r16
+ ret.32 %r23
+
+
+ * check-output-end
+ */
diff --git a/validation/optim/bitfield-store-loads.c b/validation/optim/bitfield-store-loads.c
new file mode 100644
index 00000000..dc625131
--- /dev/null
+++ b/validation/optim/bitfield-store-loads.c
@@ -0,0 +1,23 @@
+struct s {
+ char :2;
+ char f:3;
+};
+
+int foo(struct s s, int a)
+{
+ s.f = a;
+ return s.f;
+}
+
+/*
+ * check-name: bitfield-store-load signed
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-excludes: shl\\.
+ * check-output-excludes: lsr\\.
+ * check-output-excludes: or\\.
+ * check-output-excludes: [sz]ext\\.
+ * check-output-excludes: trunc\\.
+ * check-output-pattern(1): and\\.
+ */
diff --git a/validation/optim/bitfield-store-loadu.c b/validation/optim/bitfield-store-loadu.c
new file mode 100644
index 00000000..7fa1593d
--- /dev/null
+++ b/validation/optim/bitfield-store-loadu.c
@@ -0,0 +1,21 @@
+struct s {
+ unsigned int :2;
+ unsigned int f:3;
+};
+
+int foo(struct s s, int a)
+{
+ s.f = a;
+ return s.f;
+}
+
+/*
+ * check-name: bitfield-store-load unsigned
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-excludes: shl\\.
+ * check-output-excludes: lsr\\.
+ * check-output-excludes: or\\.
+ * check-output-pattern(1): and\\.
+ */
diff --git a/validation/optim/bool-context-fp.c b/validation/optim/bool-context-fp.c
index 50e96825..c41370ba 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,18 +50,17 @@ 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
- setne.1 %r26 <- %r24, $0
- ret.1 %r26
+ ret.1 %r24
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,18 +71,17 @@ 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
- setne.1 %r45 <- %r43, $0
- ret.1 %r45
+ ret.1 %r43
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/bool-sext-test.c b/validation/optim/bool-sext-test.c
new file mode 100644
index 00000000..bd85e06e
--- /dev/null
+++ b/validation/optim/bool-sext-test.c
@@ -0,0 +1,12 @@
+_Bool eqs0( signed char a) { return a == 0; }
+_Bool eqs1( signed char a) { return a == 1; }
+_Bool nes0( signed char a) { return a != 0; }
+_Bool nes1( signed char a) { return a != 1; }
+
+/*
+ * check-name: bool-sext-test
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-excludes: sext\\.
+ */
diff --git a/validation/optim/bool-simplify.c b/validation/optim/bool-simplify.c
index 68aabb78..fe8ce88b 100644
--- a/validation/optim/bool-simplify.c
+++ b/validation/optim/bool-simplify.c
@@ -43,17 +43,15 @@ and_0:
and_1:
.L2:
<entry-point>
- setne.1 %r8 <- %arg1, $0
- zext.32 %r11 <- (1) %r8
- ret.32 %r11
+ setne.32 %r9 <- %arg1, $0
+ ret.32 %r9
or_0:
.L4:
<entry-point>
- setne.1 %r14 <- %arg1, $0
- zext.32 %r17 <- (1) %r14
- ret.32 %r17
+ setne.32 %r14 <- %arg1, $0
+ ret.32 %r14
or_1:
@@ -65,9 +63,8 @@ or_1:
and_2:
.L8:
<entry-point>
- setne.1 %r26 <- %arg1, $0
- zext.32 %r29 <- (1) %r26
- ret.32 %r29
+ setne.32 %r25 <- %arg1, $0
+ ret.32 %r25
or_2:
diff --git a/validation/optim/bool-simplify2.c b/validation/optim/bool-simplify2.c
index c94b4412..a089fe62 100644
--- a/validation/optim/bool-simplify2.c
+++ b/validation/optim/bool-simplify2.c
@@ -27,7 +27,7 @@ static bool babbb(bool a, bool b, bool c) { return a && b && c; }
* check-name: bool-simplify2
* check-command: test-linearize $file
*
- * check-output-pattern(36): setne\\.
+ * check-output-pattern(20): setne\\.
* check-output-pattern(4): seteq\\.
* check-output-pattern(8): zext\\.
* check-output-pattern(12): and
@@ -75,8 +75,7 @@ boii:
setne.1 %r23 <- %arg1, $0
setne.1 %r25 <- %arg2, $0
or.1 %r26 <- %r23, %r25
- setne.1 %r28 <- %r26, $0
- ret.1 %r28
+ ret.1 %r26
baii:
@@ -85,8 +84,7 @@ baii:
setne.1 %r31 <- %arg1, $0
setne.1 %r33 <- %arg2, $0
and.1 %r34 <- %r31, %r33
- setne.1 %r36 <- %r34, $0
- ret.1 %r36
+ ret.1 %r34
ioiii:
@@ -95,9 +93,8 @@ ioiii:
setne.1 %r39 <- %arg1, $0
setne.1 %r41 <- %arg2, $0
or.1 %r42 <- %r39, %r41
- setne.1 %r44 <- %r42, $0
setne.1 %r46 <- %arg3, $0
- or.1 %r47 <- %r44, %r46
+ or.1 %r47 <- %r42, %r46
zext.32 %r48 <- (1) %r47
ret.32 %r48
@@ -108,9 +105,8 @@ iaiii:
setne.1 %r51 <- %arg1, $0
setne.1 %r53 <- %arg2, $0
and.1 %r54 <- %r51, %r53
- setne.1 %r56 <- %r54, $0
setne.1 %r58 <- %arg3, $0
- and.1 %r59 <- %r56, %r58
+ and.1 %r59 <- %r54, %r58
zext.32 %r60 <- (1) %r59
ret.32 %r60
@@ -121,11 +117,9 @@ boiii:
setne.1 %r63 <- %arg1, $0
setne.1 %r65 <- %arg2, $0
or.1 %r66 <- %r63, %r65
- setne.1 %r68 <- %r66, $0
setne.1 %r70 <- %arg3, $0
- or.1 %r71 <- %r68, %r70
- setne.1 %r73 <- %r71, $0
- ret.1 %r73
+ or.1 %r71 <- %r66, %r70
+ ret.1 %r71
baiii:
@@ -134,11 +128,9 @@ baiii:
setne.1 %r76 <- %arg1, $0
setne.1 %r78 <- %arg2, $0
and.1 %r79 <- %r76, %r78
- setne.1 %r81 <- %r79, $0
setne.1 %r83 <- %arg3, $0
- and.1 %r84 <- %r81, %r83
- setne.1 %r86 <- %r84, $0
- ret.1 %r86
+ and.1 %r84 <- %r79, %r83
+ ret.1 %r84
inb:
@@ -175,24 +167,21 @@ bobb:
.L28:
<entry-point>
or.1 %r107 <- %arg1, %arg2
- setne.1 %r109 <- %r107, $0
- ret.1 %r109
+ ret.1 %r107
babb:
.L30:
<entry-point>
and.1 %r113 <- %arg1, %arg2
- setne.1 %r115 <- %r113, $0
- ret.1 %r115
+ ret.1 %r113
iobbb:
.L32:
<entry-point>
or.1 %r119 <- %arg1, %arg2
- setne.1 %r121 <- %r119, $0
- or.1 %r123 <- %r121, %arg3
+ or.1 %r123 <- %r119, %arg3
zext.32 %r124 <- (1) %r123
ret.32 %r124
@@ -201,8 +190,7 @@ iabbb:
.L34:
<entry-point>
and.1 %r128 <- %arg1, %arg2
- setne.1 %r130 <- %r128, $0
- and.1 %r132 <- %r130, %arg3
+ and.1 %r132 <- %r128, %arg3
zext.32 %r133 <- (1) %r132
ret.32 %r133
@@ -211,20 +199,16 @@ bobbb:
.L36:
<entry-point>
or.1 %r137 <- %arg1, %arg2
- setne.1 %r139 <- %r137, $0
- or.1 %r141 <- %r139, %arg3
- setne.1 %r143 <- %r141, $0
- ret.1 %r143
+ or.1 %r141 <- %r137, %arg3
+ ret.1 %r141
babbb:
.L38:
<entry-point>
and.1 %r147 <- %arg1, %arg2
- setne.1 %r149 <- %r147, $0
- and.1 %r151 <- %r149, %arg3
- setne.1 %r153 <- %r151, $0
- ret.1 %r153
+ and.1 %r151 <- %r147, %arg3
+ ret.1 %r151
* check-output-end
diff --git a/validation/optim/bool-zext-test.c b/validation/optim/bool-zext-test.c
new file mode 100644
index 00000000..138938b0
--- /dev/null
+++ b/validation/optim/bool-zext-test.c
@@ -0,0 +1,12 @@
+_Bool equ0(unsigned char a) { return a == 0; }
+_Bool equ1(unsigned char a) { return a == 1; }
+_Bool neu0(unsigned char a) { return a != 0; }
+_Bool neu1(unsigned char a) { return a != 1; }
+
+/*
+ * check-name: bool-zext-test
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-excludes: zext\\.
+ */
diff --git a/validation/optim/call-inlined.c b/validation/optim/call-inlined.c
index 00698a4b..f21b3294 100644
--- a/validation/optim/call-inlined.c
+++ b/validation/optim/call-inlined.c
@@ -22,8 +22,8 @@ int foo(int a, int b, int p)
foo:
.L0:
<entry-point>
- select.32 %r9 <- %arg3, %arg3, $0
- ret.32 %r9
+ select.32 %r10 <- %arg3, %arg3, $0
+ ret.32 %r10
* check-output-end
diff --git a/validation/linear/cast-kinds.c b/validation/optim/cast-kinds.c
index 5df307bc..b144dc7e 100644
--- a/validation/linear/cast-kinds.c
+++ b/validation/optim/cast-kinds.c
@@ -88,8 +88,7 @@ vptr_2_int:
iptr_2_int:
.L8:
<entry-point>
- ptrtu.64 %r13 <- (64) %arg1
- trunc.32 %r14 <- (64) %r13
+ trunc.32 %r14 <- (64) %arg1
ret.32 %r14
@@ -137,8 +136,7 @@ vptr_2_uint:
iptr_2_uint:
.L22:
<entry-point>
- ptrtu.64 %r34 <- (64) %arg1
- trunc.32 %r35 <- (64) %r34
+ trunc.32 %r35 <- (64) %arg1
ret.32 %r35
@@ -185,8 +183,7 @@ vptr_2_long:
iptr_2_long:
.L36:
<entry-point>
- ptrtu.64 %r54 <- (64) %arg1
- ret.64 %r54
+ ret.64 %arg1
float_2_long:
@@ -232,8 +229,7 @@ vptr_2_ulong:
iptr_2_ulong:
.L50:
<entry-point>
- ptrtu.64 %r73 <- (64) %arg1
- ret.64 %r73
+ ret.64 %arg1
float_2_ulong:
@@ -286,30 +282,26 @@ int_2_iptr:
.L66:
<entry-point>
sext.64 %r94 <- (32) %arg1
- utptr.64 %r95 <- (64) %r94
- ret.64 %r95
+ ret.64 %r94
uint_2_iptr:
.L68:
<entry-point>
zext.64 %r98 <- (32) %arg1
- utptr.64 %r99 <- (64) %r98
- ret.64 %r99
+ ret.64 %r98
long_2_iptr:
.L70:
<entry-point>
- utptr.64 %r102 <- (64) %arg1
- ret.64 %r102
+ ret.64 %arg1
ulong_2_iptr:
.L72:
<entry-point>
- utptr.64 %r105 <- (64) %arg1
- ret.64 %r105
+ ret.64 %arg1
vptr_2_iptr:
diff --git a/validation/optim/cast-nop.c b/validation/optim/cast-nop.c
new file mode 100644
index 00000000..7741b7a7
--- /dev/null
+++ b/validation/optim/cast-nop.c
@@ -0,0 +1,18 @@
+static long p2l(long *p)
+{
+ return (long) p;
+}
+
+static long *l2p(long l)
+{
+ return (long*)l;
+}
+
+/*
+ * check-name: cast-nop
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-excludes: utptr\\.
+ * check-output-excludes: ptrtu\\.
+ */
diff --git a/validation/optim/cse-cmp-next.c b/validation/optim/cse-cmp-next.c
new file mode 100644
index 00000000..50fdbac0
--- /dev/null
+++ b/validation/optim/cse-cmp-next.c
@@ -0,0 +1,15 @@
+void foo(int p, int i, int f, int *ref, int *dst, int *src)
+{
+ if (p)
+ f = ref[i];
+ if (f)
+ dst[i] = src[i];
+}
+
+/*
+ * check-name: cse-cmp-next
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-pattern(1,2): mul\\.
+ */
diff --git a/validation/optim/ext-trunc-greater.c b/validation/optim/ext-trunc-greater.c
new file mode 100644
index 00000000..b682fc5d
--- /dev/null
+++ b/validation/optim/ext-trunc-greater.c
@@ -0,0 +1,17 @@
+short sgt(char x)
+{
+ return (int) x;
+}
+
+short ugt(unsigned char x)
+{
+ return (int) x;
+}
+
+/*
+ * check-name: ext-trunc-greater
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-excludes: trunc\\.
+ */
diff --git a/validation/optim/ext-trunc-same.c b/validation/optim/ext-trunc-same.c
new file mode 100644
index 00000000..2bfcf030
--- /dev/null
+++ b/validation/optim/ext-trunc-same.c
@@ -0,0 +1,19 @@
+short seq(short x)
+{
+ return (int) x;
+}
+
+short ueq(unsigned short x)
+{
+ return (int) x;
+}
+
+/*
+ * check-name: ext-trunc-same
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-excludes: trunc\\.
+ * check-output-excludes: sext\\.
+ * check-output-excludes: zext\\.
+ */
diff --git a/validation/optim/ext-trunc-smaller.c b/validation/optim/ext-trunc-smaller.c
new file mode 100644
index 00000000..194c98d7
--- /dev/null
+++ b/validation/optim/ext-trunc-smaller.c
@@ -0,0 +1,18 @@
+char slt(short x)
+{
+ return (int) x;
+}
+
+char ult(unsigned short x)
+{
+ return (int) x;
+}
+
+/*
+ * check-name: ext-trunc-smaller
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-excludes: sext\\.
+ * check-output-excludes: zext\\.
+ */
diff --git a/validation/optim/lsr-and0.c b/validation/optim/lsr-and0.c
new file mode 100644
index 00000000..94310ba8
--- /dev/null
+++ b/validation/optim/lsr-and0.c
@@ -0,0 +1,13 @@
+unsigned lsr_and0(unsigned x)
+{
+ unsigned t = (x & 0x00000fff);
+ return (t >> 12) & t;
+}
+
+/*
+ * check-name: lsr-and0
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-contains: ret\\..*\\$0$
+ */
diff --git a/validation/optim/lsr-and1.c b/validation/optim/lsr-and1.c
new file mode 100644
index 00000000..393679e3
--- /dev/null
+++ b/validation/optim/lsr-and1.c
@@ -0,0 +1,18 @@
+// If (t >> S) is simplified into (x >> S)
+// then the whole expression will be 0.
+// The test is only interesting if the sub-expression
+// (x & M) is referenced more than once
+// (because otherwise other simplifications apply).
+unsigned lsr_and1(unsigned x)
+{
+ unsigned t = (x & 0xfffff000);
+ return ((t >> 12) ^ (x >> 12)) & t;
+}
+
+/*
+ * check-name: lsr-and1
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-contains: ret\\..*\\$0$
+ */
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/lsr-shl0.c b/validation/optim/lsr-shl0.c
new file mode 100644
index 00000000..952baa6b
--- /dev/null
+++ b/validation/optim/lsr-shl0.c
@@ -0,0 +1,14 @@
+unsigned mask(unsigned x)
+{
+ return (x << 15) >> 15;
+}
+
+/*
+ * check-name: lsr-shl0
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-contains: and\\..*0x1ffff
+ * check-output-excludes: lsr\\.
+ * check-output-excludes: shl\\.
+ */
diff --git a/validation/optim/mask-lsr.c b/validation/optim/mask-lsr.c
new file mode 100644
index 00000000..ec636444
--- /dev/null
+++ b/validation/optim/mask-lsr.c
@@ -0,0 +1,14 @@
+// ((x & M) | y) >> S to (y >> S) when (M >> S) == 0
+
+unsigned int foo(unsigned int x, unsigned int y)
+{
+ return ((x & 0xff) | y) >> 8;
+}
+
+/*
+ * check-name: mask-lsr
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-excludes: %arg1
+ */
diff --git a/validation/optim/mask-out.c b/validation/optim/mask-out.c
new file mode 100644
index 00000000..ac85aec8
--- /dev/null
+++ b/validation/optim/mask-out.c
@@ -0,0 +1,12 @@
+unsigned mask(unsigned a, unsigned b)
+{
+ return ((a & 0xffff0000) | b) & 0x0000ffff;
+}
+
+/*
+ * check-name: mask-out
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-excludes: %arg1
+ */
diff --git a/validation/optim/mask1-setne0.c b/validation/optim/mask1-setne0.c
new file mode 100644
index 00000000..1e599dc8
--- /dev/null
+++ b/validation/optim/mask1-setne0.c
@@ -0,0 +1,28 @@
+struct s {
+ unsigned i:1;
+};
+
+int foo(struct s x)
+{
+ unsigned int i = x.i;
+
+ if (i == 0)
+ return 1;
+ else if (i == 1)
+ return 1;
+ return 0;
+}
+
+/*
+ * check-name: mask1-setne0
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-start
+foo:
+.L0:
+ <entry-point>
+ ret.32 $1
+
+
+ * check-output-end
+ */
diff --git a/validation/optim/or-and-constant1.c b/validation/optim/or-and-constant1.c
new file mode 100644
index 00000000..aa673b90
--- /dev/null
+++ b/validation/optim/or-and-constant1.c
@@ -0,0 +1,29 @@
+unsigned int and_or_equ(unsigned int a)
+{
+ return (a | 3) & 3;
+}
+
+int and_or_eqs(int a)
+{
+ return (a | 3) & 3;
+}
+
+unsigned int or_and_equ(unsigned int a)
+{
+ return (a & 3) | 3;
+}
+
+int or_and_eqs(int a)
+{
+ return (a & 3) | 3;
+}
+
+/*
+ * check-name: or-and-constant1
+ * check-command: test-linearize -Wno-decl $file
+ * check-known-to-fail
+ *
+ * check-output-ignore
+ * check-output-pattern(4): ret\\..*\\$3
+ * check-output-excludes: or\\.
+ */
diff --git a/validation/optim/setcc-mask.c b/validation/optim/setcc-mask.c
new file mode 100644
index 00000000..5d271788
--- /dev/null
+++ b/validation/optim/setcc-mask.c
@@ -0,0 +1,18 @@
+int foo (int a)
+{
+ return ((a == 0) & 1) == (a == 0);
+}
+
+/*
+ * check-name: setcc-mask
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-start
+foo:
+.L0:
+ <entry-point>
+ ret.32 $1
+
+
+ * check-output-end
+ */
diff --git a/validation/optim/setne0-sext.c b/validation/optim/setne0-sext.c
new file mode 100644
index 00000000..4167979b
--- /dev/null
+++ b/validation/optim/setne0-sext.c
@@ -0,0 +1,9 @@
+long foo(int a) { return a != 0; }
+
+/*
+ * check-name: setne0-sext
+ * check-command: test-linearize -m64 -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-excludes: sext\\.
+ */
diff --git a/validation/optim/setne0-trunc.c b/validation/optim/setne0-trunc.c
new file mode 100644
index 00000000..6c5494ec
--- /dev/null
+++ b/validation/optim/setne0-trunc.c
@@ -0,0 +1,9 @@
+char foo(int a) { return a != 0; }
+
+/*
+ * check-name: setne0-trunc
+ * check-command: test-linearize -m64 -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-excludes: trunc\\.
+ */
diff --git a/validation/optim/setne0-zext.c b/validation/optim/setne0-zext.c
new file mode 100644
index 00000000..8a074f03
--- /dev/null
+++ b/validation/optim/setne0-zext.c
@@ -0,0 +1,9 @@
+unsigned long foo(int a) { return (unsigned int) (a != 0); }
+
+/*
+ * check-name: setne0-zext
+ * check-command: test-linearize -m64 -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-excludes: zext\\.
+ */
diff --git a/validation/optim/sext-sext.c b/validation/optim/sext-sext.c
new file mode 100644
index 00000000..604a7dd4
--- /dev/null
+++ b/validation/optim/sext-sext.c
@@ -0,0 +1,12 @@
+int foo(signed char offset)
+{
+ return (int)(short) offset;
+}
+
+/*
+ * check-name: sext-sext
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-pattern(1): sext\\.
+ */
diff --git a/validation/optim/sext.c b/validation/optim/sext.c
new file mode 100644
index 00000000..719730d5
--- /dev/null
+++ b/validation/optim/sext.c
@@ -0,0 +1,15 @@
+int sext(int x)
+{
+ return (x << 5) >> 5;
+}
+
+/*
+ * check-name: sext
+ * check-command: test-linearize -Wno-decl $file
+ * check-known-to-fail
+ *
+ * check-output-ignore
+ * check-output-contains: sext\\.$27
+ * check-output-excludes: asr\\.
+ * check-output-excludes: shl\\.
+ */
diff --git a/validation/optim/sh-or-and0.c b/validation/optim/sh-or-and0.c
new file mode 100644
index 00000000..02f0cb03
--- /dev/null
+++ b/validation/optim/sh-or-and0.c
@@ -0,0 +1,20 @@
+unsigned lsr_or_and0(unsigned x, unsigned b)
+{
+ return (((x & 0x00000fff) | b) >> 12);
+}
+
+unsigned shl_or_and0(unsigned x, unsigned b)
+{
+ return (((x & 0xfff00000) | b) << 12);
+}
+
+/*
+ * check-name: sh-or-and0
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-pattern(1): lsr\\.
+ * check-output-pattern(1): shl\\.
+ * check-output-excludes: or\\.
+ * check-output-excludes: and\\.
+ */
diff --git a/validation/optim/sh-or-and1.c b/validation/optim/sh-or-and1.c
new file mode 100644
index 00000000..7b79bbf3
--- /dev/null
+++ b/validation/optim/sh-or-and1.c
@@ -0,0 +1,20 @@
+unsigned lsr_or_and1(unsigned x, unsigned b)
+{
+ return (((x & 0xfffff000) | b) >> 12);
+}
+
+unsigned shl_or_and1(unsigned x, unsigned b)
+{
+ return (((x & 0x000fffff) | b) << 12);
+}
+
+/*
+ * check-name: sh-or-and1
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-pattern(1): lsr\\.
+ * check-output-pattern(1): shl\\.
+ * check-output-pattern(2): or\\.
+ * check-output-excludes: and\\.
+ */
diff --git a/validation/optim/sh-or-and2.c b/validation/optim/sh-or-and2.c
new file mode 100644
index 00000000..241aeaff
--- /dev/null
+++ b/validation/optim/sh-or-and2.c
@@ -0,0 +1,21 @@
+unsigned lsr_or_and2(unsigned x, unsigned b)
+{
+ return (((x & 0xf0ffffff) | b) >> 12);
+}
+
+unsigned shl_or_and2(unsigned x, unsigned b)
+{
+ return (((x & 0xffffff0f) | b) << 12);
+}
+
+/*
+ * check-name: sh-or-and2
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-pattern(1): lsr\\.
+ * check-output-pattern(1): shl\\.
+ * check-output-pattern(2): or\\.
+ * check-output-pattern(1): and\\..*\\$0xf0fff000
+ * check-output-pattern(1): and\\..*\\$0xfff0f
+ */
diff --git a/validation/optim/shift-big.c b/validation/optim/shift-big.c
new file mode 100644
index 00000000..84bcd2ce
--- /dev/null
+++ b/validation/optim/shift-big.c
@@ -0,0 +1,82 @@
+typedef unsigned int u32;
+typedef int s32;
+
+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 -Wno-decl -m64 $file
+ *
+ * check-error-ignore
+ * check-output-start
+asr31:
+.L0:
+ <entry-point>
+ asr.32 %r2 <- %arg1, $31
+ ret.32 %r2
+
+
+asr32:
+.L2:
+ <entry-point>
+ asr.32 %r5 <- %arg1, $32
+ ret.32 %r5
+
+
+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
+
+
+ * check-output-end
+ */
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/shift-zext.c b/validation/optim/shift-zext.c
new file mode 100644
index 00000000..30409bec
--- /dev/null
+++ b/validation/optim/shift-zext.c
@@ -0,0 +1,12 @@
+unsigned int foo(unsigned int x)
+{
+ return (x << 20) >> 20;
+}
+
+/*
+ * check-name: shift-zext
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-contains: and\\..*%arg1, \\$0xfff
+ */
diff --git a/validation/optim/shl-and0.c b/validation/optim/shl-and0.c
new file mode 100644
index 00000000..894bd882
--- /dev/null
+++ b/validation/optim/shl-and0.c
@@ -0,0 +1,13 @@
+unsigned shl_and0(unsigned x)
+{
+ unsigned t = (x & 0xfff00000);
+ return (t << 12) & t;
+}
+
+/*
+ * check-name: shl-and0
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-contains: ret\\..*\\$0$
+ */
diff --git a/validation/optim/shl-and1.c b/validation/optim/shl-and1.c
new file mode 100644
index 00000000..13a1675b
--- /dev/null
+++ b/validation/optim/shl-and1.c
@@ -0,0 +1,18 @@
+// If (t << S) is simplified into (x << S)
+// then the whole expression will be 0.
+// The test is only interesting if the sub-expression
+// (x & M) is referenced more than once
+// (because otherwise other simplifications apply).
+unsigned shl_and1(unsigned x)
+{
+ unsigned t = (x & 0x000fffff);
+ return ((t << 12) ^ (x << 12)) & t;
+}
+
+/*
+ * check-name: shl-and1
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-contains: ret\\..*\\$0$
+ */
diff --git a/validation/optim/shl-lsr0.c b/validation/optim/shl-lsr0.c
new file mode 100644
index 00000000..fc2561bd
--- /dev/null
+++ b/validation/optim/shl-lsr0.c
@@ -0,0 +1,14 @@
+unsigned mask(unsigned x)
+{
+ return (x >> 15) << 15;
+}
+
+/*
+ * check-name: shl-lsr0
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-contains: and\\..*0xffff8000
+ * check-output-excludes: lsr\\.
+ * check-output-excludes: shl\\.
+ */
diff --git a/validation/optim/trunc-mask-zext.c b/validation/optim/trunc-mask-zext.c
new file mode 100644
index 00000000..9b604174
--- /dev/null
+++ b/validation/optim/trunc-mask-zext.c
@@ -0,0 +1,13 @@
+unsigned long long foo(unsigned long long x)
+{
+ return (((unsigned int) x) & 0x7ffU);
+}
+
+/*
+ * check-name: trunc-mask-zext
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-excludes: trunc\\.
+ * check-output-excludes: zext\\.
+ */
diff --git a/validation/optim/trunc-or-shl.c b/validation/optim/trunc-or-shl.c
new file mode 100644
index 00000000..70d8bd1d
--- /dev/null
+++ b/validation/optim/trunc-or-shl.c
@@ -0,0 +1,13 @@
+char foo(int a, int b)
+{
+ return (a << 8) | b;
+}
+
+/*
+ * check-name: trunc-or-shl
+ * check-command: test-linearize -Wno-decl $file
+ * check-known-to-fail
+ *
+ * check-output-ignore
+ * check-output-contains: ret\\..*%arg2
+ */
diff --git a/validation/optim/trunc-seteq0.c b/validation/optim/trunc-seteq0.c
new file mode 100644
index 00000000..5994b17c
--- /dev/null
+++ b/validation/optim/trunc-seteq0.c
@@ -0,0 +1,18 @@
+struct S {
+ int :1;
+ signed int s:2;
+ unsigned int u:3;
+};
+
+int os(int i, struct S *b) { return i || b->s; }
+int ou(int i, struct S *b) { return i || b->u; }
+
+/*
+ * check-name: trunc-seteq0
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-excludes: trunc\\.
+ * check-output-excludes: sext\\.
+ * check-output-excludes: zext\\.
+ */
diff --git a/validation/optim/trunc-setne0.c b/validation/optim/trunc-setne0.c
new file mode 100644
index 00000000..878c05fa
--- /dev/null
+++ b/validation/optim/trunc-setne0.c
@@ -0,0 +1,20 @@
+struct s {
+ unsigned int u:1;
+};
+
+unsigned int foo(struct s x)
+{
+ if (x.u)
+ return 1;
+ else
+ return 0;
+}
+
+/*
+ * check-name: trunc-setne0
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-contains: and\\.
+ * check-output-excludes: trunc\\.
+ */
diff --git a/validation/optim/trunc-trunc.c b/validation/optim/trunc-trunc.c
new file mode 100644
index 00000000..6dc50aee
--- /dev/null
+++ b/validation/optim/trunc-trunc.c
@@ -0,0 +1,12 @@
+char foo(int a)
+{
+ return ((((short) a) + 1) - 1);
+}
+
+/*
+ * check-name: trunc-trunc
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-pattern(1): trunc\\.
+ */
diff --git a/validation/optim/zext-and.c b/validation/optim/zext-and.c
new file mode 100644
index 00000000..a3153bf7
--- /dev/null
+++ b/validation/optim/zext-and.c
@@ -0,0 +1,12 @@
+unsigned int foo(unsigned char x)
+{
+ return (unsigned int)x & 0xffffU;
+}
+
+/*
+ * check-name: zext-and
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-excludes: and\\.
+ */
diff --git a/validation/optim/zext-and1.c b/validation/optim/zext-and1.c
new file mode 100644
index 00000000..c99a0e62
--- /dev/null
+++ b/validation/optim/zext-and1.c
@@ -0,0 +1,12 @@
+unsigned int bar(unsigned char x)
+{
+ return (unsigned int)x & 0xff01U;
+}
+
+/*
+ * check-name: zext-and1
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-contains: and\\..*\\$1
+ */
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/optim/zext-sext.c b/validation/optim/zext-sext.c
new file mode 100644
index 00000000..1fe3900d
--- /dev/null
+++ b/validation/optim/zext-sext.c
@@ -0,0 +1,13 @@
+int foo(unsigned char offset)
+{
+ return (int)(short) offset;
+}
+
+/*
+ * check-name: zext-sext
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-excludes: sext\\.
+ * check-output-pattern(1): zext\\.
+ */
diff --git a/validation/optim/zext-zext.c b/validation/optim/zext-zext.c
new file mode 100644
index 00000000..986d2242
--- /dev/null
+++ b/validation/optim/zext-zext.c
@@ -0,0 +1,13 @@
+int foo(unsigned char offset)
+{
+ return (int)(unsigned short) offset;
+}
+
+/*
+ * check-name: zext-zext
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-excludes: sext\\.
+ * check-output-pattern(1): zext\\.
+ */
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-long.c b/validation/shift-undef-long.c
new file mode 100644
index 00000000..32626743
--- /dev/null
+++ b/validation/shift-undef-long.c
@@ -0,0 +1,21 @@
+static unsigned very_big_shift(unsigned int a)
+{
+ unsigned r = 0;
+ r |= a << (0ULL ^ ~0U);
+ r |= a << ((( signed long long) ~0U) + 1);
+ r |= a << (((unsigned long long) ~0U) + 1);
+ r |= a << (~((unsigned long long) ~0U));
+ return r;
+}
+
+/*
+ * check-name: shift-undef-long
+ * 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)
+ * check-error-end
+ */
diff --git a/validation/shift-undef.c b/validation/shift-undef.c
new file mode 100644
index 00000000..4e94fa23
--- /dev/null
+++ b/validation/shift-undef.c
@@ -0,0 +1,164 @@
+int simple(int s, unsigned int u, int p)
+{
+ s = s >> 100;
+ u = u >> 101;
+ u = u << 102;
+ s = s >> -1;
+ u = u >> -2;
+ u = u << -3;
+ if (0) return s >> 103;
+ if (0) return u >> 104;
+ if (0) return u << 105;
+ if (0) return s >> -4;
+ if (0) return u >> -5;
+ if (0) return u << -6;
+ if (p && 0) return s >> 106;
+ if (p && 0) return u >> 107;
+ if (p && 0) return u << 108;
+ if (p && 0) return s >> -7;
+ if (p && 0) return u >> -8;
+ if (p && 0) return u << -9;
+ s = s >> ((p & 0) + 109); u ^= p; // reloaded because now == 0
+ u = u >> ((p & 0) + 110); u ^= p; // reloaded because now == 0
+ u = u << ((p & 0) + 111); u ^= p; // reloaded because now == 0
+ s = s >> ((p & 0) + -10);
+ u = u >> ((p & 0) + -11); u ^= p; // reloaded because now == 0
+ u = u << ((p & 0) + -12); u ^= p; // reloaded because now == 0
+ return s + u;
+}
+
+int compound(int s, unsigned int u, int p)
+{
+ s >>= 100;
+ u >>= 101;
+ u <<= 102;
+ s >>= -1;
+ u >>= -2;
+ u <<= -3;
+ if (0) return s >>= 103;
+ if (0) return u >>= 104;
+ if (0) return u <<= 105;
+ if (0) return s >>= -4;
+ if (0) return u >>= -5;
+ if (0) return u <<= -6;
+ if (p && 0) return s >>= 106;
+ if (p && 0) return u >>= 107;
+ if (p && 0) return u <<= 108;
+ if (p && 0) return s >>= -7;
+ if (p && 0) return u >>= -8;
+ if (p && 0) return u <<= -9;
+ s >>= ((p & 0) + 109); u ^= p; // reloaded because now == 0
+ u >>= ((p & 0) + 110); u ^= p; // reloaded because now == 0
+ u <<= ((p & 0) + 111); u ^= p; // reloaded because now == 0
+ s >>= ((p & 0) + -10);
+ u >>= ((p & 0) + -11); u ^= p; // reloaded because now == 0
+ u <<= ((p & 0) + -12); u ^= p; // reloaded because now == 0
+ return s + u;
+}
+
+int ok(int s, unsigned int u, int p)
+{
+ // GCC doesn't warn on these
+ if (0 && (s >> 100)) return 0;
+ if (0 && (u >> 101)) return 0;
+ if (0 && (u << 102)) return 0;
+ if (0 && (s >> -1)) return 0;
+ if (0 && (u >> -2)) return 0;
+ if (0 && (u << -3)) return 0;
+ if (0 && (s >>= 103)) return 0;
+ if (0 && (u >>= 104)) return 0;
+ if (0 && (u <<= 105)) return 0;
+ if (0 && (s >>= -4)) return 0;
+ if (0 && (u >>= -5)) return 0;
+ if (0 && (u <<= -6)) return 0;
+ return 1;
+}
+
+struct bf {
+ unsigned int u:8;
+ int s:8;
+};
+
+int bf(struct bf *p)
+{
+ unsigned int r = 0;
+ r += p->s << 8;
+ r += p->s >> 8;
+ r += p->u >> 8;
+ return r;
+}
+
+/*
+ * The following is used in the kernel at several places
+ * It shouldn't emit any warnings.
+ */
+typedef unsigned long long u64;
+typedef unsigned int u32;
+
+extern void hw_w32x2(u32 hi, u32 lo);
+
+inline void hw_w64(u64 val)
+{
+ hw_w32x2(val >> 32, (u32) val);
+}
+
+void hw_write(u32 val)
+{
+ hw_w64(val);
+}
+
+/*
+ * check-name: shift too big or negative
+ * 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: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 count is negative (-2)
+shift-undef.c:37:11: warning: shift count is negative (-3)
+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 count is negative (-5)
+shift-undef.c:43:25: warning: shift count is negative (-6)
+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 count is negative (-8)
+shift-undef.c:49:30: warning: shift count is negative (-9)
+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
+ */