Revert "[maglev] Remove input_count from Node constructors"

This reverts commit 2ee36e4cf5.

Reason for revert: https://ci.chromium.org/ui/p/v8/builders/ci/V8%20Linux64%20UBSan/20570/overview

Original change's description:
> [maglev] Remove input_count from Node constructors
>
> Change the NodeBase bitfield to be out-of-line, and initialised by
> NodeBase::Allocate. This means that we don't have to thread the
> input_count through the Derived constructor just to pass it back into
> the NodeBase constructor, and so we can remove those arguments (plus the
> opcode ones while we're at it).
>
> Bug: v8:7700
> Change-Id: I0c96db8cdd05ef106b3cfeb31c5e0d4770d13cc9
> Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3553103
> Reviewed-by: Toon Verwaest <verwaest@chromium.org>
> Commit-Queue: Leszek Swirski <leszeks@chromium.org>
> Cr-Commit-Position: refs/heads/main@{#79627}

Bug: v8:7700
Change-Id: Ice38908e85f2980dbbe66c61fab17326b3d0be41
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3553005
Owners-Override: Tobias Tebbi <tebbi@chromium.org>
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Commit-Queue: Tobias Tebbi <tebbi@chromium.org>
Cr-Commit-Position: refs/heads/main@{#79631}
This commit is contained in:
Tobias Tebbi 2022-03-25 17:25:16 +00:00 committed by V8 LUCI CQ
parent c482a66bd7
commit cfa4581e69

View File

@ -318,17 +318,7 @@ NODE_BASE_LIST(DEF_OPCODE_OF)
} // namespace detail
class NodeBase : public ZoneObject {
private:
// Bitfield specification.
using OpcodeField = base::BitField<Opcode, 0, 6>;
STATIC_ASSERT(OpcodeField::is_valid(kLastOpcode));
using InputCountField = OpcodeField::Next<uint16_t, 16>;
protected:
// Subclasses may use the remaining bitfield bits.
template <class T, int size>
using NextBitField = InputCountField::Next<T, size>;
template <class T>
static constexpr Opcode opcode_of = detail::opcode_of_helper<T>::value;
@ -360,7 +350,7 @@ class NodeBase : public ZoneObject {
static constexpr OpProperties kProperties = OpProperties::Pure();
inline const OpProperties& properties() const;
constexpr Opcode opcode() const { return OpcodeField::decode(bit_field()); }
constexpr Opcode opcode() const { return OpcodeField::decode(bit_field_); }
template <class T>
constexpr bool Is() const;
@ -382,7 +372,7 @@ class NodeBase : public ZoneObject {
constexpr bool has_inputs() const { return input_count() > 0; }
constexpr uint16_t input_count() const {
return InputCountField::decode(bit_field());
return InputCountField::decode(bit_field_);
}
Input& input(int index) { return *input_address(index); }
@ -437,23 +427,44 @@ class NodeBase : public ZoneObject {
void Print(std::ostream& os, MaglevGraphLabeller*) const;
protected:
NodeBase() : num_temporaries_needed_(0) {}
NodeBase(Opcode opcode, size_t input_count)
: bit_field_(OpcodeField::encode(opcode) |
InputCountField::encode(input_count)) {}
Input* input_address(int index) {
DCHECK_LT(index, input_count());
return reinterpret_cast<Input*>(bit_field_address()) - (index + 1);
return reinterpret_cast<Input*>(this) - (index + 1);
}
const Input* input_address(int index) const {
DCHECK_LT(index, input_count());
return reinterpret_cast<const Input*>(bit_field_address()) - (index + 1);
return reinterpret_cast<const Input*>(this) - (index + 1);
}
void set_input(int index, ValueNode* input) {
new (input_address(index)) Input(input);
}
uint32_t bit_field() const { return *bit_field_address(); }
void set_bit_field(uint32_t value) { *bit_field_address() = value; }
private:
template <class Derived, typename... Args>
static Derived* Allocate(Zone* zone, size_t input_count, Args&&... args) {
const size_t size = sizeof(Derived) + input_count * sizeof(Input);
intptr_t raw_buffer =
reinterpret_cast<intptr_t>(zone->Allocate<NodeWithInlineInputs>(size));
void* node_buffer =
reinterpret_cast<void*>(raw_buffer + input_count * sizeof(Input));
Derived* node =
new (node_buffer) Derived(input_count, std::forward<Args>(args)...);
return node;
}
protected:
// Bitfield specification.
using OpcodeField = base::BitField<Opcode, 0, 6>;
STATIC_ASSERT(OpcodeField::is_valid(kLastOpcode));
using InputCountField = OpcodeField::Next<uint16_t, 16>;
// Subclasses may use the remaining bits.
template <class T, int size>
using NextBitField = InputCountField::Next<T, size>;
void set_temporaries_needed(int value) {
#ifdef DEBUG
@ -463,38 +474,13 @@ class NodeBase : public ZoneObject {
num_temporaries_needed_ = value;
}
uint32_t bit_field_;
private:
template <class Derived, typename... Args>
static Derived* Allocate(Zone* zone, size_t input_count, Args&&... args) {
const size_t size =
sizeof(Derived) + sizeof(uint32_t) + input_count * sizeof(Input);
intptr_t raw_buffer =
reinterpret_cast<intptr_t>(zone->Allocate<NodeWithInlineInputs>(size));
void* node_buffer = reinterpret_cast<void*>(raw_buffer + sizeof(uint32_t) +
input_count * sizeof(Input));
*reinterpret_cast<uint32_t*>(reinterpret_cast<char*>(node_buffer) -
sizeof(uint32_t)) =
OpcodeField::encode(opcode_of<Derived>) |
InputCountField::encode(input_count);
Derived* node = new (node_buffer) Derived(std::forward<Args>(args)...);
return node;
}
uint32_t* bit_field_address() {
return reinterpret_cast<uint32_t*>(reinterpret_cast<char*>(this) -
sizeof(uint32_t));
}
const uint32_t* bit_field_address() const {
return reinterpret_cast<const uint32_t*>(
reinterpret_cast<const char*>(this) - sizeof(uint32_t));
}
NodeIdT id_ = kInvalidNodeId;
union {
int num_temporaries_needed_;
int num_temporaries_needed_ = 0;
RegList temporaries_;
};
#ifdef DEBUG
@ -505,6 +491,7 @@ class NodeBase : public ZoneObject {
} kTemporariesState = kUnset;
#endif // DEBUG
NodeBase() = delete;
NodeBase(const NodeBase&) = delete;
NodeBase(NodeBase&&) = delete;
NodeBase& operator=(const NodeBase&) = delete;
@ -537,6 +524,10 @@ class Node : public NodeBase {
inline ValueLocation& result();
protected:
explicit Node(Opcode opcode, size_t input_count)
: NodeBase(opcode, input_count) {}
private:
Node** next() { return &next_; }
Node* next_ = nullptr;
@ -635,8 +626,9 @@ class ValueNode : public Node {
}
protected:
ValueNode()
: last_uses_next_use_id_(&next_use_)
explicit ValueNode(Opcode opcode, size_t input_count)
: Node(opcode, input_count),
last_uses_next_use_id_(&next_use_)
#ifdef DEBUG
,
state_(kLastUse)
@ -674,8 +666,11 @@ class NodeT : public Node {
STATIC_ASSERT(!IsValueNode(opcode_of<Derived>));
public:
constexpr Opcode opcode() const { return opcode_of<Derived>; }
constexpr Opcode opcode() const { return NodeBase::opcode_of<Derived>; }
const OpProperties& properties() const { return Derived::kProperties; }
protected:
explicit NodeT(size_t input_count) : Node(opcode_of<Derived>, input_count) {}
};
template <size_t InputCount, class Derived>
@ -691,7 +686,10 @@ class FixedInputNodeT : public NodeT<Derived> {
}
protected:
FixedInputNodeT() { DCHECK_EQ(NodeBase::input_count(), kInputCount); }
explicit FixedInputNodeT(size_t input_count) : NodeT<Derived>(kInputCount) {
DCHECK_EQ(input_count, kInputCount);
USE(input_count);
}
};
template <class Derived>
@ -699,8 +697,12 @@ class ValueNodeT : public ValueNode {
STATIC_ASSERT(IsValueNode(opcode_of<Derived>));
public:
constexpr Opcode opcode() const { return opcode_of<Derived>; }
constexpr Opcode opcode() const { return NodeBase::opcode_of<Derived>; }
const OpProperties& properties() const { return Derived::kProperties; }
protected:
explicit ValueNodeT(size_t input_count)
: ValueNode(opcode_of<Derived>, input_count) {}
};
template <size_t InputCount, class Derived>
@ -716,7 +718,11 @@ class FixedInputValueNodeT : public ValueNodeT<Derived> {
}
protected:
FixedInputValueNodeT() { DCHECK_EQ(NodeBase::input_count(), kInputCount); }
explicit FixedInputValueNodeT(size_t input_count)
: ValueNodeT<Derived>(InputCount) {
DCHECK_EQ(input_count, InputCount);
USE(input_count);
}
};
template <class Derived, Operation kOperation>
@ -732,8 +738,9 @@ class UnaryWithFeedbackNode : public FixedInputValueNodeT<1, Derived> {
compiler::FeedbackSource feedback() const { return feedback_; }
protected:
explicit UnaryWithFeedbackNode(const compiler::FeedbackSource& feedback)
: feedback_(feedback) {}
explicit UnaryWithFeedbackNode(size_t input_count,
const compiler::FeedbackSource& feedback)
: Base(input_count), feedback_(feedback) {}
void AllocateVreg(MaglevVregAllocationState*, const ProcessingState&);
void GenerateCode(MaglevCodeGenState*, const ProcessingState&);
@ -757,8 +764,9 @@ class BinaryWithFeedbackNode : public FixedInputValueNodeT<2, Derived> {
compiler::FeedbackSource feedback() const { return feedback_; }
protected:
explicit BinaryWithFeedbackNode(const compiler::FeedbackSource& feedback)
: feedback_(feedback) {}
BinaryWithFeedbackNode(size_t input_count,
const compiler::FeedbackSource& feedback)
: Base(input_count), feedback_(feedback) {}
void AllocateVreg(MaglevVregAllocationState*, const ProcessingState&);
void GenerateCode(MaglevCodeGenState*, const ProcessingState&);
@ -772,8 +780,8 @@ class BinaryWithFeedbackNode : public FixedInputValueNodeT<2, Derived> {
using Base = Super<Name, Operation::k##OpName>; \
\
public: \
explicit Name(const compiler::FeedbackSource& feedback) \
: Base(feedback) {} \
Name(size_t input_count, const compiler::FeedbackSource& feedback) \
: Base(input_count, feedback) {} \
void AllocateVreg(MaglevVregAllocationState*, const ProcessingState&); \
void GenerateCode(MaglevCodeGenState*, const ProcessingState&); \
void PrintParams(std::ostream&, MaglevGraphLabeller*) const {} \
@ -793,7 +801,8 @@ class InitialValue : public FixedInputValueNodeT<0, InitialValue> {
using Base = FixedInputValueNodeT<0, InitialValue>;
public:
explicit InitialValue(interpreter::Register source) : source_(source) {}
explicit InitialValue(size_t input_count, interpreter::Register source)
: Base(input_count), source_(source) {}
interpreter::Register source() const { return source_; }
@ -809,7 +818,8 @@ class RegisterInput : public FixedInputValueNodeT<0, RegisterInput> {
using Base = FixedInputValueNodeT<0, RegisterInput>;
public:
explicit RegisterInput(Register input) : input_(input) {}
explicit RegisterInput(size_t input_count, Register input)
: Base(input_count), input_(input) {}
Register input() const { return input_; }
@ -825,7 +835,8 @@ class SmiConstant : public FixedInputValueNodeT<0, SmiConstant> {
using Base = FixedInputValueNodeT<0, SmiConstant>;
public:
explicit SmiConstant(Smi value) : value_(value) {}
explicit SmiConstant(size_t input_count, Smi value)
: Base(input_count), value_(value) {}
Smi value() const { return value_; }
@ -841,7 +852,8 @@ class Constant : public FixedInputValueNodeT<0, Constant> {
using Base = FixedInputValueNodeT<0, Constant>;
public:
explicit Constant(const compiler::HeapObjectRef& object) : object_(object) {}
explicit Constant(size_t input_count, const compiler::HeapObjectRef& object)
: Base(input_count), object_(object) {}
void AllocateVreg(MaglevVregAllocationState*, const ProcessingState&);
void GenerateCode(MaglevCodeGenState*, const ProcessingState&);
@ -855,7 +867,8 @@ class RootConstant : public FixedInputValueNodeT<0, RootConstant> {
using Base = FixedInputValueNodeT<0, RootConstant>;
public:
explicit RootConstant(RootIndex index) : index_(index) {}
explicit RootConstant(size_t input_count, RootIndex index)
: Base(input_count), index_(index) {}
RootIndex index() const { return index_; }
@ -871,7 +884,8 @@ class SoftDeopt : public FixedInputNodeT<0, SoftDeopt> {
using Base = FixedInputNodeT<0, SoftDeopt>;
public:
explicit SoftDeopt(Checkpoint* checkpoint) : checkpoint_(checkpoint) {}
explicit SoftDeopt(size_t input_count, Checkpoint* checkpoint)
: Base(input_count), checkpoint_(checkpoint) {}
static constexpr OpProperties kProperties = OpProperties::Deopt();
@ -889,8 +903,9 @@ class CheckMaps : public FixedInputNodeT<1, CheckMaps> {
using Base = FixedInputNodeT<1, CheckMaps>;
public:
explicit CheckMaps(const compiler::MapRef& map, Checkpoint* checkpoint)
: map_(map), checkpoint_(checkpoint) {}
explicit CheckMaps(size_t input_count, const compiler::MapRef& map,
Checkpoint* checkpoint)
: Base(input_count), map_(map), checkpoint_(checkpoint) {}
// TODO(verwaest): This just calls in deferred code, so probably we'll need to
// mark that to generate stack maps. Mark as call so we at least clear the
@ -918,7 +933,8 @@ class LoadField : public FixedInputValueNodeT<1, LoadField> {
using Base = FixedInputValueNodeT<1, LoadField>;
public:
explicit LoadField(int handler) : handler_(handler) {}
explicit LoadField(size_t input_count, int handler)
: Base(input_count), handler_(handler) {}
static constexpr OpProperties kProperties = OpProperties::Reading();
@ -939,7 +955,8 @@ class StoreField : public FixedInputNodeT<2, StoreField> {
using Base = FixedInputNodeT<2, StoreField>;
public:
explicit StoreField(int handler) : handler_(handler) {}
explicit StoreField(size_t input_count, int handler)
: Base(input_count), handler_(handler) {}
static constexpr OpProperties kProperties = OpProperties::Writing();
@ -962,7 +979,8 @@ class LoadGlobal : public FixedInputValueNodeT<1, LoadGlobal> {
using Base = FixedInputValueNodeT<1, LoadGlobal>;
public:
explicit LoadGlobal(const compiler::NameRef& name) : name_(name) {}
explicit LoadGlobal(size_t input_count, const compiler::NameRef& name)
: Base(input_count), name_(name) {}
// The implementation currently calls runtime.
static constexpr OpProperties kProperties = OpProperties::JSCall();
@ -982,7 +1000,8 @@ class LoadNamedGeneric : public FixedInputValueNodeT<2, LoadNamedGeneric> {
using Base = FixedInputValueNodeT<2, LoadNamedGeneric>;
public:
explicit LoadNamedGeneric(const compiler::NameRef& name) : name_(name) {}
explicit LoadNamedGeneric(size_t input_count, const compiler::NameRef& name)
: Base(input_count), name_(name) {}
// The implementation currently calls runtime.
static constexpr OpProperties kProperties = OpProperties::JSCall();
@ -1006,8 +1025,9 @@ class GapMove : public FixedInputNodeT<0, GapMove> {
using Base = FixedInputNodeT<0, GapMove>;
public:
GapMove(compiler::AllocatedOperand source, compiler::AllocatedOperand target)
: source_(source), target_(target) {}
GapMove(size_t input_count, compiler::AllocatedOperand source,
compiler::AllocatedOperand target)
: Base(input_count), source_(source), target_(target) {}
compiler::AllocatedOperand source() const { return source_; }
compiler::AllocatedOperand target() const { return target_; }
@ -1031,8 +1051,8 @@ class Phi : public ValueNodeT<Phi> {
using List = base::ThreadedList<Phi>;
// TODO(jgruber): More intuitive constructors, if possible.
Phi(interpreter::Register owner, int merge_offset)
: owner_(owner), merge_offset_(merge_offset) {}
Phi(size_t input_count, interpreter::Register owner, int merge_offset)
: Base(input_count), owner_(owner), merge_offset_(merge_offset) {}
interpreter::Register owner() const { return owner_; }
int merge_offset() const { return merge_offset_; }
@ -1058,11 +1078,12 @@ class CallProperty : public ValueNodeT<CallProperty> {
using Base = ValueNodeT<CallProperty>;
public:
CallProperty() = default;
explicit CallProperty(size_t input_count) : Base(input_count) {}
// This ctor is used when for variable input counts.
// Inputs must be initialized manually.
CallProperty(ValueNode* function, ValueNode* context) {
CallProperty(size_t input_count, ValueNode* function, ValueNode* context)
: Base(input_count) {
set_input(0, function);
set_input(1, context);
}
@ -1086,6 +1107,8 @@ class CallUndefinedReceiver : public ValueNodeT<CallUndefinedReceiver> {
using Base = ValueNodeT<CallUndefinedReceiver>;
public:
explicit CallUndefinedReceiver(size_t input_count) : Base(input_count) {}
static constexpr OpProperties kProperties = OpProperties::JSCall();
Input& function() { return input(0); }
@ -1211,6 +1234,10 @@ class ControlNode : public NodeBase {
next_post_dominating_hole_ = node;
}
protected:
explicit ControlNode(Opcode opcode, size_t input_count)
: NodeBase(opcode, input_count) {}
private:
ControlNode* next_post_dominating_hole_ = nullptr;
};
@ -1222,9 +1249,12 @@ class UnconditionalControlNode : public ControlNode {
void set_predecessor_id(int id) { predecessor_id_ = id; }
protected:
explicit UnconditionalControlNode(BasicBlockRef* target_refs)
: target_(target_refs) {}
explicit UnconditionalControlNode(BasicBlock* target) : target_(target) {}
explicit UnconditionalControlNode(Opcode opcode, size_t input_count,
BasicBlockRef* target_refs)
: ControlNode(opcode, input_count), target_(target_refs) {}
explicit UnconditionalControlNode(Opcode opcode, size_t input_count,
BasicBlock* target)
: ControlNode(opcode, input_count), target_(target) {}
private:
const BasicBlockRef target_;
@ -1238,7 +1268,7 @@ class UnconditionalControlNodeT : public UnconditionalControlNode {
public:
// Shadowing for static knowledge.
constexpr Opcode opcode() const { return opcode_of<Derived>; }
constexpr Opcode opcode() const { return NodeBase::opcode_of<Derived>; }
constexpr bool has_inputs() const { return input_count() > 0; }
constexpr uint16_t input_count() const { return kInputCount; }
auto end() {
@ -1246,21 +1276,27 @@ class UnconditionalControlNodeT : public UnconditionalControlNode {
}
protected:
explicit UnconditionalControlNodeT(BasicBlockRef* target_refs)
: UnconditionalControlNode(target_refs) {
DCHECK_EQ(NodeBase::input_count(), kInputCount);
explicit UnconditionalControlNodeT(size_t input_count,
BasicBlockRef* target_refs)
: UnconditionalControlNode(opcode_of<Derived>, kInputCount, target_refs) {
DCHECK_EQ(input_count, kInputCount);
USE(input_count);
}
explicit UnconditionalControlNodeT(BasicBlock* target)
: UnconditionalControlNode(target) {
DCHECK_EQ(NodeBase::input_count(), kInputCount);
explicit UnconditionalControlNodeT(size_t input_count, BasicBlock* target)
: UnconditionalControlNode(opcode_of<Derived>, kInputCount, target) {
DCHECK_EQ(input_count, kInputCount);
USE(input_count);
}
};
class ConditionalControlNode : public ControlNode {
public:
ConditionalControlNode(BasicBlockRef* if_true_refs,
ConditionalControlNode(Opcode opcode, size_t input_count,
BasicBlockRef* if_true_refs,
BasicBlockRef* if_false_refs)
: if_true_(if_true_refs), if_false_(if_false_refs) {}
: ControlNode(opcode, input_count),
if_true_(if_true_refs),
if_false_(if_false_refs) {}
BasicBlock* if_true() const { return if_true_.block_ptr(); }
BasicBlock* if_false() const { return if_false_.block_ptr(); }
@ -1277,7 +1313,7 @@ class ConditionalControlNodeT : public ConditionalControlNode {
public:
// Shadowing for static knowledge.
constexpr Opcode opcode() const { return opcode_of<Derived>; }
constexpr Opcode opcode() const { return NodeBase::opcode_of<Derived>; }
constexpr bool has_inputs() const { return input_count() > 0; }
constexpr uint16_t input_count() const { return kInputCount; }
auto end() {
@ -1285,10 +1321,13 @@ class ConditionalControlNodeT : public ConditionalControlNode {
}
protected:
explicit ConditionalControlNodeT(BasicBlockRef* if_true_refs,
explicit ConditionalControlNodeT(size_t input_count,
BasicBlockRef* if_true_refs,
BasicBlockRef* if_false_refs)
: ConditionalControlNode(if_true_refs, if_false_refs) {
DCHECK_EQ(NodeBase::input_count(), kInputCount);
: ConditionalControlNode(opcode_of<Derived>, kInputCount, if_true_refs,
if_false_refs) {
DCHECK_EQ(input_count, kInputCount);
USE(input_count);
}
};
@ -1296,7 +1335,8 @@ class Jump : public UnconditionalControlNodeT<Jump> {
using Base = UnconditionalControlNodeT<Jump>;
public:
explicit Jump(BasicBlockRef* target_refs) : Base(target_refs) {}
explicit Jump(size_t input_count, BasicBlockRef* target_refs)
: Base(input_count, target_refs) {}
void AllocateVreg(MaglevVregAllocationState*, const ProcessingState&);
void GenerateCode(MaglevCodeGenState*, const ProcessingState&);
@ -1307,9 +1347,11 @@ class JumpLoop : public UnconditionalControlNodeT<JumpLoop> {
using Base = UnconditionalControlNodeT<JumpLoop>;
public:
explicit JumpLoop(BasicBlock* target) : Base(target) {}
explicit JumpLoop(size_t input_count, BasicBlock* target)
: Base(input_count, target) {}
explicit JumpLoop(BasicBlockRef* ref) : Base(ref) {}
explicit JumpLoop(size_t input_count, BasicBlockRef* ref)
: Base(input_count, ref) {}
void AllocateVreg(MaglevVregAllocationState*, const ProcessingState&);
void GenerateCode(MaglevCodeGenState*, const ProcessingState&);
@ -1318,6 +1360,9 @@ class JumpLoop : public UnconditionalControlNodeT<JumpLoop> {
class Return : public ControlNode {
public:
explicit Return(size_t input_count)
: ControlNode(opcode_of<Return>, input_count) {}
Input& value_input() { return input(0); }
void AllocateVreg(MaglevVregAllocationState*, const ProcessingState&);
@ -1329,9 +1374,9 @@ class BranchIfTrue : public ConditionalControlNodeT<1, BranchIfTrue> {
using Base = ConditionalControlNodeT<1, BranchIfTrue>;
public:
explicit BranchIfTrue(BasicBlockRef* if_true_refs,
explicit BranchIfTrue(size_t input_count, BasicBlockRef* if_true_refs,
BasicBlockRef* if_false_refs)
: Base(if_true_refs, if_false_refs) {}
: Base(input_count, if_true_refs, if_false_refs) {}
Input& condition_input() { return input(0); }
@ -1345,9 +1390,10 @@ class BranchIfToBooleanTrue
using Base = ConditionalControlNodeT<1, BranchIfToBooleanTrue>;
public:
explicit BranchIfToBooleanTrue(BasicBlockRef* if_true_refs,
explicit BranchIfToBooleanTrue(size_t input_count,
BasicBlockRef* if_true_refs,
BasicBlockRef* if_false_refs)
: Base(if_true_refs, if_false_refs) {}
: Base(input_count, if_true_refs, if_false_refs) {}
static constexpr OpProperties kProperties = OpProperties::Call();
@ -1368,9 +1414,10 @@ class BranchIfCompare
Input& left_input() { return NodeBase::input(kLeftIndex); }
Input& right_input() { return NodeBase::input(kRightIndex); }
explicit BranchIfCompare(Operation operation, BasicBlockRef* if_true_refs,
explicit BranchIfCompare(size_t input_count, Operation operation,
BasicBlockRef* if_true_refs,
BasicBlockRef* if_false_refs)
: Base(if_true_refs, if_false_refs), operation_(operation) {}
: Base(input_count, if_true_refs, if_false_refs), operation_(operation) {}
void AllocateVreg(MaglevVregAllocationState*, const ProcessingState&);
void GenerateCode(MaglevCodeGenState*, const ProcessingState&);