blob: 5e0e73d193076f6ec81cdd70284e2a53337c459e [file] [log] [blame]
buzbee67bf8852011-08-17 17:51:35 -07001/*
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
buzbee1bc37c62012-11-20 13:35:41 -080017#include "arm_lir.h"
buzbee02031b12012-11-23 09:41:35 -080018#include "codegen_arm.h"
buzbee1bc37c62012-11-20 13:35:41 -080019#include "../codegen_util.h"
20#include "../ralloc_util.h"
21
Elliott Hughes11d1b0c2012-01-23 16:57:47 -080022namespace art {
23
buzbee02031b12012-11-23 09:41:35 -080024bool ArmCodegen::GenArithOpFloat(CompilationUnit* cu, Instruction::Code opcode, RegLocation rl_dest,
25 RegLocation rl_src1, RegLocation rl_src2)
buzbee67bf8852011-08-17 17:51:35 -070026{
Bill Buzbeea114add2012-05-03 15:00:40 -070027 int op = kThumbBkpt;
buzbeefa57c472012-11-21 12:06:18 -080028 RegLocation rl_result;
buzbee67bf8852011-08-17 17:51:35 -070029
Bill Buzbeea114add2012-05-03 15:00:40 -070030 /*
31 * Don't attempt to optimize register usage since these opcodes call out to
32 * the handlers.
33 */
buzbee408ad162012-06-06 16:45:18 -070034 switch (opcode) {
Bill Buzbeea114add2012-05-03 15:00:40 -070035 case Instruction::ADD_FLOAT_2ADDR:
36 case Instruction::ADD_FLOAT:
37 op = kThumb2Vadds;
38 break;
39 case Instruction::SUB_FLOAT_2ADDR:
40 case Instruction::SUB_FLOAT:
41 op = kThumb2Vsubs;
42 break;
43 case Instruction::DIV_FLOAT_2ADDR:
44 case Instruction::DIV_FLOAT:
45 op = kThumb2Vdivs;
46 break;
47 case Instruction::MUL_FLOAT_2ADDR:
48 case Instruction::MUL_FLOAT:
49 op = kThumb2Vmuls;
50 break;
51 case Instruction::REM_FLOAT_2ADDR:
52 case Instruction::REM_FLOAT:
buzbeea3a82b22012-11-27 16:09:55 -080053 FlushAllRegs(cu); // Send everything to home location
54 CallRuntimeHelperRegLocationRegLocation(cu, ENTRYPOINT_OFFSET(pFmodf), rl_src1, rl_src2, false);
55 rl_result = GetReturn(cu, true);
56 StoreValue(cu, rl_dest, rl_result);
57 return false;
58 case Instruction::NEG_FLOAT:
59 GenNegFloat(cu, rl_dest, rl_src1);
60 return false;
Bill Buzbeea114add2012-05-03 15:00:40 -070061 default:
62 return true;
63 }
buzbeefa57c472012-11-21 12:06:18 -080064 rl_src1 = LoadValue(cu, rl_src1, kFPReg);
65 rl_src2 = LoadValue(cu, rl_src2, kFPReg);
66 rl_result = EvalLoc(cu, rl_dest, kFPReg, true);
67 NewLIR3(cu, op, rl_result.low_reg, rl_src1.low_reg, rl_src2.low_reg);
68 StoreValue(cu, rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -070069 return false;
buzbee67bf8852011-08-17 17:51:35 -070070}
71
buzbee02031b12012-11-23 09:41:35 -080072bool ArmCodegen::GenArithOpDouble(CompilationUnit* cu, Instruction::Code opcode,
73 RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2)
buzbee67bf8852011-08-17 17:51:35 -070074{
Bill Buzbeea114add2012-05-03 15:00:40 -070075 int op = kThumbBkpt;
buzbeefa57c472012-11-21 12:06:18 -080076 RegLocation rl_result;
buzbee67bf8852011-08-17 17:51:35 -070077
buzbee408ad162012-06-06 16:45:18 -070078 switch (opcode) {
Bill Buzbeea114add2012-05-03 15:00:40 -070079 case Instruction::ADD_DOUBLE_2ADDR:
80 case Instruction::ADD_DOUBLE:
81 op = kThumb2Vaddd;
82 break;
83 case Instruction::SUB_DOUBLE_2ADDR:
84 case Instruction::SUB_DOUBLE:
85 op = kThumb2Vsubd;
86 break;
87 case Instruction::DIV_DOUBLE_2ADDR:
88 case Instruction::DIV_DOUBLE:
89 op = kThumb2Vdivd;
90 break;
91 case Instruction::MUL_DOUBLE_2ADDR:
92 case Instruction::MUL_DOUBLE:
93 op = kThumb2Vmuld;
94 break;
95 case Instruction::REM_DOUBLE_2ADDR:
96 case Instruction::REM_DOUBLE:
buzbeea3a82b22012-11-27 16:09:55 -080097 FlushAllRegs(cu); // Send everything to home location
98 CallRuntimeHelperRegLocationRegLocation(cu, ENTRYPOINT_OFFSET(pFmod), rl_src1, rl_src2, false);
99 rl_result = GetReturnWide(cu, true);
100 StoreValueWide(cu, rl_dest, rl_result);
101 return false;
102 case Instruction::NEG_DOUBLE:
103 GenNegDouble(cu, rl_dest, rl_src1);
104 return false;
Bill Buzbeea114add2012-05-03 15:00:40 -0700105 default:
106 return true;
107 }
buzbee67bf8852011-08-17 17:51:35 -0700108
buzbeefa57c472012-11-21 12:06:18 -0800109 rl_src1 = LoadValueWide(cu, rl_src1, kFPReg);
110 DCHECK(rl_src1.wide);
111 rl_src2 = LoadValueWide(cu, rl_src2, kFPReg);
112 DCHECK(rl_src2.wide);
113 rl_result = EvalLoc(cu, rl_dest, kFPReg, true);
114 DCHECK(rl_dest.wide);
115 DCHECK(rl_result.wide);
116 NewLIR3(cu, op, S2d(rl_result.low_reg, rl_result.high_reg), S2d(rl_src1.low_reg, rl_src1.high_reg),
117 S2d(rl_src2.low_reg, rl_src2.high_reg));
118 StoreValueWide(cu, rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -0700119 return false;
buzbee67bf8852011-08-17 17:51:35 -0700120}
121
buzbee02031b12012-11-23 09:41:35 -0800122bool ArmCodegen::GenConversion(CompilationUnit* cu, Instruction::Code opcode,
123 RegLocation rl_dest, RegLocation rl_src)
buzbee67bf8852011-08-17 17:51:35 -0700124{
Bill Buzbeea114add2012-05-03 15:00:40 -0700125 int op = kThumbBkpt;
buzbeefa57c472012-11-21 12:06:18 -0800126 int src_reg;
127 RegLocation rl_result;
buzbee67bf8852011-08-17 17:51:35 -0700128
Bill Buzbeea114add2012-05-03 15:00:40 -0700129 switch (opcode) {
130 case Instruction::INT_TO_FLOAT:
Bill Buzbeea114add2012-05-03 15:00:40 -0700131 op = kThumb2VcvtIF;
132 break;
133 case Instruction::FLOAT_TO_INT:
Bill Buzbeea114add2012-05-03 15:00:40 -0700134 op = kThumb2VcvtFI;
135 break;
136 case Instruction::DOUBLE_TO_FLOAT:
Bill Buzbeea114add2012-05-03 15:00:40 -0700137 op = kThumb2VcvtDF;
138 break;
139 case Instruction::FLOAT_TO_DOUBLE:
Bill Buzbeea114add2012-05-03 15:00:40 -0700140 op = kThumb2VcvtFd;
141 break;
142 case Instruction::INT_TO_DOUBLE:
Bill Buzbeea114add2012-05-03 15:00:40 -0700143 op = kThumb2VcvtID;
144 break;
145 case Instruction::DOUBLE_TO_INT:
Bill Buzbeea114add2012-05-03 15:00:40 -0700146 op = kThumb2VcvtDI;
147 break;
148 case Instruction::LONG_TO_DOUBLE:
buzbeea3a82b22012-11-27 16:09:55 -0800149 return GenConversionCall(cu, ENTRYPOINT_OFFSET(pL2d), rl_dest, rl_src);
Bill Buzbeea114add2012-05-03 15:00:40 -0700150 case Instruction::FLOAT_TO_LONG:
buzbeea3a82b22012-11-27 16:09:55 -0800151 return GenConversionCall(cu, ENTRYPOINT_OFFSET(pF2l), rl_dest, rl_src);
Bill Buzbeea114add2012-05-03 15:00:40 -0700152 case Instruction::LONG_TO_FLOAT:
buzbeea3a82b22012-11-27 16:09:55 -0800153 return GenConversionCall(cu, ENTRYPOINT_OFFSET(pL2f), rl_dest, rl_src);
Bill Buzbeea114add2012-05-03 15:00:40 -0700154 case Instruction::DOUBLE_TO_LONG:
buzbeea3a82b22012-11-27 16:09:55 -0800155 return GenConversionCall(cu, ENTRYPOINT_OFFSET(pD2l), rl_dest, rl_src);
Bill Buzbeea114add2012-05-03 15:00:40 -0700156 default:
157 return true;
158 }
buzbeefa57c472012-11-21 12:06:18 -0800159 if (rl_src.wide) {
160 rl_src = LoadValueWide(cu, rl_src, kFPReg);
161 src_reg = S2d(rl_src.low_reg, rl_src.high_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700162 } else {
buzbeefa57c472012-11-21 12:06:18 -0800163 rl_src = LoadValue(cu, rl_src, kFPReg);
164 src_reg = rl_src.low_reg;
Bill Buzbeea114add2012-05-03 15:00:40 -0700165 }
buzbeefa57c472012-11-21 12:06:18 -0800166 if (rl_dest.wide) {
167 rl_result = EvalLoc(cu, rl_dest, kFPReg, true);
168 NewLIR2(cu, op, S2d(rl_result.low_reg, rl_result.high_reg), src_reg);
169 StoreValueWide(cu, rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -0700170 } else {
buzbeefa57c472012-11-21 12:06:18 -0800171 rl_result = EvalLoc(cu, rl_dest, kFPReg, true);
172 NewLIR2(cu, op, rl_result.low_reg, src_reg);
173 StoreValue(cu, rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -0700174 }
175 return false;
buzbee67bf8852011-08-17 17:51:35 -0700176}
177
buzbee02031b12012-11-23 09:41:35 -0800178void ArmCodegen::GenFusedFPCmpBranch(CompilationUnit* cu, BasicBlock* bb, MIR* mir, bool gt_bias,
179 bool is_double)
buzbee84fd6932012-03-29 16:44:16 -0700180{
buzbeefa57c472012-11-21 12:06:18 -0800181 LIR* label_list = cu->block_label_list;
182 LIR* target = &label_list[bb->taken->id];
183 RegLocation rl_src1;
184 RegLocation rl_src2;
185 if (is_double) {
186 rl_src1 = GetSrcWide(cu, mir, 0);
187 rl_src2 = GetSrcWide(cu, mir, 2);
188 rl_src1 = LoadValueWide(cu, rl_src1, kFPReg);
189 rl_src2 = LoadValueWide(cu, rl_src2, kFPReg);
190 NewLIR2(cu, kThumb2Vcmpd, S2d(rl_src1.low_reg, rl_src2.high_reg),
191 S2d(rl_src2.low_reg, rl_src2.high_reg));
Bill Buzbeea114add2012-05-03 15:00:40 -0700192 } else {
buzbeefa57c472012-11-21 12:06:18 -0800193 rl_src1 = GetSrc(cu, mir, 0);
194 rl_src2 = GetSrc(cu, mir, 1);
195 rl_src1 = LoadValue(cu, rl_src1, kFPReg);
196 rl_src2 = LoadValue(cu, rl_src2, kFPReg);
197 NewLIR2(cu, kThumb2Vcmps, rl_src1.low_reg, rl_src2.low_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700198 }
buzbeefa57c472012-11-21 12:06:18 -0800199 NewLIR0(cu, kThumb2Fmstat);
Bill Buzbeea114add2012-05-03 15:00:40 -0700200 ConditionCode ccode = static_cast<ConditionCode>(mir->dalvikInsn.arg[0]);
201 switch(ccode) {
202 case kCondEq:
203 case kCondNe:
204 break;
205 case kCondLt:
buzbeefa57c472012-11-21 12:06:18 -0800206 if (gt_bias) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700207 ccode = kCondMi;
208 }
209 break;
210 case kCondLe:
buzbeefa57c472012-11-21 12:06:18 -0800211 if (gt_bias) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700212 ccode = kCondLs;
213 }
214 break;
215 case kCondGt:
buzbeefa57c472012-11-21 12:06:18 -0800216 if (gt_bias) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700217 ccode = kCondHi;
218 }
219 break;
220 case kCondGe:
buzbeefa57c472012-11-21 12:06:18 -0800221 if (gt_bias) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700222 ccode = kCondCs;
223 }
224 break;
225 default:
buzbeecbd6d442012-11-17 14:11:25 -0800226 LOG(FATAL) << "Unexpected ccode: " << ccode;
Bill Buzbeea114add2012-05-03 15:00:40 -0700227 }
buzbeefa57c472012-11-21 12:06:18 -0800228 OpCondBranch(cu, ccode, target);
buzbee84fd6932012-03-29 16:44:16 -0700229}
230
231
buzbee02031b12012-11-23 09:41:35 -0800232bool ArmCodegen::GenCmpFP(CompilationUnit* cu, Instruction::Code opcode, RegLocation rl_dest,
233 RegLocation rl_src1, RegLocation rl_src2)
buzbee67bf8852011-08-17 17:51:35 -0700234{
buzbeefa57c472012-11-21 12:06:18 -0800235 bool is_double;
236 int default_result;
237 RegLocation rl_result;
buzbee67bf8852011-08-17 17:51:35 -0700238
buzbee408ad162012-06-06 16:45:18 -0700239 switch (opcode) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700240 case Instruction::CMPL_FLOAT:
buzbeefa57c472012-11-21 12:06:18 -0800241 is_double = false;
242 default_result = -1;
Bill Buzbeea114add2012-05-03 15:00:40 -0700243 break;
244 case Instruction::CMPG_FLOAT:
buzbeefa57c472012-11-21 12:06:18 -0800245 is_double = false;
246 default_result = 1;
Bill Buzbeea114add2012-05-03 15:00:40 -0700247 break;
248 case Instruction::CMPL_DOUBLE:
buzbeefa57c472012-11-21 12:06:18 -0800249 is_double = true;
250 default_result = -1;
Bill Buzbeea114add2012-05-03 15:00:40 -0700251 break;
252 case Instruction::CMPG_DOUBLE:
buzbeefa57c472012-11-21 12:06:18 -0800253 is_double = true;
254 default_result = 1;
Bill Buzbeea114add2012-05-03 15:00:40 -0700255 break;
256 default:
257 return true;
258 }
buzbeefa57c472012-11-21 12:06:18 -0800259 if (is_double) {
260 rl_src1 = LoadValueWide(cu, rl_src1, kFPReg);
261 rl_src2 = LoadValueWide(cu, rl_src2, kFPReg);
262 ClobberSReg(cu, rl_dest.s_reg_low);
263 rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
264 LoadConstant(cu, rl_result.low_reg, default_result);
265 NewLIR2(cu, kThumb2Vcmpd, S2d(rl_src1.low_reg, rl_src2.high_reg),
266 S2d(rl_src2.low_reg, rl_src2.high_reg));
Bill Buzbeea114add2012-05-03 15:00:40 -0700267 } else {
buzbeefa57c472012-11-21 12:06:18 -0800268 rl_src1 = LoadValue(cu, rl_src1, kFPReg);
269 rl_src2 = LoadValue(cu, rl_src2, kFPReg);
270 ClobberSReg(cu, rl_dest.s_reg_low);
271 rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
272 LoadConstant(cu, rl_result.low_reg, default_result);
273 NewLIR2(cu, kThumb2Vcmps, rl_src1.low_reg, rl_src2.low_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700274 }
buzbeefa57c472012-11-21 12:06:18 -0800275 DCHECK(!ARM_FPREG(rl_result.low_reg));
276 NewLIR0(cu, kThumb2Fmstat);
buzbee67bf8852011-08-17 17:51:35 -0700277
buzbee02031b12012-11-23 09:41:35 -0800278 OpIT(cu, (default_result == -1) ? kCondGt : kCondMi, "");
buzbeefa57c472012-11-21 12:06:18 -0800279 NewLIR2(cu, kThumb2MovImmShift, rl_result.low_reg,
280 ModifiedImmediate(-default_result)); // Must not alter ccodes
281 GenBarrier(cu);
buzbee67bf8852011-08-17 17:51:35 -0700282
buzbee02031b12012-11-23 09:41:35 -0800283 OpIT(cu, kCondEq, "");
buzbeefa57c472012-11-21 12:06:18 -0800284 LoadConstant(cu, rl_result.low_reg, 0);
285 GenBarrier(cu);
buzbee67bf8852011-08-17 17:51:35 -0700286
buzbeefa57c472012-11-21 12:06:18 -0800287 StoreValue(cu, rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -0700288 return false;
buzbee67bf8852011-08-17 17:51:35 -0700289}
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800290
buzbee02031b12012-11-23 09:41:35 -0800291void ArmCodegen::GenNegFloat(CompilationUnit* cu, RegLocation rl_dest, RegLocation rl_src)
buzbeeefc63692012-11-14 16:31:52 -0800292{
buzbeefa57c472012-11-21 12:06:18 -0800293 RegLocation rl_result;
294 rl_src = LoadValue(cu, rl_src, kFPReg);
295 rl_result = EvalLoc(cu, rl_dest, kFPReg, true);
296 NewLIR2(cu, kThumb2Vnegs, rl_result.low_reg, rl_src.low_reg);
297 StoreValue(cu, rl_dest, rl_result);
buzbeeefc63692012-11-14 16:31:52 -0800298}
299
buzbee02031b12012-11-23 09:41:35 -0800300void ArmCodegen::GenNegDouble(CompilationUnit* cu, RegLocation rl_dest, RegLocation rl_src)
buzbeeefc63692012-11-14 16:31:52 -0800301{
buzbeefa57c472012-11-21 12:06:18 -0800302 RegLocation rl_result;
303 rl_src = LoadValueWide(cu, rl_src, kFPReg);
304 rl_result = EvalLoc(cu, rl_dest, kFPReg, true);
305 NewLIR2(cu, kThumb2Vnegd, S2d(rl_result.low_reg, rl_result.high_reg),
306 S2d(rl_src.low_reg, rl_src.high_reg));
307 StoreValueWide(cu, rl_dest, rl_result);
buzbeeefc63692012-11-14 16:31:52 -0800308}
309
buzbee02031b12012-11-23 09:41:35 -0800310bool ArmCodegen::GenInlinedSqrt(CompilationUnit* cu, CallInfo* info) {
buzbeefa57c472012-11-21 12:06:18 -0800311 DCHECK_EQ(cu->instruction_set, kThumb2);
buzbeeefc63692012-11-14 16:31:52 -0800312 LIR *branch;
buzbeefa57c472012-11-21 12:06:18 -0800313 RegLocation rl_src = info->args[0];
314 RegLocation rl_dest = InlineTargetWide(cu, info); // double place for result
315 rl_src = LoadValueWide(cu, rl_src, kFPReg);
316 RegLocation rl_result = EvalLoc(cu, rl_dest, kFPReg, true);
317 NewLIR2(cu, kThumb2Vsqrtd, S2d(rl_result.low_reg, rl_result.high_reg),
318 S2d(rl_src.low_reg, rl_src.high_reg));
319 NewLIR2(cu, kThumb2Vcmpd, S2d(rl_result.low_reg, rl_result.high_reg),
320 S2d(rl_result.low_reg, rl_result.high_reg));
321 NewLIR0(cu, kThumb2Fmstat);
322 branch = NewLIR2(cu, kThumbBCond, 0, kArmCondEq);
323 ClobberCalleeSave(cu);
324 LockCallTemps(cu); // Using fixed registers
325 int r_tgt = LoadHelper(cu, ENTRYPOINT_OFFSET(pSqrt));
326 NewLIR3(cu, kThumb2Fmrrd, r0, r1, S2d(rl_src.low_reg, rl_src.high_reg));
327 NewLIR1(cu, kThumbBlxR, r_tgt);
328 NewLIR3(cu, kThumb2Fmdrr, S2d(rl_result.low_reg, rl_result.high_reg), r0, r1);
329 branch->target = NewLIR0(cu, kPseudoTargetLabel);
330 StoreValueWide(cu, rl_dest, rl_result);
buzbeeefc63692012-11-14 16:31:52 -0800331 return true;
332}
333
334
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800335} // namespace art