blob: a9ea9161f020d70d58fa56ee0c2c1441ff0b383f [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:
53 case Instruction::NEG_FLOAT: {
buzbeefa57c472012-11-21 12:06:18 -080054 return GenArithOpFloatPortable(cu, opcode, rl_dest, rl_src1, rl_src2);
buzbee67bf8852011-08-17 17:51:35 -070055 }
Bill Buzbeea114add2012-05-03 15:00:40 -070056 default:
57 return true;
58 }
buzbeefa57c472012-11-21 12:06:18 -080059 rl_src1 = LoadValue(cu, rl_src1, kFPReg);
60 rl_src2 = LoadValue(cu, rl_src2, kFPReg);
61 rl_result = EvalLoc(cu, rl_dest, kFPReg, true);
62 NewLIR3(cu, op, rl_result.low_reg, rl_src1.low_reg, rl_src2.low_reg);
63 StoreValue(cu, rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -070064 return false;
buzbee67bf8852011-08-17 17:51:35 -070065}
66
buzbee02031b12012-11-23 09:41:35 -080067bool ArmCodegen::GenArithOpDouble(CompilationUnit* cu, Instruction::Code opcode,
68 RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2)
buzbee67bf8852011-08-17 17:51:35 -070069{
Bill Buzbeea114add2012-05-03 15:00:40 -070070 int op = kThumbBkpt;
buzbeefa57c472012-11-21 12:06:18 -080071 RegLocation rl_result;
buzbee67bf8852011-08-17 17:51:35 -070072
buzbee408ad162012-06-06 16:45:18 -070073 switch (opcode) {
Bill Buzbeea114add2012-05-03 15:00:40 -070074 case Instruction::ADD_DOUBLE_2ADDR:
75 case Instruction::ADD_DOUBLE:
76 op = kThumb2Vaddd;
77 break;
78 case Instruction::SUB_DOUBLE_2ADDR:
79 case Instruction::SUB_DOUBLE:
80 op = kThumb2Vsubd;
81 break;
82 case Instruction::DIV_DOUBLE_2ADDR:
83 case Instruction::DIV_DOUBLE:
84 op = kThumb2Vdivd;
85 break;
86 case Instruction::MUL_DOUBLE_2ADDR:
87 case Instruction::MUL_DOUBLE:
88 op = kThumb2Vmuld;
89 break;
90 case Instruction::REM_DOUBLE_2ADDR:
91 case Instruction::REM_DOUBLE:
92 case Instruction::NEG_DOUBLE: {
buzbeefa57c472012-11-21 12:06:18 -080093 return GenArithOpDoublePortable(cu, opcode, rl_dest, rl_src1, rl_src2);
buzbee67bf8852011-08-17 17:51:35 -070094 }
Bill Buzbeea114add2012-05-03 15:00:40 -070095 default:
96 return true;
97 }
buzbee67bf8852011-08-17 17:51:35 -070098
buzbeefa57c472012-11-21 12:06:18 -080099 rl_src1 = LoadValueWide(cu, rl_src1, kFPReg);
100 DCHECK(rl_src1.wide);
101 rl_src2 = LoadValueWide(cu, rl_src2, kFPReg);
102 DCHECK(rl_src2.wide);
103 rl_result = EvalLoc(cu, rl_dest, kFPReg, true);
104 DCHECK(rl_dest.wide);
105 DCHECK(rl_result.wide);
106 NewLIR3(cu, op, S2d(rl_result.low_reg, rl_result.high_reg), S2d(rl_src1.low_reg, rl_src1.high_reg),
107 S2d(rl_src2.low_reg, rl_src2.high_reg));
108 StoreValueWide(cu, rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -0700109 return false;
buzbee67bf8852011-08-17 17:51:35 -0700110}
111
buzbee02031b12012-11-23 09:41:35 -0800112bool ArmCodegen::GenConversion(CompilationUnit* cu, Instruction::Code opcode,
113 RegLocation rl_dest, RegLocation rl_src)
buzbee67bf8852011-08-17 17:51:35 -0700114{
Bill Buzbeea114add2012-05-03 15:00:40 -0700115 int op = kThumbBkpt;
buzbeefa57c472012-11-21 12:06:18 -0800116 int src_reg;
117 RegLocation rl_result;
buzbee67bf8852011-08-17 17:51:35 -0700118
Bill Buzbeea114add2012-05-03 15:00:40 -0700119 switch (opcode) {
120 case Instruction::INT_TO_FLOAT:
Bill Buzbeea114add2012-05-03 15:00:40 -0700121 op = kThumb2VcvtIF;
122 break;
123 case Instruction::FLOAT_TO_INT:
Bill Buzbeea114add2012-05-03 15:00:40 -0700124 op = kThumb2VcvtFI;
125 break;
126 case Instruction::DOUBLE_TO_FLOAT:
Bill Buzbeea114add2012-05-03 15:00:40 -0700127 op = kThumb2VcvtDF;
128 break;
129 case Instruction::FLOAT_TO_DOUBLE:
Bill Buzbeea114add2012-05-03 15:00:40 -0700130 op = kThumb2VcvtFd;
131 break;
132 case Instruction::INT_TO_DOUBLE:
Bill Buzbeea114add2012-05-03 15:00:40 -0700133 op = kThumb2VcvtID;
134 break;
135 case Instruction::DOUBLE_TO_INT:
Bill Buzbeea114add2012-05-03 15:00:40 -0700136 op = kThumb2VcvtDI;
137 break;
138 case Instruction::LONG_TO_DOUBLE:
139 case Instruction::FLOAT_TO_LONG:
140 case Instruction::LONG_TO_FLOAT:
141 case Instruction::DOUBLE_TO_LONG:
buzbeefa57c472012-11-21 12:06:18 -0800142 return GenConversionPortable(cu, opcode, rl_dest, rl_src);
Bill Buzbeea114add2012-05-03 15:00:40 -0700143 default:
144 return true;
145 }
buzbeefa57c472012-11-21 12:06:18 -0800146 if (rl_src.wide) {
147 rl_src = LoadValueWide(cu, rl_src, kFPReg);
148 src_reg = S2d(rl_src.low_reg, rl_src.high_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700149 } else {
buzbeefa57c472012-11-21 12:06:18 -0800150 rl_src = LoadValue(cu, rl_src, kFPReg);
151 src_reg = rl_src.low_reg;
Bill Buzbeea114add2012-05-03 15:00:40 -0700152 }
buzbeefa57c472012-11-21 12:06:18 -0800153 if (rl_dest.wide) {
154 rl_result = EvalLoc(cu, rl_dest, kFPReg, true);
155 NewLIR2(cu, op, S2d(rl_result.low_reg, rl_result.high_reg), src_reg);
156 StoreValueWide(cu, rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -0700157 } else {
buzbeefa57c472012-11-21 12:06:18 -0800158 rl_result = EvalLoc(cu, rl_dest, kFPReg, true);
159 NewLIR2(cu, op, rl_result.low_reg, src_reg);
160 StoreValue(cu, rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -0700161 }
162 return false;
buzbee67bf8852011-08-17 17:51:35 -0700163}
164
buzbee02031b12012-11-23 09:41:35 -0800165void ArmCodegen::GenFusedFPCmpBranch(CompilationUnit* cu, BasicBlock* bb, MIR* mir, bool gt_bias,
166 bool is_double)
buzbee84fd6932012-03-29 16:44:16 -0700167{
buzbeefa57c472012-11-21 12:06:18 -0800168 LIR* label_list = cu->block_label_list;
169 LIR* target = &label_list[bb->taken->id];
170 RegLocation rl_src1;
171 RegLocation rl_src2;
172 if (is_double) {
173 rl_src1 = GetSrcWide(cu, mir, 0);
174 rl_src2 = GetSrcWide(cu, mir, 2);
175 rl_src1 = LoadValueWide(cu, rl_src1, kFPReg);
176 rl_src2 = LoadValueWide(cu, rl_src2, kFPReg);
177 NewLIR2(cu, kThumb2Vcmpd, S2d(rl_src1.low_reg, rl_src2.high_reg),
178 S2d(rl_src2.low_reg, rl_src2.high_reg));
Bill Buzbeea114add2012-05-03 15:00:40 -0700179 } else {
buzbeefa57c472012-11-21 12:06:18 -0800180 rl_src1 = GetSrc(cu, mir, 0);
181 rl_src2 = GetSrc(cu, mir, 1);
182 rl_src1 = LoadValue(cu, rl_src1, kFPReg);
183 rl_src2 = LoadValue(cu, rl_src2, kFPReg);
184 NewLIR2(cu, kThumb2Vcmps, rl_src1.low_reg, rl_src2.low_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700185 }
buzbeefa57c472012-11-21 12:06:18 -0800186 NewLIR0(cu, kThumb2Fmstat);
Bill Buzbeea114add2012-05-03 15:00:40 -0700187 ConditionCode ccode = static_cast<ConditionCode>(mir->dalvikInsn.arg[0]);
188 switch(ccode) {
189 case kCondEq:
190 case kCondNe:
191 break;
192 case kCondLt:
buzbeefa57c472012-11-21 12:06:18 -0800193 if (gt_bias) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700194 ccode = kCondMi;
195 }
196 break;
197 case kCondLe:
buzbeefa57c472012-11-21 12:06:18 -0800198 if (gt_bias) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700199 ccode = kCondLs;
200 }
201 break;
202 case kCondGt:
buzbeefa57c472012-11-21 12:06:18 -0800203 if (gt_bias) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700204 ccode = kCondHi;
205 }
206 break;
207 case kCondGe:
buzbeefa57c472012-11-21 12:06:18 -0800208 if (gt_bias) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700209 ccode = kCondCs;
210 }
211 break;
212 default:
buzbeecbd6d442012-11-17 14:11:25 -0800213 LOG(FATAL) << "Unexpected ccode: " << ccode;
Bill Buzbeea114add2012-05-03 15:00:40 -0700214 }
buzbeefa57c472012-11-21 12:06:18 -0800215 OpCondBranch(cu, ccode, target);
buzbee84fd6932012-03-29 16:44:16 -0700216}
217
218
buzbee02031b12012-11-23 09:41:35 -0800219bool ArmCodegen::GenCmpFP(CompilationUnit* cu, Instruction::Code opcode, RegLocation rl_dest,
220 RegLocation rl_src1, RegLocation rl_src2)
buzbee67bf8852011-08-17 17:51:35 -0700221{
buzbeefa57c472012-11-21 12:06:18 -0800222 bool is_double;
223 int default_result;
224 RegLocation rl_result;
buzbee67bf8852011-08-17 17:51:35 -0700225
buzbee408ad162012-06-06 16:45:18 -0700226 switch (opcode) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700227 case Instruction::CMPL_FLOAT:
buzbeefa57c472012-11-21 12:06:18 -0800228 is_double = false;
229 default_result = -1;
Bill Buzbeea114add2012-05-03 15:00:40 -0700230 break;
231 case Instruction::CMPG_FLOAT:
buzbeefa57c472012-11-21 12:06:18 -0800232 is_double = false;
233 default_result = 1;
Bill Buzbeea114add2012-05-03 15:00:40 -0700234 break;
235 case Instruction::CMPL_DOUBLE:
buzbeefa57c472012-11-21 12:06:18 -0800236 is_double = true;
237 default_result = -1;
Bill Buzbeea114add2012-05-03 15:00:40 -0700238 break;
239 case Instruction::CMPG_DOUBLE:
buzbeefa57c472012-11-21 12:06:18 -0800240 is_double = true;
241 default_result = 1;
Bill Buzbeea114add2012-05-03 15:00:40 -0700242 break;
243 default:
244 return true;
245 }
buzbeefa57c472012-11-21 12:06:18 -0800246 if (is_double) {
247 rl_src1 = LoadValueWide(cu, rl_src1, kFPReg);
248 rl_src2 = LoadValueWide(cu, rl_src2, kFPReg);
249 ClobberSReg(cu, rl_dest.s_reg_low);
250 rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
251 LoadConstant(cu, rl_result.low_reg, default_result);
252 NewLIR2(cu, kThumb2Vcmpd, S2d(rl_src1.low_reg, rl_src2.high_reg),
253 S2d(rl_src2.low_reg, rl_src2.high_reg));
Bill Buzbeea114add2012-05-03 15:00:40 -0700254 } else {
buzbeefa57c472012-11-21 12:06:18 -0800255 rl_src1 = LoadValue(cu, rl_src1, kFPReg);
256 rl_src2 = LoadValue(cu, rl_src2, kFPReg);
257 ClobberSReg(cu, rl_dest.s_reg_low);
258 rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
259 LoadConstant(cu, rl_result.low_reg, default_result);
260 NewLIR2(cu, kThumb2Vcmps, rl_src1.low_reg, rl_src2.low_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700261 }
buzbeefa57c472012-11-21 12:06:18 -0800262 DCHECK(!ARM_FPREG(rl_result.low_reg));
263 NewLIR0(cu, kThumb2Fmstat);
buzbee67bf8852011-08-17 17:51:35 -0700264
buzbee02031b12012-11-23 09:41:35 -0800265 OpIT(cu, (default_result == -1) ? kCondGt : kCondMi, "");
buzbeefa57c472012-11-21 12:06:18 -0800266 NewLIR2(cu, kThumb2MovImmShift, rl_result.low_reg,
267 ModifiedImmediate(-default_result)); // Must not alter ccodes
268 GenBarrier(cu);
buzbee67bf8852011-08-17 17:51:35 -0700269
buzbee02031b12012-11-23 09:41:35 -0800270 OpIT(cu, kCondEq, "");
buzbeefa57c472012-11-21 12:06:18 -0800271 LoadConstant(cu, rl_result.low_reg, 0);
272 GenBarrier(cu);
buzbee67bf8852011-08-17 17:51:35 -0700273
buzbeefa57c472012-11-21 12:06:18 -0800274 StoreValue(cu, rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -0700275 return false;
buzbee67bf8852011-08-17 17:51:35 -0700276}
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800277
buzbee02031b12012-11-23 09:41:35 -0800278void ArmCodegen::GenNegFloat(CompilationUnit* cu, RegLocation rl_dest, RegLocation rl_src)
buzbeeefc63692012-11-14 16:31:52 -0800279{
buzbeefa57c472012-11-21 12:06:18 -0800280 RegLocation rl_result;
281 rl_src = LoadValue(cu, rl_src, kFPReg);
282 rl_result = EvalLoc(cu, rl_dest, kFPReg, true);
283 NewLIR2(cu, kThumb2Vnegs, rl_result.low_reg, rl_src.low_reg);
284 StoreValue(cu, rl_dest, rl_result);
buzbeeefc63692012-11-14 16:31:52 -0800285}
286
buzbee02031b12012-11-23 09:41:35 -0800287void ArmCodegen::GenNegDouble(CompilationUnit* cu, RegLocation rl_dest, RegLocation rl_src)
buzbeeefc63692012-11-14 16:31:52 -0800288{
buzbeefa57c472012-11-21 12:06:18 -0800289 RegLocation rl_result;
290 rl_src = LoadValueWide(cu, rl_src, kFPReg);
291 rl_result = EvalLoc(cu, rl_dest, kFPReg, true);
292 NewLIR2(cu, kThumb2Vnegd, S2d(rl_result.low_reg, rl_result.high_reg),
293 S2d(rl_src.low_reg, rl_src.high_reg));
294 StoreValueWide(cu, rl_dest, rl_result);
buzbeeefc63692012-11-14 16:31:52 -0800295}
296
buzbee02031b12012-11-23 09:41:35 -0800297bool ArmCodegen::GenInlinedSqrt(CompilationUnit* cu, CallInfo* info) {
buzbeefa57c472012-11-21 12:06:18 -0800298 DCHECK_EQ(cu->instruction_set, kThumb2);
buzbeeefc63692012-11-14 16:31:52 -0800299 LIR *branch;
buzbeefa57c472012-11-21 12:06:18 -0800300 RegLocation rl_src = info->args[0];
301 RegLocation rl_dest = InlineTargetWide(cu, info); // double place for result
302 rl_src = LoadValueWide(cu, rl_src, kFPReg);
303 RegLocation rl_result = EvalLoc(cu, rl_dest, kFPReg, true);
304 NewLIR2(cu, kThumb2Vsqrtd, S2d(rl_result.low_reg, rl_result.high_reg),
305 S2d(rl_src.low_reg, rl_src.high_reg));
306 NewLIR2(cu, kThumb2Vcmpd, S2d(rl_result.low_reg, rl_result.high_reg),
307 S2d(rl_result.low_reg, rl_result.high_reg));
308 NewLIR0(cu, kThumb2Fmstat);
309 branch = NewLIR2(cu, kThumbBCond, 0, kArmCondEq);
310 ClobberCalleeSave(cu);
311 LockCallTemps(cu); // Using fixed registers
312 int r_tgt = LoadHelper(cu, ENTRYPOINT_OFFSET(pSqrt));
313 NewLIR3(cu, kThumb2Fmrrd, r0, r1, S2d(rl_src.low_reg, rl_src.high_reg));
314 NewLIR1(cu, kThumbBlxR, r_tgt);
315 NewLIR3(cu, kThumb2Fmdrr, S2d(rl_result.low_reg, rl_result.high_reg), r0, r1);
316 branch->target = NewLIR0(cu, kPseudoTargetLabel);
317 StoreValueWide(cu, rl_dest, rl_result);
buzbeeefc63692012-11-14 16:31:52 -0800318 return true;
319}
320
321
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800322} // namespace art