blob: 8c220500b29fa074714026719d88c53612c642b9 [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
Elliott Hughes11d1b0c2012-01-23 16:57:47 -080017namespace art {
18
buzbee408ad162012-06-06 16:45:18 -070019bool genArithOpFloat(CompilationUnit* cUnit, Instruction::Code opcode, RegLocation rlDest,
buzbee31a4a6f2012-02-28 15:36:15 -080020 RegLocation rlSrc1, RegLocation rlSrc2)
buzbee67bf8852011-08-17 17:51:35 -070021{
Bill Buzbeea114add2012-05-03 15:00:40 -070022 int op = kThumbBkpt;
23 RegLocation rlResult;
buzbee67bf8852011-08-17 17:51:35 -070024
Bill Buzbeea114add2012-05-03 15:00:40 -070025 /*
26 * Don't attempt to optimize register usage since these opcodes call out to
27 * the handlers.
28 */
buzbee408ad162012-06-06 16:45:18 -070029 switch (opcode) {
Bill Buzbeea114add2012-05-03 15:00:40 -070030 case Instruction::ADD_FLOAT_2ADDR:
31 case Instruction::ADD_FLOAT:
32 op = kThumb2Vadds;
33 break;
34 case Instruction::SUB_FLOAT_2ADDR:
35 case Instruction::SUB_FLOAT:
36 op = kThumb2Vsubs;
37 break;
38 case Instruction::DIV_FLOAT_2ADDR:
39 case Instruction::DIV_FLOAT:
40 op = kThumb2Vdivs;
41 break;
42 case Instruction::MUL_FLOAT_2ADDR:
43 case Instruction::MUL_FLOAT:
44 op = kThumb2Vmuls;
45 break;
46 case Instruction::REM_FLOAT_2ADDR:
47 case Instruction::REM_FLOAT:
48 case Instruction::NEG_FLOAT: {
buzbee408ad162012-06-06 16:45:18 -070049 return genArithOpFloatPortable(cUnit, opcode, rlDest, rlSrc1, rlSrc2);
buzbee67bf8852011-08-17 17:51:35 -070050 }
Bill Buzbeea114add2012-05-03 15:00:40 -070051 default:
52 return true;
53 }
54 rlSrc1 = loadValue(cUnit, rlSrc1, kFPReg);
55 rlSrc2 = loadValue(cUnit, rlSrc2, kFPReg);
56 rlResult = oatEvalLoc(cUnit, rlDest, kFPReg, true);
57 newLIR3(cUnit, (ArmOpcode)op, rlResult.lowReg, rlSrc1.lowReg, rlSrc2.lowReg);
58 storeValue(cUnit, rlDest, rlResult);
59 return false;
buzbee67bf8852011-08-17 17:51:35 -070060}
61
buzbee408ad162012-06-06 16:45:18 -070062bool genArithOpDouble(CompilationUnit* cUnit, Instruction::Code opcode,
63 RegLocation rlDest, RegLocation rlSrc1, RegLocation rlSrc2)
buzbee67bf8852011-08-17 17:51:35 -070064{
Bill Buzbeea114add2012-05-03 15:00:40 -070065 int op = kThumbBkpt;
66 RegLocation rlResult;
buzbee67bf8852011-08-17 17:51:35 -070067
buzbee408ad162012-06-06 16:45:18 -070068 switch (opcode) {
Bill Buzbeea114add2012-05-03 15:00:40 -070069 case Instruction::ADD_DOUBLE_2ADDR:
70 case Instruction::ADD_DOUBLE:
71 op = kThumb2Vaddd;
72 break;
73 case Instruction::SUB_DOUBLE_2ADDR:
74 case Instruction::SUB_DOUBLE:
75 op = kThumb2Vsubd;
76 break;
77 case Instruction::DIV_DOUBLE_2ADDR:
78 case Instruction::DIV_DOUBLE:
79 op = kThumb2Vdivd;
80 break;
81 case Instruction::MUL_DOUBLE_2ADDR:
82 case Instruction::MUL_DOUBLE:
83 op = kThumb2Vmuld;
84 break;
85 case Instruction::REM_DOUBLE_2ADDR:
86 case Instruction::REM_DOUBLE:
87 case Instruction::NEG_DOUBLE: {
buzbee408ad162012-06-06 16:45:18 -070088 return genArithOpDoublePortable(cUnit, opcode, rlDest, rlSrc1, rlSrc2);
buzbee67bf8852011-08-17 17:51:35 -070089 }
Bill Buzbeea114add2012-05-03 15:00:40 -070090 default:
91 return true;
92 }
buzbee67bf8852011-08-17 17:51:35 -070093
Bill Buzbeea114add2012-05-03 15:00:40 -070094 rlSrc1 = loadValueWide(cUnit, rlSrc1, kFPReg);
95 DCHECK(rlSrc1.wide);
96 rlSrc2 = loadValueWide(cUnit, rlSrc2, kFPReg);
97 DCHECK(rlSrc2.wide);
98 rlResult = oatEvalLoc(cUnit, rlDest, kFPReg, true);
99 DCHECK(rlDest.wide);
100 DCHECK(rlResult.wide);
buzbeef0504cd2012-11-13 16:31:10 -0800101 newLIR3(cUnit, (ArmOpcode)op, s2d(rlResult.lowReg, rlResult.highReg),
102 s2d(rlSrc1.lowReg, rlSrc1.highReg),
103 s2d(rlSrc2.lowReg, rlSrc2.highReg));
Bill Buzbeea114add2012-05-03 15:00:40 -0700104 storeValueWide(cUnit, rlDest, rlResult);
105 return false;
buzbee67bf8852011-08-17 17:51:35 -0700106}
107
buzbee408ad162012-06-06 16:45:18 -0700108bool genConversion(CompilationUnit* cUnit, Instruction::Code opcode,
109 RegLocation rlDest, RegLocation rlSrc)
buzbee67bf8852011-08-17 17:51:35 -0700110{
Bill Buzbeea114add2012-05-03 15:00:40 -0700111 int op = kThumbBkpt;
Bill Buzbeea114add2012-05-03 15:00:40 -0700112 int srcReg;
Bill Buzbeea114add2012-05-03 15:00:40 -0700113 RegLocation rlResult;
buzbee67bf8852011-08-17 17:51:35 -0700114
Bill Buzbeea114add2012-05-03 15:00:40 -0700115 switch (opcode) {
116 case Instruction::INT_TO_FLOAT:
Bill Buzbeea114add2012-05-03 15:00:40 -0700117 op = kThumb2VcvtIF;
118 break;
119 case Instruction::FLOAT_TO_INT:
Bill Buzbeea114add2012-05-03 15:00:40 -0700120 op = kThumb2VcvtFI;
121 break;
122 case Instruction::DOUBLE_TO_FLOAT:
Bill Buzbeea114add2012-05-03 15:00:40 -0700123 op = kThumb2VcvtDF;
124 break;
125 case Instruction::FLOAT_TO_DOUBLE:
Bill Buzbeea114add2012-05-03 15:00:40 -0700126 op = kThumb2VcvtFd;
127 break;
128 case Instruction::INT_TO_DOUBLE:
Bill Buzbeea114add2012-05-03 15:00:40 -0700129 op = kThumb2VcvtID;
130 break;
131 case Instruction::DOUBLE_TO_INT:
Bill Buzbeea114add2012-05-03 15:00:40 -0700132 op = kThumb2VcvtDI;
133 break;
134 case Instruction::LONG_TO_DOUBLE:
135 case Instruction::FLOAT_TO_LONG:
136 case Instruction::LONG_TO_FLOAT:
137 case Instruction::DOUBLE_TO_LONG:
buzbee408ad162012-06-06 16:45:18 -0700138 return genConversionPortable(cUnit, opcode, rlDest, rlSrc);
Bill Buzbeea114add2012-05-03 15:00:40 -0700139 default:
140 return true;
141 }
buzbee408ad162012-06-06 16:45:18 -0700142 if (rlSrc.wide) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700143 rlSrc = loadValueWide(cUnit, rlSrc, kFPReg);
buzbeef0504cd2012-11-13 16:31:10 -0800144 srcReg = s2d(rlSrc.lowReg, rlSrc.highReg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700145 } else {
Bill Buzbeea114add2012-05-03 15:00:40 -0700146 rlSrc = loadValue(cUnit, rlSrc, kFPReg);
147 srcReg = rlSrc.lowReg;
148 }
buzbee408ad162012-06-06 16:45:18 -0700149 if (rlDest.wide) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700150 rlResult = oatEvalLoc(cUnit, rlDest, kFPReg, true);
buzbeef0504cd2012-11-13 16:31:10 -0800151 newLIR2(cUnit, (ArmOpcode)op, s2d(rlResult.lowReg, rlResult.highReg),
Bill Buzbeea114add2012-05-03 15:00:40 -0700152 srcReg);
153 storeValueWide(cUnit, rlDest, rlResult);
154 } else {
Bill Buzbeea114add2012-05-03 15:00:40 -0700155 rlResult = oatEvalLoc(cUnit, rlDest, kFPReg, true);
156 newLIR2(cUnit, (ArmOpcode)op, rlResult.lowReg, srcReg);
157 storeValue(cUnit, rlDest, rlResult);
158 }
159 return false;
buzbee67bf8852011-08-17 17:51:35 -0700160}
161
buzbee84fd6932012-03-29 16:44:16 -0700162void genFusedFPCmpBranch(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir,
163 bool gtBias, bool isDouble)
164{
buzbeea1da8a52012-07-09 14:00:21 -0700165 LIR* labelList = cUnit->blockLabelList;
Bill Buzbeea114add2012-05-03 15:00:40 -0700166 LIR* target = &labelList[bb->taken->id];
167 RegLocation rlSrc1;
168 RegLocation rlSrc2;
169 if (isDouble) {
buzbee15bf9802012-06-12 17:49:27 -0700170 rlSrc1 = oatGetSrcWide(cUnit, mir, 0);
171 rlSrc2 = oatGetSrcWide(cUnit, mir, 2);
Bill Buzbeea114add2012-05-03 15:00:40 -0700172 rlSrc1 = loadValueWide(cUnit, rlSrc1, kFPReg);
173 rlSrc2 = loadValueWide(cUnit, rlSrc2, kFPReg);
buzbeef0504cd2012-11-13 16:31:10 -0800174 newLIR2(cUnit, kThumb2Vcmpd, s2d(rlSrc1.lowReg, rlSrc2.highReg),
175 s2d(rlSrc2.lowReg, rlSrc2.highReg));
Bill Buzbeea114add2012-05-03 15:00:40 -0700176 } else {
177 rlSrc1 = oatGetSrc(cUnit, mir, 0);
178 rlSrc2 = oatGetSrc(cUnit, mir, 1);
179 rlSrc1 = loadValue(cUnit, rlSrc1, kFPReg);
180 rlSrc2 = loadValue(cUnit, rlSrc2, kFPReg);
181 newLIR2(cUnit, kThumb2Vcmps, rlSrc1.lowReg, rlSrc2.lowReg);
182 }
183 newLIR0(cUnit, kThumb2Fmstat);
184 ConditionCode ccode = static_cast<ConditionCode>(mir->dalvikInsn.arg[0]);
185 switch(ccode) {
186 case kCondEq:
187 case kCondNe:
188 break;
189 case kCondLt:
190 if (gtBias) {
191 ccode = kCondMi;
192 }
193 break;
194 case kCondLe:
195 if (gtBias) {
196 ccode = kCondLs;
197 }
198 break;
199 case kCondGt:
200 if (gtBias) {
201 ccode = kCondHi;
202 }
203 break;
204 case kCondGe:
205 if (gtBias) {
206 ccode = kCondCs;
207 }
208 break;
209 default:
210 LOG(FATAL) << "Unexpected ccode: " << (int)ccode;
211 }
212 opCondBranch(cUnit, ccode, target);
buzbee84fd6932012-03-29 16:44:16 -0700213}
214
215
buzbee408ad162012-06-06 16:45:18 -0700216bool genCmpFP(CompilationUnit* cUnit, Instruction::Code opcode, RegLocation rlDest,
Bill Buzbeea114add2012-05-03 15:00:40 -0700217 RegLocation rlSrc1, RegLocation rlSrc2)
buzbee67bf8852011-08-17 17:51:35 -0700218{
Bill Buzbeea114add2012-05-03 15:00:40 -0700219 bool isDouble;
220 int defaultResult;
221 RegLocation rlResult;
buzbee67bf8852011-08-17 17:51:35 -0700222
buzbee408ad162012-06-06 16:45:18 -0700223 switch (opcode) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700224 case Instruction::CMPL_FLOAT:
225 isDouble = false;
226 defaultResult = -1;
227 break;
228 case Instruction::CMPG_FLOAT:
229 isDouble = false;
230 defaultResult = 1;
231 break;
232 case Instruction::CMPL_DOUBLE:
233 isDouble = true;
234 defaultResult = -1;
235 break;
236 case Instruction::CMPG_DOUBLE:
237 isDouble = true;
238 defaultResult = 1;
239 break;
240 default:
241 return true;
242 }
243 if (isDouble) {
244 rlSrc1 = loadValueWide(cUnit, rlSrc1, kFPReg);
245 rlSrc2 = loadValueWide(cUnit, rlSrc2, kFPReg);
246 oatClobberSReg(cUnit, rlDest.sRegLow);
247 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
248 loadConstant(cUnit, rlResult.lowReg, defaultResult);
buzbeef0504cd2012-11-13 16:31:10 -0800249 newLIR2(cUnit, kThumb2Vcmpd, s2d(rlSrc1.lowReg, rlSrc2.highReg),
250 s2d(rlSrc2.lowReg, rlSrc2.highReg));
Bill Buzbeea114add2012-05-03 15:00:40 -0700251 } else {
252 rlSrc1 = loadValue(cUnit, rlSrc1, kFPReg);
253 rlSrc2 = loadValue(cUnit, rlSrc2, kFPReg);
254 oatClobberSReg(cUnit, rlDest.sRegLow);
255 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
256 loadConstant(cUnit, rlResult.lowReg, defaultResult);
257 newLIR2(cUnit, kThumb2Vcmps, rlSrc1.lowReg, rlSrc2.lowReg);
258 }
buzbeef0504cd2012-11-13 16:31:10 -0800259 DCHECK(!ARM_FPREG(rlResult.lowReg));
Bill Buzbeea114add2012-05-03 15:00:40 -0700260 newLIR0(cUnit, kThumb2Fmstat);
buzbee67bf8852011-08-17 17:51:35 -0700261
Bill Buzbeea114add2012-05-03 15:00:40 -0700262 opIT(cUnit, (defaultResult == -1) ? kArmCondGt : kArmCondMi, "");
263 newLIR2(cUnit, kThumb2MovImmShift, rlResult.lowReg,
264 modifiedImmediate(-defaultResult)); // Must not alter ccodes
265 genBarrier(cUnit);
buzbee67bf8852011-08-17 17:51:35 -0700266
Bill Buzbeea114add2012-05-03 15:00:40 -0700267 opIT(cUnit, kArmCondEq, "");
268 loadConstant(cUnit, rlResult.lowReg, 0);
269 genBarrier(cUnit);
buzbee67bf8852011-08-17 17:51:35 -0700270
Bill Buzbeea114add2012-05-03 15:00:40 -0700271 storeValue(cUnit, rlDest, rlResult);
272 return false;
buzbee67bf8852011-08-17 17:51:35 -0700273}
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800274
buzbeeefc63692012-11-14 16:31:52 -0800275void genNegFloat(CompilationUnit* cUnit, RegLocation rlDest, RegLocation rlSrc)
276{
277 RegLocation rlResult;
278 rlSrc = loadValue(cUnit, rlSrc, kFPReg);
279 rlResult = oatEvalLoc(cUnit, rlDest, kFPReg, true);
280 newLIR2(cUnit, kThumb2Vnegs, rlResult.lowReg, rlSrc.lowReg);
281 storeValue(cUnit, rlDest, rlResult);
282}
283
284void genNegDouble(CompilationUnit* cUnit, RegLocation rlDest, RegLocation rlSrc)
285{
286 RegLocation rlResult;
287 rlSrc = loadValueWide(cUnit, rlSrc, kFPReg);
288 rlResult = oatEvalLoc(cUnit, rlDest, kFPReg, true);
289 newLIR2(cUnit, kThumb2Vnegd, s2d(rlResult.lowReg, rlResult.highReg),
290 s2d(rlSrc.lowReg, rlSrc.highReg));
291 storeValueWide(cUnit, rlDest, rlResult);
292}
293
294bool genInlinedSqrt(CompilationUnit* cUnit, CallInfo* info) {
295 DCHECK_EQ(cUnit->instructionSet, kThumb2);
296 LIR *branch;
297 RegLocation rlSrc = info->args[0];
298 RegLocation rlDest = inlineTargetWide(cUnit, info); // double place for result
299 rlSrc = loadValueWide(cUnit, rlSrc, kFPReg);
300 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kFPReg, true);
301 newLIR2(cUnit, kThumb2Vsqrtd, s2d(rlResult.lowReg, rlResult.highReg),
302 s2d(rlSrc.lowReg, rlSrc.highReg));
303 newLIR2(cUnit, kThumb2Vcmpd, s2d(rlResult.lowReg, rlResult.highReg),
304 s2d(rlResult.lowReg, rlResult.highReg));
305 newLIR0(cUnit, kThumb2Fmstat);
306 branch = newLIR2(cUnit, kThumbBCond, 0, kArmCondEq);
307 oatClobberCalleeSave(cUnit);
308 oatLockCallTemps(cUnit); // Using fixed registers
309 int rTgt = loadHelper(cUnit, ENTRYPOINT_OFFSET(pSqrt));
310 newLIR3(cUnit, kThumb2Fmrrd, r0, r1, s2d(rlSrc.lowReg, rlSrc.highReg));
311 newLIR1(cUnit, kThumbBlxR, rTgt);
312 newLIR3(cUnit, kThumb2Fmdrr, s2d(rlResult.lowReg, rlResult.highReg), r0, r1);
313 branch->target = newLIR0(cUnit, kPseudoTargetLabel);
314 storeValueWide(cUnit, rlDest, rlResult);
315 return true;
316}
317
318
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800319} // namespace art