1/*
2 * Copyright (C) 2009 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
17static bool genArithOpFloat(CompilationUnit *cUnit, MIR *mir,
18                            RegLocation rlDest, RegLocation rlSrc1,
19                            RegLocation rlSrc2)
20{
21    int op = kThumbBkpt;
22    RegLocation rlResult;
23
24    /*
25     * Don't attempt to optimize register usage since these opcodes call out to
26     * the handlers.
27     */
28    switch (mir->dalvikInsn.opcode) {
29        case OP_ADD_FLOAT_2ADDR:
30        case OP_ADD_FLOAT:
31            op = kThumb2Vadds;
32            break;
33        case OP_SUB_FLOAT_2ADDR:
34        case OP_SUB_FLOAT:
35            op = kThumb2Vsubs;
36            break;
37        case OP_DIV_FLOAT_2ADDR:
38        case OP_DIV_FLOAT:
39            op = kThumb2Vdivs;
40            break;
41        case OP_MUL_FLOAT_2ADDR:
42        case OP_MUL_FLOAT:
43            op = kThumb2Vmuls;
44            break;
45        case OP_REM_FLOAT_2ADDR:
46        case OP_REM_FLOAT:
47        case OP_NEG_FLOAT: {
48            return genArithOpFloatPortable(cUnit, mir, rlDest, rlSrc1,
49                                              rlSrc2);
50        }
51        default:
52            return true;
53    }
54    rlSrc1 = loadValue(cUnit, rlSrc1, kFPReg);
55    rlSrc2 = loadValue(cUnit, rlSrc2, kFPReg);
56    rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kFPReg, true);
57    newLIR3(cUnit, (ArmOpcode)op, rlResult.lowReg, rlSrc1.lowReg,
58            rlSrc2.lowReg);
59    storeValue(cUnit, rlDest, rlResult);
60    return false;
61}
62
63static bool genArithOpDouble(CompilationUnit *cUnit, MIR *mir,
64                             RegLocation rlDest, RegLocation rlSrc1,
65                             RegLocation rlSrc2)
66{
67    int op = kThumbBkpt;
68    RegLocation rlResult;
69
70    switch (mir->dalvikInsn.opcode) {
71        case OP_ADD_DOUBLE_2ADDR:
72        case OP_ADD_DOUBLE:
73            op = kThumb2Vaddd;
74            break;
75        case OP_SUB_DOUBLE_2ADDR:
76        case OP_SUB_DOUBLE:
77            op = kThumb2Vsubd;
78            break;
79        case OP_DIV_DOUBLE_2ADDR:
80        case OP_DIV_DOUBLE:
81            op = kThumb2Vdivd;
82            break;
83        case OP_MUL_DOUBLE_2ADDR:
84        case OP_MUL_DOUBLE:
85            op = kThumb2Vmuld;
86            break;
87        case OP_REM_DOUBLE_2ADDR:
88        case OP_REM_DOUBLE:
89        case OP_NEG_DOUBLE: {
90            return genArithOpDoublePortable(cUnit, mir, rlDest, rlSrc1,
91                                               rlSrc2);
92        }
93        default:
94            return true;
95    }
96
97    rlSrc1 = loadValueWide(cUnit, rlSrc1, kFPReg);
98    assert(rlSrc1.wide);
99    rlSrc2 = loadValueWide(cUnit, rlSrc2, kFPReg);
100    assert(rlSrc2.wide);
101    rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kFPReg, true);
102    assert(rlDest.wide);
103    assert(rlResult.wide);
104    newLIR3(cUnit, (ArmOpcode)op, S2D(rlResult.lowReg, rlResult.highReg),
105            S2D(rlSrc1.lowReg, rlSrc1.highReg),
106            S2D(rlSrc2.lowReg, rlSrc2.highReg));
107    storeValueWide(cUnit, rlDest, rlResult);
108    return false;
109}
110
111static bool genConversion(CompilationUnit *cUnit, MIR *mir)
112{
113    Opcode opcode = mir->dalvikInsn.opcode;
114    int op = kThumbBkpt;
115    bool longSrc = false;
116    bool longDest = false;
117    int srcReg;
118    RegLocation rlSrc;
119    RegLocation rlDest;
120    RegLocation rlResult;
121
122    switch (opcode) {
123        case OP_INT_TO_FLOAT:
124            longSrc = false;
125            longDest = false;
126            op = kThumb2VcvtIF;
127            break;
128        case OP_FLOAT_TO_INT:
129            longSrc = false;
130            longDest = false;
131            op = kThumb2VcvtFI;
132            break;
133        case OP_DOUBLE_TO_FLOAT:
134            longSrc = true;
135            longDest = false;
136            op = kThumb2VcvtDF;
137            break;
138        case OP_FLOAT_TO_DOUBLE:
139            longSrc = false;
140            longDest = true;
141            op = kThumb2VcvtFd;
142            break;
143        case OP_INT_TO_DOUBLE:
144            longSrc = false;
145            longDest = true;
146            op = kThumb2VcvtID;
147            break;
148        case OP_DOUBLE_TO_INT:
149            longSrc = true;
150            longDest = false;
151            op = kThumb2VcvtDI;
152            break;
153        case OP_LONG_TO_DOUBLE:
154        case OP_FLOAT_TO_LONG:
155        case OP_LONG_TO_FLOAT:
156        case OP_DOUBLE_TO_LONG:
157            return genConversionPortable(cUnit, mir);
158        default:
159            return true;
160    }
161    if (longSrc) {
162        rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
163        rlSrc = loadValueWide(cUnit, rlSrc, kFPReg);
164        srcReg = S2D(rlSrc.lowReg, rlSrc.highReg);
165    } else {
166        rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
167        rlSrc = loadValue(cUnit, rlSrc, kFPReg);
168        srcReg = rlSrc.lowReg;
169    }
170    if (longDest) {
171        rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
172        rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kFPReg, true);
173        newLIR2(cUnit, (ArmOpcode)op, S2D(rlResult.lowReg, rlResult.highReg),
174                srcReg);
175        storeValueWide(cUnit, rlDest, rlResult);
176    } else {
177        rlDest = dvmCompilerGetDest(cUnit, mir, 0);
178        rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kFPReg, true);
179        newLIR2(cUnit, (ArmOpcode)op, rlResult.lowReg, srcReg);
180        storeValue(cUnit, rlDest, rlResult);
181    }
182    return false;
183}
184
185static bool genInlineSqrt(CompilationUnit *cUnit, MIR *mir)
186{
187    ArmLIR *branch;
188    RegLocation rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
189    RegLocation rlDest = inlinedTargetWide(cUnit, mir, true);
190    rlSrc = loadValueWide(cUnit, rlSrc, kFPReg);
191    RegLocation rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kFPReg, true);
192    newLIR2(cUnit, kThumb2Vsqrtd, S2D(rlResult.lowReg, rlResult.highReg),
193            S2D(rlSrc.lowReg, rlSrc.highReg));
194    newLIR2(cUnit, kThumb2Vcmpd, S2D(rlResult.lowReg, rlResult.highReg),
195            S2D(rlResult.lowReg, rlResult.highReg));
196    newLIR0(cUnit, kThumb2Fmstat);
197    branch = newLIR2(cUnit, kThumbBCond, 0, kArmCondEq);
198    dvmCompilerClobberCallRegs(cUnit);
199    LOAD_FUNC_ADDR(cUnit, r2, (int) (double (*)(double)) sqrt);
200    newLIR3(cUnit, kThumb2Fmrrd, r0, r1, S2D(rlSrc.lowReg, rlSrc.highReg));
201    newLIR1(cUnit, kThumbBlxR, r2);
202    newLIR3(cUnit, kThumb2Fmdrr, S2D(rlResult.lowReg, rlResult.highReg),
203            r0, r1);
204    ArmLIR *label = newLIR0(cUnit, kArmPseudoTargetLabel);
205    label->defMask = ENCODE_ALL;
206    branch->generic.target = (LIR *)label;
207    storeValueWide(cUnit, rlDest, rlResult);
208    return false;
209}
210
211static bool genCmpFP(CompilationUnit *cUnit, MIR *mir, RegLocation rlDest,
212                     RegLocation rlSrc1, RegLocation rlSrc2)
213{
214    bool isDouble;
215    int defaultResult;
216    RegLocation rlResult;
217
218    switch(mir->dalvikInsn.opcode) {
219        case OP_CMPL_FLOAT:
220            isDouble = false;
221            defaultResult = -1;
222            break;
223        case OP_CMPG_FLOAT:
224            isDouble = false;
225            defaultResult = 1;
226            break;
227        case OP_CMPL_DOUBLE:
228            isDouble = true;
229            defaultResult = -1;
230            break;
231        case OP_CMPG_DOUBLE:
232            isDouble = true;
233            defaultResult = 1;
234            break;
235        default:
236            return true;
237    }
238    if (isDouble) {
239        rlSrc1 = loadValueWide(cUnit, rlSrc1, kFPReg);
240        rlSrc2 = loadValueWide(cUnit, rlSrc2, kFPReg);
241        dvmCompilerClobberSReg(cUnit, rlDest.sRegLow);
242        rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
243        loadConstant(cUnit, rlResult.lowReg, defaultResult);
244        newLIR2(cUnit, kThumb2Vcmpd, S2D(rlSrc1.lowReg, r1Src2.highReg),
245                S2D(rlSrc2.lowReg, rlSrc2.highReg));
246    } else {
247        rlSrc1 = loadValue(cUnit, rlSrc1, kFPReg);
248        rlSrc2 = loadValue(cUnit, rlSrc2, kFPReg);
249        dvmCompilerClobberSReg(cUnit, rlDest.sRegLow);
250        rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
251        loadConstant(cUnit, rlResult.lowReg, defaultResult);
252        newLIR2(cUnit, kThumb2Vcmps, rlSrc1.lowReg, rlSrc2.lowReg);
253    }
254    assert(!FPREG(rlResult.lowReg));
255    newLIR0(cUnit, kThumb2Fmstat);
256
257    genIT(cUnit, (defaultResult == -1) ? kArmCondGt : kArmCondMi, "");
258    newLIR2(cUnit, kThumb2MovImmShift, rlResult.lowReg,
259            modifiedImmediate(-defaultResult)); // Must not alter ccodes
260    genBarrier(cUnit);
261
262    genIT(cUnit, kArmCondEq, "");
263    loadConstant(cUnit, rlResult.lowReg, 0);
264    genBarrier(cUnit);
265
266    storeValue(cUnit, rlDest, rlResult);
267    return false;
268}
269