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