summaryrefslogtreecommitdiffstats
path: root/src/greenland
diff options
context:
space:
mode:
authorShih-wei Liao <sliao@google.com>2012-06-12 05:55:00 -0700
committerShih-wei Liao <sliao@google.com>2012-09-15 04:15:17 -0700
commit21d28f510eb590f52810c83f1f3f37fe5f4adf46 (patch)
treef937b4d39aab322541b9b83cc5dd59d8e3f2fddd /src/greenland
parent0967a25d1482d8f7b4a26c5926263e7ffa63189f (diff)
downloadart-21d28f510eb590f52810c83f1f3f37fe5f4adf46.zip
art-21d28f510eb590f52810c83f1f3f37fe5f4adf46.tar.gz
art-21d28f510eb590f52810c83f1f3f37fe5f4adf46.tar.bz2
GBC Expander. Removed lir.
Change-Id: If8d13e36f1e6d82c2a7f7bfec62b8fb41fd8cdaa
Diffstat (limited to 'src/greenland')
-rw-r--r--src/greenland/arm/arm_codegen_machine.h28
-rw-r--r--src/greenland/dalvik_reg.cc443
-rw-r--r--src/greenland/dalvik_reg.h44
-rw-r--r--src/greenland/dex_lang.cc1803
-rw-r--r--src/greenland/dex_lang.h160
-rw-r--r--src/greenland/gbc_context.cc69
-rw-r--r--src/greenland/gbc_context.h80
-rw-r--r--src/greenland/gbc_function.h78
-rw-r--r--src/greenland/greenland.cc56
-rw-r--r--src/greenland/greenland.h11
-rw-r--r--src/greenland/inferred_reg_category_map.cc102
-rw-r--r--src/greenland/inferred_reg_category_map.h89
-rw-r--r--src/greenland/intrinsic_func_list.def602
-rw-r--r--src/greenland/intrinsic_helper.cc10
-rw-r--r--src/greenland/intrinsic_helper.h31
-rw-r--r--src/greenland/ir_builder.cc19
-rw-r--r--src/greenland/lir.h126
-rw-r--r--src/greenland/lir_frame_info.h105
-rw-r--r--src/greenland/lir_function.cc86
-rw-r--r--src/greenland/lir_function.h158
-rw-r--r--src/greenland/lir_operand.h151
-rw-r--r--src/greenland/mips/mips_codegen_machine.h28
-rw-r--r--src/greenland/mips/mips_lir.def (renamed from src/greenland/target_lir.def)8
-rw-r--r--src/greenland/register_allocator.cc291
-rw-r--r--src/greenland/register_allocator.h82
-rw-r--r--src/greenland/runtime/runtime_utils.h (renamed from src/greenland/target_lir_opcodes.h)28
-rw-r--r--src/greenland/runtime/support_alloc.cc69
-rw-r--r--src/greenland/runtime/support_cast.cc57
-rw-r--r--src/greenland/runtime/support_dexcache.cc (renamed from src/greenland/lir_desc.h)35
-rw-r--r--src/greenland/runtime/support_exception.cc85
-rw-r--r--src/greenland/runtime/support_field.cc50
-rw-r--r--src/greenland/runtime/support_thread.cc (renamed from src/greenland/lir.cc)22
-rw-r--r--src/greenland/runtime_entry_points.cc49
-rw-r--r--src/greenland/runtime_entry_points.h89
-rw-r--r--src/greenland/target_codegen_machine.cc29
-rw-r--r--src/greenland/target_codegen_machine.h38
-rw-r--r--src/greenland/target_data_layout.h74
-rw-r--r--src/greenland/target_lir_emitter.cc167
-rw-r--r--src/greenland/target_lir_emitter.h124
-rw-r--r--src/greenland/target_lir_info.h50
-rw-r--r--src/greenland/target_register_info.h79
-rw-r--r--src/greenland/target_registry.h2
-rw-r--r--src/greenland/tools/target_lir_builder_generator.cc574
43 files changed, 4098 insertions, 2183 deletions
diff --git a/src/greenland/arm/arm_codegen_machine.h b/src/greenland/arm/arm_codegen_machine.h
index c78ddf8..8639417 100644
--- a/src/greenland/arm/arm_codegen_machine.h
+++ b/src/greenland/arm/arm_codegen_machine.h
@@ -29,9 +29,27 @@ class ARMCodeGenMachine : public TargetCodeGenMachine {
ARMCodeGenMachine();
virtual ~ARMCodeGenMachine();
- virtual TargetLIREmitter* CreateLIREmitter(const llvm::Function& func,
- const OatCompilationUnit& cunit,
- DexLang::Context& dex_lang_ctx) {
+ virtual TargetLIREmitter* CreateLIREmitter() {
+ return NULL;
+ }
+
+ virtual const TargetDataLayout* GetDataLayout() const {
+ return NULL;
+ }
+
+ virtual const TargetLIRInfo* GetLIRInfo() const {
+ return NULL;
+ }
+
+ virtual const TargetRegisterInfo* GetRegisterInfo() const {
+ return NULL;
+ }
+
+ virtual const char* GetConditionCodeName(unsigned cond) const {
+ return NULL;
+ }
+
+ virtual TargetLIRBuilder* CreateLIRBuilder() {
return NULL;
}
@@ -42,6 +60,10 @@ class ARMCodeGenMachine : public TargetCodeGenMachine {
virtual TargetAssembler* GetAssembler() {
return NULL;
}
+
+ virtual std::string PrettyTargeteLIR(const LIR& lir) const {
+ return "";
+ }
};
} // namespace greenland
diff --git a/src/greenland/dalvik_reg.cc b/src/greenland/dalvik_reg.cc
index eb4a89c..3155a8c 100644
--- a/src/greenland/dalvik_reg.cc
+++ b/src/greenland/dalvik_reg.cc
@@ -16,350 +16,201 @@
#include "dalvik_reg.h"
-#include "dex_lang.h"
#include "ir_builder.h"
-#include "intrinsic_helper.h"
-
-#include <llvm/Function.h>
-
-using namespace art;
-using namespace art::greenland;
-
-namespace {
-
- class DalvikArgReg : public DalvikReg {
- public:
- DalvikArgReg(DexLang& dex_lang, unsigned reg_idx, JType jty);
-
- virtual llvm::Value* GetValue(JType jty, JTypeSpace space);
- virtual void SetValue(JType jty, JTypeSpace space, llvm::Value* value);
-
- private:
- llvm::Value* reg_addr_;
- JType jty_;
-
- inline void CheckJType(JType jty) const {
- CHECK_EQ(jty, jty_) << "Get value of type " << jty << " from Dalvik "
- "argument register v" << reg_idx_ << "(type: "
- << jty_ << ") without type coercion!";
- return;
- }
- };
-
- class DalvikLocalVarReg : public DalvikReg {
- public:
- DalvikLocalVarReg(DexLang& dex_lang, unsigned reg_idx);
-
- virtual llvm::Value* GetValue(JType jty, JTypeSpace space);
- virtual void SetValue(JType jty, JTypeSpace space, llvm::Value* value);
-
- private:
- llvm::Value* GetRawAddr(RegCategory cat);
-
- private:
- llvm::Value* reg_32_;
- llvm::Value* reg_64_;
- llvm::Value* reg_obj_;
- };
-} // anonymous namespace
+#include "dex_lang.h"
+namespace art {
+namespace greenland {
//----------------------------------------------------------------------------
// Dalvik Register
//----------------------------------------------------------------------------
-DalvikReg* DalvikReg::CreateArgReg(DexLang& dex_lang, unsigned reg_idx,
- JType jty) {
- return new DalvikArgReg(dex_lang, reg_idx, jty);
-}
-
-DalvikReg* DalvikReg::CreateLocalVarReg(DexLang& dex_lang, unsigned reg_idx) {
- return new DalvikLocalVarReg(dex_lang, reg_idx);
+DalvikReg::DalvikReg(DexLang& dex_lang, unsigned reg_idx)
+: dex_lang_(dex_lang), irb_(dex_lang.GetIRBuilder()),
+ reg_idx_(reg_idx), shadow_frame_entry_idx_(-1),
+ reg_32_(NULL), reg_64_(NULL), reg_obj_(NULL) {
}
-DalvikReg::DalvikReg(DexLang& dex_lang, unsigned reg_idx)
- : dex_lang_(dex_lang), irb_(dex_lang.GetIRBuilder()), reg_idx_(reg_idx),
- shadow_frame_entry_idx_(-1) {
+DalvikReg::~DalvikReg() {
}
-void DalvikReg::SetShadowEntry(llvm::Value* root_object) {
+void DalvikReg::SetShadowEntry(llvm::Value* object) {
if (shadow_frame_entry_idx_ < 0) {
shadow_frame_entry_idx_ = dex_lang_.AllocShadowFrameEntry(reg_idx_);
}
irb_.CreateCall2(irb_.GetIntrinsics(IntrinsicHelper::SetShadowFrameEntry),
- root_object, irb_.getInt32(shadow_frame_entry_idx_));
+ object, irb_.getInt32(shadow_frame_entry_idx_));
return;
}
-//----------------------------------------------------------------------------
-// Dalvik Argument Register
-//----------------------------------------------------------------------------
-DalvikArgReg::DalvikArgReg(DexLang& dex_lang, unsigned reg_idx, JType jty)
- : DalvikReg(dex_lang, reg_idx), jty_(jty) {
- reg_addr_ = dex_lang_.AllocateDalvikReg(jty, reg_idx);
- DCHECK(reg_addr_ != NULL);
-}
-
-llvm::Value* DalvikArgReg::GetValue(JType jty, JTypeSpace space) {
- DCHECK_NE(jty, kVoid) << "Dalvik register will never be void type";
-
- switch (space) {
- case kReg:
- case kField: {
- // Currently, kField is almost the same with kReg.
- RegCategory cat = GetRegCategoryFromJType(jty_);
- CHECK_EQ(cat, GetRegCategoryFromJType(jty)) << "Get value of type " << jty
- << "has different register "
- "category from the value "
- "contained in the register"
- << reg_idx_ << "(type: "
- << jty_ << ")";
- switch (jty_) {
- case kVoid: {
- break;
- }
- case kBoolean:
- case kChar: {
- return irb_.CreateZExt(irb_.CreateLoad(reg_addr_), irb_.GetJIntTy());
- }
- case kByte:
- case kShort: {
- return irb_.CreateSExt(irb_.CreateLoad(reg_addr_), irb_.GetJIntTy());
- }
- case kFloat: {
- return irb_.CreateBitCast(irb_.CreateLoad(reg_addr_),
- irb_.GetJIntTy());
- }
- case kDouble: {
- return irb_.CreateBitCast(irb_.CreateLoad(reg_addr_),
- irb_.GetJLongTy());
- }
- case kInt:
- case kLong:
- case kObject: {
- return irb_.CreateLoad(reg_addr_);
- }
- default: {
- LOG(FATAL) << "Unexpected register type: " << jty;
- break;
- }
- }
- break;
- }
- case kArray: {
- switch (jty) {
- case kVoid: {
- LOG(FATAL) << "Dalvik register with void type has no value";
- return NULL;
- }
- case kBoolean: {
- CheckJType(jty);
- // NOTE: In array type space, boolean is i8, while in accurate type
- // space, boolean is i1. For the other cases, array type space is
- // equal to accurate type space.
- return irb_.CreateZExt(irb_.CreateLoad(reg_addr_), irb_.GetJByteTy());
- }
- case kByte:
- case kChar:
- case kShort:
- case kInt:
- case kLong:
- case kFloat:
- case kDouble:
- case kObject: {
- CheckJType(jty);
- return irb_.CreateLoad(reg_addr_);
- }
- default: {
- LOG(FATAL) << "Unexpected register type: " << jty;
- break;
- }
- }
- }
- case kAccurate: {
- CheckJType(jty);
- return irb_.CreateLoad(reg_addr_);
- }
+llvm::Type* DalvikReg::GetRegCategoryEquivSizeTy(IRBuilder& irb, RegCategory reg_cat) {
+ switch (reg_cat) {
+ case kRegCat1nr: return irb.GetJIntTy();
+ case kRegCat2: return irb.GetJLongTy();
+ case kRegObject: return irb.GetJObjectTy();
+ default:
+ LOG(FATAL) << "Unknown register category: " << reg_cat;
+ return NULL;
}
- return NULL;
}
-void DalvikArgReg::SetValue(JType jty, JTypeSpace space, llvm::Value* value) {
- if ((jty == jty_) && (space == kAccurate)) {
- irb_.CreateStore(value, reg_addr_);
- if (jty == kObject) {
- SetShadowEntry(value);
- }
- } else {
- LOG(FATAL) << "Normal .dex file doesn't use argument register for method-"
- "local variable!";
+char DalvikReg::GetRegCategoryNamePrefix(RegCategory reg_cat) {
+ switch (reg_cat) {
+ case kRegCat1nr: return 'r';
+ case kRegCat2: return 'w';
+ case kRegObject: return 'p';
+ default:
+ LOG(FATAL) << "Unknown register category: " << reg_cat;
+ return '\0';
}
- return;
}
-//----------------------------------------------------------------------------
-// Dalvik Local Variable Register
-//----------------------------------------------------------------------------
+inline llvm::Value* DalvikReg::RegCat1SExt(llvm::Value* value) {
+ return irb_.CreateSExt(value, irb_.GetJIntTy());
+}
-DalvikLocalVarReg::DalvikLocalVarReg(DexLang& dex_lang, unsigned reg_idx)
- : DalvikReg(dex_lang, reg_idx), reg_32_(NULL), reg_64_(NULL),
- reg_obj_(NULL) {
+inline llvm::Value* DalvikReg::RegCat1ZExt(llvm::Value* value) {
+ return irb_.CreateZExt(value, irb_.GetJIntTy());
}
-llvm::Value* DalvikLocalVarReg::GetRawAddr(RegCategory cat) {
- switch (cat) {
- case kRegCat1nr: {
- if (reg_32_ == NULL) {
- reg_32_ = dex_lang_.AllocateDalvikReg(kInt, reg_idx_);
- }
- return reg_32_;
- }
- case kRegCat2: {
- if (reg_64_ == NULL) {
- reg_64_ = dex_lang_.AllocateDalvikReg(kLong, reg_idx_);
- }
- return reg_64_;
- }
- case kRegObject: {
- if (reg_obj_ == NULL) {
- reg_obj_ = dex_lang_.AllocateDalvikReg(kObject, reg_idx_);
- }
- return reg_obj_;
- }
- default: {
- LOG(FATAL) << "Unexpected register category: " << cat;
- return NULL;
- }
- }
- return NULL;
+inline llvm::Value* DalvikReg::RegCat1Trunc(llvm::Value* value,
+ llvm::Type* ty) {
+ return irb_.CreateTrunc(value, ty);
}
-llvm::Value* DalvikLocalVarReg::GetValue(JType jty, JTypeSpace space) {
+llvm::Value* DalvikReg::GetValue(JType jty, JTypeSpace space) {
DCHECK_NE(jty, kVoid) << "Dalvik register will never be void type";
+ llvm::Value* value = NULL;
switch (space) {
- case kReg:
- case kField: {
- // float and double require bitcast to get their value from the integer
- // register.
- DCHECK((jty != kFloat) && (jty != kDouble));
- return irb_.CreateLoad(GetRawAddr(GetRegCategoryFromJType(jty)));
- }
- 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 irb_.CreateTrunc(irb_.CreateLoad(GetRawAddr(kRegCat1nr)),
- irb_.GetJType(jty, space));
- }
- case kFloat: {
- return irb_.CreateBitCast(irb_.CreateLoad(GetRawAddr(kRegCat1nr)),
- irb_.GetJType(jty, space));
- }
- case kDouble: {
- return irb_.CreateBitCast(irb_.CreateLoad(GetRawAddr(kRegCat2)),
- irb_.GetJType(jty, space));
- }
- case kInt:
- case kLong:
- case kObject: {
- return irb_.CreateLoad(GetRawAddr(GetRegCategoryFromJType(jty)));
- }
- default: {
- LOG(FATAL) << "Unexpected register type: " << jty;
- break;
- }
- }
- }
- default: {
- LOG(FATAL) << "Unexpected register space: " << space;
+ case kReg:
+ case kField:
+ value = irb_.CreateLoad(GetAddr(jty));
+ break;
+
+ 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.
+ value = RegCat1Trunc(irb_.CreateLoad(GetAddr(jty)),
+ irb_.GetJType(jty, space));
+ break;
+
+ case kInt:
+ case kLong:
+ case kFloat:
+ case kDouble:
+ case kObject:
+ value = irb_.CreateLoad(GetAddr(jty));
break;
+
+ default:
+ LOG(FATAL) << "Unknown java type: " << jty;
+ return NULL;
}
+ break;
+
+ default:
+ LOG(FATAL) << "Couldn't GetValue of JType " << jty;
+ return NULL;
+ }
+
+ if (jty == kFloat || jty == kDouble) {
+ value = irb_.CreateBitCast(value, irb_.GetJType(jty, space));
}
- return NULL;
+ return value;
}
-void DalvikLocalVarReg::SetValue(JType jty, JTypeSpace space,
- llvm::Value* value) {
- DCHECK_NE(jty, kVoid) << "Dalvik register should never hold void type";
+void DalvikReg::SetValue(JType jty, JTypeSpace space, llvm::Value* value) {
+ DCHECK_NE(jty, kVoid) << "Dalvik register will never be void type";
if (jty == kObject) {
SetShadowEntry(value);
+ } else if (jty == kFloat || jty == kDouble) {
+ value = irb_.CreateBitCast(value, irb_.GetJType(jty, kReg));
}
switch (space) {
- case kReg:
- case kField: {
- // float and double require bitcast to get their value from the integer
- // register.
- DCHECK((jty != kFloat) && (jty != kDouble));
- irb_.CreateStore(value, GetRawAddr(GetRegCategoryFromJType(jty)));
- return;
+ case kReg:
+ case kField:
+ irb_.CreateStore(value, GetAddr(jty));
+ 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));
+ 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));
+ break;
+
+ case kInt:
+ case kLong:
+ case kFloat:
+ case kDouble:
+ case kObject:
+ irb_.CreateStore(value, GetAddr(jty));
+ break;
+
+ default:
+ LOG(FATAL) << "Unknown java type: " << jty;
+ }
+ }
+}
+
+llvm::Value* DalvikReg::GetAddr(JType jty) {
+ switch (GetRegCategoryFromJType(jty)) {
+ case kRegCat1nr:
+ if (reg_32_ == NULL) {
+ reg_32_ = dex_lang_.AllocateDalvikReg(kRegCat1nr, reg_idx_);
}
- 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.
- value = irb_.CreateZExt(value, irb_.GetJIntTy());
- irb_.CreateStore(value, GetRawAddr(kRegCat1nr));
- 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.
- value = irb_.CreateSExt(value, irb_.GetJIntTy());
- irb_.CreateStore(value, GetRawAddr(kRegCat1nr));
- break;
- }
- case kFloat: {
- value = irb_.CreateBitCast(value, irb_.GetJIntTy());
- irb_.CreateStore(value, GetRawAddr(kRegCat1nr));
- break;
- }
- case kDouble: {
- value = irb_.CreateBitCast(value, irb_.GetJLongTy());
- irb_.CreateStore(value, GetRawAddr(kRegCat2));
- break;
- }
- case kInt:
- case kLong:
- case kObject: {
- irb_.CreateStore(value, GetRawAddr(GetRegCategoryFromJType(jty)));
- break;
- }
- default: {
- LOG(FATAL) << "Unexpected register type: " << jty;
- return;
- }
- }
- return;
+ return reg_32_;
+
+ case kRegCat2:
+ if (reg_64_ == NULL) {
+ reg_64_ = dex_lang_.AllocateDalvikReg(kRegCat2, reg_idx_);
}
- default: {
- LOG(FATAL) << "Unexpected register space: " << space;
- return;
+ return reg_64_;
+
+ case kRegObject:
+ if (reg_obj_ == NULL) {
+ reg_obj_ = dex_lang_.AllocateDalvikReg(kRegObject, reg_idx_);
}
+ return reg_obj_;
+
+ default:
+ LOG(FATAL) << "Unexpected register category: "
+ << GetRegCategoryFromJType(jty);
+ return NULL;
}
}
+} // namespace greenland
+} // namespace art
diff --git a/src/greenland/dalvik_reg.h b/src/greenland/dalvik_reg.h
index 78247cc..93524cc 100644
--- a/src/greenland/dalvik_reg.h
+++ b/src/greenland/dalvik_reg.h
@@ -14,11 +14,14 @@
* limitations under the License.
*/
-#ifndef ART_SRC_GREENLAND_DALVIK_REG_H_
-#define ART_SRC_GREENLAND_DALVIK_REG_H_
+#ifndef ART_SRC_COMPILER_LLVM_DALVIK_REG_H_
+#define ART_SRC_COMPILER_LLVM_DALVIK_REG_H_
#include "backend_types.h"
+#include <stdint.h>
+#include <string>
+
namespace llvm {
class Type;
class Value;
@@ -27,41 +30,54 @@ namespace llvm {
namespace art {
namespace greenland {
-class DexLang;
class IRBuilder;
+class DexLang;
class DalvikReg {
public:
- static DalvikReg* CreateArgReg(DexLang& dex_lang, unsigned reg_idx,
- JType jty);
+ static llvm::Type* GetRegCategoryEquivSizeTy(IRBuilder& irb, RegCategory reg_cat);
- static DalvikReg* CreateLocalVarReg(DexLang& dex_lang, unsigned reg_idx);
+ static char GetRegCategoryNamePrefix(RegCategory reg_cat);
- virtual ~DalvikReg() { }
+ DalvikReg(DexLang& dex_lang, unsigned reg_idx);
+
+ ~DalvikReg();
+
+ llvm::Value* GetValue(JType jty, JTypeSpace space);
- virtual llvm::Value* GetValue(JType jty, JTypeSpace space) = 0;
llvm::Value* GetValue(char shorty, JTypeSpace space) {
return GetValue(GetJTypeFromShorty(shorty), space);
}
- virtual void SetValue(JType jty, JTypeSpace space, llvm::Value* value) = 0;
+ 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(DexLang& dex_lang, unsigned reg_idx);
+ private:
+ void SetShadowEntry(llvm::Value* object);
+
+ llvm::Value* GetAddr(JType jty);
+
+ llvm::Value* RegCat1SExt(llvm::Value* value);
+ llvm::Value* RegCat1ZExt(llvm::Value* value);
- void SetShadowEntry(llvm::Value* root_object);
+ llvm::Value* RegCat1Trunc(llvm::Value* value, llvm::Type* ty);
- protected:
DexLang& dex_lang_;
IRBuilder& irb_;
+
unsigned reg_idx_;
+
int shadow_frame_entry_idx_;
+
+ llvm::Value* reg_32_;
+ llvm::Value* reg_64_;
+ llvm::Value* reg_obj_;
};
} // namespace greenland
} // namespace art
-#endif // ART_SRC_GREENLAND_DALVIK_REG_H_
+#endif // ART_SRC_COMPILER_LLVM_DALVIK_REG_H_
diff --git a/src/greenland/dex_lang.cc b/src/greenland/dex_lang.cc
index 135cbd7..0e34492 100644
--- a/src/greenland/dex_lang.cc
+++ b/src/greenland/dex_lang.cc
@@ -18,8 +18,7 @@
#include "intrinsic_helper.h"
-#include "atomic.h"
-#include "inferred_reg_category_map.h"
+#include "compiler_llvm/inferred_reg_category_map.h"
#include "object.h" // FIXME: include this in oat_compilation_unit.h
#include "oat_compilation_unit.h"
#include "stl_util.h"
@@ -41,21 +40,10 @@ namespace greenland {
//----------------------------------------------------------------------------
// DexLang::Context
//----------------------------------------------------------------------------
-DexLang::Context::Context()
- : context_(), module_(NULL), ref_count_(1), mem_usage_(0) {
- module_ = new llvm::Module("art", context_);
-
- // Initialize the contents of an empty module
- // Type of "JavaObject"
- llvm::StructType::create(context_, "JavaObject");
- // Type of "Method"
- llvm::StructType::create(context_, "Method");
- // Type of "Thread"
- llvm::StructType::create(context_, "Thread");
-
+DexLang::Context::Context(llvm::Module& module)
+ : module_(module), intrinsic_helper_(NULL) {
// Initalize the DexLang intrinsics
- intrinsic_helper_ = new IntrinsicHelper(context_, *module_);
-
+ intrinsic_helper_ = new IntrinsicHelper(GetLLVMContext(), module_);
return;
}
@@ -64,42 +52,24 @@ DexLang::Context::~Context() {
return;
}
-DexLang::Context& DexLang::Context::IncRef() {
- android_atomic_inc(&ref_count_);
- return *this;
-}
-
-void DexLang::Context::DecRef() {
- int32_t old_ref_count = android_atomic_dec(&ref_count_);
- if (old_ref_count <= 1) {
- delete this;
- }
- return;
-}
-
-void DexLang::Context::AddMemUsageApproximation(size_t usage) {
- android_atomic_add(static_cast<int32_t>(usage), &mem_usage_);
- return;
-}
-
//----------------------------------------------------------------------------
// Constructor, Destructor and APIs
//----------------------------------------------------------------------------
DexLang::DexLang(DexLang::Context& context, Compiler& compiler,
OatCompilationUnit& cunit)
- : dex_lang_ctx_(context.IncRef()), compiler_(compiler), cunit_(cunit),
+ : dex_lang_ctx_(context), compiler_(compiler), cunit_(cunit),
dex_file_(cunit.GetDexFile()), code_item_(cunit.GetCodeItem()),
- dex_cache_(cunit.GetDexCache()),
+ dex_cache_(cunit.GetDexCache()), method_idx_(cunit.GetDexMethodIndex()),
context_(context.GetLLVMContext()), module_(context.GetOutputModule()),
intrinsic_helper_(context.GetIntrinsicHelper()),
irb_(context.GetLLVMContext(), context.GetOutputModule(),
context.GetIntrinsicHelper()),
func_(NULL), reg_alloc_bb_(NULL), arg_reg_init_bb_(NULL),
basic_blocks_(cunit.GetCodeItem()->insns_size_in_code_units_),
- retval_(NULL), retval_jty_(kVoid),
+ retval_reg_(NULL),
landing_pads_bb_(cunit.GetCodeItem()->tries_size_, NULL),
exception_unwind_bb_(NULL), cur_try_item_offset(-1),
- require_shadow_frame(false), num_shadow_frame_entries_(0) {
+ num_shadow_frame_entries_(0) {
if (cunit.GetCodeItem()->tries_size_ > 0) {
cur_try_item_offset = 0;
}
@@ -107,7 +77,7 @@ DexLang::DexLang(DexLang::Context& context, Compiler& compiler,
}
DexLang::~DexLang() {
- dex_lang_ctx_.DecRef();
+ delete retval_reg_;
return;
}
@@ -119,44 +89,27 @@ llvm::Function* DexLang::Build() {
!EmitPrologueLinkBasicBlocks() ||
!PrettyLayoutExceptionBasicBlocks() ||
!VerifyFunction() ||
+ // CompilerLLVM has its own optimizer
+#ifndef ART_USE_LLVM_COMPILER
!OptimizeFunction() ||
- !RemoveRedundantPendingExceptionChecks()) {
+ !RemoveRedundantPendingExceptionChecks() ||
+#endif
+ 0) {
return NULL;
}
- // NOTE: From statistic, the bitcode size is 4.5 times bigger than the
- // Dex file. Besides, we have to convert the code unit into bytes.
- // Thus, we got our magic number 9.
- dex_lang_ctx_.AddMemUsageApproximation(
- code_item_->insns_size_in_code_units_ * 900);
-
return func_;
}
-llvm::Value* DexLang::AllocateDalvikReg(JType jty, unsigned reg_idx) {
- RegCategory cat = GetRegCategoryFromJType(jty);
- llvm::Type* type = irb_.GetJType(jty, kAccurate);
-
- DCHECK_NE(type, static_cast<llvm::Type*>(NULL));
-
+llvm::Value* DexLang::AllocateDalvikReg(RegCategory cat, unsigned reg_idx) {
+ // Get reg_type and reg_name from DalvikReg
+ llvm::Type* reg_type = DalvikReg::GetRegCategoryEquivSizeTy(irb_, cat);
std::string reg_name;
- switch (cat) {
- case kRegCat1nr: {
- reg_name = StringPrintf("r%u", reg_idx);
- break;
- }
- case kRegCat2: {
- reg_name = StringPrintf("w%u", reg_idx);
- break;
- }
- case kRegObject: {
- reg_name = StringPrintf("p%u", reg_idx);
- break;
- }
- default: {
- LOG(FATAL) << "Unknown register category for allocation: " << cat;
- }
- }
+
+#if !defined(NDEBUG)
+ StringAppendF(&reg_name, "%c%u",
+ DalvikReg::GetRegCategoryNamePrefix(cat), reg_idx);
+#endif
// Save current IR builder insert point
DCHECK(reg_alloc_bb_ != NULL);
@@ -164,13 +117,12 @@ llvm::Value* DexLang::AllocateDalvikReg(JType jty, unsigned reg_idx) {
irb_.SetInsertPoint(reg_alloc_bb_);
// Alloca
- llvm::Value* reg_addr = irb_.CreateAlloca(type, 0, reg_name);
+ llvm::Value* reg_addr = irb_.CreateAlloca(reg_type, 0, reg_name);
// Restore IRBuilder insert point
irb_.restoreIP(irb_ip_original);
DCHECK_NE(reg_addr, static_cast<llvm::Value*>(NULL));
-
return reg_addr;
}
@@ -278,8 +230,8 @@ llvm::BasicBlock* DexLang::GetLandingPadBasicBlock(unsigned dex_pc) {
llvm::Value* ti_offset_value = irb_.getInt32(ti_offset);
llvm::Value* catch_handler_index_value =
- EmitInvokeIntrinsic2(dex_pc, IntrinsicHelper::FindCatchBlock,
- method_object_addr, ti_offset_value);
+ EmitInvokeIntrinsic2NoThrow(IntrinsicHelper::FindCatchBlock,
+ method_object_addr, ti_offset_value);
// Switch instruction (Go to unwind basic block by default)
llvm::SwitchInst* sw =
@@ -356,11 +308,10 @@ void DexLang::EmitGuard_DivZeroException(unsigned dex_pc,
irb_.CreateCondBr(equal_zero, block_exception, block_continue);
irb_.SetInsertPoint(block_exception);
- EmitUpdateDexPC(dex_pc);
EmitInvokeIntrinsic(dex_pc, IntrinsicHelper::ThrowDivZeroException);
- EmitBranchExceptionLandingPad(dex_pc);
irb_.SetInsertPoint(block_continue);
+ return;
}
void DexLang::EmitGuard_NullPointerException(unsigned dex_pc,
@@ -377,12 +328,11 @@ void DexLang::EmitGuard_NullPointerException(unsigned dex_pc,
irb_.SetInsertPoint(block_exception);
- EmitUpdateDexPC(dex_pc);
EmitInvokeIntrinsic(dex_pc, IntrinsicHelper::ThrowNullPointerException,
irb_.getInt32(dex_pc));
- EmitBranchExceptionLandingPad(dex_pc);
irb_.SetInsertPoint(block_continue);
+ return;
}
void
@@ -403,10 +353,8 @@ DexLang::EmitGuard_ArrayIndexOutOfBoundsException(unsigned dex_pc,
irb_.SetInsertPoint(block_exception);
- EmitUpdateDexPC(dex_pc);
EmitInvokeIntrinsic2(dex_pc, IntrinsicHelper::ThrowIndexOutOfBounds,
index, array_len);
- EmitBranchExceptionLandingPad(dex_pc);
irb_.SetInsertPoint(block_continue);
return;
@@ -420,7 +368,7 @@ void DexLang::EmitGuard_ArrayException(unsigned dex_pc,
void DexLang::EmitGuard_ExceptionLandingPad(unsigned dex_pc) {
llvm::Value* exception_pending =
- EmitInvokeIntrinsic(dex_pc, IntrinsicHelper::IsExceptionPending);
+ EmitInvokeIntrinsicNoThrow(IntrinsicHelper::IsExceptionPending);
llvm::BasicBlock* block_cont = CreateBasicBlockWithDexPC(dex_pc, "cont");
@@ -431,6 +379,7 @@ void DexLang::EmitGuard_ExceptionLandingPad(unsigned dex_pc) {
}
irb_.SetInsertPoint(block_cont);
+ return;
}
//----------------------------------------------------------------------------
@@ -446,7 +395,6 @@ void DexLang::EmitGuard_GarbageCollectionSuspend() {
// Shadow Frame
//----------------------------------------------------------------------------
void DexLang::EmitUpdateDexPC(unsigned dex_pc) {
- require_shadow_frame = true;
EmitInvokeIntrinsicNoThrow(IntrinsicHelper::UpdateDexPC,
irb_.getInt32(dex_pc));
return;
@@ -465,7 +413,7 @@ unsigned DexLang::AllocShadowFrameEntry(unsigned reg_idx) {
// Code Generation
//----------------------------------------------------------------------------
bool DexLang::CreateFunction() {
- std::string func_name(PrettyMethod(cunit_.GetDexMethodIndex(), *dex_file_,
+ std::string func_name(PrettyMethod(method_idx_, *dex_file_,
/* with_signature */false));
llvm::FunctionType* func_type = GetFunctionType();
@@ -521,54 +469,22 @@ llvm::FunctionType* DexLang::GetFunctionType() {
return llvm::FunctionType::get(ret_type, args_type, false);
}
-bool DexLang::PrepareDalvikRegs() {
- const unsigned num_regs = code_item_->registers_size_;
- const unsigned num_ins = code_item_->ins_size_;
- unsigned reg_idx = 0;
-
- // Registers v[0..(num_regs - num_ins - 1)] are used for local variable
- for (; reg_idx < (num_regs - num_ins); reg_idx++) {
- regs_.push_back(DalvikReg::CreateLocalVarReg(*this, reg_idx));
- }
-
- // Registers v[(num_regs - num_ins)..(num_regs - 1)] are used for input
- // argument
- uint32_t shorty_size;
- const char* shorty = cunit_.GetShorty(&shorty_size);
-
- if (!cunit_.IsStatic()) {
- // The first argument to non-static method is "this" object pointer
- regs_.push_back(DalvikReg::CreateArgReg(*this, reg_idx++, kObject));
- }
-
- for (unsigned i = 1; i < shorty_size; i++) {
- JType jty = GetJTypeFromShorty(shorty[i]);
- regs_.push_back(DalvikReg::CreateArgReg(*this, reg_idx++, jty));
- reg_idx++;
-
- if (GetRegCategoryFromJType(jty) == kRegCat2) {
- // Need a register pair to hold the value
- regs_.push_back(NULL);
- reg_idx++;
- }
- }
-
- CHECK_EQ(num_regs, regs_.size());
-
- return true;
-}
-
bool DexLang::EmitPrologue() {
reg_alloc_bb_ = llvm::BasicBlock::Create(context_, "prologue.alloca", func_);
arg_reg_init_bb_ =
llvm::BasicBlock::Create(context_, "prologue.arginit", func_);
- if (!PrepareDalvikRegs()) {
- return false;
+ // Create register array
+ const unsigned num_regs = code_item_->registers_size_;
+ for (unsigned i = 0; i < num_regs; i++) {
+ regs_.push_back(new DalvikReg(*this, i));
}
- //Store argument to dalvik register
+ // Register hold return value from invoke and filled-new-array
+ retval_reg_ = new DalvikReg(*this, num_regs);
+
+ // Store argument to dalvik register
irb_.SetInsertPoint(arg_reg_init_bb_);
if (!EmitPrologueAssignArgRegister()) {
return false;
@@ -617,10 +533,6 @@ bool DexLang::EmitPrologueAssignArgRegister() {
}
bool DexLang::EmitPrologueAllcaShadowFrame() {
- if (!require_shadow_frame) {
- return true;
- }
-
// Save current IR builder insert point
llvm::IRBuilderBase::InsertPoint irb_ip_original = irb_.saveIP();
@@ -644,7 +556,13 @@ bool DexLang::PrettyLayoutExceptionBasicBlocks() {
llvm::BasicBlock* last_non_exception_bb = &func_->back();
DCHECK(last_non_exception_bb != NULL);
- DCHECK_NE(last_non_exception_bb, exception_unwind_bb_);
+ if (last_non_exception_bb == exception_unwind_bb_) {
+ // There's no other expcetion landing pads therefore the only exception
+ // basic blocks is for exception unwinding which is already the tail basic
+ // block of the function
+ return true;
+ }
+
if (exception_unwind_bb_ != NULL) {
exception_unwind_bb_->moveAfter(last_non_exception_bb);
}
@@ -654,9 +572,14 @@ bool DexLang::PrettyLayoutExceptionBasicBlocks() {
landing_pads_bb_end = landing_pads_bb_.rend();
landing_pads_bb_iter != landing_pads_bb_end; landing_pads_bb_iter++) {
llvm::BasicBlock* landing_pads_bb = *landing_pads_bb_iter;
+ if (landing_pads_bb == NULL) {
+ continue;
+ }
+
// Move the successors (the cache handlers) first
llvm::TerminatorInst* inst = landing_pads_bb->getTerminator();
CHECK(inst != NULL);
+
for (unsigned i = 0, e = inst->getNumSuccessors(); i != e; i++) {
llvm::BasicBlock* catch_handler = inst->getSuccessor(i);
// One of the catch handler is the unwind basic block which is settled
@@ -665,8 +588,7 @@ bool DexLang::PrettyLayoutExceptionBasicBlocks() {
catch_handler->moveAfter(last_non_exception_bb);
}
}
- if (landing_pads_bb != NULL) {
- DCHECK_NE(last_non_exception_bb, landing_pads_bb);
+ if (last_non_exception_bb != landing_pads_bb) {
landing_pads_bb->moveAfter(last_non_exception_bb);
}
}
@@ -677,7 +599,7 @@ bool DexLang::PrettyLayoutExceptionBasicBlocks() {
bool DexLang::VerifyFunction() {
if (llvm::verifyFunction(*func_, llvm::PrintMessageAction)) {
LOG(INFO) << "Verification failed on function: "
- << PrettyMethod(cunit_.GetDexMethodIndex(), *dex_file_);
+ << PrettyMethod(method_idx_, *dex_file_);
return false;
}
return true;
@@ -813,39 +735,18 @@ llvm::Value* DexLang::EmitGetCurrentThread() {
return EmitInvokeIntrinsicNoThrow(IntrinsicHelper::GetCurrentThread);
}
-llvm::Value*
-DexLang::EmitInvokeIntrinsicNoThrow(IntrinsicHelper::IntrinsicId intr_id) {
- DCHECK(IntrinsicHelper::GetAttr(intr_id) & IntrinsicHelper::kAttrNoThrow);
- return irb_.CreateCall(intrinsic_helper_.GetIntrinsicFunction(intr_id));
+void DexLang::EmitMarkGCCard(llvm::Value* value, llvm::Value* target_addr) {
+ EmitInvokeIntrinsic2NoThrow(IntrinsicHelper::MarkGCCard, value, target_addr);
+ return;
}
llvm::Value*
DexLang::EmitInvokeIntrinsicNoThrow(IntrinsicHelper::IntrinsicId intr_id,
llvm::ArrayRef<llvm::Value*> args) {
- llvm::Function* intr = intrinsic_helper_.GetIntrinsicFunction(intr_id);
DCHECK(IntrinsicHelper::GetAttr(intr_id) & IntrinsicHelper::kAttrNoThrow);
- return irb_.CreateCall(intr, args);
-}
-llvm::Value*
-DexLang::EmitInvokeIntrinsic(unsigned dex_pc,
- IntrinsicHelper::IntrinsicId intr_id) {
llvm::Function* intr = intrinsic_helper_.GetIntrinsicFunction(intr_id);
- unsigned intr_attr = IntrinsicHelper::GetAttr(intr_id);
- bool may_throw = !(intr_attr & IntrinsicHelper::kAttrNoThrow);
-
- // Setup PC before invocation when the intrinsics may generate the exception
- if (may_throw) {
- EmitUpdateDexPC(dex_pc);
- }
-
- llvm::Value* ret_val = irb_.CreateCall(intr);
-
- if (may_throw) {
- EmitGuard_ExceptionLandingPad(dex_pc);
- }
-
- return ret_val;
+ return ((args.empty()) ? irb_.CreateCall(intr) : irb_.CreateCall(intr, args));
}
llvm::Value* DexLang::EmitInvokeIntrinsic(unsigned dex_pc,
@@ -853,38 +754,155 @@ llvm::Value* DexLang::EmitInvokeIntrinsic(unsigned dex_pc,
llvm::ArrayRef<llvm::Value*> args) {
llvm::Function* intr = intrinsic_helper_.GetIntrinsicFunction(intr_id);
unsigned intr_attr = IntrinsicHelper::GetAttr(intr_id);
- bool may_throw = !(intr_attr & IntrinsicHelper::kAttrNoThrow);
+ DCHECK(!(intr_attr & IntrinsicHelper::kAttrNoThrow));
// Setup PC before invocation when the intrinsics may generate the exception
- if (may_throw) {
- EmitUpdateDexPC(dex_pc);
- }
+ EmitUpdateDexPC(dex_pc);
- llvm::Value* ret_val = irb_.CreateCall(intr, args);
+ llvm::Value* ret_val = ((args.empty()) ? irb_.CreateCall(intr) :
+ irb_.CreateCall(intr, args));
- if (may_throw) {
+ if (intr_attr & IntrinsicHelper::kAttrDoThrow) {
+ // Directly branch to exception landingpad when the intrinsic is known to
+ // throw exception always
+ EmitBranchExceptionLandingPad(dex_pc);
+ } else {
EmitGuard_ExceptionLandingPad(dex_pc);
}
return ret_val;
}
-RegCategory DexLang::GetInferredRegCategory(unsigned dex_pc, unsigned reg_idx) {
- Compiler::MethodReference mref(dex_file_, cunit_.GetDexMethodIndex());
+compiler_llvm::RegCategory DexLang::GetInferredRegCategory(unsigned dex_pc,
+ unsigned reg_idx) {
+ Compiler::MethodReference mref(dex_file_, method_idx_);
- const InferredRegCategoryMap* map =
+ const compiler_llvm::InferredRegCategoryMap* map =
verifier::MethodVerifier::GetInferredRegCategoryMap(mref);
- CHECK_NE(map, static_cast<InferredRegCategoryMap*>(NULL));
+ CHECK_NE(map, static_cast<compiler_llvm::InferredRegCategoryMap*>(NULL));
return map->GetRegCategory(dex_pc, reg_idx);
}
+llvm::Value* DexLang::EmitLoadConstantClass(unsigned dex_pc,
+ uint32_t type_idx) {
+ llvm::Value* type_idx_value = irb_.getInt32(type_idx);
+
+ llvm::Value* method_object_addr = EmitLoadMethodObjectAddr();
+
+ llvm::Value* thread_object_addr = EmitGetCurrentThread();
+
+ if (!compiler_.CanAccessTypeWithoutChecks(method_idx_, dex_cache_,
+ *dex_file_, type_idx)) {
+ return EmitInvokeIntrinsic3(dex_pc, IntrinsicHelper::InitializeTypeAndVerifyAccess,
+ type_idx_value, method_object_addr,
+ thread_object_addr);
+ } else {
+ // Try to load the class (type) object from the dex cache
+ llvm::Value* type_object_addr =
+ EmitInvokeIntrinsicNoThrow(IntrinsicHelper::LoadTypeFromDexCache,
+ type_idx_value);
+
+ if (compiler_.CanAssumeTypeIsPresentInDexCache(dex_cache_, type_idx)) {
+ return type_object_addr;
+ }
+
+ llvm::BasicBlock* block_original = irb_.GetInsertBlock();
+
+ // Test whether class (type) object is in the dex cache or not
+ llvm::Value* equal_null =
+ irb_.CreateICmpEQ(type_object_addr, irb_.GetJNull());
+
+ llvm::BasicBlock* block_cont =
+ CreateBasicBlockWithDexPC(dex_pc, "cont");
+
+ llvm::BasicBlock* block_load_class =
+ CreateBasicBlockWithDexPC(dex_pc, "load_class");
+
+ irb_.CreateCondBr(equal_null, block_load_class, block_cont);
+
+ // Failback routine to load the class object
+ irb_.SetInsertPoint(block_load_class);
+
+ llvm::Value* loaded_type_object_addr =
+ EmitInvokeIntrinsic3(dex_pc, IntrinsicHelper::InitializeType,
+ type_idx_value, method_object_addr,
+ thread_object_addr);
+
+ llvm::BasicBlock* block_after_load_class = irb_.GetInsertBlock();
+
+ irb_.CreateBr(block_cont);
+
+ // Now the class object must be loaded
+ irb_.SetInsertPoint(block_cont);
+
+ llvm::PHINode* phi = irb_.CreatePHI(irb_.GetJObjectTy(), 2);
+
+ phi->addIncoming(type_object_addr, block_original);
+ phi->addIncoming(loaded_type_object_addr, block_after_load_class);
+
+ return phi;
+ }
+}
+
llvm::Value* DexLang::EmitLoadArrayLength(llvm::Value* array) {
// Load array length
return EmitInvokeIntrinsicNoThrow(IntrinsicHelper::ArrayLength, array);
}
+llvm::Value* DexLang::EmitAllocNewArray(unsigned dex_pc, int32_t length,
+ uint32_t type_idx,
+ bool is_filled_new_array) {
+ bool skip_access_check = compiler_.CanAccessTypeWithoutChecks(method_idx_,
+ dex_cache_,
+ *dex_file_,
+ type_idx);
+
+ llvm::Value* array_length_value;
+ IntrinsicHelper::IntrinsicId intrinsic;
+
+ // Select intrinsic and load the array length
+ if (is_filled_new_array) {
+ intrinsic =
+ skip_access_check ? IntrinsicHelper::CheckAndAllocArray :
+ IntrinsicHelper::CheckAndAllocArrayWithAccessCheck;
+ array_length_value = irb_.getInt32(length);
+ } else {
+ intrinsic =
+ skip_access_check ? IntrinsicHelper::AllocArray :
+ IntrinsicHelper::AllocArrayWithAccessCheck;
+ array_length_value = EmitLoadDalvikReg(length, kInt, kAccurate);
+ }
+
+ llvm::Constant* type_index_value = irb_.getInt32(type_idx);
+
+ llvm::Value* method_object_addr = EmitLoadMethodObjectAddr();
+
+ llvm::Value* thread_object_addr = EmitGetCurrentThread();
+
+ llvm::Value* array_addr = EmitInvokeIntrinsic4(dex_pc, intrinsic,
+ type_index_value,
+ method_object_addr,
+ array_length_value,
+ thread_object_addr);
+
+ return array_addr;
+}
+
+llvm::Value* DexLang::EmitCompareResultSelection(llvm::Value* cmp_eq,
+ llvm::Value* cmp_lt) {
+
+ llvm::Constant* zero = irb_.GetJInt(0);
+ llvm::Constant* pos1 = irb_.GetJInt(1);
+ llvm::Constant* neg1 = irb_.GetJInt(-1);
+
+ llvm::Value* result_lt = irb_.CreateSelect(cmp_lt, neg1, pos1);
+ llvm::Value* result_eq = irb_.CreateSelect(cmp_eq, zero, result_lt);
+
+ return result_eq;
+}
+
llvm::Value*
DexLang::EmitLoadStaticStorage(unsigned dex_pc, unsigned type_idx) {
llvm::BasicBlock* block_load_static =
@@ -896,8 +914,8 @@ DexLang::EmitLoadStaticStorage(unsigned dex_pc, unsigned type_idx) {
// Load static storage from dex cache
llvm::Value* storage_object_addr =
- EmitInvokeIntrinsic(dex_pc, IntrinsicHelper::LoadClassSSBFromDexCache,
- type_idx_value);
+ EmitInvokeIntrinsicNoThrow(IntrinsicHelper::LoadClassSSBFromDexCache,
+ type_idx_value);
llvm::BasicBlock* block_original = irb_.GetInsertBlock();
@@ -1002,6 +1020,38 @@ llvm::Value* DexLang::EmitIntArithmResultComputation(unsigned dex_pc,
return NULL;
}
+llvm::Value*
+DexLang::EmitIntShiftArithmResultComputation(uint32_t dex_pc,
+ llvm::Value* lhs,
+ llvm::Value* rhs,
+ IntShiftArithmKind arithm,
+ JType op_jty) {
+ DCHECK(op_jty == kInt || op_jty == kLong) << op_jty;
+
+ if (op_jty == kInt) {
+ rhs = irb_.CreateAnd(rhs, 0x1f);
+ } else {
+ llvm::Value* masked_rhs = irb_.CreateAnd(rhs, 0x3f);
+ rhs = irb_.CreateZExt(masked_rhs, irb_.GetJLongTy());
+ }
+
+ switch (arithm) {
+ case kIntArithm_Shl: {
+ return irb_.CreateShl(lhs, rhs);
+ }
+ case kIntArithm_Shr: {
+ return irb_.CreateAShr(lhs, rhs);
+ }
+ case kIntArithm_UShr: {
+ return irb_.CreateLShr(lhs, rhs);
+ }
+ default: {
+ LOG(FATAL) << "Unknown integer shift arithmetic kind: " << arithm;
+ return NULL;
+ }
+ }
+}
+
llvm::Value* DexLang::EmitIntDivRemResultComputation(unsigned dex_pc,
llvm::Value* dividend,
llvm::Value* divisor,
@@ -1035,7 +1085,7 @@ llvm::Value* DexLang::EmitIntDivRemResultComputation(unsigned dex_pc,
}
}
- return EmitInvokeIntrinsic2(dex_pc, arithm_intrinsic, dividend, divisor);
+ return EmitInvokeIntrinsic2NoThrow(arithm_intrinsic, dividend, divisor);
}
//----------------------------------------------------------------------------
@@ -1069,17 +1119,8 @@ void DexLang::EmitInsn_MoveResult(unsigned dex_pc, const Instruction* insn,
JType jty) {
DecodedInstruction dec_insn(insn);
- CHECK(retval_ != NULL) << "move-result must immediately after an invoke-kind "
- "instruction";
- // Check the type
- CHECK_EQ(irb_.GetJType(jty, kReg), irb_.GetJType(retval_jty_, kReg))
- << "Mismatch type between the value from the most recent invoke-kind "
- "instruction (" << retval_jty_ << ") and the kind of move-result "
- "used! (" << jty << ")";
-
- EmitStoreDalvikReg(dec_insn.vA, retval_jty_, kReg, retval_);
-
- retval_ = NULL;
+ llvm::Value* src_value = EmitLoadDalvikRetValReg(jty, kReg);
+ EmitStoreDalvikReg(dec_insn.vA, jty, kReg, src_value);
irb_.CreateBr(GetNextBasicBlock(dex_pc));
return;
@@ -1097,6 +1138,18 @@ void DexLang::EmitInsn_MoveException(unsigned dex_pc, const Instruction* insn) {
return;
}
+void DexLang::EmitInsn_ThrowException(unsigned dex_pc,
+ const Instruction* insn) {
+ DecodedInstruction dec_insn(insn);
+
+ llvm::Value* exception_addr =
+ EmitLoadDalvikReg(dec_insn.vA, kObject, kAccurate);
+
+ EmitInvokeIntrinsic(dex_pc, IntrinsicHelper::ThrowException, exception_addr);
+
+ return;
+}
+
void DexLang::EmitInsn_ReturnVoid(unsigned dex_pc, const Instruction* insn) {
// Garbage collection safe-point
EmitGuard_GarbageCollectionSuspend();
@@ -1192,18 +1245,230 @@ void DexLang::EmitInsn_LoadConstantString(unsigned dex_pc,
uint32_t string_idx = dec_insn.vB;
llvm::Value* string_idx_value = irb_.getInt32(string_idx);
- IntrinsicHelper::IntrinsicId intrinsic = IntrinsicHelper::UnknownId;
- if (compiler_.CanAssumeStringIsPresentInDexCache(dex_cache_, string_idx)) {
- intrinsic = IntrinsicHelper::ConstStringFast;
+ llvm::Value* string_addr =
+ EmitInvokeIntrinsicNoThrow(IntrinsicHelper::LoadStringFromDexCache,
+ string_idx_value);
+
+ if (!compiler_.CanAssumeStringIsPresentInDexCache(dex_cache_, string_idx)) {
+ llvm::BasicBlock* block_str_exist =
+ CreateBasicBlockWithDexPC(dex_pc, "str_exist");
+
+ llvm::BasicBlock* block_str_resolve =
+ CreateBasicBlockWithDexPC(dex_pc, "str_resolve");
+
+ // Test: Is the string resolved and in the dex cache?
+ llvm::Value* equal_null = irb_.CreateICmpEQ(string_addr, irb_.GetJNull());
+
+ irb_.CreateCondBr(equal_null, block_str_resolve, block_str_exist);
+
+ // String is resolved, go to next basic block.
+ irb_.SetInsertPoint(block_str_exist);
+ EmitStoreDalvikReg(dec_insn.vA, kObject, kAccurate, string_addr);
+ irb_.CreateBr(GetNextBasicBlock(dex_pc));
+
+ // String is not resolved yet, resolve it now.
+ irb_.SetInsertPoint(block_str_resolve);
+
+ llvm::Value* method_object_addr = EmitLoadMethodObjectAddr();
+
+ string_addr = EmitInvokeIntrinsic2(dex_pc, IntrinsicHelper::ResolveString,
+ method_object_addr, string_idx_value);
+ }
+
+ EmitStoreDalvikReg(dec_insn.vA, kObject, kAccurate, string_addr);
+
+ irb_.CreateBr(GetNextBasicBlock(dex_pc));
+ return;
+}
+
+void DexLang::EmitInsn_LoadConstantClass(unsigned dex_pc,
+ const Instruction* insn) {
+ DecodedInstruction dec_insn(insn);
+
+ llvm::Value* type_object_addr = EmitLoadConstantClass(dex_pc, dec_insn.vB);
+ EmitStoreDalvikReg(dec_insn.vA, kObject, kAccurate, type_object_addr);
+
+ irb_.CreateBr(GetNextBasicBlock(dex_pc));
+ return;
+}
+
+void DexLang::EmitInsn_MonitorEnter(unsigned dex_pc, const Instruction* insn) {
+ DecodedInstruction dec_insn(insn);
+
+ llvm::Value* object_addr =
+ EmitLoadDalvikReg(dec_insn.vA, kObject, kAccurate);
+
+ EmitGuard_NullPointerException(dex_pc, object_addr);
+
+ llvm::Value* thread_object_addr = EmitGetCurrentThread();
+
+ EmitInvokeIntrinsic2NoThrow(IntrinsicHelper::LockObject,
+ object_addr, thread_object_addr);
+
+ irb_.CreateBr(GetNextBasicBlock(dex_pc));
+ return;
+}
+
+void DexLang::EmitInsn_MonitorExit(unsigned dex_pc, const Instruction* insn) {
+ DecodedInstruction dec_insn(insn);
+
+ llvm::Value* object_addr =
+ EmitLoadDalvikReg(dec_insn.vA, kObject, kAccurate);
+
+ EmitGuard_NullPointerException(dex_pc, object_addr);
+
+ llvm::Value* thread_object_addr = EmitGetCurrentThread();
+
+ EmitInvokeIntrinsic2(dex_pc, IntrinsicHelper::UnlockObject,
+ object_addr, thread_object_addr);
+
+ irb_.CreateBr(GetNextBasicBlock(dex_pc));
+ return;
+}
+
+void DexLang::EmitInsn_CheckCast(unsigned dex_pc, const Instruction* insn) {
+ DecodedInstruction dec_insn(insn);
+
+ llvm::BasicBlock* block_test_class =
+ CreateBasicBlockWithDexPC(dex_pc, "test_class");
+
+ llvm::BasicBlock* block_test_sub_class =
+ CreateBasicBlockWithDexPC(dex_pc, "test_sub_class");
+
+ llvm::Value* object_addr =
+ EmitLoadDalvikReg(dec_insn.vA, kObject, kAccurate);
+
+ // Test: Is the reference equal to null? Act as no-op when it is null.
+ llvm::Value* equal_null = irb_.CreateICmpEQ(object_addr, irb_.GetJNull());
+
+ irb_.CreateCondBr(equal_null,
+ GetNextBasicBlock(dex_pc),
+ block_test_class);
+
+ // Test: Is the object instantiated from the given class?
+ irb_.SetInsertPoint(block_test_class);
+ llvm::Value* type_object_addr = EmitLoadConstantClass(dex_pc, dec_insn.vB);
+ DCHECK_EQ(Object::ClassOffset().Int32Value(), 0);
+
+ llvm::PointerType* jobject_ptr_ty = irb_.GetJObjectTy();
+
+ llvm::Value* object_type_field_addr =
+ irb_.CreateBitCast(object_addr, jobject_ptr_ty->getPointerTo());
+
+ llvm::Value* object_type_object_addr =
+ irb_.CreateLoad(object_type_field_addr);
+
+ llvm::Value* equal_class =
+ irb_.CreateICmpEQ(type_object_addr, object_type_object_addr);
+
+ irb_.CreateCondBr(equal_class,
+ GetNextBasicBlock(dex_pc),
+ block_test_sub_class);
+
+ // Test: Is the object instantiated from the subclass of the given class?
+ irb_.SetInsertPoint(block_test_sub_class);
+
+ EmitInvokeIntrinsic2(dex_pc, IntrinsicHelper::CheckCast,
+ type_object_addr, object_type_object_addr);
+
+ irb_.CreateBr(GetNextBasicBlock(dex_pc));
+ return;
+}
+
+void DexLang::EmitInsn_InstanceOf(unsigned dex_pc, const Instruction* insn) {
+ DecodedInstruction dec_insn(insn);
+
+ llvm::Constant* zero = irb_.GetJInt(0);
+ llvm::Constant* one = irb_.GetJInt(1);
+
+ llvm::BasicBlock* block_nullp = CreateBasicBlockWithDexPC(dex_pc, "nullp");
+
+ llvm::BasicBlock* block_test_class =
+ CreateBasicBlockWithDexPC(dex_pc, "test_class");
+
+ llvm::BasicBlock* block_class_equals =
+ CreateBasicBlockWithDexPC(dex_pc, "class_eq");
+
+ llvm::BasicBlock* block_test_sub_class =
+ CreateBasicBlockWithDexPC(dex_pc, "test_sub_class");
+
+ llvm::Value* object_addr =
+ EmitLoadDalvikReg(dec_insn.vB, kObject, kAccurate);
+
+ // Overview of the following code :
+ // We check for null, if so, then false, otherwise check for class == . If so
+ // then true, otherwise do callout slowpath.
+ //
+ // Test: Is the reference equal to null? Set 0 when it is null.
+ llvm::Value* equal_null = irb_.CreateICmpEQ(object_addr, irb_.GetJNull());
+
+ irb_.CreateCondBr(equal_null, block_nullp, block_test_class);
+
+ irb_.SetInsertPoint(block_nullp);
+ EmitStoreDalvikReg(dec_insn.vA, kInt, kAccurate, zero);
+ irb_.CreateBr(GetNextBasicBlock(dex_pc));
+
+ // Test: Is the object instantiated from the given class?
+ irb_.SetInsertPoint(block_test_class);
+ llvm::Value* type_object_addr = EmitLoadConstantClass(dex_pc, dec_insn.vC);
+ DCHECK_EQ(Object::ClassOffset().Int32Value(), 0);
+
+ llvm::PointerType* jobject_ptr_ty = irb_.GetJObjectTy();
+
+ llvm::Value* object_type_field_addr =
+ irb_.CreateBitCast(object_addr, jobject_ptr_ty->getPointerTo());
+
+ llvm::Value* object_type_object_addr =
+ irb_.CreateLoad(object_type_field_addr);
+
+ llvm::Value* equal_class =
+ irb_.CreateICmpEQ(type_object_addr, object_type_object_addr);
+
+ irb_.CreateCondBr(equal_class, block_class_equals, block_test_sub_class);
+
+ irb_.SetInsertPoint(block_class_equals);
+ EmitStoreDalvikReg(dec_insn.vA, kInt, kAccurate, one);
+ irb_.CreateBr(GetNextBasicBlock(dex_pc));
+
+ // Test: Is the object instantiated from the subclass of the given class?
+ irb_.SetInsertPoint(block_test_sub_class);
+
+ llvm::Value* result =
+ EmitInvokeIntrinsic2NoThrow(IntrinsicHelper::IsAssignable,
+ type_object_addr, object_type_object_addr);
+
+ EmitStoreDalvikReg(dec_insn.vA, kInt, kAccurate, result);
+
+ irb_.CreateBr(GetNextBasicBlock(dex_pc));
+ return;
+}
+
+void DexLang::EmitInsn_NewInstance(unsigned dex_pc, const Instruction* insn) {
+ DecodedInstruction dec_insn(insn);
+
+ IntrinsicHelper::IntrinsicId alloc_intrinsic;
+ if (compiler_.CanAccessInstantiableTypeWithoutChecks(method_idx_,
+ dex_cache_,
+ *dex_file_,
+ dec_insn.vB)) {
+ alloc_intrinsic = IntrinsicHelper::AllocObject;
} else {
- intrinsic = IntrinsicHelper::ConstString;
+ alloc_intrinsic = IntrinsicHelper::AllocObjectWithAccessCheck;
}
- llvm::Value* string_addr =
- EmitInvokeIntrinsic(dex_pc, intrinsic, string_idx_value);
+ llvm::Constant* type_index_value = irb_.getInt32(dec_insn.vB);
- EmitStoreDalvikReg(dec_insn.vA, kObject, kAccurate, string_addr);
+ llvm::Value* method_object_addr = EmitLoadMethodObjectAddr();
+
+ llvm::Value* thread_object_addr = EmitGetCurrentThread();
+
+ llvm::Value* object_addr = EmitInvokeIntrinsic3(dex_pc, alloc_intrinsic,
+ type_index_value,
+ method_object_addr,
+ thread_object_addr);
+
+ EmitStoreDalvikReg(dec_insn.vA, kObject, kAccurate, object_addr);
irb_.CreateBr(GetNextBasicBlock(dex_pc));
return;
@@ -1239,13 +1504,8 @@ void DexLang::EmitInsn_ArrayLength(unsigned dex_pc, const Instruction* insn) {
void DexLang::EmitInsn_NewArray(unsigned dex_pc, const Instruction* insn) {
DecodedInstruction dec_insn(insn);
- // Prepare argument to intrinsic
- llvm::Value* array_length = EmitLoadDalvikReg(dec_insn.vB, kInt, kAccurate);
- llvm::Value* type_idx = irb_.getInt32(dec_insn.vC);
-
- llvm::Value* array_addr =
- EmitInvokeIntrinsic2(dex_pc, IntrinsicHelper::NewArray,
- array_length, type_idx);
+ llvm::Value* array_addr = EmitAllocNewArray(dex_pc, dec_insn.vB, dec_insn.vC,
+ /* is_filled_new_array */false);
EmitStoreDalvikReg(dec_insn.vA, kObject, kAccurate, array_addr);
@@ -1253,25 +1513,116 @@ void DexLang::EmitInsn_NewArray(unsigned dex_pc, const Instruction* insn) {
return;
}
+void DexLang::EmitInsn_FilledNewArray(unsigned dex_pc, const Instruction* insn,
+ bool is_range) {
+ DecodedInstruction dec_insn(insn);
+
+ llvm::Value* object_addr = EmitAllocNewArray(dex_pc, dec_insn.vA, dec_insn.vB,
+ /* is_filled_new_array */true);
+
+ if (dec_insn.vA > 0) {
+ // Check for the element type
+ uint32_t type_desc_len = 0;
+ const char* type_desc =
+ dex_file_->StringByTypeIdx(dec_insn.vB, &type_desc_len);
+
+ DCHECK_GE(type_desc_len, 2u); // should be guaranteed by verifier
+ DCHECK_EQ(type_desc[0], '['); // should be guaranteed by verifier
+
+ // NOTE: Currently filled-new-array only supports 'L', '[', and 'I' as the
+ // element, therefore the element is either a primitive int or a reference
+ JType element_jty = ((type_desc[1] == 'I') ? kInt : kObject);
+
+ std::vector<llvm::Value*> args;
+ // Destination array object
+ args.push_back(object_addr);
+ // Type of the array element
+ //
+ // FIXME: Actually, dec_insn.vB (type_idx of the element) should be here to
+ // the intrinsic instead of element_jty. However, since GBCExpander cannot
+ // know which dex_file this filled-new-array instruction associated with, it
+ // is unable to know the exact type of the type_idx is. In the near future,
+ // metadata will be used to record the type information (i.e., type_desc)
+ args.push_back(irb_.getInt32(element_jty));
+
+ for (uint32_t i = 0; i < dec_insn.vA; ++i) {
+ int reg_index;
+ if (is_range) {
+ reg_index = dec_insn.vC + i;
+ } else {
+ reg_index = dec_insn.arg[i];
+ }
+
+ llvm::Value* reg_value =
+ EmitLoadDalvikReg(reg_index, element_jty, kAccurate);
+
+ args.push_back(reg_value);
+ }
+
+ EmitInvokeIntrinsicNoThrow(IntrinsicHelper::FilledNewArray, args);
+ }
+
+ EmitStoreDalvikRetValReg(kObject, kAccurate, object_addr);
+
+ irb_.CreateBr(GetNextBasicBlock(dex_pc));
+ return;
+}
+
+void DexLang::EmitInsn_FillArrayData(unsigned dex_pc, const Instruction* insn) {
+ DecodedInstruction dec_insn(insn);
+
+ // Read the payload
+ int32_t payload_offset = static_cast<int32_t>(dex_pc) +
+ static_cast<int32_t>(dec_insn.vB);
+
+ const Instruction::ArrayDataPayload* payload =
+ reinterpret_cast<const Instruction::ArrayDataPayload*>(
+ code_item_->insns_ + payload_offset);
+
+ // Load array object
+ llvm::Value* array_addr = EmitLoadDalvikReg(dec_insn.vA, kObject, kAccurate);
+
+ if (payload->element_count == 0) {
+ // When the number of the elements in the payload is zero, we don't have
+ // to copy any numbers. However, we should check whether the array object
+ // address is equal to null or not.
+ EmitGuard_NullPointerException(dex_pc, array_addr);
+ } else {
+ // To save the code size, we are going to call the runtime function to
+ // copy the content from DexFile.
+
+ // NOTE: We will check for the NullPointerException in the runtime.
+ llvm::Value* method_object_addr = EmitLoadMethodObjectAddr();
+
+ EmitInvokeIntrinsic4(dex_pc, IntrinsicHelper::FillArrayData,
+ method_object_addr, irb_.getInt32(dex_pc), array_addr,
+ irb_.getInt32(payload_offset));
+ }
+
+ irb_.CreateBr(GetNextBasicBlock(dex_pc));
+ return;
+}
+
void DexLang::EmitInsn_UnaryConditionalBranch(unsigned dex_pc,
const Instruction* insn,
CondBranchKind cond) {
DecodedInstruction dec_insn(insn);
- int8_t src_reg_cat = GetInferredRegCategory(dex_pc, dec_insn.vA);
+ compiler_llvm::RegCategory src_reg_cat =
+ GetInferredRegCategory(dex_pc, dec_insn.vA);
- DCHECK_NE(kRegUnknown, src_reg_cat);
- DCHECK_NE(kRegCat2, src_reg_cat);
+ DCHECK_NE(compiler_llvm::kRegUnknown, src_reg_cat);
+ DCHECK_NE(compiler_llvm::kRegCat2, src_reg_cat);
int32_t branch_offset = dec_insn.vB;
llvm::Value* src1_value;
llvm::Value* src2_value;
- if (src_reg_cat == kRegZero) {
+ if (src_reg_cat == compiler_llvm::kRegZero) {
src1_value = irb_.getInt32(0);
src2_value = irb_.getInt32(0);
- } else if (src_reg_cat == kRegCat1nr) {
+ } else if (src_reg_cat == compiler_llvm::kRegCat1nr) {
src1_value = EmitLoadDalvikReg(dec_insn.vA, kInt, kReg);
src2_value = irb_.getInt32(0);
} else {
@@ -1341,8 +1692,7 @@ void DexLang::EmitInsn_BinaryConditionalBranch(unsigned dex_pc,
}
}
- llvm::Value* cond_value =
- EmitConditionResult(src1_value, src2_value, cond);
+ llvm::Value* cond_value = EmitConditionResult(src1_value, src2_value, cond);
irb_.CreateCondBr(cond_value,
GetBasicBlock(dex_pc + branch_offset),
@@ -1350,6 +1700,93 @@ void DexLang::EmitInsn_BinaryConditionalBranch(unsigned dex_pc,
return;
}
+void DexLang::EmitInsn_PackedSwitch(unsigned dex_pc, const Instruction* insn) {
+ DecodedInstruction dec_insn(insn);
+
+ int32_t payload_offset = static_cast<int32_t>(dex_pc) +
+ static_cast<int32_t>(dec_insn.vB);
+
+ const Instruction::PackedSwitchPayload* payload =
+ reinterpret_cast<const Instruction::PackedSwitchPayload*>(
+ code_item_->insns_ + payload_offset);
+
+ llvm::Value* value = EmitLoadDalvikReg(dec_insn.vA, kInt, kAccurate);
+
+ llvm::SwitchInst* sw =
+ irb_.CreateSwitch(value, GetNextBasicBlock(dex_pc), payload->case_count);
+
+ for (uint16_t i = 0; i < payload->case_count; ++i) {
+ sw->addCase(irb_.getInt32(payload->first_key + i),
+ GetBasicBlock(dex_pc + payload->targets[i]));
+ }
+ return;
+}
+
+void DexLang::EmitInsn_SparseSwitch(unsigned dex_pc, const Instruction* insn) {
+ DecodedInstruction dec_insn(insn);
+
+ int32_t payload_offset = static_cast<int32_t>(dex_pc) +
+ static_cast<int32_t>(dec_insn.vB);
+
+ const Instruction::SparseSwitchPayload* payload =
+ reinterpret_cast<const Instruction::SparseSwitchPayload*>(
+ code_item_->insns_ + payload_offset);
+
+ const int32_t* keys = payload->GetKeys();
+ const int32_t* targets = payload->GetTargets();
+
+ llvm::Value* value = EmitLoadDalvikReg(dec_insn.vA, kInt, kAccurate);
+
+ llvm::SwitchInst* sw =
+ irb_.CreateSwitch(value, GetNextBasicBlock(dex_pc), payload->case_count);
+
+ for (size_t i = 0; i < payload->case_count; ++i) {
+ sw->addCase(irb_.getInt32(keys[i]), GetBasicBlock(dex_pc + targets[i]));
+ }
+ return;
+}
+
+void DexLang::EmitInsn_FPCompare(unsigned dex_pc, const Instruction* insn,
+ JType fp_jty, bool gt_bias) {
+ DecodedInstruction dec_insn(insn);
+
+ DCHECK(fp_jty == kFloat || fp_jty == kDouble) << "JType: " << fp_jty;
+
+ llvm::Value* src1_value = EmitLoadDalvikReg(dec_insn.vB, fp_jty, kAccurate);
+ llvm::Value* src2_value = EmitLoadDalvikReg(dec_insn.vC, fp_jty, kAccurate);
+
+ llvm::Value* cmp_eq = irb_.CreateFCmpOEQ(src1_value, src2_value);
+ llvm::Value* cmp_lt;
+
+ if (gt_bias) {
+ cmp_lt = irb_.CreateFCmpOLT(src1_value, src2_value);
+ } else {
+ cmp_lt = irb_.CreateFCmpULT(src1_value, src2_value);
+ }
+
+ llvm::Value* result = EmitCompareResultSelection(cmp_eq, cmp_lt);
+ EmitStoreDalvikReg(dec_insn.vA, kInt, kAccurate, result);
+
+ irb_.CreateBr(GetNextBasicBlock(dex_pc));
+ return;
+}
+
+void DexLang::EmitInsn_LongCompare(unsigned dex_pc, const Instruction* insn) {
+ DecodedInstruction dec_insn(insn);
+
+ llvm::Value* src1_value = EmitLoadDalvikReg(dec_insn.vB, kLong, kAccurate);
+ llvm::Value* src2_value = EmitLoadDalvikReg(dec_insn.vC, kLong, kAccurate);
+
+ llvm::Value* cmp_eq = irb_.CreateICmpEQ(src1_value, src2_value);
+ llvm::Value* cmp_lt = irb_.CreateICmpSLT(src1_value, src2_value);
+
+ llvm::Value* result = EmitCompareResultSelection(cmp_eq, cmp_lt);
+ EmitStoreDalvikReg(dec_insn.vA, kInt, kAccurate, result);
+
+ irb_.CreateBr(GetNextBasicBlock(dex_pc));
+ return;
+}
+
void DexLang::EmitInsn_AGet(unsigned dex_pc, const Instruction* insn,
JType elem_jty) {
DecodedInstruction dec_insn(insn);
@@ -1398,10 +1835,9 @@ void DexLang::EmitInsn_AGet(unsigned dex_pc, const Instruction* insn,
EmitGuard_ArrayException(dex_pc, array_addr, index_value);
- llvm::Value* array_element_value = EmitInvokeIntrinsic2(dex_pc,
- aget_intrinsic,
- array_addr,
- index_value);
+ llvm::Value* array_element_value = EmitInvokeIntrinsic2NoThrow(aget_intrinsic,
+ array_addr,
+ index_value);
EmitStoreDalvikReg(dec_insn.vA, elem_jty, kArray, array_element_value);
@@ -1451,24 +1887,218 @@ void DexLang::EmitInsn_APut(unsigned dex_pc, const Instruction* insn,
}
}
- // Construct argument list passed to the intrinsic
- llvm::Value* elem_addr = EmitLoadDalvikReg(dec_insn.vA, elem_jty, kAccurate);
llvm::Value* array_addr = EmitLoadDalvikReg(dec_insn.vB, kObject, kAccurate);
llvm::Value* index_value = EmitLoadDalvikReg(dec_insn.vC, kInt, kAccurate);
EmitGuard_ArrayException(dex_pc, array_addr, index_value);
+ llvm::Value* new_value = EmitLoadDalvikReg(dec_insn.vA, elem_jty, kArray);
+
// Check the type if an object is putting
if (elem_jty == kObject) {
EmitInvokeIntrinsic2(dex_pc, IntrinsicHelper::CheckPutArrayElement,
- elem_addr, array_addr);
+ new_value, array_addr);
+
+ EmitMarkGCCard(new_value, array_addr);
}
- EmitInvokeIntrinsic3(dex_pc, aput_intrinsic,
- elem_addr, array_addr, index_value);
+ EmitInvokeIntrinsic3NoThrow(aput_intrinsic, new_value, array_addr, index_value);
irb_.CreateBr(GetNextBasicBlock(dex_pc));
+ return;
+}
+
+void DexLang::EmitInsn_IGet(unsigned dex_pc, const Instruction* insn,
+ JType field_jty) {
+ DecodedInstruction dec_insn(insn);
+
+ uint32_t reg_idx = dec_insn.vB;
+ uint32_t field_idx = dec_insn.vC;
+
+ llvm::Value* object_addr = EmitLoadDalvikReg(reg_idx, kObject, kAccurate);
+
+ EmitGuard_NullPointerException(dex_pc, object_addr);
+
+ int field_offset;
+ bool is_volatile;
+ bool is_fast_path = compiler_.ComputeInstanceFieldInfo(field_idx, &cunit_,
+ field_offset,
+ is_volatile,
+ /* is_put */false);
+ // Select corresponding intrinsic accroding to the field type and is_fast_path
+ IntrinsicHelper::IntrinsicId iget_intrinsic = IntrinsicHelper::UnknownId;
+
+ switch (field_jty) {
+ case kInt: {
+ iget_intrinsic =
+ (is_fast_path) ? IntrinsicHelper::InstanceFieldGetFast :
+ IntrinsicHelper::InstanceFieldGet;
+ break;
+ }
+ case kLong: {
+ iget_intrinsic =
+ (is_fast_path) ? IntrinsicHelper::InstanceFieldGetWideFast :
+ IntrinsicHelper::InstanceFieldGetWide;
+ break;
+ }
+ case kObject: {
+ iget_intrinsic =
+ (is_fast_path) ? IntrinsicHelper::InstanceFieldGetObjectFast :
+ IntrinsicHelper::InstanceFieldGetObject;
+ break;
+ }
+ case kBoolean: {
+ iget_intrinsic =
+ (is_fast_path) ? IntrinsicHelper::InstanceFieldGetBooleanFast :
+ IntrinsicHelper::InstanceFieldGetBoolean;
+ break;
+ }
+ case kByte: {
+ iget_intrinsic =
+ (is_fast_path) ? IntrinsicHelper::InstanceFieldGetByteFast :
+ IntrinsicHelper::InstanceFieldGetByte;
+ break;
+ }
+ case kChar: {
+ iget_intrinsic =
+ (is_fast_path) ? IntrinsicHelper::InstanceFieldGetCharFast :
+ IntrinsicHelper::InstanceFieldGetChar;
+ break;
+ }
+ case kShort: {
+ iget_intrinsic =
+ (is_fast_path) ? IntrinsicHelper::InstanceFieldGetShortFast :
+ IntrinsicHelper::InstanceFieldGetShort;
+ break;
+ }
+ default: {
+ LOG(FATAL) << "Unexpected element type got in iget instruction!";
+ return;
+ }
+ }
+
+ llvm::Value* instance_field_value;
+
+ if (!is_fast_path) {
+ llvm::Constant* field_idx_value = irb_.getInt32(field_idx);
+
+ llvm::Value* method_object_addr = EmitLoadMethodObjectAddr();
+
+ instance_field_value = EmitInvokeIntrinsic3(dex_pc, iget_intrinsic,
+ field_idx_value,
+ method_object_addr,
+ object_addr);
+ } else {
+ DCHECK_GE(field_offset, 0);
+
+ instance_field_value =
+ EmitInvokeIntrinsic3NoThrow(iget_intrinsic,
+ irb_.getInt32(field_offset),
+ irb_.getInt1(is_volatile),
+ object_addr);
+ }
+
+ EmitStoreDalvikReg(dec_insn.vA, field_jty, kField, instance_field_value);
+
+ irb_.CreateBr(GetNextBasicBlock(dex_pc));
+ return;
+}
+
+void DexLang::EmitInsn_IPut(unsigned dex_pc, const Instruction* insn,
+ JType field_jty) {
+ DecodedInstruction dec_insn(insn);
+
+ uint32_t reg_idx = dec_insn.vB;
+ uint32_t field_idx = dec_insn.vC;
+
+ llvm::Value* object_addr = EmitLoadDalvikReg(reg_idx, kObject, kAccurate);
+
+ EmitGuard_NullPointerException(dex_pc, object_addr);
+
+ llvm::Value* new_value = EmitLoadDalvikReg(dec_insn.vA, field_jty, kField);
+
+ int field_offset;
+ bool is_volatile;
+ bool is_fast_path = compiler_.ComputeInstanceFieldInfo(field_idx, &cunit_,
+ field_offset,
+ is_volatile,
+ /* is_iput */true);
+
+ // Select corresponding intrinsic accroding to the field type and is_fast_path
+ IntrinsicHelper::IntrinsicId iput_intrinsic = IntrinsicHelper::UnknownId;
+
+ switch (field_jty) {
+ case kInt: {
+ iput_intrinsic =
+ (is_fast_path) ? IntrinsicHelper::InstanceFieldPutFast :
+ IntrinsicHelper::InstanceFieldPut;
+ break;
+ }
+ case kLong: {
+ iput_intrinsic =
+ (is_fast_path) ? IntrinsicHelper::InstanceFieldPutWideFast :
+ IntrinsicHelper::InstanceFieldPutWide;
+ break;
+ }
+ case kObject: {
+ iput_intrinsic =
+ (is_fast_path) ? IntrinsicHelper::InstanceFieldPutObjectFast :
+ IntrinsicHelper::InstanceFieldPutObject;
+ break;
+ }
+ case kBoolean: {
+ iput_intrinsic =
+ (is_fast_path) ? IntrinsicHelper::InstanceFieldPutBooleanFast :
+ IntrinsicHelper::InstanceFieldPutBoolean;
+ break;
+ }
+ case kByte: {
+ iput_intrinsic =
+ (is_fast_path) ? IntrinsicHelper::InstanceFieldPutByteFast :
+ IntrinsicHelper::InstanceFieldPutByte;
+ break;
+ }
+ case kChar: {
+ iput_intrinsic =
+ (is_fast_path) ? IntrinsicHelper::InstanceFieldPutCharFast :
+ IntrinsicHelper::InstanceFieldPutChar;
+ break;
+ }
+ case kShort: {
+ iput_intrinsic =
+ (is_fast_path) ? IntrinsicHelper::InstanceFieldPutShortFast :
+ IntrinsicHelper::InstanceFieldPutShort;
+ break;
+ }
+ default: {
+ LOG(FATAL) << "Unexpected element type got in iput instruction!";
+ return;
+ }
+ }
+
+ if (!is_fast_path) {
+ llvm::Value* field_idx_value = irb_.getInt32(field_idx);
+
+ llvm::Value* method_object_addr = EmitLoadMethodObjectAddr();
+
+ EmitInvokeIntrinsic4(dex_pc, iput_intrinsic, field_idx_value,
+ method_object_addr, object_addr, new_value);
+
+ } else {
+ DCHECK_GE(field_offset, 0);
+
+ EmitInvokeIntrinsic4NoThrow(iput_intrinsic, irb_.getInt32(field_offset),
+ irb_.getInt1(is_volatile), object_addr,
+ new_value);
+
+ // If put an object, mark the GC card table
+ if (field_jty == kObject) {
+ EmitMarkGCCard(new_value, object_addr);
+ }
+ }
+
+ irb_.CreateBr(GetNextBasicBlock(dex_pc));
return;
}
@@ -1560,8 +2190,8 @@ void DexLang::EmitInsn_SGet(unsigned dex_pc, const Instruction* insn,
llvm::Value* method_object_addr = EmitLoadMethodObjectAddr();
static_storage_addr =
- EmitInvokeIntrinsic(dex_pc, IntrinsicHelper::LoadDeclaringClassSSB,
- method_object_addr);
+ EmitInvokeIntrinsicNoThrow(IntrinsicHelper::LoadDeclaringClassSSB,
+ method_object_addr);
} else {
// Medium path, static storage base in a different class which
// requires checks that the other class is initialized
@@ -1570,9 +2200,10 @@ void DexLang::EmitInsn_SGet(unsigned dex_pc, const Instruction* insn,
}
static_field_value =
- EmitInvokeIntrinsic3(dex_pc, sget_intrinsic,
- static_storage_addr, irb_.getInt32(field_offset),
- irb_.getInt1(is_volatile));
+ EmitInvokeIntrinsic3NoThrow(sget_intrinsic,
+ static_storage_addr,
+ irb_.getInt32(field_offset),
+ irb_.getInt1(is_volatile));
}
EmitStoreDalvikReg(dec_insn.vA, field_jty, kField, static_field_value);
@@ -1668,8 +2299,8 @@ void DexLang::EmitInsn_SPut(unsigned dex_pc, const Instruction* insn,
llvm::Value* method_object_addr = EmitLoadMethodObjectAddr();
static_storage_addr =
- EmitInvokeIntrinsic(dex_pc, IntrinsicHelper::LoadDeclaringClassSSB,
- method_object_addr);
+ EmitInvokeIntrinsicNoThrow(IntrinsicHelper::LoadDeclaringClassSSB,
+ method_object_addr);
} else {
// Medium path, static storage base in a different class which
// requires checks that the other class is initialized
@@ -1677,9 +2308,14 @@ void DexLang::EmitInsn_SPut(unsigned dex_pc, const Instruction* insn,
static_storage_addr = EmitLoadStaticStorage(dex_pc, ssb_index);
}
- EmitInvokeIntrinsic4(dex_pc, sput_intrinsic,
- static_storage_addr, irb_.getInt32(field_offset),
- irb_.getInt1(is_volatile), new_value);
+ EmitInvokeIntrinsic4NoThrow(sput_intrinsic, static_storage_addr,
+ irb_.getInt32(field_offset),
+ irb_.getInt1(is_volatile), new_value);
+
+ // If put an object, mark the GC card table
+ if (field_jty == kObject) {
+ EmitMarkGCCard(new_value, static_storage_addr);
+ }
}
irb_.CreateBr(GetNextBasicBlock(dex_pc));
@@ -1725,13 +2361,40 @@ void DexLang::EmitInsn_Invoke(unsigned dex_pc, const Instruction* insn,
llvm::Value* thread_object_addr = EmitGetCurrentThread();
+ // Select intrinsic according to the invoke_type
+ IntrinsicHelper::IntrinsicId invoke_intr = IntrinsicHelper::UnknownId;
+ switch (invoke_type) {
+ case kStatic: {
+ invoke_intr = IntrinsicHelper::FindStaticMethodWithAccessCheck;
+ break;
+ }
+ case kDirect: {
+ invoke_intr = IntrinsicHelper::FindDirectMethodWithAccessCheck;
+ break;
+ }
+ case kVirtual: {
+ invoke_intr = IntrinsicHelper::FindVirtualMethodWithAccessCheck;
+ break;
+ }
+ case kSuper: {
+ invoke_intr = IntrinsicHelper::FindSuperMethodWithAccessCheck;
+ break;
+ }
+ case kInterface: {
+ invoke_intr = IntrinsicHelper::FindInterfaceMethodWithAccessCheck;
+ break;
+ }
+ default: {
+ LOG(FATAL) << "Unknown type of invoke: " << invoke_type;
+ }
+ }
+
callee_method_object_addr =
- EmitInvokeIntrinsic5(dex_pc, IntrinsicHelper::GetCalleeMethodObjAddr,
- this_addr,
+ EmitInvokeIntrinsic4(dex_pc, invoke_intr,
callee_method_idx_value,
+ this_addr,
caller_method_object_addr,
- thread_object_addr,
- irb_.getInt32(static_cast<unsigned>(invoke_type)));
+ thread_object_addr);
} else {
switch (invoke_type) {
case kStatic:
@@ -1743,18 +2406,16 @@ void DexLang::EmitInsn_Invoke(unsigned dex_pc, const Instruction* insn,
irb_.GetJMethodTy());
} else {
callee_method_object_addr =
- EmitInvokeIntrinsic(dex_pc,
- IntrinsicHelper::GetSDCalleeMethodObjAddrFast,
- callee_method_idx_value);
+ EmitInvokeIntrinsicNoThrow(IntrinsicHelper::GetSDCalleeMethodObjAddrFast,
+ callee_method_idx_value);
}
break;
}
case kVirtual: {
DCHECK(vtable_idx != -1);
callee_method_object_addr =
- EmitInvokeIntrinsic2(dex_pc,
- IntrinsicHelper::GetVirtualCalleeMethodObjAddrFast,
- irb_.getInt32(vtable_idx), this_addr);
+ EmitInvokeIntrinsic2NoThrow(IntrinsicHelper::GetVirtualCalleeMethodObjAddrFast,
+ irb_.getInt32(vtable_idx), this_addr);
break;
}
case kSuper: {
@@ -1770,8 +2431,8 @@ void DexLang::EmitInsn_Invoke(unsigned dex_pc, const Instruction* insn,
callee_method_object_addr =
EmitInvokeIntrinsic4(dex_pc,
IntrinsicHelper::GetInterfaceCalleeMethodObjAddrFast,
- this_addr,
callee_method_idx_value,
+ this_addr,
caller_method_object_addr,
thread_object_addr);
break;
@@ -1792,27 +2453,50 @@ void DexLang::EmitInsn_Invoke(unsigned dex_pc, const Instruction* insn,
// Select the corresponding intrinsic according to the return type
IntrinsicHelper::IntrinsicId invoke_intrinsic = IntrinsicHelper::UnknownId;
- if (callee_ret_jty == kVoid) {
- invoke_intrinsic = IntrinsicHelper::InvokeRetVoid;
- } else {
- switch (GetRegCategoryFromJType(callee_ret_jty)) {
- case kRegCat1nr: {
- invoke_intrinsic = IntrinsicHelper::InvokeRetCat1;
- break;
- }
- case kRegCat2: {
- invoke_intrinsic = IntrinsicHelper::InvokeRetCat2;
- break;
- }
- case kRegObject: {
- invoke_intrinsic = IntrinsicHelper::InvokeRetObject;
- break;
- }
- default: {
- LOG(FATAL) << "Unknown register category for type: "
- << callee_ret_jty;
- break;
- }
+ switch (callee_ret_jty) {
+ case kVoid: {
+ invoke_intrinsic = IntrinsicHelper::InvokeRetVoid;
+ break;
+ }
+ case kBoolean: {
+ invoke_intrinsic = IntrinsicHelper::InvokeRetBoolean;
+ break;
+ }
+ case kByte: {
+ invoke_intrinsic = IntrinsicHelper::InvokeRetByte;
+ break;
+ }
+ case kChar: {
+ invoke_intrinsic = IntrinsicHelper::InvokeRetChar;
+ break;
+ }
+ case kShort: {
+ invoke_intrinsic = IntrinsicHelper::InvokeRetShort;
+ break;
+ }
+ case kInt: {
+ invoke_intrinsic = IntrinsicHelper::InvokeRetInt;
+ break;
+ }
+ case kLong: {
+ invoke_intrinsic = IntrinsicHelper::InvokeRetLong;
+ break;
+ }
+ case kFloat: {
+ invoke_intrinsic = IntrinsicHelper::InvokeRetFloat;
+ break;
+ }
+ case kDouble: {
+ invoke_intrinsic = IntrinsicHelper::InvokeRetDouble;
+ break;
+ }
+ case kObject: {
+ invoke_intrinsic = IntrinsicHelper::InvokeRetObject;
+ break;
+ }
+ default: {
+ LOG(FATAL) << "Unknown register category for type: " << callee_ret_jty;
+ break;
}
}
@@ -1833,8 +2517,8 @@ void DexLang::EmitInsn_Invoke(unsigned dex_pc, const Instruction* insn,
// Load argument values according to the shorty
for (uint32_t i = 1; i < callee_shorty_size; i++) {
- unsigned reg_idx = (arg_fmt == kArgReg) ? (dec_insn.vC + arg_idx) :
- (dec_insn.arg[arg_idx]);
+ unsigned reg_idx = (arg_fmt == kArgRange) ? (dec_insn.vC + arg_idx) :
+ (dec_insn.arg[arg_idx]);
JType jty = GetJTypeFromShorty(callee_shorty[i]);
args.push_back(EmitLoadDalvikReg(reg_idx, jty, kAccurate));
arg_idx++;
@@ -1853,16 +2537,166 @@ void DexLang::EmitInsn_Invoke(unsigned dex_pc, const Instruction* insn,
// Store the return value for the subsequent move-result
if (callee_shorty[0] != 'V') {
- retval_ = retval;
- retval_jty_ = GetJTypeFromShorty(callee_shorty[0]);
- } else {
- retval_ = NULL;
+ EmitStoreDalvikRetValReg(callee_ret_jty, kAccurate, retval);
}
irb_.CreateBr(GetNextBasicBlock(dex_pc));
return;
}
+void DexLang::EmitInsn_Neg(unsigned dex_pc, const Instruction* insn,
+ JType op_jty) {
+ DecodedInstruction dec_insn(insn);
+
+ DCHECK(op_jty == kInt || op_jty == kLong) << op_jty;
+
+ llvm::Value* src_value = EmitLoadDalvikReg(dec_insn.vB, op_jty, kAccurate);
+ llvm::Value* result_value = irb_.CreateNeg(src_value);
+ EmitStoreDalvikReg(dec_insn.vA, op_jty, kAccurate, result_value);
+
+ irb_.CreateBr(GetNextBasicBlock(dex_pc));
+ return;
+}
+
+void DexLang::EmitInsn_Not(unsigned dex_pc, const Instruction* insn,
+ JType op_jty) {
+ DecodedInstruction dec_insn(insn);
+
+ DCHECK(op_jty == kInt || op_jty == kLong) << op_jty;
+
+ llvm::Value* src_value = EmitLoadDalvikReg(dec_insn.vB, op_jty, kAccurate);
+ llvm::Value* result_value = irb_.CreateXor(src_value, 0xFFFFFFFFFFFFFFFFLL);
+
+ EmitStoreDalvikReg(dec_insn.vA, op_jty, kAccurate, result_value);
+
+ irb_.CreateBr(GetNextBasicBlock(dex_pc));
+ return;
+}
+
+void DexLang::EmitInsn_SExt(unsigned dex_pc, const Instruction* insn) {
+ DecodedInstruction dec_insn(insn);
+
+ llvm::Value* src_value = EmitLoadDalvikReg(dec_insn.vB, kInt, kAccurate);
+ llvm::Value* result_value = irb_.CreateSExt(src_value, irb_.GetJLongTy());
+ EmitStoreDalvikReg(dec_insn.vA, kLong, kAccurate, result_value);
+
+ irb_.CreateBr(GetNextBasicBlock(dex_pc));
+ return;
+}
+
+void DexLang::EmitInsn_Trunc(unsigned dex_pc, const Instruction* insn) {
+ DecodedInstruction dec_insn(insn);
+
+ llvm::Value* src_value = EmitLoadDalvikReg(dec_insn.vB, kLong, kAccurate);
+ llvm::Value* result_value = irb_.CreateTrunc(src_value, irb_.GetJIntTy());
+ EmitStoreDalvikReg(dec_insn.vA, kInt, kAccurate, result_value);
+
+ irb_.CreateBr(GetNextBasicBlock(dex_pc));
+ return;
+}
+
+void DexLang::EmitInsn_TruncAndSExt(unsigned dex_pc, const Instruction* insn,
+ unsigned N) {
+ DecodedInstruction dec_insn(insn);
+
+ llvm::Value* src_value = EmitLoadDalvikReg(dec_insn.vB, kInt, kAccurate);
+
+ llvm::Value* trunc_value =
+ irb_.CreateTrunc(src_value, llvm::Type::getIntNTy(context_, N));
+
+ llvm::Value* result_value = irb_.CreateSExt(trunc_value, irb_.GetJIntTy());
+
+ EmitStoreDalvikReg(dec_insn.vA, kInt, kAccurate, result_value);
+
+ irb_.CreateBr(GetNextBasicBlock(dex_pc));
+ return;
+}
+
+void DexLang::EmitInsn_TruncAndZExt(unsigned dex_pc, const Instruction* insn,
+ unsigned N) {
+ DecodedInstruction dec_insn(insn);
+
+ llvm::Value* src_value = EmitLoadDalvikReg(dec_insn.vB, kInt, kAccurate);
+
+ llvm::Value* trunc_value =
+ irb_.CreateTrunc(src_value, llvm::Type::getIntNTy(context_, N));
+
+ llvm::Value* result_value = irb_.CreateZExt(trunc_value, irb_.GetJIntTy());
+
+ EmitStoreDalvikReg(dec_insn.vA, kInt, kAccurate, result_value);
+
+ irb_.CreateBr(GetNextBasicBlock(dex_pc));
+ return;
+}
+
+void DexLang::EmitInsn_FNeg(unsigned dex_pc, const Instruction* insn,
+ JType op_jty) {
+ DecodedInstruction dec_insn(insn);
+
+ DCHECK(op_jty == kFloat || op_jty == kDouble) << op_jty;
+
+ llvm::Value* src_value = EmitLoadDalvikReg(dec_insn.vB, op_jty, kAccurate);
+ llvm::Value* result_value = irb_.CreateFNeg(src_value);
+ EmitStoreDalvikReg(dec_insn.vA, op_jty, kAccurate, result_value);
+
+ irb_.CreateBr(GetNextBasicBlock(dex_pc));
+ return;
+}
+
+void DexLang::EmitInsn_IntToFP(unsigned dex_pc, const Instruction* insn,
+ JType src_jty, JType dest_jty) {
+ DecodedInstruction dec_insn(insn);
+
+ DCHECK(src_jty == kInt || src_jty == kLong) << src_jty;
+ DCHECK(dest_jty == kFloat || dest_jty == kDouble) << dest_jty;
+
+ llvm::Value* src_value = EmitLoadDalvikReg(dec_insn.vB, src_jty, kAccurate);
+ llvm::Type* dest_type = irb_.GetJType(dest_jty, kAccurate);
+ llvm::Value* dest_value = irb_.CreateSIToFP(src_value, dest_type);
+ EmitStoreDalvikReg(dec_insn.vA, dest_jty, kAccurate, dest_value);
+
+ irb_.CreateBr(GetNextBasicBlock(dex_pc));
+ return;
+}
+
+void DexLang::EmitInsn_FPToInt(unsigned dex_pc, const Instruction* insn,
+ JType src_jty, JType dest_jty,
+ IntrinsicHelper::IntrinsicId intr_id) {
+ DecodedInstruction dec_insn(insn);
+
+ DCHECK(src_jty == kFloat || src_jty == kDouble) << src_jty;
+ DCHECK(dest_jty == kInt || dest_jty == kLong) << dest_jty;
+
+ llvm::Value* src_value = EmitLoadDalvikReg(dec_insn.vB, src_jty, kAccurate);
+ llvm::Value* dest_value = EmitInvokeIntrinsicNoThrow(intr_id, src_value);
+ EmitStoreDalvikReg(dec_insn.vA, dest_jty, kAccurate, dest_value);
+
+ irb_.CreateBr(GetNextBasicBlock(dex_pc));
+ return;
+}
+
+void DexLang::EmitInsn_FExt(unsigned dex_pc, const Instruction* insn) {
+ DecodedInstruction dec_insn(insn);
+
+ llvm::Value* src_value = EmitLoadDalvikReg(dec_insn.vB, kFloat, kAccurate);
+ llvm::Value* result_value = irb_.CreateFPExt(src_value, irb_.GetJDoubleTy());
+ EmitStoreDalvikReg(dec_insn.vA, kDouble, kAccurate, result_value);
+
+ irb_.CreateBr(GetNextBasicBlock(dex_pc));
+ return;
+}
+
+void DexLang::EmitInsn_FTrunc(unsigned dex_pc, const Instruction* insn) {
+ DecodedInstruction dec_insn(insn);
+
+ llvm::Value* src_value = EmitLoadDalvikReg(dec_insn.vB, kDouble, kAccurate);
+ llvm::Value* result_value = irb_.CreateFPTrunc(src_value, irb_.GetJFloatTy());
+ EmitStoreDalvikReg(dec_insn.vA, kFloat, kAccurate, result_value);
+
+ irb_.CreateBr(GetNextBasicBlock(dex_pc));
+ return;
+}
+
void DexLang::EmitInsn_IntArithm(unsigned dex_pc, const Instruction* insn,
IntArithmKind arithm, JType op_jty,
bool is_2addr) {
@@ -1909,6 +2743,70 @@ void DexLang::EmitInsn_IntArithmImmediate(unsigned dex_pc,
return;
}
+void DexLang::EmitInsn_IntShiftArithm(unsigned dex_pc, const Instruction* insn,
+ IntShiftArithmKind arithm, JType op_jty,
+ bool is_2addr) {
+ DecodedInstruction dec_insn(insn);
+
+ DCHECK(op_jty == kInt || op_jty == kLong) << op_jty;
+
+ llvm::Value* src1_value;
+ llvm::Value* src2_value;
+
+ // NOTE: The 2nd operand of the shift arithmetic instruction is
+ // 32-bit integer regardless of the 1st operand.
+ if (is_2addr) {
+ src1_value = EmitLoadDalvikReg(dec_insn.vA, op_jty, kAccurate);
+ src2_value = EmitLoadDalvikReg(dec_insn.vB, kInt, kAccurate);
+ } else {
+ src1_value = EmitLoadDalvikReg(dec_insn.vB, op_jty, kAccurate);
+ src2_value = EmitLoadDalvikReg(dec_insn.vC, kInt, kAccurate);
+ }
+
+ llvm::Value* result_value = EmitIntShiftArithmResultComputation(dex_pc,
+ src1_value,
+ src2_value,
+ arithm,
+ op_jty);
+
+ EmitStoreDalvikReg(dec_insn.vA, op_jty, kAccurate, result_value);
+
+ irb_.CreateBr(GetNextBasicBlock(dex_pc));
+ return;
+}
+
+void DexLang::EmitInsn_IntShiftArithmImmediate(unsigned dex_pc,
+ const Instruction* insn,
+ IntShiftArithmKind arithm) {
+ DecodedInstruction dec_insn(insn);
+
+ llvm::Value* src_value = EmitLoadDalvikReg(dec_insn.vB, kInt, kAccurate);
+
+ llvm::Value* imm_value = irb_.getInt32(dec_insn.vC);
+
+ llvm::Value* result_value = EmitIntShiftArithmResultComputation(dex_pc,
+ src_value,
+ imm_value,
+ arithm, kInt);
+
+ EmitStoreDalvikReg(dec_insn.vA, kInt, kAccurate, result_value);
+
+ irb_.CreateBr(GetNextBasicBlock(dex_pc));
+ return;
+}
+
+void DexLang::EmitInsn_RSubImmediate(unsigned dex_pc, const Instruction* insn) {
+ DecodedInstruction dec_insn(insn);
+
+ llvm::Value* src_value = EmitLoadDalvikReg(dec_insn.vB, kInt, kAccurate);
+ llvm::Value* imm_value = irb_.getInt32(dec_insn.vC);
+ llvm::Value* result_value = irb_.CreateSub(imm_value, src_value);
+ EmitStoreDalvikReg(dec_insn.vA, kInt, kAccurate, result_value);
+
+ irb_.CreateBr(GetNextBasicBlock(dex_pc));
+ return;
+}
+
void DexLang::EmitInsn_FPArithm(unsigned dex_pc, const Instruction* insn,
FPArithmKind arithm, JType op_jty,
bool is_2addr) {
@@ -2048,32 +2946,32 @@ bool DexLang::EmitInstruction(unsigned dex_pc, const Instruction* insn) {
EmitInsn_LoadConstantString(ARGS);
break;
}
- case Instruction::CONST_CLASS:
- //EmitInsn_LoadConstantClass(ARGS);
+ case Instruction::CONST_CLASS: {
+ EmitInsn_LoadConstantClass(ARGS);
break;
-
- case Instruction::MONITOR_ENTER:
- //EmitInsn_MonitorEnter(ARGS);
+ }
+ case Instruction::MONITOR_ENTER: {
+ EmitInsn_MonitorEnter(ARGS);
break;
-
- case Instruction::MONITOR_EXIT:
- //EmitInsn_MonitorExit(ARGS);
+ }
+ case Instruction::MONITOR_EXIT: {
+ EmitInsn_MonitorExit(ARGS);
break;
-
- case Instruction::CHECK_CAST:
- //EmitInsn_CheckCast(ARGS);
+ }
+ case Instruction::CHECK_CAST: {
+ EmitInsn_CheckCast(ARGS);
break;
-
- case Instruction::INSTANCE_OF:
- //EmitInsn_InstanceOf(ARGS);
+ }
+ case Instruction::INSTANCE_OF: {
+ EmitInsn_InstanceOf(ARGS);
break;
-
+ }
case Instruction::ARRAY_LENGTH: {
EmitInsn_ArrayLength(ARGS);
break;
}
case Instruction::NEW_INSTANCE:
- //EmitInsn_NewInstance(ARGS);
+ EmitInsn_NewInstance(ARGS);
break;
case Instruction::NEW_ARRAY: {
@@ -2081,55 +2979,55 @@ bool DexLang::EmitInstruction(unsigned dex_pc, const Instruction* insn) {
break;
}
case Instruction::FILLED_NEW_ARRAY:
- //EmitInsn_FilledNewArray(ARGS, false);
+ EmitInsn_FilledNewArray(ARGS, /* is_range */false);
break;
case Instruction::FILLED_NEW_ARRAY_RANGE:
- //EmitInsn_FilledNewArray(ARGS, true);
+ EmitInsn_FilledNewArray(ARGS, /* is_range */true);
break;
case Instruction::FILL_ARRAY_DATA:
- //EmitInsn_FillArrayData(ARGS);
+ EmitInsn_FillArrayData(ARGS);
break;
- case Instruction::THROW:
- //EmitInsn_ThrowException(ARGS);
+ case Instruction::THROW: {
+ EmitInsn_ThrowException(ARGS);
break;
-
+ }
case Instruction::GOTO:
case Instruction::GOTO_16:
case Instruction::GOTO_32: {
EmitInsn_UnconditionalBranch(ARGS);
break;
}
- case Instruction::PACKED_SWITCH:
- //EmitInsn_PackedSwitch(ARGS);
+ case Instruction::PACKED_SWITCH: {
+ EmitInsn_PackedSwitch(ARGS);
break;
-
- case Instruction::SPARSE_SWITCH:
- //EmitInsn_SparseSwitch(ARGS);
+ }
+ case Instruction::SPARSE_SWITCH: {
+ EmitInsn_SparseSwitch(ARGS);
break;
-
- case Instruction::CMPL_FLOAT:
- //EmitInsn_FPCompare(ARGS, kFloat, false);
+ }
+ case Instruction::CMPL_FLOAT: {
+ EmitInsn_FPCompare(ARGS, kFloat, false);
break;
-
- case Instruction::CMPG_FLOAT:
- //EmitInsn_FPCompare(ARGS, kFloat, true);
+ }
+ case Instruction::CMPG_FLOAT: {
+ EmitInsn_FPCompare(ARGS, kFloat, true);
break;
-
- case Instruction::CMPL_DOUBLE:
- //EmitInsn_FPCompare(ARGS, kDouble, false);
+ }
+ case Instruction::CMPL_DOUBLE: {
+ EmitInsn_FPCompare(ARGS, kDouble, false);
break;
-
- case Instruction::CMPG_DOUBLE:
- //EmitInsn_FPCompare(ARGS, kDouble, true);
+ }
+ case Instruction::CMPG_DOUBLE: {
+ EmitInsn_FPCompare(ARGS, kDouble, true);
break;
-
- case Instruction::CMP_LONG:
- //EmitInsn_LongCompare(ARGS);
+ }
+ case Instruction::CMP_LONG: {
+ EmitInsn_LongCompare(ARGS);
break;
-
+ }
case Instruction::IF_EQ: {
EmitInsn_BinaryConditionalBranch(ARGS, kCondBranch_EQ);
break;
@@ -2234,62 +3132,62 @@ bool DexLang::EmitInstruction(unsigned dex_pc, const Instruction* insn) {
EmitInsn_APut(ARGS, kShort);
break;
}
- case Instruction::IGET:
- //EmitInsn_IGet(ARGS, kInt);
+ case Instruction::IGET: {
+ EmitInsn_IGet(ARGS, kInt);
break;
-
- case Instruction::IGET_WIDE:
- //EmitInsn_IGet(ARGS, kLong);
+ }
+ case Instruction::IGET_WIDE: {
+ EmitInsn_IGet(ARGS, kLong);
break;
-
- case Instruction::IGET_OBJECT:
- //EmitInsn_IGet(ARGS, kObject);
+ }
+ case Instruction::IGET_OBJECT: {
+ EmitInsn_IGet(ARGS, kObject);
break;
-
- case Instruction::IGET_BOOLEAN:
- //EmitInsn_IGet(ARGS, kBoolean);
+ }
+ case Instruction::IGET_BOOLEAN: {
+ EmitInsn_IGet(ARGS, kBoolean);
break;
-
- case Instruction::IGET_BYTE:
- //EmitInsn_IGet(ARGS, kByte);
+ }
+ case Instruction::IGET_BYTE: {
+ EmitInsn_IGet(ARGS, kByte);
break;
-
- case Instruction::IGET_CHAR:
- //EmitInsn_IGet(ARGS, kChar);
+ }
+ case Instruction::IGET_CHAR: {
+ EmitInsn_IGet(ARGS, kChar);
break;
-
- case Instruction::IGET_SHORT:
- //EmitInsn_IGet(ARGS, kShort);
+ }
+ case Instruction::IGET_SHORT: {
+ EmitInsn_IGet(ARGS, kShort);
break;
-
- case Instruction::IPUT:
- //EmitInsn_IPut(ARGS, kInt);
+ }
+ case Instruction::IPUT: {
+ EmitInsn_IPut(ARGS, kInt);
break;
-
- case Instruction::IPUT_WIDE:
- //EmitInsn_IPut(ARGS, kLong);
+ }
+ case Instruction::IPUT_WIDE: {
+ EmitInsn_IPut(ARGS, kLong);
break;
-
- case Instruction::IPUT_OBJECT:
- //EmitInsn_IPut(ARGS, kObject);
+ }
+ case Instruction::IPUT_OBJECT: {
+ EmitInsn_IPut(ARGS, kObject);
break;
-
- case Instruction::IPUT_BOOLEAN:
- //EmitInsn_IPut(ARGS, kBoolean);
+ }
+ case Instruction::IPUT_BOOLEAN: {
+ EmitInsn_IPut(ARGS, kBoolean);
break;
-
- case Instruction::IPUT_BYTE:
- //EmitInsn_IPut(ARGS, kByte);
+ }
+ case Instruction::IPUT_BYTE: {
+ EmitInsn_IPut(ARGS, kByte);
break;
-
- case Instruction::IPUT_CHAR:
- //EmitInsn_IPut(ARGS, kChar);
+ }
+ case Instruction::IPUT_CHAR: {
+ EmitInsn_IPut(ARGS, kChar);
break;
-
- case Instruction::IPUT_SHORT:
- //EmitInsn_IPut(ARGS, kShort);
+ }
+ case Instruction::IPUT_SHORT: {
+ EmitInsn_IPut(ARGS, kShort);
break;
-
+ }
case Instruction::SGET: {
EmitInsn_SGet(ARGS, kInt);
break;
@@ -2386,90 +3284,90 @@ bool DexLang::EmitInstruction(unsigned dex_pc, const Instruction* insn) {
EmitInsn_Invoke(ARGS, kInterface, kArgRange);
break;
}
- case Instruction::NEG_INT:
- //EmitInsn_Neg(ARGS, kInt);
+ case Instruction::NEG_INT: {
+ EmitInsn_Neg(ARGS, kInt);
break;
-
- case Instruction::NOT_INT:
- //EmitInsn_Not(ARGS, kInt);
+ }
+ case Instruction::NOT_INT: {
+ EmitInsn_Not(ARGS, kInt);
break;
-
- case Instruction::NEG_LONG:
- //EmitInsn_Neg(ARGS, kLong);
+ }
+ case Instruction::NEG_LONG: {
+ EmitInsn_Neg(ARGS, kLong);
break;
-
- case Instruction::NOT_LONG:
- //EmitInsn_Not(ARGS, kLong);
+ }
+ case Instruction::NOT_LONG: {
+ EmitInsn_Not(ARGS, kLong);
break;
-
- case Instruction::NEG_FLOAT:
- //EmitInsn_FNeg(ARGS, kFloat);
+ }
+ case Instruction::NEG_FLOAT: {
+ EmitInsn_FNeg(ARGS, kFloat);
break;
-
- case Instruction::NEG_DOUBLE:
- //EmitInsn_FNeg(ARGS, kDouble);
+ }
+ case Instruction::NEG_DOUBLE: {
+ EmitInsn_FNeg(ARGS, kDouble);
break;
-
- case Instruction::INT_TO_LONG:
- //EmitInsn_SExt(ARGS);
+ }
+ case Instruction::INT_TO_LONG: {
+ EmitInsn_SExt(ARGS);
break;
-
- case Instruction::INT_TO_FLOAT:
- //EmitInsn_IntToFP(ARGS, kInt, kFloat);
+ }
+ case Instruction::INT_TO_FLOAT: {
+ EmitInsn_IntToFP(ARGS, kInt, kFloat);
break;
-
- case Instruction::INT_TO_DOUBLE:
- //EmitInsn_IntToFP(ARGS, kInt, kDouble);
+ }
+ case Instruction::INT_TO_DOUBLE: {
+ EmitInsn_IntToFP(ARGS, kInt, kDouble);
break;
-
- case Instruction::LONG_TO_INT:
- //EmitInsn_Trunc(ARGS);
+ }
+ case Instruction::LONG_TO_INT: {
+ EmitInsn_Trunc(ARGS);
break;
-
- case Instruction::LONG_TO_FLOAT:
- //EmitInsn_IntToFP(ARGS, kLong, kFloat);
+ }
+ case Instruction::LONG_TO_FLOAT: {
+ EmitInsn_IntToFP(ARGS, kLong, kFloat);
break;
-
- case Instruction::LONG_TO_DOUBLE:
- //EmitInsn_IntToFP(ARGS, kLong, kDouble);
+ }
+ case Instruction::LONG_TO_DOUBLE: {
+ EmitInsn_IntToFP(ARGS, kLong, kDouble);
break;
-
- case Instruction::FLOAT_TO_INT:
- //EmitInsn_FPToInt(ARGS, kFloat, kInt, F2I);
+ }
+ case Instruction::FLOAT_TO_INT: {
+ EmitInsn_FPToInt(ARGS, kFloat, kInt, IntrinsicHelper::F2I);
break;
-
- case Instruction::FLOAT_TO_LONG:
- //EmitInsn_FPToInt(ARGS, kFloat, kLong, F2L);
+ }
+ case Instruction::FLOAT_TO_LONG: {
+ EmitInsn_FPToInt(ARGS, kFloat, kLong, IntrinsicHelper::F2L);
break;
-
- case Instruction::FLOAT_TO_DOUBLE:
- //EmitInsn_FExt(ARGS);
+ }
+ case Instruction::FLOAT_TO_DOUBLE: {
+ EmitInsn_FExt(ARGS);
break;
-
- case Instruction::DOUBLE_TO_INT:
- //EmitInsn_FPToInt(ARGS, kDouble, kInt, D2I);
+ }
+ case Instruction::DOUBLE_TO_INT: {
+ EmitInsn_FPToInt(ARGS, kDouble, kInt, IntrinsicHelper::D2I);
break;
-
- case Instruction::DOUBLE_TO_LONG:
- //EmitInsn_FPToInt(ARGS, kDouble, kLong, D2L);
+ }
+ case Instruction::DOUBLE_TO_LONG: {
+ EmitInsn_FPToInt(ARGS, kDouble, kLong, IntrinsicHelper::D2L);
break;
-
- case Instruction::DOUBLE_TO_FLOAT:
- //EmitInsn_FTrunc(ARGS);
+ }
+ case Instruction::DOUBLE_TO_FLOAT: {
+ EmitInsn_FTrunc(ARGS);
break;
-
- case Instruction::INT_TO_BYTE:
- //EmitInsn_TruncAndSExt(ARGS, 8);
+ }
+ case Instruction::INT_TO_BYTE: {
+ EmitInsn_TruncAndSExt(ARGS, 8);
break;
-
- case Instruction::INT_TO_CHAR:
- //EmitInsn_TruncAndZExt(ARGS, 16);
+ }
+ case Instruction::INT_TO_CHAR: {
+ EmitInsn_TruncAndZExt(ARGS, 16);
break;
-
- case Instruction::INT_TO_SHORT:
- //EmitInsn_TruncAndSExt(ARGS, 16);
+ }
+ case Instruction::INT_TO_SHORT: {
+ EmitInsn_TruncAndSExt(ARGS, 16);
break;
-
+ }
case Instruction::ADD_INT: {
EmitInsn_IntArithm(ARGS, kIntArithm_Add, kInt, false);
break;
@@ -2502,18 +3400,18 @@ bool DexLang::EmitInstruction(unsigned dex_pc, const Instruction* insn) {
EmitInsn_IntArithm(ARGS, kIntArithm_Xor, kInt, false);
break;
}
- case Instruction::SHL_INT:
- //EmitInsn_IntShiftArithm(ARGS, kIntArithm_Shl, kInt, false);
+ case Instruction::SHL_INT: {
+ EmitInsn_IntShiftArithm(ARGS, kIntArithm_Shl, kInt, false);
break;
-
- case Instruction::SHR_INT:
- //EmitInsn_IntShiftArithm(ARGS, kIntArithm_Shr, kInt, false);
+ }
+ case Instruction::SHR_INT: {
+ EmitInsn_IntShiftArithm(ARGS, kIntArithm_Shr, kInt, false);
break;
-
- case Instruction::USHR_INT:
- //EmitInsn_IntShiftArithm(ARGS, kIntArithm_UShr, kInt, false);
+ }
+ case Instruction::USHR_INT: {
+ EmitInsn_IntShiftArithm(ARGS, kIntArithm_UShr, kInt, false);
break;
-
+ }
case Instruction::ADD_LONG: {
EmitInsn_IntArithm(ARGS, kIntArithm_Add, kLong, false);
break;
@@ -2546,18 +3444,18 @@ bool DexLang::EmitInstruction(unsigned dex_pc, const Instruction* insn) {
EmitInsn_IntArithm(ARGS, kIntArithm_Xor, kLong, false);
break;
}
- case Instruction::SHL_LONG:
- //EmitInsn_IntShiftArithm(ARGS, kIntArithm_Shl, kLong, false);
+ case Instruction::SHL_LONG: {
+ EmitInsn_IntShiftArithm(ARGS, kIntArithm_Shl, kLong, false);
break;
-
- case Instruction::SHR_LONG:
- //EmitInsn_IntShiftArithm(ARGS, kIntArithm_Shr, kLong, false);
+ }
+ case Instruction::SHR_LONG: {
+ EmitInsn_IntShiftArithm(ARGS, kIntArithm_Shr, kLong, false);
break;
-
- case Instruction::USHR_LONG:
- //EmitInsn_IntShiftArithm(ARGS, kIntArithm_UShr, kLong, false);
+ }
+ case Instruction::USHR_LONG: {
+ EmitInsn_IntShiftArithm(ARGS, kIntArithm_UShr, kLong, false);
break;
-
+ }
case Instruction::ADD_FLOAT: {
EmitInsn_FPArithm(ARGS, kFPArithm_Add, kFloat, false);
break;
@@ -2630,18 +3528,18 @@ bool DexLang::EmitInstruction(unsigned dex_pc, const Instruction* insn) {
EmitInsn_IntArithm(ARGS, kIntArithm_Xor, kInt, true);
break;
}
- case Instruction::SHL_INT_2ADDR:
- //EmitInsn_IntShiftArithm(ARGS, kIntArithm_Shl, kInt, true);
+ case Instruction::SHL_INT_2ADDR: {
+ EmitInsn_IntShiftArithm(ARGS, kIntArithm_Shl, kInt, true);
break;
-
- case Instruction::SHR_INT_2ADDR:
- //EmitInsn_IntShiftArithm(ARGS, kIntArithm_Shr, kInt, true);
+ }
+ case Instruction::SHR_INT_2ADDR: {
+ EmitInsn_IntShiftArithm(ARGS, kIntArithm_Shr, kInt, true);
break;
-
- case Instruction::USHR_INT_2ADDR:
- //EmitInsn_IntShiftArithm(ARGS, kIntArithm_UShr, kInt, true);
+ }
+ case Instruction::USHR_INT_2ADDR: {
+ EmitInsn_IntShiftArithm(ARGS, kIntArithm_UShr, kInt, true);
break;
-
+ }
case Instruction::ADD_LONG_2ADDR: {
EmitInsn_IntArithm(ARGS, kIntArithm_Add, kLong, true);
break;
@@ -2674,18 +3572,18 @@ bool DexLang::EmitInstruction(unsigned dex_pc, const Instruction* insn) {
EmitInsn_IntArithm(ARGS, kIntArithm_Xor, kLong, true);
break;
}
- case Instruction::SHL_LONG_2ADDR:
- //EmitInsn_IntShiftArithm(ARGS, kIntArithm_Shl, kLong, true);
+ case Instruction::SHL_LONG_2ADDR: {
+ EmitInsn_IntShiftArithm(ARGS, kIntArithm_Shl, kLong, true);
break;
-
- case Instruction::SHR_LONG_2ADDR:
- //EmitInsn_IntShiftArithm(ARGS, kIntArithm_Shr, kLong, true);
+ }
+ case Instruction::SHR_LONG_2ADDR: {
+ EmitInsn_IntShiftArithm(ARGS, kIntArithm_Shr, kLong, true);
break;
-
- case Instruction::USHR_LONG_2ADDR:
- //EmitInsn_IntShiftArithm(ARGS, kIntArithm_UShr, kLong, true);
+ }
+ case Instruction::USHR_LONG_2ADDR: {
+ EmitInsn_IntShiftArithm(ARGS, kIntArithm_UShr, kLong, true);
break;
-
+ }
case Instruction::ADD_FLOAT_2ADDR: {
EmitInsn_FPArithm(ARGS, kFPArithm_Add, kFloat, true);
break;
@@ -2732,10 +3630,10 @@ bool DexLang::EmitInstruction(unsigned dex_pc, const Instruction* insn) {
break;
}
case Instruction::RSUB_INT:
- case Instruction::RSUB_INT_LIT8:
- //EmitInsn_RSubImmediate(ARGS);
+ case Instruction::RSUB_INT_LIT8: {
+ EmitInsn_RSubImmediate(ARGS);
break;
-
+ }
case Instruction::MUL_INT_LIT16:
case Instruction::MUL_INT_LIT8: {
EmitInsn_IntArithmImmediate(ARGS, kIntArithm_Mul);
@@ -2766,17 +3664,18 @@ bool DexLang::EmitInstruction(unsigned dex_pc, const Instruction* insn) {
EmitInsn_IntArithmImmediate(ARGS, kIntArithm_Xor);
break;
}
- case Instruction::SHL_INT_LIT8:
- //EmitInsn_IntShiftArithmImmediate(ARGS, kIntArithm_Shl);
+ case Instruction::SHL_INT_LIT8: {
+ EmitInsn_IntShiftArithmImmediate(ARGS, kIntArithm_Shl);
break;
-
- case Instruction::SHR_INT_LIT8:
- //EmitInsn_IntShiftArithmImmediate(ARGS, kIntArithm_Shr);
+ }
+ case Instruction::SHR_INT_LIT8: {
+ EmitInsn_IntShiftArithmImmediate(ARGS, kIntArithm_Shr);
break;
-
- case Instruction::USHR_INT_LIT8:
- //EmitInsn_IntShiftArithmImmediate(ARGS, kIntArithm_UShr);
+ }
+ case Instruction::USHR_INT_LIT8: {
+ EmitInsn_IntShiftArithmImmediate(ARGS, kIntArithm_UShr);
break;
+ }
case Instruction::UNUSED_3E:
case Instruction::UNUSED_3F:
diff --git a/src/greenland/dex_lang.h b/src/greenland/dex_lang.h
index ce4b462..6b212d0 100644
--- a/src/greenland/dex_lang.h
+++ b/src/greenland/dex_lang.h
@@ -18,6 +18,7 @@
#define ART_SRC_GREENLAND_DEX_LANG_H_
#include "backend_types.h"
+#include "compiler_llvm/backend_types.h"
#include "dalvik_reg.h"
#include "ir_builder.h"
@@ -28,14 +29,13 @@
#include <vector>
-#include <llvm/LLVMContext.h>
+#include <llvm/Module.h>
#include <llvm/ADT/ArrayRef.h>
namespace llvm {
class BasicBlock;
class Function;
class LLVMContext;
- class Module;
class Type;
}
@@ -54,34 +54,26 @@ class DexLang {
public:
class Context {
private:
- llvm::LLVMContext context_;
- llvm::Module* module_;
+ llvm::Module& module_;
IntrinsicHelper* intrinsic_helper_;
- volatile int32_t ref_count_;
- volatile int32_t mem_usage_;
-
- ~Context();
-
- DISALLOW_COPY_AND_ASSIGN(Context);
-
public:
- Context();
+ Context(llvm::Module& module);
+ ~Context();
inline llvm::LLVMContext& GetLLVMContext()
- { return context_; }
+ { return module_.getContext(); }
+
inline llvm::Module& GetOutputModule()
- { return *module_; }
+ { return module_; }
+
inline IntrinsicHelper& GetIntrinsicHelper()
{ return *intrinsic_helper_; }
+ inline const IntrinsicHelper& GetIntrinsicHelper() const
+ { return *intrinsic_helper_; }
- Context& IncRef();
- void DecRef();
-
- void AddMemUsageApproximation(size_t usage);
- inline bool IsMemUsageThresholdReached() const {
- return (mem_usage_ > (30 << 20)); // (threshold: 30MiB)
- }
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Context);
};
public:
@@ -94,7 +86,7 @@ class DexLang {
inline IRBuilder& GetIRBuilder() {
return irb_;
}
- llvm::Value* AllocateDalvikReg(JType jty, unsigned reg_idx);
+ llvm::Value* AllocateDalvikReg(RegCategory cat, unsigned reg_idx);
private:
Context& dex_lang_ctx_;
@@ -104,6 +96,7 @@ class DexLang {
const DexFile* dex_file_;
const DexFile::CodeItem* code_item_;
DexCache* dex_cache_;
+ uint32_t method_idx_;
llvm::LLVMContext& context_;
llvm::Module& module_;
@@ -161,9 +154,27 @@ class DexLang {
// Return Value Related
//----------------------------------------------------------------------------
// Hold the return value returned from the lastest invoke-* instruction
- llvm::Value* retval_;
- // The type of ret_val_
- JType retval_jty_;
+ DalvikReg* retval_reg_;
+
+ 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);
+ return;
+ }
+
+ void EmitStoreDalvikRetValReg(char shorty, JTypeSpace space,
+ llvm::Value* new_value) {
+ EmitStoreDalvikRetValReg(GetJTypeFromShorty(shorty), space, new_value);
+ return;
+ }
private:
//----------------------------------------------------------------------------
@@ -211,7 +222,6 @@ class DexLang {
//----------------------------------------------------------------------------
// Shadow Frame
//----------------------------------------------------------------------------
- bool require_shadow_frame;
unsigned num_shadow_frame_entries_;
void EmitUpdateDexPC(unsigned dex_pc);
@@ -228,8 +238,6 @@ class DexLang {
bool CreateFunction();
llvm::FunctionType* GetFunctionType();
- bool PrepareDalvikRegs();
-
bool EmitPrologue();
bool EmitPrologueAssignArgRegister();
bool EmitPrologueAllcaShadowFrame();
@@ -263,6 +271,12 @@ class DexLang {
kIntArithm_Xor,
};
+ enum IntShiftArithmKind {
+ kIntArithm_Shl,
+ kIntArithm_Shr,
+ kIntArithm_UShr,
+ };
+
enum FPArithmKind {
kFPArithm_Add,
kFPArithm_Sub,
@@ -280,14 +294,37 @@ class DexLang {
llvm::Value* EmitGetCurrentThread();
- llvm::Value* EmitInvokeIntrinsicNoThrow(IntrinsicHelper::IntrinsicId intr_id);
+ void EmitMarkGCCard(llvm::Value* value, llvm::Value* target_addr);
+
llvm::Value* EmitInvokeIntrinsicNoThrow(IntrinsicHelper::IntrinsicId intr_id,
- llvm::ArrayRef<llvm::Value*> args);
- llvm::Value* EmitInvokeIntrinsic(unsigned dex_pc,
- IntrinsicHelper::IntrinsicId intr_id);
+ llvm::ArrayRef<llvm::Value*> args
+ = llvm::ArrayRef<llvm::Value*>());
+ llvm::Value* EmitInvokeIntrinsic2NoThrow(IntrinsicHelper::IntrinsicId intr_id,
+ llvm::Value* arg1,
+ llvm::Value* arg2) {
+ llvm::Value* args[] = { arg1, arg2 };
+ return EmitInvokeIntrinsicNoThrow(intr_id, args);
+ }
+ llvm::Value* EmitInvokeIntrinsic3NoThrow(IntrinsicHelper::IntrinsicId intr_id,
+ llvm::Value* arg1,
+ llvm::Value* arg2,
+ llvm::Value* arg3) {
+ llvm::Value* args[] = { arg1, arg2, arg3 };
+ return EmitInvokeIntrinsicNoThrow(intr_id, args);
+ }
+ llvm::Value* EmitInvokeIntrinsic4NoThrow(IntrinsicHelper::IntrinsicId intr_id,
+ llvm::Value* arg1,
+ llvm::Value* arg2,
+ llvm::Value* arg3,
+ llvm::Value* arg4) {
+ llvm::Value* args[] = { arg1, arg2, arg3, arg4 };
+ return EmitInvokeIntrinsicNoThrow(intr_id, args);
+ }
+
llvm::Value* EmitInvokeIntrinsic(unsigned dex_pc,
IntrinsicHelper::IntrinsicId intr_id,
- llvm::ArrayRef<llvm::Value*> args);
+ llvm::ArrayRef<llvm::Value*> args
+ = llvm::ArrayRef<llvm::Value*>());
llvm::Value* EmitInvokeIntrinsic2(unsigned dex_pc,
IntrinsicHelper::IntrinsicId intr_id,
llvm::Value* arg1,
@@ -323,10 +360,19 @@ class DexLang {
return EmitInvokeIntrinsic(dex_pc, intr_id, args);
}
- RegCategory GetInferredRegCategory(unsigned dex_pc, unsigned reg_idx);
+ compiler_llvm::RegCategory GetInferredRegCategory(unsigned dex_pc,
+ unsigned reg_idx);
+
+ llvm::Value* EmitLoadConstantClass(unsigned dex_pc, uint32_t type_idx);
llvm::Value* EmitLoadArrayLength(llvm::Value* array);
+ llvm::Value* EmitAllocNewArray(unsigned dex_pc, int32_t length,
+ uint32_t type_idx, bool is_filled_new_array);
+
+ llvm::Value* EmitCompareResultSelection(llvm::Value* cmp_eq,
+ llvm::Value* cmp_lt);
+
llvm::Value* EmitLoadStaticStorage(unsigned dex_pc, unsigned type_idx);
llvm::Value* EmitConditionResult(llvm::Value* lhs, llvm::Value* rhs,
@@ -338,6 +384,12 @@ class DexLang {
IntArithmKind arithm,
JType op_jty);
+ llvm::Value* EmitIntShiftArithmResultComputation(uint32_t dex_pc,
+ llvm::Value* lhs,
+ llvm::Value* rhs,
+ IntShiftArithmKind arithm,
+ JType op_jty);
+
llvm::Value* EmitIntDivRemResultComputation(unsigned dex_pc,
llvm::Value* dividend,
llvm::Value* divisor,
@@ -354,18 +406,15 @@ class DexLang {
// MOVE_EXCEPTION, THROW instructions
void EmitInsn_MoveException(GEN_INSN_ARGS);
-#if 0
void EmitInsn_ThrowException(GEN_INSN_ARGS);
// RETURN instructions
-#endif
void EmitInsn_ReturnVoid(GEN_INSN_ARGS);
void EmitInsn_Return(GEN_INSN_ARGS);
// CONST, CONST_CLASS, CONST_STRING instructions
void EmitInsn_LoadConstant(GEN_INSN_ARGS, JType imm_jty);
void EmitInsn_LoadConstantString(GEN_INSN_ARGS);
-#if 0
void EmitInsn_LoadConstantClass(GEN_INSN_ARGS);
// MONITOR_ENTER, MONITOR_EXIT instructions
@@ -378,22 +427,18 @@ class DexLang {
// NEW_INSTANCE instructions
void EmitInsn_NewInstance(GEN_INSN_ARGS);
-#endif
// ARRAY_LEN, NEW_ARRAY, FILLED_NEW_ARRAY, FILL_ARRAY_DATA instructions
void EmitInsn_ArrayLength(GEN_INSN_ARGS);
void EmitInsn_NewArray(GEN_INSN_ARGS);
-#if 0
void EmitInsn_FilledNewArray(GEN_INSN_ARGS, bool is_range);
void EmitInsn_FillArrayData(GEN_INSN_ARGS);
-#endif
// GOTO, IF_TEST, IF_TESTZ instructions
void EmitInsn_UnconditionalBranch(GEN_INSN_ARGS);
- void EmitInsn_BinaryConditionalBranch(GEN_INSN_ARGS, CondBranchKind cond);
void EmitInsn_UnaryConditionalBranch(GEN_INSN_ARGS, CondBranchKind cond);
+ void EmitInsn_BinaryConditionalBranch(GEN_INSN_ARGS, CondBranchKind cond);
-#if 0
// PACKED_SWITCH, SPARSE_SWITCH instrutions
void EmitInsn_PackedSwitch(GEN_INSN_ARGS);
void EmitInsn_SparseSwitch(GEN_INSN_ARGS);
@@ -402,48 +447,22 @@ class DexLang {
void EmitInsn_FPCompare(GEN_INSN_ARGS, JType fp_jty, bool gt_bias);
void EmitInsn_LongCompare(GEN_INSN_ARGS);
-#endif
// AGET, APUT instrutions
void EmitInsn_AGet(GEN_INSN_ARGS, JType elem_jty);
void EmitInsn_APut(GEN_INSN_ARGS, JType elem_jty);
-#if 0
// IGET, IPUT instructions
void EmitInsn_IGet(GEN_INSN_ARGS, JType field_jty);
void EmitInsn_IPut(GEN_INSN_ARGS, JType field_jty);
-#endif
// SGET, SPUT instructions
void EmitInsn_SGet(GEN_INSN_ARGS, JType field_jty);
void EmitInsn_SPut(GEN_INSN_ARGS, JType field_jty);
-#if 0
- // INVOKE instructions
- llvm::Value* EmitFixStub(llvm::Value* callee_method_object_addr,
- uint32_t method_idx,
- bool is_static);
- llvm::Value* EmitEnsureResolved(llvm::Value* callee,
- llvm::Value* caller,
- uint32_t dex_method_idx,
- bool is_virtual);
-#endif
-
void EmitInsn_Invoke(GEN_INSN_ARGS,
InvokeType invoke_type,
InvokeArgFmt arg_fmt);
-#if 0
- llvm::Value* EmitLoadSDCalleeMethodObjectAddr(uint32_t callee_method_idx);
-
- llvm::Value* EmitLoadVirtualCalleeMethodObjectAddr(int vtable_idx,
- llvm::Value* this_addr);
-
- llvm::Value* EmitCallRuntimeForCalleeMethodObjectAddr(uint32_t callee_method_idx,
- InvokeType invoke_type,
- llvm::Value* this_addr,
- unsigned dex_pc,
- bool is_fast_path);
-
// Unary instructions
void EmitInsn_Neg(GEN_INSN_ARGS, JType op_jty);
void EmitInsn_Not(GEN_INSN_ARGS, JType op_jty);
@@ -455,18 +474,16 @@ class DexLang {
void EmitInsn_FNeg(GEN_INSN_ARGS, JType op_jty);
void EmitInsn_IntToFP(GEN_INSN_ARGS, JType src_jty, JType dest_jty);
void EmitInsn_FPToInt(GEN_INSN_ARGS, JType src_jty, JType dest_jty,
- runtime_support::RuntimeId runtime_func_id);
+ IntrinsicHelper::IntrinsicId intr_id);
void EmitInsn_FExt(GEN_INSN_ARGS);
void EmitInsn_FTrunc(GEN_INSN_ARGS);
-#endif
// Integer binary arithmetic instructions
void EmitInsn_IntArithm(GEN_INSN_ARGS, IntArithmKind arithm,
JType op_jty, bool is_2addr);
void EmitInsn_IntArithmImmediate(GEN_INSN_ARGS, IntArithmKind arithm);
-#if 0
void EmitInsn_IntShiftArithm(GEN_INSN_ARGS, IntShiftArithmKind arithm,
JType op_jty, bool is_2addr);
@@ -475,7 +492,6 @@ class DexLang {
void EmitInsn_RSubImmediate(GEN_INSN_ARGS);
-#endif
// Floating-point binary arithmetic instructions
void EmitInsn_FPArithm(GEN_INSN_ARGS, FPArithmKind arithm,
JType op_jty, bool is_2addr);
diff --git a/src/greenland/gbc_context.cc b/src/greenland/gbc_context.cc
new file mode 100644
index 0000000..ec86bfb
--- /dev/null
+++ b/src/greenland/gbc_context.cc
@@ -0,0 +1,69 @@
+/*
+ * 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 "gbc_context.h"
+
+#include "atomic.h"
+
+namespace art {
+namespace greenland {
+
+GBCContext::GBCContext()
+ : context_(), module_(NULL), ref_count_(1), mem_usage_(0) {
+ module_ = new llvm::Module("art", context_);
+
+ // Initialize the contents of an empty module
+ // Type of "JavaObject"
+ llvm::StructType::create(context_, "JavaObject");
+ // Type of "Method"
+ llvm::StructType::create(context_, "Method");
+ // Type of "Thread"
+ llvm::StructType::create(context_, "Thread");
+
+ dex_lang_ctx_ = new DexLang::Context(*module_);
+ return;
+}
+
+GBCContext::~GBCContext() {
+ delete dex_lang_ctx_;
+ return;
+}
+
+GBCContext& GBCContext::IncRef() {
+ android_atomic_inc(&ref_count_);
+ return *this;
+}
+
+const GBCContext& GBCContext::IncRef() const {
+ android_atomic_inc(&ref_count_);
+ return *this;
+}
+
+void GBCContext::DecRef() const {
+ int32_t old_ref_count = android_atomic_dec(&ref_count_);
+ if (old_ref_count <= 1) {
+ delete this;
+ }
+ return;
+}
+
+void GBCContext::AddMemUsageApproximation(size_t usage) {
+ android_atomic_add(static_cast<int32_t>(usage), &mem_usage_);
+ return;
+}
+
+} // namespace greenland
+} // namespace art
diff --git a/src/greenland/gbc_context.h b/src/greenland/gbc_context.h
new file mode 100644
index 0000000..7c31816
--- /dev/null
+++ b/src/greenland/gbc_context.h
@@ -0,0 +1,80 @@
+/*
+ * 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_GREENLAND_GBC_CONTEXT_H_
+#define ART_SRC_GREENLAND_GBC_CONTEXT_H_
+
+#include "dex_lang.h"
+
+#include "macros.h"
+
+#include <llvm/LLVMContext.h>
+
+namespace llvm {
+ class Module;
+} // namespace llvm
+
+namespace art {
+namespace greenland {
+
+class IntrinsicHelper;
+
+class GBCContext {
+ private:
+ llvm::LLVMContext context_;
+ llvm::Module* module_;
+ DexLang::Context* dex_lang_ctx_;
+
+ mutable volatile int32_t ref_count_;
+ volatile int32_t mem_usage_;
+
+ ~GBCContext();
+
+ public:
+ GBCContext();
+
+ inline llvm::LLVMContext& GetLLVMContext()
+ { return context_; }
+ inline llvm::Module& GetOutputModule()
+ { return *module_; }
+
+ inline IntrinsicHelper& GetIntrinsicHelper()
+ { return dex_lang_ctx_->GetIntrinsicHelper(); }
+ inline const IntrinsicHelper& GetIntrinsicHelper() const
+ { return dex_lang_ctx_->GetIntrinsicHelper(); }
+
+ inline DexLang::Context& GetDexLangContext()
+ { return *dex_lang_ctx_; }
+ inline const DexLang::Context& GetDexLangContext() const
+ { return *dex_lang_ctx_; }
+
+ GBCContext& IncRef();
+ const GBCContext& IncRef() const;
+ void DecRef() const;
+
+ void AddMemUsageApproximation(size_t usage);
+ inline bool IsMemUsageThresholdReached() const {
+ return (mem_usage_ > (30 << 20)); // (threshold: 30MiB)
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(GBCContext);
+};
+
+} // namespace greenland
+} // namespace art
+
+#endif // ART_SRC_GREENLAND_GBC_CONTEXT_H_
diff --git a/src/greenland/gbc_function.h b/src/greenland/gbc_function.h
new file mode 100644
index 0000000..b7cbea6
--- /dev/null
+++ b/src/greenland/gbc_function.h
@@ -0,0 +1,78 @@
+/*
+ * 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_GREENLAND_GBC_FUNCTION_H_
+#define ART_SRC_GREENLAND_GBC_FUNCTION_H_
+
+#include "gbc_context.h"
+
+namespace llvm {
+ class Function;
+} // namespace llvm
+
+namespace art {
+ class OatCompilationUnit;
+} // namespace art
+
+namespace art {
+namespace greenland {
+
+class GBCContext;
+
+class GBCFunction {
+ private:
+ // The GBCContext associated with this GBCFunction
+ GBCContext& context_;
+
+ // The LLVM Function in Greenland bitcode
+ llvm::Function& func_;
+
+ // The associated OatCompilationUnit
+ const OatCompilationUnit& cunit_;
+
+ public:
+ GBCFunction(GBCContext& context, llvm::Function& func,
+ const OatCompilationUnit& cunit)
+ : context_(context.IncRef()), func_(func), cunit_(cunit) { }
+
+ ~GBCFunction() {
+ context_.DecRef();
+ return;
+ }
+
+ IntrinsicHelper& GetIntrinsicHelper() {
+ return context_.GetIntrinsicHelper();
+ }
+ const IntrinsicHelper& GetIntrinsicHelper() const {
+ return context_.GetIntrinsicHelper();
+ }
+
+ llvm::Function& GetBitcode() {
+ return func_;
+ }
+ const llvm::Function& GetBitcode() const {
+ return func_;
+ }
+
+ const OatCompilationUnit& GetOatCompilationUnit() const {
+ return cunit_;
+ }
+};
+
+} // namespace greenland
+} // namespace art
+
+#endif // ART_SRC_GREENLAND_GBC_FUNCTION_H_
diff --git a/src/greenland/greenland.cc b/src/greenland/greenland.cc
index bbf990d..469f7d5 100644
--- a/src/greenland/greenland.cc
+++ b/src/greenland/greenland.cc
@@ -16,6 +16,8 @@
#include "greenland.h"
+#include "gbc_context.h"
+#include "gbc_function.h"
#include "target_codegen_machine.h"
#include "target_registry.h"
@@ -63,6 +65,9 @@ void InitializeAllInvokeStubCompilers() {
}
void InitializeGreenland() {
+ // Initialize LLVM internal data structure for multithreading
+ llvm::llvm_start_multithreaded();
+
// Initialize passes
llvm::PassRegistry &registry = *llvm::PassRegistry::getPassRegistry();
@@ -83,9 +88,6 @@ void InitializeGreenland() {
InitializeAllCodeGenMachines();
InitializeAllInvokeStubCompilers();
- // Initialize LLVM internal data structure for multithreading
- llvm::llvm_start_multithreaded();
-
return;
}
@@ -96,7 +98,7 @@ namespace greenland {
Greenland::Greenland(art::Compiler& compiler)
: compiler_(compiler), codegen_machine_(NULL),
- lock_("greenland_compiler_lock"), cur_dex_lang_ctx_(NULL) {
+ lock_("greenland_compiler_lock"), cur_gbc_ctx_(NULL) {
// Initialize Greenland
pthread_once(&greenland_initialized, InitializeGreenland);
@@ -107,7 +109,7 @@ Greenland::Greenland(art::Compiler& compiler)
}
Greenland::~Greenland() {
- cur_dex_lang_ctx_->DecRef();
+ cur_gbc_ctx_->DecRef();
delete codegen_machine_;
}
@@ -115,9 +117,10 @@ CompiledMethod* Greenland::Compile(OatCompilationUnit& cunit) {
MutexLock GUARD(lock_);
// Dex to LLVM IR
- DexLang::Context& dex_lang_ctx = GetDexLangContext();
+ GBCContext& gbc_ctx = GetGBCContext();
- UniquePtr<DexLang> dex_lang(new DexLang(dex_lang_ctx, compiler_, cunit));
+ UniquePtr<DexLang> dex_lang(new DexLang(gbc_ctx.GetDexLangContext(),
+ compiler_, cunit));
llvm::Function* func = dex_lang->Build();
@@ -127,40 +130,47 @@ CompiledMethod* Greenland::Compile(OatCompilationUnit& cunit) {
return NULL;
}
- dex_lang_ctx.GetOutputModule().dump();
+ func->dump();
+
+ // NOTE: From statistic, the bitcode size is 4.5 times bigger than the
+ // Dex file. Besides, we have to convert the code unit into bytes.
+ // Thus, we got our magic number 9.
+ gbc_ctx.AddMemUsageApproximation(
+ cunit.GetCodeItem()->insns_size_in_code_units_ * 900);
+
+ GBCFunction gbc_func(gbc_ctx, *func, cunit);
- UniquePtr<CompiledMethod> result(codegen_machine_->Run(*this, *func, cunit,
- dex_lang_ctx));
+ UniquePtr<CompiledMethod> result(codegen_machine_->Run(compiler_, gbc_func));
- // dex_lang_ctx was no longer needed
- dex_lang_ctx.DecRef();
+ // gbc_ctx was no longer needed
+ gbc_ctx.DecRef();
return result.release();
}
-DexLang::Context& Greenland::GetDexLangContext() {
+GBCContext& Greenland::GetGBCContext() {
//MutexLock GUARD(lock_);
- ResetDexLangContextIfThresholdReached();
+ ResetGBCContextIfThresholdReached();
- if (cur_dex_lang_ctx_ == NULL) {
- cur_dex_lang_ctx_ = new DexLang::Context();
+ if (cur_gbc_ctx_ == NULL) {
+ cur_gbc_ctx_ = new GBCContext();
}
- CHECK(cur_dex_lang_ctx_ != NULL);
+ CHECK(cur_gbc_ctx_ != NULL);
- return cur_dex_lang_ctx_->IncRef();
+ return cur_gbc_ctx_->IncRef();
}
-void Greenland::ResetDexLangContextIfThresholdReached() {
+void Greenland::ResetGBCContextIfThresholdReached() {
lock_.AssertHeld();
- if (cur_dex_lang_ctx_ == NULL) {
+ if (cur_gbc_ctx_ == NULL) {
return;
}
- if (cur_dex_lang_ctx_->IsMemUsageThresholdReached()) {
- cur_dex_lang_ctx_->DecRef();
- cur_dex_lang_ctx_ = NULL;
+ if (cur_gbc_ctx_->IsMemUsageThresholdReached()) {
+ cur_gbc_ctx_->DecRef();
+ cur_gbc_ctx_ = NULL;
}
return;
}
diff --git a/src/greenland/greenland.h b/src/greenland/greenland.h
index 4407c92..1d6f8e5 100644
--- a/src/greenland/greenland.h
+++ b/src/greenland/greenland.h
@@ -17,8 +17,6 @@
#ifndef ART_SRC_GREENLAND_GREENLAND_H_
#define ART_SRC_GREENLAND_GREENLAND_H_
-#include "dex_lang.h"
-
#include "macros.h"
#include "object.h"
@@ -31,6 +29,7 @@ namespace art {
namespace art {
namespace greenland {
+class GBCContext;
class TargetCodeGenMachine;
class Greenland {
@@ -54,11 +53,11 @@ class Greenland {
Mutex lock_;
- // NOTE: Ensure that the lock_ is held before altering cur_dex_lang_ctx_
- DexLang::Context *cur_dex_lang_ctx_;
+ // NOTE: Ensure that the lock_ is held before altering cur_gbc_ctx
+ GBCContext *cur_gbc_ctx_;
- DexLang::Context& GetDexLangContext();
- void ResetDexLangContextIfThresholdReached();
+ GBCContext& GetGBCContext();
+ void ResetGBCContextIfThresholdReached();
DISALLOW_COPY_AND_ASSIGN(Greenland);
};
diff --git a/src/greenland/inferred_reg_category_map.cc b/src/greenland/inferred_reg_category_map.cc
deleted file mode 100644
index 4f7f4ff..0000000
--- a/src/greenland/inferred_reg_category_map.cc
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * 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 "inferred_reg_category_map.h"
-
-#include "backend_types.h"
-#include "stl_util.h"
-
-#include <stdint.h>
-#include <vector>
-
-namespace art {
-namespace greenland {
-
-InferredRegCategoryMap::InferredRegCategoryMap(uint32_t insns_size,
- uint8_t regs_size)
-: registers_size_(regs_size), lines_(insns_size, NULL), can_be_object_(regs_size) {
-}
-
-InferredRegCategoryMap::~InferredRegCategoryMap() {
- STLDeleteElements(&lines_);
-}
-
-RegCategory InferredRegCategoryMap::GetRegCategory(uint32_t dex_pc,
- uint16_t reg_idx) const {
- if (lines_[dex_pc] == NULL) {
- return kRegUnknown;
- }
- return lines_[dex_pc]->GetRegCategory(reg_idx);
-}
-
-void InferredRegCategoryMap::SetRegCategory(uint32_t dex_pc,
- uint16_t reg_idx,
- RegCategory cat) {
- if (cat != kRegUnknown) {
- if (lines_[dex_pc] == NULL) {
- lines_[dex_pc] = new RegCategoryLine();
- }
-
- (*lines_[dex_pc]).SetRegCategory(reg_idx, cat);
- }
-}
-
-bool InferredRegCategoryMap::IsRegCanBeObject(uint16_t reg_idx) const {
- return can_be_object_[reg_idx];
-}
-
-void InferredRegCategoryMap::SetRegCanBeObject(uint16_t reg_idx) {
- can_be_object_[reg_idx] = true;
-}
-
-bool InferredRegCategoryMap::
-operator==(InferredRegCategoryMap const& rhs) const {
-
- if (registers_size_ != rhs.registers_size_) {
- return false;
- }
-
- if (lines_.size() != rhs.lines_.size()) {
- return false;
- }
-
- for (size_t i = 0; i < lines_.size(); ++i) {
- if (lines_[i] == NULL && rhs.lines_[i] == NULL) {
- continue;
- }
-
- if ((lines_[i] == NULL && rhs.lines_[i] != NULL) ||
- (lines_[i] != NULL && rhs.lines_[i] == NULL)) {
- return false;
- }
-
- if (*lines_[i] != *rhs.lines_[i]) {
- return false;
- }
- }
-
- return true;
-}
-
-bool InferredRegCategoryMap::
-operator!=(InferredRegCategoryMap const& rhs) const {
-
- return !(*this == rhs);
-}
-
-
-} // namespace greenland
-} // namespace art
diff --git a/src/greenland/inferred_reg_category_map.h b/src/greenland/inferred_reg_category_map.h
deleted file mode 100644
index 57e0c30..0000000
--- a/src/greenland/inferred_reg_category_map.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * 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_GREENLAND_INFERRED_REG_CATEGORY_MAP_H_
-#define ART_SRC_GREENLAND_INFERRED_REG_CATEGORY_MAP_H_
-
-#include "backend_types.h"
-
-#include <stdint.h>
-#include <vector>
-
-#include "safe_map.h"
-
-namespace art {
-namespace greenland {
-
-class InferredRegCategoryMap {
- private:
- class RegCategoryLine {
- private:
- typedef SafeMap<uint16_t, uint8_t> Table;
- Table reg_category_line_;
-
- public:
- RegCategory GetRegCategory(uint16_t reg_idx) const {
- // TODO: C++0x auto
- Table::const_iterator result = reg_category_line_.find(reg_idx);
- if (result == reg_category_line_.end()) {
- return kRegUnknown;
- }
- return static_cast<RegCategory>(result->second);
- }
-
- void SetRegCategory(uint16_t reg_idx, RegCategory cat) {
- if (cat != kRegUnknown) {
- reg_category_line_.Put(reg_idx, cat);
- }
- }
-
- bool operator==(RegCategoryLine const& rhs) const {
- return reg_category_line_ == rhs.reg_category_line_;
- }
- bool operator!=(RegCategoryLine const& rhs) const {
- return reg_category_line_ != rhs.reg_category_line_;
- }
- };
-
- public:
- InferredRegCategoryMap(uint32_t insns_size_in_code_units, uint8_t regs_size);
-
- ~InferredRegCategoryMap();
-
- RegCategory GetRegCategory(uint32_t dex_pc, uint16_t reg_idx) const;
- void SetRegCategory(uint32_t dex_pc, uint16_t reg_idx, RegCategory cat);
-
- bool IsRegCanBeObject(uint16_t reg_idx) const;
- void SetRegCanBeObject(uint16_t reg_idx);
-
- bool operator==(InferredRegCategoryMap const& rhs) const;
- bool operator!=(InferredRegCategoryMap const& rhs) const;
-
- private:
- uint16_t registers_size_;
-
- std::vector<RegCategoryLine*> lines_;
-
- std::vector<bool> can_be_object_;
-
- DISALLOW_COPY_AND_ASSIGN(InferredRegCategoryMap);
-};
-
-
-} // namespace greenland
-} // namespace art
-
-#endif // ART_SRC_GREENLAND_INFERRED_REG_CATEGORY_MAP_H_
diff --git a/src/greenland/intrinsic_func_list.def b/src/greenland/intrinsic_func_list.def
index 3f3fae1..f288bbc 100644
--- a/src/greenland/intrinsic_func_list.def
+++ b/src/greenland/intrinsic_func_list.def
@@ -58,10 +58,31 @@
// Thread* dex_lang_get_current_thread()
_EVAL_DEF_INTRINSICS_FUNC(GetCurrentThread,
dex_lang_get_current_thread,
- kAttrReadOnly | kAttrNoThrow,
- kJavaThreadTy,
+ kAttrReadNone | kAttrNoThrow,
+ kJavaThreadTy,
_EXPAND_ARG0())
+// void dex_lang_test_suspend(Thread* thread)
+_EVAL_DEF_INTRINSICS_FUNC(TestSuspend,
+ dex_lang_test_suspend,
+ kAttrNoThrow,
+ kVoidTy,
+ _EXPAND_ARG1(kJavaThreadTy))
+
+// void dex_lang_check_suspend() /* Expands to GetCurrentThread/TestSuspend */
+_EVAL_DEF_INTRINSICS_FUNC(CheckSuspend,
+ dex_lang_check_suspend,
+ kAttrNoThrow,
+ kVoidTy,
+ _EXPAND_ARG0())
+
+// void dex_lang_mark_gc_card(Object* new_value, Object* object)
+_EVAL_DEF_INTRINSICS_FUNC(MarkGCCard,
+ dex_lang_mark_gc_card,
+ kAttrNoThrow,
+ kVoidTy,
+ _EXPAND_ARG2(kJavaObjectTy, kJavaObjectTy))
+
//----------------------------------------------------------------------------
// Exception
//----------------------------------------------------------------------------
@@ -78,6 +99,13 @@ _EVAL_DEF_INTRINSICS_FUNC(CatchTargets,
kInt32Ty,
_EXPAND_ARG1(kInt32ConstantTy))
+// void dex_lang_throw_exception(JavaObject* exception)
+_EVAL_DEF_INTRINSICS_FUNC(ThrowException,
+ dex_lang_throw_exception,
+ kAttrDoThrow,
+ kVoidTy,
+ _EXPAND_ARG1(kJavaObjectTy))
+
// JavaObject* dex_lang_get_current_exception()
_EVAL_DEF_INTRINSICS_FUNC(GetException,
dex_lang_get_current_exception,
@@ -102,31 +130,24 @@ _EVAL_DEF_INTRINSICS_FUNC(FindCatchBlock,
// void dex_lang_throw_div_zero()
_EVAL_DEF_INTRINSICS_FUNC(ThrowDivZeroException,
dex_lang_throw_div_zero,
- kAttrNoThrow,
+ kAttrDoThrow,
kVoidTy,
_EXPAND_ARG0())
// void dex_lang_throw_null_pointer_exception(uint32_t dex_pc)
_EVAL_DEF_INTRINSICS_FUNC(ThrowNullPointerException,
dex_lang_throw_null_pointer_exception,
- kAttrNoThrow,
+ kAttrDoThrow,
kVoidTy,
_EXPAND_ARG1(kInt32ConstantTy))
// void dex_lang_throw_array_bounds(int index, int array_len)
_EVAL_DEF_INTRINSICS_FUNC(ThrowIndexOutOfBounds,
dex_lang_throw_array_bounds,
- kAttrNoThrow,
+ kAttrDoThrow,
kVoidTy,
_EXPAND_ARG2(kInt32Ty, kInt32Ty))
-// void dex_lang_throw(exception_object)
-_EVAL_DEF_INTRINSICS_FUNC(Throw,
- dex_lang_throw,
- kAttrNoThrow,
- kVoidTy,
- _EXPAND_ARG1(kJavaObjectTy))
-
//----------------------------------------------------------------------------
// ConstString
//----------------------------------------------------------------------------
@@ -138,16 +159,24 @@ _EVAL_DEF_INTRINSICS_FUNC(ConstString,
kJavaObjectTy,
_EXPAND_ARG1(kInt32ConstantTy))
-// JavaObject* dex_lang_const_string(uint32_t string_idx)
-_EVAL_DEF_INTRINSICS_FUNC(ConstStringFast,
- dex_lang_const_string.fast,
+// JavaObject* dex_lang_load_string_from_dex_cache(Method* method, uint32_t string_idx)
+_EVAL_DEF_INTRINSICS_FUNC(LoadStringFromDexCache,
+ dex_lang_load_string_from_dex_cache,
kAttrReadOnly | kAttrNoThrow,
kJavaObjectTy,
_EXPAND_ARG1(kInt32ConstantTy))
+// JavaObject* dex_lang_resolve_string(Method* method, uint32_t string_idx)
+_EVAL_DEF_INTRINSICS_FUNC(ResolveString,
+ dex_lang_resolve_string,
+ kAttrNone,
+ kJavaObjectTy,
+ _EXPAND_ARG2(kJavaMethodTy, kInt32ConstantTy))
+
//----------------------------------------------------------------------------
// ConstClass
//----------------------------------------------------------------------------
+
// JavaObject* dex_lang_const_class(uint32_t type_idx)
_EVAL_DEF_INTRINSICS_FUNC(ConstClass,
dex_lang_const_class,
@@ -155,16 +184,96 @@ _EVAL_DEF_INTRINSICS_FUNC(ConstClass,
kJavaObjectTy,
_EXPAND_ARG1(kInt32ConstantTy))
+// JavaObject* dex_lang_initialize_type_and_verify_access(uint32_t type_idx,
+// Method* referrer,
+// Thread* thread)
+_EVAL_DEF_INTRINSICS_FUNC(InitializeTypeAndVerifyAccess,
+ dex_lang_initialize_type_and_verify_access,
+ kAttrNone,
+ kJavaObjectTy,
+ _EXPAND_ARG3(kInt32ConstantTy, kJavaMethodTy, kJavaThreadTy))
+
+// JavaObject* dex_lang_load_type_from_dex_cache(uint32_t type_idx)
+_EVAL_DEF_INTRINSICS_FUNC(LoadTypeFromDexCache,
+ dex_lang_load_type_from_dex_cache,
+ kAttrReadOnly | kAttrNoThrow,
+ kJavaObjectTy,
+ _EXPAND_ARG1(kInt32ConstantTy))
+
+// JavaObject* dex_lang_initialize_type(uint32_t type_idx,
+// Method* referrer,
+// Thread* thread)
+_EVAL_DEF_INTRINSICS_FUNC(InitializeType,
+ dex_lang_initialize_type,
+ kAttrNone,
+ kJavaObjectTy,
+ _EXPAND_ARG3(kInt32ConstantTy, kJavaMethodTy, kJavaThreadTy))
+
+//----------------------------------------------------------------------------
+// Lock
+//----------------------------------------------------------------------------
+
+// void dex_lang_lock_object(JavaObject* obj, Thread* thread)
+_EVAL_DEF_INTRINSICS_FUNC(LockObject,
+ dex_lang_lock_object,
+ kAttrNoThrow,
+ kVoidTy,
+ _EXPAND_ARG2(kJavaObjectTy, kJavaThreadTy))
+
+// void dex_lang_unlock_object(JavaObject* obj, Thread* thread)
+_EVAL_DEF_INTRINSICS_FUNC(UnlockObject,
+ dex_lang_unlock_object,
+ kAttrNone,
+ kVoidTy,
+ _EXPAND_ARG2(kJavaObjectTy, kJavaThreadTy))
+
//----------------------------------------------------------------------------
-// CheckCast
+// Cast
//----------------------------------------------------------------------------
-// void dex_lang_check_cast(uint32_t type_idx, JavaObject* obj)
+
+// void dex_lang_check_cast(JavaObject* dest_type, JavaObject* src_type)
_EVAL_DEF_INTRINSICS_FUNC(CheckCast,
dex_lang_check_cast,
+ kAttrNone,
+ kVoidTy,
+ _EXPAND_ARG2(kJavaObjectTy, kJavaObjectTy))
+
+// void dex_lang_hl_check_cast(uint32_t type_idx, JavaObject* obj)
+_EVAL_DEF_INTRINSICS_FUNC(HLCheckCast,
+ dex_lang_hl_check_cast,
kAttrReadOnly | kAttrNoThrow,
kVoidTy,
_EXPAND_ARG2(kInt32ConstantTy, kJavaObjectTy))
+// int dex_lang_is_assignable(JavaObject* dest_type, JavaObject* src_type)
+_EVAL_DEF_INTRINSICS_FUNC(IsAssignable,
+ dex_lang_is_assignable,
+ kAttrReadOnly | kAttrNoThrow,
+ kInt32Ty,
+ _EXPAND_ARG2(kJavaObjectTy, kJavaObjectTy))
+
+//----------------------------------------------------------------------------
+// Allocation
+//----------------------------------------------------------------------------
+
+// JavaObject* dex_lang_alloc_object(uint32_t type_idx,
+// Method* referrer,
+// Thread* thread)
+_EVAL_DEF_INTRINSICS_FUNC(AllocObject,
+ dex_lang_alloc_object,
+ kAttrNone,
+ kJavaObjectTy,
+ _EXPAND_ARG3(kInt32ConstantTy, kJavaMethodTy, kJavaThreadTy))
+
+// JavaObject* dex_lang_alloc_object_with_access_check(uint32_t type_idx,
+// Method* referrer,
+// Thread* thread)
+_EVAL_DEF_INTRINSICS_FUNC(AllocObjectWithAccessCheck,
+ dex_lang_alloc_object_with_access_check,
+ kAttrNone,
+ kJavaObjectTy,
+ _EXPAND_ARG3(kInt32ConstantTy, kJavaMethodTy, kJavaThreadTy))
+
//----------------------------------------------------------------------------
// Instance
//----------------------------------------------------------------------------
@@ -187,13 +296,6 @@ _EVAL_DEF_INTRINSICS_FUNC(InstanceOf,
// Array
//----------------------------------------------------------------------------
-// uint32_t dex_lang_array_length(int32_t opt_flags, JavaObject* array)
-_EVAL_DEF_INTRINSICS_FUNC(ArrayLength,
- dex_lang_array_length,
- kAttrReadOnly | kAttrNoThrow,
- kInt32Ty,
- _EXPAND_ARG2(kInt32Ty, kJavaObjectTy))
-
// JavaObject* dex_lang_new_array(uint32_t type_idx, uint32_t array_size)
_EVAL_DEF_INTRINSICS_FUNC(NewArray,
dex_lang_new_array,
@@ -201,12 +303,59 @@ _EVAL_DEF_INTRINSICS_FUNC(NewArray,
kJavaObjectTy,
_EXPAND_ARG2(kInt32ConstantTy, kInt32Ty))
-// void dex_lang_fill_array_data(int32_t offset, JavaObject* array)
-_EVAL_DEF_INTRINSICS_FUNC(FillArrayData,
- dex_lang_fill_array_data,
+// uint32_t dex_lang_opt_array_length(int32_t opt_flags, JavaObject* array)
+_EVAL_DEF_INTRINSICS_FUNC(OptArrayLength,
+ dex_lang_opt_array_length,
+ kAttrReadOnly | kAttrNoThrow,
+ kInt32Ty,
+ _EXPAND_ARG2(kInt32Ty, kJavaObjectTy))
+
+// uint32_t dex_lang_array_length(JavaObject* array)
+_EVAL_DEF_INTRINSICS_FUNC(ArrayLength,
+ dex_lang_array_length,
+ kAttrReadOnly | kAttrNoThrow,
+ kInt32Ty,
+ _EXPAND_ARG1(kJavaObjectTy))
+
+// JavaObject* dex_lang_alloc_array(uint32_t type_idx,
+// Method* referrer,
+// uint32_t length,
+// Thread* thread)
+_EVAL_DEF_INTRINSICS_FUNC(AllocArray,
+ dex_lang_alloc_array,
kAttrNone,
- kVoidTy,
- _EXPAND_ARG2(kInt32ConstantTy, kJavaObjectTy))
+ kJavaObjectTy,
+ _EXPAND_ARG4(kInt32ConstantTy, kJavaMethodTy, kInt32Ty, kJavaThreadTy))
+
+// JavaObject* dex_lang_alloc_array_with_access_check(uint32_t type_idx,
+// Method* referrer,
+// uint32_t length,
+// Thread* thread)
+_EVAL_DEF_INTRINSICS_FUNC(AllocArrayWithAccessCheck,
+ dex_lang_alloc_array_with_access_check,
+ kAttrNone,
+ kJavaObjectTy,
+ _EXPAND_ARG4(kInt32ConstantTy, kJavaMethodTy, kInt32Ty, kJavaThreadTy))
+
+// JavaObject* dex_lang_check_and_alloc_array(uint32_t type_idx,
+// Method* referrer,
+// uint32_t length,
+// Thread* thread)
+_EVAL_DEF_INTRINSICS_FUNC(CheckAndAllocArray,
+ dex_lang_check_and_alloc_array,
+ kAttrNone,
+ kJavaObjectTy,
+ _EXPAND_ARG4(kInt32ConstantTy, kJavaMethodTy, kInt32ConstantTy, kJavaThreadTy))
+
+// JavaObject* dex_lang_check_and_alloc_array_with_access_check(uint32_t type_idx,
+// Method* referrer,
+// uint32_t length,
+// Thread* thread)
+_EVAL_DEF_INTRINSICS_FUNC(CheckAndAllocArrayWithAccessCheck,
+ dex_lang_check_and_alloc_array_with_access_check,
+ kAttrNone,
+ kJavaObjectTy,
+ _EXPAND_ARG4(kInt32ConstantTy, kJavaMethodTy, kInt32ConstantTy, kJavaThreadTy))
// dex_lang_aget_* and dex_lang_aput_* never generate exception since the
// necessary checking on arguments (e.g., array and index) has already done
@@ -301,10 +450,221 @@ _EVAL_DEF_INTRINSICS_FUNC(ArrayPutShort,
// void dex_lang_check_put_array_element(JavaObject* value, JavaObject* array)
_EVAL_DEF_INTRINSICS_FUNC(CheckPutArrayElement,
dex_lang_check_put_array_element,
- kAttrReadOnly | kAttrNoThrow,
+ kAttrNone,
kVoidTy,
_EXPAND_ARG2(kJavaObjectTy, kJavaObjectTy))
+// void dex_lang_filled_new_array(Array* array,
+// uint32_t elem_jty, ...)
+_EVAL_DEF_INTRINSICS_FUNC(FilledNewArray,
+ dex_lang_filled_new_array,
+ kAttrNoThrow,
+ kVoidTy,
+ _EXPAND_ARG3(kJavaObjectTy, kInt32ConstantTy, kVarArgTy))
+
+// void dex_lang_fill_array_data(Method* referrer,
+// uint32_t dex_pc,
+// Array* array,
+// uint32_t payload_offset)
+_EVAL_DEF_INTRINSICS_FUNC(FillArrayData,
+ dex_lang_fill_array_data,
+ kAttrNone,
+ kVoidTy,
+ _EXPAND_ARG4(kJavaMethodTy, kInt32ConstantTy, kJavaObjectTy, kInt32ConstantTy))
+
+// void dex_lang_hl_fill_array_data(int32_t offset, JavaObject* array)
+_EVAL_DEF_INTRINSICS_FUNC(HLFillArrayData,
+ dex_lang_hl_fill_array_data,
+ kAttrNone,
+ kVoidTy,
+ _EXPAND_ARG2(kInt32ConstantTy, kJavaObjectTy))
+
+//----------------------------------------------------------------------------
+// Instance Field
+//----------------------------------------------------------------------------
+
+// [type] dex_lang_iget_[type](uint32_t field_idx,
+// Method* referrer,
+// JavaObject* obj)
+_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldGet,
+ dex_lang_iget,
+ kAttrNone,
+ _JTYPE(kInt32Ty, kField),
+ _EXPAND_ARG3(kInt32ConstantTy, kJavaMethodTy, kJavaObjectTy))
+
+_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldGetWide,
+ dex_lang_iget_wide,
+ kAttrNone,
+ _JTYPE(kInt64Ty, kField),
+ _EXPAND_ARG3(kInt32ConstantTy, kJavaMethodTy, kJavaObjectTy))
+
+_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldGetObject,
+ dex_lang_iget_object,
+ kAttrNone,
+ _JTYPE(kJavaObjectTy, kField),
+ _EXPAND_ARG3(kInt32ConstantTy, kJavaMethodTy, kJavaObjectTy))
+
+_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldGetBoolean,
+ dex_lang_iget_boolean,
+ kAttrNone,
+ _JTYPE(kInt1Ty, kField),
+ _EXPAND_ARG3(kInt32ConstantTy, kJavaMethodTy, kJavaObjectTy))
+
+_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldGetByte,
+ dex_lang_iget_byte,
+ kAttrNone,
+ _JTYPE(kInt8Ty, kField),
+ _EXPAND_ARG3(kInt32ConstantTy, kJavaMethodTy, kJavaObjectTy))
+
+_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldGetChar,
+ dex_lang_iget_char,
+ kAttrNone,
+ _JTYPE(kInt16Ty, kField),
+ _EXPAND_ARG3(kInt32ConstantTy, kJavaMethodTy, kJavaObjectTy))
+
+_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldGetShort,
+ dex_lang_iget_short,
+ kAttrNone,
+ _JTYPE(kInt16Ty, kField),
+ _EXPAND_ARG3(kInt32ConstantTy, kJavaMethodTy, kJavaObjectTy))
+
+// [type] dex_lang_iget_[type].fast(int field_offset,
+// bool is_volatile,
+// JavaObject* obj)
+_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldGetFast,
+ dex_lang_iget.fast,
+ kAttrReadOnly | kAttrNoThrow,
+ _JTYPE(kInt32Ty, kField),
+ _EXPAND_ARG3(kInt32ConstantTy, kInt1ConstantTy, kJavaObjectTy))
+
+_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldGetWideFast,
+ dex_lang_iget_wide.fast,
+ kAttrReadOnly | kAttrNoThrow,
+ _JTYPE(kInt64Ty, kField),
+ _EXPAND_ARG3(kInt32ConstantTy, kInt1ConstantTy, kJavaObjectTy))
+
+_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldGetObjectFast,
+ dex_lang_iget_object.fast,
+ kAttrReadOnly | kAttrNoThrow,
+ _JTYPE(kJavaObjectTy, kField),
+ _EXPAND_ARG3(kInt32ConstantTy, kInt1ConstantTy, kJavaObjectTy))
+
+_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldGetBooleanFast,
+ dex_lang_iget_boolean.fast,
+ kAttrReadOnly | kAttrNoThrow,
+ _JTYPE(kInt1Ty, kField),
+ _EXPAND_ARG3(kInt32ConstantTy, kInt1ConstantTy, kJavaObjectTy))
+
+_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldGetByteFast,
+ dex_lang_iget_byte.fast,
+ kAttrReadOnly | kAttrNoThrow,
+ _JTYPE(kInt8Ty, kField),
+ _EXPAND_ARG3(kInt32ConstantTy, kInt1ConstantTy, kJavaObjectTy))
+
+_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldGetCharFast,
+ dex_lang_iget_char.fast,
+ kAttrReadOnly | kAttrNoThrow,
+ _JTYPE(kInt16Ty, kField),
+ _EXPAND_ARG3(kInt32ConstantTy, kInt1ConstantTy, kJavaObjectTy))
+
+_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldGetShortFast,
+ dex_lang_iget_short.fast,
+ kAttrReadOnly | kAttrNoThrow,
+ _JTYPE(kInt16Ty, kField),
+ _EXPAND_ARG3(kInt32ConstantTy, kInt1ConstantTy, kJavaObjectTy))
+
+// void dex_lang_iput_[type](uint32_t field_idx,
+// Method* referrer,
+// JavaObject* obj,
+// [type] new_value)
+_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldPut,
+ dex_lang_iput,
+ kAttrNone,
+ kVoidTy,
+ _EXPAND_ARG4(kInt32ConstantTy, kJavaMethodTy, kJavaObjectTy, _JTYPE(kInt32Ty, kField)))
+
+_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldPutWide,
+ dex_lang_iput_wide,
+ kAttrNone,
+ kVoidTy,
+ _EXPAND_ARG4(kInt32ConstantTy, kJavaMethodTy, kJavaObjectTy, _JTYPE(kInt64Ty, kField)))
+
+_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldPutObject,
+ dex_lang_iput_object,
+ kAttrNone,
+ kVoidTy,
+ _EXPAND_ARG4(kInt32ConstantTy, kJavaMethodTy, kJavaObjectTy, _JTYPE(kJavaObjectTy, kField)))
+
+_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldPutBoolean,
+ dex_lang_iput_boolean,
+ kAttrNone,
+ kVoidTy,
+ _EXPAND_ARG4(kInt32ConstantTy, kJavaMethodTy, kJavaObjectTy, _JTYPE(kInt1Ty, kField)))
+
+_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldPutByte,
+ dex_lang_iput_byte,
+ kAttrNone,
+ kVoidTy,
+ _EXPAND_ARG4(kInt32ConstantTy, kJavaMethodTy, kJavaObjectTy, _JTYPE(kInt8Ty, kField)))
+
+_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldPutChar,
+ dex_lang_iput_char,
+ kAttrNone,
+ kVoidTy,
+ _EXPAND_ARG4(kInt32ConstantTy, kJavaMethodTy, kJavaObjectTy, _JTYPE(kInt16Ty, kField)))
+
+_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldPutShort,
+ dex_lang_iput_short,
+ kAttrNone,
+ kVoidTy,
+ _EXPAND_ARG4(kInt32ConstantTy, kJavaMethodTy, kJavaObjectTy, _JTYPE(kInt16Ty, kField)))
+
+// void dex_lang_iput_[type].fast(int field_offset,
+// bool is_volatile,
+// JavaObject* obj,
+// [type] new_value)
+_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldPutFast,
+ dex_lang_iput.fast,
+ kAttrNoThrow,
+ kVoidTy,
+ _EXPAND_ARG4(kInt32ConstantTy, kInt1ConstantTy, kJavaObjectTy, _JTYPE(kInt32Ty, kField)))
+
+_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldPutWideFast,
+ dex_lang_iput_wide.fast,
+ kAttrNoThrow,
+ kVoidTy,
+ _EXPAND_ARG4(kInt32ConstantTy, kInt1ConstantTy, kJavaObjectTy, _JTYPE(kInt64Ty, kField)))
+
+_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldPutObjectFast,
+ dex_lang_iput_object.fast,
+ kAttrNoThrow,
+ kVoidTy,
+ _EXPAND_ARG4(kInt32ConstantTy, kInt1ConstantTy, kJavaObjectTy, _JTYPE(kJavaObjectTy, kField)))
+
+_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldPutBooleanFast,
+ dex_lang_iput_boolean.fast,
+ kAttrNoThrow,
+ kVoidTy,
+ _EXPAND_ARG4(kInt32ConstantTy, kInt1ConstantTy, kJavaObjectTy, _JTYPE(kInt1Ty, kField)))
+
+_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldPutByteFast,
+ dex_lang_iput_byte.fast,
+ kAttrNoThrow,
+ kVoidTy,
+ _EXPAND_ARG4(kInt32ConstantTy, kInt1ConstantTy, kJavaObjectTy, _JTYPE(kInt8Ty, kField)))
+
+_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldPutCharFast,
+ dex_lang_iput_char.fast,
+ kAttrNoThrow,
+ kVoidTy,
+ _EXPAND_ARG4(kInt32ConstantTy, kInt1ConstantTy, kJavaObjectTy, _JTYPE(kInt16Ty, kField)))
+
+_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldPutShortFast,
+ dex_lang_iput_short.fast,
+ kAttrNoThrow,
+ kVoidTy,
+ _EXPAND_ARG4(kInt32ConstantTy, kInt1ConstantTy, kJavaObjectTy, _JTYPE(kInt16Ty, kField)))
+
//----------------------------------------------------------------------------
// Static Field
//----------------------------------------------------------------------------
@@ -312,43 +672,43 @@ _EVAL_DEF_INTRINSICS_FUNC(CheckPutArrayElement,
// [type] dex_lang_sget_[type](uint32_t field_idx, Method* referrer)
_EVAL_DEF_INTRINSICS_FUNC(StaticFieldGet,
dex_lang_sget,
- kAttrReadOnly,
+ kAttrNone,
_JTYPE(kInt32Ty, kField),
_EXPAND_ARG2(kInt32ConstantTy, kJavaMethodTy))
_EVAL_DEF_INTRINSICS_FUNC(StaticFieldGetWide,
dex_lang_sget_wide,
- kAttrReadOnly,
+ kAttrNone,
_JTYPE(kInt64Ty, kField),
_EXPAND_ARG2(kInt32ConstantTy, kJavaMethodTy))
_EVAL_DEF_INTRINSICS_FUNC(StaticFieldGetObject,
dex_lang_sget_object,
- kAttrReadOnly,
+ kAttrNone,
_JTYPE(kJavaObjectTy, kField),
_EXPAND_ARG2(kInt32ConstantTy, kJavaMethodTy))
_EVAL_DEF_INTRINSICS_FUNC(StaticFieldGetBoolean,
dex_lang_sget_boolean,
- kAttrReadOnly,
+ kAttrNone,
_JTYPE(kInt1Ty, kField),
_EXPAND_ARG2(kInt32ConstantTy, kJavaMethodTy))
_EVAL_DEF_INTRINSICS_FUNC(StaticFieldGetByte,
dex_lang_sget_byte,
- kAttrReadOnly,
+ kAttrNone,
_JTYPE(kInt8Ty, kField),
_EXPAND_ARG2(kInt32ConstantTy, kJavaMethodTy))
_EVAL_DEF_INTRINSICS_FUNC(StaticFieldGetChar,
dex_lang_sget_char,
- kAttrReadOnly,
+ kAttrNone,
_JTYPE(kInt16Ty, kField),
_EXPAND_ARG2(kInt32ConstantTy, kJavaMethodTy))
_EVAL_DEF_INTRINSICS_FUNC(StaticFieldGetShort,
dex_lang_sget_short,
- kAttrReadOnly,
+ kAttrNone,
_JTYPE(kInt16Ty, kField),
_EXPAND_ARG2(kInt32ConstantTy, kJavaMethodTy))
@@ -802,7 +1162,7 @@ _EVAL_DEF_INTRINSICS_FUNC(HLInvokeDouble,
_EXPAND_ARG1(kVarArgTy))
// FILLED_NEW_ARRAY returns object
-_EVAL_DEF_INTRINSICS_FUNC(FilledNewArray,
+_EVAL_DEF_INTRINSICS_FUNC(HLFilledNewArray,
dex_lang_hl_filled_new_array,
kAttrNone,
kJavaObjectTy,
@@ -812,21 +1172,60 @@ _EVAL_DEF_INTRINSICS_FUNC(FilledNewArray,
// Invoke
//----------------------------------------------------------------------------
-// Method* dex_lang_get_callee_method_obj_addr(uint32_t method_idx,
-// JavaObject* this,
-// Method* referrer,
-// Thread* thread,
-// InvokeType type)
-_EVAL_DEF_INTRINSICS_FUNC(GetCalleeMethodObjAddr,
- dex_lang_get_callee_method_obj_addr,
- kAttrReadOnly,
+// Method* dex_lang_find_static_method_with_access_check(uint32_t method_idx,
+// JavaObject* this,
+// Method* referrer,
+// Thread* thread)
+_EVAL_DEF_INTRINSICS_FUNC(FindStaticMethodWithAccessCheck,
+ dex_lang_find_static_method_with_access_check,
+ kAttrNone,
+ kJavaMethodTy,
+ _EXPAND_ARG4(kInt32ConstantTy, kJavaObjectTy, kJavaMethodTy, kJavaThreadTy))
+
+// Method* dex_lang_find_direct_method_with_access_check(uint32_t method_idx,
+// JavaObject* this,
+// Method* referrer,
+// Thread* thread)
+_EVAL_DEF_INTRINSICS_FUNC(FindDirectMethodWithAccessCheck,
+ dex_lang_find_direct_method_with_access_check,
+ kAttrNone,
kJavaMethodTy,
- _EXPAND_ARG5(kInt32ConstantTy, kJavaObjectTy, kJavaMethodTy, kJavaThreadTy, kInt32ConstantTy))
+ _EXPAND_ARG4(kInt32ConstantTy, kJavaObjectTy, kJavaMethodTy, kJavaThreadTy))
+
+// Method* dex_lang_find_virtual_method_with_access_check(uint32_t method_idx,
+// JavaObject* this,
+// Method* referrer,
+// Thread* thread)
+_EVAL_DEF_INTRINSICS_FUNC(FindVirtualMethodWithAccessCheck,
+ dex_lang_find_virtual_method_with_access_check,
+ kAttrNone,
+ kJavaMethodTy,
+ _EXPAND_ARG4(kInt32ConstantTy, kJavaObjectTy, kJavaMethodTy, kJavaThreadTy))
+
+// Method* dex_lang_find_super_method_with_access_check(uint32_t method_idx,
+// JavaObject* this,
+// Method* referrer,
+// Thread* thread)
+_EVAL_DEF_INTRINSICS_FUNC(FindSuperMethodWithAccessCheck,
+ dex_lang_find_super_method_with_access_check,
+ kAttrNone,
+ kJavaMethodTy,
+ _EXPAND_ARG4(kInt32ConstantTy, kJavaObjectTy, kJavaMethodTy, kJavaThreadTy))
+
+// Method* dex_lang_find_interface_method_with_access_check(uint32_t method_idx,
+// JavaObject* this,
+// Method* referrer,
+// Thread* thread)
+_EVAL_DEF_INTRINSICS_FUNC(FindInterfaceMethodWithAccessCheck,
+ dex_lang_find_interface_method_with_access_check,
+ kAttrNone,
+ kJavaMethodTy,
+ _EXPAND_ARG4(kInt32ConstantTy, kJavaObjectTy, kJavaMethodTy, kJavaThreadTy))
// Method* dex_lang_get_sd_callee_method_obj_addr(uint32_t method_idx)
_EVAL_DEF_INTRINSICS_FUNC(GetSDCalleeMethodObjAddrFast,
dex_lang_get_sd_callee_method_obj_addr_fast,
- kAttrReadOnly,
+ kAttrReadOnly | kAttrNoThrow,
kJavaMethodTy,
_EXPAND_ARG1(kInt32ConstantTy))
@@ -844,7 +1243,7 @@ _EVAL_DEF_INTRINSICS_FUNC(GetVirtualCalleeMethodObjAddrFast,
// Thread* thread)
_EVAL_DEF_INTRINSICS_FUNC(GetInterfaceCalleeMethodObjAddrFast,
dex_lang_get_interface_callee_method_obj_addr_fast,
- kAttrReadOnly,
+ kAttrNone,
kJavaMethodTy,
_EXPAND_ARG4(kInt32ConstantTy, kJavaObjectTy, kJavaMethodTy, kJavaThreadTy))
@@ -856,21 +1255,63 @@ _EVAL_DEF_INTRINSICS_FUNC(InvokeRetVoid,
kVoidTy,
_EXPAND_ARG2(kJavaMethodTy, kVarArgTy))
-// INVOKE method returns the value of type in Dalvik register category 1
-_EVAL_DEF_INTRINSICS_FUNC(InvokeRetCat1,
- dex_lang_invoke.i32,
+// INVOKE method returns the value of type boolean
+_EVAL_DEF_INTRINSICS_FUNC(InvokeRetBoolean,
+ dex_lang_invoke.bool,
+ kAttrNone,
+ kInt1Ty,
+ _EXPAND_ARG2(kJavaMethodTy, kVarArgTy))
+
+// INVOKE method returns the value of type byte
+_EVAL_DEF_INTRINSICS_FUNC(InvokeRetByte,
+ dex_lang_invoke.byte,
+ kAttrNone,
+ kInt8Ty,
+ _EXPAND_ARG2(kJavaMethodTy, kVarArgTy))
+
+// INVOKE method returns the value of type char
+_EVAL_DEF_INTRINSICS_FUNC(InvokeRetChar,
+ dex_lang_invoke.char,
+ kAttrNone,
+ kInt16Ty,
+ _EXPAND_ARG2(kJavaMethodTy, kVarArgTy))
+
+// INVOKE method returns the value of type short
+_EVAL_DEF_INTRINSICS_FUNC(InvokeRetShort,
+ dex_lang_invoke.short,
+ kAttrNone,
+ kInt16Ty,
+ _EXPAND_ARG2(kJavaMethodTy, kVarArgTy))
+
+// INVOKE method returns the value of type int
+_EVAL_DEF_INTRINSICS_FUNC(InvokeRetInt,
+ dex_lang_invoke.int,
kAttrNone,
kInt32Ty,
_EXPAND_ARG2(kJavaMethodTy, kVarArgTy))
-// INVOKE method returns the value of type in Dalvik register category 2
-_EVAL_DEF_INTRINSICS_FUNC(InvokeRetCat2,
- dex_lang_invoke.i64,
+// INVOKE method returns the value of type long
+_EVAL_DEF_INTRINSICS_FUNC(InvokeRetLong,
+ dex_lang_invoke.long,
kAttrNone,
kInt64Ty,
_EXPAND_ARG2(kJavaMethodTy, kVarArgTy))
-// INVOKE method returns the value of type in Dalvik register category "object"
+// INVOKE method returns the value of type float
+_EVAL_DEF_INTRINSICS_FUNC(InvokeRetFloat,
+ dex_lang_invoke.float,
+ kAttrNone,
+ kFloatTy,
+ _EXPAND_ARG2(kJavaMethodTy, kVarArgTy))
+
+// INVOKE method returns the value of type double
+_EVAL_DEF_INTRINSICS_FUNC(InvokeRetDouble,
+ dex_lang_invoke.double,
+ kAttrNone,
+ kDoubleTy,
+ _EXPAND_ARG2(kJavaMethodTy, kVarArgTy))
+
+// INVOKE method returns the value of type "object"
_EVAL_DEF_INTRINSICS_FUNC(InvokeRetObject,
dex_lang_invoke.object,
kAttrNone,
@@ -884,46 +1325,57 @@ _EVAL_DEF_INTRINSICS_FUNC(InvokeRetObject,
// int dex_lang_{div,rem}_int(int a, int b)
_EVAL_DEF_INTRINSICS_FUNC(DivInt,
dex_lang_div_int,
- kAttrReadOnly | kAttrNoThrow,
+ kAttrReadNone | kAttrNoThrow,
kInt32Ty,
_EXPAND_ARG2(kInt32Ty, kInt32Ty))
_EVAL_DEF_INTRINSICS_FUNC(RemInt,
dex_lang_rem_int,
- kAttrReadOnly | kAttrNoThrow,
+ kAttrReadNone | kAttrNoThrow,
kInt32Ty,
_EXPAND_ARG2(kInt32Ty, kInt32Ty))
// long dex_lang_{div,rem}_long(long a, long b)
_EVAL_DEF_INTRINSICS_FUNC(DivLong,
dex_lang_div_long,
- kAttrReadOnly | kAttrNoThrow,
+ kAttrReadNone | kAttrNoThrow,
kInt64Ty,
_EXPAND_ARG2(kInt64Ty, kInt64Ty))
_EVAL_DEF_INTRINSICS_FUNC(RemLong,
dex_lang_rem_long,
- kAttrReadOnly | kAttrNoThrow,
+ kAttrReadNone | kAttrNoThrow,
kInt64Ty,
_EXPAND_ARG2(kInt64Ty, kInt64Ty))
-//----------------------------------------------------------------------------
-// Suspend Test
-//----------------------------------------------------------------------------
+// int64_t dex_lang_d2l(double f)
+_EVAL_DEF_INTRINSICS_FUNC(D2L,
+ dex_lang_d2l,
+ kAttrReadNone | kAttrNoThrow,
+ kInt64Ty,
+ _EXPAND_ARG1(kDoubleTy))
-// void dex_lang_test_suspend(Thread* thread)
-_EVAL_DEF_INTRINSICS_FUNC(TestSuspend,
- dex_lang_test_suspend,
- kAttrNoThrow,
- kVoidTy,
- _EXPAND_ARG1(kJavaThreadTy))
+// int32_t dex_lang_d2l(double f)
+_EVAL_DEF_INTRINSICS_FUNC(D2I,
+ dex_lang_d2i,
+ kAttrReadNone | kAttrNoThrow,
+ kInt32Ty,
+ _EXPAND_ARG1(kDoubleTy))
+
+// int64_t dex_lang_f2l(float f)
+_EVAL_DEF_INTRINSICS_FUNC(F2L,
+ dex_lang_f2l,
+ kAttrReadNone | kAttrNoThrow,
+ kInt64Ty,
+ _EXPAND_ARG1(kFloatTy))
+
+// int32_t dex_lang_f2i(float f)
+_EVAL_DEF_INTRINSICS_FUNC(F2I,
+ dex_lang_f2i,
+ kAttrReadNone | kAttrNoThrow,
+ kInt32Ty,
+ _EXPAND_ARG1(kFloatTy))
-// void dex_lang_check_suspend() /* Expands to GetCurrentThread/TestSuspend */
-_EVAL_DEF_INTRINSICS_FUNC(CheckSuspend,
- dex_lang_check_suspend,
- kAttrNoThrow,
- kVoidTy,
- _EXPAND_ARG0())
//----------------------------------------------------------------------------
// sput intrinsics to assist MIR to Greenland_ir conversion.
// "HL" versions - will be deprecated when fast/slow path handling done
diff --git a/src/greenland/intrinsic_helper.cc b/src/greenland/intrinsic_helper.cc
index b1837fb..7e926d6 100644
--- a/src/greenland/intrinsic_helper.cc
+++ b/src/greenland/intrinsic_helper.cc
@@ -21,7 +21,6 @@
#include <llvm/DerivedTypes.h>
#include <llvm/Function.h>
#include <llvm/Intrinsics.h>
-#include <llvm/Module.h>
#include <llvm/Support/IRBuilder.h>
using namespace art;
@@ -65,10 +64,12 @@ GetLLVMTypeOfIntrinsicValType(IRBuilder& irb,
case IntrinsicHelper::kInt64ConstantTy: {
return irb.getInt64Ty();
}
- case IntrinsicHelper::kFloatTy: {
+ case IntrinsicHelper::kFloatTy:
+ case IntrinsicHelper::kFloatConstantTy: {
return irb.getFloatTy();
}
- case IntrinsicHelper::kDoubleTy: {
+ case IntrinsicHelper::kDoubleTy:
+ case IntrinsicHelper::kDoubleConstantTy: {
return irb.getDoubleTy();
}
case IntrinsicHelper::kNone:
@@ -86,7 +87,7 @@ GetLLVMTypeOfIntrinsicValType(IRBuilder& irb,
namespace art {
namespace greenland {
-const IntrinsicHelper::IntrinsicInfo IntrinsicHelper::Info[MaxIntrinsicId] = {
+const IntrinsicHelper::IntrinsicInfo IntrinsicHelper::Info[] = {
#define DEF_INTRINSICS_FUNC(_, NAME, ATTR, RET_TYPE, ARG1_TYPE, ARG2_TYPE, \
ARG3_TYPE, ARG4_TYPE, \
ARG5_TYPE) \
@@ -144,6 +145,7 @@ IntrinsicHelper::IntrinsicHelper(llvm::LLVMContext& context,
info.name_, &module);
fn->setOnlyReadsMemory(info.attr_ & kAttrReadOnly);
+ fn->setDoesNotAccessMemory(info.attr_ & kAttrReadNone);
// None of the intrinsics throws exception
fn->setDoesNotThrow(true);
diff --git a/src/greenland/intrinsic_helper.h b/src/greenland/intrinsic_helper.h
index 7e84cc9..365d529 100644
--- a/src/greenland/intrinsic_helper.h
+++ b/src/greenland/intrinsic_helper.h
@@ -47,11 +47,22 @@ class IntrinsicHelper {
enum IntrinsicAttribute {
kAttrNone = 0,
- // Intrinsic that doesn't modify the memory state
- kAttrReadOnly = 1 << 0,
+ // Intrinsic that neither modified the memory state nor refer to the global
+ // state
+ kAttrReadNone = 1 << 0,
+
+ // Intrinsic that doesn't modify the memory state. Note that one should set
+ // this flag carefully when the intrinsic may throw exception. Since the
+ // thread state is implicitly modified when an exception is thrown.
+ kAttrReadOnly = 1 << 1,
+
+ // Note that intrinsic without kAttrNoThrow and kAttrDoThrow set means that
+ // intrinsic generates exception in some cases
// Intrinsic that never generates exception
- kAttrNoThrow = 1 << 1,
+ kAttrNoThrow = 1 << 2,
+ // Intrinsic that always generate exception
+ kAttrDoThrow = 1 << 3,
};
enum IntrinsicValType {
@@ -68,15 +79,16 @@ class IntrinsicHelper {
kInt16Ty,
kInt32Ty,
kInt64Ty,
+ kFloatTy,
+ kDoubleTy,
kInt1ConstantTy,
kInt8ConstantTy,
kInt16ConstantTy,
kInt32ConstantTy,
kInt64ConstantTy,
-
- kFloatTy,
- kDoubleTy,
+ kFloatConstantTy,
+ kDoubleConstantTy,
kVarArgTy,
};
@@ -93,7 +105,7 @@ class IntrinsicHelper {
} IntrinsicInfo;
private:
- static const IntrinsicInfo Info[MaxIntrinsicId];
+ static const IntrinsicInfo Info[];
public:
static const IntrinsicInfo& GetInfo(IntrinsicId id) {
@@ -130,7 +142,10 @@ class IntrinsicHelper {
}
private:
- llvm::Function* intrinsic_funcs_[MaxIntrinsicId];
+ // FIXME: "+1" is to workaround the GCC bugs:
+ // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=43949
+ // Remove this when uses newer GCC (> 4.4.3)
+ llvm::Function* intrinsic_funcs_[MaxIntrinsicId + 1];
// Map a llvm::Function to its intrinsic id
llvm::DenseMap<const llvm::Function*, IntrinsicId> intrinsic_funcs_map_;
diff --git a/src/greenland/ir_builder.cc b/src/greenland/ir_builder.cc
index d47a458..e83996a 100644
--- a/src/greenland/ir_builder.cc
+++ b/src/greenland/ir_builder.cc
@@ -25,9 +25,24 @@ IRBuilder::IRBuilder(llvm::LLVMContext& context, llvm::Module& module,
IntrinsicHelper& intrinsic_helper)
: LLVMIRBuilder(context), java_object_type_(NULL), java_method_type_(NULL),
java_thread_type_(NULL), intrinsic_helper_(intrinsic_helper) {
+ // JavaObject must be defined in the module
java_object_type_ = module.getTypeByName("JavaObject")->getPointerTo();
- java_method_type_ = module.getTypeByName("Method")->getPointerTo();
- java_thread_type_ = module.getTypeByName("Thread")->getPointerTo();
+
+ // If type of Method is not explicitly defined in the module, use JavaObject*
+ llvm::Type* type = module.getTypeByName("Method");
+ if (type != NULL) {
+ java_method_type_ = type->getPointerTo();
+ } else {
+ java_method_type_ = java_object_type_;
+ }
+
+ // If type of Thread is not explicitly defined in the module, use JavaObject*
+ type = module.getTypeByName("Thread");
+ if (type != NULL) {
+ java_thread_type_ = type->getPointerTo();
+ } else {
+ java_thread_type_ = java_object_type_;
+ }
}
llvm::Type* IRBuilder::GetJTypeInAccurateSpace(JType jty) {
diff --git a/src/greenland/lir.h b/src/greenland/lir.h
deleted file mode 100644
index 82116b2..0000000
--- a/src/greenland/lir.h
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * 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_GREENLAND_LIR_H_
-#define ART_SRC_GREENLAND_LIR_H_
-
-#include "logging.h"
-#include "macros.h"
-#include "object.h"
-
-#include "lir_desc.h"
-#include "lir_operand.h"
-
-#include <vector>
-
-#include <llvm/ADT/ilist_node.h>
-
-namespace art {
-namespace greenland {
-
-class LIRFunction;
-
-class LIR : public llvm::ilist_node<LIR> {
- private:
- // LIRs are allocated and owned by LIRFunction.
- friend class LIRFunction;
-
- LIR(const LIRDesc& desc);
-
- ~LIR() { }
-
- private:
- LIRFunction* parent_;
-
- const LIRDesc& desc_; // Instruction descriptor
-
- std::vector<LIROperand> operands_;
-
-#if 0
- struct {
- bool is_nop:1; // LIR is optimized away
- bool pc_rel_fixup:1; // May need pc-relative fixup
- unsigned int age:4; // default is 0, set lazily by the optimizer
- unsigned int size:5; // in bytes
- unsigned int unused:21;
- } flags_;
-
- int alias_info_; // For Dalvik register & litpool disambiguation
- uint8_t use_mask_; // Resource mask for use
- uint8_t def_mask_; // Resource mask for def
-#endif
-
- private:
- // Intrusive list support
- friend struct llvm::ilist_traits<LIR>;
- friend struct llvm::ilist_traits<LIRFunction>;
- void SetParent(LIRFunction *parent) {
- parent_ = parent;
- }
-
- public:
- const LIRFunction* GetParent() const {
- return parent_;
- }
-
- LIRFunction* GetParent() {
- return parent_;
- }
-
- const LIRDesc& GetDesc() const {
- return desc_;
- }
-
- int GetOpcode() const {
- return desc_.opcode_;
- }
-
- public:
- //----------------------------------------------------------------------------
- // Operand Operations
- //----------------------------------------------------------------------------
- unsigned GetNumOperands() const {
- return static_cast<unsigned>(operands_.size());
- }
-
- const LIROperand& GetOperand(unsigned i) const {
- DCHECK(i < GetNumOperands()) << "GetOperand() out of range!";
- return operands_[i];
- }
-
- LIROperand& GetOperand(unsigned i) {
- DCHECK(i < GetNumOperands()) << "GetOperand() out of range!";
- return operands_[i];
- }
-
- /// iterator/begin/end - Iterate over all operands of a machine instruction.
- typedef std::vector<LIROperand>::iterator op_iterator;
- typedef std::vector<LIROperand>::const_iterator const_op_iterator;
-
- op_iterator operands_begin() { return operands_.begin(); }
- op_iterator operands_end() { return operands_.end(); }
-
- const_op_iterator operands_begin() const { return operands_.begin(); }
- const_op_iterator operands_end() const { return operands_.end(); }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(LIR);
-};
-
-} // namespace greenland
-} // namespace art
-
-#endif // ART_SRC_GREENLAND_LIR_H_
diff --git a/src/greenland/lir_frame_info.h b/src/greenland/lir_frame_info.h
deleted file mode 100644
index ecaa7f3..0000000
--- a/src/greenland/lir_frame_info.h
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * 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_GREENLAND_LIR_FRAME_INFO_H_
-#define ART_SRC_GREENLAND_LIR_FRAME_INFO_H_
-
-#include "logging.h"
-
-#include <vector>
-
-namespace art {
-namespace greenland {
-
-class LIRFrameInfo {
- private:
- struct StackObject {
- // The offset from the stack pointer
- off_t sp_offset_;
-
- // The object is a dead object if its size is 0
- size_t size_;
-
- unsigned alignment_;
-
- StackObject(size_t size, unsigned alignment)
- : size_(size), alignment_(alignment) { }
- };
-
- // stack_size_ and sp_offset_ in each StackObject will be updated by ...
- size_t stack_size_;
-
- std::vector<StackObject> objects_;
-
- public:
- LIRFrameInfo() : stack_size_(0) { }
-
- bool HasStackObjects() const {
- return !objects_.empty();
- }
-
- unsigned GetNumObjects() const {
- return objects_.size();
- }
-
- size_t GetStackSize() const {
- return stack_size_;
- }
- void SetStackSize(size_t stack_size) {
- stack_size_ = stack_size;
- return;
- }
-
- //----------------------------------------------------------------------------
- // Stack Object
- //----------------------------------------------------------------------------
- size_t GetObjectOffset(unsigned idx) const {
- DCHECK(idx < GetNumObjects()) << "Invalid frame index!";
- return objects_[idx].sp_offset_;
- }
- void SetObjectOffset(unsigned idx, off_t sp_offset) {
- DCHECK(idx < GetNumObjects()) << "Invalid frame index!";
- objects_[idx].sp_offset_ = sp_offset;
- return;
- }
-
- size_t GetObjectSize(unsigned idx) const {
- DCHECK(idx < GetNumObjects()) << "Invalid frame index!";
- return objects_[idx].size_;
- }
-
- size_t GetObjectAlignment(unsigned idx) const {
- DCHECK(idx < GetNumObjects()) << "Invalid frame index!";
- return objects_[idx].alignment_;
- }
-
- unsigned AllocateStackObject(size_t size, unsigned alignment = 1) {
- DCHECK(size > 0);
- objects_.push_back(StackObject(size, alignment));
- return objects_.size() - 1;
- }
-
- void RemoveStackObject(unsigned idx) {
- DCHECK(idx < GetNumObjects()) << "Invalid frame index!";
- objects_[idx].size_ = 0;
- return;
- }
-};
-
-} // namespace greenland
-} // namespace art
-
-#endif // ART_SRC_GREENLAND_LIR_FRAME_INFO_H_
diff --git a/src/greenland/lir_function.cc b/src/greenland/lir_function.cc
deleted file mode 100644
index 5def2ac..0000000
--- a/src/greenland/lir_function.cc
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * 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 "lir_function.h"
-
-#include "lir_frame_info.h"
-
-#include "logging.h"
-
-namespace llvm {
-
-using art::greenland::LIR;
-using art::greenland::LIRFunction;
-
-void ilist_traits<LIR>::addNodeToList(LIR* lir) {
- DCHECK(lir->GetParent() == 0) << "LIR already in a function";
- // Update the LIR::parent_
- lir->SetParent(parent_);
- return;
-}
-
-void ilist_traits<LIR>::removeNodeFromList(LIR* lir) {
- DCHECK(lir->GetParent() == 0) << "LIR is not in a function";
- // Update the LIR::parent_
- lir->SetParent(NULL);
- return;
-}
-
-void ilist_traits<LIR>::transferNodesFromList(ilist_traits &src_traits,
- ilist_iterator<LIR> first,
- ilist_iterator<LIR> last) {
- UNIMPLEMENTED(FATAL);
- return;
-}
-
-void ilist_traits<LIR>::deleteNode(LIR* lir) {
- CHECK(!lir->GetParent()) << "LIR is still in a block!";
- parent_->DeleteLIR(lir);
- return;
-}
-
-} // namespace llvm
-
-namespace art {
-namespace greenland {
-
-LIRFunction::LIRFunction() : frame_info_(NULL) {
- lirs_.parent_ = this;
- frame_info_ = new (allocator_) LIRFrameInfo();
- return;
-}
-
-LIRFunction::~LIRFunction() {
- lirs_.clear();
- lir_recycler_.clear(allocator_);
-
- frame_info_->~LIRFrameInfo();
- allocator_.Deallocate(frame_info_);
-
- return;
-}
-
-LIR* LIRFunction::CreateLIR(const LIRDesc& desc) {
- return new (lir_recycler_.Allocate<LIR>(allocator_)) LIR(desc);
-}
-
-void LIRFunction::DeleteLIR(LIR* lir) {
- lir->~LIR();
- lir_recycler_.Deallocate(allocator_, lir);
-}
-
-} // namespace greenland
-} // namespace art
diff --git a/src/greenland/lir_function.h b/src/greenland/lir_function.h
deleted file mode 100644
index 0e77f17..0000000
--- a/src/greenland/lir_function.h
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * 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_GREENLAND_LIR_FUNCTION_H_
-#define ART_SRC_GREENLAND_LIR_FUNCTION_H_
-
-#include "lir.h"
-
-#include <llvm/ADT/ilist.h>
-#include <llvm/Support/Allocator.h>
-#include <llvm/Support/Recycler.h>
-
-namespace llvm {
-
-template <>
-struct ilist_traits<art::greenland::LIR> :
- public ilist_default_traits<art::greenland::LIR> {
- private:
- mutable ilist_half_node<art::greenland::LIR> sentinel_;
-
- friend class art::greenland::LIRFunction;
- art::greenland::LIRFunction* parent_;
-
- public:
- art::greenland::LIR *createSentinel() const {
- return static_cast<art::greenland::LIR*>(&sentinel_);
- }
- void destroySentinel(art::greenland::LIR *) const {}
-
- art::greenland::LIR *provideInitialHead() const {
- return createSentinel();
- }
- art::greenland::LIR *ensureHead(art::greenland::LIR*) const {
- return createSentinel();
- }
- static void noteHead(art::greenland::LIR*, art::greenland::LIR*) {}
-
- void addNodeToList(art::greenland::LIR* N);
- void removeNodeFromList(art::greenland::LIR* N);
- void transferNodesFromList(ilist_traits &src_traits,
- ilist_iterator<art::greenland::LIR> first,
- ilist_iterator<art::greenland::LIR> last);
- void deleteNode(art::greenland::LIR *N);
-private:
- void createNode(const art::greenland::LIR &);
-};
-
-} // namespace llvm
-
-namespace art {
-namespace greenland {
-
-class LIRFrameInfo;
-
-class LIRFunction {
- private:
- llvm::ilist<LIR> lirs_;
-
- // Pool-allocate the objects reside in this instance
- llvm::BumpPtrAllocator allocator_;
-
- // Allocation management for instructions in function.
- llvm::Recycler<LIR> lir_recycler_;
-
- // The stack information
- LIRFrameInfo* frame_info_;
-
- public:
- LIRFunction();
- ~LIRFunction();
-
- public:
- //----------------------------------------------------------------------------
- // LIR Accessor Functions
- //----------------------------------------------------------------------------
- typedef llvm::ilist<LIR>::iterator iterator;
- typedef llvm::ilist<LIR>::const_iterator const_iterator;
- typedef std::reverse_iterator<iterator> reverse_iterator;
- typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
-
- unsigned GetNumLIRs() const {
- return static_cast<unsigned>(lirs_.size());
- }
- bool IsEmpty() const {
- return lirs_.empty();
- }
-
- LIR& front() { return lirs_.front(); }
- LIR& back() { return lirs_.back(); }
- const LIR& front() const { return lirs_.front(); }
- const LIR& back() const { return lirs_.back(); }
-
- iterator begin() { return lirs_.begin(); }
- const_iterator begin() const { return lirs_.begin(); }
- iterator end() { return lirs_.end(); }
- const_iterator end() const { return lirs_.end(); }
- reverse_iterator rbegin() { return lirs_.rbegin(); }
- const_reverse_iterator rbegin() const { return lirs_.rbegin(); }
- reverse_iterator rend () { return lirs_.rend(); }
- const_reverse_iterator rend () const { return lirs_.rend(); }
-
- void pop_front() {
- lirs_.pop_front();
- }
-
- void push_back(LIR *lir) {
- lirs_.push_back(lir);
- }
-
- iterator insert(iterator i, LIR* lir) {
- return lirs_.insert(i, lir);
- }
-
- iterator erase(iterator i) {
- return lirs_.erase(i);
- }
-
- LIR* remove(iterator i) {
- return lirs_.remove(i);
- }
-
- public:
- //----------------------------------------------------------------------------
- // LIR Memory Allocation
- //----------------------------------------------------------------------------
- LIR* CreateLIR(const LIRDesc& desc);
-
- void DeleteLIR(LIR* lir);
-
- public:
- const LIRFrameInfo& GetFrameInfo() const {
- return *frame_info_;
- }
- LIRFrameInfo& GetFrameInfo() {
- return *frame_info_;
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(LIRFunction);
-};
-
-} // namespace greenland
-} // namespace art
-
-#endif // ART_SRC_GREENLAND_LIR_FUNCTION_H_
diff --git a/src/greenland/lir_operand.h b/src/greenland/lir_operand.h
deleted file mode 100644
index d6d9232..0000000
--- a/src/greenland/lir_operand.h
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * 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_GREENLAND_LIR_OPERAND_H_
-#define ART_SRC_GREENLAND_LIR_OPERAND_H_
-
-#include "logging.h"
-
-namespace llvm {
- class ConstantFP;
-}
-
-namespace art {
-namespace greenland {
-
-class LIR;
-
-class LIROperand {
- public:
- enum Type {
- UnknownType,
- RegisterType,
- ImmediateType,
- FPImmediateType,
- LabelType,
- };
-
- private:
- Type type_;
-
- union {
- // RegisterType
- unsigned reg_no_;
-
- // ImmediateType
- int64_t imm_val_;
-
- // FPImmediateType
- const llvm::ConstantFP *fp_imm_val_;
-
- // LabelType
- const LIR* target_;
- } contents_;
-
- friend class LIR;
- LIROperand() : type_(UnknownType) { }
-
- void SetType(enum Type type) {
- type_ = type;
- return;
- }
-
- public:
- enum Type GetType() const {
- return type_;
- }
-
- bool IsReg() const {
- return (type_ == RegisterType);
- }
- bool IsImm() const {
- return (type_ == ImmediateType);
- }
- bool IsFPImm() const {
- return (type_ == FPImmediateType);
- }
- bool IsLabel() const {
- return (type_ == LabelType);
- }
-
- //----------------------------------------------------------------------------
- // Accessors
- //----------------------------------------------------------------------------
- unsigned GetReg() const {
- CHECK(IsReg()) << "This is not a register operand!";
- return contents_.reg_no_;
- }
-
- int64_t GetImm() const {
- CHECK(IsImm()) << "This is not a immediate operand!";
- return contents_.imm_val_;
- }
-
- const llvm::ConstantFP* GetFPImm() const {
- CHECK(IsFPImm()) << "This is not a FP immediate operand!";
- return contents_.fp_imm_val_;
- }
-
- const LIR* GetLabelTarget() const {
- CHECK(IsFPImm()) << "This is not a label operand!";
- return contents_.target_;
- }
-
- //----------------------------------------------------------------------------
- // Mutators
- //----------------------------------------------------------------------------
- void SetReg(unsigned reg_no) {
- if (type_ == UnknownType) {
- type_ = RegisterType;
- }
- CHECK(IsReg()) << "This is not a register operand!";
- contents_.reg_no_ = reg_no;
- return;
- }
-
- void SetImm(int64_t imm_val) {
- if (type_ == UnknownType) {
- type_ = ImmediateType;
- }
- CHECK(IsImm()) << "This is not a immediate operand!";
- contents_.imm_val_ = imm_val;
- return;
- }
-
- void SetFPImm(const llvm::ConstantFP* fp_imm_val) {
- if (type_ == UnknownType) {
- type_ = FPImmediateType;
- }
- CHECK(IsFPImm()) << "This is not a FP immediate operand!";
- contents_.fp_imm_val_ = fp_imm_val;
- return;
- }
-
- void SetLabelTarget(LIR* target) {
- if (type_ == UnknownType) {
- type_ = LabelType;
- }
- CHECK(IsLabel()) << "This is not a label operand!";
- contents_.target_ = target;
- return;
- }
-
-};
-
-} // namespace greenland
-} // namespace art
-
-#endif // ART_SRC_GREENLAND_LIR_OPERAND_H_
diff --git a/src/greenland/mips/mips_codegen_machine.h b/src/greenland/mips/mips_codegen_machine.h
index e3412e9..c9f0abf 100644
--- a/src/greenland/mips/mips_codegen_machine.h
+++ b/src/greenland/mips/mips_codegen_machine.h
@@ -29,9 +29,27 @@ class MipsCodeGenMachine : public TargetCodeGenMachine {
MipsCodeGenMachine();
virtual ~MipsCodeGenMachine();
- virtual TargetLIREmitter* CreateLIREmitter(const llvm::Function& func,
- const OatCompilationUnit& cunit,
- DexLang::Context& dex_lang_ctx) {
+ virtual TargetLIREmitter* CreateLIREmitter() {
+ return NULL;
+ }
+
+ virtual const TargetDataLayout* GetDataLayout() const {
+ return NULL;
+ }
+
+ virtual const TargetLIRInfo* GetLIRInfo() const {
+ return NULL;
+ }
+
+ virtual const TargetRegisterInfo* GetRegisterInfo() const {
+ return NULL;
+ }
+
+ virtual const char* GetConditionCodeName(unsigned cond) const {
+ return NULL;
+ }
+
+ virtual TargetLIRBuilder* CreateLIRBuilder() {
return NULL;
}
@@ -42,6 +60,10 @@ class MipsCodeGenMachine : public TargetCodeGenMachine {
virtual TargetAssembler* GetAssembler() {
return NULL;
}
+
+ virtual std::string PrettyTargeteLIR(const LIR& lir) const {
+ return "";
+ }
};
} // namespace greenland
diff --git a/src/greenland/target_lir.def b/src/greenland/mips/mips_lir.def
index a3838c6..0741f1b 100644
--- a/src/greenland/target_lir.def
+++ b/src/greenland/mips/mips_lir.def
@@ -14,9 +14,5 @@
* limitations under the License.
*/
-// DEF_LIR_DESC(OPCODE, NUM_OPS)
-#ifndef DEF_LIR_DESC
-# error "missing DEF_LIR_DESC definition!"
-#endif
-
-DEF_LIR_DESC(kBlockLabel, 1)
+#include "greenland/target_lir.def"
+#include "greenland/clear_target_lir.def"
diff --git a/src/greenland/register_allocator.cc b/src/greenland/register_allocator.cc
new file mode 100644
index 0000000..b19f111
--- /dev/null
+++ b/src/greenland/register_allocator.cc
@@ -0,0 +1,291 @@
+/*
+ * 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 "register_allocator.h"
+#include "lir_function.h"
+#include "lir_frame_info.h"
+#include "lir_reg.h"
+
+#include "target_register_info.h"
+
+#include "logging.h"
+#include "stl_util.h"
+
+namespace art {
+namespace greenland {
+
+void RegisterAllocator::BuildKillInfo(LIRFunction& lir_func) {
+ //TODO: Build Register KillInfo
+}
+
+static LIRBasicBlock::iterator
+GetSourceIterator(LIRBasicBlock& sourceBB, LIRBasicBlock& targetBB) {
+ LIRBasicBlock::iterator it;
+ for (it = sourceBB.back(); it != sourceBB.begin(); --it) {
+ if (it->IsBranch() && (it->GetOperand(0).GetLabelTarget() == &targetBB))
+ break;
+ }
+ return it;
+}
+
+void RegisterAllocator::PHIElimination(LIRFunction& lir_func) {
+ for (LIRFunction::iterator bb = lir_func.begin(); bb != lir_func.end(); ++bb) {
+ if (bb->IsEmpty() || !bb->front().IsPHI())
+ continue;
+
+ LIRBasicBlock::iterator it; // current LIR
+ LIRBasicBlock::iterator next_it; // next LIR
+ for(it = bb->begin(); it != bb->end(); it = next_it) {
+ next_it = it; ++next_it;
+ if (!it->IsPHI())
+ break;
+
+ for (unsigned i = 1; i < it->GetNumOperands(); i+=2) {
+ const LIROperand& dst = it->GetOperand(0);
+ const LIROperand& src = it->GetOperand(i);
+ LIRBasicBlock* sourceBB =
+ const_cast<LIRBasicBlock*> (it->GetOperand(i + 1).GetLabelTarget());
+
+ LIR* lir = reg_info_.CreateCopy(lir_func, dst.GetReg(), src);
+ LOG(INFO) << "PHIElimination: Insert COPY into BB: " << sourceBB->GetName();
+ sourceBB->insert(GetSourceIterator(*sourceBB, *bb), lir);
+ }
+
+ bb->erase(it);
+ }
+ }
+}
+
+RegisterAllocator::Storage
+RegisterAllocator::AllocateStorage(LIRFunction &lir_func, unsigned vreg_idx) {
+ // The virtual register is allocated, return it.
+ if (allocated_map_.find(vreg_idx) != allocated_map_.end()) {
+ return allocated_map_[vreg_idx];
+ }
+
+ Storage s;
+ // Have free register(s).
+ if (!allocatable_list_.empty()) {
+ s.regTag = kPhyRegType;
+ s.index = allocatable_list_.front();
+ allocatable_list_.pop_front();
+ }
+ else {
+ s.regTag = kFrameType;
+ if (stackstorage_list_.empty()) {
+ // FIXME: Get register subword
+ s.index = lir_func.GetFrameInfo().AllocateStackObject(4);
+ }
+ else {
+ s.index = stackstorage_list_.front();
+ stackstorage_list_.pop_front();
+ }
+ }
+ allocated_map_[vreg_idx] = s;
+ return s;
+}
+
+void RegisterAllocator::KeepStorage(const LIR& lir) {
+ unsigned reg_value = lir.GetOperand(0).GetReg();
+ int frame_idx = lir.GetOperand(1).GetFrameIndex();
+
+ if (!LIRReg::IsVirtualReg(reg_value))
+ return;
+
+ unsigned vreg_idx = LIRReg::GetRegNo(reg_value);
+
+ LOG(INFO) << "VIRTUAL REG " << vreg_idx << " Keep in Stack Frame [" << frame_idx << "];";
+
+ Storage s;
+ s.regTag = kInStackType;
+ s.index = frame_idx;
+ allocated_map_[vreg_idx] = s;
+}
+
+void RegisterAllocator::FreeStorage(unsigned vreg_idx) {
+ //TODO: Check vreg_idx must be allocated
+ Storage s = allocated_map_[vreg_idx];
+
+ if (s.regTag == kInStackType)
+ return;
+
+ if (s.regTag == kPhyRegType)
+ allocatable_list_.push_front(s.index);
+ else
+ stackstorage_list_.push_front(s.index);
+
+ allocated_map_.erase(vreg_idx);
+}
+
+void RegisterAllocator::InitializeAllocation(LIRFunction &lir_func) {
+ allocatable_list_ = reg_info_.GetAllocatableList();
+ stackstorage_list_.clear();
+ allocated_map_.clear();
+}
+
+void RegisterAllocator::PreRegisterAllocation(LIRFunction &lir_func) {
+ PHIElimination(lir_func);
+}
+
+void
+RegisterAllocator::HandleInsnCopy(LIRBasicBlock &bb,
+ LIRBasicBlock::iterator it,
+ LIRBasicBlock::iterator next_it) {
+ unsigned reg_dst = it->GetOperand(0).GetReg();
+ unsigned reg_src = it->GetOperand(1).GetReg();
+
+ Storage stor_dst = {-1, kNoneType};
+ Storage stor_src = {-1, kNoneType};
+ unsigned vidx_dst = 0, vidx_src = 0;
+
+ if (LIRReg::IsVirtualReg(reg_dst)) {
+ vidx_dst = LIRReg::GetRegNo(reg_dst);
+ LOG(INFO) << "VIRTUAL REG " << vidx_dst << " in COPY need allocated !!";
+ stor_dst = AllocateStorage(bb.GetParent(), vidx_dst);
+ }
+
+ if (LIRReg::IsVirtualReg(reg_src)) {
+ vidx_src = LIRReg::GetRegNo(reg_src);
+ LOG(INFO) << "VIRTUAL REG " << vidx_src << " in COPY need allocated !!";
+ stor_src = AllocateStorage(bb.GetParent(), vidx_src);
+ }
+
+ if ((LIRReg::IsPhysicalReg(reg_dst) || (stor_dst.regTag == kPhyRegType))
+ && (LIRReg::IsPhysicalReg(reg_src) || (stor_src.regTag == kPhyRegType))) {
+ // MovRR
+ unsigned idx_dst = (LIRReg::IsPhysicalReg(reg_dst)) ?
+ LIRReg::GetRegNo(reg_dst) : stor_dst.index;
+ unsigned idx_src = (LIRReg::IsPhysicalReg(reg_src)) ?
+ LIRReg::GetRegNo(reg_src) : stor_src.index;
+ LOG(INFO) << "\t [COPY] create MOVE: move " << idx_dst << ", "<< idx_src;
+ LIR* lir = reg_info_.CreateMoveReg(bb.GetParent(), idx_dst, idx_src);
+ bb.insert(next_it, lir);
+ bb.erase(it);
+
+ if(LIRReg::IsVirtualReg(reg_src)) {
+ FreeStorage(vidx_src);
+ }
+ return;
+ }
+
+ if ((stor_dst.regTag == stor_src.regTag) && (stor_dst.index == stor_src.index)) {
+ // Redundant move
+ FreeStorage(vidx_dst);
+ FreeStorage(vidx_src);
+ bb.erase(it);
+ return;
+ }
+
+ if (stor_dst.regTag != kPhyRegType && stor_src.regTag != kPhyRegType) {
+ unsigned idx = reg_info_.GetTempRegsiter(0);
+ LIR* lir = reg_info_.CreateLoadStack(bb.GetParent(), idx, stor_src.index);
+ bb.insert(it, lir);
+ lir = reg_info_.CreateStoreStack(bb.GetParent(), idx, stor_dst.index);
+ bb.insert(next_it, lir);
+ bb.erase(it);
+ return;
+ }
+
+ if (stor_dst.regTag != kPhyRegType) {
+ unsigned idx = (LIRReg::IsPhysicalReg(reg_src)) ?
+ LIRReg::GetRegNo(reg_src) : stor_src.index;
+ LOG(INFO) << "\t [COPY] create StoreStack: move " << idx << ", "<< stor_dst.index;
+ LIR* lir = reg_info_.CreateStoreStack(bb.GetParent(), idx, stor_dst.index);
+ bb.insert(next_it, lir);
+ bb.erase(it);
+ return;
+ }
+
+ if (stor_src.regTag != kPhyRegType) {
+ unsigned idx = (LIRReg::IsPhysicalReg(reg_dst)) ?
+ LIRReg::GetRegNo(reg_dst) : stor_dst.index;
+ LOG(INFO) << "\t [COPY] create LoadStack: move " << idx << ", "<< stor_src.index;
+ LIR* lir = reg_info_.CreateLoadStack(bb.GetParent(), idx, stor_src.index);
+ bb.insert(next_it, lir);
+ bb.erase(it);
+ return;
+ }
+}
+
+void RegisterAllocator::FunctionRegisterAllocation(LIRFunction &lir_func) {
+ for (LIRFunction::iterator bb = lir_func.begin(); bb != lir_func.end(); ++bb) {
+ LIRBasicBlock::iterator it; // current LIR
+ LIRBasicBlock::iterator next_it; // next LIR
+ for (LIRBasicBlock::iterator it = bb->begin(); it != bb->end(); it = next_it) {
+ next_it = it; ++next_it;
+
+ // Handle Incoming Args
+ if (reg_info_.IsLoadIncomingArgs(it)) {
+ KeepStorage(*it);
+ bb->erase(it);
+ continue;
+ }
+
+ // Handle Copy
+ if (it->GetOpcode() == opcode::kCOPY) {
+ HandleInsnCopy(*bb, *it, *next_it);
+ continue;
+ }
+
+ std::vector<unsigned> free_list;
+ //for (LIR::op_iterator opi = i->operands_begin(); opi != i->operands_end(); ++opi) {
+ for (unsigned i = 0 ; i < it->GetNumOperands(); i++) {
+ LIROperand& lir_opd = it->GetOperand(i);
+ unsigned temp_count = 0;
+
+ if (!lir_opd.IsReg())
+ continue;
+
+ unsigned reg_value = lir_opd.GetReg();
+ if (!LIRReg::IsVirtualReg(reg_value))
+ continue;
+ unsigned vreg_idx = LIRReg::GetRegNo(reg_value);
+ LOG(INFO) << "\t" << "VIRTUAL REG " << vreg_idx << " need allocated !!";
+ Storage s = AllocateStorage(lir_func, vreg_idx);
+ if (!s.regTag) {
+ LOG(INFO) << "\t" << "VIRTUAL REG " << vreg_idx << " is map to REG[" << s.index << "]!!";
+ lir_opd.SetReg(s.index);
+ } else {
+ unsigned temp_idx = reg_info_.GetTempRegsiter(temp_count++);
+ if ( lir_opd.IsDef() ) {
+ LIR* lir = reg_info_.CreateStoreStack(lir_func, temp_idx, s.index);
+ bb->insert(next_it, lir);
+ lir_opd.SetReg(temp_idx);
+ } else {
+ LIR* lir = reg_info_.CreateLoadStack(lir_func, temp_idx, s.index);
+ bb->insert(it, lir);
+ lir_opd.SetReg(temp_idx);
+ }
+
+ LOG(INFO) << "\t" << "VIRTUAL REG " << vreg_idx << " is map to Frame[" << s.index << "]!!";
+ }
+
+ if (lir_opd.IsKill()) {
+ free_list.push_back(vreg_idx);
+ LOG(INFO) << "\t" << "VIRTUAL REG " << vreg_idx << " is mark kill!!";
+ }
+ }
+
+ for (size_t i = 0 ; i < free_list.size(); i++) {
+ LOG(INFO) << "\t" << "VIRTUAL REG " << free_list[i] << " is kill!!";
+ FreeStorage(free_list[i]);
+ }
+ }
+ }
+}
+
+} // namespace greenland
+} // namespace art
diff --git a/src/greenland/register_allocator.h b/src/greenland/register_allocator.h
new file mode 100644
index 0000000..ffe0914
--- /dev/null
+++ b/src/greenland/register_allocator.h
@@ -0,0 +1,82 @@
+/*
+ * 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_GREENLAND_REGISTER_ALLOCATOR_H_
+#define ART_SRC_GREENLAND_REGISTER_ALLOCATOR_H_
+
+#include "backend_types.h"
+
+#include "lir_basic_block.h"
+
+#include <stdint.h>
+#include <list>
+#include <map>
+
+namespace art {
+namespace greenland {
+
+class LIR;
+class LIRFunction;
+class TargetRegisterInfo;
+
+class RegisterAllocator {
+ private:
+ enum RegTypeTag {
+ kPhyRegType = 0, kFrameType, kInStackType, kNoneType = -1
+ };
+
+ struct Storage {
+ int index;
+ RegTypeTag regTag;
+ };
+
+ // Storage Allocation
+ Storage AllocateStorage(LIRFunction &lir_func, unsigned vreg_idx);
+ void KeepStorage(const LIR& lir);
+ void FreeStorage(unsigned vreg_idx);
+ void HandleInsnCopy(LIRBasicBlock& bb,
+ LIRBasicBlock::iterator it,
+ LIRBasicBlock::iterator next_lir);
+
+ // Pre-RA
+ void BuildKillInfo(LIRFunction& lir_func);
+ void PHIElimination(LIRFunction& lir_func);
+
+ void InitializeAllocation(LIRFunction& lir_func);
+ void PreRegisterAllocation(LIRFunction& lir_func);
+ void FunctionRegisterAllocation(LIRFunction& lir_func);
+ public:
+ RegisterAllocator(const TargetRegisterInfo& info) : reg_info_(info) { }
+ ~RegisterAllocator() { }
+
+ void AllocateRegisters(LIRFunction& lir_func) {
+ InitializeAllocation(lir_func);
+ PreRegisterAllocation(lir_func);
+ FunctionRegisterAllocation(lir_func);
+ }
+
+ private:
+ std::list<unsigned> allocatable_list_;
+ std::list<unsigned> stackstorage_list_;
+ std::map<unsigned, Storage> allocated_map_;
+ const TargetRegisterInfo& reg_info_;
+ DISALLOW_COPY_AND_ASSIGN(RegisterAllocator);
+};
+
+} // namespace greenland
+} // namespace art
+
+#endif // ART_SRC_GREENLAND_REGISTER_ALLOCATOR_H_
diff --git a/src/greenland/target_lir_opcodes.h b/src/greenland/runtime/runtime_utils.h
index 27027ca..cbdfcc6 100644
--- a/src/greenland/target_lir_opcodes.h
+++ b/src/greenland/runtime/runtime_utils.h
@@ -14,21 +14,29 @@
* limitations under the License.
*/
-#ifndef ART_SRC_GREENLAND_TARGET_LIR_OPCODES_H_
-#define ART_SRC_GREENLAND_TARGET_LIR_OPCODES_H_
+#ifndef ART_SRC_GREENLAND_RUNTIME_UTILS_H_
+#define ART_SRC_GREENLAND_RUNTIME_UTILS_H_
+
+#include "asm_support.h"
+#include "thread.h"
namespace art {
namespace greenland {
-namespace opcode {
-enum {
-#define DEF_LIR_DESC(OPCODE, ...) OPCODE,
-#include "target_lir.def"
-#undef DEF_LIR_DESC
-};
+static inline Thread* art_get_current_thread() {
+#if defined(__i386__)
+ Thread* ptr;
+ __asm__ __volatile__("movl %%fs:(%1), %0"
+ : "=r"(ptr) // output
+ : "r"(THREAD_SELF_OFFSET) // input
+ :); // clobber
+ return ptr;
+#else
+ return Thread::Current();
+#endif
+}
-} // namespace opcode
} // namespace greenland
} // namespace art
-#endif // ART_SRC_GREENLAND_TARGET_LIR_OPCODES_H_
+#endif // ART_SRC_GREENLAND_RUNTIME_UTILS_H_
diff --git a/src/greenland/runtime/support_alloc.cc b/src/greenland/runtime/support_alloc.cc
new file mode 100644
index 0000000..5198903
--- /dev/null
+++ b/src/greenland/runtime/support_alloc.cc
@@ -0,0 +1,69 @@
+/*
+ * 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 "greenland/runtime_entry_points.h"
+
+#include "runtime_utils.h"
+#include "runtime_support.h"
+
+using namespace art;
+using namespace art::greenland;
+
+namespace {
+
+Object* art_alloc_array_from_code(uint32_t type_idx,
+ Method* referrer,
+ uint32_t length,
+ Thread* thread) {
+ return AllocArrayFromCode(type_idx, referrer, length, thread, false);
+}
+
+Object* art_alloc_array_from_code_with_access_check(uint32_t type_idx,
+ Method* referrer,
+ uint32_t length,
+ Thread* thread) {
+ return AllocArrayFromCode(type_idx, referrer, length, thread, true);
+}
+
+Object* art_check_and_alloc_array_from_code(uint32_t type_idx,
+ Method* referrer,
+ uint32_t length,
+ Thread* thread) {
+ return CheckAndAllocArrayFromCode(type_idx, referrer, length, thread, false);
+}
+
+Object* art_check_and_alloc_array_from_code_with_access_check(uint32_t type_idx,
+ Method* referrer,
+ uint32_t length,
+ Thread* thread) {
+ return CheckAndAllocArrayFromCode(type_idx, referrer, length, thread, true);
+}
+
+} // anonymous namespace
+
+namespace art {
+namespace greenland {
+
+void InitAllocRuntimes(RuntimeEntryPoints* entry_points) {
+ entry_points->AllocArray = art_alloc_array_from_code;
+ entry_points->AllocArrayWithAccessCheck = art_alloc_array_from_code_with_access_check;
+ entry_points->CheckAndAllocArray = art_check_and_alloc_array_from_code;
+ entry_points->CheckAndAllocArrayWithAccessCheck = art_check_and_alloc_array_from_code_with_access_check;
+ return;
+}
+
+} // namespace greenland
+} // namespace art
diff --git a/src/greenland/runtime/support_cast.cc b/src/greenland/runtime/support_cast.cc
new file mode 100644
index 0000000..d74dbe7
--- /dev/null
+++ b/src/greenland/runtime/support_cast.cc
@@ -0,0 +1,57 @@
+/*
+ * 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 "greenland/runtime_entry_points.h"
+
+#include "runtime_utils.h"
+#include "runtime_support.h"
+
+using namespace art;
+using namespace art::greenland;
+
+namespace {
+
+void art_check_put_array_element_from_code(const Object* element,
+ const Object* array) {
+ if (element == NULL) {
+ return;
+ }
+ DCHECK(array != NULL);
+ Class* array_class = array->GetClass();
+ DCHECK(array_class != NULL);
+ Class* component_type = array_class->GetComponentType();
+ Class* element_class = element->GetClass();
+ if (UNLIKELY(!component_type->IsAssignableFrom(element_class))) {
+ Thread* thread = art_get_current_thread();
+ thread->ThrowNewExceptionF("Ljava/lang/ArrayStoreException;",
+ "%s cannot be stored in an array of type %s",
+ PrettyDescriptor(element_class).c_str(),
+ PrettyDescriptor(array_class).c_str());
+ }
+ return;
+}
+
+} // anonymous namespace
+
+namespace art {
+namespace greenland {
+
+void InitCastRuntimes(RuntimeEntryPoints* entry_points) {
+ entry_points->CheckPutArrayElement = art_check_put_array_element_from_code;
+}
+
+} // namespace greenland
+} // namespace art
diff --git a/src/greenland/lir_desc.h b/src/greenland/runtime/support_dexcache.cc
index 84b7af6..903e5cc 100644
--- a/src/greenland/lir_desc.h
+++ b/src/greenland/runtime/support_dexcache.cc
@@ -14,27 +14,28 @@
* limitations under the License.
*/
-#ifndef ART_SRC_GREENLAND_LIR_DESC_H_
-#define ART_SRC_GREENLAND_LIR_DESC_H_
+#include "greenland/runtime_entry_points.h"
-namespace art {
-namespace greenland {
+#include "runtime_utils.h"
+#include "runtime_support.h"
+
+using namespace art;
+using namespace art::greenland;
+
+namespace {
-class LIRDesc {
- public:
- unsigned opcode_; // The opcode number
- unsigned short num_operands_; // Num of args (may be more if variable_ops)
+Object* art_resolve_string(Method* referrer, uint32_t string_idx) {
+ return ResolveStringFromCode(referrer, string_idx);
+}
- unsigned GetOpcode() const {
- return opcode_;
- }
+} // anonymous namespace
- unsigned GetNumOperands() const {
- return num_operands_;
- }
-};
+namespace art {
+namespace greenland {
+
+void InitDexCacheRuntimes(RuntimeEntryPoints* entry_points) {
+ entry_points->ResolveString = art_resolve_string;
+}
} // namespace greenland
} // namespace art
-
-#endif // ART_SRC_GREENLAND_LIR_DESC_H_
diff --git a/src/greenland/runtime/support_exception.cc b/src/greenland/runtime/support_exception.cc
new file mode 100644
index 0000000..2470051
--- /dev/null
+++ b/src/greenland/runtime/support_exception.cc
@@ -0,0 +1,85 @@
+/*
+ * 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 "greenland/runtime_entry_points.h"
+
+#include "nth_caller_visitor.h"
+#include "runtime_utils.h"
+#include "runtime_support.h"
+
+using namespace art;
+using namespace art::greenland;
+
+namespace {
+
+int32_t art_find_catch_block(Method* current_method, uint32_t ti_offset) {
+ Thread* thread = art_get_current_thread();
+ Class* exception_type = thread->GetException()->GetClass();
+ MethodHelper mh(current_method);
+ const DexFile::CodeItem* code_item = mh.GetCodeItem();
+ DCHECK_LT(ti_offset, code_item->tries_size_);
+ const DexFile::TryItem* try_item = DexFile::GetTryItems(*code_item, ti_offset);
+
+ int iter_index = 0;
+ // Iterate over the catch handlers associated with dex_pc
+ for (CatchHandlerIterator it(*code_item, *try_item); it.HasNext(); it.Next()) {
+ uint16_t iter_type_idx = it.GetHandlerTypeIndex();
+ // Catch all case
+ if (iter_type_idx == DexFile::kDexNoIndex16) {
+ return iter_index;
+ }
+ // Does this catch exception type apply?
+ Class* iter_exception_type = mh.GetDexCacheResolvedType(iter_type_idx);
+ if (iter_exception_type == NULL) {
+ // The verifier should take care of resolving all exception classes early
+ LOG(WARNING) << "Unresolved exception class when finding catch block: "
+ << mh.GetTypeDescriptorFromTypeIdx(iter_type_idx);
+ } else if (iter_exception_type->IsAssignableFrom(exception_type)) {
+ return iter_index;
+ }
+ ++iter_index;
+ }
+ // Handler not found
+ return -1;
+}
+
+void art_throw_array_bounds(int32_t length, int32_t index) {
+ Thread* thread = art_get_current_thread();
+ thread->ThrowNewExceptionF("Ljava/lang/ArrayIndexOutOfBoundsException;",
+ "length=%d; index=%d", length, index);
+}
+
+void art_throw_null_pointer_exception(uint32_t dex_pc) {
+ Thread* thread = art_get_current_thread();
+ NthCallerVisitor visitor(0);
+ thread->WalkStack(&visitor);
+ Method* throw_method = visitor.caller;
+ ThrowNullPointerExceptionFromDexPC(thread, throw_method, dex_pc);
+}
+
+} // anonymous namespace
+
+namespace art {
+namespace greenland {
+
+void InitExceptionRuntimes(RuntimeEntryPoints* entry_points) {
+ entry_points->FindCatchBlock = art_find_catch_block;
+ entry_points->ThrowIndexOutOfBounds = art_throw_array_bounds;
+ entry_points->ThrowNullPointerException = art_throw_null_pointer_exception;
+}
+
+} // namespace greenland
+} // namespace art
diff --git a/src/greenland/runtime/support_field.cc b/src/greenland/runtime/support_field.cc
new file mode 100644
index 0000000..523740f
--- /dev/null
+++ b/src/greenland/runtime/support_field.cc
@@ -0,0 +1,50 @@
+/*
+ * 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 "greenland/runtime_entry_points.h"
+
+#include "runtime_utils.h"
+#include "runtime_support.h"
+
+using namespace art;
+using namespace art::greenland;
+
+namespace {
+
+Object* art_get_obj_static_from_code(uint32_t field_idx, Method* referrer) {
+ Field* field = FindFieldFast(field_idx, referrer, false, false, sizeof(Object*));
+ if (LIKELY(field != NULL)) {
+ return field->GetObj(NULL);
+ }
+ field = FindFieldFromCode(field_idx, referrer, art_get_current_thread(),
+ true, false, false, sizeof(Object*));
+ if (LIKELY(field != NULL)) {
+ return field->GetObj(NULL);
+ }
+ return 0;
+}
+
+} // anonymous namespace
+
+namespace art {
+namespace greenland {
+
+void InitFieldRuntimes(RuntimeEntryPoints* entry_points) {
+ entry_points->GetObjectStatic = art_get_obj_static_from_code;
+}
+
+} // namespace greenland
+} // namespace art
diff --git a/src/greenland/lir.cc b/src/greenland/runtime/support_thread.cc
index 72fb03b..25fb698 100644
--- a/src/greenland/lir.cc
+++ b/src/greenland/runtime/support_thread.cc
@@ -14,16 +14,28 @@
* limitations under the License.
*/
-#include "lir.h"
+#include "greenland/runtime_entry_points.h"
-#include "lir_desc.h"
-#include "lir_function.h"
+#include "runtime_utils.h"
+#include "runtime_support.h"
+#include "thread_list.h"
+
+using namespace art;
+using namespace art::greenland;
+
+namespace {
+
+void art_test_suspend(Thread* thread) {
+ Runtime::Current()->GetThreadList()->FullSuspendCheck(thread);
+}
+
+} // anonymous namespace
namespace art {
namespace greenland {
-LIR::LIR(const LIRDesc& desc) : parent_(NULL), desc_(desc) {
- operands_.reserve(desc_.GetNumOperands());
+void InitThreadRuntimes(RuntimeEntryPoints* entry_points) {
+ entry_points->TestSuspend = art_test_suspend;
}
} // namespace greenland
diff --git a/src/greenland/runtime_entry_points.cc b/src/greenland/runtime_entry_points.cc
new file mode 100644
index 0000000..a9b1edc
--- /dev/null
+++ b/src/greenland/runtime_entry_points.cc
@@ -0,0 +1,49 @@
+/*
+ * 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 "runtime_entry_points.h"
+
+namespace art {
+
+// Forward Declarations
+namespace greenland {
+
+void InitThreadRuntimes(RuntimeEntryPoints* entry_points);
+void InitExceptionRuntimes(RuntimeEntryPoints* entry_points);
+void InitAllocRuntimes(RuntimeEntryPoints* entry_points);
+void InitDexCacheRuntimes(RuntimeEntryPoints* entry_points);
+void InitFieldRuntimes(RuntimeEntryPoints* entry_points);
+void InitCastRuntimes(RuntimeEntryPoints* entry_points);
+
+} // namespace greenland
+
+void InitRuntimeEntryPoints(RuntimeEntryPoints* entry_points) {
+ // Defined in runtime/support_thread.cc
+ greenland::InitThreadRuntimes(entry_points);
+ // Defined in runtime/support_exception.cc
+ greenland::InitExceptionRuntimes(entry_points);
+ // Defined in runtime/support_alloc.cc
+ greenland::InitAllocRuntimes(entry_points);
+ // Defined in runtime/support_dexcache.cc
+ greenland::InitDexCacheRuntimes(entry_points);
+ // Defined in runtime/support_field.cc
+ greenland::InitFieldRuntimes(entry_points);
+ // Defined in runtime/support_case.cc
+ greenland::InitCastRuntimes(entry_points);
+ return;
+}
+
+} // namespace art
diff --git a/src/greenland/runtime_entry_points.h b/src/greenland/runtime_entry_points.h
new file mode 100644
index 0000000..8cd8ce4
--- /dev/null
+++ b/src/greenland/runtime_entry_points.h
@@ -0,0 +1,89 @@
+/*
+ * 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_GREENLAND_RUNTIME_ENTRY_POINTS_H_
+#define ART_SRC_GREENLAND_RUNTIME_ENTRY_POINTS_H_
+
+#include "macros.h"
+
+#include <stdint.h>
+
+#define RUNTIME_ENTRYPOINT(x) \
+ (static_cast<uintptr_t>(OFFSETOF_MEMBER(Thread, runtime_entry_points_)) + \
+ static_cast<uintptr_t>(OFFSETOF_MEMBER(RuntimeEntryPoints, x)))
+
+namespace art {
+
+class Method;
+class Object;
+class Thread;
+
+struct PACKED RuntimeEntryPoints {
+ //----------------------------------------------------------------------------
+ // Thread
+ //----------------------------------------------------------------------------
+ void (*TestSuspend)(Thread* thread);
+
+ //----------------------------------------------------------------------------
+ // Exception
+ //----------------------------------------------------------------------------
+ int32_t (*FindCatchBlock)(Method* current_method, uint32_t ti_offset);
+ void (*ThrowIndexOutOfBounds)(int32_t length, int32_t index);
+ void (*ThrowNullPointerException)(unsigned dex_pc);
+
+ //----------------------------------------------------------------------------
+ // Alloc
+ //----------------------------------------------------------------------------
+ Object* (*AllocArray)(uint32_t type_idx, Method* referrer,
+ uint32_t length, Thread* thread);
+
+ Object* (*AllocArrayWithAccessCheck)(uint32_t type_idx, Method* referrer,
+ uint32_t length, Thread* thread);
+
+ Object* (*CheckAndAllocArray)(uint32_t type_idx, Method* referrer,
+ uint32_t length, Thread* thread);
+
+ Object* (*CheckAndAllocArrayWithAccessCheck)(uint32_t type_idx,
+ Method* referrer,
+ uint32_t length,
+ Thread* thread);
+
+ //----------------------------------------------------------------------------
+ // DexCache
+ //----------------------------------------------------------------------------
+ Object* (*ResolveString)(Method* referrer, uint32_t string_idx);
+
+ //----------------------------------------------------------------------------
+ // Field
+ //----------------------------------------------------------------------------
+ Object* (*GetObjectStatic)(uint32_t field_idx, Method* referrer);
+
+ //----------------------------------------------------------------------------
+ // Cast
+ //----------------------------------------------------------------------------
+ void (*CheckPutArrayElement)(const Object* element, const Object* array);
+
+ //----------------------------------------------------------------------------
+ // JNI
+ //----------------------------------------------------------------------------
+};
+
+// Initialize an entry point data structure.
+void InitRuntimeEntryPoints(RuntimeEntryPoints* entry_points);
+
+} // namespace art
+
+#endif // ART_SRC_GREENLAND_RUNTIME_ENTRY_POINTS_H_
diff --git a/src/greenland/target_codegen_machine.cc b/src/greenland/target_codegen_machine.cc
index 87a215e..3c65a68 100644
--- a/src/greenland/target_codegen_machine.cc
+++ b/src/greenland/target_codegen_machine.cc
@@ -16,12 +16,16 @@
#include "target_codegen_machine.h"
-#include "greenland.h"
+#include "lir_function.h"
+#include "lir_pass_manager.h"
#include "target_lir_emitter.h"
+#include "target_lir_opcodes.h"
#include "target_registry.h"
#include "compiled_method.h"
#include "compiler.h"
+#include "oat_compilation_unit.h"
+#include "utils.h"
#include <UniquePtr.h>
@@ -39,23 +43,24 @@ TargetCodeGenMachine* TargetCodeGenMachine::Create(InstructionSet insn_set) {
return (*ctor)();
}
-CompiledMethod* TargetCodeGenMachine::Run(const Greenland& parent,
- const llvm::Function& func,
- const OatCompilationUnit& cunit,
- DexLang::Context& dex_lang_ctx) {
-#if 0
- UniquePtr<TargetLIREmitter> emitter(CreateLIREmitter(func, cunit,
- dex_lang_ctx));
- LIRFunction* lir_func = emitter->Emit();
- if (lir_func == NULL) {
+CompiledMethod* TargetCodeGenMachine::Run(const Compiler& compiler,
+ const GBCFunction& gbc_func) {
+ LIRPassManager lir_pm;
+
+ lir_pm.Add(CreateLIREmitter());
+
+ LIRFunction lir_func(*this, gbc_func);
+
+ if (!lir_pm.Run(lir_func)) {
return NULL;
}
-#endif
+
+ lir_func.Dump();
// 0x90 is the NOP in x86
std::vector<uint8_t> code(10, 0x90);
- return new CompiledMethod(parent.GetCompiler().GetInstructionSet(), code,
+ return new CompiledMethod(compiler.GetInstructionSet(), code,
/* frame_size_in_bytes */0,
/* core_spill_mask */0,
/* fp_spill_mask */0);
diff --git a/src/greenland/target_codegen_machine.h b/src/greenland/target_codegen_machine.h
index a0962fe..8cae791 100644
--- a/src/greenland/target_codegen_machine.h
+++ b/src/greenland/target_codegen_machine.h
@@ -17,26 +17,27 @@
#ifndef ART_SRC_GREENLAND_TARGET_CODEGEN_MACHINE_H_
#define ART_SRC_GREENLAND_TARGET_CODEGEN_MACHINE_H_
-#include "dex_lang.h"
-
#include "instruction_set.h"
+#include <string>
+
namespace art {
class CompiledMethod;
- class OatCompilationUnit;
-}
-
-namespace llvm {
- class Function;
+ class Compiler;
}
namespace art {
namespace greenland {
-class Greenland;
-class TargetLIREmitter;
+class GBCFunction;
+class LIR;
class RegisterAllocator;
class TargetAssembler;
+class TargetDataLayout;
+class TargetLIRBuilder;
+class TargetLIREmitter;
+class TargetLIRInfo;
+class TargetRegisterInfo;
class TargetCodeGenMachine {
protected:
@@ -45,9 +46,17 @@ class TargetCodeGenMachine {
public:
virtual ~TargetCodeGenMachine() { }
- virtual TargetLIREmitter* CreateLIREmitter(const llvm::Function& func,
- const OatCompilationUnit& cunit,
- DexLang::Context& dex_lang_ctx) =0;
+ virtual TargetLIREmitter* CreateLIREmitter() = 0;
+
+ virtual const TargetDataLayout* GetDataLayout() const = 0;
+
+ virtual const TargetLIRInfo* GetLIRInfo() const = 0;
+
+ virtual const TargetRegisterInfo* GetRegisterInfo() const = 0;
+
+ virtual const char* GetConditionCodeName(unsigned cond) const = 0;
+
+ virtual TargetLIRBuilder* CreateLIRBuilder() = 0;
virtual RegisterAllocator* GetRegisterAllocator() = 0;
@@ -56,10 +65,7 @@ class TargetCodeGenMachine {
static TargetCodeGenMachine* Create(InstructionSet insn_set);
public:
- CompiledMethod* Run(const Greenland& parent,
- const llvm::Function& func,
- const OatCompilationUnit& cunit,
- DexLang::Context& dex_lang_ctx);
+ CompiledMethod* Run(const Compiler& compiler, const GBCFunction& gbc_func);
};
} // namespace greenland
diff --git a/src/greenland/target_data_layout.h b/src/greenland/target_data_layout.h
new file mode 100644
index 0000000..7b634cf
--- /dev/null
+++ b/src/greenland/target_data_layout.h
@@ -0,0 +1,74 @@
+/*
+ * 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_GREENLAND_TARGET_DATA_LAYOUT_H_
+#define ART_SRC_GREENLAND_TARGET_DATA_LAYOUT_H_
+
+#include "lir.h"
+
+#include "logging.h"
+
+namespace art {
+namespace greenland {
+
+class TargetDataLayout {
+ private:
+ // Size of pointer in bytes
+ unsigned pointer_size_;
+
+ // Stack alignment in bytes
+ unsigned stack_alignment_;
+
+ public:
+ TargetDataLayout(unsigned pointer_size, unsigned stack_alignment)
+ : pointer_size_(pointer_size), stack_alignment_(stack_alignment) { }
+
+ unsigned GetPointerSize() const {
+ return pointer_size_;
+ }
+ unsigned GetPointerSizeInBits() const {
+ return (pointer_size_ << 3);
+ }
+
+ unsigned GetStackAlignment() const {
+ return stack_alignment_;
+ }
+
+ unsigned GetOpTypeSize(LIR::OperationType op_type) const {
+ switch (op_type) {
+ case LIR::kUInt8TypeOp: return 1; break;
+ case LIR::kSInt8TypeOp: return 1; break;
+ case LIR::kUInt16TypeOp: return 2; break;
+ case LIR::kSInt16TypeOp: return 2; break;
+ case LIR::kInt32TypeOp: return 4; break;
+ case LIR::kInt64TypeOp: return 8; break;
+ case LIR::kFloatTypeOp: return 4; break;
+ case LIR::kDoubleTypeOp: return 8; break;
+ case LIR::kPointerTypeOp: return pointer_size_; break;
+ case LIR::kUnknownTypeOp:
+ default: {
+ LOG(FATAL) << "Unknown operation type: " << op_type;
+ return 0;
+ }
+ }
+ // unreachable
+ }
+};
+
+} // namespace greenland
+} // namespace art
+
+#endif // ART_SRC_GREENLAND_TARGET_DATA_LAYOUT_H_
diff --git a/src/greenland/target_lir_emitter.cc b/src/greenland/target_lir_emitter.cc
deleted file mode 100644
index babb114..0000000
--- a/src/greenland/target_lir_emitter.cc
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * 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 "target_lir_emitter.h"
-
-#include "target_lir_info.h"
-#include "target_lir_opcodes.h"
-
-#include "intrinsic_helper.h"
-#include "lir_function.h"
-
-#include <llvm/Function.h>
-
-namespace art {
-namespace greenland {
-
-TargetLIREmitter::TargetLIREmitter(const llvm::Function& func,
- const OatCompilationUnit& cunit,
- DexLang::Context& dex_lang_ctx,
- TargetLIRInfo& target_lir_info)
- : func_(func), cunit_(cunit), dex_lang_ctx_(dex_lang_ctx.IncRef()),
- info_(target_lir_info), lir_func_() {
- return;
-}
-
-TargetLIREmitter::~TargetLIREmitter() {
- dex_lang_ctx_.DecRef();
- return;
-}
-
-bool TargetLIREmitter::visitBasicBlock(const llvm::BasicBlock& bb) {
- // Place the corresponding block label to the output
- llvm::DenseMap<const llvm::BasicBlock*, LIR*>::const_iterator label_iter =
- block_labels_.find(&bb);
-
- DCHECK(label_iter != block_labels_.end());
- lir_func_.push_back(label_iter->second);
-
- // Now, iterate over and process all instructions within the basic block
- for (llvm::BasicBlock::const_iterator inst_iter = bb.begin(),
- inst_end = bb.end(); inst_iter != inst_end; inst_iter++) {
- const llvm::Instruction& inst = *inst_iter;
- switch (inst.getOpcode()) {
-#define VISIT(OPCODE, CLASS) \
- case llvm::Instruction::OPCODE: { \
- if (!visit ## CLASS(static_cast<const llvm::CLASS&>(inst))) { \
- return false; \
- } \
- break; \
- }
-
- VISIT(Ret, ReturnInst);
- VISIT(Br, BranchInst);
- VISIT(ICmp, ICmpInst);
- VISIT(IntToPtr, IntToPtrInst);
- VISIT(Call, CallInst);
-
-#undef VISIT
- default : {
- LOG(INFO) << "Unhandled instruction hit!";
- inst.dump();
- return false;
- }
- }
- }
-
- return true;
-}
-
-bool TargetLIREmitter::visitReturnInst(const llvm::ReturnInst& inst) {
- inst.dump();
- return true;
-}
-
-bool TargetLIREmitter::visitBranchInst(const llvm::BranchInst& inst) {
- inst.dump();
- return true;
-}
-
-bool TargetLIREmitter::visitICmpInst(const llvm::ICmpInst& inst) {
- inst.dump();
- return true;
-}
-
-bool TargetLIREmitter::visitIntToPtrInst(const llvm::IntToPtrInst& inst) {
- inst.dump();
- return true;
-}
-
-bool TargetLIREmitter::visitCallInst(const llvm::CallInst& inst) {
- // The callee must be a DexLang intrinsic
- return visitDexLangIntrinsics(inst);
-}
-
-bool TargetLIREmitter::visitDexLangIntrinsics(const llvm::CallInst& inst) {
- const llvm::Function* callee = inst.getCalledFunction();
- IntrinsicHelper::IntrinsicId intr_id =
- dex_lang_ctx_.GetIntrinsicHelper().GetIntrinsicId(callee);
-
- if (intr_id == IntrinsicHelper::UnknownId) {
- LOG(INFO) << "Unexpected call instruction to '"
- << callee->getName().str() << "'";
- return false;
- }
-
- //const IntrinsicHelper::IntrinsicInfo& intr_info =
- // IntrinsicHelper::GetInfo(intr_id);
-
-
- return true;
-}
-
-LIRFunction* TargetLIREmitter::Emit() {
- if (EmitBasicBlockLabels() &&
- EmitEntrySequence() &&
- EmitInstructions() &&
- EmitExitSequence()) {
- return &lir_func_;
- }
-
- return NULL;
-}
-
-bool TargetLIREmitter::EmitBasicBlockLabels() {
- for (llvm::Function::const_iterator bb_iter = func_.begin(),
- bb_end = func_.end(); bb_iter != bb_end; bb_iter++) {
- LIR* lir = lir_func_.CreateLIR(info_.GetLIRDesc(opcode::kBlockLabel));
- CHECK(block_labels_.insert(std::make_pair(bb_iter, lir)).second);
- }
- return true;
-}
-
-bool TargetLIREmitter::EmitEntrySequence() {
- // Flush all function arguments to the virtual registers
- return true;
-}
-
-bool TargetLIREmitter::EmitInstructions() {
- // Iterator over all basic blocks
- for (llvm::Function::const_iterator bb_iter = func_.begin(),
- bb_end = func_.end(); bb_iter != bb_end; bb_iter++) {
- if (!visitBasicBlock(*bb_iter)) {
- return false;
- }
- }
- return true;
-}
-
-bool TargetLIREmitter::EmitExitSequence() {
- return true;
-}
-
-} // namespace greenland
-} // namespace art
diff --git a/src/greenland/target_lir_emitter.h b/src/greenland/target_lir_emitter.h
deleted file mode 100644
index 8e39e4c..0000000
--- a/src/greenland/target_lir_emitter.h
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * 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_GREENLAND_TARGET_LIR_EMITTER_H_
-#define ART_SRC_GREENLAND_TARGET_LIR_EMITTER_H_
-
-#include "dex_lang.h"
-
-#include "lir_function.h"
-
-#include <llvm/ADT/DenseMap.h>
-
-namespace art {
- class OatCompilationUnit;
-}
-
-namespace llvm {
- class BasicBlock;
- class BranchInst;
- class CallInst;
- class Function;
- class ICmpInst;
- class Instruction;
- class IntToPtrInst;
- class ReturnInst;
-}
-
-namespace art {
-namespace greenland {
-
-class LIRFunction;
-class TargetLIRInfo;
-
-class TargetLIREmitter {
- private:
- const llvm::Function& func_;
- const OatCompilationUnit& cunit_;
- DexLang::Context& dex_lang_ctx_;
- TargetLIRInfo& info_;
-
- private:
- llvm::DenseMap<const llvm::BasicBlock*, LIR*> block_labels_;
-
- protected:
- LIRFunction lir_func_;
-
- TargetLIREmitter(const llvm::Function& func,
- const OatCompilationUnit& cunit,
- DexLang::Context& dex_lang_ctx,
- TargetLIRInfo& target_lir_info);
-
- private:
- bool visitBasicBlock(const llvm::BasicBlock& bb);
-
- bool visitReturnInst(const llvm::ReturnInst& inst);
- bool visitBranchInst(const llvm::BranchInst& inst);
- //bool visitSwitchInst(SwitchInst &I) { DELEGATE(TerminatorInst);}
- //bool visitIndirectBrInst(IndirectBrInst &I) { DELEGATE(TerminatorInst);}
- //bool visitInvokeInst(InvokeInst &I) { DELEGATE(TerminatorInst);}
- //bool visitResumeInst(ResumeInst &I) { DELEGATE(TerminatorInst);}
- //bool visitUnreachableInst(UnreachableInst &I) { DELEGATE(TerminatorInst);}
- bool visitICmpInst(const llvm::ICmpInst& inst);
- //bool visitFCmpInst(FCmpInst &I) { DELEGATE(CmpInst);}
- //bool visitAllocaInst(AllocaInst &I) { DELEGATE(UnaryInstruction);}
- //bool visitLoadInst(LoadInst &I) { DELEGATE(UnaryInstruction);}
- //bool visitStoreInst(StoreInst &I) { DELEGATE(Instruction);}
- //bool visitAtomicCmpXchgInst(AtomicCmpXchgInst &I) { DELEGATE(Instruction);}
- //bool visitAtomicRMWInst(AtomicRMWInst &I) { DELEGATE(Instruction);}
- //bool visitFenceInst(FenceInst &I) { DELEGATE(Instruction);}
- //bool visitGetElementPtrInst(GetElementPtrInst &I){ DELEGATE(Instruction);}
- //bool visitPHINode(PHINode &I) { DELEGATE(Instruction);}
- //bool visitTruncInst(TruncInst &I) { DELEGATE(CastInst);}
- //bool visitZExtInst(ZExtInst &I) { DELEGATE(CastInst);}
- //bool visitSExtInst(SExtInst &I) { DELEGATE(CastInst);}
- //bool visitFPTruncInst(FPTruncInst &I) { DELEGATE(CastInst);}
- //bool visitFPExtInst(FPExtInst &I) { DELEGATE(CastInst);}
- //bool visitFPToUIInst(FPToUIInst &I) { DELEGATE(CastInst);}
- //bool visitFPToSIInst(FPToSIInst &I) { DELEGATE(CastInst);}
- //bool visitUIToFPInst(UIToFPInst &I) { DELEGATE(CastInst);}
- //bool visitSIToFPInst(SIToFPInst &I) { DELEGATE(CastInst);}
- //bool visitPtrToIntInst(PtrToIntInst &I) { DELEGATE(CastInst);}
- bool visitIntToPtrInst(const llvm::IntToPtrInst& inst);
- //bool visitBitCastInst(BitCastInst &I) { DELEGATE(CastInst);}
- //bool visitSelectInst(SelectInst &I) { DELEGATE(Instruction);}
- bool visitCallInst(const llvm::CallInst& inst);
- //bool visitVAArgInst(VAArgInst &I) { DELEGATE(UnaryInstruction);}
- //bool visitExtractElementInst(ExtractElementInst &I) { DELEGATE(Instruction);}
- //bool visitInsertElementInst(InsertElementInst &I) { DELEGATE(Instruction);}
- //bool visitShuffleVectorInst(ShuffleVectorInst &I) { DELEGATE(Instruction);}
- //bool visitExtractValueInst(ExtractValueInst &I){ DELEGATE(UnaryInstruction);}
- //bool visitInsertValueInst(InsertValueInst &I) { DELEGATE(Instruction); }
- //bool visitLandingPadInst(LandingPadInst &I) { DELEGATE(Instruction); }
-
- bool visitDexLangIntrinsics(const llvm::CallInst& inst);
-
- public:
- virtual ~TargetLIREmitter();
-
- LIRFunction* Emit();
-
- private:
- bool EmitBasicBlockLabels();
- bool EmitEntrySequence();
- bool EmitInstructions();
- bool EmitExitSequence();
-};
-
-} // namespace greenland
-} // namespace art
-
-#endif // ART_SRC_GREENLAND_TARGET_LIR_EMITTER_H_
diff --git a/src/greenland/target_lir_info.h b/src/greenland/target_lir_info.h
deleted file mode 100644
index 1ed86fa..0000000
--- a/src/greenland/target_lir_info.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * 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_GREENLAND_TARGET_LIR_INFO_H_
-#define ART_SRC_GREENLAND_TARGET_LIR_INFO_H_
-
-#include "lir_desc.h"
-
-#include "logging.h"
-
-namespace art {
-namespace greenland {
-
-class TargetLIRInfo {
- private:
- // An array of target's LIR instruction description
- const LIRDesc* desc_;
-
- unsigned num_desc_;
-
- public:
- TargetLIRInfo(const LIRDesc* desc, unsigned num_desc)
- : desc_(desc), num_desc_(num_desc) {
- }
-
- virtual ~TargetLIRInfo() { }
-
- const LIRDesc& GetLIRDesc(unsigned opcode) {
- DCHECK(opcode < num_desc_) << "Invalid opcode: " << opcode;
- return desc_[opcode];
- }
-};
-
-} // namespace greenland
-} // namespace art
-
-#endif // ART_SRC_GREENLAND_TARGET_LIR_INFO_H_
diff --git a/src/greenland/target_register_info.h b/src/greenland/target_register_info.h
new file mode 100644
index 0000000..41d69e1
--- /dev/null
+++ b/src/greenland/target_register_info.h
@@ -0,0 +1,79 @@
+/*
+ * 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_GREENLAND_TARGET_REGISTER_INFO_H_
+#define ART_SRC_GREENLAND_TARGET_REGISTER_INFO_H_
+
+#include "lir_function.h"
+#include "lir_reg.h"
+
+#include "target_lir_builder.h"
+#include "target_lir_info.h"
+
+#include <string>
+
+namespace art {
+namespace greenland {
+
+class TargetRegisterInfo {
+ protected:
+ const TargetLIRInfo& lir_info_;
+ TargetRegisterInfo(const TargetLIRInfo& info) :lir_info_(info) { }
+
+ public:
+ virtual const char* GetPhyRegName(unsigned reg) const = 0;
+
+ std::string GetRegName(unsigned reg) const {
+ if (LIRReg::IsVirtualReg(reg)) {
+ return LIRReg::GetVirtualRegName(reg);
+ } else {
+ return GetPhyRegName(reg);
+ }
+ }
+
+ virtual LIR*
+ CreateLoadStack(LIRFunction& lir_func,
+ unsigned reg,
+ int frame_idx) const = 0;
+
+ virtual LIR*
+ CreateStoreStack(LIRFunction& lir_func,
+ unsigned reg,
+ int frame_idx) const = 0;
+
+ virtual LIR*
+ CreateMoveReg(LIRFunction& lir_func,
+ unsigned dst,
+ unsigned src) const = 0;
+
+ virtual bool
+ IsLoadIncomingArgs(const LIR* lir) const = 0;
+
+ virtual LIR*
+ CreateCopy(LIRFunction& lir_func,
+ unsigned dst,
+ const LIROperand& src) const = 0;
+
+ virtual std::list<unsigned> GetAllocatableList() const = 0;
+ virtual unsigned GetTempRegsiter(unsigned idx) const = 0;
+
+ virtual ~TargetRegisterInfo() { }
+};
+
+} // namespace greenland
+} // namespace art
+
+#endif // ART_SRC_GREENLAND_TARGET_REGISTER_INFO_H_
diff --git a/src/greenland/target_registry.h b/src/greenland/target_registry.h
index 1f93665..0f490e0 100644
--- a/src/greenland/target_registry.h
+++ b/src/greenland/target_registry.h
@@ -40,7 +40,7 @@ class TargetRegistry {
uint32_t shorty_len);
static void RegisterTargetCodeGenMachine(InstructionSet insn_set,
- TargetCodeGenMachineCtorTy ctor);
+ TargetCodeGenMachineCtorTy ctor);
static TargetCodeGenMachineCtorTy GetTargetCodeGenMachineCtor(InstructionSet insn_set);
static void RegisterInvokeStubCompiler(InstructionSet insn_set,
diff --git a/src/greenland/tools/target_lir_builder_generator.cc b/src/greenland/tools/target_lir_builder_generator.cc
new file mode 100644
index 0000000..2a48136
--- /dev/null
+++ b/src/greenland/tools/target_lir_builder_generator.cc
@@ -0,0 +1,574 @@
+/*
+ * 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 <cassert>
+#include <cctype>
+#include <cstring>
+#include <iostream>
+#include <string>
+
+// Should be synced with the one in lir_desc.h
+#define MAX_LIR_OPERANDS 6
+
+//----------------------------------------------------------------------------
+// Operand Info
+//----------------------------------------------------------------------------
+class LIROperand {
+ public:
+ enum Type {
+ UnknownType,
+ RegisterType,
+ ImmediateType,
+ LabelType,
+ FrameIndexType,
+ };
+};
+
+// Copy from lir_desc.h
+class LIRDescFlag {
+ public:
+ enum Flag {
+ kNone,
+ kPseudo,
+ kVariadic,
+
+ kIsLoad,
+ kIsStore,
+ kIsBranch,
+
+ kDefReg0,
+ kDefReg1,
+
+ kUseReg0,
+ kUseReg1,
+ kUseReg2,
+ kUseReg3,
+ kUseReg4,
+ kUseReg5,
+
+ kSetCCodes,
+ kUseCCodes,
+
+ kNeedRelax,
+ };
+};
+
+class LIROperandInfo {
+ public:
+ class TypeStrings {
+ public:
+ // Take RegisterType as example:
+ // type_string_ is "unsigned"
+ // var_string_ is "reg"
+ // set_method_ is "SetReg"
+ const char* type_string_;
+ const char* var_string_;
+ const char* set_method_;
+ };
+
+ LIROperand::Type GetOperandType(unsigned i) const {
+ assert((i < num_operands_) && "Invalid operand index!");
+ return info_[i].type_;
+ }
+
+ const TypeStrings& GetOperandTypeStrings(unsigned i) const {
+ return OperandTypeStrings[GetOperandType(i)];
+ }
+
+ private:
+ static const TypeStrings OperandTypeStrings[];
+
+ public:
+ const char* name_;
+ unsigned num_operands_;
+ struct {
+ enum LIROperand::Type type_;
+ } info_[MAX_LIR_OPERANDS];
+};
+
+const LIROperandInfo::TypeStrings LIROperandInfo::OperandTypeStrings[] = {
+ /* UnknownType */ { "void", "", "", },
+ /* RegisterType */ { "unsigned", "reg", "SetReg" },
+ /* ImmediateType */ { "int32_t" , "imm_val", "SetImm" },
+ /* LabelType */ { "LIRBasicBlock*", "target", "SetLabelTarget" },
+ /* FrameIndexType */ { "int", "frame_index", "SetFrameIndex" }
+};
+
+#define DEF_LIR_OPERAND_INFO(INFO_ID, NUM_OPS, INFO_DEF) \
+static const LIROperandInfo OpInfo ## INFO_ID = \
+ { #INFO_ID, NUM_OPS, INFO_DEF };
+#include "greenland/target_lir.def"
+#include "greenland/clear_target_lir.def"
+
+static const LIROperandInfo* const OpInfos[] = {
+#define DEF_LIR_OPERAND_INFO(INFO_ID, NUM_OPS, INFO_DEF) \
+ &OpInfo ## INFO_ID,
+#include "greenland/target_lir.def"
+#include "greenland/clear_target_lir.def"
+};
+
+static const unsigned NumObInfos = sizeof(OpInfos) / sizeof(OpInfos[0]);
+
+//----------------------------------------------------------------------------
+// Data structure of LIRDesc to load {target}_lir.def
+//----------------------------------------------------------------------------
+
+class LIRDesc {
+ public:
+ const char* opcode_name_;
+ const char* name_;
+ const char* format_;
+ unsigned flags;
+ const LIROperandInfo& operand_info_;
+
+ bool IsPseudo() const {
+ return (flags & (1 << LIRDescFlag::kPseudo));
+ }
+};
+
+//----------------------------------------------------------------------------
+// Target-independent LIR Enumeration
+//----------------------------------------------------------------------------
+// This is here to get the number of target-independent LIRs
+// (i.e., kNumTargetIndependentLIR)
+enum {
+#define DEF_LIR_DESC(OPCODE, ...) OPCODE,
+#include "greenland/target_lir.def"
+#include "greenland/clear_target_lir.def"
+
+ kNumTargetIndependentLIR
+};
+
+//----------------------------------------------------------------------------
+// ARM
+//----------------------------------------------------------------------------
+static const LIRDesc ARMLIR[] = {
+#define DEF_LIR_DESC(OPCODE, KIND, FLAGS, NAME, FORMAT, OPS_INFO) \
+ { #OPCODE, NAME, FORMAT, FLAGS, OpInfo ## OPS_INFO },
+#include "greenland/arm/arm_lir.def"
+};
+
+//----------------------------------------------------------------------------
+// Mips
+//----------------------------------------------------------------------------
+static const LIRDesc MipsLIR[] = {
+#define DEF_LIR_DESC(OPCODE, KIND, FLAGS, NAME, FORMAT, OPS_INFO) \
+ { #OPCODE, NAME, FORMAT, FLAGS, OpInfo ## OPS_INFO },
+#include "greenland/mips/mips_lir.def"
+};
+
+//----------------------------------------------------------------------------
+// X86
+//----------------------------------------------------------------------------
+static const LIRDesc X86LIR[] = {
+#define DEF_LIR_DESC(OPCODE, KIND, FLAGS, NAME, FORMAT, OPS_INFO) \
+ { #OPCODE, NAME, FORMAT, FLAGS, OpInfo ## OPS_INFO },
+#include "greenland/x86/x86_lir.def"
+};
+
+class Context {
+ private:
+ std::ostream& out_;
+ unsigned indent_;
+
+ public:
+ Context(std::ostream& out) : out_(out), indent_(0) { }
+
+ void IncIndent() {
+ indent_ += 2;
+ return;
+ }
+
+ void DecIndent() {
+ indent_ -= 2;
+ }
+
+ std::ostream& Indent() {
+ for (unsigned i = 0; i < indent_; i += 2) {
+ out_.write(" ", 2);
+ }
+ return out_;
+ }
+
+ std::ostream& Newline() {
+ return out_ << std::endl;
+ }
+
+ std::ostream& Out() {
+ return out_;
+ }
+
+ const LIRDesc* target_lirs_;
+ unsigned num_target_lirs_;
+
+ std::string lowercase_target_string_;
+ std::string uppercase_target_string_;
+ std::string class_name_;
+};
+
+class GenPrototype {
+ const LIROperandInfo& op_info_;
+ const char* preface_;
+ public:
+ GenPrototype(const LIROperandInfo& op_info, const char* preface = NULL)
+ : op_info_(op_info), preface_(preface) { }
+
+ friend std::ostream& operator<<(std::ostream& out, const GenPrototype& obj);
+};
+
+std::ostream& operator<<(std::ostream& out, const GenPrototype& obj) {
+ out << "(";
+
+ unsigned num_ops = obj.op_info_.num_operands_;
+ if (obj.preface_ != NULL) {
+ out << obj.preface_;
+ if (num_ops > 0) {
+ out << ", ";
+ }
+ }
+
+ for (unsigned i = 0; i < num_ops; i++) {
+ const LIROperandInfo::TypeStrings& type_strings =
+ obj.op_info_.GetOperandTypeStrings(i);
+
+ out << type_strings.type_string_ << " " << type_strings.var_string_ << i;
+
+ if (i != (num_ops - 1)) {
+ // Append "," if not the last one
+ out << ", ";
+ }
+ }
+
+ out << ")";
+ return out;
+}
+
+//----------------------------------------------------------------------------
+
+// Forward Declarations
+static void GenBeginNamespace(Context& C);
+static void GenCreateTargetLIR(Context& C, const LIRDesc& lir, bool proto_only);
+static void GenCallSetOperands(Context& C, const LIROperandInfo& operand_info);
+static void GenEndNamespace(Context& C);
+
+static void GenLicenseNote(Context& C) {
+ C.Indent() << "/*" << std::endl;
+ C.Indent() << " * Copyright (C) 2012 The Android Open Source Project" << std::endl;
+ C.Indent() << " *" << std::endl;
+ C.Indent() << " * Licensed under the Apache License, Version 2.0 (the \"License\"" << std::endl;
+ C.Indent() << " * you may not use this file except in compliance with the License." << std::endl;
+ C.Indent() << " * You may obtain a copy of the License at" << std::endl;
+ C.Indent() << " *" << std::endl;
+ C.Indent() << " * http://www.apache.org/licenses/LICENSE-2.0" << std::endl;
+ C.Indent() << " *" << std::endl;
+ C.Indent() << " * Unless required by applicable law or agreed to in writing, software" << std::endl;
+ C.Indent() << " * distributed under the License is distributed on an \"AS IS\" BASIS," << std::endl;
+ C.Indent() << " * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied." << std::endl;
+ C.Indent() << " * See the License for the specific language governing permissions and" << std::endl;
+ C.Indent() << " * limitations under the License." << std::endl;
+ C.Indent() << " */" << std::endl;
+ C.Newline();
+ return;
+}
+
+//----------------------------------------------------------------------------
+
+static void GenTargetLIRBuilderHeader(Context& C) {
+ C.Indent() << "#ifdef GET_" << C.uppercase_target_string_ << "_LIR_BUILDER_HEADER";
+ C.Newline();
+
+ //----------------------------------------------------------------------------
+ // Include Files
+ //----------------------------------------------------------------------------
+ C.Indent() << "#include \"greenland/target_lir_builder.h\"" << std::endl;;
+ C.Indent() << "#include \"greenland/target_lir_info.h\"" << std::endl;
+ C.Newline();
+
+ GenBeginNamespace(C);
+
+ //----------------------------------------------------------------------------
+ // Forward Declarations
+ //----------------------------------------------------------------------------
+ C.Indent() << "class TargetLIRInfo;" << std::endl;
+ C.Newline();
+
+ C.Indent() << "class " << C.class_name_ << " : public TargetLIRBuilder {"
+ << std::endl;
+
+ //----------------------------------------------------------------------------
+ // Members
+ //----------------------------------------------------------------------------
+ C.Indent() << " private:" << std::endl;
+ C.IncIndent();
+ C.Indent() << "const TargetLIRInfo& info_;" << std::endl;
+ C.DecIndent();
+ C.Newline();
+
+ //----------------------------------------------------------------------------
+ // APIs
+ //----------------------------------------------------------------------------
+ C.Indent() << " public:" << std::endl;
+
+ C.IncIndent();
+
+ //----------------------------------------------------------------------------
+ // Constructor
+ //----------------------------------------------------------------------------
+ C.Indent() << C.class_name_ << "(const TargetLIRInfo& info) "
+ ": TargetLIRBuilder(), info_(info) { }"
+ << std::endl;
+ C.Newline();
+
+ //----------------------------------------------------------------------------
+ // LIR* Create(unsigned opcode)
+ //----------------------------------------------------------------------------
+ C.Indent() << "LIR* Create(unsigned opcode) {" << std::endl;
+ C.IncIndent();
+
+ C.Indent() << "return bb_->GetParent().CreateLIR(*bb_, info_.GetLIRDesc(opcode));" << std::endl;
+
+ C.DecIndent();
+ C.Indent() << "}" << std::endl;
+ C.Newline();
+
+ //----------------------------------------------------------------------------
+ // LIR* Create(LIRDesc& desc)
+ //----------------------------------------------------------------------------
+ C.Indent() << "LIR* Create(const LIRDesc& desc) {" << std::endl;
+ C.IncIndent();
+
+ C.Indent() << "return bb_->GetParent().CreateLIR(*bb_, desc);" << std::endl;
+
+ C.DecIndent();
+ C.Indent() << "}" << std::endl;
+ C.Newline();
+
+ //----------------------------------------------------------------------------
+ // LIR* Create_*([operand...])
+ //----------------------------------------------------------------------------
+ for (unsigned i = 0; i < C.num_target_lirs_; i++) {
+ const LIRDesc& lir = C.target_lirs_[i];
+ if (!lir.IsPseudo() || (i > kNumTargetIndependentLIR)) {
+ GenCreateTargetLIR(C, lir, /* proto_only */true);
+ }
+ }
+
+ C.DecIndent();
+
+ C.Indent() << "};" << std::endl;
+ C.Newline();
+
+ GenEndNamespace(C);
+
+ C.Indent() << "#undef GET_" << C.uppercase_target_string_ << "_LIR_BUILDER_HEADER" << std::endl;
+ C.Indent() << "#endif // GET_" << C.uppercase_target_string_ << "_LIR_BUILDER_HEADER" << std::endl;
+ return;
+}
+
+static void GenTargetLIRBuilderImpl(Context& C) {
+ C.Indent() << "#ifdef GET_" << C.uppercase_target_string_ << "_LIR_BUILDER_IMPL";
+ C.Newline();
+
+ //----------------------------------------------------------------------------
+ // Include Files
+ //----------------------------------------------------------------------------
+ C.Indent() << "#include \"greenland/lir_desc.h\"" << std::endl;
+ C.Indent() << "#include \"greenland/lir_function.h\"" << std::endl;
+ C.Indent() << "#include \"greenland/" << C.lowercase_target_string_
+ << "/" << C.lowercase_target_string_ << "_lir_opcodes.h\""
+ << std::endl;
+ C.Newline();
+
+ GenBeginNamespace(C);
+
+ for (unsigned i = 0; i < C.num_target_lirs_; i++) {
+ const LIRDesc& lir = C.target_lirs_[i];
+ if (!lir.IsPseudo() || (i > kNumTargetIndependentLIR)) {
+ GenCreateTargetLIR(C, lir, /* proto_only */false);
+ }
+ }
+
+ C.Newline();
+
+ GenEndNamespace(C);
+
+ C.Indent() << "#undef GET_" << C.uppercase_target_string_ << "_LIR_BUILDER_IMPL" << std::endl;
+ C.Indent() << "#endif // GET_" << C.uppercase_target_string_ << "_LIR_BUILDER_IMPL" << std::endl;
+ C.Newline();
+ return;
+}
+
+//----------------------------------------------------------------------------
+
+static void GenBeginNamespace(Context& C) {
+ C.Indent() << "namespace art {" << std::endl;
+ C.Indent() << "namespace greenland {" << std::endl;
+ C.Newline();
+ return;
+}
+
+static void GenCreateTargetLIR(Context& C, const LIRDesc& lir, bool proto_only){
+ C.Indent() << "// " << lir.name_ << " " << lir.format_ << std::endl;
+
+ if (proto_only) {
+ C.Indent() << "LIR* Create_" << &lir.opcode_name_[1] /* hack: skip 'k' */
+ << GenPrototype(lir.operand_info_) << ";" << std::endl;
+ return;
+ } else {
+ C.Indent() << "LIR* " << C.class_name_ << "::Create_"
+ << &lir.opcode_name_[1] /* hack: skip 'k' */
+ << GenPrototype(lir.operand_info_) << " {" << std::endl;
+ }
+
+ C.IncIndent();
+ C.Indent() << "LIR* lir = Create("
+ << C.lowercase_target_string_ << "::" << lir.opcode_name_<< ");"
+ << std::endl;
+ GenCallSetOperands(C, lir.operand_info_);
+ C.Indent() << "return lir;" << std::endl;
+ C.DecIndent();
+
+ C.Indent() << "}" << std::endl;
+ C.Newline();
+ return;
+}
+
+static void
+GenCallSetOperands(Context& C, const LIROperandInfo& operand_info) {
+ if (operand_info.num_operands_ > 0) {
+ C.Indent() << "Set" << operand_info.name_ << "Operands(*lir, ";
+
+ for (unsigned i = 0; i < operand_info.num_operands_; i++) {
+ const LIROperandInfo::TypeStrings& type_strings =
+ operand_info.GetOperandTypeStrings(i);
+
+ C.Out() << type_strings.var_string_ << i;
+
+ if (i != (operand_info.num_operands_ - 1)) {
+ // Append "," if not the last one
+ C.Out() << ", ";
+ }
+ }
+
+ C.Out() << ");" << std::endl;
+ }
+ return;
+}
+
+static void GenEndNamespace(Context& C) {
+ C.Newline();
+ C.Indent() << "} // namespace greenland" << std::endl;
+ C.Indent() << "} // namespace art" << std::endl;
+ C.Newline();
+ return;
+}
+
+//----------------------------------------------------------------------------
+// Special functionality to generate Set*Operands in TargetLIRBuilder
+//----------------------------------------------------------------------------
+static void GenSetOperandsImpl(Context& C, const LIROperandInfo& operand_info);
+
+static void GenSetOperands(Context& C) {
+ for (unsigned i = 0; i < NumObInfos; i++) {
+ const LIROperandInfo& op_info = *OpInfos[i];
+ C.Indent() << "static inline void Set" << op_info.name_
+ << "Operands" << GenPrototype(op_info, /* preface */"LIR& lir")
+ << " {" << std::endl;
+ C.IncIndent();
+ GenSetOperandsImpl(C, op_info);
+ C.DecIndent();
+ C.Indent() << "}" << std::endl;
+ C.Newline();
+ }
+
+ return;
+}
+
+static void GenSetOperandsImpl(Context& C, const LIROperandInfo& operand_info) {
+ if (operand_info.num_operands_ <= 0) {
+ return;
+ }
+
+ C.Indent() << "lir";
+ for (unsigned i = 0; i < operand_info.num_operands_; i++) {
+ const LIROperandInfo::TypeStrings& type_strings =
+ operand_info.GetOperandTypeStrings(i);
+
+ if (i != 0) {
+ C.Indent() << " ";
+ }
+
+ C.Out() << "." << type_strings.set_method_ << "(" << i << ", "
+ << type_strings.var_string_ << i
+ << ")";
+ if (i == (operand_info.num_operands_ - 1)) {
+ // Append ";" if not the last one
+ C.Out() << ";";
+ }
+ C.Out() << std::endl;
+ }
+
+ C.Indent() << "return;" << std::endl;
+
+ return;
+}
+
+int main(int argc, char** argv) {
+ if (argc < 2) {
+ std::cerr << "usage: " << argv[0] << " [target]" << std::endl;
+ return 1;
+ }
+
+ Context C(std::cout);
+
+ C.lowercase_target_string_ = argv[1];
+ for (size_t i = 0, e = C.lowercase_target_string_.length(); i != e; i++) {
+ C.lowercase_target_string_[i] = ::tolower(C.lowercase_target_string_[i]);
+ }
+
+ // Special function to generate TargetLIRBuilder::Set*Operands(...).
+ if (C.lowercase_target_string_ == "gen_set_operands") {
+ GenSetOperands(C);
+ return 0;
+ }
+
+ // Setup the context according to the target supplied
+ if (C.lowercase_target_string_ == "arm") {
+ C.target_lirs_ = ARMLIR;
+ C.num_target_lirs_ = sizeof(ARMLIR) / sizeof(ARMLIR[0]);
+ C.uppercase_target_string_ = "ARM";
+ C.class_name_ = "ARMLIRBuilderBase";
+ } else if (C.lowercase_target_string_ == "mips") {
+ C.target_lirs_ = MipsLIR;
+ C.num_target_lirs_ = sizeof(MipsLIR) / sizeof(MipsLIR[0]);
+ C.uppercase_target_string_ = "MIPS";
+ C.class_name_ = "MipsLIRBuilderBase";
+ } else if (C.lowercase_target_string_ == "x86") {
+ C.target_lirs_ = X86LIR;
+ C.num_target_lirs_ = sizeof(X86LIR) / sizeof(X86LIR[0]);
+ C.uppercase_target_string_ = "X86";
+ C.class_name_ = "X86LIRBuilderBase";
+ } else {
+ std::cerr << "unknown target `" << argv[1] << "'!" << std::endl;
+ return 1;
+ }
+
+ GenLicenseNote(C);
+ GenTargetLIRBuilderHeader(C);
+ GenTargetLIRBuilderImpl(C);
+
+ return 0;
+}