diff options
29 files changed, 537 insertions, 57 deletions
diff --git a/Documentation/api.rst b/Documentation/api.rst index cb8a0982..22b7dfd2 100644 --- a/Documentation/api.rst +++ b/Documentation/api.rst @@ -10,6 +10,7 @@ Utilities .. c:autodoc:: ptrlist.c .. c:autodoc:: utils.h +.. c:autodoc:: flowgraph.h Parsing ~~~~~~~ @@ -24,4 +25,6 @@ Typing Optimization ~~~~~~~~~~~~ +.. c:autodoc:: optimize.c +.. c:autodoc:: flow.c .. c:autodoc:: simplify.c diff --git a/Documentation/doc-guide.rst b/Documentation/doc-guide.rst index 29f39aab..fb4cb322 100644 --- a/Documentation/doc-guide.rst +++ b/Documentation/doc-guide.rst @@ -138,7 +138,7 @@ For example, a doc-block like:: will be displayed like this: .. c:function:: int inc(int val) - :noindex: + :noindexentry: :param val: the value to increment :return: the incremented value diff --git a/Documentation/sphinx/cdoc.py b/Documentation/sphinx/cdoc.py index 73c128cb..cca5ad28 100755 --- a/Documentation/sphinx/cdoc.py +++ b/Documentation/sphinx/cdoc.py @@ -228,8 +228,9 @@ def convert_to_rst(info): if 'short' in info: (n, l) = info['short'] l = l[0].capitalize() + l[1:].strip('.') - l = '\t' + l + '.' - lst.append((n, l + '\n')) + if l[-1] != '?': + l = l + '.' + lst.append((n, '\t' + l + '\n')) if 'tags' in info: for (n, name, l) in info.get('tags', []): if name != 'return': @@ -61,6 +61,20 @@ static inline int valid_subexpr_type(struct expression *expr) && valid_expr_type(expr->right); } +static struct symbol *unqualify_type(struct symbol *ctype) +{ + if (!ctype) + return ctype; + if (ctype->type == SYM_NODE && (ctype->ctype.modifiers & MOD_QUALIFIER)) { + struct symbol *unqual = alloc_symbol(ctype->pos, 0); + + *unqual = *ctype; + unqual->ctype.modifiers &= ~MOD_QUALIFIER; + return unqual; + } + return ctype; +} + static struct symbol *evaluate_symbol_expression(struct expression *expr) { struct expression *addr; @@ -1014,7 +1028,7 @@ static struct symbol *evaluate_binop(struct expression *expr) static struct symbol *evaluate_comma(struct expression *expr) { - expr->ctype = degenerate(expr->right); + expr->ctype = unqualify_type(degenerate(expr->right)); if (expr->ctype == &null_ctype) expr->ctype = &ptr_ctype; expr->flags &= expr->left->flags & expr->right->flags; @@ -1907,8 +1921,7 @@ static struct symbol *evaluate_postop(struct expression *expr) return NULL; } - if ((class & TYPE_RESTRICT) && restricted_unop(expr->op, &ctype)) - unrestrict(expr, class, &ctype); + unrestrict(expr, class, &ctype); if (class & TYPE_NUM) { multiply = 1; @@ -3025,6 +3038,7 @@ static struct symbol *evaluate_cast(struct expression *expr) return evaluate_compound_literal(expr, source); ctype = examine_symbol_type(expr->cast_type); + ctype = unqualify_type(ctype); expr->ctype = ctype; expr->cast_type = ctype; @@ -3935,7 +3949,7 @@ struct symbol *evaluate_statement(struct statement *stmt) return NULL; if (stmt->expression->ctype == &null_ctype) stmt->expression = cast_to(stmt->expression, &ptr_ctype); - return degenerate(stmt->expression); + return unqualify_type(degenerate(stmt->expression)); case STMT_COMPOUND: { struct statement *s; @@ -1,10 +1,11 @@ /* - * Flow - walk the linearized flowgraph, simplifying it as we - * go along. - * * Copyright (C) 2004 Linus Torvalds */ +/// +// Flow simplification +// ------------------- + #include <string.h> #include <stdarg.h> #include <stdlib.h> @@ -17,6 +18,7 @@ #include "linearize.h" #include "flow.h" #include "target.h" +#include "flowgraph.h" unsigned long bb_generation; @@ -43,6 +45,25 @@ static int rewrite_branch(struct basic_block *bb, return 1; } +/// +// returns the phi-node corresponding to a phi-source +static struct instruction *get_phinode(struct instruction *phisrc) +{ + struct pseudo_user *pu; + + FOR_EACH_PTR(phisrc->target->users, pu) { + struct instruction *user; + + if (!pu) + continue; + user = pu->insn; + assert(user->opcode == OP_PHI); + return user; + } END_FOR_EACH_PTR(pu); + assert(0); +} + + /* * Return the known truth value of a pseudo, or -1 if * it's not known. @@ -66,6 +87,34 @@ static int pseudo_truth_value(pseudo_t pseudo) } } +/// +// check if the BB is empty or only contains phi-sources +static int bb_is_trivial(struct basic_block *bb) +{ + struct instruction *insn; + int n = 0; + + FOR_EACH_PTR(bb->insns, insn) { + if (!insn->bb) + continue; + switch (insn->opcode) { + case OP_TERMINATOR ... OP_TERMINATOR_END: + return n ? -1 : 1; + case OP_NOP: + case OP_INLINED_CALL: + continue; + case OP_PHISOURCE: + n++; + continue; + default: + goto out; + } + } END_FOR_EACH_PTR(insn); + +out: + return 0; +} + /* * Does a basic block depend on the pseudos that "src" defines? */ @@ -102,6 +151,106 @@ static int bb_depends_on_phi(struct basic_block *target, struct basic_block *src return 0; } +/// +// does the BB contains ignorable instructions but a final branch? +// :note: something could be done for phi-sources but ... we'll see. +static bool bb_is_forwarder(struct basic_block *bb) +{ + struct instruction *insn; + + FOR_EACH_PTR(bb->insns, insn) { + if (!insn->bb) + continue; + switch (insn->opcode) { + case OP_NOP: + case OP_INLINED_CALL: + continue; + case OP_CBR: + case OP_BR: + return true; + default: + goto out; + } + } END_FOR_EACH_PTR(insn); +out: + return false; +} + +/// +// do jump threading in dominated BBs +// @dom: the BB which must dominate the modified BBs. +// @old: the old target BB +// @new: the new target BB +// @return: 0 if no chnages have been made, 1 otherwise. +// +// In all BB dominated by @dom, rewrite branches to @old into branches to @new +static int retarget_bb(struct basic_block *dom, struct basic_block *old, struct basic_block *new) +{ + struct basic_block *bb; + int changed = 0; + + if (new == old) + return 0; + +restart: + FOR_EACH_PTR(old->parents, bb) { + struct instruction *last; + struct multijmp *jmp; + + if (!domtree_dominates(dom, bb)) + continue; + last = last_instruction(bb->insns); + switch (last->opcode) { + case OP_BR: + changed |= rewrite_branch(bb, &last->bb_true, old, new); + break; + case OP_CBR: + changed |= rewrite_branch(bb, &last->bb_true, old, new); + changed |= rewrite_branch(bb, &last->bb_false, old, new); + break; + case OP_SWITCH: + case OP_COMPUTEDGOTO: + FOR_EACH_PTR(last->multijmp_list, jmp) { + changed |= rewrite_branch(bb, &jmp->target, old, new); + } END_FOR_EACH_PTR(jmp); + break; + default: + continue; + } + + // since rewrite_branch() will modify old->parents() the list + // iteration won't work correctly. Several solution exist for + // this but in this case the simplest is to restart the loop. + goto restart; + } END_FOR_EACH_PTR(bb); + return changed; +} + +static int simplify_cbr_cbr(struct instruction *insn) +{ + struct instruction *last; + struct basic_block *bot = insn->bb; + struct basic_block *top = bot->idom; + int changed = 0; + int trivial; + + if (!top) + return 0; + + trivial = bb_is_trivial(bot); + if (trivial == 0) + return 0; + if (trivial < 0) + return 0; + last = last_instruction(top->insns); + if (last->opcode != OP_CBR || last->cond != insn->cond) + return 0; + + changed |= retarget_bb(last->bb_true , bot, insn->bb_true); + changed |= retarget_bb(last->bb_false, bot, insn->bb_false); + return changed; +} + /* * When we reach here, we have: * - a basic block that ends in a conditional branch and @@ -249,6 +398,8 @@ static int simplify_one_branch(struct basic_block *bb, struct instruction *br) { if (simplify_phi_branch(bb, br)) return 1; + if (simplify_cbr_cbr(br)) + return 1; return simplify_branch_branch(bb, br, &br->bb_true, 1) | simplify_branch_branch(bb, br, &br->bb_false, 0); } @@ -723,13 +874,145 @@ void vrfy_flow(struct entrypoint *ep) assert(!entry); } +static int retarget_parents(struct basic_block *bb, struct basic_block *target) +{ + struct basic_block *parent; + + /* + * We can't do FOR_EACH_PTR() here, because the parent list + * may change when we rewrite the parent. + */ + while ((parent = first_basic_block(bb->parents))) { + if (!rewrite_parent_branch(parent, bb, target)) + return 0; + } + kill_bb(bb); + return REPEAT_CFG_CLEANUP; +} + +static void remove_merging_phisrc(struct basic_block *top, struct instruction *insn) +{ + struct instruction *user = get_phinode(insn); + pseudo_t phi; + + FOR_EACH_PTR(user->phi_list, phi) { + struct instruction *phisrc; + + if (phi == VOID) + continue; + phisrc = phi->def; + if (phisrc->bb != top) + continue; + REPLACE_CURRENT_PTR(phi, VOID); + kill_instruction(phisrc); + } END_FOR_EACH_PTR(phi); +} + +static void remove_merging_phi(struct basic_block *top, struct instruction *insn) +{ + pseudo_t phi; + + FOR_EACH_PTR(insn->phi_list, phi) { + struct instruction *def; + + if (phi == VOID) + continue; + + def = phi->def; + if (def->bb != top) + continue; + + convert_instruction_target(insn, def->src); + kill_instruction(def); + kill_instruction(insn); + } END_FOR_EACH_PTR(phi); +} + +/// +// merge two BBs +// @top: the first BB to be merged +// @bot: the second BB to be merged +static int merge_bb(struct basic_block *top, struct basic_block *bot) +{ + struct instruction *insn; + struct basic_block *bb; + + if (top == bot) + return 0; + + top->children = bot->children; + bot->children = NULL; + bot->parents = NULL; + + FOR_EACH_PTR(top->children, bb) { + replace_bb_in_list(&bb->parents, bot, top, 1); + } END_FOR_EACH_PTR(bb); + + kill_instruction(delete_last_instruction(&top->insns)); + FOR_EACH_PTR(bot->insns, insn) { + if (!insn->bb) + continue; + assert(insn->bb == bot); + switch (insn->opcode) { + case OP_PHI: + remove_merging_phi(top, insn); + continue; + case OP_PHISOURCE: + remove_merging_phisrc(top, insn); + break; + } + insn->bb = top; + add_instruction(&top->insns, insn); + } END_FOR_EACH_PTR(insn); + bot->insns = NULL; + bot->ep = NULL; + return REPEAT_CFG_CLEANUP; +} + +/// +// early simplification of the CFG +// Three things are done here: +// # inactive BB are removed +// # branches to a 'forwarder' BB are redirected to the forwardee. +// # merge single-child/single-parent BBs. +int simplify_cfg_early(struct entrypoint *ep) +{ + struct basic_block *bb; + int changed = 0; + + FOR_EACH_PTR_REVERSE(ep->bbs, bb) { + struct instruction *insn; + struct basic_block *tgt; + + if (!bb->ep) { + DELETE_CURRENT_PTR(bb); + changed = REPEAT_CFG_CLEANUP; + continue; + } + + insn = last_instruction(bb->insns); + if (!insn) + continue; + switch (insn->opcode) { + case OP_BR: + tgt = insn->bb_true; + if (bb_is_forwarder(bb)) + changed |= retarget_parents(bb, tgt); + else if (bb_list_size(tgt->parents) == 1) + changed |= merge_bb(bb, tgt); + break; + } + } END_FOR_EACH_PTR_REVERSE(bb); + return changed; +} + void pack_basic_blocks(struct entrypoint *ep) { struct basic_block *bb; /* See if we can merge a bb into another one.. */ FOR_EACH_PTR(ep->bbs, bb) { - struct instruction *first, *insn; + struct instruction *first; struct basic_block *parent, *child, *last; if (!bb_reachable(bb)) @@ -786,28 +1069,7 @@ out: goto no_merge; } END_FOR_EACH_PTR(child); - /* - * Merge the two. - */ - repeat_phase |= REPEAT_CFG_CLEANUP; - - parent->children = bb->children; - bb->children = NULL; - bb->parents = NULL; - - FOR_EACH_PTR(parent->children, child) { - replace_bb_in_list(&child->parents, bb, parent, 0); - } END_FOR_EACH_PTR(child); - - kill_instruction(delete_last_instruction(&parent->insns)); - FOR_EACH_PTR(bb->insns, insn) { - if (!insn->bb) - continue; - assert(insn->bb == bb); - insn->bb = parent; - add_instruction(&parent->insns, insn); - } END_FOR_EACH_PTR(insn); - bb->insns = NULL; + repeat_phase |= merge_bb(parent, bb); no_merge: /* nothing to do */; @@ -18,6 +18,7 @@ extern void kill_dead_stores(struct entrypoint *ep, pseudo_t addr, int local); extern void simplify_symbol_usage(struct entrypoint *ep); extern void simplify_memops(struct entrypoint *ep); extern void pack_basic_blocks(struct entrypoint *ep); +extern int simplify_cfg_early(struct entrypoint *ep); extern void convert_instruction_target(struct instruction *insn, pseudo_t src); extern void remove_dead_insns(struct entrypoint *); diff --git a/flowgraph.h b/flowgraph.h index 7226c55f..5a9c2607 100644 --- a/flowgraph.h +++ b/flowgraph.h @@ -1,13 +1,33 @@ #ifndef FLOWGRAPH_H #define FLOWGRAPH_H +/// +// Utilities for flowgraphs +// ------------------------ + #include <stdbool.h> struct entrypoint; struct basic_block; +/// +// Set the BB's reverse postorder links +// Each BB will also have its 'order number' set. int cfg_postorder(struct entrypoint *ep); + +/// +// Build the dominance tree. +// Each BB will then have: +// - a link to its immediate dominator (::idom) +// - the list of BB it immediately dominates (::doms) +// - its level in the dominance tree (::dom_level) void domtree_build(struct entrypoint *ep); + +/// +// Test the dominance between two basic blocks. +// @a: the basic block expected to dominate +// @b: the basic block expected to be dominated +// @return: ``true`` if @a dominates @b, ``false`` otherwise. bool domtree_dominates(struct basic_block *a, struct basic_block *b); #endif diff --git a/linearize.c b/linearize.c index 4391f09c..8a3cf09b 100644 --- a/linearize.c +++ b/linearize.c @@ -28,12 +28,8 @@ static pseudo_t linearize_expression(struct entrypoint *ep, struct expression *e static pseudo_t add_cast(struct entrypoint *ep, struct symbol *to, struct symbol *from, int op, pseudo_t src); static pseudo_t add_binary_op(struct entrypoint *ep, struct symbol *ctype, int op, pseudo_t left, pseudo_t right); -static pseudo_t add_setval(struct entrypoint *ep, struct symbol *ctype, struct expression *val); static pseudo_t linearize_one_symbol(struct entrypoint *ep, struct symbol *sym); -struct access_data; -static pseudo_t add_load(struct entrypoint *ep, struct access_data *); -static pseudo_t linearize_initializer(struct entrypoint *ep, struct expression *initializer, struct access_data *); static pseudo_t cast_pseudo(struct entrypoint *ep, pseudo_t src, struct symbol *from, struct symbol *to); struct pseudo void_pseudo = {}; @@ -732,6 +728,7 @@ void insert_branch(struct basic_block *bb, struct instruction *jmp, struct basic remove_parent(child, bb); } END_FOR_EACH_PTR(child); PACK_PTR_LIST(&bb->children); + repeat_phase |= REPEAT_CFG_CLEANUP; } @@ -146,10 +146,12 @@ static void simplify_loads(struct basic_block *bb) } rewrite_load_instruction(insn, dominators); } else { // cleanup pending phi-sources + int repeat = repeat_phase; pseudo_t phi; FOR_EACH_PTR(dominators, phi) { kill_instruction(phi->def); } END_FOR_EACH_PTR(phi); + repeat_phase = repeat; } } next_load: @@ -1,10 +1,12 @@ // SPDX-License-Identifier: MIT // -// optimize.c - main optimization loop -// // Copyright (C) 2004 Linus Torvalds // Copyright (C) 2004 Christopher Li +/// +// Optimization main loop +// ---------------------- + #include <assert.h> #include "optimize.h" #include "flowgraph.h" @@ -45,6 +47,14 @@ static void clean_up_insns(struct entrypoint *ep) } END_FOR_EACH_PTR(bb); } +static void cleanup_cfg(struct entrypoint *ep) +{ + kill_unreachable_bbs(ep); + domtree_build(ep); +} + +/// +// optimization main loop void optimize(struct entrypoint *ep) { if (fdump_ir & PASS_LINEARIZE) @@ -57,6 +67,11 @@ void optimize(struct entrypoint *ep) kill_unreachable_bbs(ep); ir_validate(ep); + cfg_postorder(ep); + if (simplify_cfg_early(ep)) + kill_unreachable_bbs(ep); + ir_validate(ep); + domtree_build(ep); /* @@ -84,13 +99,11 @@ repeat: kill_unreachable_bbs(ep); cse_eliminate(ep); - - if (repeat_phase & REPEAT_SYMBOL_CLEANUP) - simplify_memops(ep); + simplify_memops(ep); } while (repeat_phase); pack_basic_blocks(ep); if (repeat_phase & REPEAT_CFG_CLEANUP) - kill_unreachable_bbs(ep); + cleanup_cfg(ep); } while (repeat_phase); vrfy_flow(ep); @@ -110,7 +123,7 @@ repeat: if (simplify_flow(ep)) { clear_liveness(ep); if (repeat_phase & REPEAT_CFG_CLEANUP) - kill_unreachable_bbs(ep); + cleanup_cfg(ep); goto repeat; } @@ -7,6 +7,18 @@ /// // Pointer list manipulation // ------------------------- +// +// The data structure handled here is designed to hold pointers +// but two special cases need to be avoided or need special care: +// * NULL is used by {PREPARE,NEXT}_PTR_LIST() to indicate the end-of-list. +// Thus, NULL can't be stored in lists using this API but is fine to +// use with FOR_EACH_PTR() and its variants. +// * VOID is used to replace a removed pseudo 'usage'. Since phi-nodes +// (OP_PHI) use a list to store their operands, a VOID in a phi-node +// list must be ignored since it represents a removed operand. As +// consequence, VOIDs must never be used as phi-node operand. +// This is fine since phi-nodes make no sense with void values +// but VOID is also used for invalid types and in case of errors. #include <stdlib.h> #include <string.h> @@ -2049,7 +2049,7 @@ static int simplify_branch(struct instruction *insn) kill_use(&insn->cond); insn->cond = NULL; insn->opcode = OP_BR; - return REPEAT_CSE; + return REPEAT_CSE|REPEAT_CFG_CLEANUP; } /* Conditional on a SETNE $0 or SETEQ $0 */ diff --git a/validation/call-inlined.c b/validation/call-inlined.c index 3612c5c4..a6cb4b5b 100644 --- a/validation/call-inlined.c +++ b/validation/call-inlined.c @@ -28,12 +28,14 @@ foo: <entry-point> add.32 %r3 <- %arg1, %arg2 add.32 %r5 <- %r3, $1 + # call %r6 <- add, %r3, $1 ret.32 %r5 bar: .L3: <entry-point> + # call %r13 <- add, %r10, $1 ret @@ -41,6 +43,7 @@ bas: .L6: <entry-point> add.64 %r16 <- "abc", $1 + # call %r17 <- lstrip, %r14 ret.64 %r16 @@ -48,6 +51,7 @@ qus: .L9: <entry-point> add.64 %r21 <- messg, $1 + # call %r22 <- lstrip, %r19 ret.64 %r21 diff --git a/validation/eval/unqual-cast.c b/validation/eval/unqual-cast.c new file mode 100644 index 00000000..4106ec3b --- /dev/null +++ b/validation/eval/unqual-cast.c @@ -0,0 +1,14 @@ +#define cvr const volatile restrict + +_Static_assert([typeof((cvr int) 0)] == [int]); +_Static_assert([typeof((cvr int *) 0)] == [cvr int *]); + +static int *function(volatile int x) +{ + extern typeof((typeof(x)) (x)) y; + return &y; +} + +/* + * check-name: unqual-cast + */ diff --git a/validation/eval/unqual-comma.c b/validation/eval/unqual-comma.c new file mode 100644 index 00000000..11546d22 --- /dev/null +++ b/validation/eval/unqual-comma.c @@ -0,0 +1,12 @@ +#define __unqual_typeof(x) typeof(((void)0, (x))) + +int *foo(volatile int x); +int *foo(volatile int x) +{ + extern __unqual_typeof(x) y; + return &y; +} + +/* + * check-name: unqual-comma + */ diff --git a/validation/eval/unqual-postop.c b/validation/eval/unqual-postop.c new file mode 100644 index 00000000..fb3082dc --- /dev/null +++ b/validation/eval/unqual-postop.c @@ -0,0 +1,23 @@ +static void test_volatile(void) +{ + volatile int x = 0; + int *pp; + + typeof(++x) v1; pp = &v1; // KO + typeof(x++) v2; pp = &v2; // KO +} + +/* + * check-name: unqual-postop + * check-command: sparse -Wno-declaration-after-statement $file + * check-known-to-fail + * + * check-error-start +eval/unqual-postop.c:6:40: warning: incorrect type in assignment (different modifiers) +eval/unqual-postop.c:6:40: expected int *pp +eval/unqual-postop.c:6:40: got int volatile * +eval/unqual-postop.c:7:40: warning: incorrect type in assignment (different modifiers) +eval/unqual-postop.c:7:40: expected int *pp +eval/unqual-postop.c:7:40: got int volatile * + * check-error-end + */ diff --git a/validation/eval/unqual-stmt-expr.c b/validation/eval/unqual-stmt-expr.c new file mode 100644 index 00000000..280c2fe8 --- /dev/null +++ b/validation/eval/unqual-stmt-expr.c @@ -0,0 +1,12 @@ +#define __unqual_typeof(x) typeof(({ x; })) + +int *foo(volatile int x); +int *foo(volatile int x) +{ + extern __unqual_typeof(x) y; + return &y; +} + +/* + * check-name: unqual-stmt-expr + */ diff --git a/validation/eval/unqual02.c b/validation/eval/unqual02.c new file mode 100644 index 00000000..f136cbd5 --- /dev/null +++ b/validation/eval/unqual02.c @@ -0,0 +1,26 @@ +static void test_const(volatile int x) +{ + const int x = 0; + typeof(1?x:x) i3; i3 = 0; // should be OK + typeof(+x) i4; i4 = 0; // should be OK + typeof(-x) i5; i5 = 0; // should be OK + typeof(!x) i6; i6 = 0; // should be OK + typeof(x+x) i7; i7 = 0; // should be OK +} + +static void test_volatile(void) +{ + volatile int x = 0; + int *pp; + + typeof(1?x:x) i3; pp = &i3; // should be OK + typeof(+x) i4; pp = &i4; // should be OK + typeof(-x) i5; pp = &i5; // should be OK + typeof(!x) i6; pp = &i6; // should be OK + typeof(x+x) i7; pp = &i7; // should be OK +} + +/* + * check-name: unqual02 + * check-command: sparse -Wno-declaration-after-statement $file + */ diff --git a/validation/expand/builtin_constant_inline0.c b/validation/expand/builtin_constant_inline0.c index a0057f20..d72a211f 100644 --- a/validation/expand/builtin_constant_inline0.c +++ b/validation/expand/builtin_constant_inline0.c @@ -16,6 +16,7 @@ int foo(void) foo: .L0: <entry-point> + # call %r1 <- is_const, $42 ret.32 $42 diff --git a/validation/inline_base0.c b/validation/inline_base0.c index 517ee972..698c760f 100644 --- a/validation/inline_base0.c +++ b/validation/inline_base0.c @@ -27,6 +27,7 @@ foo0: .L0: <entry-point> add.32 %r5 <- %arg1, %arg2 + # call %r6 <- add, %r1, %r2 ret.32 %r5 @@ -34,12 +35,14 @@ foo1: .L3: <entry-point> add.32 %r10 <- %arg1, $1 + # call %r11 <- add, %r8, $1 ret.32 %r10 foo2: .L6: <entry-point> + # call %r13 <- add, $1, $2 ret.32 $3 diff --git a/validation/linear/builtin_unreachable0.c b/validation/linear/builtin_unreachable0.c index 911ed7f9..4fc56473 100644 --- a/validation/linear/builtin_unreachable0.c +++ b/validation/linear/builtin_unreachable0.c @@ -14,12 +14,12 @@ foo: .L0: <entry-point> seteq.32 %r2 <- %arg1, $3 - cbr %r2, .L1, .L3 + cbr %r2, .L1, .L2 .L1: unreachable -.L3: +.L2: ret.32 %arg1 diff --git a/validation/linear/builtin_unreachable1.c b/validation/linear/builtin_unreachable1.c index 70f6674c..2fc1d728 100644 --- a/validation/linear/builtin_unreachable1.c +++ b/validation/linear/builtin_unreachable1.c @@ -16,9 +16,9 @@ int foo(int c) foo: .L0: <entry-point> - cbr %arg1, .L3, .L2 + cbr %arg1, .L1, .L2 -.L3: +.L1: ret.32 $1 .L2: diff --git a/validation/linear/call-inline.c b/validation/linear/call-inline.c index dfd49b62..1ad785ee 100644 --- a/validation/linear/call-inline.c +++ b/validation/linear/call-inline.c @@ -13,6 +13,6 @@ int i3(void) { return (***fun)(); } // C99,C11 6.5.3.2p4 * * check-output-ignore * check-output-excludes: load - * check-output-excludes: call + * check-output-excludes: \\tcall * check-output-pattern(5): ret\\..* \\$42 */ diff --git a/validation/mem2reg/cond-expr.c b/validation/mem2reg/cond-expr.c index 8acb00ac..2474d65d 100644 --- a/validation/mem2reg/cond-expr.c +++ b/validation/mem2reg/cond-expr.c @@ -9,6 +9,6 @@ int foo(int a, int b, int c) * check-name: cond-expr * check-command: test-linearize -Wno-decl -fdump-ir=mem2reg $file * check-output-ignore - * check-output-pattern(2): phi\\. - * check-output-pattern(3): phisrc\\. + * check-output-pattern(1): phi\\. + * check-output-pattern(2): phisrc\\. */ diff --git a/validation/mem2reg/cond-expr5.c b/validation/mem2reg/cond-expr5.c index a3ce5e3a..beef8f25 100644 --- a/validation/mem2reg/cond-expr5.c +++ b/validation/mem2reg/cond-expr5.c @@ -15,7 +15,6 @@ int foo(int p, int q, int a) * check-output-ignore * check-output-excludes: load\\. * check-output-excludes: store\\. - * check-output-excludes: phi\\..*, .*, .* - * check-output-pattern(3): phi\\. - * check-output-pattern(5): phisrc\\. + * check-output-pattern(2): phi\\. + * check-output-pattern(4): phisrc\\. */ diff --git a/validation/optim/cse-size.c b/validation/optim/cse-size.c index 5b31420c..0c0c2d14 100644 --- a/validation/optim/cse-size.c +++ b/validation/optim/cse-size.c @@ -1,7 +1,7 @@ static void foo(void) { unsigned short p = 0; - int x; + int x = 1; for (;;) if (p) @@ -13,5 +13,6 @@ static void foo(void) * check-command: test-linearize -Wno-decl $file * * check-output-ignore - * check-output-pattern(2): phi\\. + * check-output-excludes: phi\\. + * check-output-excludes: cbr */ diff --git a/validation/optim/memops-missed01.c b/validation/optim/memops-missed01.c new file mode 100644 index 00000000..fc616f19 --- /dev/null +++ b/validation/optim/memops-missed01.c @@ -0,0 +1,23 @@ +void bar(int); + +void foo(void) +{ + char buf[1] = { 42 }; + const char *p = buf; + const char **q = &p; + int ch = 0; + switch (**q) { + case 4: + ch = 2; + } + bar(ch); +} + +/* + * check-name: memops-missed01 + * check-command: test-linearize -Wno-decl $file + * + * check-output-ignore + * check-output-excludes: store\\. + * check-output-excludes: load\\. + */ diff --git a/validation/optim/memops-missed02.c b/validation/optim/memops-missed02.c new file mode 100644 index 00000000..6f028649 --- /dev/null +++ b/validation/optim/memops-missed02.c @@ -0,0 +1,14 @@ +void foo(int a[]) +{ + int i, val; + for (;; i++) + val = a[i] ? a[i] : val; +} + +/* + * check-name: memops-missed02 + * check-command: test-linearize -Wno-decl $file + * + * check-output-ignore + * check-output-pattern(1): load\\. + */ diff --git a/validation/optim/merge_bbe-adjust_phi.c b/validation/optim/merge_bbe-adjust_phi.c new file mode 100644 index 00000000..6a8ebb73 --- /dev/null +++ b/validation/optim/merge_bbe-adjust_phi.c @@ -0,0 +1,23 @@ +extern int array[2]; + +static inline int stupid_select(int idx) +{ + if (idx) + idx = 0; + return array[idx]; +} + +int select(void) +{ + int d = stupid_select(-1); + return d; +} + +/* + * check-name: merge_bbe-adjust_phi + * check-command: test-linearize -Wno-decl $file + * + * check-output-ignore + * check-output-excludes: phisrc\\. + * check-output-excludes: phi\\. + */ |
