blob: 8cd32b45fd21f4a4e044e9d7a11b761406c33d58 [file] [log] [blame]
buzbeee88dfbf2012-03-05 11:19:57 -08001/*
2 * Copyright (C) 2012 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
17namespace art {
18
buzbee408ad162012-06-06 16:45:18 -070019static bool genArithOpFloat(CompilationUnit *cUnit, Instruction::Code opcode,
Bill Buzbeea114add2012-05-03 15:00:40 -070020 RegLocation rlDest, RegLocation rlSrc1,
21 RegLocation rlSrc2) {
Ian Rogersb5d09b22012-03-06 22:14:17 -080022 X86OpCode op = kX86Nop;
23 RegLocation rlResult;
jeffhaofdffdf82012-07-11 16:08:43 -070024 int tempReg;
buzbeee88dfbf2012-03-05 11:19:57 -080025
Ian Rogersb5d09b22012-03-06 22:14:17 -080026 /*
27 * Don't attempt to optimize register usage since these opcodes call out to
28 * the handlers.
29 */
buzbee408ad162012-06-06 16:45:18 -070030 switch (opcode) {
Ian Rogersb5d09b22012-03-06 22:14:17 -080031 case Instruction::ADD_FLOAT_2ADDR:
32 case Instruction::ADD_FLOAT:
33 op = kX86AddssRR;
34 break;
35 case Instruction::SUB_FLOAT_2ADDR:
36 case Instruction::SUB_FLOAT:
37 op = kX86SubssRR;
38 break;
39 case Instruction::DIV_FLOAT_2ADDR:
40 case Instruction::DIV_FLOAT:
41 op = kX86DivssRR;
42 break;
43 case Instruction::MUL_FLOAT_2ADDR:
44 case Instruction::MUL_FLOAT:
45 op = kX86MulssRR;
46 break;
47 case Instruction::NEG_FLOAT:
jeffhaofdffdf82012-07-11 16:08:43 -070048 // TODO: Make this an XorpsRM where the memory location holds 0x80000000
49 rlSrc1 = loadValue(cUnit, rlSrc1, kFPReg);
50 rlResult = oatEvalLoc(cUnit, rlDest, kFPReg, true);
51 tempReg = oatAllocTemp(cUnit);
52 loadConstant(cUnit, tempReg, 0x80000000);
53 newLIR2(cUnit, kX86MovdxrRR, rlResult.lowReg, tempReg);
54 newLIR2(cUnit, kX86XorpsRR, rlResult.lowReg, rlSrc1.lowReg);
jeffhao292188d2012-05-17 15:45:04 -070055 storeValue(cUnit, rlDest, rlResult);
56 return false;
Ian Rogersb5d09b22012-03-06 22:14:17 -080057 case Instruction::REM_FLOAT_2ADDR:
58 case Instruction::REM_FLOAT: {
buzbee408ad162012-06-06 16:45:18 -070059 return genArithOpFloatPortable(cUnit, opcode, rlDest, rlSrc1, rlSrc2);
buzbeee88dfbf2012-03-05 11:19:57 -080060 }
Ian Rogersb5d09b22012-03-06 22:14:17 -080061 default:
62 return true;
63 }
64 rlSrc1 = loadValue(cUnit, rlSrc1, kFPReg);
65 rlSrc2 = loadValue(cUnit, rlSrc2, kFPReg);
66 rlResult = oatEvalLoc(cUnit, rlDest, kFPReg, true);
67 int rDest = rlResult.lowReg;
68 int rSrc1 = rlSrc1.lowReg;
69 int rSrc2 = rlSrc2.lowReg;
jeffhao4abb1a92012-06-08 17:02:08 -070070 if (rSrc2 == rDest) {
71 rSrc2 = oatAllocTempFloat(cUnit);
72 opRegCopy(cUnit, rSrc2, rDest);
73 }
Ian Rogersb5d09b22012-03-06 22:14:17 -080074 opRegCopy(cUnit, rDest, rSrc1);
75 newLIR2(cUnit, op, rDest, rSrc2);
76 storeValue(cUnit, rlDest, rlResult);
buzbeee88dfbf2012-03-05 11:19:57 -080077
Ian Rogersb5d09b22012-03-06 22:14:17 -080078 return false;
buzbeee88dfbf2012-03-05 11:19:57 -080079}
80
buzbee408ad162012-06-06 16:45:18 -070081static bool genArithOpDouble(CompilationUnit *cUnit, Instruction::Code opcode,
buzbeee88dfbf2012-03-05 11:19:57 -080082 RegLocation rlDest, RegLocation rlSrc1,
Ian Rogersb5d09b22012-03-06 22:14:17 -080083 RegLocation rlSrc2) {
84 X86OpCode op = kX86Nop;
85 RegLocation rlResult;
jeffhaofdffdf82012-07-11 16:08:43 -070086 int tempReg;
buzbeee88dfbf2012-03-05 11:19:57 -080087
buzbee408ad162012-06-06 16:45:18 -070088 switch (opcode) {
Ian Rogersb5d09b22012-03-06 22:14:17 -080089 case Instruction::ADD_DOUBLE_2ADDR:
90 case Instruction::ADD_DOUBLE:
91 op = kX86AddsdRR;
92 break;
93 case Instruction::SUB_DOUBLE_2ADDR:
94 case Instruction::SUB_DOUBLE:
95 op = kX86SubsdRR;
96 break;
97 case Instruction::DIV_DOUBLE_2ADDR:
98 case Instruction::DIV_DOUBLE:
99 op = kX86DivsdRR;
100 break;
101 case Instruction::MUL_DOUBLE_2ADDR:
102 case Instruction::MUL_DOUBLE:
103 op = kX86MulsdRR;
104 break;
105 case Instruction::NEG_DOUBLE:
jeffhaofdffdf82012-07-11 16:08:43 -0700106 // TODO: Make this an XorpdRM where the memory location holds 0x8000000000000000
107 rlSrc1 = loadValueWide(cUnit, rlSrc1, kFPReg);
108 rlResult = oatEvalLoc(cUnit, rlDest, kFPReg, true);
109 tempReg = oatAllocTemp(cUnit);
110 loadConstant(cUnit, tempReg, 0x80000000);
111 newLIR2(cUnit, kX86MovdxrRR, rlResult.lowReg, tempReg);
112 newLIR2(cUnit, kX86PsllqRI, rlResult.lowReg, 32);
113 newLIR2(cUnit, kX86XorpsRR, rlResult.lowReg, rlSrc1.lowReg);
jeffhao292188d2012-05-17 15:45:04 -0700114 storeValueWide(cUnit, rlDest, rlResult);
115 return false;
Ian Rogersb5d09b22012-03-06 22:14:17 -0800116 case Instruction::REM_DOUBLE_2ADDR:
117 case Instruction::REM_DOUBLE: {
buzbee408ad162012-06-06 16:45:18 -0700118 return genArithOpDoublePortable(cUnit, opcode, rlDest, rlSrc1, rlSrc2);
buzbeee88dfbf2012-03-05 11:19:57 -0800119 }
Ian Rogersb5d09b22012-03-06 22:14:17 -0800120 default:
121 return true;
122 }
123 rlSrc1 = loadValueWide(cUnit, rlSrc1, kFPReg);
124 DCHECK(rlSrc1.wide);
125 rlSrc2 = loadValueWide(cUnit, rlSrc2, kFPReg);
126 DCHECK(rlSrc2.wide);
127 rlResult = oatEvalLoc(cUnit, rlDest, kFPReg, true);
128 DCHECK(rlDest.wide);
129 DCHECK(rlResult.wide);
130 int rDest = S2D(rlResult.lowReg, rlResult.highReg);
131 int rSrc1 = S2D(rlSrc1.lowReg, rlSrc1.highReg);
132 int rSrc2 = S2D(rlSrc2.lowReg, rlSrc2.highReg);
jeffhao4abb1a92012-06-08 17:02:08 -0700133 if (rDest == rSrc2) {
134 rSrc2 = oatAllocTempDouble(cUnit) | FP_DOUBLE;
135 opRegCopy(cUnit, rSrc2, rDest);
136 }
Ian Rogersb5d09b22012-03-06 22:14:17 -0800137 opRegCopy(cUnit, rDest, rSrc1);
138 newLIR2(cUnit, op, rDest, rSrc2);
139 storeValueWide(cUnit, rlDest, rlResult);
140 return false;
buzbeee88dfbf2012-03-05 11:19:57 -0800141}
142
buzbee408ad162012-06-06 16:45:18 -0700143static bool genConversion(CompilationUnit *cUnit, Instruction::Code opcode,
144 RegLocation rlDest, RegLocation rlSrc) {
jeffhao5121e0b2012-05-08 18:23:38 -0700145 RegisterClass rcSrc = kFPReg;
Ian Rogersb5d09b22012-03-06 22:14:17 -0800146 X86OpCode op = kX86Nop;
147 int srcReg;
148 RegLocation rlResult;
149 switch (opcode) {
150 case Instruction::INT_TO_FLOAT:
jeffhao5121e0b2012-05-08 18:23:38 -0700151 rcSrc = kCoreReg;
Ian Rogersb5d09b22012-03-06 22:14:17 -0800152 op = kX86Cvtsi2ssRR;
153 break;
154 case Instruction::DOUBLE_TO_FLOAT:
jeffhao5121e0b2012-05-08 18:23:38 -0700155 rcSrc = kFPReg;
Ian Rogersb5d09b22012-03-06 22:14:17 -0800156 op = kX86Cvtsd2ssRR;
157 break;
158 case Instruction::FLOAT_TO_DOUBLE:
jeffhao5121e0b2012-05-08 18:23:38 -0700159 rcSrc = kFPReg;
Ian Rogersb5d09b22012-03-06 22:14:17 -0800160 op = kX86Cvtss2sdRR;
161 break;
162 case Instruction::INT_TO_DOUBLE:
jeffhao5121e0b2012-05-08 18:23:38 -0700163 rcSrc = kCoreReg;
Ian Rogersb5d09b22012-03-06 22:14:17 -0800164 op = kX86Cvtsi2sdRR;
165 break;
jeffhao292188d2012-05-17 15:45:04 -0700166 case Instruction::FLOAT_TO_INT: {
jeffhao41005dd2012-05-09 17:58:52 -0700167 rlSrc = loadValue(cUnit, rlSrc, kFPReg);
168 srcReg = rlSrc.lowReg;
jeffhao41005dd2012-05-09 17:58:52 -0700169 oatClobberSReg(cUnit, rlDest.sRegLow);
170 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
jeffhao292188d2012-05-17 15:45:04 -0700171 int tempReg = oatAllocTempFloat(cUnit);
jeffhao41005dd2012-05-09 17:58:52 -0700172
173 loadConstant(cUnit, rlResult.lowReg, 0x7fffffff);
174 newLIR2(cUnit, kX86Cvtsi2ssRR, tempReg, rlResult.lowReg);
175 newLIR2(cUnit, kX86ComissRR, srcReg, tempReg);
jeffhao292188d2012-05-17 15:45:04 -0700176 LIR* branchPosOverflow = newLIR2(cUnit, kX86Jcc8, 0, kX86CondA);
177 LIR* branchNaN = newLIR2(cUnit, kX86Jcc8, 0, kX86CondP);
178 newLIR2(cUnit, kX86Cvttss2siRR, rlResult.lowReg, srcReg);
179 LIR* branchNormal = newLIR1(cUnit, kX86Jmp8, 0);
180 branchNaN->target = newLIR0(cUnit, kPseudoTargetLabel);
181 newLIR2(cUnit, kX86Xor32RR, rlResult.lowReg, rlResult.lowReg);
182 branchPosOverflow->target = newLIR0(cUnit, kPseudoTargetLabel);
183 branchNormal->target = newLIR0(cUnit, kPseudoTargetLabel);
jeffhao41005dd2012-05-09 17:58:52 -0700184 storeValue(cUnit, rlDest, rlResult);
185 return false;
jeffhao292188d2012-05-17 15:45:04 -0700186 }
187 case Instruction::DOUBLE_TO_INT: {
jeffhao41005dd2012-05-09 17:58:52 -0700188 rlSrc = loadValueWide(cUnit, rlSrc, kFPReg);
189 srcReg = rlSrc.lowReg;
jeffhao41005dd2012-05-09 17:58:52 -0700190 oatClobberSReg(cUnit, rlDest.sRegLow);
191 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
jeffhao4abb1a92012-06-08 17:02:08 -0700192 int tempReg = oatAllocTempDouble(cUnit) | FP_DOUBLE;
jeffhao41005dd2012-05-09 17:58:52 -0700193
194 loadConstant(cUnit, rlResult.lowReg, 0x7fffffff);
195 newLIR2(cUnit, kX86Cvtsi2sdRR, tempReg, rlResult.lowReg);
196 newLIR2(cUnit, kX86ComisdRR, srcReg, tempReg);
jeffhao292188d2012-05-17 15:45:04 -0700197 LIR* branchPosOverflow = newLIR2(cUnit, kX86Jcc8, 0, kX86CondA);
198 LIR* branchNaN = newLIR2(cUnit, kX86Jcc8, 0, kX86CondP);
199 newLIR2(cUnit, kX86Cvttsd2siRR, rlResult.lowReg, srcReg);
200 LIR* branchNormal = newLIR1(cUnit, kX86Jmp8, 0);
201 branchNaN->target = newLIR0(cUnit, kPseudoTargetLabel);
202 newLIR2(cUnit, kX86Xor32RR, rlResult.lowReg, rlResult.lowReg);
203 branchPosOverflow->target = newLIR0(cUnit, kPseudoTargetLabel);
204 branchNormal->target = newLIR0(cUnit, kPseudoTargetLabel);
jeffhao41005dd2012-05-09 17:58:52 -0700205 storeValue(cUnit, rlDest, rlResult);
206 return false;
jeffhao292188d2012-05-17 15:45:04 -0700207 }
Ian Rogersb5d09b22012-03-06 22:14:17 -0800208 case Instruction::LONG_TO_DOUBLE:
Ian Rogersb5d09b22012-03-06 22:14:17 -0800209 case Instruction::LONG_TO_FLOAT:
jeffhao41005dd2012-05-09 17:58:52 -0700210 // These can be implemented inline by using memory as a 64-bit source.
211 // However, this can't be done easily if the register has been promoted.
212 UNIMPLEMENTED(WARNING) << "inline l2[df] " << PrettyMethod(cUnit->method_idx, *cUnit->dex_file);
213 case Instruction::FLOAT_TO_LONG:
Ian Rogersb5d09b22012-03-06 22:14:17 -0800214 case Instruction::DOUBLE_TO_LONG:
buzbee408ad162012-06-06 16:45:18 -0700215 return genConversionPortable(cUnit, opcode, rlDest, rlSrc);
Ian Rogersb5d09b22012-03-06 22:14:17 -0800216 default:
217 return true;
218 }
buzbee408ad162012-06-06 16:45:18 -0700219 if (rlSrc.wide) {
jeffhao5121e0b2012-05-08 18:23:38 -0700220 rlSrc = loadValueWide(cUnit, rlSrc, rcSrc);
Ian Rogersb5d09b22012-03-06 22:14:17 -0800221 srcReg = S2D(rlSrc.lowReg, rlSrc.highReg);
222 } else {
jeffhao5121e0b2012-05-08 18:23:38 -0700223 rlSrc = loadValue(cUnit, rlSrc, rcSrc);
Ian Rogersb5d09b22012-03-06 22:14:17 -0800224 srcReg = rlSrc.lowReg;
225 }
buzbee408ad162012-06-06 16:45:18 -0700226 if (rlDest.wide) {
Ian Rogersb5d09b22012-03-06 22:14:17 -0800227 rlResult = oatEvalLoc(cUnit, rlDest, kFPReg, true);
228 newLIR2(cUnit, op, S2D(rlResult.lowReg, rlResult.highReg), srcReg);
229 storeValueWide(cUnit, rlDest, rlResult);
230 } else {
Ian Rogersb5d09b22012-03-06 22:14:17 -0800231 rlResult = oatEvalLoc(cUnit, rlDest, kFPReg, true);
232 newLIR2(cUnit, op, rlResult.lowReg, srcReg);
233 storeValue(cUnit, rlDest, rlResult);
234 }
235 return false;
buzbeee88dfbf2012-03-05 11:19:57 -0800236}
237
buzbee408ad162012-06-06 16:45:18 -0700238static bool genCmpFP(CompilationUnit *cUnit, Instruction::Code code, RegLocation rlDest,
Ian Rogersb5d09b22012-03-06 22:14:17 -0800239 RegLocation rlSrc1, RegLocation rlSrc2) {
Ian Rogersb5d09b22012-03-06 22:14:17 -0800240 bool single = (code == Instruction::CMPL_FLOAT) || (code == Instruction::CMPG_FLOAT);
241 bool unorderedGt = (code == Instruction::CMPG_DOUBLE) || (code == Instruction::CMPG_FLOAT);
242 int srcReg1;
243 int srcReg2;
244 if (single) {
Ian Rogersb5d09b22012-03-06 22:14:17 -0800245 rlSrc1 = loadValue(cUnit, rlSrc1, kFPReg);
246 srcReg1 = rlSrc1.lowReg;
jeffhao644d5312012-05-03 19:04:49 -0700247 rlSrc2 = loadValue(cUnit, rlSrc2, kFPReg);
248 srcReg2 = rlSrc2.lowReg;
Ian Rogersb5d09b22012-03-06 22:14:17 -0800249 } else {
Ian Rogersb5d09b22012-03-06 22:14:17 -0800250 rlSrc1 = loadValueWide(cUnit, rlSrc1, kFPReg);
251 srcReg1 = S2D(rlSrc1.lowReg, rlSrc1.highReg);
Ian Rogersb5d09b22012-03-06 22:14:17 -0800252 rlSrc2 = loadValueWide(cUnit, rlSrc2, kFPReg);
253 srcReg2 = S2D(rlSrc2.lowReg, rlSrc2.highReg);
254 }
jeffhao41005dd2012-05-09 17:58:52 -0700255 oatClobberSReg(cUnit, rlDest.sRegLow);
Ian Rogersc6f3bb82012-03-21 20:40:33 -0700256 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
257 loadConstantNoClobber(cUnit, rlResult.lowReg, unorderedGt ? 1 : 0);
Ian Rogersb5d09b22012-03-06 22:14:17 -0800258 if (single) {
259 newLIR2(cUnit, kX86UcomissRR, srcReg1, srcReg2);
260 } else {
261 newLIR2(cUnit, kX86UcomisdRR, srcReg1, srcReg2);
262 }
263 LIR* branch = NULL;
264 if (unorderedGt) {
Ian Rogersb41b33b2012-03-20 14:22:54 -0700265 branch = newLIR2(cUnit, kX86Jcc8, 0, kX86CondPE);
Ian Rogersb5d09b22012-03-06 22:14:17 -0800266 }
jeffhao703f2cd2012-07-13 17:25:52 -0700267 // If the result reg can't be byte accessed, use a jump and move instead of a set.
268 if (rlResult.lowReg >= 4) {
269 LIR* branch2 = NULL;
270 if (unorderedGt) {
271 branch2 = newLIR2(cUnit, kX86Jcc8, 0, kX86CondA);
272 newLIR2(cUnit, kX86Mov32RI, rlResult.lowReg, 0x0);
273 } else {
274 branch2 = newLIR2(cUnit, kX86Jcc8, 0, kX86CondBe);
275 newLIR2(cUnit, kX86Mov32RI, rlResult.lowReg, 0x1);
276 }
277 branch2->target = newLIR0(cUnit, kPseudoTargetLabel);
278 } else {
279 newLIR2(cUnit, kX86Set8R, rlResult.lowReg, kX86CondA /* above - unsigned > */);
280 }
Ian Rogersb5d09b22012-03-06 22:14:17 -0800281 newLIR2(cUnit, kX86Sbb32RI, rlResult.lowReg, 0);
282 if (unorderedGt) {
283 branch->target = newLIR0(cUnit, kPseudoTargetLabel);
284 }
jeffhao644d5312012-05-03 19:04:49 -0700285 storeValue(cUnit, rlDest, rlResult);
Ian Rogersb5d09b22012-03-06 22:14:17 -0800286 return false;
buzbeee88dfbf2012-03-05 11:19:57 -0800287}
288
289} // namespace art