From 5666568c1cc04c6342757d29f3d4daafbdf9cdb6 Mon Sep 17 00:00:00 2001 From: Mid <245600-midn@users.noreply.gitlab.com> Date: Thu, 31 Aug 2023 15:26:08 +0300 Subject: [PATCH] Assemble ud-chain and use that for register allocation --- src/ast.c | 30 +++++++ src/ast.h | 4 +- src/cg.c | 14 +++- src/optims.c | 22 +----- src/parse.c | 192 ++++++++++++++++++++++++++------------------- src/vartable.c | 49 ++++++++++++ src/vartable.h | 41 ++++++++-- tests/mandelbrot.b | 145 ++++++++++++++++++++++++++++++++++ 8 files changed, 384 insertions(+), 113 deletions(-) create mode 100644 tests/mandelbrot.b diff --git a/src/ast.c b/src/ast.c index 7f152c5..642892b 100644 --- a/src/ast.c +++ b/src/ast.c @@ -30,4 +30,34 @@ int ast_expression_equal(AST *a, AST *b) { } return 0; +} + +// ... Ew +int ast_stmt_is_after(const AST *chunk, const AST *s1, const AST *s2) { + const AST *s = chunk->chunk.statementFirst; + + while(s) { + if(s == s1) { + return 0; + } + if(s == s2) { + return 1; + } + + if(s->nodeKind == AST_STMT_IF) { + int i = ast_stmt_is_after(s->stmtIf.then, s1, s2); + if(i != -1) { + return i; + } + } else if(s->nodeKind == AST_STMT_LOOP) { + int i = ast_stmt_is_after(s->stmtLoop.body, s1, s2); + if(i != -1) { + return i; + } + } + + s = s->statement.next; + } + + return -1; } \ No newline at end of file diff --git a/src/ast.h b/src/ast.h index aecff7d..920aeea 100644 --- a/src/ast.h +++ b/src/ast.h @@ -168,7 +168,7 @@ typedef struct { typedef struct { ASTStmt; - ASTChunk *body; + union AST *body; } ASTStmtLoop; typedef struct { @@ -254,4 +254,6 @@ typedef union AST { AST *ast_expression_optimize(AST*); int ast_expression_equal(AST*, AST*); +int ast_stmt_is_after(const AST *chunk, const AST *s1, const AST *s2); + #endif diff --git a/src/cg.c b/src/cg.c index d4994e2..518528a 100644 --- a/src/cg.c +++ b/src/cg.c @@ -99,6 +99,8 @@ static const char *xop(AST *e) { xv(e->exprUnOp.operand->exprBinOp.operands[1]->exprBinOp.operands[1]->exprVar.thing)); } else if(e->nodeKind == AST_EXPR_UNARY_OP && e->exprUnOp.operator == UNOP_REF && e->exprUnOp.operand->nodeKind == AST_EXPR_VAR && e->exprUnOp.operand->exprVar.thing->kind == VARTABLEENTRY_SYMBOL) { snprintf(ret, XOPBUFSZ, "%s", e->exprUnOp.operand->exprVar.thing->data.symbol.name); + } else if(e->nodeKind == AST_EXPR_UNARY_OP && e->exprUnOp.operator == UNOP_DEREF && e->exprUnOp.operand->nodeKind == AST_EXPR_VAR && e->exprUnOp.operand->exprVar.thing->kind == VARTABLEENTRY_VAR) { + snprintf(ret, XOPBUFSZ, "[%s]", xv(e->exprUnOp.operand->exprVar.thing)); } else { return NULL; } @@ -265,9 +267,15 @@ void cg_go(AST *a) { VarTableEntry *v2 = vars[v2i]; /* 1D intersection test */ - if((v1->data.var.start >= v2->data.var.start && v1->data.var.start <= v2->data.var.end) - || (v1->data.var.end >= v2->data.var.start && v1->data.var.end <= v2->data.var.end)) { - +// if((v1->data.var.start >= v2->data.var.start && v1->data.var.start <= v2->data.var.end) +// || (v1->data.var.end >= v2->data.var.start && v1->data.var.end <= v2->data.var.end)) { + if( + (ast_stmt_is_after(a, v1->data.var.usedefFirst->stmt, v2->data.var.usedefFirst->stmt) == 1 + && ast_stmt_is_after(a, v2->data.var.usedefLast->stmt, v1->data.var.usedefFirst->stmt) == 1) + || + (ast_stmt_is_after(a, v1->data.var.usedefLast->stmt, v2->data.var.usedefFirst->stmt) == 1 + && ast_stmt_is_after(a, v2->data.var.usedefLast->stmt, v1->data.var.usedefLast->stmt) == 1) + ) { VarTableEntry *min = v1 < v2 ? v1 : v2; VarTableEntry *max = v1 < v2 ? v2 : v1; diff --git a/src/optims.c b/src/optims.c index 1806835..fefbfc5 100644 --- a/src/optims.c +++ b/src/optims.c @@ -6,26 +6,8 @@ // But CP is NECESSARY, otherwise it creates too many variables // that are unable to be coalesced by the regallocator -static void recalc_lifespan(VarTableEntry *vte) { - assert(vte->kind == VARTABLEENTRY_VAR); - - size_t start = 0xFFFFFFFF, end = 0; - - UseDef *ud = vte->data.var.usedefFirst; - while(ud) { - if(ud->t < start) start = ud->t; - - if(ud->t > end) end = ud->t; - - ud = ud->next; - } - - vte->data.var.start = start; - vte->data.var.end = end; -} - void optim_chunk(ASTChunk *chu) { - AST *s = chu->statementFirst, *sPrev = NULL; + /*AST *s = chu->statementFirst, *sPrev = NULL; while(s) { if(s->nodeKind == AST_STMT_ASSIGN && s->stmtAssign.what->nodeKind == AST_EXPR_VAR && s->stmtAssign.to->nodeKind == AST_EXPR_VAR) { VarTableEntry *dst = ((AST*) s->stmtAssign.what)->exprVar.thing; @@ -89,5 +71,5 @@ void optim_chunk(ASTChunk *chu) { copypropfail: sPrev = s; s = s->statement.next; - } + }*/ } \ No newline at end of file diff --git a/src/parse.c b/src/parse.c index 2bc17b5..ff00bb8 100644 --- a/src/parse.c +++ b/src/parse.c @@ -9,17 +9,26 @@ #include #include +typedef struct { + UseDef ud; + VarTableEntry *to; +} UseDefToAdd; + typedef struct { Token *tokens; ssize_t i; - size_t t; - VarTable *scope; + // Used to coalesce all scopes into one after parsing, to perform global register allocation + ASTChunk *topLevel; + + // Used by pushstat to add statements ASTChunk *currentChunk; - ASTChunk *topLevel; + // Used by pushstmt to assemble use-def chain + size_t udsToAddCount; + UseDefToAdd *udsToAdd; } Parser; static Token get(Parser *P) { @@ -59,6 +68,23 @@ static int maybe(Parser *P, TokenKind t) { } static void pushstat(Parser *P, void *a) { + for(size_t i = 0; i < P->udsToAddCount; i++) { + VarTableEntry *to = P->udsToAdd[i].to; + + UseDef *ud = malloc(sizeof(*ud)); + memcpy(ud, &P->udsToAdd[i].ud, sizeof(*ud)); + ud->stmt = a; + + if(to->data.var.usedefFirst) { + to->data.var.usedefLast->next = ud; + to->data.var.usedefLast = ud; + } else { + to->data.var.usedefFirst = to->data.var.usedefLast = ud; + } + } + + P->udsToAddCount = 0; + if(P->currentChunk->statementFirst) { P->currentChunk->statementLast->statement.next = a; P->currentChunk->statementLast = a; @@ -86,15 +112,31 @@ static ASTExprPrimitive *parse_prim(Parser *P) { return ret; } -static AST *exprvar(Parser *P, VarTableEntry *v) { - if(v->kind == VARTABLEENTRY_VAR) { - v->data.var.end = P->t; +static void newusedef(Parser *P, VarTableEntry *v, AST *expr) { + for(size_t i = 0; i < v->data.var.reachingDefs->defCount; i++) { + P->udsToAdd = realloc(P->udsToAdd, sizeof(*P->udsToAdd) * (++P->udsToAddCount)); + P->udsToAdd[P->udsToAddCount - 1] = (UseDefToAdd) { + .ud = { + .def = v->data.var.reachingDefs->defs[i], + .use = expr, + .stmt = NULL, // set by pushstmt + .next = NULL, + }, + .to = v + }; } - +} + +static AST *exprvar(Parser *P, VarTableEntry *v) { AST *a = malloc(sizeof(ASTExprVar)); a->nodeKind = AST_EXPR_VAR; a->exprVar.type = v->type; a->exprVar.thing = v; + + if(v->kind == VARTABLEENTRY_VAR) { + newusedef(P, v, a); + } + return a; } @@ -318,28 +360,6 @@ AST *nct_parse_expression(Parser *P, int lOP) { stahp(P->tokens[P->i].row, P->tokens[P->i].column, "Invalid combination of operator and operand types."); } - if(0) if(operand->nodeKind == AST_EXPR_PRIMITIVE) { - VarTableEntry *thing = malloc(sizeof(*thing)); - thing->type = operand->expression.type; - thing->kind = VARTABLEENTRY_VAR; - thing->data.var.start = thing->data.var.end = P->t; - - P->topLevel->vars = realloc(P->topLevel->vars, sizeof(*P->topLevel->vars) * (P->topLevel->varCount + 1)); - P->topLevel->vars[P->topLevel->varCount++] = thing; - - AST *decl = malloc(sizeof(ASTStmtDecl)); - decl->nodeKind = AST_STMT_DECL; - decl->stmtDecl.thing = thing; - decl->stmtDecl.expression = operand; - pushstat(P, decl); - - AST *operand2 = malloc(sizeof(ASTExprVar)); - operand2->nodeKind = AST_EXPR_VAR; - operand2->expression.type = operand->expression.type; - operand2->exprVar.thing = thing; - operand = operand2; - } - astop->operands[1] = operand; if(!astop->type) { @@ -541,70 +561,73 @@ static AST *parse_declaration(Parser *P) { } else { entry = calloc(sizeof(*entry), 1); entry->type = type; - vartable_set(P->scope, name.content, entry); } - ASTStmtDecl *ret = malloc(sizeof(*ret)); - ret->nodeKind = AST_STMT_DECL; - ret->thing = entry; - ret->next = NULL; + AST *ret = NULL; - if(maybe(P, TOKEN_EQUALS)) { - if(isLocal || isExternal) { /* Impossible, error. */ + if(maybe(P, TOKEN_EQUALS) || (peek(P, 0).type == TOKEN_SEMICOLON && !isExternal && !isLocal)) { + /*if(isExternal || isLocal) { fputs("'local' and 'extern' keywords are to be used for symbol declaration only.\n", stderr); abort(); return NULL; - } + }*/ entry->kind = VARTABLEENTRY_VAR; - entry->data.var.start = entry->data.var.end = P->t; entry->data.var.priority = 1; - ret->expression = NULL; - - pushstat(P, ret); - - AST *assign = malloc(sizeof(ASTStmtAssign)); + ASTStmtAssign *assign = malloc(sizeof(*assign)); assign->nodeKind = AST_STMT_ASSIGN; - assign->stmtAssign.what = exprvar(P, entry); - assign->stmtAssign.to = nct_parse_expression(P, 0); - ret = assign; - } else if(maybe(P, TOKEN_COLON)) { - if(isExternal) { - fputs("External symbols may not be defined.\n", stderr); - abort(); - return NULL; - } + entry->data.var.reachingDefs = reachingdefs_push(NULL); + reachingdefs_set(entry->data.var.reachingDefs, (AST*) assign); - entry->kind = VARTABLEENTRY_SYMBOL; - entry->data.symbol.isLocal = isLocal; - entry->data.symbol.isExternal = isExternal; - entry->data.symbol.name = name.content; + assign->what = exprvar(P, entry); + assign->to = peek(P, 0).type == TOKEN_SEMICOLON ? NULL : nct_parse_expression(P, 0); - ret->expression = nct_cast_expr(nct_parse_expression(P, 0), type); + ret = (AST*) assign; - if(ret->expression) { - //if(ret->expression->expression.constantType == EXPRESSION_NOT_CONSTANT) { - // stahp(1, 4142, "Symbol declaration may contain constant expressions only."); - //} - } - } else if(isExternal) { - entry->kind = VARTABLEENTRY_SYMBOL; - entry->data.symbol.isLocal = isLocal; - entry->data.symbol.isExternal = isExternal; - entry->data.symbol.name = name.content; } else { - entry->kind = VARTABLEENTRY_VAR; - entry->data.var.start = entry->data.var.end = P->t; - entry->data.var.priority = 1; + ASTStmtDecl *decl = malloc(sizeof(*ret)); + decl->nodeKind = AST_STMT_DECL; + decl->thing = entry; + decl->next = NULL; - ret->expression = NULL; + if(maybe(P, TOKEN_COLON)) { + if(isExternal) { + fputs("External symbols may not be defined.\n", stderr); + abort(); + return NULL; + } + + entry->kind = VARTABLEENTRY_SYMBOL; + entry->data.symbol.isLocal = isLocal; + entry->data.symbol.isExternal = isExternal; + entry->data.symbol.name = name.content; + + decl->expression = nct_cast_expr(nct_parse_expression(P, 0), type); + + if(decl->expression) { + //if(ret->expression->expression.constantType == EXPRESSION_NOT_CONSTANT) { + // stahp(1, 4142, "Symbol declaration may contain constant expressions only."); + //} + } + } else if(isExternal) { + entry->kind = VARTABLEENTRY_SYMBOL; + entry->data.symbol.isLocal = isLocal; + entry->data.symbol.isExternal = isExternal; + entry->data.symbol.name = name.content; + } else { + abort(); + } + + ret = (AST*) decl; } + vartable_set(P->scope, name.content, entry); + expect(P, TOKEN_SEMICOLON); - return (AST*) ret; + return ret; backtrack: P->i = oldIdx; return NULL; @@ -612,8 +635,6 @@ backtrack: ASTChunk *nct_parse_chunk(Parser*, int, int); void nct_parse_statement(Parser *P) { - P->t++; - if(maybe(P, TOKEN_IF)) { expect(P, TOKEN_PAREN_L); AST *e = nct_parse_expression(P, 0); @@ -625,11 +646,11 @@ void nct_parse_statement(Parser *P) { ret->expression = e; + pushstat(P, ret); + expect(P, TOKEN_SQUIGGLY_L); ret->then = (AST*) nct_parse_chunk(P, 0, 0); expect(P, TOKEN_SQUIGGLY_R); - - pushstat(P, ret); return; } else if(maybe(P, TOKEN_LOOP)) { ASTStmtLoop *ret = malloc(sizeof(*ret)); @@ -637,7 +658,7 @@ void nct_parse_statement(Parser *P) { ret->next = NULL; expect(P, TOKEN_SQUIGGLY_L); - ret->body = nct_parse_chunk(P, 0, 1); + ret->body = (AST*) nct_parse_chunk(P, 0, 1); expect(P, TOKEN_SQUIGGLY_R); pushstat(P, ret); @@ -730,6 +751,10 @@ void nct_parse_statement(Parser *P) { ret->what = e; ret->to = nct_parse_expression(P, 0);//nct_cast_expr(nct_parse_expression(P, 0), ret->what->expression.type); + if(ret->what->nodeKind == AST_EXPR_VAR) { + reachingdefs_set(ret->what->exprVar.thing->data.var.reachingDefs, (AST*) ret); + } + expect(P, TOKEN_SEMICOLON); pushstat(P, ret); @@ -748,6 +773,9 @@ void nct_parse_statement(Parser *P) { } ASTChunk *nct_parse_chunk(Parser *P, int isTopLevel, int varPrioritize) { + if(P->scope) { + } + AST *ret = malloc(sizeof(ASTChunk)); ret->nodeKind = AST_CHUNK; ret->chunk.statementFirst = ret->chunk.statementLast = NULL; @@ -763,6 +791,8 @@ ASTChunk *nct_parse_chunk(Parser *P, int isTopLevel, int varPrioritize) { P->topLevel = &ret->chunk; } + vartable_new_reachingdefs_for_all_vars(P->scope); + /* Find all symbol names and struct types ahead of time. Searches for colons as those can only mean symbol declarations */ { @@ -790,7 +820,7 @@ ASTChunk *nct_parse_chunk(Parser *P, int isTopLevel, int varPrioritize) { } while(P->i >= 0 && P->tokens[P->i].type != TOKEN_SEMICOLON && P->tokens[P->i].type != TOKEN_SQUIGGLY_R && P->tokens[P->i].type != TOKEN_PAREN_R); P->i++; - ASTStmtDecl *d = &parse_declaration(P)->stmtDecl; + AST *d = parse_declaration(P); if(!d) abort(); free(d); /* We don't need it. */ @@ -805,6 +835,8 @@ ASTChunk *nct_parse_chunk(Parser *P, int isTopLevel, int varPrioritize) { nct_parse_statement(P); } + vartable_coalesce_reachingdefs_for_all_vars(P->scope); + size_t nonSymbols = 0; for(size_t i = 0; i < P->scope->count; i++) { if(P->scope->data[i]->kind == VARTABLEENTRY_VAR) { @@ -831,9 +863,7 @@ ASTChunk *nct_parse_chunk(Parser *P, int isTopLevel, int varPrioritize) { AST *nct_parse(Token *tokens) { Parser P; + memset(&P, 0, sizeof(P)); P.tokens = tokens; - P.t = 0; - P.i = 0; - P.scope = NULL; return (AST*) nct_parse_chunk(&P, 1, 0); } diff --git a/src/vartable.c b/src/vartable.c index 8127ec5..8d2b59a 100644 --- a/src/vartable.c +++ b/src/vartable.c @@ -4,6 +4,30 @@ #include #include +struct ReachingDefs *reachingdefs_push(struct ReachingDefs *this) { + struct ReachingDefs *ret = calloc(1, sizeof(*ret)); + ret->parent = this; + return ret; +} + +struct ReachingDefs *reachingdefs_coalesce(struct ReachingDefs *this) { + struct ReachingDefs *parent = this->parent; + if(parent) { + parent->defs = realloc(parent->defs, sizeof(*parent->defs) * (parent->defCount + this->defCount)); + memcpy(&parent->defs[parent->defCount], this->defs, sizeof(*this->defs) * this->defCount); + parent->defCount += this->defCount; + } + free(this->defs); + free(this); + return parent; +} + +void reachingdefs_set(struct ReachingDefs *this, union AST *def) { + this->defCount = 1; + this->defs = realloc(this->defs, sizeof(*this->defs) * this->defCount); + this->defs[0] = def; +} + VarTable *vartable_new(VarTable *parent) { VarTable *ret = malloc(sizeof(*ret)); ret->parent = parent; @@ -39,5 +63,30 @@ VarTableEntry *vartable_set(VarTable *this, const char *name, VarTableEntry *e) this->names[this->count] = name; this->data[this->count] = e; this->count++; + if(e->kind == VARTABLEENTRY_VAR) e->data.var.name = name; return e; } + +void vartable_new_reachingdefs_for_all_vars(VarTable *this) { + for(size_t i = 0; i < this->count; i++) { + if(this->data[i]->kind == VARTABLEENTRY_VAR) { + this->data[i]->data.var.reachingDefs = reachingdefs_push(this->data[i]->data.var.reachingDefs); + } + } + + if(this->parent) { + vartable_new_reachingdefs_for_all_vars(this->parent); + } +} + +void vartable_coalesce_reachingdefs_for_all_vars(VarTable *this) { + for(size_t i = 0; i < this->count; i++) { + if(this->data[i]->kind == VARTABLEENTRY_VAR) { + this->data[i]->data.var.reachingDefs = reachingdefs_coalesce(this->data[i]->data.var.reachingDefs); + } + } + + if(this->parent) { + vartable_coalesce_reachingdefs_for_all_vars(this->parent); + } +} diff --git a/src/vartable.h b/src/vartable.h index c7bed10..e47c557 100644 --- a/src/vartable.h +++ b/src/vartable.h @@ -7,13 +7,25 @@ typedef enum { VARTABLEENTRY_SYMBOL, VARTABLEENTRY_TYPE, VARTABLEENTRY_VAR } VarTableEntryKind; +union AST; typedef struct UseDef { - union AST *use; //expr - union AST *def; //assign stmt - size_t t; + union AST *def; // assign stmt + union AST *use; // corresponding AST_EXPR_VAR + union AST *stmt; // whole using stmt struct UseDef *next; } UseDef; +// Stack, necessary for "possible reaching defs" such as from if statements +typedef struct ReachingDefs { + size_t defCount; + union AST **defs; + + struct ReachingDefs *parent; +} ReachingDefs; +struct ReachingDefs *reachingdefs_push(struct ReachingDefs*); +struct ReachingDefs *reachingdefs_coalesce(struct ReachingDefs*); +void reachingdefs_set(struct ReachingDefs*, union AST*); + typedef struct VarTableEntry { Type *type; @@ -26,18 +38,28 @@ typedef struct VarTableEntry { const char *name; } symbol; struct { - uint16_t color, degree; - size_t start, end; + // For debugging + + const char *name; + + // Register allocation + + // vars in loops have higher priority + // a more advanced approach would be to use weights for different colors (e.g. vars for mul "should" be in eax) uint8_t priority; + uint16_t color, degree; + + // Used during parsing + + ReachingDefs *reachingDefs; + + // Optimizations UseDef *usedefFirst; UseDef *usedefLast; } var; }; - struct VarTableEntry *offset; } data; - - void *userdata; } VarTableEntry; typedef struct VarTable { @@ -53,4 +75,7 @@ VarTableEntry *vartable_get(VarTable*, const char*); VarTableEntry *vartable_find(VarTable*, const char*); VarTableEntry *vartable_set(VarTable*, const char*, VarTableEntry*); +void vartable_new_reachingdefs_for_all_vars(VarTable*); +void vartable_coalesce_reachingdefs_for_all_vars(VarTable*); + #endif diff --git a/tests/mandelbrot.b b/tests/mandelbrot.b new file mode 100644 index 0000000..5e253e1 --- /dev/null +++ b/tests/mandelbrot.b @@ -0,0 +1,145 @@ + A mandelbrot set fractal viewer in brainf*** written by Erik Bosman ++++++++++++++[->++>>>+++++>++>+<<<<<<]>>>>>++++++>--->>>>>>>>>>+++++++++++++++[[ +>>>>>>>>>]+[<<<<<<<<<]>>>>>>>>>-]+[>>>>>>>>[-]>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>[-]+ +<<<<<<<+++++[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>>>>+>>>>>>>>>>>>>>>>>>>>>>>>>> +>+<<<<<<<<<<<<<<<<<[<<<<<<<<<]>>>[-]+[>>>>>>[>>>>>>>[-]>>]<<<<<<<<<[<<<<<<<<<]>> +>>>>>[-]+<<<<<<++++[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>>>+<<<<<<+++++++[-[->>> +>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>>>+<<<<<<<<<<<<<<<<[<<<<<<<<<]>>>[[-]>>>>>>[>>>>> +>>[-<<<<<<+>>>>>>]<<<<<<[->>>>>>+<<+<<<+<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>> +[>>>>>>>>[-<<<<<<<+>>>>>>>]<<<<<<<[->>>>>>>+<<+<<<+<<]>>>>>>>>]<<<<<<<<<[<<<<<<< +<<]>>>>>>>[-<<<<<<<+>>>>>>>]<<<<<<<[->>>>>>>+<<+<<<<<]>>>>>>>>>+++++++++++++++[[ +>>>>>>>>>]+>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+[ +>+>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>->>>>[-<<<<+>>>>]<<<<[->>>>+<<<<<[->>[ +-<<+>>]<<[->>+>>+<<<<]+>>>>>>>>>]<<<<<<<<[<<<<<<<<<]]>>>>>>>>>[>>>>>>>>>]<<<<<<< +<<[>[->>>>>>>>>+<<<<<<<<<]<<<<<<<<<<]>[->>>>>>>>>+<<<<<<<<<]<+>>>>>>>>]<<<<<<<<< +[>[-]<->>>>[-<<<<+>[<->-<<<<<<+>>>>>>]<[->+<]>>>>]<<<[->>>+<<<]<+<<<<<<<<<]>>>>> +>>>>[>+>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>->>>>>[-<<<<<+>>>>>]<<<<<[->>>>>+ +<<<<<<[->>>[-<<<+>>>]<<<[->>>+>+<<<<]+>>>>>>>>>]<<<<<<<<[<<<<<<<<<]]>>>>>>>>>[>> +>>>>>>>]<<<<<<<<<[>>[->>>>>>>>>+<<<<<<<<<]<<<<<<<<<<<]>>[->>>>>>>>>+<<<<<<<<<]<< ++>>>>>>>>]<<<<<<<<<[>[-]<->>>>[-<<<<+>[<->-<<<<<<+>>>>>>]<[->+<]>>>>]<<<[->>>+<< +<]<+<<<<<<<<<]>>>>>>>>>[>>>>[-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>> +>>>>>>>>>>>>>>>>>>>>>>>]>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>+++++++++++++++[[>>>> +>>>>>]<<<<<<<<<-<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+>>>>>>>>>>>>>>>>>>>>>+<<<[<<<<<< +<<<]>>>>>>>>>[>>>[-<<<->>>]+<<<[->>>->[-<<<<+>>>>]<<<<[->>>>+<<<<<<<<<<<<<[<<<<< +<<<<]>>>>[-]+>>>>>[>>>>>>>>>]>+<]]+>>>>[-<<<<->>>>]+<<<<[->>>>-<[-<<<+>>>]<<<[-> +>>+<<<<<<<<<<<<[<<<<<<<<<]>>>[-]+>>>>>>[>>>>>>>>>]>[-]+<]]+>[-<[>>>>>>>>>]<<<<<< +<<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]<<<<<<<[->+>>>-<<<<]>>>>>>>>>+++++++++++++++++++ ++++++++>>[-<<<<+>>>>]<<<<[->>>>+<<[-]<<]>>[<<<<<<<+<[-<+>>>>+<<[-]]>[-<<[->+>>>- +<<<<]>>>]>>>>>>>>>>>>>[>>[-]>[-]>[-]>>>>>]<<<<<<<<<[<<<<<<<<<]>>>[-]>>>>>>[>>>>> +[-<<<<+>>>>]<<<<[->>>>+<<<+<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>>[-<<<<<<<< +<+>>>>>>>>>]>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>+++++++++++++++[[>>>>>>>>>]+>[- +]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+[>+>>>>>>>>]<<< +<<<<<<[<<<<<<<<<]>>>>>>>>>[>->>>>>[-<<<<<+>>>>>]<<<<<[->>>>>+<<<<<<[->>[-<<+>>]< +<[->>+>+<<<]+>>>>>>>>>]<<<<<<<<[<<<<<<<<<]]>>>>>>>>>[>>>>>>>>>]<<<<<<<<<[>[->>>> +>>>>>+<<<<<<<<<]<<<<<<<<<<]>[->>>>>>>>>+<<<<<<<<<]<+>>>>>>>>]<<<<<<<<<[>[-]<->>> +[-<<<+>[<->-<<<<<<<+>>>>>>>]<[->+<]>>>]<<[->>+<<]<+<<<<<<<<<]>>>>>>>>>[>>>>>>[-< +<<<<+>>>>>]<<<<<[->>>>>+<<<<+<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>+>>>>>>>> +]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>->>>>>[-<<<<<+>>>>>]<<<<<[->>>>>+<<<<<<[->>[-<<+ +>>]<<[->>+>>+<<<<]+>>>>>>>>>]<<<<<<<<[<<<<<<<<<]]>>>>>>>>>[>>>>>>>>>]<<<<<<<<<[> +[->>>>>>>>>+<<<<<<<<<]<<<<<<<<<<]>[->>>>>>>>>+<<<<<<<<<]<+>>>>>>>>]<<<<<<<<<[>[- +]<->>>>[-<<<<+>[<->-<<<<<<+>>>>>>]<[->+<]>>>>]<<<[->>>+<<<]<+<<<<<<<<<]>>>>>>>>> +[>>>>[-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> +]>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>>>[-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+> +>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>]>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>++++++++ ++++++++[[>>>>>>>>>]<<<<<<<<<-<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+[>>>>>>>>[-<<<<<<<+ +>>>>>>>]<<<<<<<[->>>>>>>+<<<<<<+<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>>>>>>[ +-]>>>]<<<<<<<<<[<<<<<<<<<]>>>>+>[-<-<<<<+>>>>>]>[-<<<<<<[->>>>>+<++<<<<]>>>>>[-< +<<<<+>>>>>]<->+>]<[->+<]<<<<<[->>>>>+<<<<<]>>>>>>[-]<<<<<<+>>>>[-<<<<->>>>]+<<<< +[->>>>->>>>>[>>[-<<->>]+<<[->>->[-<<<+>>>]<<<[->>>+<<<<<<<<<<<<[<<<<<<<<<]>>>[-] ++>>>>>>[>>>>>>>>>]>+<]]+>>>[-<<<->>>]+<<<[->>>-<[-<<+>>]<<[->>+<<<<<<<<<<<[<<<<< +<<<<]>>>>[-]+>>>>>[>>>>>>>>>]>[-]+<]]+>[-<[>>>>>>>>>]<<<<<<<<]>>>>>>>>]<<<<<<<<< +[<<<<<<<<<]>>>>[-<<<<+>>>>]<<<<[->>>>+>>>>>[>+>>[-<<->>]<<[->>+<<]>>>>>>>>]<<<<< +<<<+<[>[->>>>>+<<<<[->>>>-<<<<<<<<<<<<<<+>>>>>>>>>>>[->>>+<<<]<]>[->>>-<<<<<<<<< +<<<<<+>>>>>>>>>>>]<<]>[->>>>+<<<[->>>-<<<<<<<<<<<<<<+>>>>>>>>>>>]<]>[->>>+<<<]<< +<<<<<<<<<<]>>>>[-]<<<<]>>>[-<<<+>>>]<<<[->>>+>>>>>>[>+>[-<->]<[->+<]>>>>>>>>]<<< +<<<<<+<[>[->>>>>+<<<[->>>-<<<<<<<<<<<<<<+>>>>>>>>>>[->>>>+<<<<]>]<[->>>>-<<<<<<< +<<<<<<<+>>>>>>>>>>]<]>>[->>>+<<<<[->>>>-<<<<<<<<<<<<<<+>>>>>>>>>>]>]<[->>>>+<<<< +]<<<<<<<<<<<]>>>>>>+<<<<<<]]>>>>[-<<<<+>>>>]<<<<[->>>>+>>>>>[>>>>>>>>>]<<<<<<<<< +[>[->>>>>+<<<<[->>>>-<<<<<<<<<<<<<<+>>>>>>>>>>>[->>>+<<<]<]>[->>>-<<<<<<<<<<<<<< ++>>>>>>>>>>>]<<]>[->>>>+<<<[->>>-<<<<<<<<<<<<<<+>>>>>>>>>>>]<]>[->>>+<<<]<<<<<<< +<<<<<]]>[-]>>[-]>[-]>>>>>[>>[-]>[-]>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>>>>>[-< +<<<+>>>>]<<<<[->>>>+<<<+<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>+++++++++++++++[ +[>>>>>>>>>]+>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+ +[>+>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>->>>>[-<<<<+>>>>]<<<<[->>>>+<<<<<[->> +[-<<+>>]<<[->>+>+<<<]+>>>>>>>>>]<<<<<<<<[<<<<<<<<<]]>>>>>>>>>[>>>>>>>>>]<<<<<<<< +<[>[->>>>>>>>>+<<<<<<<<<]<<<<<<<<<<]>[->>>>>>>>>+<<<<<<<<<]<+>>>>>>>>]<<<<<<<<<[ +>[-]<->>>[-<<<+>[<->-<<<<<<<+>>>>>>>]<[->+<]>>>]<<[->>+<<]<+<<<<<<<<<]>>>>>>>>>[ +>>>[-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>]> +>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>[-]>>>>+++++++++++++++[[>>>>>>>>>]<<<<<<<<<-<<<<< +<<<<[<<<<<<<<<]>>>>>>>>>-]+[>>>[-<<<->>>]+<<<[->>>->[-<<<<+>>>>]<<<<[->>>>+<<<<< +<<<<<<<<[<<<<<<<<<]>>>>[-]+>>>>>[>>>>>>>>>]>+<]]+>>>>[-<<<<->>>>]+<<<<[->>>>-<[- +<<<+>>>]<<<[->>>+<<<<<<<<<<<<[<<<<<<<<<]>>>[-]+>>>>>>[>>>>>>>>>]>[-]+<]]+>[-<[>> +>>>>>>>]<<<<<<<<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>[-<<<+>>>]<<<[->>>+>>>>>>[>+>>> +[-<<<->>>]<<<[->>>+<<<]>>>>>>>>]<<<<<<<<+<[>[->+>[-<-<<<<<<<<<<+>>>>>>>>>>>>[-<< ++>>]<]>[-<<-<<<<<<<<<<+>>>>>>>>>>>>]<<<]>>[-<+>>[-<<-<<<<<<<<<<+>>>>>>>>>>>>]<]> +[-<<+>>]<<<<<<<<<<<<<]]>>>>[-<<<<+>>>>]<<<<[->>>>+>>>>>[>+>>[-<<->>]<<[->>+<<]>> +>>>>>>]<<<<<<<<+<[>[->+>>[-<<-<<<<<<<<<<+>>>>>>>>>>>[-<+>]>]<[-<-<<<<<<<<<<+>>>> +>>>>>>>]<<]>>>[-<<+>[-<-<<<<<<<<<<+>>>>>>>>>>>]>]<[-<+>]<<<<<<<<<<<<]>>>>>+<<<<< +]>>>>>>>>>[>>>[-]>[-]>[-]>>>>]<<<<<<<<<[<<<<<<<<<]>>>[-]>[-]>>>>>[>>>>>>>[-<<<<< +<+>>>>>>]<<<<<<[->>>>>>+<<<<+<<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>+>[-<-<<<<+>>>> +>]>>[-<<<<<<<[->>>>>+<++<<<<]>>>>>[-<<<<<+>>>>>]<->+>>]<<[->>+<<]<<<<<[->>>>>+<< +<<<]+>>>>[-<<<<->>>>]+<<<<[->>>>->>>>>[>>>[-<<<->>>]+<<<[->>>-<[-<<+>>]<<[->>+<< +<<<<<<<<<[<<<<<<<<<]>>>>[-]+>>>>>[>>>>>>>>>]>+<]]+>>[-<<->>]+<<[->>->[-<<<+>>>]< +<<[->>>+<<<<<<<<<<<<[<<<<<<<<<]>>>[-]+>>>>>>[>>>>>>>>>]>[-]+<]]+>[-<[>>>>>>>>>]< +<<<<<<<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>[-<<<+>>>]<<<[->>>+>>>>>>[>+>[-<->]<[->+ +<]>>>>>>>>]<<<<<<<<+<[>[->>>>+<<[->>-<<<<<<<<<<<<<+>>>>>>>>>>[->>>+<<<]>]<[->>>- +<<<<<<<<<<<<<+>>>>>>>>>>]<]>>[->>+<<<[->>>-<<<<<<<<<<<<<+>>>>>>>>>>]>]<[->>>+<<< +]<<<<<<<<<<<]>>>>>[-]>>[-<<<<<<<+>>>>>>>]<<<<<<<[->>>>>>>+<<+<<<<<]]>>>>[-<<<<+> +>>>]<<<<[->>>>+>>>>>[>+>>[-<<->>]<<[->>+<<]>>>>>>>>]<<<<<<<<+<[>[->>>>+<<<[->>>- +<<<<<<<<<<<<<+>>>>>>>>>>>[->>+<<]<]>[->>-<<<<<<<<<<<<<+>>>>>>>>>>>]<<]>[->>>+<<[ +->>-<<<<<<<<<<<<<+>>>>>>>>>>>]<]>[->>+<<]<<<<<<<<<<<<]]>>>>[-]<<<<]>>>>[-<<<<+>> +>>]<<<<[->>>>+>[-]>>[-<<<<<<<+>>>>>>>]<<<<<<<[->>>>>>>+<<+<<<<<]>>>>>>>>>[>>>>>> +>>>]<<<<<<<<<[>[->>>>+<<<[->>>-<<<<<<<<<<<<<+>>>>>>>>>>>[->>+<<]<]>[->>-<<<<<<<< +<<<<<+>>>>>>>>>>>]<<]>[->>>+<<[->>-<<<<<<<<<<<<<+>>>>>>>>>>>]<]>[->>+<<]<<<<<<<< +<<<<]]>>>>>>>>>[>>[-]>[-]>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>[-]>[-]>>>>>[>>>>>[-<<<<+ +>>>>]<<<<[->>>>+<<<+<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>>>>>>[-<<<<<+>>>>> +]<<<<<[->>>>>+<<<+<<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>+++++++++++++++[[>>>> +>>>>>]+>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+[>+>> +>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>->>>>[-<<<<+>>>>]<<<<[->>>>+<<<<<[->>[-<<+ +>>]<<[->>+>>+<<<<]+>>>>>>>>>]<<<<<<<<[<<<<<<<<<]]>>>>>>>>>[>>>>>>>>>]<<<<<<<<<[> +[->>>>>>>>>+<<<<<<<<<]<<<<<<<<<<]>[->>>>>>>>>+<<<<<<<<<]<+>>>>>>>>]<<<<<<<<<[>[- +]<->>>>[-<<<<+>[<->-<<<<<<+>>>>>>]<[->+<]>>>>]<<<[->>>+<<<]<+<<<<<<<<<]>>>>>>>>> +[>+>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>->>>>>[-<<<<<+>>>>>]<<<<<[->>>>>+<<<< +<<[->>>[-<<<+>>>]<<<[->>>+>+<<<<]+>>>>>>>>>]<<<<<<<<[<<<<<<<<<]]>>>>>>>>>[>>>>>> +>>>]<<<<<<<<<[>>[->>>>>>>>>+<<<<<<<<<]<<<<<<<<<<<]>>[->>>>>>>>>+<<<<<<<<<]<<+>>> +>>>>>]<<<<<<<<<[>[-]<->>>>[-<<<<+>[<->-<<<<<<+>>>>>>]<[->+<]>>>>]<<<[->>>+<<<]<+ +<<<<<<<<<]>>>>>>>>>[>>>>[-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>> +>>>>>>>>>>>>>>>>>>>]>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>+++++++++++++++[[>>>>>>>> +>]<<<<<<<<<-<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+>>>>>>>>>>>>>>>>>>>>>+<<<[<<<<<<<<<] +>>>>>>>>>[>>>[-<<<->>>]+<<<[->>>->[-<<<<+>>>>]<<<<[->>>>+<<<<<<<<<<<<<[<<<<<<<<< +]>>>>[-]+>>>>>[>>>>>>>>>]>+<]]+>>>>[-<<<<->>>>]+<<<<[->>>>-<[-<<<+>>>]<<<[->>>+< +<<<<<<<<<<<[<<<<<<<<<]>>>[-]+>>>>>>[>>>>>>>>>]>[-]+<]]+>[-<[>>>>>>>>>]<<<<<<<<]> +>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>->>[-<<<<+>>>>]<<<<[->>>>+<<[-]<<]>>]<<+>>>>[-<<<< +->>>>]+<<<<[->>>>-<<<<<<.>>]>>>>[-<<<<<<<.>>>>>>>]<<<[-]>[-]>[-]>[-]>[-]>[-]>>>[ +>[-]>[-]>[-]>[-]>[-]>[-]>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>>>>>[-]>>>>]<<<<<<<<< +[<<<<<<<<<]>+++++++++++[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>+>>>>>>>>>+<<<<<<<< +<<<<<<[<<<<<<<<<]>>>>>>>[-<<<<<<<+>>>>>>>]<<<<<<<[->>>>>>>+[-]>>[>>>>>>>>>]<<<<< +<<<<[>>>>>>>[-<<<<<<+>>>>>>]<<<<<<[->>>>>>+<<<<<<<[<<<<<<<<<]>>>>>>>[-]+>>>]<<<< +<<<<<<]]>>>>>>>[-<<<<<<<+>>>>>>>]<<<<<<<[->>>>>>>+>>[>+>>>>[-<<<<->>>>]<<<<[->>> +>+<<<<]>>>>>>>>]<<+<<<<<<<[>>>>>[->>+<<]<<<<<<<<<<<<<<]>>>>>>>>>[>>>>>>>>>]<<<<< +<<<<[>[-]<->>>>>>>[-<<<<<<<+>[<->-<<<+>>>]<[->+<]>>>>>>>]<<<<<<[->>>>>>+<<<<<<]< ++<<<<<<<<<]>>>>>>>-<<<<[-]+<<<]+>>>>>>>[-<<<<<<<->>>>>>>]+<<<<<<<[->>>>>>>->>[>> +>>>[->>+<<]>>>>]<<<<<<<<<[>[-]<->>>>>>>[-<<<<<<<+>[<->-<<<+>>>]<[->+<]>>>>>>>]<< +<<<<[->>>>>>+<<<<<<]<+<<<<<<<<<]>+++++[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>+<<< +<<[<<<<<<<<<]>>>>>>>>>[>>>>>[-<<<<<->>>>>]+<<<<<[->>>>>->>[-<<<<<<<+>>>>>>>]<<<< +<<<[->>>>>>>+<<<<<<<<<<<<<<<<[<<<<<<<<<]>>>>[-]+>>>>>[>>>>>>>>>]>+<]]+>>>>>>>[-< +<<<<<<->>>>>>>]+<<<<<<<[->>>>>>>-<<[-<<<<<+>>>>>]<<<<<[->>>>>+<<<<<<<<<<<<<<[<<< +<<<<<<]>>>[-]+>>>>>>[>>>>>>>>>]>[-]+<]]+>[-<[>>>>>>>>>]<<<<<<<<]>>>>>>>>]<<<<<<< +<<[<<<<<<<<<]>>>>[-]<<<+++++[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>-<<<<<[<<<<<<< +<<]]>>>]<<<<.>>>>>>>>>>[>>>>>>[-]>>>]<<<<<<<<<[<<<<<<<<<]>++++++++++[-[->>>>>>>> +>+<<<<<<<<<]>>>>>>>>>]>>>>>+>>>>>>>>>+<<<<<<<<<<<<<<<[<<<<<<<<<]>>>>>>>>[-<<<<<< +<<+>>>>>>>>]<<<<<<<<[->>>>>>>>+[-]>[>>>>>>>>>]<<<<<<<<<[>>>>>>>>[-<<<<<<<+>>>>>> +>]<<<<<<<[->>>>>>>+<<<<<<<<[<<<<<<<<<]>>>>>>>>[-]+>>]<<<<<<<<<<]]>>>>>>>>[-<<<<< +<<<+>>>>>>>>]<<<<<<<<[->>>>>>>>+>[>+>>>>>[-<<<<<->>>>>]<<<<<[->>>>>+<<<<<]>>>>>> +>>]<+<<<<<<<<[>>>>>>[->>+<<]<<<<<<<<<<<<<<<]>>>>>>>>>[>>>>>>>>>]<<<<<<<<<[>[-]<- +>>>>>>>>[-<<<<<<<<+>[<->-<<+>>]<[->+<]>>>>>>>>]<<<<<<<[->>>>>>>+<<<<<<<]<+<<<<<< +<<<]>>>>>>>>-<<<<<[-]+<<<]+>>>>>>>>[-<<<<<<<<->>>>>>>>]+<<<<<<<<[->>>>>>>>->[>>> +>>>[->>+<<]>>>]<<<<<<<<<[>[-]<->>>>>>>>[-<<<<<<<<+>[<->-<<+>>]<[->+<]>>>>>>>>]<< +<<<<<[->>>>>>>+<<<<<<<]<+<<<<<<<<<]>+++++[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>> ++>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<[<<<<<<<<<]>>>>>>>>>[>>>>>>[-<<<<<<->>>>>>]+< +<<<<<[->>>>>>->>[-<<<<<<<<+>>>>>>>>]<<<<<<<<[->>>>>>>>+<<<<<<<<<<<<<<<<<[<<<<<<< +<<]>>>>[-]+>>>>>[>>>>>>>>>]>+<]]+>>>>>>>>[-<<<<<<<<->>>>>>>>]+<<<<<<<<[->>>>>>>> +-<<[-<<<<<<+>>>>>>]<<<<<<[->>>>>>+<<<<<<<<<<<<<<<[<<<<<<<<<]>>>[-]+>>>>>>[>>>>>> +>>>]>[-]+<]]+>[-<[>>>>>>>>>]<<<<<<<<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>[-]<<<++++ ++[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>>->>>>>>>>>>>>>>>>>>>>>>>>>>>-<<<<<<[<<<< +<<<<<]]>>>]