blob: 46695b9e515fae7e503a5e368572028b837cfaa8 [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"
18#include "../codegen_util.h"
19#include "../ralloc_util.h"
20
Elliott Hughes11d1b0c2012-01-23 16:57:47 -080021namespace art {
22
buzbeefa57c472012-11-21 12:06:18 -080023bool GenArithOpFloat(CompilationUnit* cu, Instruction::Code opcode, RegLocation rl_dest,
24 RegLocation rl_src1, RegLocation rl_src2)
buzbee67bf8852011-08-17 17:51:35 -070025{
Bill Buzbeea114add2012-05-03 15:00:40 -070026 int op = kThumbBkpt;
buzbeefa57c472012-11-21 12:06:18 -080027 RegLocation rl_result;
buzbee67bf8852011-08-17 17:51:35 -070028
Bill Buzbeea114add2012-05-03 15:00:40 -070029 /*
30 * Don't attempt to optimize register usage since these opcodes call out to
31 * the handlers.
32 */
buzbee408ad162012-06-06 16:45:18 -070033 switch (opcode) {
Bill Buzbeea114add2012-05-03 15:00:40 -070034 case Instruction::ADD_FLOAT_2ADDR:
35 case Instruction::ADD_FLOAT:
36 op = kThumb2Vadds;
37 break;
38 case Instruction::SUB_FLOAT_2ADDR:
39 case Instruction::SUB_FLOAT:
40 op = kThumb2Vsubs;
41 break;
42 case Instruction::DIV_FLOAT_2ADDR:
43 case Instruction::DIV_FLOAT:
44 op = kThumb2Vdivs;
45 break;
46 case Instruction::MUL_FLOAT_2ADDR:
47 case Instruction::MUL_FLOAT:
48 op = kThumb2Vmuls;
49 break;
50 case Instruction::REM_FLOAT_2ADDR:
51 case Instruction::REM_FLOAT:
52 case Instruction::NEG_FLOAT: {
buzbeefa57c472012-11-21 12:06:18 -080053 return GenArithOpFloatPortable(cu, opcode, rl_dest, rl_src1, rl_src2);
buzbee67bf8852011-08-17 17:51:35 -070054 }
Bill Buzbeea114add2012-05-03 15:00:40 -070055 default:
56 return true;
57 }
buzbeefa57c472012-11-21 12:06:18 -080058 rl_src1 = LoadValue(cu, rl_src1, kFPReg);
59 rl_src2 = LoadValue(cu, rl_src2, kFPReg);
60 rl_result = EvalLoc(cu, rl_dest, kFPReg, true);
61 NewLIR3(cu, op, rl_result.low_reg, rl_src1.low_reg, rl_src2.low_reg);
62 StoreValue(cu, rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -070063 return false;
buzbee67bf8852011-08-17 17:51:35 -070064}
65
buzbeefa57c472012-11-21 12:06:18 -080066bool GenArithOpDouble(CompilationUnit* cu, Instruction::Code opcode,
67 RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2)
buzbee67bf8852011-08-17 17:51:35 -070068{
Bill Buzbeea114add2012-05-03 15:00:40 -070069 int op = kThumbBkpt;
buzbeefa57c472012-11-21 12:06:18 -080070 RegLocation rl_result;
buzbee67bf8852011-08-17 17:51:35 -070071
buzbee408ad162012-06-06 16:45:18 -070072 switch (opcode) {
Bill Buzbeea114add2012-05-03 15:00:40 -070073 case Instruction::ADD_DOUBLE_2ADDR:
74 case Instruction::ADD_DOUBLE:
75 op = kThumb2Vaddd;
76 break;
77 case Instruction::SUB_DOUBLE_2ADDR:
78 case Instruction::SUB_DOUBLE:
79 op = kThumb2Vsubd;
80 break;
81 case Instruction::DIV_DOUBLE_2ADDR:
82 case Instruction::DIV_DOUBLE:
83 op = kThumb2Vdivd;
84 break;
85 case Instruction::MUL_DOUBLE_2ADDR:
86 case Instruction::MUL_DOUBLE:
87 op = kThumb2Vmuld;
88 break;
89 case Instruction::REM_DOUBLE_2ADDR:
90 case Instruction::REM_DOUBLE:
91 case Instruction::NEG_DOUBLE: {
buzbeefa57c472012-11-21 12:06:18 -080092 return GenArithOpDoublePortable(cu, opcode, rl_dest, rl_src1, rl_src2);
buzbee67bf8852011-08-17 17:51:35 -070093 }
Bill Buzbeea114add2012-05-03 15:00:40 -070094 default:
95 return true;
96 }
buzbee67bf8852011-08-17 17:51:35 -070097
buzbeefa57c472012-11-21 12:06:18 -080098 rl_src1 = LoadValueWide(cu, rl_src1, kFPReg);
99 DCHECK(rl_src1.wide);
100 rl_src2 = LoadValueWide(cu, rl_src2, kFPReg);
101 DCHECK(rl_src2.wide);
102 rl_result = EvalLoc(cu, rl_dest, kFPReg, true);
103 DCHECK(rl_dest.wide);
104 DCHECK(rl_result.wide);
105 NewLIR3(cu, op, S2d(rl_result.low_reg, rl_result.high_reg), S2d(rl_src1.low_reg, rl_src1.high_reg),
106 S2d(rl_src2.low_reg, rl_src2.high_reg));
107 StoreValueWide(cu, rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -0700108 return false;
buzbee67bf8852011-08-17 17:51:35 -0700109}
110
buzbeefa57c472012-11-21 12:06:18 -0800111bool GenConversion(CompilationUnit* cu, Instruction::Code opcode,
112 RegLocation rl_dest, RegLocation rl_src)
buzbee67bf8852011-08-17 17:51:35 -0700113{
Bill Buzbeea114add2012-05-03 15:00:40 -0700114 int op = kThumbBkpt;
buzbeefa57c472012-11-21 12:06:18 -0800115 int src_reg;
116 RegLocation rl_result;
buzbee67bf8852011-08-17 17:51:35 -0700117
Bill Buzbeea114add2012-05-03 15:00:40 -0700118 switch (opcode) {
119 case Instruction::INT_TO_FLOAT:
Bill Buzbeea114add2012-05-03 15:00:40 -0700120 op = kThumb2VcvtIF;
121 break;
122 case Instruction::FLOAT_TO_INT:
Bill Buzbeea114add2012-05-03 15:00:40 -0700123 op = kThumb2VcvtFI;
124 break;
125 case Instruction::DOUBLE_TO_FLOAT:
Bill Buzbeea114add2012-05-03 15:00:40 -0700126 op = kThumb2VcvtDF;
127 break;
128 case Instruction::FLOAT_TO_DOUBLE:
Bill Buzbeea114add2012-05-03 15:00:40 -0700129 op = kThumb2VcvtFd;
130 break;
131 case Instruction::INT_TO_DOUBLE:
Bill Buzbeea114add2012-05-03 15:00:40 -0700132 op = kThumb2VcvtID;
133 break;
134 case Instruction::DOUBLE_TO_INT:
Bill Buzbeea114add2012-05-03 15:00:40 -0700135 op = kThumb2VcvtDI;
136 break;
137 case Instruction::LONG_TO_DOUBLE:
138 case Instruction::FLOAT_TO_LONG:
139 case Instruction::LONG_TO_FLOAT:
140 case Instruction::DOUBLE_TO_LONG:
buzbeefa57c472012-11-21 12:06:18 -0800141 return GenConversionPortable(cu, opcode, rl_dest, rl_src);
Bill Buzbeea114add2012-05-03 15:00:40 -0700142 default:
143 return true;
144 }
buzbeefa57c472012-11-21 12:06:18 -0800145 if (rl_src.wide) {
146 rl_src = LoadValueWide(cu, rl_src, kFPReg);
147 src_reg = S2d(rl_src.low_reg, rl_src.high_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700148 } else {
buzbeefa57c472012-11-21 12:06:18 -0800149 rl_src = LoadValue(cu, rl_src, kFPReg);
150 src_reg = rl_src.low_reg;
Bill Buzbeea114add2012-05-03 15:00:40 -0700151 }
buzbeefa57c472012-11-21 12:06:18 -0800152 if (rl_dest.wide) {
153 rl_result = EvalLoc(cu, rl_dest, kFPReg, true);
154 NewLIR2(cu, op, S2d(rl_result.low_reg, rl_result.high_reg), src_reg);
155 StoreValueWide(cu, rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -0700156 } else {
buzbeefa57c472012-11-21 12:06:18 -0800157 rl_result = EvalLoc(cu, rl_dest, kFPReg, true);
158 NewLIR2(cu, op, rl_result.low_reg, src_reg);
159 StoreValue(cu, rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -0700160 }
161 return false;
buzbee67bf8852011-08-17 17:51:35 -0700162}
163
buzbeefa57c472012-11-21 12:06:18 -0800164void GenFusedFPCmpBranch(CompilationUnit* cu, BasicBlock* bb, MIR* mir,
165 bool gt_bias, bool is_double)
buzbee84fd6932012-03-29 16:44:16 -0700166{
buzbeefa57c472012-11-21 12:06:18 -0800167 LIR* label_list = cu->block_label_list;
168 LIR* target = &label_list[bb->taken->id];
169 RegLocation rl_src1;
170 RegLocation rl_src2;
171 if (is_double) {
172 rl_src1 = GetSrcWide(cu, mir, 0);
173 rl_src2 = GetSrcWide(cu, mir, 2);
174 rl_src1 = LoadValueWide(cu, rl_src1, kFPReg);
175 rl_src2 = LoadValueWide(cu, rl_src2, kFPReg);
176 NewLIR2(cu, kThumb2Vcmpd, S2d(rl_src1.low_reg, rl_src2.high_reg),
177 S2d(rl_src2.low_reg, rl_src2.high_reg));
Bill Buzbeea114add2012-05-03 15:00:40 -0700178 } else {
buzbeefa57c472012-11-21 12:06:18 -0800179 rl_src1 = GetSrc(cu, mir, 0);
180 rl_src2 = GetSrc(cu, mir, 1);
181 rl_src1 = LoadValue(cu, rl_src1, kFPReg);
182 rl_src2 = LoadValue(cu, rl_src2, kFPReg);
183 NewLIR2(cu, kThumb2Vcmps, rl_src1.low_reg, rl_src2.low_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700184 }
buzbeefa57c472012-11-21 12:06:18 -0800185 NewLIR0(cu, kThumb2Fmstat);
Bill Buzbeea114add2012-05-03 15:00:40 -0700186 ConditionCode ccode = static_cast<ConditionCode>(mir->dalvikInsn.arg[0]);
187 switch(ccode) {
188 case kCondEq:
189 case kCondNe:
190 break;
191 case kCondLt:
buzbeefa57c472012-11-21 12:06:18 -0800192 if (gt_bias) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700193 ccode = kCondMi;
194 }
195 break;
196 case kCondLe:
buzbeefa57c472012-11-21 12:06:18 -0800197 if (gt_bias) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700198 ccode = kCondLs;
199 }
200 break;
201 case kCondGt:
buzbeefa57c472012-11-21 12:06:18 -0800202 if (gt_bias) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700203 ccode = kCondHi;
204 }
205 break;
206 case kCondGe:
buzbeefa57c472012-11-21 12:06:18 -0800207 if (gt_bias) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700208 ccode = kCondCs;
209 }
210 break;
211 default:
buzbeecbd6d442012-11-17 14:11:25 -0800212 LOG(FATAL) << "Unexpected ccode: " << ccode;
Bill Buzbeea114add2012-05-03 15:00:40 -0700213 }
buzbeefa57c472012-11-21 12:06:18 -0800214 OpCondBranch(cu, ccode, target);
buzbee84fd6932012-03-29 16:44:16 -0700215}
216
217
buzbeefa57c472012-11-21 12:06:18 -0800218bool GenCmpFP(CompilationUnit* cu, Instruction::Code opcode, RegLocation rl_dest,
219 RegLocation rl_src1, RegLocation rl_src2)
buzbee67bf8852011-08-17 17:51:35 -0700220{
buzbeefa57c472012-11-21 12:06:18 -0800221 bool is_double;
222 int default_result;
223 RegLocation rl_result;
buzbee67bf8852011-08-17 17:51:35 -0700224
buzbee408ad162012-06-06 16:45:18 -0700225 switch (opcode) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700226 case Instruction::CMPL_FLOAT:
buzbeefa57c472012-11-21 12:06:18 -0800227 is_double = false;
228 default_result = -1;
Bill Buzbeea114add2012-05-03 15:00:40 -0700229 break;
230 case Instruction::CMPG_FLOAT:
buzbeefa57c472012-11-21 12:06:18 -0800231 is_double = false;
232 default_result = 1;
Bill Buzbeea114add2012-05-03 15:00:40 -0700233 break;
234 case Instruction::CMPL_DOUBLE:
buzbeefa57c472012-11-21 12:06:18 -0800235 is_double = true;
236 default_result = -1;
Bill Buzbeea114add2012-05-03 15:00:40 -0700237 break;
238 case Instruction::CMPG_DOUBLE:
buzbeefa57c472012-11-21 12:06:18 -0800239 is_double = true;
240 default_result = 1;
Bill Buzbeea114add2012-05-03 15:00:40 -0700241 break;
242 default:
243 return true;
244 }
buzbeefa57c472012-11-21 12:06:18 -0800245 if (is_double) {
246 rl_src1 = LoadValueWide(cu, rl_src1, kFPReg);
247 rl_src2 = LoadValueWide(cu, rl_src2, kFPReg);
248 ClobberSReg(cu, rl_dest.s_reg_low);
249 rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
250 LoadConstant(cu, rl_result.low_reg, default_result);
251 NewLIR2(cu, kThumb2Vcmpd, S2d(rl_src1.low_reg, rl_src2.high_reg),
252 S2d(rl_src2.low_reg, rl_src2.high_reg));
Bill Buzbeea114add2012-05-03 15:00:40 -0700253 } else {
buzbeefa57c472012-11-21 12:06:18 -0800254 rl_src1 = LoadValue(cu, rl_src1, kFPReg);
255 rl_src2 = LoadValue(cu, rl_src2, kFPReg);
256 ClobberSReg(cu, rl_dest.s_reg_low);
257 rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
258 LoadConstant(cu, rl_result.low_reg, default_result);
259 NewLIR2(cu, kThumb2Vcmps, rl_src1.low_reg, rl_src2.low_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700260 }
buzbeefa57c472012-11-21 12:06:18 -0800261 DCHECK(!ARM_FPREG(rl_result.low_reg));
262 NewLIR0(cu, kThumb2Fmstat);
buzbee67bf8852011-08-17 17:51:35 -0700263
buzbeefa57c472012-11-21 12:06:18 -0800264 OpIT(cu, (default_result == -1) ? kArmCondGt : kArmCondMi, "");
265 NewLIR2(cu, kThumb2MovImmShift, rl_result.low_reg,
266 ModifiedImmediate(-default_result)); // Must not alter ccodes
267 GenBarrier(cu);
buzbee67bf8852011-08-17 17:51:35 -0700268
buzbeefa57c472012-11-21 12:06:18 -0800269 OpIT(cu, kArmCondEq, "");
270 LoadConstant(cu, rl_result.low_reg, 0);
271 GenBarrier(cu);
buzbee67bf8852011-08-17 17:51:35 -0700272
buzbeefa57c472012-11-21 12:06:18 -0800273 StoreValue(cu, rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -0700274 return false;
buzbee67bf8852011-08-17 17:51:35 -0700275}
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800276
buzbeefa57c472012-11-21 12:06:18 -0800277void GenNegFloat(CompilationUnit* cu, RegLocation rl_dest, RegLocation rl_src)
buzbeeefc63692012-11-14 16:31:52 -0800278{
buzbeefa57c472012-11-21 12:06:18 -0800279 RegLocation rl_result;
280 rl_src = LoadValue(cu, rl_src, kFPReg);
281 rl_result = EvalLoc(cu, rl_dest, kFPReg, true);
282 NewLIR2(cu, kThumb2Vnegs, rl_result.low_reg, rl_src.low_reg);
283 StoreValue(cu, rl_dest, rl_result);
buzbeeefc63692012-11-14 16:31:52 -0800284}
285
buzbeefa57c472012-11-21 12:06:18 -0800286void GenNegDouble(CompilationUnit* cu, RegLocation rl_dest, RegLocation rl_src)
buzbeeefc63692012-11-14 16:31:52 -0800287{
buzbeefa57c472012-11-21 12:06:18 -0800288 RegLocation rl_result;
289 rl_src = LoadValueWide(cu, rl_src, kFPReg);
290 rl_result = EvalLoc(cu, rl_dest, kFPReg, true);
291 NewLIR2(cu, kThumb2Vnegd, S2d(rl_result.low_reg, rl_result.high_reg),
292 S2d(rl_src.low_reg, rl_src.high_reg));
293 StoreValueWide(cu, rl_dest, rl_result);
buzbeeefc63692012-11-14 16:31:52 -0800294}
295
buzbeefa57c472012-11-21 12:06:18 -0800296bool GenInlinedSqrt(CompilationUnit* cu, CallInfo* info) {
297 DCHECK_EQ(cu->instruction_set, kThumb2);
buzbeeefc63692012-11-14 16:31:52 -0800298 LIR *branch;
buzbeefa57c472012-11-21 12:06:18 -0800299 RegLocation rl_src = info->args[0];
300 RegLocation rl_dest = InlineTargetWide(cu, info); // double place for result
301 rl_src = LoadValueWide(cu, rl_src, kFPReg);
302 RegLocation rl_result = EvalLoc(cu, rl_dest, kFPReg, true);
303 NewLIR2(cu, kThumb2Vsqrtd, S2d(rl_result.low_reg, rl_result.high_reg),
304 S2d(rl_src.low_reg, rl_src.high_reg));
305 NewLIR2(cu, kThumb2Vcmpd, S2d(rl_result.low_reg, rl_result.high_reg),
306 S2d(rl_result.low_reg, rl_result.high_reg));
307 NewLIR0(cu, kThumb2Fmstat);
308 branch = NewLIR2(cu, kThumbBCond, 0, kArmCondEq);
309 ClobberCalleeSave(cu);
310 LockCallTemps(cu); // Using fixed registers
311 int r_tgt = LoadHelper(cu, ENTRYPOINT_OFFSET(pSqrt));
312 NewLIR3(cu, kThumb2Fmrrd, r0, r1, S2d(rl_src.low_reg, rl_src.high_reg));
313 NewLIR1(cu, kThumbBlxR, r_tgt);
314 NewLIR3(cu, kThumb2Fmdrr, S2d(rl_result.low_reg, rl_result.high_reg), r0, r1);
315 branch->target = NewLIR0(cu, kPseudoTargetLabel);
316 StoreValueWide(cu, rl_dest, rl_result);
buzbeeefc63692012-11-14 16:31:52 -0800317 return true;
318}
319
320
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800321} // namespace art