blob: c00b5fc7ff6e1b5789a2592314b5ce2c168704b0 [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;
buzbeee88dfbf2012-03-05 11:19:57 -080024
Ian Rogersb5d09b22012-03-06 22:14:17 -080025 /*
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) {
Ian Rogersb5d09b22012-03-06 22:14:17 -080030 case Instruction::ADD_FLOAT_2ADDR:
31 case Instruction::ADD_FLOAT:
32 op = kX86AddssRR;
33 break;
34 case Instruction::SUB_FLOAT_2ADDR:
35 case Instruction::SUB_FLOAT:
36 op = kX86SubssRR;
37 break;
38 case Instruction::DIV_FLOAT_2ADDR:
39 case Instruction::DIV_FLOAT:
40 op = kX86DivssRR;
41 break;
42 case Instruction::MUL_FLOAT_2ADDR:
43 case Instruction::MUL_FLOAT:
44 op = kX86MulssRR;
45 break;
46 case Instruction::NEG_FLOAT:
jeffhao4abb1a92012-06-08 17:02:08 -070047 // TODO: Make this nicer. Subtracting the source from 0 doesn't work in
48 // the 0 case, and using FCHS is difficult with register promotion. This
49 // code treats the value as a CoreReg to make it easy to manipulate.
50 rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
51 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
52 opRegRegImm(cUnit, kOpAdd, rlResult.lowReg, rlSrc1.lowReg, 0x80000000);
jeffhao292188d2012-05-17 15:45:04 -070053 storeValue(cUnit, rlDest, rlResult);
54 return false;
Ian Rogersb5d09b22012-03-06 22:14:17 -080055 case Instruction::REM_FLOAT_2ADDR:
56 case Instruction::REM_FLOAT: {
buzbee408ad162012-06-06 16:45:18 -070057 return genArithOpFloatPortable(cUnit, opcode, rlDest, rlSrc1, rlSrc2);
buzbeee88dfbf2012-03-05 11:19:57 -080058 }
Ian Rogersb5d09b22012-03-06 22:14:17 -080059 default:
60 return true;
61 }
62 rlSrc1 = loadValue(cUnit, rlSrc1, kFPReg);
63 rlSrc2 = loadValue(cUnit, rlSrc2, kFPReg);
64 rlResult = oatEvalLoc(cUnit, rlDest, kFPReg, true);
65 int rDest = rlResult.lowReg;
66 int rSrc1 = rlSrc1.lowReg;
67 int rSrc2 = rlSrc2.lowReg;
jeffhao4abb1a92012-06-08 17:02:08 -070068 if (rSrc2 == rDest) {
69 rSrc2 = oatAllocTempFloat(cUnit);
70 opRegCopy(cUnit, rSrc2, rDest);
71 }
Ian Rogersb5d09b22012-03-06 22:14:17 -080072 opRegCopy(cUnit, rDest, rSrc1);
73 newLIR2(cUnit, op, rDest, rSrc2);
74 storeValue(cUnit, rlDest, rlResult);
buzbeee88dfbf2012-03-05 11:19:57 -080075
Ian Rogersb5d09b22012-03-06 22:14:17 -080076 return false;
buzbeee88dfbf2012-03-05 11:19:57 -080077}
78
buzbee408ad162012-06-06 16:45:18 -070079static bool genArithOpDouble(CompilationUnit *cUnit, Instruction::Code opcode,
buzbeee88dfbf2012-03-05 11:19:57 -080080 RegLocation rlDest, RegLocation rlSrc1,
Ian Rogersb5d09b22012-03-06 22:14:17 -080081 RegLocation rlSrc2) {
82 X86OpCode op = kX86Nop;
83 RegLocation rlResult;
buzbeee88dfbf2012-03-05 11:19:57 -080084
buzbee408ad162012-06-06 16:45:18 -070085 switch (opcode) {
Ian Rogersb5d09b22012-03-06 22:14:17 -080086 case Instruction::ADD_DOUBLE_2ADDR:
87 case Instruction::ADD_DOUBLE:
88 op = kX86AddsdRR;
89 break;
90 case Instruction::SUB_DOUBLE_2ADDR:
91 case Instruction::SUB_DOUBLE:
92 op = kX86SubsdRR;
93 break;
94 case Instruction::DIV_DOUBLE_2ADDR:
95 case Instruction::DIV_DOUBLE:
96 op = kX86DivsdRR;
97 break;
98 case Instruction::MUL_DOUBLE_2ADDR:
99 case Instruction::MUL_DOUBLE:
100 op = kX86MulsdRR;
101 break;
102 case Instruction::NEG_DOUBLE:
jeffhao4abb1a92012-06-08 17:02:08 -0700103 // TODO: Make this nicer. Subtracting the source from 0 doesn't work in
104 // the 0 case, and using FCHS is difficult with register promotion. This
105 // code treats the value as a CoreReg to make it easy to manipulate.
106 rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
107 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
108 opRegRegImm(cUnit, kOpAdd, rlResult.highReg, rlSrc1.highReg, 0x80000000);
109 opRegCopy(cUnit, rlResult.lowReg, rlSrc1.lowReg);
jeffhao292188d2012-05-17 15:45:04 -0700110 storeValueWide(cUnit, rlDest, rlResult);
111 return false;
Ian Rogersb5d09b22012-03-06 22:14:17 -0800112 case Instruction::REM_DOUBLE_2ADDR:
113 case Instruction::REM_DOUBLE: {
buzbee408ad162012-06-06 16:45:18 -0700114 return genArithOpDoublePortable(cUnit, opcode, rlDest, rlSrc1, rlSrc2);
buzbeee88dfbf2012-03-05 11:19:57 -0800115 }
Ian Rogersb5d09b22012-03-06 22:14:17 -0800116 default:
117 return true;
118 }
119 rlSrc1 = loadValueWide(cUnit, rlSrc1, kFPReg);
120 DCHECK(rlSrc1.wide);
121 rlSrc2 = loadValueWide(cUnit, rlSrc2, kFPReg);
122 DCHECK(rlSrc2.wide);
123 rlResult = oatEvalLoc(cUnit, rlDest, kFPReg, true);
124 DCHECK(rlDest.wide);
125 DCHECK(rlResult.wide);
126 int rDest = S2D(rlResult.lowReg, rlResult.highReg);
127 int rSrc1 = S2D(rlSrc1.lowReg, rlSrc1.highReg);
128 int rSrc2 = S2D(rlSrc2.lowReg, rlSrc2.highReg);
jeffhao4abb1a92012-06-08 17:02:08 -0700129 if (rDest == rSrc2) {
130 rSrc2 = oatAllocTempDouble(cUnit) | FP_DOUBLE;
131 opRegCopy(cUnit, rSrc2, rDest);
132 }
Ian Rogersb5d09b22012-03-06 22:14:17 -0800133 opRegCopy(cUnit, rDest, rSrc1);
134 newLIR2(cUnit, op, rDest, rSrc2);
135 storeValueWide(cUnit, rlDest, rlResult);
136 return false;
buzbeee88dfbf2012-03-05 11:19:57 -0800137}
138
buzbee408ad162012-06-06 16:45:18 -0700139static bool genConversion(CompilationUnit *cUnit, Instruction::Code opcode,
140 RegLocation rlDest, RegLocation rlSrc) {
jeffhao5121e0b2012-05-08 18:23:38 -0700141 RegisterClass rcSrc = kFPReg;
Ian Rogersb5d09b22012-03-06 22:14:17 -0800142 X86OpCode op = kX86Nop;
143 int srcReg;
144 RegLocation rlResult;
145 switch (opcode) {
146 case Instruction::INT_TO_FLOAT:
jeffhao5121e0b2012-05-08 18:23:38 -0700147 rcSrc = kCoreReg;
Ian Rogersb5d09b22012-03-06 22:14:17 -0800148 op = kX86Cvtsi2ssRR;
149 break;
150 case Instruction::DOUBLE_TO_FLOAT:
jeffhao5121e0b2012-05-08 18:23:38 -0700151 rcSrc = kFPReg;
Ian Rogersb5d09b22012-03-06 22:14:17 -0800152 op = kX86Cvtsd2ssRR;
153 break;
154 case Instruction::FLOAT_TO_DOUBLE:
jeffhao5121e0b2012-05-08 18:23:38 -0700155 rcSrc = kFPReg;
Ian Rogersb5d09b22012-03-06 22:14:17 -0800156 op = kX86Cvtss2sdRR;
157 break;
158 case Instruction::INT_TO_DOUBLE:
jeffhao5121e0b2012-05-08 18:23:38 -0700159 rcSrc = kCoreReg;
Ian Rogersb5d09b22012-03-06 22:14:17 -0800160 op = kX86Cvtsi2sdRR;
161 break;
jeffhao292188d2012-05-17 15:45:04 -0700162 case Instruction::FLOAT_TO_INT: {
jeffhao41005dd2012-05-09 17:58:52 -0700163 rlSrc = loadValue(cUnit, rlSrc, kFPReg);
164 srcReg = rlSrc.lowReg;
jeffhao41005dd2012-05-09 17:58:52 -0700165 oatClobberSReg(cUnit, rlDest.sRegLow);
166 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
jeffhao292188d2012-05-17 15:45:04 -0700167 int tempReg = oatAllocTempFloat(cUnit);
jeffhao41005dd2012-05-09 17:58:52 -0700168
169 loadConstant(cUnit, rlResult.lowReg, 0x7fffffff);
170 newLIR2(cUnit, kX86Cvtsi2ssRR, tempReg, rlResult.lowReg);
171 newLIR2(cUnit, kX86ComissRR, srcReg, tempReg);
jeffhao292188d2012-05-17 15:45:04 -0700172 LIR* branchPosOverflow = newLIR2(cUnit, kX86Jcc8, 0, kX86CondA);
173 LIR* branchNaN = newLIR2(cUnit, kX86Jcc8, 0, kX86CondP);
174 newLIR2(cUnit, kX86Cvttss2siRR, rlResult.lowReg, srcReg);
175 LIR* branchNormal = newLIR1(cUnit, kX86Jmp8, 0);
176 branchNaN->target = newLIR0(cUnit, kPseudoTargetLabel);
177 newLIR2(cUnit, kX86Xor32RR, rlResult.lowReg, rlResult.lowReg);
178 branchPosOverflow->target = newLIR0(cUnit, kPseudoTargetLabel);
179 branchNormal->target = newLIR0(cUnit, kPseudoTargetLabel);
jeffhao41005dd2012-05-09 17:58:52 -0700180 storeValue(cUnit, rlDest, rlResult);
181 return false;
jeffhao292188d2012-05-17 15:45:04 -0700182 }
183 case Instruction::DOUBLE_TO_INT: {
jeffhao41005dd2012-05-09 17:58:52 -0700184 rlSrc = loadValueWide(cUnit, rlSrc, kFPReg);
185 srcReg = rlSrc.lowReg;
jeffhao41005dd2012-05-09 17:58:52 -0700186 oatClobberSReg(cUnit, rlDest.sRegLow);
187 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
jeffhao4abb1a92012-06-08 17:02:08 -0700188 int tempReg = oatAllocTempDouble(cUnit) | FP_DOUBLE;
jeffhao41005dd2012-05-09 17:58:52 -0700189
190 loadConstant(cUnit, rlResult.lowReg, 0x7fffffff);
191 newLIR2(cUnit, kX86Cvtsi2sdRR, tempReg, rlResult.lowReg);
192 newLIR2(cUnit, kX86ComisdRR, srcReg, tempReg);
jeffhao292188d2012-05-17 15:45:04 -0700193 LIR* branchPosOverflow = newLIR2(cUnit, kX86Jcc8, 0, kX86CondA);
194 LIR* branchNaN = newLIR2(cUnit, kX86Jcc8, 0, kX86CondP);
195 newLIR2(cUnit, kX86Cvttsd2siRR, rlResult.lowReg, srcReg);
196 LIR* branchNormal = newLIR1(cUnit, kX86Jmp8, 0);
197 branchNaN->target = newLIR0(cUnit, kPseudoTargetLabel);
198 newLIR2(cUnit, kX86Xor32RR, rlResult.lowReg, rlResult.lowReg);
199 branchPosOverflow->target = newLIR0(cUnit, kPseudoTargetLabel);
200 branchNormal->target = newLIR0(cUnit, kPseudoTargetLabel);
jeffhao41005dd2012-05-09 17:58:52 -0700201 storeValue(cUnit, rlDest, rlResult);
202 return false;
jeffhao292188d2012-05-17 15:45:04 -0700203 }
Ian Rogersb5d09b22012-03-06 22:14:17 -0800204 case Instruction::LONG_TO_DOUBLE:
Ian Rogersb5d09b22012-03-06 22:14:17 -0800205 case Instruction::LONG_TO_FLOAT:
jeffhao41005dd2012-05-09 17:58:52 -0700206 // These can be implemented inline by using memory as a 64-bit source.
207 // However, this can't be done easily if the register has been promoted.
208 UNIMPLEMENTED(WARNING) << "inline l2[df] " << PrettyMethod(cUnit->method_idx, *cUnit->dex_file);
209 case Instruction::FLOAT_TO_LONG:
Ian Rogersb5d09b22012-03-06 22:14:17 -0800210 case Instruction::DOUBLE_TO_LONG:
buzbee408ad162012-06-06 16:45:18 -0700211 return genConversionPortable(cUnit, opcode, rlDest, rlSrc);
Ian Rogersb5d09b22012-03-06 22:14:17 -0800212 default:
213 return true;
214 }
buzbee408ad162012-06-06 16:45:18 -0700215 if (rlSrc.wide) {
jeffhao5121e0b2012-05-08 18:23:38 -0700216 rlSrc = loadValueWide(cUnit, rlSrc, rcSrc);
Ian Rogersb5d09b22012-03-06 22:14:17 -0800217 srcReg = S2D(rlSrc.lowReg, rlSrc.highReg);
218 } else {
jeffhao5121e0b2012-05-08 18:23:38 -0700219 rlSrc = loadValue(cUnit, rlSrc, rcSrc);
Ian Rogersb5d09b22012-03-06 22:14:17 -0800220 srcReg = rlSrc.lowReg;
221 }
buzbee408ad162012-06-06 16:45:18 -0700222 if (rlDest.wide) {
Ian Rogersb5d09b22012-03-06 22:14:17 -0800223 rlResult = oatEvalLoc(cUnit, rlDest, kFPReg, true);
224 newLIR2(cUnit, op, S2D(rlResult.lowReg, rlResult.highReg), srcReg);
225 storeValueWide(cUnit, rlDest, rlResult);
226 } else {
Ian Rogersb5d09b22012-03-06 22:14:17 -0800227 rlResult = oatEvalLoc(cUnit, rlDest, kFPReg, true);
228 newLIR2(cUnit, op, rlResult.lowReg, srcReg);
229 storeValue(cUnit, rlDest, rlResult);
230 }
231 return false;
buzbeee88dfbf2012-03-05 11:19:57 -0800232}
233
buzbee408ad162012-06-06 16:45:18 -0700234static bool genCmpFP(CompilationUnit *cUnit, Instruction::Code code, RegLocation rlDest,
Ian Rogersb5d09b22012-03-06 22:14:17 -0800235 RegLocation rlSrc1, RegLocation rlSrc2) {
Ian Rogersb5d09b22012-03-06 22:14:17 -0800236 bool single = (code == Instruction::CMPL_FLOAT) || (code == Instruction::CMPG_FLOAT);
237 bool unorderedGt = (code == Instruction::CMPG_DOUBLE) || (code == Instruction::CMPG_FLOAT);
238 int srcReg1;
239 int srcReg2;
240 if (single) {
Ian Rogersb5d09b22012-03-06 22:14:17 -0800241 rlSrc1 = loadValue(cUnit, rlSrc1, kFPReg);
242 srcReg1 = rlSrc1.lowReg;
jeffhao644d5312012-05-03 19:04:49 -0700243 rlSrc2 = loadValue(cUnit, rlSrc2, kFPReg);
244 srcReg2 = rlSrc2.lowReg;
Ian Rogersb5d09b22012-03-06 22:14:17 -0800245 } else {
Ian Rogersb5d09b22012-03-06 22:14:17 -0800246 rlSrc1 = loadValueWide(cUnit, rlSrc1, kFPReg);
247 srcReg1 = S2D(rlSrc1.lowReg, rlSrc1.highReg);
Ian Rogersb5d09b22012-03-06 22:14:17 -0800248 rlSrc2 = loadValueWide(cUnit, rlSrc2, kFPReg);
249 srcReg2 = S2D(rlSrc2.lowReg, rlSrc2.highReg);
250 }
jeffhao41005dd2012-05-09 17:58:52 -0700251 oatClobberSReg(cUnit, rlDest.sRegLow);
Ian Rogersc6f3bb82012-03-21 20:40:33 -0700252 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
253 loadConstantNoClobber(cUnit, rlResult.lowReg, unorderedGt ? 1 : 0);
Ian Rogersb5d09b22012-03-06 22:14:17 -0800254 if (single) {
255 newLIR2(cUnit, kX86UcomissRR, srcReg1, srcReg2);
256 } else {
257 newLIR2(cUnit, kX86UcomisdRR, srcReg1, srcReg2);
258 }
259 LIR* branch = NULL;
260 if (unorderedGt) {
Ian Rogersb41b33b2012-03-20 14:22:54 -0700261 branch = newLIR2(cUnit, kX86Jcc8, 0, kX86CondPE);
Ian Rogersb5d09b22012-03-06 22:14:17 -0800262 }
263 newLIR2(cUnit, kX86Set8R, rlResult.lowReg, kX86CondA /* above - unsigned > */);
264 newLIR2(cUnit, kX86Sbb32RI, rlResult.lowReg, 0);
265 if (unorderedGt) {
266 branch->target = newLIR0(cUnit, kPseudoTargetLabel);
267 }
jeffhao644d5312012-05-03 19:04:49 -0700268 storeValue(cUnit, rlDest, rlResult);
Ian Rogersb5d09b22012-03-06 22:14:17 -0800269 return false;
buzbeee88dfbf2012-03-05 11:19:57 -0800270}
271
272} // namespace art