blob: 265e8d20207c158b6c96a002f8770f1f7b380ce0 [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
Zheng Xu2d41a652014-06-09 11:05:31 +080048 // TODO: Fix xSELF.
Andreas Gampe2f244e92014-05-08 03:35:25 -070049 CallRuntimeHelperRegLocationRegLocation(QUICK_ENTRYPOINT_OFFSET(8, pFmodf), rl_src1, rl_src2,
Matteo Franchin43ec8732014-03-31 15:00:14 +010050 false);
buzbeea0cd2d72014-06-01 09:33:49 -070051 rl_result = GetReturn(kFPReg);
Matteo Franchin43ec8732014-03-31 15:00:14 +010052 StoreValue(rl_dest, rl_result);
53 return;
54 case Instruction::NEG_FLOAT:
55 GenNegFloat(rl_dest, rl_src1);
56 return;
57 default:
58 LOG(FATAL) << "Unexpected opcode: " << opcode;
59 }
60 rl_src1 = LoadValue(rl_src1, kFPReg);
61 rl_src2 = LoadValue(rl_src2, kFPReg);
62 rl_result = EvalLoc(rl_dest, kFPReg, true);
63 NewLIR3(op, rl_result.reg.GetReg(), rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
64 StoreValue(rl_dest, rl_result);
65}
66
67void Arm64Mir2Lir::GenArithOpDouble(Instruction::Code opcode,
Matteo Franchine45fb9e2014-05-06 10:10:30 +010068 RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2) {
69 int op = kA64Brk1d;
Matteo Franchin43ec8732014-03-31 15:00:14 +010070 RegLocation rl_result;
71
72 switch (opcode) {
73 case Instruction::ADD_DOUBLE_2ADDR:
74 case Instruction::ADD_DOUBLE:
Matteo Franchine45fb9e2014-05-06 10:10:30 +010075 op = kA64Fadd3fff;
Matteo Franchin43ec8732014-03-31 15:00:14 +010076 break;
77 case Instruction::SUB_DOUBLE_2ADDR:
78 case Instruction::SUB_DOUBLE:
Matteo Franchine45fb9e2014-05-06 10:10:30 +010079 op = kA64Fsub3fff;
Matteo Franchin43ec8732014-03-31 15:00:14 +010080 break;
81 case Instruction::DIV_DOUBLE_2ADDR:
82 case Instruction::DIV_DOUBLE:
Matteo Franchine45fb9e2014-05-06 10:10:30 +010083 op = kA64Fdiv3fff;
Matteo Franchin43ec8732014-03-31 15:00:14 +010084 break;
85 case Instruction::MUL_DOUBLE_2ADDR:
86 case Instruction::MUL_DOUBLE:
Matteo Franchine45fb9e2014-05-06 10:10:30 +010087 op = kA64Fmul3fff;
Matteo Franchin43ec8732014-03-31 15:00:14 +010088 break;
89 case Instruction::REM_DOUBLE_2ADDR:
90 case Instruction::REM_DOUBLE:
91 FlushAllRegs(); // Send everything to home location
Zheng Xu2d41a652014-06-09 11:05:31 +080092 // TODO: Fix xSELF.
93 {
94 ThreadOffset<8> helper_offset = QUICK_ENTRYPOINT_OFFSET(8, pFmod);
95 RegStorage r_tgt = CallHelperSetup(helper_offset);
96 LoadValueDirectWideFixed(rl_src1, rs_d0);
97 LoadValueDirectWideFixed(rl_src2, rs_d1);
98 ClobberCallerSave();
99 CallHelper(r_tgt, helper_offset, false);
100 }
buzbeea0cd2d72014-06-01 09:33:49 -0700101 rl_result = GetReturnWide(kFPReg);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100102 StoreValueWide(rl_dest, rl_result);
103 return;
104 case Instruction::NEG_DOUBLE:
105 GenNegDouble(rl_dest, rl_src1);
106 return;
107 default:
108 LOG(FATAL) << "Unexpected opcode: " << opcode;
109 }
110
111 rl_src1 = LoadValueWide(rl_src1, kFPReg);
112 DCHECK(rl_src1.wide);
113 rl_src2 = LoadValueWide(rl_src2, kFPReg);
114 DCHECK(rl_src2.wide);
115 rl_result = EvalLoc(rl_dest, kFPReg, true);
116 DCHECK(rl_dest.wide);
117 DCHECK(rl_result.wide);
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100118 NewLIR3(FWIDE(op), rl_result.reg.GetReg(), rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
Matteo Franchin43ec8732014-03-31 15:00:14 +0100119 StoreValueWide(rl_dest, rl_result);
120}
121
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100122void Arm64Mir2Lir::GenConversion(Instruction::Code opcode,
123 RegLocation rl_dest, RegLocation rl_src) {
124 int op = kA64Brk1d;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100125 RegLocation rl_result;
Serban Constantinescu032d3772014-05-23 17:38:18 +0100126 RegisterClass src_reg_class = kInvalidRegClass;
127 RegisterClass dst_reg_class = kInvalidRegClass;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100128
129 switch (opcode) {
130 case Instruction::INT_TO_FLOAT:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100131 op = kA64Scvtf2fw;
Serban Constantinescu032d3772014-05-23 17:38:18 +0100132 src_reg_class = kCoreReg;
133 dst_reg_class = kFPReg;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100134 break;
135 case Instruction::FLOAT_TO_INT:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100136 op = kA64Fcvtzs2wf;
Serban Constantinescu032d3772014-05-23 17:38:18 +0100137 src_reg_class = kFPReg;
138 dst_reg_class = kCoreReg;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100139 break;
140 case Instruction::DOUBLE_TO_FLOAT:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100141 op = kA64Fcvt2sS;
Serban Constantinescu032d3772014-05-23 17:38:18 +0100142 src_reg_class = kFPReg;
143 dst_reg_class = kFPReg;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100144 break;
145 case Instruction::FLOAT_TO_DOUBLE:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100146 op = kA64Fcvt2Ss;
Serban Constantinescu032d3772014-05-23 17:38:18 +0100147 src_reg_class = kFPReg;
148 dst_reg_class = kFPReg;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100149 break;
150 case Instruction::INT_TO_DOUBLE:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100151 op = FWIDE(kA64Scvtf2fw);
Serban Constantinescu032d3772014-05-23 17:38:18 +0100152 src_reg_class = kCoreReg;
153 dst_reg_class = kFPReg;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100154 break;
155 case Instruction::DOUBLE_TO_INT:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100156 op = FWIDE(kA64Fcvtzs2wf);
Serban Constantinescu032d3772014-05-23 17:38:18 +0100157 src_reg_class = kFPReg;
158 dst_reg_class = kCoreReg;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100159 break;
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100160 case Instruction::LONG_TO_DOUBLE:
161 op = FWIDE(kA64Scvtf2fx);
Serban Constantinescu032d3772014-05-23 17:38:18 +0100162 src_reg_class = kCoreReg;
163 dst_reg_class = kFPReg;
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100164 break;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100165 case Instruction::FLOAT_TO_LONG:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100166 op = kA64Fcvtzs2xf;
Serban Constantinescu032d3772014-05-23 17:38:18 +0100167 src_reg_class = kFPReg;
168 dst_reg_class = kCoreReg;
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100169 break;
170 case Instruction::LONG_TO_FLOAT:
171 op = kA64Scvtf2fx;
Serban Constantinescu032d3772014-05-23 17:38:18 +0100172 src_reg_class = kCoreReg;
173 dst_reg_class = kFPReg;
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100174 break;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100175 case Instruction::DOUBLE_TO_LONG:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100176 op = FWIDE(kA64Fcvtzs2xf);
Serban Constantinescu032d3772014-05-23 17:38:18 +0100177 src_reg_class = kFPReg;
178 dst_reg_class = kCoreReg;
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100179 break;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100180 default:
181 LOG(FATAL) << "Unexpected opcode: " << opcode;
182 }
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100183
Serban Constantinescu032d3772014-05-23 17:38:18 +0100184 DCHECK_NE(src_reg_class, kInvalidRegClass);
185 DCHECK_NE(dst_reg_class, kInvalidRegClass);
186 DCHECK_NE(op, kA64Brk1d);
187
Matteo Franchin43ec8732014-03-31 15:00:14 +0100188 if (rl_src.wide) {
Serban Constantinescu032d3772014-05-23 17:38:18 +0100189 rl_src = LoadValueWide(rl_src, src_reg_class);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100190 } else {
Serban Constantinescu032d3772014-05-23 17:38:18 +0100191 rl_src = LoadValue(rl_src, src_reg_class);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100192 }
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100193
Serban Constantinescu032d3772014-05-23 17:38:18 +0100194 rl_result = EvalLoc(rl_dest, dst_reg_class, true);
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100195 NewLIR2(op, rl_result.reg.GetReg(), rl_src.reg.GetReg());
196
Matteo Franchin43ec8732014-03-31 15:00:14 +0100197 if (rl_dest.wide) {
Matteo Franchin43ec8732014-03-31 15:00:14 +0100198 StoreValueWide(rl_dest, rl_result);
199 } else {
Matteo Franchin43ec8732014-03-31 15:00:14 +0100200 StoreValue(rl_dest, rl_result);
201 }
202}
203
204void Arm64Mir2Lir::GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir, bool gt_bias,
205 bool is_double) {
206 LIR* target = &block_label_list_[bb->taken];
207 RegLocation rl_src1;
208 RegLocation rl_src2;
209 if (is_double) {
210 rl_src1 = mir_graph_->GetSrcWide(mir, 0);
211 rl_src2 = mir_graph_->GetSrcWide(mir, 2);
212 rl_src1 = LoadValueWide(rl_src1, kFPReg);
213 rl_src2 = LoadValueWide(rl_src2, kFPReg);
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100214 NewLIR2(FWIDE(kA64Fcmp2ff), rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
Matteo Franchin43ec8732014-03-31 15:00:14 +0100215 } else {
216 rl_src1 = mir_graph_->GetSrc(mir, 0);
217 rl_src2 = mir_graph_->GetSrc(mir, 1);
218 rl_src1 = LoadValue(rl_src1, kFPReg);
219 rl_src2 = LoadValue(rl_src2, kFPReg);
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100220 NewLIR2(kA64Fcmp2ff, rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
Matteo Franchin43ec8732014-03-31 15:00:14 +0100221 }
Matteo Franchin43ec8732014-03-31 15:00:14 +0100222 ConditionCode ccode = mir->meta.ccode;
223 switch (ccode) {
224 case kCondEq:
225 case kCondNe:
226 break;
227 case kCondLt:
228 if (gt_bias) {
229 ccode = kCondMi;
230 }
231 break;
232 case kCondLe:
233 if (gt_bias) {
234 ccode = kCondLs;
235 }
236 break;
237 case kCondGt:
238 if (gt_bias) {
239 ccode = kCondHi;
240 }
241 break;
242 case kCondGe:
243 if (gt_bias) {
244 ccode = kCondUge;
245 }
246 break;
247 default:
248 LOG(FATAL) << "Unexpected ccode: " << ccode;
249 }
250 OpCondBranch(ccode, target);
251}
252
253
254void Arm64Mir2Lir::GenCmpFP(Instruction::Code opcode, RegLocation rl_dest,
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100255 RegLocation rl_src1, RegLocation rl_src2) {
Matteo Franchin43ec8732014-03-31 15:00:14 +0100256 bool is_double = false;
257 int default_result = -1;
258 RegLocation rl_result;
259
260 switch (opcode) {
261 case Instruction::CMPL_FLOAT:
262 is_double = false;
263 default_result = -1;
264 break;
265 case Instruction::CMPG_FLOAT:
266 is_double = false;
267 default_result = 1;
268 break;
269 case Instruction::CMPL_DOUBLE:
270 is_double = true;
271 default_result = -1;
272 break;
273 case Instruction::CMPG_DOUBLE:
274 is_double = true;
275 default_result = 1;
276 break;
277 default:
278 LOG(FATAL) << "Unexpected opcode: " << opcode;
279 }
280 if (is_double) {
281 rl_src1 = LoadValueWide(rl_src1, kFPReg);
282 rl_src2 = LoadValueWide(rl_src2, kFPReg);
283 // In case result vreg is also a src vreg, 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(FWIDE(kA64Fcmp2ff), rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
Matteo Franchin43ec8732014-03-31 15:00:14 +0100288 } else {
289 rl_src1 = LoadValue(rl_src1, kFPReg);
290 rl_src2 = LoadValue(rl_src2, kFPReg);
291 // In case result vreg is also a srcvreg, break association to avoid useless copy by EvalLoc()
292 ClobberSReg(rl_dest.s_reg_low);
293 rl_result = EvalLoc(rl_dest, kCoreReg, true);
294 LoadConstant(rl_result.reg, default_result);
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100295 NewLIR2(kA64Fcmp2ff, rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
Matteo Franchin43ec8732014-03-31 15:00:14 +0100296 }
297 DCHECK(!rl_result.reg.IsFloat());
Matteo Franchin43ec8732014-03-31 15:00:14 +0100298
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100299 // TODO(Arm64): should we rather do this?
300 // csinc wD, wzr, wzr, eq
301 // csneg wD, wD, wD, le
302 // (which requires 2 instructions rather than 3)
Matteo Franchin43ec8732014-03-31 15:00:14 +0100303
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100304 // Rd = if cond then Rd else -Rd.
305 NewLIR4(kA64Csneg4rrrc, rl_result.reg.GetReg(), rl_result.reg.GetReg(),
306 rl_result.reg.GetReg(), (default_result == 1) ? kArmCondPl : kArmCondLe);
307 NewLIR4(kA64Csel4rrrc, rl_result.reg.GetReg(), rwzr, rl_result.reg.GetReg(),
308 kArmCondEq);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100309 StoreValue(rl_dest, rl_result);
310}
311
312void Arm64Mir2Lir::GenNegFloat(RegLocation rl_dest, RegLocation rl_src) {
313 RegLocation rl_result;
314 rl_src = LoadValue(rl_src, kFPReg);
315 rl_result = EvalLoc(rl_dest, kFPReg, true);
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100316 NewLIR2(kA64Fneg2ff, rl_result.reg.GetReg(), rl_src.reg.GetReg());
Matteo Franchin43ec8732014-03-31 15:00:14 +0100317 StoreValue(rl_dest, rl_result);
318}
319
320void Arm64Mir2Lir::GenNegDouble(RegLocation rl_dest, RegLocation rl_src) {
321 RegLocation rl_result;
322 rl_src = LoadValueWide(rl_src, kFPReg);
323 rl_result = EvalLoc(rl_dest, kFPReg, true);
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100324 NewLIR2(FWIDE(kA64Fneg2ff), rl_result.reg.GetReg(), rl_src.reg.GetReg());
Matteo Franchin43ec8732014-03-31 15:00:14 +0100325 StoreValueWide(rl_dest, rl_result);
326}
327
328bool Arm64Mir2Lir::GenInlinedSqrt(CallInfo* info) {
Matteo Franchin43ec8732014-03-31 15:00:14 +0100329 RegLocation rl_src = info->args[0];
330 RegLocation rl_dest = InlineTargetWide(info); // double place for result
331 rl_src = LoadValueWide(rl_src, kFPReg);
332 RegLocation rl_result = EvalLoc(rl_dest, kFPReg, true);
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100333 NewLIR2(FWIDE(kA64Fsqrt2ff), rl_result.reg.GetReg(), rl_src.reg.GetReg());
Matteo Franchin43ec8732014-03-31 15:00:14 +0100334 StoreValueWide(rl_dest, rl_result);
335 return true;
336}
337
Matteo Franchin43ec8732014-03-31 15:00:14 +0100338} // namespace art