blob: f54c58cff941b14ad683ce5367fbe5ccc9720303 [file] [log] [blame]
buzbeeefc63692012-11-14 16:31:52 -08001/*
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
17/* This file contains codegen for the Thumb2 ISA. */
18
19#include "oat_compilation_unit.h"
20#include "oat/runtime/oat_support_entrypoints.h"
buzbee1bc37c62012-11-20 13:35:41 -080021#include "arm_lir.h"
22#include "../codegen_util.h"
23#include "../ralloc_util.h"
buzbeeefc63692012-11-14 16:31:52 -080024
25namespace art {
26
27LIR* opCmpBranch(CompilationUnit* cUnit, ConditionCode cond, int src1,
28 int src2, LIR* target)
29{
30 opRegReg(cUnit, kOpCmp, src1, src2);
31 return opCondBranch(cUnit, cond, target);
32}
33
34/*
35 * Generate a Thumb2 IT instruction, which can nullify up to
36 * four subsequent instructions based on a condition and its
37 * inverse. The condition applies to the first instruction, which
38 * is executed if the condition is met. The string "guide" consists
39 * of 0 to 3 chars, and applies to the 2nd through 4th instruction.
40 * A "T" means the instruction is executed if the condition is
41 * met, and an "E" means the instruction is executed if the condition
42 * is not met.
43 */
44LIR* opIT(CompilationUnit* cUnit, ArmConditionCode code, const char* guide)
45{
46 int mask;
47 int condBit = code & 1;
48 int altBit = condBit ^ 1;
49 int mask3 = 0;
50 int mask2 = 0;
51 int mask1 = 0;
52
53 //Note: case fallthroughs intentional
54 switch (strlen(guide)) {
55 case 3:
56 mask1 = (guide[2] == 'T') ? condBit : altBit;
57 case 2:
58 mask2 = (guide[1] == 'T') ? condBit : altBit;
59 case 1:
60 mask3 = (guide[0] == 'T') ? condBit : altBit;
61 break;
62 case 0:
63 break;
64 default:
65 LOG(FATAL) << "OAT: bad case in opIT";
66 }
67 mask = (mask3 << 3) | (mask2 << 2) | (mask1 << 1) |
68 (1 << (3 - strlen(guide)));
69 return newLIR2(cUnit, kThumb2It, code, mask);
70}
71
72/*
73 * 64-bit 3way compare function.
74 * mov rX, #-1
75 * cmp op1hi, op2hi
76 * blt done
77 * bgt flip
78 * sub rX, op1lo, op2lo (treat as unsigned)
79 * beq done
80 * ite hi
81 * mov(hi) rX, #-1
82 * mov(!hi) rX, #1
83 * flip:
84 * neg rX
85 * done:
86 */
87void genCmpLong(CompilationUnit* cUnit, RegLocation rlDest,
88 RegLocation rlSrc1, RegLocation rlSrc2)
89{
90 LIR* target1;
91 LIR* target2;
92 rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
93 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
94 int tReg = oatAllocTemp(cUnit);
95 loadConstant(cUnit, tReg, -1);
96 opRegReg(cUnit, kOpCmp, rlSrc1.highReg, rlSrc2.highReg);
97 LIR* branch1 = opCondBranch(cUnit, kCondLt, NULL);
98 LIR* branch2 = opCondBranch(cUnit, kCondGt, NULL);
99 opRegRegReg(cUnit, kOpSub, tReg, rlSrc1.lowReg, rlSrc2.lowReg);
100 LIR* branch3 = opCondBranch(cUnit, kCondEq, NULL);
101
102 opIT(cUnit, kArmCondHi, "E");
103 newLIR2(cUnit, kThumb2MovImmShift, tReg, modifiedImmediate(-1));
104 loadConstant(cUnit, tReg, 1);
105 genBarrier(cUnit);
106
107 target2 = newLIR0(cUnit, kPseudoTargetLabel);
108 opRegReg(cUnit, kOpNeg, tReg, tReg);
109
110 target1 = newLIR0(cUnit, kPseudoTargetLabel);
111
112 RegLocation rlTemp = locCReturn(); // Just using as template, will change
113 rlTemp.lowReg = tReg;
114 storeValue(cUnit, rlDest, rlTemp);
115 oatFreeTemp(cUnit, tReg);
116
buzbeecbd6d442012-11-17 14:11:25 -0800117 branch1->target = target1;
118 branch2->target = target2;
buzbeeefc63692012-11-14 16:31:52 -0800119 branch3->target = branch1->target;
120}
121
122void genFusedLongCmpBranch(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir)
123{
124 LIR* labelList = cUnit->blockLabelList;
125 LIR* taken = &labelList[bb->taken->id];
126 LIR* notTaken = &labelList[bb->fallThrough->id];
127 RegLocation rlSrc1 = oatGetSrcWide(cUnit, mir, 0);
128 RegLocation rlSrc2 = oatGetSrcWide(cUnit, mir, 2);
129 rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
130 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
131 ConditionCode ccode = static_cast<ConditionCode>(mir->dalvikInsn.arg[0]);
132 opRegReg(cUnit, kOpCmp, rlSrc1.highReg, rlSrc2.highReg);
133 switch(ccode) {
134 case kCondEq:
135 opCondBranch(cUnit, kCondNe, notTaken);
136 break;
137 case kCondNe:
138 opCondBranch(cUnit, kCondNe, taken);
139 break;
140 case kCondLt:
141 opCondBranch(cUnit, kCondLt, taken);
142 opCondBranch(cUnit, kCondGt, notTaken);
143 ccode = kCondCc;
144 break;
145 case kCondLe:
146 opCondBranch(cUnit, kCondLt, taken);
147 opCondBranch(cUnit, kCondGt, notTaken);
148 ccode = kCondLs;
149 break;
150 case kCondGt:
151 opCondBranch(cUnit, kCondGt, taken);
152 opCondBranch(cUnit, kCondLt, notTaken);
153 ccode = kCondHi;
154 break;
155 case kCondGe:
156 opCondBranch(cUnit, kCondGt, taken);
157 opCondBranch(cUnit, kCondLt, notTaken);
158 ccode = kCondCs;
159 break;
160 default:
buzbeecbd6d442012-11-17 14:11:25 -0800161 LOG(FATAL) << "Unexpected ccode: " << ccode;
buzbeeefc63692012-11-14 16:31:52 -0800162 }
163 opRegReg(cUnit, kOpCmp, rlSrc1.lowReg, rlSrc2.lowReg);
164 opCondBranch(cUnit, ccode, taken);
165}
166
167/*
168 * Generate a register comparison to an immediate and branch. Caller
169 * is responsible for setting branch target field.
170 */
171LIR* opCmpImmBranch(CompilationUnit* cUnit, ConditionCode cond, int reg,
172 int checkValue, LIR* target)
173{
174 LIR* branch;
175 int modImm;
176 ArmConditionCode armCond = oatArmConditionEncoding(cond);
177 if ((ARM_LOWREG(reg)) && (checkValue == 0) &&
178 ((armCond == kArmCondEq) || (armCond == kArmCondNe))) {
179 branch = newLIR2(cUnit, (armCond == kArmCondEq) ? kThumb2Cbz : kThumb2Cbnz,
180 reg, 0);
181 } else {
182 modImm = modifiedImmediate(checkValue);
183 if (ARM_LOWREG(reg) && ((checkValue & 0xff) == checkValue)) {
184 newLIR2(cUnit, kThumbCmpRI8, reg, checkValue);
185 } else if (modImm >= 0) {
186 newLIR2(cUnit, kThumb2CmpRI8, reg, modImm);
187 } else {
188 int tReg = oatAllocTemp(cUnit);
189 loadConstant(cUnit, tReg, checkValue);
190 opRegReg(cUnit, kOpCmp, reg, tReg);
191 }
192 branch = newLIR2(cUnit, kThumbBCond, 0, armCond);
193 }
194 branch->target = target;
195 return branch;
196}
197LIR* opRegCopyNoInsert(CompilationUnit* cUnit, int rDest, int rSrc)
198{
199 LIR* res;
200 int opcode;
201 if (ARM_FPREG(rDest) || ARM_FPREG(rSrc))
202 return fpRegCopy(cUnit, rDest, rSrc);
203 if (ARM_LOWREG(rDest) && ARM_LOWREG(rSrc))
204 opcode = kThumbMovRR;
205 else if (!ARM_LOWREG(rDest) && !ARM_LOWREG(rSrc))
206 opcode = kThumbMovRR_H2H;
207 else if (ARM_LOWREG(rDest))
208 opcode = kThumbMovRR_H2L;
209 else
210 opcode = kThumbMovRR_L2H;
211 res = rawLIR(cUnit, cUnit->currentDalvikOffset, opcode, rDest, rSrc);
212 if (!(cUnit->disableOpt & (1 << kSafeOptimizations)) && rDest == rSrc) {
213 res->flags.isNop = true;
214 }
215 return res;
216}
217
218LIR* opRegCopy(CompilationUnit* cUnit, int rDest, int rSrc)
219{
220 LIR* res = opRegCopyNoInsert(cUnit, rDest, rSrc);
buzbeecbd6d442012-11-17 14:11:25 -0800221 oatAppendLIR(cUnit, res);
buzbeeefc63692012-11-14 16:31:52 -0800222 return res;
223}
224
225void opRegCopyWide(CompilationUnit* cUnit, int destLo, int destHi,
226 int srcLo, int srcHi)
227{
228 bool destFP = ARM_FPREG(destLo) && ARM_FPREG(destHi);
229 bool srcFP = ARM_FPREG(srcLo) && ARM_FPREG(srcHi);
230 DCHECK_EQ(ARM_FPREG(srcLo), ARM_FPREG(srcHi));
231 DCHECK_EQ(ARM_FPREG(destLo), ARM_FPREG(destHi));
232 if (destFP) {
233 if (srcFP) {
234 opRegCopy(cUnit, s2d(destLo, destHi), s2d(srcLo, srcHi));
235 } else {
236 newLIR3(cUnit, kThumb2Fmdrr, s2d(destLo, destHi), srcLo, srcHi);
237 }
238 } else {
239 if (srcFP) {
240 newLIR3(cUnit, kThumb2Fmrrd, destLo, destHi, s2d(srcLo, srcHi));
241 } else {
242 // Handle overlap
243 if (srcHi == destLo) {
244 opRegCopy(cUnit, destHi, srcHi);
245 opRegCopy(cUnit, destLo, srcLo);
246 } else {
247 opRegCopy(cUnit, destLo, srcLo);
248 opRegCopy(cUnit, destHi, srcHi);
249 }
250 }
251 }
252}
253
254// Table of magic divisors
buzbeeefc63692012-11-14 16:31:52 -0800255struct MagicTable {
256 uint32_t magic;
257 uint32_t shift;
258 DividePattern pattern;
259};
260
261static const MagicTable magicTable[] = {
262 {0, 0, DivideNone}, // 0
263 {0, 0, DivideNone}, // 1
264 {0, 0, DivideNone}, // 2
265 {0x55555556, 0, Divide3}, // 3
266 {0, 0, DivideNone}, // 4
267 {0x66666667, 1, Divide5}, // 5
268 {0x2AAAAAAB, 0, Divide3}, // 6
269 {0x92492493, 2, Divide7}, // 7
270 {0, 0, DivideNone}, // 8
271 {0x38E38E39, 1, Divide5}, // 9
272 {0x66666667, 2, Divide5}, // 10
273 {0x2E8BA2E9, 1, Divide5}, // 11
274 {0x2AAAAAAB, 1, Divide5}, // 12
275 {0x4EC4EC4F, 2, Divide5}, // 13
276 {0x92492493, 3, Divide7}, // 14
277 {0x88888889, 3, Divide7}, // 15
278};
279
280// Integer division by constant via reciprocal multiply (Hacker's Delight, 10-4)
281bool smallLiteralDivide(CompilationUnit* cUnit, Instruction::Code dalvikOpcode,
282 RegLocation rlSrc, RegLocation rlDest, int lit)
283{
buzbeecbd6d442012-11-17 14:11:25 -0800284 if ((lit < 0) || (lit >= static_cast<int>(sizeof(magicTable)/sizeof(magicTable[0])))) {
buzbeeefc63692012-11-14 16:31:52 -0800285 return false;
286 }
287 DividePattern pattern = magicTable[lit].pattern;
288 if (pattern == DivideNone) {
289 return false;
290 }
291 // Tuning: add rem patterns
292 if (dalvikOpcode != Instruction::DIV_INT_LIT8) {
293 return false;
294 }
295
296 int rMagic = oatAllocTemp(cUnit);
297 loadConstant(cUnit, rMagic, magicTable[lit].magic);
298 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
299 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
300 int rHi = oatAllocTemp(cUnit);
301 int rLo = oatAllocTemp(cUnit);
302 newLIR4(cUnit, kThumb2Smull, rLo, rHi, rMagic, rlSrc.lowReg);
303 switch(pattern) {
304 case Divide3:
305 opRegRegRegShift(cUnit, kOpSub, rlResult.lowReg, rHi,
306 rlSrc.lowReg, encodeShift(kArmAsr, 31));
307 break;
308 case Divide5:
309 opRegRegImm(cUnit, kOpAsr, rLo, rlSrc.lowReg, 31);
310 opRegRegRegShift(cUnit, kOpRsub, rlResult.lowReg, rLo, rHi,
311 encodeShift(kArmAsr, magicTable[lit].shift));
312 break;
313 case Divide7:
314 opRegReg(cUnit, kOpAdd, rHi, rlSrc.lowReg);
315 opRegRegImm(cUnit, kOpAsr, rLo, rlSrc.lowReg, 31);
316 opRegRegRegShift(cUnit, kOpRsub, rlResult.lowReg, rLo, rHi,
317 encodeShift(kArmAsr, magicTable[lit].shift));
318 break;
319 default:
buzbeecbd6d442012-11-17 14:11:25 -0800320 LOG(FATAL) << "Unexpected pattern: " << pattern;
buzbeeefc63692012-11-14 16:31:52 -0800321 }
322 storeValue(cUnit, rlDest, rlResult);
323 return true;
324}
325
326LIR* genRegMemCheck(CompilationUnit* cUnit, ConditionCode cCode,
327 int reg1, int base, int offset, ThrowKind kind)
328{
329 LOG(FATAL) << "Unexpected use of genRegMemCheck for Arm";
330 return NULL;
331}
332
333RegLocation genDivRemLit(CompilationUnit* cUnit, RegLocation rlDest, int reg1, int lit, bool isDiv)
334{
335 LOG(FATAL) << "Unexpected use of genDivRemLit for Arm";
336 return rlDest;
337}
338
339RegLocation genDivRem(CompilationUnit* cUnit, RegLocation rlDest, int reg1, int reg2, bool isDiv)
340{
341 LOG(FATAL) << "Unexpected use of genDivRem for Arm";
342 return rlDest;
343}
344
345bool genInlinedMinMaxInt(CompilationUnit *cUnit, CallInfo* info, bool isMin)
346{
347 DCHECK_EQ(cUnit->instructionSet, kThumb2);
348 RegLocation rlSrc1 = info->args[0];
349 RegLocation rlSrc2 = info->args[1];
350 rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
351 rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
352 RegLocation rlDest = inlineTarget(cUnit, info);
353 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
354 opRegReg(cUnit, kOpCmp, rlSrc1.lowReg, rlSrc2.lowReg);
355 opIT(cUnit, (isMin) ? kArmCondGt : kArmCondLt, "E");
356 opRegReg(cUnit, kOpMov, rlResult.lowReg, rlSrc2.lowReg);
357 opRegReg(cUnit, kOpMov, rlResult.lowReg, rlSrc1.lowReg);
358 genBarrier(cUnit);
359 storeValue(cUnit, rlDest, rlResult);
360 return true;
361}
362
363void opLea(CompilationUnit* cUnit, int rBase, int reg1, int reg2, int scale, int offset)
364{
365 LOG(FATAL) << "Unexpected use of opLea for Arm";
366}
367
368void opTlsCmp(CompilationUnit* cUnit, int offset, int val)
369{
370 LOG(FATAL) << "Unexpected use of opTlsCmp for Arm";
371}
372
373bool genInlinedCas32(CompilationUnit* cUnit, CallInfo* info, bool need_write_barrier) {
374 DCHECK_EQ(cUnit->instructionSet, kThumb2);
375 // Unused - RegLocation rlSrcUnsafe = info->args[0];
376 RegLocation rlSrcObj= info->args[1]; // Object - known non-null
377 RegLocation rlSrcOffset= info->args[2]; // long low
378 rlSrcOffset.wide = 0; // ignore high half in info->args[3]
379 RegLocation rlSrcExpected= info->args[4]; // int or Object
380 RegLocation rlSrcNewValue= info->args[5]; // int or Object
381 RegLocation rlDest = inlineTarget(cUnit, info); // boolean place for result
382
383
buzbee1bc37c62012-11-20 13:35:41 -0800384 // Release store semantics, get the barrier out of the way. TODO: revisit
385 oatGenMemBarrier(cUnit, kStoreLoad);
buzbeeefc63692012-11-14 16:31:52 -0800386
387 RegLocation rlObject = loadValue(cUnit, rlSrcObj, kCoreReg);
388 RegLocation rlNewValue = loadValue(cUnit, rlSrcNewValue, kCoreReg);
389
390 if (need_write_barrier) {
391 // Mark card for object assuming new value is stored.
392 markGCCard(cUnit, rlNewValue.lowReg, rlObject.lowReg);
393 }
394
395 RegLocation rlOffset = loadValue(cUnit, rlSrcOffset, kCoreReg);
396
397 int rPtr = oatAllocTemp(cUnit);
398 opRegRegReg(cUnit, kOpAdd, rPtr, rlObject.lowReg, rlOffset.lowReg);
399
400 // Free now unneeded rlObject and rlOffset to give more temps.
401 oatClobberSReg(cUnit, rlObject.sRegLow);
402 oatFreeTemp(cUnit, rlObject.lowReg);
403 oatClobberSReg(cUnit, rlOffset.sRegLow);
404 oatFreeTemp(cUnit, rlOffset.lowReg);
405
406 int rOldValue = oatAllocTemp(cUnit);
407 newLIR3(cUnit, kThumb2Ldrex, rOldValue, rPtr, 0); // rOldValue := [rPtr]
408
409 RegLocation rlExpected = loadValue(cUnit, rlSrcExpected, kCoreReg);
410
411 // if (rOldValue == rExpected) {
412 // [rPtr] <- rNewValue && rResult := success ? 0 : 1
413 // rResult ^= 1
414 // } else {
415 // rResult := 0
416 // }
417 opRegReg(cUnit, kOpCmp, rOldValue, rlExpected.lowReg);
418 oatFreeTemp(cUnit, rOldValue); // Now unneeded.
419 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
420 opIT(cUnit, kArmCondEq, "TE");
421 newLIR4(cUnit, kThumb2Strex, rlResult.lowReg, rlNewValue.lowReg, rPtr, 0);
422 oatFreeTemp(cUnit, rPtr); // Now unneeded.
423 opRegImm(cUnit, kOpXor, rlResult.lowReg, 1);
424 opRegReg(cUnit, kOpXor, rlResult.lowReg, rlResult.lowReg);
425
426 storeValue(cUnit, rlDest, rlResult);
427
428 return true;
429}
430
431LIR* opPcRelLoad(CompilationUnit* cUnit, int reg, LIR* target)
432{
433 return rawLIR(cUnit, cUnit->currentDalvikOffset, kThumb2LdrPcRel12, reg, 0, 0, 0, 0, target);
434}
435
436LIR* opVldm(CompilationUnit* cUnit, int rBase, int count)
437{
438 return newLIR3(cUnit, kThumb2Vldms, rBase, fr0, count);
439}
440
441LIR* opVstm(CompilationUnit* cUnit, int rBase, int count)
442{
443 return newLIR3(cUnit, kThumb2Vstms, rBase, fr0, count);
444}
445
446void genMultiplyByTwoBitMultiplier(CompilationUnit* cUnit, RegLocation rlSrc,
447 RegLocation rlResult, int lit,
448 int firstBit, int secondBit)
449{
450 opRegRegRegShift(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, rlSrc.lowReg,
451 encodeShift(kArmLsl, secondBit - firstBit));
452 if (firstBit != 0) {
453 opRegRegImm(cUnit, kOpLsl, rlResult.lowReg, rlResult.lowReg, firstBit);
454 }
455}
456
457void genDivZeroCheck(CompilationUnit* cUnit, int regLo, int regHi)
458{
459 int tReg = oatAllocTemp(cUnit);
460 newLIR4(cUnit, kThumb2OrrRRRs, tReg, regLo, regHi, 0);
461 oatFreeTemp(cUnit, tReg);
462 genCheck(cUnit, kCondEq, kThrowDivZero);
463}
464
465// Test suspend flag, return target of taken suspend branch
466LIR* opTestSuspend(CompilationUnit* cUnit, LIR* target)
467{
468 newLIR2(cUnit, kThumbSubRI8, rARM_SUSPEND, 1);
469 return opCondBranch(cUnit, (target == NULL) ? kCondEq : kCondNe, target);
470}
471
472// Decrement register and branch on condition
473LIR* opDecAndBranch(CompilationUnit* cUnit, ConditionCode cCode, int reg, LIR* target)
474{
475 // Combine sub & test using sub setflags encoding here
476 newLIR3(cUnit, kThumb2SubsRRI12, reg, reg, 1);
477 return opCondBranch(cUnit, cCode, target);
478}
479
buzbee1bc37c62012-11-20 13:35:41 -0800480void oatGenMemBarrier(CompilationUnit* cUnit, MemBarrierKind barrierKind)
buzbeeefc63692012-11-14 16:31:52 -0800481{
482#if ANDROID_SMP != 0
buzbee1bc37c62012-11-20 13:35:41 -0800483 int dmbFlavor;
484 // TODO: revisit Arm barrier kinds
485 switch (barrierKind) {
486 case kLoadStore: dmbFlavor = kSY; break;
487 case kLoadLoad: dmbFlavor = kSY; break;
488 case kStoreStore: dmbFlavor = kST; break;
489 case kStoreLoad: dmbFlavor = kSY; break;
490 default:
491 LOG(FATAL) << "Unexpected MemBarrierKind: " << barrierKind;
492 dmbFlavor = kSY; // quiet gcc.
493 break;
494 }
495 LIR* dmb = newLIR1(cUnit, kThumb2Dmb, dmbFlavor);
buzbeeefc63692012-11-14 16:31:52 -0800496 dmb->defMask = ENCODE_ALL;
497#endif
498}
499
500bool genNegLong(CompilationUnit* cUnit, RegLocation rlDest,
501 RegLocation rlSrc)
502{
503 rlSrc = loadValueWide(cUnit, rlSrc, kCoreReg);
504 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
505 int zReg = oatAllocTemp(cUnit);
506 loadConstantNoClobber(cUnit, zReg, 0);
507 // Check for destructive overlap
508 if (rlResult.lowReg == rlSrc.highReg) {
509 int tReg = oatAllocTemp(cUnit);
510 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, zReg, rlSrc.lowReg);
511 opRegRegReg(cUnit, kOpSbc, rlResult.highReg, zReg, tReg);
512 oatFreeTemp(cUnit, tReg);
513 } else {
514 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, zReg, rlSrc.lowReg);
515 opRegRegReg(cUnit, kOpSbc, rlResult.highReg, zReg, rlSrc.highReg);
516 }
517 oatFreeTemp(cUnit, zReg);
518 storeValueWide(cUnit, rlDest, rlResult);
519 return false;
520}
521
522bool genAddLong(CompilationUnit* cUnit, RegLocation rlDest,
523 RegLocation rlSrc1, RegLocation rlSrc2)
524{
525 LOG(FATAL) << "Unexpected use of genAddLong for Arm";
526 return false;
527}
528
529bool genSubLong(CompilationUnit* cUnit, RegLocation rlDest,
530 RegLocation rlSrc1, RegLocation rlSrc2)
531{
532 LOG(FATAL) << "Unexpected use of genSubLong for Arm";
533 return false;
534}
535
536bool genAndLong(CompilationUnit* cUnit, RegLocation rlDest,
537 RegLocation rlSrc1, RegLocation rlSrc2)
538{
539 LOG(FATAL) << "Unexpected use of genAndLong for Arm";
540 return false;
541}
542
543bool genOrLong(CompilationUnit* cUnit, RegLocation rlDest,
544 RegLocation rlSrc1, RegLocation rlSrc2)
545{
546 LOG(FATAL) << "Unexpected use of genOrLong for Arm";
547 return false;
548}
549
550bool genXorLong(CompilationUnit* cUnit, RegLocation rlDest,
551 RegLocation rlSrc1, RegLocation rlSrc2)
552{
553 LOG(FATAL) << "Unexpected use of genXoLong for Arm";
554 return false;
555}
556
557} // namespace art