From 388813581e25e2ed5707b865f377cb5c25c69e6e Mon Sep 17 00:00:00 2001 From: "whesse@chromium.org" Date: Thu, 20 Oct 2011 10:26:45 +0000 Subject: [PATCH] Speed up comparison with a constant. Improve optimized code for comparison of an int32 against a constant, or comparison of two double constants. Contributed by m.m.capewell. Original codereview is http://codereview.chromium.org/7489045/. This cl is just created in order to commit the change. BUG= TEST= Review URL: http://codereview.chromium.org/8352040 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@9718 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/arm/lithium-arm.cc | 4 +-- src/arm/lithium-codegen-arm.cc | 54 +++++++++++++++++++++---------- src/arm/lithium-codegen-arm.h | 2 +- src/assembler.cc | 17 ++++++++++ src/assembler.h | 2 ++ src/ia32/lithium-codegen-ia32.cc | 50 ++++++++++++++++++----------- src/ia32/lithium-codegen-ia32.h | 2 +- src/ia32/lithium-ia32.cc | 13 ++++++-- src/x64/lithium-codegen-x64.cc | 68 +++++++++++++++++++++++++--------------- src/x64/lithium-codegen-x64.h | 2 +- src/x64/lithium-x64.cc | 13 ++++++-- 11 files changed, 156 insertions(+), 71 deletions(-) diff --git a/src/arm/lithium-arm.cc b/src/arm/lithium-arm.cc index c737822..5197842 100644 --- a/src/arm/lithium-arm.cc +++ b/src/arm/lithium-arm.cc @@ -1425,8 +1425,8 @@ LInstruction* LChunkBuilder::DoCompareIDAndBranch( if (r.IsInteger32()) { ASSERT(instr->left()->representation().IsInteger32()); ASSERT(instr->right()->representation().IsInteger32()); - LOperand* left = UseRegisterAtStart(instr->left()); - LOperand* right = UseRegisterAtStart(instr->right()); + LOperand* left = UseRegisterOrConstantAtStart(instr->left()); + LOperand* right = UseRegisterOrConstantAtStart(instr->right()); return new LCmpIDAndBranch(left, right); } else { ASSERT(r.IsDouble()); diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc index 47f297d..0265382 100644 --- a/src/arm/lithium-codegen-arm.cc +++ b/src/arm/lithium-codegen-arm.cc @@ -410,6 +410,12 @@ int LCodeGen::ToInteger32(LConstantOperand* op) const { } +double LCodeGen::ToDouble(LConstantOperand* op) const { + Handle value = chunk_->LookupLiteral(op); + return value->Number(); +} + + Operand LCodeGen::ToOperand(LOperand* op) { if (op->IsConstantOperand()) { LConstantOperand* const_op = LConstantOperand::cast(op); @@ -1705,30 +1711,44 @@ Condition LCodeGen::TokenToCondition(Token::Value op, bool is_unsigned) { } -void LCodeGen::EmitCmpI(LOperand* left, LOperand* right) { - __ cmp(ToRegister(left), ToRegister(right)); -} - - void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) { LOperand* left = instr->InputAt(0); LOperand* right = instr->InputAt(1); int false_block = chunk_->LookupDestination(instr->false_block_id()); int true_block = chunk_->LookupDestination(instr->true_block_id()); - - if (instr->is_double()) { - // Compare left and right as doubles and load the - // resulting flags into the normal status register. - __ VFPCompareAndSetFlags(ToDoubleRegister(left), ToDoubleRegister(right)); - // If a NaN is involved, i.e. the result is unordered (V set), - // jump to false block label. - __ b(vs, chunk_->GetAssemblyLabel(false_block)); + Condition cond = TokenToCondition(instr->op(), false); + + if (left->IsConstantOperand() && right->IsConstantOperand()) { + // We can statically evaluate the comparison. + double left_val = ToDouble(LConstantOperand::cast(left)); + double right_val = ToDouble(LConstantOperand::cast(right)); + int next_block = + EvalComparison(instr->op(), left_val, right_val) ? true_block + : false_block; + EmitGoto(next_block); } else { - EmitCmpI(left, right); + if (instr->is_double()) { + // Compare left and right operands as doubles and load the + // resulting flags into the normal status register. + __ VFPCompareAndSetFlags(ToDoubleRegister(left), ToDoubleRegister(right)); + // If a NaN is involved, i.e. the result is unordered (V set), + // jump to false block label. + __ b(vs, chunk_->GetAssemblyLabel(false_block)); + } else { + if (right->IsConstantOperand()) { + __ cmp(ToRegister(left), + Operand(ToInteger32(LConstantOperand::cast(right)))); + } else if (left->IsConstantOperand()) { + __ cmp(ToRegister(right), + Operand(ToInteger32(LConstantOperand::cast(left)))); + // We transposed the operands. Reverse the condition. + cond = ReverseCondition(cond); + } else { + __ cmp(ToRegister(left), ToRegister(right)); + } + } + EmitBranch(true_block, false_block, cond); } - - Condition cc = TokenToCondition(instr->op(), instr->is_double()); - EmitBranch(true_block, false_block, cc); } diff --git a/src/arm/lithium-codegen-arm.h b/src/arm/lithium-codegen-arm.h index cf6b0b2..d13e7d4 100644 --- a/src/arm/lithium-codegen-arm.h +++ b/src/arm/lithium-codegen-arm.h @@ -86,6 +86,7 @@ class LCodeGen BASE_EMBEDDED { SwVfpRegister flt_scratch, DoubleRegister dbl_scratch); int ToInteger32(LConstantOperand* op) const; + double ToDouble(LConstantOperand* op) const; Operand ToOperand(LOperand* op); MemOperand ToMemOperand(LOperand* op) const; // Returns a MemOperand pointing to the high word of a DoubleStackSlot. @@ -263,7 +264,6 @@ class LCodeGen BASE_EMBEDDED { static Condition TokenToCondition(Token::Value op, bool is_unsigned); void EmitGoto(int block); void EmitBranch(int left_block, int right_block, Condition cc); - void EmitCmpI(LOperand* left, LOperand* right); void EmitNumberUntagD(Register input, DoubleRegister result, bool deoptimize_on_undefined, diff --git a/src/assembler.cc b/src/assembler.cc index bda85e6..7e76ccf 100644 --- a/src/assembler.cc +++ b/src/assembler.cc @@ -1137,6 +1137,23 @@ static int native_compare_doubles(double y, double x) { } +bool EvalComparison(Token::Value op, double op1, double op2) { + ASSERT(Token::IsCompareOp(op)); + switch (op) { + case Token::EQ: + case Token::EQ_STRICT: return (op1 == op2); + case Token::NE: return (op1 != op2); + case Token::LT: return (op1 < op2); + case Token::GT: return (op1 > op2); + case Token::LTE: return (op1 <= op2); + case Token::GTE: return (op1 >= op2); + default: + UNREACHABLE(); + return false; + } +} + + ExternalReference ExternalReference::double_fp_operation( Token::Value operation, Isolate* isolate) { typedef double BinaryFPOperation(double x, double y); diff --git a/src/assembler.h b/src/assembler.h index e5661c9..aca91b3 100644 --- a/src/assembler.h +++ b/src/assembler.h @@ -847,6 +847,8 @@ static inline int NumberOfBitsSet(uint32_t x) { return num_bits_set; } +bool EvalComparison(Token::Value op, double op1, double op2); + // Computes pow(x, y) with the special cases in the spec for Math.pow. double power_double_int(double x, int y); double power_double_double(double x, double y); diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc index 3d519fb..5016778 100644 --- a/src/ia32/lithium-codegen-ia32.cc +++ b/src/ia32/lithium-codegen-ia32.cc @@ -355,6 +355,12 @@ int LCodeGen::ToInteger32(LConstantOperand* op) const { } +double LCodeGen::ToDouble(LConstantOperand* op) const { + Handle value = chunk_->LookupLiteral(op); + return value->Number(); +} + + Immediate LCodeGen::ToImmediate(LOperand* op) { LConstantOperand* const_op = LConstantOperand::cast(op); Handle literal = chunk_->LookupLiteral(const_op); @@ -1574,32 +1580,40 @@ Condition LCodeGen::TokenToCondition(Token::Value op, bool is_unsigned) { } -void LCodeGen::EmitCmpI(LOperand* left, LOperand* right) { - if (right->IsConstantOperand()) { - __ cmp(ToOperand(left), ToImmediate(right)); - } else { - __ cmp(ToRegister(left), ToOperand(right)); - } -} - - void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) { LOperand* left = instr->InputAt(0); LOperand* right = instr->InputAt(1); int false_block = chunk_->LookupDestination(instr->false_block_id()); int true_block = chunk_->LookupDestination(instr->true_block_id()); + Condition cc = TokenToCondition(instr->op(), instr->is_double()); - if (instr->is_double()) { - // Don't base result on EFLAGS when a NaN is involved. Instead - // jump to the false block. - __ ucomisd(ToDoubleRegister(left), ToDoubleRegister(right)); - __ j(parity_even, chunk_->GetAssemblyLabel(false_block)); + if (left->IsConstantOperand() && right->IsConstantOperand()) { + // We can statically evaluate the comparison. + double left_val = ToDouble(LConstantOperand::cast(left)); + double right_val = ToDouble(LConstantOperand::cast(right)); + int next_block = + EvalComparison(instr->op(), left_val, right_val) ? true_block + : false_block; + EmitGoto(next_block); } else { - EmitCmpI(left, right); + if (instr->is_double()) { + // Don't base result on EFLAGS when a NaN is involved. Instead + // jump to the false block. + __ ucomisd(ToDoubleRegister(left), ToDoubleRegister(right)); + __ j(parity_even, chunk_->GetAssemblyLabel(false_block)); + } else { + if (right->IsConstantOperand()) { + __ cmp(ToRegister(left), ToImmediate(right)); + } else if (left->IsConstantOperand()) { + __ cmp(ToOperand(right), ToImmediate(left)); + // We transposed the operands. Reverse the condition. + cc = ReverseCondition(cc); + } else { + __ cmp(ToRegister(left), ToOperand(right)); + } + } + EmitBranch(true_block, false_block, cc); } - - Condition cc = TokenToCondition(instr->op(), instr->is_double()); - EmitBranch(true_block, false_block, cc); } diff --git a/src/ia32/lithium-codegen-ia32.h b/src/ia32/lithium-codegen-ia32.h index 4de8ba6..d48359d 100644 --- a/src/ia32/lithium-codegen-ia32.h +++ b/src/ia32/lithium-codegen-ia32.h @@ -227,6 +227,7 @@ class LCodeGen BASE_EMBEDDED { Register ToRegister(int index) const; XMMRegister ToDoubleRegister(int index) const; int ToInteger32(LConstantOperand* op) const; + double ToDouble(LConstantOperand* op) const; Operand BuildFastArrayOperand(LOperand* elements_pointer, LOperand* key, ElementsKind elements_kind, @@ -261,7 +262,6 @@ class LCodeGen BASE_EMBEDDED { static Condition TokenToCondition(Token::Value op, bool is_unsigned); void EmitGoto(int block); void EmitBranch(int left_block, int right_block, Condition cc); - void EmitCmpI(LOperand* left, LOperand* right); void EmitNumberUntagD(Register input, XMMRegister result, bool deoptimize_on_undefined, diff --git a/src/ia32/lithium-ia32.cc b/src/ia32/lithium-ia32.cc index 6a0ed0d..626f899 100644 --- a/src/ia32/lithium-ia32.cc +++ b/src/ia32/lithium-ia32.cc @@ -1456,15 +1456,22 @@ LInstruction* LChunkBuilder::DoCompareIDAndBranch( if (r.IsInteger32()) { ASSERT(instr->left()->representation().IsInteger32()); ASSERT(instr->right()->representation().IsInteger32()); - LOperand* left = UseRegisterAtStart(instr->left()); + LOperand* left = UseRegisterOrConstantAtStart(instr->left()); LOperand* right = UseOrConstantAtStart(instr->right()); return new LCmpIDAndBranch(left, right); } else { ASSERT(r.IsDouble()); ASSERT(instr->left()->representation().IsDouble()); ASSERT(instr->right()->representation().IsDouble()); - LOperand* left = UseRegisterAtStart(instr->left()); - LOperand* right = UseRegisterAtStart(instr->right()); + LOperand* left; + LOperand* right; + if (instr->left()->IsConstant() && instr->right()->IsConstant()) { + left = UseRegisterOrConstantAtStart(instr->left()); + right = UseRegisterOrConstantAtStart(instr->right()); + } else { + left = UseRegisterAtStart(instr->left()); + right = UseRegisterAtStart(instr->right()); + } return new LCmpIDAndBranch(left, right); } } diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc index 5047c8e..5379cf9 100644 --- a/src/x64/lithium-codegen-x64.cc +++ b/src/x64/lithium-codegen-x64.cc @@ -374,6 +374,12 @@ int LCodeGen::ToInteger32(LConstantOperand* op) const { } +double LCodeGen::ToDouble(LConstantOperand* op) const { + Handle value = chunk_->LookupLiteral(op); + return value->Number(); +} + + Handle LCodeGen::ToHandle(LConstantOperand* op) const { Handle literal = chunk_->LookupLiteral(op); ASSERT(chunk_->LookupLiteralRepresentation(op).IsTagged()); @@ -1526,39 +1532,51 @@ inline Condition LCodeGen::TokenToCondition(Token::Value op, bool is_unsigned) { } -void LCodeGen::EmitCmpI(LOperand* left, LOperand* right) { - if (right->IsConstantOperand()) { - int32_t value = ToInteger32(LConstantOperand::cast(right)); - if (left->IsRegister()) { - __ cmpl(ToRegister(left), Immediate(value)); - } else { - __ cmpl(ToOperand(left), Immediate(value)); - } - } else if (right->IsRegister()) { - __ cmpl(ToRegister(left), ToRegister(right)); - } else { - __ cmpl(ToRegister(left), ToOperand(right)); - } -} - - void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) { LOperand* left = instr->InputAt(0); LOperand* right = instr->InputAt(1); int false_block = chunk_->LookupDestination(instr->false_block_id()); int true_block = chunk_->LookupDestination(instr->true_block_id()); + Condition cc = TokenToCondition(instr->op(), instr->is_double()); - if (instr->is_double()) { - // Don't base result on EFLAGS when a NaN is involved. Instead - // jump to the false block. - __ ucomisd(ToDoubleRegister(left), ToDoubleRegister(right)); - __ j(parity_even, chunk_->GetAssemblyLabel(false_block)); + if (left->IsConstantOperand() && right->IsConstantOperand()) { + // We can statically evaluate the comparison. + double left_val = ToDouble(LConstantOperand::cast(left)); + double right_val = ToDouble(LConstantOperand::cast(right)); + int next_block = + EvalComparison(instr->op(), left_val, right_val) ? true_block + : false_block; + EmitGoto(next_block); } else { - EmitCmpI(left, right); + if (instr->is_double()) { + // Don't base result on EFLAGS when a NaN is involved. Instead + // jump to the false block. + __ ucomisd(ToDoubleRegister(left), ToDoubleRegister(right)); + __ j(parity_even, chunk_->GetAssemblyLabel(false_block)); + } else { + int32_t value; + if (right->IsConstantOperand()) { + value = ToInteger32(LConstantOperand::cast(right)); + __ cmpl(ToRegister(left), Immediate(value)); + } else if (left->IsConstantOperand()) { + value = ToInteger32(LConstantOperand::cast(left)); + if (right->IsRegister()) { + __ cmpl(ToRegister(right), Immediate(value)); + } else { + __ cmpl(ToOperand(right), Immediate(value)); + } + // We transposed the operands. Reverse the condition. + cc = ReverseCondition(cc); + } else { + if (right->IsRegister()) { + __ cmpl(ToRegister(left), ToRegister(right)); + } else { + __ cmpl(ToRegister(left), ToOperand(right)); + } + } + } + EmitBranch(true_block, false_block, cc); } - - Condition cc = TokenToCondition(instr->op(), instr->is_double()); - EmitBranch(true_block, false_block, cc); } diff --git a/src/x64/lithium-codegen-x64.h b/src/x64/lithium-codegen-x64.h index 1b36b0b..a521c14 100644 --- a/src/x64/lithium-codegen-x64.h +++ b/src/x64/lithium-codegen-x64.h @@ -77,6 +77,7 @@ class LCodeGen BASE_EMBEDDED { XMMRegister ToDoubleRegister(LOperand* op) const; bool IsInteger32Constant(LConstantOperand* op) const; int ToInteger32(LConstantOperand* op) const; + double ToDouble(LConstantOperand* op) const; bool IsTaggedConstant(LConstantOperand* op) const; Handle ToHandle(LConstantOperand* op) const; Operand ToOperand(LOperand* op) const; @@ -250,7 +251,6 @@ class LCodeGen BASE_EMBEDDED { static Condition TokenToCondition(Token::Value op, bool is_unsigned); void EmitGoto(int block); void EmitBranch(int left_block, int right_block, Condition cc); - void EmitCmpI(LOperand* left, LOperand* right); void EmitNumberUntagD(Register input, XMMRegister result, bool deoptimize_on_undefined, diff --git a/src/x64/lithium-x64.cc b/src/x64/lithium-x64.cc index 0cc06e3..0af2ce4 100644 --- a/src/x64/lithium-x64.cc +++ b/src/x64/lithium-x64.cc @@ -1417,15 +1417,22 @@ LInstruction* LChunkBuilder::DoCompareIDAndBranch( if (r.IsInteger32()) { ASSERT(instr->left()->representation().IsInteger32()); ASSERT(instr->right()->representation().IsInteger32()); - LOperand* left = UseRegisterAtStart(instr->left()); + LOperand* left = UseRegisterOrConstantAtStart(instr->left()); LOperand* right = UseOrConstantAtStart(instr->right()); return new LCmpIDAndBranch(left, right); } else { ASSERT(r.IsDouble()); ASSERT(instr->left()->representation().IsDouble()); ASSERT(instr->right()->representation().IsDouble()); - LOperand* left = UseRegisterAtStart(instr->left()); - LOperand* right = UseRegisterAtStart(instr->right()); + LOperand* left; + LOperand* right; + if (instr->left()->IsConstant() && instr->right()->IsConstant()) { + left = UseRegisterOrConstantAtStart(instr->left()); + right = UseRegisterOrConstantAtStart(instr->right()); + } else { + left = UseRegisterAtStart(instr->left()); + right = UseRegisterAtStart(instr->right()); + } return new LCmpIDAndBranch(left, right); } } -- 2.7.4