mirror of
https://github.com/ton-blockchain/ton
synced 2025-03-09 15:40:10 +00:00
A series of FunC improvements (#378)
* Don't use IFJMP/IFNOTJMP in inline functions * Fix incorrect ifelse branch code generation https://github.com/ton-blockchain/ton/issues/374 * Make generate_code_all clearer * Don't replace IFJMP with IF in inner blocks in inline functions * Allow unbalance if/else by using RETALT * Fix wrong PUSHCONT * Bugfix in IF code generation for inline functions * Fix unbalanced if/else * Bugfix and improvements in code generation * Fix analyzing while(0) in func https://github.com/ton-blockchain/ton/issues/377 * FunC and Asm.fif: Fix inlining large functions https://github.com/ton-blockchain/ton/issues/375 Co-authored-by: SpyCheese <mikle98@yandex.ru>
This commit is contained in:
parent
fecf760aae
commit
40cec56e28
5 changed files with 144 additions and 81 deletions
|
@ -1,15 +1,17 @@
|
||||||
library TVM_Asm
|
library TVM_Asm
|
||||||
// simple TVM Assembler
|
// simple TVM Assembler
|
||||||
variable @atend
|
variable @atend
|
||||||
|
variable @was-split
|
||||||
|
false @was-split !
|
||||||
{ "not in asm context" abort } @atend !
|
{ "not in asm context" abort } @atend !
|
||||||
{ `normal eq? not abort"must be terminated by }>" } : @normal?
|
{ `normal eq? not abort"must be terminated by }>" } : @normal?
|
||||||
{ @atend @ 1 { @atend ! @normal? } does @atend ! } : @pushatend
|
{ @atend @ 1 { @atend ! @normal? } does @atend ! } : @pushatend
|
||||||
{ @pushatend <b } : <{
|
{ @pushatend <b } : <{
|
||||||
{ @atend @ execute } : @endblk
|
{ @atend @ execute } : @endblk
|
||||||
{ `normal @endblk } : }>
|
{ false @was-split ! `normal @endblk } : }>
|
||||||
{ }> b> } : }>c
|
{ }> b> } : }>c
|
||||||
{ }>c <s } : }>s
|
{ }>c <s } : }>s
|
||||||
{ @atend @ 2 { @atend ! rot b> ref, swap @endblk } does @atend ! <b } : @|
|
{ @atend @ 2 { true @was-split ! @atend ! rot b> ref, swap @endblk } does @atend ! <b } : @|
|
||||||
{ @atend @ 3 { @atend ! 2swap rot execute } does @atend ! <b } : @doafter<{
|
{ @atend @ 3 { @atend ! 2swap rot execute } does @atend ! <b } : @doafter<{
|
||||||
{ over brembits <= } : @havebits
|
{ over brembits <= } : @havebits
|
||||||
{ rot + -rot + swap } : pair+
|
{ rot + -rot + swap } : pair+
|
||||||
|
@ -1225,6 +1227,10 @@ variable asm-mode 1 asm-mode !
|
||||||
} : PROGRAM{
|
} : PROGRAM{
|
||||||
{ over sbits < { s>c <b swap ref, b> <s } if } : @adj-long-proc
|
{ over sbits < { s>c <b swap ref, b> <s } if } : @adj-long-proc
|
||||||
{ // i s l
|
{ // i s l
|
||||||
|
dup 0< {
|
||||||
|
negate
|
||||||
|
@was-split @ { drop 0 } if
|
||||||
|
} if
|
||||||
@adj-long-proc over @procdict @ @procdictkeylen
|
@adj-long-proc over @procdict @ @procdictkeylen
|
||||||
idict!+ not abort"cannot define procedure, redefined?"
|
idict!+ not abort"cannot define procedure, redefined?"
|
||||||
@procdict ! 2 2 @procinfo~!
|
@procdict ! 2 2 @procinfo~!
|
||||||
|
@ -1234,6 +1240,7 @@ variable asm-mode 1 asm-mode !
|
||||||
{ @have-procinfo? { 8 8 @procinfo~! } { drop } cond } : @proc-called
|
{ @have-procinfo? { 8 8 @procinfo~! } { drop } cond } : @proc-called
|
||||||
{ 1000 @def-proc } : PROC
|
{ 1000 @def-proc } : PROC
|
||||||
{ 0 @def-proc } : PROCREF
|
{ 0 @def-proc } : PROCREF
|
||||||
|
{ -1000 @def-proc } : PROCINLINE
|
||||||
{ @procdict @ @procdictkeylen idict@ abort"procedure already defined"
|
{ @procdict @ @procdictkeylen idict@ abort"procedure already defined"
|
||||||
} : @fail-ifdef
|
} : @fail-ifdef
|
||||||
{ u@?+ { swap abort"first bits are not zeroes" } if } : @cut-zeroes
|
{ u@?+ { swap abort"first bits are not zeroes" } if } : @cut-zeroes
|
||||||
|
@ -1243,6 +1250,7 @@ variable asm-mode 1 asm-mode !
|
||||||
} : @PROC:<{
|
} : @PROC:<{
|
||||||
{ 1000 @PROC:<{ } : PROC:<{
|
{ 1000 @PROC:<{ } : PROC:<{
|
||||||
{ 0 @PROC:<{ } : PROCREF:<{
|
{ 0 @PROC:<{ } : PROCREF:<{
|
||||||
|
{ -1000 @PROC:<{ } : PROCINLINE:<{
|
||||||
{ dup @proc-called CALLDICT } dup : CALL : CALLDICT
|
{ dup @proc-called CALLDICT } dup : CALL : CALLDICT
|
||||||
{ dup @proc-called JMPDICT } dup : JMP : JMPDICT
|
{ dup @proc-called JMPDICT } dup : JMP : JMPDICT
|
||||||
{ dup @proc-called PREPAREDICT } dup : PREPARE : PREPAREDICT
|
{ dup @proc-called PREPAREDICT } dup : PREPARE : PREPAREDICT
|
||||||
|
|
|
@ -586,7 +586,7 @@ bool prune_unreachable(std::unique_ptr<Op>& ops) {
|
||||||
// block1 never executed
|
// block1 never executed
|
||||||
op.block0->last().next = std::move(op.next);
|
op.block0->last().next = std::move(op.next);
|
||||||
ops = std::move(op.block0);
|
ops = std::move(op.block0);
|
||||||
return false;
|
return prune_unreachable(ops);
|
||||||
} else if (c_var && c_var->always_true()) {
|
} else if (c_var && c_var->always_true()) {
|
||||||
if (!prune_unreachable(op.block1)) {
|
if (!prune_unreachable(op.block1)) {
|
||||||
// block1 never returns
|
// block1 never returns
|
||||||
|
|
|
@ -277,12 +277,16 @@ bool Op::generate_code_step(Stack& stack) {
|
||||||
stack.drop_vars_except(var_info);
|
stack.drop_vars_except(var_info);
|
||||||
stack.opt_show();
|
stack.opt_show();
|
||||||
const auto& next_var_info = next->var_info;
|
const auto& next_var_info = next->var_info;
|
||||||
|
bool inline_func = stack.mode & Stack::_InlineFunc;
|
||||||
switch (cl) {
|
switch (cl) {
|
||||||
case _Nop:
|
case _Nop:
|
||||||
case _Import:
|
case _Import:
|
||||||
return true;
|
return true;
|
||||||
case _Return: {
|
case _Return: {
|
||||||
stack.enforce_state(left);
|
stack.enforce_state(left);
|
||||||
|
if (stack.o.retalt_ && (stack.mode & Stack::_NeedRetAlt)) {
|
||||||
|
stack.o << "RETALT";
|
||||||
|
}
|
||||||
stack.opt_show();
|
stack.opt_show();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -532,9 +536,7 @@ bool Op::generate_code_step(Stack& stack) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (!next->noreturn() && (block0->noreturn() != block1->noreturn())) {
|
if (!next->noreturn() && (block0->noreturn() != block1->noreturn())) {
|
||||||
// simple fix of unbalanced returns in if/else branches
|
stack.o.retalt_ = true;
|
||||||
// (to be replaced with a finer condition working in loop bodies)
|
|
||||||
throw src::ParseError{where, "`if` and `else` branches should both return or both not return"};
|
|
||||||
}
|
}
|
||||||
var_idx_t x = left[0];
|
var_idx_t x = left[0];
|
||||||
stack.rearrange_top(x, var_info[x] && var_info[x]->is_last());
|
stack.rearrange_top(x, var_info[x] && var_info[x]->is_last());
|
||||||
|
@ -542,71 +544,57 @@ bool Op::generate_code_step(Stack& stack) {
|
||||||
stack.opt_show();
|
stack.opt_show();
|
||||||
stack.s.pop_back();
|
stack.s.pop_back();
|
||||||
stack.modified();
|
stack.modified();
|
||||||
if (block1->is_empty()) {
|
if (inline_func && (block0->noreturn() || block1->noreturn())) {
|
||||||
|
bool is0 = block0->noreturn();
|
||||||
|
Op* block_noreturn = is0 ? block0.get() : block1.get();
|
||||||
|
Op* block_other = is0 ? block1.get() : block0.get();
|
||||||
|
stack.mode &= ~Stack::_InlineFunc;
|
||||||
|
stack.o << (is0 ? "IF:<{" : "IFNOT:<{");
|
||||||
|
stack.o.indent();
|
||||||
|
Stack stack_copy{stack};
|
||||||
|
block_noreturn->generate_code_all(stack_copy);
|
||||||
|
stack.o.undent();
|
||||||
|
stack.o << "}>ELSE<{";
|
||||||
|
stack.o.indent();
|
||||||
|
block_other->generate_code_all(stack);
|
||||||
|
if (!block_other->noreturn()) {
|
||||||
|
next->generate_code_all(stack);
|
||||||
|
}
|
||||||
|
stack.o.undent();
|
||||||
|
stack.o << "}>";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (block1->is_empty() || block0->is_empty()) {
|
||||||
|
bool is0 = block1->is_empty();
|
||||||
|
Op* block = is0 ? block0.get() : block1.get();
|
||||||
// if (left) block0; ...
|
// if (left) block0; ...
|
||||||
if (block0->noreturn()) {
|
|
||||||
stack.o << "IFJMP:<{";
|
|
||||||
stack.o.indent();
|
|
||||||
Stack stack_copy{stack};
|
|
||||||
block0->generate_code_all(stack_copy);
|
|
||||||
stack.o.undent();
|
|
||||||
stack.o << "}>";
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
stack.o << "IF:<{";
|
|
||||||
stack.o.indent();
|
|
||||||
Stack stack_copy{stack}, stack_target{stack};
|
|
||||||
stack_target.disable_output();
|
|
||||||
stack_target.drop_vars_except(next->var_info);
|
|
||||||
block0->generate_code_all(stack_copy);
|
|
||||||
stack_copy.drop_vars_except(var_info);
|
|
||||||
stack_copy.opt_show();
|
|
||||||
if (stack_copy == stack) {
|
|
||||||
stack.o.undent();
|
|
||||||
stack.o << "}>";
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
// stack_copy.drop_vars_except(next->var_info);
|
|
||||||
stack_copy.enforce_state(stack_target.vars());
|
|
||||||
stack_copy.opt_show();
|
|
||||||
if (stack_copy.vars() == stack.vars()) {
|
|
||||||
stack.o.undent();
|
|
||||||
stack.o << "}>";
|
|
||||||
stack.merge_const(stack_copy);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
stack.o.undent();
|
|
||||||
stack.o << "}>ELSE<{";
|
|
||||||
stack.o.indent();
|
|
||||||
stack.merge_state(stack_copy);
|
|
||||||
stack.opt_show();
|
|
||||||
stack.o.undent();
|
|
||||||
stack.o << "}>";
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (block0->is_empty()) {
|
|
||||||
// if (!left) block1; ...
|
// if (!left) block1; ...
|
||||||
if (block1->noreturn()) {
|
if (block->noreturn()) {
|
||||||
stack.o << "IFNOTJMP:<{";
|
stack.o << (is0 ? "IFJMP:<{" : "IFNOTJMP:<{");
|
||||||
stack.o.indent();
|
stack.o.indent();
|
||||||
Stack stack_copy{stack};
|
Stack stack_copy{stack};
|
||||||
block1->generate_code_all(stack_copy);
|
stack_copy.mode &= ~Stack::_InlineFunc;
|
||||||
|
stack_copy.mode |= next->noreturn() ? 0 : Stack::_NeedRetAlt;
|
||||||
|
block->generate_code_all(stack_copy);
|
||||||
stack.o.undent();
|
stack.o.undent();
|
||||||
stack.o << "}>";
|
stack.o << "}>";
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
stack.o << "IFNOT:<{";
|
stack.o << (is0 ? "IF:<{" : "IFNOT:<{");
|
||||||
stack.o.indent();
|
stack.o.indent();
|
||||||
Stack stack_copy{stack}, stack_target{stack};
|
Stack stack_copy{stack}, stack_target{stack};
|
||||||
stack_target.disable_output();
|
stack_target.disable_output();
|
||||||
stack_target.drop_vars_except(next->var_info);
|
stack_target.drop_vars_except(next->var_info);
|
||||||
block1->generate_code_all(stack_copy);
|
stack_copy.mode &= ~Stack::_InlineFunc;
|
||||||
|
block->generate_code_all(stack_copy);
|
||||||
stack_copy.drop_vars_except(var_info);
|
stack_copy.drop_vars_except(var_info);
|
||||||
stack_copy.opt_show();
|
stack_copy.opt_show();
|
||||||
if (stack_copy.vars() == stack.vars()) {
|
if ((is0 && stack_copy == stack) || (!is0 && stack_copy.vars() == stack.vars())) {
|
||||||
stack.o.undent();
|
stack.o.undent();
|
||||||
stack.o << "}>";
|
stack.o << "}>";
|
||||||
stack.merge_const(stack_copy);
|
if (!is0) {
|
||||||
|
stack.merge_const(stack_copy);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// stack_copy.drop_vars_except(next->var_info);
|
// stack_copy.drop_vars_except(next->var_info);
|
||||||
|
@ -627,33 +615,32 @@ bool Op::generate_code_step(Stack& stack) {
|
||||||
stack.o << "}>";
|
stack.o << "}>";
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (block0->noreturn()) {
|
if (block0->noreturn() || block1->noreturn()) {
|
||||||
stack.o << "IFJMP:<{";
|
bool is0 = block0->noreturn();
|
||||||
|
Op* block_noreturn = is0 ? block0.get() : block1.get();
|
||||||
|
Op* block_other = is0 ? block1.get() : block0.get();
|
||||||
|
stack.o << (is0 ? "IFJMP:<{" : "IFNOTJMP:<{");
|
||||||
stack.o.indent();
|
stack.o.indent();
|
||||||
Stack stack_copy{stack};
|
Stack stack_copy{stack};
|
||||||
block0->generate_code_all(stack_copy);
|
stack_copy.mode &= ~Stack::_InlineFunc;
|
||||||
|
stack_copy.mode |= (block_other->noreturn() || next->noreturn()) ? 0 : Stack::_NeedRetAlt;
|
||||||
|
block_noreturn->generate_code_all(stack_copy);
|
||||||
stack.o.undent();
|
stack.o.undent();
|
||||||
stack.o << "}>";
|
stack.o << "}>";
|
||||||
return block1->generate_code_all(stack);
|
block_other->generate_code_all(stack);
|
||||||
}
|
return !block_other->noreturn();
|
||||||
if (block1->noreturn()) {
|
|
||||||
stack.o << "IFNOTJMP:<{";
|
|
||||||
stack.o.indent();
|
|
||||||
Stack stack_copy{stack};
|
|
||||||
block1->generate_code_all(stack_copy);
|
|
||||||
stack.o.undent();
|
|
||||||
stack.o << "}>";
|
|
||||||
return block0->generate_code_all(stack);
|
|
||||||
}
|
}
|
||||||
stack.o << "IF:<{";
|
stack.o << "IF:<{";
|
||||||
stack.o.indent();
|
stack.o.indent();
|
||||||
Stack stack_copy{stack};
|
Stack stack_copy{stack};
|
||||||
|
stack_copy.mode &= ~Stack::_InlineFunc;
|
||||||
block0->generate_code_all(stack_copy);
|
block0->generate_code_all(stack_copy);
|
||||||
stack_copy.drop_vars_except(next->var_info);
|
stack_copy.drop_vars_except(next->var_info);
|
||||||
stack_copy.opt_show();
|
stack_copy.opt_show();
|
||||||
stack.o.undent();
|
stack.o.undent();
|
||||||
stack.o << "}>ELSE<{";
|
stack.o << "}>ELSE<{";
|
||||||
stack.o.indent();
|
stack.o.indent();
|
||||||
|
stack.mode &= ~Stack::_InlineFunc;
|
||||||
block1->generate_code_all(stack);
|
block1->generate_code_all(stack);
|
||||||
stack.merge_state(stack_copy);
|
stack.merge_state(stack_copy);
|
||||||
stack.opt_show();
|
stack.opt_show();
|
||||||
|
@ -669,11 +656,16 @@ bool Op::generate_code_step(Stack& stack) {
|
||||||
stack.opt_show();
|
stack.opt_show();
|
||||||
stack.s.pop_back();
|
stack.s.pop_back();
|
||||||
stack.modified();
|
stack.modified();
|
||||||
|
if (block0->noreturn()) {
|
||||||
|
stack.o.retalt_ = true;
|
||||||
|
}
|
||||||
if (true || !next->is_empty()) {
|
if (true || !next->is_empty()) {
|
||||||
stack.o << "REPEAT:<{";
|
stack.o << "REPEAT:<{";
|
||||||
stack.o.indent();
|
stack.o.indent();
|
||||||
stack.forget_const();
|
stack.forget_const();
|
||||||
StackLayout layout1 = stack.vars();
|
StackLayout layout1 = stack.vars();
|
||||||
|
stack.mode &= ~Stack::_InlineFunc;
|
||||||
|
stack.mode |= Stack::_NeedRetAlt;
|
||||||
block0->generate_code_all(stack);
|
block0->generate_code_all(stack);
|
||||||
stack.enforce_state(std::move(layout1));
|
stack.enforce_state(std::move(layout1));
|
||||||
stack.opt_show();
|
stack.opt_show();
|
||||||
|
@ -693,11 +685,16 @@ bool Op::generate_code_step(Stack& stack) {
|
||||||
case _Again: {
|
case _Again: {
|
||||||
stack.drop_vars_except(block0->var_info);
|
stack.drop_vars_except(block0->var_info);
|
||||||
stack.opt_show();
|
stack.opt_show();
|
||||||
if (!next->is_empty()) {
|
if (block0->noreturn()) {
|
||||||
|
stack.o.retalt_ = true;
|
||||||
|
}
|
||||||
|
if (!next->is_empty() || inline_func) {
|
||||||
stack.o << "AGAIN:<{";
|
stack.o << "AGAIN:<{";
|
||||||
stack.o.indent();
|
stack.o.indent();
|
||||||
stack.forget_const();
|
stack.forget_const();
|
||||||
StackLayout layout1 = stack.vars();
|
StackLayout layout1 = stack.vars();
|
||||||
|
stack.mode &= ~Stack::_InlineFunc;
|
||||||
|
stack.mode |= Stack::_NeedRetAlt;
|
||||||
block0->generate_code_all(stack);
|
block0->generate_code_all(stack);
|
||||||
stack.enforce_state(std::move(layout1));
|
stack.enforce_state(std::move(layout1));
|
||||||
stack.opt_show();
|
stack.opt_show();
|
||||||
|
@ -717,11 +714,16 @@ bool Op::generate_code_step(Stack& stack) {
|
||||||
case _Until: {
|
case _Until: {
|
||||||
// stack.drop_vars_except(block0->var_info);
|
// stack.drop_vars_except(block0->var_info);
|
||||||
// stack.opt_show();
|
// stack.opt_show();
|
||||||
|
if (block0->noreturn()) {
|
||||||
|
stack.o.retalt_ = true;
|
||||||
|
}
|
||||||
if (true || !next->is_empty()) {
|
if (true || !next->is_empty()) {
|
||||||
stack.o << "UNTIL:<{";
|
stack.o << "UNTIL:<{";
|
||||||
stack.o.indent();
|
stack.o.indent();
|
||||||
stack.forget_const();
|
stack.forget_const();
|
||||||
auto layout1 = stack.vars();
|
auto layout1 = stack.vars();
|
||||||
|
stack.mode &= ~Stack::_InlineFunc;
|
||||||
|
stack.mode |= Stack::_NeedRetAlt;
|
||||||
block0->generate_code_all(stack);
|
block0->generate_code_all(stack);
|
||||||
layout1.push_back(left[0]);
|
layout1.push_back(left[0]);
|
||||||
stack.enforce_state(std::move(layout1));
|
stack.enforce_state(std::move(layout1));
|
||||||
|
@ -749,9 +751,14 @@ bool Op::generate_code_step(Stack& stack) {
|
||||||
stack.opt_show();
|
stack.opt_show();
|
||||||
StackLayout layout1 = stack.vars();
|
StackLayout layout1 = stack.vars();
|
||||||
bool next_empty = false && next->is_empty();
|
bool next_empty = false && next->is_empty();
|
||||||
|
if (block0->noreturn()) {
|
||||||
|
stack.o.retalt_ = true;
|
||||||
|
}
|
||||||
stack.o << "WHILE:<{";
|
stack.o << "WHILE:<{";
|
||||||
stack.o.indent();
|
stack.o.indent();
|
||||||
stack.forget_const();
|
stack.forget_const();
|
||||||
|
stack.mode &= ~Stack::_InlineFunc;
|
||||||
|
stack.mode |= Stack::_NeedRetAlt;
|
||||||
block0->generate_code_all(stack);
|
block0->generate_code_all(stack);
|
||||||
stack.rearrange_top(x, !next->var_info[x] && !block1->var_info[x]);
|
stack.rearrange_top(x, !next->var_info[x] && !block1->var_info[x]);
|
||||||
stack.opt_show();
|
stack.opt_show();
|
||||||
|
@ -781,11 +788,12 @@ bool Op::generate_code_step(Stack& stack) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Op::generate_code_all(Stack& stack) {
|
void Op::generate_code_all(Stack& stack) {
|
||||||
if (generate_code_step(stack) && next) {
|
int saved_mode = stack.mode;
|
||||||
return next->generate_code_all(stack);
|
auto cont = generate_code_step(stack);
|
||||||
} else {
|
stack.mode = (stack.mode & ~Stack::_ModeSave) | (saved_mode & Stack::_ModeSave);
|
||||||
return false;
|
if (cont && next) {
|
||||||
|
next->generate_code_all(stack);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -796,6 +804,7 @@ void CodeBlob::generate_code(AsmOpList& out, int mode) {
|
||||||
stack.push_new_var(x);
|
stack.push_new_var(x);
|
||||||
}
|
}
|
||||||
ops->generate_code_all(stack);
|
ops->generate_code_all(stack);
|
||||||
|
stack.apply_wrappers();
|
||||||
if (!(mode & Stack::_DisableOpt)) {
|
if (!(mode & Stack::_DisableOpt)) {
|
||||||
optimize_code(out);
|
optimize_code(out);
|
||||||
}
|
}
|
||||||
|
|
|
@ -99,12 +99,28 @@ void generate_output_func(SymDef* func_sym) {
|
||||||
if (verbosity >= 2) {
|
if (verbosity >= 2) {
|
||||||
std::cerr << "\n---------- resulting code for " << name << " -------------\n";
|
std::cerr << "\n---------- resulting code for " << name << " -------------\n";
|
||||||
}
|
}
|
||||||
|
bool inline_func = (func_val->flags & 1);
|
||||||
bool inline_ref = (func_val->flags & 2);
|
bool inline_ref = (func_val->flags & 2);
|
||||||
*outs << std::string(indent * 2, ' ') << name << " PROC" << (inline_ref ? "REF" : "") << ":<{\n";
|
const char* modifier = "";
|
||||||
code.generate_code(
|
if (inline_func) {
|
||||||
*outs,
|
modifier = "INLINE";
|
||||||
(stack_layout_comments ? Stack::_StkCmt | Stack::_CptStkCmt : 0) | (opt_level < 2 ? Stack::_DisableOpt : 0),
|
} else if (inline_ref) {
|
||||||
indent + 1);
|
modifier = "REF";
|
||||||
|
}
|
||||||
|
*outs << std::string(indent * 2, ' ') << name << " PROC" << modifier << ":<{\n";
|
||||||
|
int mode = 0;
|
||||||
|
if (stack_layout_comments) {
|
||||||
|
mode |= Stack::_StkCmt | Stack::_CptStkCmt;
|
||||||
|
}
|
||||||
|
if (opt_level < 2) {
|
||||||
|
mode |= Stack::_DisableOpt;
|
||||||
|
}
|
||||||
|
auto fv = dynamic_cast<const SymValCodeFunc*>(func_sym->value);
|
||||||
|
// Flags: 1 - inline, 2 - inline_ref
|
||||||
|
if (fv && (fv->flags & 1) && code.ops->noreturn()) {
|
||||||
|
mode |= Stack::_InlineFunc;
|
||||||
|
}
|
||||||
|
code.generate_code(*outs, mode, indent + 1);
|
||||||
*outs << std::string(indent * 2, ' ') << "}>\n";
|
*outs << std::string(indent * 2, ' ') << "}>\n";
|
||||||
if (verbosity >= 2) {
|
if (verbosity >= 2) {
|
||||||
std::cerr << "--------------\n";
|
std::cerr << "--------------\n";
|
||||||
|
|
|
@ -613,7 +613,7 @@ struct Op {
|
||||||
return !(flags & _Impure);
|
return !(flags & _Impure);
|
||||||
}
|
}
|
||||||
bool generate_code_step(Stack& stack);
|
bool generate_code_step(Stack& stack);
|
||||||
bool generate_code_all(Stack& stack);
|
void generate_code_all(Stack& stack);
|
||||||
Op& last() {
|
Op& last() {
|
||||||
return next ? next->last() : *this;
|
return next ? next->last() : *this;
|
||||||
}
|
}
|
||||||
|
@ -1121,6 +1121,7 @@ struct AsmOpList {
|
||||||
int indent_{0};
|
int indent_{0};
|
||||||
const std::vector<TmpVar>* var_names_{nullptr};
|
const std::vector<TmpVar>* var_names_{nullptr};
|
||||||
std::vector<Const> constants_;
|
std::vector<Const> constants_;
|
||||||
|
bool retalt_{false};
|
||||||
void out(std::ostream& os, int mode = 0) const;
|
void out(std::ostream& os, int mode = 0) const;
|
||||||
AsmOpList(int indent = 0, const std::vector<TmpVar>* var_names = nullptr) : indent_(indent), var_names_(var_names) {
|
AsmOpList(int indent = 0, const std::vector<TmpVar>* var_names = nullptr) : indent_(indent), var_names_(var_names) {
|
||||||
}
|
}
|
||||||
|
@ -1168,6 +1169,19 @@ struct AsmOpList {
|
||||||
void set_indent(int new_indent) {
|
void set_indent(int new_indent) {
|
||||||
indent_ = new_indent;
|
indent_ = new_indent;
|
||||||
}
|
}
|
||||||
|
void insert(size_t pos, std::string str) {
|
||||||
|
insert(pos, AsmOp(AsmOp::a_custom, 255, 255, str));
|
||||||
|
}
|
||||||
|
void insert(size_t pos, const AsmOp& op) {
|
||||||
|
auto ip = list_.begin() + pos;
|
||||||
|
ip = list_.insert(ip, op);
|
||||||
|
ip->indent = (ip == list_.begin()) ? indent_ : (ip - 1)->indent;
|
||||||
|
}
|
||||||
|
void indent_all() {
|
||||||
|
for (auto &op : list_) {
|
||||||
|
++op.indent;
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
inline std::ostream& operator<<(std::ostream& os, const AsmOpList& op_list) {
|
inline std::ostream& operator<<(std::ostream& os, const AsmOpList& op_list) {
|
||||||
|
@ -1498,7 +1512,12 @@ void optimize_code(AsmOpList& ops);
|
||||||
struct Stack {
|
struct Stack {
|
||||||
StackLayoutExt s;
|
StackLayoutExt s;
|
||||||
AsmOpList& o;
|
AsmOpList& o;
|
||||||
enum { _StkCmt = 1, _CptStkCmt = 2, _DisableOpt = 4, _DisableOut = 128, _Shown = 256, _Garbage = -0x10000 };
|
enum {
|
||||||
|
_StkCmt = 1, _CptStkCmt = 2, _DisableOpt = 4, _DisableOut = 128, _Shown = 256,
|
||||||
|
_InlineFunc = 512, _NeedRetAlt = 1024,
|
||||||
|
_ModeSave = _InlineFunc | _NeedRetAlt,
|
||||||
|
_Garbage = -0x10000
|
||||||
|
};
|
||||||
int mode;
|
int mode;
|
||||||
Stack(AsmOpList& _o, int _mode = 0) : o(_o), mode(_mode) {
|
Stack(AsmOpList& _o, int _mode = 0) : o(_o), mode(_mode) {
|
||||||
}
|
}
|
||||||
|
@ -1571,6 +1590,17 @@ struct Stack {
|
||||||
bool operator==(const Stack& y) const & {
|
bool operator==(const Stack& y) const & {
|
||||||
return s == y.s;
|
return s == y.s;
|
||||||
}
|
}
|
||||||
|
void apply_wrappers() {
|
||||||
|
if (o.retalt_) {
|
||||||
|
o.insert(0, "SAMEALTSAVE");
|
||||||
|
if (mode & _InlineFunc) {
|
||||||
|
o.indent_all();
|
||||||
|
o.insert(0, "CONT:<{");
|
||||||
|
o << "}>";
|
||||||
|
o << "EXECUTE";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue