aboutsummaryrefslogtreecommitdiff
path: root/deps/v8/src/compiler/x64/code-generator-x64.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/compiler/x64/code-generator-x64.cc')
-rw-r--r--deps/v8/src/compiler/x64/code-generator-x64.cc319
1 files changed, 261 insertions, 58 deletions
diff --git a/deps/v8/src/compiler/x64/code-generator-x64.cc b/deps/v8/src/compiler/x64/code-generator-x64.cc
index 3160734788..0f1e959adc 100644
--- a/deps/v8/src/compiler/x64/code-generator-x64.cc
+++ b/deps/v8/src/compiler/x64/code-generator-x64.cc
@@ -44,7 +44,8 @@ class X64OperandConverter : public InstructionOperandConverter {
Operand ToOperand(InstructionOperand* op, int extra = 0) {
DCHECK(op->IsStackSlot() || op->IsDoubleStackSlot());
// The linkage computes where all spill slots are located.
- FrameOffset offset = linkage()->GetFrameOffset(op->index(), frame(), extra);
+ FrameOffset offset = linkage()->GetFrameOffset(
+ AllocatedOperand::cast(op)->index(), frame(), extra);
return Operand(offset.from_stack_pointer() ? rsp : rbp, offset.offset());
}
@@ -142,37 +143,37 @@ bool HasImmediateInput(Instruction* instr, size_t index) {
}
-class OutOfLineLoadZero FINAL : public OutOfLineCode {
+class OutOfLineLoadZero final : public OutOfLineCode {
public:
OutOfLineLoadZero(CodeGenerator* gen, Register result)
: OutOfLineCode(gen), result_(result) {}
- void Generate() FINAL { __ xorl(result_, result_); }
+ void Generate() final { __ xorl(result_, result_); }
private:
Register const result_;
};
-class OutOfLineLoadNaN FINAL : public OutOfLineCode {
+class OutOfLineLoadNaN final : public OutOfLineCode {
public:
OutOfLineLoadNaN(CodeGenerator* gen, XMMRegister result)
: OutOfLineCode(gen), result_(result) {}
- void Generate() FINAL { __ pcmpeqd(result_, result_); }
+ void Generate() final { __ pcmpeqd(result_, result_); }
private:
XMMRegister const result_;
};
-class OutOfLineTruncateDoubleToI FINAL : public OutOfLineCode {
+class OutOfLineTruncateDoubleToI final : public OutOfLineCode {
public:
OutOfLineTruncateDoubleToI(CodeGenerator* gen, Register result,
XMMRegister input)
: OutOfLineCode(gen), result_(result), input_(input) {}
- void Generate() FINAL {
+ void Generate() final {
__ subp(rsp, Immediate(kDoubleSize));
__ movsd(MemOperand(rsp, 0), input_);
__ SlowTruncateToI(result_, rsp, 0);
@@ -265,7 +266,7 @@ class OutOfLineTruncateDoubleToI FINAL : public OutOfLineCode {
} while (0)
-#define ASSEMBLE_DOUBLE_BINOP(asm_instr) \
+#define ASSEMBLE_SSE_BINOP(asm_instr) \
do { \
if (instr->InputAt(1)->IsDoubleRegister()) { \
__ asm_instr(i.InputDoubleRegister(0), i.InputDoubleRegister(1)); \
@@ -275,7 +276,17 @@ class OutOfLineTruncateDoubleToI FINAL : public OutOfLineCode {
} while (0)
-#define ASSEMBLE_AVX_DOUBLE_BINOP(asm_instr) \
+#define ASSEMBLE_SSE_UNOP(asm_instr) \
+ do { \
+ if (instr->InputAt(0)->IsDoubleRegister()) { \
+ __ asm_instr(i.OutputDoubleRegister(), i.InputDoubleRegister(0)); \
+ } else { \
+ __ asm_instr(i.OutputDoubleRegister(), i.InputOperand(0)); \
+ } \
+ } while (0)
+
+
+#define ASSEMBLE_AVX_BINOP(asm_instr) \
do { \
CpuFeatureScope avx_scope(masm(), AVX); \
if (instr->InputAt(1)->IsDoubleRegister()) { \
@@ -304,7 +315,7 @@ class OutOfLineTruncateDoubleToI FINAL : public OutOfLineCode {
auto length = i.InputInt32(3); \
DCHECK_LE(index2, length); \
__ cmpq(index1, Immediate(length - index2)); \
- class OutOfLineLoadFloat FINAL : public OutOfLineCode { \
+ class OutOfLineLoadFloat final : public OutOfLineCode { \
public: \
OutOfLineLoadFloat(CodeGenerator* gen, XMMRegister result, \
Register buffer, Register index1, int32_t index2, \
@@ -316,7 +327,7 @@ class OutOfLineTruncateDoubleToI FINAL : public OutOfLineCode {
index2_(index2), \
length_(length) {} \
\
- void Generate() FINAL { \
+ void Generate() final { \
__ leal(kScratchRegister, Operand(index1_, index2_)); \
__ pcmpeqd(result_, result_); \
__ cmpl(kScratchRegister, Immediate(length_)); \
@@ -357,7 +368,7 @@ class OutOfLineTruncateDoubleToI FINAL : public OutOfLineCode {
auto length = i.InputInt32(3); \
DCHECK_LE(index2, length); \
__ cmpq(index1, Immediate(length - index2)); \
- class OutOfLineLoadInteger FINAL : public OutOfLineCode { \
+ class OutOfLineLoadInteger final : public OutOfLineCode { \
public: \
OutOfLineLoadInteger(CodeGenerator* gen, Register result, \
Register buffer, Register index1, int32_t index2, \
@@ -369,7 +380,7 @@ class OutOfLineTruncateDoubleToI FINAL : public OutOfLineCode {
index2_(index2), \
length_(length) {} \
\
- void Generate() FINAL { \
+ void Generate() final { \
Label oob; \
__ leal(kScratchRegister, Operand(index1_, index2_)); \
__ cmpl(kScratchRegister, Immediate(length_)); \
@@ -415,7 +426,7 @@ class OutOfLineTruncateDoubleToI FINAL : public OutOfLineCode {
auto length = i.InputInt32(3); \
DCHECK_LE(index2, length); \
__ cmpq(index1, Immediate(length - index2)); \
- class OutOfLineStoreFloat FINAL : public OutOfLineCode { \
+ class OutOfLineStoreFloat final : public OutOfLineCode { \
public: \
OutOfLineStoreFloat(CodeGenerator* gen, Register buffer, \
Register index1, int32_t index2, int32_t length, \
@@ -427,7 +438,7 @@ class OutOfLineTruncateDoubleToI FINAL : public OutOfLineCode {
length_(length), \
value_(value) {} \
\
- void Generate() FINAL { \
+ void Generate() final { \
__ leal(kScratchRegister, Operand(index1_, index2_)); \
__ cmpl(kScratchRegister, Immediate(length_)); \
__ j(above_equal, exit()); \
@@ -468,7 +479,7 @@ class OutOfLineTruncateDoubleToI FINAL : public OutOfLineCode {
auto length = i.InputInt32(3); \
DCHECK_LE(index2, length); \
__ cmpq(index1, Immediate(length - index2)); \
- class OutOfLineStoreInteger FINAL : public OutOfLineCode { \
+ class OutOfLineStoreInteger final : public OutOfLineCode { \
public: \
OutOfLineStoreInteger(CodeGenerator* gen, Register buffer, \
Register index1, int32_t index2, int32_t length, \
@@ -480,7 +491,7 @@ class OutOfLineTruncateDoubleToI FINAL : public OutOfLineCode {
length_(length), \
value_(value) {} \
\
- void Generate() FINAL { \
+ void Generate() final { \
__ leal(kScratchRegister, Operand(index1_, index2_)); \
__ cmpl(kScratchRegister, Immediate(length_)); \
__ j(above_equal, exit()); \
@@ -516,6 +527,23 @@ class OutOfLineTruncateDoubleToI FINAL : public OutOfLineCode {
} while (false)
+void CodeGenerator::AssembleDeconstructActivationRecord() {
+ CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
+ int stack_slots = frame()->GetSpillSlotCount();
+ if (descriptor->IsJSFunctionCall() || stack_slots > 0) {
+ __ movq(rsp, rbp);
+ __ popq(rbp);
+ int32_t bytes_to_pop =
+ descriptor->IsJSFunctionCall()
+ ? static_cast<int32_t>(descriptor->JSParameterCount() *
+ kPointerSize)
+ : 0;
+ __ popq(Operand(rsp, bytes_to_pop));
+ __ addq(rsp, Immediate(bytes_to_pop));
+ }
+}
+
+
// Assembles an instruction after register allocation, producing machine code.
void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
X64OperandConverter i(this, instr);
@@ -534,6 +562,18 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
RecordCallPosition(instr);
break;
}
+ case kArchTailCallCodeObject: {
+ AssembleDeconstructActivationRecord();
+ if (HasImmediateInput(instr, 0)) {
+ Handle<Code> code = Handle<Code>::cast(i.InputHeapObject(0));
+ __ jmp(code, RelocInfo::CODE_TARGET);
+ } else {
+ Register reg = i.InputRegister(0);
+ int entry = Code::kHeaderSize - kHeapObjectTag;
+ __ jmp(Operand(reg, entry));
+ }
+ break;
+ }
case kArchCallJSFunction: {
EnsureSpaceForLazyDeopt();
Register func = i.InputRegister(0);
@@ -546,6 +586,17 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
RecordCallPosition(instr);
break;
}
+ case kArchTailCallJSFunction: {
+ Register func = i.InputRegister(0);
+ if (FLAG_debug_code) {
+ // Check the function's context matches the context argument.
+ __ cmpp(rsi, FieldOperand(func, JSFunction::kContextOffset));
+ __ Assert(equal, kWrongFunctionContext);
+ }
+ AssembleDeconstructActivationRecord();
+ __ jmp(FieldOperand(func, JSFunction::kCodeEntryOffset));
+ break;
+ }
case kArchJmp:
AssembleArchJump(i.InputRpo(0));
break;
@@ -701,20 +752,67 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
__ Lzcntl(i.OutputRegister(), i.InputOperand(0));
}
break;
+ case kSSEFloat32Cmp:
+ ASSEMBLE_SSE_BINOP(ucomiss);
+ break;
+ case kSSEFloat32Add:
+ ASSEMBLE_SSE_BINOP(addss);
+ break;
+ case kSSEFloat32Sub:
+ ASSEMBLE_SSE_BINOP(subss);
+ break;
+ case kSSEFloat32Mul:
+ ASSEMBLE_SSE_BINOP(mulss);
+ break;
+ case kSSEFloat32Div:
+ ASSEMBLE_SSE_BINOP(divss);
+ // Don't delete this mov. It may improve performance on some CPUs,
+ // when there is a (v)mulss depending on the result.
+ __ movaps(i.OutputDoubleRegister(), i.OutputDoubleRegister());
+ break;
+ case kSSEFloat32Abs: {
+ // TODO(bmeurer): Use RIP relative 128-bit constants.
+ __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
+ __ psrlq(kScratchDoubleReg, 33);
+ __ andps(i.OutputDoubleRegister(), kScratchDoubleReg);
+ break;
+ }
+ case kSSEFloat32Neg: {
+ // TODO(bmeurer): Use RIP relative 128-bit constants.
+ __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
+ __ psllq(kScratchDoubleReg, 31);
+ __ xorps(i.OutputDoubleRegister(), kScratchDoubleReg);
+ break;
+ }
+ case kSSEFloat32Sqrt:
+ ASSEMBLE_SSE_UNOP(sqrtss);
+ break;
+ case kSSEFloat32Max:
+ ASSEMBLE_SSE_BINOP(maxss);
+ break;
+ case kSSEFloat32Min:
+ ASSEMBLE_SSE_BINOP(minss);
+ break;
+ case kSSEFloat32ToFloat64:
+ ASSEMBLE_SSE_UNOP(cvtss2sd);
+ break;
case kSSEFloat64Cmp:
- ASSEMBLE_DOUBLE_BINOP(ucomisd);
+ ASSEMBLE_SSE_BINOP(ucomisd);
break;
case kSSEFloat64Add:
- ASSEMBLE_DOUBLE_BINOP(addsd);
+ ASSEMBLE_SSE_BINOP(addsd);
break;
case kSSEFloat64Sub:
- ASSEMBLE_DOUBLE_BINOP(subsd);
+ ASSEMBLE_SSE_BINOP(subsd);
break;
case kSSEFloat64Mul:
- ASSEMBLE_DOUBLE_BINOP(mulsd);
+ ASSEMBLE_SSE_BINOP(mulsd);
break;
case kSSEFloat64Div:
- ASSEMBLE_DOUBLE_BINOP(divsd);
+ ASSEMBLE_SSE_BINOP(divsd);
+ // Don't delete this mov. It may improve performance on some CPUs,
+ // when there is a (v)mulsd depending on the result.
+ __ movaps(i.OutputDoubleRegister(), i.OutputDoubleRegister());
break;
case kSSEFloat64Mod: {
__ subq(rsp, Immediate(kDoubleSize));
@@ -749,17 +847,27 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
break;
}
case kSSEFloat64Max:
- ASSEMBLE_DOUBLE_BINOP(maxsd);
+ ASSEMBLE_SSE_BINOP(maxsd);
break;
case kSSEFloat64Min:
- ASSEMBLE_DOUBLE_BINOP(minsd);
+ ASSEMBLE_SSE_BINOP(minsd);
break;
+ case kSSEFloat64Abs: {
+ // TODO(bmeurer): Use RIP relative 128-bit constants.
+ __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
+ __ psrlq(kScratchDoubleReg, 1);
+ __ andpd(i.OutputDoubleRegister(), kScratchDoubleReg);
+ break;
+ }
+ case kSSEFloat64Neg: {
+ // TODO(bmeurer): Use RIP relative 128-bit constants.
+ __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
+ __ psllq(kScratchDoubleReg, 63);
+ __ xorpd(i.OutputDoubleRegister(), kScratchDoubleReg);
+ break;
+ }
case kSSEFloat64Sqrt:
- if (instr->InputAt(0)->IsDoubleRegister()) {
- __ sqrtsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
- } else {
- __ sqrtsd(i.OutputDoubleRegister(), i.InputOperand(0));
- }
+ ASSEMBLE_SSE_UNOP(sqrtsd);
break;
case kSSEFloat64Round: {
CpuFeatureScope sse_scope(masm(), SSE4_1);
@@ -768,19 +876,8 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
__ roundsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0), mode);
break;
}
- case kSSECvtss2sd:
- if (instr->InputAt(0)->IsDoubleRegister()) {
- __ cvtss2sd(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
- } else {
- __ cvtss2sd(i.OutputDoubleRegister(), i.InputOperand(0));
- }
- break;
- case kSSECvtsd2ss:
- if (instr->InputAt(0)->IsDoubleRegister()) {
- __ cvtsd2ss(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
- } else {
- __ cvtsd2ss(i.OutputDoubleRegister(), i.InputOperand(0));
- }
+ case kSSEFloat64ToFloat32:
+ ASSEMBLE_SSE_UNOP(cvtsd2ss);
break;
case kSSEFloat64ToInt32:
if (instr->InputAt(0)->IsDoubleRegister()) {
@@ -848,24 +945,122 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
__ movd(i.OutputDoubleRegister(), i.InputOperand(0));
}
break;
+ case kAVXFloat32Cmp: {
+ CpuFeatureScope avx_scope(masm(), AVX);
+ if (instr->InputAt(1)->IsDoubleRegister()) {
+ __ vucomiss(i.InputDoubleRegister(0), i.InputDoubleRegister(1));
+ } else {
+ __ vucomiss(i.InputDoubleRegister(0), i.InputOperand(1));
+ }
+ break;
+ }
+ case kAVXFloat32Add:
+ ASSEMBLE_AVX_BINOP(vaddss);
+ break;
+ case kAVXFloat32Sub:
+ ASSEMBLE_AVX_BINOP(vsubss);
+ break;
+ case kAVXFloat32Mul:
+ ASSEMBLE_AVX_BINOP(vmulss);
+ break;
+ case kAVXFloat32Div:
+ ASSEMBLE_AVX_BINOP(vdivss);
+ // Don't delete this mov. It may improve performance on some CPUs,
+ // when there is a (v)mulss depending on the result.
+ __ movaps(i.OutputDoubleRegister(), i.OutputDoubleRegister());
+ break;
+ case kAVXFloat32Max:
+ ASSEMBLE_AVX_BINOP(vmaxss);
+ break;
+ case kAVXFloat32Min:
+ ASSEMBLE_AVX_BINOP(vminss);
+ break;
+ case kAVXFloat64Cmp: {
+ CpuFeatureScope avx_scope(masm(), AVX);
+ if (instr->InputAt(1)->IsDoubleRegister()) {
+ __ vucomisd(i.InputDoubleRegister(0), i.InputDoubleRegister(1));
+ } else {
+ __ vucomisd(i.InputDoubleRegister(0), i.InputOperand(1));
+ }
+ break;
+ }
case kAVXFloat64Add:
- ASSEMBLE_AVX_DOUBLE_BINOP(vaddsd);
+ ASSEMBLE_AVX_BINOP(vaddsd);
break;
case kAVXFloat64Sub:
- ASSEMBLE_AVX_DOUBLE_BINOP(vsubsd);
+ ASSEMBLE_AVX_BINOP(vsubsd);
break;
case kAVXFloat64Mul:
- ASSEMBLE_AVX_DOUBLE_BINOP(vmulsd);
+ ASSEMBLE_AVX_BINOP(vmulsd);
break;
case kAVXFloat64Div:
- ASSEMBLE_AVX_DOUBLE_BINOP(vdivsd);
+ ASSEMBLE_AVX_BINOP(vdivsd);
+ // Don't delete this mov. It may improve performance on some CPUs,
+ // when there is a (v)mulsd depending on the result.
+ __ movaps(i.OutputDoubleRegister(), i.OutputDoubleRegister());
break;
case kAVXFloat64Max:
- ASSEMBLE_AVX_DOUBLE_BINOP(vmaxsd);
+ ASSEMBLE_AVX_BINOP(vmaxsd);
break;
case kAVXFloat64Min:
- ASSEMBLE_AVX_DOUBLE_BINOP(vminsd);
+ ASSEMBLE_AVX_BINOP(vminsd);
break;
+ case kAVXFloat32Abs: {
+ // TODO(bmeurer): Use RIP relative 128-bit constants.
+ __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
+ __ psrlq(kScratchDoubleReg, 33);
+ CpuFeatureScope avx_scope(masm(), AVX);
+ if (instr->InputAt(0)->IsDoubleRegister()) {
+ __ vandps(i.OutputDoubleRegister(), kScratchDoubleReg,
+ i.InputDoubleRegister(0));
+ } else {
+ __ vandps(i.OutputDoubleRegister(), kScratchDoubleReg,
+ i.InputOperand(0));
+ }
+ break;
+ }
+ case kAVXFloat32Neg: {
+ // TODO(bmeurer): Use RIP relative 128-bit constants.
+ __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
+ __ psllq(kScratchDoubleReg, 31);
+ CpuFeatureScope avx_scope(masm(), AVX);
+ if (instr->InputAt(0)->IsDoubleRegister()) {
+ __ vxorps(i.OutputDoubleRegister(), kScratchDoubleReg,
+ i.InputDoubleRegister(0));
+ } else {
+ __ vxorps(i.OutputDoubleRegister(), kScratchDoubleReg,
+ i.InputOperand(0));
+ }
+ break;
+ }
+ case kAVXFloat64Abs: {
+ // TODO(bmeurer): Use RIP relative 128-bit constants.
+ __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
+ __ psrlq(kScratchDoubleReg, 1);
+ CpuFeatureScope avx_scope(masm(), AVX);
+ if (instr->InputAt(0)->IsDoubleRegister()) {
+ __ vandpd(i.OutputDoubleRegister(), kScratchDoubleReg,
+ i.InputDoubleRegister(0));
+ } else {
+ __ vandpd(i.OutputDoubleRegister(), kScratchDoubleReg,
+ i.InputOperand(0));
+ }
+ break;
+ }
+ case kAVXFloat64Neg: {
+ // TODO(bmeurer): Use RIP relative 128-bit constants.
+ __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
+ __ psllq(kScratchDoubleReg, 63);
+ CpuFeatureScope avx_scope(masm(), AVX);
+ if (instr->InputAt(0)->IsDoubleRegister()) {
+ __ vxorpd(i.OutputDoubleRegister(), kScratchDoubleReg,
+ i.InputDoubleRegister(0));
+ } else {
+ __ vxorpd(i.OutputDoubleRegister(), kScratchDoubleReg,
+ i.InputOperand(0));
+ }
+ break;
+ }
case kX64Movsxbl:
ASSEMBLE_MOVX(movsxbl);
__ AssertZeroExtended(i.OutputRegister());
@@ -1014,13 +1209,20 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
break;
case kX64StoreWriteBarrier: {
Register object = i.InputRegister(0);
- Register index = i.InputRegister(1);
Register value = i.InputRegister(2);
- __ movq(Operand(object, index, times_1, 0), value);
- __ leaq(index, Operand(object, index, times_1, 0));
SaveFPRegsMode mode =
frame()->DidAllocateDoubleRegisters() ? kSaveFPRegs : kDontSaveFPRegs;
- __ RecordWrite(object, index, value, mode);
+ if (HasImmediateInput(instr, 1)) {
+ int index = i.InputInt32(1);
+ Register scratch = i.TempRegister(1);
+ __ movq(Operand(object, index), value);
+ __ RecordWriteContextSlot(object, index, value, scratch, mode);
+ } else {
+ Register index = i.InputRegister(1);
+ __ movq(Operand(object, index, times_1, 0), value);
+ __ leaq(index, Operand(object, index, times_1, 0));
+ __ RecordWrite(object, index, value, mode);
+ }
break;
}
case kCheckedLoadInt8:
@@ -1308,7 +1510,7 @@ void CodeGenerator::AssembleReturn() {
int pop_count = descriptor->IsJSFunctionCall()
? static_cast<int>(descriptor->JSParameterCount())
: 0;
- __ ret(pop_count * kPointerSize);
+ __ Ret(pop_count * kPointerSize, rbx);
} else {
__ ret(0);
}
@@ -1369,11 +1571,12 @@ void CodeGenerator::AssembleMove(InstructionOperand* source,
break;
case Constant::kHeapObject: {
Handle<HeapObject> src_object = src.ToHeapObject();
- if (info()->IsOptimizing() &&
- src_object.is_identical_to(info()->context())) {
- // Loading the context from the frame is way cheaper than
- // materializing the actual context heap object address.
- __ movp(dst, Operand(rbp, StandardFrameConstants::kContextOffset));
+ Heap::RootListIndex index;
+ int offset;
+ if (IsMaterializableFromFrame(src_object, &offset)) {
+ __ movp(dst, Operand(rbp, offset));
+ } else if (IsMaterializableFromRoot(src_object, &index)) {
+ __ LoadRoot(dst, index);
} else {
__ Move(dst, src_object);
}