Home | History | Annotate | Download | only in optimizing
      1 /*
      2  * Copyright (C) 2015 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 #ifndef ART_COMPILER_OPTIMIZING_COMMON_ARM64_H_
     18 #define ART_COMPILER_OPTIMIZING_COMMON_ARM64_H_
     19 
     20 #include "locations.h"
     21 #include "nodes.h"
     22 #include "utils/arm64/assembler_arm64.h"
     23 #include "vixl/a64/disasm-a64.h"
     24 #include "vixl/a64/macro-assembler-a64.h"
     25 
     26 namespace art {
     27 namespace arm64 {
     28 namespace helpers {
     29 
     30 // Convenience helpers to ease conversion to and from VIXL operands.
     31 static_assert((SP == 31) && (WSP == 31) && (XZR == 32) && (WZR == 32),
     32               "Unexpected values for register codes.");
     33 
     34 static inline int VIXLRegCodeFromART(int code) {
     35   if (code == SP) {
     36     return vixl::kSPRegInternalCode;
     37   }
     38   if (code == XZR) {
     39     return vixl::kZeroRegCode;
     40   }
     41   return code;
     42 }
     43 
     44 static inline int ARTRegCodeFromVIXL(int code) {
     45   if (code == vixl::kSPRegInternalCode) {
     46     return SP;
     47   }
     48   if (code == vixl::kZeroRegCode) {
     49     return XZR;
     50   }
     51   return code;
     52 }
     53 
     54 static inline vixl::Register XRegisterFrom(Location location) {
     55   DCHECK(location.IsRegister());
     56   return vixl::Register::XRegFromCode(VIXLRegCodeFromART(location.reg()));
     57 }
     58 
     59 static inline vixl::Register WRegisterFrom(Location location) {
     60   DCHECK(location.IsRegister());
     61   return vixl::Register::WRegFromCode(VIXLRegCodeFromART(location.reg()));
     62 }
     63 
     64 static inline vixl::Register RegisterFrom(Location location, Primitive::Type type) {
     65   DCHECK(type != Primitive::kPrimVoid && !Primitive::IsFloatingPointType(type));
     66   return type == Primitive::kPrimLong ? XRegisterFrom(location) : WRegisterFrom(location);
     67 }
     68 
     69 static inline vixl::Register OutputRegister(HInstruction* instr) {
     70   return RegisterFrom(instr->GetLocations()->Out(), instr->GetType());
     71 }
     72 
     73 static inline vixl::Register InputRegisterAt(HInstruction* instr, int input_index) {
     74   return RegisterFrom(instr->GetLocations()->InAt(input_index),
     75                       instr->InputAt(input_index)->GetType());
     76 }
     77 
     78 static inline vixl::FPRegister DRegisterFrom(Location location) {
     79   DCHECK(location.IsFpuRegister());
     80   return vixl::FPRegister::DRegFromCode(location.reg());
     81 }
     82 
     83 static inline vixl::FPRegister SRegisterFrom(Location location) {
     84   DCHECK(location.IsFpuRegister());
     85   return vixl::FPRegister::SRegFromCode(location.reg());
     86 }
     87 
     88 static inline vixl::FPRegister FPRegisterFrom(Location location, Primitive::Type type) {
     89   DCHECK(Primitive::IsFloatingPointType(type));
     90   return type == Primitive::kPrimDouble ? DRegisterFrom(location) : SRegisterFrom(location);
     91 }
     92 
     93 static inline vixl::FPRegister OutputFPRegister(HInstruction* instr) {
     94   return FPRegisterFrom(instr->GetLocations()->Out(), instr->GetType());
     95 }
     96 
     97 static inline vixl::FPRegister InputFPRegisterAt(HInstruction* instr, int input_index) {
     98   return FPRegisterFrom(instr->GetLocations()->InAt(input_index),
     99                         instr->InputAt(input_index)->GetType());
    100 }
    101 
    102 static inline vixl::CPURegister CPURegisterFrom(Location location, Primitive::Type type) {
    103   return Primitive::IsFloatingPointType(type) ? vixl::CPURegister(FPRegisterFrom(location, type))
    104                                               : vixl::CPURegister(RegisterFrom(location, type));
    105 }
    106 
    107 static inline vixl::CPURegister OutputCPURegister(HInstruction* instr) {
    108   return Primitive::IsFloatingPointType(instr->GetType())
    109       ? static_cast<vixl::CPURegister>(OutputFPRegister(instr))
    110       : static_cast<vixl::CPURegister>(OutputRegister(instr));
    111 }
    112 
    113 static inline vixl::CPURegister InputCPURegisterAt(HInstruction* instr, int index) {
    114   return Primitive::IsFloatingPointType(instr->InputAt(index)->GetType())
    115       ? static_cast<vixl::CPURegister>(InputFPRegisterAt(instr, index))
    116       : static_cast<vixl::CPURegister>(InputRegisterAt(instr, index));
    117 }
    118 
    119 static inline int64_t Int64ConstantFrom(Location location) {
    120   HConstant* instr = location.GetConstant();
    121   if (instr->IsIntConstant()) {
    122     return instr->AsIntConstant()->GetValue();
    123   } else if (instr->IsNullConstant()) {
    124     return 0;
    125   } else {
    126     DCHECK(instr->IsLongConstant());
    127     return instr->AsLongConstant()->GetValue();
    128   }
    129 }
    130 
    131 static inline vixl::Operand OperandFrom(Location location, Primitive::Type type) {
    132   if (location.IsRegister()) {
    133     return vixl::Operand(RegisterFrom(location, type));
    134   } else {
    135     return vixl::Operand(Int64ConstantFrom(location));
    136   }
    137 }
    138 
    139 static inline vixl::Operand InputOperandAt(HInstruction* instr, int input_index) {
    140   return OperandFrom(instr->GetLocations()->InAt(input_index),
    141                      instr->InputAt(input_index)->GetType());
    142 }
    143 
    144 static inline vixl::MemOperand StackOperandFrom(Location location) {
    145   return vixl::MemOperand(vixl::sp, location.GetStackIndex());
    146 }
    147 
    148 static inline vixl::MemOperand HeapOperand(const vixl::Register& base, size_t offset = 0) {
    149   // A heap reference must be 32bit, so fit in a W register.
    150   DCHECK(base.IsW());
    151   return vixl::MemOperand(base.X(), offset);
    152 }
    153 
    154 static inline vixl::MemOperand HeapOperand(const vixl::Register& base, Offset offset) {
    155   return HeapOperand(base, offset.SizeValue());
    156 }
    157 
    158 static inline vixl::MemOperand HeapOperandFrom(Location location, Offset offset) {
    159   return HeapOperand(RegisterFrom(location, Primitive::kPrimNot), offset);
    160 }
    161 
    162 static inline Location LocationFrom(const vixl::Register& reg) {
    163   return Location::RegisterLocation(ARTRegCodeFromVIXL(reg.code()));
    164 }
    165 
    166 static inline Location LocationFrom(const vixl::FPRegister& fpreg) {
    167   return Location::FpuRegisterLocation(fpreg.code());
    168 }
    169 
    170 static inline vixl::Operand OperandFromMemOperand(const vixl::MemOperand& mem_op) {
    171   if (mem_op.IsImmediateOffset()) {
    172     return vixl::Operand(mem_op.offset());
    173   } else {
    174     DCHECK(mem_op.IsRegisterOffset());
    175     if (mem_op.extend() != vixl::NO_EXTEND) {
    176       return vixl::Operand(mem_op.regoffset(), mem_op.extend(), mem_op.shift_amount());
    177     } else if (mem_op.shift() != vixl::NO_SHIFT) {
    178       return vixl::Operand(mem_op.regoffset(), mem_op.shift(), mem_op.shift_amount());
    179     } else {
    180       LOG(FATAL) << "Should not reach here";
    181       UNREACHABLE();
    182     }
    183   }
    184 }
    185 
    186 static bool CanEncodeConstantAsImmediate(HConstant* constant, HInstruction* instr) {
    187   DCHECK(constant->IsIntConstant() || constant->IsLongConstant() || constant->IsNullConstant());
    188 
    189   // For single uses we let VIXL handle the constant generation since it will
    190   // use registers that are not managed by the register allocator (wip0, wip1).
    191   if (constant->GetUses().HasOnlyOneUse()) {
    192     return true;
    193   }
    194 
    195   int64_t value = CodeGenerator::GetInt64ValueOf(constant);
    196 
    197   if (instr->IsAdd() || instr->IsSub() || instr->IsCondition() ||
    198       instr->IsCompare() || instr->IsBoundsCheck()) {
    199     // Uses aliases of ADD/SUB instructions.
    200     return vixl::Assembler::IsImmAddSub(value);
    201   } else if (instr->IsAnd() || instr->IsOr() || instr->IsXor()) {
    202     // Uses logical operations.
    203     return vixl::Assembler::IsImmLogical(value, vixl::kXRegSize);
    204   } else {
    205     DCHECK(instr->IsNeg());
    206     // Uses mov -immediate.
    207     return vixl::Assembler::IsImmMovn(value, vixl::kXRegSize);
    208   }
    209 }
    210 
    211 static inline Location ARM64EncodableConstantOrRegister(HInstruction* constant,
    212                                                         HInstruction* instr) {
    213   if (constant->IsConstant()
    214       && CanEncodeConstantAsImmediate(constant->AsConstant(), instr)) {
    215     return Location::ConstantLocation(constant->AsConstant());
    216   }
    217 
    218   return Location::RequiresRegister();
    219 }
    220 
    221 }  // namespace helpers
    222 }  // namespace arm64
    223 }  // namespace art
    224 
    225 #endif  // ART_COMPILER_OPTIMIZING_COMMON_ARM64_H_
    226