Commit 6c6a71b3 authored by titzer@chromium.org's avatar titzer@chromium.org

Move input/output counts directly into Operators, simplying OperatorProperties.

This is a first step to refactoring OperatorProperties out of existence.
The next step is to inline OperatorProperties::GetXXXCount into the callers.

R=rossberg@chromium.org
BUG=

Review URL: https://codereview.chromium.org/680313003

Cr-Commit-Position: refs/heads/master@{#24983}
git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24983 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent eca12478
This diff is collapsed.
......@@ -19,7 +19,7 @@ namespace compiler {
// Forward declarations.
class CallDescriptor;
struct CommonOperatorBuilderImpl;
struct CommonOperatorGlobalCache;
class Operator;
......@@ -197,7 +197,7 @@ class CommonOperatorBuilder FINAL : public ZoneObject {
private:
Zone* zone() const { return zone_; }
const CommonOperatorBuilderImpl& impl_;
const CommonOperatorGlobalCache& cache_;
Zone* const zone_;
DISALLOW_COPY_AND_ASSIGN(CommonOperatorBuilder);
......
......@@ -962,7 +962,7 @@ void InstructionSelector::VisitThrow(Node* value) {
void InstructionSelector::FillTypeVectorFromStateValues(
ZoneVector<MachineType>* types, Node* state_values) {
DCHECK(state_values->opcode() == IrOpcode::kStateValues);
int count = OpParameter<int>(state_values);
int count = state_values->InputCount();
types->reserve(static_cast<size_t>(count));
for (int i = 0; i < count; i++) {
types->push_back(GetMachineType(state_values->InputAt(i)));
......@@ -974,11 +974,14 @@ FrameStateDescriptor* InstructionSelector::GetFrameStateDescriptor(
Node* state) {
DCHECK(state->opcode() == IrOpcode::kFrameState);
DCHECK_EQ(5, state->InputCount());
DCHECK_EQ(IrOpcode::kStateValues, state->InputAt(0)->opcode());
DCHECK_EQ(IrOpcode::kStateValues, state->InputAt(1)->opcode());
DCHECK_EQ(IrOpcode::kStateValues, state->InputAt(2)->opcode());
FrameStateCallInfo state_info = OpParameter<FrameStateCallInfo>(state);
int parameters = OpParameter<int>(state->InputAt(0));
int locals = OpParameter<int>(state->InputAt(1));
int stack = OpParameter<int>(state->InputAt(2));
int parameters = state->InputAt(0)->InputCount();
int locals = state->InputAt(1)->InputCount();
int stack = state->InputAt(2)->InputCount();
FrameStateDescriptor* outer_state = NULL;
Node* outer_node = state->InputAt(4);
......
......@@ -165,8 +165,8 @@ class CopyVisitor : public NullNodeVisitor {
source_graph_(source_graph),
target_graph_(target_graph),
temp_zone_(temp_zone),
sentinel_op_(IrOpcode::kDead, Operator::kNoProperties, 0, 0,
"sentinel") {}
sentinel_op_(IrOpcode::kDead, Operator::kNoProperties, "sentinel", 0, 0,
0, 0, 0, 0) {}
GenericGraphVisit::Control Post(Node* original) {
NodeVector inputs(temp_zone_);
......@@ -224,7 +224,7 @@ class CopyVisitor : public NullNodeVisitor {
Graph* source_graph_;
Graph* target_graph_;
Zone* temp_zone_;
SimpleOperator sentinel_op_;
Operator sentinel_op_;
};
......@@ -453,7 +453,7 @@ class JSCallRuntimeAccessor {
Node* effect() const { return NodeProperties::GetEffectInput(call_); }
const Runtime::Function* function() const {
return Runtime::FunctionForId(OpParameter<Runtime::FunctionId>(call_));
return Runtime::FunctionForId(CallRuntimeParametersOf(call_->op()).id());
}
NodeVector inputs(Zone* zone) const {
......
This diff is collapsed.
......@@ -14,7 +14,7 @@ namespace compiler {
// Forward declarations.
class Operator;
struct JSOperatorBuilderImpl;
struct JSOperatorGlobalCache;
// Defines the arity and the call flags for a JavaScript function call. This is
......@@ -264,7 +264,7 @@ class JSOperatorBuilder FINAL : public ZoneObject {
private:
Zone* zone() const { return zone_; }
const JSOperatorBuilderImpl& impl_;
const JSOperatorGlobalCache& cache_;
Zone* const zone_;
DISALLOW_COPY_AND_ASSIGN(JSOperatorBuilder);
......
This diff is collapsed.
......@@ -13,7 +13,7 @@ namespace internal {
namespace compiler {
// Forward declarations.
struct MachineOperatorBuilderImpl;
struct MachineOperatorGlobalCache;
class Operator;
......@@ -210,7 +210,7 @@ class MachineOperatorBuilder FINAL : public ZoneObject {
#undef PSEUDO_OP_LIST
private:
const MachineOperatorBuilderImpl& impl_;
const MachineOperatorGlobalCache& cache_;
const MachineType word_;
const Flags flags_;
DISALLOW_COPY_AND_ASSIGN(MachineOperatorBuilder);
......
......@@ -264,6 +264,7 @@ class IrOpcode {
// Returns the mnemonic name of an opcode.
static const char* Mnemonic(Value val) {
// TODO(turbofan): make this a table lookup.
switch (val) {
#define RETURN_NAME(x) \
case k##x: \
......@@ -277,6 +278,7 @@ class IrOpcode {
static bool IsJsOpcode(Value val) {
switch (val) {
// TODO(turbofan): make this a range check.
#define RETURN_NAME(x) \
case k##x: \
return true;
......@@ -289,6 +291,7 @@ class IrOpcode {
static bool IsControlOpcode(Value val) {
switch (val) {
// TODO(turbofan): make this a range check.
#define RETURN_NAME(x) \
case k##x: \
return true;
......@@ -301,6 +304,7 @@ class IrOpcode {
static bool IsLeafOpcode(Value val) {
switch (val) {
// TODO(turbofan): make this a table lookup.
#define RETURN_NAME(x) \
case k##x: \
return true;
......@@ -313,6 +317,7 @@ class IrOpcode {
static bool IsCommonOpcode(Value val) {
switch (val) {
// TODO(turbofan): make this a table lookup or a range check.
#define RETURN_NAME(x) \
case k##x: \
return true;
......
......@@ -16,7 +16,7 @@ namespace internal {
namespace compiler {
inline bool OperatorProperties::HasValueInput(const Operator* op) {
return OperatorProperties::GetValueInputCount(op) > 0;
return op->ValueInputCount() > 0;
}
inline bool OperatorProperties::HasContextInput(const Operator* op) {
......@@ -25,11 +25,11 @@ inline bool OperatorProperties::HasContextInput(const Operator* op) {
}
inline bool OperatorProperties::HasEffectInput(const Operator* op) {
return OperatorProperties::GetEffectInputCount(op) > 0;
return op->EffectInputCount() > 0;
}
inline bool OperatorProperties::HasControlInput(const Operator* op) {
return OperatorProperties::GetControlInputCount(op) > 0;
return op->ControlInputCount() > 0;
}
inline bool OperatorProperties::HasFrameStateInput(const Operator* op) {
......@@ -94,7 +94,7 @@ inline bool OperatorProperties::HasFrameStateInput(const Operator* op) {
}
inline int OperatorProperties::GetValueInputCount(const Operator* op) {
return op->InputCount();
return op->ValueInputCount();
}
inline int OperatorProperties::GetContextInputCount(const Operator* op) {
......@@ -106,44 +106,11 @@ inline int OperatorProperties::GetFrameStateInputCount(const Operator* op) {
}
inline int OperatorProperties::GetEffectInputCount(const Operator* op) {
if (op->opcode() == IrOpcode::kEffectPhi ||
op->opcode() == IrOpcode::kFinish ||
op->opcode() == IrOpcode::kTerminate) {
return OpParameter<int>(op);
}
if (op->HasProperty(Operator::kNoRead) && op->HasProperty(Operator::kNoWrite))
return 0; // no effects.
return 1;
return op->EffectInputCount();
}
inline int OperatorProperties::GetControlInputCount(const Operator* op) {
// TODO(titzer): fix this mess; just make them a count on the operator.
switch (op->opcode()) {
case IrOpcode::kPhi:
case IrOpcode::kEffectPhi:
case IrOpcode::kLoad:
case IrOpcode::kLoadField:
case IrOpcode::kInt32Div:
case IrOpcode::kInt32Mod:
case IrOpcode::kUint32Div:
case IrOpcode::kUint32Mod:
return 1;
#define OPCODE_CASE(x) case IrOpcode::k##x:
CONTROL_OP_LIST(OPCODE_CASE)
#undef OPCODE_CASE
if (op->opcode() == IrOpcode::kBranch) return 1;
if (op->opcode() == IrOpcode::kTerminate) return 1;
// Control operators are Operator1<int>.
return OpParameter<int>(op);
default:
// Operators that have write effects must have a control
// dependency. Effect dependencies only ensure the correct order of
// write/read operations without consideration of control flow. Without an
// explicit control dependency writes can be float in the schedule too
// early along a path that shouldn't generate a side-effect.
return op->HasProperty(Operator::kNoWrite) ? 0 : 1;
}
return 0;
return op->ControlInputCount();
}
inline int OperatorProperties::GetTotalInputCount(const Operator* op) {
......@@ -156,33 +123,28 @@ inline int OperatorProperties::GetTotalInputCount(const Operator* op) {
// Output properties.
inline bool OperatorProperties::HasValueOutput(const Operator* op) {
return GetValueOutputCount(op) > 0;
return op->ValueOutputCount() > 0;
}
inline bool OperatorProperties::HasEffectOutput(const Operator* op) {
return op->opcode() == IrOpcode::kStart ||
op->opcode() == IrOpcode::kValueEffect ||
(op->opcode() != IrOpcode::kFinish &&
op->opcode() != IrOpcode::kTerminate && GetEffectInputCount(op) > 0);
return op->EffectOutputCount() > 0;
}
inline bool OperatorProperties::HasControlOutput(const Operator* op) {
IrOpcode::Value opcode = static_cast<IrOpcode::Value>(op->opcode());
return (opcode != IrOpcode::kEnd && IrOpcode::IsControlOpcode(opcode));
return op->ControlOutputCount() > 0;
}
inline int OperatorProperties::GetValueOutputCount(const Operator* op) {
return op->OutputCount();
return op->ValueOutputCount();
}
inline int OperatorProperties::GetEffectOutputCount(const Operator* op) {
return HasEffectOutput(op) ? 1 : 0;
return op->EffectOutputCount();
}
inline int OperatorProperties::GetControlOutputCount(const Operator* node) {
return node->opcode() == IrOpcode::kBranch ? 2 : HasControlOutput(node) ? 1
: 0;
inline int OperatorProperties::GetControlOutputCount(const Operator* op) {
return op->ControlOutputCount();
}
......
......@@ -10,46 +10,35 @@ namespace v8 {
namespace internal {
namespace compiler {
Operator::~Operator() {}
std::ostream& operator<<(std::ostream& os, const Operator& op) {
op.PrintTo(os);
return os;
template <typename N>
static inline N CheckRange(size_t val) {
CHECK(val <= std::numeric_limits<N>::max());
return static_cast<N>(val);
}
SimpleOperator::SimpleOperator(Opcode opcode, Properties properties,
size_t input_count, size_t output_count,
const char* mnemonic)
: Operator(opcode, properties, mnemonic),
input_count_(static_cast<uint8_t>(input_count)),
output_count_(static_cast<uint8_t>(output_count)) {
DCHECK(input_count <= std::numeric_limits<uint8_t>::max());
DCHECK(output_count <= std::numeric_limits<uint8_t>::max());
}
Operator::Operator(Opcode opcode, Properties properties, const char* mnemonic,
size_t value_in, size_t effect_in, size_t control_in,
size_t value_out, size_t effect_out, size_t control_out)
: opcode_(opcode),
properties_(properties),
mnemonic_(mnemonic),
value_in_(CheckRange<uint32_t>(value_in)),
effect_in_(CheckRange<uint16_t>(effect_in)),
control_in_(CheckRange<uint16_t>(control_in)),
value_out_(CheckRange<uint16_t>(value_out)),
effect_out_(CheckRange<uint8_t>(effect_out)),
control_out_(CheckRange<uint8_t>(control_out)) {}
SimpleOperator::~SimpleOperator() {}
bool SimpleOperator::Equals(const Operator* that) const {
return opcode() == that->opcode();
}
size_t SimpleOperator::HashCode() const {
return base::hash<Opcode>()(opcode());
std::ostream& operator<<(std::ostream& os, const Operator& op) {
op.PrintTo(os);
return os;
}
int SimpleOperator::InputCount() const { return input_count_; }
int SimpleOperator::OutputCount() const { return output_count_; }
void SimpleOperator::PrintTo(std::ostream& os) const { os << mnemonic(); }
void Operator::PrintTo(std::ostream& os) const { os << mnemonic(); }
} // namespace compiler
} // namespace internal
......
......@@ -49,9 +49,12 @@ class Operator : public ZoneObject {
};
typedef base::Flags<Property, uint8_t> Properties;
Operator(Opcode opcode, Properties properties, const char* mnemonic)
: opcode_(opcode), properties_(properties), mnemonic_(mnemonic) {}
virtual ~Operator();
// Constructor.
Operator(Opcode opcode, Properties properties, const char* mnemonic,
size_t value_in, size_t effect_in, size_t control_in,
size_t value_out, size_t effect_out, size_t control_out);
virtual ~Operator() {}
// A small integer unique to all instances of a particular kind of operator,
// useful for quick matching for specific kinds of operators. For fast access
......@@ -65,12 +68,14 @@ class Operator : public ZoneObject {
// Check if this operator equals another operator. Equivalent operators can
// be merged, and nodes with equivalent operators and equivalent inputs
// can be merged.
virtual bool Equals(const Operator*) const = 0;
virtual bool Equals(const Operator* that) const {
return this->opcode() == that->opcode();
}
// Compute a hashcode to speed up equivalence-set checking.
// Equal operators should always have equal hashcodes, and unequal operators
// should have unequal hashcodes with high probability.
virtual size_t HashCode() const = 0;
virtual size_t HashCode() const { return base::hash<Opcode>()(opcode()); }
// Check whether this operator has the given property.
bool HasProperty(Property property) const {
......@@ -78,24 +83,45 @@ class Operator : public ZoneObject {
}
// Number of data inputs to the operator, for verifying graph structure.
virtual int InputCount() const = 0;
// TODO(titzer): convert callers to ValueInputCount();
int InputCount() const { return ValueInputCount(); }
// Number of data outputs from the operator, for verifying graph structure.
virtual int OutputCount() const = 0;
// TODO(titzer): convert callers to ValueOutputCount();
int OutputCount() const { return ValueOutputCount(); }
Properties properties() const { return properties_; }
// TODO(titzer): convert return values here to size_t.
int ValueInputCount() const { return value_in_; }
int EffectInputCount() const { return effect_in_; }
int ControlInputCount() const { return control_in_; }
int ValueOutputCount() const { return value_out_; }
int EffectOutputCount() const { return effect_out_; }
int ControlOutputCount() const { return control_out_; }
static inline size_t ZeroIfPure(Properties properties) {
return (properties & kPure) == kPure ? 0 : 1;
}
// TODO(titzer): API for input and output types, for typechecking graph.
protected:
// Print the full operator into the given stream, including any
// static parameters. Useful for debugging and visualizing the IR.
virtual void PrintTo(std::ostream& os) const = 0; // NOLINT
virtual void PrintTo(std::ostream& os) const;
friend std::ostream& operator<<(std::ostream& os, const Operator& op);
private:
Opcode opcode_;
Properties properties_;
const char* mnemonic_;
uint32_t value_in_;
uint16_t effect_in_;
uint16_t control_in_;
uint16_t value_out_;
uint8_t effect_out_;
uint8_t control_out_;
DISALLOW_COPY_AND_ASSIGN(Operator);
};
......@@ -105,42 +131,18 @@ DEFINE_OPERATORS_FOR_FLAGS(Operator::Properties)
std::ostream& operator<<(std::ostream& os, const Operator& op);
// An implementation of Operator that has no static parameters. Such operators
// have just a name, an opcode, and a fixed number of inputs and outputs.
// They can represented by singletons and shared globally.
class SimpleOperator : public Operator {
public:
SimpleOperator(Opcode opcode, Properties properties, size_t input_count,
size_t output_count, const char* mnemonic);
~SimpleOperator();
virtual bool Equals(const Operator* that) const FINAL;
virtual size_t HashCode() const FINAL;
virtual int InputCount() const FINAL;
virtual int OutputCount() const FINAL;
private:
virtual void PrintTo(std::ostream& os) const FINAL;
uint8_t input_count_;
uint8_t output_count_;
DISALLOW_COPY_AND_ASSIGN(SimpleOperator);
};
// A templatized implementation of Operator that has one static parameter of
// type {T}.
template <typename T, typename Pred = std::equal_to<T>,
typename Hash = base::hash<T>>
class Operator1 : public Operator {
public:
Operator1(Opcode opcode, Properties properties, int input_count,
int output_count, const char* mnemonic, T parameter,
Pred const& pred = Pred(), Hash const& hash = Hash())
: Operator(opcode, properties, mnemonic),
input_count_(input_count),
output_count_(output_count),
Operator1(Opcode opcode, Properties properties, const char* mnemonic,
size_t value_in, size_t effect_in, size_t control_in,
size_t value_out, size_t effect_out, size_t control_out,
T parameter, Pred const& pred = Pred(), Hash const& hash = Hash())
: Operator(opcode, properties, mnemonic, value_in, effect_in, control_in,
value_out, effect_out, control_out),
parameter_(parameter),
pred_(pred),
hash_(hash) {}
......@@ -155,8 +157,6 @@ class Operator1 : public Operator {
virtual size_t HashCode() const FINAL {
return base::hash_combine(this->opcode(), this->hash_(this->parameter()));
}
virtual int InputCount() const FINAL { return input_count_; }
virtual int OutputCount() const FINAL { return output_count_; }
virtual void PrintParameter(std::ostream& os) const {
os << "[" << this->parameter() << "]";
}
......@@ -168,8 +168,6 @@ class Operator1 : public Operator {
}
private:
int const input_count_;
int const output_count_;
T const parameter_;
Pred const pred_;
Hash const hash_;
......
......@@ -1122,7 +1122,7 @@ void SimplifiedLowering::DoLoadField(Node* node) {
const FieldAccess& access = FieldAccessOf(node->op());
node->set_op(machine()->Load(access.machine_type));
Node* offset = jsgraph()->Int32Constant(access.offset - access.tag());
node->InsertInput(zone(), 1, offset);
node->InsertInput(graph()->zone(), 1, offset);
}
......@@ -1133,7 +1133,7 @@ void SimplifiedLowering::DoStoreField(Node* node) {
node->set_op(
machine()->Store(StoreRepresentation(access.machine_type, kind)));
Node* offset = jsgraph()->Int32Constant(access.offset - access.tag());
node->InsertInput(zone(), 1, offset);
node->InsertInput(graph()->zone(), 1, offset);
}
......@@ -1336,10 +1336,11 @@ void SimplifiedLowering::DoStringAdd(Node* node) {
CallDescriptor* desc =
Linkage::GetStubCallDescriptor(callable.descriptor(), 0, flags, zone());
node->set_op(common()->Call(desc));
node->InsertInput(zone(), 0, jsgraph()->HeapConstant(callable.code()));
node->AppendInput(zone(), jsgraph()->UndefinedConstant());
node->AppendInput(zone(), graph()->start());
node->AppendInput(zone(), graph()->start());
node->InsertInput(graph()->zone(), 0,
jsgraph()->HeapConstant(callable.code()));
node->AppendInput(graph()->zone(), jsgraph()->UndefinedConstant());
node->AppendInput(graph()->zone(), graph()->start());
node->AppendInput(graph()->zone(), graph()->start());
}
......
......@@ -140,53 +140,55 @@ const ElementAccess& ElementAccessOf(const Operator* op) {
V(ObjectIsNonNegativeSmi, Operator::kNoProperties, 1)
#define ACCESS_OP_LIST(V) \
V(LoadField, FieldAccess, Operator::kNoWrite, 1, 1) \
V(StoreField, FieldAccess, Operator::kNoRead, 2, 0) \
V(LoadElement, ElementAccess, Operator::kNoWrite, 3, 1) \
V(StoreElement, ElementAccess, Operator::kNoRead, 4, 0)
struct SimplifiedOperatorBuilderImpl FINAL {
#define PURE(Name, properties, input_count) \
struct Name##Operator FINAL : public SimpleOperator { \
Name##Operator() \
: SimpleOperator(IrOpcode::k##Name, Operator::kPure | properties, \
input_count, 1, #Name) {} \
}; \
struct SimplifiedOperatorGlobalCache FINAL {
#define PURE(Name, properties, input_count) \
struct Name##Operator FINAL : public Operator { \
Name##Operator() \
: Operator(IrOpcode::k##Name, Operator::kPure | properties, #Name, \
input_count, 0, 0, 1, 0, 0) {} \
}; \
Name##Operator k##Name;
PURE_OP_LIST(PURE)
#undef PURE
};
static base::LazyInstance<SimplifiedOperatorBuilderImpl>::type kImpl =
static base::LazyInstance<SimplifiedOperatorGlobalCache>::type kCache =
LAZY_INSTANCE_INITIALIZER;
SimplifiedOperatorBuilder::SimplifiedOperatorBuilder(Zone* zone)
: impl_(kImpl.Get()), zone_(zone) {}
: cache_(kCache.Get()), zone_(zone) {}
#define PURE(Name, properties, input_count) \
const Operator* SimplifiedOperatorBuilder::Name() { return &impl_.k##Name; }
const Operator* SimplifiedOperatorBuilder::Name() { return &cache_.k##Name; }
PURE_OP_LIST(PURE)
#undef PURE
const Operator* SimplifiedOperatorBuilder::ReferenceEqual(Type* type) {
// TODO(titzer): What about the type parameter?
return new (zone()) SimpleOperator(IrOpcode::kReferenceEqual,
Operator::kCommutative | Operator::kPure,
2, 1, "ReferenceEqual");
return new (zone()) Operator(IrOpcode::kReferenceEqual,
Operator::kCommutative | Operator::kPure,
"ReferenceEqual", 2, 0, 0, 1, 0, 0);
}
#define ACCESS(Name, Type, properties, input_count, output_count) \
const Operator* SimplifiedOperatorBuilder::Name(const Type& access) { \
return new (zone()) \
Operator1<Type>(IrOpcode::k##Name, Operator::kNoThrow | properties, \
input_count, output_count, #Name, access); \
#define ACCESS_OP_LIST(V) \
V(LoadField, FieldAccess, Operator::kNoWrite, 1, 1, 1) \
V(StoreField, FieldAccess, Operator::kNoRead, 2, 1, 0) \
V(LoadElement, ElementAccess, Operator::kNoWrite, 3, 0, 1) \
V(StoreElement, ElementAccess, Operator::kNoRead, 4, 1, 0)
#define ACCESS(Name, Type, properties, value_input_count, control_input_count, \
output_count) \
const Operator* SimplifiedOperatorBuilder::Name(const Type& access) { \
return new (zone()) \
Operator1<Type>(IrOpcode::k##Name, Operator::kNoThrow | properties, \
#Name, value_input_count, 1, control_input_count, \
output_count, 1, 0, access); \
}
ACCESS_OP_LIST(ACCESS)
#undef ACCESS
......
......@@ -25,7 +25,7 @@ namespace compiler {
// Forward declarations.
class Operator;
struct SimplifiedOperatorBuilderImpl;
struct SimplifiedOperatorGlobalCache;
enum BaseTaggedness { kUntaggedBase, kTaggedBase };
......@@ -161,7 +161,7 @@ class SimplifiedOperatorBuilder FINAL {
private:
Zone* zone() const { return zone_; }
const SimplifiedOperatorBuilderImpl& impl_;
const SimplifiedOperatorGlobalCache& cache_;
Zone* const zone_;
DISALLOW_COPY_AND_ASSIGN(SimplifiedOperatorBuilder);
......
......@@ -301,7 +301,7 @@ GenericGraphVisit::Control Verifier::Visitor::Pre(Node* node) {
break;
case IrOpcode::kProjection: {
// Projection has an input that produces enough values.
int index = OpParameter<int>(node->op());
int index = static_cast<int>(OpParameter<size_t>(node->op()));
Node* input = NodeProperties::GetValueInput(node, 0);
CHECK_GT(OperatorProperties::GetValueOutputCount(input->op()), index);
// Type can be anything.
......
......@@ -76,10 +76,8 @@ Node* SimplifiedGraphBuilder::MakeNode(const Operator* op,
if (has_effect) {
effect_ = result;
}
if (OperatorProperties::HasControlOutput(result->op())) {
// This graph builder does not support control flow.
UNREACHABLE();
}
// This graph builder does not support control flow.
CHECK_EQ(0, op->ControlOutputCount());
}
return result;
......
......@@ -21,15 +21,15 @@ const uint8_t OPCODE_C0 = 30;
const uint8_t OPCODE_C1 = 31;
const uint8_t OPCODE_C2 = 32;
static SimpleOperator OPA0(OPCODE_A0, Operator::kNoWrite, 0, 0, "opa0");
static SimpleOperator OPA1(OPCODE_A1, Operator::kNoWrite, 1, 0, "opa1");
static SimpleOperator OPA2(OPCODE_A2, Operator::kNoWrite, 2, 0, "opa2");
static SimpleOperator OPB0(OPCODE_B0, Operator::kNoWrite, 0, 0, "opa0");
static SimpleOperator OPB1(OPCODE_B1, Operator::kNoWrite, 1, 0, "opa1");
static SimpleOperator OPB2(OPCODE_B2, Operator::kNoWrite, 2, 0, "opa2");
static SimpleOperator OPC0(OPCODE_C0, Operator::kNoWrite, 0, 0, "opc0");
static SimpleOperator OPC1(OPCODE_C1, Operator::kNoWrite, 1, 0, "opc1");
static SimpleOperator OPC2(OPCODE_C2, Operator::kNoWrite, 2, 0, "opc2");
static Operator OPA0(OPCODE_A0, Operator::kNoWrite, "opa0", 0, 0, 0, 0, 0, 0);
static Operator OPA1(OPCODE_A1, Operator::kNoWrite, "opa1", 1, 0, 0, 0, 0, 0);
static Operator OPA2(OPCODE_A2, Operator::kNoWrite, "opa2", 2, 0, 0, 0, 0, 0);
static Operator OPB0(OPCODE_B0, Operator::kNoWrite, "opa0", 0, 0, 0, 0, 0, 0);
static Operator OPB1(OPCODE_B1, Operator::kNoWrite, "opa1", 1, 0, 0, 0, 0, 0);
static Operator OPB2(OPCODE_B2, Operator::kNoWrite, "opa2", 2, 0, 0, 0, 0, 0);
static Operator OPC0(OPCODE_C0, Operator::kNoWrite, "opc0", 0, 0, 0, 0, 0, 0);
static Operator OPC1(OPCODE_C1, Operator::kNoWrite, "opc1", 1, 0, 0, 0, 0, 0);
static Operator OPC2(OPCODE_C2, Operator::kNoWrite, "opc2", 2, 0, 0, 0, 0, 0);
// Replaces all "A" operators with "B" operators without creating new nodes.
......
......@@ -23,8 +23,8 @@
using namespace v8::internal;
using namespace v8::internal::compiler;
static SimpleOperator dummy_operator(IrOpcode::kParameter, Operator::kNoWrite,
0, 0, "dummy");
static Operator dummy_operator(IrOpcode::kParameter, Operator::kNoWrite,
"dummy", 0, 0, 0, 0, 0, 0);
// So we can get a real JS function.
static Handle<JSFunction> Compile(const char* source) {
......
......@@ -18,8 +18,8 @@
using namespace v8::internal;
using namespace v8::internal::compiler;
static SimpleOperator dummy_operator(IrOpcode::kParameter, Operator::kNoWrite,
0, 0, "dummy");
static Operator dummy_operator(IrOpcode::kParameter, Operator::kNoWrite,
"dummy", 0, 0, 0, 1, 0, 0);
class PreNodeVisitor : public NullNodeVisitor {
public:
......
......@@ -14,8 +14,8 @@
using namespace v8::internal;
using namespace v8::internal::compiler;
static SimpleOperator dummy_operator(IrOpcode::kParameter, Operator::kNoWrite,
0, 0, "dummy");
static Operator dummy_operator(IrOpcode::kParameter, Operator::kNoWrite,
"dummy", 0, 0, 0, 1, 0, 0);
TEST(NodeAllocation) {
GraphTester graph;
......
......@@ -12,41 +12,45 @@
using namespace v8::internal;
using namespace v8::internal::compiler;
TEST(TestOperatorMnemonic) {
SimpleOperator op1(10, Operator::kNoProperties, 0, 0, "ThisOne");
#define NONE Operator::kNoProperties
#define FOLD Operator::kFoldable
TEST(TestOperator_Mnemonic) {
Operator op1(10, NONE, "ThisOne", 0, 0, 0, 0, 0, 0);
CHECK_EQ(0, strcmp(op1.mnemonic(), "ThisOne"));
SimpleOperator op2(11, Operator::kNoProperties, 0, 0, "ThatOne");
Operator op2(11, NONE, "ThatOne", 0, 0, 0, 0, 0, 0);
CHECK_EQ(0, strcmp(op2.mnemonic(), "ThatOne"));
Operator1<int> op3(12, Operator::kNoProperties, 0, 1, "Mnemonic1", 12333);
Operator1<int> op3(12, NONE, "Mnemonic1", 0, 0, 0, 1, 0, 0, 12333);
CHECK_EQ(0, strcmp(op3.mnemonic(), "Mnemonic1"));
Operator1<double> op4(13, Operator::kNoProperties, 0, 1, "TheOther", 99.9);
Operator1<double> op4(13, NONE, "TheOther", 0, 0, 0, 1, 0, 0, 99.9);
CHECK_EQ(0, strcmp(op4.mnemonic(), "TheOther"));
}
TEST(TestSimpleOperatorHash) {
SimpleOperator op1(17, Operator::kNoProperties, 0, 0, "Another");
TEST(TestOperator_Hash) {
Operator op1(17, NONE, "Another", 0, 0, 0, 0, 0, 0);
CHECK_EQ(17, static_cast<int>(op1.HashCode()));
SimpleOperator op2(18, Operator::kNoProperties, 0, 0, "Falsch");
Operator op2(18, NONE, "Falsch", 0, 0, 0, 0, 0, 0);
CHECK_EQ(18, static_cast<int>(op2.HashCode()));
}
TEST(TestSimpleOperatorEquals) {
SimpleOperator op1a(19, Operator::kNoProperties, 0, 0, "Another1");
SimpleOperator op1b(19, Operator::kFoldable, 2, 2, "Another2");
TEST(TestOperator_Equals) {
Operator op1a(19, NONE, "Another1", 0, 0, 0, 0, 0, 0);
Operator op1b(19, FOLD, "Another2", 2, 0, 0, 2, 0, 0);
CHECK(op1a.Equals(&op1a));
CHECK(op1a.Equals(&op1b));
CHECK(op1b.Equals(&op1a));
CHECK(op1b.Equals(&op1b));
SimpleOperator op2a(20, Operator::kNoProperties, 0, 0, "Falsch1");
SimpleOperator op2b(20, Operator::kFoldable, 1, 1, "Falsch2");
Operator op2a(20, NONE, "Falsch1", 0, 0, 0, 0, 0, 0);
Operator op2b(20, FOLD, "Falsch2", 1, 0, 0, 1, 0, 0);
CHECK(op2a.Equals(&op2a));
CHECK(op2a.Equals(&op2b));
......@@ -72,46 +76,46 @@ static SmartArrayPointer<const char> OperatorToString(Operator* op) {
}
TEST(TestSimpleOperatorPrint) {
SimpleOperator op1a(19, Operator::kNoProperties, 0, 0, "Another1");
SimpleOperator op1b(19, Operator::kFoldable, 2, 2, "Another2");
TEST(TestOperator_Print) {
Operator op1a(19, NONE, "Another1", 0, 0, 0, 0, 0, 0);
Operator op1b(19, FOLD, "Another2", 2, 0, 0, 2, 0, 0);
CHECK_EQ("Another1", OperatorToString(&op1a).get());
CHECK_EQ("Another2", OperatorToString(&op1b).get());
SimpleOperator op2a(20, Operator::kNoProperties, 0, 0, "Flog1");
SimpleOperator op2b(20, Operator::kFoldable, 1, 1, "Flog2");
Operator op2a(20, NONE, "Flog1", 0, 0, 0, 0, 0, 0);
Operator op2b(20, FOLD, "Flog2", 1, 0, 0, 1, 0, 0);
CHECK_EQ("Flog1", OperatorToString(&op2a).get());
CHECK_EQ("Flog2", OperatorToString(&op2b).get());
}
TEST(TestOperator1intHash) {
Operator1<int> op1a(23, Operator::kNoProperties, 0, 0, "Wolfie", 11);
Operator1<int> op1b(23, Operator::kFoldable, 2, 2, "Doggie", 11);
TEST(TestOperator1int_Hash) {
Operator1<int> op1a(23, NONE, "Wolfie", 0, 0, 0, 0, 0, 0, 11);
Operator1<int> op1b(23, FOLD, "Doggie", 2, 0, 0, 2, 0, 0, 11);
CHECK(op1a.HashCode() == op1b.HashCode());
Operator1<int> op2a(24, Operator::kNoProperties, 0, 0, "Arfie", 3);
Operator1<int> op2b(24, Operator::kNoProperties, 0, 0, "Arfie", 4);
Operator1<int> op2a(24, NONE, "Arfie", 0, 0, 0, 0, 0, 0, 3);
Operator1<int> op2b(24, NONE, "Arfie", 0, 0, 0, 0, 0, 0, 4);
CHECK(op1a.HashCode() != op2a.HashCode());
CHECK(op2a.HashCode() != op2b.HashCode());
}
TEST(TestOperator1intEquals) {
Operator1<int> op1a(23, Operator::kNoProperties, 0, 0, "Scratchy", 11);
Operator1<int> op1b(23, Operator::kFoldable, 2, 2, "Scratchy", 11);
TEST(TestOperator1int_Equals) {
Operator1<int> op1a(23, NONE, "Scratchy", 0, 0, 0, 0, 0, 0, 11);
Operator1<int> op1b(23, FOLD, "Scratchy", 2, 0, 0, 2, 0, 0, 11);
CHECK(op1a.Equals(&op1a));
CHECK(op1a.Equals(&op1b));
CHECK(op1b.Equals(&op1a));
CHECK(op1b.Equals(&op1b));
Operator1<int> op2a(24, Operator::kNoProperties, 0, 0, "Im", 3);
Operator1<int> op2b(24, Operator::kNoProperties, 0, 0, "Im", 4);
Operator1<int> op2a(24, NONE, "Im", 0, 0, 0, 0, 0, 0, 3);
Operator1<int> op2b(24, NONE, "Im", 0, 0, 0, 0, 0, 0, 4);
CHECK(op2a.Equals(&op2a));
CHECK(!op2a.Equals(&op2b));
......@@ -128,7 +132,7 @@ TEST(TestOperator1intEquals) {
CHECK(!op2b.Equals(&op1a));
CHECK(!op2b.Equals(&op1b));
SimpleOperator op3(25, Operator::kNoProperties, 0, 0, "Weepy");
Operator op3(25, NONE, "Weepy", 0, 0, 0, 0, 0, 0);
CHECK(!op1a.Equals(&op3));
CHECK(!op1b.Equals(&op3));
......@@ -142,46 +146,55 @@ TEST(TestOperator1intEquals) {
}
TEST(TestOperator1intPrint) {
Operator1<int> op1(12, Operator::kNoProperties, 0, 1, "Op1Test", 0);
TEST(TestOperator1int_Print) {
Operator1<int> op1(12, NONE, "Op1Test", 0, 0, 0, 1, 0, 0, 0);
CHECK_EQ("Op1Test[0]", OperatorToString(&op1).get());
Operator1<int> op2(12, Operator::kNoProperties, 0, 1, "Op1Test", 66666666);
Operator1<int> op2(12, NONE, "Op1Test", 0, 0, 0, 1, 0, 0, 66666666);
CHECK_EQ("Op1Test[66666666]", OperatorToString(&op2).get());
Operator1<int> op3(12, Operator::kNoProperties, 0, 1, "FooBar", 2347);
Operator1<int> op3(12, NONE, "FooBar", 0, 0, 0, 1, 0, 0, 2347);
CHECK_EQ("FooBar[2347]", OperatorToString(&op3).get());
Operator1<int> op4(12, Operator::kNoProperties, 0, 1, "BarFoo", -879);
Operator1<int> op4(12, NONE, "BarFoo", 0, 0, 0, 1, 0, 0, -879);
CHECK_EQ("BarFoo[-879]", OperatorToString(&op4).get());
}
TEST(TestOperator1doubleHash) {
Operator1<double> op1a(23, Operator::kNoProperties, 0, 0, "Wolfie", 11.77);
Operator1<double> op1b(23, Operator::kFoldable, 2, 2, "Doggie", 11.77);
TEST(TestOperator1double_Hash) {
Operator1<double> op1a(23, NONE, "Wolfie", 0, 0, 0, 0, 0, 0, 11.77);
Operator1<double> op1b(23, FOLD, "Doggie", 2, 0, 0, 2, 0, 0, 11.77);
CHECK(op1a.HashCode() == op1b.HashCode());
Operator1<double> op2a(24, Operator::kNoProperties, 0, 0, "Arfie", -6.7);
Operator1<double> op2b(24, Operator::kNoProperties, 0, 0, "Arfie", -6.8);
Operator1<double> op2a(24, NONE, "Arfie", 0, 0, 0, 0, 0, 0, -6.7);
Operator1<double> op2b(24, NONE, "Arfie", 0, 0, 0, 0, 0, 0, -6.8);
CHECK(op1a.HashCode() != op2a.HashCode());
CHECK(op2a.HashCode() != op2b.HashCode());
}
TEST(TestOperator1doubleEquals) {
Operator1<double> op1a(23, Operator::kNoProperties, 0, 0, "Scratchy", 11.77);
Operator1<double> op1b(23, Operator::kFoldable, 2, 2, "Scratchy", 11.77);
TEST(TestOperator1doublePrint) {
Operator1<double> op1a(23, NONE, "Canary", 0, 0, 0, 0, 0, 0, 0.5);
Operator1<double> op1b(23, FOLD, "Finch", 2, 0, 0, 2, 0, 0, -1.5);
CHECK_EQ("Canary[0.5]", OperatorToString(&op1a).get());
CHECK_EQ("Finch[-1.5]", OperatorToString(&op1b).get());
}
TEST(TestOperator1double_Equals) {
Operator1<double> op1a(23, NONE, "Scratchy", 0, 0, 0, 0, 0, 0, 11.77);
Operator1<double> op1b(23, FOLD, "Scratchy", 2, 0, 0, 2, 0, 0, 11.77);
CHECK(op1a.Equals(&op1a));
CHECK(op1a.Equals(&op1b));
CHECK(op1b.Equals(&op1a));
CHECK(op1b.Equals(&op1b));
Operator1<double> op2a(24, Operator::kNoProperties, 0, 0, "Im", 3.1);
Operator1<double> op2b(24, Operator::kNoProperties, 0, 0, "Im", 3.2);
Operator1<double> op2a(24, NONE, "Im", 0, 0, 0, 0, 0, 0, 3.1);
Operator1<double> op2b(24, NONE, "Im", 0, 0, 0, 0, 0, 0, 3.2);
CHECK(op2a.Equals(&op2a));
CHECK(!op2a.Equals(&op2b));
......@@ -198,7 +211,7 @@ TEST(TestOperator1doubleEquals) {
CHECK(!op2b.Equals(&op1a));
CHECK(!op2b.Equals(&op1b));
SimpleOperator op3(25, Operator::kNoProperties, 0, 0, "Weepy");
Operator op3(25, NONE, "Weepy", 0, 0, 0, 0, 0, 0);
CHECK(!op1a.Equals(&op3));
CHECK(!op1b.Equals(&op3));
......@@ -210,8 +223,8 @@ TEST(TestOperator1doubleEquals) {
CHECK(!op3.Equals(&op2a));
CHECK(!op3.Equals(&op2b));
Operator1<double> op4a(24, Operator::kNoProperties, 0, 0, "Bashful", 1.0);
Operator1<double> op4b(24, Operator::kNoProperties, 0, 0, "Bashful", 1.0);
Operator1<double> op4a(24, NONE, "Bashful", 0, 0, 0, 0, 0, 0, 1.0);
Operator1<double> op4b(24, NONE, "Bashful", 0, 0, 0, 0, 0, 0, 1.0);
CHECK(op4a.Equals(&op4a));
CHECK(op4a.Equals(&op4b));
......@@ -223,3 +236,48 @@ TEST(TestOperator1doubleEquals) {
CHECK(!op3.Equals(&op4a));
CHECK(!op3.Equals(&op4b));
}
TEST(TestOpParameter_Operator1double) {
double values[] = {7777.5, -66, 0, 11, 0.1};
for (size_t i = 0; i < arraysize(values); i++) {
Operator1<double> op(33, NONE, "Scurvy", 0, 0, 0, 0, 0, 0, values[i]);
CHECK_EQ(values[i], OpParameter<double>(&op));
}
}
TEST(TestOpParameter_Operator1float) {
float values[] = {// thanks C++.
static_cast<float>(7777.5), static_cast<float>(-66),
static_cast<float>(0), static_cast<float>(11),
static_cast<float>(0.1)};
for (size_t i = 0; i < arraysize(values); i++) {
Operator1<float> op(33, NONE, "Scurvy", 0, 0, 0, 0, 0, 0, values[i]);
CHECK_EQ(values[i], OpParameter<float>(&op));
}
}
TEST(TestOpParameter_Operator1int) {
int values[] = {7777, -66, 0, 11, 1, 0x666aff};
for (size_t i = 0; i < arraysize(values); i++) {
Operator1<int> op(33, NONE, "Scurvy", 0, 0, 0, 0, 0, 0, values[i]);
CHECK_EQ(values[i], OpParameter<int>(&op));
}
}
TEST(Operator_CountsOrder) {
Operator op(29, NONE, "Flashy", 11, 22, 33, 44, 55, 66);
CHECK_EQ(11, op.ValueInputCount());
CHECK_EQ(22, op.EffectInputCount());
CHECK_EQ(33, op.ControlInputCount());
CHECK_EQ(44, op.ValueOutputCount());
CHECK_EQ(55, op.EffectOutputCount());
CHECK_EQ(66, op.ControlOutputCount());
}
......@@ -16,8 +16,8 @@
using namespace v8::internal;
using namespace v8::internal::compiler;
static SimpleOperator dummy_operator(IrOpcode::kParameter, Operator::kNoWrite,
0, 0, "dummy");
static Operator dummy_operator(IrOpcode::kParameter, Operator::kNoWrite,
"dummy", 0, 0, 0, 0, 0, 0);
TEST(TestScheduleAllocation) {
HandleAndZoneScope scope;
......
......@@ -49,8 +49,8 @@ const SharedOperator kSharedOperators[] = {
SHARED(End, Operator::kFoldable, 0, 0, 1, 0, 0),
SHARED(IfTrue, Operator::kFoldable, 0, 0, 1, 0, 1),
SHARED(IfFalse, Operator::kFoldable, 0, 0, 1, 0, 1),
SHARED(Throw, Operator::kFoldable, 1, 0, 1, 0, 1),
SHARED(Return, Operator::kNoProperties, 1, 1, 1, 1, 1)
SHARED(Throw, Operator::kFoldable, 1, 1, 1, 0, 1),
SHARED(Return, Operator::kNoProperties, 1, 1, 1, 0, 1)
#undef SHARED
};
......@@ -130,7 +130,7 @@ class CommonOperatorTest : public TestWithZone {
};
const int kArguments[] = {1, 5, 6, 42, 100, 10000, kMaxInt};
const int kArguments[] = {1, 5, 6, 42, 100, 10000, 65000};
const float kFloatValues[] = {-std::numeric_limits<float>::infinity(),
......
......@@ -18,10 +18,18 @@ namespace v8 {
namespace internal {
namespace compiler {
struct TestOperator : public Operator {
TestOperator(Operator::Opcode opcode, Operator::Properties properties,
size_t value_in, size_t value_out)
: Operator(opcode, properties, "TestOp", value_in, 0, 0, value_out, 0,
0) {}
};
namespace {
SimpleOperator OP0(0, Operator::kNoWrite, 0, 1, "op0");
SimpleOperator OP1(1, Operator::kNoProperties, 1, 1, "op1");
TestOperator OP0(0, Operator::kNoWrite, 0, 1);
TestOperator OP1(1, Operator::kNoProperties, 1, 1);
struct MockReducer : public Reducer {
......
......@@ -68,7 +68,7 @@ const SharedOperator kSharedOperators[] = {
SHARED(ToName, Operator::kNoProperties, 1, 0, 1, 1, 1, 1),
SHARED(ToObject, Operator::kNoProperties, 1, 1, 1, 1, 1, 1),
SHARED(Yield, Operator::kNoProperties, 1, 0, 1, 1, 1, 1),
SHARED(Create, Operator::kEliminatable, 0, 0, 1, 0, 1, 1),
SHARED(Create, Operator::kEliminatable, 0, 0, 1, 1, 1, 1),
SHARED(HasProperty, Operator::kNoProperties, 2, 1, 1, 1, 1, 1),
SHARED(TypeOf, Operator::kPure, 1, 0, 0, 0, 1, 0),
SHARED(InstanceOf, Operator::kNoProperties, 2, 1, 1, 1, 1, 1),
......
......@@ -12,12 +12,16 @@ namespace v8 {
namespace internal {
namespace compiler {
namespace {
struct TestOperator : public Operator {
TestOperator(Operator::Opcode opcode, Operator::Properties properties,
size_t value_in, size_t value_out)
: Operator(opcode, properties, "TestOp", value_in, 0, 0, value_out, 0,
0) {}
};
const SimpleOperator kOp0(0, Operator::kEliminatable, 0, 1, "op0");
const SimpleOperator kOp1(1, Operator::kEliminatable, 1, 1, "op1");
} // namespace
static const TestOperator kOp0(0, Operator::kEliminatable, 0, 1);
static const TestOperator kOp1(1, Operator::kEliminatable, 1, 1);
class ValueNumberingReducerTest : public TestWithZone {
......@@ -55,7 +59,7 @@ TEST_F(ValueNumberingReducerTest, DeadNodesAreNeverReturned) {
TEST_F(ValueNumberingReducerTest, OnlyEliminatableNodesAreReduced) {
SimpleOperator op(0, Operator::kNoProperties, 0, 1, "op");
TestOperator op(0, Operator::kNoProperties, 0, 1);
Node* n0 = graph()->NewNode(&op);
Node* n1 = graph()->NewNode(&op);
EXPECT_FALSE(Reduce(n0).Changed());
......@@ -69,20 +73,18 @@ TEST_F(ValueNumberingReducerTest, OperatorEqualityNotIdentity) {
for (size_t i = 0; i < arraysize(inputs); ++i) {
Operator::Opcode opcode = static_cast<Operator::Opcode>(
std::numeric_limits<Operator::Opcode>::max() - i);
inputs[i] = graph()->NewNode(new (zone()) SimpleOperator(
opcode, Operator::kEliminatable, 0, 1, "Operator"));
inputs[i] = graph()->NewNode(
new (zone()) TestOperator(opcode, Operator::kEliminatable, 0, 1));
}
TRACED_FORRANGE(size_t, input_count, 0, arraysize(inputs)) {
const SimpleOperator op1(static_cast<Operator::Opcode>(input_count),
Operator::kEliminatable,
static_cast<int>(input_count), 1, "op");
const TestOperator op1(static_cast<Operator::Opcode>(input_count),
Operator::kEliminatable, input_count, 1);
Node* n1 = graph()->NewNode(&op1, static_cast<int>(input_count), inputs);
Reduction r1 = Reduce(n1);
EXPECT_FALSE(r1.Changed());
const SimpleOperator op2(static_cast<Operator::Opcode>(input_count),
Operator::kEliminatable,
static_cast<int>(input_count), 1, "op");
const TestOperator op2(static_cast<Operator::Opcode>(input_count),
Operator::kEliminatable, input_count, 1);
Node* n2 = graph()->NewNode(&op2, static_cast<int>(input_count), inputs);
Reduction r2 = Reduce(n2);
EXPECT_TRUE(r2.Changed());
......@@ -97,12 +99,11 @@ TEST_F(ValueNumberingReducerTest, SubsequentReductionsYieldTheSameNode) {
for (size_t i = 0; i < arraysize(inputs); ++i) {
Operator::Opcode opcode = static_cast<Operator::Opcode>(
std::numeric_limits<Operator::Opcode>::max() - i);
inputs[i] = graph()->NewNode(new (zone()) SimpleOperator(
opcode, Operator::kEliminatable, 0, 1, "Operator"));
inputs[i] = graph()->NewNode(
new (zone()) TestOperator(opcode, Operator::kEliminatable, 0, 1));
}
TRACED_FORRANGE(size_t, input_count, 0, arraysize(inputs)) {
const SimpleOperator op1(1, Operator::kEliminatable,
static_cast<int>(input_count), 1, "op1");
const TestOperator op1(1, Operator::kEliminatable, input_count, 1);
Node* n = graph()->NewNode(&op1, static_cast<int>(input_count), inputs);
Reduction r = Reduce(n);
EXPECT_FALSE(r.Changed());
......
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