diff options
-rw-r--r-- | Makefile | 1 | ||||
-rw-r--r-- | linearize.h | 2 | ||||
-rw-r--r-- | parse.c | 2 | ||||
-rw-r--r-- | simplify.c | 98 | ||||
-rw-r--r-- | ssa.c | 171 | ||||
-rw-r--r-- | sset.c | 28 | ||||
-rw-r--r-- | sset.h | 56 | ||||
-rw-r--r-- | validation/knr-attr-crash.c | 12 | ||||
-rw-r--r-- | validation/mem2reg/not-same-memop0.c | 48 | ||||
-rw-r--r-- | validation/mem2reg/packed-bitfield.c | 35 | ||||
-rw-r--r-- | validation/optim/cmpe-and0.c | 10 | ||||
-rw-r--r-- | validation/optim/cmpe-or0.c | 10 | ||||
-rw-r--r-- | validation/optim/cmps-and0.c | 21 | ||||
-rw-r--r-- | validation/optim/cmps-minmax.c | 8 | ||||
-rw-r--r-- | validation/optim/cmps-or0.c | 21 | ||||
-rw-r--r-- | validation/optim/cmps0-and0.c | 12 | ||||
-rw-r--r-- | validation/optim/cmpu-and0.c | 17 | ||||
-rw-r--r-- | validation/optim/cmpu-or0.c | 18 | ||||
-rwxr-xr-x | validation/test-suite | 11 |
19 files changed, 403 insertions, 178 deletions
@@ -63,7 +63,6 @@ LIB_OBJS += show-parse.o LIB_OBJS += simplify.o LIB_OBJS += sort.o LIB_OBJS += ssa.o -LIB_OBJS += sset.o LIB_OBJS += stats.o LIB_OBJS += storage.o LIB_OBJS += symbol.o diff --git a/linearize.h b/linearize.h index 7909b01f..86ae119c 100644 --- a/linearize.h +++ b/linearize.h @@ -18,7 +18,7 @@ struct pseudo_user { DECLARE_ALLOCATOR(pseudo_user); DECLARE_PTR_LIST(pseudo_user_list, struct pseudo_user); -DECLARE_PTRMAP(phi_map, struct symbol *, pseudo_t); +DECLARE_PTRMAP(phi_map, struct symbol *, struct instruction *); enum pseudo_type { @@ -1653,7 +1653,7 @@ static bool match_attribute(struct token *token) if (token_type(token) != TOKEN_IDENT) return false; sym = lookup_keyword(token->ident, NS_TYPEDEF); - if (!sym) + if (!sym || !sym->op) return false; return sym->op->type & KW_ATTRIBUTE; } @@ -1258,6 +1258,104 @@ static int simplify_compare_constant(struct instruction *insn, long long value) src2 = insn->src2; value = src2->value; switch (DEF_OPCODE(def, src1)) { + case OP_AND: + if (!constant(def->src2)) + break; + bits = def->src2->value; + switch (insn->opcode) { + case OP_SET_EQ: + if ((value & bits) != value) + return replace_with_value(insn, 0); + break; + case OP_SET_NE: + if ((value & bits) != value) + return replace_with_value(insn, 1); + break; + case OP_SET_LE: + value = sign_extend(value, def->size); + if (bits & sign_bit(def->size)) + break; + if (value < 0) + return replace_with_value(insn, 0); + if (value >= (long long)bits) + return replace_with_value(insn, 1); + if (value == 0) + return replace_opcode(insn, OP_SET_EQ); + break; + case OP_SET_GT: + value = sign_extend(value, def->size); + if (bits & sign_bit(def->size)) + break; + if (value < 0) + return replace_with_value(insn, 1); + if (value >= (long long)bits) + return replace_with_value(insn, 0); + if (value == 0) + return replace_opcode(insn, OP_SET_NE); + break; + case OP_SET_B: + if (value > bits) + return replace_with_value(insn, 1); + break; + case OP_SET_BE: + if (value >= bits) + return replace_with_value(insn, 1); + break; + case OP_SET_AE: + if (value > bits) + return replace_with_value(insn, 0); + break; + case OP_SET_A: + if (value >= bits) + return replace_with_value(insn, 0); + break; + } + break; + case OP_OR: + if (!constant(def->src2)) + break; + bits = def->src2->value; + switch (insn->opcode) { + case OP_SET_EQ: + if ((value & bits) != bits) + return replace_with_value(insn, 0); + break; + case OP_SET_NE: + if ((value & bits) != bits) + return replace_with_value(insn, 1); + break; + case OP_SET_B: + if (bits >= value) + return replace_with_value(insn, 0); + break; + case OP_SET_BE: + if (bits > value) + return replace_with_value(insn, 0); + break; + case OP_SET_AE: + if (bits > value) + return replace_with_value(insn, 1); + break; + case OP_SET_A: + if (bits >= value) + return replace_with_value(insn, 1); + break; + case OP_SET_LE: + value = sign_extend(value, def->size); + if (bits & sign_bit(def->size)) { + if (value >= -1) + return replace_with_value(insn, 1); + } + break; + case OP_SET_GT: + value = sign_extend(value, def->size); + if (bits & sign_bit(def->size)) { + if (value >= -1) + return replace_with_value(insn, 0); + } + break; + } + break; case OP_SEXT: // sext(x) cmp C --> x cmp trunc(C) osize = def->orig_type->bit_size; if (is_signed_constant(value, osize, size)) { @@ -7,7 +7,6 @@ #include <assert.h> #include "ssa.h" #include "lib.h" -#include "sset.h" #include "dominate.h" #include "flowgraph.h" #include "linearize.h" @@ -33,6 +32,9 @@ static inline bool is_promotable(struct symbol *type) case SYM_STRUCT: // we allow a single scalar field // but a run of bitfields count for 1 + // (and packed bifields are excluded). + if (type->packed) + return 0; nbr = 0; bf_seen = 0; FOR_EACH_PTR(type->symbol_list, member) { @@ -72,21 +74,6 @@ static inline bool is_promotable(struct symbol *type) return 0; } -static bool insn_before(struct instruction *a, struct instruction *b) -{ - struct basic_block *bb = a->bb; - struct instruction *insn; - - assert(b->bb == bb); - FOR_EACH_PTR(bb->insns, insn) { - if (insn == a) - return true; - if (insn == b) - return false; - } END_FOR_EACH_PTR(insn); - assert(0); -} - static void kill_store(struct instruction *insn) { remove_use(&insn->src); @@ -94,10 +81,22 @@ static void kill_store(struct instruction *insn) insn->bb = NULL; } +static bool same_memop(struct instruction *a, struct instruction *b) +{ + if (a->size != b->size || a->offset != b->offset) + return false; + if (is_integral_type(a->type) && is_float_type(b->type)) + return false; + if (is_float_type(a->type) && is_integral_type(b->type)) + return false; + return true; +} + static void rewrite_local_var(struct basic_block *bb, pseudo_t addr, int nbr_stores, int nbr_uses) { + struct instruction *store = NULL; struct instruction *insn; - pseudo_t val = NULL; + bool remove = false; if (!bb) return; @@ -108,71 +107,32 @@ static void rewrite_local_var(struct basic_block *bb, pseudo_t addr, int nbr_sto continue; switch (insn->opcode) { case OP_LOAD: - if (!val) - val = undef_pseudo(); - replace_with_pseudo(insn, val); + if (!store) + replace_with_pseudo(insn, undef_pseudo()); + else if (same_memop(store, insn)) + replace_with_pseudo(insn, store->target); + else + remove = false; break; case OP_STORE: - val = insn->target; - // can't use kill_instruction() unless - // we add a fake user to val - kill_store(insn); + store = insn; + remove = true; break; } } END_FOR_EACH_PTR(insn); + if (remove) + kill_store(store); } -static bool rewrite_single_store(struct instruction *store) -{ - pseudo_t addr = store->src; - struct pseudo_user *pu; - - FOR_EACH_PTR(addr->users, pu) { - struct instruction *insn = pu->insn; - - if (insn->opcode != OP_LOAD) - continue; - - // Let's try to replace the value of the load - // by the value from the store. This is only valid - // if the store dominate the load. - - if (insn->bb == store->bb) { - // the load and the store are in the same BB - // we can convert if the load is after the store. - if (!insn_before(store, insn)) - continue; - } else if (!domtree_dominates(store->bb, insn->bb)) { - // we can't convert this load - continue; - } - - // OK, we can rewrite this load - - // undefs ? - - replace_with_pseudo(insn, store->target); - } END_FOR_EACH_PTR(pu); - - // is there some unconverted loads? - if (pseudo_user_list_size(addr->users) > 1) - return false; - - kill_store(store); - return true; -} - -static struct sset *processed; - // we would like to know: // is there one or more stores? // are all loads & stores local/done in a single block? static void ssa_convert_one_var(struct entrypoint *ep, struct symbol *var) { + unsigned long generation = ++bb_generation; struct basic_block_list *alpha = NULL; struct basic_block_list *idf = NULL; struct basic_block *samebb = NULL; - struct instruction *store = NULL; struct basic_block *bb; struct pseudo_user *pu; unsigned long mod = var->ctype.modifiers; @@ -199,7 +159,6 @@ static void ssa_convert_one_var(struct entrypoint *ep, struct symbol *var) return; // 1) insert in the worklist all BBs that may modify var - sset_reset(processed); FOR_EACH_PTR(addr->users, pu) { struct instruction *insn = pu->insn; struct basic_block *bb = insn->bb; @@ -207,9 +166,10 @@ static void ssa_convert_one_var(struct entrypoint *ep, struct symbol *var) switch (insn->opcode) { case OP_STORE: nbr_stores++; - store = insn; - if (!sset_testset(processed, bb->nr)) + if (bb->generation != generation) { + bb->generation = generation; add_bb(&alpha, bb); + } /* fall through */ case OP_LOAD: if (local) { @@ -229,11 +189,6 @@ static void ssa_convert_one_var(struct entrypoint *ep, struct symbol *var) } } END_FOR_EACH_PTR(pu); - if (nbr_stores == 1) { - if (rewrite_single_store(store)) - return; - } - // if all uses are local to a single block // they can easily be rewritten and doesn't need phi-nodes // FIXME: could be done for extended BB too @@ -255,21 +210,40 @@ external_visibility: kill_dead_stores(ep, addr, !mod); } -static pseudo_t lookup_var(struct basic_block *bb, struct symbol *var) +static struct instruction *lookup_var(struct basic_block *bb, struct symbol *var) { do { - pseudo_t val = phi_map_lookup(bb->phi_map, var); - if (val) - return val; + struct instruction *insn = phi_map_lookup(bb->phi_map, var); + if (insn) + return insn; } while ((bb = bb->idom)); - return undef_pseudo(); + return NULL; } static struct instruction_list *phis_all; static struct instruction_list *phis_used; +static struct instruction_list *stores; + +static bool matching_load(struct instruction *def, struct instruction *insn) +{ + if (insn->size != def->size) + return false; + switch (def->opcode) { + case OP_STORE: + case OP_LOAD: + if (insn->offset != def->offset) + return false; + case OP_PHI: + break; + default: + return false; + } + return true; +} static void ssa_rename_insn(struct basic_block *bb, struct instruction *insn) { + struct instruction *def; struct symbol *var; pseudo_t addr; pseudo_t val; @@ -282,8 +256,8 @@ static void ssa_rename_insn(struct basic_block *bb, struct instruction *insn) var = addr->sym; if (!var || !var->torename) break; - phi_map_update(&bb->phi_map, var, insn->target); - kill_store(insn); + phi_map_update(&bb->phi_map, var, insn); + add_instruction(&stores, insn); break; case OP_LOAD: addr = insn->src; @@ -292,14 +266,22 @@ static void ssa_rename_insn(struct basic_block *bb, struct instruction *insn) var = addr->sym; if (!var || !var->torename) break; - val = lookup_var(bb, var); + def = lookup_var(bb, var); + if (!def) { + val = undef_pseudo(); + } else if (!matching_load(def, insn)) { + var->torename = false; + break; + } else { + val = def->target; + } replace_with_pseudo(insn, val); break; case OP_PHI: var = insn->type; if (!var || !var->torename) break; - phi_map_update(&bb->phi_map, var, insn->target); + phi_map_update(&bb->phi_map, var, insn); add_instruction(&phis_all, insn); break; } @@ -346,7 +328,8 @@ static void ssa_rename_phi(struct instruction *insn) return; FOR_EACH_PTR(insn->bb->parents, par) { struct instruction *term = delete_last_instruction(&par->insns); - pseudo_t val = lookup_var(par, var); + struct instruction *def = lookup_var(par, var); + pseudo_t val = def ? def->target : undef_pseudo(); pseudo_t phi = alloc_phi(par, val, var); phi->ident = var->ident; add_instruction(&par->insns, term); @@ -374,6 +357,18 @@ static void ssa_rename_phis(struct entrypoint *ep) } END_FOR_EACH_PTR(phi); } +static void remove_dead_stores(struct instruction_list *stores) +{ + struct instruction *store; + + FOR_EACH_PTR(stores, store) { + struct symbol *var = store->addr->sym; + + if (var->torename) + kill_store(store); + } END_FOR_EACH_PTR(store); +} + void ssa_convert(struct entrypoint *ep) { struct basic_block *bb; @@ -390,9 +385,8 @@ void ssa_convert(struct entrypoint *ep) bb->phi_map = NULL; } END_FOR_EACH_PTR(bb); - processed = sset_init(first, last); - // try to promote memory accesses to pseudos + stores = NULL; FOR_EACH_PTR(ep->accesses, pseudo) { ssa_convert_one_var(ep, pseudo->sym); } END_FOR_EACH_PTR(pseudo); @@ -401,4 +395,7 @@ void ssa_convert(struct entrypoint *ep) phis_all = phis_used = NULL; ssa_rename_insns(ep); ssa_rename_phis(ep); + + // remove now dead stores + remove_dead_stores(stores); } diff --git a/sset.c b/sset.c deleted file mode 100644 index e9681e00..00000000 --- a/sset.c +++ /dev/null @@ -1,28 +0,0 @@ -// SPDX-License-Identifier: MIT -// -// sset.c - an all O(1) implementation of sparse sets as presented in: -// "An Efficient Representation for Sparse Sets" -// by Preston Briggs and Linda Torczon -// -// Copyright (C) 2017 - Luc Van Oostenryck - -#include "sset.h" -#include "lib.h" -#include <stdlib.h> - - -struct sset *sset_init(unsigned int first, unsigned int last) -{ - unsigned int size = last - first + 1; - struct sset *s = malloc(sizeof(*s) + size * 2 * sizeof(s->sets[0])); - - s->size = size; - s->off = first; - s->nbr = 0; - return s; -} - -void sset_free(struct sset *s) -{ - free(s); -} diff --git a/sset.h b/sset.h deleted file mode 100644 index 69cee18a..00000000 --- a/sset.h +++ /dev/null @@ -1,56 +0,0 @@ -// SPDX-License-Identifier: MIT - -#ifndef SSET_H -#define SSET_H - -/* - * sset.h - an all O(1) implementation of sparse sets as presented in: - * "An Efficient Representation for Sparse Sets" - * by Preston Briggs and Linda Torczon - * - * Copyright (C) 2017 - Luc Van Oostenryck - */ - -#include <stdbool.h> - -struct sset { - unsigned int nbr; - unsigned int off; - unsigned int size; - unsigned int sets[0]; -}; - -extern struct sset *sset_init(unsigned int size, unsigned int off); -extern void sset_free(struct sset *s); - - -static inline void sset_reset(struct sset *s) -{ - s->nbr = 0; -} - -static inline void sset_add(struct sset *s, unsigned int idx) -{ - unsigned int __idx = idx - s->off; - unsigned int n = s->nbr++; - s->sets[__idx] = n; - s->sets[s->size + n] = __idx; -} - -static inline bool sset_test(struct sset *s, unsigned int idx) -{ - unsigned int __idx = idx - s->off; - unsigned int n = s->sets[__idx]; - - return (n < s->nbr) && (s->sets[s->size + n] == __idx); -} - -static inline bool sset_testset(struct sset *s, unsigned int idx) -{ - if (sset_test(s, idx)) - return true; - sset_add(s, idx); - return false; -} - -#endif diff --git a/validation/knr-attr-crash.c b/validation/knr-attr-crash.c new file mode 100644 index 00000000..176ff503 --- /dev/null +++ b/validation/knr-attr-crash.c @@ -0,0 +1,12 @@ +typedef int word; + +void foo(word x); + +void foo(x) + word x; +{ } + +/* + * check-name: knr-attr-crash + * check-command: sparse -Wno-old-style-definition $file + */ diff --git a/validation/mem2reg/not-same-memop0.c b/validation/mem2reg/not-same-memop0.c new file mode 100644 index 00000000..4de98195 --- /dev/null +++ b/validation/mem2reg/not-same-memop0.c @@ -0,0 +1,48 @@ +struct s { + int:16; + short f:6; +}; + +static short local(struct s s) +{ + return s.f; +} + +static void foo(struct s s) +{ + while (s.f) ; +} + +/* + * check-name: not-same-memop0 + * check-command: test-linearize -Wno-decl -fdump-ir=mem2reg $file + * + * check-output-start +local: +.L0: + <entry-point> + store.32 %arg1 -> 0[s] + load.16 %r1 <- 2[s] + trunc.6 %r2 <- (16) %r1 + sext.16 %r3 <- (6) %r2 + ret.16 %r3 + + +foo: +.L2: + <entry-point> + store.32 %arg1 -> 0[s] + br .L6 + +.L6: + load.16 %r5 <- 2[s] + trunc.6 %r6 <- (16) %r5 + setne.1 %r7 <- %r6, $0 + cbr %r7, .L6, .L5 + +.L5: + ret + + + * check-output-end + */ diff --git a/validation/mem2reg/packed-bitfield.c b/validation/mem2reg/packed-bitfield.c new file mode 100644 index 00000000..f3ee259a --- /dev/null +++ b/validation/mem2reg/packed-bitfield.c @@ -0,0 +1,35 @@ +struct s { + int:16; + int f:16; +} __attribute__((__packed__)); + +static void foo(struct s s) +{ + while (s.f) + ; +} + +/* + * check-name: packed-bitfield + * check-command: test-linearize -fmem2reg $file + * + * check-output-contains: store.32 + * check-output-contains: load.16 + * + * check-output-start +foo: +.L0: + <entry-point> + store.32 %arg1 -> 0[s] + br .L4 + +.L4: + load.16 %r1 <- 2[s] + cbr %r1, .L4, .L3 + +.L3: + ret + + + * check-output-end + */ diff --git a/validation/optim/cmpe-and0.c b/validation/optim/cmpe-and0.c new file mode 100644 index 00000000..75af7752 --- /dev/null +++ b/validation/optim/cmpe-and0.c @@ -0,0 +1,10 @@ +int cmpe_and_eq(int a) { return ((a & 0xff00) == 0xff01) + 1; } +int cmpe_and_ne(int a) { return ((a & 0xff00) != 0xff01) + 0; } + +/* + * check-name: cmpe-and0 + * check-command: test-linearize -Wno-decl $file + * + * check-output-ignore + * check-output-returns: 1 + */ diff --git a/validation/optim/cmpe-or0.c b/validation/optim/cmpe-or0.c new file mode 100644 index 00000000..2e89d611 --- /dev/null +++ b/validation/optim/cmpe-or0.c @@ -0,0 +1,10 @@ +int cmp_eq(int a) { return ((a | 1) != 0) + 0; } +int cmp_ne(int a) { return ((a | 1) == 0) + 1; } + +/* + * check-name: cmpe-or0 + * check-command: test-linearize -Wno-decl $file + * + * check-output-ignore + * check-output-returns: 1 + */ diff --git a/validation/optim/cmps-and0.c b/validation/optim/cmps-and0.c new file mode 100644 index 00000000..962fbd2d --- /dev/null +++ b/validation/optim/cmps-and0.c @@ -0,0 +1,21 @@ +#define MINUS_ONE -1 +#define MASK 32 + + +int cmps_and_lt_lt0(int a) { return ((a & MASK) < MINUS_ONE) + 1; } +int cmps_and_lt_gtm(int a) { return ((a & MASK) < (MASK + 1)) + 0; } +int cmps_and_le_lt0(int a) { return ((a & MASK) <= MINUS_ONE) + 1; } +int cmps_and_le_gtm(int a) { return ((a & MASK) <= (MASK + 1)) + 0; } + +int cmps_and_gt_lt0(int a) { return ((a & MASK) > MINUS_ONE) + 0; } +int cmps_and_gt_gtm(int a) { return ((a & MASK) > (MASK + 1)) + 1; } +int cmps_and_ge_lt0(int a) { return ((a & MASK) >= MINUS_ONE) + 0; } +int cmps_and_ge_gtm(int a) { return ((a & MASK) >= (MASK + 1)) + 1; } + +/* + * check-name: cmps-and0 + * check-command: test-linearize -Wno-decl $file + * + * check-output-ignore + * check-output-returns: 1 + */ diff --git a/validation/optim/cmps-minmax.c b/validation/optim/cmps-minmax.c index 5802cdbc..0b1a0a09 100644 --- a/validation/optim/cmps-minmax.c +++ b/validation/optim/cmps-minmax.c @@ -1,11 +1,11 @@ #define SMAX __INT_MAX__ #define SMIN (-__INT_MAX__-1) -int lt_smin(int a) { return (a < SMIN) == 0; } -int le_smax(int a) { return (a <= SMAX) == 1; } +int lt_smin(int a) { return (a < SMIN) + 1; } +int le_smax(int a) { return (a <= SMAX) + 0; } -int ge_smin(int a) { return (a >= SMIN) == 1; } -int gt_smax(int a) { return (a > SMAX) == 0; } +int ge_smin(int a) { return (a >= SMIN) + 0; } +int gt_smax(int a) { return (a > SMAX) + 1; } /* * check-name: cmps-minmax diff --git a/validation/optim/cmps-or0.c b/validation/optim/cmps-or0.c new file mode 100644 index 00000000..70fcb024 --- /dev/null +++ b/validation/optim/cmps-or0.c @@ -0,0 +1,21 @@ +#define EQ(X) + (X == 0) +#define SIGN (1 << 31) +#define MASK (SIGN | 32) + + +int cmps_ior_lt_x(int a) { return ((a | MASK) < 4) EQ(1); } +int cmps_ior_lt_0(int a) { return ((a | MASK) < 0) EQ(1); } +int cmps_ior_le_x(int a) { return ((a | MASK) <= 4) EQ(1); } +int cmps_ior_le_0(int a) { return ((a | MASK) <= 0) EQ(1); } +int cmps_ior_ge_x(int a) { return ((a | MASK) >= 4) EQ(0); } +int cmps_ior_ge_0(int a) { return ((a | MASK) >= 0) EQ(0); } +int cmps_ior_gt_x(int a) { return ((a | MASK) > 4) EQ(0); } +int cmps_ior_gt_0(int a) { return ((a | MASK) > 0) EQ(0); } + +/* + * check-name: cmps-or0 + * check-command: test-linearize -Wno-decl $file + * + * check-output-ignore + * check-output-returns: 1 + */ diff --git a/validation/optim/cmps0-and0.c b/validation/optim/cmps0-and0.c new file mode 100644 index 00000000..8316916a --- /dev/null +++ b/validation/optim/cmps0-and0.c @@ -0,0 +1,12 @@ +#define M 32 + +int cmps_and_sle0(int a) { return ((a & M) <= 0) == ((a & M) == 0); } +int cmps_and_sgt0(int a) { return ((a & M) > 0) == ((a & M) != 0); } + +/* + * check-name: cmps0-and + * check-command: test-linearize -Wno-decl $file + * + * check-output-ignore + * check-output-returns: 1 + */ diff --git a/validation/optim/cmpu-and0.c b/validation/optim/cmpu-and0.c new file mode 100644 index 00000000..927b9fb6 --- /dev/null +++ b/validation/optim/cmpu-and0.c @@ -0,0 +1,17 @@ +#define MASK 32U + + +int cmps_and_ltu_gt(int a) { return ((a & MASK) < (MASK + 1)) + 0; } +int cmps_and_leu_gt(int a) { return ((a & MASK) <= (MASK + 1)) + 0; } +int cmps_and_leu_eq(int a) { return ((a & MASK) <= (MASK + 0)) + 0; } +int cmps_and_geu_gt(int a) { return ((a & MASK) >= (MASK + 1)) + 1; } +int cmps_and_gtu_gt(int a) { return ((a & MASK) > (MASK + 1)) + 1; } +int cmps_and_gtu_eq(int a) { return ((a & MASK) > (MASK + 0)) + 1; } + +/* + * check-name: cmpu-and0 + * check-command: test-linearize -Wno-decl $file + * + * check-output-ignore + * check-output-returns: 1 + */ diff --git a/validation/optim/cmpu-or0.c b/validation/optim/cmpu-or0.c new file mode 100644 index 00000000..e97e9180 --- /dev/null +++ b/validation/optim/cmpu-or0.c @@ -0,0 +1,18 @@ +#define EQ(X) + (X == 0) +#define MASK 32U + + +int cmpu_ior_lt_lt(int a) { return ((a | MASK) < (MASK - 1)) EQ(0); } +int cmpu_ior_lt_eq(int a) { return ((a | MASK) < (MASK )) EQ(0); } +int cmpu_ior_le_lt(int a) { return ((a | MASK) <= (MASK - 1)) EQ(0); } +int cmpu_ior_ge_lt(int a) { return ((a | MASK) >= (MASK - 1)) EQ(1); } +int cmpu_ior_ge_eq(int a) { return ((a | MASK) >= (MASK )) EQ(1); } +int cmpu_ior_gt_lt(int a) { return ((a | MASK) > (MASK - 1)) EQ(1); } + +/* + * check-name: cmpu-or0 + * check-command: test-linearize -Wno-decl $file + * + * check-output-ignore + * check-output-returns: 1 + */ diff --git a/validation/test-suite b/validation/test-suite index 2f7950ef..305edd1f 100755 --- a/validation/test-suite +++ b/validation/test-suite @@ -515,6 +515,7 @@ echo "options:" echo " -a append the created test to the input file" echo " -f write a test known to fail" echo " -l write a test for linearized code" +echo " -r write a test for linearized code returning 1" echo " -p write a test for pre-processing" echo " -s write a test for symbolic checking" echo @@ -532,6 +533,7 @@ do_format() append=0 linear=0 fail=0 + ret='' while [ $# -gt 0 ] ; do case "$1" in @@ -542,6 +544,9 @@ do_format() -l) def_cmd='test-linearize -Wno-decl $file' linear=1 ;; + -r) + def_cmd='test-linearize -Wno-decl $file' + ret=1 ;; -p) def_cmd='sparse -E $file' ;; -s) @@ -588,6 +593,12 @@ _EOF if [ $fail != 0 ]; then echo " * check-known-to-fail" fi + if [ "$ret" != '' ]; then + echo ' *' + echo ' * check-output-ignore' + echo " * check-output-returns: $ret" + rm -f "$file.output.got" + fi if [ $linear != 0 ]; then echo ' *' echo ' * check-output-ignore' |