--- /dev/null
+package org.simantics.scl.compiler.internal.codegen.ssa.exits;
+
+import java.util.ArrayList;
+
+import org.objectweb.asm.Label;
+import org.simantics.scl.compiler.common.exceptions.InternalCompilerError;
+import org.simantics.scl.compiler.constants.BooleanConstant;
+import org.simantics.scl.compiler.internal.codegen.continuations.Cont;
+import org.simantics.scl.compiler.internal.codegen.continuations.ContRef;
+import org.simantics.scl.compiler.internal.codegen.references.Val;
+import org.simantics.scl.compiler.internal.codegen.references.ValRef;
+import org.simantics.scl.compiler.internal.codegen.ssa.SSABlock;
+import org.simantics.scl.compiler.internal.codegen.ssa.SSAExit;
+import org.simantics.scl.compiler.internal.codegen.ssa.SSAFunction;
+import org.simantics.scl.compiler.internal.codegen.ssa.binders.ValRefBinder;
+import org.simantics.scl.compiler.internal.codegen.utils.CopyContext;
+import org.simantics.scl.compiler.internal.codegen.utils.MethodBuilder;
+import org.simantics.scl.compiler.internal.codegen.utils.PrintingContext;
+import org.simantics.scl.compiler.internal.codegen.utils.SSASimplificationContext;
+import org.simantics.scl.compiler.internal.codegen.utils.SSAValidationContext;
+import org.simantics.scl.compiler.types.TVar;
+import org.simantics.scl.compiler.types.Type;
+import org.simantics.scl.compiler.types.Types;
+
+public class If extends SSAExit implements ValRefBinder {
+ private ValRef condition;
+ private ContRef thenTarget;
+ private ContRef elseTarget;
+
+ public If(ValRef condition, ContRef thenTarget, ContRef elseTarget) {
+ setCondition(condition);
+ setThenTarget(thenTarget);
+ setElseTarget(elseTarget);
+ }
+
+ public void setCondition(ValRef condition) {
+ this.condition = condition;
+ condition.setParent(this);
+ }
+
+ public void setThenTarget(ContRef thenTarget) {
+ this.thenTarget = thenTarget;
+ thenTarget.setParent(this);
+ }
+
+ public void setElseTarget(ContRef elseTarget) {
+ this.elseTarget = elseTarget;
+ elseTarget.setParent(this);
+ }
+
+ @Override
+ public void generateCode(MethodBuilder mb) {
+ mb.push(condition.getBinding(), Types.BOOLEAN);
+ Label elseLabel = mb.getLabel(elseTarget.getBinding());
+ mb.ifZeroComparisonBranch(elseLabel, "==");
+ mb.jump(thenTarget.getBinding());
+ mb.ensureExists(elseTarget.getBinding());
+ }
+
+ @Override
+ public void toString(PrintingContext context) {
+ context.append("if ");
+ context.append(condition);
+ context.append(" then ");
+ {
+ Cont thenCont = thenTarget.getBinding();
+ if(thenCont instanceof SSABlock) {
+ SSABlock thenBlock = (SSABlock)thenCont;
+ if(thenCont.hasMoreThanOneOccurences()) {
+ context.append(thenCont);
+ context.addBlock(thenBlock);
+ context.append(' ');
+ }
+ else {
+ context.append('\n');
+ thenBlock.bodyToString(context);
+ context.indentation();
+ }
+ }
+ else {
+ context.append(thenCont);
+ context.append(' ');
+ }
+ }
+ context.append("else ");
+ {
+ Cont elseCont = elseTarget.getBinding();
+ if(elseCont instanceof SSABlock) {
+ SSABlock elseBlock = (SSABlock)elseCont;
+ if(elseCont.hasMoreThanOneOccurences()) {
+ context.append(elseCont);
+ context.addBlock(elseBlock);
+ context.append('\n');
+ }
+ else {
+ context.append('\n');
+ elseBlock.bodyToString(context);
+ }
+ }
+ else {
+ context.append(elseCont);
+ context.append('\n');
+ }
+ }
+ }
+
+ @Override
+ public void validate(SSAValidationContext context) {
+ context.validate(condition);
+ context.validate(elseTarget);
+ context.validate(thenTarget);
+ if(condition.getParent() != this)
+ throw new InternalCompilerError();
+ if(elseTarget.getParent() != this)
+ throw new InternalCompilerError();
+ if(thenTarget.getParent() != this)
+ throw new InternalCompilerError();
+ context.assertEquals(this, condition.getType(), Types.BOOLEAN);
+ context.assertEquals(elseTarget.getBinding().getArity(), 0);
+ context.assertEquals(thenTarget.getBinding().getArity(), 0);
+ }
+
+ @Override
+ public void destroy() {
+ condition.remove();
+ elseTarget.remove();
+ thenTarget.remove();
+ }
+
+ @Override
+ public SSAExit copy(CopyContext context) {
+ return new If(context.copy(condition),
+ context.copy(thenTarget),
+ context.copy(elseTarget));
+ }
+
+ @Override
+ public void replace(TVar[] vars, Type[] replacements) {
+ condition.replace(vars, replacements);
+ }
+
+ @Override
+ public void simplify(SSASimplificationContext context) {
+ Val cond = condition.getBinding();
+ if(cond instanceof BooleanConstant) {
+ SSAExit newExit;
+ if(((BooleanConstant) cond).getValue()) {
+ newExit = new Jump(thenTarget);
+ elseTarget.remove();
+ }
+ else {
+ newExit = new Jump(elseTarget);
+ thenTarget.remove();
+ }
+ condition.remove();
+ getParent().setExit(newExit);
+ context.markModified("beta-if");
+ }
+ else if(thenTarget.getBinding() == elseTarget.getBinding()) {
+ elseTarget.remove();
+ condition.remove();
+ getParent().setExit(new Jump(thenTarget));
+ context.markModified("equal-branches-if");
+ }
+ }
+
+ @Override
+ public void collectFreeVariables(SSAFunction function,
+ ArrayList<ValRef> vars) {
+ condition.collectFreeVariables(function, vars);
+ }
+
+ @Override
+ public Cont addParametersInFrontOf(ContRef contRef, Val[] newParameters, Val[] oldParameters,
+ Cont proxy) {
+ if(proxy == null)
+ proxy = contRef.getBinding().createProxy(getParent().getParent(), newParameters, oldParameters);
+ ContRef proxyRef = proxy.createOccurrence();
+ if(thenTarget == contRef)
+ setThenTarget(proxyRef);
+ else
+ setElseTarget(proxyRef);
+ return proxy;
+ }
+
+ @Override
+ public SSABlock[] getSuccessors() {
+ Cont thenCont = thenTarget.getBinding();
+ Cont elseCont = elseTarget.getBinding();
+ if(thenCont instanceof SSABlock) {
+ if(elseCont instanceof SSABlock)
+ return new SSABlock[] {(SSABlock)thenCont, (SSABlock)elseCont};
+ else
+ return new SSABlock[] {(SSABlock)thenCont};
+ }
+ else {
+ if(elseCont instanceof SSABlock)
+ return new SSABlock[] {(SSABlock)elseCont};
+ else
+ return SSABlock.EMPTY_ARRAY;
+ }
+ }
+}