Merge pull request #4 from sebastianrcnt/agent/extract-m5-ownership
refactor: extract M5 ownership analysis
This commit is contained in:
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
CC ?= cc
|
CC ?= cc
|
||||||
CFLAGS ?= -O2 -Wall -Wextra -std=c89
|
CFLAGS ?= -O2 -Wall -Wextra -std=c89
|
||||||
CPPFLAGS ?= -Isrc
|
CPPFLAGS ?= -Isrc
|
||||||
SRC = src/arena.c src/diag.c src/lexer.c src/ast.c src/parser.c src/types.c src/check.c src/emit_c.c src/driver.c
|
SRC = src/arena.c src/diag.c src/lexer.c src/ast.c src/parser.c src/types.c src/own.c src/check.c src/emit_c.c src/driver.c
|
||||||
OBJ = $(SRC:.c=.o)
|
OBJ = $(SRC:.c=.o)
|
||||||
|
|
||||||
.PHONY: all clean dos-build
|
.PHONY: all clean dos-build
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ wcl -q -za -wx -bt=dos -ml -k32768 -c -fo=parser.obj src\parser.c
|
|||||||
if errorlevel 1 goto build_fail
|
if errorlevel 1 goto build_fail
|
||||||
wcl -q -za -wx -bt=dos -ml -k32768 -c -fo=types.obj src\types.c
|
wcl -q -za -wx -bt=dos -ml -k32768 -c -fo=types.obj src\types.c
|
||||||
if errorlevel 1 goto build_fail
|
if errorlevel 1 goto build_fail
|
||||||
|
wcl -q -za -wx -bt=dos -ml -k32768 -c -fo=own.obj src\own.c
|
||||||
|
if errorlevel 1 goto build_fail
|
||||||
wcl -q -za -wx -bt=dos -ml -k32768 -c -fo=check.obj src\check.c
|
wcl -q -za -wx -bt=dos -ml -k32768 -c -fo=check.obj src\check.c
|
||||||
if errorlevel 1 goto build_fail
|
if errorlevel 1 goto build_fail
|
||||||
rem Use an unambiguous short object name for the emit_c source.
|
rem Use an unambiguous short object name for the emit_c source.
|
||||||
|
|||||||
+14
-51
@@ -1,4 +1,5 @@
|
|||||||
#include "check.h"
|
#include "check.h"
|
||||||
|
#include "own.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
@@ -49,50 +50,15 @@ static int known(FeType *t)
|
|||||||
return t && t->kind != FE_TYPE_UNKNOWN && t->kind != FE_TYPE_ERROR;
|
return t && t->kind != FE_TYPE_UNKNOWN && t->kind != FE_TYPE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int is_copy_type(FeType *t)
|
|
||||||
{
|
|
||||||
unsigned i;
|
|
||||||
if (!t) return 1;
|
|
||||||
if (t->kind==FE_TYPE_OWNED) return 0;
|
|
||||||
if (t->kind==FE_TYPE_REF || t->kind==FE_TYPE_SLICE) return !t->ref_mut;
|
|
||||||
if (t->kind==FE_TYPE_ARRAY) return is_copy_type(t->elem);
|
|
||||||
if (t->kind==FE_TYPE_STRUCT) {
|
|
||||||
if (t->has_drop) return 0;
|
|
||||||
for (i=0;i<t->field_count;i++) if (!is_copy_type(t->fields[i].type)) return 0;
|
|
||||||
}
|
|
||||||
if (t->kind==FE_TYPE_ENUM)
|
|
||||||
for (i=0;i<t->variant_count;i++) {
|
|
||||||
unsigned j;
|
|
||||||
for (j=0;j<t->variants[i].field_count;j++)
|
|
||||||
if (!is_copy_type(t->variants[i].fields[j].type)) return 0;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void mark_moved(FeCheckerState *s, FeNode *n, FeType *t)
|
static void mark_moved(FeCheckerState *s, FeNode *n, FeType *t)
|
||||||
{
|
{
|
||||||
FeSym *sym;
|
FeSym *sym=0;
|
||||||
if (!n || !t || is_copy_type(t)) return;
|
if (n && n->kind==FE_N_IDENT)
|
||||||
if(n->kind==FE_N_INDEX && t->kind==FE_TYPE_SLICE &&
|
|
||||||
(n->c || !n->b)) return;
|
|
||||||
if(n->kind==FE_N_MEMBER || n->kind==FE_N_INDEX) {
|
|
||||||
err(s->c,n->loc,
|
|
||||||
"cannot move a non-Copy value out of a projection; use mem.replace");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(n->kind!=FE_N_IDENT) return;
|
|
||||||
sym=find_symbol(s->scope,n->text ? n->text : "");
|
sym=find_symbol(s->scope,n->text ? n->text : "");
|
||||||
if (sym) {
|
fe_own_mark_consumed(s->c->diags,
|
||||||
if (s->defer_depth) {
|
sym ? &sym->moved : 0,
|
||||||
if (sym->decl) sym->decl->flags |= 0x200U;
|
sym ? sym->decl : 0,
|
||||||
} else {
|
n,t,s->defer_depth != 0);
|
||||||
sym->moved=1;
|
|
||||||
/* Mark this consuming expression, not the declaration. Branches
|
|
||||||
may move conditionally; the declaration's runtime live flag
|
|
||||||
must remain available to guard cleanup on the other path. */
|
|
||||||
n->flags |= 0x100U;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int compatible(FeType *want, FeType *got, FeNode *value)
|
static int compatible(FeType *want, FeType *got, FeNode *value)
|
||||||
@@ -244,7 +210,7 @@ static FeSym *add_symbol(FeCheckerState *s, FeScope *scope,
|
|||||||
sym->fn = fn;
|
sym->fn = fn;
|
||||||
sym->mutable = mutable;
|
sym->mutable = mutable;
|
||||||
sym->initialized = initialized;
|
sym->initialized = initialized;
|
||||||
sym->moved = 0;
|
sym->moved = FE_OWN_AVAILABLE;
|
||||||
sym->decl = decl;
|
sym->decl = decl;
|
||||||
if (decl) {
|
if (decl) {
|
||||||
decl->cname = cname;
|
decl->cname = cname;
|
||||||
@@ -329,9 +295,8 @@ static void flow_merge(FeFlowSlot *base, FeFlowSlot *left, FeFlowSlot *right,
|
|||||||
{
|
{
|
||||||
unsigned i;
|
unsigned i;
|
||||||
for (i=0; i<count; ++i) {
|
for (i=0; i<count; ++i) {
|
||||||
base[i].sym->moved = left[i].moved==1 && right[i].moved==1 ? 1 :
|
base[i].sym->moved=fe_own_merge_move(left[i].moved,right[i].moved);
|
||||||
(left[i].moved || right[i].moved ? 2 : 0);
|
base[i].sym->initialized=left[i].initialized && right[i].initialized;
|
||||||
base[i].sym->initialized = left[i].initialized && right[i].initialized;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -579,8 +544,7 @@ static FeType *check_identifier(FeCheckerState *s, FeNode *n, int read)
|
|||||||
}
|
}
|
||||||
n->cname = sym->cname;
|
n->cname = sym->cname;
|
||||||
n->sem_type = sym->type;
|
n->sem_type = sym->type;
|
||||||
if (sym->moved == 1) err(s->c,n->loc,"use of moved value");
|
fe_own_check_use(s->c->diags,sym->moved,n->loc);
|
||||||
else if (sym->moved == 2) err(s->c,n->loc,"use of possibly moved value");
|
|
||||||
if (read && !sym->initialized && !sym->fn)
|
if (read && !sym->initialized && !sym->fn)
|
||||||
err(s->c, n->loc, "use of uninitialized variable");
|
err(s->c, n->loc, "use of uninitialized variable");
|
||||||
return sym->type;
|
return sym->type;
|
||||||
@@ -1007,8 +971,7 @@ static void check_match(FeCheckerState *s, FeNode *n)
|
|||||||
have_merged=1;
|
have_merged=1;
|
||||||
} else {
|
} else {
|
||||||
for(i=0;i<flow_count;++i) {
|
for(i=0;i<flow_count;++i) {
|
||||||
merged[i].moved=merged[i].moved==1 && current[i].moved==1 ? 1 :
|
merged[i].moved=fe_own_merge_move(merged[i].moved,current[i].moved);
|
||||||
(merged[i].moved || current[i].moved ? 2 : 0);
|
|
||||||
merged[i].initialized=merged[i].initialized && current[i].initialized;
|
merged[i].initialized=merged[i].initialized && current[i].initialized;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1233,7 +1196,7 @@ static void check_stmt(FeCheckerState *s, FeNode *n)
|
|||||||
flow_capture(s->scope,body,flow_count);
|
flow_capture(s->scope,body,flow_count);
|
||||||
for (i=0;i<flow_count;++i) {
|
for (i=0;i<flow_count;++i) {
|
||||||
entry2[i]=base[i];
|
entry2[i]=base[i];
|
||||||
if(body[i].moved!=base[i].moved) entry2[i].moved=2;
|
entry2[i].moved=fe_own_loop_entry(base[i].moved,body[i].moved);
|
||||||
if(!body[i].initialized) entry2[i].initialized=0;
|
if(!body[i].initialized) entry2[i].initialized=0;
|
||||||
}
|
}
|
||||||
flow_restore(entry2,flow_count);
|
flow_restore(entry2,flow_count);
|
||||||
@@ -1242,7 +1205,7 @@ static void check_stmt(FeCheckerState *s, FeNode *n)
|
|||||||
if (s->loop_depth) --s->loop_depth;
|
if (s->loop_depth) --s->loop_depth;
|
||||||
flow_capture(s->scope,body,flow_count);
|
flow_capture(s->scope,body,flow_count);
|
||||||
for(i=0;i<flow_count;++i) {
|
for(i=0;i<flow_count;++i) {
|
||||||
if(body[i].moved) entry2[i].moved=2;
|
entry2[i].moved=fe_own_loop_exit(entry2[i].moved,body[i].moved);
|
||||||
if(!body[i].initialized) entry2[i].initialized=0;
|
if(!body[i].initialized) entry2[i].initialized=0;
|
||||||
}
|
}
|
||||||
flow_restore(entry2,flow_count);
|
flow_restore(entry2,flow_count);
|
||||||
|
|||||||
@@ -0,0 +1,80 @@
|
|||||||
|
#include "own.h"
|
||||||
|
|
||||||
|
int fe_own_is_copy_type(FeType *type)
|
||||||
|
{
|
||||||
|
unsigned i;
|
||||||
|
if (!type) return 1;
|
||||||
|
if (type->kind == FE_TYPE_OWNED) return 0;
|
||||||
|
if (type->kind == FE_TYPE_REF || type->kind == FE_TYPE_SLICE)
|
||||||
|
return !type->ref_mut;
|
||||||
|
if (type->kind == FE_TYPE_ARRAY)
|
||||||
|
return fe_own_is_copy_type(type->elem);
|
||||||
|
if (type->kind == FE_TYPE_STRUCT) {
|
||||||
|
if (type->has_drop) return 0;
|
||||||
|
for (i = 0; i < type->field_count; ++i)
|
||||||
|
if (!fe_own_is_copy_type(type->fields[i].type)) return 0;
|
||||||
|
}
|
||||||
|
if (type->kind == FE_TYPE_ENUM) {
|
||||||
|
for (i = 0; i < type->variant_count; ++i) {
|
||||||
|
unsigned j;
|
||||||
|
for (j = 0; j < type->variants[i].field_count; ++j)
|
||||||
|
if (!fe_own_is_copy_type(type->variants[i].fields[j].type))
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void fe_own_mark_consumed(FeDiags *diags, int *state, FeNode *decl,
|
||||||
|
FeNode *expr, FeType *type, int in_defer)
|
||||||
|
{
|
||||||
|
if (!expr || !type || fe_own_is_copy_type(type)) return;
|
||||||
|
if (expr->kind == FE_N_INDEX && type->kind == FE_TYPE_SLICE &&
|
||||||
|
(expr->c || !expr->b))
|
||||||
|
return;
|
||||||
|
if (expr->kind == FE_N_MEMBER || expr->kind == FE_N_INDEX) {
|
||||||
|
fe_diag_error(diags, expr->loc,
|
||||||
|
"cannot move a non-Copy value out of a projection; use mem.replace");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (expr->kind != FE_N_IDENT || !state) return;
|
||||||
|
|
||||||
|
if (in_defer) {
|
||||||
|
if (decl) decl->flags |= FE_OWN_NODE_DEFER_CAPTURE;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
*state = FE_OWN_MOVED;
|
||||||
|
/* The consuming use owns the live-flag transition. The declaration must
|
||||||
|
stay live on control-flow paths where the move did not execute. */
|
||||||
|
expr->flags |= FE_OWN_NODE_CONSUMED;
|
||||||
|
}
|
||||||
|
|
||||||
|
void fe_own_check_use(FeDiags *diags, int state, FeLoc loc)
|
||||||
|
{
|
||||||
|
if (state == FE_OWN_MOVED)
|
||||||
|
fe_diag_error(diags, loc, "use of moved value");
|
||||||
|
else if (state == FE_OWN_MAYBE_MOVED)
|
||||||
|
fe_diag_error(diags, loc, "use of possibly moved value");
|
||||||
|
}
|
||||||
|
|
||||||
|
int fe_own_merge_move(int left, int right)
|
||||||
|
{
|
||||||
|
if (left == FE_OWN_MOVED && right == FE_OWN_MOVED)
|
||||||
|
return FE_OWN_MOVED;
|
||||||
|
if (left != FE_OWN_AVAILABLE || right != FE_OWN_AVAILABLE)
|
||||||
|
return FE_OWN_MAYBE_MOVED;
|
||||||
|
return FE_OWN_AVAILABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fe_own_loop_entry(int before, int after)
|
||||||
|
{
|
||||||
|
if (before == after) return before;
|
||||||
|
return FE_OWN_MAYBE_MOVED;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fe_own_loop_exit(int state, int after)
|
||||||
|
{
|
||||||
|
if (after != FE_OWN_AVAILABLE) return FE_OWN_MAYBE_MOVED;
|
||||||
|
return state;
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
#ifndef FE_OWN_H
|
||||||
|
#define FE_OWN_H
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
#include "diag.h"
|
||||||
|
|
||||||
|
#define FE_OWN_NODE_CONSUMED 0x100U
|
||||||
|
#define FE_OWN_NODE_DEFER_CAPTURE 0x200U
|
||||||
|
|
||||||
|
enum FeOwnMoveState {
|
||||||
|
FE_OWN_AVAILABLE = 0,
|
||||||
|
FE_OWN_MOVED = 1,
|
||||||
|
FE_OWN_MAYBE_MOVED = 2
|
||||||
|
};
|
||||||
|
|
||||||
|
int fe_own_is_copy_type(FeType *type);
|
||||||
|
void fe_own_mark_consumed(FeDiags *diags, int *state, FeNode *decl,
|
||||||
|
FeNode *expr, FeType *type, int in_defer);
|
||||||
|
void fe_own_check_use(FeDiags *diags, int state, FeLoc loc);
|
||||||
|
int fe_own_merge_move(int left, int right);
|
||||||
|
int fe_own_loop_entry(int before, int after);
|
||||||
|
int fe_own_loop_exit(int state, int after);
|
||||||
|
|
||||||
|
#endif
|
||||||
Reference in New Issue
Block a user