aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
-rw-r--r--Documentation/IR.rst12
-rw-r--r--Documentation/dev-options.rst1
-rw-r--r--cse.c11
-rw-r--r--dominate.c2
-rw-r--r--dominate.h4
-rw-r--r--evaluate.c4
-rw-r--r--flow.c2
-rw-r--r--flow.h1
-rw-r--r--ident-list.h1
-rw-r--r--ir.c55
-rw-r--r--lib.c4
-rw-r--r--lib.h1
-rw-r--r--linearize.c162
-rw-r--r--linearize.h131
-rw-r--r--liveness.c5
-rw-r--r--memops.c4
-rw-r--r--opcode.c49
-rw-r--r--opcode.def114
-rw-r--r--opcode.h13
-rw-r--r--parse.c50
-rw-r--r--pre-process.c33
-rw-r--r--simplify.c30
-rw-r--r--sparse.19
-rw-r--r--sparse.c2
-rw-r--r--ssa.c1
-rw-r--r--ssa.h2
-rw-r--r--validation/Waddress-space-strict.c56
-rw-r--r--validation/enum+mode.c18
-rw-r--r--validation/linear/asm-toplevel.c (renamed from validation/asm-toplevel.c)0
-rw-r--r--validation/linear/logical-phi0.c48
-rw-r--r--validation/linear/logical.c180
-rw-r--r--validation/linear/missing-return0.c10
-rw-r--r--validation/linear/missing-return1.c15
-rw-r--r--validation/linear/missing-return2.c11
-rw-r--r--validation/linear/missing-return3.c18
-rw-r--r--validation/linear/missing-return4.c14
-rw-r--r--validation/linear/missing-return5.c23
-rw-r--r--validation/linear/phi-order01.c16
-rw-r--r--validation/linear/phi-order02.c16
-rw-r--r--validation/linear/phi-order03.c8
-rw-r--r--validation/linear/phi-order04.c12
-rw-r--r--validation/linear/unreachable-label0.c19
-rw-r--r--validation/optim/volatile-bitfield.c16
-rw-r--r--validation/preprocessor/has-attribute.c56
44 files changed, 873 insertions, 366 deletions
diff --git a/Documentation/IR.rst b/Documentation/IR.rst
index 0419ac41..8ffc921a 100644
--- a/Documentation/IR.rst
+++ b/Documentation/IR.rst
@@ -241,6 +241,12 @@ Unary ops
* .target: result of the operation (must be a floating-point type)
* .type: type of .target
+.. op:: OP_SYMADDR
+ Create a pseudo corresponding to the address of a symbol.
+
+ * .src: input symbol (must be a PSEUDO_SYM)
+ * .target: symbol's address
+
.. op:: OP_COPY
Copy (only needed after out-of-SSA).
@@ -327,12 +333,6 @@ Memory ops
Others
------
-.. op:: OP_SYMADDR
- Create a pseudo corresponding to the address of a symbol.
-
- * .symbol: (pseudo_t) input symbol (alias .src)
- * .target: symbol's address
-
.. op:: OP_SETFVAL
Create a pseudo corresponding to a floating-point literal.
diff --git a/Documentation/dev-options.rst b/Documentation/dev-options.rst
index 04fb651f..23e8096c 100644
--- a/Documentation/dev-options.rst
+++ b/Documentation/dev-options.rst
@@ -33,6 +33,7 @@ OPTIONS
The passes currently understood are:
+ * ``linearize`` (can't be disabled)
* ``mem2reg``
* ``optim``
diff --git a/cse.c b/cse.c
index 1395a8af..22dfd4ba 100644
--- a/cse.c
+++ b/cse.c
@@ -76,6 +76,7 @@ void cse_collect(struct instruction *insn)
/* Unary */
case OP_NOT: case OP_NEG:
case OP_FNEG:
+ case OP_SYMADDR:
hash += hashval(insn->src1);
break;
@@ -87,10 +88,6 @@ void cse_collect(struct instruction *insn)
hash += hashval(insn->fvalue);
break;
- case OP_SYMADDR:
- hash += hashval(insn->symbol);
- break;
-
case OP_SEXT: case OP_ZEXT:
case OP_TRUNC:
case OP_PTRCAST:
@@ -213,15 +210,11 @@ static int insn_compare(const void *_i1, const void *_i2)
/* Unary */
case OP_NOT: case OP_NEG:
case OP_FNEG:
+ case OP_SYMADDR:
if (i1->src1 != i2->src1)
return i1->src1 < i2->src1 ? -1 : 1;
break;
- case OP_SYMADDR:
- if (i1->symbol != i2->symbol)
- return i1->symbol < i2->symbol ? -1 : 1;
- break;
-
case OP_SETVAL:
if (i1->val != i2->val)
return i1->val < i2->val ? -1 : 1;
diff --git a/dominate.c b/dominate.c
index 8085171d..bf2ae63a 100644
--- a/dominate.c
+++ b/dominate.c
@@ -23,7 +23,7 @@ struct piggy {
struct basic_block_list *lists[0];
};
-struct piggy *bank_init(unsigned levels)
+static struct piggy *bank_init(unsigned levels)
{
struct piggy *bank;
bank = calloc(1, sizeof(*bank) + levels * sizeof(bank->lists[0]));
diff --git a/dominate.h b/dominate.h
index 6ac515d0..a06216ca 100644
--- a/dominate.h
+++ b/dominate.h
@@ -6,4 +6,8 @@ struct basic_block_list;
void idf_compute(struct entrypoint *ep, struct basic_block_list **idf, struct basic_block_list *alpha);
+
+// For debugging only
+void idf_dump(struct entrypoint *ep);
+
#endif
diff --git a/evaluate.c b/evaluate.c
index 7ab7db81..6d5d4793 100644
--- a/evaluate.c
+++ b/evaluate.c
@@ -3003,14 +3003,14 @@ static struct symbol *evaluate_cast(struct expression *expr)
}
}
- if (ttype == &ulong_ctype)
+ if (ttype == &ulong_ctype && !Wcast_from_as)
tas = -1;
else if (tclass == TYPE_PTR) {
examine_pointer_target(ttype);
tas = ttype->ctype.as;
}
- if (stype == &ulong_ctype)
+ if (stype == &ulong_ctype && !Wcast_from_as)
sas = -1;
else if (sclass == TYPE_PTR) {
examine_pointer_target(stype);
diff --git a/flow.c b/flow.c
index 40f1ba58..ef8d04e5 100644
--- a/flow.c
+++ b/flow.c
@@ -174,7 +174,7 @@ static int bb_has_side_effects(struct basic_block *bb)
case OP_LOAD:
if (!insn->type)
return 1;
- if (insn->type->ctype.modifiers & MOD_VOLATILE)
+ if (insn->is_volatile)
return 1;
continue;
diff --git a/flow.h b/flow.h
index c8e12cf0..099767d4 100644
--- a/flow.h
+++ b/flow.h
@@ -20,6 +20,7 @@ extern void simplify_memops(struct entrypoint *ep);
extern void pack_basic_blocks(struct entrypoint *ep);
extern void convert_instruction_target(struct instruction *insn, pseudo_t src);
+extern void remove_dead_insns(struct entrypoint *);
extern int simplify_instruction(struct instruction *);
extern void kill_bb(struct basic_block *);
diff --git a/ident-list.h b/ident-list.h
index a37a4a1b..75740b9d 100644
--- a/ident-list.h
+++ b/ident-list.h
@@ -59,6 +59,7 @@ IDENT_RESERVED(__label__);
* sparse. */
IDENT(defined);
IDENT(once);
+IDENT(__has_attribute);
IDENT(__has_builtin);
__IDENT(pragma_ident, "__pragma__", 0);
__IDENT(__VA_ARGS___ident, "__VA_ARGS__", 0);
diff --git a/ir.c b/ir.c
index 1890eb13..2e284c25 100644
--- a/ir.c
+++ b/ir.c
@@ -29,6 +29,9 @@ static int check_phi_node(struct instruction *insn)
pseudo_t phi;
int err = 0;
+ if (!has_users(insn->target))
+ return err;
+
if (bb_list_size(insn->bb->parents) != nbr_phi_operands(insn)) {
sparse_error(insn->pos, "bad number of phi operands in:\n\t%s",
show_instruction(insn));
@@ -82,7 +85,40 @@ static int check_user(struct instruction *insn, pseudo_t pseudo)
return 0;
}
-static int validate_insn(struct instruction *insn)
+static int check_branch(struct entrypoint *ep, struct instruction *insn, struct basic_block *bb)
+{
+ if (bb->ep && lookup_bb(ep->bbs, bb))
+ return 0;
+ sparse_error(insn->pos, "branch to dead BB: %s", show_instruction(insn));
+ return 1;
+}
+
+static int check_switch(struct entrypoint *ep, struct instruction *insn)
+{
+ struct multijmp *jmp;
+ int err = 0;
+
+ FOR_EACH_PTR(insn->multijmp_list, jmp) {
+ err = check_branch(ep, insn, jmp->target);
+ if (err)
+ return err;
+ } END_FOR_EACH_PTR(jmp);
+
+ return err;
+}
+
+static int check_return(struct instruction *insn)
+{
+ struct symbol *ctype = insn->type;
+
+ if (ctype && ctype->bit_size > 0 && insn->src == VOID) {
+ sparse_error(insn->pos, "return without value");
+ return 1;
+ }
+ return 0;
+}
+
+static int validate_insn(struct entrypoint *ep, struct instruction *insn)
{
int err = 0;
@@ -104,6 +140,9 @@ static int validate_insn(struct instruction *insn)
break;
case OP_CBR:
+ err += check_branch(ep, insn, insn->bb_true);
+ err += check_branch(ep, insn, insn->bb_false);
+ /* fall through */
case OP_COMPUTEDGOTO:
err += check_user(insn, insn->cond);
break;
@@ -124,8 +163,18 @@ static int validate_insn(struct instruction *insn)
err += check_user(insn, insn->src);
break;
- case OP_ENTRY:
+ case OP_RET:
+ err += check_return(insn);
+ break;
+
case OP_BR:
+ err += check_branch(ep, insn, insn->bb_true);
+ break;
+ case OP_SWITCH:
+ err += check_switch(ep, insn);
+ break;
+
+ case OP_ENTRY:
case OP_SETVAL:
default:
break;
@@ -147,7 +196,7 @@ int ir_validate(struct entrypoint *ep)
FOR_EACH_PTR(bb->insns, insn) {
if (!insn->bb)
continue;
- err += validate_insn(insn);
+ err += validate_insn(ep, insn);
} END_FOR_EACH_PTR(insn);
} END_FOR_EACH_PTR(bb);
diff --git a/lib.c b/lib.c
index db456a63..07a5b9cd 100644
--- a/lib.c
+++ b/lib.c
@@ -248,6 +248,7 @@ static struct token *pre_buffer_end = NULL;
int Waddress = 0;
int Waddress_space = 1;
int Wbitwise = 1;
+int Wcast_from_as = 0;
int Wcast_to_as = 0;
int Wcast_truncate = 1;
int Wconstexpr_not_const = 0;
@@ -682,6 +683,7 @@ static const struct flag warnings[] = {
{ "address", &Waddress },
{ "address-space", &Waddress_space },
{ "bitwise", &Wbitwise },
+ { "cast-from-as", &Wcast_from_as },
{ "cast-to-as", &Wcast_to_as },
{ "cast-truncate", &Wcast_truncate },
{ "constexpr-not-const", &Wconstexpr_not_const},
@@ -956,6 +958,7 @@ static int handle_fmax_warnings(const char *arg, const char *opt, const struct f
static struct flag fflags[] = {
{ "diagnostic-prefix", NULL, handle_fdiagnostic_prefix },
{ "dump-ir", NULL, handle_fdump_ir },
+ { "linearize", NULL, handle_fpasses, PASS_LINEARIZE },
{ "max-warnings=", NULL, handle_fmax_warnings },
{ "mem-report", &fmem_report },
{ "memcpy-max-count=", NULL, handle_fmemcpy_max_count },
@@ -1287,6 +1290,7 @@ static void create_builtin_stream(void)
add_pre_buffer("#add_system \"%s/include-fixed\"\n", gcc_base_dir);
add_pre_buffer("#define __has_builtin(x) 0\n");
+ add_pre_buffer("#define __has_attribute(x) 0\n");
add_pre_buffer("#define __builtin_stdarg_start(a,b) ((a) = (__builtin_va_list)(&(b)))\n");
add_pre_buffer("#define __builtin_va_start(a,b) ((a) = (__builtin_va_list)(&(b)))\n");
add_pre_buffer("#define __builtin_ms_va_start(a,b) ((a) = (__builtin_ms_va_list)(&(b)))\n");
diff --git a/lib.h b/lib.h
index 8b445204..cd1af9c4 100644
--- a/lib.h
+++ b/lib.h
@@ -138,6 +138,7 @@ extern int preprocess_only;
extern int Waddress;
extern int Waddress_space;
extern int Wbitwise;
+extern int Wcast_from_as;
extern int Wcast_to_as;
extern int Wcast_truncate;
extern int Wconstexpr_not_const;
diff --git a/linearize.c b/linearize.c
index a56c272f..670e3830 100644
--- a/linearize.c
+++ b/linearize.c
@@ -351,11 +351,6 @@ const char *show_instruction(struct instruction *insn)
buf += sprintf(buf, "%s", show_label(insn->bb_true));
break;
- case OP_SYMADDR:
- buf += sprintf(buf, "%s <- ", show_pseudo(insn->target));
- buf += sprintf(buf, "%s", show_pseudo(insn->symbol));
- break;
-
case OP_SETVAL: {
struct expression *expr = insn->val;
buf += sprintf(buf, "%s <- ", show_pseudo(insn->target));
@@ -481,6 +476,7 @@ const char *show_instruction(struct instruction *insn)
case OP_NOT: case OP_NEG:
case OP_FNEG:
+ case OP_SYMADDR:
buf += sprintf(buf, "%s <- %s", show_pseudo(insn->target), show_pseudo(insn->src1));
break;
@@ -991,6 +987,7 @@ static pseudo_t add_load(struct entrypoint *ep, struct access_data *ad)
insn->target = new;
insn->offset = ad->offset;
+ insn->is_volatile = ad->type && (ad->type->ctype.modifiers & MOD_VOLATILE);
use_pseudo(insn, ad->address, &insn->src);
add_one_insn(ep, insn);
return new;
@@ -1006,6 +1003,7 @@ static void add_store(struct entrypoint *ep, struct access_data *ad, pseudo_t va
store = alloc_typed_instruction(OP_STORE, ad->btype);
store->offset = ad->offset;
+ store->is_volatile = ad->type && (ad->type->ctype.modifiers & MOD_VOLATILE);
use_pseudo(store, value, &store->target);
use_pseudo(store, ad->address, &store->src);
add_one_insn(ep, store);
@@ -1104,7 +1102,7 @@ static pseudo_t add_symbol_address(struct entrypoint *ep, struct symbol *sym)
pseudo_t target = alloc_pseudo(insn);
insn->target = target;
- use_pseudo(insn, symbol_pseudo(ep, sym), &insn->symbol);
+ use_pseudo(insn, symbol_pseudo(ep, sym), &insn->src);
add_one_insn(ep, insn);
return target;
}
@@ -1697,41 +1695,54 @@ static pseudo_t linearize_conditional(struct entrypoint *ep, struct expression *
return add_join_conditional(ep, expr, phi1, phi2);
}
+static void insert_phis(struct basic_block *bb, pseudo_t src, struct symbol *ctype,
+ struct instruction *node)
+{
+ struct basic_block *parent;
+
+ FOR_EACH_PTR(bb->parents, parent) {
+ struct instruction *br = delete_last_instruction(&parent->insns);
+ pseudo_t phi = alloc_phi(parent, src, ctype);
+ add_instruction(&parent->insns, br);
+ use_pseudo(node, phi, add_pseudo(&node->phi_list, phi));
+ } END_FOR_EACH_PTR(parent);
+}
+
static pseudo_t linearize_logical(struct entrypoint *ep, struct expression *expr)
{
+ struct symbol *ctype = expr->ctype;
struct basic_block *other, *merge;
- pseudo_t phi1, phi2;
+ struct instruction *node;
+ pseudo_t src1, src2, phi2;
if (!ep->active || !expr->left || !expr->right)
return VOID;
other = alloc_basic_block(ep, expr->right->pos);
merge = alloc_basic_block(ep, expr->pos);
+ node = alloc_phi_node(merge, ctype, NULL);
+ // LHS and its shortcut
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);
+ src1 = value_pseudo(1);
} 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);
+ src1 = value_pseudo(0);
}
+ insert_phis(merge, src1, ctype, node);
+ // RHS
+ set_activeblock(ep, other);
+ src2 = linearize_expression_to_bool(ep, expr->right);
+ src2 = cast_pseudo(ep, src2, &bool_ctype, ctype);
+ phi2 = alloc_phi(ep->active, src2, ctype);
+ use_pseudo(node, phi2, add_pseudo(&node->phi_list, phi2));
+
+ // join
set_activeblock(ep, merge);
- return add_join_conditional(ep, expr, phi1, phi2);
+ add_instruction(&merge->insns, node);
+ return node->target;
}
static pseudo_t linearize_compare(struct entrypoint *ep, struct expression *expr)
@@ -1971,22 +1982,49 @@ static pseudo_t linearize_compound_statement(struct entrypoint *ep, struct state
{
pseudo_t pseudo;
struct statement *s;
- struct symbol *ret = stmt->ret;
pseudo = VOID;
FOR_EACH_PTR(stmt->stmts, s) {
pseudo = linearize_statement(ep, s);
} END_FOR_EACH_PTR(s);
- if (ret) {
- struct basic_block *bb = add_label(ep, ret);
- struct instruction *phi_node = first_instruction(bb->insns);
+ return pseudo;
+}
- if (!phi_node)
- return pseudo;
- return phi_node->target;
+static void add_return(struct entrypoint *ep, struct basic_block *bb, struct symbol *ctype, pseudo_t src)
+{
+ struct instruction *phi_node = first_instruction(bb->insns);
+ pseudo_t phi;
+ if (!phi_node) {
+ phi_node = alloc_typed_instruction(OP_PHI, ctype);
+ phi_node->target = alloc_pseudo(phi_node);
+ phi_node->bb = bb;
+ add_instruction(&bb->insns, phi_node);
}
+ phi = alloc_phi(ep->active, src, ctype);
+ phi->ident = &return_ident;
+ use_pseudo(phi_node, phi, add_pseudo(&phi_node->phi_list, phi));
+}
+static pseudo_t linearize_fn_statement(struct entrypoint *ep, struct statement *stmt)
+{
+ struct instruction *phi_node;
+ struct basic_block *bb;
+ pseudo_t pseudo;
+
+ pseudo = linearize_compound_statement(ep, stmt);
+ if (!is_void_type(stmt->ret)) { // non-void function
+ struct basic_block *active = ep->active;
+ if (active && !bb_terminated(active)) { // missing return
+ struct basic_block *bb_ret;
+ bb_ret = get_bound_block(ep, stmt->ret);
+ add_return(ep, bb_ret, stmt->ret, undef_pseudo());
+ }
+ }
+ bb = add_label(ep, stmt->ret);
+ phi_node = first_instruction(bb->insns);
+ if (phi_node)
+ pseudo = phi_node->target;
return pseudo;
}
@@ -2007,10 +2045,12 @@ static pseudo_t linearize_inlined_call(struct entrypoint *ep, struct statement *
} END_FOR_EACH_PTR(sym);
}
- insn->target = pseudo = linearize_compound_statement(ep, stmt);
+ pseudo = linearize_fn_statement(ep, stmt);
+ insn->target = pseudo;
+
use_pseudo(insn, symbol_pseudo(ep, stmt->inline_fn), &insn->func);
bb = ep->active;
- if (bb && !bb->insns)
+ if (!bb->insns)
bb->pos = stmt->pos;
add_one_insn(ep, insn);
return pseudo;
@@ -2146,22 +2186,13 @@ static pseudo_t linearize_declaration(struct entrypoint *ep, struct statement *s
static pseudo_t linearize_return(struct entrypoint *ep, struct statement *stmt)
{
struct expression *expr = stmt->expression;
- struct basic_block *bb_return = get_bound_block(ep, stmt->ret_target);
+ struct symbol *ret = stmt->ret_target;
+ struct basic_block *bb_return = get_bound_block(ep, ret);
struct basic_block *active;
pseudo_t src = linearize_expression(ep, expr);
active = ep->active;
- if (active && src != VOID) {
- struct instruction *phi_node = first_instruction(bb_return->insns);
- pseudo_t phi;
- if (!phi_node) {
- phi_node = alloc_typed_instruction(OP_PHI, expr->ctype);
- phi_node->target = alloc_pseudo(phi_node);
- phi_node->bb = bb_return;
- add_instruction(&bb_return->insns, phi_node);
- }
- phi = alloc_phi(active, src, expr->ctype);
- phi->ident = &return_ident;
- use_pseudo(phi_node, phi, add_pseudo(&phi_node->phi_list, phi));
+ if (active && !is_void_type(ret)) {
+ add_return(ep, bb_return, ret, src);
}
add_goto(ep, bb_return);
return VOID;
@@ -2177,13 +2208,14 @@ static pseudo_t linearize_switch(struct entrypoint *ep, struct statement *stmt)
struct multijmp *jmp;
pseudo_t pseudo;
+ if (!expr || !expr->ctype)
+ return VOID;
pseudo = linearize_expression(ep, expr);
- if (pseudo == VOID)
- return pseudo;
-
active = ep->active;
- if (!bb_reachable(active))
- return VOID;
+ if (!active) {
+ active = alloc_basic_block(ep, stmt->pos);
+ set_activeblock(ep, active);
+ }
switch_ins = alloc_typed_instruction(OP_SWITCH, expr->ctype);
use_pseudo(switch_ins, pseudo, &switch_ins->cond);
@@ -2417,23 +2449,30 @@ static pseudo_t linearize_statement(struct entrypoint *ep, struct statement *stm
static struct entrypoint *linearize_fn(struct symbol *sym, struct symbol *base_type)
{
+ struct statement *stmt = base_type->stmt;
struct entrypoint *ep;
struct basic_block *bb;
+ struct symbol *ret_type;
struct symbol *arg;
struct instruction *entry;
+ struct instruction *ret;
pseudo_t result;
int i;
- if (!base_type->stmt)
+ if (!stmt)
return NULL;
ep = alloc_entrypoint();
- bb = alloc_basic_block(ep, sym->pos);
-
ep->name = sym;
sym->ep = ep;
+ bb = alloc_basic_block(ep, sym->pos);
set_activeblock(ep, bb);
+ if (stmt->type == STMT_ASM) { // top-level asm
+ linearize_asm_statement(ep, stmt);
+ return ep;
+ }
+
entry = alloc_instruction(OP_ENTRY, 0);
add_one_insn(ep, entry);
ep->entry = entry;
@@ -2446,15 +2485,12 @@ static struct entrypoint *linearize_fn(struct symbol *sym, struct symbol *base_t
linearize_argument(ep, arg, ++i);
} END_FOR_EACH_PTR(arg);
- result = linearize_statement(ep, base_type->stmt);
- if (bb_reachable(ep->active) && !bb_terminated(ep->active)) {
- struct symbol *ret_type = base_type->ctype.base_type;
- struct instruction *insn = alloc_typed_instruction(OP_RET, ret_type);
-
- if (type_size(ret_type) > 0)
- use_pseudo(insn, result, &insn->src);
- add_one_insn(ep, insn);
- }
+ result = linearize_fn_statement(ep, stmt);
+ ret_type = base_type->ctype.base_type;
+ ret = alloc_typed_instruction(OP_RET, ret_type);
+ if (type_size(ret_type) > 0)
+ use_pseudo(ret, result, &ret->src);
+ add_one_insn(ep, ret);
optimize(ep);
return ep;
diff --git a/linearize.h b/linearize.h
index 5eb9562e..89da3db6 100644
--- a/linearize.h
+++ b/linearize.h
@@ -113,7 +113,11 @@ struct instruction {
struct /* unops */ {
pseudo_t src;
struct symbol *orig_type; /* casts */
- unsigned int offset; /* memops */
+ };
+ struct /* memops */ {
+ pseudo_t addr; /* alias .src */
+ unsigned int offset;
+ unsigned int is_volatile:1;
};
struct /* binops and sel */ {
pseudo_t src1, src2, src3;
@@ -122,9 +126,6 @@ struct instruction {
pseudo_t base;
unsigned from, len;
};
- struct /* symaddr */ {
- pseudo_t symbol; /* Subtle: same offset as "src" !! */
- };
struct /* setval */ {
struct expression *val;
};
@@ -148,122 +149,6 @@ struct instruction {
};
};
-enum opcode {
- OP_BADOP,
-
- /* Entry */
- OP_ENTRY,
-
- /* Terminator */
- OP_TERMINATOR,
- OP_RET = OP_TERMINATOR,
- OP_BR,
- OP_CBR,
- OP_SWITCH,
- OP_COMPUTEDGOTO,
- OP_TERMINATOR_END = OP_COMPUTEDGOTO,
-
- /* Binary */
- OP_BINARY,
- OP_ADD = OP_BINARY,
- OP_SUB,
- OP_MUL,
- OP_DIVU, OP_DIVS,
- OP_MODU, OP_MODS,
- OP_SHL,
- OP_LSR, OP_ASR,
-
- /* Floating-point binops */
- OP_FADD,
- OP_FSUB,
- OP_FMUL,
- OP_FDIV,
-
- /* Logical */
- OP_AND,
- OP_OR,
- OP_XOR,
- OP_BINARY_END = OP_XOR,
-
- /* floating-point comparison */
- OP_FPCMP,
- OP_FCMP_ORD = OP_FPCMP,
- OP_FCMP_OEQ,
- OP_FCMP_ONE,
- OP_FCMP_OLE,
- OP_FCMP_OGE,
- OP_FCMP_OLT,
- OP_FCMP_OGT,
- OP_FCMP_UEQ,
- OP_FCMP_UNE,
- OP_FCMP_ULE,
- OP_FCMP_UGE,
- OP_FCMP_ULT,
- OP_FCMP_UGT,
- OP_FCMP_UNO,
- OP_FPCMP_END = OP_FCMP_UNO,
-
- /* Binary comparison */
- OP_BINCMP,
- OP_SET_EQ = OP_BINCMP,
- OP_SET_NE,
- OP_SET_LE,
- OP_SET_GE,
- OP_SET_LT,
- OP_SET_GT,
- OP_SET_B,
- OP_SET_A,
- OP_SET_BE,
- OP_SET_AE,
- OP_BINCMP_END = OP_SET_AE,
-
- /* Uni */
- OP_UNOP,
- OP_NOT = OP_UNOP,
- OP_NEG,
- OP_FNEG,
-
- /* Casts */
- OP_TRUNC,
- OP_ZEXT, OP_SEXT,
- OP_FCVTU, OP_FCVTS,
- OP_UCVTF, OP_SCVTF,
- OP_FCVTF,
- OP_UTPTR,
- OP_PTRTU,
- OP_PTRCAST,
- OP_UNOP_END = OP_PTRCAST,
-
- /* Select - three input values */
- OP_SEL,
-
- /* Memory */
- OP_LOAD,
- OP_STORE,
- OP_SETVAL,
- OP_SETFVAL,
- OP_SYMADDR,
-
- /* Other */
- OP_PHI,
- OP_PHISOURCE,
- OP_INLINED_CALL,
- OP_CALL,
- OP_SLICE,
- OP_NOP,
- OP_DEATHNOTE,
- OP_ASM,
-
- /* Sparse tagging (line numbers, context, whatever) */
- OP_CONTEXT,
- OP_RANGE,
-
- /* Needed to translate SSA back to normal form */
- OP_COPY,
-
- OP_LAST, /* keep this one last! */
-};
-
struct basic_block_list;
struct instruction_list;
@@ -343,6 +228,12 @@ static inline int bb_reachable(struct basic_block *bb)
return bb != NULL;
}
+static inline int lookup_bb(struct basic_block_list *list, struct basic_block *bb)
+{
+ return lookup_ptr_list_entry((struct ptr_list *)list, bb);
+}
+
+
static inline void add_pseudo_user_ptr(struct pseudo_user *user, struct pseudo_user_list **list)
{
add_ptr_list(list, user);
diff --git a/liveness.c b/liveness.c
index d1968ce4..93a7cc30 100644
--- a/liveness.c
+++ b/liveness.c
@@ -72,6 +72,7 @@ static void track_instruction_usage(struct basic_block *bb, struct instruction *
/* Uni */
case OP_UNOP ... OP_UNOP_END:
+ case OP_SYMADDR:
USES(src1); DEFINES(target);
break;
@@ -93,10 +94,6 @@ static void track_instruction_usage(struct basic_block *bb, struct instruction *
DEFINES(target);
break;
- case OP_SYMADDR:
- USES(symbol); DEFINES(target);
- break;
-
/* Other */
case OP_PHI:
/* Phi-nodes are "backwards" nodes. Their def doesn't matter */
diff --git a/memops.c b/memops.c
index 20806175..5df2c033 100644
--- a/memops.c
+++ b/memops.c
@@ -99,7 +99,7 @@ static void simplify_loads(struct basic_block *bb)
/* Check for illegal offsets.. */
check_access(insn);
- if (insn->type->ctype.modifiers & MOD_VOLATILE)
+ if (insn->is_volatile)
continue;
RECURSE_PTR_REVERSE(insn, dom) {
@@ -160,7 +160,7 @@ static void kill_dominated_stores(struct basic_block *bb)
if (!insn->type)
continue;
- if (insn->type->ctype.modifiers & MOD_VOLATILE)
+ if (insn->is_volatile)
continue;
local = local_pseudo(pseudo);
diff --git a/opcode.c b/opcode.c
index d872556e..98ad768f 100644
--- a/opcode.c
+++ b/opcode.c
@@ -20,42 +20,19 @@
* THE SOFTWARE.
*/
-#include "linearize.h"
+#include "opcode.h"
const struct opcode_table opcode_table[OP_LAST] = {
- [OP_SET_EQ] = { .negate = OP_SET_NE, .swap = OP_SET_EQ, .to_float = OP_FCMP_OEQ, },
- [OP_SET_NE] = { .negate = OP_SET_EQ, .swap = OP_SET_NE, .to_float = OP_FCMP_UNE, },
- [OP_SET_LT] = { .negate = OP_SET_GE, .swap = OP_SET_GT, .to_float = OP_FCMP_OLT, },
- [OP_SET_LE] = { .negate = OP_SET_GT, .swap = OP_SET_GE, .to_float = OP_FCMP_OLE, },
- [OP_SET_GE] = { .negate = OP_SET_LT, .swap = OP_SET_LE, .to_float = OP_FCMP_OGE, },
- [OP_SET_GT] = { .negate = OP_SET_LE, .swap = OP_SET_LT, .to_float = OP_FCMP_OGT, },
- [OP_SET_B ] = { .negate = OP_SET_AE, .swap = OP_SET_A , .to_float = OP_FCMP_OLT, },
- [OP_SET_BE] = { .negate = OP_SET_A , .swap = OP_SET_AE, .to_float = OP_FCMP_OLE, },
- [OP_SET_AE] = { .negate = OP_SET_B , .swap = OP_SET_BE, .to_float = OP_FCMP_OGE, },
- [OP_SET_A ] = { .negate = OP_SET_BE, .swap = OP_SET_B , .to_float = OP_FCMP_OGT, },
-
- [OP_FCMP_ORD] = { .negate = OP_FCMP_UNO, .swap = OP_FCMP_ORD, },
- [OP_FCMP_UNO] = { .negate = OP_FCMP_ORD, .swap = OP_FCMP_UNO, },
-
- [OP_FCMP_OEQ] = { .negate = OP_FCMP_UNE, .swap = OP_FCMP_OEQ, },
- [OP_FCMP_ONE] = { .negate = OP_FCMP_UEQ, .swap = OP_FCMP_ONE, },
- [OP_FCMP_UEQ] = { .negate = OP_FCMP_ONE, .swap = OP_FCMP_UEQ, },
- [OP_FCMP_UNE] = { .negate = OP_FCMP_OEQ, .swap = OP_FCMP_UNE, },
-
- [OP_FCMP_OLT] = { .negate = OP_FCMP_UGE, .swap = OP_FCMP_OGT, },
- [OP_FCMP_OLE] = { .negate = OP_FCMP_UGT, .swap = OP_FCMP_OGE, },
- [OP_FCMP_OGE] = { .negate = OP_FCMP_ULT, .swap = OP_FCMP_OLE, },
- [OP_FCMP_OGT] = { .negate = OP_FCMP_ULE, .swap = OP_FCMP_OLT, },
-
- [OP_FCMP_ULT] = { .negate = OP_FCMP_OGE, .swap = OP_FCMP_UGT, },
- [OP_FCMP_ULE] = { .negate = OP_FCMP_OGT, .swap = OP_FCMP_UGE, },
- [OP_FCMP_UGE] = { .negate = OP_FCMP_OLT, .swap = OP_FCMP_ULE, },
- [OP_FCMP_UGT] = { .negate = OP_FCMP_OLE, .swap = OP_FCMP_ULT, },
-
- [OP_ADD] = { .to_float = OP_FADD, },
- [OP_SUB] = { .to_float = OP_FSUB, },
- [OP_MUL] = { .to_float = OP_FMUL, },
- [OP_DIVS] = { .to_float = OP_FDIV, },
- [OP_DIVU] = { .to_float = OP_FDIV, },
- [OP_NEG] = { .to_float = OP_FNEG, },
+#define OPCODE(OP,NG,SW,TF,N,FL) \
+ [OP_##OP] = { \
+ .negate = OP_##NG, \
+ .swap = OP_##SW, \
+ .to_float = OP_##TF, \
+ .arity = N, \
+ .flags = FL, \
+ },
+#define OPCODE_RANGE(OP,S,E)
+#include "opcode.def"
+#undef OPCODE
+#undef OPCODE_RANGE
};
diff --git a/opcode.def b/opcode.def
new file mode 100644
index 00000000..57d827f4
--- /dev/null
+++ b/opcode.def
@@ -0,0 +1,114 @@
+// OPCODE negated swaped float arity, flags
+
+OPCODE(BADOP, BADOP, BADOP, BADOP, 0, OPF_NONE)
+
+/* Entry */
+OPCODE(ENTRY, BADOP, BADOP, BADOP, 0, OPF_NONE)
+
+/* Terminator */
+OPCODE(RET, BADOP, BADOP, BADOP, 1, OPF_NONE)
+OPCODE(BR, BADOP, BADOP, BADOP, 0, OPF_NONE)
+OPCODE(CBR, BADOP, BADOP, BADOP, 1, OPF_NONE)
+OPCODE(SWITCH, BADOP, BADOP, BADOP, 1, OPF_NONE)
+OPCODE(COMPUTEDGOTO, BADOP, BADOP, BADOP, 1, OPF_NONE)
+OPCODE_RANGE(TERMINATOR, RET, COMPUTEDGOTO)
+
+/* Binary */
+OPCODE(ADD, BADOP, BADOP, FADD, 2, OPF_TARGET)
+OPCODE(SUB, BADOP, BADOP, FSUB, 2, OPF_TARGET)
+OPCODE(MUL, BADOP, BADOP, FMUL, 2, OPF_TARGET)
+OPCODE(DIVU, BADOP, BADOP, FDIV, 2, OPF_TARGET)
+OPCODE(DIVS, BADOP, BADOP, FDIV, 2, OPF_TARGET)
+OPCODE(MODU, BADOP, BADOP, BADOP, 2, OPF_TARGET)
+OPCODE(MODS, BADOP, BADOP, BADOP, 2, OPF_TARGET)
+OPCODE(SHL, BADOP, BADOP, BADOP, 2, OPF_TARGET)
+OPCODE(LSR, BADOP, BADOP, BADOP, 2, OPF_TARGET)
+OPCODE(ASR, BADOP, BADOP, BADOP, 2, OPF_TARGET)
+
+/* Floating-point binops */
+OPCODE(FADD, BADOP, BADOP, BADOP, 2, OPF_TARGET)
+OPCODE(FSUB, BADOP, BADOP, BADOP, 2, OPF_TARGET)
+OPCODE(FMUL, BADOP, BADOP, BADOP, 2, OPF_TARGET)
+OPCODE(FDIV, BADOP, BADOP, BADOP, 2, OPF_TARGET)
+
+/* Logical */
+OPCODE(AND_BOOL, BADOP, BADOP, BADOP, 2, OPF_TARGET)
+OPCODE(OR_BOOL, BADOP, BADOP, BADOP, 2, OPF_TARGET)
+OPCODE(AND, BADOP, BADOP, BADOP, 2, OPF_TARGET)
+OPCODE(OR, BADOP, BADOP, BADOP, 2, OPF_TARGET)
+OPCODE(XOR, BADOP, BADOP, BADOP, 2, OPF_TARGET)
+OPCODE_RANGE(BINARY, ADD, XOR)
+
+/* floating-point comparison */
+OPCODE(FCMP_ORD, FCMP_UNO, FCMP_ORD, BADOP, 2, OPF_TARGET)
+OPCODE(FCMP_OEQ, FCMP_UNE, FCMP_OEQ, BADOP, 2, OPF_TARGET)
+OPCODE(FCMP_ONE, FCMP_UEQ, FCMP_ONE, BADOP, 2, OPF_TARGET)
+OPCODE(FCMP_UEQ, FCMP_ONE, FCMP_UEQ, BADOP, 2, OPF_TARGET)
+OPCODE(FCMP_UNE, FCMP_OEQ, FCMP_UNE, BADOP, 2, OPF_TARGET)
+OPCODE(FCMP_OLT, FCMP_UGE, FCMP_OGT, BADOP, 2, OPF_TARGET)
+OPCODE(FCMP_OLE, FCMP_UGT, FCMP_OGE, BADOP, 2, OPF_TARGET)
+OPCODE(FCMP_OGE, FCMP_ULT, FCMP_OLE, BADOP, 2, OPF_TARGET)
+OPCODE(FCMP_OGT, FCMP_ULE, FCMP_OLT, BADOP, 2, OPF_TARGET)
+OPCODE(FCMP_ULT, FCMP_OGE, FCMP_UGT, BADOP, 2, OPF_TARGET)
+OPCODE(FCMP_ULE, FCMP_OGT, FCMP_UGE, BADOP, 2, OPF_TARGET)
+OPCODE(FCMP_UGE, FCMP_OLT, FCMP_ULE, BADOP, 2, OPF_TARGET)
+OPCODE(FCMP_UGT, FCMP_OLE, FCMP_ULT, BADOP, 2, OPF_TARGET)
+OPCODE(FCMP_UNO, FCMP_ORD, FCMP_UNO, BADOP, 2, OPF_TARGET)
+OPCODE_RANGE(FPCMP, FCMP_ORD, FCMP_UNO)
+
+/* Binary comparison */
+OPCODE(SET_EQ, SET_NE, SET_EQ, FCMP_OEQ, 2, OPF_TARGET)
+OPCODE(SET_LT, SET_GE, SET_GT, FCMP_OLT, 2, OPF_TARGET)
+OPCODE(SET_LE, SET_GT, SET_GE, FCMP_OLE, 2, OPF_TARGET)
+OPCODE(SET_GE, SET_LT, SET_LE, FCMP_OGE, 2, OPF_TARGET)
+OPCODE(SET_GT, SET_LE, SET_LT, FCMP_OGT, 2, OPF_TARGET)
+OPCODE(SET_B, SET_AE, SET_A, FCMP_OLT, 2, OPF_TARGET)
+OPCODE(SET_BE, SET_A, SET_AE, FCMP_OLE, 2, OPF_TARGET)
+OPCODE(SET_AE, SET_B, SET_BE, FCMP_OGE, 2, OPF_TARGET)
+OPCODE(SET_A, SET_BE, SET_B, FCMP_OGT, 2, OPF_TARGET)
+OPCODE(SET_NE, SET_EQ, SET_NE, FCMP_UNE, 2, OPF_TARGET)
+OPCODE_RANGE(BINCMP, SET_EQ, SET_NE)
+
+/* Uni */
+OPCODE(NOT, BADOP, BADOP, BADOP, 1, OPF_TARGET)
+OPCODE(NEG, BADOP, BADOP, FNEG, 1, OPF_TARGET)
+OPCODE(FNEG, BADOP, BADOP, BADOP, 1, OPF_TARGET)
+OPCODE(TRUNC, BADOP, BADOP, BADOP, 1, OPF_TARGET)
+OPCODE(ZEXT, BADOP, BADOP, BADOP, 1, OPF_TARGET)
+OPCODE(SEXT, BADOP, BADOP, BADOP, 1, OPF_TARGET)
+OPCODE(FCVTU, BADOP, BADOP, BADOP, 1, OPF_TARGET)
+OPCODE(FCVTS, BADOP, BADOP, BADOP, 1, OPF_TARGET)
+OPCODE(UCVTF, BADOP, BADOP, BADOP, 1, OPF_TARGET)
+OPCODE(SCVTF, BADOP, BADOP, BADOP, 1, OPF_TARGET)
+OPCODE(FCVTF, BADOP, BADOP, BADOP, 1, OPF_TARGET)
+OPCODE(UTPTR, BADOP, BADOP, BADOP, 1, OPF_TARGET)
+OPCODE(PTRTU, BADOP, BADOP, BADOP, 1, OPF_TARGET)
+OPCODE(PTRCAST, BADOP, BADOP, BADOP, 1, OPF_TARGET)
+OPCODE_RANGE(UNOP, NOT, PTRCAST)
+OPCODE(SYMADDR, BADOP, BADOP, BADOP, 1, OPF_TARGET)
+OPCODE(SLICE, BADOP, BADOP, BADOP, 1, OPF_TARGET)
+
+/* Select - three input values */
+OPCODE(SEL, BADOP, BADOP, BADOP, 3, OPF_TARGET)
+
+/* Memory */
+OPCODE(LOAD, BADOP, BADOP, BADOP, 1, OPF_TARGET)
+OPCODE(STORE, BADOP, BADOP, BADOP, 1, OPF_NONE)
+
+/* Other */
+OPCODE(PHISOURCE, BADOP, BADOP, BADOP, 1, OPF_TARGET)
+OPCODE(PHI, BADOP, BADOP, BADOP, 0, OPF_TARGET)
+OPCODE(SETVAL, BADOP, BADOP, BADOP, 0, OPF_TARGET)
+OPCODE(SETFVAL, BADOP, BADOP, BADOP, 0, OPF_TARGET)
+OPCODE(CALL, BADOP, BADOP, BADOP, 1, OPF_TARGET)
+OPCODE(INLINED_CALL, BADOP, BADOP, BADOP, 0, OPF_NONE)
+OPCODE(NOP, BADOP, BADOP, BADOP, 0, OPF_NONE)
+OPCODE(DEATHNOTE, BADOP, BADOP, BADOP, 0, OPF_NONE)
+OPCODE(ASM, BADOP, BADOP, BADOP, 0, OPF_NONE)
+
+/* Sparse tagging (line numbers, context, whatever) */
+OPCODE(CONTEXT, BADOP, BADOP, BADOP, 0, OPF_NONE)
+OPCODE(RANGE, BADOP, BADOP, BADOP, 3, OPF_NONE)
+
+/* Needed to translate SSA back to normal form */
+OPCODE(COPY, BADOP, BADOP, BADOP, 1, OPF_TARGET)
diff --git a/opcode.h b/opcode.h
index eda4c3a7..e426bed4 100644
--- a/opcode.h
+++ b/opcode.h
@@ -3,10 +3,23 @@
#include "symbol.h"
+enum opcode {
+#define OPCODE(OP,NG,SW,TF,N,FL) OP_##OP,
+#define OPCODE_RANGE(OP,S,E) OP_##OP = OP_##S, OP_##OP##_END = OP_##E,
+#include "opcode.def"
+#undef OPCODE
+#undef OPCODE_RANGE
+ OP_LAST, /* keep this one last! */
+};
+
extern const struct opcode_table {
int negate:8;
int swap:8;
int to_float:8;
+ unsigned int arity:2;
+ unsigned int flags:6;
+#define OPF_NONE 0
+#define OPF_TARGET (1 << 0)
} opcode_table[];
diff --git a/parse.c b/parse.c
index 270ab7bf..00b8ebbd 100644
--- a/parse.c
+++ b/parse.c
@@ -91,7 +91,8 @@ static attr_t
typedef struct symbol *to_mode_t(struct symbol *);
static to_mode_t
- to_QI_mode, to_HI_mode, to_SI_mode, to_DI_mode, to_TI_mode, to_word_mode;
+ to_QI_mode, to_HI_mode, to_SI_mode, to_DI_mode, to_TI_mode;
+static to_mode_t to_pointer_mode, to_word_mode;
enum {
Set_T = 1,
@@ -410,6 +411,11 @@ static struct symbol_op mode_TI_op = {
.to_mode = to_TI_mode
};
+static struct symbol_op mode_pointer_op = {
+ .type = KW_MODE,
+ .to_mode = to_pointer_mode
+};
+
static struct symbol_op mode_word_op = {
.type = KW_MODE,
.to_mode = to_word_mode
@@ -525,9 +531,10 @@ static struct init_keyword {
{ "bitwise", NS_KEYWORD, MOD_BITWISE, .op = &attr_bitwise_op },
{ "__bitwise__",NS_KEYWORD, MOD_BITWISE, .op = &attr_bitwise_op },
{ "address_space",NS_KEYWORD, .op = &address_space_op },
- { "mode", NS_KEYWORD, .op = &mode_op },
{ "context", NS_KEYWORD, .op = &context_op },
{ "designated_init", NS_KEYWORD, .op = &designated_init_op },
+ { "__designated_init__", NS_KEYWORD, .op = &designated_init_op },
+ { "transparent_union", NS_KEYWORD, .op = &transparent_union_op },
{ "__transparent_union__", NS_KEYWORD, .op = &transparent_union_op },
{ "noreturn", NS_KEYWORD, MOD_NORETURN, .op = &attr_mod_op },
{ "__noreturn__", NS_KEYWORD, MOD_NORETURN, .op = &attr_mod_op },
@@ -537,19 +544,24 @@ static struct init_keyword {
{"__const", NS_KEYWORD, MOD_PURE, .op = &attr_mod_op },
{"__const__", NS_KEYWORD, MOD_PURE, .op = &attr_mod_op },
+ { "mode", NS_KEYWORD, .op = &mode_op },
{ "__mode__", NS_KEYWORD, .op = &mode_op },
- { "QI", NS_KEYWORD, MOD_CHAR, .op = &mode_QI_op },
- { "__QI__", NS_KEYWORD, MOD_CHAR, .op = &mode_QI_op },
- { "HI", NS_KEYWORD, MOD_SHORT, .op = &mode_HI_op },
- { "__HI__", NS_KEYWORD, MOD_SHORT, .op = &mode_HI_op },
- { "SI", NS_KEYWORD, .op = &mode_SI_op },
- { "__SI__", NS_KEYWORD, .op = &mode_SI_op },
- { "DI", NS_KEYWORD, MOD_LONGLONG, .op = &mode_DI_op },
- { "__DI__", NS_KEYWORD, MOD_LONGLONG, .op = &mode_DI_op },
- { "TI", NS_KEYWORD, MOD_LONGLONGLONG, .op = &mode_TI_op },
- { "__TI__", NS_KEYWORD, MOD_LONGLONGLONG, .op = &mode_TI_op },
- { "word", NS_KEYWORD, MOD_LONG, .op = &mode_word_op },
- { "__word__", NS_KEYWORD, MOD_LONG, .op = &mode_word_op },
+ { "QI", NS_KEYWORD, .op = &mode_QI_op },
+ { "__QI__", NS_KEYWORD, .op = &mode_QI_op },
+ { "HI", NS_KEYWORD, .op = &mode_HI_op },
+ { "__HI__", NS_KEYWORD, .op = &mode_HI_op },
+ { "SI", NS_KEYWORD, .op = &mode_SI_op },
+ { "__SI__", NS_KEYWORD, .op = &mode_SI_op },
+ { "DI", NS_KEYWORD, .op = &mode_DI_op },
+ { "__DI__", NS_KEYWORD, .op = &mode_DI_op },
+ { "TI", NS_KEYWORD, .op = &mode_TI_op },
+ { "__TI__", NS_KEYWORD, .op = &mode_TI_op },
+ { "byte", NS_KEYWORD, .op = &mode_QI_op },
+ { "__byte__", NS_KEYWORD, .op = &mode_QI_op },
+ { "pointer", NS_KEYWORD, .op = &mode_pointer_op },
+ { "__pointer__",NS_KEYWORD, .op = &mode_pointer_op },
+ { "word", NS_KEYWORD, .op = &mode_word_op },
+ { "__word__", NS_KEYWORD, .op = &mode_word_op },
};
@@ -1105,6 +1117,14 @@ static struct symbol *to_TI_mode(struct symbol *ctype)
: &slllong_ctype;
}
+static struct symbol *to_pointer_mode(struct symbol *ctype)
+{
+ if (ctype->ctype.base_type != &int_type)
+ return NULL;
+ return ctype->ctype.modifiers & MOD_UNSIGNED ? uintptr_ctype
+ : intptr_ctype;
+}
+
static struct symbol *to_word_mode(struct symbol *ctype)
{
if (ctype->ctype.base_type != &int_type)
@@ -1121,7 +1141,7 @@ static struct token *attribute_mode(struct token *token, struct symbol *attr, st
if (mode && mode->op->type == KW_MODE)
ctx->mode = mode->op;
else
- sparse_error(token->pos, "unknown mode attribute %s\n", show_ident(token->ident));
+ sparse_error(token->pos, "unknown mode attribute %s", show_ident(token->ident));
token = token->next;
} else
sparse_error(token->pos, "expect attribute mode symbol\n");
diff --git a/pre-process.c b/pre-process.c
index da4b7acd..bf4b8e76 100644
--- a/pre-process.c
+++ b/pre-process.c
@@ -165,6 +165,12 @@ static void replace_with_has_builtin(struct token *token)
replace_with_bool(token, sym && sym->builtin);
}
+static void replace_with_has_attribute(struct token *token)
+{
+ struct symbol *sym = lookup_symbol(token->ident, NS_KEYWORD);
+ replace_with_bool(token, sym && sym->op && sym->op->attribute);
+}
+
static void expand_line(struct token *token)
{
replace_with_integer(token, token->pos.line);
@@ -1592,6 +1598,10 @@ static int expression_value(struct token **where)
state = 4;
beginning = list;
break;
+ } else if (p->ident == &__has_attribute_ident) {
+ state = 6;
+ beginning = list;
+ break;
}
if (!expand_one_symbol(list))
continue;
@@ -1623,29 +1633,34 @@ static int expression_value(struct token **where)
*list = p->next;
continue;
- // __has_builtin(xyz)
- case 4:
+ // __has_builtin(x) or __has_attribute(x)
+ case 4: case 6:
if (match_op(p, '(')) {
- state = 5;
+ state++;
} else {
- sparse_error(p->pos, "missing '(' after \"__has_builtin\"");
+ sparse_error(p->pos, "missing '(' after \"__has_%s\"",
+ state == 4 ? "builtin" : "attribute");
state = 0;
}
*beginning = p;
break;
- case 5:
+ case 5: case 7:
if (token_type(p) != TOKEN_IDENT) {
sparse_error(p->pos, "identifier expected");
state = 0;
break;
}
if (!match_op(p->next, ')'))
- sparse_error(p->pos, "missing ')' after \"__has_builtin\"");
- state = 6;
- replace_with_has_builtin(p);
+ sparse_error(p->pos, "missing ')' after \"__has_%s\"",
+ state == 5 ? "builtin" : "attribute");
+ if (state == 5)
+ replace_with_has_builtin(p);
+ else
+ replace_with_has_attribute(p);
+ state = 8;
*beginning = p;
break;
- case 6:
+ case 8:
state = 0;
*list = p->next;
continue;
diff --git a/simplify.c b/simplify.c
index 696d9d58..6397f426 100644
--- a/simplify.c
+++ b/simplify.c
@@ -337,7 +337,7 @@ int kill_insn(struct instruction *insn, int force)
break;
case OP_SYMADDR:
- kill_use(&insn->symbol);
+ kill_use(&insn->src);
repeat_phase |= REPEAT_SYMBOL_CLEANUP;
break;
@@ -361,7 +361,7 @@ int kill_insn(struct instruction *insn, int force)
break;
case OP_LOAD:
- if (!force && insn->type->ctype.modifiers & MOD_VOLATILE)
+ if (!force && insn->is_volatile)
return 0;
kill_use(&insn->src);
break;
@@ -401,6 +401,28 @@ static int dead_insn(struct instruction *insn, pseudo_t *src1, pseudo_t *src2, p
return REPEAT_CSE;
}
+static inline bool has_target(struct instruction *insn)
+{
+ return opcode_table[insn->opcode].flags & OPF_TARGET;
+}
+
+void remove_dead_insns(struct entrypoint *ep)
+{
+ struct basic_block *bb;
+
+ FOR_EACH_PTR_REVERSE(ep->bbs, bb) {
+ struct instruction *insn;
+ FOR_EACH_PTR_REVERSE(bb->insns, insn) {
+ if (!insn->bb)
+ continue;
+ if (!has_target(insn))
+ continue;
+ if (!has_users(insn->target))
+ kill_instruction(insn);
+ } END_FOR_EACH_PTR_REVERSE(insn);
+ } END_FOR_EACH_PTR_REVERSE(bb);
+}
+
static inline int constant(pseudo_t pseudo)
{
return pseudo->type == PSEUDO_VAL;
@@ -1729,9 +1751,9 @@ int simplify_instruction(struct instruction *insn)
case OP_STORE:
return simplify_memop(insn);
case OP_SYMADDR:
- if (dead_insn(insn, &insn->symbol, NULL, NULL))
+ if (dead_insn(insn, &insn->src, NULL, NULL))
return REPEAT_CSE | REPEAT_SYMBOL_CLEANUP;
- return replace_with_pseudo(insn, insn->symbol);
+ return replace_with_pseudo(insn, insn->src);
case OP_SEXT: case OP_ZEXT:
case OP_TRUNC:
return simplify_cast(insn);
diff --git a/sparse.1 b/sparse.1
index 8a14a6be..3e135235 100644
--- a/sparse.1
+++ b/sparse.1
@@ -77,6 +77,15 @@ Sparse issues these warnings by default. To turn them off, use
\fB\-Wno\-bitwise\fR.
.
.TP
+.B \-Wcast\-from\-as
+Warn about which remove an address space to a pointer type.
+
+This is similar to \fB\-Waddress\-space\fR but will also warn
+on casts to \fBunsigned long\fR.
+
+Sparse does not issues these warnings by default.
+.
+.TP
.B \-Wcast\-to\-as
Warn about casts which add an address space to a pointer type.
diff --git a/sparse.c b/sparse.c
index 6a445a17..975c0a4b 100644
--- a/sparse.c
+++ b/sparse.c
@@ -315,7 +315,7 @@ static void check_symbols(struct symbol_list *list)
expand_symbol(sym);
ep = linearize_symbol(sym);
- if (ep) {
+ if (ep && ep->entry) {
if (dbg_entry)
show_entry(ep);
diff --git a/ssa.c b/ssa.c
index d67c8ded..1c1ec695 100644
--- a/ssa.c
+++ b/ssa.c
@@ -5,6 +5,7 @@
//
#include <assert.h>
+#include "ssa.h"
#include "lib.h"
#include "sset.h"
#include "dominate.h"
diff --git a/ssa.h b/ssa.h
index cbcbc3a4..8537ac7b 100644
--- a/ssa.h
+++ b/ssa.h
@@ -1,6 +1,8 @@
#ifndef SSA_H
#define SSA_H
+struct entrypoint;
+
void ssa_convert(struct entrypoint *ep);
#endif
diff --git a/validation/Waddress-space-strict.c b/validation/Waddress-space-strict.c
new file mode 100644
index 00000000..5071aab2
--- /dev/null
+++ b/validation/Waddress-space-strict.c
@@ -0,0 +1,56 @@
+#define __user __attribute__((address_space(1)))
+
+typedef unsigned long ulong;
+typedef long long llong;
+typedef struct s obj_t;
+
+static void expl(int i, ulong u, llong l, void *v, obj_t *o, obj_t __user *p)
+{
+ (obj_t*)(i);
+ (obj_t __user*)(i);
+
+ (obj_t*)(u);
+ (obj_t __user*)(u);
+
+ (obj_t*)(l);
+ (obj_t __user*)(l);
+
+ (obj_t*)(v);
+ (obj_t __user*)(v);
+
+ (int)(o);
+ (ulong)(o);
+ (llong)(o);
+ (void *)(o);
+ (obj_t*)(o);
+ (obj_t __user*)(o);
+
+ (int)(p); // w
+ (ulong)(p); // w!
+ (llong)(p); // w
+ (void *)(p); // w
+ (obj_t*)(p); // w
+ (obj_t __user*)(p); // ok
+}
+
+/*
+ * check-name: Waddress-space-strict
+ * check-command: sparse -Wcast-from-as -Wcast-to-as $file
+ *
+ * check-error-start
+Waddress-space-strict.c:10:10: warning: cast adds address space to expression (<asn:1>)
+Waddress-space-strict.c:13:10: warning: cast adds address space to expression (<asn:1>)
+Waddress-space-strict.c:16:10: warning: cast adds address space to expression (<asn:1>)
+Waddress-space-strict.c:19:10: warning: cast adds address space to expression (<asn:1>)
+Waddress-space-strict.c:26:10: warning: cast adds address space to expression (<asn:1>)
+Waddress-space-strict.c:28:10: warning: cast removes address space of expression
+Waddress-space-strict.c:29:10: warning: cast removes address space of expression
+Waddress-space-strict.c:30:10: warning: cast removes address space of expression
+Waddress-space-strict.c:31:10: warning: cast removes address space of expression
+Waddress-space-strict.c:32:10: warning: cast removes address space of expression
+Waddress-space-strict.c:9:18: warning: non size-preserving integer to pointer cast
+Waddress-space-strict.c:10:25: warning: non size-preserving integer to pointer cast
+Waddress-space-strict.c:21:15: warning: non size-preserving pointer to integer cast
+Waddress-space-strict.c:28:15: warning: non size-preserving pointer to integer cast
+ * check-error-end
+ */
diff --git a/validation/enum+mode.c b/validation/enum+mode.c
new file mode 100644
index 00000000..182af189
--- /dev/null
+++ b/validation/enum+mode.c
@@ -0,0 +1,18 @@
+enum e { ZERO, ONE, TWO };
+
+struct s {
+ enum e __attribute__ ((mode(__byte__))) b;
+ enum e __attribute__ ((mode(__word__))) w;
+ enum e __attribute__ ((mode(__TI__))) t;
+};
+
+static struct s s;
+
+_Static_assert(sizeof(s.b) == 1, "");
+_Static_assert(sizeof(s.w) == sizeof(long), "");
+_Static_assert(sizeof(s.t) == sizeof(long long), "");
+
+/*
+ * check-name: enum+mode
+ * check-known-to-fail
+ */
diff --git a/validation/asm-toplevel.c b/validation/linear/asm-toplevel.c
index 8bdd7fc1..8bdd7fc1 100644
--- a/validation/asm-toplevel.c
+++ b/validation/linear/asm-toplevel.c
diff --git a/validation/linear/logical-phi0.c b/validation/linear/logical-phi0.c
new file mode 100644
index 00000000..96a47dba
--- /dev/null
+++ b/validation/linear/logical-phi0.c
@@ -0,0 +1,48 @@
+int a(void);
+int b(void);
+int c(void);
+
+static int laa(void)
+{
+ return (a() && b()) && c();
+}
+
+static int lao(void)
+{
+ return (a() && b()) || c();
+}
+
+static int loa(void)
+{
+ return (a() || b()) && c();
+}
+
+static int loo(void)
+{
+ return (a() || b()) || c();
+}
+
+static int raa(void)
+{
+ return a() && (b() && c());
+}
+
+static int rao(void)
+{
+ return a() && (b() || c());
+}
+
+static int roa(void)
+{
+ return a() || (b() && c());
+}
+
+static int roo(void)
+{
+ return a() || (b() || c());
+}
+
+/*
+ * check-name: bad-logical-phi0
+ * check-command: sparse -vir -flinearize=last $file
+ */
diff --git a/validation/linear/logical.c b/validation/linear/logical.c
index 0f502c6b..b190f608 100644
--- a/validation/linear/logical.c
+++ b/validation/linear/logical.c
@@ -26,24 +26,24 @@ os:
<entry-point>
store.32 %arg1 -> 0[i]
store.64 %arg2 -> 0[b]
+ load.32 %r2 <- 0[i]
+ setne.1 %r3 <- %r2, $0
phisrc.32 %phi1 <- $1
- load.32 %r1 <- 0[i]
- setne.1 %r2 <- %r1, $0
- cbr %r2, .L3, .L2
+ cbr %r3, .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
+ load.64 %r4 <- 0[b]
+ load.32 %r5 <- 0[%r4]
+ lsr.32 %r6 <- %r5, $1
+ trunc.2 %r7 <- (32) %r6
+ setne.1 %r8 <- %r7, $0
+ zext.32 %r9 <- (1) %r8
+ phisrc.32 %phi2 <- %r9
br .L3
.L3:
- phi.32 %r9 <- %phi1, %phi2
- phisrc.32 %phi3(return) <- %r9
+ phi.32 %r1 <- %phi1, %phi2
+ phisrc.32 %phi3(return) <- %r1
br .L1
.L1:
@@ -56,24 +56,24 @@ ou:
<entry-point>
store.32 %arg1 -> 0[i]
store.64 %arg2 -> 0[b]
+ load.32 %r12 <- 0[i]
+ setne.1 %r13 <- %r12, $0
phisrc.32 %phi4 <- $1
- load.32 %r11 <- 0[i]
- setne.1 %r12 <- %r11, $0
- cbr %r12, .L7, .L6
+ cbr %r13, .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 %phi5 <- %r18
+ load.64 %r14 <- 0[b]
+ load.32 %r15 <- 0[%r14]
+ lsr.32 %r16 <- %r15, $3
+ trunc.3 %r17 <- (32) %r16
+ setne.1 %r18 <- %r17, $0
+ zext.32 %r19 <- (1) %r18
+ phisrc.32 %phi5 <- %r19
br .L7
.L7:
- phi.32 %r19 <- %phi4, %phi5
- phisrc.32 %phi6(return) <- %r19
+ phi.32 %r11 <- %phi4, %phi5
+ phisrc.32 %phi6(return) <- %r11
br .L5
.L5:
@@ -86,22 +86,22 @@ ol:
<entry-point>
store.32 %arg1 -> 0[i]
store.64 %arg2 -> 0[b]
+ load.32 %r22 <- 0[i]
+ setne.1 %r23 <- %r22, $0
phisrc.32 %phi7 <- $1
- load.32 %r21 <- 0[i]
- setne.1 %r22 <- %r21, $0
- cbr %r22, .L11, .L10
+ cbr %r23, .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 %phi8 <- %r26
+ load.64 %r24 <- 0[b]
+ load.64 %r25 <- 8[%r24]
+ setne.1 %r26 <- %r25, $0
+ zext.32 %r27 <- (1) %r26
+ phisrc.32 %phi8 <- %r27
br .L11
.L11:
- phi.32 %r27 <- %phi7, %phi8
- phisrc.32 %phi9(return) <- %r27
+ phi.32 %r21 <- %phi7, %phi8
+ phisrc.32 %phi9(return) <- %r21
br .L9
.L9:
@@ -114,23 +114,23 @@ od:
<entry-point>
store.32 %arg1 -> 0[i]
store.64 %arg2 -> 0[b]
+ load.32 %r30 <- 0[i]
+ setne.1 %r31 <- %r30, $0
phisrc.32 %phi10 <- $1
- load.32 %r29 <- 0[i]
- setne.1 %r30 <- %r29, $0
- cbr %r30, .L15, .L14
+ cbr %r31, .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 %phi11 <- %r35
+ load.64 %r32 <- 0[b]
+ load.64 %r33 <- 16[%r32]
+ setfval.64 %r34 <- 0.000000e+00
+ fcmpune.1 %r35 <- %r33, %r34
+ zext.32 %r36 <- (1) %r35
+ phisrc.32 %phi11 <- %r36
br .L15
.L15:
- phi.32 %r36 <- %phi10, %phi11
- phisrc.32 %phi12(return) <- %r36
+ phi.32 %r29 <- %phi10, %phi11
+ phisrc.32 %phi12(return) <- %r29
br .L13
.L13:
@@ -143,24 +143,24 @@ as:
<entry-point>
store.32 %arg1 -> 0[i]
store.64 %arg2 -> 0[b]
+ load.32 %r39 <- 0[i]
+ setne.1 %r40 <- %r39, $0
phisrc.32 %phi13 <- $0
- load.32 %r38 <- 0[i]
- setne.1 %r39 <- %r38, $0
- cbr %r39, .L18, .L19
+ cbr %r40, .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 %phi14 <- %r45
+ load.64 %r41 <- 0[b]
+ load.32 %r42 <- 0[%r41]
+ lsr.32 %r43 <- %r42, $1
+ trunc.2 %r44 <- (32) %r43
+ setne.1 %r45 <- %r44, $0
+ zext.32 %r46 <- (1) %r45
+ phisrc.32 %phi14 <- %r46
br .L19
.L19:
- phi.32 %r46 <- %phi14, %phi13
- phisrc.32 %phi15(return) <- %r46
+ phi.32 %r38 <- %phi13, %phi14
+ phisrc.32 %phi15(return) <- %r38
br .L17
.L17:
@@ -173,24 +173,24 @@ au:
<entry-point>
store.32 %arg1 -> 0[i]
store.64 %arg2 -> 0[b]
+ load.32 %r49 <- 0[i]
+ setne.1 %r50 <- %r49, $0
phisrc.32 %phi16 <- $0
- load.32 %r48 <- 0[i]
- setne.1 %r49 <- %r48, $0
- cbr %r49, .L22, .L23
+ cbr %r50, .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 %phi17 <- %r55
+ load.64 %r51 <- 0[b]
+ load.32 %r52 <- 0[%r51]
+ lsr.32 %r53 <- %r52, $3
+ trunc.3 %r54 <- (32) %r53
+ setne.1 %r55 <- %r54, $0
+ zext.32 %r56 <- (1) %r55
+ phisrc.32 %phi17 <- %r56
br .L23
.L23:
- phi.32 %r56 <- %phi17, %phi16
- phisrc.32 %phi18(return) <- %r56
+ phi.32 %r48 <- %phi16, %phi17
+ phisrc.32 %phi18(return) <- %r48
br .L21
.L21:
@@ -203,22 +203,22 @@ al:
<entry-point>
store.32 %arg1 -> 0[i]
store.64 %arg2 -> 0[b]
+ load.32 %r59 <- 0[i]
+ setne.1 %r60 <- %r59, $0
phisrc.32 %phi19 <- $0
- load.32 %r58 <- 0[i]
- setne.1 %r59 <- %r58, $0
- cbr %r59, .L26, .L27
+ cbr %r60, .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 %phi20 <- %r63
+ load.64 %r61 <- 0[b]
+ load.64 %r62 <- 8[%r61]
+ setne.1 %r63 <- %r62, $0
+ zext.32 %r64 <- (1) %r63
+ phisrc.32 %phi20 <- %r64
br .L27
.L27:
- phi.32 %r64 <- %phi20, %phi19
- phisrc.32 %phi21(return) <- %r64
+ phi.32 %r58 <- %phi19, %phi20
+ phisrc.32 %phi21(return) <- %r58
br .L25
.L25:
@@ -231,23 +231,23 @@ ad:
<entry-point>
store.32 %arg1 -> 0[i]
store.64 %arg2 -> 0[b]
+ load.32 %r67 <- 0[i]
+ setne.1 %r68 <- %r67, $0
phisrc.32 %phi22 <- $0
- load.32 %r66 <- 0[i]
- setne.1 %r67 <- %r66, $0
- cbr %r67, .L30, .L31
+ cbr %r68, .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 %phi23 <- %r72
+ load.64 %r69 <- 0[b]
+ load.64 %r70 <- 16[%r69]
+ setfval.64 %r71 <- 0.000000e+00
+ fcmpune.1 %r72 <- %r70, %r71
+ zext.32 %r73 <- (1) %r72
+ phisrc.32 %phi23 <- %r73
br .L31
.L31:
- phi.32 %r73 <- %phi23, %phi22
- phisrc.32 %phi24(return) <- %r73
+ phi.32 %r66 <- %phi22, %phi23
+ phisrc.32 %phi24(return) <- %r66
br .L29
.L29:
diff --git a/validation/linear/missing-return0.c b/validation/linear/missing-return0.c
new file mode 100644
index 00000000..77ab5abd
--- /dev/null
+++ b/validation/linear/missing-return0.c
@@ -0,0 +1,10 @@
+static int foo(int a)
+{
+ if (a)
+ return 1;
+}
+
+/*
+ * check-name: missing-return0
+ * check-command: sparse -vir -flinearize=last $file
+ */
diff --git a/validation/linear/missing-return1.c b/validation/linear/missing-return1.c
new file mode 100644
index 00000000..4a8a9517
--- /dev/null
+++ b/validation/linear/missing-return1.c
@@ -0,0 +1,15 @@
+static inline int fun(int a)
+{
+ if (a)
+ return 1;
+}
+
+static int foo(int a)
+{
+ return fun(a);
+}
+
+/*
+ * check-name: missing-return1
+ * check-command: sparse -vir -flinearize=last $file
+ */
diff --git a/validation/linear/missing-return2.c b/validation/linear/missing-return2.c
new file mode 100644
index 00000000..395dcc14
--- /dev/null
+++ b/validation/linear/missing-return2.c
@@ -0,0 +1,11 @@
+static int foo(int a)
+{
+ switch (a)
+ case 3:
+ return 4;
+}
+
+/*
+ * check-name: missing-return2
+ * check-command: sparse -vir -flinearize=last $file
+ */
diff --git a/validation/linear/missing-return3.c b/validation/linear/missing-return3.c
new file mode 100644
index 00000000..b32e5eea
--- /dev/null
+++ b/validation/linear/missing-return3.c
@@ -0,0 +1,18 @@
+static int foo(int a)
+{
+ if (a)
+ return;
+}
+
+static void ref(void)
+{
+}
+
+/*
+ * check-name: missing-return3
+ * check-command: sparse -vir -flinearize=last $file
+ *
+ * check-error-start
+linear/missing-return3.c:4:17: error: return with no return value
+ * check-error-end
+ */
diff --git a/validation/linear/missing-return4.c b/validation/linear/missing-return4.c
new file mode 100644
index 00000000..779893a0
--- /dev/null
+++ b/validation/linear/missing-return4.c
@@ -0,0 +1,14 @@
+static int foo(int a)
+{
+ int r = a;
+ r;
+}
+
+/*
+ * check-name: missing-return4
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-error-ignore
+ * check-output-ignore
+ * check-output-contains: ret\\..*UNDEF
+ */
diff --git a/validation/linear/missing-return5.c b/validation/linear/missing-return5.c
new file mode 100644
index 00000000..e5504a19
--- /dev/null
+++ b/validation/linear/missing-return5.c
@@ -0,0 +1,23 @@
+int foo(int p)
+{
+ if (p)
+ return 0;
+}
+
+int bar(int p)
+{
+ if (p)
+ return 0;
+ p++;
+}
+
+/*
+ * check-name: missing/undef return
+ * check-command: test-linearize -Wno-decl -fdump-ir=linearize $file
+ *
+ * check-output-ignore
+ * check-output-pattern(2): phi\\..*,.*
+ * check-output-pattern(2): phisrc\\..*\\$0
+ * check-output-pattern(2): phisrc\\..*UNDEF
+ * check-output-excludes: ret\\..*\\$0
+ */
diff --git a/validation/linear/phi-order01.c b/validation/linear/phi-order01.c
new file mode 100644
index 00000000..0c4004fe
--- /dev/null
+++ b/validation/linear/phi-order01.c
@@ -0,0 +1,16 @@
+int fun(void);
+
+static int foo(int a)
+{
+ return a && fun();
+}
+
+static int bar(int a)
+{
+ return a || fun();
+}
+
+/*
+ * check-name: phi-order01
+ * check-command: sparse -vir -flinearize=last $file
+ */
diff --git a/validation/linear/phi-order02.c b/validation/linear/phi-order02.c
new file mode 100644
index 00000000..d217ae45
--- /dev/null
+++ b/validation/linear/phi-order02.c
@@ -0,0 +1,16 @@
+int fun(void);
+
+static int foo(int a) { return 0 || fun(); }
+static int bar(int a) { return 1 || fun(); }
+static int baz(int a) { return 0 && fun(); }
+static int qux(int a) { return 1 && fun(); }
+
+static int oof(int a) { return fun() || 1; }
+static int rab(int a) { return fun() || 0; }
+static int zab(int a) { return fun() && 1; }
+static int xuq(int a) { return fun() && 0; }
+
+/*
+ * check-name: phi-order02
+ * check-command: sparse -vir -flinearize=last $file
+ */
diff --git a/validation/linear/phi-order03.c b/validation/linear/phi-order03.c
new file mode 100644
index 00000000..24ae10e7
--- /dev/null
+++ b/validation/linear/phi-order03.c
@@ -0,0 +1,8 @@
+int fun(void);
+
+static int foo(void) { return ((0 || fun()) && fun()); }
+
+/*
+ * check-name: phi-order03
+ * check-command: sparse -vir -flinearize=last $file
+ */
diff --git a/validation/linear/phi-order04.c b/validation/linear/phi-order04.c
new file mode 100644
index 00000000..7548537a
--- /dev/null
+++ b/validation/linear/phi-order04.c
@@ -0,0 +1,12 @@
+static void foo(int *b)
+{
+ if (1) {
+ int c;
+ b = &c;
+ }
+}
+
+/*
+ * check-name: phi-order04
+ * check-command: sparse -vir -flinearize=last $file
+ */
diff --git a/validation/linear/unreachable-label0.c b/validation/linear/unreachable-label0.c
new file mode 100644
index 00000000..695e5cb0
--- /dev/null
+++ b/validation/linear/unreachable-label0.c
@@ -0,0 +1,19 @@
+static int foo(int a)
+{
+ goto label;
+ switch(a) {
+ default:
+label:
+ break;
+ }
+ return 0;
+}
+
+/*
+ * check-name: unreachable-label0
+ * check-command: test-linearize $file
+ *
+ * check-output-ignore
+ * check-output-contains: ret\\.
+ * check-output-excludes: END
+ */
diff --git a/validation/optim/volatile-bitfield.c b/validation/optim/volatile-bitfield.c
new file mode 100644
index 00000000..99db4401
--- /dev/null
+++ b/validation/optim/volatile-bitfield.c
@@ -0,0 +1,16 @@
+struct s {
+ int f:3;
+};
+
+void foo(volatile struct s *p)
+{
+ p->f;
+}
+
+/*
+ * check-name: volatile-bitfield
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-contains: load\\.
+ */
diff --git a/validation/preprocessor/has-attribute.c b/validation/preprocessor/has-attribute.c
new file mode 100644
index 00000000..3149cbfa
--- /dev/null
+++ b/validation/preprocessor/has-attribute.c
@@ -0,0 +1,56 @@
+#ifndef __has_attribute
+__has_attribute()??? Quesako?
+#define __has_attribute(x) 0
+#else
+"has __has_attribute(), yeah!"
+#endif
+
+123 __has_attribute(nothinx) def
+
+#if __has_attribute(nothinx)
+#error "not a attribute!"
+#endif
+
+#if 1 \
+ && __has_attribute(packed) \
+ && __has_attribute(aligned) \
+ && __has_attribute(const) \
+ && __has_attribute(pure) \
+ && __has_attribute(noreturn) \
+ && __has_attribute(designated_init) \
+ && __has_attribute(transparent_union) \
+
+"ok gcc"
+#endif
+
+#if 1 \
+ && __has_attribute(fastcall) \
+
+"ok gcc ignore"
+#endif
+
+#if 1 \
+ && __has_attribute(nocast) \
+ && __has_attribute(noderef) \
+ && __has_attribute(safe) \
+ && __has_attribute(force) \
+ && __has_attribute(bitwise) \
+ && __has_attribute(address_space) \
+ && __has_attribute(context) \
+
+"ok sparse specific"
+#endif
+
+/*
+ * check-name: has-attribute
+ * check-command: sparse -E $file
+ *
+ * check-output-start
+
+"has __has_attribute(), yeah!"
+123 0 def
+"ok gcc"
+"ok gcc ignore"
+"ok sparse specific"
+ * check-output-end
+ */