aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2020-03-20 16:24:19 +0100
committerLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2020-03-20 16:24:19 +0100
commitbff9b106e8fc02ab89da5fc7bf6d5e05b676da13 (patch)
tree962e41b4a6f9b891d41a28c04b107665a51cdb02
parent83789bbc4d38bef139259e6b0b3c04ea79e91f9f (diff)
parentd2be323e25c3378c60963c1f4250e2e286f0be3c (diff)
downloadsparse-bff9b106e8fc02ab89da5fc7bf6d5e05b676da13.tar.gz
Merge branch 'unreach'
* generate OP_UNREACH from __builtin_unreachable() * add OP_UNREACH after calls to __noreturn functions
-rw-r--r--Documentation/IR.rst3
-rw-r--r--builtin.c2
-rw-r--r--linearize.c52
-rw-r--r--opcode.def1
-rw-r--r--symbol.h7
-rw-r--r--validation/context-unreachable.c15
-rw-r--r--validation/linear/builtin_unreachable0.c27
-rw-r--r--validation/linear/builtin_unreachable1.c (renamed from validation/linear/builtin_unreachable.c)15
-rw-r--r--validation/linear/noreturn-unreachable0.c22
9 files changed, 135 insertions, 9 deletions
diff --git a/Documentation/IR.rst b/Documentation/IR.rst
index 9d6f2299..33a76166 100644
--- a/Documentation/IR.rst
+++ b/Documentation/IR.rst
@@ -47,6 +47,9 @@ Terminators
* .type: type of .cond, must be an integral type
* .multijmp_list: pairs of case-value - destination basic block
+.. op:: OP_UNREACH
+ Mark code as unreachable
+
.. op:: OP_COMPUTEDGOTO
Computed goto / branch to register
diff --git a/builtin.c b/builtin.c
index 52285a91..debc22c0 100644
--- a/builtin.c
+++ b/builtin.c
@@ -418,6 +418,8 @@ void init_builtins(int stream)
sym->op = ptr->op;
sym->builtin = 1;
}
+
+ init_linearized_builtins(stream);
}
static void declare_builtin(const char *name, struct symbol *rtype, int variadic, ...)
diff --git a/linearize.c b/linearize.c
index 30ed2a30..b040d345 100644
--- a/linearize.c
+++ b/linearize.c
@@ -183,6 +183,7 @@ static const char *opcodes[] = {
[OP_BR] = "br",
[OP_CBR] = "cbr",
[OP_SWITCH] = "switch",
+ [OP_UNREACH] = "unreachable",
[OP_COMPUTEDGOTO] = "jmp *",
/* Binary */
@@ -399,6 +400,8 @@ const char *show_instruction(struct instruction *insn)
} END_FOR_EACH_PTR(jmp);
break;
}
+ case OP_UNREACH:
+ break;
case OP_PHISOURCE: {
struct instruction *phi;
@@ -654,6 +657,13 @@ static void add_one_insn(struct entrypoint *ep, struct instruction *insn)
}
}
+static void add_unreachable(struct entrypoint *ep)
+{
+ struct instruction *insn = alloc_instruction(OP_UNREACH, 0);
+ add_one_insn(ep, insn);
+ ep->active = NULL;
+}
+
static void set_activeblock(struct entrypoint *ep, struct basic_block *bb)
{
if (!bb_terminated(ep->active))
@@ -1499,6 +1509,11 @@ static pseudo_t linearize_call_expression(struct entrypoint *ep, struct expressi
fn = expr->fn;
fntype = fn->ctype;
+
+ // handle builtins
+ if (fntype->op && fntype->op->linearize)
+ return fntype->op->linearize(ep, expr);
+
ctype = &fntype->ctype;
if (fntype->type == SYM_NODE)
fntype = fntype->ctype.base_type;
@@ -1548,6 +1563,9 @@ static pseudo_t linearize_call_expression(struct entrypoint *ep, struct expressi
add_one_insn(ep, insn);
}
} END_FOR_EACH_PTR(context);
+
+ if (ctype->modifiers & MOD_NORETURN)
+ add_unreachable(ep);
}
return retval;
@@ -2513,3 +2531,37 @@ struct entrypoint *linearize_symbol(struct symbol *sym)
return linearize_fn(sym, base_type);
return NULL;
}
+
+/*
+ * Builtin functions
+ */
+
+static pseudo_t linearize_unreachable(struct entrypoint *ep, struct expression *exp)
+{
+ add_unreachable(ep);
+ return VOID;
+}
+
+static struct sym_init {
+ const char *name;
+ pseudo_t (*linearize)(struct entrypoint *, struct expression*);
+ struct symbol_op op;
+} builtins_table[] = {
+ // must be declared in builtin.c:declare_builtins[]
+ { "__builtin_unreachable", linearize_unreachable },
+ { }
+};
+
+void init_linearized_builtins(int stream)
+{
+ struct sym_init *ptr;
+
+ for (ptr = builtins_table; ptr->name; ptr++) {
+ struct symbol *sym;
+ sym = create_symbol(stream, ptr->name, SYM_NODE, NS_SYMBOL);
+ if (!sym->op)
+ sym->op = &ptr->op;
+ sym->op->type |= KW_BUILTIN;
+ ptr->op.linearize = ptr->linearize;
+ }
+}
diff --git a/opcode.def b/opcode.def
index 57d827f4..2583e2f4 100644
--- a/opcode.def
+++ b/opcode.def
@@ -10,6 +10,7 @@ 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(UNREACH, BADOP, BADOP, BADOP, 0, OPF_NONE)
OPCODE(COMPUTEDGOTO, BADOP, BADOP, BADOP, 1, OPF_NONE)
OPCODE_RANGE(TERMINATOR, RET, COMPUTEDGOTO)
diff --git a/symbol.h b/symbol.h
index 9ef5a886..270ae098 100644
--- a/symbol.h
+++ b/symbol.h
@@ -78,7 +78,7 @@ enum keyword {
KW_MODIFIER = 1 << 1,
KW_QUALIFIER = 1 << 2,
KW_ATTRIBUTE = 1 << 3,
- // KW UNUSED = 1 << 4,
+ KW_BUILTIN = 1 << 4,
KW_ASM = 1 << 5,
KW_MODE = 1 << 6,
// KW UNUSED = 1 << 7,
@@ -112,11 +112,15 @@ struct decl_state {
unsigned char is_ext_visible;
};
+struct pseudo;
+struct entrypoint;
+
struct symbol_op {
enum keyword type;
int (*evaluate)(struct expression *);
int (*expand)(struct expression *, int);
int (*args)(struct expression *);
+ struct pseudo *(*linearize)(struct entrypoint *, struct expression *);
/* keywords */
struct token *(*declarator)(struct token *token, struct decl_state *ctx);
@@ -308,6 +312,7 @@ extern struct symbol *lookup_symbol(struct ident *, enum namespace);
extern struct symbol *create_symbol(int stream, const char *name, int type, int namespace);
extern void init_symbols(void);
extern void init_builtins(int stream);
+extern void init_linearized_builtins(int stream);
extern void declare_builtins(void);
extern void init_ctype(void);
extern struct symbol *alloc_symbol(struct position, int type);
diff --git a/validation/context-unreachable.c b/validation/context-unreachable.c
new file mode 100644
index 00000000..8664962e
--- /dev/null
+++ b/validation/context-unreachable.c
@@ -0,0 +1,15 @@
+int fun(void);
+
+static void foo(void)
+{
+ __context__(1);
+ if (!fun()) {
+ __builtin_unreachable();
+ return;
+ }
+ __context__(-1);
+}
+
+/*
+ * check-name: context-unreachable
+ */
diff --git a/validation/linear/builtin_unreachable0.c b/validation/linear/builtin_unreachable0.c
new file mode 100644
index 00000000..911ed7f9
--- /dev/null
+++ b/validation/linear/builtin_unreachable0.c
@@ -0,0 +1,27 @@
+int foo(int p)
+{
+ if (p == 3)
+ __builtin_unreachable();
+ return p;
+}
+
+/*
+ * check-name: builtin_unreachable0
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-start
+foo:
+.L0:
+ <entry-point>
+ seteq.32 %r2 <- %arg1, $3
+ cbr %r2, .L1, .L3
+
+.L1:
+ unreachable
+
+.L3:
+ ret.32 %arg1
+
+
+ * check-output-end
+ */
diff --git a/validation/linear/builtin_unreachable.c b/validation/linear/builtin_unreachable1.c
index 4f13b892..70f6674c 100644
--- a/validation/linear/builtin_unreachable.c
+++ b/validation/linear/builtin_unreachable1.c
@@ -1,31 +1,30 @@
-void function_that_never_returns(void);
+void die(void);
int foo(int c)
{
if (c)
return 1;
- function_that_never_returns();
+ die();
__builtin_unreachable();
}
/*
- * check-name: __builtin_unreachable()
+ * check-name: builtin_unreachable1
* check-command: test-linearize -Wno-decl $file
*
- * check-known-to-fail
* check-output-start
foo:
.L0:
<entry-point>
cbr %arg1, .L3, .L2
-.L2:
- call function_that_never_returns
- unreach
-
.L3:
ret.32 $1
+.L2:
+ call die
+ unreachable
+
* check-output-end
*/
diff --git a/validation/linear/noreturn-unreachable0.c b/validation/linear/noreturn-unreachable0.c
new file mode 100644
index 00000000..9bcd605f
--- /dev/null
+++ b/validation/linear/noreturn-unreachable0.c
@@ -0,0 +1,22 @@
+extern void die(void) __attribute__((noreturn));
+
+int foo(void)
+{
+ die();
+ return 0;
+}
+
+/*
+ * check-name: noreturn-unreachable0
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-start
+foo:
+.L0:
+ <entry-point>
+ call die
+ unreachable
+
+
+ * check-output-end
+ */