Continued fleshout out of Quick compiler
Conversion support for IGET/IPUT, more array stuff, some conversions
and miscellaneous bug fixes. Note that I'm adding what I hope are
intend to be temporary intrinsics to speed development.
With this CL, most of run-test 027 passes.
Change-Id: Ib74233fba0aab3194c383be6f7330921c04a3a62
diff --git a/src/compiler/codegen/MethodBitcode.cc b/src/compiler/codegen/MethodBitcode.cc
index 690f022..92cc6cc 100644
--- a/src/compiler/codegen/MethodBitcode.cc
+++ b/src/compiler/codegen/MethodBitcode.cc
@@ -161,6 +161,18 @@
cUnit->irb->CreateCall(intr, args);
}
+void convertFillArrayData(CompilationUnit* cUnit, int32_t offset,
+ RegLocation rlArray)
+{
+ greenland::IntrinsicHelper::IntrinsicId id;
+ id = greenland::IntrinsicHelper::FillArrayData;
+ llvm::SmallVector<llvm::Value*, 2> args;
+ args.push_back(cUnit->irb->getInt32(offset));
+ args.push_back(getLLVMValue(cUnit, rlArray.origSReg));
+ llvm::Function* intr = cUnit->intrinsic_helper->GetIntrinsicFunction(id);
+ cUnit->irb->CreateCall(intr, args);
+}
+
llvm::Value* emitConst(CompilationUnit* cUnit, llvm::ArrayRef<llvm::Value*> src,
RegLocation loc)
{
@@ -376,7 +388,6 @@
llvm::Value* src1 = getLLVMValue(cUnit, rlSrc1.origSReg);
llvm::Value* src2 = getLLVMValue(cUnit, rlSrc2.origSReg);
llvm::Value* res = NULL;
-LOG(INFO) << "in convertFPArithOp";
switch(op) {
case kOpAdd: res = cUnit->irb->CreateFAdd(src1, src2); break;
case kOpSub: res = cUnit->irb->CreateFSub(src1, src2); break;
@@ -393,18 +404,20 @@
RegLocation rlSrc1, RegLocation rlSrc2)
{
llvm::Value* src1 = getLLVMValue(cUnit, rlSrc1.origSReg);
- llvm::Value* src2a = getLLVMValue(cUnit, rlSrc2.origSReg);
- llvm::Value* src2b;
- // Limit shift counnt to 63 for long and 31 for int
+ llvm::Value* src2 = getLLVMValue(cUnit, rlSrc2.origSReg);
+ /*
+ * TODO: Figure out how best to handle constraining the shift
+ * amount to 31 for int and 63 for long. We take care of this
+ * inline for int and in the out-of-line handler for longs, so
+ * it's a bit of a waste to generate llvm bitcode for this.
+ * Yet more intrinsics?
+ */
+ UNIMPLEMENTED(WARNING) << "llvm shift mismatch";
if (rlDest.wide) {
- // Note: creates 2 unnamed temps
- llvm::Value* t1 = cUnit->irb->CreateAnd(src2a, 0x3f);
- src2b = cUnit->irb->CreateZExt(t1, cUnit->irb->getInt64Ty());
- } else {
- // Note: creates 1 unnamed temp
- src2b = cUnit->irb->CreateAnd(src2a, 0x1f);
+ // llvm thinks the shift could should be in 64 bits.
+ src2 = cUnit->irb->CreateZExt(src2, cUnit->irb->getInt64Ty());
}
- llvm::Value* res = genArithOp(cUnit, op, rlDest.wide, src1, src2b);
+ llvm::Value* res = genArithOp(cUnit, op, rlDest.wide, src1, src2);
defineValue(cUnit, res, rlDest.origSReg);
}
@@ -446,8 +459,13 @@
defineValue(cUnit, res, rlDest.origSReg);
}
+/*
+ * Process arguments for invoke. Note: this code is also used to
+ * collect and process arguments for NEW_FILLED_ARRAY and NEW_FILLED_ARRAY_RANGE.
+ * The requirements are similar.
+ */
void convertInvoke(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir,
- InvokeType invokeType, bool isRange)
+ InvokeType invokeType, bool isRange, bool isNewArray)
{
CallInfo* info = oatNewCallInfo(cUnit, bb, mir, invokeType, isRange);
llvm::SmallVector<llvm::Value*, 10> args;
@@ -475,7 +493,9 @@
* is not used, we'll treat this as a void invoke.
*/
greenland::IntrinsicHelper::IntrinsicId id;
- if (info->result.location == kLocInvalid) {
+ if (isNewArray) {
+ id = greenland::IntrinsicHelper::NewArray;
+ } else if (info->result.location == kLocInvalid) {
id = greenland::IntrinsicHelper::HLInvokeVoid;
} else {
if (info->result.wide) {
@@ -499,17 +519,28 @@
}
}
-void convertConstString(CompilationUnit* cUnit, BasicBlock* bb,
- uint32_t string_idx, RegLocation rlDest)
+void convertConstObject(CompilationUnit* cUnit, uint32_t idx,
+ greenland::IntrinsicHelper::IntrinsicId id,
+ RegLocation rlDest)
{
- greenland::IntrinsicHelper::IntrinsicId id;
- id = greenland::IntrinsicHelper::ConstString;
llvm::Function* intr = cUnit->intrinsic_helper->GetIntrinsicFunction(id);
- llvm::Value* index = cUnit->irb->getInt32(string_idx);
+ llvm::Value* index = cUnit->irb->getInt32(idx);
llvm::Value* res = cUnit->irb->CreateCall(intr, index);
defineValue(cUnit, res, rlDest.origSReg);
}
+void convertCheckCast(CompilationUnit* cUnit, uint32_t type_idx,
+ RegLocation rlSrc)
+{
+ greenland::IntrinsicHelper::IntrinsicId id;
+ id = greenland::IntrinsicHelper::CheckCast;
+ llvm::Function* intr = cUnit->intrinsic_helper->GetIntrinsicFunction(id);
+ llvm::SmallVector<llvm::Value*, 2> args;
+ args.push_back(cUnit->irb->getInt32(type_idx));
+ args.push_back(getLLVMValue(cUnit, rlSrc.origSReg));
+ cUnit->irb->CreateCall(intr, args);
+}
+
void convertNewInstance(CompilationUnit* cUnit, uint32_t type_idx,
RegLocation rlDest)
{
@@ -560,6 +591,32 @@
cUnit->irb->CreateCall(intr, args);
}
+void convertIget(CompilationUnit* cUnit, int optFlags,
+ greenland::IntrinsicHelper::IntrinsicId id,
+ RegLocation rlDest, RegLocation rlObj, int fieldIndex)
+{
+ llvm::SmallVector<llvm::Value*, 3> args;
+ args.push_back(cUnit->irb->getInt32(optFlags));
+ args.push_back(getLLVMValue(cUnit, rlObj.origSReg));
+ args.push_back(cUnit->irb->getInt32(fieldIndex));
+ llvm::Function* intr = cUnit->intrinsic_helper->GetIntrinsicFunction(id);
+ llvm::Value* res = cUnit->irb->CreateCall(intr, args);
+ defineValue(cUnit, res, rlDest.origSReg);
+}
+
+void convertIput(CompilationUnit* cUnit, int optFlags,
+ greenland::IntrinsicHelper::IntrinsicId id,
+ RegLocation rlSrc, RegLocation rlObj, int fieldIndex)
+{
+ llvm::SmallVector<llvm::Value*, 4> args;
+ args.push_back(cUnit->irb->getInt32(optFlags));
+ args.push_back(getLLVMValue(cUnit, rlSrc.origSReg));
+ args.push_back(getLLVMValue(cUnit, rlObj.origSReg));
+ args.push_back(cUnit->irb->getInt32(fieldIndex));
+ llvm::Function* intr = cUnit->intrinsic_helper->GetIntrinsicFunction(id);
+ cUnit->irb->CreateCall(intr, args);
+}
+
void convertInstanceOf(CompilationUnit* cUnit, uint32_t type_idx,
RegLocation rlDest, RegLocation rlSrc)
{
@@ -573,6 +630,24 @@
defineValue(cUnit, res, rlDest.origSReg);
}
+void convertIntToLong(CompilationUnit* cUnit, RegLocation rlDest,
+ RegLocation rlSrc)
+{
+ llvm::Value* res = cUnit->irb->CreateSExt(getLLVMValue(cUnit, rlSrc.origSReg),
+ cUnit->irb->getInt64Ty());
+ defineValue(cUnit, res, rlDest.origSReg);
+}
+
+void convertIntNarrowing(CompilationUnit* cUnit, RegLocation rlDest,
+ RegLocation rlSrc,
+ greenland::IntrinsicHelper::IntrinsicId id)
+{
+ llvm::Function* intr = cUnit->intrinsic_helper->GetIntrinsicFunction(id);
+ llvm::Value* res = cUnit->irb->CreateCall(intr,
+ getLLVMValue(cUnit, rlSrc.origSReg));
+ defineValue(cUnit, res, rlDest.origSReg);
+}
+
/*
* Target-independent code generation. Use only high-level
* load/store utilities here, or target-dependent genXX() handlers
@@ -942,10 +1017,10 @@
convertArithOpLit(cUnit, kOpLsl, rlDest, rlSrc[0], vC & 0x1f);
break;
case Instruction::SHR_INT_LIT8:
- convertArithOpLit(cUnit, kOpLsr, rlDest, rlSrc[0], vC & 0x1f);
+ convertArithOpLit(cUnit, kOpAsr, rlDest, rlSrc[0], vC & 0x1f);
break;
case Instruction::USHR_INT_LIT8:
- convertArithOpLit(cUnit, kOpAsr, rlDest, rlSrc[0], vC & 0x1f);
+ convertArithOpLit(cUnit, kOpLsr, rlDest, rlSrc[0], vC & 0x1f);
break;
case Instruction::ADD_FLOAT:
@@ -984,43 +1059,71 @@
break;
case Instruction::INVOKE_STATIC:
- convertInvoke(cUnit, bb, mir, kStatic, false /*range*/);
+ convertInvoke(cUnit, bb, mir, kStatic, false /*range*/,
+ false /* NewFilledArray */);
break;
case Instruction::INVOKE_STATIC_RANGE:
- convertInvoke(cUnit, bb, mir, kStatic, true /*range*/);
+ convertInvoke(cUnit, bb, mir, kStatic, true /*range*/,
+ false /* NewFilledArray */);
break;
case Instruction::INVOKE_DIRECT:
- convertInvoke(cUnit, bb, mir, kDirect, false /*range*/);
+ convertInvoke(cUnit, bb, mir, kDirect, false /*range*/,
+ false /* NewFilledArray */);
break;
case Instruction::INVOKE_DIRECT_RANGE:
- convertInvoke(cUnit, bb, mir, kDirect, true /*range*/);
+ convertInvoke(cUnit, bb, mir, kDirect, true /*range*/,
+ false /* NewFilledArray */);
break;
case Instruction::INVOKE_VIRTUAL:
- convertInvoke(cUnit, bb, mir, kVirtual, false /*range*/);
+ convertInvoke(cUnit, bb, mir, kVirtual, false /*range*/,
+ false /* NewFilledArray */);
break;
case Instruction::INVOKE_VIRTUAL_RANGE:
- convertInvoke(cUnit, bb, mir, kVirtual, true /*range*/);
+ convertInvoke(cUnit, bb, mir, kVirtual, true /*range*/,
+ false /* NewFilledArray */);
break;
case Instruction::INVOKE_SUPER:
- convertInvoke(cUnit, bb, mir, kSuper, false /*range*/);
+ convertInvoke(cUnit, bb, mir, kSuper, false /*range*/,
+ false /* NewFilledArray */);
break;
case Instruction::INVOKE_SUPER_RANGE:
- convertInvoke(cUnit, bb, mir, kSuper, true /*range*/);
+ convertInvoke(cUnit, bb, mir, kSuper, true /*range*/,
+ false /* NewFilledArray */);
break;
case Instruction::INVOKE_INTERFACE:
- convertInvoke(cUnit, bb, mir, kInterface, false /*range*/);
+ convertInvoke(cUnit, bb, mir, kInterface, false /*range*/,
+ false /* NewFilledArray */);
break;
case Instruction::INVOKE_INTERFACE_RANGE:
- convertInvoke(cUnit, bb, mir, kInterface, true /*range*/);
+ convertInvoke(cUnit, bb, mir, kInterface, true /*range*/,
+ false /* NewFilledArray */);
+ break;
+ case Instruction::FILLED_NEW_ARRAY:
+ convertInvoke(cUnit, bb, mir, kInterface, false /*range*/,
+ true /* NewFilledArray */);
+ break;
+ case Instruction::FILLED_NEW_ARRAY_RANGE:
+ convertInvoke(cUnit, bb, mir, kInterface, true /*range*/,
+ true /* NewFilledArray */);
break;
case Instruction::CONST_STRING:
case Instruction::CONST_STRING_JUMBO:
- convertConstString(cUnit, bb, vB, rlDest);
+ convertConstObject(cUnit, vB, greenland::IntrinsicHelper::ConstString,
+ rlDest);
+ break;
+
+ case Instruction::CONST_CLASS:
+ convertConstObject(cUnit, vB, greenland::IntrinsicHelper::ConstClass,
+ rlDest);
+ break;
+
+ case Instruction::CHECK_CAST:
+ convertCheckCast(cUnit, vB, rlSrc[0]);
break;
case Instruction::NEW_INSTANCE:
@@ -1153,24 +1256,106 @@
}
break;
-#if 0
-
- case Instruction::CHECK_CAST:
- genCheckCast(cUnit, mir, rlSrc[0]);
+ case Instruction::IGET:
+ if (rlDest.fp) {
+ convertIget(cUnit, optFlags, greenland::IntrinsicHelper::HLIGetFloat,
+ rlSrc[0], rlSrc[1], vC);
+ } else {
+ convertIget(cUnit, optFlags, greenland::IntrinsicHelper::HLIGet,
+ rlSrc[0], rlSrc[1], vC);
+ }
break;
-
- case Instruction::CONST_CLASS:
- genConstClass(cUnit, mir, rlDest, rlSrc[0]);
+ case Instruction::IGET_OBJECT:
+ convertIget(cUnit, optFlags, greenland::IntrinsicHelper::HLIGetObject,
+ rlSrc[0], rlSrc[1], vC);
+ break;
+ case Instruction::IGET_BOOLEAN:
+ convertIget(cUnit, optFlags, greenland::IntrinsicHelper::HLIGetBoolean,
+ rlSrc[0], rlSrc[1], vC);
+ break;
+ case Instruction::IGET_BYTE:
+ convertIget(cUnit, optFlags, greenland::IntrinsicHelper::HLIGetByte,
+ rlSrc[0], rlSrc[1], vC);
+ break;
+ case Instruction::IGET_CHAR:
+ convertIget(cUnit, optFlags, greenland::IntrinsicHelper::HLIGetChar,
+ rlSrc[0], rlSrc[1], vC);
+ break;
+ case Instruction::IGET_SHORT:
+ convertIget(cUnit, optFlags, greenland::IntrinsicHelper::HLIGetShort,
+ rlSrc[0], rlSrc[1], vC);
+ break;
+ case Instruction::IGET_WIDE:
+ if (rlDest.fp) {
+ convertIget(cUnit, optFlags, greenland::IntrinsicHelper::HLIGetDouble,
+ rlSrc[0], rlSrc[1], vC);
+ } else {
+ convertIget(cUnit, optFlags, greenland::IntrinsicHelper::HLIGetWide,
+ rlSrc[0], rlSrc[1], vC);
+ }
+ break;
+ case Instruction::IPUT:
+ if (rlDest.fp) {
+ convertIput(cUnit, optFlags, greenland::IntrinsicHelper::HLIPutFloat,
+ rlSrc[0], rlSrc[1], vC);
+ } else {
+ convertIput(cUnit, optFlags, greenland::IntrinsicHelper::HLIPut,
+ rlSrc[0], rlSrc[1], vC);
+ }
+ break;
+ case Instruction::IPUT_OBJECT:
+ convertIput(cUnit, optFlags, greenland::IntrinsicHelper::HLIPutObject,
+ rlSrc[0], rlSrc[1], vC);
+ break;
+ case Instruction::IPUT_BOOLEAN:
+ convertIput(cUnit, optFlags, greenland::IntrinsicHelper::HLIPutBoolean,
+ rlSrc[0], rlSrc[1], vC);
+ break;
+ case Instruction::IPUT_BYTE:
+ convertIput(cUnit, optFlags, greenland::IntrinsicHelper::HLIPutByte,
+ rlSrc[0], rlSrc[1], vC);
+ break;
+ case Instruction::IPUT_CHAR:
+ convertIput(cUnit, optFlags, greenland::IntrinsicHelper::HLIPutChar,
+ rlSrc[0], rlSrc[1], vC);
+ break;
+ case Instruction::IPUT_SHORT:
+ convertIput(cUnit, optFlags, greenland::IntrinsicHelper::HLIPutShort,
+ rlSrc[0], rlSrc[1], vC);
+ break;
+ case Instruction::IPUT_WIDE:
+ if (rlDest.fp) {
+ convertIput(cUnit, optFlags, greenland::IntrinsicHelper::HLIPutDouble,
+ rlSrc[0], rlSrc[1], vC);
+ } else {
+ convertIput(cUnit, optFlags, greenland::IntrinsicHelper::HLIPutWide,
+ rlSrc[0], rlSrc[1], vC);
+ }
break;
case Instruction::FILL_ARRAY_DATA:
- genFillArrayData(cUnit, mir, rlSrc[0]);
+ convertFillArrayData(cUnit, vB, rlSrc[0]);
break;
- case Instruction::FILLED_NEW_ARRAY_RANGE:
- genFilledNewArray(cUnit, mir, true /* range */);
+ case Instruction::INT_TO_LONG:
+ convertIntToLong(cUnit, rlDest, rlSrc[0]);
break;
+ case Instruction::INT_TO_CHAR:
+ convertIntNarrowing(cUnit, rlDest, rlSrc[0],
+ greenland::IntrinsicHelper::IntToChar);
+ break;
+ case Instruction::INT_TO_BYTE:
+ convertIntNarrowing(cUnit, rlDest, rlSrc[0],
+ greenland::IntrinsicHelper::IntToByte);
+ break;
+ case Instruction::INT_TO_SHORT:
+ convertIntNarrowing(cUnit, rlDest, rlSrc[0],
+ greenland::IntrinsicHelper::IntToShort);
+ break;
+
+#if 0
+
case Instruction::PACKED_SWITCH:
genPackedSwitch(cUnit, mir, rlSrc[0]);
break;
@@ -1190,62 +1375,6 @@
genCmpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
break;
- case Instruction::IGET_OBJECT:
- //case Instruction::IGET_OBJECT_VOLATILE:
- genIGet(cUnit, mir, kWord, rlDest, rlSrc[0], false, true);
- break;
-
- case Instruction::IGET_WIDE:
- //case Instruction::IGET_WIDE_VOLATILE:
- genIGet(cUnit, mir, kLong, rlDest, rlSrc[0], true, false);
- break;
-
- case Instruction::IGET:
- //case Instruction::IGET_VOLATILE:
- genIGet(cUnit, mir, kWord, rlDest, rlSrc[0], false, false);
- break;
-
- case Instruction::IGET_CHAR:
- genIGet(cUnit, mir, kUnsignedHalf, rlDest, rlSrc[0], false, false);
- break;
-
- case Instruction::IGET_SHORT:
- genIGet(cUnit, mir, kSignedHalf, rlDest, rlSrc[0], false, false);
- break;
-
- case Instruction::IGET_BOOLEAN:
- case Instruction::IGET_BYTE:
- genIGet(cUnit, mir, kUnsignedByte, rlDest, rlSrc[0], false, false);
- break;
-
- case Instruction::IPUT_WIDE:
- //case Instruction::IPUT_WIDE_VOLATILE:
- genIPut(cUnit, mir, kLong, rlSrc[0], rlSrc[1], true, false);
- break;
-
- case Instruction::IPUT_OBJECT:
- //case Instruction::IPUT_OBJECT_VOLATILE:
- genIPut(cUnit, mir, kWord, rlSrc[0], rlSrc[1], false, true);
- break;
-
- case Instruction::IPUT:
- //case Instruction::IPUT_VOLATILE:
- genIPut(cUnit, mir, kWord, rlSrc[0], rlSrc[1], false, false);
- break;
-
- case Instruction::IPUT_BOOLEAN:
- case Instruction::IPUT_BYTE:
- genIPut(cUnit, mir, kUnsignedByte, rlSrc[0], rlSrc[1], false, false);
- break;
-
- case Instruction::IPUT_CHAR:
- genIPut(cUnit, mir, kUnsignedHalf, rlSrc[0], rlSrc[1], false, false);
- break;
-
- case Instruction::IPUT_SHORT:
- genIPut(cUnit, mir, kSignedHalf, rlSrc[0], rlSrc[1], false, false);
- break;
-
case Instruction::NEG_INT:
case Instruction::NOT_INT:
res = genArithOpInt(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
@@ -1264,22 +1393,12 @@
res = genArithOpDouble(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
break;
- case Instruction::INT_TO_LONG:
- genIntToLong(cUnit, mir, rlDest, rlSrc[0]);
- break;
-
case Instruction::LONG_TO_INT:
rlSrc[0] = oatUpdateLocWide(cUnit, rlSrc[0]);
rlSrc[0] = oatWideToNarrow(cUnit, rlSrc[0]);
storeValue(cUnit, rlDest, rlSrc[0]);
break;
- case Instruction::INT_TO_BYTE:
- case Instruction::INT_TO_SHORT:
- case Instruction::INT_TO_CHAR:
- genIntNarrowing(cUnit, mir, rlDest, rlSrc[0]);
- break;
-
case Instruction::INT_TO_FLOAT:
case Instruction::INT_TO_DOUBLE:
case Instruction::LONG_TO_FLOAT:
@@ -1656,6 +1775,8 @@
if (it == cUnit->locMap.end()) {
std::string valName = val->getName().str();
if (valName.empty()) {
+ // FIXME: need to be more robust, handle FP and be in a position to
+ // manage unnamed temps whose lifetimes span basic block boundaries
UNIMPLEMENTED(WARNING) << "Need to handle unnamed llvm temps";
memset(&res, 0, sizeof(res));
res.location = kLocPhysReg;
@@ -1663,6 +1784,12 @@
res.home = true;
res.sRegLow = INVALID_SREG;
res.origSReg = INVALID_SREG;
+ llvm::Type* ty = val->getType();
+ res.wide = ((ty == cUnit->irb->getInt64Ty()) ||
+ (ty == cUnit->irb->getDoubleTy()));
+ if (res.wide) {
+ res.highReg = oatAllocTemp(cUnit);
+ }
cUnit->locMap.Put(val, res);
} else {
DCHECK_EQ(valName[0], 'v');
@@ -1767,6 +1894,37 @@
}
}
+void cvtIntNarrowing(CompilationUnit* cUnit, llvm::Instruction* inst,
+ Instruction::Code opcode)
+{
+ RegLocation rlDest = getLoc(cUnit, inst);
+ RegLocation rlSrc = getLoc(cUnit, inst->getOperand(0));
+ genIntNarrowing(cUnit, opcode, rlDest, rlSrc);
+}
+
+void cvtIntExt(CompilationUnit* cUnit, llvm::Instruction* inst, bool isSigned)
+{
+ // TODO: evaluate src/tgt types and add general support for more than int to long
+ RegLocation rlDest = getLoc(cUnit, inst);
+ RegLocation rlSrc = getLoc(cUnit, inst->getOperand(0));
+ DCHECK(rlDest.wide);
+ DCHECK(!rlSrc.wide);
+ DCHECK(!rlDest.fp);
+ DCHECK(!rlSrc.fp);
+ RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
+ if (rlSrc.location == kLocPhysReg) {
+ opRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
+ } else {
+ loadValueDirect(cUnit, rlSrc, rlResult.lowReg);
+ }
+ if (isSigned) {
+ opRegRegImm(cUnit, kOpAsr, rlResult.highReg, rlResult.lowReg, 31);
+ } else {
+ loadConstant(cUnit, rlResult.highReg, 0);
+ }
+ storeValueWide(cUnit, rlDest, rlResult);
+}
+
void cvtBinOp(CompilationUnit* cUnit, OpKind op, llvm::Instruction* inst)
{
RegLocation rlDest = getLoc(cUnit, inst);
@@ -1796,6 +1954,46 @@
}
}
+void cvtShiftOp(CompilationUnit* cUnit, OpKind op, llvm::Instruction* inst)
+{
+ if (inst->getType() == cUnit->irb->getInt64Ty()) {
+ /*
+ * llvm wants the shift amount to be 64 bits, whereas we've constained
+ * it to be in 6 bits. It should always be held as an unnamed temp
+ * at this point that was the result of a previous UExt. We'll backtrack
+ * to find the pre-extension value and use that.
+ * TODO: probably better to handle this in cvtIntExt() or just intrinsify
+ */
+ RegLocation rlDest = getLoc(cUnit, inst);
+ RegLocation rlSrc = getLoc(cUnit, inst->getOperand(0));
+ RegLocation rlShift = getLoc(cUnit, inst->getOperand(1));
+ DCHECK(rlShift.wide);
+ DCHECK_EQ(rlShift.sRegLow, INVALID_SREG);
+ // Now, free the temp registers - we won't need them.
+ // TODO: kill the dead extend ops
+ oatFreeTemp(cUnit, rlShift.lowReg);
+ oatFreeTemp(cUnit, rlShift.highReg);
+ // Get the pre-extend operand
+ llvm::Instruction* extInst =
+ llvm::dyn_cast<llvm::Instruction>(inst->getOperand(1));
+ DCHECK(extInst != NULL);
+ rlShift = getLoc(cUnit, extInst->getOperand(0));
+ DCHECK(!rlShift.wide);
+ Instruction::Code opcode;
+ if (op == kOpLsl)
+ opcode = Instruction::SHL_LONG;
+ else if (op == kOpAsr)
+ opcode = Instruction::SHR_LONG;
+ else {
+ DCHECK_EQ(op, kOpLsr);
+ opcode = Instruction::USHR_LONG;
+ }
+ genShiftOpLong(cUnit, opcode, rlDest, rlSrc, rlShift);
+ } else {
+ cvtBinOp(cUnit, op, inst);
+ }
+}
+
void cvtBr(CompilationUnit* cUnit, llvm::Instruction* inst)
{
llvm::BranchInst* brInst = llvm::dyn_cast<llvm::BranchInst>(inst);
@@ -1922,14 +2120,28 @@
}
}
-void cvtConstString(CompilationUnit* cUnit, llvm::CallInst* callInst)
+void cvtConstObject(CompilationUnit* cUnit, llvm::CallInst* callInst,
+ bool isString)
{
DCHECK_EQ(callInst->getNumArgOperands(), 1U);
- llvm::ConstantInt* stringIdxVal =
+ llvm::ConstantInt* idxVal =
llvm::dyn_cast<llvm::ConstantInt>(callInst->getArgOperand(0));
- uint32_t stringIdx = stringIdxVal->getZExtValue();
+ uint32_t index = idxVal->getZExtValue();
RegLocation rlDest = getLoc(cUnit, callInst);
- genConstString(cUnit, stringIdx, rlDest);
+ if (isString) {
+ genConstString(cUnit, index, rlDest);
+ } else {
+ genConstClass(cUnit, index, rlDest);
+ }
+}
+
+void cvtFillArrayData(CompilationUnit* cUnit, llvm::CallInst* callInst)
+{
+ DCHECK_EQ(callInst->getNumArgOperands(), 2U);
+ llvm::ConstantInt* offsetVal =
+ llvm::dyn_cast<llvm::ConstantInt>(callInst->getArgOperand(0));
+ RegLocation rlSrc = getLoc(cUnit, callInst->getArgOperand(1));
+ genFillArrayData(cUnit, offsetVal->getSExtValue(), rlSrc);
}
void cvtNewInstance(CompilationUnit* cUnit, llvm::CallInst* callInst)
@@ -2083,8 +2295,45 @@
rlSrc, scale);
}
+void cvtIget(CompilationUnit* cUnit, llvm::CallInst* callInst, OpSize size,
+ bool isWide, bool isObj)
+{
+ DCHECK_EQ(callInst->getNumArgOperands(), 3U);
+ llvm::ConstantInt* optFlags =
+ llvm::dyn_cast<llvm::ConstantInt>(callInst->getArgOperand(0));
+ RegLocation rlObj = getLoc(cUnit, callInst->getArgOperand(1));
+ llvm::ConstantInt* fieldIdx =
+ llvm::dyn_cast<llvm::ConstantInt>(callInst->getArgOperand(2));
+ RegLocation rlDest = getLoc(cUnit, callInst);
+ genIGet(cUnit, fieldIdx->getZExtValue(), optFlags->getZExtValue(),
+ size, rlDest, rlObj, isWide, isObj);
+}
+
+void cvtIput(CompilationUnit* cUnit, llvm::CallInst* callInst, OpSize size,
+ bool isWide, bool isObj)
+{
+ DCHECK_EQ(callInst->getNumArgOperands(), 4U);
+ llvm::ConstantInt* optFlags =
+ llvm::dyn_cast<llvm::ConstantInt>(callInst->getArgOperand(0));
+ RegLocation rlSrc = getLoc(cUnit, callInst->getArgOperand(1));
+ RegLocation rlObj = getLoc(cUnit, callInst->getArgOperand(2));
+ llvm::ConstantInt* fieldIdx =
+ llvm::dyn_cast<llvm::ConstantInt>(callInst->getArgOperand(2));
+ genIPut(cUnit, fieldIdx->getZExtValue(), optFlags->getZExtValue(),
+ size, rlSrc, rlObj, isWide, isObj);
+}
+
+void cvtCheckCast(CompilationUnit* cUnit, llvm::CallInst* callInst)
+{
+ DCHECK_EQ(callInst->getNumArgOperands(), 2U);
+ llvm::ConstantInt* typeIdx =
+ llvm::dyn_cast<llvm::ConstantInt>(callInst->getArgOperand(0));
+ RegLocation rlSrc = getLoc(cUnit, callInst->getArgOperand(1));
+ genCheckCast(cUnit, typeIdx->getZExtValue(), rlSrc);
+}
+
void cvtInvoke(CompilationUnit* cUnit, llvm::CallInst* callInst,
- bool isVoid)
+ bool isVoid, bool isNewArray)
{
CallInfo* info = (CallInfo*)oatNew(cUnit, sizeof(CallInfo), true,
kAllocMisc);
@@ -2129,7 +2378,11 @@
}
next++;
}
- genInvoke(cUnit, info);
+ if (isNewArray) {
+ genFilledNewArray(cUnit, info);
+ } else {
+ genInvoke(cUnit, info);
+ }
}
/* Look up the RegLocation associated with a Value. Must already be defined */
@@ -2279,13 +2532,25 @@
case greenland::IntrinsicHelper::HLInvokeDouble:
case greenland::IntrinsicHelper::HLInvokeLong:
case greenland::IntrinsicHelper::HLInvokeInt:
- cvtInvoke(cUnit, callInst, false /* isVoid */);
+ cvtInvoke(cUnit, callInst, false /* isVoid */, false /* newArray */);
break;
case greenland::IntrinsicHelper::HLInvokeVoid:
- cvtInvoke(cUnit, callInst, true /* isVoid */);
+ cvtInvoke(cUnit, callInst, true /* isVoid */, false /* newArray */);
+ break;
+ case greenland::IntrinsicHelper::FilledNewArray:
+ cvtInvoke(cUnit, callInst, false /* isVoid */, true /* newArray */);
+ break;
+ case greenland::IntrinsicHelper::FillArrayData:
+ cvtFillArrayData(cUnit, callInst);
break;
case greenland::IntrinsicHelper::ConstString:
- cvtConstString(cUnit, callInst);
+ cvtConstObject(cUnit, callInst, true /* isString */);
+ break;
+ case greenland::IntrinsicHelper::ConstClass:
+ cvtConstObject(cUnit, callInst, false /* isString */);
+ break;
+ case greenland::IntrinsicHelper::CheckCast:
+ cvtCheckCast(cUnit, callInst);
break;
case greenland::IntrinsicHelper::NewInstance:
cvtNewInstance(cUnit, callInst);
@@ -2374,6 +2639,72 @@
cvtAput(cUnit, callInst, kSignedHalf, 1);
break;
+ case greenland::IntrinsicHelper::HLIGet:
+ case greenland::IntrinsicHelper::HLIGetFloat:
+ cvtIget(cUnit, callInst, kWord, false /* isWide */, false /* obj */);
+ break;
+ case greenland::IntrinsicHelper::HLIGetObject:
+ cvtIget(cUnit, callInst, kWord, false /* isWide */, true /* obj */);
+ break;
+ case greenland::IntrinsicHelper::HLIGetWide:
+ case greenland::IntrinsicHelper::HLIGetDouble:
+ cvtIget(cUnit, callInst, kLong, true /* isWide */, false /* obj */);
+ break;
+ case greenland::IntrinsicHelper::HLIGetBoolean:
+ cvtIget(cUnit, callInst, kUnsignedByte, false /* isWide */,
+ false /* obj */);
+ break;
+ case greenland::IntrinsicHelper::HLIGetByte:
+ cvtIget(cUnit, callInst, kSignedByte, false /* isWide */,
+ false /* obj */);
+ break;
+ case greenland::IntrinsicHelper::HLIGetChar:
+ cvtIget(cUnit, callInst, kUnsignedHalf, false /* isWide */,
+ false /* obj */);
+ break;
+ case greenland::IntrinsicHelper::HLIGetShort:
+ cvtIget(cUnit, callInst, kSignedHalf, false /* isWide */,
+ false /* obj */);
+ break;
+
+ case greenland::IntrinsicHelper::HLIPut:
+ case greenland::IntrinsicHelper::HLIPutFloat:
+ cvtIput(cUnit, callInst, kWord, false /* isWide */, false /* obj */);
+ break;
+ case greenland::IntrinsicHelper::HLIPutObject:
+ cvtIput(cUnit, callInst, kWord, false /* isWide */, true /* obj */);
+ break;
+ case greenland::IntrinsicHelper::HLIPutWide:
+ case greenland::IntrinsicHelper::HLIPutDouble:
+ cvtIput(cUnit, callInst, kLong, true /* isWide */, false /* obj */);
+ break;
+ case greenland::IntrinsicHelper::HLIPutBoolean:
+ cvtIput(cUnit, callInst, kUnsignedByte, false /* isWide */,
+ false /* obj */);
+ break;
+ case greenland::IntrinsicHelper::HLIPutByte:
+ cvtIput(cUnit, callInst, kSignedByte, false /* isWide */,
+ false /* obj */);
+ break;
+ case greenland::IntrinsicHelper::HLIPutChar:
+ cvtIput(cUnit, callInst, kUnsignedHalf, false /* isWide */,
+ false /* obj */);
+ break;
+ case greenland::IntrinsicHelper::HLIPutShort:
+ cvtIput(cUnit, callInst, kSignedHalf, false /* isWide */,
+ false /* obj */);
+ break;
+
+ case greenland::IntrinsicHelper::IntToChar:
+ cvtIntNarrowing(cUnit, callInst, Instruction::INT_TO_CHAR);
+ break;
+ case greenland::IntrinsicHelper::IntToShort:
+ cvtIntNarrowing(cUnit, callInst, Instruction::INT_TO_SHORT);
+ break;
+ case greenland::IntrinsicHelper::IntToByte:
+ cvtIntNarrowing(cUnit, callInst, Instruction::INT_TO_BYTE);
+ break;
+
case greenland::IntrinsicHelper::UnknownId:
cvtCall(cUnit, callInst, callee);
break;
@@ -2393,9 +2724,9 @@
case llvm::Instruction::And: cvtBinOp(cUnit, kOpAnd, inst); break;
case llvm::Instruction::Or: cvtBinOp(cUnit, kOpOr, inst); break;
case llvm::Instruction::Xor: cvtBinOp(cUnit, kOpXor, inst); break;
- case llvm::Instruction::Shl: cvtBinOp(cUnit, kOpLsl, inst); break;
- case llvm::Instruction::LShr: cvtBinOp(cUnit, kOpLsr, inst); break;
- case llvm::Instruction::AShr: cvtBinOp(cUnit, kOpAsr, inst); break;
+ case llvm::Instruction::Shl: cvtShiftOp(cUnit, kOpLsl, inst); break;
+ case llvm::Instruction::LShr: cvtShiftOp(cUnit, kOpLsr, inst); break;
+ case llvm::Instruction::AShr: cvtShiftOp(cUnit, kOpAsr, inst); break;
case llvm::Instruction::PHI: cvtPhi(cUnit, inst); break;
case llvm::Instruction::Ret: cvtRet(cUnit, inst); break;
case llvm::Instruction::FAdd: cvtBinFPOp(cUnit, kOpAdd, inst); break;
@@ -2404,13 +2735,16 @@
case llvm::Instruction::FDiv: cvtBinFPOp(cUnit, kOpDiv, inst); break;
case llvm::Instruction::FRem: cvtBinFPOp(cUnit, kOpRem, inst); break;
+ case llvm::Instruction::ZExt: cvtIntExt(cUnit, inst, false /* signed */);
+ break;
+ case llvm::Instruction::SExt: cvtIntExt(cUnit, inst, true /* signed */);
+ break;
+
case llvm::Instruction::Unreachable:
break; // FIXME: can we really ignore these?
case llvm::Instruction::Invoke:
case llvm::Instruction::Trunc:
- case llvm::Instruction::ZExt:
- case llvm::Instruction::SExt:
case llvm::Instruction::FPToUI:
case llvm::Instruction::FPToSI:
case llvm::Instruction::UIToFP:
@@ -2421,7 +2755,7 @@
case llvm::Instruction::IntToPtr:
case llvm::Instruction::Switch:
case llvm::Instruction::FCmp:
- UNIMPLEMENTED(FATAL) << "Unimplemented llvm opcode: " << opcode; break;
+ UNIMPLEMENTED(FATAL) << "Unimplemented llvm opcode: " << opcode;
break;
case llvm::Instruction::URem: