diff options
author | Luc Van Oostenryck <luc.vanoostenryck@gmail.com> | 2020-03-20 16:24:19 +0100 |
---|---|---|
committer | Luc Van Oostenryck <luc.vanoostenryck@gmail.com> | 2020-03-20 16:24:19 +0100 |
commit | bff9b106e8fc02ab89da5fc7bf6d5e05b676da13 (patch) | |
tree | 962e41b4a6f9b891d41a28c04b107665a51cdb02 | |
parent | 83789bbc4d38bef139259e6b0b3c04ea79e91f9f (diff) | |
parent | d2be323e25c3378c60963c1f4250e2e286f0be3c (diff) | |
download | sparse-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.rst | 3 | ||||
-rw-r--r-- | builtin.c | 2 | ||||
-rw-r--r-- | linearize.c | 52 | ||||
-rw-r--r-- | opcode.def | 1 | ||||
-rw-r--r-- | symbol.h | 7 | ||||
-rw-r--r-- | validation/context-unreachable.c | 15 | ||||
-rw-r--r-- | validation/linear/builtin_unreachable0.c | 27 | ||||
-rw-r--r-- | validation/linear/builtin_unreachable1.c (renamed from validation/linear/builtin_unreachable.c) | 15 | ||||
-rw-r--r-- | validation/linear/noreturn-unreachable0.c | 22 |
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 @@ -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; + } +} @@ -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) @@ -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 + */ |