You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@systemml.apache.org by mb...@apache.org on 2018/08/14 08:12:10 UTC
systemml git commit: [SYSTEMML-2488] Fix function inlining of
multi-return builtin functions
Repository: systemml
Updated Branches:
refs/heads/master 1e851ef62 -> db0207900
[SYSTEMML-2488] Fix function inlining of multi-return builtin functions
The inlining during parser validate of functions that call multi-return
builtin functions is invalid in special cases as the append of output
mapping statements can violate internal assumptions. This patch
introduces new mechanics for doing in-place function output mapping.
Since the compiler still struggles to handle these multi-return builtin
operations, this also includes a correctness fix for deciding on
function inlining.
Project: http://git-wip-us.apache.org/repos/asf/systemml/repo
Commit: http://git-wip-us.apache.org/repos/asf/systemml/commit/db020790
Tree: http://git-wip-us.apache.org/repos/asf/systemml/tree/db020790
Diff: http://git-wip-us.apache.org/repos/asf/systemml/diff/db020790
Branch: refs/heads/master
Commit: db02079000e1cba56c938374b1fa1641d40b551d
Parents: 1e851ef
Author: Matthias Boehm <mb...@gmail.com>
Authored: Tue Aug 14 01:10:09 2018 -0700
Committer: Matthias Boehm <mb...@gmail.com>
Committed: Tue Aug 14 01:14:01 2018 -0700
----------------------------------------------------------------------
.../sysml/parser/AssignmentStatement.java | 4 +
.../sysml/parser/MultiAssignmentStatement.java | 6 +
.../org/apache/sysml/parser/StatementBlock.java | 295 +++++++++++--------
.../functions/misc/FunctionPotpourriTest.java | 21 +-
.../misc/FunPotpourriMultiReturnBuiltin1.dml | 28 ++
.../misc/FunPotpourriMultiReturnBuiltin2.dml | 34 +++
6 files changed, 260 insertions(+), 128 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/systemml/blob/db020790/src/main/java/org/apache/sysml/parser/AssignmentStatement.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/sysml/parser/AssignmentStatement.java b/src/main/java/org/apache/sysml/parser/AssignmentStatement.java
index 72b2ce8..1a4963c 100644
--- a/src/main/java/org/apache/sysml/parser/AssignmentStatement.java
+++ b/src/main/java/org/apache/sysml/parser/AssignmentStatement.java
@@ -73,6 +73,10 @@ public class AssignmentStatement extends Statement
return _targetList;
}
+ public void setTarget(DataIdentifier di) {
+ _targetList.set(0, di);
+ }
+
public Expression getSource(){
return _source;
}
http://git-wip-us.apache.org/repos/asf/systemml/blob/db020790/src/main/java/org/apache/sysml/parser/MultiAssignmentStatement.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/sysml/parser/MultiAssignmentStatement.java b/src/main/java/org/apache/sysml/parser/MultiAssignmentStatement.java
index b01dd2e..7909f71 100644
--- a/src/main/java/org/apache/sysml/parser/MultiAssignmentStatement.java
+++ b/src/main/java/org/apache/sysml/parser/MultiAssignmentStatement.java
@@ -20,6 +20,7 @@
package org.apache.sysml.parser;
import java.util.ArrayList;
+import java.util.List;
import org.apache.sysml.api.DMLScript;
import org.apache.sysml.debug.DMLBreakpointManager;
@@ -61,6 +62,11 @@ public class MultiAssignmentStatement extends Statement
return _targetList;
}
+ public void setTargetList(List<DataIdentifier> diList) {
+ _targetList.clear();
+ _targetList.addAll(diList);
+ }
+
public Expression getSource(){
return _source;
}
http://git-wip-us.apache.org/repos/asf/systemml/blob/db020790/src/main/java/org/apache/sysml/parser/StatementBlock.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/sysml/parser/StatementBlock.java b/src/main/java/org/apache/sysml/parser/StatementBlock.java
index 4498eaa..3988a7f 100644
--- a/src/main/java/org/apache/sysml/parser/StatementBlock.java
+++ b/src/main/java/org/apache/sysml/parser/StatementBlock.java
@@ -288,12 +288,18 @@ public class StatementBlock extends LiveVariableAnalysis implements ParseInfo
if( !ret ) return false;
}
- if( s instanceof MultiAssignmentStatement && ((MultiAssignmentStatement)s).getSource() instanceof FunctionCallIdentifier )
- {
- FunctionCallIdentifier fcall = (FunctionCallIdentifier) ((MultiAssignmentStatement)s).getSource();
- FunctionStatementBlock fblock2 = prog.getFunctionStatementBlock(fcall.getNamespace(), fcall.getName());
- ret &= rIsInlineableFunction(fblock2, prog);
- if( !ret ) return false;
+ else if( s instanceof MultiAssignmentStatement ) {
+ MultiAssignmentStatement mas = (MultiAssignmentStatement)s;
+ if( mas.getSource() instanceof FunctionCallIdentifier ) {
+ FunctionCallIdentifier fcall = (FunctionCallIdentifier) ((MultiAssignmentStatement)s).getSource();
+ FunctionStatementBlock fblock2 = prog.getFunctionStatementBlock(fcall.getNamespace(), fcall.getName());
+ ret &= rIsInlineableFunction(fblock2, prog);
+ if( !ret ) return false;
+ }
+ else if( mas.getSource() instanceof BuiltinFunctionExpression
+ && ((BuiltinFunctionExpression)mas.getSource()).multipleReturns() ) {
+ return false;
+ }
}
}
}
@@ -574,143 +580,180 @@ public class StatementBlock extends LiveVariableAnalysis implements ParseInfo
public ArrayList<Statement> rewriteFunctionCallStatements (DMLProgram dmlProg, ArrayList<Statement> statements) {
ArrayList<Statement> newStatements = new ArrayList<>();
- for (Statement current : statements){
- if (isRewritableFunctionCall(current, dmlProg)){
-
- Expression sourceExpr = null;
- if (current instanceof AssignmentStatement)
- sourceExpr = ((AssignmentStatement)current).getSource();
- else
- sourceExpr = ((MultiAssignmentStatement)current).getSource();
+ for (Statement current : statements) {
+ if( !isRewritableFunctionCall(current, dmlProg) ) {
+ newStatements.add(current);
+ continue;
+ }
- FunctionCallIdentifier fcall = (FunctionCallIdentifier) sourceExpr;
- FunctionStatementBlock fblock = dmlProg.getFunctionStatementBlock(fcall.getNamespace(), fcall.getName());
- if (fblock == null){
- fcall.raiseValidateError("function " + fcall.getName() + " is undefined in namespace " + fcall.getNamespace(), false);
- }
- FunctionStatement fstmt = (FunctionStatement)fblock.getStatement(0);
+ Expression sourceExpr = (current instanceof AssignmentStatement) ?
+ ((AssignmentStatement)current).getSource() :
+ ((MultiAssignmentStatement)current).getSource();
+ FunctionCallIdentifier fcall = (FunctionCallIdentifier) sourceExpr;
+ FunctionStatementBlock fblock = dmlProg.getFunctionStatementBlock(fcall.getNamespace(), fcall.getName());
+ if( fblock == null )
+ fcall.raiseValidateError("function " + fcall.getName() + " is undefined in namespace " + fcall.getNamespace(), false);
+ FunctionStatement fstmt = (FunctionStatement)fblock.getStatement(0);
+
+ // recursive inlining (no memo required because update-inplace of function statement blocks, so no redundant inlining)
+ if( rIsInlineableFunction(fblock, dmlProg) ){
+ fstmt.getBody().get(0).setStatements(
+ rewriteFunctionCallStatements(dmlProg, fstmt.getBody().get(0).getStatements()));
+ }
- // recursive inlining (no memo required because update-inplace of function statement blocks, so no redundant inlining)
- if( rIsInlineableFunction(fblock, dmlProg) ){
- fstmt.getBody().get(0).setStatements(rewriteFunctionCallStatements(dmlProg, fstmt.getBody().get(0).getStatements()));
- }
+ //MB: we cannot use the hash since multiple interleaved inlined functions should be independent.
+ String prefix = _seq.getNextID() + "_";
- //MB: we cannot use the hash since multiple interleaved inlined functions should be independent.
- String prefix = _seq.getNextID() + "_";
+ if (fstmt.getBody().size() > 1){
+ sourceExpr.raiseValidateError("rewritable function can only have 1 statement block", false);
+ }
+ StatementBlock sblock = fstmt.getBody().get(0);
- if (fstmt.getBody().size() > 1){
- sourceExpr.raiseValidateError("rewritable function can only have 1 statement block", false);
- }
- StatementBlock sblock = fstmt.getBody().get(0);
+ if( fcall.getParamExprs().size() != fstmt.getInputParams().size() ) {
+ sourceExpr.raiseValidateError("Wrong number of function input arguments: "+
+ fcall.getParamExprs().size() + " found, but " + fstmt.getInputParams().size()+" expected.");
+ }
- if( fcall.getParamExprs().size() != fstmt.getInputParams().size() ) {
- sourceExpr.raiseValidateError("Wrong number of function input arguments: "+
- fcall.getParamExprs().size() + " found, but " + fstmt.getInputParams().size()+" expected.");
+ for (int i =0; i < fcall.getParamExprs().size(); i++) {
+ ParameterExpression inputArg = fcall.getParamExprs().get(i);
+ DataIdentifier currFormalParam = (inputArg.getName()==null) ?
+ fstmt.getInputParams().get(i) : fstmt.getInputParam(inputArg.getName());
+ if( currFormalParam == null )
+ throw new LanguageException("Non-existing named function argument '"
+ + inputArg.getName()+"' in call to "+fcall.getName()+".");
+
+ // create new assignment statement
+ String newFormalParameterName = prefix + currFormalParam.getName();
+ DataIdentifier newTarget = new DataIdentifier(currFormalParam);
+ newTarget.setName(newFormalParameterName);
+
+ Expression currCallParam = inputArg.getExpr();
+
+ //auto casting of inputs on inlining (if required)
+ ValueType targetVT = newTarget.getValueType();
+ if (newTarget.getDataType() == DataType.SCALAR && currCallParam.getOutput() != null
+ && targetVT != currCallParam.getOutput().getValueType() && targetVT != ValueType.STRING) {
+ currCallParam = new BuiltinFunctionExpression(
+ BuiltinFunctionExpression.getValueTypeCastOperator(targetVT),
+ new Expression[] { currCallParam }, newTarget);
}
- for (int i =0; i < fcall.getParamExprs().size(); i++) {
- ParameterExpression inputArg = fcall.getParamExprs().get(i);
- DataIdentifier currFormalParam = (inputArg.getName()==null) ?
- fstmt.getInputParams().get(i) : fstmt.getInputParam(inputArg.getName());
- if( currFormalParam == null )
- throw new LanguageException("Non-existing named function argument '"
- + inputArg.getName()+"' in call to "+fcall.getName()+".");
-
- // create new assignment statement
- String newFormalParameterName = prefix + currFormalParam.getName();
- DataIdentifier newTarget = new DataIdentifier(currFormalParam);
- newTarget.setName(newFormalParameterName);
-
- Expression currCallParam = inputArg.getExpr();
-
- //auto casting of inputs on inlining (if required)
- ValueType targetVT = newTarget.getValueType();
- if (newTarget.getDataType() == DataType.SCALAR && currCallParam.getOutput() != null
- && targetVT != currCallParam.getOutput().getValueType() && targetVT != ValueType.STRING) {
- currCallParam = new BuiltinFunctionExpression(
- BuiltinFunctionExpression.getValueTypeCastOperator(targetVT),
- new Expression[] { currCallParam }, newTarget);
- }
-
- // create the assignment statement to bind the call parameter to formal parameter
- newStatements.add(new AssignmentStatement(newTarget, currCallParam, newTarget));
- }
+ // create the assignment statement to bind the call parameter to formal parameter
+ newStatements.add(new AssignmentStatement(newTarget, currCallParam, newTarget));
+ }
- for (Statement stmt : sblock._statements){
- // rewrite the statement to use the "rewritten" name
- Statement rewrittenStmt = stmt.rewriteStatement(prefix);
- newStatements.add(rewrittenStmt);
- }
+ for (Statement stmt : sblock._statements){
+ // rewrite the statement to use the "rewritten" name
+ Statement rewrittenStmt = stmt.rewriteStatement(prefix);
+ newStatements.add(rewrittenStmt);
+ }
- if (current instanceof AssignmentStatement) {
- if (fstmt.getOutputParams().size() == 0) {
- AssignmentStatement as = (AssignmentStatement) current;
- if ((as.getTargetList().size() == 1) && (as.getTargetList().get(0) != null)) {
- raiseValidateError("Function '" + fcall.getName()
- + "' does not return a value but is assigned to " + as.getTargetList().get(0),
- true);
- }
- }
- } else if (current instanceof MultiAssignmentStatement) {
- if (fstmt.getOutputParams().size() == 0) {
- MultiAssignmentStatement mas = (MultiAssignmentStatement) current;
+ if (current instanceof AssignmentStatement) {
+ if (fstmt.getOutputParams().size() == 0) {
+ AssignmentStatement as = (AssignmentStatement) current;
+ if ((as.getTargetList().size() == 1) && (as.getTargetList().get(0) != null)) {
raiseValidateError("Function '" + fcall.getName()
- + "' does not return a value but is assigned to " + mas.getTargetList(), true);
+ + "' does not return a value but is assigned to " + as.getTargetList().get(0),
+ true);
}
}
- // handle the return values
- for (int i = 0; i < fstmt.getOutputParams().size(); i++){
-
- // get the target (return parameter from function)
- DataIdentifier currReturnParam = fstmt.getOutputParams().get(i);
- String newSourceName = prefix + currReturnParam.getName();
- DataIdentifier newSource = new DataIdentifier(currReturnParam);
- newSource.setName(newSourceName);
-
- // get binding
- DataIdentifier newTarget = null;
- if (current instanceof AssignmentStatement){
- if (i > 0) {
- fstmt.raiseValidateError("Assignment statement cannot return multiple values", false);
- }
- AssignmentStatement as = (AssignmentStatement) current;
- DataIdentifier targ = as.getTarget();
- if (targ == null) {
- Expression exp = as.getSource();
- FunctionCallIdentifier fci = (FunctionCallIdentifier) exp;
- String functionName = fci.getName();
- fstmt.raiseValidateError(functionName + " requires LHS value", false);
- } else {
- newTarget = new DataIdentifier(((AssignmentStatement)current).getTarget());
- }
- }
- else{
- newTarget = new DataIdentifier(((MultiAssignmentStatement)current).getTargetList().get(i));
- }
-
- //auto casting of inputs on inlining (always, redundant cast removed during Hop Rewrites)
- ValueType sourceVT = newSource.getValueType();
- if (newSource.getDataType() == DataType.SCALAR && sourceVT != ValueType.STRING) {
- newSource = new BuiltinFunctionExpression(
- BuiltinFunctionExpression.getValueTypeCastOperator(sourceVT),
- new Expression[] { newSource }, newTarget);
- }
-
- // create the assignment statement to bind the call parameter to formal parameter
- AssignmentStatement binding = new AssignmentStatement(newTarget, newSource, newTarget);
-
- newStatements.add(binding);
+ } else if (current instanceof MultiAssignmentStatement) {
+ if (fstmt.getOutputParams().size() == 0) {
+ MultiAssignmentStatement mas = (MultiAssignmentStatement) current;
+ raiseValidateError("Function '" + fcall.getName()
+ + "' does not return a value but is assigned to " + mas.getTargetList(), true);
}
-
- } // end if (isRewritableFunctionCall(current, dmlProg)
-
- else {
- newStatements.add(current);
}
+
+ // handle returns by appending name mappings, but with special handling of
+ // statements that contain function calls or multi-return builtin expressions (but disabled)
+// Statement lastAdd = newStatements.get(newStatements.size()-1);
+// if( isOutputBindingViaFunctionCall(lastAdd, prefix, fstmt) && lastAdd instanceof AssignmentStatement )
+// ((AssignmentStatement)lastAdd).setTarget(((AssignmentStatement)current).getTarget());
+// else if ( isOutputBindingViaFunctionCall(lastAdd, prefix, fstmt) && lastAdd instanceof MultiAssignmentStatement )
+// if( current instanceof MultiAssignmentStatement )
+// ((MultiAssignmentStatement)lastAdd).setTargetList(((MultiAssignmentStatement)current).getTargetList());
+// else //correct for multi-assignment to assignment transform
+// newStatements.set(newStatements.size()-1, createNewPartialMultiAssignment(lastAdd, current, prefix, fstmt));
+// else
+ appendOutputAssignments(current, prefix, fstmt, newStatements);
}
-
return newStatements;
}
+
+ @SuppressWarnings("unused")
+ private static boolean isOutputBindingViaFunctionCall(Statement last, String prefix, FunctionStatement fstmt) {
+ if( last instanceof AssignmentStatement ) {
+ AssignmentStatement as = (AssignmentStatement) last;
+ String newName = prefix + fstmt.getOutputParams().get(0).getName();
+ return as.getSource() instanceof FunctionCallIdentifier
+ && as.getTarget().getName().equals(newName);
+ }
+ else if( last instanceof MultiAssignmentStatement ) {
+ MultiAssignmentStatement mas = (MultiAssignmentStatement) last;
+ List<DataIdentifier> tlist1 = mas.getTargetList();
+ boolean ret = mas.getSource() instanceof FunctionCallIdentifier
+ || (mas.getSource() instanceof BuiltinFunctionExpression
+ && ((BuiltinFunctionExpression)mas.getSource()).multipleReturns());
+ for( DataIdentifier di : fstmt.getOutputParams() )
+ ret &= tlist1.stream().anyMatch(d -> d.getName().equals(prefix+di.getName()));
+ return ret;
+ }
+ return false; //default
+ }
+
+ @SuppressWarnings("unused")
+ private static MultiAssignmentStatement createNewPartialMultiAssignment(Statement last, Statement current, String prefix, FunctionStatement fstmt) {
+ MultiAssignmentStatement mas = (MultiAssignmentStatement) last;
+ AssignmentStatement as = (AssignmentStatement) current;
+ ArrayList<DataIdentifier> tlist = new ArrayList<>();
+ String tmpStr = prefix+fstmt.getOutputParams().get(0).getName();
+ for( DataIdentifier di : mas.getTargetList() )
+ tlist.add( di.getName().equals(tmpStr) ? as.getTarget() : di );
+ return new MultiAssignmentStatement(tlist, mas.getSource());
+ }
+
+ private static void appendOutputAssignments(Statement current, String prefix, FunctionStatement fstmt, List<Statement> newStatements) {
+ for (int i = 0; i < fstmt.getOutputParams().size(); i++){
+ // get the target (return parameter from function)
+ DataIdentifier currReturnParam = fstmt.getOutputParams().get(i);
+ String newSourceName = prefix + currReturnParam.getName();
+ DataIdentifier newSource = new DataIdentifier(currReturnParam);
+ newSource.setName(newSourceName);
+
+ // get binding
+ DataIdentifier newTarget = null;
+ if (current instanceof AssignmentStatement){
+ if (i > 0) {
+ fstmt.raiseValidateError("Assignment statement cannot return multiple values", false);
+ }
+ AssignmentStatement as = (AssignmentStatement) current;
+ DataIdentifier targ = as.getTarget();
+ if (targ == null) {
+ Expression exp = as.getSource();
+ FunctionCallIdentifier fci = (FunctionCallIdentifier) exp;
+ String functionName = fci.getName();
+ fstmt.raiseValidateError(functionName + " requires LHS value", false);
+ } else {
+ newTarget = new DataIdentifier(((AssignmentStatement)current).getTarget());
+ }
+ }
+ else{
+ newTarget = new DataIdentifier(((MultiAssignmentStatement)current).getTargetList().get(i));
+ }
+
+ //auto casting of inputs on inlining (always, redundant cast removed during Hop Rewrites)
+ ValueType sourceVT = newSource.getValueType();
+ if (newSource.getDataType() == DataType.SCALAR && sourceVT != ValueType.STRING) {
+ newSource = new BuiltinFunctionExpression(
+ BuiltinFunctionExpression.getValueTypeCastOperator(sourceVT),
+ new Expression[] { newSource }, newTarget);
+ }
+
+ // create the assignment statement to bind the call parameter to formal parameter
+ newStatements.add(new AssignmentStatement(newTarget, newSource, newTarget));
+ }
+ }
public VariableSet validate(DMLProgram dmlProg, VariableSet ids, HashMap<String, ConstIdentifier> constVars, boolean conditional)
{
http://git-wip-us.apache.org/repos/asf/systemml/blob/db020790/src/test/java/org/apache/sysml/test/integration/functions/misc/FunctionPotpourriTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/sysml/test/integration/functions/misc/FunctionPotpourriTest.java b/src/test/java/org/apache/sysml/test/integration/functions/misc/FunctionPotpourriTest.java
index 68e8f00..f1ce7b0 100644
--- a/src/test/java/org/apache/sysml/test/integration/functions/misc/FunctionPotpourriTest.java
+++ b/src/test/java/org/apache/sysml/test/integration/functions/misc/FunctionPotpourriTest.java
@@ -20,6 +20,7 @@
package org.apache.sysml.test.integration.functions.misc;
+import org.junit.Assert;
import org.junit.Test;
import org.apache.sysml.api.DMLException;
import org.apache.sysml.test.integration.AutomatedTestBase;
@@ -45,6 +46,8 @@ public class FunctionPotpourriTest extends AutomatedTestBase
private final static String TEST_NAME15 = "FunPotpourriDefaultArgScalarMatrix1";
private final static String TEST_NAME16 = "FunPotpourriDefaultArgScalarMatrix2";
private final static String TEST_NAME17 = "FunPotpourriNamedArgsQuotedAssign";
+ private final static String TEST_NAME18 = "FunPotpourriMultiReturnBuiltin1";
+ private final static String TEST_NAME19 = "FunPotpourriMultiReturnBuiltin2";
private final static String TEST_DIR = "functions/misc/";
private final static String TEST_CLASS_DIR = TEST_DIR + FunctionPotpourriTest.class.getSimpleName() + "/";
@@ -69,6 +72,8 @@ public class FunctionPotpourriTest extends AutomatedTestBase
addTestConfiguration( TEST_NAME15, new TestConfiguration(TEST_CLASS_DIR, TEST_NAME15, new String[] { "R" }) );
addTestConfiguration( TEST_NAME16, new TestConfiguration(TEST_CLASS_DIR, TEST_NAME16, new String[] { "R" }) );
addTestConfiguration( TEST_NAME17, new TestConfiguration(TEST_CLASS_DIR, TEST_NAME17, new String[] { "R" }) );
+ addTestConfiguration( TEST_NAME18, new TestConfiguration(TEST_CLASS_DIR, TEST_NAME18, new String[] { "R" }) );
+ addTestConfiguration( TEST_NAME19, new TestConfiguration(TEST_CLASS_DIR, TEST_NAME19, new String[] { "R" }) );
}
@Test
@@ -166,16 +171,28 @@ public class FunctionPotpourriTest extends AutomatedTestBase
runFunctionTest( TEST_NAME17, false );
}
+ @Test
+ public void testFunctionMultiReturnBuiltin1() {
+ runFunctionTest( TEST_NAME18, false );
+ }
+
+ @Test
+ public void testFunctionMultiReturnBuiltin2() {
+ runFunctionTest( TEST_NAME19, false );
+ }
+
private void runFunctionTest(String testName, boolean error) {
TestConfiguration config = getTestConfiguration(testName);
loadTestConfiguration(config);
String HOME = SCRIPT_DIR + TEST_DIR;
fullDMLScriptName = HOME + testName + ".dml";
- programArgs = new String[]{"-explain", "-stats",
+ programArgs = new String[]{"-explain","hops", "-stats",
"-args", String.valueOf(error).toUpperCase()};
-
+
//run script and compare output
runTest(true, error, DMLException.class, -1);
+ if( testName.equals(TEST_NAME18) )
+ Assert.assertTrue(heavyHittersContainsString("print"));
}
}
http://git-wip-us.apache.org/repos/asf/systemml/blob/db020790/src/test/scripts/functions/misc/FunPotpourriMultiReturnBuiltin1.dml
----------------------------------------------------------------------
diff --git a/src/test/scripts/functions/misc/FunPotpourriMultiReturnBuiltin1.dml b/src/test/scripts/functions/misc/FunPotpourriMultiReturnBuiltin1.dml
new file mode 100644
index 0000000..cac2ac4
--- /dev/null
+++ b/src/test/scripts/functions/misc/FunPotpourriMultiReturnBuiltin1.dml
@@ -0,0 +1,28 @@
+#-------------------------------------------------------------
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+#-------------------------------------------------------------
+
+foo = function(Matrix[Double] A) return (Matrix[Double] B) {
+ [w, B] = eigen(A)
+}
+
+X = matrix(0.1, rows=100, cols=100);
+Y = foo(X);
+print(toString(Y))
http://git-wip-us.apache.org/repos/asf/systemml/blob/db020790/src/test/scripts/functions/misc/FunPotpourriMultiReturnBuiltin2.dml
----------------------------------------------------------------------
diff --git a/src/test/scripts/functions/misc/FunPotpourriMultiReturnBuiltin2.dml b/src/test/scripts/functions/misc/FunPotpourriMultiReturnBuiltin2.dml
new file mode 100644
index 0000000..1efcab4
--- /dev/null
+++ b/src/test/scripts/functions/misc/FunPotpourriMultiReturnBuiltin2.dml
@@ -0,0 +1,34 @@
+#-------------------------------------------------------------
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+#-------------------------------------------------------------
+
+foo2 = function(Matrix[Double] A) return (Matrix[Double] w, Matrix[Double] B) {
+ while(FALSE){}
+ w = A - 1;
+ B = A + 1;
+}
+
+foo = function(Matrix[Double] A) return (Matrix[Double] B) {
+ [w, B] = foo2(A)
+}
+
+X = matrix(0.1, rows=100, cols=100);
+Y = foo(X);
+print(toString(Y))