Restore one-pass LIR->IR conversion.
Bug: b/225838009
Change-Id: Iebcd0b7fb54c97af3484576e0fd2252a6bff82ed
diff --git a/src/main/java/com/android/tools/r8/lightir/IR2LIRConverter.java b/src/main/java/com/android/tools/r8/lightir/IR2LIRConverter.java
index 9908098..77533c9 100644
--- a/src/main/java/com/android/tools/r8/lightir/IR2LIRConverter.java
+++ b/src/main/java/com/android/tools/r8/lightir/IR2LIRConverter.java
@@ -71,7 +71,16 @@
while (it.hasNext()) {
Instruction instruction = it.next();
builder.setCurrentPosition(instruction.getPosition());
- instruction.buildLIR(builder);
+ if (instruction.isGoto()) {
+ BasicBlock nextBlock = blockIt.peekNext();
+ if (instruction.asGoto().getTarget() == nextBlock) {
+ builder.addFallthrough();
+ } else {
+ instruction.buildLIR(builder);
+ }
+ } else {
+ instruction.buildLIR(builder);
+ }
}
}
return builder.build();
diff --git a/src/main/java/com/android/tools/r8/lightir/LIR2IRConverter.java b/src/main/java/com/android/tools/r8/lightir/LIR2IRConverter.java
index efccdb9..a726649 100644
--- a/src/main/java/com/android/tools/r8/lightir/LIR2IRConverter.java
+++ b/src/main/java/com/android/tools/r8/lightir/LIR2IRConverter.java
@@ -48,7 +48,6 @@
public static IRCode translate(ProgramMethod method, LIRCode lirCode, AppView<?> appView) {
Parser parser = new Parser(lirCode, method.getReference(), appView);
- parser.computeControlFlowGraph();
parser.parseArguments(method);
lirCode.forEach(view -> view.accept(parser));
return parser.getIRCode(method);
@@ -93,12 +92,13 @@
}
private void ensureCurrentBlock() {
- BasicBlock nextBlock = blocks.get(nextInstructionIndex);
- if (nextBlock != null) {
- assert currentBlock != nextBlock;
- currentBlock = nextBlock;
+ // Control instructions must close the block, thus the current block is null iff the
+ // instruction denotes a new block.
+ if (currentBlock == null) {
+ currentBlock = blocks.computeIfAbsent(nextInstructionIndex, k -> new BasicBlock());
+ } else {
+ assert !blocks.containsKey(nextInstructionIndex);
}
- assert currentBlock != null;
}
private void ensureCurrentPosition() {
@@ -116,34 +116,8 @@
: null;
}
- public void computeControlFlowGraph() {
- // TODO(b/225838009): Since each basic block has a terminal instruction we can compute block
- // structure lazily while iterating the instructions and avoid this additional pass.
- // Always create an entry block as it cannot be targeted from code.
- blocks.put(ENTRY_BLOCK_INDEX, createBlock());
- for (LIRInstructionView view : code) {
- int opcode = view.getOpcode();
- if (LIROpcodes.isControlFlowInstruction(opcode)) {
- // TODO(b/225838009): Deal with multi-target instructions.
- int target = view.getNextBlockOperand();
- blocks.computeIfAbsent(target, k -> createBlock());
- if (LIROpcodes.isControlFlowInstructionWithFallthrough(opcode)) {
- blocks.computeIfAbsent(view.getInstructionIndex() + 1, k -> createBlock());
- }
- }
- }
- }
-
- public BasicBlock createBlock() {
- BasicBlock block = new BasicBlock();
- block.setNumber(basicBlockNumberGenerator.next());
- // The LIR is in SSA with accurate phis. The blocks are thus filled by construction.
- block.setFilled();
- return block;
- }
-
public void parseArguments(ProgramMethod method) {
- currentBlock = blocks.get(ENTRY_BLOCK_INDEX);
+ currentBlock = getBasicBlock(ENTRY_BLOCK_INDEX);
boolean hasReceiverArgument = !method.getDefinition().isStatic();
assert code.getArgumentCount()
== method.getParameters().size() + (hasReceiverArgument ? 1 : 0);
@@ -159,13 +133,13 @@
}
public IRCode getIRCode(ProgramMethod method) {
- // TODO(b/225838009): Support control flow.
- currentBlock.setFilled();
LinkedList<BasicBlock> blockList = new LinkedList<>();
IntList blockIndices = new IntArrayList(blocks.keySet());
blockIndices.sort(Integer::compare);
for (int i = 0; i < blockIndices.size(); i++) {
- blockList.add(blocks.get(blockIndices.getInt(i)));
+ BasicBlock block = blocks.get(blockIndices.getInt(i));
+ block.setFilled();
+ blockList.add(block);
}
return new IRCode(
appView.options(),
@@ -180,9 +154,13 @@
}
public BasicBlock getBasicBlock(int instructionIndex) {
- BasicBlock block = blocks.get(instructionIndex);
- assert block != null;
- return block;
+ return blocks.computeIfAbsent(
+ instructionIndex,
+ k -> {
+ BasicBlock block = new BasicBlock();
+ block.setNumber(basicBlockNumberGenerator.next());
+ return block;
+ });
}
public Value getValue(int index) {
@@ -301,6 +279,12 @@
}
@Override
+ public void onFallthrough() {
+ int nextBlockIndex = peekNextInstructionIndex() + 1;
+ onGoto(nextBlockIndex);
+ }
+
+ @Override
public void onGoto(int blockIndex) {
BasicBlock targetBlock = getBasicBlock(blockIndex);
addInstruction(new Goto());
@@ -341,6 +325,7 @@
@Override
public void onReturnVoid() {
addInstruction(new Return());
+ closeCurrentBlock();
}
@Override
diff --git a/src/main/java/com/android/tools/r8/lightir/LIRBuilder.java b/src/main/java/com/android/tools/r8/lightir/LIRBuilder.java
index 409f02e..927d3bf 100644
--- a/src/main/java/com/android/tools/r8/lightir/LIRBuilder.java
+++ b/src/main/java/com/android/tools/r8/lightir/LIRBuilder.java
@@ -241,6 +241,10 @@
return addNoOperandInstruction(LIROpcodes.DEBUGPOS);
}
+ public void addFallthrough() {
+ addNoOperandInstruction(LIROpcodes.FALLTHROUGH);
+ }
+
public LIRBuilder<V, B> addGoto(B target) {
int targetIndex = getBlockIndex(target);
int operandSize = blockIndexSize(targetIndex);
diff --git a/src/main/java/com/android/tools/r8/lightir/LIROpcodes.java b/src/main/java/com/android/tools/r8/lightir/LIROpcodes.java
index 7e0c520..5e9235f 100644
--- a/src/main/java/com/android/tools/r8/lightir/LIROpcodes.java
+++ b/src/main/java/com/android/tools/r8/lightir/LIROpcodes.java
@@ -14,26 +14,7 @@
static boolean isOneByteInstruction(int opcode) {
assert opcode >= ACONST_NULL;
- return opcode <= DCONST_1 || opcode == RETURN || opcode == DEBUGPOS;
- }
-
- static boolean isControlFlowInstruction(int opcode) {
- return opcode == GOTO || isControlFlowInstructionWithFallthrough(opcode);
- }
-
- static boolean isControlFlowInstructionWithFallthrough(int opcode) {
- switch (opcode) {
- case IFEQ:
- case IFNE:
- case IFLT:
- case IFGE:
- case IFGT:
- case IFLE:
- // TODO(b/225838009): put in the rest!
- return true;
- default:
- return false;
- }
+ return opcode <= DCONST_1 || opcode == RETURN || opcode == DEBUGPOS || opcode == FALLTHROUGH;
}
// Instructions maintaining the same opcode as defined in CF.
@@ -203,6 +184,7 @@
int INVOKEDIRECT = 204;
int DEBUGPOS = 205;
int PHI = 206;
+ int FALLTHROUGH = 207;
static String toString(int opcode) {
switch (opcode) {
@@ -511,6 +493,8 @@
return "DEBUGPOS";
case PHI:
return "PHI";
+ case FALLTHROUGH:
+ return "FALLTHROUGH";
default:
throw new Unreachable("Unexpected LIR opcode: " + opcode);
diff --git a/src/main/java/com/android/tools/r8/lightir/LIRParsedInstructionCallback.java b/src/main/java/com/android/tools/r8/lightir/LIRParsedInstructionCallback.java
index 8f32cf5..ed822c9 100644
--- a/src/main/java/com/android/tools/r8/lightir/LIRParsedInstructionCallback.java
+++ b/src/main/java/com/android/tools/r8/lightir/LIRParsedInstructionCallback.java
@@ -40,6 +40,8 @@
public void onGoto(int blockIndex) {}
+ public void onFallthrough() {}
+
public void onInvokeMethodInstruction(DexMethod method, IntList arguments) {}
public void onInvokeDirect(DexMethod method, IntList arguments) {
@@ -144,6 +146,11 @@
onPhi(type, operands);
break;
}
+ case LIROpcodes.FALLTHROUGH:
+ {
+ onFallthrough();
+ break;
+ }
default:
throw new Unimplemented("No dispatch for opcode " + LIROpcodes.toString(view.getOpcode()));
}