transformer: eliminate unreachable branches in IfExpr and fold more expressions and statements (#12135)
* v: fix using constant as length in fixed array * format test file * v/trasnformer: discard unreachable if branches * transform more expressions and statements * replace IfExpr with EmptyExpr when all branches were eliminated * fix typo * fix gens * only allows branch elimination on if expression statement * fix native gen * fix handling of multi branch ifs in the native backend, also allow for `if true {}` Co-authored-by: KyleLin921021 <43753315+KyleLin921021@users.noreply.github.com> Co-authored-by: Delyan Angelov <delian66@gmail.com>pull/12153/head
parent
35b301f73c
commit
d0c961ebc0
|
@ -5066,7 +5066,9 @@ fn (mut g Gen) if_expr(node ast.IfExpr) {
|
||||||
g.stmt_path_pos << stmt_pos
|
g.stmt_path_pos << stmt_pos
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
g.writeln('}')
|
if node.branches.len > 0 {
|
||||||
|
g.writeln('}')
|
||||||
|
}
|
||||||
g.set_current_pos_as_last_stmt_pos()
|
g.set_current_pos_as_last_stmt_pos()
|
||||||
if needs_tmp_var {
|
if needs_tmp_var {
|
||||||
if g.infix_left_var_name.len > 0 {
|
if g.infix_left_var_name.len > 0 {
|
||||||
|
|
|
@ -2387,7 +2387,9 @@ fn (mut g JsGen) gen_if_expr(node ast.IfExpr) {
|
||||||
g.stmts(branch.stmts)
|
g.stmts(branch.stmts)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
g.writeln('}')
|
if node.branches.len > 0 {
|
||||||
|
g.writeln('}')
|
||||||
|
}
|
||||||
if needs_tmp_var {
|
if needs_tmp_var {
|
||||||
g.write('$tmp')
|
g.write('$tmp')
|
||||||
}
|
}
|
||||||
|
|
|
@ -1268,22 +1268,32 @@ fn (mut g Gen) condition(infix_expr ast.InfixExpr, neg bool) int {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g Gen) if_expr(node ast.IfExpr) {
|
fn (mut g Gen) if_expr(node ast.IfExpr) {
|
||||||
branch := node.branches[0]
|
|
||||||
infix_expr := branch.cond as ast.InfixExpr
|
|
||||||
cjmp_addr := g.condition(infix_expr, false)
|
|
||||||
if node.is_comptime {
|
if node.is_comptime {
|
||||||
g.n_error('ignored comptime')
|
g.n_error('ignored comptime')
|
||||||
}
|
}
|
||||||
g.stmts(branch.stmts)
|
|
||||||
// Now that we know where we need to jump if the condition is false, update the `jne` call.
|
|
||||||
// The value is the relative address, difference between current position and the location
|
|
||||||
// after `jne 00 00 00 00`
|
|
||||||
// println('after if g.pos=$g.pos() jneaddr=$cjmp_addr')
|
|
||||||
g.write32_at(cjmp_addr, int(g.pos() - cjmp_addr - 4)) // 4 is for "00 00 00 00"
|
|
||||||
|
|
||||||
if node.has_else {
|
if node.has_else {
|
||||||
g.n_error('else statements not yet supported')
|
g.n_error('else statements not yet supported')
|
||||||
}
|
}
|
||||||
|
if node.branches.len == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for idx in 0 .. node.branches.len {
|
||||||
|
branch := node.branches[idx]
|
||||||
|
if branch.cond is ast.BoolLiteral {
|
||||||
|
if branch.cond.val {
|
||||||
|
g.stmts(branch.stmts)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
infix_expr := branch.cond as ast.InfixExpr
|
||||||
|
cjmp_addr := g.condition(infix_expr, false)
|
||||||
|
g.stmts(branch.stmts)
|
||||||
|
// Now that we know where we need to jump if the condition is false, update the `jne` call.
|
||||||
|
// The value is the relative address, difference between current position and the location
|
||||||
|
// after `jne 00 00 00 00`
|
||||||
|
// println('after if g.pos=$g.pos() jneaddr=$cjmp_addr')
|
||||||
|
g.write32_at(cjmp_addr, int(g.pos() - cjmp_addr - 4)) // 4 is for "00 00 00 00"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g Gen) infloop() {
|
fn (mut g Gen) infloop() {
|
||||||
|
|
|
@ -56,10 +56,19 @@ pub fn (t Transformer) stmt(mut node ast.Stmt) {
|
||||||
ast.DeferStmt {}
|
ast.DeferStmt {}
|
||||||
ast.EnumDecl {}
|
ast.EnumDecl {}
|
||||||
ast.ExprStmt {
|
ast.ExprStmt {
|
||||||
expr := t.expr(node.expr)
|
if node.expr is ast.IfExpr {
|
||||||
node = &ast.ExprStmt{
|
mut untrans_expr := node.expr as ast.IfExpr
|
||||||
...node
|
expr := t.if_expr(mut untrans_expr)
|
||||||
expr: expr
|
node = &ast.ExprStmt{
|
||||||
|
...node
|
||||||
|
expr: expr
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
expr := t.expr(node.expr)
|
||||||
|
node = &ast.ExprStmt{
|
||||||
|
...node
|
||||||
|
expr: expr
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ast.FnDecl {
|
ast.FnDecl {
|
||||||
|
@ -69,7 +78,15 @@ pub fn (t Transformer) stmt(mut node ast.Stmt) {
|
||||||
}
|
}
|
||||||
ast.ForCStmt {}
|
ast.ForCStmt {}
|
||||||
ast.ForInStmt {}
|
ast.ForInStmt {}
|
||||||
ast.ForStmt {}
|
ast.ForStmt {
|
||||||
|
node = &ast.ForStmt{
|
||||||
|
...node
|
||||||
|
cond: t.expr(node.cond)
|
||||||
|
}
|
||||||
|
if node.cond is ast.BoolLiteral && !(node.cond as ast.BoolLiteral).val { // for false { ... } should be eleminated
|
||||||
|
node = &ast.EmptyStmt{}
|
||||||
|
}
|
||||||
|
}
|
||||||
ast.GlobalDecl {}
|
ast.GlobalDecl {}
|
||||||
ast.GotoLabel {}
|
ast.GotoLabel {}
|
||||||
ast.GotoStmt {}
|
ast.GotoStmt {}
|
||||||
|
@ -89,12 +106,71 @@ pub fn (t Transformer) stmt(mut node ast.Stmt) {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (t Transformer) expr(node ast.Expr) ast.Expr {
|
pub fn (t Transformer) expr(node ast.Expr) ast.Expr {
|
||||||
match node {
|
match mut node {
|
||||||
ast.InfixExpr { return t.infix_expr(node) }
|
ast.InfixExpr {
|
||||||
else { return node }
|
return t.infix_expr(node)
|
||||||
|
}
|
||||||
|
ast.IndexExpr {
|
||||||
|
return ast.IndexExpr{
|
||||||
|
...node
|
||||||
|
index: t.expr(node.index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ast.MatchExpr {
|
||||||
|
for mut branch in node.branches {
|
||||||
|
for mut stmt in branch.stmts {
|
||||||
|
t.stmt(mut stmt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return node
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn (t Transformer) if_expr(mut original ast.IfExpr) ast.Expr {
|
||||||
|
mut stop_index, mut unreachable_branches := -1, []int{cap: original.branches.len}
|
||||||
|
for i, mut branch in original.branches {
|
||||||
|
for mut stmt in branch.stmts {
|
||||||
|
t.stmt(mut stmt)
|
||||||
|
}
|
||||||
|
cond := t.expr(branch.cond)
|
||||||
|
branch = ast.IfBranch{
|
||||||
|
...(*branch)
|
||||||
|
cond: cond
|
||||||
|
}
|
||||||
|
if cond is ast.BoolLiteral {
|
||||||
|
if cond.val { // eliminates remaining branches when reached first bool literal `true`
|
||||||
|
stop_index = i
|
||||||
|
break
|
||||||
|
} else { // discard unreachable branch when reached bool literal `false`
|
||||||
|
unreachable_branches << i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if stop_index != -1 {
|
||||||
|
unreachable_branches = unreachable_branches.filter(it < stop_index)
|
||||||
|
original.branches = original.branches[..stop_index + 1]
|
||||||
|
}
|
||||||
|
for unreachable_branches.len != 0 {
|
||||||
|
original.branches.delete(unreachable_branches.pop())
|
||||||
|
}
|
||||||
|
if original.branches.len == 0 { // no remain branches to walk through
|
||||||
|
return ast.EmptyExpr{}
|
||||||
|
}
|
||||||
|
if original.branches.len == 1 && original.branches[0].cond.type_name() == 'unknown v.ast.Expr' {
|
||||||
|
original.branches[0] = &ast.IfBranch{
|
||||||
|
...original.branches[0]
|
||||||
|
cond: ast.BoolLiteral{
|
||||||
|
val: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return *original
|
||||||
|
}
|
||||||
|
|
||||||
pub fn (t Transformer) infix_expr(original ast.InfixExpr) ast.Expr {
|
pub fn (t Transformer) infix_expr(original ast.InfixExpr) ast.Expr {
|
||||||
mut node := original
|
mut node := original
|
||||||
node.left = t.expr(node.left)
|
node.left = t.expr(node.left)
|
||||||
|
@ -109,6 +185,16 @@ pub fn (t Transformer) infix_expr(original ast.InfixExpr) ast.Expr {
|
||||||
match right_node {
|
match right_node {
|
||||||
ast.BoolLiteral {
|
ast.BoolLiteral {
|
||||||
match node.op {
|
match node.op {
|
||||||
|
.eq {
|
||||||
|
return ast.BoolLiteral{
|
||||||
|
val: left_node.val == right_node.val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.ne {
|
||||||
|
return ast.BoolLiteral{
|
||||||
|
val: left_node.val != right_node.val
|
||||||
|
}
|
||||||
|
}
|
||||||
.and {
|
.and {
|
||||||
return ast.BoolLiteral{
|
return ast.BoolLiteral{
|
||||||
val: left_node.val && right_node.val
|
val: left_node.val && right_node.val
|
||||||
|
@ -133,6 +219,16 @@ pub fn (t Transformer) infix_expr(original ast.InfixExpr) ast.Expr {
|
||||||
match right_node {
|
match right_node {
|
||||||
ast.StringLiteral {
|
ast.StringLiteral {
|
||||||
match node.op {
|
match node.op {
|
||||||
|
.eq {
|
||||||
|
return ast.BoolLiteral{
|
||||||
|
val: left_node.val == right_node.val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.ne {
|
||||||
|
return ast.BoolLiteral{
|
||||||
|
val: left_node.val != right_node.val
|
||||||
|
}
|
||||||
|
}
|
||||||
.plus {
|
.plus {
|
||||||
return ast.StringLiteral{
|
return ast.StringLiteral{
|
||||||
val: left_node.val + right_node.val
|
val: left_node.val + right_node.val
|
||||||
|
@ -155,6 +251,36 @@ pub fn (t Transformer) infix_expr(original ast.InfixExpr) ast.Expr {
|
||||||
left_val := left_node.val.int()
|
left_val := left_node.val.int()
|
||||||
right_val := right_node.val.int()
|
right_val := right_node.val.int()
|
||||||
match node.op {
|
match node.op {
|
||||||
|
.eq {
|
||||||
|
return ast.BoolLiteral{
|
||||||
|
val: left_node.val == right_node.val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.ne {
|
||||||
|
return ast.BoolLiteral{
|
||||||
|
val: left_node.val != right_node.val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.gt {
|
||||||
|
return ast.BoolLiteral{
|
||||||
|
val: left_node.val > right_node.val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.ge {
|
||||||
|
return ast.BoolLiteral{
|
||||||
|
val: left_node.val >= right_node.val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.lt {
|
||||||
|
return ast.BoolLiteral{
|
||||||
|
val: left_node.val < right_node.val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.le {
|
||||||
|
return ast.BoolLiteral{
|
||||||
|
val: left_node.val <= right_node.val
|
||||||
|
}
|
||||||
|
}
|
||||||
.plus {
|
.plus {
|
||||||
return ast.IntegerLiteral{
|
return ast.IntegerLiteral{
|
||||||
val: (left_val + right_val).str()
|
val: (left_val + right_val).str()
|
||||||
|
@ -203,6 +329,24 @@ pub fn (t Transformer) infix_expr(original ast.InfixExpr) ast.Expr {
|
||||||
pos: pos
|
pos: pos
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.left_shift {
|
||||||
|
return ast.IntegerLiteral{
|
||||||
|
val: (left_val << right_val).str()
|
||||||
|
pos: pos
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.right_shift {
|
||||||
|
return ast.IntegerLiteral{
|
||||||
|
val: (left_val >> right_val).str()
|
||||||
|
pos: pos
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.unsigned_right_shift {
|
||||||
|
return ast.IntegerLiteral{
|
||||||
|
val: (left_val >>> right_val).str()
|
||||||
|
pos: pos
|
||||||
|
}
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
return node
|
return node
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue