blob: 882ee6660d2e21ccbc2d11962b8e9b5cf2ee82b7 [file] [log] [blame]
Matteo Franchin43ec8732014-03-31 15:00:14 +01001/*
2 * Copyright (C) 2011 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 "arm64_lir.h"
18#include "codegen_arm64.h"
19#include "dex/quick/mir_to_lir-inl.h"
20
21namespace art {
22
23void Arm64Mir2Lir::GenArithOpFloat(Instruction::Code opcode, RegLocation rl_dest,
Matteo Franchine45fb9e2014-05-06 10:10:30 +010024 RegLocation rl_src1, RegLocation rl_src2) {
25 int op = kA64Brk1d;
Matteo Franchin43ec8732014-03-31 15:00:14 +010026 RegLocation rl_result;
27
Matteo Franchin43ec8732014-03-31 15:00:14 +010028 switch (opcode) {
29 case Instruction::ADD_FLOAT_2ADDR:
30 case Instruction::ADD_FLOAT:
Matteo Franchine45fb9e2014-05-06 10:10:30 +010031 op = kA64Fadd3fff;
Matteo Franchin43ec8732014-03-31 15:00:14 +010032 break;
33 case Instruction::SUB_FLOAT_2ADDR:
34 case Instruction::SUB_FLOAT:
Matteo Franchine45fb9e2014-05-06 10:10:30 +010035 op = kA64Fsub3fff;
Matteo Franchin43ec8732014-03-31 15:00:14 +010036 break;
37 case Instruction::DIV_FLOAT_2ADDR:
38 case Instruction::DIV_FLOAT:
Matteo Franchine45fb9e2014-05-06 10:10:30 +010039 op = kA64Fdiv3fff;
Matteo Franchin43ec8732014-03-31 15:00:14 +010040 break;
41 case Instruction::MUL_FLOAT_2ADDR:
42 case Instruction::MUL_FLOAT:
Matteo Franchine45fb9e2014-05-06 10:10:30 +010043 op = kA64Fmul3fff;
Matteo Franchin43ec8732014-03-31 15:00:14 +010044 break;
45 case Instruction::REM_FLOAT_2ADDR:
46 case Instruction::REM_FLOAT:
47 FlushAllRegs(); // Send everything to home location
Andreas Gampe2f244e92014-05-08 03:35:25 -070048 CallRuntimeHelperRegLocationRegLocation(QUICK_ENTRYPOINT_OFFSET(8, pFmodf), rl_src1, rl_src2,
Matteo Franchin43ec8732014-03-31 15:00:14 +010049 false);
50 rl_result = GetReturn(true);
51 StoreValue(rl_dest, rl_result);
52 return;
53 case Instruction::NEG_FLOAT:
54 GenNegFloat(rl_dest, rl_src1);
55 return;
56 default:
57 LOG(FATAL) << "Unexpected opcode: " << opcode;
58 }
59 rl_src1 = LoadValue(rl_src1, kFPReg);
60 rl_src2 = LoadValue(rl_src2, kFPReg);
61 rl_result = EvalLoc(rl_dest, kFPReg, true);
62 NewLIR3(op, rl_result.reg.GetReg(), rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
63 StoreValue(rl_dest, rl_result);
64}
65
66void Arm64Mir2Lir::GenArithOpDouble(Instruction::Code opcode,
Matteo Franchine45fb9e2014-05-06 10:10:30 +010067 RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2) {
68 int op = kA64Brk1d;
Matteo Franchin43ec8732014-03-31 15:00:14 +010069 RegLocation rl_result;
70
71 switch (opcode) {
72 case Instruction::ADD_DOUBLE_2ADDR:
73 case Instruction::ADD_DOUBLE:
Matteo Franchine45fb9e2014-05-06 10:10:30 +010074 op = kA64Fadd3fff;
Matteo Franchin43ec8732014-03-31 15:00:14 +010075 break;
76 case Instruction::SUB_DOUBLE_2ADDR:
77 case Instruction::SUB_DOUBLE:
Matteo Franchine45fb9e2014-05-06 10:10:30 +010078 op = kA64Fsub3fff;
Matteo Franchin43ec8732014-03-31 15:00:14 +010079 break;
80 case Instruction::DIV_DOUBLE_2ADDR:
81 case Instruction::DIV_DOUBLE:
Matteo Franchine45fb9e2014-05-06 10:10:30 +010082 op = kA64Fdiv3fff;
Matteo Franchin43ec8732014-03-31 15:00:14 +010083 break;
84 case Instruction::MUL_DOUBLE_2ADDR:
85 case Instruction::MUL_DOUBLE:
Matteo Franchine45fb9e2014-05-06 10:10:30 +010086 op = kA64Fmul3fff;
Matteo Franchin43ec8732014-03-31 15:00:14 +010087 break;
88 case Instruction::REM_DOUBLE_2ADDR:
89 case Instruction::REM_DOUBLE:
90 FlushAllRegs(); // Send everything to home location
Andreas Gampe2f244e92014-05-08 03:35:25 -070091 CallRuntimeHelperRegLocationRegLocation(QUICK_ENTRYPOINT_OFFSET(8, pFmod), rl_src1, rl_src2,
Matteo Franchin43ec8732014-03-31 15:00:14 +010092 false);
93 rl_result = GetReturnWide(true);
94 StoreValueWide(rl_dest, rl_result);
95 return;
96 case Instruction::NEG_DOUBLE:
97 GenNegDouble(rl_dest, rl_src1);
98 return;
99 default:
100 LOG(FATAL) << "Unexpected opcode: " << opcode;
101 }
102
103 rl_src1 = LoadValueWide(rl_src1, kFPReg);
104 DCHECK(rl_src1.wide);
105 rl_src2 = LoadValueWide(rl_src2, kFPReg);
106 DCHECK(rl_src2.wide);
107 rl_result = EvalLoc(rl_dest, kFPReg, true);
108 DCHECK(rl_dest.wide);
109 DCHECK(rl_result.wide);
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100110 NewLIR3(FWIDE(op), rl_result.reg.GetReg(), rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
Matteo Franchin43ec8732014-03-31 15:00:14 +0100111 StoreValueWide(rl_dest, rl_result);
112}
113
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100114void Arm64Mir2Lir::GenConversion(Instruction::Code opcode,
115 RegLocation rl_dest, RegLocation rl_src) {
116 int op = kA64Brk1d;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100117 RegLocation rl_result;
Serban Constantinescu032d3772014-05-23 17:38:18 +0100118 RegisterClass src_reg_class = kInvalidRegClass;
119 RegisterClass dst_reg_class = kInvalidRegClass;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100120
121 switch (opcode) {
122 case Instruction::INT_TO_FLOAT:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100123 op = kA64Scvtf2fw;
Serban Constantinescu032d3772014-05-23 17:38:18 +0100124 src_reg_class = kCoreReg;
125 dst_reg_class = kFPReg;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100126 break;
127 case Instruction::FLOAT_TO_INT:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100128 op = kA64Fcvtzs2wf;
Serban Constantinescu032d3772014-05-23 17:38:18 +0100129 src_reg_class = kFPReg;
130 dst_reg_class = kCoreReg;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100131 break;
132 case Instruction::DOUBLE_TO_FLOAT:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100133 op = kA64Fcvt2sS;
Serban Constantinescu032d3772014-05-23 17:38:18 +0100134 src_reg_class = kFPReg;
135 dst_reg_class = kFPReg;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100136 break;
137 case Instruction::FLOAT_TO_DOUBLE:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100138 op = kA64Fcvt2Ss;
Serban Constantinescu032d3772014-05-23 17:38:18 +0100139 src_reg_class = kFPReg;
140 dst_reg_class = kFPReg;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100141 break;
142 case Instruction::INT_TO_DOUBLE:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100143 op = FWIDE(kA64Scvtf2fw);
Serban Constantinescu032d3772014-05-23 17:38:18 +0100144 src_reg_class = kCoreReg;
145 dst_reg_class = kFPReg;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100146 break;
147 case Instruction::DOUBLE_TO_INT:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100148 op = FWIDE(kA64Fcvtzs2wf);
Serban Constantinescu032d3772014-05-23 17:38:18 +0100149 src_reg_class = kFPReg;
150 dst_reg_class = kCoreReg;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100151 break;
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100152 case Instruction::LONG_TO_DOUBLE:
153 op = FWIDE(kA64Scvtf2fx);
Serban Constantinescu032d3772014-05-23 17:38:18 +0100154 src_reg_class = kCoreReg;
155 dst_reg_class = kFPReg;
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100156 break;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100157 case Instruction::FLOAT_TO_LONG:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100158 op = kA64Fcvtzs2xf;
Serban Constantinescu032d3772014-05-23 17:38:18 +0100159 src_reg_class = kFPReg;
160 dst_reg_class = kCoreReg;
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100161 break;
162 case Instruction::LONG_TO_FLOAT:
163 op = kA64Scvtf2fx;
Serban Constantinescu032d3772014-05-23 17:38:18 +0100164 src_reg_class = kCoreReg;
165 dst_reg_class = kFPReg;
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100166 break;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100167 case Instruction::DOUBLE_TO_LONG:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100168 op = FWIDE(kA64Fcvtzs2xf);
Serban Constantinescu032d3772014-05-23 17:38:18 +0100169 src_reg_class = kFPReg;
170 dst_reg_class = kCoreReg;
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100171 break;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100172 default:
173 LOG(FATAL) << "Unexpected opcode: " << opcode;
174 }
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100175
Serban Constantinescu032d3772014-05-23 17:38:18 +0100176 DCHECK_NE(src_reg_class, kInvalidRegClass);
177 DCHECK_NE(dst_reg_class, kInvalidRegClass);
178 DCHECK_NE(op, kA64Brk1d);
179
Matteo Franchin43ec8732014-03-31 15:00:14 +0100180 if (rl_src.wide) {
Serban Constantinescu032d3772014-05-23 17:38:18 +0100181 rl_src = LoadValueWide(rl_src, src_reg_class);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100182 } else {
Serban Constantinescu032d3772014-05-23 17:38:18 +0100183 rl_src = LoadValue(rl_src, src_reg_class);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100184 }
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100185
Serban Constantinescu032d3772014-05-23 17:38:18 +0100186 rl_result = EvalLoc(rl_dest, dst_reg_class, true);
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100187 NewLIR2(op, rl_result.reg.GetReg(), rl_src.reg.GetReg());
188
Matteo Franchin43ec8732014-03-31 15:00:14 +0100189 if (rl_dest.wide) {
Matteo Franchin43ec8732014-03-31 15:00:14 +0100190 StoreValueWide(rl_dest, rl_result);
191 } else {
Matteo Franchin43ec8732014-03-31 15:00:14 +0100192 StoreValue(rl_dest, rl_result);
193 }
194}
195
196void Arm64Mir2Lir::GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir, bool gt_bias,
197 bool is_double) {
198 LIR* target = &block_label_list_[bb->taken];
199 RegLocation rl_src1;
200 RegLocation rl_src2;
201 if (is_double) {
202 rl_src1 = mir_graph_->GetSrcWide(mir, 0);
203 rl_src2 = mir_graph_->GetSrcWide(mir, 2);
204 rl_src1 = LoadValueWide(rl_src1, kFPReg);
205 rl_src2 = LoadValueWide(rl_src2, kFPReg);
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100206 NewLIR2(FWIDE(kA64Fcmp2ff), rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
Matteo Franchin43ec8732014-03-31 15:00:14 +0100207 } else {
208 rl_src1 = mir_graph_->GetSrc(mir, 0);
209 rl_src2 = mir_graph_->GetSrc(mir, 1);
210 rl_src1 = LoadValue(rl_src1, kFPReg);
211 rl_src2 = LoadValue(rl_src2, kFPReg);
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100212 NewLIR2(kA64Fcmp2ff, rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
Matteo Franchin43ec8732014-03-31 15:00:14 +0100213 }
Matteo Franchin43ec8732014-03-31 15:00:14 +0100214 ConditionCode ccode = mir->meta.ccode;
215 switch (ccode) {
216 case kCondEq:
217 case kCondNe:
218 break;
219 case kCondLt:
220 if (gt_bias) {
221 ccode = kCondMi;
222 }
223 break;
224 case kCondLe:
225 if (gt_bias) {
226 ccode = kCondLs;
227 }
228 break;
229 case kCondGt:
230 if (gt_bias) {
231 ccode = kCondHi;
232 }
233 break;
234 case kCondGe:
235 if (gt_bias) {
236 ccode = kCondUge;
237 }
238 break;
239 default:
240 LOG(FATAL) << "Unexpected ccode: " << ccode;
241 }
242 OpCondBranch(ccode, target);
243}
244
245
246void Arm64Mir2Lir::GenCmpFP(Instruction::Code opcode, RegLocation rl_dest,
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100247 RegLocation rl_src1, RegLocation rl_src2) {
Matteo Franchin43ec8732014-03-31 15:00:14 +0100248 bool is_double = false;
249 int default_result = -1;
250 RegLocation rl_result;
251
252 switch (opcode) {
253 case Instruction::CMPL_FLOAT:
254 is_double = false;
255 default_result = -1;
256 break;
257 case Instruction::CMPG_FLOAT:
258 is_double = false;
259 default_result = 1;
260 break;
261 case Instruction::CMPL_DOUBLE:
262 is_double = true;
263 default_result = -1;
264 break;
265 case Instruction::CMPG_DOUBLE:
266 is_double = true;
267 default_result = 1;
268 break;
269 default:
270 LOG(FATAL) << "Unexpected opcode: " << opcode;
271 }
272 if (is_double) {
273 rl_src1 = LoadValueWide(rl_src1, kFPReg);
274 rl_src2 = LoadValueWide(rl_src2, kFPReg);
275 // In case result vreg is also a src vreg, break association to avoid useless copy by EvalLoc()
276 ClobberSReg(rl_dest.s_reg_low);
277 rl_result = EvalLoc(rl_dest, kCoreReg, true);
278 LoadConstant(rl_result.reg, default_result);
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100279 NewLIR2(FWIDE(kA64Fcmp2ff), rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
Matteo Franchin43ec8732014-03-31 15:00:14 +0100280 } else {
281 rl_src1 = LoadValue(rl_src1, kFPReg);
282 rl_src2 = LoadValue(rl_src2, kFPReg);
283 // In case result vreg is also a srcvreg, break association to avoid useless copy by EvalLoc()
284 ClobberSReg(rl_dest.s_reg_low);
285 rl_result = EvalLoc(rl_dest, kCoreReg, true);
286 LoadConstant(rl_result.reg, default_result);
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100287 NewLIR2(kA64Fcmp2ff, rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
Matteo Franchin43ec8732014-03-31 15:00:14 +0100288 }
289 DCHECK(!rl_result.reg.IsFloat());
Matteo Franchin43ec8732014-03-31 15:00:14 +0100290
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100291 // TODO(Arm64): should we rather do this?
292 // csinc wD, wzr, wzr, eq
293 // csneg wD, wD, wD, le
294 // (which requires 2 instructions rather than 3)
Matteo Franchin43ec8732014-03-31 15:00:14 +0100295
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100296 // Rd = if cond then Rd else -Rd.
297 NewLIR4(kA64Csneg4rrrc, rl_result.reg.GetReg(), rl_result.reg.GetReg(),
298 rl_result.reg.GetReg(), (default_result == 1) ? kArmCondPl : kArmCondLe);
299 NewLIR4(kA64Csel4rrrc, rl_result.reg.GetReg(), rwzr, rl_result.reg.GetReg(),
300 kArmCondEq);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100301 StoreValue(rl_dest, rl_result);
302}
303
304void Arm64Mir2Lir::GenNegFloat(RegLocation rl_dest, RegLocation rl_src) {
305 RegLocation rl_result;
306 rl_src = LoadValue(rl_src, kFPReg);
307 rl_result = EvalLoc(rl_dest, kFPReg, true);
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100308 NewLIR2(kA64Fneg2ff, rl_result.reg.GetReg(), rl_src.reg.GetReg());
Matteo Franchin43ec8732014-03-31 15:00:14 +0100309 StoreValue(rl_dest, rl_result);
310}
311
312void Arm64Mir2Lir::GenNegDouble(RegLocation rl_dest, RegLocation rl_src) {
313 RegLocation rl_result;
314 rl_src = LoadValueWide(rl_src, kFPReg);
315 rl_result = EvalLoc(rl_dest, kFPReg, true);
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100316 NewLIR2(FWIDE(kA64Fneg2ff), rl_result.reg.GetReg(), rl_src.reg.GetReg());
Matteo Franchin43ec8732014-03-31 15:00:14 +0100317 StoreValueWide(rl_dest, rl_result);
318}
319
320bool Arm64Mir2Lir::GenInlinedSqrt(CallInfo* info) {
Matteo Franchin43ec8732014-03-31 15:00:14 +0100321 RegLocation rl_src = info->args[0];
322 RegLocation rl_dest = InlineTargetWide(info); // double place for result
323 rl_src = LoadValueWide(rl_src, kFPReg);
324 RegLocation rl_result = EvalLoc(rl_dest, kFPReg, true);
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100325 NewLIR2(FWIDE(kA64Fsqrt2ff), rl_result.reg.GetReg(), rl_src.reg.GetReg());
Matteo Franchin43ec8732014-03-31 15:00:14 +0100326 StoreValueWide(rl_dest, rl_result);
327 return true;
328}
329
Matteo Franchin43ec8732014-03-31 15:00:14 +0100330} // namespace art