code_generator_x86.cc revision 01bc96d007b67fdb7fe349232a83e4b354ce3d08
1/*
2 * Copyright (C) 2014 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 "code_generator_x86.h"
18#include "utils/assembler.h"
19#include "utils/x86/assembler_x86.h"
20#include "utils/x86/managed_register_x86.h"
21
22#include "mirror/array.h"
23#include "mirror/art_method.h"
24
25#define __ reinterpret_cast<X86Assembler*>(GetAssembler())->
26
27namespace art {
28
29x86::X86ManagedRegister Location::AsX86() const {
30  return reg().AsX86();
31}
32
33namespace x86 {
34
35static constexpr int kNumberOfPushedRegistersAtEntry = 1;
36static constexpr int kCurrentMethodStackOffset = 0;
37
38static Location X86CpuLocation(Register reg) {
39  return Location::RegisterLocation(X86ManagedRegister::FromCpuRegister(reg));
40}
41
42InstructionCodeGeneratorX86::InstructionCodeGeneratorX86(HGraph* graph, CodeGeneratorX86* codegen)
43      : HGraphVisitor(graph),
44        assembler_(codegen->GetAssembler()),
45        codegen_(codegen) {}
46
47void CodeGeneratorX86::GenerateFrameEntry() {
48  // Create a fake register to mimic Quick.
49  static const int kFakeReturnRegister = 8;
50  core_spill_mask_ |= (1 << kFakeReturnRegister);
51
52  // Add the current ART method to the frame size, the return PC, and the filler.
53  SetFrameSize(RoundUp((
54      GetGraph()->GetMaximumNumberOfOutVRegs() + GetGraph()->GetNumberOfVRegs() + 3) * kX86WordSize,
55      kStackAlignment));
56  // The return PC has already been pushed on the stack.
57  __ subl(ESP, Immediate(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kX86WordSize));
58  __ movl(Address(ESP, kCurrentMethodStackOffset), EAX);
59}
60
61void CodeGeneratorX86::GenerateFrameExit() {
62  __ addl(ESP, Immediate(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kX86WordSize));
63}
64
65void CodeGeneratorX86::Bind(Label* label) {
66  __ Bind(label);
67}
68
69void InstructionCodeGeneratorX86::LoadCurrentMethod(Register reg) {
70  __ movl(reg, Address(ESP, kCurrentMethodStackOffset));
71}
72
73int32_t CodeGeneratorX86::GetStackSlot(HLocal* local) const {
74  uint16_t reg_number = local->GetRegNumber();
75  uint16_t number_of_vregs = GetGraph()->GetNumberOfVRegs();
76  uint16_t number_of_in_vregs = GetGraph()->GetNumberOfInVRegs();
77  if (reg_number >= number_of_vregs - number_of_in_vregs) {
78    // Local is a parameter of the method. It is stored in the caller's frame.
79    return GetFrameSize() + kX86WordSize  // ART method
80                          + (reg_number - number_of_vregs + number_of_in_vregs) * kX86WordSize;
81  } else {
82    // Local is a temporary in this method. It is stored in this method's frame.
83    return GetFrameSize() - (kNumberOfPushedRegistersAtEntry * kX86WordSize)
84                          - kX86WordSize  // filler.
85                          - (number_of_vregs * kX86WordSize)
86                          + (reg_number * kX86WordSize);
87  }
88}
89
90static constexpr Register kParameterCoreRegisters[] = { ECX, EDX, EBX };
91static constexpr RegisterPair kParameterCorePairRegisters[] = { ECX_EDX, EDX_EBX };
92static constexpr size_t kParameterCoreRegistersLength = arraysize(kParameterCoreRegisters);
93
94class InvokeDexCallingConvention : public CallingConvention<Register> {
95 public:
96  InvokeDexCallingConvention()
97      : CallingConvention(kParameterCoreRegisters, kParameterCoreRegistersLength) {}
98
99  RegisterPair GetRegisterPairAt(size_t argument_index) {
100    DCHECK_LT(argument_index + 1, GetNumberOfRegisters());
101    return kParameterCorePairRegisters[argument_index];
102  }
103
104 private:
105  DISALLOW_COPY_AND_ASSIGN(InvokeDexCallingConvention);
106};
107
108void CodeGeneratorX86::Move32(Location destination, Location source) {
109  if (source.Equals(destination)) {
110    return;
111  }
112  if (destination.IsRegister()) {
113    if (source.IsRegister()) {
114      __ movl(destination.AsX86().AsCpuRegister(), source.AsX86().AsCpuRegister());
115    } else {
116      DCHECK(source.IsStackSlot());
117      __ movl(destination.AsX86().AsCpuRegister(), Address(ESP, source.GetStackIndex()));
118    }
119  } else {
120    if (source.IsRegister()) {
121      __ movl(Address(ESP, destination.GetStackIndex()), source.AsX86().AsCpuRegister());
122    } else {
123      DCHECK(source.IsStackSlot());
124      __ movl(EAX, Address(ESP, source.GetStackIndex()));
125      __ movl(Address(ESP, destination.GetStackIndex()), EAX);
126    }
127  }
128}
129
130void CodeGeneratorX86::Move64(Location destination, Location source) {
131  if (source.Equals(destination)) {
132    return;
133  }
134  if (destination.IsRegister()) {
135    if (source.IsRegister()) {
136      __ movl(destination.AsX86().AsRegisterPairLow(), source.AsX86().AsRegisterPairLow());
137      __ movl(destination.AsX86().AsRegisterPairHigh(), source.AsX86().AsRegisterPairHigh());
138    } else if (source.IsQuickParameter()) {
139      uint32_t argument_index = source.GetQuickParameterIndex();
140      InvokeDexCallingConvention calling_convention;
141      __ movl(destination.AsX86().AsRegisterPairLow(),
142              calling_convention.GetRegisterAt(argument_index));
143      __ movl(destination.AsX86().AsRegisterPairHigh(),
144              Address(ESP,
145                      calling_convention.GetStackOffsetOf(argument_index + 1) + GetFrameSize()));
146    } else {
147      DCHECK(source.IsDoubleStackSlot());
148      __ movl(destination.AsX86().AsRegisterPairLow(), Address(ESP, source.GetStackIndex()));
149      __ movl(destination.AsX86().AsRegisterPairHigh(),
150              Address(ESP, source.GetHighStackIndex(kX86WordSize)));
151    }
152  } else if (destination.IsQuickParameter()) {
153    InvokeDexCallingConvention calling_convention;
154    uint32_t argument_index = destination.GetQuickParameterIndex();
155    if (source.IsRegister()) {
156      __ movl(calling_convention.GetRegisterAt(argument_index), source.AsX86().AsRegisterPairLow());
157      __ movl(Address(ESP, calling_convention.GetStackOffsetOf(argument_index + 1)),
158              source.AsX86().AsRegisterPairHigh());
159    } else {
160      DCHECK(source.IsDoubleStackSlot());
161      __ movl(calling_convention.GetRegisterAt(argument_index),
162              Address(ESP, source.GetStackIndex()));
163      __ movl(EAX, Address(ESP, source.GetHighStackIndex(kX86WordSize)));
164      __ movl(Address(ESP, calling_convention.GetStackOffsetOf(argument_index + 1)), EAX);
165    }
166  } else {
167    if (source.IsRegister()) {
168      __ movl(Address(ESP, destination.GetStackIndex()), source.AsX86().AsRegisterPairLow());
169      __ movl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)),
170              source.AsX86().AsRegisterPairHigh());
171    } else if (source.IsQuickParameter()) {
172      InvokeDexCallingConvention calling_convention;
173      uint32_t argument_index = source.GetQuickParameterIndex();
174      __ movl(Address(ESP, destination.GetStackIndex()),
175              calling_convention.GetRegisterAt(argument_index));
176      __ movl(EAX,
177              Address(ESP,
178                      calling_convention.GetStackOffsetOf(argument_index + 1) + GetFrameSize()));
179      __ movl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)), EAX);
180    } else {
181      DCHECK(source.IsDoubleStackSlot());
182      __ movl(EAX, Address(ESP, source.GetStackIndex()));
183      __ movl(Address(ESP, destination.GetStackIndex()), EAX);
184      __ movl(EAX, Address(ESP, source.GetHighStackIndex(kX86WordSize)));
185      __ movl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)), EAX);
186    }
187  }
188}
189
190void CodeGeneratorX86::Move(HInstruction* instruction, Location location, HInstruction* move_for) {
191  if (instruction->AsIntConstant() != nullptr) {
192    Immediate imm(instruction->AsIntConstant()->GetValue());
193    if (location.IsRegister()) {
194      __ movl(location.AsX86().AsCpuRegister(), imm);
195    } else {
196      __ movl(Address(ESP, location.GetStackIndex()), imm);
197    }
198  } else if (instruction->AsLongConstant() != nullptr) {
199    int64_t value = instruction->AsLongConstant()->GetValue();
200    if (location.IsRegister()) {
201      __ movl(location.AsX86().AsRegisterPairLow(), Immediate(Low32Bits(value)));
202      __ movl(location.AsX86().AsRegisterPairHigh(), Immediate(High32Bits(value)));
203    } else {
204      __ movl(Address(ESP, location.GetStackIndex()), Immediate(Low32Bits(value)));
205      __ movl(Address(ESP, location.GetHighStackIndex(kX86WordSize)), Immediate(High32Bits(value)));
206    }
207  } else if (instruction->AsLoadLocal() != nullptr) {
208    switch (instruction->GetType()) {
209      case Primitive::kPrimBoolean:
210      case Primitive::kPrimByte:
211      case Primitive::kPrimChar:
212      case Primitive::kPrimShort:
213      case Primitive::kPrimInt:
214      case Primitive::kPrimNot:
215        Move32(location, Location::StackSlot(GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
216        break;
217
218      case Primitive::kPrimLong:
219        Move64(location, Location::DoubleStackSlot(
220            GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
221        break;
222
223      default:
224        LOG(FATAL) << "Unimplemented local type " << instruction->GetType();
225    }
226  } else {
227    // This can currently only happen when the instruction that requests the move
228    // is the next to be compiled.
229    DCHECK_EQ(instruction->GetNext(), move_for);
230    switch (instruction->GetType()) {
231      case Primitive::kPrimBoolean:
232      case Primitive::kPrimByte:
233      case Primitive::kPrimChar:
234      case Primitive::kPrimShort:
235      case Primitive::kPrimInt:
236      case Primitive::kPrimNot:
237        Move32(location, instruction->GetLocations()->Out());
238        break;
239
240      case Primitive::kPrimLong:
241        Move64(location, instruction->GetLocations()->Out());
242        break;
243
244      default:
245        LOG(FATAL) << "Unimplemented type " << instruction->GetType();
246    }
247  }
248}
249
250void LocationsBuilderX86::VisitGoto(HGoto* got) {
251  got->SetLocations(nullptr);
252}
253
254void InstructionCodeGeneratorX86::VisitGoto(HGoto* got) {
255  HBasicBlock* successor = got->GetSuccessor();
256  if (GetGraph()->GetExitBlock() == successor) {
257    codegen_->GenerateFrameExit();
258  } else if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
259    __ jmp(codegen_->GetLabelOf(successor));
260  }
261}
262
263void LocationsBuilderX86::VisitExit(HExit* exit) {
264  exit->SetLocations(nullptr);
265}
266
267void InstructionCodeGeneratorX86::VisitExit(HExit* exit) {
268  if (kIsDebugBuild) {
269    __ Comment("Unreachable");
270    __ int3();
271  }
272}
273
274void LocationsBuilderX86::VisitIf(HIf* if_instr) {
275  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(if_instr);
276  locations->SetInAt(0, X86CpuLocation(EAX));
277  if_instr->SetLocations(locations);
278}
279
280void InstructionCodeGeneratorX86::VisitIf(HIf* if_instr) {
281  // TODO: Generate the input as a condition, instead of materializing in a register.
282  __ cmpl(if_instr->GetLocations()->InAt(0).AsX86().AsCpuRegister(), Immediate(0));
283  __ j(kEqual, codegen_->GetLabelOf(if_instr->IfFalseSuccessor()));
284  if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), if_instr->IfTrueSuccessor())) {
285    __ jmp(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
286  }
287}
288
289void LocationsBuilderX86::VisitLocal(HLocal* local) {
290  local->SetLocations(nullptr);
291}
292
293void InstructionCodeGeneratorX86::VisitLocal(HLocal* local) {
294  DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
295}
296
297void LocationsBuilderX86::VisitLoadLocal(HLoadLocal* local) {
298  local->SetLocations(nullptr);
299}
300
301void InstructionCodeGeneratorX86::VisitLoadLocal(HLoadLocal* load) {
302  // Nothing to do, this is driven by the code generator.
303}
304
305void LocationsBuilderX86::VisitStoreLocal(HStoreLocal* store) {
306  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(store);
307  switch (store->InputAt(1)->GetType()) {
308    case Primitive::kPrimBoolean:
309    case Primitive::kPrimByte:
310    case Primitive::kPrimChar:
311    case Primitive::kPrimShort:
312    case Primitive::kPrimInt:
313    case Primitive::kPrimNot:
314      locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
315      break;
316
317    case Primitive::kPrimLong:
318      locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
319      break;
320
321    default:
322      LOG(FATAL) << "Unimplemented local type " << store->InputAt(1)->GetType();
323  }
324  store->SetLocations(locations);
325}
326
327void InstructionCodeGeneratorX86::VisitStoreLocal(HStoreLocal* store) {
328}
329
330void LocationsBuilderX86::VisitEqual(HEqual* equal) {
331  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(equal);
332  locations->SetInAt(0, X86CpuLocation(EAX));
333  locations->SetInAt(1, X86CpuLocation(ECX));
334  locations->SetOut(X86CpuLocation(EAX));
335  equal->SetLocations(locations);
336}
337
338void InstructionCodeGeneratorX86::VisitEqual(HEqual* equal) {
339  __ cmpl(equal->GetLocations()->InAt(0).AsX86().AsCpuRegister(),
340          equal->GetLocations()->InAt(1).AsX86().AsCpuRegister());
341  __ setb(kEqual, equal->GetLocations()->Out().AsX86().AsCpuRegister());
342}
343
344void LocationsBuilderX86::VisitIntConstant(HIntConstant* constant) {
345  constant->SetLocations(nullptr);
346}
347
348void InstructionCodeGeneratorX86::VisitIntConstant(HIntConstant* constant) {
349  // Will be generated at use site.
350}
351
352void LocationsBuilderX86::VisitLongConstant(HLongConstant* constant) {
353  constant->SetLocations(nullptr);
354}
355
356void InstructionCodeGeneratorX86::VisitLongConstant(HLongConstant* constant) {
357  // Will be generated at use site.
358}
359
360void LocationsBuilderX86::VisitReturnVoid(HReturnVoid* ret) {
361  ret->SetLocations(nullptr);
362}
363
364void InstructionCodeGeneratorX86::VisitReturnVoid(HReturnVoid* ret) {
365  codegen_->GenerateFrameExit();
366  __ ret();
367}
368
369void LocationsBuilderX86::VisitReturn(HReturn* ret) {
370  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(ret);
371  switch (ret->InputAt(0)->GetType()) {
372    case Primitive::kPrimBoolean:
373    case Primitive::kPrimByte:
374    case Primitive::kPrimChar:
375    case Primitive::kPrimShort:
376    case Primitive::kPrimInt:
377    case Primitive::kPrimNot:
378      locations->SetInAt(0, X86CpuLocation(EAX));
379      break;
380
381    case Primitive::kPrimLong:
382      locations->SetInAt(
383          0, Location::RegisterLocation(X86ManagedRegister::FromRegisterPair(EAX_EDX)));
384      break;
385
386    default:
387      LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
388  }
389  ret->SetLocations(locations);
390}
391
392void InstructionCodeGeneratorX86::VisitReturn(HReturn* ret) {
393  if (kIsDebugBuild) {
394    switch (ret->InputAt(0)->GetType()) {
395      case Primitive::kPrimBoolean:
396      case Primitive::kPrimByte:
397      case Primitive::kPrimChar:
398      case Primitive::kPrimShort:
399      case Primitive::kPrimInt:
400      case Primitive::kPrimNot:
401        DCHECK_EQ(ret->GetLocations()->InAt(0).AsX86().AsCpuRegister(), EAX);
402        break;
403
404      case Primitive::kPrimLong:
405        DCHECK_EQ(ret->GetLocations()->InAt(0).AsX86().AsRegisterPair(), EAX_EDX);
406        break;
407
408      default:
409        LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
410    }
411  }
412  codegen_->GenerateFrameExit();
413  __ ret();
414}
415
416static constexpr Register kRuntimeParameterCoreRegisters[] = { EAX, ECX, EDX };
417static constexpr size_t kRuntimeParameterCoreRegistersLength =
418    arraysize(kRuntimeParameterCoreRegisters);
419
420class InvokeRuntimeCallingConvention : public CallingConvention<Register> {
421 public:
422  InvokeRuntimeCallingConvention()
423      : CallingConvention(kRuntimeParameterCoreRegisters,
424                          kRuntimeParameterCoreRegistersLength) {}
425
426 private:
427  DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention);
428};
429
430void LocationsBuilderX86::VisitPushArgument(HPushArgument* argument) {
431  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(argument);
432  InvokeDexCallingConvention calling_convention;
433  uint32_t argument_index = argument->GetArgumentIndex();
434  switch (argument->InputAt(0)->GetType()) {
435    case Primitive::kPrimBoolean:
436    case Primitive::kPrimByte:
437    case Primitive::kPrimChar:
438    case Primitive::kPrimShort:
439    case Primitive::kPrimInt:
440    case Primitive::kPrimNot: {
441      if (argument_index < calling_convention.GetNumberOfRegisters()) {
442        locations->SetInAt(
443            0, X86CpuLocation(calling_convention.GetRegisterAt(argument->GetArgumentIndex())));
444      } else {
445        locations->SetInAt(
446            0, Location::StackSlot(calling_convention.GetStackOffsetOf(argument_index)));
447      }
448      break;
449    }
450    case Primitive::kPrimLong: {
451      if (argument_index + 1 < calling_convention.GetNumberOfRegisters()) {
452        Location location = Location::RegisterLocation(X86ManagedRegister::FromRegisterPair(
453            calling_convention.GetRegisterPairAt(argument_index)));
454        locations->SetInAt(0, location);
455      } else if (argument_index + 1 == calling_convention.GetNumberOfRegisters()) {
456        locations->SetInAt(0, Location::QuickParameter(argument_index));
457      } else {
458        locations->SetInAt(
459            0, Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(argument_index)));
460      }
461      break;
462    }
463    default:
464      LOG(FATAL) << "Unimplemented argument type " << argument->InputAt(0)->GetType();
465  }
466
467  argument->SetLocations(locations);
468}
469
470void InstructionCodeGeneratorX86::VisitPushArgument(HPushArgument* argument) {
471  // Nothing to do.
472}
473
474void LocationsBuilderX86::VisitInvokeStatic(HInvokeStatic* invoke) {
475  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(invoke);
476  locations->AddTemp(X86CpuLocation(EAX));
477  switch (invoke->GetType()) {
478    case Primitive::kPrimBoolean:
479    case Primitive::kPrimByte:
480    case Primitive::kPrimChar:
481    case Primitive::kPrimShort:
482    case Primitive::kPrimInt:
483    case Primitive::kPrimNot:
484      locations->SetOut(X86CpuLocation(EAX));
485      break;
486
487    case Primitive::kPrimLong:
488      locations->SetOut(Location::RegisterLocation(X86ManagedRegister::FromRegisterPair(EAX_EDX)));
489      break;
490
491    case Primitive::kPrimVoid:
492      break;
493
494    case Primitive::kPrimDouble:
495    case Primitive::kPrimFloat:
496      LOG(FATAL) << "Unimplemented return type " << invoke->GetType();
497      break;
498  }
499
500  invoke->SetLocations(locations);
501}
502
503void InstructionCodeGeneratorX86::VisitInvokeStatic(HInvokeStatic* invoke) {
504  Register temp = invoke->GetLocations()->GetTemp(0).AsX86().AsCpuRegister();
505  size_t index_in_cache = mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value() +
506      invoke->GetIndexInDexCache() * kX86WordSize;
507
508  // TODO: Implement all kinds of calls:
509  // 1) boot -> boot
510  // 2) app -> boot
511  // 3) app -> app
512  //
513  // Currently we implement the app -> app logic, which looks up in the resolve cache.
514
515  // temp = method;
516  LoadCurrentMethod(temp);
517  // temp = temp->dex_cache_resolved_methods_;
518  __ movl(temp, Address(temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value()));
519  // temp = temp[index_in_cache]
520  __ movl(temp, Address(temp, index_in_cache));
521  // (temp + offset_of_quick_compiled_code)()
522  __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value()));
523
524  codegen_->RecordPcInfo(invoke->GetDexPc());
525}
526
527void LocationsBuilderX86::VisitAdd(HAdd* add) {
528  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(add);
529  switch (add->GetResultType()) {
530    case Primitive::kPrimInt: {
531      locations->SetInAt(0, X86CpuLocation(EAX));
532      locations->SetInAt(1, X86CpuLocation(ECX));
533      locations->SetOut(X86CpuLocation(EAX));
534      break;
535    }
536    case Primitive::kPrimLong: {
537      locations->SetInAt(
538          0, Location::RegisterLocation(X86ManagedRegister::FromRegisterPair(EAX_EDX)));
539      locations->SetInAt(
540          1, Location::RegisterLocation(X86ManagedRegister::FromRegisterPair(ECX_EBX)));
541      locations->SetOut(Location::RegisterLocation(X86ManagedRegister::FromRegisterPair(EAX_EDX)));
542      break;
543    }
544
545    case Primitive::kPrimBoolean:
546    case Primitive::kPrimByte:
547    case Primitive::kPrimChar:
548    case Primitive::kPrimShort:
549      LOG(FATAL) << "Unexpected add type " << add->GetResultType();
550      break;
551
552    default:
553      LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
554  }
555  add->SetLocations(locations);
556}
557
558void InstructionCodeGeneratorX86::VisitAdd(HAdd* add) {
559  LocationSummary* locations = add->GetLocations();
560  switch (add->GetResultType()) {
561    case Primitive::kPrimInt: {
562      DCHECK_EQ(locations->InAt(0).AsX86().AsCpuRegister(),
563                locations->Out().AsX86().AsCpuRegister());
564      __ addl(locations->InAt(0).AsX86().AsCpuRegister(),
565              locations->InAt(1).AsX86().AsCpuRegister());
566      break;
567    }
568
569    case Primitive::kPrimLong: {
570      DCHECK_EQ(locations->InAt(0).AsX86().AsRegisterPair(),
571                locations->Out().AsX86().AsRegisterPair());
572      __ addl(locations->InAt(0).AsX86().AsRegisterPairLow(),
573              locations->InAt(1).AsX86().AsRegisterPairLow());
574      __ adcl(locations->InAt(0).AsX86().AsRegisterPairHigh(),
575              locations->InAt(1).AsX86().AsRegisterPairHigh());
576      break;
577    }
578
579    case Primitive::kPrimBoolean:
580    case Primitive::kPrimByte:
581    case Primitive::kPrimChar:
582    case Primitive::kPrimShort:
583      LOG(FATAL) << "Unexpected add type " << add->GetResultType();
584      break;
585
586    default:
587      LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
588  }
589}
590
591void LocationsBuilderX86::VisitSub(HSub* sub) {
592  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(sub);
593  switch (sub->GetResultType()) {
594    case Primitive::kPrimInt: {
595      locations->SetInAt(0, X86CpuLocation(EAX));
596      locations->SetInAt(1, X86CpuLocation(ECX));
597      locations->SetOut(X86CpuLocation(EAX));
598      break;
599    }
600
601    case Primitive::kPrimLong: {
602      locations->SetInAt(
603          0, Location::RegisterLocation(X86ManagedRegister::FromRegisterPair(EAX_EDX)));
604      locations->SetInAt(
605          1, Location::RegisterLocation(X86ManagedRegister::FromRegisterPair(ECX_EBX)));
606      locations->SetOut(Location::RegisterLocation(X86ManagedRegister::FromRegisterPair(EAX_EDX)));
607      break;
608    }
609
610    case Primitive::kPrimBoolean:
611    case Primitive::kPrimByte:
612    case Primitive::kPrimChar:
613    case Primitive::kPrimShort:
614      LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
615      break;
616
617    default:
618      LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
619  }
620  sub->SetLocations(locations);
621}
622
623void InstructionCodeGeneratorX86::VisitSub(HSub* sub) {
624  LocationSummary* locations = sub->GetLocations();
625  switch (sub->GetResultType()) {
626    case Primitive::kPrimInt: {
627      DCHECK_EQ(locations->InAt(0).AsX86().AsCpuRegister(),
628                locations->Out().AsX86().AsCpuRegister());
629      __ subl(locations->InAt(0).AsX86().AsCpuRegister(),
630              locations->InAt(1).AsX86().AsCpuRegister());
631      break;
632    }
633
634    case Primitive::kPrimLong: {
635      DCHECK_EQ(locations->InAt(0).AsX86().AsRegisterPair(),
636                locations->Out().AsX86().AsRegisterPair());
637      __ subl(locations->InAt(0).AsX86().AsRegisterPairLow(),
638              locations->InAt(1).AsX86().AsRegisterPairLow());
639      __ sbbl(locations->InAt(0).AsX86().AsRegisterPairHigh(),
640              locations->InAt(1).AsX86().AsRegisterPairHigh());
641      break;
642    }
643
644    case Primitive::kPrimBoolean:
645    case Primitive::kPrimByte:
646    case Primitive::kPrimChar:
647    case Primitive::kPrimShort:
648      LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
649      break;
650
651    default:
652      LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
653  }
654}
655
656void LocationsBuilderX86::VisitNewInstance(HNewInstance* instruction) {
657  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
658  locations->SetOut(X86CpuLocation(EAX));
659  instruction->SetLocations(locations);
660}
661
662void InstructionCodeGeneratorX86::VisitNewInstance(HNewInstance* instruction) {
663  InvokeRuntimeCallingConvention calling_convention;
664  LoadCurrentMethod(calling_convention.GetRegisterAt(1));
665  __ movl(calling_convention.GetRegisterAt(0),
666          Immediate(instruction->GetTypeIndex()));
667
668  __ fs()->call(
669      Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pAllocObjectWithAccessCheck)));
670
671  codegen_->RecordPcInfo(instruction->GetDexPc());
672}
673
674void LocationsBuilderX86::VisitParameterValue(HParameterValue* instruction) {
675  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
676  InvokeDexCallingConvention calling_convention;
677  uint32_t argument_index = instruction->GetIndex();
678  switch (instruction->GetType()) {
679    case Primitive::kPrimBoolean:
680    case Primitive::kPrimByte:
681    case Primitive::kPrimChar:
682    case Primitive::kPrimShort:
683    case Primitive::kPrimInt:
684    case Primitive::kPrimNot:
685      if (argument_index < calling_convention.GetNumberOfRegisters()) {
686        locations->SetOut(X86CpuLocation(calling_convention.GetRegisterAt(argument_index)));
687      } else {
688        locations->SetOut(Location::StackSlot(
689            calling_convention.GetStackOffsetOf(argument_index) + codegen_->GetFrameSize()));
690      }
691      break;
692
693    case Primitive::kPrimLong:
694      if (argument_index + 1 < calling_convention.GetNumberOfRegisters()) {
695        locations->SetOut(Location::RegisterLocation(X86ManagedRegister::FromRegisterPair(
696            (calling_convention.GetRegisterPairAt(argument_index)))));
697      } else if (argument_index + 1 == calling_convention.GetNumberOfRegisters()) {
698        locations->SetOut(Location::QuickParameter(argument_index));
699      } else {
700        locations->SetOut(Location::DoubleStackSlot(
701            calling_convention.GetStackOffsetOf(argument_index) + codegen_->GetFrameSize()));
702      }
703      break;
704
705    default:
706      LOG(FATAL) << "Unimplemented parameter type " << instruction->GetType();
707  }
708  instruction->SetLocations(locations);
709}
710
711void InstructionCodeGeneratorX86::VisitParameterValue(HParameterValue* instruction) {
712  // Nothing to do, the parameter is already at its location.
713}
714
715void LocationsBuilderX86::VisitNot(HNot* instruction) {
716  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
717  locations->SetInAt(0, X86CpuLocation(EAX));
718  locations->SetOut(X86CpuLocation(EAX));
719  instruction->SetLocations(locations);
720}
721
722void InstructionCodeGeneratorX86::VisitNot(HNot* instruction) {
723  LocationSummary* locations = instruction->GetLocations();
724  DCHECK_EQ(locations->InAt(0).AsX86().AsCpuRegister(), locations->Out().AsX86().AsCpuRegister());
725  __ xorl(locations->Out().AsX86().AsCpuRegister(), Immediate(1));
726}
727
728}  // namespace x86
729}  // namespace art
730