Index: src/compiler/mips64/code-generator-mips64.cc |
diff --git a/src/compiler/mips/code-generator-mips.cc b/src/compiler/mips64/code-generator-mips64.cc |
similarity index 68% |
copy from src/compiler/mips/code-generator-mips.cc |
copy to src/compiler/mips64/code-generator-mips64.cc |
index 3904a71947b850f1a69bb67865feab9dd7921c46..32ec9206d894514e5d51023ceae006982b02ff47 100644 |
--- a/src/compiler/mips/code-generator-mips.cc |
+++ b/src/compiler/mips64/code-generator-mips64.cc |
@@ -19,7 +19,7 @@ namespace compiler { |
// TODO(plind): Possibly avoid using these lithium names. |
#define kScratchReg kLithiumScratchReg |
-#define kCompareReg kLithiumScratchReg2 |
+#define kScratchReg2 kLithiumScratchReg2 |
#define kScratchDoubleReg kLithiumScratchDouble |
@@ -58,13 +58,14 @@ class MipsOperandConverter FINAL : public InstructionOperandConverter { |
switch (constant.type()) { |
case Constant::kInt32: |
return Operand(constant.ToInt32()); |
+ case Constant::kInt64: |
+ return Operand(constant.ToInt64()); |
case Constant::kFloat32: |
return Operand( |
isolate()->factory()->NewNumber(constant.ToFloat32(), TENURED)); |
case Constant::kFloat64: |
return Operand( |
isolate()->factory()->NewNumber(constant.ToFloat64(), TENURED)); |
- case Constant::kInt64: |
case Constant::kExternalReference: |
case Constant::kHeapObject: |
// TODO(plind): Maybe we should handle ExtRef & HeapObj here? |
@@ -133,7 +134,7 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) { |
__ Call(Handle<Code>::cast(i.InputHeapObject(0)), |
RelocInfo::CODE_TARGET); |
} else { |
- __ addiu(at, i.InputRegister(0), Code::kHeaderSize - kHeapObjectTag); |
+ __ daddiu(at, i.InputRegister(0), Code::kHeaderSize - kHeapObjectTag); |
__ Call(at); |
} |
AddSafepointAndDeopt(instr); |
@@ -144,11 +145,11 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) { |
Register func = i.InputRegister(0); |
if (FLAG_debug_code) { |
// Check the function's context matches the context argument. |
- __ lw(kScratchReg, FieldMemOperand(func, JSFunction::kContextOffset)); |
+ __ ld(kScratchReg, FieldMemOperand(func, JSFunction::kContextOffset)); |
__ Assert(eq, kWrongFunctionContext, cp, Operand(kScratchReg)); |
} |
- __ lw(at, FieldMemOperand(func, JSFunction::kCodeEntryOffset)); |
+ __ ld(at, FieldMemOperand(func, JSFunction::kCodeEntryOffset)); |
__ Call(at); |
AddSafepointAndDeopt(instr); |
break; |
@@ -168,51 +169,66 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) { |
case kArchTruncateDoubleToI: |
__ TruncateDoubleToI(i.OutputRegister(), i.InputDoubleRegister(0)); |
break; |
- case kMipsAdd: |
+ case kMips64Add: |
__ Addu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); |
break; |
- case kMipsAddOvf: |
- __ AdduAndCheckForOverflow(i.OutputRegister(), i.InputRegister(0), |
- i.InputOperand(1), kCompareReg, kScratchReg); |
+ case kMips64Dadd: |
+ __ Daddu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); |
break; |
- case kMipsSub: |
+ case kMips64Sub: |
__ Subu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); |
break; |
- case kMipsSubOvf: |
- __ SubuAndCheckForOverflow(i.OutputRegister(), i.InputRegister(0), |
- i.InputOperand(1), kCompareReg, kScratchReg); |
+ case kMips64Dsub: |
+ __ Dsubu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); |
break; |
- case kMipsMul: |
+ case kMips64Mul: |
__ Mul(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); |
break; |
- case kMipsMulHigh: |
+ case kMips64MulHigh: |
__ Mulh(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); |
break; |
- case kMipsMulHighU: |
+ case kMips64MulHighU: |
__ Mulhu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); |
break; |
- case kMipsDiv: |
+ case kMips64Div: |
__ Div(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); |
break; |
- case kMipsDivU: |
+ case kMips64DivU: |
__ Divu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); |
break; |
- case kMipsMod: |
+ case kMips64Mod: |
__ Mod(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); |
break; |
- case kMipsModU: |
+ case kMips64ModU: |
__ Modu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); |
break; |
- case kMipsAnd: |
+ case kMips64Dmul: |
+ __ Dmul(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); |
+ break; |
+ case kMips64Ddiv: |
+ __ Ddiv(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); |
+ break; |
+ case kMips64DdivU: |
+ __ Ddivu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); |
+ break; |
+ case kMips64Dmod: |
+ __ Dmod(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); |
+ break; |
+ case kMips64DmodU: |
+ __ Dmodu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); |
+ break; |
+ __ And(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); |
+ break; |
+ case kMips64And: |
__ And(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); |
break; |
- case kMipsOr: |
+ case kMips64Or: |
__ Or(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); |
break; |
- case kMipsXor: |
+ case kMips64Xor: |
__ Xor(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); |
break; |
- case kMipsShl: |
+ case kMips64Shl: |
if (instr->InputAt(1)->IsRegister()) { |
__ sllv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1)); |
} else { |
@@ -220,7 +236,7 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) { |
__ sll(i.OutputRegister(), i.InputRegister(0), imm); |
} |
break; |
- case kMipsShr: |
+ case kMips64Shr: |
if (instr->InputAt(1)->IsRegister()) { |
__ srlv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1)); |
} else { |
@@ -228,7 +244,7 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) { |
__ srl(i.OutputRegister(), i.InputRegister(0), imm); |
} |
break; |
- case kMipsSar: |
+ case kMips64Sar: |
if (instr->InputAt(1)->IsRegister()) { |
__ srav(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1)); |
} else { |
@@ -236,16 +252,65 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) { |
__ sra(i.OutputRegister(), i.InputRegister(0), imm); |
} |
break; |
- case kMipsRor: |
+ case kMips64Ext: |
+ __ Ext(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1), |
+ i.InputInt8(2)); |
+ break; |
+ case kMips64Dext: |
+ __ Dext(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1), |
+ i.InputInt8(2)); |
+ break; |
+ case kMips64Dshl: |
+ if (instr->InputAt(1)->IsRegister()) { |
+ __ dsllv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1)); |
+ } else { |
+ int32_t imm = i.InputOperand(1).immediate(); |
+ if (imm < 32) { |
+ __ dsll(i.OutputRegister(), i.InputRegister(0), imm); |
+ } else { |
+ __ dsll32(i.OutputRegister(), i.InputRegister(0), imm - 32); |
+ } |
+ } |
+ break; |
+ case kMips64Dshr: |
+ if (instr->InputAt(1)->IsRegister()) { |
+ __ dsrlv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1)); |
+ } else { |
+ int32_t imm = i.InputOperand(1).immediate(); |
+ if (imm < 32) { |
+ __ dsrl(i.OutputRegister(), i.InputRegister(0), imm); |
+ } else { |
+ __ dsrl32(i.OutputRegister(), i.InputRegister(0), imm - 32); |
+ } |
+ } |
+ break; |
+ case kMips64Dsar: |
+ if (instr->InputAt(1)->IsRegister()) { |
+ __ dsrav(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1)); |
+ } else { |
+ int32_t imm = i.InputOperand(1).immediate(); |
+ if (imm < 32) { |
+ __ dsra(i.OutputRegister(), i.InputRegister(0), imm); |
+ } else { |
+ __ dsra32(i.OutputRegister(), i.InputRegister(0), imm - 32); |
+ } |
+ } |
+ break; |
+ case kMips64Ror: |
__ Ror(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); |
break; |
- case kMipsTst: |
- // Pseudo-instruction used for tst/branch. No opcode emitted here. |
+ case kMips64Dror: |
+ __ Dror(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); |
+ break; |
+ case kMips64Tst: |
+ case kMips64Tst32: |
+ // Pseudo-instruction used for cmp/branch. No opcode emitted here. |
break; |
- case kMipsCmp: |
+ case kMips64Cmp: |
+ case kMips64Cmp32: |
// Pseudo-instruction used for cmp/branch. No opcode emitted here. |
break; |
- case kMipsMov: |
+ case kMips64Mov: |
// TODO(plind): Should we combine mov/li like this, or use separate instr? |
// - Also see x64 ASSEMBLE_BINOP & RegisterOrOperandType |
if (HasRegisterInput(instr, 0)) { |
@@ -255,28 +320,28 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) { |
} |
break; |
- case kMipsCmpD: |
+ case kMips64CmpD: |
// Psuedo-instruction used for FP cmp/branch. No opcode emitted here. |
break; |
- case kMipsAddD: |
+ case kMips64AddD: |
// TODO(plind): add special case: combine mult & add. |
__ add_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0), |
i.InputDoubleRegister(1)); |
break; |
- case kMipsSubD: |
+ case kMips64SubD: |
__ sub_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0), |
i.InputDoubleRegister(1)); |
break; |
- case kMipsMulD: |
+ case kMips64MulD: |
// TODO(plind): add special case: right op is -1.0, see arm port. |
__ mul_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0), |
i.InputDoubleRegister(1)); |
break; |
- case kMipsDivD: |
+ case kMips64DivD: |
__ div_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0), |
i.InputDoubleRegister(1)); |
break; |
- case kMipsModD: { |
+ case kMips64ModD: { |
// TODO(bmeurer): We should really get rid of this special instruction, |
// and generate a CallAddress instruction instead. |
FrameScope scope(masm(), StackFrame::MANUAL); |
@@ -289,37 +354,52 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) { |
__ MovFromFloatResult(i.OutputDoubleRegister()); |
break; |
} |
- case kMipsSqrtD: { |
+ case kMips64FloorD: { |
+ __ floor_l_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0)); |
+ __ cvt_d_l(i.OutputDoubleRegister(), i.OutputDoubleRegister()); |
+ break; |
+ } |
+ case kMips64CeilD: { |
+ __ ceil_l_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0)); |
+ __ cvt_d_l(i.OutputDoubleRegister(), i.OutputDoubleRegister()); |
+ break; |
+ } |
+ case kMips64RoundTruncateD: { |
+ __ trunc_l_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0)); |
+ __ cvt_d_l(i.OutputDoubleRegister(), i.OutputDoubleRegister()); |
+ break; |
+ } |
+ case kMips64SqrtD: { |
__ sqrt_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0)); |
break; |
} |
- case kMipsCvtSD: { |
+ case kMips64CvtSD: { |
__ cvt_s_d(i.OutputSingleRegister(), i.InputDoubleRegister(0)); |
break; |
} |
- case kMipsCvtDS: { |
+ case kMips64CvtDS: { |
__ cvt_d_s(i.OutputDoubleRegister(), i.InputSingleRegister(0)); |
break; |
} |
- case kMipsCvtDW: { |
+ case kMips64CvtDW: { |
FPURegister scratch = kScratchDoubleReg; |
__ mtc1(i.InputRegister(0), scratch); |
__ cvt_d_w(i.OutputDoubleRegister(), scratch); |
break; |
} |
- case kMipsCvtDUw: { |
+ case kMips64CvtDUw: { |
FPURegister scratch = kScratchDoubleReg; |
__ Cvt_d_uw(i.OutputDoubleRegister(), i.InputRegister(0), scratch); |
break; |
} |
- case kMipsTruncWD: { |
+ case kMips64TruncWD: { |
FPURegister scratch = kScratchDoubleReg; |
// Other arches use round to zero here, so we follow. |
__ trunc_w_d(scratch, i.InputDoubleRegister(0)); |
__ mfc1(i.OutputRegister(), scratch); |
break; |
} |
- case kMipsTruncUwD: { |
+ case kMips64TruncUwD: { |
FPURegister scratch = kScratchDoubleReg; |
// TODO(plind): Fix wrong param order of Trunc_uw_d() macro-asm function. |
__ Trunc_uw_d(i.InputDoubleRegister(0), i.OutputRegister(), scratch); |
@@ -327,55 +407,61 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) { |
} |
// ... more basic instructions ... |
- case kMipsLbu: |
+ case kMips64Lbu: |
__ lbu(i.OutputRegister(), i.MemoryOperand()); |
break; |
- case kMipsLb: |
+ case kMips64Lb: |
__ lb(i.OutputRegister(), i.MemoryOperand()); |
break; |
- case kMipsSb: |
+ case kMips64Sb: |
__ sb(i.InputRegister(2), i.MemoryOperand()); |
break; |
- case kMipsLhu: |
+ case kMips64Lhu: |
__ lhu(i.OutputRegister(), i.MemoryOperand()); |
break; |
- case kMipsLh: |
+ case kMips64Lh: |
__ lh(i.OutputRegister(), i.MemoryOperand()); |
break; |
- case kMipsSh: |
+ case kMips64Sh: |
__ sh(i.InputRegister(2), i.MemoryOperand()); |
break; |
- case kMipsLw: |
+ case kMips64Lw: |
__ lw(i.OutputRegister(), i.MemoryOperand()); |
break; |
- case kMipsSw: |
+ case kMips64Ld: |
+ __ ld(i.OutputRegister(), i.MemoryOperand()); |
+ break; |
+ case kMips64Sw: |
__ sw(i.InputRegister(2), i.MemoryOperand()); |
break; |
- case kMipsLwc1: { |
+ case kMips64Sd: |
+ __ sd(i.InputRegister(2), i.MemoryOperand()); |
+ break; |
+ case kMips64Lwc1: { |
__ lwc1(i.OutputSingleRegister(), i.MemoryOperand()); |
break; |
} |
- case kMipsSwc1: { |
+ case kMips64Swc1: { |
int index = 0; |
MemOperand operand = i.MemoryOperand(&index); |
__ swc1(i.InputSingleRegister(index), operand); |
break; |
} |
- case kMipsLdc1: |
+ case kMips64Ldc1: |
__ ldc1(i.OutputDoubleRegister(), i.MemoryOperand()); |
break; |
- case kMipsSdc1: |
+ case kMips64Sdc1: |
__ sdc1(i.InputDoubleRegister(2), i.MemoryOperand()); |
break; |
- case kMipsPush: |
+ case kMips64Push: |
__ Push(i.InputRegister(0)); |
break; |
- case kMipsStoreWriteBarrier: |
+ case kMips64StoreWriteBarrier: |
Register object = i.InputRegister(0); |
Register index = i.InputRegister(1); |
Register value = i.InputRegister(2); |
- __ addu(index, object, index); |
- __ sw(value, MemOperand(index)); |
+ __ daddu(index, object, index); |
+ __ sd(value, MemOperand(index)); |
SaveFPRegsMode mode = |
frame()->DidAllocateDoubleRegisters() ? kSaveFPRegs : kDontSaveFPRegs; |
RAStatus ra_status = kRAHasNotBeenSaved; |
@@ -416,7 +502,7 @@ void CodeGenerator::AssembleArchBranch(Instruction* instr, |
// TODO(plind): Add CHECK() to ensure that test/cmp and this branch were |
// not separated by other instructions. |
- if (instr->arch_opcode() == kMipsTst) { |
+ if (instr->arch_opcode() == kMips64Tst) { |
switch (condition) { |
case kNotEqual: |
cc = ne; |
@@ -425,29 +511,49 @@ void CodeGenerator::AssembleArchBranch(Instruction* instr, |
cc = eq; |
break; |
default: |
- UNSUPPORTED_COND(kMipsTst, condition); |
+ UNSUPPORTED_COND(kMips64Tst, condition); |
break; |
} |
__ And(at, i.InputRegister(0), i.InputOperand(1)); |
__ Branch(tlabel, cc, at, Operand(zero_reg)); |
- |
- } else if (instr->arch_opcode() == kMipsAddOvf || |
- instr->arch_opcode() == kMipsSubOvf) { |
- // kMipsAddOvf, SubOvf emit negative result to 'kCompareReg' on overflow. |
+ } else if (instr->arch_opcode() == kMips64Tst32) { |
+ switch (condition) { |
+ case kNotEqual: |
+ cc = ne; |
+ break; |
+ case kEqual: |
+ cc = eq; |
+ break; |
+ default: |
+ UNSUPPORTED_COND(kMips64Tst32, condition); |
+ break; |
+ } |
+ // Zero-extend registers on MIPS64 only 64-bit operand |
+ // branch and compare op. is available. |
+ // This is a disadvantage to perform 32-bit operation on MIPS64. |
+ // Try to force globally in front-end Word64 representation to be preferred |
+ // for MIPS64 even for Word32. |
+ __ And(at, i.InputRegister(0), i.InputOperand(1)); |
+ __ Dext(at, at, 0, 32); |
+ __ Branch(tlabel, cc, at, Operand(zero_reg)); |
+ } else if (instr->arch_opcode() == kMips64Dadd || |
+ instr->arch_opcode() == kMips64Dsub) { |
switch (condition) { |
case kOverflow: |
- cc = lt; |
+ cc = ne; |
break; |
case kNotOverflow: |
- cc = ge; |
+ cc = eq; |
break; |
default: |
- UNSUPPORTED_COND(kMipsAddOvf, condition); |
+ UNSUPPORTED_COND(kMips64Dadd, condition); |
break; |
} |
- __ Branch(tlabel, cc, kCompareReg, Operand(zero_reg)); |
- } else if (instr->arch_opcode() == kMipsCmp) { |
+ __ dsra32(kScratchReg, i.OutputRegister(), 0); |
+ __ sra(at, i.OutputRegister(), 31); |
+ __ Branch(tlabel, cc, at, Operand(kScratchReg)); |
+ } else if (instr->arch_opcode() == kMips64Cmp) { |
switch (condition) { |
case kEqual: |
cc = eq; |
@@ -480,7 +586,7 @@ void CodeGenerator::AssembleArchBranch(Instruction* instr, |
cc = hi; |
break; |
default: |
- UNSUPPORTED_COND(kMipsCmp, condition); |
+ UNSUPPORTED_COND(kMips64Cmp, condition); |
break; |
} |
__ Branch(tlabel, cc, i.InputRegister(0), i.InputOperand(1)); |
@@ -488,7 +594,77 @@ void CodeGenerator::AssembleArchBranch(Instruction* instr, |
if (!fallthru) __ Branch(flabel); // no fallthru to flabel. |
__ bind(&done); |
- } else if (instr->arch_opcode() == kMipsCmpD) { |
+ } else if (instr->arch_opcode() == kMips64Cmp32) { |
+ switch (condition) { |
+ case kEqual: |
+ cc = eq; |
+ break; |
+ case kNotEqual: |
+ cc = ne; |
+ break; |
+ case kSignedLessThan: |
+ cc = lt; |
+ break; |
+ case kSignedGreaterThanOrEqual: |
+ cc = ge; |
+ break; |
+ case kSignedLessThanOrEqual: |
+ cc = le; |
+ break; |
+ case kSignedGreaterThan: |
+ cc = gt; |
+ break; |
+ case kUnsignedLessThan: |
+ cc = lo; |
+ break; |
+ case kUnsignedGreaterThanOrEqual: |
+ cc = hs; |
+ break; |
+ case kUnsignedLessThanOrEqual: |
+ cc = ls; |
+ break; |
+ case kUnsignedGreaterThan: |
+ cc = hi; |
+ break; |
+ default: |
+ UNSUPPORTED_COND(kMips64Cmp32, condition); |
+ break; |
+ } |
+ |
+ switch (condition) { |
+ case kEqual: |
+ case kNotEqual: |
+ case kSignedLessThan: |
+ case kSignedGreaterThanOrEqual: |
+ case kSignedLessThanOrEqual: |
+ case kSignedGreaterThan: |
+ // Sign-extend registers on MIPS64 only 64-bit operand |
+ // branch and compare op. is available. |
+ __ sll(i.InputRegister(0), i.InputRegister(0), 0); |
+ if (instr->InputAt(1)->IsRegister()) { |
+ __ sll(i.InputRegister(1), i.InputRegister(1), 0); |
+ } |
+ break; |
+ case kUnsignedLessThan: |
+ case kUnsignedGreaterThanOrEqual: |
+ case kUnsignedLessThanOrEqual: |
+ case kUnsignedGreaterThan: |
+ // Zero-extend registers on MIPS64 only 64-bit operand |
+ // branch and compare op. is available. |
+ __ Dext(i.InputRegister(0), i.InputRegister(0), 0, 32); |
+ if (instr->InputAt(1)->IsRegister()) { |
+ __ Dext(i.InputRegister(1), i.InputRegister(1), 0, 32); |
+ } |
+ break; |
+ default: |
+ UNSUPPORTED_COND(kMips64Cmp, condition); |
+ break; |
+ } |
+ __ Branch(tlabel, cc, i.InputRegister(0), i.InputOperand(1)); |
+ |
+ if (!fallthru) __ Branch(flabel); // no fallthru to flabel. |
+ __ bind(&done); |
+ } else if (instr->arch_opcode() == kMips64CmpD) { |
// TODO(dusmil) optimize unordered checks to use less instructions |
// even if we have to unfold BranchF macro. |
Label* nan = flabel; |
@@ -515,7 +691,7 @@ void CodeGenerator::AssembleArchBranch(Instruction* instr, |
nan = tlabel; |
break; |
default: |
- UNSUPPORTED_COND(kMipsCmpD, condition); |
+ UNSUPPORTED_COND(kMips64CmpD, condition); |
break; |
} |
__ BranchF(tlabel, nan, cc, i.InputDoubleRegister(0), |
@@ -547,15 +723,13 @@ void CodeGenerator::AssembleArchBoolean(Instruction* instr, |
// MIPS does not have condition code flags, so compare and branch are |
// implemented differently than on the other arch's. The compare operations |
- // emit mips psuedo-instructions, which are checked and handled here. |
+ // emit mips pseudo-instructions, which are checked and handled here. |
// For materializations, we use delay slot to set the result true, and |
- // in the false case, where we fall thru the branch, we reset the result |
+ // in the false case, where we fall through the branch, we reset the result |
// false. |
- // TODO(plind): Add CHECK() to ensure that test/cmp and this branch were |
- // not separated by other instructions. |
- if (instr->arch_opcode() == kMipsTst) { |
+ if (instr->arch_opcode() == kMips64Tst) { |
switch (condition) { |
case kNotEqual: |
cc = ne; |
@@ -564,32 +738,48 @@ void CodeGenerator::AssembleArchBoolean(Instruction* instr, |
cc = eq; |
break; |
default: |
- UNSUPPORTED_COND(kMipsTst, condition); |
+ UNSUPPORTED_COND(kMips64Tst, condition); |
break; |
} |
__ And(at, i.InputRegister(0), i.InputOperand(1)); |
__ Branch(USE_DELAY_SLOT, &done, cc, at, Operand(zero_reg)); |
__ li(result, Operand(1)); // In delay slot. |
- |
- } else if (instr->arch_opcode() == kMipsAddOvf || |
- instr->arch_opcode() == kMipsSubOvf) { |
- // kMipsAddOvf, SubOvf emits negative result to 'kCompareReg' on overflow. |
+ } else if (instr->arch_opcode() == kMips64Tst32) { |
+ switch (condition) { |
+ case kNotEqual: |
+ cc = ne; |
+ break; |
+ case kEqual: |
+ cc = eq; |
+ break; |
+ default: |
+ UNSUPPORTED_COND(kMips64Tst, condition); |
+ break; |
+ } |
+ // Zero-extend register on MIPS64 only 64-bit operand |
+ // branch and compare op. is available. |
+ __ And(at, i.InputRegister(0), i.InputOperand(1)); |
+ __ Dext(at, at, 0, 32); |
+ __ Branch(USE_DELAY_SLOT, &done, cc, at, Operand(zero_reg)); |
+ __ li(result, Operand(1)); // In delay slot. |
+ } else if (instr->arch_opcode() == kMips64Dadd || |
+ instr->arch_opcode() == kMips64Dsub) { |
switch (condition) { |
case kOverflow: |
- cc = lt; |
+ cc = ne; |
break; |
case kNotOverflow: |
- cc = ge; |
+ cc = eq; |
break; |
default: |
- UNSUPPORTED_COND(kMipsAddOvf, condition); |
+ UNSUPPORTED_COND(kMips64DAdd, condition); |
break; |
} |
- __ Branch(USE_DELAY_SLOT, &done, cc, kCompareReg, Operand(zero_reg)); |
+ __ dsra32(kScratchReg, i.OutputRegister(), 0); |
+ __ sra(at, i.OutputRegister(), 31); |
+ __ Branch(USE_DELAY_SLOT, &done, cc, at, Operand(kScratchReg)); |
__ li(result, Operand(1)); // In delay slot. |
- |
- |
- } else if (instr->arch_opcode() == kMipsCmp) { |
+ } else if (instr->arch_opcode() == kMips64Cmp) { |
Register left = i.InputRegister(0); |
Operand right = i.InputOperand(1); |
switch (condition) { |
@@ -624,13 +814,82 @@ void CodeGenerator::AssembleArchBoolean(Instruction* instr, |
cc = hi; |
break; |
default: |
- UNSUPPORTED_COND(kMipsCmp, condition); |
+ UNSUPPORTED_COND(kMips64Cmp, condition); |
break; |
} |
__ Branch(USE_DELAY_SLOT, &done, cc, left, right); |
__ li(result, Operand(1)); // In delay slot. |
+ } else if (instr->arch_opcode() == kMips64Cmp32) { |
+ Register left = i.InputRegister(0); |
+ Operand right = i.InputOperand(1); |
+ switch (condition) { |
+ case kEqual: |
+ cc = eq; |
+ break; |
+ case kNotEqual: |
+ cc = ne; |
+ break; |
+ case kSignedLessThan: |
+ cc = lt; |
+ break; |
+ case kSignedGreaterThanOrEqual: |
+ cc = ge; |
+ break; |
+ case kSignedLessThanOrEqual: |
+ cc = le; |
+ break; |
+ case kSignedGreaterThan: |
+ cc = gt; |
+ break; |
+ case kUnsignedLessThan: |
+ cc = lo; |
+ break; |
+ case kUnsignedGreaterThanOrEqual: |
+ cc = hs; |
+ break; |
+ case kUnsignedLessThanOrEqual: |
+ cc = ls; |
+ break; |
+ case kUnsignedGreaterThan: |
+ cc = hi; |
+ break; |
+ default: |
+ UNSUPPORTED_COND(kMips64Cmp, condition); |
+ break; |
+ } |
- } else if (instr->arch_opcode() == kMipsCmpD) { |
+ switch (condition) { |
+ case kEqual: |
+ case kNotEqual: |
+ case kSignedLessThan: |
+ case kSignedGreaterThanOrEqual: |
+ case kSignedLessThanOrEqual: |
+ case kSignedGreaterThan: |
+ // Sign-extend registers on MIPS64 only 64-bit operand |
+ // branch and compare op. is available. |
+ __ sll(left, left, 0); |
+ if (instr->InputAt(1)->IsRegister()) { |
+ __ sll(i.InputRegister(1), i.InputRegister(1), 0); |
+ } |
+ break; |
+ case kUnsignedLessThan: |
+ case kUnsignedGreaterThanOrEqual: |
+ case kUnsignedLessThanOrEqual: |
+ case kUnsignedGreaterThan: |
+ // Zero-extend registers on MIPS64 only 64-bit operand |
+ // branch and compare op. is available. |
+ __ Dext(left, left, 0, 32); |
+ if (instr->InputAt(1)->IsRegister()) { |
+ __ Dext(i.InputRegister(1), i.InputRegister(1), 0, 32); |
+ } |
+ break; |
+ default: |
+ UNSUPPORTED_COND(kMips64Cmp32, condition); |
+ break; |
+ } |
+ __ Branch(USE_DELAY_SLOT, &done, cc, left, right); |
+ __ li(result, Operand(1)); // In delay slot. |
+ } else if (instr->arch_opcode() == kMips64CmpD) { |
FPURegister left = i.InputDoubleRegister(0); |
FPURegister right = i.InputDoubleRegister(1); |
// TODO(plind): Provide NaN-testing macro-asm function without need for |
@@ -667,7 +926,7 @@ void CodeGenerator::AssembleArchBoolean(Instruction* instr, |
cc = gt; |
break; |
default: |
- UNSUPPORTED_COND(kMipsCmp, condition); |
+ UNSUPPORTED_COND(kMips64Cmp, condition); |
break; |
} |
__ BranchF(USE_DELAY_SLOT, &done, NULL, cc, left, right); |
@@ -682,7 +941,7 @@ void CodeGenerator::AssembleArchBoolean(Instruction* instr, |
} |
// Fallthru case is the false materialization. |
__ bind(&false_value); |
- __ li(result, Operand(0)); |
+ __ li(result, Operand(static_cast<int64_t>(0))); |
__ bind(&done); |
} |
@@ -715,6 +974,24 @@ void CodeGenerator::AssemblePrologue() { |
__ Prologue(info->IsCodePreAgingActive()); |
frame()->SetRegisterSaveAreaSize( |
StandardFrameConstants::kFixedFrameSizeFromFp); |
+ |
+ // Sloppy mode functions and builtins need to replace the receiver with the |
+ // global proxy when called as functions (without an explicit receiver |
+ // object). |
+ // TODO(mstarzinger/verwaest): Should this be moved back into the CallIC? |
+ if (info->strict_mode() == SLOPPY && !info->is_native()) { |
+ Label ok; |
+ // +2 for return address and saved frame pointer. |
+ int receiver_slot = info->scope()->num_parameters() + 2; |
+ __ ld(a2, MemOperand(fp, receiver_slot * kPointerSize)); |
+ __ LoadRoot(at, Heap::kUndefinedValueRootIndex); |
+ __ Branch(&ok, ne, a2, Operand(at)); |
+ |
+ __ ld(a2, GlobalObjectOperand()); |
+ __ ld(a2, FieldMemOperand(a2, GlobalObject::kGlobalProxyOffset)); |
+ __ sd(a2, MemOperand(fp, receiver_slot * kPointerSize)); |
+ __ bind(&ok); |
+ } |
} else { |
__ StubPrologue(); |
frame()->SetRegisterSaveAreaSize( |
@@ -722,7 +999,7 @@ void CodeGenerator::AssemblePrologue() { |
} |
int stack_slots = frame()->GetSpillSlotCount(); |
if (stack_slots > 0) { |
- __ Subu(sp, sp, Operand(stack_slots * kPointerSize)); |
+ __ Dsubu(sp, sp, Operand(stack_slots * kPointerSize)); |
} |
} |
@@ -734,7 +1011,7 @@ void CodeGenerator::AssembleReturn() { |
// Remove this frame's spill slots first. |
int stack_slots = frame()->GetSpillSlotCount(); |
if (stack_slots > 0) { |
- __ Addu(sp, sp, Operand(stack_slots * kPointerSize)); |
+ __ Daddu(sp, sp, Operand(stack_slots * kPointerSize)); |
} |
// Restore registers. |
const RegList saves = descriptor->CalleeSavedRegisters(); |
@@ -767,17 +1044,17 @@ void CodeGenerator::AssembleMove(InstructionOperand* source, |
if (destination->IsRegister()) { |
__ mov(g.ToRegister(destination), src); |
} else { |
- __ sw(src, g.ToMemOperand(destination)); |
+ __ sd(src, g.ToMemOperand(destination)); |
} |
} else if (source->IsStackSlot()) { |
DCHECK(destination->IsRegister() || destination->IsStackSlot()); |
MemOperand src = g.ToMemOperand(source); |
if (destination->IsRegister()) { |
- __ lw(g.ToRegister(destination), src); |
+ __ ld(g.ToRegister(destination), src); |
} else { |
Register temp = kScratchReg; |
- __ lw(temp, src); |
- __ sw(temp, g.ToMemOperand(destination)); |
+ __ ld(temp, src); |
+ __ sd(temp, g.ToMemOperand(destination)); |
} |
} else if (source->IsConstant()) { |
Constant src = g.ToConstant(source); |
@@ -792,7 +1069,7 @@ void CodeGenerator::AssembleMove(InstructionOperand* source, |
__ li(dst, isolate()->factory()->NewNumber(src.ToFloat32(), TENURED)); |
break; |
case Constant::kInt64: |
- UNREACHABLE(); |
+ __ li(dst, Operand(src.ToInt64())); |
break; |
case Constant::kFloat64: |
__ li(dst, isolate()->factory()->NewNumber(src.ToFloat64(), TENURED)); |
@@ -804,7 +1081,7 @@ void CodeGenerator::AssembleMove(InstructionOperand* source, |
__ li(dst, src.ToHeapObject()); |
break; |
} |
- if (destination->IsStackSlot()) __ sw(dst, g.ToMemOperand(destination)); |
+ if (destination->IsStackSlot()) __ sd(dst, g.ToMemOperand(destination)); |
} else if (src.type() == Constant::kFloat32) { |
FPURegister dst = destination->IsDoubleRegister() |
? g.ToDoubleRegister(destination) |
@@ -868,19 +1145,19 @@ void CodeGenerator::AssembleSwap(InstructionOperand* source, |
DCHECK(destination->IsStackSlot()); |
MemOperand dst = g.ToMemOperand(destination); |
__ mov(temp, src); |
- __ lw(src, dst); |
- __ sw(temp, dst); |
+ __ ld(src, dst); |
+ __ sd(temp, dst); |
} |
} else if (source->IsStackSlot()) { |
DCHECK(destination->IsStackSlot()); |
Register temp_0 = kScratchReg; |
- Register temp_1 = kCompareReg; |
+ Register temp_1 = kScratchReg2; |
MemOperand src = g.ToMemOperand(source); |
MemOperand dst = g.ToMemOperand(destination); |
- __ lw(temp_0, src); |
- __ lw(temp_1, dst); |
- __ sw(temp_0, dst); |
- __ sw(temp_1, src); |
+ __ ld(temp_0, src); |
+ __ ld(temp_1, dst); |
+ __ sd(temp_0, dst); |
+ __ sd(temp_1, src); |
} else if (source->IsDoubleRegister()) { |
FPURegister temp = kScratchDoubleReg; |
FPURegister src = g.ToDoubleRegister(source); |