Home | History | Annotate | Download | only in optimizing
      1 /*
      2  * Copyright (C) 2016 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "scheduler_arm64.h"
     18 
     19 #include "code_generator_utils.h"
     20 #include "mirror/array-inl.h"
     21 #include "mirror/string.h"
     22 
     23 namespace art {
     24 namespace arm64 {
     25 
     26 void SchedulingLatencyVisitorARM64::VisitBinaryOperation(HBinaryOperation* instr) {
     27   last_visited_latency_ = DataType::IsFloatingPointType(instr->GetResultType())
     28       ? kArm64FloatingPointOpLatency
     29       : kArm64IntegerOpLatency;
     30 }
     31 
     32 void SchedulingLatencyVisitorARM64::VisitBitwiseNegatedRight(
     33     HBitwiseNegatedRight* ATTRIBUTE_UNUSED) {
     34   last_visited_latency_ = kArm64IntegerOpLatency;
     35 }
     36 
     37 void SchedulingLatencyVisitorARM64::VisitDataProcWithShifterOp(
     38     HDataProcWithShifterOp* ATTRIBUTE_UNUSED) {
     39   last_visited_latency_ = kArm64DataProcWithShifterOpLatency;
     40 }
     41 
     42 void SchedulingLatencyVisitorARM64::VisitIntermediateAddress(
     43     HIntermediateAddress* ATTRIBUTE_UNUSED) {
     44   // Although the code generated is a simple `add` instruction, we found through empirical results
     45   // that spacing it from its use in memory accesses was beneficial.
     46   last_visited_latency_ = kArm64IntegerOpLatency + 2;
     47 }
     48 
     49 void SchedulingLatencyVisitorARM64::VisitIntermediateAddressIndex(
     50     HIntermediateAddressIndex* instr ATTRIBUTE_UNUSED) {
     51   // Although the code generated is a simple `add` instruction, we found through empirical results
     52   // that spacing it from its use in memory accesses was beneficial.
     53   last_visited_latency_ = kArm64DataProcWithShifterOpLatency + 2;
     54 }
     55 
     56 void SchedulingLatencyVisitorARM64::VisitMultiplyAccumulate(HMultiplyAccumulate* ATTRIBUTE_UNUSED) {
     57   last_visited_latency_ = kArm64MulIntegerLatency;
     58 }
     59 
     60 void SchedulingLatencyVisitorARM64::VisitArrayGet(HArrayGet* instruction) {
     61   if (!instruction->GetArray()->IsIntermediateAddress()) {
     62     // Take the intermediate address computation into account.
     63     last_visited_internal_latency_ = kArm64IntegerOpLatency;
     64   }
     65   last_visited_latency_ = kArm64MemoryLoadLatency;
     66 }
     67 
     68 void SchedulingLatencyVisitorARM64::VisitArrayLength(HArrayLength* ATTRIBUTE_UNUSED) {
     69   last_visited_latency_ = kArm64MemoryLoadLatency;
     70 }
     71 
     72 void SchedulingLatencyVisitorARM64::VisitArraySet(HArraySet* ATTRIBUTE_UNUSED) {
     73   last_visited_latency_ = kArm64MemoryStoreLatency;
     74 }
     75 
     76 void SchedulingLatencyVisitorARM64::VisitBoundsCheck(HBoundsCheck* ATTRIBUTE_UNUSED) {
     77   last_visited_internal_latency_ = kArm64IntegerOpLatency;
     78   // Users do not use any data results.
     79   last_visited_latency_ = 0;
     80 }
     81 
     82 void SchedulingLatencyVisitorARM64::VisitDiv(HDiv* instr) {
     83   DataType::Type type = instr->GetResultType();
     84   switch (type) {
     85     case DataType::Type::kFloat32:
     86       last_visited_latency_ = kArm64DivFloatLatency;
     87       break;
     88     case DataType::Type::kFloat64:
     89       last_visited_latency_ = kArm64DivDoubleLatency;
     90       break;
     91     default:
     92       // Follow the code path used by code generation.
     93       if (instr->GetRight()->IsConstant()) {
     94         int64_t imm = Int64FromConstant(instr->GetRight()->AsConstant());
     95         if (imm == 0) {
     96           last_visited_internal_latency_ = 0;
     97           last_visited_latency_ = 0;
     98         } else if (imm == 1 || imm == -1) {
     99           last_visited_internal_latency_ = 0;
    100           last_visited_latency_ = kArm64IntegerOpLatency;
    101         } else if (IsPowerOfTwo(AbsOrMin(imm))) {
    102           last_visited_internal_latency_ = 4 * kArm64IntegerOpLatency;
    103           last_visited_latency_ = kArm64IntegerOpLatency;
    104         } else {
    105           DCHECK(imm <= -2 || imm >= 2);
    106           last_visited_internal_latency_ = 4 * kArm64IntegerOpLatency;
    107           last_visited_latency_ = kArm64MulIntegerLatency;
    108         }
    109       } else {
    110         last_visited_latency_ = kArm64DivIntegerLatency;
    111       }
    112       break;
    113   }
    114 }
    115 
    116 void SchedulingLatencyVisitorARM64::VisitInstanceFieldGet(HInstanceFieldGet* ATTRIBUTE_UNUSED) {
    117   last_visited_latency_ = kArm64MemoryLoadLatency;
    118 }
    119 
    120 void SchedulingLatencyVisitorARM64::VisitInstanceOf(HInstanceOf* ATTRIBUTE_UNUSED) {
    121   last_visited_internal_latency_ = kArm64CallInternalLatency;
    122   last_visited_latency_ = kArm64IntegerOpLatency;
    123 }
    124 
    125 void SchedulingLatencyVisitorARM64::VisitInvoke(HInvoke* ATTRIBUTE_UNUSED) {
    126   last_visited_internal_latency_ = kArm64CallInternalLatency;
    127   last_visited_latency_ = kArm64CallLatency;
    128 }
    129 
    130 void SchedulingLatencyVisitorARM64::VisitLoadString(HLoadString* ATTRIBUTE_UNUSED) {
    131   last_visited_internal_latency_ = kArm64LoadStringInternalLatency;
    132   last_visited_latency_ = kArm64MemoryLoadLatency;
    133 }
    134 
    135 void SchedulingLatencyVisitorARM64::VisitMul(HMul* instr) {
    136   last_visited_latency_ = DataType::IsFloatingPointType(instr->GetResultType())
    137       ? kArm64MulFloatingPointLatency
    138       : kArm64MulIntegerLatency;
    139 }
    140 
    141 void SchedulingLatencyVisitorARM64::VisitNewArray(HNewArray* ATTRIBUTE_UNUSED) {
    142   last_visited_internal_latency_ = kArm64IntegerOpLatency + kArm64CallInternalLatency;
    143   last_visited_latency_ = kArm64CallLatency;
    144 }
    145 
    146 void SchedulingLatencyVisitorARM64::VisitNewInstance(HNewInstance* instruction) {
    147   if (instruction->IsStringAlloc()) {
    148     last_visited_internal_latency_ = 2 + kArm64MemoryLoadLatency + kArm64CallInternalLatency;
    149   } else {
    150     last_visited_internal_latency_ = kArm64CallInternalLatency;
    151   }
    152   last_visited_latency_ = kArm64CallLatency;
    153 }
    154 
    155 void SchedulingLatencyVisitorARM64::VisitRem(HRem* instruction) {
    156   if (DataType::IsFloatingPointType(instruction->GetResultType())) {
    157     last_visited_internal_latency_ = kArm64CallInternalLatency;
    158     last_visited_latency_ = kArm64CallLatency;
    159   } else {
    160     // Follow the code path used by code generation.
    161     if (instruction->GetRight()->IsConstant()) {
    162       int64_t imm = Int64FromConstant(instruction->GetRight()->AsConstant());
    163       if (imm == 0) {
    164         last_visited_internal_latency_ = 0;
    165         last_visited_latency_ = 0;
    166       } else if (imm == 1 || imm == -1) {
    167         last_visited_internal_latency_ = 0;
    168         last_visited_latency_ = kArm64IntegerOpLatency;
    169       } else if (IsPowerOfTwo(AbsOrMin(imm))) {
    170         last_visited_internal_latency_ = 4 * kArm64IntegerOpLatency;
    171         last_visited_latency_ = kArm64IntegerOpLatency;
    172       } else {
    173         DCHECK(imm <= -2 || imm >= 2);
    174         last_visited_internal_latency_ = 4 * kArm64IntegerOpLatency;
    175         last_visited_latency_ = kArm64MulIntegerLatency;
    176       }
    177     } else {
    178       last_visited_internal_latency_ = kArm64DivIntegerLatency;
    179       last_visited_latency_ = kArm64MulIntegerLatency;
    180     }
    181   }
    182 }
    183 
    184 void SchedulingLatencyVisitorARM64::VisitStaticFieldGet(HStaticFieldGet* ATTRIBUTE_UNUSED) {
    185   last_visited_latency_ = kArm64MemoryLoadLatency;
    186 }
    187 
    188 void SchedulingLatencyVisitorARM64::VisitSuspendCheck(HSuspendCheck* instruction) {
    189   HBasicBlock* block = instruction->GetBlock();
    190   DCHECK((block->GetLoopInformation() != nullptr) ||
    191          (block->IsEntryBlock() && instruction->GetNext()->IsGoto()));
    192   // Users do not use any data results.
    193   last_visited_latency_ = 0;
    194 }
    195 
    196 void SchedulingLatencyVisitorARM64::VisitTypeConversion(HTypeConversion* instr) {
    197   if (DataType::IsFloatingPointType(instr->GetResultType()) ||
    198       DataType::IsFloatingPointType(instr->GetInputType())) {
    199     last_visited_latency_ = kArm64TypeConversionFloatingPointIntegerLatency;
    200   } else {
    201     last_visited_latency_ = kArm64IntegerOpLatency;
    202   }
    203 }
    204 
    205 void SchedulingLatencyVisitorARM64::HandleSimpleArithmeticSIMD(HVecOperation *instr) {
    206   if (DataType::IsFloatingPointType(instr->GetPackedType())) {
    207     last_visited_latency_ = kArm64SIMDFloatingPointOpLatency;
    208   } else {
    209     last_visited_latency_ = kArm64SIMDIntegerOpLatency;
    210   }
    211 }
    212 
    213 void SchedulingLatencyVisitorARM64::VisitVecReplicateScalar(
    214     HVecReplicateScalar* instr ATTRIBUTE_UNUSED) {
    215   last_visited_latency_ = kArm64SIMDReplicateOpLatency;
    216 }
    217 
    218 void SchedulingLatencyVisitorARM64::VisitVecExtractScalar(HVecExtractScalar* instr) {
    219   HandleSimpleArithmeticSIMD(instr);
    220 }
    221 
    222 void SchedulingLatencyVisitorARM64::VisitVecReduce(HVecReduce* instr) {
    223   HandleSimpleArithmeticSIMD(instr);
    224 }
    225 
    226 void SchedulingLatencyVisitorARM64::VisitVecCnv(HVecCnv* instr ATTRIBUTE_UNUSED) {
    227   last_visited_latency_ = kArm64SIMDTypeConversionInt2FPLatency;
    228 }
    229 
    230 void SchedulingLatencyVisitorARM64::VisitVecNeg(HVecNeg* instr) {
    231   HandleSimpleArithmeticSIMD(instr);
    232 }
    233 
    234 void SchedulingLatencyVisitorARM64::VisitVecAbs(HVecAbs* instr) {
    235   HandleSimpleArithmeticSIMD(instr);
    236 }
    237 
    238 void SchedulingLatencyVisitorARM64::VisitVecNot(HVecNot* instr) {
    239   if (instr->GetPackedType() == DataType::Type::kBool) {
    240     last_visited_internal_latency_ = kArm64SIMDIntegerOpLatency;
    241   }
    242   last_visited_latency_ = kArm64SIMDIntegerOpLatency;
    243 }
    244 
    245 void SchedulingLatencyVisitorARM64::VisitVecAdd(HVecAdd* instr) {
    246   HandleSimpleArithmeticSIMD(instr);
    247 }
    248 
    249 void SchedulingLatencyVisitorARM64::VisitVecHalvingAdd(HVecHalvingAdd* instr) {
    250   HandleSimpleArithmeticSIMD(instr);
    251 }
    252 
    253 void SchedulingLatencyVisitorARM64::VisitVecSub(HVecSub* instr) {
    254   HandleSimpleArithmeticSIMD(instr);
    255 }
    256 
    257 void SchedulingLatencyVisitorARM64::VisitVecMul(HVecMul* instr) {
    258   if (DataType::IsFloatingPointType(instr->GetPackedType())) {
    259     last_visited_latency_ = kArm64SIMDMulFloatingPointLatency;
    260   } else {
    261     last_visited_latency_ = kArm64SIMDMulIntegerLatency;
    262   }
    263 }
    264 
    265 void SchedulingLatencyVisitorARM64::VisitVecDiv(HVecDiv* instr) {
    266   if (instr->GetPackedType() == DataType::Type::kFloat32) {
    267     last_visited_latency_ = kArm64SIMDDivFloatLatency;
    268   } else {
    269     DCHECK(instr->GetPackedType() == DataType::Type::kFloat64);
    270     last_visited_latency_ = kArm64SIMDDivDoubleLatency;
    271   }
    272 }
    273 
    274 void SchedulingLatencyVisitorARM64::VisitVecMin(HVecMin* instr) {
    275   HandleSimpleArithmeticSIMD(instr);
    276 }
    277 
    278 void SchedulingLatencyVisitorARM64::VisitVecMax(HVecMax* instr) {
    279   HandleSimpleArithmeticSIMD(instr);
    280 }
    281 
    282 void SchedulingLatencyVisitorARM64::VisitVecAnd(HVecAnd* instr ATTRIBUTE_UNUSED) {
    283   last_visited_latency_ = kArm64SIMDIntegerOpLatency;
    284 }
    285 
    286 void SchedulingLatencyVisitorARM64::VisitVecAndNot(HVecAndNot* instr ATTRIBUTE_UNUSED) {
    287   last_visited_latency_ = kArm64SIMDIntegerOpLatency;
    288 }
    289 
    290 void SchedulingLatencyVisitorARM64::VisitVecOr(HVecOr* instr ATTRIBUTE_UNUSED) {
    291   last_visited_latency_ = kArm64SIMDIntegerOpLatency;
    292 }
    293 
    294 void SchedulingLatencyVisitorARM64::VisitVecXor(HVecXor* instr ATTRIBUTE_UNUSED) {
    295   last_visited_latency_ = kArm64SIMDIntegerOpLatency;
    296 }
    297 
    298 void SchedulingLatencyVisitorARM64::VisitVecShl(HVecShl* instr) {
    299   HandleSimpleArithmeticSIMD(instr);
    300 }
    301 
    302 void SchedulingLatencyVisitorARM64::VisitVecShr(HVecShr* instr) {
    303   HandleSimpleArithmeticSIMD(instr);
    304 }
    305 
    306 void SchedulingLatencyVisitorARM64::VisitVecUShr(HVecUShr* instr) {
    307   HandleSimpleArithmeticSIMD(instr);
    308 }
    309 
    310 void SchedulingLatencyVisitorARM64::VisitVecSetScalars(HVecSetScalars* instr) {
    311   HandleSimpleArithmeticSIMD(instr);
    312 }
    313 
    314 void SchedulingLatencyVisitorARM64::VisitVecMultiplyAccumulate(
    315     HVecMultiplyAccumulate* instr ATTRIBUTE_UNUSED) {
    316   last_visited_latency_ = kArm64SIMDMulIntegerLatency;
    317 }
    318 
    319 void SchedulingLatencyVisitorARM64::HandleVecAddress(
    320     HVecMemoryOperation* instruction,
    321     size_t size ATTRIBUTE_UNUSED) {
    322   HInstruction* index = instruction->InputAt(1);
    323   if (!index->IsConstant()) {
    324     last_visited_internal_latency_ += kArm64DataProcWithShifterOpLatency;
    325   }
    326 }
    327 
    328 void SchedulingLatencyVisitorARM64::VisitVecLoad(HVecLoad* instr) {
    329   last_visited_internal_latency_ = 0;
    330   size_t size = DataType::Size(instr->GetPackedType());
    331 
    332   if (instr->GetPackedType() == DataType::Type::kUint16
    333       && mirror::kUseStringCompression
    334       && instr->IsStringCharAt()) {
    335     // Set latencies for the uncompressed case.
    336     last_visited_internal_latency_ += kArm64MemoryLoadLatency + kArm64BranchLatency;
    337     HandleVecAddress(instr, size);
    338     last_visited_latency_ = kArm64SIMDMemoryLoadLatency;
    339   } else {
    340     HandleVecAddress(instr, size);
    341     last_visited_latency_ = kArm64SIMDMemoryLoadLatency;
    342   }
    343 }
    344 
    345 void SchedulingLatencyVisitorARM64::VisitVecStore(HVecStore* instr) {
    346   last_visited_internal_latency_ = 0;
    347   size_t size = DataType::Size(instr->GetPackedType());
    348   HandleVecAddress(instr, size);
    349   last_visited_latency_ = kArm64SIMDMemoryStoreLatency;
    350 }
    351 
    352 }  // namespace arm64
    353 }  // namespace art
    354