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(®s_);
}
@@ -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);
+ }
};