blob: 3d2ac5d3de35e0445203dfbfe3f2d12118e48276 [file] [log] [blame]
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "Dalvik.h"
#include "Dataflow.h"
namespace art {
/*
* Main table containing data flow attributes for each bytecode. The
* first kNumPackedOpcodes entries are for Dalvik bytecode
* instructions, where extended opcode at the MIR level are appended
* afterwards.
*
* TODO - many optimization flags are incomplete - they will only limit the
* scope of optimizations but will not cause mis-optimizations.
*/
const int oatDataFlowAttributes[kMirOpLast] = {
// 00 NOP
DF_NOP,
// 01 MOVE vA, vB
DF_DA | DF_UB | DF_IS_MOVE,
// 02 MOVE_FROM16 vAA, vBBBB
DF_DA | DF_UB | DF_IS_MOVE,
// 03 MOVE_16 vAAAA, vBBBB
DF_DA | DF_UB | DF_IS_MOVE,
// 04 MOVE_WIDE vA, vB
DF_DA | DF_A_WIDE | DF_UB | DF_B_WIDE | DF_IS_MOVE,
// 05 MOVE_WIDE_FROM16 vAA, vBBBB
DF_DA | DF_A_WIDE | DF_UB | DF_B_WIDE | DF_IS_MOVE,
// 06 MOVE_WIDE_16 vAAAA, vBBBB
DF_DA | DF_A_WIDE | DF_UB | DF_B_WIDE | DF_IS_MOVE,
// 07 MOVE_OBJECT vA, vB
DF_DA | DF_UB | DF_NULL_TRANSFER_0 | DF_IS_MOVE | DF_REF_A | DF_REF_B,
// 08 MOVE_OBJECT_FROM16 vAA, vBBBB
DF_DA | DF_UB | DF_NULL_TRANSFER_0 | DF_IS_MOVE | DF_REF_A | DF_REF_B,
// 09 MOVE_OBJECT_16 vAAAA, vBBBB
DF_DA | DF_UB | DF_NULL_TRANSFER_0 | DF_IS_MOVE | DF_REF_A | DF_REF_B,
// 0A MOVE_RESULT vAA
DF_DA,
// 0B MOVE_RESULT_WIDE vAA
DF_DA | DF_A_WIDE,
// 0C MOVE_RESULT_OBJECT vAA
DF_DA | DF_REF_A,
// 0D MOVE_EXCEPTION vAA
DF_DA | DF_CORE_A,
// 0E RETURN_VOID
DF_NOP,
// 0F RETURN vAA
DF_UA,
// 10 RETURN_WIDE vAA
DF_UA | DF_A_WIDE,
// 11 RETURN_OBJECT vAA
DF_UA | DF_REF_A,
// 12 CONST_4 vA, #+B
DF_DA | DF_SETS_CONST,
// 13 CONST_16 vAA, #+BBBB
DF_DA | DF_SETS_CONST,
// 14 CONST vAA, #+BBBBBBBB
DF_DA | DF_SETS_CONST,
// 15 CONST_HIGH16 VAA, #+BBBB0000
DF_DA | DF_SETS_CONST,
// 16 CONST_WIDE_16 vAA, #+BBBB
DF_DA | DF_A_WIDE | DF_SETS_CONST,
// 17 CONST_WIDE_32 vAA, #+BBBBBBBB
DF_DA | DF_A_WIDE | DF_SETS_CONST,
// 18 CONST_WIDE vAA, #+BBBBBBBBBBBBBBBB
DF_DA | DF_A_WIDE | DF_SETS_CONST,
// 19 CONST_WIDE_HIGH16 vAA, #+BBBB000000000000
DF_DA | DF_A_WIDE | DF_SETS_CONST,
// 1A CONST_STRING vAA, string@BBBB
DF_DA | DF_REF_A,
// 1B CONST_STRING_JUMBO vAA, string@BBBBBBBB
DF_DA | DF_REF_A,
// 1C CONST_CLASS vAA, type@BBBB
DF_DA | DF_REF_A,
// 1D MONITOR_ENTER vAA
DF_UA | DF_NULL_CHK_0 | DF_REF_A,
// 1E MONITOR_EXIT vAA
DF_UA | DF_NULL_CHK_0 | DF_REF_A,
// 1F CHK_CAST vAA, type@BBBB
DF_UA | DF_REF_A | DF_UMS,
// 20 INSTANCE_OF vA, vB, type@CCCC
DF_DA | DF_UB | DF_CORE_A | DF_REF_B | DF_UMS,
// 21 ARRAY_LENGTH vA, vB
DF_DA | DF_UB | DF_NULL_CHK_0 | DF_CORE_A | DF_REF_B,
// 22 NEW_INSTANCE vAA, type@BBBB
DF_DA | DF_NON_NULL_DST | DF_REF_A | DF_UMS,
// 23 NEW_ARRAY vA, vB, type@CCCC
DF_DA | DF_UB | DF_NON_NULL_DST | DF_REF_A | DF_CORE_B | DF_UMS,
// 24 FILLED_NEW_ARRAY {vD, vE, vF, vG, vA}
DF_FORMAT_35C | DF_NON_NULL_RET | DF_UMS,
// 25 FILLED_NEW_ARRAY_RANGE {vCCCC .. vNNNN}, type@BBBB
DF_FORMAT_3RC | DF_NON_NULL_RET | DF_UMS,
// 26 FILL_ARRAY_DATA vAA, +BBBBBBBB
DF_UA | DF_REF_A | DF_UMS,
// 27 THROW vAA
DF_UA | DF_REF_A | DF_UMS,
// 28 GOTO
DF_NOP,
// 29 GOTO_16
DF_NOP,
// 2A GOTO_32
DF_NOP,
// 2B PACKED_SWITCH vAA, +BBBBBBBB
DF_UA,
// 2C SPARSE_SWITCH vAA, +BBBBBBBB
DF_UA,
// 2D CMPL_FLOAT vAA, vBB, vCC
DF_DA | DF_UB | DF_UC | DF_FP_B | DF_FP_C | DF_CORE_A,
// 2E CMPG_FLOAT vAA, vBB, vCC
DF_DA | DF_UB | DF_UC | DF_FP_B | DF_FP_C | DF_CORE_A,
// 2F CMPL_DOUBLE vAA, vBB, vCC
DF_DA | DF_UB | DF_B_WIDE | DF_UC | DF_C_WIDE | DF_FP_B | DF_FP_C | DF_CORE_A,
// 30 CMPG_DOUBLE vAA, vBB, vCC
DF_DA | DF_UB | DF_B_WIDE | DF_UC | DF_C_WIDE | DF_FP_B | DF_FP_C | DF_CORE_A,
// 31 CMP_LONG vAA, vBB, vCC
DF_DA | DF_UB | DF_B_WIDE | DF_UC | DF_C_WIDE | DF_CORE_A | DF_CORE_B | DF_CORE_C,
// 32 IF_EQ vA, vB, +CCCC
DF_UA | DF_UB | DF_CORE_A | DF_CORE_B,
// 33 IF_NE vA, vB, +CCCC
DF_UA | DF_UB | DF_CORE_A | DF_CORE_B,
// 34 IF_LT vA, vB, +CCCC
DF_UA | DF_UB | DF_CORE_A | DF_CORE_B,
// 35 IF_GE vA, vB, +CCCC
DF_UA | DF_UB | DF_CORE_A | DF_CORE_B,
// 36 IF_GT vA, vB, +CCCC
DF_UA | DF_UB | DF_CORE_A | DF_CORE_B,
// 37 IF_LE vA, vB, +CCCC
DF_UA | DF_UB | DF_CORE_A | DF_CORE_B,
// 38 IF_EQZ vAA, +BBBB
DF_UA | DF_CORE_A,
// 39 IF_NEZ vAA, +BBBB
DF_UA | DF_CORE_A,
// 3A IF_LTZ vAA, +BBBB
DF_UA | DF_CORE_A,
// 3B IF_GEZ vAA, +BBBB
DF_UA | DF_CORE_A,
// 3C IF_GTZ vAA, +BBBB
DF_UA | DF_CORE_A,
// 3D IF_LEZ vAA, +BBBB
DF_UA | DF_CORE_A,
// 3E UNUSED_3E
DF_NOP,
// 3F UNUSED_3F
DF_NOP,
// 40 UNUSED_40
DF_NOP,
// 41 UNUSED_41
DF_NOP,
// 42 UNUSED_42
DF_NOP,
// 43 UNUSED_43
DF_NOP,
// 44 AGET vAA, vBB, vCC
DF_DA | DF_UB | DF_UC | DF_NULL_CHK_0 | DF_RANGE_CHK_1 | DF_REF_B | DF_CORE_C,
// 45 AGET_WIDE vAA, vBB, vCC
DF_DA | DF_A_WIDE | DF_UB | DF_UC | DF_NULL_CHK_0 | DF_RANGE_CHK_1 | DF_REF_B | DF_CORE_C,
// 46 AGET_OBJECT vAA, vBB, vCC
DF_DA | DF_UB | DF_UC | DF_NULL_CHK_0 | DF_RANGE_CHK_1 | DF_REF_A | DF_REF_B | DF_CORE_C,
// 47 AGET_BOOLEAN vAA, vBB, vCC
DF_DA | DF_UB | DF_UC | DF_NULL_CHK_0 | DF_RANGE_CHK_1 | DF_REF_B | DF_CORE_C,
// 48 AGET_BYTE vAA, vBB, vCC
DF_DA | DF_UB | DF_UC | DF_NULL_CHK_0 | DF_RANGE_CHK_1 | DF_REF_B | DF_CORE_C,
// 49 AGET_CHAR vAA, vBB, vCC
DF_DA | DF_UB | DF_UC | DF_NULL_CHK_0 | DF_RANGE_CHK_1 | DF_REF_B | DF_CORE_C,
// 4A AGET_SHORT vAA, vBB, vCC
DF_DA | DF_UB | DF_UC | DF_NULL_CHK_0 | DF_RANGE_CHK_1 | DF_REF_B | DF_CORE_C,
// 4B APUT vAA, vBB, vCC
DF_UA | DF_UB | DF_UC | DF_NULL_CHK_1 | DF_RANGE_CHK_2 | DF_REF_B | DF_CORE_C,
// 4C APUT_WIDE vAA, vBB, vCC
DF_UA | DF_A_WIDE | DF_UB | DF_UC | DF_NULL_CHK_2 | DF_RANGE_CHK_3 | DF_REF_B | DF_CORE_C,
// 4D APUT_OBJECT vAA, vBB, vCC
DF_UA | DF_UB | DF_UC | DF_NULL_CHK_1 | DF_RANGE_CHK_2 | DF_REF_A | DF_REF_B | DF_CORE_C,
// 4E APUT_BOOLEAN vAA, vBB, vCC
DF_UA | DF_UB | DF_UC | DF_NULL_CHK_1 | DF_RANGE_CHK_2 | DF_REF_B | DF_CORE_C,
// 4F APUT_BYTE vAA, vBB, vCC
DF_UA | DF_UB | DF_UC | DF_NULL_CHK_1 | DF_RANGE_CHK_2 | DF_REF_B | DF_CORE_C,
// 50 APUT_CHAR vAA, vBB, vCC
DF_UA | DF_UB | DF_UC | DF_NULL_CHK_1 | DF_RANGE_CHK_2 | DF_REF_B | DF_CORE_C,
// 51 APUT_SHORT vAA, vBB, vCC
DF_UA | DF_UB | DF_UC | DF_NULL_CHK_1 | DF_RANGE_CHK_2 | DF_REF_B | DF_CORE_C,
// 52 IGET vA, vB, field@CCCC
DF_DA | DF_UB | DF_NULL_CHK_0 | DF_REF_B,
// 53 IGET_WIDE vA, vB, field@CCCC
DF_DA | DF_A_WIDE | DF_UB | DF_NULL_CHK_0 | DF_REF_B,
// 54 IGET_OBJECT vA, vB, field@CCCC
DF_DA | DF_UB | DF_NULL_CHK_0 | DF_REF_A | DF_REF_B,
// 55 IGET_BOOLEAN vA, vB, field@CCCC
DF_DA | DF_UB | DF_NULL_CHK_0 | DF_REF_B,
// 56 IGET_BYTE vA, vB, field@CCCC
DF_DA | DF_UB | DF_NULL_CHK_0 | DF_REF_B,
// 57 IGET_CHAR vA, vB, field@CCCC
DF_DA | DF_UB | DF_NULL_CHK_0 | DF_REF_B,
// 58 IGET_SHORT vA, vB, field@CCCC
DF_DA | DF_UB | DF_NULL_CHK_0 | DF_REF_B,
// 59 IPUT vA, vB, field@CCCC
DF_UA | DF_UB | DF_NULL_CHK_1 | DF_REF_B,
// 5A IPUT_WIDE vA, vB, field@CCCC
DF_UA | DF_A_WIDE | DF_UB | DF_NULL_CHK_2 | DF_REF_B,
// 5B IPUT_OBJECT vA, vB, field@CCCC
DF_UA | DF_UB | DF_NULL_CHK_1 | DF_REF_A | DF_REF_B,
// 5C IPUT_BOOLEAN vA, vB, field@CCCC
DF_UA | DF_UB | DF_NULL_CHK_1 | DF_REF_B,
// 5D IPUT_BYTE vA, vB, field@CCCC
DF_UA | DF_UB | DF_NULL_CHK_1 | DF_REF_B,
// 5E IPUT_CHAR vA, vB, field@CCCC
DF_UA | DF_UB | DF_NULL_CHK_1 | DF_REF_B,
// 5F IPUT_SHORT vA, vB, field@CCCC
DF_UA | DF_UB | DF_NULL_CHK_1 | DF_REF_B,
// 60 SGET vAA, field@BBBB
DF_DA | DF_UMS,
// 61 SGET_WIDE vAA, field@BBBB
DF_DA | DF_A_WIDE | DF_UMS,
// 62 SGET_OBJECT vAA, field@BBBB
DF_DA | DF_REF_A | DF_UMS,
// 63 SGET_BOOLEAN vAA, field@BBBB
DF_DA | DF_UMS,
// 64 SGET_BYTE vAA, field@BBBB
DF_DA | DF_UMS,
// 65 SGET_CHAR vAA, field@BBBB
DF_DA | DF_UMS,
// 66 SGET_SHORT vAA, field@BBBB
DF_DA | DF_UMS,
// 67 SPUT vAA, field@BBBB
DF_UA | DF_UMS,
// 68 SPUT_WIDE vAA, field@BBBB
DF_UA | DF_A_WIDE | DF_UMS,
// 69 SPUT_OBJECT vAA, field@BBBB
DF_UA | DF_REF_A | DF_UMS,
// 6A SPUT_BOOLEAN vAA, field@BBBB
DF_UA | DF_UMS,
// 6B SPUT_BYTE vAA, field@BBBB
DF_UA | DF_UMS,
// 6C SPUT_CHAR vAA, field@BBBB
DF_UA | DF_UMS,
// 6D SPUT_SHORT vAA, field@BBBB
DF_UA | DF_UMS,
// 6E INVOKE_VIRTUAL {vD, vE, vF, vG, vA}
DF_FORMAT_35C | DF_NULL_CHK_OUT0 | DF_UMS,
// 6F INVOKE_SUPER {vD, vE, vF, vG, vA}
DF_FORMAT_35C | DF_NULL_CHK_OUT0 | DF_UMS,
// 70 INVOKE_DIRECT {vD, vE, vF, vG, vA}
DF_FORMAT_35C | DF_NULL_CHK_OUT0 | DF_UMS,
// 71 INVOKE_STATIC {vD, vE, vF, vG, vA}
DF_FORMAT_35C | DF_UMS,
// 72 INVOKE_INTERFACE {vD, vE, vF, vG, vA}
DF_FORMAT_35C | DF_UMS,
// 73 UNUSED_73
DF_NOP,
// 74 INVOKE_VIRTUAL_RANGE {vCCCC .. vNNNN}
DF_FORMAT_3RC | DF_NULL_CHK_OUT0 | DF_UMS,
// 75 INVOKE_SUPER_RANGE {vCCCC .. vNNNN}
DF_FORMAT_3RC | DF_NULL_CHK_OUT0 | DF_UMS,
// 76 INVOKE_DIRECT_RANGE {vCCCC .. vNNNN}
DF_FORMAT_3RC | DF_NULL_CHK_OUT0 | DF_UMS,
// 77 INVOKE_STATIC_RANGE {vCCCC .. vNNNN}
DF_FORMAT_3RC | DF_UMS,
// 78 INVOKE_INTERFACE_RANGE {vCCCC .. vNNNN}
DF_FORMAT_3RC | DF_UMS,
// 79 UNUSED_79
DF_NOP,
// 7A UNUSED_7A
DF_NOP,
// 7B NEG_INT vA, vB
DF_DA | DF_UB | DF_CORE_A | DF_CORE_B,
// 7C NOT_INT vA, vB
DF_DA | DF_UB | DF_CORE_A | DF_CORE_B,
// 7D NEG_LONG vA, vB
DF_DA | DF_A_WIDE | DF_UB | DF_B_WIDE | DF_CORE_A | DF_CORE_B,
// 7E NOT_LONG vA, vB
DF_DA | DF_A_WIDE | DF_UB | DF_B_WIDE | DF_CORE_A | DF_CORE_B,
// 7F NEG_FLOAT vA, vB
DF_DA | DF_UB | DF_FP_A | DF_FP_B,
// 80 NEG_DOUBLE vA, vB
DF_DA | DF_A_WIDE | DF_UB | DF_B_WIDE | DF_FP_A | DF_FP_B,
// 81 INT_TO_LONG vA, vB
DF_DA | DF_A_WIDE | DF_UB | DF_CORE_A | DF_CORE_B,
// 82 INT_TO_FLOAT vA, vB
DF_DA | DF_UB | DF_FP_A | DF_CORE_B,
// 83 INT_TO_DOUBLE vA, vB
DF_DA | DF_A_WIDE | DF_UB | DF_FP_A | DF_CORE_B,
// 84 LONG_TO_INT vA, vB
DF_DA | DF_UB | DF_B_WIDE | DF_CORE_A | DF_CORE_B,
// 85 LONG_TO_FLOAT vA, vB
DF_DA | DF_UB | DF_B_WIDE | DF_FP_A | DF_CORE_B,
// 86 LONG_TO_DOUBLE vA, vB
DF_DA | DF_A_WIDE | DF_UB | DF_B_WIDE | DF_FP_A | DF_CORE_B,
// 87 FLOAT_TO_INT vA, vB
DF_DA | DF_UB | DF_FP_B | DF_CORE_A,
// 88 FLOAT_TO_LONG vA, vB
DF_DA | DF_A_WIDE | DF_UB | DF_FP_B | DF_CORE_A,
// 89 FLOAT_TO_DOUBLE vA, vB
DF_DA | DF_A_WIDE | DF_UB | DF_FP_A | DF_FP_B,
// 8A DOUBLE_TO_INT vA, vB
DF_DA | DF_UB | DF_B_WIDE | DF_FP_B | DF_CORE_A,
// 8B DOUBLE_TO_LONG vA, vB
DF_DA | DF_A_WIDE | DF_UB | DF_B_WIDE | DF_FP_B | DF_CORE_A,
// 8C DOUBLE_TO_FLOAT vA, vB
DF_DA | DF_UB | DF_B_WIDE | DF_FP_A | DF_FP_B,
// 8D INT_TO_BYTE vA, vB
DF_DA | DF_UB | DF_CORE_A | DF_CORE_B,
// 8E INT_TO_CHAR vA, vB
DF_DA | DF_UB | DF_CORE_A | DF_CORE_B,
// 8F INT_TO_SHORT vA, vB
DF_DA | DF_UB | DF_CORE_A | DF_CORE_B,
// 90 ADD_INT vAA, vBB, vCC
DF_DA | DF_UB | DF_UC | DF_CORE_A | DF_CORE_B | DF_CORE_C,
// 91 SUB_INT vAA, vBB, vCC
DF_DA | DF_UB | DF_UC | DF_CORE_A | DF_CORE_B | DF_CORE_C,
// 92 MUL_INT vAA, vBB, vCC
DF_DA | DF_UB | DF_UC | DF_CORE_A | DF_CORE_B | DF_CORE_C,
// 93 DIV_INT vAA, vBB, vCC
DF_DA | DF_UB | DF_UC | DF_CORE_A | DF_CORE_B | DF_CORE_C,
// 94 REM_INT vAA, vBB, vCC
DF_DA | DF_UB | DF_UC | DF_CORE_A | DF_CORE_B | DF_CORE_C,
// 95 AND_INT vAA, vBB, vCC
DF_DA | DF_UB | DF_UC | DF_CORE_A | DF_CORE_B | DF_CORE_C,
// 96 OR_INT vAA, vBB, vCC
DF_DA | DF_UB | DF_UC | DF_CORE_A | DF_CORE_B | DF_CORE_C,
// 97 XOR_INT vAA, vBB, vCC
DF_DA | DF_UB | DF_UC | DF_CORE_A | DF_CORE_B | DF_CORE_C,
// 98 SHL_INT vAA, vBB, vCC
DF_DA | DF_UB | DF_UC | DF_CORE_A | DF_CORE_B | DF_CORE_C,
// 99 SHR_INT vAA, vBB, vCC
DF_DA | DF_UB | DF_UC | DF_CORE_A | DF_CORE_B | DF_CORE_C,
// 9A USHR_INT vAA, vBB, vCC
DF_DA | DF_UB | DF_UC | DF_CORE_A | DF_CORE_B | DF_CORE_C,
// 9B ADD_LONG vAA, vBB, vCC
DF_DA | DF_A_WIDE | DF_UB | DF_B_WIDE | DF_UC | DF_C_WIDE | DF_CORE_A | DF_CORE_B | DF_CORE_C,
// 9C SUB_LONG vAA, vBB, vCC
DF_DA | DF_A_WIDE | DF_UB | DF_B_WIDE | DF_UC | DF_C_WIDE | DF_CORE_A | DF_CORE_B | DF_CORE_C,
// 9D MUL_LONG vAA, vBB, vCC
DF_DA | DF_A_WIDE | DF_UB | DF_B_WIDE | DF_UC | DF_C_WIDE | DF_CORE_A | DF_CORE_B | DF_CORE_C,
// 9E DIV_LONG vAA, vBB, vCC
DF_DA | DF_A_WIDE | DF_UB | DF_B_WIDE | DF_UC | DF_C_WIDE | DF_CORE_A | DF_CORE_B | DF_CORE_C,
// 9F REM_LONG vAA, vBB, vCC
DF_DA | DF_A_WIDE | DF_UB | DF_B_WIDE | DF_UC | DF_C_WIDE | DF_CORE_A | DF_CORE_B | DF_CORE_C,
// A0 AND_LONG vAA, vBB, vCC
DF_DA | DF_A_WIDE | DF_UB | DF_B_WIDE | DF_UC | DF_C_WIDE | DF_CORE_A | DF_CORE_B | DF_CORE_C,
// A1 OR_LONG vAA, vBB, vCC
DF_DA | DF_A_WIDE | DF_UB | DF_B_WIDE | DF_UC | DF_C_WIDE | DF_CORE_A | DF_CORE_B | DF_CORE_C,
// A2 XOR_LONG vAA, vBB, vCC
DF_DA | DF_A_WIDE | DF_UB | DF_B_WIDE | DF_UC | DF_C_WIDE | DF_CORE_A | DF_CORE_B | DF_CORE_C,
// A3 SHL_LONG vAA, vBB, vCC
DF_DA | DF_A_WIDE | DF_UB | DF_B_WIDE | DF_UC | DF_CORE_A | DF_CORE_B | DF_CORE_C,
// A4 SHR_LONG vAA, vBB, vCC
DF_DA | DF_A_WIDE | DF_UB | DF_B_WIDE | DF_UC | DF_CORE_A | DF_CORE_B | DF_CORE_C,
// A5 USHR_LONG vAA, vBB, vCC
DF_DA | DF_A_WIDE | DF_UB | DF_B_WIDE | DF_UC | DF_CORE_A | DF_CORE_B | DF_CORE_C,
// A6 ADD_FLOAT vAA, vBB, vCC
DF_DA | DF_UB | DF_UC | DF_FP_A | DF_FP_B | DF_FP_C,
// A7 SUB_FLOAT vAA, vBB, vCC
DF_DA | DF_UB | DF_UC | DF_FP_A | DF_FP_B | DF_FP_C,
// A8 MUL_FLOAT vAA, vBB, vCC
DF_DA | DF_UB | DF_UC | DF_FP_A | DF_FP_B | DF_FP_C,
// A9 DIV_FLOAT vAA, vBB, vCC
DF_DA | DF_UB | DF_UC | DF_FP_A | DF_FP_B | DF_FP_C,
// AA REM_FLOAT vAA, vBB, vCC
DF_DA | DF_UB | DF_UC | DF_FP_A | DF_FP_B | DF_FP_C,
// AB ADD_DOUBLE vAA, vBB, vCC
DF_DA | DF_A_WIDE | DF_UB | DF_B_WIDE | DF_UC | DF_C_WIDE | DF_FP_A | DF_FP_B | DF_FP_C,
// AC SUB_DOUBLE vAA, vBB, vCC
DF_DA | DF_A_WIDE | DF_UB | DF_B_WIDE | DF_UC | DF_C_WIDE | DF_FP_A | DF_FP_B | DF_FP_C,
// AD MUL_DOUBLE vAA, vBB, vCC
DF_DA | DF_A_WIDE | DF_UB | DF_B_WIDE | DF_UC | DF_C_WIDE | DF_FP_A | DF_FP_B | DF_FP_C,
// AE DIV_DOUBLE vAA, vBB, vCC
DF_DA | DF_A_WIDE | DF_UB | DF_B_WIDE | DF_UC | DF_C_WIDE | DF_FP_A | DF_FP_B | DF_FP_C,
// AF REM_DOUBLE vAA, vBB, vCC
DF_DA | DF_A_WIDE | DF_UB | DF_B_WIDE | DF_UC | DF_C_WIDE | DF_FP_A | DF_FP_B | DF_FP_C,
// B0 ADD_INT_2ADDR vA, vB
DF_DA | DF_UA | DF_UB | DF_CORE_A | DF_CORE_B,
// B1 SUB_INT_2ADDR vA, vB
DF_DA | DF_UA | DF_UB | DF_CORE_A | DF_CORE_B,
// B2 MUL_INT_2ADDR vA, vB
DF_DA | DF_UA | DF_UB | DF_CORE_A | DF_CORE_B,
// B3 DIV_INT_2ADDR vA, vB
DF_DA | DF_UA | DF_UB | DF_CORE_A | DF_CORE_B,
// B4 REM_INT_2ADDR vA, vB
DF_DA | DF_UA | DF_UB | DF_CORE_A | DF_CORE_B,
// B5 AND_INT_2ADDR vA, vB
DF_DA | DF_UA | DF_UB | DF_CORE_A | DF_CORE_B,
// B6 OR_INT_2ADDR vA, vB
DF_DA | DF_UA | DF_UB | DF_CORE_A | DF_CORE_B,
// B7 XOR_INT_2ADDR vA, vB
DF_DA | DF_UA | DF_UB | DF_CORE_A | DF_CORE_B,
// B8 SHL_INT_2ADDR vA, vB
DF_DA | DF_UA | DF_UB | DF_CORE_A | DF_CORE_B,
// B9 SHR_INT_2ADDR vA, vB
DF_DA | DF_UA | DF_UB | DF_CORE_A | DF_CORE_B,
// BA USHR_INT_2ADDR vA, vB
DF_DA | DF_UA | DF_UB | DF_CORE_A | DF_CORE_B,
// BB ADD_LONG_2ADDR vA, vB
DF_DA | DF_A_WIDE | DF_UA | DF_UB | DF_B_WIDE | DF_CORE_A | DF_CORE_B,
// BC SUB_LONG_2ADDR vA, vB
DF_DA | DF_A_WIDE | DF_UA | DF_UB | DF_B_WIDE | DF_CORE_A | DF_CORE_B,
// BD MUL_LONG_2ADDR vA, vB
DF_DA | DF_A_WIDE | DF_UA | DF_UB | DF_B_WIDE | DF_CORE_A | DF_CORE_B,
// BE DIV_LONG_2ADDR vA, vB
DF_DA | DF_A_WIDE | DF_UA | DF_UB | DF_B_WIDE | DF_CORE_A | DF_CORE_B,
// BF REM_LONG_2ADDR vA, vB
DF_DA | DF_A_WIDE | DF_UA | DF_UB | DF_B_WIDE | DF_CORE_A | DF_CORE_B,
// C0 AND_LONG_2ADDR vA, vB
DF_DA | DF_A_WIDE | DF_UA | DF_UB | DF_B_WIDE | DF_CORE_A | DF_CORE_B,
// C1 OR_LONG_2ADDR vA, vB
DF_DA | DF_A_WIDE | DF_UA | DF_UB | DF_B_WIDE | DF_CORE_A | DF_CORE_B,
// C2 XOR_LONG_2ADDR vA, vB
DF_DA | DF_A_WIDE | DF_UA | DF_UB | DF_B_WIDE | DF_CORE_A | DF_CORE_B,
// C3 SHL_LONG_2ADDR vA, vB
DF_DA | DF_A_WIDE | DF_UA | DF_UB | DF_CORE_A | DF_CORE_B,
// C4 SHR_LONG_2ADDR vA, vB
DF_DA | DF_A_WIDE | DF_UA | DF_UB | DF_CORE_A | DF_CORE_B,
// C5 USHR_LONG_2ADDR vA, vB
DF_DA | DF_A_WIDE | DF_UA | DF_UB | DF_CORE_A | DF_CORE_B,
// C6 ADD_FLOAT_2ADDR vA, vB
DF_DA | DF_UA | DF_UB | DF_FP_A | DF_FP_B,
// C7 SUB_FLOAT_2ADDR vA, vB
DF_DA | DF_UA | DF_UB | DF_FP_A | DF_FP_B,
// C8 MUL_FLOAT_2ADDR vA, vB
DF_DA | DF_UA | DF_UB | DF_FP_A | DF_FP_B,
// C9 DIV_FLOAT_2ADDR vA, vB
DF_DA | DF_UA | DF_UB | DF_FP_A | DF_FP_B,
// CA REM_FLOAT_2ADDR vA, vB
DF_DA | DF_UA | DF_UB | DF_FP_A | DF_FP_B,
// CB ADD_DOUBLE_2ADDR vA, vB
DF_DA | DF_A_WIDE | DF_UA | DF_UB | DF_B_WIDE | DF_FP_A | DF_FP_B,
// CC SUB_DOUBLE_2ADDR vA, vB
DF_DA | DF_A_WIDE | DF_UA | DF_UB | DF_B_WIDE | DF_FP_A | DF_FP_B,
// CD MUL_DOUBLE_2ADDR vA, vB
DF_DA | DF_A_WIDE | DF_UA | DF_UB | DF_B_WIDE | DF_FP_A | DF_FP_B,
// CE DIV_DOUBLE_2ADDR vA, vB
DF_DA | DF_A_WIDE | DF_UA | DF_UB | DF_B_WIDE | DF_FP_A | DF_FP_B,
// CF REM_DOUBLE_2ADDR vA, vB
DF_DA | DF_A_WIDE | DF_UA | DF_UB | DF_B_WIDE | DF_FP_A | DF_FP_B,
// D0 ADD_INT_LIT16 vA, vB, #+CCCC
DF_DA | DF_UB | DF_CORE_A | DF_CORE_B,
// D1 RSUB_INT vA, vB, #+CCCC
DF_DA | DF_UB | DF_CORE_A | DF_CORE_B,
// D2 MUL_INT_LIT16 vA, vB, #+CCCC
DF_DA | DF_UB | DF_CORE_A | DF_CORE_B,
// D3 DIV_INT_LIT16 vA, vB, #+CCCC
DF_DA | DF_UB | DF_CORE_A | DF_CORE_B,
// D4 REM_INT_LIT16 vA, vB, #+CCCC
DF_DA | DF_UB | DF_CORE_A | DF_CORE_B,
// D5 AND_INT_LIT16 vA, vB, #+CCCC
DF_DA | DF_UB | DF_CORE_A | DF_CORE_B,
// D6 OR_INT_LIT16 vA, vB, #+CCCC
DF_DA | DF_UB | DF_CORE_A | DF_CORE_B,
// D7 XOR_INT_LIT16 vA, vB, #+CCCC
DF_DA | DF_UB | DF_CORE_A | DF_CORE_B,
// D8 ADD_INT_LIT8 vAA, vBB, #+CC
DF_DA | DF_UB | DF_CORE_A | DF_CORE_B,
// D9 RSUB_INT_LIT8 vAA, vBB, #+CC
DF_DA | DF_UB | DF_CORE_A | DF_CORE_B,
// DA MUL_INT_LIT8 vAA, vBB, #+CC
DF_DA | DF_UB | DF_CORE_A | DF_CORE_B,
// DB DIV_INT_LIT8 vAA, vBB, #+CC
DF_DA | DF_UB | DF_CORE_A | DF_CORE_B,
// DC REM_INT_LIT8 vAA, vBB, #+CC
DF_DA | DF_UB | DF_CORE_A | DF_CORE_B,
// DD AND_INT_LIT8 vAA, vBB, #+CC
DF_DA | DF_UB | DF_CORE_A | DF_CORE_B,
// DE OR_INT_LIT8 vAA, vBB, #+CC
DF_DA | DF_UB | DF_CORE_A | DF_CORE_B,
// DF XOR_INT_LIT8 vAA, vBB, #+CC
DF_DA | DF_UB | DF_CORE_A | DF_CORE_B,
// E0 SHL_INT_LIT8 vAA, vBB, #+CC
DF_DA | DF_UB | DF_CORE_A | DF_CORE_B,
// E1 SHR_INT_LIT8 vAA, vBB, #+CC
DF_DA | DF_UB | DF_CORE_A | DF_CORE_B,
// E2 USHR_INT_LIT8 vAA, vBB, #+CC
DF_DA | DF_UB | DF_CORE_A | DF_CORE_B,
// E3 IGET_VOLATILE
DF_DA | DF_UB | DF_NULL_CHK_0 | DF_REF_B,
// E4 IPUT_VOLATILE
DF_UA | DF_UB | DF_NULL_CHK_1 | DF_REF_B,
// E5 SGET_VOLATILE
DF_DA | DF_UMS,
// E6 SPUT_VOLATILE
DF_UA | DF_UMS,
// E7 IGET_OBJECT_VOLATILE
DF_DA | DF_UB | DF_NULL_CHK_0 | DF_REF_A | DF_REF_B,
// E8 IGET_WIDE_VOLATILE
DF_DA | DF_A_WIDE | DF_UB | DF_NULL_CHK_0 | DF_REF_B,
// E9 IPUT_WIDE_VOLATILE
DF_UA | DF_A_WIDE | DF_UB | DF_NULL_CHK_2 | DF_REF_B,
// EA SGET_WIDE_VOLATILE
DF_DA | DF_A_WIDE | DF_UMS,
// EB SPUT_WIDE_VOLATILE
DF_UA | DF_A_WIDE | DF_UMS,
// EC BREAKPOINT
DF_NOP,
// ED THROW_VERIFICATION_ERROR
DF_NOP | DF_UMS,
// EE EXECUTE_INLINE
DF_FORMAT_35C,
// EF EXECUTE_INLINE_RANGE
DF_FORMAT_3RC,
// F0 INVOKE_OBJECT_INIT_RANGE
DF_NOP | DF_NULL_CHK_0,
// F1 RETURN_VOID_BARRIER
DF_NOP,
// F2 IGET_QUICK
DF_DA | DF_UB | DF_NULL_CHK_0,
// F3 IGET_WIDE_QUICK
DF_DA | DF_A_WIDE | DF_UB | DF_NULL_CHK_0,
// F4 IGET_OBJECT_QUICK
DF_DA | DF_UB | DF_NULL_CHK_0,
// F5 IPUT_QUICK
DF_UA | DF_UB | DF_NULL_CHK_1,
// F6 IPUT_WIDE_QUICK
DF_UA | DF_A_WIDE | DF_UB | DF_NULL_CHK_2,
// F7 IPUT_OBJECT_QUICK
DF_UA | DF_UB | DF_NULL_CHK_1,
// F8 INVOKE_VIRTUAL_QUICK
DF_FORMAT_35C | DF_NULL_CHK_OUT0 | DF_UMS,
// F9 INVOKE_VIRTUAL_QUICK_RANGE
DF_FORMAT_3RC | DF_NULL_CHK_OUT0 | DF_UMS,
// FA INVOKE_SUPER_QUICK
DF_FORMAT_35C | DF_NULL_CHK_OUT0 | DF_UMS,
// FB INVOKE_SUPER_QUICK_RANGE
DF_FORMAT_3RC | DF_NULL_CHK_OUT0 | DF_UMS,
// FC IPUT_OBJECT_VOLATILE
DF_UA | DF_UB | DF_NULL_CHK_1 | DF_REF_A | DF_REF_B,
// FD SGET_OBJECT_VOLATILE
DF_DA | DF_REF_A | DF_UMS,
// FE SPUT_OBJECT_VOLATILE
DF_UA | DF_REF_A | DF_UMS,
// FF UNUSED_FF
DF_NOP,
// Beginning of extended MIR opcodes
// 100 MIR_PHI
DF_DA | DF_NULL_TRANSFER_N,
// 101 MIR_COPY
DF_DA | DF_UB | DF_IS_MOVE,
// 102 MIR_FUSED_CMPL_FLOAT
DF_UA | DF_UB | DF_FP_A | DF_FP_B,
// 103 MIR_FUSED_CMPG_FLOAT
DF_UA | DF_UB | DF_FP_A | DF_FP_B,
// 104 MIR_FUSED_CMPL_DOUBLE
DF_UA | DF_A_WIDE | DF_UB | DF_B_WIDE | DF_FP_A | DF_FP_B,
// 105 MIR_FUSED_CMPG_DOUBLE
DF_UA | DF_A_WIDE | DF_UB | DF_B_WIDE | DF_FP_A | DF_FP_B,
// 106 MIR_FUSED_CMP_LONG
DF_UA | DF_A_WIDE | DF_UB | DF_B_WIDE | DF_CORE_A | DF_CORE_B,
// 107 MIR_NOP
DF_NOP,
// 108 MIR_NULL_RANGE_UP_CHECK
0,
// 109 MIR_NULL_RANGE_DOWN_CHECK
0,
// 110 MIR_LOWER_BOUND
0,
};
/* Return the base virtual register for a SSA name */
int SRegToVReg(const CompilationUnit* cUnit, int ssaReg)
{
DCHECK_LT(ssaReg, (int)cUnit->ssaBaseVRegs->numUsed);
return GET_ELEM_N(cUnit->ssaBaseVRegs, int, ssaReg);
}
int SRegToSubscript(const CompilationUnit* cUnit, int ssaReg)
{
DCHECK(ssaReg < (int)cUnit->ssaSubscripts->numUsed);
return GET_ELEM_N(cUnit->ssaSubscripts, int, ssaReg);
}
int getSSAUseCount(CompilationUnit* cUnit, int sReg)
{
DCHECK(sReg < (int)cUnit->rawUseCounts.numUsed);
return cUnit->rawUseCounts.elemList[sReg];
}
char* oatGetDalvikDisassembly(CompilationUnit* cUnit,
const DecodedInstruction& insn, const char* note)
{
char buffer[256];
Instruction::Code opcode = insn.opcode;
int dfAttributes = oatDataFlowAttributes[opcode];
int flags;
char* ret;
buffer[0] = 0;
if ((int)opcode >= (int)kMirOpFirst) {
if ((int)opcode == (int)kMirOpPhi) {
strcpy(buffer, "PHI");
} else {
sprintf(buffer, "Opcode %#x", opcode);
}
flags = 0;
} else {
strcpy(buffer, Instruction::Name(opcode));
flags = Instruction::Flags(opcode);
}
if (note)
strcat(buffer, note);
/* For branches, decode the instructions to print out the branch targets */
if (flags & Instruction::kBranch) {
Instruction::Format dalvikFormat = Instruction::FormatOf(insn.opcode);
int offset = 0;
switch (dalvikFormat) {
case Instruction::k21t:
snprintf(buffer + strlen(buffer), 256, " v%d,", insn.vA);
offset = (int) insn.vB;
break;
case Instruction::k22t:
snprintf(buffer + strlen(buffer), 256, " v%d, v%d,", insn.vA, insn.vB);
offset = (int) insn.vC;
break;
case Instruction::k10t:
case Instruction::k20t:
case Instruction::k30t:
offset = (int) insn.vA;
break;
default:
LOG(FATAL) << "Unexpected branch format " << (int)dalvikFormat
<< " / opcode " << (int)opcode;
}
snprintf(buffer + strlen(buffer), 256, " (%c%x)",
offset > 0 ? '+' : '-',
offset > 0 ? offset : -offset);
} else if (dfAttributes & DF_FORMAT_35C) {
unsigned int i;
for (i = 0; i < insn.vA; i++) {
if (i != 0) strcat(buffer, ",");
snprintf(buffer + strlen(buffer), 256, " v%d", insn.arg[i]);
}
}
else if (dfAttributes & DF_FORMAT_3RC) {
snprintf(buffer + strlen(buffer), 256,
" v%d..v%d", insn.vC, insn.vC + insn.vA - 1);
} else {
if (dfAttributes & DF_A_IS_REG) {
snprintf(buffer + strlen(buffer), 256, " v%d", insn.vA);
}
if (dfAttributes & DF_B_IS_REG) {
snprintf(buffer + strlen(buffer), 256, ", v%d", insn.vB);
} else if ((int)opcode < (int)kMirOpFirst) {
snprintf(buffer + strlen(buffer), 256, ", (#%d)", insn.vB);
}
if (dfAttributes & DF_C_IS_REG) {
snprintf(buffer + strlen(buffer), 256, ", v%d", insn.vC);
} else if ((int)opcode < (int)kMirOpFirst) {
snprintf(buffer + strlen(buffer), 256, ", (#%d)", insn.vC);
}
}
int length = strlen(buffer) + 1;
ret = (char*)oatNew(cUnit, length, false, kAllocDFInfo);
memcpy(ret, buffer, length);
return ret;
}
char* getSSAName(const CompilationUnit* cUnit, int ssaReg, char* name)
{
sprintf(name, "v%d_%d", SRegToVReg(cUnit, ssaReg),
SRegToSubscript(cUnit, ssaReg));
return name;
}
/*
* Dalvik instruction disassembler with optional SSA printing.
*/
char* oatFullDisassembler(CompilationUnit* cUnit, const MIR* mir)
{
char buffer[256];
char operand0[32], operand1[32];
const DecodedInstruction* insn = &mir->dalvikInsn;
Instruction::Code opcode = insn->opcode;
int dfAttributes = oatDataFlowAttributes[opcode];
char* ret;
int length;
buffer[0] = 0;
if (static_cast<int>(opcode) >= static_cast<int>(kMirOpFirst)) {
if (static_cast<int>(opcode) == static_cast<int>(kMirOpPhi)) {
snprintf(buffer, 256, "PHI %s = (%s",
getSSAName(cUnit, mir->ssaRep->defs[0], operand0),
getSSAName(cUnit, mir->ssaRep->uses[0], operand1));
int i;
for (i = 1; i < mir->ssaRep->numUses; i++) {
snprintf(buffer + strlen(buffer), 256, ", %s",
getSSAName(cUnit, mir->ssaRep->uses[i], operand0));
}
snprintf(buffer + strlen(buffer), 256, ")");
} else {
sprintf(buffer, "Opcode %#x", opcode);
}
goto done;
} else {
strcpy(buffer, Instruction::Name(opcode));
}
/* For branches, decode the instructions to print out the branch targets */
if (Instruction::Flags(insn->opcode) & Instruction::kBranch) {
Instruction::Format dalvikFormat = Instruction::FormatOf(insn->opcode);
int delta = 0;
switch (dalvikFormat) {
case Instruction::k21t:
snprintf(buffer + strlen(buffer), 256, " %s, ",
getSSAName(cUnit, mir->ssaRep->uses[0], operand0));
delta = (int) insn->vB;
break;
case Instruction::k22t:
snprintf(buffer + strlen(buffer), 256, " %s, %s, ",
getSSAName(cUnit, mir->ssaRep->uses[0], operand0),
getSSAName(cUnit, mir->ssaRep->uses[1], operand1));
delta = (int) insn->vC;
break;
case Instruction::k10t:
case Instruction::k20t:
case Instruction::k30t:
delta = (int) insn->vA;
break;
default:
LOG(FATAL) << "Unexpected branch format: " << (int)dalvikFormat;
}
snprintf(buffer + strlen(buffer), 256, " %04x",
mir->offset + delta);
} else if (dfAttributes & (DF_FORMAT_35C | DF_FORMAT_3RC)) {
unsigned int i;
for (i = 0; i < insn->vA; i++) {
if (i != 0) strcat(buffer, ",");
snprintf(buffer + strlen(buffer), 256, " %s",
getSSAName(cUnit, mir->ssaRep->uses[i], operand0));
}
} else {
int udIdx;
if (mir->ssaRep->numDefs) {
for (udIdx = 0; udIdx < mir->ssaRep->numDefs; udIdx++) {
snprintf(buffer + strlen(buffer), 256, " %s",
getSSAName(cUnit, mir->ssaRep->defs[udIdx], operand0));
}
strcat(buffer, ",");
}
if (mir->ssaRep->numUses) {
/* No leading ',' for the first use */
snprintf(buffer + strlen(buffer), 256, " %s",
getSSAName(cUnit, mir->ssaRep->uses[0], operand0));
for (udIdx = 1; udIdx < mir->ssaRep->numUses; udIdx++) {
snprintf(buffer + strlen(buffer), 256, ", %s",
getSSAName(cUnit, mir->ssaRep->uses[udIdx], operand0));
}
}
if (static_cast<int>(opcode) < static_cast<int>(kMirOpFirst)) {
Instruction::Format dalvikFormat = Instruction::FormatOf(opcode);
switch (dalvikFormat) {
case Instruction::k11n: // op vA, #+B
case Instruction::k21s: // op vAA, #+BBBB
case Instruction::k21h: // op vAA, #+BBBB00000[00000000]
case Instruction::k31i: // op vAA, #+BBBBBBBB
case Instruction::k51l: // op vAA, #+BBBBBBBBBBBBBBBB
snprintf(buffer + strlen(buffer), 256, " #%#x", insn->vB);
break;
case Instruction::k21c: // op vAA, thing@BBBB
case Instruction::k31c: // op vAA, thing@BBBBBBBB
snprintf(buffer + strlen(buffer), 256, " @%#x", insn->vB);
break;
case Instruction::k22b: // op vAA, vBB, #+CC
case Instruction::k22s: // op vA, vB, #+CCCC
snprintf(buffer + strlen(buffer), 256, " #%#x", insn->vC);
break;
case Instruction::k22c: // op vA, vB, thing@CCCC
snprintf(buffer + strlen(buffer), 256, " @%#x", insn->vC);
break;
/* No need for special printing */
default:
break;
}
}
}
done:
length = strlen(buffer) + 1;
ret = (char*) oatNew(cUnit, length, false, kAllocDFInfo);
memcpy(ret, buffer, length);
return ret;
}
char* oatGetSSAString(CompilationUnit* cUnit, SSARepresentation* ssaRep)
{
char buffer[256];
char* ret;
int i;
buffer[0] = 0;
for (i = 0; i < ssaRep->numDefs; i++) {
int ssaReg = ssaRep->defs[i];
sprintf(buffer + strlen(buffer), "s%d(v%d_%d) ", ssaReg,
SRegToVReg(cUnit, ssaReg), SRegToSubscript(cUnit, ssaReg));
}
if (ssaRep->numDefs) {
strcat(buffer, "<- ");
}
for (i = 0; i < ssaRep->numUses; i++) {
int len = strlen(buffer);
int ssaReg = ssaRep->uses[i];
if (snprintf(buffer + len, 250 - len, "s%d(v%d_%d) ", ssaReg,
SRegToVReg(cUnit, ssaReg),
SRegToSubscript(cUnit, ssaReg))) {
strcat(buffer, "...");
break;
}
}
int length = strlen(buffer) + 1;
ret = (char*)oatNew(cUnit, length, false, kAllocDFInfo);
memcpy(ret, buffer, length);
return ret;
}
/* Any register that is used before being defined is considered live-in */
inline void handleLiveInUse(CompilationUnit* cUnit, ArenaBitVector* useV,
ArenaBitVector* defV, ArenaBitVector* liveInV,
int dalvikRegId)
{
oatSetBit(cUnit, useV, dalvikRegId);
if (!oatIsBitSet(defV, dalvikRegId)) {
oatSetBit(cUnit, liveInV, dalvikRegId);
}
}
/* Mark a reg as being defined */
inline void handleDef(CompilationUnit* cUnit, ArenaBitVector* defV,
int dalvikRegId)
{
oatSetBit(cUnit, defV, dalvikRegId);
}
/*
* Find out live-in variables for natural loops. Variables that are live-in in
* the main loop body are considered to be defined in the entry block.
*/
bool oatFindLocalLiveIn(CompilationUnit* cUnit, BasicBlock* bb)
{
MIR* mir;
ArenaBitVector *useV, *defV, *liveInV;
if (bb->dataFlowInfo == NULL) return false;
useV = bb->dataFlowInfo->useV =
oatAllocBitVector(cUnit, cUnit->numDalvikRegisters, false, kBitMapUse);
defV = bb->dataFlowInfo->defV =
oatAllocBitVector(cUnit, cUnit->numDalvikRegisters, false, kBitMapDef);
liveInV = bb->dataFlowInfo->liveInV =
oatAllocBitVector(cUnit, cUnit->numDalvikRegisters, false,
kBitMapLiveIn);
for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
int dfAttributes = oatDataFlowAttributes[mir->dalvikInsn.opcode];
DecodedInstruction *dInsn = &mir->dalvikInsn;
if (dfAttributes & DF_HAS_USES) {
if (dfAttributes & DF_UA) {
handleLiveInUse(cUnit, useV, defV, liveInV, dInsn->vA);
if (dfAttributes & DF_A_WIDE) {
handleLiveInUse(cUnit, useV, defV, liveInV, dInsn->vA+1);
}
}
if (dfAttributes & DF_UB) {
handleLiveInUse(cUnit, useV, defV, liveInV, dInsn->vB);
if (dfAttributes & DF_B_WIDE) {
handleLiveInUse(cUnit, useV, defV, liveInV, dInsn->vB+1);
}
}
if (dfAttributes & DF_UC) {
handleLiveInUse(cUnit, useV, defV, liveInV, dInsn->vC);
if (dfAttributes & DF_C_WIDE) {
handleLiveInUse(cUnit, useV, defV, liveInV, dInsn->vC+1);
}
}
}
if (dfAttributes & DF_FORMAT_35C) {
for (unsigned int i = 0; i < dInsn->vA; i++) {
handleLiveInUse(cUnit, useV, defV, liveInV, dInsn->arg[i]);
}
}
if (dfAttributes & DF_FORMAT_3RC) {
for (unsigned int i = 0; i < dInsn->vA; i++) {
handleLiveInUse(cUnit, useV, defV, liveInV, dInsn->vC+i);
}
}
if (dfAttributes & DF_HAS_DEFS) {
handleDef(cUnit, defV, dInsn->vA);
if (dfAttributes & DF_A_WIDE) {
handleDef(cUnit, defV, dInsn->vA+1);
}
}
}
return true;
}
int addNewSReg(CompilationUnit* cUnit, int vReg)
{
// Compiler temps always have a subscript of 0
int subscript = (vReg < 0) ? 0 : ++cUnit->SSALastDefs[vReg];
int ssaReg = cUnit->numSSARegs++;
oatInsertGrowableList(cUnit, cUnit->ssaBaseVRegs, vReg);
oatInsertGrowableList(cUnit, cUnit->ssaSubscripts, subscript);
DCHECK_EQ(cUnit->ssaBaseVRegs->numUsed, cUnit->ssaSubscripts->numUsed);
return ssaReg;
}
/* Find out the latest SSA register for a given Dalvik register */
void handleSSAUse(CompilationUnit* cUnit, int* uses, int dalvikReg,
int regIndex)
{
DCHECK((dalvikReg >= 0) && (dalvikReg < cUnit->numDalvikRegisters));
uses[regIndex] = cUnit->vRegToSSAMap[dalvikReg];
}
/* Setup a new SSA register for a given Dalvik register */
void handleSSADef(CompilationUnit* cUnit, int* defs, int dalvikReg,
int regIndex)
{
DCHECK((dalvikReg >= 0) && (dalvikReg < cUnit->numDalvikRegisters));
int ssaReg = addNewSReg(cUnit, dalvikReg);
cUnit->vRegToSSAMap[dalvikReg] = ssaReg;
defs[regIndex] = ssaReg;
}
/* Look up new SSA names for format_35c instructions */
void dataFlowSSAFormat35C(CompilationUnit* cUnit, MIR* mir)
{
DecodedInstruction *dInsn = &mir->dalvikInsn;
int numUses = dInsn->vA;
int i;
mir->ssaRep->numUses = numUses;
mir->ssaRep->uses = (int *)oatNew(cUnit, sizeof(int) * numUses, true,
kAllocDFInfo);
// NOTE: will be filled in during type & size inference pass
mir->ssaRep->fpUse = (bool *)oatNew(cUnit, sizeof(bool) * numUses, true,
kAllocDFInfo);
for (i = 0; i < numUses; i++) {
handleSSAUse(cUnit, mir->ssaRep->uses, dInsn->arg[i], i);
}
}
/* Look up new SSA names for format_3rc instructions */
void dataFlowSSAFormat3RC(CompilationUnit* cUnit, MIR* mir)
{
DecodedInstruction *dInsn = &mir->dalvikInsn;
int numUses = dInsn->vA;
int i;
mir->ssaRep->numUses = numUses;
mir->ssaRep->uses = (int *)oatNew(cUnit, sizeof(int) * numUses, true,
kAllocDFInfo);
// NOTE: will be filled in during type & size inference pass
mir->ssaRep->fpUse = (bool *)oatNew(cUnit, sizeof(bool) * numUses, true,
kAllocDFInfo);
for (i = 0; i < numUses; i++) {
handleSSAUse(cUnit, mir->ssaRep->uses, dInsn->vC+i, i);
}
}
/* Entry function to convert a block into SSA representation */
bool oatDoSSAConversion(CompilationUnit* cUnit, BasicBlock* bb)
{
MIR* mir;
if (bb->dataFlowInfo == NULL) return false;
for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
mir->ssaRep = (struct SSARepresentation *)
oatNew(cUnit, sizeof(SSARepresentation), true, kAllocDFInfo);
int dfAttributes = oatDataFlowAttributes[mir->dalvikInsn.opcode];
// If not a pseudo-op, note non-leaf or can throw
if (static_cast<int>(mir->dalvikInsn.opcode) <
static_cast<int>(kNumPackedOpcodes)) {
int flags = Instruction::Flags(mir->dalvikInsn.opcode);
if (flags & Instruction::kThrow) {
cUnit->attrs &= ~METHOD_IS_THROW_FREE;
}
if (flags & Instruction::kInvoke) {
cUnit->attrs &= ~METHOD_IS_LEAF;
}
}
int numUses = 0;
if (dfAttributes & DF_FORMAT_35C) {
dataFlowSSAFormat35C(cUnit, mir);
continue;
}
if (dfAttributes & DF_FORMAT_3RC) {
dataFlowSSAFormat3RC(cUnit, mir);
continue;
}
if (dfAttributes & DF_HAS_USES) {
if (dfAttributes & DF_UA) {
numUses++;
if (dfAttributes & DF_A_WIDE) {
numUses ++;
}
}
if (dfAttributes & DF_UB) {
numUses++;
if (dfAttributes & DF_B_WIDE) {
numUses ++;
}
}
if (dfAttributes & DF_UC) {
numUses++;
if (dfAttributes & DF_C_WIDE) {
numUses ++;
}
}
}
if (numUses) {
mir->ssaRep->numUses = numUses;
mir->ssaRep->uses = (int *)oatNew(cUnit, sizeof(int) * numUses,
false, kAllocDFInfo);
mir->ssaRep->fpUse = (bool *)oatNew(cUnit, sizeof(bool) * numUses,
false, kAllocDFInfo);
}
int numDefs = 0;
if (dfAttributes & DF_HAS_DEFS) {
numDefs++;
if (dfAttributes & DF_A_WIDE) {
numDefs++;
}
}
if (numDefs) {
mir->ssaRep->numDefs = numDefs;
mir->ssaRep->defs = (int *)oatNew(cUnit, sizeof(int) * numDefs,
false, kAllocDFInfo);
mir->ssaRep->fpDef = (bool *)oatNew(cUnit, sizeof(bool) * numDefs,
false, kAllocDFInfo);
}
DecodedInstruction *dInsn = &mir->dalvikInsn;
if (dfAttributes & DF_HAS_USES) {
numUses = 0;
if (dfAttributes & DF_UA) {
mir->ssaRep->fpUse[numUses] = dfAttributes & DF_FP_A;
handleSSAUse(cUnit, mir->ssaRep->uses, dInsn->vA, numUses++);
if (dfAttributes & DF_A_WIDE) {
mir->ssaRep->fpUse[numUses] = dfAttributes & DF_FP_A;
handleSSAUse(cUnit, mir->ssaRep->uses, dInsn->vA+1, numUses++);
}
}
if (dfAttributes & DF_UB) {
mir->ssaRep->fpUse[numUses] = dfAttributes & DF_FP_B;
handleSSAUse(cUnit, mir->ssaRep->uses, dInsn->vB, numUses++);
if (dfAttributes & DF_B_WIDE) {
mir->ssaRep->fpUse[numUses] = dfAttributes & DF_FP_B;
handleSSAUse(cUnit, mir->ssaRep->uses, dInsn->vB+1, numUses++);
}
}
if (dfAttributes & DF_UC) {
mir->ssaRep->fpUse[numUses] = dfAttributes & DF_FP_C;
handleSSAUse(cUnit, mir->ssaRep->uses, dInsn->vC, numUses++);
if (dfAttributes & DF_C_WIDE) {
mir->ssaRep->fpUse[numUses] = dfAttributes & DF_FP_C;
handleSSAUse(cUnit, mir->ssaRep->uses, dInsn->vC+1, numUses++);
}
}
}
if (dfAttributes & DF_HAS_DEFS) {
mir->ssaRep->fpDef[0] = dfAttributes & DF_FP_A;
handleSSADef(cUnit, mir->ssaRep->defs, dInsn->vA, 0);
if (dfAttributes & DF_A_WIDE) {
mir->ssaRep->fpDef[1] = dfAttributes & DF_FP_A;
handleSSADef(cUnit, mir->ssaRep->defs, dInsn->vA+1, 1);
}
}
}
if (!cUnit->disableDataflow) {
/*
* Take a snapshot of Dalvik->SSA mapping at the end of each block. The
* input to PHI nodes can be derived from the snapshot of all
* predecessor blocks.
*/
bb->dataFlowInfo->vRegToSSAMap =
(int *)oatNew(cUnit, sizeof(int) * cUnit->numDalvikRegisters, false,
kAllocDFInfo);
memcpy(bb->dataFlowInfo->vRegToSSAMap, cUnit->vRegToSSAMap,
sizeof(int) * cUnit->numDalvikRegisters);
}
return true;
}
/* Setup a constant value for opcodes thare have the DF_SETS_CONST attribute */
void setConstant(CompilationUnit* cUnit, int ssaReg, int value)
{
oatSetBit(cUnit, cUnit->isConstantV, ssaReg);
cUnit->constantValues[ssaReg] = value;
}
bool oatDoConstantPropagation(CompilationUnit* cUnit, BasicBlock* bb)
{
MIR* mir;
ArenaBitVector *isConstantV = cUnit->isConstantV;
for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
int dfAttributes = oatDataFlowAttributes[mir->dalvikInsn.opcode];
DecodedInstruction *dInsn = &mir->dalvikInsn;
if (!(dfAttributes & DF_HAS_DEFS)) continue;
/* Handle instructions that set up constants directly */
if (dfAttributes & DF_SETS_CONST) {
if (dfAttributes & DF_DA) {
switch (dInsn->opcode) {
case Instruction::CONST_4:
case Instruction::CONST_16:
case Instruction::CONST:
setConstant(cUnit, mir->ssaRep->defs[0], dInsn->vB);
break;
case Instruction::CONST_HIGH16:
setConstant(cUnit, mir->ssaRep->defs[0], dInsn->vB << 16);
break;
case Instruction::CONST_WIDE_16:
case Instruction::CONST_WIDE_32:
setConstant(cUnit, mir->ssaRep->defs[0], dInsn->vB);
setConstant(cUnit, mir->ssaRep->defs[1], 0);
break;
case Instruction::CONST_WIDE:
setConstant(cUnit, mir->ssaRep->defs[0], (int) dInsn->vB_wide);
setConstant(cUnit, mir->ssaRep->defs[1],
(int) (dInsn->vB_wide >> 32));
break;
case Instruction::CONST_WIDE_HIGH16:
setConstant(cUnit, mir->ssaRep->defs[0], 0);
setConstant(cUnit, mir->ssaRep->defs[1], dInsn->vB << 16);
break;
default:
break;
}
}
/* Handle instructions that set up constants directly */
} else if (dfAttributes & DF_IS_MOVE) {
int i;
for (i = 0; i < mir->ssaRep->numUses; i++) {
if (!oatIsBitSet(isConstantV, mir->ssaRep->uses[i])) break;
}
/* Move a register holding a constant to another register */
if (i == mir->ssaRep->numUses) {
setConstant(cUnit, mir->ssaRep->defs[0],
cUnit->constantValues[mir->ssaRep->uses[0]]);
if (dfAttributes & DF_A_WIDE) {
setConstant(cUnit, mir->ssaRep->defs[1],
cUnit->constantValues[mir->ssaRep->uses[1]]);
}
}
}
}
/* TODO: implement code to handle arithmetic operations */
return true;
}
/* Setup the basic data structures for SSA conversion */
void oatInitializeSSAConversion(CompilationUnit* cUnit)
{
int i;
int numDalvikReg = cUnit->numDalvikRegisters;
cUnit->ssaBaseVRegs = (GrowableList *)oatNew(cUnit, sizeof(GrowableList),
false, kAllocDFInfo);
cUnit->ssaSubscripts = (GrowableList *)oatNew(cUnit, sizeof(GrowableList),
false, kAllocDFInfo);
// Create the ssa mappings, estimating the max size
oatInitGrowableList(cUnit, cUnit->ssaBaseVRegs,
numDalvikReg + cUnit->defCount + 128,
kListSSAtoDalvikMap);
oatInitGrowableList(cUnit, cUnit->ssaSubscripts,
numDalvikReg + cUnit->defCount + 128,
kListSSAtoDalvikMap);
/*
* Initial number of SSA registers is equal to the number of Dalvik
* registers.
*/
cUnit->numSSARegs = numDalvikReg;
/*
* Initialize the SSA2Dalvik map list. For the first numDalvikReg elements,
* the subscript is 0 so we use the ENCODE_REG_SUB macro to encode the value
* into "(0 << 16) | i"
*/
for (i = 0; i < numDalvikReg; i++) {
oatInsertGrowableList(cUnit, cUnit->ssaBaseVRegs, i);
oatInsertGrowableList(cUnit, cUnit->ssaSubscripts, 0);
}
/*
* Initialize the DalvikToSSAMap map. There is one entry for each
* Dalvik register, and the SSA names for those are the same.
*/
cUnit->vRegToSSAMap = (int *)oatNew(cUnit, sizeof(int) * numDalvikReg,
false, kAllocDFInfo);
/* Keep track of the higest def for each dalvik reg */
cUnit->SSALastDefs = (int *)oatNew(cUnit, sizeof(int) * numDalvikReg,
false, kAllocDFInfo);
for (i = 0; i < numDalvikReg; i++) {
cUnit->vRegToSSAMap[i] = i;
cUnit->SSALastDefs[i] = 0;
}
/* Add ssa reg for Method* */
cUnit->methodSReg = addNewSReg(cUnit, SSA_METHOD_BASEREG);
/*
* Allocate the BasicBlockDataFlow structure for the entry and code blocks
*/
GrowableListIterator iterator;
oatGrowableListIteratorInit(&cUnit->blockList, &iterator);
while (true) {
BasicBlock* bb = (BasicBlock *) oatGrowableListIteratorNext(&iterator);
if (bb == NULL) break;
if (bb->hidden == true) continue;
if (bb->blockType == kDalvikByteCode ||
bb->blockType == kEntryBlock ||
bb->blockType == kExitBlock) {
bb->dataFlowInfo = (BasicBlockDataFlow *)
oatNew(cUnit, sizeof(BasicBlockDataFlow), true, kAllocDFInfo);
}
}
}
/* Clear the visited flag for each BB */
bool oatClearVisitedFlag(struct CompilationUnit* cUnit, struct BasicBlock* bb)
{
bb->visited = false;
return true;
}
void oatDataFlowAnalysisDispatcher(CompilationUnit* cUnit,
bool (*func)(CompilationUnit*, BasicBlock*),
DataFlowAnalysisMode dfaMode,
bool isIterative)
{
bool change = true;
while (change) {
change = false;
switch (dfaMode) {
/* Scan all blocks and perform the operations specified in func */
case kAllNodes:
{
GrowableListIterator iterator;
oatGrowableListIteratorInit(&cUnit->blockList, &iterator);
while (true) {
BasicBlock* bb =
(BasicBlock *) oatGrowableListIteratorNext(&iterator);
if (bb == NULL) break;
if (bb->hidden == true) continue;
change |= (*func)(cUnit, bb);
}
}
break;
/* Scan reachable blocks and perform the ops specified in func. */
case kReachableNodes:
{
int numReachableBlocks = cUnit->numReachableBlocks;
int idx;
const GrowableList *blockList = &cUnit->blockList;
for (idx = 0; idx < numReachableBlocks; idx++) {
int blockIdx = cUnit->dfsOrder.elemList[idx];
BasicBlock* bb = (BasicBlock *)
oatGrowableListGetElement(blockList, blockIdx);
change |= (*func)(cUnit, bb);
}
}
break;
/* Scan reachable blocks by pre-order dfs and invoke func on each. */
case kPreOrderDFSTraversal:
{
int numReachableBlocks = cUnit->numReachableBlocks;
int idx;
const GrowableList *blockList = &cUnit->blockList;
for (idx = 0; idx < numReachableBlocks; idx++) {
int dfsIdx = cUnit->dfsOrder.elemList[idx];
BasicBlock* bb = (BasicBlock *)
oatGrowableListGetElement(blockList, dfsIdx);
change |= (*func)(cUnit, bb);
}
}
break;
/* Scan reachable blocks post-order dfs and invoke func on each. */
case kPostOrderDFSTraversal:
{
int numReachableBlocks = cUnit->numReachableBlocks;
int idx;
const GrowableList *blockList = &cUnit->blockList;
for (idx = numReachableBlocks - 1; idx >= 0; idx--) {
int dfsIdx = cUnit->dfsOrder.elemList[idx];
BasicBlock* bb = (BasicBlock *)
oatGrowableListGetElement(blockList, dfsIdx);
change |= (*func)(cUnit, bb);
}
}
break;
/* Scan reachable post-order dom tree and invoke func on each. */
case kPostOrderDOMTraversal:
{
int numReachableBlocks = cUnit->numReachableBlocks;
int idx;
const GrowableList *blockList = &cUnit->blockList;
for (idx = 0; idx < numReachableBlocks; idx++) {
int domIdx = cUnit->domPostOrderTraversal.elemList[idx];
BasicBlock* bb = (BasicBlock *)
oatGrowableListGetElement(blockList, domIdx);
change |= (*func)(cUnit, bb);
}
}
break;
/* Scan reachable blocks reverse post-order dfs, invoke func on each */
case kReversePostOrderTraversal:
{
int numReachableBlocks = cUnit->numReachableBlocks;
int idx;
const GrowableList *blockList = &cUnit->blockList;
for (idx = numReachableBlocks - 1; idx >= 0; idx--) {
int revIdx = cUnit->dfsPostOrder.elemList[idx];
BasicBlock* bb = (BasicBlock *)
oatGrowableListGetElement(blockList, revIdx);
change |= (*func)(cUnit, bb);
}
}
break;
default:
LOG(FATAL) << "Unknown traversal mode " << (int)dfaMode;
}
/* If isIterative is false, exit the loop after the first iteration */
change &= isIterative;
}
}
/* Advance to next strictly dominated MIR node in an extended basic block */
MIR* advanceMIR(CompilationUnit* cUnit, BasicBlock** pBb, MIR* mir,
ArenaBitVector* bv, bool clearMark) {
BasicBlock* bb = *pBb;
if (mir != NULL) {
mir = mir->next;
if (mir == NULL) {
bb = bb->fallThrough;
if ((bb == NULL) || bb->predecessors->numUsed != 1) {
mir = NULL;
} else {
if (bv) {
oatSetBit(cUnit, bv, bb->id);
}
*pBb = bb;
mir = bb->firstMIRInsn;
}
}
}
if (mir && clearMark) {
mir->optimizationFlags &= ~MIR_MARK;
}
return mir;
}
/*
* To be used at an invoke mir. If the logically next mir node represents
* a move-result, return it. Else, return NULL. If a move-result exists,
* it is required to immediately follow the invoke with no intervening
* opcodes or incoming arcs. However, if the result of the invoke is not
* used, a move-result may not be present.
*/
MIR* oatFindMoveResult(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir,
bool wide)
{
BasicBlock* tbb = bb;
mir = advanceMIR(cUnit, &tbb, mir, NULL, false);
while (mir != NULL) {
if (!wide && mir->dalvikInsn.opcode == Instruction::MOVE_RESULT) {
break;
}
if (wide && mir->dalvikInsn.opcode == Instruction::MOVE_RESULT_WIDE) {
break;
}
// Keep going if pseudo op, otherwise terminate
if (mir->dalvikInsn.opcode <
static_cast<Instruction::Code>(kNumPackedOpcodes)) {
mir = NULL;
} else {
mir = advanceMIR(cUnit, &tbb, mir, NULL, false);
}
}
return mir;
}
void squashDupRangeChecks(CompilationUnit* cUnit, BasicBlock** pBp, MIR* mir,
int arraySreg, int indexSreg)
{
while (true) {
mir = advanceMIR(cUnit, pBp, mir, NULL, false);
if (!mir) {
break;
}
if ((mir->ssaRep == NULL) ||
(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
continue;
}
int checkArray = INVALID_SREG;
int checkIndex = INVALID_SREG;
switch (mir->dalvikInsn.opcode) {
case Instruction::AGET:
case Instruction::AGET_OBJECT:
case Instruction::AGET_BOOLEAN:
case Instruction::AGET_BYTE:
case Instruction::AGET_CHAR:
case Instruction::AGET_SHORT:
case Instruction::AGET_WIDE:
checkArray = mir->ssaRep->uses[0];
checkIndex = mir->ssaRep->uses[1];
break;
case Instruction::APUT:
case Instruction::APUT_OBJECT:
case Instruction::APUT_SHORT:
case Instruction::APUT_CHAR:
case Instruction::APUT_BYTE:
case Instruction::APUT_BOOLEAN:
checkArray = mir->ssaRep->uses[1];
checkIndex = mir->ssaRep->uses[2];
break;
case Instruction::APUT_WIDE:
checkArray = mir->ssaRep->uses[2];
checkIndex = mir->ssaRep->uses[3];
default:
break;
}
if (checkArray == INVALID_SREG) {
continue;
}
if ((arraySreg == checkArray) && (indexSreg == checkIndex)) {
if (cUnit->printMe) {
LOG(INFO) << "Squashing range check @ 0x" << std::hex << mir->offset;
}
mir->optimizationFlags |= MIR_IGNORE_RANGE_CHECK;
}
}
}
/* Allocate a compiler temp, return Sreg. Reuse existing if no conflict */
int allocCompilerTempSreg(CompilationUnit* cUnit, ArenaBitVector* bv)
{
for (int i = 0; i < cUnit->numCompilerTemps; i++) {
CompilerTemp* ct = (CompilerTemp*)cUnit->compilerTemps.elemList[i];
ArenaBitVector* tBv = ct->bv;
if (!oatTestBitVectors(bv, tBv)) {
// Combine live maps and reuse existing temp
oatUnifyBitVectors(tBv, tBv, bv);
return ct->sReg;
}
}
// Create a new compiler temp & associated live bitmap
CompilerTemp* ct = (CompilerTemp*)oatNew(cUnit, sizeof(CompilerTemp),
true, kAllocMisc);
ArenaBitVector *nBv = oatAllocBitVector(cUnit, cUnit->numBlocks, true,
kBitMapMisc);
oatCopyBitVector(nBv, bv);
ct->bv = nBv;
ct->sReg = addNewSReg(cUnit, SSA_CTEMP_BASEREG - cUnit->numCompilerTemps);
cUnit->numCompilerTemps++;
oatInsertGrowableList(cUnit, &cUnit->compilerTemps, (intptr_t)ct);
DCHECK_EQ(cUnit->numCompilerTemps, (int)cUnit->compilerTemps.numUsed);
return ct->sReg;
}
/* Creata a new MIR node for a new pseudo op. */
MIR* rawMIR(CompilationUnit* cUnit, Instruction::Code opcode, int defs,
int uses)
{
MIR* res = (MIR*)oatNew( cUnit, sizeof(MIR), true, kAllocMIR);
res->ssaRep =(struct SSARepresentation *)
oatNew(cUnit, sizeof(SSARepresentation), true, kAllocDFInfo);
if (uses) {
res->ssaRep->numUses = uses;
res->ssaRep->uses = (int*)oatNew(cUnit, sizeof(int) * uses, false,
kAllocDFInfo);
}
if (defs) {
res->ssaRep->numDefs = defs;
res->ssaRep->defs = (int*)oatNew(cUnit, sizeof(int) * defs, false,
kAllocDFInfo);
res->ssaRep->fpDef = (bool*)oatNew(cUnit, sizeof(bool) * defs, true,
kAllocDFInfo);
}
res->dalvikInsn.opcode = opcode;
return res;
}
/* Do some MIR-level basic block optimizations */
bool basicBlockOpt(CompilationUnit* cUnit, BasicBlock* bb)
{
int numTemps = 0;
for (MIR* mir = bb->firstMIRInsn; mir; mir = mir->next) {
// Look for interesting opcodes, skip otherwise
Instruction::Code opcode = mir->dalvikInsn.opcode;
switch (opcode) {
case Instruction::AGET:
case Instruction::AGET_OBJECT:
case Instruction::AGET_BOOLEAN:
case Instruction::AGET_BYTE:
case Instruction::AGET_CHAR:
case Instruction::AGET_SHORT:
case Instruction::AGET_WIDE:
if (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
int arrSreg = mir->ssaRep->uses[0];
int idxSreg = mir->ssaRep->uses[1];
BasicBlock* tbb = bb;
squashDupRangeChecks(cUnit, &tbb, mir, arrSreg, idxSreg);
}
break;
case Instruction::APUT:
case Instruction::APUT_OBJECT:
case Instruction::APUT_SHORT:
case Instruction::APUT_CHAR:
case Instruction::APUT_BYTE:
case Instruction::APUT_BOOLEAN:
case Instruction::APUT_WIDE:
if (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
int start = (opcode == Instruction::APUT_WIDE) ? 2 : 1;
int arrSreg = mir->ssaRep->uses[start];
int idxSreg = mir->ssaRep->uses[start + 1];
BasicBlock* tbb = bb;
squashDupRangeChecks(cUnit, &tbb, mir, arrSreg, idxSreg);
}
break;
case Instruction::CMPL_FLOAT:
case Instruction::CMPL_DOUBLE:
case Instruction::CMPG_FLOAT:
case Instruction::CMPG_DOUBLE:
case Instruction::CMP_LONG:
if (mir->next != NULL) {
MIR* mirNext = mir->next;
Instruction::Code brOpcode = mirNext->dalvikInsn.opcode;
ConditionCode ccode = kCondNv;
switch(brOpcode) {
case Instruction::IF_EQZ:
ccode = kCondEq;
break;
case Instruction::IF_NEZ:
ccode = kCondNe;
break;
case Instruction::IF_LTZ:
ccode = kCondLt;
break;
case Instruction::IF_GEZ:
ccode = kCondGe;
break;
case Instruction::IF_GTZ:
ccode = kCondGt;
break;
case Instruction::IF_LEZ:
ccode = kCondLe;
break;
default:
break;
}
// Make sure result of cmp is used by next insn and nowhere else
if ((ccode != kCondNv) &&
(mir->ssaRep->defs[0] == mirNext->ssaRep->uses[0]) &&
(getSSAUseCount(cUnit, mir->ssaRep->defs[0]) == 1)) {
mirNext->dalvikInsn.arg[0] = ccode;
switch(opcode) {
case Instruction::CMPL_FLOAT:
mirNext->dalvikInsn.opcode =
static_cast<Instruction::Code>(kMirOpFusedCmplFloat);
break;
case Instruction::CMPL_DOUBLE:
mirNext->dalvikInsn.opcode =
static_cast<Instruction::Code>(kMirOpFusedCmplDouble);
break;
case Instruction::CMPG_FLOAT:
mirNext->dalvikInsn.opcode =
static_cast<Instruction::Code>(kMirOpFusedCmpgFloat);
break;
case Instruction::CMPG_DOUBLE:
mirNext->dalvikInsn.opcode =
static_cast<Instruction::Code>(kMirOpFusedCmpgDouble);
break;
case Instruction::CMP_LONG:
mirNext->dalvikInsn.opcode =
static_cast<Instruction::Code>(kMirOpFusedCmpLong);
break;
default: LOG(ERROR) << "Unexpected opcode: " << (int)opcode;
}
mir->dalvikInsn.opcode = static_cast<Instruction::Code>(kMirOpNop);
mirNext->ssaRep->numUses = mir->ssaRep->numUses;
mirNext->ssaRep->uses = mir->ssaRep->uses;
mirNext->ssaRep->fpUse = mir->ssaRep->fpUse;
mirNext->ssaRep->numDefs = 0;
mir->ssaRep->numUses = 0;
mir->ssaRep->numDefs = 0;
}
}
break;
default:
break;
}
}
if (numTemps > cUnit->numCompilerTemps) {
cUnit->numCompilerTemps = numTemps;
}
return true;
}
bool nullCheckEliminationInit(struct CompilationUnit* cUnit,
struct BasicBlock* bb)
{
if (bb->dataFlowInfo == NULL) return false;
bb->dataFlowInfo->endingNullCheckV =
oatAllocBitVector(cUnit, cUnit->numSSARegs, false, kBitMapNullCheck);
oatClearAllBits(bb->dataFlowInfo->endingNullCheckV);
return true;
}
/* Eliminate unnecessary null checks for a basic block. */
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->access_flags & kAccStatic) == 0) {
// If non-static method, mark "this" as non-null
int thisReg = cUnit->numDalvikRegisters - cUnit->numIns;
oatSetBit(cUnit, cUnit->tempSSARegisterV, thisReg);
}
} else {
// Starting state is intesection of all incoming arcs
GrowableListIterator iter;
oatGrowableListIteratorInit(bb->predecessors, &iter);
BasicBlock* predBB = (BasicBlock*)oatGrowableListIteratorNext(&iter);
DCHECK(predBB != NULL);
oatCopyBitVector(cUnit->tempSSARegisterV,
predBB->dataFlowInfo->endingNullCheckV);
while (true) {
predBB = (BasicBlock*)oatGrowableListIteratorNext(&iter);
if (!predBB) break;
if ((predBB->dataFlowInfo == NULL) ||
(predBB->dataFlowInfo->endingNullCheckV == NULL)) {
continue;
}
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, 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 MOVE_RESULT_OBJECT
if (nextMir &&
nextMir->dalvikInsn.opcode == Instruction::MOVE_RESULT_OBJECT) {
// Mark as null checked
oatSetBit(cUnit, cUnit->tempSSARegisterV, nextMir->ssaRep->defs[0]);
} else {
if (nextMir) {
LOG(WARNING) << "Unexpected opcode following new: "
<< (int)nextMir->dalvikInsn.opcode;
} else if (bb->fallThrough) {
// Look in next basic block
struct BasicBlock* nextBB = bb->fallThrough;
for (MIR* tmir = nextBB->firstMIRInsn; tmir;
tmir =tmir->next) {
if ((int)tmir->dalvikInsn.opcode >= (int)kMirOpFirst) {
continue;
}
// First non-pseudo should be MOVE_RESULT_OBJECT
if (tmir->dalvikInsn.opcode == Instruction::MOVE_RESULT_OBJECT) {
// Mark as null checked
oatSetBit(cUnit, cUnit->tempSSARegisterV, tmir->ssaRep->defs[0]);
} else {
LOG(WARNING) << "Unexpected op after new: "
<< (int)tmir->dalvikInsn.opcode;
}
break;
}
}
}
}
/*
* 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, cUnit->tempSSARegisterV, tgtSreg);
}
}
// Already nullchecked?
if (dfAttributes & DF_HAS_NULL_CHKS) {
int srcIdx;
if (dfAttributes & DF_NULL_CHK_1) {
srcIdx = 1;
} else if (dfAttributes & DF_NULL_CHK_2) {
srcIdx = 2;
} else {
srcIdx = 0;
}
int srcSreg = mir->ssaRep->uses[srcIdx];
if (oatIsBitSet(cUnit->tempSSARegisterV, srcSreg)) {
// Eliminate the null check
mir->optimizationFlags |= MIR_IGNORE_NULL_CHECK;
} else {
// Mark sReg as null-checked
oatSetBit(cUnit, 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 */);
}
}
void oatMethodBasicBlockOptimization(CompilationUnit *cUnit)
{
if (!(cUnit->disableOpt & (1 << kBBOpt))) {
oatInitGrowableList(cUnit, &cUnit->compilerTemps, 6, kListMisc);
DCHECK_EQ(cUnit->numCompilerTemps, 0);
if (!(cUnit->disableOpt & (1 << kBBOpt))) {
oatDataFlowAnalysisDispatcher(cUnit, basicBlockOpt,
kAllNodes, false /* isIterative */);
}
}
}
void addLoopHeader(CompilationUnit* cUnit, BasicBlock* header,
BasicBlock* backEdge)
{
GrowableListIterator iter;
oatGrowableListIteratorInit(&cUnit->loopHeaders, &iter);
for (LoopInfo* loop = (LoopInfo*)oatGrowableListIteratorNext(&iter);
(loop != NULL); loop = (LoopInfo*)oatGrowableListIteratorNext(&iter)) {
if (loop->header == header) {
oatInsertGrowableList(cUnit, &loop->incomingBackEdges,
(intptr_t)backEdge);
return;
}
}
LoopInfo* info = (LoopInfo*)oatNew(cUnit, sizeof(LoopInfo), true,
kAllocDFInfo);
info->header = header;
oatInitGrowableList(cUnit, &info->incomingBackEdges, 2, kListMisc);
oatInsertGrowableList(cUnit, &info->incomingBackEdges, (intptr_t)backEdge);
oatInsertGrowableList(cUnit, &cUnit->loopHeaders, (intptr_t)info);
}
bool findBackEdges(struct CompilationUnit* cUnit, struct BasicBlock* bb)
{
if ((bb->dataFlowInfo == NULL) || (bb->lastMIRInsn == NULL)) {
return false;
}
Instruction::Code opcode = bb->lastMIRInsn->dalvikInsn.opcode;
if (Instruction::Flags(opcode) & Instruction::kBranch) {
if (bb->taken && (bb->taken->startOffset <= bb->startOffset)) {
DCHECK(bb->dominators != NULL);
if (oatIsBitSet(bb->dominators, bb->taken->id)) {
if (cUnit->printMe) {
LOG(INFO) << "Loop backedge from 0x"
<< std::hex << bb->lastMIRInsn->offset
<< " to 0x" << std::hex << bb->taken->startOffset;
}
addLoopHeader(cUnit, bb->taken, bb);
}
}
}
return false;
}
void addBlocksToLoop(CompilationUnit* cUnit, ArenaBitVector* blocks,
BasicBlock* bb, int headId)
{
if (!oatIsBitSet(bb->dominators, headId) ||
oatIsBitSet(blocks, bb->id)) {
return;
}
oatSetBit(cUnit, blocks, bb->id);
GrowableListIterator iter;
oatGrowableListIteratorInit(bb->predecessors, &iter);
BasicBlock* predBB;
for (predBB = (BasicBlock*)oatGrowableListIteratorNext(&iter); predBB;
predBB = (BasicBlock*)oatGrowableListIteratorNext(&iter)) {
addBlocksToLoop(cUnit, blocks, predBB, headId);
}
}
void oatDumpLoops(CompilationUnit *cUnit)
{
GrowableListIterator iter;
oatGrowableListIteratorInit(&cUnit->loopHeaders, &iter);
for (LoopInfo* loop = (LoopInfo*)oatGrowableListIteratorNext(&iter);
(loop != NULL); loop = (LoopInfo*)oatGrowableListIteratorNext(&iter)) {
LOG(INFO) << "Loop head block id " << loop->header->id
<< ", offset 0x" << std::hex << loop->header->startOffset
<< ", Depth: " << loop->header->nestingDepth;
GrowableListIterator iter;
oatGrowableListIteratorInit(&loop->incomingBackEdges, &iter);
BasicBlock* edgeBB;
for (edgeBB = (BasicBlock*)oatGrowableListIteratorNext(&iter); edgeBB;
edgeBB = (BasicBlock*)oatGrowableListIteratorNext(&iter)) {
LOG(INFO) << " Backedge block id " << edgeBB->id
<< ", offset 0x" << std::hex << edgeBB->startOffset;
ArenaBitVectorIterator bIter;
oatBitVectorIteratorInit(loop->blocks, &bIter);
for (int bbId = oatBitVectorIteratorNext(&bIter); bbId != -1;
bbId = oatBitVectorIteratorNext(&bIter)) {
BasicBlock *bb;
bb = (BasicBlock*)
oatGrowableListGetElement(&cUnit->blockList, bbId);
LOG(INFO) << " (" << bb->id << ", 0x" << std::hex
<< bb->startOffset << ")";
}
}
}
}
void oatMethodLoopDetection(CompilationUnit *cUnit)
{
if (cUnit->disableOpt & (1 << kPromoteRegs)) {
return;
}
oatInitGrowableList(cUnit, &cUnit->loopHeaders, 6, kListMisc);
// Find the loop headers
oatDataFlowAnalysisDispatcher(cUnit, findBackEdges,
kAllNodes, false /* isIterative */);
GrowableListIterator iter;
oatGrowableListIteratorInit(&cUnit->loopHeaders, &iter);
// Add blocks to each header
for (LoopInfo* loop = (LoopInfo*)oatGrowableListIteratorNext(&iter);
loop; loop = (LoopInfo*)oatGrowableListIteratorNext(&iter)) {
loop->blocks = oatAllocBitVector(cUnit, cUnit->numBlocks, true,
kBitMapMisc);
oatSetBit(cUnit, loop->blocks, loop->header->id);
GrowableListIterator iter;
oatGrowableListIteratorInit(&loop->incomingBackEdges, &iter);
BasicBlock* edgeBB;
for (edgeBB = (BasicBlock*)oatGrowableListIteratorNext(&iter); edgeBB;
edgeBB = (BasicBlock*)oatGrowableListIteratorNext(&iter)) {
addBlocksToLoop(cUnit, loop->blocks, edgeBB, loop->header->id);
}
}
// Compute the nesting depth of each header
oatGrowableListIteratorInit(&cUnit->loopHeaders, &iter);
for (LoopInfo* loop = (LoopInfo*)oatGrowableListIteratorNext(&iter);
loop; loop = (LoopInfo*)oatGrowableListIteratorNext(&iter)) {
GrowableListIterator iter2;
oatGrowableListIteratorInit(&cUnit->loopHeaders, &iter2);
LoopInfo* loop2;
for (loop2 = (LoopInfo*)oatGrowableListIteratorNext(&iter2);
loop2; loop2 = (LoopInfo*)oatGrowableListIteratorNext(&iter2)) {
if (oatIsBitSet(loop2->blocks, loop->header->id)) {
loop->header->nestingDepth++;
}
}
}
// Assign nesting depth to each block in all loops
oatGrowableListIteratorInit(&cUnit->loopHeaders, &iter);
for (LoopInfo* loop = (LoopInfo*)oatGrowableListIteratorNext(&iter);
(loop != NULL); loop = (LoopInfo*)oatGrowableListIteratorNext(&iter)) {
ArenaBitVectorIterator bIter;
oatBitVectorIteratorInit(loop->blocks, &bIter);
for (int bbId = oatBitVectorIteratorNext(&bIter); bbId != -1;
bbId = oatBitVectorIteratorNext(&bIter)) {
BasicBlock *bb;
bb = (BasicBlock*) oatGrowableListGetElement(&cUnit->blockList, bbId);
bb->nestingDepth = std::max(bb->nestingDepth,
loop->header->nestingDepth);
}
}
if (cUnit->printMe) {
oatDumpLoops(cUnit);
}
}
/*
* This function will make a best guess at whether the invoke will
* end up using Method*. It isn't critical to get it exactly right,
* and attempting to do would involve more complexity than it's
* worth.
*/
bool invokeUsesMethodStar(CompilationUnit* cUnit, MIR* mir)
{
InvokeType type;
Instruction::Code opcode = mir->dalvikInsn.opcode;
switch (opcode) {
case Instruction::INVOKE_STATIC:
case Instruction::INVOKE_STATIC_RANGE:
type = kStatic;
break;
case Instruction::INVOKE_DIRECT:
case Instruction::INVOKE_DIRECT_RANGE:
type = kDirect;
break;
case Instruction::INVOKE_VIRTUAL:
case Instruction::INVOKE_VIRTUAL_RANGE:
type = kVirtual;
break;
case Instruction::INVOKE_INTERFACE:
case Instruction::INVOKE_INTERFACE_RANGE:
return false;
case Instruction::INVOKE_SUPER_RANGE:
case Instruction::INVOKE_SUPER:
type = kSuper;
break;
default:
LOG(WARNING) << "Unexpected invoke op: " << (int)opcode;
return false;
}
OatCompilationUnit mUnit(cUnit->class_loader, cUnit->class_linker,
*cUnit->dex_file, *cUnit->dex_cache,
cUnit->code_item, cUnit->method_idx,
cUnit->access_flags);
// TODO: add a flag so we don't counts the stats for this twice
uint32_t dexMethodIdx = mir->dalvikInsn.vB;
int vtableIdx;
uintptr_t directCode;
uintptr_t directMethod;
bool fastPath =
cUnit->compiler->ComputeInvokeInfo(dexMethodIdx, &mUnit, type,
vtableIdx, directCode,
directMethod) &&
!SLOW_INVOKE_PATH;
return (((type == kDirect) || (type == kStatic)) &&
fastPath && ((directCode == 0) || (directMethod == 0)));
}
/*
* Count uses, weighting by loop nesting depth. This code only
* counts explicitly used sRegs. A later phase will add implicit
* counts for things such as Method*, null-checked references, etc.
*/
bool countUses(struct CompilationUnit* cUnit, struct BasicBlock* bb)
{
if (bb->blockType != kDalvikByteCode) {
return false;
}
for (MIR* mir = bb->firstMIRInsn; (mir != NULL); mir = mir->next) {
if (mir->ssaRep == NULL) {
continue;
}
uint32_t weight = std::min(16U, (uint32_t)bb->nestingDepth);
for (int i = 0; i < mir->ssaRep->numUses; i++) {
int sReg = mir->ssaRep->uses[i];
DCHECK_LT(sReg, (int)cUnit->useCounts.numUsed);
cUnit->rawUseCounts.elemList[sReg]++;
cUnit->useCounts.elemList[sReg] += (1 << weight);
}
if (!(cUnit->disableOpt & (1 << kPromoteCompilerTemps))) {
int dfAttributes = oatDataFlowAttributes[mir->dalvikInsn.opcode];
// Implicit use of Method* ? */
if (dfAttributes & DF_UMS) {
/*
* Some invokes will not use Method* - need to perform test similar
* to that found in genInvoke() to decide whether to count refs
* for Method* on invoke-class opcodes.
* TODO: refactor for common test here, save results for genInvoke
*/
int usesMethodStar = true;
if ((dfAttributes & (DF_FORMAT_35C | DF_FORMAT_3RC)) &&
!(dfAttributes & DF_NON_NULL_RET)) {
usesMethodStar &= invokeUsesMethodStar(cUnit, mir);
}
if (usesMethodStar) {
cUnit->rawUseCounts.elemList[cUnit->methodSReg]++;
cUnit->useCounts.elemList[cUnit->methodSReg] += (1 << weight);
}
}
}
}
return false;
}
void oatMethodUseCount(CompilationUnit *cUnit)
{
oatInitGrowableList(cUnit, &cUnit->useCounts, cUnit->numSSARegs + 32,
kListMisc);
oatInitGrowableList(cUnit, &cUnit->rawUseCounts, cUnit->numSSARegs + 32,
kListMisc);
// Initialize list
for (int i = 0; i < cUnit->numSSARegs; i++) {
oatInsertGrowableList(cUnit, &cUnit->useCounts, 0);
oatInsertGrowableList(cUnit, &cUnit->rawUseCounts, 0);
}
if (cUnit->disableOpt & (1 << kPromoteRegs)) {
return;
}
oatDataFlowAnalysisDispatcher(cUnit, countUses,
kAllNodes, false /* isIterative */);
}
} // namespace art