From: Jürg Billeter Date: Sat, 29 Nov 2008 17:25:51 +0000 (+0000) Subject: Convert binary conditional expressions into if statements X-Git-Tag: VALA_0_5_2~26 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9c112c985e1edafa2602416962702f185a5583a0;p=thirdparty%2Fvala.git Convert binary conditional expressions into if statements 2008-11-29 Jürg Billeter * vala/valaaddressofexpression.vala: * vala/valaarraycreationexpression.vala: * vala/valaassignment.vala: * vala/valabaseaccess.vala: * vala/valabinaryexpression.vala: * vala/valacastexpression.vala: * vala/valaconditionalexpression.vala: * vala/valadostatement.vala: * vala/valaelementaccess.vala: * vala/valaexpression.vala: * vala/valaforstatement.vala: * vala/valainitializerlist.vala: * vala/valalambdaexpression.vala: * vala/valaliteral.vala: * vala/valamemberaccess.vala: * vala/valamethodcall.vala: * vala/valaobjectcreationexpression.vala: * vala/valaparenthesizedexpression.vala: * vala/valapointerindirection.vala: * vala/valapostfixexpression.vala: * vala/valareferencetransferexpression.vala: * vala/valasizeofexpression.vala: * vala/valatuple.vala: * vala/valatypecheck.vala: * vala/valatypeofexpression.vala: * vala/valaunaryexpression.vala: * vala/valawhilestatement.vala: Convert binary conditional expressions into if statements svn path=/trunk/; revision=2085 --- diff --git a/ChangeLog b/ChangeLog index e820029b7..291be4b64 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,35 @@ +2008-11-29 Jürg Billeter + + * vala/valaaddressofexpression.vala: + * vala/valaarraycreationexpression.vala: + * vala/valaassignment.vala: + * vala/valabaseaccess.vala: + * vala/valabinaryexpression.vala: + * vala/valacastexpression.vala: + * vala/valaconditionalexpression.vala: + * vala/valadostatement.vala: + * vala/valaelementaccess.vala: + * vala/valaexpression.vala: + * vala/valaforstatement.vala: + * vala/valainitializerlist.vala: + * vala/valalambdaexpression.vala: + * vala/valaliteral.vala: + * vala/valamemberaccess.vala: + * vala/valamethodcall.vala: + * vala/valaobjectcreationexpression.vala: + * vala/valaparenthesizedexpression.vala: + * vala/valapointerindirection.vala: + * vala/valapostfixexpression.vala: + * vala/valareferencetransferexpression.vala: + * vala/valasizeofexpression.vala: + * vala/valatuple.vala: + * vala/valatypecheck.vala: + * vala/valatypeofexpression.vala: + * vala/valaunaryexpression.vala: + * vala/valawhilestatement.vala: + + Convert binary conditional expressions into if statements + 2008-11-29 Jürg Billeter * vala/valaflowanalyzer.vala: diff --git a/vala/valaaddressofexpression.vala b/vala/valaaddressofexpression.vala index 4874a2b0a..be21b9572 100644 --- a/vala/valaaddressofexpression.vala +++ b/vala/valaaddressofexpression.vala @@ -97,4 +97,8 @@ public class Vala.AddressofExpression : Expression { return !error; } + + public override bool in_single_basic_block () { + return inner.in_single_basic_block (); + } } diff --git a/vala/valaarraycreationexpression.vala b/vala/valaarraycreationexpression.vala index 9ef841c54..8e2f891d7 100644 --- a/vala/valaarraycreationexpression.vala +++ b/vala/valaarraycreationexpression.vala @@ -220,4 +220,13 @@ public class Vala.ArrayCreationExpression : Expression { return !error; } + + public override bool in_single_basic_block () { + foreach (Expression size in sizes) { + if (!size.in_single_basic_block ()) { + return false; + } + } + return true; + } } diff --git a/vala/valaassignment.vala b/vala/valaassignment.vala index d3ad077f7..026040b30 100644 --- a/vala/valaassignment.vala +++ b/vala/valaassignment.vala @@ -400,6 +400,10 @@ public class Vala.Assignment : Expression { } right.get_used_variables (collection); } + + public override bool in_single_basic_block () { + return left.in_single_basic_block () && right.in_single_basic_block (); + } } public enum Vala.AssignmentOperator { diff --git a/vala/valabaseaccess.vala b/vala/valabaseaccess.vala index 1de0c7a78..7db98c878 100644 --- a/vala/valabaseaccess.vala +++ b/vala/valabaseaccess.vala @@ -88,4 +88,8 @@ public class Vala.BaseAccess : Expression { return !error; } + + public override bool in_single_basic_block () { + return true; + } } diff --git a/vala/valabinaryexpression.vala b/vala/valabinaryexpression.vala index 1ba915d54..024ec9dcb 100644 --- a/vala/valabinaryexpression.vala +++ b/vala/valabinaryexpression.vala @@ -145,6 +145,47 @@ public class Vala.BinaryExpression : Expression { checked = true; + if (operator == BinaryOperator.AND || operator == BinaryOperator.OR) { + // convert conditional expression into if statement + // required for flow analysis and exception handling + + var local = new LocalVariable (new ValueType (analyzer.bool_type.data_type), get_temp_name (), null, source_reference); + var decl = new DeclarationStatement (local, source_reference); + decl.check (analyzer); + + var right_stmt = new ExpressionStatement (new Assignment (new MemberAccess.simple (local.name, right.source_reference), right, AssignmentOperator.SIMPLE, right.source_reference), right.source_reference); + + var stmt = new ExpressionStatement (new Assignment (new MemberAccess.simple (local.name, left.source_reference), new BooleanLiteral ((operator == BinaryOperator.OR), left.source_reference), AssignmentOperator.SIMPLE, left.source_reference), left.source_reference); + + var true_block = new Block (source_reference); + var false_block = new Block (source_reference); + + if (operator == BinaryOperator.AND) { + true_block.add_statement (right_stmt); + false_block.add_statement (stmt); + } else { + true_block.add_statement (stmt); + false_block.add_statement (right_stmt); + } + + var if_stmt = new IfStatement (left, true_block, false_block, source_reference); + + insert_statement ((Block) analyzer.current_symbol, decl); + insert_statement ((Block) analyzer.current_symbol, if_stmt); + + if (!if_stmt.check (analyzer)) { + return false; + } + + var ma = new MemberAccess.simple (local.name, source_reference); + ma.target_type = target_type; + ma.check (analyzer); + + parent_node.replace_expression (this, ma); + + return true; + } + if (!left.check (analyzer) || !right.check (analyzer)) { /* if there were any errors in inner expressions, skip type check */ error = true; @@ -260,14 +301,6 @@ public class Vala.BinaryExpression : Expression { // integer type or flags type value_type = left.value_type; - } else if (operator == BinaryOperator.AND - || operator == BinaryOperator.OR) { - if (!left.value_type.compatible (analyzer.bool_type) || !right.value_type.compatible (analyzer.bool_type)) { - error = true; - Report.error (source_reference, "Operands must be boolean"); - } - - value_type = analyzer.bool_type; } else if (operator == BinaryOperator.IN) { if (left.value_type.compatible (analyzer.int_type) && right.value_type.compatible (analyzer.int_type)) { @@ -315,6 +348,14 @@ public class Vala.BinaryExpression : Expression { left.get_used_variables (collection); right.get_used_variables (collection); } + + public override bool in_single_basic_block () { + if (operator == BinaryOperator.AND + || operator == BinaryOperator.OR) { + return false; + } + return left.in_single_basic_block () && right.in_single_basic_block (); + } } public enum Vala.BinaryOperator { diff --git a/vala/valacastexpression.vala b/vala/valacastexpression.vala index 4f94832ce..598b5a28d 100644 --- a/vala/valacastexpression.vala +++ b/vala/valacastexpression.vala @@ -131,4 +131,8 @@ public class Vala.CastExpression : Expression { public override void get_used_variables (Collection collection) { inner.get_used_variables (collection); } + + public override bool in_single_basic_block () { + return inner.in_single_basic_block (); + } } diff --git a/vala/valaconditionalexpression.vala b/vala/valaconditionalexpression.vala index f53cd1a15..ff798a6a0 100644 --- a/vala/valaconditionalexpression.vala +++ b/vala/valaconditionalexpression.vala @@ -113,6 +113,9 @@ public class Vala.ConditionalExpression : Expression { true_expression.target_type = target_type; false_expression.target_type = target_type; + var local = new LocalVariable (null, temp_name, null, source_reference); + var decl = new DeclarationStatement (local, source_reference); + var true_local = new LocalVariable (null, temp_name, true_expression, true_expression.source_reference); var true_block = new Block (true_expression.source_reference); var true_decl = new DeclarationStatement (true_local, true_expression.source_reference); @@ -124,6 +127,10 @@ public class Vala.ConditionalExpression : Expression { false_block.add_statement (false_decl); var if_stmt = new IfStatement (condition, true_block, false_block, source_reference); + + insert_statement ((Block) analyzer.current_symbol, decl); + insert_statement ((Block) analyzer.current_symbol, if_stmt); + if (!if_stmt.check (analyzer)) { return false; } @@ -146,8 +153,7 @@ public class Vala.ConditionalExpression : Expression { value_type.value_owned = (true_expression.value_type.value_owned || false_expression.value_type.value_owned); - var local = new LocalVariable (value_type, temp_name, null, source_reference); - var decl = new DeclarationStatement (local, source_reference); + local.variable_type = value_type; decl.check (analyzer); true_expression.target_type = value_type; @@ -162,9 +168,6 @@ public class Vala.ConditionalExpression : Expression { true_block.replace_statement (true_decl, true_stmt); false_block.replace_statement (false_decl, false_stmt); - insert_statement ((Block) analyzer.current_symbol, decl); - insert_statement ((Block) analyzer.current_symbol, if_stmt); - var ma = new MemberAccess.simple (local.name, source_reference); ma.target_type = target_type; ma.check (analyzer); @@ -173,4 +176,8 @@ public class Vala.ConditionalExpression : Expression { return true; } + + public override bool in_single_basic_block () { + return false; + } } diff --git a/vala/valadostatement.vala b/vala/valadostatement.vala index 8700c883c..443aca541 100644 --- a/vala/valadostatement.vala +++ b/vala/valadostatement.vala @@ -94,6 +94,43 @@ public class Vala.DoStatement : CodeNode, Statement { checked = true; + if (!condition.in_single_basic_block ()) { + /* move condition into the loop body to allow split + * in multiple statements + * + * first = false; + * do { + * if (first) { + * if (!condition) { + * break; + * } + * } + * first = true; + * ... + * } while (true); + */ + + var first_local = new LocalVariable (new ValueType (analyzer.bool_type.data_type), get_temp_name (), new BooleanLiteral (false, source_reference), source_reference); + var first_decl = new DeclarationStatement (first_local, source_reference); + first_decl.check (analyzer); + var block = (Block) analyzer.current_symbol; + block.insert_before (this, first_decl); + + var if_condition = new UnaryExpression (UnaryOperator.LOGICAL_NEGATION, condition, condition.source_reference); + var true_block = new Block (condition.source_reference); + true_block.add_statement (new BreakStatement (condition.source_reference)); + var if_stmt = new IfStatement (if_condition, true_block, null, condition.source_reference); + + var condition_block = new Block (condition.source_reference); + condition_block.add_statement (if_stmt); + + var first_if = new IfStatement (new MemberAccess.simple (first_local.name, source_reference), condition_block, null, source_reference); + body.insert_statement (0, first_if); + body.insert_statement (1, new ExpressionStatement (new Assignment (new MemberAccess.simple (first_local.name, source_reference), new BooleanLiteral (true, source_reference), AssignmentOperator.SIMPLE, source_reference), source_reference)); + + condition = new BooleanLiteral (true, source_reference); + } + body.check (analyzer); if (!condition.check (analyzer)) { diff --git a/vala/valaelementaccess.vala b/vala/valaelementaccess.vala index 847518763..e6b4dc8b2 100644 --- a/vala/valaelementaccess.vala +++ b/vala/valaelementaccess.vala @@ -222,4 +222,13 @@ public class Vala.ElementAccess : Expression { index.get_used_variables (collection); } } + + public override bool in_single_basic_block () { + foreach (Expression index in indices) { + if (!index.in_single_basic_block ()) { + return false; + } + } + return container.in_single_basic_block (); + } } diff --git a/vala/valaexpression.vala b/vala/valaexpression.vala index 11d43950a..47fb7cdac 100644 --- a/vala/valaexpression.vala +++ b/vala/valaexpression.vala @@ -105,4 +105,10 @@ public abstract class Vala.Expression : CodeNode { public void insert_statement (Block block, Statement stmt) { block.insert_before (parent_statement, stmt); } + + /** + * Returns whether this expression is guaranteed to be part of a + * single basic block in the control flow graph. + */ + public abstract bool in_single_basic_block (); } diff --git a/vala/valaforstatement.vala b/vala/valaforstatement.vala index cf02aa726..ebd8de526 100644 --- a/vala/valaforstatement.vala +++ b/vala/valaforstatement.vala @@ -164,6 +164,20 @@ public class Vala.ForStatement : CodeNode, Statement { checked = true; + + if (condition != null && !condition.in_single_basic_block ()) { + // move condition into the loop body to allow split + // in multiple statements + + var if_condition = new UnaryExpression (UnaryOperator.LOGICAL_NEGATION, condition, condition.source_reference); + var true_block = new Block (condition.source_reference); + true_block.add_statement (new BreakStatement (condition.source_reference)); + var if_stmt = new IfStatement (if_condition, true_block, null, condition.source_reference); + body.insert_statement (0, if_stmt); + + condition = new BooleanLiteral (true, source_reference); + } + foreach (Expression init_expr in initializer) { init_expr.check (analyzer); } diff --git a/vala/valainitializerlist.vala b/vala/valainitializerlist.vala index 4b10f1607..5284d08bc 100644 --- a/vala/valainitializerlist.vala +++ b/vala/valainitializerlist.vala @@ -170,4 +170,13 @@ public class Vala.InitializerList : Expression { return !error; } + + public override bool in_single_basic_block () { + foreach (Expression initializer in initializers) { + if (!initializer.in_single_basic_block ()) { + return false; + } + } + return true; + } } diff --git a/vala/valalambdaexpression.vala b/vala/valalambdaexpression.vala index 52415a915..20a7fbef9 100644 --- a/vala/valalambdaexpression.vala +++ b/vala/valalambdaexpression.vala @@ -203,4 +203,8 @@ public class Vala.LambdaExpression : Expression { return !error; } + + public override bool in_single_basic_block () { + return true; + } } diff --git a/vala/valaliteral.vala b/vala/valaliteral.vala index 62f17a3af..932f0f58c 100644 --- a/vala/valaliteral.vala +++ b/vala/valaliteral.vala @@ -33,4 +33,8 @@ public abstract class Vala.Literal : Expression { public override bool is_pure () { return true; } + + public override bool in_single_basic_block () { + return true; + } } diff --git a/vala/valamemberaccess.vala b/vala/valamemberaccess.vala index 031d66f6f..2c59a6eb7 100644 --- a/vala/valamemberaccess.vala +++ b/vala/valamemberaccess.vala @@ -551,4 +551,8 @@ public class Vala.MemberAccess : Expression { collection.add (local); } } + + public override bool in_single_basic_block () { + return inner == null || inner.in_single_basic_block (); + } } diff --git a/vala/valamethodcall.vala b/vala/valamethodcall.vala index 984318923..477198c92 100644 --- a/vala/valamethodcall.vala +++ b/vala/valamethodcall.vala @@ -422,4 +422,13 @@ public class Vala.MethodCall : Expression { arg.get_used_variables (collection); } } + + public override bool in_single_basic_block () { + foreach (Expression arg in argument_list) { + if (!arg.in_single_basic_block ()) { + return false; + } + } + return call.in_single_basic_block (); + } } diff --git a/vala/valaobjectcreationexpression.vala b/vala/valaobjectcreationexpression.vala index 9fc43fd10..5d64b05f8 100644 --- a/vala/valaobjectcreationexpression.vala +++ b/vala/valaobjectcreationexpression.vala @@ -372,4 +372,13 @@ public class Vala.ObjectCreationExpression : Expression { arg.get_used_variables (collection); } } + + public override bool in_single_basic_block () { + foreach (Expression arg in argument_list) { + if (!arg.in_single_basic_block ()) { + return false; + } + } + return true; + } } diff --git a/vala/valaparenthesizedexpression.vala b/vala/valaparenthesizedexpression.vala index 2a29d9332..e1c97d487 100644 --- a/vala/valaparenthesizedexpression.vala +++ b/vala/valaparenthesizedexpression.vala @@ -112,4 +112,8 @@ public class Vala.ParenthesizedExpression : Expression { public override void get_used_variables (Collection collection) { inner.get_used_variables (collection); } + + public override bool in_single_basic_block () { + return inner.in_single_basic_block (); + } } diff --git a/vala/valapointerindirection.vala b/vala/valapointerindirection.vala index 84f1b6e6f..f926c7a53 100644 --- a/vala/valapointerindirection.vala +++ b/vala/valapointerindirection.vala @@ -109,4 +109,8 @@ public class Vala.PointerIndirection : Expression { public override void get_used_variables (Collection collection) { inner.get_used_variables (collection); } + + public override bool in_single_basic_block () { + return inner.in_single_basic_block (); + } } diff --git a/vala/valapostfixexpression.vala b/vala/valapostfixexpression.vala index 3ff4d6d69..e34365472 100644 --- a/vala/valapostfixexpression.vala +++ b/vala/valapostfixexpression.vala @@ -75,4 +75,8 @@ public class Vala.PostfixExpression : Expression { return !error; } + + public override bool in_single_basic_block () { + return true; + } } diff --git a/vala/valareferencetransferexpression.vala b/vala/valareferencetransferexpression.vala index dcf2e5369..fc83f1a0d 100644 --- a/vala/valareferencetransferexpression.vala +++ b/vala/valareferencetransferexpression.vala @@ -115,4 +115,8 @@ public class Vala.ReferenceTransferExpression : Expression { public override void get_used_variables (Collection collection) { inner.get_used_variables (collection); } + + public override bool in_single_basic_block () { + return inner.in_single_basic_block (); + } } diff --git a/vala/valasizeofexpression.vala b/vala/valasizeofexpression.vala index 673b16e9c..0000d2ced 100644 --- a/vala/valasizeofexpression.vala +++ b/vala/valasizeofexpression.vala @@ -82,4 +82,8 @@ public class Vala.SizeofExpression : Expression { return !error; } + + public override bool in_single_basic_block () { + return true; + } } diff --git a/vala/valatuple.vala b/vala/valatuple.vala index fc05984e8..16354f607 100644 --- a/vala/valatuple.vala +++ b/vala/valatuple.vala @@ -43,5 +43,14 @@ public class Vala.Tuple : Expression { public override bool is_pure () { return false; } + + public override bool in_single_basic_block () { + foreach (Expression expr in expression_list) { + if (!expr.in_single_basic_block ()) { + return false; + } + } + return true; + } } diff --git a/vala/valatypecheck.vala b/vala/valatypecheck.vala index 2dee142f1..dea9708b4 100644 --- a/vala/valatypecheck.vala +++ b/vala/valatypecheck.vala @@ -101,4 +101,8 @@ public class Vala.TypeCheck : Expression { return !error; } + + public override bool in_single_basic_block () { + return expression.in_single_basic_block (); + } } diff --git a/vala/valatypeofexpression.vala b/vala/valatypeofexpression.vala index 9331a8f39..e18be52ae 100644 --- a/vala/valatypeofexpression.vala +++ b/vala/valatypeofexpression.vala @@ -84,4 +84,8 @@ public class Vala.TypeofExpression : Expression { return !error; } + + public override bool in_single_basic_block () { + return true; + } } diff --git a/vala/valaunaryexpression.vala b/vala/valaunaryexpression.vala index 9f478d8e9..16260859e 100644 --- a/vala/valaunaryexpression.vala +++ b/vala/valaunaryexpression.vala @@ -241,6 +241,10 @@ public class Vala.UnaryExpression : Expression { inner.get_used_variables (collection); } } + + public override bool in_single_basic_block () { + return inner.in_single_basic_block (); + } } public enum Vala.UnaryOperator { diff --git a/vala/valawhilestatement.vala b/vala/valawhilestatement.vala index 028538c0d..3a595256a 100644 --- a/vala/valawhilestatement.vala +++ b/vala/valawhilestatement.vala @@ -94,6 +94,19 @@ public class Vala.WhileStatement : CodeNode, Statement { checked = true; + if (!condition.in_single_basic_block ()) { + // move condition into the loop body to allow split + // in multiple statements + + var if_condition = new UnaryExpression (UnaryOperator.LOGICAL_NEGATION, condition, condition.source_reference); + var true_block = new Block (condition.source_reference); + true_block.add_statement (new BreakStatement (condition.source_reference)); + var if_stmt = new IfStatement (if_condition, true_block, null, condition.source_reference); + body.insert_statement (0, if_stmt); + + condition = new BooleanLiteral (true, source_reference); + } + condition.check (analyzer); body.check (analyzer);