[stubs] Introduce code stubs for bitwise binary operations.
Add BitwiseAndStub, BitwiseOrStub and BitwiseXorStub, and hook them up with Ignition and TurboFan. R=epertoso@chromium.org Review URL: https://codereview.chromium.org/1825793002 Cr-Commit-Position: refs/heads/master@{#35029}
This commit is contained in:
parent
d30d861a0c
commit
db18219e4b
@ -218,6 +218,24 @@ Callable CodeFactory::Subtract(Isolate* isolate) {
|
||||
return Callable(stub.GetCode(), stub.GetCallInterfaceDescriptor());
|
||||
}
|
||||
|
||||
// static
|
||||
Callable CodeFactory::BitwiseAnd(Isolate* isolate) {
|
||||
BitwiseAndStub stub(isolate);
|
||||
return Callable(stub.GetCode(), stub.GetCallInterfaceDescriptor());
|
||||
}
|
||||
|
||||
// static
|
||||
Callable CodeFactory::BitwiseOr(Isolate* isolate) {
|
||||
BitwiseOrStub stub(isolate);
|
||||
return Callable(stub.GetCode(), stub.GetCallInterfaceDescriptor());
|
||||
}
|
||||
|
||||
// static
|
||||
Callable CodeFactory::BitwiseXor(Isolate* isolate) {
|
||||
BitwiseXorStub stub(isolate);
|
||||
return Callable(stub.GetCode(), stub.GetCallInterfaceDescriptor());
|
||||
}
|
||||
|
||||
// static
|
||||
Callable CodeFactory::LessThan(Isolate* isolate) {
|
||||
LessThanStub stub(isolate);
|
||||
|
@ -81,6 +81,9 @@ class CodeFactory final {
|
||||
|
||||
static Callable Add(Isolate* isolate);
|
||||
static Callable Subtract(Isolate* isolate);
|
||||
static Callable BitwiseAnd(Isolate* isolate);
|
||||
static Callable BitwiseOr(Isolate* isolate);
|
||||
static Callable BitwiseXor(Isolate* isolate);
|
||||
static Callable LessThan(Isolate* isolate);
|
||||
static Callable LessThanOrEqual(Isolate* isolate);
|
||||
static Callable GreaterThan(Isolate* isolate);
|
||||
|
@ -1035,6 +1035,182 @@ void SubtractStub::GenerateAssembly(
|
||||
|
||||
namespace {
|
||||
|
||||
void GenerateBitwiseOperation(
|
||||
compiler::CodeStubAssembler* assembler,
|
||||
compiler::Node* (compiler::CodeStubAssembler::*bitop)(compiler::Node*,
|
||||
compiler::Node*)) {
|
||||
typedef compiler::CodeStubAssembler::Label Label;
|
||||
typedef compiler::Node Node;
|
||||
typedef compiler::CodeStubAssembler::Variable Variable;
|
||||
|
||||
Node* context = assembler->Parameter(2);
|
||||
|
||||
// Shared entry for word32 bitwise operation.
|
||||
Label do_bitop(assembler);
|
||||
Variable var_bitop_lhs(assembler, MachineRepresentation::kWord32),
|
||||
var_bitop_rhs(assembler, MachineRepresentation::kWord32);
|
||||
|
||||
// We might need to loop several times due to ToNumber conversions.
|
||||
Variable var_lhs(assembler, MachineRepresentation::kTagged),
|
||||
var_rhs(assembler, MachineRepresentation::kTagged);
|
||||
Variable* loop_vars[2] = {&var_lhs, &var_rhs};
|
||||
Label loop(assembler, 2, loop_vars);
|
||||
var_lhs.Bind(assembler->Parameter(0));
|
||||
var_rhs.Bind(assembler->Parameter(1));
|
||||
assembler->Goto(&loop);
|
||||
assembler->Bind(&loop);
|
||||
{
|
||||
// Load the current {lhs} and {rhs} values.
|
||||
Node* lhs = var_lhs.value();
|
||||
Node* rhs = var_rhs.value();
|
||||
|
||||
// Check if the {lhs} is a Smi or a HeapObject.
|
||||
Label if_lhsissmi(assembler), if_lhsisnotsmi(assembler);
|
||||
assembler->Branch(assembler->WordIsSmi(lhs), &if_lhsissmi, &if_lhsisnotsmi);
|
||||
|
||||
assembler->Bind(&if_lhsissmi);
|
||||
{
|
||||
// Check if the {rhs} is also a Smi.
|
||||
Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler);
|
||||
assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi,
|
||||
&if_rhsisnotsmi);
|
||||
|
||||
assembler->Bind(&if_rhsissmi);
|
||||
{
|
||||
// Perform the word32 bitwise operation.
|
||||
var_bitop_lhs.Bind(assembler->SmiToInt32(lhs));
|
||||
var_bitop_rhs.Bind(assembler->SmiToInt32(rhs));
|
||||
assembler->Goto(&do_bitop);
|
||||
}
|
||||
|
||||
assembler->Bind(&if_rhsisnotsmi);
|
||||
{
|
||||
// Load the map of the {rhs}.
|
||||
Node* rhs_map = assembler->LoadMap(rhs);
|
||||
|
||||
// Check if {rhs} is a HeapNumber.
|
||||
Label if_rhsisnumber(assembler),
|
||||
if_rhsisnotnumber(assembler, Label::kDeferred);
|
||||
Node* number_map = assembler->HeapNumberMapConstant();
|
||||
assembler->Branch(assembler->WordEqual(rhs_map, number_map),
|
||||
&if_rhsisnumber, &if_rhsisnotnumber);
|
||||
|
||||
assembler->Bind(&if_rhsisnumber);
|
||||
{
|
||||
// Perform the word32 bitwise operation.
|
||||
var_bitop_lhs.Bind(assembler->SmiToInt32(lhs));
|
||||
var_bitop_rhs.Bind(assembler->TruncateHeapNumberValueToInt32(rhs));
|
||||
assembler->Goto(&do_bitop);
|
||||
}
|
||||
|
||||
assembler->Bind(&if_rhsisnotnumber);
|
||||
{
|
||||
// Convert the {rhs} to a Number first.
|
||||
Callable callable =
|
||||
CodeFactory::NonNumberToNumber(assembler->isolate());
|
||||
var_rhs.Bind(assembler->CallStub(callable, context, rhs));
|
||||
assembler->Goto(&loop);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assembler->Bind(&if_lhsisnotsmi);
|
||||
{
|
||||
// Load the map of the {lhs}.
|
||||
Node* lhs_map = assembler->LoadMap(lhs);
|
||||
|
||||
// Check if the {lhs} is a HeapNumber.
|
||||
Label if_lhsisnumber(assembler),
|
||||
if_lhsisnotnumber(assembler, Label::kDeferred);
|
||||
Node* number_map = assembler->HeapNumberMapConstant();
|
||||
assembler->Branch(assembler->WordEqual(lhs_map, number_map),
|
||||
&if_lhsisnumber, &if_lhsisnotnumber);
|
||||
|
||||
assembler->Bind(&if_lhsisnumber);
|
||||
{
|
||||
// Check if the {rhs} is a Smi.
|
||||
Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler);
|
||||
assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi,
|
||||
&if_rhsisnotsmi);
|
||||
|
||||
assembler->Bind(&if_rhsissmi);
|
||||
{
|
||||
// Perform the word32 bitwise operation.
|
||||
var_bitop_lhs.Bind(assembler->TruncateHeapNumberValueToInt32(lhs));
|
||||
var_bitop_rhs.Bind(assembler->SmiToInt32(rhs));
|
||||
assembler->Goto(&do_bitop);
|
||||
}
|
||||
|
||||
assembler->Bind(&if_rhsisnotsmi);
|
||||
{
|
||||
// Load the map of the {rhs}.
|
||||
Node* rhs_map = assembler->LoadMap(rhs);
|
||||
|
||||
// Check if the {rhs} is a HeapNumber.
|
||||
Label if_rhsisnumber(assembler),
|
||||
if_rhsisnotnumber(assembler, Label::kDeferred);
|
||||
assembler->Branch(assembler->WordEqual(rhs_map, number_map),
|
||||
&if_rhsisnumber, &if_rhsisnotnumber);
|
||||
|
||||
assembler->Bind(&if_rhsisnumber);
|
||||
{
|
||||
// Perform the word32 bitwise operation.
|
||||
var_bitop_lhs.Bind(assembler->TruncateHeapNumberValueToInt32(lhs));
|
||||
var_bitop_rhs.Bind(assembler->TruncateHeapNumberValueToInt32(rhs));
|
||||
assembler->Goto(&do_bitop);
|
||||
}
|
||||
|
||||
assembler->Bind(&if_rhsisnotnumber);
|
||||
{
|
||||
// Convert the {rhs} to a Number first.
|
||||
Callable callable =
|
||||
CodeFactory::NonNumberToNumber(assembler->isolate());
|
||||
var_rhs.Bind(assembler->CallStub(callable, context, rhs));
|
||||
assembler->Goto(&loop);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assembler->Bind(&if_lhsisnotnumber);
|
||||
{
|
||||
// Convert the {lhs} to a Number first.
|
||||
Callable callable =
|
||||
CodeFactory::NonNumberToNumber(assembler->isolate());
|
||||
var_lhs.Bind(assembler->CallStub(callable, context, lhs));
|
||||
assembler->Goto(&loop);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assembler->Bind(&do_bitop);
|
||||
{
|
||||
Node* lhs_value = var_bitop_lhs.value();
|
||||
Node* rhs_value = var_bitop_rhs.value();
|
||||
Node* value = (assembler->*bitop)(lhs_value, rhs_value);
|
||||
Node* result = assembler->ChangeInt32ToTagged(value);
|
||||
assembler->Return(result);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void BitwiseAndStub::GenerateAssembly(
|
||||
compiler::CodeStubAssembler* assembler) const {
|
||||
GenerateBitwiseOperation(assembler, &compiler::CodeStubAssembler::Word32And);
|
||||
}
|
||||
|
||||
void BitwiseOrStub::GenerateAssembly(
|
||||
compiler::CodeStubAssembler* assembler) const {
|
||||
GenerateBitwiseOperation(assembler, &compiler::CodeStubAssembler::Word32Or);
|
||||
}
|
||||
|
||||
void BitwiseXorStub::GenerateAssembly(
|
||||
compiler::CodeStubAssembler* assembler) const {
|
||||
GenerateBitwiseOperation(assembler, &compiler::CodeStubAssembler::Word32Xor);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
enum RelationalComparisonMode {
|
||||
kLessThan,
|
||||
kLessThanOrEqual,
|
||||
|
@ -113,6 +113,9 @@ namespace internal {
|
||||
V(StringLength) \
|
||||
V(Add) \
|
||||
V(Subtract) \
|
||||
V(BitwiseAnd) \
|
||||
V(BitwiseOr) \
|
||||
V(BitwiseXor) \
|
||||
V(LessThan) \
|
||||
V(LessThanOrEqual) \
|
||||
V(GreaterThan) \
|
||||
@ -685,6 +688,30 @@ class SubtractStub final : public TurboFanCodeStub {
|
||||
DEFINE_TURBOFAN_CODE_STUB(Subtract, TurboFanCodeStub);
|
||||
};
|
||||
|
||||
class BitwiseAndStub final : public TurboFanCodeStub {
|
||||
public:
|
||||
explicit BitwiseAndStub(Isolate* isolate) : TurboFanCodeStub(isolate) {}
|
||||
|
||||
DEFINE_CALL_INTERFACE_DESCRIPTOR(BinaryOp);
|
||||
DEFINE_TURBOFAN_CODE_STUB(BitwiseAnd, TurboFanCodeStub);
|
||||
};
|
||||
|
||||
class BitwiseOrStub final : public TurboFanCodeStub {
|
||||
public:
|
||||
explicit BitwiseOrStub(Isolate* isolate) : TurboFanCodeStub(isolate) {}
|
||||
|
||||
DEFINE_CALL_INTERFACE_DESCRIPTOR(BinaryOp);
|
||||
DEFINE_TURBOFAN_CODE_STUB(BitwiseOr, TurboFanCodeStub);
|
||||
};
|
||||
|
||||
class BitwiseXorStub final : public TurboFanCodeStub {
|
||||
public:
|
||||
explicit BitwiseXorStub(Isolate* isolate) : TurboFanCodeStub(isolate) {}
|
||||
|
||||
DEFINE_CALL_INTERFACE_DESCRIPTOR(BinaryOp);
|
||||
DEFINE_TURBOFAN_CODE_STUB(BitwiseXor, TurboFanCodeStub);
|
||||
};
|
||||
|
||||
class LessThanStub final : public TurboFanCodeStub {
|
||||
public:
|
||||
explicit LessThanStub(Isolate* isolate) : TurboFanCodeStub(isolate) {}
|
||||
|
@ -259,6 +259,12 @@ Node* CodeStubAssembler::StoreHeapNumberValue(Node* object, Node* value) {
|
||||
IntPtrConstant(HeapNumber::kValueOffset - kHeapObjectTag), value);
|
||||
}
|
||||
|
||||
Node* CodeStubAssembler::TruncateHeapNumberValueToInt32(Node* object) {
|
||||
Node* value = LoadHeapNumberValue(object);
|
||||
return raw_assembler_->TruncateFloat64ToInt32(TruncationMode::kJavaScript,
|
||||
value);
|
||||
}
|
||||
|
||||
Node* CodeStubAssembler::LoadMapBitField(Node* map) {
|
||||
return Load(MachineType::Uint8(), map,
|
||||
IntPtrConstant(Map::kBitFieldOffset - kHeapObjectTag));
|
||||
@ -504,6 +510,33 @@ Node* CodeStubAssembler::BitFieldDecode(Node* word32, uint32_t shift,
|
||||
raw_assembler_->Int32Constant(shift));
|
||||
}
|
||||
|
||||
Node* CodeStubAssembler::ChangeInt32ToTagged(Node* value) {
|
||||
if (raw_assembler_->machine()->Is64()) {
|
||||
return SmiTag(ChangeInt32ToInt64(value));
|
||||
}
|
||||
Variable var_result(this, MachineRepresentation::kTagged);
|
||||
Node* pair = Int32AddWithOverflow(value, value);
|
||||
Node* overflow = Projection(1, pair);
|
||||
Label if_overflow(this, Label::kDeferred), if_notoverflow(this),
|
||||
if_join(this);
|
||||
Branch(overflow, &if_overflow, &if_notoverflow);
|
||||
Bind(&if_overflow);
|
||||
{
|
||||
Node* value64 = ChangeInt32ToFloat64(value);
|
||||
Node* result = AllocateHeapNumberWithValue(value64);
|
||||
var_result.Bind(result);
|
||||
}
|
||||
Goto(&if_join);
|
||||
Bind(&if_notoverflow);
|
||||
{
|
||||
Node* result = Projection(0, pair);
|
||||
var_result.Bind(result);
|
||||
}
|
||||
Goto(&if_join);
|
||||
Bind(&if_join);
|
||||
return var_result.value();
|
||||
}
|
||||
|
||||
void CodeStubAssembler::BranchIf(Node* condition, Label* if_true,
|
||||
Label* if_false) {
|
||||
Label if_condition_is_true(this), if_condition_is_false(this);
|
||||
|
@ -70,6 +70,7 @@ class Schedule;
|
||||
V(IntPtrSub) \
|
||||
V(IntPtrSubWithOverflow) \
|
||||
V(Int32Add) \
|
||||
V(Int32AddWithOverflow) \
|
||||
V(Int32Sub) \
|
||||
V(Int32Mul) \
|
||||
V(WordOr) \
|
||||
@ -294,6 +295,8 @@ class CodeStubAssembler {
|
||||
Node* LoadHeapNumberValue(Node* object);
|
||||
// Store the floating point value of a HeapNumber.
|
||||
Node* StoreHeapNumberValue(Node* object, Node* value);
|
||||
// Truncate the floating point value of a HeapNumber to an Int32.
|
||||
Node* TruncateHeapNumberValueToInt32(Node* object);
|
||||
// Load the bit field of a Map.
|
||||
Node* LoadMapBitField(Node* map);
|
||||
// Load the instance type of a Map.
|
||||
@ -329,6 +332,9 @@ class CodeStubAssembler {
|
||||
|
||||
Node* BitFieldDecode(Node* word32, uint32_t shift, uint32_t mask);
|
||||
|
||||
// Conversions.
|
||||
Node* ChangeInt32ToTagged(Node* value);
|
||||
|
||||
// Branching helpers.
|
||||
// TODO(danno): Can we be more cleverish wrt. edge-split?
|
||||
void BranchIf(Node* condition, Label* if_true, Label* if_false);
|
||||
|
@ -70,9 +70,6 @@ Reduction JSGenericLowering::Reduce(Node* node) {
|
||||
ReplaceWithStubCall(node, CodeFactory::BinaryOpIC(isolate(), token), \
|
||||
CallDescriptor::kPatchableCallSiteWithNop | flags); \
|
||||
}
|
||||
REPLACE_BINARY_OP_IC_CALL(JSBitwiseOr, Token::BIT_OR)
|
||||
REPLACE_BINARY_OP_IC_CALL(JSBitwiseXor, Token::BIT_XOR)
|
||||
REPLACE_BINARY_OP_IC_CALL(JSBitwiseAnd, Token::BIT_AND)
|
||||
REPLACE_BINARY_OP_IC_CALL(JSShiftLeft, Token::SHL)
|
||||
REPLACE_BINARY_OP_IC_CALL(JSShiftRight, Token::SAR)
|
||||
REPLACE_BINARY_OP_IC_CALL(JSShiftRightLogical, Token::SHR)
|
||||
@ -98,6 +95,9 @@ REPLACE_RUNTIME_CALL(JSConvertReceiver, Runtime::kConvertReceiver)
|
||||
}
|
||||
REPLACE_STUB_CALL(Add)
|
||||
REPLACE_STUB_CALL(Subtract)
|
||||
REPLACE_STUB_CALL(BitwiseAnd)
|
||||
REPLACE_STUB_CALL(BitwiseOr)
|
||||
REPLACE_STUB_CALL(BitwiseXor)
|
||||
REPLACE_STUB_CALL(LessThan)
|
||||
REPLACE_STUB_CALL(LessThanOrEqual)
|
||||
REPLACE_STUB_CALL(GreaterThan)
|
||||
|
@ -690,7 +690,7 @@ void Interpreter::DoMod(InterpreterAssembler* assembler) {
|
||||
//
|
||||
// BitwiseOr register <src> to accumulator.
|
||||
void Interpreter::DoBitwiseOr(InterpreterAssembler* assembler) {
|
||||
DoBinaryOp(Runtime::kBitwiseOr, assembler);
|
||||
DoBinaryOp(CodeFactory::BitwiseOr(isolate_), assembler);
|
||||
}
|
||||
|
||||
|
||||
@ -698,7 +698,7 @@ void Interpreter::DoBitwiseOr(InterpreterAssembler* assembler) {
|
||||
//
|
||||
// BitwiseXor register <src> to accumulator.
|
||||
void Interpreter::DoBitwiseXor(InterpreterAssembler* assembler) {
|
||||
DoBinaryOp(Runtime::kBitwiseXor, assembler);
|
||||
DoBinaryOp(CodeFactory::BitwiseXor(isolate_), assembler);
|
||||
}
|
||||
|
||||
|
||||
@ -706,7 +706,7 @@ void Interpreter::DoBitwiseXor(InterpreterAssembler* assembler) {
|
||||
//
|
||||
// BitwiseAnd register <src> to accumulator.
|
||||
void Interpreter::DoBitwiseAnd(InterpreterAssembler* assembler) {
|
||||
DoBinaryOp(Runtime::kBitwiseAnd, assembler);
|
||||
DoBinaryOp(CodeFactory::BitwiseAnd(isolate_), assembler);
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user