Add Dalvik register allocation codegen.

Change-Id: I8842b1b03ff3fa362b69d386cc5927be6d65b460
diff --git a/build/Android.common.mk b/build/Android.common.mk
index d28cc83..c7bfbe5 100644
--- a/build/Android.common.mk
+++ b/build/Android.common.mk
@@ -216,6 +216,7 @@
 ifeq ($(ART_USE_LLVM_COMPILER),true)
 LIBART_COMMON_SRC_FILES += \
 	src/compiler_llvm/compiler_llvm.cc \
+	src/compiler_llvm/dalvik_reg.cc \
 	src/compiler_llvm/frontend.cc \
 	src/compiler_llvm/ir_builder.cc \
 	src/compiler_llvm/inferred_reg_category_map.cc \
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;
+  }
+}
diff --git a/src/compiler_llvm/dalvik_reg.h b/src/compiler_llvm/dalvik_reg.h
new file mode 100644
index 0000000..e6e5b05
--- /dev/null
+++ b/src/compiler_llvm/dalvik_reg.h
@@ -0,0 +1,77 @@
+/*
+ * 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.
+ */
+
+#ifndef ART_SRC_COMPILER_LLVM_DALVIK_REG_H_
+#define ART_SRC_COMPILER_LLVM_DALVIK_REG_H_
+
+#include "backend_types.h"
+
+#include <stdint.h>
+
+namespace llvm {
+  class Type;
+  class Value;
+}
+
+namespace art {
+namespace compiler_llvm {
+
+class IRBuilder;
+class MethodCompiler;
+
+class DalvikReg {
+ public:
+  static DalvikReg* CreateLocalVarReg(MethodCompiler& method_compiler,
+                                      uint32_t reg_idx);
+
+  static DalvikReg* CreateRetValReg(MethodCompiler& method_compiler);
+
+  virtual ~DalvikReg();
+
+  llvm::Value* GetValue(JType jty, JTypeSpace space);
+
+  llvm::Value* GetValue(char shorty, JTypeSpace space) {
+    return GetValue(GetJTypeFromShorty(shorty), space);
+  }
+
+  void SetValue(JType jty, JTypeSpace space, llvm::Value* value);
+
+  void SetValue(char shorty, JTypeSpace space, llvm::Value* value) {
+    return SetValue(GetJTypeFromShorty(shorty), space, value);
+  }
+
+ protected:
+  DalvikReg(MethodCompiler& method_compiler);
+
+ private:
+  llvm::Value* GetAddr(JType jty, JTypeSpace space);
+
+  llvm::Value* RegCat1SExt(llvm::Value* value);
+  llvm::Value* RegCat1ZExt(llvm::Value* value);
+
+  llvm::Value* RegCat1Trunc(llvm::Value* value, llvm::Type* ty);
+
+  virtual llvm::Value* GetRawAddr(JType jty, JTypeSpace space) = 0;
+
+ protected:
+  MethodCompiler* method_compiler_;
+  IRBuilder& irb_;
+};
+
+} // namespace compiler_llvm
+} // namespace art
+
+#endif // ART_SRC_COMPILER_LLVM_DALVIK_REG_H_
diff --git a/src/compiler_llvm/method_compiler.cc b/src/compiler_llvm/method_compiler.cc
index 0ceca0d..31e3c07 100644
--- a/src/compiler_llvm/method_compiler.cc
+++ b/src/compiler_llvm/method_compiler.cc
@@ -29,6 +29,7 @@
 #include <iomanip>
 
 #include <llvm/Analysis/Verifier.h>
