blob: 14d766f27a1e67478bb1a14d1eee540a98c19f64 [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"
Brian Carlstrom641ce032013-01-31 15:21:37 -080019#include "compiler/codegen/codegen_util.h"
20#include "compiler/codegen/ralloc_util.h"
buzbee1bc37c62012-11-20 13:35:41 -080021
Elliott Hughes11d1b0c2012-01-23 16:57:47 -080022namespace art {
23
buzbeea5954be2013-02-07 10:41:40 -080024void ArmCodegen::GenArithOpFloat(CompilationUnit* cu, Instruction::Code opcode, RegLocation rl_dest,
buzbee02031b12012-11-23 09:41:35 -080025 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);
buzbeea5954be2013-02-07 10:41:40 -080057 return;
buzbeea3a82b22012-11-27 16:09:55 -080058 case Instruction::NEG_FLOAT:
59 GenNegFloat(cu, rl_dest, rl_src1);
buzbeea5954be2013-02-07 10:41:40 -080060 return;
Bill Buzbeea114add2012-05-03 15:00:40 -070061 default:
buzbeea5954be2013-02-07 10:41:40 -080062 LOG(FATAL) << "Unexpected opcode: " << opcode;
Bill Buzbeea114add2012-05-03 15:00:40 -070063 }
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);
buzbee67bf8852011-08-17 17:51:35 -070069}
70
buzbeea5954be2013-02-07 10:41:40 -080071void ArmCodegen::GenArithOpDouble(CompilationUnit* cu, Instruction::Code opcode,
buzbee02031b12012-11-23 09:41:35 -080072 RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2)
buzbee67bf8852011-08-17 17:51:35 -070073{
Bill Buzbeea114add2012-05-03 15:00:40 -070074 int op = kThumbBkpt;
buzbeefa57c472012-11-21 12:06:18 -080075 RegLocation rl_result;
buzbee67bf8852011-08-17 17:51:35 -070076
buzbee408ad162012-06-06 16:45:18 -070077 switch (opcode) {
Bill Buzbeea114add2012-05-03 15:00:40 -070078 case Instruction::ADD_DOUBLE_2ADDR:
79 case Instruction::ADD_DOUBLE:
80 op = kThumb2Vaddd;
81 break;
82 case Instruction::SUB_DOUBLE_2ADDR:
83 case Instruction::SUB_DOUBLE:
84 op = kThumb2Vsubd;
85 break;
86 case Instruction::DIV_DOUBLE_2ADDR:
87 case Instruction::DIV_DOUBLE:
88 op = kThumb2Vdivd;
89 break;
90 case Instruction::MUL_DOUBLE_2ADDR:
91 case Instruction::MUL_DOUBLE:
92 op = kThumb2Vmuld;
93 break;
94 case Instruction::REM_DOUBLE_2ADDR:
95 case Instruction::REM_DOUBLE:
buzbeea3a82b22012-11-27 16:09:55 -080096 FlushAllRegs(cu); // Send everything to home location
97 CallRuntimeHelperRegLocationRegLocation(cu, ENTRYPOINT_OFFSET(pFmod), rl_src1, rl_src2, false);
98 rl_result = GetReturnWide(cu, true);
99 StoreValueWide(cu, rl_dest, rl_result);
buzbeea5954be2013-02-07 10:41:40 -0800100 return;
buzbeea3a82b22012-11-27 16:09:55 -0800101 case Instruction::NEG_DOUBLE:
102 GenNegDouble(cu, rl_dest, rl_src1);
buzbeea5954be2013-02-07 10:41:40 -0800103 return;
Bill Buzbeea114add2012-05-03 15:00:40 -0700104 default:
buzbeea5954be2013-02-07 10:41:40 -0800105 LOG(FATAL) << "Unexpected opcode: " << opcode;
Bill Buzbeea114add2012-05-03 15:00:40 -0700106 }
buzbee67bf8852011-08-17 17:51:35 -0700107
buzbeefa57c472012-11-21 12:06:18 -0800108 rl_src1 = LoadValueWide(cu, rl_src1, kFPReg);
109 DCHECK(rl_src1.wide);
110 rl_src2 = LoadValueWide(cu, rl_src2, kFPReg);
111 DCHECK(rl_src2.wide);
112 rl_result = EvalLoc(cu, rl_dest, kFPReg, true);
113 DCHECK(rl_dest.wide);
114 DCHECK(rl_result.wide);
115 NewLIR3(cu, op, S2d(rl_result.low_reg, rl_result.high_reg), S2d(rl_src1.low_reg, rl_src1.high_reg),
116 S2d(rl_src2.low_reg, rl_src2.high_reg));
117 StoreValueWide(cu, rl_dest, rl_result);
buzbee67bf8852011-08-17 17:51:35 -0700118}
119
buzbeea5954be2013-02-07 10:41:40 -0800120void ArmCodegen::GenConversion(CompilationUnit* cu, Instruction::Code opcode,
buzbee02031b12012-11-23 09:41:35 -0800121 RegLocation rl_dest, RegLocation rl_src)
buzbee67bf8852011-08-17 17:51:35 -0700122{
Bill Buzbeea114add2012-05-03 15:00:40 -0700123 int op = kThumbBkpt;
buzbeefa57c472012-11-21 12:06:18 -0800124 int src_reg;
125 RegLocation rl_result;
buzbee67bf8852011-08-17 17:51:35 -0700126
Bill Buzbeea114add2012-05-03 15:00:40 -0700127 switch (opcode) {
128 case Instruction::INT_TO_FLOAT:
Bill Buzbeea114add2012-05-03 15:00:40 -0700129 op = kThumb2VcvtIF;
130 break;
131 case Instruction::FLOAT_TO_INT:
Bill Buzbeea114add2012-05-03 15:00:40 -0700132 op = kThumb2VcvtFI;
133 break;
134 case Instruction::DOUBLE_TO_FLOAT:
Bill Buzbeea114add2012-05-03 15:00:40 -0700135 op = kThumb2VcvtDF;
136 break;
137 case Instruction::FLOAT_TO_DOUBLE:
Bill Buzbeea114add2012-05-03 15:00:40 -0700138 op = kThumb2VcvtFd;
139 break;
140 case Instruction::INT_TO_DOUBLE:
Bill Buzbeea114add2012-05-03 15:00:40 -0700141 op = kThumb2VcvtID;
142 break;
143 case Instruction::DOUBLE_TO_INT:
Bill Buzbeea114add2012-05-03 15:00:40 -0700144 op = kThumb2VcvtDI;
145 break;
146 case Instruction::LONG_TO_DOUBLE:
buzbeea5954be2013-02-07 10:41:40 -0800147 GenConversionCall(cu, ENTRYPOINT_OFFSET(pL2d), rl_dest, rl_src);
148 return;
Bill Buzbeea114add2012-05-03 15:00:40 -0700149 case Instruction::FLOAT_TO_LONG:
buzbeea5954be2013-02-07 10:41:40 -0800150 GenConversionCall(cu, ENTRYPOINT_OFFSET(pF2l), rl_dest, rl_src);
151 return;
Bill Buzbeea114add2012-05-03 15:00:40 -0700152 case Instruction::LONG_TO_FLOAT:
buzbeea5954be2013-02-07 10:41:40 -0800153 GenConversionCall(cu, ENTRYPOINT_OFFSET(pL2f), rl_dest, rl_src);
154 return;
Bill Buzbeea114add2012-05-03 15:00:40 -0700155 case Instruction::DOUBLE_TO_LONG:
buzbeea5954be2013-02-07 10:41:40 -0800156 GenConversionCall(cu, ENTRYPOINT_OFFSET(pD2l), rl_dest, rl_src);
157 return;
Bill Buzbeea114add2012-05-03 15:00:40 -0700158 default:
buzbeea5954be2013-02-07 10:41:40 -0800159 LOG(FATAL) << "Unexpected opcode: " << opcode;
Bill Buzbeea114add2012-05-03 15:00:40 -0700160 }
buzbeefa57c472012-11-21 12:06:18 -0800161 if (rl_src.wide) {
162 rl_src = LoadValueWide(cu, rl_src, kFPReg);
163 src_reg = S2d(rl_src.low_reg, rl_src.high_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700164 } else {
buzbeefa57c472012-11-21 12:06:18 -0800165 rl_src = LoadValue(cu, rl_src, kFPReg);
166 src_reg = rl_src.low_reg;
Bill Buzbeea114add2012-05-03 15:00:40 -0700167 }
buzbeefa57c472012-11-21 12:06:18 -0800168 if (rl_dest.wide) {
169 rl_result = EvalLoc(cu, rl_dest, kFPReg, true);
170 NewLIR2(cu, op, S2d(rl_result.low_reg, rl_result.high_reg), src_reg);
171 StoreValueWide(cu, rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -0700172 } else {
buzbeefa57c472012-11-21 12:06:18 -0800173 rl_result = EvalLoc(cu, rl_dest, kFPReg, true);
174 NewLIR2(cu, op, rl_result.low_reg, src_reg);
175 StoreValue(cu, rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -0700176 }
buzbee67bf8852011-08-17 17:51:35 -0700177}
178
buzbee02031b12012-11-23 09:41:35 -0800179void ArmCodegen::GenFusedFPCmpBranch(CompilationUnit* cu, BasicBlock* bb, MIR* mir, bool gt_bias,
180 bool is_double)
buzbee84fd6932012-03-29 16:44:16 -0700181{
buzbeefa57c472012-11-21 12:06:18 -0800182 LIR* label_list = cu->block_label_list;
183 LIR* target = &label_list[bb->taken->id];
184 RegLocation rl_src1;
185 RegLocation rl_src2;
186 if (is_double) {
187 rl_src1 = GetSrcWide(cu, mir, 0);
188 rl_src2 = GetSrcWide(cu, mir, 2);
189 rl_src1 = LoadValueWide(cu, rl_src1, kFPReg);
190 rl_src2 = LoadValueWide(cu, rl_src2, kFPReg);
191 NewLIR2(cu, kThumb2Vcmpd, S2d(rl_src1.low_reg, rl_src2.high_reg),
192 S2d(rl_src2.low_reg, rl_src2.high_reg));
Bill Buzbeea114add2012-05-03 15:00:40 -0700193 } else {
buzbeefa57c472012-11-21 12:06:18 -0800194 rl_src1 = GetSrc(cu, mir, 0);
195 rl_src2 = GetSrc(cu, mir, 1);
196 rl_src1 = LoadValue(cu, rl_src1, kFPReg);
197 rl_src2 = LoadValue(cu, rl_src2, kFPReg);
198 NewLIR2(cu, kThumb2Vcmps, rl_src1.low_reg, rl_src2.low_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700199 }
buzbeefa57c472012-11-21 12:06:18 -0800200 NewLIR0(cu, kThumb2Fmstat);
Bill Buzbeea114add2012-05-03 15:00:40 -0700201 ConditionCode ccode = static_cast<ConditionCode>(mir->dalvikInsn.arg[0]);
202 switch(ccode) {
203 case kCondEq:
204 case kCondNe:
205 break;
206 case kCondLt:
buzbeefa57c472012-11-21 12:06:18 -0800207 if (gt_bias) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700208 ccode = kCondMi;
209 }
210 break;
211 case kCondLe:
buzbeefa57c472012-11-21 12:06:18 -0800212 if (gt_bias) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700213 ccode = kCondLs;
214 }
215 break;
216 case kCondGt:
buzbeefa57c472012-11-21 12:06:18 -0800217 if (gt_bias) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700218 ccode = kCondHi;
219 }
220 break;
221 case kCondGe:
buzbeefa57c472012-11-21 12:06:18 -0800222 if (gt_bias) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700223 ccode = kCondCs;
224 }
225 break;
226 default:
buzbeecbd6d442012-11-17 14:11:25 -0800227 LOG(FATAL) << "Unexpected ccode: " << ccode;
Bill Buzbeea114add2012-05-03 15:00:40 -0700228 }
buzbeefa57c472012-11-21 12:06:18 -0800229 OpCondBranch(cu, ccode, target);
buzbee84fd6932012-03-29 16:44:16 -0700230}
231
232
buzbeea5954be2013-02-07 10:41:40 -0800233void ArmCodegen::GenCmpFP(CompilationUnit* cu, Instruction::Code opcode, RegLocation rl_dest,
buzbee02031b12012-11-23 09:41:35 -0800234 RegLocation rl_src1, RegLocation rl_src2)
buzbee67bf8852011-08-17 17:51:35 -0700235{
buzbeea5954be2013-02-07 10:41:40 -0800236 bool is_double = false;
237 int default_result = -1;
buzbeefa57c472012-11-21 12:06:18 -0800238 RegLocation rl_result;
buzbee67bf8852011-08-17 17:51:35 -0700239
buzbee408ad162012-06-06 16:45:18 -0700240 switch (opcode) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700241 case Instruction::CMPL_FLOAT:
buzbeefa57c472012-11-21 12:06:18 -0800242 is_double = false;
243 default_result = -1;
Bill Buzbeea114add2012-05-03 15:00:40 -0700244 break;
245 case Instruction::CMPG_FLOAT:
buzbeefa57c472012-11-21 12:06:18 -0800246 is_double = false;
247 default_result = 1;
Bill Buzbeea114add2012-05-03 15:00:40 -0700248 break;
249 case Instruction::CMPL_DOUBLE:
buzbeefa57c472012-11-21 12:06:18 -0800250 is_double = true;
251 default_result = -1;
Bill Buzbeea114add2012-05-03 15:00:40 -0700252 break;
253 case Instruction::CMPG_DOUBLE:
buzbeefa57c472012-11-21 12:06:18 -0800254 is_double = true;
255 default_result = 1;
Bill Buzbeea114add2012-05-03 15:00:40 -0700256 break;
257 default:
buzbeea5954be2013-02-07 10:41:40 -0800258 LOG(FATAL) << "Unexpected opcode: " << opcode;
Bill Buzbeea114add2012-05-03 15:00:40 -0700259 }
buzbeefa57c472012-11-21 12:06:18 -0800260 if (is_double) {
261 rl_src1 = LoadValueWide(cu, rl_src1, kFPReg);
262 rl_src2 = LoadValueWide(cu, rl_src2, kFPReg);
buzbee078fa452012-12-03 15:51:33 -0800263 // In case result vreg is also a src vreg, break association to avoid useless copy by EvalLoc()
buzbeefa57c472012-11-21 12:06:18 -0800264 ClobberSReg(cu, rl_dest.s_reg_low);
265 rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
266 LoadConstant(cu, rl_result.low_reg, default_result);
267 NewLIR2(cu, kThumb2Vcmpd, S2d(rl_src1.low_reg, rl_src2.high_reg),
268 S2d(rl_src2.low_reg, rl_src2.high_reg));
Bill Buzbeea114add2012-05-03 15:00:40 -0700269 } else {
buzbeefa57c472012-11-21 12:06:18 -0800270 rl_src1 = LoadValue(cu, rl_src1, kFPReg);
271 rl_src2 = LoadValue(cu, rl_src2, kFPReg);
buzbee078fa452012-12-03 15:51:33 -0800272 // In case result vreg is also a srcvreg, break association to avoid useless copy by EvalLoc()
buzbeefa57c472012-11-21 12:06:18 -0800273 ClobberSReg(cu, rl_dest.s_reg_low);
274 rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
275 LoadConstant(cu, rl_result.low_reg, default_result);
276 NewLIR2(cu, kThumb2Vcmps, rl_src1.low_reg, rl_src2.low_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700277 }
buzbeefa57c472012-11-21 12:06:18 -0800278 DCHECK(!ARM_FPREG(rl_result.low_reg));
279 NewLIR0(cu, kThumb2Fmstat);
buzbee67bf8852011-08-17 17:51:35 -0700280
buzbee02031b12012-11-23 09:41:35 -0800281 OpIT(cu, (default_result == -1) ? kCondGt : kCondMi, "");
buzbeefa57c472012-11-21 12:06:18 -0800282 NewLIR2(cu, kThumb2MovImmShift, rl_result.low_reg,
283 ModifiedImmediate(-default_result)); // Must not alter ccodes
284 GenBarrier(cu);
buzbee67bf8852011-08-17 17:51:35 -0700285
buzbee02031b12012-11-23 09:41:35 -0800286 OpIT(cu, kCondEq, "");
buzbeefa57c472012-11-21 12:06:18 -0800287 LoadConstant(cu, rl_result.low_reg, 0);
288 GenBarrier(cu);
buzbee67bf8852011-08-17 17:51:35 -0700289
buzbeefa57c472012-11-21 12:06:18 -0800290 StoreValue(cu, rl_dest, rl_result);
buzbee67bf8852011-08-17 17:51:35 -0700291}
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800292
buzbee02031b12012-11-23 09:41:35 -0800293void ArmCodegen::GenNegFloat(CompilationUnit* cu, RegLocation rl_dest, RegLocation rl_src)
buzbeeefc63692012-11-14 16:31:52 -0800294{
buzbeefa57c472012-11-21 12:06:18 -0800295 RegLocation rl_result;
296 rl_src = LoadValue(cu, rl_src, kFPReg);
297 rl_result = EvalLoc(cu, rl_dest, kFPReg, true);
298 NewLIR2(cu, kThumb2Vnegs, rl_result.low_reg, rl_src.low_reg);
299 StoreValue(cu, rl_dest, rl_result);
buzbeeefc63692012-11-14 16:31:52 -0800300}
301
buzbee02031b12012-11-23 09:41:35 -0800302void ArmCodegen::GenNegDouble(CompilationUnit* cu, RegLocation rl_dest, RegLocation rl_src)
buzbeeefc63692012-11-14 16:31:52 -0800303{
buzbeefa57c472012-11-21 12:06:18 -0800304 RegLocation rl_result;
305 rl_src = LoadValueWide(cu, rl_src, kFPReg);
306 rl_result = EvalLoc(cu, rl_dest, kFPReg, true);
307 NewLIR2(cu, kThumb2Vnegd, S2d(rl_result.low_reg, rl_result.high_reg),
308 S2d(rl_src.low_reg, rl_src.high_reg));
309 StoreValueWide(cu, rl_dest, rl_result);
buzbeeefc63692012-11-14 16:31:52 -0800310}
311
buzbee02031b12012-11-23 09:41:35 -0800312bool ArmCodegen::GenInlinedSqrt(CompilationUnit* cu, CallInfo* info) {
buzbeefa57c472012-11-21 12:06:18 -0800313 DCHECK_EQ(cu->instruction_set, kThumb2);
buzbeeefc63692012-11-14 16:31:52 -0800314 LIR *branch;
buzbeefa57c472012-11-21 12:06:18 -0800315 RegLocation rl_src = info->args[0];
316 RegLocation rl_dest = InlineTargetWide(cu, info); // double place for result
317 rl_src = LoadValueWide(cu, rl_src, kFPReg);
318 RegLocation rl_result = EvalLoc(cu, rl_dest, kFPReg, true);
319 NewLIR2(cu, kThumb2Vsqrtd, S2d(rl_result.low_reg, rl_result.high_reg),
320 S2d(rl_src.low_reg, rl_src.high_reg));
321 NewLIR2(cu, kThumb2Vcmpd, S2d(rl_result.low_reg, rl_result.high_reg),
322 S2d(rl_result.low_reg, rl_result.high_reg));
323 NewLIR0(cu, kThumb2Fmstat);
324 branch = NewLIR2(cu, kThumbBCond, 0, kArmCondEq);
325 ClobberCalleeSave(cu);
326 LockCallTemps(cu); // Using fixed registers
327 int r_tgt = LoadHelper(cu, ENTRYPOINT_OFFSET(pSqrt));
328 NewLIR3(cu, kThumb2Fmrrd, r0, r1, S2d(rl_src.low_reg, rl_src.high_reg));
329 NewLIR1(cu, kThumbBlxR, r_tgt);
330 NewLIR3(cu, kThumb2Fmdrr, S2d(rl_result.low_reg, rl_result.high_reg), r0, r1);
331 branch->target = NewLIR0(cu, kPseudoTargetLabel);
332 StoreValueWide(cu, rl_dest, rl_result);
buzbeeefc63692012-11-14 16:31:52 -0800333 return true;
334}
335
336
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800337} // namespace art