Pseudocode: Introduce "merge" instruction

This commit is contained in:
Alexey Sedunov
2014-06-03 21:06:16 +04:00
parent 9ddfc32cdc
commit 587a9558bc
13 changed files with 87 additions and 19 deletions
@@ -118,6 +118,12 @@ public interface JetControlFlowBuilder {
boolean synthetic
);
@NotNull
PseudoValue merge(
@NotNull JetExpression expression,
@NotNull List<PseudoValue> inputValues
);
@NotNull
PseudoValue readThis(@NotNull JetExpression expression, @Nullable ReceiverParameterDescriptor parameterDescriptor);
@NotNull
@@ -76,6 +76,14 @@ public abstract class JetControlFlowBuilderAdapter implements JetControlFlowBuil
return getDelegateBuilder().magic(instructionElement, valueElement, inputValues, synthetic);
}
@NotNull
@Override
public PseudoValue merge(
@NotNull JetExpression expression, @NotNull List<PseudoValue> inputValues
) {
return getDelegateBuilder().merge(expression, inputValues);
}
@NotNull
@Override
public PseudoValue readThis(@NotNull JetExpression expression, @Nullable ReceiverParameterDescriptor parameterDescriptor) {
@@ -203,7 +203,7 @@ public class JetControlFlowProcessor {
builder.bindValue(values.get(0), to);
break;
default:
builder.magic(to, to, values, true);
builder.merge(to, values);
break;
}
}
@@ -256,6 +256,7 @@ public class JetFlowInformationProvider {
for (Instruction deadInstruction : pseudocode.getDeadInstructions()) {
if (!(deadInstruction instanceof JetElementInstruction)
|| deadInstruction instanceof LoadUnitValueInstruction
|| deadInstruction instanceof MergeInstruction
|| (deadInstruction instanceof MagicInstruction && ((MagicInstruction) deadInstruction).getSynthetic())) continue;
JetElement element = ((JetElementInstruction) deadInstruction).getElement();
@@ -21,6 +21,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.cfg.pseudocode.instructions.Instruction;
import org.jetbrains.jet.lang.cfg.pseudocode.instructions.InstructionVisitorWithResult;
import org.jetbrains.jet.lang.cfg.pseudocode.instructions.eval.MagicInstruction;
import org.jetbrains.jet.lang.cfg.pseudocode.instructions.eval.MergeInstruction;
import org.jetbrains.jet.lang.cfg.pseudocode.instructions.jumps.AbstractJumpInstruction;
import org.jetbrains.jet.lang.cfg.pseudocode.instructions.jumps.ThrowExceptionInstruction;
import org.jetbrains.jet.lang.cfg.pseudocode.instructions.special.MarkInstruction;
@@ -76,4 +77,9 @@ public class TailRecursionDetector extends InstructionVisitorWithResult<Boolean>
public Boolean visitMagic(@NotNull MagicInstruction instruction) {
return instruction.getSynthetic();
}
@Override
public Boolean visitMerge(@NotNull MergeInstruction instruction) {
return true;
}
}
@@ -437,6 +437,14 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd
return instruction.getOutputValue();
}
@NotNull
@Override
public PseudoValue merge(@NotNull JetExpression expression, @NotNull List<PseudoValue> inputValues) {
MergeInstruction instruction = MergeInstruction.object$.create(expression, getCurrentScope(), inputValues, valueFactory);
add(instruction);
return instruction.getOutputValue();
}
@NotNull
@Override
public PseudoValue readThis(@NotNull JetExpression expression, @Nullable ReceiverParameterDescriptor parameterDescriptor) {
@@ -101,6 +101,10 @@ public open class InstructionVisitor() {
visitOperation(instruction)
}
public open fun visitMerge(instruction: MergeInstruction) {
visitOperation(instruction)
}
public open fun visitCompilationErrorInstruction(instruction: CompilationErrorInstruction) {
visitInstructionWithNext(instruction)
}
@@ -100,6 +100,10 @@ public abstract class InstructionVisitorWithResult<R>() {
return visitOperation(instruction)
}
public open fun visitMerge(instruction: MergeInstruction): R {
return visitOperation(instruction)
}
public open fun visitCompilationErrorInstruction(instruction: CompilationErrorInstruction): R {
return visitInstructionWithNext(instruction)
}
@@ -52,6 +52,11 @@ public abstract class OperationInstruction protected(
}
}
trait StrictlyValuedOperationInstruction: OperationInstruction {
override val outputValue: PseudoValue
get() = resultValue!!
}
public class CallInstruction private(
element: JetElement,
lexicalScope: LexicalScope,
@@ -95,16 +100,13 @@ public class CallInstruction private(
// denote value transformation which can't be expressed by other instructions (such as call or read)
// pass more than one value to instruction which formally requires only one (e.g. jump)
// "Synthetic" means that the instruction does not correspond to some operation explicitly expressed by PSI element
// Examples: merging branches of 'if', 'when' and 'try' expressions, providing initial values for parameters, etc.
// Examples: providing initial values for parameters, missing right-hand side in assignments
public class MagicInstruction(
element: JetElement,
lexicalScope: LexicalScope,
val synthetic: Boolean,
inputValues: List<PseudoValue>
) : OperationInstruction(element, lexicalScope, inputValues) {
override val outputValue: PseudoValue
get() = resultValue!!
) : OperationInstruction(element, lexicalScope, inputValues), StrictlyValuedOperationInstruction {
override fun accept(visitor: InstructionVisitor) {
visitor.visitMagic(this)
}
@@ -128,4 +130,33 @@ public class MagicInstruction(
factory: PseudoValueFactory
): MagicInstruction = MagicInstruction(element, lexicalScope, synthetic, inputValues).setResult(factory, valueElement) as MagicInstruction
}
}
// Merges values produced by alternative control-flow paths (such as 'if' branches)
class MergeInstruction private(
element: JetElement,
lexicalScope: LexicalScope,
inputValues: List<PseudoValue>
): OperationInstruction(element, lexicalScope, inputValues), StrictlyValuedOperationInstruction {
override fun accept(visitor: InstructionVisitor) {
visitor.visitMerge(this)
}
override fun <R> accept(visitor: InstructionVisitorWithResult<R>): R {
return visitor.visitMerge(this)
}
override fun createCopy() =
MergeInstruction(element, lexicalScope, inputValues).setResult(resultValue)
override fun toString() = renderInstruction("merge", render(element))
class object {
fun create(
element: JetElement,
lexicalScope: LexicalScope,
inputValues: List<PseudoValue>,
factory: PseudoValueFactory
): MergeInstruction = MergeInstruction(element, lexicalScope, inputValues).setResult(factory) as MergeInstruction
}
}
@@ -110,7 +110,7 @@ L6 [skipFinallyToErrorBlock]:
3 mark({ return 1 }) PREV:[jmp(L6 [skipFinallyToErrorBlock])]
r(1) -> <v5>
ret(*|<v5>) L1 NEXT:[<END>]
- 2 magic(try { doSmth() } catch (e: NullPointerException) { doSmth1() } catch (e: Exception) { doSmth2() } finally { return 1 }|<v0>, <v2>, <v4>) -> <v6> PREV:[]
- 2 merge(try { doSmth() } catch (e: NullPointerException) { doSmth1() } catch (e: Exception) { doSmth2() } finally { return 1 }|<v0>, <v2>, <v4>) -> <v6> PREV:[]
L1:
1 <END> NEXT:[<SINK>] PREV:[ret(*|<v5>) L1, ret(*|<v5>) L1]
error:
@@ -195,9 +195,9 @@ L10 [skipFinallyToErrorBlock]:
call(cond, cond) -> <v6>
jf(copy L12|<v6>) NEXT:[jmp(L2 [loop entry point]), ret L1]
ret L1 NEXT:[<END>]
- jmp(copy L13) NEXT:[magic(try { doSmth() } catch (e: NullPointerException) { doSmth1() } catch (e: Exception) { doSmth2() } finally { if (cond()) return else continue }|<v1>, <v3>, <v5>) -> <v7>] PREV:[]
- jmp(copy L13) NEXT:[merge(try { doSmth() } catch (e: NullPointerException) { doSmth1() } catch (e: Exception) { doSmth2() } finally { if (cond()) return else continue }|<v1>, <v3>, <v5>) -> <v7>] PREV:[]
jmp(L2 [loop entry point]) NEXT:[mark(cond())] PREV:[jf(copy L12|<v6>)]
- 3 magic(try { doSmth() } catch (e: NullPointerException) { doSmth1() } catch (e: Exception) { doSmth2() } finally { if (cond()) return else continue }|<v1>, <v3>, <v5>) -> <v7> PREV:[]
- 3 merge(try { doSmth() } catch (e: NullPointerException) { doSmth1() } catch (e: Exception) { doSmth2() } finally { if (cond()) return else continue }|<v1>, <v3>, <v5>) -> <v7> PREV:[]
- 2 jmp(L2 [loop entry point]) NEXT:[mark(cond())] PREV:[]
L3 [loop exit point]:
read (Unit) PREV:[jf(L3 [loop exit point]|<v0>)]
@@ -276,7 +276,7 @@ L6 [skipFinallyToErrorBlock]:
jf(copy L9 [loop exit point]|<v5>) NEXT:[read (Unit), jmp(copy L8 [loop entry point])]
jmp(copy L8 [loop entry point]) NEXT:[mark(cond())]
read (Unit) PREV:[jf(copy L9 [loop exit point]|<v5>)]
2 magic(try { doSmth() } catch (e: NullPointerException) { doSmth1() } catch (e: Exception) { doSmth2() } finally { while (cond()); }|<v0>, <v2>, <v4>) -> <v6>
2 merge(try { doSmth() } catch (e: NullPointerException) { doSmth1() } catch (e: Exception) { doSmth2() } finally { while (cond()); }|<v0>, <v2>, <v4>) -> <v6>
L1:
1 <END> NEXT:[<SINK>]
error:
@@ -46,11 +46,11 @@ L0:
r(true) -> <v5>
jf(L2|<v5>) NEXT:[r(2) -> <v7>, r(1) -> <v6>]
r(1) -> <v6>
jmp(L3) NEXT:[magic(if (true) 1 else 2|<v6>, <v7>) -> <v8>]
jmp(L3) NEXT:[merge(if (true) 1 else 2|<v6>, <v7>) -> <v8>]
L2:
r(2) -> <v7> PREV:[jf(L2|<v5>)]
L3:
magic(if (true) 1 else 2|<v6>, <v7>) -> <v8> PREV:[jmp(L3), r(2) -> <v7>]
merge(if (true) 1 else 2|<v6>, <v7>) -> <v8> PREV:[jmp(L3), r(2) -> <v7>]
w(x|<v8>)
v(val y = true && false)
r(true) -> <v9>
@@ -31,12 +31,12 @@ L0:
jf(L2|<v2>) NEXT:[mark({ 2 }), mark({ 1 })]
3 mark({ 1 })
r(1) -> <v3>
2 jmp(L3) NEXT:[magic(if (a) { 1 } else { 2 }|<v3>, <v4>) -> <v5>]
2 jmp(L3) NEXT:[merge(if (a) { 1 } else { 2 }|<v3>, <v4>) -> <v5>]
L2:
3 mark({ 2 }) PREV:[jf(L2|<v2>)]
r(2) -> <v4>
L3:
2 magic(if (a) { 1 } else { 2 }|<v3>, <v4>) -> <v5> PREV:[jmp(L3), r(2) -> <v4>]
2 merge(if (a) { 1 } else { 2 }|<v3>, <v4>) -> <v5> PREV:[jmp(L3), r(2) -> <v4>]
r(3) -> <v6>
mark(if (a && b) 5 else 6)
r(a) -> <v7>
@@ -45,11 +45,11 @@ L3:
L4:
jf(L5) NEXT:[r(6) -> <v10>, r(5) -> <v9>] PREV:[jf(L4|<v7>), r(b) -> <v8>]
r(5) -> <v9>
jmp(L6) NEXT:[magic(if (a && b) 5 else 6|<v9>, <v10>) -> <v11>]
jmp(L6) NEXT:[merge(if (a && b) 5 else 6|<v9>, <v10>) -> <v11>]
L5:
r(6) -> <v10> PREV:[jf(L5)]
L6:
magic(if (a && b) 5 else 6|<v9>, <v10>) -> <v11> PREV:[jmp(L6), r(6) -> <v10>]
merge(if (a && b) 5 else 6|<v9>, <v10>) -> <v11> PREV:[jmp(L6), r(6) -> <v10>]
r(7) -> <v12>
mark(if (a || b) 8 else 9)
r(a) -> <v13>
@@ -58,11 +58,11 @@ L6:
L7:
jf(L8) NEXT:[r(9) -> <v16>, r(8) -> <v15>] PREV:[jt(L7|<v13>), r(b) -> <v14>]
r(8) -> <v15>
jmp(L9) NEXT:[magic(if (a || b) 8 else 9|<v15>, <v16>) -> <v17>]
jmp(L9) NEXT:[merge(if (a || b) 8 else 9|<v15>, <v16>) -> <v17>]
L8:
r(9) -> <v16> PREV:[jf(L8)]
L9:
magic(if (a || b) 8 else 9|<v15>, <v16>) -> <v17> PREV:[jmp(L9), r(9) -> <v16>]
merge(if (a || b) 8 else 9|<v15>, <v16>) -> <v17> PREV:[jmp(L9), r(9) -> <v16>]
r(10) -> <v18>
mark(if (a) 11)
r(a) -> <v19>
@@ -40,7 +40,7 @@ L5 [skipFinallyToErrorBlock]:
3 mark({ test() }) PREV:[jmp(L5 [skipFinallyToErrorBlock])]
mark(test())
call(test, test) -> <v3>
2 magic(try { test() } catch (any : Exception) { test() } finally { test() }|<v0>, <v2>) -> <v4>
2 merge(try { test() } catch (any : Exception) { test() } finally { test() }|<v0>, <v2>) -> <v4>
L1:
1 <END> NEXT:[<SINK>]
error: