1 /*
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
17 #include "codegen_mips.h"
18 #include "dex/quick/mir_to_lir-inl.h"
19 #include "entrypoints/quick/quick_entrypoints.h"
20 #include "mips_lir.h"
21
22 namespace art {
23
GenArithOpFloat(Instruction::Code opcode,RegLocation rl_dest,RegLocation rl_src1,RegLocation rl_src2)24 void MipsMir2Lir::GenArithOpFloat(Instruction::Code opcode,
25 RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2) {
26 int op = kMipsNop;
27 RegLocation rl_result;
28
29 /*
30 * Don't attempt to optimize register usage since these opcodes call out to
31 * the handlers.
32 */
33 switch (opcode) {
34 case Instruction::ADD_FLOAT_2ADDR:
35 case Instruction::ADD_FLOAT:
36 op = kMipsFadds;
37 break;
38 case Instruction::SUB_FLOAT_2ADDR:
39 case Instruction::SUB_FLOAT:
40 op = kMipsFsubs;
41 break;
42 case Instruction::DIV_FLOAT_2ADDR:
43 case Instruction::DIV_FLOAT:
44 op = kMipsFdivs;
45 break;
46 case Instruction::MUL_FLOAT_2ADDR:
47 case Instruction::MUL_FLOAT:
48 op = kMipsFmuls;
49 break;
50 case Instruction::REM_FLOAT_2ADDR:
51 case Instruction::REM_FLOAT:
52 FlushAllRegs(); // Send everything to home location
53 CallRuntimeHelperRegLocationRegLocation(kQuickFmodf, rl_src1, rl_src2, false);
54 rl_result = GetReturn(kFPReg);
55 StoreValue(rl_dest, rl_result);
56 return;
57 case Instruction::NEG_FLOAT:
58 GenNegFloat(rl_dest, rl_src1);
59 return;
60 default:
61 LOG(FATAL) << "Unexpected opcode: " << opcode;
62 }
63 rl_src1 = LoadValue(rl_src1, kFPReg);
64 rl_src2 = LoadValue(rl_src2, kFPReg);
65 rl_result = EvalLoc(rl_dest, kFPReg, true);
66 NewLIR3(op, rl_result.reg.GetReg(), rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
67 StoreValue(rl_dest, rl_result);
68 }
69
GenArithOpDouble(Instruction::Code opcode,RegLocation rl_dest,RegLocation rl_src1,RegLocation rl_src2)70 void MipsMir2Lir::GenArithOpDouble(Instruction::Code opcode,
71 RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2) {
72 int op = kMipsNop;
73 RegLocation rl_result;
74
75 switch (opcode) {
76 case Instruction::ADD_DOUBLE_2ADDR:
77 case Instruction::ADD_DOUBLE:
78 op = kMipsFaddd;
79 break;
80 case Instruction::SUB_DOUBLE_2ADDR:
81 case Instruction::SUB_DOUBLE:
82 op = kMipsFsubd;
83 break;
84 case Instruction::DIV_DOUBLE_2ADDR:
85 case Instruction::DIV_DOUBLE:
86 op = kMipsFdivd;
87 break;
88 case Instruction::MUL_DOUBLE_2ADDR:
89 case Instruction::MUL_DOUBLE:
90 op = kMipsFmuld;
91 break;
92 case Instruction::REM_DOUBLE_2ADDR:
93 case Instruction::REM_DOUBLE:
94 FlushAllRegs(); // Send everything to home location
95 CallRuntimeHelperRegLocationRegLocation(kQuickFmod, rl_src1, rl_src2, false);
96 rl_result = GetReturnWide(kFPReg);
97 StoreValueWide(rl_dest, rl_result);
98 return;
99 case Instruction::NEG_DOUBLE:
100 GenNegDouble(rl_dest, rl_src1);
101 return;
102 default:
103 LOG(FATAL) << "Unpexpected opcode: " << opcode;
104 }
105 rl_src1 = LoadValueWide(rl_src1, kFPReg);
106 DCHECK(rl_src1.wide);
107 rl_src2 = LoadValueWide(rl_src2, kFPReg);
108 DCHECK(rl_src2.wide);
109 rl_result = EvalLoc(rl_dest, kFPReg, true);
110 DCHECK(rl_dest.wide);
111 DCHECK(rl_result.wide);
112 NewLIR3(op, rl_result.reg.GetReg(), rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
113 StoreValueWide(rl_dest, rl_result);
114 }
115
GenConversion(Instruction::Code opcode,RegLocation rl_dest,RegLocation rl_src)116 void MipsMir2Lir::GenConversion(Instruction::Code opcode, RegLocation rl_dest,
117 RegLocation rl_src) {
118 int op = kMipsNop;
119 RegLocation rl_result;
120 switch (opcode) {
121 case Instruction::INT_TO_FLOAT:
122 op = kMipsFcvtsw;
123 break;
124 case Instruction::DOUBLE_TO_FLOAT:
125 op = kMipsFcvtsd;
126 break;
127 case Instruction::FLOAT_TO_DOUBLE:
128 op = kMipsFcvtds;
129 break;
130 case Instruction::INT_TO_DOUBLE:
131 op = kMipsFcvtdw;
132 break;
133 case Instruction::FLOAT_TO_INT:
134 GenConversionCall(kQuickF2iz, rl_dest, rl_src);
135 return;
136 case Instruction::DOUBLE_TO_INT:
137 GenConversionCall(kQuickD2iz, rl_dest, rl_src);
138 return;
139 case Instruction::LONG_TO_DOUBLE:
140 GenConversionCall(kQuickL2d, rl_dest, rl_src);
141 return;
142 case Instruction::FLOAT_TO_LONG:
143 GenConversionCall(kQuickF2l, rl_dest, rl_src);
144 return;
145 case Instruction::LONG_TO_FLOAT:
146 GenConversionCall(kQuickL2f, rl_dest, rl_src);
147 return;
148 case Instruction::DOUBLE_TO_LONG:
149 GenConversionCall(kQuickD2l, rl_dest, rl_src);
150 return;
151 default:
152 LOG(FATAL) << "Unexpected opcode: " << opcode;
153 }
154 if (rl_src.wide) {
155 rl_src = LoadValueWide(rl_src, kFPReg);
156 } else {
157 rl_src = LoadValue(rl_src, kFPReg);
158 }
159 rl_result = EvalLoc(rl_dest, kFPReg, true);
160 NewLIR2(op, rl_result.reg.GetReg(), rl_src.reg.GetReg());
161 if (rl_dest.wide) {
162 StoreValueWide(rl_dest, rl_result);
163 } else {
164 StoreValue(rl_dest, rl_result);
165 }
166 }
167
GenCmpFP(Instruction::Code opcode,RegLocation rl_dest,RegLocation rl_src1,RegLocation rl_src2)168 void MipsMir2Lir::GenCmpFP(Instruction::Code opcode, RegLocation rl_dest,
169 RegLocation rl_src1, RegLocation rl_src2) {
170 bool wide = true;
171 QuickEntrypointEnum target;
172
173 switch (opcode) {
174 case Instruction::CMPL_FLOAT:
175 target = kQuickCmplFloat;
176 wide = false;
177 break;
178 case Instruction::CMPG_FLOAT:
179 target = kQuickCmpgFloat;
180 wide = false;
181 break;
182 case Instruction::CMPL_DOUBLE:
183 target = kQuickCmplDouble;
184 break;
185 case Instruction::CMPG_DOUBLE:
186 target = kQuickCmpgDouble;
187 break;
188 default:
189 LOG(FATAL) << "Unexpected opcode: " << opcode;
190 target = kQuickCmplFloat;
191 }
192 FlushAllRegs();
193 LockCallTemps();
194 if (wide) {
195 RegStorage r_tmp1(RegStorage::k64BitPair, rMIPS_FARG0, rMIPS_FARG1);
196 RegStorage r_tmp2(RegStorage::k64BitPair, rMIPS_FARG2, rMIPS_FARG3);
197 LoadValueDirectWideFixed(rl_src1, r_tmp1);
198 LoadValueDirectWideFixed(rl_src2, r_tmp2);
199 } else {
200 LoadValueDirectFixed(rl_src1, rs_rMIPS_FARG0);
201 LoadValueDirectFixed(rl_src2, rs_rMIPS_FARG2);
202 }
203 RegStorage r_tgt = LoadHelper(target);
204 // NOTE: not a safepoint
205 OpReg(kOpBlx, r_tgt);
206 RegLocation rl_result = GetReturn(kCoreReg);
207 StoreValue(rl_dest, rl_result);
208 }
209
GenFusedFPCmpBranch(BasicBlock * bb,MIR * mir,bool gt_bias,bool is_double)210 void MipsMir2Lir::GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir,
211 bool gt_bias, bool is_double) {
212 UNIMPLEMENTED(FATAL) << "Need codegen for fused fp cmp branch";
213 }
214
GenNegFloat(RegLocation rl_dest,RegLocation rl_src)215 void MipsMir2Lir::GenNegFloat(RegLocation rl_dest, RegLocation rl_src) {
216 RegLocation rl_result;
217 rl_src = LoadValue(rl_src, kCoreReg);
218 rl_result = EvalLoc(rl_dest, kCoreReg, true);
219 OpRegRegImm(kOpAdd, rl_result.reg, rl_src.reg, 0x80000000);
220 StoreValue(rl_dest, rl_result);
221 }
222
GenNegDouble(RegLocation rl_dest,RegLocation rl_src)223 void MipsMir2Lir::GenNegDouble(RegLocation rl_dest, RegLocation rl_src) {
224 RegLocation rl_result;
225 rl_src = LoadValueWide(rl_src, kCoreReg);
226 rl_result = EvalLoc(rl_dest, kCoreReg, true);
227 OpRegRegImm(kOpAdd, rl_result.reg.GetHigh(), rl_src.reg.GetHigh(), 0x80000000);
228 OpRegCopy(rl_result.reg, rl_src.reg);
229 StoreValueWide(rl_dest, rl_result);
230 }
231
GenInlinedMinMax(CallInfo * info,bool is_min,bool is_long)232 bool MipsMir2Lir::GenInlinedMinMax(CallInfo* info, bool is_min, bool is_long) {
233 // TODO: need Mips implementation
234 return false;
235 }
236
237 } // namespace art
238