+#include <llvm/BasicBlock.h>
 #include <llvm/Function.h>
 
 namespace art {
@@ -52,12 +53,14 @@
   method_helper_(method_), method_idx_(method_idx),
   access_flags_(access_flags), module_(compiler_llvm_->GetModule()),
   context_(compiler_llvm_->GetLLVMContext()),
-  irb_(*compiler_llvm_->GetIRBuilder()), func_(NULL),
-  prologue_(NULL), basic_blocks_(code_item->insns_size_in_code_units_) {
+  irb_(*compiler_llvm_->GetIRBuilder()), func_(NULL), retval_reg_(NULL),
+  basic_block_reg_alloca_(NULL), basic_block_reg_zero_init_(NULL),
+  basic_blocks_(code_item->insns_size_in_code_units_) {
 }
 
 
 MethodCompiler::~MethodCompiler() {
+  STLDeleteElements(&regs_);
 }
 
 
@@ -123,7 +126,28 @@
 
 
 void MethodCompiler::EmitPrologue() {
-  // UNIMPLEMENTED(WARNING);
+  // Create basic blocks for prologue
+  basic_block_reg_alloca_ =
+    llvm::BasicBlock::Create(*context_, "prologue.alloca", func_);
+
+  basic_block_reg_zero_init_ =
+    llvm::BasicBlock::Create(*context_, "prologue.zeroinit", func_);
+
+  // Create register array
+  for (uint16_t r = 0; r < code_item_->registers_size_; ++r) {
+    regs_.push_back(DalvikReg::CreateLocalVarReg(*this, r));
+  }
+
+  retval_reg_.reset(DalvikReg::CreateRetValReg(*this));
+}
+
+
+void MethodCompiler::EmitPrologueLastBranch() {
+  irb_.SetInsertPoint(basic_block_reg_alloca_);
+  irb_.CreateBr(basic_block_reg_zero_init_);
+
+  irb_.SetInsertPoint(basic_block_reg_zero_init_);
+  irb_.CreateBr(GetBasicBlock(0));
 }
 
 
@@ -154,6 +178,7 @@
 
   EmitPrologue();
   EmitInstructions();
+  EmitPrologueLastBranch();
 
   // Verify the generated bitcode
   llvm::verifyFunction(*func_, llvm::PrintMessageAction);
@@ -205,5 +230,89 @@
 }
 
 
+llvm::Value* MethodCompiler::AllocDalvikLocalVarReg(RegCategory cat,
+                                                    uint32_t reg_idx) {
+
+  // Save current IR builder insert point
+  llvm::IRBuilderBase::InsertPoint irb_ip_original = irb_.saveIP();
+
+  // Alloca
+  llvm::Value* reg_addr = NULL;
+
+  switch (cat) {
+  case kRegCat1nr:
+    irb_.SetInsertPoint(basic_block_reg_alloca_);
+    reg_addr = irb_.CreateAlloca(irb_.getJIntTy(), 0,
+                                 StringPrintf("r%u", reg_idx));
+
+    irb_.SetInsertPoint(basic_block_reg_zero_init_);
+    irb_.CreateStore(irb_.getJInt(0), reg_addr);
+    break;
+
+  case kRegCat2:
+    irb_.SetInsertPoint(basic_block_reg_alloca_);
+    reg_addr = irb_.CreateAlloca(irb_.getJLongTy(), 0,
+                                 StringPrintf("w%u", reg_idx));
+
+    irb_.SetInsertPoint(basic_block_reg_zero_init_);
+    irb_.CreateStore(irb_.getJLong(0), reg_addr);
+    break;
+
+  case kRegObject:
+    irb_.SetInsertPoint(basic_block_reg_alloca_);
+    reg_addr = irb_.CreateAlloca(irb_.getJObjectTy(), 0,
+                                 StringPrintf("p%u", reg_idx));
+
+    irb_.SetInsertPoint(basic_block_reg_zero_init_);
+    irb_.CreateStore(irb_.getJNull(), reg_addr);
+    break;
+
+  default:
+    LOG(FATAL) << "Unknown register category for allocation: " << cat;
+  }
+
+  // Restore IRBuilder insert point
+  irb_.restoreIP(irb_ip_original);
+
+  DCHECK_NE(reg_addr, static_cast<llvm::Value*>(NULL));
+  return reg_addr;
+}
+
+
+llvm::Value* MethodCompiler::AllocDalvikRetValReg(RegCategory cat) {
+  // Save current IR builder insert point
+  llvm::IRBuilderBase::InsertPoint irb_ip_original = irb_.saveIP();
+
+  // Alloca
+  llvm::Value* reg_addr = NULL;
+
+  switch (cat) {
+  case kRegCat1nr:
+    irb_.SetInsertPoint(basic_block_reg_alloca_);
+    reg_addr = irb_.CreateAlloca(irb_.getJIntTy(), 0, "r_res");
+    break;
+
+  case kRegCat2:
+    irb_.SetInsertPoint(basic_block_reg_alloca_);
+    reg_addr = irb_.CreateAlloca(irb_.getJLongTy(), 0, "w_res");
+    break;
+
+  case kRegObject:
+    irb_.SetInsertPoint(basic_block_reg_alloca_);
+    reg_addr = irb_.CreateAlloca(irb_.getJObjectTy(), 0, "p_res");
+    break;
+
+  default:
+    LOG(FATAL) << "Unknown register category for allocation: " << cat;
+  }
+
+  // Restore IRBuilder insert point
+  irb_.restoreIP(irb_ip_original);
+
+  DCHECK_NE(reg_addr, static_cast<llvm::Value*>(NULL));
+  return reg_addr;
+}
+
+
 } // namespace compiler_llvm
 } // namespace art
