Commit 7bd88e82 authored by whesse@chromium.org's avatar whesse@chromium.org

X64: Optimize MOD operator by a constant power of 2.

Review URL: http://codereview.chromium.org/164054

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@2634 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 6a19a8f5
...@@ -97,6 +97,78 @@ CodeGenState::~CodeGenState() { ...@@ -97,6 +97,78 @@ CodeGenState::~CodeGenState() {
} }
// -------------------------------------------------------------------------
// Deferred code objects
//
// These subclasses of DeferredCode add pieces of code to the end of generated
// code. They are branched to from the generated code, and
// keep some slower code out of the main body of the generated code.
// Many of them call a code stub or a runtime function.
class DeferredInlineSmiAdd: public DeferredCode {
public:
DeferredInlineSmiAdd(Register dst,
Smi* value,
OverwriteMode overwrite_mode)
: dst_(dst), value_(value), overwrite_mode_(overwrite_mode) {
set_comment("[ DeferredInlineSmiAdd");
}
virtual void Generate();
private:
Register dst_;
Smi* value_;
OverwriteMode overwrite_mode_;
};
class DeferredInlineSmiSub: public DeferredCode {
public:
DeferredInlineSmiSub(Register dst,
Smi* value,
OverwriteMode overwrite_mode)
: dst_(dst), value_(value), overwrite_mode_(overwrite_mode) {
set_comment("[ DeferredInlineSmiSub");
}
virtual void Generate();
private:
Register dst_;
Smi* value_;
OverwriteMode overwrite_mode_;
};
// Call the appropriate binary operation stub to compute src op value
// and leave the result in dst.
class DeferredInlineSmiOperation: public DeferredCode {
public:
DeferredInlineSmiOperation(Token::Value op,
Register dst,
Register src,
Smi* value,
OverwriteMode overwrite_mode)
: op_(op),
dst_(dst),
src_(src),
value_(value),
overwrite_mode_(overwrite_mode) {
set_comment("[ DeferredInlineSmiOperation");
}
virtual void Generate();
private:
Token::Value op_;
Register dst_;
Register src_;
Smi* value_;
OverwriteMode overwrite_mode_;
};
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// CodeGenerator implementation. // CodeGenerator implementation.
...@@ -4771,29 +4843,6 @@ void DeferredReferenceGetNamedValue::Generate() { ...@@ -4771,29 +4843,6 @@ void DeferredReferenceGetNamedValue::Generate() {
} }
// The result of src + value is in dst. It either overflowed or was not
// smi tagged. Undo the speculative addition and call the appropriate
// specialized stub for add. The result is left in dst.
class DeferredInlineSmiAdd: public DeferredCode {
public:
DeferredInlineSmiAdd(Register dst,
Smi* value,
OverwriteMode overwrite_mode)
: dst_(dst), value_(value), overwrite_mode_(overwrite_mode) {
set_comment("[ DeferredInlineSmiAdd");
}
virtual void Generate();
private:
Register dst_;
Smi* value_;
OverwriteMode overwrite_mode_;
};
void DeferredInlineSmiAdd::Generate() { void DeferredInlineSmiAdd::Generate() {
__ push(dst_); __ push(dst_);
__ push(Immediate(value_)); __ push(Immediate(value_));
...@@ -4825,7 +4874,7 @@ class DeferredInlineSmiAddReversed: public DeferredCode { ...@@ -4825,7 +4874,7 @@ class DeferredInlineSmiAddReversed: public DeferredCode {
void DeferredInlineSmiAddReversed::Generate() { void DeferredInlineSmiAddReversed::Generate() {
__ push(Immediate(value_)); __ push(Immediate(value_)); // Note: sign extended.
__ push(dst_); __ push(dst_);
GenericBinaryOpStub igostub(Token::ADD, overwrite_mode_, SMI_CODE_INLINED); GenericBinaryOpStub igostub(Token::ADD, overwrite_mode_, SMI_CODE_INLINED);
__ CallStub(&igostub); __ CallStub(&igostub);
...@@ -4833,37 +4882,28 @@ void DeferredInlineSmiAddReversed::Generate() { ...@@ -4833,37 +4882,28 @@ void DeferredInlineSmiAddReversed::Generate() {
} }
// The result of src - value is in dst. It either overflowed or was not
// smi tagged. Undo the speculative subtraction and call the
// appropriate specialized stub for subtract. The result is left in
// dst.
class DeferredInlineSmiSub: public DeferredCode {
public:
DeferredInlineSmiSub(Register dst,
Smi* value,
OverwriteMode overwrite_mode)
: dst_(dst), value_(value), overwrite_mode_(overwrite_mode) {
set_comment("[ DeferredInlineSmiSub");
}
virtual void Generate();
private:
Register dst_;
Smi* value_;
OverwriteMode overwrite_mode_;
};
void DeferredInlineSmiSub::Generate() { void DeferredInlineSmiSub::Generate() {
__ push(dst_); __ push(dst_);
__ push(Immediate(value_)); __ push(Immediate(value_)); // Note: sign extended.
GenericBinaryOpStub igostub(Token::SUB, overwrite_mode_, SMI_CODE_INLINED); GenericBinaryOpStub igostub(Token::SUB, overwrite_mode_, SMI_CODE_INLINED);
__ CallStub(&igostub); __ CallStub(&igostub);
if (!dst_.is(rax)) __ movq(dst_, rax); if (!dst_.is(rax)) __ movq(dst_, rax);
} }
void DeferredInlineSmiOperation::Generate() {
__ push(src_);
__ push(Immediate(value_)); // Note: sign extended.
// For mod we don't generate all the Smi code inline.
GenericBinaryOpStub stub(
op_,
overwrite_mode_,
(op_ == Token::MOD) ? SMI_CODE_IN_STUB : SMI_CODE_INLINED);
__ CallStub(&stub);
if (!dst_.is(rax)) __ movq(dst_, rax);
}
void CodeGenerator::ConstantSmiBinaryOperation(Token::Value op, void CodeGenerator::ConstantSmiBinaryOperation(Token::Value op,
Result* operand, Result* operand,
Handle<Object> value, Handle<Object> value,
...@@ -4892,6 +4932,7 @@ void CodeGenerator::ConstantSmiBinaryOperation(Token::Value op, ...@@ -4892,6 +4932,7 @@ void CodeGenerator::ConstantSmiBinaryOperation(Token::Value op,
// Get the literal value. // Get the literal value.
Smi* smi_value = Smi::cast(*value); Smi* smi_value = Smi::cast(*value);
int int_value = smi_value->value();
switch (op) { switch (op) {
case Token::ADD: { case Token::ADD: {
...@@ -4921,6 +4962,36 @@ void CodeGenerator::ConstantSmiBinaryOperation(Token::Value op, ...@@ -4921,6 +4962,36 @@ void CodeGenerator::ConstantSmiBinaryOperation(Token::Value op,
break; break;
} }
// TODO(X64): Move other implementations from ia32 to here. // TODO(X64): Move other implementations from ia32 to here.
// Generate inline code for mod of powers of 2 and negative powers of 2.
case Token::MOD:
if (!reversed &&
int_value != 0 &&
(IsPowerOf2(int_value) || IsPowerOf2(-int_value))) {
operand->ToRegister();
frame_->Spill(operand->reg());
DeferredCode* deferred = new DeferredInlineSmiOperation(op,
operand->reg(),
operand->reg(),
smi_value,
overwrite_mode);
// Check for negative or non-Smi left hand side.
__ testl(operand->reg(),
Immediate(static_cast<int32_t>(kSmiTagMask | 0x80000000)));
deferred->Branch(not_zero);
if (int_value < 0) int_value = -int_value;
if (int_value == 1) {
__ movl(operand->reg(), Immediate(Smi::FromInt(0)));
} else {
__ and_(operand->reg(), Immediate((int_value << kSmiTagSize) - 1));
}
deferred->BindExit();
frame_->Push(operand);
break; // This break only applies if we generated code for MOD.
}
// Fall through if we did not find a power of 2 on the right hand side!
// The next case must be the default.
default: { default: {
Result constant_operand(value); Result constant_operand(value);
if (reversed) { if (reversed) {
......
...@@ -601,6 +601,15 @@ class CodeGenerator: public AstVisitor { ...@@ -601,6 +601,15 @@ class CodeGenerator: public AstVisitor {
}; };
// -------------------------------------------------------------------------
// Code stubs
//
// These independent code objects are created once, and used multiple
// times by generated code to perform common tasks, often the slow
// case of a JavaScript operation. They are all subclasses of CodeStub,
// which is declared in code-stubs.h.
// Flag that indicates whether or not the code that handles smi arguments // Flag that indicates whether or not the code that handles smi arguments
// should be placed in the stub, inlined, or omitted entirely. // should be placed in the stub, inlined, or omitted entirely.
enum GenericBinaryFlags { enum GenericBinaryFlags {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment