Add Dalvik register allocation codegen.

Change-Id: I8842b1b03ff3fa362b69d386cc5927be6d65b460
diff --git a/src/compiler_llvm/dalvik_reg.cc b/src/compiler_llvm/dalvik_reg.cc
new file mode 100644
index 0000000..379fcb0
--- /dev/null
+++ b/src/compiler_llvm/dalvik_reg.cc
@@ -0,0 +1,278 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "dalvik_reg.h"
+
+#include "ir_builder.h"
+#include "method_compiler.h"
+
+using namespace art;
+using namespace art::compiler_llvm;
+
+
+namespace {
+
+  class DalvikLocalVarReg : public DalvikReg {
+   public:
+    DalvikLocalVarReg(MethodCompiler& method_compiler, uint32_t reg_idx);
+
+    virtual ~DalvikLocalVarReg();
+
+   private:
+    virtual llvm::Value* GetRawAddr(JType jty, JTypeSpace space);
+
+   private:
+    uint32_t reg_idx_;
+    llvm::Value* reg_32_;
+    llvm::Value* reg_64_;
+    llvm::Value* reg_obj_;
+  };
+
+  class DalvikRetValReg : public DalvikReg {
+   public:
+    DalvikRetValReg(MethodCompiler& method_compiler);
+
+    virtual ~DalvikRetValReg();
+
+   private:
+    virtual llvm::Value* GetRawAddr(JType jty, JTypeSpace space);
+
+   private:
+    llvm::Value* reg_32_;
+    llvm::Value* reg_64_;
+    llvm::Value* reg_obj_;
+  };
+
+} // anonymous namespace
+
+
+//----------------------------------------------------------------------------
+// Dalvik Register
+//----------------------------------------------------------------------------
+
+DalvikReg* DalvikReg::CreateLocalVarReg(MethodCompiler& method_compiler,
+                                        uint32_t reg_idx) {
+  return new DalvikLocalVarReg(method_compiler, reg_idx);
+}
+
+
+DalvikReg* DalvikReg::CreateRetValReg(MethodCompiler& method_compiler) {
+  return new DalvikRetValReg(method_compiler);
+}
+
+
+DalvikReg::DalvikReg(MethodCompiler& method_compiler)
+: method_compiler_(&method_compiler), irb_(method_compiler.GetIRBuilder()) {
+}
+
+
+DalvikReg::~DalvikReg() {
+}
+
+
+inline llvm::Value* DalvikReg::RegCat1SExt(llvm::Value* value) {
+  return irb_.CreateSExt(value, irb_.getJIntTy());
+}
+
+
+inline llvm::Value* DalvikReg::RegCat1ZExt(llvm::Value* value) {
+  return irb_.CreateZExt(value, irb_.getJIntTy());
+}
+
+
+inline llvm::Value* DalvikReg::RegCat1Trunc(llvm::Value* value,
+                                            llvm::Type* ty) {
+  return irb_.CreateTrunc(value, ty);
+}
+
+
+llvm::Value* DalvikReg::GetValue(JType jty, JTypeSpace space) {
+  DCHECK_NE(jty, kVoid) << "Dalvik register will never be void type";
+
+  switch (space) {
+  case kReg:
+  case kField:
+    return irb_.CreateLoad(GetAddr(jty, space));
+
+  case kAccurate:
+  case kArray:
+    switch (jty) {
+    case kVoid:
+      LOG(FATAL) << "Dalvik register with void type has no value";
+      return NULL;
+
+    case kBoolean:
+    case kChar:
+    case kByte:
+    case kShort:
+      // NOTE: In array type space, boolean is truncated from i32 to i8, while
+      // in accurate type space, boolean is truncated from i32 to i1.
+      // For the other cases, array type space is equal to accurate type space.
+      return RegCat1Trunc(irb_.CreateLoad(GetAddr(jty, space)),
+                          irb_.getJType(jty, space));
+
+    case kInt:
+    case kLong:
+    case kFloat:
+    case kDouble:
+    case kObject:
+      return irb_.CreateLoad(GetAddr(jty, space));
+    }
+  }
+
+  LOG(FATAL) << "Couldn't GetValue of JType " << jty;
+  return NULL;
+}
+
+
+void DalvikReg::SetValue(JType jty, JTypeSpace space, llvm::Value* value) {
+  DCHECK_NE(jty, kVoid) << "Dalvik register will never be void type";
+
+  switch (space) {
+  case kReg:
+  case kField:
+    irb_.CreateStore(value, GetAddr(jty, space));
+    return;
+
+  case kAccurate:
+  case kArray:
+    switch (jty) {
+    case kVoid:
+      break;
+
+    case kBoolean:
+    case kChar:
+      // NOTE: In accurate type space, we have to zero extend boolean from
+      // i1 to i32, and char from i16 to i32.  In array type space, we have
+      // to zero extend boolean from i8 to i32, and char from i16 to i32.
+      irb_.CreateStore(RegCat1ZExt(value), GetAddr(jty, space));
+      break;
+
+    case kByte:
+    case kShort:
+      // NOTE: In accurate type space, we have to signed extend byte from
+      // i8 to i32, and short from i16 to i32.  In array type space, we have
+      // to sign extend byte from i8 to i32, and short from i16 to i32.
+      irb_.CreateStore(RegCat1SExt(value), GetAddr(jty, space));
+      break;
+
+    case kInt:
+    case kLong:
+    case kFloat:
+    case kDouble:
+    case kObject:
+      irb_.CreateStore(value, GetAddr(jty, space));
+      break;
+    }
+  }
+}
+
+
+llvm::Value* DalvikReg::GetAddr(JType jty, JTypeSpace space) {
+  if (jty == kFloat) {
+    return irb_.CreateBitCast(GetRawAddr(jty, space),
+                              irb_.getJFloatTy()->getPointerTo());
+  } else if (jty == kDouble) {
+    return irb_.CreateBitCast(GetRawAddr(jty, space),
+                              irb_.getJDoubleTy()->getPointerTo());
+  } else {
+    return GetRawAddr(jty, space);
+  }
+}
+
+
+//----------------------------------------------------------------------------
+// Dalvik Local Variable Register
+//----------------------------------------------------------------------------
+
+DalvikLocalVarReg::DalvikLocalVarReg(MethodCompiler& method_compiler,
+                                     uint32_t reg_idx)
+: DalvikReg(method_compiler), reg_idx_(reg_idx),
+  reg_32_(NULL), reg_64_(NULL), reg_obj_(NULL) {
+}
+
+
+DalvikLocalVarReg::~DalvikLocalVarReg() {
+}
+
+
+llvm::Value* DalvikLocalVarReg::GetRawAddr(JType jty, JTypeSpace space) {
+  switch (GetRegCategoryFromJType(jty)) {
+  case kRegCat1nr:
+    if (reg_32_ == NULL) {
+      reg_32_ = method_compiler_->AllocDalvikLocalVarReg(kRegCat1nr, reg_idx_);
+    }
+    return reg_32_;
+
+  case kRegCat2:
+    if (reg_64_ == NULL) {
+      reg_64_ = method_compiler_->AllocDalvikLocalVarReg(kRegCat2, reg_idx_);
+    }
+    return reg_64_;
+
+  case kRegObject:
+    if (reg_obj_ == NULL) {
+      reg_obj_ = method_compiler_->AllocDalvikLocalVarReg(kRegObject, reg_idx_);
+    }
+    return reg_obj_;
+
+  default:
+    LOG(FATAL) << "Unexpected register category: "
+               << GetRegCategoryFromJType(jty);
+    return NULL;
+  }
+}
+
+
+//----------------------------------------------------------------------------
+// Dalvik Returned Value Temporary Register
+//----------------------------------------------------------------------------
+
+DalvikRetValReg::DalvikRetValReg(MethodCompiler& method_compiler)
+: DalvikReg(method_compiler), reg_32_(NULL), reg_64_(NULL), reg_obj_(NULL) {
+}
+
+
+DalvikRetValReg::~DalvikRetValReg() {
+}
+
+
+llvm::Value* DalvikRetValReg::GetRawAddr(JType jty, JTypeSpace space) {
+  switch (GetRegCategoryFromJType(jty)) {
+  case kRegCat1nr:
+    if (reg_32_ == NULL) {
+      reg_32_ = method_compiler_->AllocDalvikRetValReg(kRegCat1nr);
+    }
+    return reg_32_;
+
+  case kRegCat2:
+    if (reg_64_ == NULL) {
+      reg_64_ = method_compiler_->AllocDalvikRetValReg(kRegCat2);
+    }
+    return reg_64_;
+
+  case kRegObject:
+    if (reg_obj_ == NULL) {
+      reg_obj_ = method_compiler_->AllocDalvikRetValReg(kRegObject);
+    }
+    return reg_obj_;
+
+  default:
+    LOG(FATAL) << "Unexpected register category: "
+               << GetRegCategoryFromJType(jty);
+    return NULL;
+  }
+}