diff --git a/src/compiler_llvm/method_compiler.h b/src/compiler_llvm/method_compiler.h
index 532ad1a..7834657 100644
--- a/src/compiler_llvm/method_compiler.h
+++ b/src/compiler_llvm/method_compiler.h
@@ -19,6 +19,7 @@
 
 #include "backend_types.h"
 #include "constants.h"
+#include "dalvik_reg.h"
 #include "dex_file.h"
 #include "dex_instruction.h"
 #include "object_utils.h"
@@ -80,8 +81,11 @@
   IRBuilder& irb_;
   llvm::Function* func_;
 
-  llvm::BasicBlock* prologue_;
+  std::vector<DalvikReg*> regs_;
+  UniquePtr<DalvikReg> retval_reg_;
 
+  llvm::BasicBlock* basic_block_reg_alloca_;
+  llvm::BasicBlock* basic_block_reg_zero_init_;
   std::vector<llvm::BasicBlock*> basic_blocks_;
 
 
@@ -100,10 +104,27 @@
 
   CompiledMethod* Compile();
 
+
+  // Code generation helper function
+
+  IRBuilder& GetIRBuilder() const {
+    return irb_;
+  }
+
+
+  // Register helper function
+
+  llvm::Value* AllocDalvikLocalVarReg(RegCategory cat, uint32_t reg_idx);
+
+  llvm::Value* AllocDalvikRetValReg(RegCategory cat);
+
+
  private:
   void CreateFunction();
 
+
   void EmitPrologue();
+  void EmitPrologueLastBranch();
   void EmitInstructions();
   void EmitInstruction(uint32_t dex_pc, Instruction const* insn);
 
@@ -123,6 +144,46 @@
   llvm::BasicBlock* CreateBasicBlockWithDexPC(uint32_t dex_pc,
                                               char const* postfix = NULL);
 
+
+  // Register helper function
+
+  llvm::Value* EmitLoadDalvikReg(uint32_t reg_idx, JType jty,
+                                 JTypeSpace space) {
+    return regs_[reg_idx]->GetValue(jty, space);
+  }
+
+  llvm::Value* EmitLoadDalvikReg(uint32_t reg_idx, char shorty,
+                                 JTypeSpace space) {
+    return EmitLoadDalvikReg(reg_idx, GetJTypeFromShorty(shorty), space);
+  }
+
+  void EmitStoreDalvikReg(uint32_t reg_idx, JType jty,
+                          JTypeSpace space, llvm::Value* new_value) {
+    regs_[reg_idx]->SetValue(jty, space, new_value);
+  }
+
+  void EmitStoreDalvikReg(uint32_t reg_idx, char shorty,
+                          JTypeSpace space, llvm::Value* new_value) {
+    EmitStoreDalvikReg(reg_idx, GetJTypeFromShorty(shorty), space, new_value);
+  }
+
+  llvm::Value* EmitLoadDalvikRetValReg(JType jty, JTypeSpace space) {
+    return retval_reg_->GetValue(jty, space);
+  }
+
+  llvm::Value* EmitLoadDalvikRetValReg(char shorty, JTypeSpace space) {
+    return EmitLoadDalvikRetValReg(GetJTypeFromShorty(shorty), space);
+  }
+
+  void EmitStoreDalvikRetValReg(JType jty, JTypeSpace space,
+                                llvm::Value* new_value) {
+    retval_reg_->SetValue(jty, space, new_value);
+  }
+
+  void EmitStoreDalvikRetValReg(char shorty, JTypeSpace space,
+                                llvm::Value* new_value) {
+    EmitStoreDalvikRetValReg(GetJTypeFromShorty(shorty), space, new_value);
+  }
 };