Fix null check elimination
The existing null check elimination mechanism suffered from the same
limitation as the SSA renaming: it took shortcuts that were valid in
a trace compilation world, but not in a method compilation world.
This CL replaces the old mechanism, and additionally takes advantage
of some the fact that "this" is always non-null, as are objects returned
from OP_NEW_* (thanks Ian!).
Two test cases added. The one for ensuring that unnecessary null checks
are elminated requires manual inspection. The other - that we don't
eliminate a necessary null check - is disabled until exceptions are working.
Change-Id: I2a9b72741f56617bf609e4d7c20244796c988f28
diff --git a/src/compiler/CompilerIR.h b/src/compiler/CompilerIR.h
index e2418b8..e25acd9 100644
--- a/src/compiler/CompilerIR.h
+++ b/src/compiler/CompilerIR.h
@@ -111,7 +111,7 @@
struct MIR* prev;
struct MIR* next;
struct SSARepresentation* ssaRep;
- int OptimizationFlags;
+ int optimizationFlags;
int seqNum;
union {
// Used by the inlined insn from the callee to find the mother method
@@ -135,6 +135,7 @@
int id;
bool visited;
bool hidden;
+ bool catchEntry;
unsigned int startOffset;
const Method* containingMethod; // For blocks from the callee
BBType blockType;
diff --git a/src/compiler/Dataflow.cc b/src/compiler/Dataflow.cc
index 3369e9e..827470e 100644
--- a/src/compiler/Dataflow.cc
+++ b/src/compiler/Dataflow.cc
@@ -50,13 +50,13 @@
DF_DA_WIDE | DF_UB_WIDE | DF_IS_MOVE,
// 07 OP_MOVE_OBJECT vA, vB
- DF_DA | DF_UB | DF_IS_MOVE,
+ DF_DA | DF_UB | DF_NULL_TRANSFER_0 | DF_IS_MOVE,
// 08 OP_MOVE_OBJECT_FROM16 vAA, vBBBB
- DF_DA | DF_UB | DF_IS_MOVE,
+ DF_DA | DF_UB | DF_NULL_TRANSFER_0 | DF_IS_MOVE,
// 09 OP_MOVE_OBJECT_16 vAAAA, vBBBB
- DF_DA | DF_UB | DF_IS_MOVE,
+ DF_DA | DF_UB | DF_NULL_TRANSFER_0 | DF_IS_MOVE,
// 0A OP_MOVE_RESULT vAA
DF_DA,
@@ -116,31 +116,31 @@
DF_DA,
// 1D OP_MONITOR_ENTER vAA
- DF_UA,
+ DF_UA | DF_NULL_CHK_0,
// 1E OP_MONITOR_EXIT vAA
- DF_UA,
+ DF_UA | DF_NULL_CHK_0,
- // 1F OP_CHECK_CAST vAA, type@BBBB
+ // 1F OP_CHK_CAST vAA, type@BBBB
DF_UA,
// 20 OP_INSTANCE_OF vA, vB, type@CCCC
DF_DA | DF_UB,
// 21 OP_ARRAY_LENGTH vA, vB
- DF_DA | DF_UB,
+ DF_DA | DF_UB | DF_NULL_CHK_0,
// 22 OP_NEW_INSTANCE vAA, type@BBBB
- DF_DA,
+ DF_DA | DF_NON_NULL_DST,
// 23 OP_NEW_ARRAY vA, vB, type@CCCC
- DF_DA | DF_UB,
+ DF_DA | DF_UB | DF_NON_NULL_DST,
// 24 OP_FILLED_NEW_ARRAY {vD, vE, vF, vG, vA}
- DF_FORMAT_35C,
+ DF_FORMAT_35C | DF_NON_NULL_RET,
// 25 OP_FILLED_NEW_ARRAY_RANGE {vCCCC .. vNNNN}, type@BBBB
- DF_FORMAT_3RC,
+ DF_FORMAT_3RC | DF_NON_NULL_RET,
// 26 OP_FILL_ARRAY_DATA vAA, +BBBBBBBB
DF_UA,
@@ -234,88 +234,88 @@
DF_NOP,
// 44 OP_AGET vAA, vBB, vCC
- DF_DA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_0 | DF_IS_GETTER,
+ DF_DA | DF_UB | DF_UC | DF_NULL_CHK_0 | DF_RANGE_CHK_1 | DF_IS_GETTER,
// 45 OP_AGET_WIDE vAA, vBB, vCC
- DF_DA_WIDE | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_0 | DF_IS_GETTER,
+ DF_DA_WIDE | DF_UB | DF_UC | DF_NULL_CHK_0 | DF_RANGE_CHK_1 | DF_IS_GETTER,
// 46 OP_AGET_OBJECT vAA, vBB, vCC
- DF_DA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_0 | DF_IS_GETTER,
+ DF_DA | DF_UB | DF_UC | DF_NULL_CHK_0 | DF_RANGE_CHK_1 | DF_IS_GETTER,
// 47 OP_AGET_BOOLEAN vAA, vBB, vCC
- DF_DA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_0 | DF_IS_GETTER,
+ DF_DA | DF_UB | DF_UC | DF_NULL_CHK_0 | DF_RANGE_CHK_1 | DF_IS_GETTER,
// 48 OP_AGET_BYTE vAA, vBB, vCC
- DF_DA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_0 | DF_IS_GETTER,
+ DF_DA | DF_UB | DF_UC | DF_NULL_CHK_0 | DF_RANGE_CHK_1 | DF_IS_GETTER,
// 49 OP_AGET_CHAR vAA, vBB, vCC
- DF_DA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_0 | DF_IS_GETTER,
+ DF_DA | DF_UB | DF_UC | DF_NULL_CHK_0 | DF_RANGE_CHK_1 | DF_IS_GETTER,
// 4A OP_AGET_SHORT vAA, vBB, vCC
- DF_DA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_0 | DF_IS_GETTER,
+ DF_DA | DF_UB | DF_UC | DF_NULL_CHK_0 | DF_RANGE_CHK_1 | DF_IS_GETTER,
// 4B OP_APUT vAA, vBB, vCC
- DF_UA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_1 | DF_IS_SETTER,
+ DF_UA | DF_UB | DF_UC | DF_NULL_CHK_1 | DF_RANGE_CHK_2 | DF_IS_SETTER,
// 4C OP_APUT_WIDE vAA, vBB, vCC
- DF_UA_WIDE | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_2 | DF_IS_SETTER,
+ DF_UA_WIDE | DF_UB | DF_UC | DF_NULL_CHK_1 | DF_RANGE_CHK_2 | DF_IS_SETTER,
// 4D OP_APUT_OBJECT vAA, vBB, vCC
- DF_UA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_1 | DF_IS_SETTER,
+ DF_UA | DF_UB | DF_UC | DF_NULL_CHK_1 | DF_RANGE_CHK_2 | DF_IS_SETTER,
// 4E OP_APUT_BOOLEAN vAA, vBB, vCC
- DF_UA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_1 | DF_IS_SETTER,
+ DF_UA | DF_UB | DF_UC | DF_NULL_CHK_1 | DF_RANGE_CHK_2 | DF_IS_SETTER,
// 4F OP_APUT_BYTE vAA, vBB, vCC
- DF_UA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_1 | DF_IS_SETTER,
+ DF_UA | DF_UB | DF_UC | DF_NULL_CHK_1 | DF_RANGE_CHK_2 | DF_IS_SETTER,
// 50 OP_APUT_CHAR vAA, vBB, vCC
- DF_UA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_1 | DF_IS_SETTER,
+ DF_UA | DF_UB | DF_UC | DF_NULL_CHK_1 | DF_RANGE_CHK_2 | DF_IS_SETTER,
// 51 OP_APUT_SHORT vAA, vBB, vCC
- DF_UA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_1 | DF_IS_SETTER,
+ DF_UA | DF_UB | DF_UC | DF_NULL_CHK_1 | DF_RANGE_CHK_2 | DF_IS_SETTER,
// 52 OP_IGET vA, vB, field@CCCC
- DF_DA | DF_UB | DF_IS_GETTER,
+ DF_DA | DF_UB | DF_NULL_CHK_0 | DF_IS_GETTER,
// 53 OP_IGET_WIDE vA, vB, field@CCCC
- DF_DA_WIDE | DF_UB | DF_IS_GETTER,
+ DF_DA_WIDE | DF_UB | DF_NULL_CHK_0 | DF_IS_GETTER,
// 54 OP_IGET_OBJECT vA, vB, field@CCCC
- DF_DA | DF_UB | DF_IS_GETTER,
+ DF_DA | DF_UB | DF_NULL_CHK_0 | DF_IS_GETTER,
// 55 OP_IGET_BOOLEAN vA, vB, field@CCCC
- DF_DA | DF_UB | DF_IS_GETTER,
+ DF_DA | DF_UB | DF_NULL_CHK_0 | DF_IS_GETTER,
// 56 OP_IGET_BYTE vA, vB, field@CCCC
- DF_DA | DF_UB | DF_IS_GETTER,
+ DF_DA | DF_UB | DF_NULL_CHK_0 | DF_IS_GETTER,
// 57 OP_IGET_CHAR vA, vB, field@CCCC
- DF_DA | DF_UB | DF_IS_GETTER,
+ DF_DA | DF_UB | DF_NULL_CHK_0 | DF_IS_GETTER,
// 58 OP_IGET_SHORT vA, vB, field@CCCC
- DF_DA | DF_UB | DF_IS_GETTER,
+ DF_DA | DF_UB | DF_NULL_CHK_0 | DF_IS_GETTER,
// 59 OP_IPUT vA, vB, field@CCCC
- DF_UA | DF_UB | DF_IS_SETTER,
+ DF_UA | DF_UB | DF_NULL_CHK_1 | DF_IS_SETTER,
// 5A OP_IPUT_WIDE vA, vB, field@CCCC
- DF_UA_WIDE | DF_UB | DF_IS_SETTER,
+ DF_UA_WIDE | DF_UB | DF_NULL_CHK_1 | DF_IS_SETTER,
// 5B OP_IPUT_OBJECT vA, vB, field@CCCC
- DF_UA | DF_UB | DF_IS_SETTER,
+ DF_UA | DF_UB | DF_NULL_CHK_1 | DF_IS_SETTER,
// 5C OP_IPUT_BOOLEAN vA, vB, field@CCCC
- DF_UA | DF_UB | DF_IS_SETTER,
+ DF_UA | DF_UB | DF_NULL_CHK_1 | DF_IS_SETTER,
// 5D OP_IPUT_BYTE vA, vB, field@CCCC
- DF_UA | DF_UB | DF_IS_SETTER,
+ DF_UA | DF_UB | DF_NULL_CHK_1 | DF_IS_SETTER,
// 5E OP_IPUT_CHAR vA, vB, field@CCCC
- DF_UA | DF_UB | DF_IS_SETTER,
+ DF_UA | DF_UB | DF_NULL_CHK_1 | DF_IS_SETTER,
// 5F OP_IPUT_SHORT vA, vB, field@CCCC
- DF_UA | DF_UB | DF_IS_SETTER,
+ DF_UA | DF_UB | DF_NULL_CHK_1 | DF_IS_SETTER,
// 60 OP_SGET vAA, field@BBBB
DF_DA | DF_IS_GETTER,
@@ -360,13 +360,13 @@
DF_UA | DF_IS_SETTER,
// 6E OP_INVOKE_VIRTUAL {vD, vE, vF, vG, vA}
- DF_FORMAT_35C,
+ DF_FORMAT_35C | DF_NULL_CHK_OUT0,
// 6F OP_INVOKE_SUPER {vD, vE, vF, vG, vA}
- DF_FORMAT_35C,
+ DF_FORMAT_35C | DF_NULL_CHK_OUT0,
// 70 OP_INVOKE_DIRECT {vD, vE, vF, vG, vA}
- DF_FORMAT_35C,
+ DF_FORMAT_35C | DF_NULL_CHK_OUT0,
// 71 OP_INVOKE_STATIC {vD, vE, vF, vG, vA}
DF_FORMAT_35C,
@@ -378,13 +378,13 @@
DF_NOP,
// 74 OP_INVOKE_VIRTUAL_RANGE {vCCCC .. vNNNN}
- DF_FORMAT_3RC,
+ DF_FORMAT_3RC | DF_NULL_CHK_OUT0,
// 75 OP_INVOKE_SUPER_RANGE {vCCCC .. vNNNN}
- DF_FORMAT_3RC,
+ DF_FORMAT_3RC | DF_NULL_CHK_OUT0,
// 76 OP_INVOKE_DIRECT_RANGE {vCCCC .. vNNNN}
- DF_FORMAT_3RC,
+ DF_FORMAT_3RC | DF_NULL_CHK_OUT0,
// 77 OP_INVOKE_STATIC_RANGE {vCCCC .. vNNNN}
DF_FORMAT_3RC,
@@ -711,10 +711,10 @@
DF_DA | DF_UB,
// E3 OP_IGET_VOLATILE
- DF_DA | DF_UB,
+ DF_DA | DF_UB | DF_NULL_CHK_0,
// E4 OP_IPUT_VOLATILE
- DF_UA | DF_UB,
+ DF_UA | DF_UB | DF_NULL_CHK_1,
// E5 OP_SGET_VOLATILE
DF_DA,
@@ -723,13 +723,13 @@
DF_UA,
// E7 OP_IGET_OBJECT_VOLATILE
- DF_DA | DF_UB,
+ DF_DA | DF_UB | DF_NULL_CHK_0,
// E8 OP_IGET_WIDE_VOLATILE
- DF_DA_WIDE | DF_UB,
+ DF_DA_WIDE | DF_UB | DF_NULL_CHK_0,
// E9 OP_IPUT_WIDE_VOLATILE
- DF_UA_WIDE | DF_UB,
+ DF_UA_WIDE | DF_UB | DF_NULL_CHK_1,
// EA OP_SGET_WIDE_VOLATILE
DF_DA_WIDE,
@@ -750,43 +750,43 @@
DF_FORMAT_3RC,
// F0 OP_INVOKE_OBJECT_INIT_RANGE
- DF_NOP,
+ DF_NOP | DF_NULL_CHK_0,
// F1 OP_RETURN_VOID_BARRIER
DF_NOP,
// F2 OP_IGET_QUICK
- DF_DA | DF_UB | DF_IS_GETTER,
+ DF_DA | DF_UB | DF_NULL_CHK_0 | DF_IS_GETTER,
// F3 OP_IGET_WIDE_QUICK
- DF_DA_WIDE | DF_UB | DF_IS_GETTER,
+ DF_DA_WIDE | DF_UB | DF_NULL_CHK_0 | DF_IS_GETTER,
// F4 OP_IGET_OBJECT_QUICK
- DF_DA | DF_UB | DF_IS_GETTER,
+ DF_DA | DF_UB | DF_NULL_CHK_0 | DF_IS_GETTER,
// F5 OP_IPUT_QUICK
- DF_UA | DF_UB | DF_IS_SETTER,
+ DF_UA | DF_UB | DF_NULL_CHK_1 | DF_IS_SETTER,
// F6 OP_IPUT_WIDE_QUICK
- DF_UA_WIDE | DF_UB | DF_IS_SETTER,
+ DF_UA_WIDE | DF_UB | DF_NULL_CHK_1 |DF_IS_SETTER,
// F7 OP_IPUT_OBJECT_QUICK
- DF_UA | DF_UB | DF_IS_SETTER,
+ DF_UA | DF_UB | DF_NULL_CHK_1 | DF_IS_SETTER,
// F8 OP_INVOKE_VIRTUAL_QUICK
- DF_FORMAT_35C,
+ DF_FORMAT_35C | DF_NULL_CHK_OUT0,
// F9 OP_INVOKE_VIRTUAL_QUICK_RANGE
- DF_FORMAT_3RC,
+ DF_FORMAT_3RC | DF_NULL_CHK_OUT0,
// FA OP_INVOKE_SUPER_QUICK
- DF_FORMAT_35C,
+ DF_FORMAT_35C | DF_NULL_CHK_OUT0,
// FB OP_INVOKE_SUPER_QUICK_RANGE
- DF_FORMAT_3RC,
+ DF_FORMAT_3RC | DF_NULL_CHK_OUT0,
// FC OP_IPUT_OBJECT_VOLATILE
- DF_UA | DF_UB,
+ DF_UA | DF_UB | DF_NULL_CHK_1,
// FD OP_SGET_OBJECT_VOLATILE
DF_DA,
@@ -797,65 +797,67 @@
// FF OP_DISPATCH_FF
DF_NOP,
+ //TODO: remove jumbo opcodes
+
// 100 OP_CONST_CLASS_JUMBO vAAAA, type@BBBBBBBB
DF_DA,
- // 101 OP_CHECK_CAST_JUMBO vAAAA, type@BBBBBBBB
+ // 101 OP_CHK_CAST_JUMBO vAAAA, type@BBBBBBBB
DF_UA,
// 102 OP_INSTANCE_OF_JUMBO vAAAA, vBBBB, type@CCCCCCCC
DF_DA | DF_UB,
// 103 OP_NEW_INSTANCE_JUMBO vAAAA, type@BBBBBBBB
- DF_DA,
+ DF_DA | DF_NON_NULL_DST,
// 104 OP_NEW_ARRAY_JUMBO vAAAA, vBBBB, type@CCCCCCCC
- DF_DA | DF_UB,
+ DF_DA | DF_UB | DF_NON_NULL_DST,
// 105 OP_FILLED_NEW_ARRAY_JUMBO {vCCCC .. vNNNN}, type@BBBBBBBB
- DF_FORMAT_3RC,
+ DF_FORMAT_3RC | DF_NON_NULL_RET,
// 106 OP_IGET_JUMBO vAAAA, vBBBB, field@CCCCCCCC
- DF_DA | DF_UB | DF_IS_GETTER,
+ DF_DA | DF_UB | DF_NULL_CHK_0 | DF_IS_GETTER,
// 107 OP_IGET_WIDE_JUMBO vAAAA, vBBBB, field@CCCCCCCC
- DF_DA_WIDE | DF_UB | DF_IS_GETTER,
+ DF_DA_WIDE | DF_UB | DF_NULL_CHK_0 | DF_IS_GETTER,
// 108 OP_IGET_OBJECT_JUMBO vAAAA, vBBBB, field@CCCCCCCC
- DF_DA | DF_UB | DF_IS_GETTER,
+ DF_DA | DF_UB | DF_NULL_CHK_0 | DF_IS_GETTER,
// 109 OP_IGET_BOOLEAN_JUMBO vAAAA, vBBBB, field@CCCCCCCC
- DF_DA | DF_UB | DF_IS_GETTER,
+ DF_DA | DF_UB | DF_NULL_CHK_0 | DF_IS_GETTER,
// 10A OP_IGET_BYTE_JUMBO vAAAA, vBBBB, field@CCCCCCCC
- DF_DA | DF_UB | DF_IS_GETTER,
+ DF_DA | DF_UB | DF_NULL_CHK_0 | DF_IS_GETTER,
// 10B OP_IGET_CHAR_JUMBO vAAAA, vBBBB, field@CCCCCCCC
- DF_DA | DF_UB | DF_IS_GETTER,
+ DF_DA | DF_UB | DF_NULL_CHK_0 | DF_IS_GETTER,
// 10C OP_IGET_SHORT_JUMBO vAAAA, vBBBB, field@CCCCCCCC
- DF_DA | DF_UB | DF_IS_GETTER,
+ DF_DA | DF_UB | DF_NULL_CHK_0 | DF_IS_GETTER,
// 10D OP_IPUT_JUMBO vAAAA, vBBBB, field@CCCCCCCC
- DF_UA | DF_UB | DF_IS_SETTER,
+ DF_UA | DF_UB | DF_NULL_CHK_1 | DF_IS_SETTER,
// 10E OP_IPUT_WIDE_JUMBO vAAAA, vBBBB, field@CCCCCCCC
- DF_UA_WIDE | DF_UB | DF_IS_SETTER,
+ DF_UA_WIDE | DF_UB | DF_NULL_CHK_1 | DF_IS_SETTER,
// 10F OP_IPUT_OBJECT_JUMBO vAAAA, vBBBB, field@CCCCCCCC
- DF_UA | DF_UB | DF_IS_SETTER,
+ DF_UA | DF_UB | DF_NULL_CHK_1 | DF_IS_SETTER,
// 110 OP_IPUT_BOOLEAN_JUMBO vAAAA, vBBBB, field@CCCCCCCC
- DF_UA | DF_UB | DF_IS_SETTER,
+ DF_UA | DF_UB | DF_NULL_CHK_1 | DF_IS_SETTER,
// 111 OP_IPUT_BYTE_JUMBO vAAAA, vBBBB, field@CCCCCCCC
- DF_UA | DF_UB | DF_IS_SETTER,
+ DF_UA | DF_UB | DF_NULL_CHK_1 | DF_IS_SETTER,
// 112 OP_IPUT_CHAR_JUMBO vAAAA, vBBBB, field@CCCCCCCC
- DF_UA | DF_UB | DF_IS_SETTER,
+ DF_UA | DF_UB | DF_NULL_CHK_1 | DF_IS_SETTER,
// 113 OP_IPUT_SHORT_JUMBO vAAAA, vBBBB, field@CCCCCCCC
- DF_UA | DF_UB | DF_IS_SETTER,
+ DF_UA | DF_UB | DF_NULL_CHK_1 | DF_IS_SETTER,
// 114 OP_SGET_JUMBO vAAAA, vBBBB, field@CCCCCCCC
DF_DA | DF_IS_GETTER,
@@ -900,13 +902,13 @@
DF_UA | DF_IS_SETTER,
// 122 OP_INVOKE_VIRTUAL_JUMBO {vCCCC .. vNNNN}, meth@BBBBBBBB
- DF_FORMAT_3RC,
+ DF_FORMAT_3RC | DF_NULL_CHK_OUT0,
// 123 OP_INVOKE_SUPER_JUMBO {vCCCC .. vNNNN}, meth@BBBBBBBB
- DF_FORMAT_3RC,
+ DF_FORMAT_3RC | DF_NULL_CHK_OUT0,
// 124 OP_INVOKE_DIRECT_JUMBO {vCCCC .. vNNNN}, meth@BBBBBBBB
- DF_FORMAT_3RC,
+ DF_FORMAT_3RC | DF_NULL_CHK_OUT0,
// 125 OP_INVOKE_STATIC_JUMBO {vCCCC .. vNNNN}, meth@BBBBBBBB
DF_FORMAT_3RC,
@@ -1524,25 +1526,25 @@
DF_NOP,
// 1F2 OP_INVOKE_OBJECT_INIT_JUMBO
- DF_NOP,
+ DF_NOP | DF_NULL_CHK_0,
// 1F3 OP_IGET_VOLATILE_JUMBO
- DF_DA | DF_UB,
+ DF_DA | DF_UB | DF_NULL_CHK_0,
// 1F4 OP_IGET_WIDE_VOLATILE_JUMBO
- DF_DA_WIDE | DF_UB,
+ DF_DA_WIDE | DF_UB | DF_NULL_CHK_0,
// 1F5 OP_IGET_OBJECT_VOLATILE_JUMBO
- DF_DA | DF_UB,
+ DF_DA | DF_UB | DF_NULL_CHK_0,
// 1F6 OP_IPUT_VOLATILE_JUMBO
- DF_UA | DF_UB,
+ DF_UA | DF_UB | DF_NULL_CHK_1,
// 1F7 OP_IPUT_WIDE_VOLATILE_JUMBO
- DF_UA_WIDE | DF_UB,
+ DF_UA_WIDE | DF_UB | DF_NULL_CHK_1,
// 1F8 OP_IPUT_OBJECT_VOLATILE_JUMBO
- DF_UA | DF_UB,
+ DF_UA | DF_UB | DF_NULL_CHK_1,
// 1F9 OP_SGET_VOLATILE_JUMBO
DF_DA,
@@ -1567,7 +1569,7 @@
// Beginning of extended MIR opcodes
// 200 OP_MIR_PHI
- DF_PHI | DF_DA,
+ DF_PHI | DF_DA | DF_NULL_TRANSFER_N,
/*
* For extended MIR inserted at the MIR2LIR stage, it is okay to have
* undefined values here.
@@ -2357,3 +2359,140 @@
change &= isIterative;
}
}
+
+static bool nullCheckEliminationInit(struct CompilationUnit* cUnit,
+ struct BasicBlock* bb)
+{
+ if (bb->dataFlowInfo == NULL) return false;
+ bb->dataFlowInfo->endingNullCheckV =
+ oatAllocBitVector(cUnit->numSSARegs, false);
+ oatClearAllBits(bb->dataFlowInfo->endingNullCheckV);
+ return true;
+}
+
+/* Eliminate unnecessary null checks for a basic block. */
+static bool eliminateNullChecks( struct CompilationUnit* cUnit,
+ struct BasicBlock* bb)
+{
+ if (bb->dataFlowInfo == NULL) return false;
+ /*
+ * Set initial state. Be conservative with catch
+ * blocks and start with no assumptions about null check
+ * status (except for "this").
+ */
+
+ if ((bb->blockType == kEntryBlock) | bb->catchEntry) {
+ oatClearAllBits(cUnit->tempSSARegisterV);
+ if (!cUnit->method->IsStatic()) {
+ // If non-static method, mark "this" as non-null
+ int thisReg = cUnit->method->NumRegisters() -
+ cUnit->method->NumIns();
+ oatSetBit(cUnit->tempSSARegisterV, thisReg);
+ }
+ } else {
+ // Starting state is intesection of all incoming arcs
+ GrowableList* blockList = &cUnit->blockList;
+ ArenaBitVectorIterator bvIterator;
+ oatBitVectorIteratorInit(bb->predecessors, &bvIterator);
+ int predBBIdx = oatBitVectorIteratorNext(&bvIterator);
+ DCHECK(predBBIdx != -1);
+ BasicBlock* predBB = (BasicBlock*)oatGrowableListGetElement(
+ blockList, predBBIdx);
+ oatCopyBitVector(cUnit->tempSSARegisterV,
+ predBB->dataFlowInfo->endingNullCheckV);
+ while (true) {
+ predBBIdx = oatBitVectorIteratorNext(&bvIterator);
+ if (predBBIdx == -1) break;
+ predBB = (BasicBlock*)oatGrowableListGetElement(
+ blockList, predBBIdx);
+ oatIntersectBitVectors(cUnit->tempSSARegisterV,
+ cUnit->tempSSARegisterV,
+ predBB->dataFlowInfo->endingNullCheckV);
+ }
+ }
+
+ // Walk through the instruction in the block, updating as necessary
+ for (MIR* mir = bb->firstMIRInsn; mir; mir = mir->next) {
+ if (mir->ssaRep == NULL) {
+ continue;
+ }
+ int dfAttributes =
+ oatDataFlowAttributes[mir->dalvikInsn.opcode];
+
+ // Mark target of NEW* as non-null
+ if (dfAttributes & DF_NON_NULL_DST) {
+ oatSetBit(cUnit->tempSSARegisterV, mir->ssaRep->defs[0]);
+ }
+
+ // Mark non-null returns from invoke-style NEW*
+ if (dfAttributes & DF_NON_NULL_RET) {
+ MIR* nextMir = mir->next;
+ // Next should be an OP_MOVE_RESULT_OBJECT
+ if (nextMir && nextMir->dalvikInsn.opcode == OP_MOVE_RESULT_OBJECT) {
+ // Mark as null checked
+ oatSetBit(cUnit->tempSSARegisterV, nextMir->ssaRep->uses[0]);
+ } else {
+ if (nextMir) {
+ LOG(WARNING) << "Unexpected opcode following new: " <<
+ (int)nextMir->dalvikInsn.opcode;
+ } else {
+ LOG(WARNING) << "Unexpected termination following new";
+ }
+ }
+ }
+
+ /*
+ * Propagate nullcheck state on register copies (including
+ * Phi pseudo copies. For the latter, nullcheck state is
+ * the "and" of all the Phi's operands.
+ */
+ if (dfAttributes & (DF_NULL_TRANSFER_0 | DF_NULL_TRANSFER_N)) {
+ int tgtSreg = mir->ssaRep->defs[0];
+ int operands = (dfAttributes & DF_NULL_TRANSFER_0) ? 1 :
+ mir->ssaRep->numUses;
+ bool nullChecked = true;
+ for (int i = 0; i < operands; i++) {
+ nullChecked &= oatIsBitSet(cUnit->tempSSARegisterV,
+ mir->ssaRep->uses[i]);
+ }
+ if (nullChecked) {
+ oatSetBit(cUnit->tempSSARegisterV, tgtSreg);
+ }
+ }
+
+ // Already nullchecked?
+ if (dfAttributes & DF_HAS_NULL_CHKS) {
+ int srcSreg = (dfAttributes & DF_NULL_CHK_1) ?
+ mir->ssaRep->uses[1] : mir->ssaRep->uses[0];
+ if (oatIsBitSet(cUnit->tempSSARegisterV, srcSreg)) {
+ // Eliminate the null check
+ mir->optimizationFlags |= MIR_IGNORE_NULL_CHECK;
+ } else {
+ // Mark sReg as null-checked
+ oatSetBit(cUnit->tempSSARegisterV, srcSreg);
+ }
+ }
+ }
+
+ // Did anything change?
+ bool res = oatCompareBitVectors(bb->dataFlowInfo->endingNullCheckV,
+ cUnit->tempSSARegisterV);
+ if (res) {
+ oatCopyBitVector(bb->dataFlowInfo->endingNullCheckV,
+ cUnit->tempSSARegisterV);
+ }
+ return res;
+}
+
+void oatMethodNullCheckElimination(CompilationUnit *cUnit)
+{
+ if (!(cUnit->disableOpt & (1 << kNullCheckElimination))) {
+ DCHECK(cUnit->tempSSARegisterV != NULL);
+ oatDataFlowAnalysisDispatcher(cUnit, nullCheckEliminationInit,
+ kAllNodes,
+ false /* isIterative */);
+ oatDataFlowAnalysisDispatcher(cUnit, eliminateNullChecks,
+ kPreOrderDFSTraversal,
+ true /* isIterative */);
+ }
+}
diff --git a/src/compiler/Dataflow.h b/src/compiler/Dataflow.h
index 235ad31..e4a3726 100644
--- a/src/compiler/Dataflow.h
+++ b/src/compiler/Dataflow.h
@@ -35,9 +35,15 @@
kFormat35c,
kFormat3rc,
kPhi,
- kNullNRangeCheck0,
- kNullNRangeCheck1,
- kNullNRangeCheck2,
+ kNullCheckSrc0, // Null check of src[0]
+ kNullCheckSrc1, // Null check of src[1]
+ kNullCheckOut0, // Null check out outgoing arg0
+ kDstNonNull, // May assume dst is non-null
+ kRetNonNull, // May assume retval is non-null
+ kNullTransferSrc0, // Object copy src[0] -> dst
+ kNullTransferSrcN, // Phi null check state transfer
+ kRangeCheckSrc1, // Range check of src[1]
+ kRangeCheckSrc2, // Range check of src[2]
kFPA,
kFPB,
kFPC,
@@ -60,9 +66,15 @@
#define DF_FORMAT_35C (1 << kFormat35c)
#define DF_FORMAT_3RC (1 << kFormat3rc)
#define DF_PHI (1 << kPhi)
-#define DF_NULL_N_RANGE_CHECK_0 (1 << kNullNRangeCheck0)
-#define DF_NULL_N_RANGE_CHECK_1 (1 << kNullNRangeCheck1)
-#define DF_NULL_N_RANGE_CHECK_2 (1 << kNullNRangeCheck2)
+#define DF_NULL_CHK_0 (1 << kNullCheckSrc0)
+#define DF_NULL_CHK_1 (1 << kNullCheckSrc1)
+#define DF_NULL_CHK_OUT0 (1 << kNullCheckOut0)
+#define DF_NON_NULL_DST (1 << kDstNonNull)
+#define DF_NON_NULL_RET (1 << kRetNonNull)
+#define DF_NULL_TRANSFER_0 (1 << kNullTransferSrc0)
+#define DF_NULL_TRANSFER_N (1 << kNullTransferSrcN)
+#define DF_RANGE_CHK_1 (1 << kRangeCheckSrc1)
+#define DF_RANGE_CHK_2 (1 << kRangeCheckSrc2)
#define DF_FP_A (1 << kFPA)
#define DF_FP_B (1 << kFPB)
#define DF_FP_C (1 << kFPC)
@@ -74,9 +86,13 @@
#define DF_HAS_DEFS (DF_DA | DF_DA_WIDE)
-#define DF_HAS_NR_CHECKS (DF_NULL_N_RANGE_CHECK_0 | \
- DF_NULL_N_RANGE_CHECK_1 | \
- DF_NULL_N_RANGE_CHECK_2)
+#define DF_HAS_NULL_CHKS (DF_NULL_CHK_0 | \
+ DF_NULL_CHK_1 | \
+ DF_NULL_CHK_OUT0)
+
+#define DF_HAS_NR_CHKS (DF_HAS_NULL_CHKS | \
+ DF_RANGE_CHK_1 | \
+ DF_RANGE_CHK_2)
#define DF_A_IS_REG (DF_UA | DF_UA_WIDE | DF_DA | DF_DA_WIDE)
#define DF_B_IS_REG (DF_UB | DF_UB_WIDE)
@@ -91,6 +107,7 @@
ArenaBitVector* liveInV;
ArenaBitVector* phiV;
int* dalvikToSSAMap;
+ ArenaBitVector* endingNullCheckV;
} BasicBlockDataFlow;
typedef struct SSARepresentation {
@@ -125,4 +142,7 @@
#define DECODE_REG(v) (v & 0xffff)
#define DECODE_SUB(v) (((unsigned int) v) >> 16)
+
+void oatMethodNullCheckElimination(CompilationUnit*);
+
#endif // ART_SRC_COMPILER_DATAFLOW_H_
diff --git a/src/compiler/Frontend.cc b/src/compiler/Frontend.cc
index c419f1a..086c0bb 100644
--- a/src/compiler/Frontend.cc
+++ b/src/compiler/Frontend.cc
@@ -619,6 +619,7 @@
BasicBlock *catchBlock = findBlock(cUnit, iterator.Get().address_,
false /* split*/,
false /* creat */);
+ catchBlock->catchEntry = true;
SuccessorBlockInfo *successorBlockInfo =
(SuccessorBlockInfo *) oatNew(sizeof(SuccessorBlockInfo),
false);
@@ -702,6 +703,7 @@
(1 << kLoadStoreElimination) |
(1 << kLoadHoisting) |
(1 << kSuppressLoads) |
+ (1 << kNullCheckElimination) |
(1 << kPromoteRegs) |
0;
#endif
@@ -841,6 +843,9 @@
/* Perform SSA transformation for the whole method */
oatMethodSSATransformation(&cUnit);
+ /* Perform null check elimination */
+ oatMethodNullCheckElimination(&cUnit);
+
oatInitializeRegAlloc(&cUnit); // Needs to happen after SSA naming
/* Allocate Registers using simple local allocation scheme */
diff --git a/src/compiler/codegen/CodegenFactory.cc b/src/compiler/codegen/CodegenFactory.cc
index 5a75cee..14c7e57 100644
--- a/src/compiler/codegen/CodegenFactory.cc
+++ b/src/compiler/codegen/CodegenFactory.cc
@@ -127,7 +127,6 @@
LIR* defEnd;
assert(!rlDest.wide);
assert(!rlSrc.wide);
- oatKillNullCheckedLoc(cUnit, rlDest);
rlSrc = oatUpdateLoc(cUnit, rlSrc);
rlDest = oatUpdateLoc(cUnit, rlDest);
if (rlSrc.location == kLocPhysReg) {
@@ -190,7 +189,6 @@
assert(FPREG(rlSrc.lowReg)==FPREG(rlSrc.highReg));
assert(rlDest.wide);
assert(rlSrc.wide);
- oatKillNullCheckedLoc(cUnit, rlDest);
if (rlSrc.location == kLocPhysReg) {
if (oatIsLive(cUnit, rlSrc.lowReg) ||
oatIsLive(cUnit, rlSrc.highReg) ||
diff --git a/src/compiler/codegen/Optimizer.h b/src/compiler/codegen/Optimizer.h
index b234587..23f0f17 100644
--- a/src/compiler/codegen/Optimizer.h
+++ b/src/compiler/codegen/Optimizer.h
@@ -27,6 +27,7 @@
kLoadStoreElimination = 0,
kLoadHoisting,
kSuppressLoads,
+ kNullCheckElimination,
kPromoteRegs,
};
diff --git a/src/compiler/codegen/Ralloc.h b/src/compiler/codegen/Ralloc.h
index 82ce23e..ad19475 100644
--- a/src/compiler/codegen/Ralloc.h
+++ b/src/compiler/codegen/Ralloc.h
@@ -45,12 +45,6 @@
return DECODE_REG(oatConvertSSARegToDalvik(cUnit, sReg));
}
-/* Reset the tracker to unknown state */
-static inline void oatResetNullCheck(CompilationUnit* cUnit)
-{
- oatClearAllBits(cUnit->regPool->nullCheckedRegs);
-}
-
/*
* Get the "real" sreg number associated with an sReg slot. In general,
* sReg values passed through codegen are the SSA names created by
@@ -161,10 +155,6 @@
extern void oatResetDefTracking(CompilationUnit* cUnit);
-/* Kill the corresponding bit in the null-checked register list */
-extern void oatKillNullCheckedLoc(CompilationUnit* cUnit,
- RegLocation loc);
-
extern RegisterInfo *oatIsLive(CompilationUnit* cUnit, int reg);
/* To be used when explicitly managing register use */
diff --git a/src/compiler/codegen/RallocUtil.cc b/src/compiler/codegen/RallocUtil.cc
index 8295b33..8b84500 100644
--- a/src/compiler/codegen/RallocUtil.cc
+++ b/src/compiler/codegen/RallocUtil.cc
@@ -1036,17 +1036,3 @@
assert(res.wide);
return res;
}
-
-/* Kill the corresponding bit in the null-checked register list */
-extern void oatKillNullCheckedLoc(CompilationUnit* cUnit,
- RegLocation loc)
-{
- if (loc.sRegLow == INVALID_SREG)
- return;
- oatClearBit(cUnit->regPool->nullCheckedRegs, loc.sRegLow);
- if (loc.wide) {
- assert(oatSRegHi(loc.sRegLow) != INVALID_SREG);
- oatClearBit(cUnit->regPool->nullCheckedRegs,
- oatSRegHi(loc.sRegLow));
- }
-}
diff --git a/src/compiler/codegen/arm/ArchFactory.cc b/src/compiler/codegen/arm/ArchFactory.cc
index 34a333d..8012d7d 100644
--- a/src/compiler/codegen/arm/ArchFactory.cc
+++ b/src/compiler/codegen/arm/ArchFactory.cc
@@ -70,19 +70,14 @@
return branch;
}
-/*
- * Perform null-check on a register. sReg is the ssa register being checked,
- * and mReg is the machine register holding the actual value. If internal state
- * indicates that sReg has been checked before the check request is ignored.
- */
+/* Perform null-check on a register. */
static ArmLIR* genNullCheck(CompilationUnit* cUnit, int sReg, int mReg,
MIR* mir)
{
- if (oatIsBitSet(cUnit->regPool->nullCheckedRegs, sReg)) {
- /* This particular Dalvik register has been null-checked */
+ if (!(cUnit->disableOpt & (1 << kNullCheckElimination)) &&
+ mir->optimizationFlags & MIR_IGNORE_NULL_CHECK) {
return NULL;
}
- oatSetBit(cUnit->regPool->nullCheckedRegs, sReg);
return genImmedCheck(cUnit, kArmCondEq, mReg, 0, mir, kArmThrowNullPointer);
}
diff --git a/src/compiler/codegen/arm/ArmLIR.h b/src/compiler/codegen/arm/ArmLIR.h
index 212358f..53e8dc8 100644
--- a/src/compiler/codegen/arm/ArmLIR.h
+++ b/src/compiler/codegen/arm/ArmLIR.h
@@ -149,7 +149,6 @@
} RegisterInfo;
typedef struct RegisterPool {
- ArenaBitVector *nullCheckedRegs; // Which registers have been null-checked?
int numCoreRegs;
RegisterInfo *coreRegs;
int nextCoreReg;
diff --git a/src/compiler/codegen/arm/MethodCodegenDriver.cc b/src/compiler/codegen/arm/MethodCodegenDriver.cc
index 10f470d..7196efc 100644
--- a/src/compiler/codegen/arm/MethodCodegenDriver.cc
+++ b/src/compiler/codegen/arm/MethodCodegenDriver.cc
@@ -681,7 +681,7 @@
break;
case 4: // Get ...->super_class_->vtable [u/s r0]
loadWordDisp(cUnit, r0, Class::VTableOffset().Int32Value(), r0);
- if (!(mir->OptimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
+ if (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
// Range check, throw NSM on failure
tReg = oatAllocTemp(cUnit);
loadWordDisp(cUnit, r0, art::Array::LengthOffset().Int32Value(),
@@ -1110,7 +1110,7 @@
break;
case OP_MOVE_RESULT_WIDE:
- if (mir->OptimizationFlags & MIR_INLINED)
+ if (mir->optimizationFlags & MIR_INLINED)
break; // Nop - combined w/ previous invoke
/*
* Somewhat hacky here. Because we're now passing
@@ -1130,7 +1130,7 @@
case OP_MOVE_RESULT:
case OP_MOVE_RESULT_OBJECT:
- if (mir->OptimizationFlags & MIR_INLINED)
+ if (mir->optimizationFlags & MIR_INLINED)
break; // Nop - combined w/ previous invoke
/* See comment for OP_MOVE_RESULT_WIDE */
assert(retLoc.lowReg == r0);
@@ -1420,55 +1420,55 @@
case OP_IGET_WIDE:
case OP_IGET_WIDE_VOLATILE:
- genIGetWideX(cUnit, mir, rlDest, rlSrc[0]);
+ genIGetWide(cUnit, mir, rlDest, rlSrc[0]);
break;
case OP_IGET:
case OP_IGET_VOLATILE:
case OP_IGET_OBJECT:
case OP_IGET_OBJECT_VOLATILE:
- genIGetX(cUnit, mir, kWord, rlDest, rlSrc[0]);
+ genIGet(cUnit, mir, kWord, rlDest, rlSrc[0]);
break;
case OP_IGET_BOOLEAN:
case OP_IGET_BYTE:
- genIGetX(cUnit, mir, kUnsignedByte, rlDest, rlSrc[0]);
+ genIGet(cUnit, mir, kUnsignedByte, rlDest, rlSrc[0]);
break;
case OP_IGET_CHAR:
- genIGetX(cUnit, mir, kUnsignedHalf, rlDest, rlSrc[0]);
+ genIGet(cUnit, mir, kUnsignedHalf, rlDest, rlSrc[0]);
break;
case OP_IGET_SHORT:
- genIGetX(cUnit, mir, kSignedHalf, rlDest, rlSrc[0]);
+ genIGet(cUnit, mir, kSignedHalf, rlDest, rlSrc[0]);
break;
case OP_IPUT_WIDE:
case OP_IPUT_WIDE_VOLATILE:
- genIPutWideX(cUnit, mir, rlSrc[0], rlSrc[1]);
+ genIPutWide(cUnit, mir, rlSrc[0], rlSrc[1]);
break;
case OP_IPUT_OBJECT:
case OP_IPUT_OBJECT_VOLATILE:
- genIPutX(cUnit, mir, kWord, rlSrc[0], rlSrc[1], true);
+ genIPut(cUnit, mir, kWord, rlSrc[0], rlSrc[1], true);
break;
case OP_IPUT:
case OP_IPUT_VOLATILE:
- genIPutX(cUnit, mir, kWord, rlSrc[0], rlSrc[1], false);
+ genIPut(cUnit, mir, kWord, rlSrc[0], rlSrc[1], false);
break;
case OP_IPUT_BOOLEAN:
case OP_IPUT_BYTE:
- genIPutX(cUnit, mir, kUnsignedByte, rlSrc[0], rlSrc[1], false);
+ genIPut(cUnit, mir, kUnsignedByte, rlSrc[0], rlSrc[1], false);
break;
case OP_IPUT_CHAR:
- genIPutX(cUnit, mir, kUnsignedHalf, rlSrc[0], rlSrc[1], false);
+ genIPut(cUnit, mir, kUnsignedHalf, rlSrc[0], rlSrc[1], false);
break;
case OP_IPUT_SHORT:
- genIPutX(cUnit, mir, kSignedHalf, rlSrc[0], rlSrc[1], false);
+ genIPut(cUnit, mir, kSignedHalf, rlSrc[0], rlSrc[1], false);
break;
case OP_SGET:
@@ -1805,7 +1805,6 @@
oatAppendLIR(cUnit, (LIR*) &labelList[blockId]);
oatClobberAllRegs(cUnit);
- oatResetNullCheck(cUnit);
ArmLIR* headLIR = NULL;
diff --git a/src/compiler/codegen/arm/Thumb2/Gen.cc b/src/compiler/codegen/arm/Thumb2/Gen.cc
index cd3a64a..c54a0a8 100644
--- a/src/compiler/codegen/arm/Thumb2/Gen.cc
+++ b/src/compiler/codegen/arm/Thumb2/Gen.cc
@@ -450,7 +450,7 @@
loadWordDisp(cUnit, r0, art::Field::OffsetOffset().Int32Value(), r0);
}
-static void genIGetX(CompilationUnit* cUnit, MIR* mir, OpSize size,
+static void genIGet(CompilationUnit* cUnit, MIR* mir, OpSize size,
RegLocation rlDest, RegLocation rlObj)
{
Field* fieldPtr = cUnit->method->GetDeclaringClass()->GetDexCache()->
@@ -485,7 +485,7 @@
}
}
-static void genIPutX(CompilationUnit* cUnit, MIR* mir, OpSize size,
+static void genIPut(CompilationUnit* cUnit, MIR* mir, OpSize size,
RegLocation rlSrc, RegLocation rlObj, bool isObject)
{
Field* fieldPtr = cUnit->method->GetDeclaringClass()->GetDexCache()->
@@ -521,7 +521,7 @@
}
}
-static void genIGetWideX(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
+static void genIGetWide(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
RegLocation rlObj)
{
Field* fieldPtr = cUnit->method->GetDeclaringClass()->GetDexCache()->
@@ -564,7 +564,7 @@
}
}
-static void genIPutWideX(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc,
+static void genIPutWide(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc,
RegLocation rlObj)
{
Field* fieldPtr = cUnit->method->GetDeclaringClass()->GetDexCache()->
@@ -886,8 +886,6 @@
for (int i = 0; i < numFPTemps; i++) {
oatMarkTemp(cUnit, fpTemps[i]);
}
- pool->nullCheckedRegs =
- oatAllocBitVector(cUnit->numSSARegs, false);
}
/*
@@ -1267,11 +1265,7 @@
loadValueDirectFixed(cUnit, rlSrc, r0);
/* null array object? */
- ArmLIR* pcrLabel = NULL;
-
- if (!(mir->OptimizationFlags & MIR_IGNORE_NULL_CHECK)) {
- pcrLabel = genNullCheck(cUnit, rlArray.sRegLow, r1, mir);
- }
+ genNullCheck(cUnit, rlArray.sRegLow, r1, mir);
loadWordDisp(cUnit, rSELF,
OFFSETOF_MEMBER(Thread, pCanPutArrayElementFromCode), rLR);
/* Get the array's clazz */
@@ -1295,7 +1289,7 @@
genRegCopy(cUnit, regPtr, rlArray.lowReg);
}
- if (!(mir->OptimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
+ if (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
int regLen = oatAllocTemp(cUnit);
//NOTE: max live temps(4) here.
/* Get len */
@@ -1331,15 +1325,11 @@
int regPtr;
/* null object? */
- ArmLIR* pcrLabel = NULL;
-
- if (!(mir->OptimizationFlags & MIR_IGNORE_NULL_CHECK)) {
- pcrLabel = genNullCheck(cUnit, rlArray.sRegLow, rlArray.lowReg, mir);
- }
+ genNullCheck(cUnit, rlArray.sRegLow, rlArray.lowReg, mir);
regPtr = oatAllocTemp(cUnit);
- if (!(mir->OptimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
+ if (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
int regLen = oatAllocTemp(cUnit);
/* Get len */
loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
@@ -1405,13 +1395,9 @@
}
/* null object? */
- ArmLIR* pcrLabel = NULL;
+ genNullCheck(cUnit, rlArray.sRegLow, rlArray.lowReg, mir);
- if (!(mir->OptimizationFlags & MIR_IGNORE_NULL_CHECK)) {
- pcrLabel = genNullCheck(cUnit, rlArray.sRegLow, rlArray.lowReg, mir);
- }
-
- if (!(mir->OptimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
+ if (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
int regLen = oatAllocTemp(cUnit);
//NOTE: max live temps(4) here.
/* Get len */