blob: 1447aec1991bca83836151c8cd5239dea9a27a81 [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
buzbee1bc37c62012-11-20 13:35:41 -080019#include "arm_lir.h"
buzbee02031b12012-11-23 09:41:35 -080020#include "codegen_arm.h"
Brian Carlstrom641ce032013-01-31 15:21:37 -080021#include "compiler/codegen/codegen_util.h"
22#include "compiler/codegen/ralloc_util.h"
23#include "oat/runtime/oat_support_entrypoints.h"
24#include "oat_compilation_unit.h"
buzbeeefc63692012-11-14 16:31:52 -080025
26namespace art {
27
buzbee02031b12012-11-23 09:41:35 -080028LIR* ArmCodegen::OpCmpBranch(CompilationUnit* cu, ConditionCode cond, int src1,
buzbeeefc63692012-11-14 16:31:52 -080029 int src2, LIR* target)
30{
buzbeefa57c472012-11-21 12:06:18 -080031 OpRegReg(cu, kOpCmp, src1, src2);
32 return OpCondBranch(cu, cond, target);
buzbeeefc63692012-11-14 16:31:52 -080033}
34
35/*
36 * Generate a Thumb2 IT instruction, which can nullify up to
37 * four subsequent instructions based on a condition and its
38 * inverse. The condition applies to the first instruction, which
39 * is executed if the condition is met. The string "guide" consists
40 * of 0 to 3 chars, and applies to the 2nd through 4th instruction.
41 * A "T" means the instruction is executed if the condition is
42 * met, and an "E" means the instruction is executed if the condition
43 * is not met.
44 */
buzbee02031b12012-11-23 09:41:35 -080045LIR* ArmCodegen::OpIT(CompilationUnit* cu, ConditionCode ccode, const char* guide)
buzbeeefc63692012-11-14 16:31:52 -080046{
47 int mask;
buzbeeefc63692012-11-14 16:31:52 -080048 int mask3 = 0;
49 int mask2 = 0;
50 int mask1 = 0;
buzbee02031b12012-11-23 09:41:35 -080051 ArmConditionCode code = ArmConditionEncoding(ccode);
52 int cond_bit = code & 1;
53 int alt_bit = cond_bit ^ 1;
buzbeeefc63692012-11-14 16:31:52 -080054
55 //Note: case fallthroughs intentional
56 switch (strlen(guide)) {
57 case 3:
buzbeefa57c472012-11-21 12:06:18 -080058 mask1 = (guide[2] == 'T') ? cond_bit : alt_bit;
buzbeeefc63692012-11-14 16:31:52 -080059 case 2:
buzbeefa57c472012-11-21 12:06:18 -080060 mask2 = (guide[1] == 'T') ? cond_bit : alt_bit;
buzbeeefc63692012-11-14 16:31:52 -080061 case 1:
buzbeefa57c472012-11-21 12:06:18 -080062 mask3 = (guide[0] == 'T') ? cond_bit : alt_bit;
buzbeeefc63692012-11-14 16:31:52 -080063 break;
64 case 0:
65 break;
66 default:
buzbee52a77fc2012-11-20 19:50:46 -080067 LOG(FATAL) << "OAT: bad case in OpIT";
buzbeeefc63692012-11-14 16:31:52 -080068 }
69 mask = (mask3 << 3) | (mask2 << 2) | (mask1 << 1) |
70 (1 << (3 - strlen(guide)));
buzbeefa57c472012-11-21 12:06:18 -080071 return NewLIR2(cu, kThumb2It, code, mask);
buzbeeefc63692012-11-14 16:31:52 -080072}
73
74/*
75 * 64-bit 3way compare function.
76 * mov rX, #-1
77 * cmp op1hi, op2hi
78 * blt done
79 * bgt flip
80 * sub rX, op1lo, op2lo (treat as unsigned)
81 * beq done
82 * ite hi
83 * mov(hi) rX, #-1
84 * mov(!hi) rX, #1
85 * flip:
86 * neg rX
87 * done:
88 */
buzbee02031b12012-11-23 09:41:35 -080089void ArmCodegen::GenCmpLong(CompilationUnit* cu, RegLocation rl_dest, RegLocation rl_src1,
90 RegLocation rl_src2)
buzbeeefc63692012-11-14 16:31:52 -080091{
92 LIR* target1;
93 LIR* target2;
buzbeefa57c472012-11-21 12:06:18 -080094 rl_src1 = LoadValueWide(cu, rl_src1, kCoreReg);
95 rl_src2 = LoadValueWide(cu, rl_src2, kCoreReg);
96 int t_reg = AllocTemp(cu);
97 LoadConstant(cu, t_reg, -1);
98 OpRegReg(cu, kOpCmp, rl_src1.high_reg, rl_src2.high_reg);
99 LIR* branch1 = OpCondBranch(cu, kCondLt, NULL);
100 LIR* branch2 = OpCondBranch(cu, kCondGt, NULL);
101 OpRegRegReg(cu, kOpSub, t_reg, rl_src1.low_reg, rl_src2.low_reg);
102 LIR* branch3 = OpCondBranch(cu, kCondEq, NULL);
buzbeeefc63692012-11-14 16:31:52 -0800103
buzbee02031b12012-11-23 09:41:35 -0800104 OpIT(cu, kCondHi, "E");
buzbeefa57c472012-11-21 12:06:18 -0800105 NewLIR2(cu, kThumb2MovImmShift, t_reg, ModifiedImmediate(-1));
106 LoadConstant(cu, t_reg, 1);
107 GenBarrier(cu);
buzbeeefc63692012-11-14 16:31:52 -0800108
buzbeefa57c472012-11-21 12:06:18 -0800109 target2 = NewLIR0(cu, kPseudoTargetLabel);
110 OpRegReg(cu, kOpNeg, t_reg, t_reg);
buzbeeefc63692012-11-14 16:31:52 -0800111
buzbeefa57c472012-11-21 12:06:18 -0800112 target1 = NewLIR0(cu, kPseudoTargetLabel);
buzbeeefc63692012-11-14 16:31:52 -0800113
buzbeefa57c472012-11-21 12:06:18 -0800114 RegLocation rl_temp = LocCReturn(); // Just using as template, will change
115 rl_temp.low_reg = t_reg;
116 StoreValue(cu, rl_dest, rl_temp);
117 FreeTemp(cu, t_reg);
buzbeeefc63692012-11-14 16:31:52 -0800118
buzbeecbd6d442012-11-17 14:11:25 -0800119 branch1->target = target1;
120 branch2->target = target2;
buzbeeefc63692012-11-14 16:31:52 -0800121 branch3->target = branch1->target;
122}
123
buzbee4ef3e452012-12-14 13:35:28 -0800124void ArmCodegen::GenFusedLongCmpImmBranch(CompilationUnit* cu, BasicBlock* bb, RegLocation rl_src1,
125 int64_t val, ConditionCode ccode)
buzbeeefc63692012-11-14 16:31:52 -0800126{
buzbee4ef3e452012-12-14 13:35:28 -0800127 int32_t val_lo = Low32Bits(val);
128 int32_t val_hi = High32Bits(val);
129 DCHECK(ModifiedImmediate(val_lo) >= 0);
130 DCHECK(ModifiedImmediate(val_hi) >= 0);
buzbeefa57c472012-11-21 12:06:18 -0800131 LIR* label_list = cu->block_label_list;
132 LIR* taken = &label_list[bb->taken->id];
133 LIR* not_taken = &label_list[bb->fall_through->id];
buzbee4ef3e452012-12-14 13:35:28 -0800134 rl_src1 = LoadValueWide(cu, rl_src1, kCoreReg);
135 int32_t low_reg = rl_src1.low_reg;
136 int32_t high_reg = rl_src1.high_reg;
137
138 switch(ccode) {
139 case kCondEq:
buzbee4ef3e452012-12-14 13:35:28 -0800140 case kCondNe:
buzbeec7d1f912013-02-07 15:22:39 -0800141 LIR* target;
142 ConditionCode condition;
143 if (ccode == kCondEq) {
144 target = not_taken;
145 condition = kCondEq;
146 } else {
147 target = taken;
148 condition = kCondNe;
149 }
150 if (val == 0) {
151 int t_reg = AllocTemp(cu);
152 NewLIR4(cu, kThumb2OrrRRRs, t_reg, low_reg, high_reg, 0);
153 FreeTemp(cu, t_reg);
154 OpCondBranch(cu, condition, taken);
155 return;
156 }
157 OpCmpImmBranch(cu, kCondNe, high_reg, val_hi, target);
buzbee4ef3e452012-12-14 13:35:28 -0800158 break;
159 case kCondLt:
160 OpCmpImmBranch(cu, kCondLt, high_reg, val_hi, taken);
161 OpCmpImmBranch(cu, kCondGt, high_reg, val_hi, not_taken);
162 ccode = kCondCc;
163 break;
164 case kCondLe:
165 OpCmpImmBranch(cu, kCondLt, high_reg, val_hi, taken);
166 OpCmpImmBranch(cu, kCondGt, high_reg, val_hi, not_taken);
167 ccode = kCondLs;
168 break;
169 case kCondGt:
170 OpCmpImmBranch(cu, kCondGt, high_reg, val_hi, taken);
171 OpCmpImmBranch(cu, kCondLt, high_reg, val_hi, not_taken);
172 ccode = kCondHi;
173 break;
174 case kCondGe:
175 OpCmpImmBranch(cu, kCondGt, high_reg, val_hi, taken);
176 OpCmpImmBranch(cu, kCondLt, high_reg, val_hi, not_taken);
177 ccode = kCondCs;
178 break;
179 default:
180 LOG(FATAL) << "Unexpected ccode: " << ccode;
181 }
182 OpCmpImmBranch(cu, ccode, low_reg, val_lo, taken);
183}
184
buzbeef662a7c2013-02-12 16:19:43 -0800185void ArmCodegen::GenSelect(CompilationUnit* cu, BasicBlock* bb, MIR* mir)
186{
187 RegLocation rl_result;
188 RegLocation rl_src = GetSrc(cu, mir, 0);
189 RegLocation rl_dest = GetDest(cu, mir);
190 rl_src = LoadValue(cu, rl_src, kCoreReg);
191 if (mir->ssa_rep->num_uses == 1) {
192 // CONST case
193 int true_val = mir->dalvikInsn.vB;
194 int false_val = mir->dalvikInsn.vC;
195 rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
196 if ((true_val == 1) && (false_val == 0)) {
197 OpRegRegImm(cu, kOpRsub, rl_result.low_reg, rl_src.low_reg, 1);
198 OpIT(cu, kCondCc, "");
199 LoadConstant(cu, rl_result.low_reg, 0);
200 GenBarrier(cu); // Add a scheduling barrier to keep the IT shadow intact
201 } else if (InexpensiveConstantInt(true_val) && InexpensiveConstantInt(false_val)) {
202 OpRegImm(cu, kOpCmp, rl_src.low_reg, 0);
203 OpIT(cu, kCondEq, "E");
204 LoadConstant(cu, rl_result.low_reg, true_val);
205 LoadConstant(cu, rl_result.low_reg, false_val);
206 GenBarrier(cu); // Add a scheduling barrier to keep the IT shadow intact
207 } else {
208 // Unlikely case - could be tuned.
209 int t_reg1 = AllocTemp(cu);
210 int t_reg2 = AllocTemp(cu);
211 LoadConstant(cu, t_reg1, true_val);
212 LoadConstant(cu, t_reg2, false_val);
213 OpRegImm(cu, kOpCmp, rl_src.low_reg, 0);
214 OpIT(cu, kCondEq, "E");
215 OpRegCopy(cu, rl_result.low_reg, t_reg1);
216 OpRegCopy(cu, rl_result.low_reg, t_reg2);
217 GenBarrier(cu); // Add a scheduling barrier to keep the IT shadow intact
218 }
219 } else {
220 // MOVE case
221 RegLocation rl_true = cu->reg_location[mir->ssa_rep->uses[1]];
222 RegLocation rl_false = cu->reg_location[mir->ssa_rep->uses[2]];
223 rl_true = LoadValue(cu, rl_true, kCoreReg);
224 rl_false = LoadValue(cu, rl_false, kCoreReg);
225 rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
226 OpRegImm(cu, kOpCmp, rl_src.low_reg, 0);
227 OpIT(cu, kCondEq, "E");
228 LIR* l1 = OpRegCopy(cu, rl_result.low_reg, rl_true.low_reg);
229 l1->flags.is_nop = false; // Make sure this instruction isn't optimized away
230 LIR* l2 = OpRegCopy(cu, rl_result.low_reg, rl_false.low_reg);
231 l2->flags.is_nop = false; // Make sure this instruction isn't optimized away
232 GenBarrier(cu); // Add a scheduling barrier to keep the IT shadow intact
233 }
234 StoreValue(cu, rl_dest, rl_result);
235}
buzbee4ef3e452012-12-14 13:35:28 -0800236
237void ArmCodegen::GenFusedLongCmpBranch(CompilationUnit* cu, BasicBlock* bb, MIR* mir)
238{
buzbeefa57c472012-11-21 12:06:18 -0800239 RegLocation rl_src1 = GetSrcWide(cu, mir, 0);
240 RegLocation rl_src2 = GetSrcWide(cu, mir, 2);
buzbee4ef3e452012-12-14 13:35:28 -0800241 // Normalize such that if either operand is constant, src2 will be constant.
242 ConditionCode ccode = static_cast<ConditionCode>(mir->dalvikInsn.arg[0]);
243 if (rl_src1.is_const) {
244 RegLocation rl_temp = rl_src1;
245 rl_src1 = rl_src2;
246 rl_src2 = rl_temp;
247 ccode = FlipComparisonOrder(ccode);
248 }
249 if (rl_src2.is_const) {
250 RegLocation rl_temp = UpdateLocWide(cu, rl_src2);
251 // Do special compare/branch against simple const operand if not already in registers.
252 int64_t val = ConstantValueWide(cu, rl_src2);
253 if ((rl_temp.location != kLocPhysReg) &&
254 ((ModifiedImmediate(Low32Bits(val)) >= 0) && (ModifiedImmediate(High32Bits(val)) >= 0))) {
255 GenFusedLongCmpImmBranch(cu, bb, rl_src1, val, ccode);
256 return;
257 }
258 }
259 LIR* label_list = cu->block_label_list;
260 LIR* taken = &label_list[bb->taken->id];
261 LIR* not_taken = &label_list[bb->fall_through->id];
buzbeefa57c472012-11-21 12:06:18 -0800262 rl_src1 = LoadValueWide(cu, rl_src1, kCoreReg);
263 rl_src2 = LoadValueWide(cu, rl_src2, kCoreReg);
buzbeefa57c472012-11-21 12:06:18 -0800264 OpRegReg(cu, kOpCmp, rl_src1.high_reg, rl_src2.high_reg);
buzbeeefc63692012-11-14 16:31:52 -0800265 switch(ccode) {
266 case kCondEq:
buzbeefa57c472012-11-21 12:06:18 -0800267 OpCondBranch(cu, kCondNe, not_taken);
buzbeeefc63692012-11-14 16:31:52 -0800268 break;
269 case kCondNe:
buzbeefa57c472012-11-21 12:06:18 -0800270 OpCondBranch(cu, kCondNe, taken);
buzbeeefc63692012-11-14 16:31:52 -0800271 break;
272 case kCondLt:
buzbeefa57c472012-11-21 12:06:18 -0800273 OpCondBranch(cu, kCondLt, taken);
274 OpCondBranch(cu, kCondGt, not_taken);
buzbeeefc63692012-11-14 16:31:52 -0800275 ccode = kCondCc;
276 break;
277 case kCondLe:
buzbeefa57c472012-11-21 12:06:18 -0800278 OpCondBranch(cu, kCondLt, taken);
279 OpCondBranch(cu, kCondGt, not_taken);
buzbeeefc63692012-11-14 16:31:52 -0800280 ccode = kCondLs;
281 break;
282 case kCondGt:
buzbeefa57c472012-11-21 12:06:18 -0800283 OpCondBranch(cu, kCondGt, taken);
284 OpCondBranch(cu, kCondLt, not_taken);
buzbeeefc63692012-11-14 16:31:52 -0800285 ccode = kCondHi;
286 break;
287 case kCondGe:
buzbeefa57c472012-11-21 12:06:18 -0800288 OpCondBranch(cu, kCondGt, taken);
289 OpCondBranch(cu, kCondLt, not_taken);
buzbeeefc63692012-11-14 16:31:52 -0800290 ccode = kCondCs;
291 break;
292 default:
buzbeecbd6d442012-11-17 14:11:25 -0800293 LOG(FATAL) << "Unexpected ccode: " << ccode;
buzbeeefc63692012-11-14 16:31:52 -0800294 }
buzbeefa57c472012-11-21 12:06:18 -0800295 OpRegReg(cu, kOpCmp, rl_src1.low_reg, rl_src2.low_reg);
296 OpCondBranch(cu, ccode, taken);
buzbeeefc63692012-11-14 16:31:52 -0800297}
298
299/*
300 * Generate a register comparison to an immediate and branch. Caller
301 * is responsible for setting branch target field.
302 */
buzbee02031b12012-11-23 09:41:35 -0800303LIR* ArmCodegen::OpCmpImmBranch(CompilationUnit* cu, ConditionCode cond, int reg, int check_value,
304 LIR* target)
buzbeeefc63692012-11-14 16:31:52 -0800305{
306 LIR* branch;
buzbeefa57c472012-11-21 12:06:18 -0800307 int mod_imm;
308 ArmConditionCode arm_cond = ArmConditionEncoding(cond);
309 if ((ARM_LOWREG(reg)) && (check_value == 0) &&
310 ((arm_cond == kArmCondEq) || (arm_cond == kArmCondNe))) {
311 branch = NewLIR2(cu, (arm_cond == kArmCondEq) ? kThumb2Cbz : kThumb2Cbnz,
buzbeeefc63692012-11-14 16:31:52 -0800312 reg, 0);
313 } else {
buzbeefa57c472012-11-21 12:06:18 -0800314 mod_imm = ModifiedImmediate(check_value);
315 if (ARM_LOWREG(reg) && ((check_value & 0xff) == check_value)) {
316 NewLIR2(cu, kThumbCmpRI8, reg, check_value);
317 } else if (mod_imm >= 0) {
buzbee4ef3e452012-12-14 13:35:28 -0800318 NewLIR2(cu, kThumb2CmpRI12, reg, mod_imm);
buzbeeefc63692012-11-14 16:31:52 -0800319 } else {
buzbeefa57c472012-11-21 12:06:18 -0800320 int t_reg = AllocTemp(cu);
321 LoadConstant(cu, t_reg, check_value);
322 OpRegReg(cu, kOpCmp, reg, t_reg);
buzbeeefc63692012-11-14 16:31:52 -0800323 }
buzbeefa57c472012-11-21 12:06:18 -0800324 branch = NewLIR2(cu, kThumbBCond, 0, arm_cond);
buzbeeefc63692012-11-14 16:31:52 -0800325 }
326 branch->target = target;
327 return branch;
328}
buzbee02031b12012-11-23 09:41:35 -0800329
330LIR* ArmCodegen::OpRegCopyNoInsert(CompilationUnit* cu, int r_dest, int r_src)
buzbeeefc63692012-11-14 16:31:52 -0800331{
332 LIR* res;
333 int opcode;
buzbeefa57c472012-11-21 12:06:18 -0800334 if (ARM_FPREG(r_dest) || ARM_FPREG(r_src))
buzbee02031b12012-11-23 09:41:35 -0800335 return OpFpRegCopy(cu, r_dest, r_src);
buzbeefa57c472012-11-21 12:06:18 -0800336 if (ARM_LOWREG(r_dest) && ARM_LOWREG(r_src))
buzbeeefc63692012-11-14 16:31:52 -0800337 opcode = kThumbMovRR;
buzbeefa57c472012-11-21 12:06:18 -0800338 else if (!ARM_LOWREG(r_dest) && !ARM_LOWREG(r_src))
buzbeeefc63692012-11-14 16:31:52 -0800339 opcode = kThumbMovRR_H2H;
buzbeefa57c472012-11-21 12:06:18 -0800340 else if (ARM_LOWREG(r_dest))
buzbeeefc63692012-11-14 16:31:52 -0800341 opcode = kThumbMovRR_H2L;
342 else
343 opcode = kThumbMovRR_L2H;
buzbeefa57c472012-11-21 12:06:18 -0800344 res = RawLIR(cu, cu->current_dalvik_offset, opcode, r_dest, r_src);
345 if (!(cu->disable_opt & (1 << kSafeOptimizations)) && r_dest == r_src) {
346 res->flags.is_nop = true;
buzbeeefc63692012-11-14 16:31:52 -0800347 }
348 return res;
349}
350
buzbee02031b12012-11-23 09:41:35 -0800351LIR* ArmCodegen::OpRegCopy(CompilationUnit* cu, int r_dest, int r_src)
buzbeeefc63692012-11-14 16:31:52 -0800352{
buzbeefa57c472012-11-21 12:06:18 -0800353 LIR* res = OpRegCopyNoInsert(cu, r_dest, r_src);
354 AppendLIR(cu, res);
buzbeeefc63692012-11-14 16:31:52 -0800355 return res;
356}
357
buzbee02031b12012-11-23 09:41:35 -0800358void ArmCodegen::OpRegCopyWide(CompilationUnit* cu, int dest_lo, int dest_hi, int src_lo,
359 int src_hi)
buzbeeefc63692012-11-14 16:31:52 -0800360{
buzbeefa57c472012-11-21 12:06:18 -0800361 bool dest_fp = ARM_FPREG(dest_lo) && ARM_FPREG(dest_hi);
362 bool src_fp = ARM_FPREG(src_lo) && ARM_FPREG(src_hi);
363 DCHECK_EQ(ARM_FPREG(src_lo), ARM_FPREG(src_hi));
364 DCHECK_EQ(ARM_FPREG(dest_lo), ARM_FPREG(dest_hi));
365 if (dest_fp) {
366 if (src_fp) {
367 OpRegCopy(cu, S2d(dest_lo, dest_hi), S2d(src_lo, src_hi));
buzbeeefc63692012-11-14 16:31:52 -0800368 } else {
buzbeefa57c472012-11-21 12:06:18 -0800369 NewLIR3(cu, kThumb2Fmdrr, S2d(dest_lo, dest_hi), src_lo, src_hi);
buzbeeefc63692012-11-14 16:31:52 -0800370 }
371 } else {
buzbeefa57c472012-11-21 12:06:18 -0800372 if (src_fp) {
373 NewLIR3(cu, kThumb2Fmrrd, dest_lo, dest_hi, S2d(src_lo, src_hi));
buzbeeefc63692012-11-14 16:31:52 -0800374 } else {
375 // Handle overlap
buzbeefa57c472012-11-21 12:06:18 -0800376 if (src_hi == dest_lo) {
377 OpRegCopy(cu, dest_hi, src_hi);
378 OpRegCopy(cu, dest_lo, src_lo);
buzbeeefc63692012-11-14 16:31:52 -0800379 } else {
buzbeefa57c472012-11-21 12:06:18 -0800380 OpRegCopy(cu, dest_lo, src_lo);
381 OpRegCopy(cu, dest_hi, src_hi);
buzbeeefc63692012-11-14 16:31:52 -0800382 }
383 }
384 }
385}
386
387// Table of magic divisors
buzbeeefc63692012-11-14 16:31:52 -0800388struct MagicTable {
389 uint32_t magic;
390 uint32_t shift;
391 DividePattern pattern;
392};
393
buzbeefa57c472012-11-21 12:06:18 -0800394static const MagicTable magic_table[] = {
buzbeeefc63692012-11-14 16:31:52 -0800395 {0, 0, DivideNone}, // 0
396 {0, 0, DivideNone}, // 1
397 {0, 0, DivideNone}, // 2
398 {0x55555556, 0, Divide3}, // 3
399 {0, 0, DivideNone}, // 4
400 {0x66666667, 1, Divide5}, // 5
401 {0x2AAAAAAB, 0, Divide3}, // 6
402 {0x92492493, 2, Divide7}, // 7
403 {0, 0, DivideNone}, // 8
404 {0x38E38E39, 1, Divide5}, // 9
405 {0x66666667, 2, Divide5}, // 10
406 {0x2E8BA2E9, 1, Divide5}, // 11
407 {0x2AAAAAAB, 1, Divide5}, // 12
408 {0x4EC4EC4F, 2, Divide5}, // 13
409 {0x92492493, 3, Divide7}, // 14
410 {0x88888889, 3, Divide7}, // 15
411};
412
413// Integer division by constant via reciprocal multiply (Hacker's Delight, 10-4)
buzbee02031b12012-11-23 09:41:35 -0800414bool ArmCodegen::SmallLiteralDivide(CompilationUnit* cu, Instruction::Code dalvik_opcode,
415 RegLocation rl_src, RegLocation rl_dest, int lit)
buzbeeefc63692012-11-14 16:31:52 -0800416{
buzbeefa57c472012-11-21 12:06:18 -0800417 if ((lit < 0) || (lit >= static_cast<int>(sizeof(magic_table)/sizeof(magic_table[0])))) {
buzbeeefc63692012-11-14 16:31:52 -0800418 return false;
419 }
buzbeefa57c472012-11-21 12:06:18 -0800420 DividePattern pattern = magic_table[lit].pattern;
buzbeeefc63692012-11-14 16:31:52 -0800421 if (pattern == DivideNone) {
422 return false;
423 }
424 // Tuning: add rem patterns
buzbeefa57c472012-11-21 12:06:18 -0800425 if (dalvik_opcode != Instruction::DIV_INT_LIT8) {
buzbeeefc63692012-11-14 16:31:52 -0800426 return false;
427 }
428
buzbeefa57c472012-11-21 12:06:18 -0800429 int r_magic = AllocTemp(cu);
430 LoadConstant(cu, r_magic, magic_table[lit].magic);
431 rl_src = LoadValue(cu, rl_src, kCoreReg);
432 RegLocation rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
433 int r_hi = AllocTemp(cu);
434 int r_lo = AllocTemp(cu);
435 NewLIR4(cu, kThumb2Smull, r_lo, r_hi, r_magic, rl_src.low_reg);
buzbeeefc63692012-11-14 16:31:52 -0800436 switch(pattern) {
437 case Divide3:
buzbeefa57c472012-11-21 12:06:18 -0800438 OpRegRegRegShift(cu, kOpSub, rl_result.low_reg, r_hi,
439 rl_src.low_reg, EncodeShift(kArmAsr, 31));
buzbeeefc63692012-11-14 16:31:52 -0800440 break;
441 case Divide5:
buzbeefa57c472012-11-21 12:06:18 -0800442 OpRegRegImm(cu, kOpAsr, r_lo, rl_src.low_reg, 31);
443 OpRegRegRegShift(cu, kOpRsub, rl_result.low_reg, r_lo, r_hi,
444 EncodeShift(kArmAsr, magic_table[lit].shift));
buzbeeefc63692012-11-14 16:31:52 -0800445 break;
446 case Divide7:
buzbeefa57c472012-11-21 12:06:18 -0800447 OpRegReg(cu, kOpAdd, r_hi, rl_src.low_reg);
448 OpRegRegImm(cu, kOpAsr, r_lo, rl_src.low_reg, 31);
449 OpRegRegRegShift(cu, kOpRsub, rl_result.low_reg, r_lo, r_hi,
450 EncodeShift(kArmAsr, magic_table[lit].shift));
buzbeeefc63692012-11-14 16:31:52 -0800451 break;
452 default:
buzbeecbd6d442012-11-17 14:11:25 -0800453 LOG(FATAL) << "Unexpected pattern: " << pattern;
buzbeeefc63692012-11-14 16:31:52 -0800454 }
buzbeefa57c472012-11-21 12:06:18 -0800455 StoreValue(cu, rl_dest, rl_result);
buzbeeefc63692012-11-14 16:31:52 -0800456 return true;
457}
458
buzbee02031b12012-11-23 09:41:35 -0800459LIR* ArmCodegen::GenRegMemCheck(CompilationUnit* cu, ConditionCode c_code,
buzbeeefc63692012-11-14 16:31:52 -0800460 int reg1, int base, int offset, ThrowKind kind)
461{
buzbee52a77fc2012-11-20 19:50:46 -0800462 LOG(FATAL) << "Unexpected use of GenRegMemCheck for Arm";
buzbeeefc63692012-11-14 16:31:52 -0800463 return NULL;
464}
465
buzbee02031b12012-11-23 09:41:35 -0800466RegLocation ArmCodegen::GenDivRemLit(CompilationUnit* cu, RegLocation rl_dest, int reg1, int lit,
467 bool is_div)
buzbeeefc63692012-11-14 16:31:52 -0800468{
buzbee52a77fc2012-11-20 19:50:46 -0800469 LOG(FATAL) << "Unexpected use of GenDivRemLit for Arm";
buzbeefa57c472012-11-21 12:06:18 -0800470 return rl_dest;
buzbeeefc63692012-11-14 16:31:52 -0800471}
472
buzbee02031b12012-11-23 09:41:35 -0800473RegLocation ArmCodegen::GenDivRem(CompilationUnit* cu, RegLocation rl_dest, int reg1, int reg2,
474 bool is_div)
buzbeeefc63692012-11-14 16:31:52 -0800475{
buzbee52a77fc2012-11-20 19:50:46 -0800476 LOG(FATAL) << "Unexpected use of GenDivRem for Arm";
buzbeefa57c472012-11-21 12:06:18 -0800477 return rl_dest;
buzbeeefc63692012-11-14 16:31:52 -0800478}
479
buzbee02031b12012-11-23 09:41:35 -0800480bool ArmCodegen::GenInlinedMinMaxInt(CompilationUnit *cu, CallInfo* info, bool is_min)
buzbeeefc63692012-11-14 16:31:52 -0800481{
buzbeefa57c472012-11-21 12:06:18 -0800482 DCHECK_EQ(cu->instruction_set, kThumb2);
483 RegLocation rl_src1 = info->args[0];
484 RegLocation rl_src2 = info->args[1];
485 rl_src1 = LoadValue(cu, rl_src1, kCoreReg);
486 rl_src2 = LoadValue(cu, rl_src2, kCoreReg);
487 RegLocation rl_dest = InlineTarget(cu, info);
488 RegLocation rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
489 OpRegReg(cu, kOpCmp, rl_src1.low_reg, rl_src2.low_reg);
buzbee02031b12012-11-23 09:41:35 -0800490 OpIT(cu, (is_min) ? kCondGt : kCondLt, "E");
buzbeefa57c472012-11-21 12:06:18 -0800491 OpRegReg(cu, kOpMov, rl_result.low_reg, rl_src2.low_reg);
492 OpRegReg(cu, kOpMov, rl_result.low_reg, rl_src1.low_reg);
493 GenBarrier(cu);
494 StoreValue(cu, rl_dest, rl_result);
buzbeeefc63692012-11-14 16:31:52 -0800495 return true;
496}
497
buzbee02031b12012-11-23 09:41:35 -0800498void ArmCodegen::OpLea(CompilationUnit* cu, int rBase, int reg1, int reg2, int scale, int offset)
buzbeeefc63692012-11-14 16:31:52 -0800499{
buzbee52a77fc2012-11-20 19:50:46 -0800500 LOG(FATAL) << "Unexpected use of OpLea for Arm";
buzbeeefc63692012-11-14 16:31:52 -0800501}
502
buzbee02031b12012-11-23 09:41:35 -0800503void ArmCodegen::OpTlsCmp(CompilationUnit* cu, int offset, int val)
buzbeeefc63692012-11-14 16:31:52 -0800504{
buzbee52a77fc2012-11-20 19:50:46 -0800505 LOG(FATAL) << "Unexpected use of OpTlsCmp for Arm";
buzbeeefc63692012-11-14 16:31:52 -0800506}
507
buzbee02031b12012-11-23 09:41:35 -0800508bool ArmCodegen::GenInlinedCas32(CompilationUnit* cu, CallInfo* info, bool need_write_barrier) {
buzbeefa57c472012-11-21 12:06:18 -0800509 DCHECK_EQ(cu->instruction_set, kThumb2);
510 // Unused - RegLocation rl_src_unsafe = info->args[0];
511 RegLocation rl_src_obj= info->args[1]; // Object - known non-null
512 RegLocation rl_src_offset= info->args[2]; // long low
513 rl_src_offset.wide = 0; // ignore high half in info->args[3]
514 RegLocation rl_src_expected= info->args[4]; // int or Object
515 RegLocation rl_src_new_value= info->args[5]; // int or Object
516 RegLocation rl_dest = InlineTarget(cu, info); // boolean place for result
buzbeeefc63692012-11-14 16:31:52 -0800517
518
buzbee1bc37c62012-11-20 13:35:41 -0800519 // Release store semantics, get the barrier out of the way. TODO: revisit
buzbeefa57c472012-11-21 12:06:18 -0800520 GenMemBarrier(cu, kStoreLoad);
buzbeeefc63692012-11-14 16:31:52 -0800521
buzbeefa57c472012-11-21 12:06:18 -0800522 RegLocation rl_object = LoadValue(cu, rl_src_obj, kCoreReg);
523 RegLocation rl_new_value = LoadValue(cu, rl_src_new_value, kCoreReg);
buzbeeefc63692012-11-14 16:31:52 -0800524
buzbee6a791b22013-02-07 05:35:08 -0800525 if (need_write_barrier && !IsConstantNullRef(cu, rl_new_value)) {
buzbeeefc63692012-11-14 16:31:52 -0800526 // Mark card for object assuming new value is stored.
buzbeefa57c472012-11-21 12:06:18 -0800527 MarkGCCard(cu, rl_new_value.low_reg, rl_object.low_reg);
buzbeeefc63692012-11-14 16:31:52 -0800528 }
529
buzbeefa57c472012-11-21 12:06:18 -0800530 RegLocation rl_offset = LoadValue(cu, rl_src_offset, kCoreReg);
buzbeeefc63692012-11-14 16:31:52 -0800531
buzbeefa57c472012-11-21 12:06:18 -0800532 int r_ptr = AllocTemp(cu);
533 OpRegRegReg(cu, kOpAdd, r_ptr, rl_object.low_reg, rl_offset.low_reg);
buzbeeefc63692012-11-14 16:31:52 -0800534
buzbeefa57c472012-11-21 12:06:18 -0800535 // Free now unneeded rl_object and rl_offset to give more temps.
536 ClobberSReg(cu, rl_object.s_reg_low);
537 FreeTemp(cu, rl_object.low_reg);
538 ClobberSReg(cu, rl_offset.s_reg_low);
539 FreeTemp(cu, rl_offset.low_reg);
buzbeeefc63692012-11-14 16:31:52 -0800540
buzbeefa57c472012-11-21 12:06:18 -0800541 int r_old_value = AllocTemp(cu);
542 NewLIR3(cu, kThumb2Ldrex, r_old_value, r_ptr, 0); // r_old_value := [r_ptr]
buzbeeefc63692012-11-14 16:31:52 -0800543
buzbeefa57c472012-11-21 12:06:18 -0800544 RegLocation rl_expected = LoadValue(cu, rl_src_expected, kCoreReg);
buzbeeefc63692012-11-14 16:31:52 -0800545
buzbeefa57c472012-11-21 12:06:18 -0800546 // if (r_old_value == rExpected) {
547 // [r_ptr] <- r_new_value && r_result := success ? 0 : 1
548 // r_result ^= 1
buzbeeefc63692012-11-14 16:31:52 -0800549 // } else {
buzbeefa57c472012-11-21 12:06:18 -0800550 // r_result := 0
buzbeeefc63692012-11-14 16:31:52 -0800551 // }
buzbeefa57c472012-11-21 12:06:18 -0800552 OpRegReg(cu, kOpCmp, r_old_value, rl_expected.low_reg);
553 FreeTemp(cu, r_old_value); // Now unneeded.
554 RegLocation rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
buzbee02031b12012-11-23 09:41:35 -0800555 OpIT(cu, kCondEq, "TE");
buzbeefa57c472012-11-21 12:06:18 -0800556 NewLIR4(cu, kThumb2Strex, rl_result.low_reg, rl_new_value.low_reg, r_ptr, 0);
557 FreeTemp(cu, r_ptr); // Now unneeded.
558 OpRegImm(cu, kOpXor, rl_result.low_reg, 1);
559 OpRegReg(cu, kOpXor, rl_result.low_reg, rl_result.low_reg);
buzbeeefc63692012-11-14 16:31:52 -0800560
buzbeefa57c472012-11-21 12:06:18 -0800561 StoreValue(cu, rl_dest, rl_result);
buzbeeefc63692012-11-14 16:31:52 -0800562
563 return true;
564}
565
buzbee02031b12012-11-23 09:41:35 -0800566LIR* ArmCodegen::OpPcRelLoad(CompilationUnit* cu, int reg, LIR* target)
buzbeeefc63692012-11-14 16:31:52 -0800567{
buzbeefa57c472012-11-21 12:06:18 -0800568 return RawLIR(cu, cu->current_dalvik_offset, kThumb2LdrPcRel12, reg, 0, 0, 0, 0, target);
buzbeeefc63692012-11-14 16:31:52 -0800569}
570
buzbee02031b12012-11-23 09:41:35 -0800571LIR* ArmCodegen::OpVldm(CompilationUnit* cu, int rBase, int count)
buzbeeefc63692012-11-14 16:31:52 -0800572{
buzbeefa57c472012-11-21 12:06:18 -0800573 return NewLIR3(cu, kThumb2Vldms, rBase, fr0, count);
buzbeeefc63692012-11-14 16:31:52 -0800574}
575
buzbee02031b12012-11-23 09:41:35 -0800576LIR* ArmCodegen::OpVstm(CompilationUnit* cu, int rBase, int count)
buzbeeefc63692012-11-14 16:31:52 -0800577{
buzbeefa57c472012-11-21 12:06:18 -0800578 return NewLIR3(cu, kThumb2Vstms, rBase, fr0, count);
buzbeeefc63692012-11-14 16:31:52 -0800579}
580
buzbee02031b12012-11-23 09:41:35 -0800581void ArmCodegen::GenMultiplyByTwoBitMultiplier(CompilationUnit* cu, RegLocation rl_src,
582 RegLocation rl_result, int lit,
583 int first_bit, int second_bit)
buzbeeefc63692012-11-14 16:31:52 -0800584{
buzbeefa57c472012-11-21 12:06:18 -0800585 OpRegRegRegShift(cu, kOpAdd, rl_result.low_reg, rl_src.low_reg, rl_src.low_reg,
586 EncodeShift(kArmLsl, second_bit - first_bit));
587 if (first_bit != 0) {
588 OpRegRegImm(cu, kOpLsl, rl_result.low_reg, rl_result.low_reg, first_bit);
buzbeeefc63692012-11-14 16:31:52 -0800589 }
590}
591
buzbee02031b12012-11-23 09:41:35 -0800592void ArmCodegen::GenDivZeroCheck(CompilationUnit* cu, int reg_lo, int reg_hi)
buzbeeefc63692012-11-14 16:31:52 -0800593{
buzbeefa57c472012-11-21 12:06:18 -0800594 int t_reg = AllocTemp(cu);
595 NewLIR4(cu, kThumb2OrrRRRs, t_reg, reg_lo, reg_hi, 0);
596 FreeTemp(cu, t_reg);
597 GenCheck(cu, kCondEq, kThrowDivZero);
buzbeeefc63692012-11-14 16:31:52 -0800598}
599
600// Test suspend flag, return target of taken suspend branch
buzbee02031b12012-11-23 09:41:35 -0800601LIR* ArmCodegen::OpTestSuspend(CompilationUnit* cu, LIR* target)
buzbeeefc63692012-11-14 16:31:52 -0800602{
buzbeefa57c472012-11-21 12:06:18 -0800603 NewLIR2(cu, kThumbSubRI8, rARM_SUSPEND, 1);
604 return OpCondBranch(cu, (target == NULL) ? kCondEq : kCondNe, target);
buzbeeefc63692012-11-14 16:31:52 -0800605}
606
607// Decrement register and branch on condition
buzbee02031b12012-11-23 09:41:35 -0800608LIR* ArmCodegen::OpDecAndBranch(CompilationUnit* cu, ConditionCode c_code, int reg, LIR* target)
buzbeeefc63692012-11-14 16:31:52 -0800609{
610 // Combine sub & test using sub setflags encoding here
buzbeefa57c472012-11-21 12:06:18 -0800611 NewLIR3(cu, kThumb2SubsRRI12, reg, reg, 1);
612 return OpCondBranch(cu, c_code, target);
buzbeeefc63692012-11-14 16:31:52 -0800613}
614
buzbee02031b12012-11-23 09:41:35 -0800615void ArmCodegen::GenMemBarrier(CompilationUnit* cu, MemBarrierKind barrier_kind)
buzbeeefc63692012-11-14 16:31:52 -0800616{
617#if ANDROID_SMP != 0
buzbeefa57c472012-11-21 12:06:18 -0800618 int dmb_flavor;
buzbee1bc37c62012-11-20 13:35:41 -0800619 // TODO: revisit Arm barrier kinds
buzbeefa57c472012-11-21 12:06:18 -0800620 switch (barrier_kind) {
621 case kLoadStore: dmb_flavor = kSY; break;
622 case kLoadLoad: dmb_flavor = kSY; break;
623 case kStoreStore: dmb_flavor = kST; break;
624 case kStoreLoad: dmb_flavor = kSY; break;
buzbee1bc37c62012-11-20 13:35:41 -0800625 default:
buzbeefa57c472012-11-21 12:06:18 -0800626 LOG(FATAL) << "Unexpected MemBarrierKind: " << barrier_kind;
627 dmb_flavor = kSY; // quiet gcc.
buzbee1bc37c62012-11-20 13:35:41 -0800628 break;
629 }
buzbeefa57c472012-11-21 12:06:18 -0800630 LIR* dmb = NewLIR1(cu, kThumb2Dmb, dmb_flavor);
631 dmb->def_mask = ENCODE_ALL;
buzbeeefc63692012-11-14 16:31:52 -0800632#endif
633}
634
buzbeea5954be2013-02-07 10:41:40 -0800635void ArmCodegen::GenNegLong(CompilationUnit* cu, RegLocation rl_dest, RegLocation rl_src)
buzbeeefc63692012-11-14 16:31:52 -0800636{
buzbeefa57c472012-11-21 12:06:18 -0800637 rl_src = LoadValueWide(cu, rl_src, kCoreReg);
638 RegLocation rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
639 int z_reg = AllocTemp(cu);
640 LoadConstantNoClobber(cu, z_reg, 0);
buzbeeefc63692012-11-14 16:31:52 -0800641 // Check for destructive overlap
buzbeefa57c472012-11-21 12:06:18 -0800642 if (rl_result.low_reg == rl_src.high_reg) {
643 int t_reg = AllocTemp(cu);
644 OpRegRegReg(cu, kOpSub, rl_result.low_reg, z_reg, rl_src.low_reg);
645 OpRegRegReg(cu, kOpSbc, rl_result.high_reg, z_reg, t_reg);
646 FreeTemp(cu, t_reg);
buzbeeefc63692012-11-14 16:31:52 -0800647 } else {
buzbeefa57c472012-11-21 12:06:18 -0800648 OpRegRegReg(cu, kOpSub, rl_result.low_reg, z_reg, rl_src.low_reg);
649 OpRegRegReg(cu, kOpSbc, rl_result.high_reg, z_reg, rl_src.high_reg);
buzbeeefc63692012-11-14 16:31:52 -0800650 }
buzbeefa57c472012-11-21 12:06:18 -0800651 FreeTemp(cu, z_reg);
652 StoreValueWide(cu, rl_dest, rl_result);
buzbeeefc63692012-11-14 16:31:52 -0800653}
654
buzbee4ef3e452012-12-14 13:35:28 -0800655
656 /*
657 * Check to see if a result pair has a misaligned overlap with an operand pair. This
658 * is not usual for dx to generate, but it is legal (for now). In a future rev of
659 * dex, we'll want to make this case illegal.
660 */
661static bool BadOverlap(CompilationUnit* cu, RegLocation rl_src, RegLocation rl_dest)
662{
663 DCHECK(rl_src.wide);
664 DCHECK(rl_dest.wide);
665 return (abs(SRegToVReg(cu, rl_src.s_reg_low) - SRegToVReg(cu, rl_dest.s_reg_low)) == 1);
666}
667
668void ArmCodegen::GenMulLong(CompilationUnit* cu, RegLocation rl_dest, RegLocation rl_src1,
669 RegLocation rl_src2)
670{
671 /*
672 * To pull off inline multiply, we have a worst-case requirement of 8 temporary
673 * registers. Normally for Arm, we get 5. We can get to 6 by including
674 * lr in the temp set. The only problematic case is all operands and result are
675 * distinct, and none have been promoted. In that case, we can succeed by aggressively
676 * freeing operand temp registers after they are no longer needed. All other cases
677 * can proceed normally. We'll just punt on the case of the result having a misaligned
678 * overlap with either operand and send that case to a runtime handler.
679 */
680 RegLocation rl_result;
681 if (BadOverlap(cu, rl_src1, rl_dest) || (BadOverlap(cu, rl_src2, rl_dest))) {
682 int func_offset = ENTRYPOINT_OFFSET(pLmul);
683 FlushAllRegs(cu);
684 CallRuntimeHelperRegLocationRegLocation(cu, func_offset, rl_src1, rl_src2, false);
685 rl_result = GetReturnWide(cu, false);
686 StoreValueWide(cu, rl_dest, rl_result);
687 return;
688 }
689 // Temporarily add LR to the temp pool, and assign it to tmp1
690 MarkTemp(cu, rARM_LR);
691 FreeTemp(cu, rARM_LR);
692 int tmp1 = rARM_LR;
693 LockTemp(cu, rARM_LR);
694
695 rl_src1 = LoadValueWide(cu, rl_src1, kCoreReg);
696 rl_src2 = LoadValueWide(cu, rl_src2, kCoreReg);
697
698 bool special_case = true;
699 // If operands are the same, or any pair has been promoted we're not the special case.
700 if ((rl_src1.s_reg_low == rl_src2.s_reg_low) ||
701 (!IsTemp(cu, rl_src1.low_reg) && !IsTemp(cu, rl_src1.high_reg)) ||
702 (!IsTemp(cu, rl_src2.low_reg) && !IsTemp(cu, rl_src2.high_reg))) {
703 special_case = false;
704 }
705 // Tuning: if rl_dest has been promoted and is *not* either operand, could use directly.
706 int res_lo = AllocTemp(cu);
707 int res_hi;
708 if (rl_src1.low_reg == rl_src2.low_reg) {
709 res_hi = AllocTemp(cu);
710 NewLIR3(cu, kThumb2MulRRR, tmp1, rl_src1.low_reg, rl_src1.high_reg);
711 NewLIR4(cu, kThumb2Umull, res_lo, res_hi, rl_src1.low_reg, rl_src1.low_reg);
712 OpRegRegRegShift(cu, kOpAdd, res_hi, res_hi, tmp1, EncodeShift(kArmLsl, 1));
713 } else {
714 // In the special case, all temps are now allocated
715 NewLIR3(cu, kThumb2MulRRR, tmp1, rl_src2.low_reg, rl_src1.high_reg);
716 if (special_case) {
717 DCHECK_NE(rl_src1.low_reg, rl_src2.low_reg);
718 DCHECK_NE(rl_src1.high_reg, rl_src2.high_reg);
719 FreeTemp(cu, rl_src1.high_reg);
720 }
721 res_hi = AllocTemp(cu);
722
723 NewLIR4(cu, kThumb2Umull, res_lo, res_hi, rl_src2.low_reg, rl_src1.low_reg);
724 NewLIR4(cu, kThumb2Mla, tmp1, rl_src1.low_reg, rl_src2.high_reg, tmp1);
725 NewLIR4(cu, kThumb2AddRRR, res_hi, tmp1, res_hi, 0);
726 if (special_case) {
727 FreeTemp(cu, rl_src1.low_reg);
728 Clobber(cu, rl_src1.low_reg);
729 Clobber(cu, rl_src1.high_reg);
730 }
731 }
732 FreeTemp(cu, tmp1);
733 rl_result = GetReturnWide(cu, false); // Just using as a template.
734 rl_result.low_reg = res_lo;
735 rl_result.high_reg = res_hi;
736 StoreValueWide(cu, rl_dest, rl_result);
737 // Now, restore lr to its non-temp status.
738 Clobber(cu, rARM_LR);
739 UnmarkTemp(cu, rARM_LR);
740}
741
buzbeea5954be2013-02-07 10:41:40 -0800742void ArmCodegen::GenAddLong(CompilationUnit* cu, RegLocation rl_dest, RegLocation rl_src1,
buzbee02031b12012-11-23 09:41:35 -0800743 RegLocation rl_src2)
buzbeeefc63692012-11-14 16:31:52 -0800744{
buzbee52a77fc2012-11-20 19:50:46 -0800745 LOG(FATAL) << "Unexpected use of GenAddLong for Arm";
buzbeeefc63692012-11-14 16:31:52 -0800746}
747
buzbeea5954be2013-02-07 10:41:40 -0800748void ArmCodegen::GenSubLong(CompilationUnit* cu, RegLocation rl_dest, RegLocation rl_src1,
buzbee02031b12012-11-23 09:41:35 -0800749 RegLocation rl_src2)
buzbeeefc63692012-11-14 16:31:52 -0800750{
buzbee52a77fc2012-11-20 19:50:46 -0800751 LOG(FATAL) << "Unexpected use of GenSubLong for Arm";
buzbeeefc63692012-11-14 16:31:52 -0800752}
753
buzbeea5954be2013-02-07 10:41:40 -0800754void ArmCodegen::GenAndLong(CompilationUnit* cu, RegLocation rl_dest, RegLocation rl_src1,
buzbee02031b12012-11-23 09:41:35 -0800755 RegLocation rl_src2)
buzbeeefc63692012-11-14 16:31:52 -0800756{
buzbee52a77fc2012-11-20 19:50:46 -0800757 LOG(FATAL) << "Unexpected use of GenAndLong for Arm";
buzbeeefc63692012-11-14 16:31:52 -0800758}
759
buzbeea5954be2013-02-07 10:41:40 -0800760void ArmCodegen::GenOrLong(CompilationUnit* cu, RegLocation rl_dest, RegLocation rl_src1,
buzbee02031b12012-11-23 09:41:35 -0800761 RegLocation rl_src2)
buzbeeefc63692012-11-14 16:31:52 -0800762{
buzbee52a77fc2012-11-20 19:50:46 -0800763 LOG(FATAL) << "Unexpected use of GenOrLong for Arm";
buzbeeefc63692012-11-14 16:31:52 -0800764}
765
buzbeea5954be2013-02-07 10:41:40 -0800766void ArmCodegen::GenXorLong(CompilationUnit* cu, RegLocation rl_dest, RegLocation rl_src1,
buzbee02031b12012-11-23 09:41:35 -0800767 RegLocation rl_src2)
buzbeeefc63692012-11-14 16:31:52 -0800768{
769 LOG(FATAL) << "Unexpected use of genXoLong for Arm";
buzbeeefc63692012-11-14 16:31:52 -0800770}
771
buzbeee6285f92012-12-06 15:57:46 -0800772/*
773 * Generate array load
774 */
775void ArmCodegen::GenArrayGet(CompilationUnit* cu, int opt_flags, OpSize size, RegLocation rl_array,
776 RegLocation rl_index, RegLocation rl_dest, int scale)
777{
778 RegisterClass reg_class = oat_reg_class_by_size(size);
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800779 int len_offset = mirror::Array::LengthOffset().Int32Value();
buzbeee6285f92012-12-06 15:57:46 -0800780 int data_offset;
781 RegLocation rl_result;
buzbee4ef3e452012-12-14 13:35:28 -0800782 bool constant_index = rl_index.is_const;
buzbeee6285f92012-12-06 15:57:46 -0800783 rl_array = LoadValue(cu, rl_array, kCoreReg);
buzbee4ef3e452012-12-14 13:35:28 -0800784 if (!constant_index) {
785 rl_index = LoadValue(cu, rl_index, kCoreReg);
786 }
buzbeee6285f92012-12-06 15:57:46 -0800787
788 if (rl_dest.wide) {
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800789 data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Int32Value();
buzbeee6285f92012-12-06 15:57:46 -0800790 } else {
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800791 data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Int32Value();
buzbeee6285f92012-12-06 15:57:46 -0800792 }
793
buzbee4ef3e452012-12-14 13:35:28 -0800794 // If index is constant, just fold it into the data offset
795 if (constant_index) {
796 data_offset += ConstantValue(cu, rl_index) << scale;
797 }
798
buzbeee6285f92012-12-06 15:57:46 -0800799 /* null object? */
800 GenNullCheck(cu, rl_array.s_reg_low, rl_array.low_reg, opt_flags);
801
802 bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK));
803 int reg_len = INVALID_REG;
804 if (needs_range_check) {
805 reg_len = AllocTemp(cu);
806 /* Get len */
807 LoadWordDisp(cu, rl_array.low_reg, len_offset, reg_len);
808 }
buzbee4ef3e452012-12-14 13:35:28 -0800809 if (rl_dest.wide || rl_dest.fp || constant_index) {
810 int reg_ptr;
811 if (constant_index) {
812 reg_ptr = rl_array.low_reg; // NOTE: must not alter reg_ptr in constant case.
813 } else {
814 // No special indexed operation, lea + load w/ displacement
815 reg_ptr = AllocTemp(cu);
816 OpRegRegRegShift(cu, kOpAdd, reg_ptr, rl_array.low_reg, rl_index.low_reg,
817 EncodeShift(kArmLsl, scale));
818 FreeTemp(cu, rl_index.low_reg);
819 }
buzbeee6285f92012-12-06 15:57:46 -0800820 rl_result = EvalLoc(cu, rl_dest, reg_class, true);
821
822 if (needs_range_check) {
buzbee4ef3e452012-12-14 13:35:28 -0800823 if (constant_index) {
824 GenImmedCheck(cu, kCondLs, reg_len, ConstantValue(cu, rl_index), kThrowConstantArrayBounds);
825 } else {
826 GenRegRegCheck(cu, kCondLs, reg_len, rl_index.low_reg, kThrowArrayBounds);
827 }
buzbeee6285f92012-12-06 15:57:46 -0800828 FreeTemp(cu, reg_len);
829 }
830 if (rl_dest.wide) {
831 LoadBaseDispWide(cu, reg_ptr, data_offset, rl_result.low_reg, rl_result.high_reg, INVALID_SREG);
buzbee4ef3e452012-12-14 13:35:28 -0800832 if (!constant_index) {
833 FreeTemp(cu, reg_ptr);
834 }
buzbeee6285f92012-12-06 15:57:46 -0800835 StoreValueWide(cu, rl_dest, rl_result);
836 } else {
837 LoadBaseDisp(cu, reg_ptr, data_offset, rl_result.low_reg, size, INVALID_SREG);
buzbee4ef3e452012-12-14 13:35:28 -0800838 if (!constant_index) {
839 FreeTemp(cu, reg_ptr);
840 }
buzbeee6285f92012-12-06 15:57:46 -0800841 StoreValue(cu, rl_dest, rl_result);
842 }
843 } else {
844 // Offset base, then use indexed load
845 int reg_ptr = AllocTemp(cu);
846 OpRegRegImm(cu, kOpAdd, reg_ptr, rl_array.low_reg, data_offset);
847 FreeTemp(cu, rl_array.low_reg);
848 rl_result = EvalLoc(cu, rl_dest, reg_class, true);
849
850 if (needs_range_check) {
851 // TODO: change kCondCS to a more meaningful name, is the sense of
852 // carry-set/clear flipped?
853 GenRegRegCheck(cu, kCondCs, rl_index.low_reg, reg_len, kThrowArrayBounds);
854 FreeTemp(cu, reg_len);
855 }
856 LoadBaseIndexed(cu, reg_ptr, rl_index.low_reg, rl_result.low_reg, scale, size);
857 FreeTemp(cu, reg_ptr);
858 StoreValue(cu, rl_dest, rl_result);
859 }
860}
861
862/*
863 * Generate array store
864 *
865 */
866void ArmCodegen::GenArrayPut(CompilationUnit* cu, int opt_flags, OpSize size, RegLocation rl_array,
867 RegLocation rl_index, RegLocation rl_src, int scale)
868{
869 RegisterClass reg_class = oat_reg_class_by_size(size);
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800870 int len_offset = mirror::Array::LengthOffset().Int32Value();
buzbeee6285f92012-12-06 15:57:46 -0800871 int data_offset;
buzbee4ef3e452012-12-14 13:35:28 -0800872 bool constant_index = rl_index.is_const;
buzbeee6285f92012-12-06 15:57:46 -0800873
buzbee4ef3e452012-12-14 13:35:28 -0800874 if (rl_src.wide) {
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800875 data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Int32Value();
buzbeee6285f92012-12-06 15:57:46 -0800876 } else {
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800877 data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Int32Value();
buzbeee6285f92012-12-06 15:57:46 -0800878 }
879
buzbee4ef3e452012-12-14 13:35:28 -0800880 // If index is constant, just fold it into the data offset.
881 if (constant_index) {
882 data_offset += ConstantValue(cu, rl_index) << scale;
883 }
884
buzbeee6285f92012-12-06 15:57:46 -0800885 rl_array = LoadValue(cu, rl_array, kCoreReg);
buzbee4ef3e452012-12-14 13:35:28 -0800886 if (!constant_index) {
887 rl_index = LoadValue(cu, rl_index, kCoreReg);
888 }
889
890 int reg_ptr;
891 if (constant_index) {
892 reg_ptr = rl_array.low_reg;
893 } else if (IsTemp(cu, rl_array.low_reg)) {
buzbeee6285f92012-12-06 15:57:46 -0800894 Clobber(cu, rl_array.low_reg);
895 reg_ptr = rl_array.low_reg;
896 } else {
897 reg_ptr = AllocTemp(cu);
898 }
899
900 /* null object? */
901 GenNullCheck(cu, rl_array.s_reg_low, rl_array.low_reg, opt_flags);
902
903 bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK));
904 int reg_len = INVALID_REG;
905 if (needs_range_check) {
906 reg_len = AllocTemp(cu);
907 //NOTE: max live temps(4) here.
908 /* Get len */
909 LoadWordDisp(cu, rl_array.low_reg, len_offset, reg_len);
910 }
911 /* at this point, reg_ptr points to array, 2 live temps */
buzbee4ef3e452012-12-14 13:35:28 -0800912 if (rl_src.wide || rl_src.fp || constant_index) {
buzbeee6285f92012-12-06 15:57:46 -0800913 if (rl_src.wide) {
914 rl_src = LoadValueWide(cu, rl_src, reg_class);
915 } else {
916 rl_src = LoadValue(cu, rl_src, reg_class);
917 }
buzbee4ef3e452012-12-14 13:35:28 -0800918 if (!constant_index) {
919 OpRegRegRegShift(cu, kOpAdd, reg_ptr, rl_array.low_reg, rl_index.low_reg,
920 EncodeShift(kArmLsl, scale));
921 }
buzbeee6285f92012-12-06 15:57:46 -0800922 if (needs_range_check) {
buzbee4ef3e452012-12-14 13:35:28 -0800923 if (constant_index) {
924 GenImmedCheck(cu, kCondLs, reg_len, ConstantValue(cu, rl_index), kThrowConstantArrayBounds);
925 } else {
926 GenRegRegCheck(cu, kCondLs, reg_len, rl_index.low_reg, kThrowArrayBounds);
927 }
buzbeee6285f92012-12-06 15:57:46 -0800928 FreeTemp(cu, reg_len);
929 }
buzbee4ef3e452012-12-14 13:35:28 -0800930
buzbeee6285f92012-12-06 15:57:46 -0800931 if (rl_src.wide) {
932 StoreBaseDispWide(cu, reg_ptr, data_offset, rl_src.low_reg, rl_src.high_reg);
933 } else {
934 StoreBaseDisp(cu, reg_ptr, data_offset, rl_src.low_reg, size);
935 }
936 } else {
937 /* reg_ptr -> array data */
938 OpRegRegImm(cu, kOpAdd, reg_ptr, rl_array.low_reg, data_offset);
939 rl_src = LoadValue(cu, rl_src, reg_class);
940 if (needs_range_check) {
941 GenRegRegCheck(cu, kCondCs, rl_index.low_reg, reg_len, kThrowArrayBounds);
942 FreeTemp(cu, reg_len);
943 }
944 StoreBaseIndexed(cu, reg_ptr, rl_index.low_reg, rl_src.low_reg,
945 scale, size);
946 }
buzbee4ef3e452012-12-14 13:35:28 -0800947 if (!constant_index) {
948 FreeTemp(cu, reg_ptr);
949 }
buzbeee6285f92012-12-06 15:57:46 -0800950}
951
952/*
953 * Generate array store
954 *
955 */
956void ArmCodegen::GenArrayObjPut(CompilationUnit* cu, int opt_flags, RegLocation rl_array,
957 RegLocation rl_index, RegLocation rl_src, int scale)
958{
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800959 int len_offset = mirror::Array::LengthOffset().Int32Value();
960 int data_offset = mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value();
buzbeee6285f92012-12-06 15:57:46 -0800961
962 FlushAllRegs(cu); // Use explicit registers
963 LockCallTemps(cu);
964
965 int r_value = TargetReg(kArg0); // Register holding value
966 int r_array_class = TargetReg(kArg1); // Register holding array's Class
967 int r_array = TargetReg(kArg2); // Register holding array
968 int r_index = TargetReg(kArg3); // Register holding index into array
969
970 LoadValueDirectFixed(cu, rl_array, r_array); // Grab array
971 LoadValueDirectFixed(cu, rl_src, r_value); // Grab value
972 LoadValueDirectFixed(cu, rl_index, r_index); // Grab index
973
974 GenNullCheck(cu, rl_array.s_reg_low, r_array, opt_flags); // NPE?
975
976 // Store of null?
977 LIR* null_value_check = OpCmpImmBranch(cu, kCondEq, r_value, 0, NULL);
978
979 // Get the array's class.
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800980 LoadWordDisp(cu, r_array, mirror::Object::ClassOffset().Int32Value(), r_array_class);
buzbeee6285f92012-12-06 15:57:46 -0800981 CallRuntimeHelperRegReg(cu, ENTRYPOINT_OFFSET(pCanPutArrayElementFromCode), r_value,
982 r_array_class, true);
983 // Redo LoadValues in case they didn't survive the call.
984 LoadValueDirectFixed(cu, rl_array, r_array); // Reload array
985 LoadValueDirectFixed(cu, rl_index, r_index); // Reload index
986 LoadValueDirectFixed(cu, rl_src, r_value); // Reload value
987 r_array_class = INVALID_REG;
988
989 // Branch here if value to be stored == null
990 LIR* target = NewLIR0(cu, kPseudoTargetLabel);
991 null_value_check->target = target;
992
993 bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK));
994 int reg_len = INVALID_REG;
995 if (needs_range_check) {
996 reg_len = TargetReg(kArg1);
997 LoadWordDisp(cu, r_array, len_offset, reg_len); // Get len
998 }
999 /* r_ptr -> array data */
1000 int r_ptr = AllocTemp(cu);
1001 OpRegRegImm(cu, kOpAdd, r_ptr, r_array, data_offset);
1002 if (needs_range_check) {
1003 GenRegRegCheck(cu, kCondCs, r_index, reg_len, kThrowArrayBounds);
1004 }
1005 StoreBaseIndexed(cu, r_ptr, r_index, r_value, scale, kWord);
1006 FreeTemp(cu, r_ptr);
1007 FreeTemp(cu, r_index);
buzbee6a791b22013-02-07 05:35:08 -08001008 if (!IsConstantNullRef(cu, rl_src)) {
1009 MarkGCCard(cu, r_value, r_array);
1010 }
buzbeee6285f92012-12-06 15:57:46 -08001011}
1012
buzbeea5954be2013-02-07 10:41:40 -08001013void ArmCodegen::GenShiftImmOpLong(CompilationUnit* cu, Instruction::Code opcode,
buzbee4ef3e452012-12-14 13:35:28 -08001014 RegLocation rl_dest, RegLocation rl_src, RegLocation rl_shift)
1015{
1016 rl_src = LoadValueWide(cu, rl_src, kCoreReg);
1017 // Per spec, we only care about low 6 bits of shift amount.
1018 int shift_amount = ConstantValue(cu, rl_shift) & 0x3f;
1019 if (shift_amount == 0) {
1020 StoreValueWide(cu, rl_dest, rl_src);
buzbeea5954be2013-02-07 10:41:40 -08001021 return;
buzbee4ef3e452012-12-14 13:35:28 -08001022 }
1023 if (BadOverlap(cu, rl_src, rl_dest)) {
buzbeea5954be2013-02-07 10:41:40 -08001024 GenShiftOpLong(cu, opcode, rl_dest, rl_src, rl_shift);
1025 return;
buzbee4ef3e452012-12-14 13:35:28 -08001026 }
1027 RegLocation rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
1028 switch(opcode) {
1029 case Instruction::SHL_LONG:
1030 case Instruction::SHL_LONG_2ADDR:
1031 if (shift_amount == 1) {
1032 OpRegRegReg(cu, kOpAdd, rl_result.low_reg, rl_src.low_reg, rl_src.low_reg);
1033 OpRegRegReg(cu, kOpAdc, rl_result.high_reg, rl_src.high_reg, rl_src.high_reg);
1034 } else if (shift_amount == 32) {
1035 OpRegCopy(cu, rl_result.high_reg, rl_src.low_reg);
1036 LoadConstant(cu, rl_result.low_reg, 0);
1037 } else if (shift_amount > 31) {
1038 OpRegRegImm(cu, kOpLsl, rl_result.high_reg, rl_src.low_reg, shift_amount - 32);
1039 LoadConstant(cu, rl_result.low_reg, 0);
1040 } else {
1041 OpRegRegImm(cu, kOpLsl, rl_result.high_reg, rl_src.high_reg, shift_amount);
1042 OpRegRegRegShift(cu, kOpOr, rl_result.high_reg, rl_result.high_reg, rl_src.low_reg,
1043 EncodeShift(kArmLsr, 32 - shift_amount));
1044 OpRegRegImm(cu, kOpLsl, rl_result.low_reg, rl_src.low_reg, shift_amount);
1045 }
1046 break;
1047 case Instruction::SHR_LONG:
1048 case Instruction::SHR_LONG_2ADDR:
1049 if (shift_amount == 32) {
1050 OpRegCopy(cu, rl_result.low_reg, rl_src.high_reg);
1051 OpRegRegImm(cu, kOpAsr, rl_result.high_reg, rl_src.high_reg, 31);
1052 } else if (shift_amount > 31) {
1053 OpRegRegImm(cu, kOpAsr, rl_result.low_reg, rl_src.high_reg, shift_amount - 32);
1054 OpRegRegImm(cu, kOpAsr, rl_result.high_reg, rl_src.high_reg, 31);
1055 } else {
1056 int t_reg = AllocTemp(cu);
1057 OpRegRegImm(cu, kOpLsr, t_reg, rl_src.low_reg, shift_amount);
1058 OpRegRegRegShift(cu, kOpOr, rl_result.low_reg, t_reg, rl_src.high_reg,
1059 EncodeShift(kArmLsl, 32 - shift_amount));
1060 FreeTemp(cu, t_reg);
1061 OpRegRegImm(cu, kOpAsr, rl_result.high_reg, rl_src.high_reg, shift_amount);
1062 }
1063 break;
1064 case Instruction::USHR_LONG:
1065 case Instruction::USHR_LONG_2ADDR:
1066 if (shift_amount == 32) {
1067 OpRegCopy(cu, rl_result.low_reg, rl_src.high_reg);
1068 LoadConstant(cu, rl_result.high_reg, 0);
1069 } else if (shift_amount > 31) {
1070 OpRegRegImm(cu, kOpLsr, rl_result.low_reg, rl_src.high_reg, shift_amount - 32);
1071 LoadConstant(cu, rl_result.high_reg, 0);
1072 } else {
1073 int t_reg = AllocTemp(cu);
1074 OpRegRegImm(cu, kOpLsr, t_reg, rl_src.low_reg, shift_amount);
1075 OpRegRegRegShift(cu, kOpOr, rl_result.low_reg, t_reg, rl_src.high_reg,
1076 EncodeShift(kArmLsl, 32 - shift_amount));
1077 FreeTemp(cu, t_reg);
1078 OpRegRegImm(cu, kOpLsr, rl_result.high_reg, rl_src.high_reg, shift_amount);
1079 }
1080 break;
1081 default:
1082 LOG(FATAL) << "Unexpected case";
buzbee4ef3e452012-12-14 13:35:28 -08001083 }
1084 StoreValueWide(cu, rl_dest, rl_result);
buzbee4ef3e452012-12-14 13:35:28 -08001085}
1086
buzbeea5954be2013-02-07 10:41:40 -08001087void ArmCodegen::GenArithImmOpLong(CompilationUnit* cu, Instruction::Code opcode,
buzbee4ef3e452012-12-14 13:35:28 -08001088 RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2)
1089{
1090 if ((opcode == Instruction::SUB_LONG_2ADDR) || (opcode == Instruction::SUB_LONG)) {
1091 if (!rl_src2.is_const) {
1092 // Don't bother with special handling for subtract from immediate.
buzbeea5954be2013-02-07 10:41:40 -08001093 GenArithOpLong(cu, opcode, rl_dest, rl_src1, rl_src2);
1094 return;
buzbee4ef3e452012-12-14 13:35:28 -08001095 }
1096 } else {
1097 // Normalize
1098 if (!rl_src2.is_const) {
1099 DCHECK(rl_src1.is_const);
1100 RegLocation rl_temp = rl_src1;
1101 rl_src1 = rl_src2;
1102 rl_src2 = rl_temp;
1103 }
1104 }
1105 if (BadOverlap(cu, rl_src1, rl_dest)) {
buzbeea5954be2013-02-07 10:41:40 -08001106 GenArithOpLong(cu, opcode, rl_dest, rl_src1, rl_src2);
1107 return;
buzbee4ef3e452012-12-14 13:35:28 -08001108 }
1109 DCHECK(rl_src2.is_const);
1110 int64_t val = ConstantValueWide(cu, rl_src2);
1111 uint32_t val_lo = Low32Bits(val);
1112 uint32_t val_hi = High32Bits(val);
1113 int32_t mod_imm_lo = ModifiedImmediate(val_lo);
1114 int32_t mod_imm_hi = ModifiedImmediate(val_hi);
1115
1116 // Only a subset of add/sub immediate instructions set carry - so bail if we don't fit
1117 switch(opcode) {
1118 case Instruction::ADD_LONG:
1119 case Instruction::ADD_LONG_2ADDR:
1120 case Instruction::SUB_LONG:
1121 case Instruction::SUB_LONG_2ADDR:
1122 if ((mod_imm_lo < 0) || (mod_imm_hi < 0)) {
buzbeea5954be2013-02-07 10:41:40 -08001123 GenArithOpLong(cu, opcode, rl_dest, rl_src1, rl_src2);
1124 return;
buzbee4ef3e452012-12-14 13:35:28 -08001125 }
1126 break;
1127 default:
1128 break;
1129 }
1130 rl_src1 = LoadValueWide(cu, rl_src1, kCoreReg);
1131 RegLocation rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
1132 // NOTE: once we've done the EvalLoc on dest, we can no longer bail.
1133 switch (opcode) {
1134 case Instruction::ADD_LONG:
1135 case Instruction::ADD_LONG_2ADDR:
1136 NewLIR3(cu, kThumb2AddRRI8, rl_result.low_reg, rl_src1.low_reg, mod_imm_lo);
1137 NewLIR3(cu, kThumb2AdcRRI8, rl_result.high_reg, rl_src1.high_reg, mod_imm_hi);
1138 break;
1139 case Instruction::OR_LONG:
1140 case Instruction::OR_LONG_2ADDR:
1141 if ((val_lo != 0) || (rl_result.low_reg != rl_src1.low_reg)) {
1142 OpRegRegImm(cu, kOpOr, rl_result.low_reg, rl_src1.low_reg, val_lo);
1143 }
1144 if ((val_hi != 0) || (rl_result.high_reg != rl_src1.high_reg)) {
1145 OpRegRegImm(cu, kOpOr, rl_result.high_reg, rl_src1.high_reg, val_hi);
1146 }
1147 break;
1148 case Instruction::XOR_LONG:
1149 case Instruction::XOR_LONG_2ADDR:
1150 OpRegRegImm(cu, kOpXor, rl_result.low_reg, rl_src1.low_reg, val_lo);
1151 OpRegRegImm(cu, kOpXor, rl_result.high_reg, rl_src1.high_reg, val_hi);
1152 break;
1153 case Instruction::AND_LONG:
1154 case Instruction::AND_LONG_2ADDR:
1155 if ((val_lo != 0xffffffff) || (rl_result.low_reg != rl_src1.low_reg)) {
1156 OpRegRegImm(cu, kOpAnd, rl_result.low_reg, rl_src1.low_reg, val_lo);
1157 }
1158 if ((val_hi != 0xffffffff) || (rl_result.high_reg != rl_src1.high_reg)) {
1159 OpRegRegImm(cu, kOpAnd, rl_result.high_reg, rl_src1.high_reg, val_hi);
1160 }
1161 break;
1162 case Instruction::SUB_LONG_2ADDR:
1163 case Instruction::SUB_LONG:
1164 NewLIR3(cu, kThumb2SubRRI8, rl_result.low_reg, rl_src1.low_reg, mod_imm_lo);
1165 NewLIR3(cu, kThumb2SbcRRI8, rl_result.high_reg, rl_src1.high_reg, mod_imm_hi);
1166 break;
1167 default:
1168 LOG(FATAL) << "Unexpected opcode " << opcode;
1169 }
1170 StoreValueWide(cu, rl_dest, rl_result);
buzbee4ef3e452012-12-14 13:35:28 -08001171}
1172
buzbeeefc63692012-11-14 16:31:52 -08001173} // namespace art