]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/constants/SCLConstant.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / constants / SCLConstant.java
diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/constants/SCLConstant.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/constants/SCLConstant.java
new file mode 100644 (file)
index 0000000..a4c47ea
--- /dev/null
@@ -0,0 +1,376 @@
+package org.simantics.scl.compiler.constants;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Arrays;\r
+\r
+import org.simantics.scl.compiler.common.names.Name;\r
+import org.simantics.scl.compiler.common.names.Named;\r
+import org.simantics.scl.compiler.internal.codegen.optimization.Optimization;\r
+import org.simantics.scl.compiler.internal.codegen.optimization.OptimizationMap;\r
+import org.simantics.scl.compiler.internal.codegen.references.BoundVar;\r
+import org.simantics.scl.compiler.internal.codegen.references.Val;\r
+import org.simantics.scl.compiler.internal.codegen.references.ValRef;\r
+import org.simantics.scl.compiler.internal.codegen.ssa.SSABlock;\r
+import org.simantics.scl.compiler.internal.codegen.ssa.SSAFunction;\r
+import org.simantics.scl.compiler.internal.codegen.ssa.exits.Jump;\r
+import org.simantics.scl.compiler.internal.codegen.ssa.statements.LetApply;\r
+import org.simantics.scl.compiler.internal.codegen.ssa.statements.LetFunctions;\r
+import org.simantics.scl.compiler.internal.codegen.utils.SSASimplificationContext;\r
+import org.simantics.scl.compiler.types.TVar;\r
+import org.simantics.scl.compiler.types.Type;\r
+import org.simantics.scl.compiler.types.Types;\r
+\r
+public class SCLConstant extends DelegateConstant implements Named {\r
+\r
+    public Name name; // Needed only for debugging\r
+    public SSAFunction definition;\r
+    public SSAFunction inlinableDefinition;\r
+    public int inlineArity = Integer.MAX_VALUE;\r
+    public int inlinePhaseMask = 0xffffffff;\r
+    public boolean isPrivate = false;    \r
+    \r
+    public SCLConstant(Name name, Type type) {\r
+        super(type);\r
+        this.name = name;\r
+    }\r
+    \r
+    public void setInlineArity(int inlineArity, int inlinePhaseMask) {\r
+        this.inlineArity = inlineArity;\r
+        this.inlinePhaseMask = inlinePhaseMask;\r
+        //System.out.println(name + " " + inlineArity + " " + inlinePhaseMask);\r
+    }\r
+    \r
+    public void setPrivate(boolean isPrivate) {\r
+        this.isPrivate = isPrivate;\r
+    }\r
+    \r
+    public void setDefinition(SSAFunction definition) {\r
+        this.definition = definition;\r
+    }\r
+    \r
+    public SSAFunction getDefinition() {\r
+        return definition;\r
+    }\r
+\r
+    @Override\r
+    public void inline(SSASimplificationContext context, LetApply apply) {\r
+        if(inlineTailCallToSelf(context, apply)) {\r
+            return;\r
+        }\r
+        /*if(tryBetaReduce(context, apply)) {\r
+            return;\r
+        }*/\r
+        if(basicInline(context, apply)) {\r
+            return;\r
+        }\r
+        trySpecialize(context, apply);\r
+        \r
+        Optimization opt = OptimizationMap.OPTIMIZATIONS.get(name);\r
+        if(opt != null)\r
+            opt.inline(context, apply);\r
+    }\r
+\r
+    static int inlineCount = 0;\r
+    \r
+    private boolean canInlineInPhase(int phase) {\r
+        return ((inlinePhaseMask >> phase)&1) == 1;\r
+    }\r
+    \r
+    private boolean basicInline(SSASimplificationContext context, LetApply apply) {\r
+        if(!canInlineInPhase(context.getPhase())) {\r
+            //System.out.println("Cannot optimize " + name + " in phase " + context.getPhase());\r
+            return false;\r
+        }\r
+        ValRef functionRef = apply.getFunction();\r
+        ValRef[] parameters = apply.getParameters();\r
+        SSAFunction def = inlinableDefinition == null ? definition : inlinableDefinition;\r
+        if(parameters.length < inlineArity &&\r
+                (!isPrivate \r
+                        || parameters.length != def.getArity() \r
+                        || hasMoreThanOneOccurences()))\r
+            return false;\r
+        \r
+        //if(def.getArity() == 0)\r
+        //    return false; // FIXME\r
+        \r
+        //System.out.println("basicInline: " + apply);\r
+        //System.out.println("def: " + def);\r
+        \r
+        if(isPrivate && !hasMoreThanOneOccurences())\r
+            context.removeConstant(name);\r
+        else\r
+            def = def.copy();\r
+        \r
+        if(parameters.length >= def.getArity()) {\r
+            if(parameters.length != def.getArity())\r
+                apply.split(def.getArity());\r
+            apply.inline(def);\r
+            context.markModified("SCLConstant.beta-constant " + getName());\r
+        }\r
+        else /*if(parameters.length < def.getArity())*/ {\r
+            def.applyTypes(functionRef.getTypeParameters());\r
+            def.apply(parameters);\r
+                        \r
+            def.setTarget(apply.getTarget());\r
+            new LetFunctions(def).insertBefore(apply);\r
+\r
+            apply.remove();\r
+            context.markModified("SCLConstant.partial-beta-constant " + getName());\r
+        }\r
+                        \r
+        /*Name newName = Name.create(name.module,\r
+                name.name + "_S" + (++inlineCount));\r
+        SCLConstant newConstant = new SCLConstant(newName, type);\r
+        newConstant.setPrivate(true);\r
+        newConstant.setDefinition(definition.copy());    */    \r
+        /*System.out.println("*** 1 *************************************");\r
+        System.out.println(definition);\r
+        System.out.println("*** 2 *************************************");\r
+        System.out.println(newConstant.definition);\r
+        \r
+        function.remove();\r
+        apply.setFunction(newConstant.createOccurrence(function.getTypeParameters()));\r
+        \r
+        context.addConstant(newConstant);\r
+        \r
+        context.markModified();\r
+        \r
+        newConstant.trySpecialize(context, apply);\r
+        */\r
+        \r
+        return true;\r
+    }\r
+\r
+    private boolean inlineTailCallToSelf(SSASimplificationContext context, LetApply apply) {\r
+        SSAFunction thisFunction = apply.getParent().getParent();\r
+        if(thisFunction != definition)\r
+            return false;\r
+        ValRef ref = apply.getTarget().getOccurrence();\r
+        if(ref == null || ref.getNext() != null)\r
+            return false;\r
+        if(!(ref.getParent() instanceof Jump))\r
+            return false;\r
+        Jump jump = (Jump)ref.getParent();\r
+        if(jump.getParameters().length != 1)\r
+            return false;\r
+        if(jump.getTarget().getBinding() != thisFunction.getReturnCont())\r
+            return false;\r
+        if(apply.getParameters().length != thisFunction.getArity())\r
+            return false;\r
+        \r
+        jump.getTarget().remove();\r
+        jump.setTarget(thisFunction.getFirstBlock().createOccurrence());\r
+        jump.setParameters(apply.getParameters());\r
+        \r
+        apply.getFunction().remove();\r
+        apply.detach();\r
+        \r
+        context.markModified("SCLConstant.simplify-tail-call");\r
+        \r
+        return true;\r
+    }\r
+\r
+    private void trySpecialize(SSASimplificationContext context, LetApply apply) {\r
+        if(!isPrivate)\r
+            return;\r
+        if(hasMoreThanOneOccurences())\r
+            return;\r
+        if(apply.getParent().getParent() == definition)\r
+            return;\r
+\r
+        // Specialization of type parameters\r
+        {\r
+            ValRef functionRef = apply.getFunction();\r
+            Type[] pValues = functionRef.getTypeParameters();   \r
+            boolean hasComplexTypes = false;\r
+            for(Type type : pValues)\r
+                if(!(Types.canonical(type) instanceof TVar)) {\r
+                    hasComplexTypes = true;\r
+                    break;\r
+                }\r
+            if(hasComplexTypes) {                \r
+                /*PrintingContext pc = new PrintingContext();\r
+                pc.append(">> BEFORE >>\n");\r
+                definition.toString(pc);*/   \r
+                \r
+                TVar[] pVars = definition.getTypeParameters();\r
+                TVar[] pVarsTail;\r
+                if(pVars.length == pValues.length)\r
+                    pVarsTail = TVar.EMPTY_ARRAY;\r
+                else {\r
+                    pVarsTail = Arrays.copyOfRange(pVars, pValues.length, pVars.length);\r
+                    pVars = Arrays.copyOf(pVars, pValues.length);\r
+                }\r
+                type = Types.instantiate(type, pValues);\r
+                /*pc.append("REPLACE: ");\r
+                pc.append(pVars);\r
+                pc.append(" -> ");\r
+                pc.append(pValues);\r
+                pc.append('\n');*/\r
+                definition.replace(pVars, pValues);\r
+                TVar[] newParameters = Types.freeVarsArray(pValues);\r
+                type = Types.forAll(newParameters, type);\r
+                functionRef.setTypeParameters(newParameters);\r
+                definition.setTypeParameters(Types.concat(newParameters, pVarsTail));               \r
+                \r
+                /*pc.append(">> AFTER >>\n");\r
+                definition.toString(pc);\r
+                System.out.println(pc);*/\r
+                context.markModified("SCLConstant.specialize-types");\r
+            }\r
+        }\r
+        \r
+        if(!definition.getFirstBlock().hasNoOccurences())\r
+            // TODO We can flex this requirement if all jumps to the first block\r
+            //      give same values to the first block\r
+            return;\r
+        \r
+        // Specialization of parameters\r
+        ValRef[] parameters = apply.getParameters();\r
+        ValRef[] specialization = null;\r
+        int arity = Math.min(parameters.length, definition.getArity());\r
+        for(int i=0;i<arity;++i) {\r
+            Val val = parameters[i].getBinding();\r
+            if(val instanceof Constant) {\r
+                if(specialization == null)\r
+                    specialization = new ValRef[arity];\r
+                specialization[i] = parameters[i];\r
+            }\r
+        }\r
+        \r
+        if(specialization != null)\r
+            specialize(context, apply, specialization);\r
+    }\r
+\r
+    private void specialize(SSASimplificationContext context, LetApply apply,\r
+            ValRef[] specialization) {\r
+        /*System.out.println("=== SPECIALIZE ====================");\r
+        System.out.println(apply);\r
+        System.out.println("--------");\r
+        System.out.println(definition);\r
+        System.out.println("========");*/\r
+        // *** Modify apply *******************************        \r
+        {\r
+            // Handle old parameters\r
+            ValRef[] oldParameters = apply.getParameters();\r
+            int newParameterCount = oldParameters.length - specialization.length;\r
+            for(int i=0;i<specialization.length;++i)\r
+                if(specialization[i] == null)\r
+                    ++newParameterCount;            \r
+\r
+            if(newParameterCount == 0) {\r
+                // If apply would be degenerated, remove it\r
+                apply.getTarget().replaceBy(apply.getFunction());\r
+                apply.remove();\r
+            }            \r
+            else {\r
+                // Create new parameter array\r
+                ValRef[] newParameters = new ValRef[newParameterCount];\r
+                int k=0;\r
+                for(int i=0;i<specialization.length;++i)\r
+                    if(specialization[i] == null)\r
+                        newParameters[k++] = oldParameters[i];\r
+                    else\r
+                        oldParameters[i].remove();                        \r
+                for(int i=specialization.length;i<oldParameters.length;++i)\r
+                    newParameters[k++] = oldParameters[i];\r
+                        \r
+                apply.setParameters(newParameters);\r
+            }\r
+        }\r
+        \r
+        // *** Modify definition **************************        \r
+        {\r
+            SSABlock firstBlock = definition.getFirstBlock();\r
+            BoundVar[] parameters = firstBlock.getParameters();\r
+            ArrayList<BoundVar> newParameters = new ArrayList<BoundVar>(parameters.length); \r
+            for(int i=0;i<specialization.length;++i)\r
+                if(specialization[i] != null)\r
+                    parameters[i].replaceBy(specialization[i]);\r
+                else\r
+                    newParameters.add(parameters[i]);\r
+            for(int i=specialization.length;i<parameters.length;++i)\r
+                newParameters.add(parameters[i]);\r
+            firstBlock.setParameters(newParameters.toArray(new BoundVar[newParameters.size()]));\r
+            \r
+            type = definition.getType();\r
+        }\r
+        \r
+        /*System.out.println(apply);\r
+        System.out.println("--------");\r
+        System.out.println(definition);*/\r
+        context.markModified("SCLConstant.specialize");  \r
+    }\r
+\r
+    @Override\r
+    public String toString() {\r
+        char c = name.name.charAt(0);\r
+        if(Character.isJavaIdentifierStart(c) || name.name.charAt(0) == '(' || c == '[')\r
+            return name.name;\r
+        else\r
+            return "(" + name.name + ")";\r
+    }\r
+\r
+    @Override\r
+    public Name getName() {\r
+        return name;\r
+    }\r
+\r
+    public Constant getBase() {\r
+        return base;\r
+    }\r
+    \r
+    public boolean isPrivate() {\r
+        return isPrivate;\r
+    }\r
+\r
+    private boolean simplifyConstantFunction(SSASimplificationContext context) {\r
+        ValRef constant = definition.isEqualToConstant();\r
+        if(constant == null)\r
+            return false;\r
+        Val binding = constant.getBinding();\r
+        if(binding == this)\r
+            return false;\r
+        if(binding instanceof Constant) {\r
+            /*System.out.println(name + " -> " + constant.getBinding());\r
+            System.out.println("replace: " + this);\r
+            System.out.println("of type: " + this.getType());\r
+            System.out.println("by: " + binding);\r
+            System.out.println("of type: " + binding.getType());\r
+            System.out.println("parameters: " + Types.toString(definition.getTypeParameters()));\r
+            System.out.println("parameters2: " + Types.toString(constant.getTypeParameters()));\r
+            System.out.println("private: " + isPrivate);*/            \r
+            replaceBy(binding,\r
+                    definition.getTypeParameters(), \r
+                    constant.getTypeParameters());                \r
+            if(isPrivate) {\r
+                definition.destroy();\r
+                context.removeConstant(name);\r
+            }\r
+            context.markModified("SCLConstant.simplify-constant");\r
+            return true;\r
+        }\r
+        return false;\r
+    }\r
+    \r
+    public void simplify(SSASimplificationContext context) {\r
+        if(!hasNoOccurences() /* TODO why this condition is needed? */) {\r
+            if(simplifyConstantFunction(context))\r
+                return;\r
+        }\r
+        /*if(isPrivate)\r
+            definition.tryToMakeMonadic(context);*/\r
+        definition.simplify(context);\r
+        if(inlineArity == Integer.MAX_VALUE && definition.isSimpleEnoughForInline()) {\r
+            inlineArity = definition.getArity();\r
+            inlinableDefinition = definition.copy();\r
+            context.markModified("mark inlineable " + name);\r
+            // FIXME this will make self calling function inlinable that may crash the compiler\r
+        }\r
+    }\r
+\r
+    public void saveInlinableDefinition() {\r
+        if(inlineArity < Integer.MAX_VALUE)\r
+            inlinableDefinition = definition.copy();\r
+    }\r
+}\r