op == Token::SUB);
HValue* left = instr->left();
HValue* right = instr->right();
- ASSERT(left->representation().IsSmiOrTagged());
- ASSERT(right->representation().IsSmiOrTagged());
+ ASSERT(left->representation().IsTagged());
+ ASSERT(right->representation().IsTagged());
LOperand* left_operand = UseFixed(left, r1);
LOperand* right_operand = UseFixed(right, r0);
LArithmeticT* result =
LInstruction* LChunkBuilder::DoBitwise(HBitwise* instr) {
- if (instr->representation().IsInteger32()) {
- ASSERT(instr->left()->representation().IsInteger32());
- ASSERT(instr->right()->representation().IsInteger32());
+ if (instr->representation().IsSmiOrInteger32()) {
+ ASSERT(instr->left()->representation().Equals(instr->representation()));
+ ASSERT(instr->right()->representation().Equals(instr->representation()));
LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
LOperand* right = UseOrConstantAtStart(instr->BetterRightOperand());
return DefineAsRegister(new(zone()) LBitI(left, right));
} else {
- ASSERT(instr->representation().IsSmiOrTagged());
- ASSERT(instr->left()->representation().IsSmiOrTagged());
- ASSERT(instr->right()->representation().IsSmiOrTagged());
+ ASSERT(instr->representation().IsTagged());
+ ASSERT(instr->left()->representation().IsTagged());
+ ASSERT(instr->right()->representation().IsTagged());
LOperand* left = UseFixed(instr->left(), r1);
LOperand* right = UseFixed(instr->right(), r0);
LInstruction* LChunkBuilder::DoDiv(HDiv* instr) {
if (instr->representation().IsDouble()) {
return DoArithmeticD(Token::DIV, instr);
- } else if (instr->representation().IsInteger32()) {
+ } else if (instr->representation().IsSmiOrInteger32()) {
+ ASSERT(instr->left()->representation().Equals(instr->representation()));
+ ASSERT(instr->right()->representation().Equals(instr->representation()));
if (instr->HasPowerOf2Divisor()) {
ASSERT(!instr->CheckFlag(HValue::kCanBeDivByZero));
LOperand* value = UseRegisterAtStart(instr->left());
LInstruction* LChunkBuilder::DoMod(HMod* instr) {
HValue* left = instr->left();
HValue* right = instr->right();
- if (instr->representation().IsInteger32()) {
- ASSERT(left->representation().IsInteger32());
- ASSERT(right->representation().IsInteger32());
+ if (instr->representation().IsSmiOrInteger32()) {
+ ASSERT(instr->left()->representation().Equals(instr->representation()));
+ ASSERT(instr->right()->representation().Equals(instr->representation()));
if (instr->HasPowerOf2Divisor()) {
ASSERT(!right->CanBeZero());
LModI* mod = new(zone()) LModI(UseRegisterAtStart(left),
? AssignEnvironment(result)
: result;
}
- } else if (instr->representation().IsSmiOrTagged()) {
+ } else if (instr->representation().IsTagged()) {
return DoArithmeticT(Token::MOD, instr);
} else {
ASSERT(instr->representation().IsDouble());
LInstruction* LChunkBuilder::DoMul(HMul* instr) {
- if (instr->representation().IsInteger32()) {
- ASSERT(instr->left()->representation().IsInteger32());
- ASSERT(instr->right()->representation().IsInteger32());
+ if (instr->representation().IsSmiOrInteger32()) {
+ ASSERT(instr->left()->representation().Equals(instr->representation()));
+ ASSERT(instr->right()->representation().Equals(instr->representation()));
LOperand* left;
LOperand* right = UseOrConstant(instr->BetterRightOperand());
LOperand* temp = NULL;
LInstruction* LChunkBuilder::DoSub(HSub* instr) {
- if (instr->representation().IsInteger32()) {
- ASSERT(instr->left()->representation().IsInteger32());
- ASSERT(instr->right()->representation().IsInteger32());
+ if (instr->representation().IsSmiOrInteger32()) {
+ ASSERT(instr->left()->representation().Equals(instr->representation()));
+ ASSERT(instr->right()->representation().Equals(instr->representation()));
if (instr->left()->IsConstant()) {
// If lhs is constant, do reverse subtraction instead.
LInstruction* LChunkBuilder::DoRSub(HSub* instr) {
- ASSERT(instr->representation().IsInteger32());
- ASSERT(instr->left()->representation().IsInteger32());
- ASSERT(instr->right()->representation().IsInteger32());
+ ASSERT(instr->representation().IsSmiOrInteger32());
+ ASSERT(instr->left()->representation().Equals(instr->representation()));
+ ASSERT(instr->right()->representation().Equals(instr->representation()));
// Note: The lhs of the subtraction becomes the rhs of the
// reverse-subtraction.
LInstruction* LChunkBuilder::DoAdd(HAdd* instr) {
- if (instr->representation().IsInteger32()) {
- ASSERT(instr->left()->representation().IsInteger32());
- ASSERT(instr->right()->representation().IsInteger32());
+ if (instr->representation().IsSmiOrInteger32()) {
+ ASSERT(instr->left()->representation().Equals(instr->representation()));
+ ASSERT(instr->right()->representation().Equals(instr->representation()));
LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
LOperand* right = UseOrConstantAtStart(instr->BetterRightOperand());
LAddI* add = new(zone()) LAddI(left, right);
return DoArithmeticD(Token::ADD, instr);
} else {
- ASSERT(instr->representation().IsSmiOrTagged());
+ ASSERT(instr->representation().IsTagged());
return DoArithmeticT(Token::ADD, instr);
}
}
LInstruction* LChunkBuilder::DoMathMinMax(HMathMinMax* instr) {
LOperand* left = NULL;
LOperand* right = NULL;
- if (instr->representation().IsInteger32()) {
- ASSERT(instr->left()->representation().IsInteger32());
- ASSERT(instr->right()->representation().IsInteger32());
+ if (instr->representation().IsSmiOrInteger32()) {
+ ASSERT(instr->left()->representation().Equals(instr->representation()));
+ ASSERT(instr->right()->representation().Equals(instr->representation()));
left = UseRegisterAtStart(instr->BetterLeftOperand());
right = UseOrConstantAtStart(instr->BetterRightOperand());
} else {
LInstruction* LChunkBuilder::DoLoadKeyed(HLoadKeyed* instr) {
- ASSERT(instr->key()->representation().IsInteger32() ||
- instr->key()->representation().IsSmi());
+ ASSERT(instr->key()->representation().IsSmiOrInteger32());
ElementsKind elements_kind = instr->elements_kind();
LOperand* key = UseRegisterOrConstantAtStart(instr->key());
LLoadKeyed* result = NULL;
}
-int LCodeGen::ToInteger32(LConstantOperand* op) const {
+int32_t LCodeGen::ToInteger32(LConstantOperand* op) const {
+ return ToRepresentation(op, Representation::Integer32());
+}
+
+
+int32_t LCodeGen::ToRepresentation(LConstantOperand* op,
+ const Representation& r) const {
HConstant* constant = chunk_->LookupConstant(op);
- return constant->Integer32Value();
+ int32_t value = constant->Integer32Value();
+ if (r.IsInteger32()) return value;
+ ASSERT(r.IsSmiOrTagged());
+ return reinterpret_cast<int32_t>(Smi::FromInt(value));
}
LConstantOperand* const_op = LConstantOperand::cast(op);
HConstant* constant = chunk()->LookupConstant(const_op);
Representation r = chunk_->LookupLiteralRepresentation(const_op);
- if (r.IsInteger32()) {
+ if (r.IsSmi()) {
+ ASSERT(constant->HasSmiValue());
+ return Operand(Smi::FromInt(constant->Integer32Value()));
+ } else if (r.IsInteger32()) {
ASSERT(constant->HasInteger32Value());
return Operand(constant->Integer32Value());
} else if (r.IsDouble()) {
if (right_op->IsConstantOperand() && !can_overflow) {
// Use optimized code for specific constants.
- int32_t constant = ToInteger32(LConstantOperand::cast(right_op));
+ int32_t constant = ToRepresentation(
+ LConstantOperand::cast(right_op),
+ instr->hydrogen()->right()->representation());
if (bailout_on_minus_zero && (constant < 0)) {
// The case of a null constant will be handled separately.
if (can_overflow) {
// scratch:result = left * right.
- __ smull(result, scratch, left, right);
+ if (instr->hydrogen()->representation().IsSmi()) {
+ __ SmiUntag(result, left);
+ __ smull(result, scratch, result, right);
+ } else {
+ __ smull(result, scratch, left, right);
+ }
__ cmp(scratch, Operand(result, ASR, 31));
DeoptimizeIf(ne, instr->environment());
} else {
- __ mul(result, left, right);
+ if (instr->hydrogen()->representation().IsSmi()) {
+ __ SmiUntag(result, left);
+ __ mul(result, result, right);
+ } else {
+ __ mul(result, left, right);
+ }
}
if (bailout_on_minus_zero) {
LOperand* left = instr->left();
LOperand* right = instr->right();
HMathMinMax::Operation operation = instr->hydrogen()->operation();
- if (instr->hydrogen()->representation().IsInteger32()) {
+ if (instr->hydrogen()->representation().IsSmiOrInteger32()) {
Condition condition = (operation == HMathMinMax::kMathMin) ? le : ge;
Register left_reg = ToRegister(left);
Operand right_op = (right->IsRegister() || right->IsConstantOperand())
DwVfpRegister EmitLoadDoubleRegister(LOperand* op,
SwVfpRegister flt_scratch,
DwVfpRegister dbl_scratch);
- int ToInteger32(LConstantOperand* op) const;
+ int ToRepresentation(LConstantOperand* op, const Representation& r) const;
+ int32_t ToInteger32(LConstantOperand* op) const;
Smi* ToSmi(LConstantOperand* op) const;
double ToDouble(LConstantOperand* op) const;
Operand ToOperand(LOperand* op);
LConstantOperand* constant_source = LConstantOperand::cast(source);
if (destination->IsRegister()) {
Register dst = cgen_->ToRegister(destination);
- if (cgen_->IsSmi(constant_source)) {
- __ mov(dst, Operand(cgen_->ToSmi(constant_source)));
- } else if (cgen_->IsInteger32(constant_source)) {
- __ mov(dst, Operand(cgen_->ToInteger32(constant_source)));
+ Representation r = cgen_->IsSmi(constant_source)
+ ? Representation::Smi() : Representation::Integer32();
+ if (cgen_->IsInteger32(constant_source)) {
+ __ mov(dst, Operand(cgen_->ToRepresentation(constant_source, r)));
} else {
__ LoadObject(dst, cgen_->ToHandle(constant_source));
}
} else {
ASSERT(destination->IsStackSlot());
ASSERT(!in_cycle_); // Constant moves happen after all cycles are gone.
- if (cgen_->IsSmi(constant_source)) {
- __ mov(kSavedValueRegister, Operand(cgen_->ToSmi(constant_source)));
- } else if (cgen_->IsInteger32(constant_source)) {
+ Representation r = cgen_->IsSmi(constant_source)
+ ? Representation::Smi() : Representation::Integer32();
+ if (cgen_->IsInteger32(constant_source)) {
__ mov(kSavedValueRegister,
- Operand(cgen_->ToInteger32(constant_source)));
+ Operand(cgen_->ToRepresentation(constant_source, r)));
} else {
__ LoadObject(kSavedValueRegister,
cgen_->ToHandle(constant_source));
DEFINE_implication(track_double_fields, track_fields)
DEFINE_implication(track_heap_object_fields, track_fields)
DEFINE_implication(track_computed_fields, track_fields)
+DEFINE_bool(smi_binop, true, "support smi representation in binary operations")
// Flags for data representation optimizations
DEFINE_bool(unbox_double_arrays, true, "automatically unbox arrays of doubles")
for (int i = 0; i < blocks->length(); ++i) {
for (HInstructionIterator it(blocks->at(i)); !it.Done(); it.Advance()) {
HInstruction* instr = it.Current();
- if (instr->IsArithmeticBinaryOperation() &&
- instr->representation().IsInteger32() &&
- instr->HasAtLeastOneUseWithFlagAndNoneWithout(
- HInstruction::kTruncatingToInt32)) {
- instr->SetFlag(HInstruction::kAllUsesTruncatingToInt32);
+ if (instr->IsArithmeticBinaryOperation()) {
+ if (instr->representation().IsInteger32()) {
+ if (instr->HasAtLeastOneUseWithFlagAndNoneWithout(
+ HInstruction::kTruncatingToInt32)) {
+ instr->SetFlag(HInstruction::kAllUsesTruncatingToInt32);
+ }
+ } else if (instr->representation().IsSmi()) {
+ if (instr->HasAtLeastOneUseWithFlagAndNoneWithout(
+ HInstruction::kTruncatingToSmi)) {
+ instr->SetFlag(HInstruction::kAllUsesTruncatingToSmi);
+ }
+ }
}
}
}
UpdateRepresentation(new_rep, h_infer, "inputs");
new_rep = RepresentationFromUses();
UpdateRepresentation(new_rep, h_infer, "uses");
- new_rep = RepresentationFromUseRequirements();
- if (new_rep.fits_into(Representation::Integer32())) {
- UpdateRepresentation(new_rep, h_infer, "use requirements");
+ if (representation().IsSmi() && HasNonSmiUse()) {
+ UpdateRepresentation(
+ Representation::Integer32(), h_infer, "use requirements");
}
}
}
-static int32_t ConvertAndSetOverflow(int64_t result, bool* overflow) {
- if (result > kMaxInt) {
- *overflow = true;
- return kMaxInt;
- }
- if (result < kMinInt) {
- *overflow = true;
- return kMinInt;
+static int32_t ConvertAndSetOverflow(Representation r,
+ int64_t result,
+ bool* overflow) {
+ if (r.IsSmi()) {
+ if (result > Smi::kMaxValue) {
+ *overflow = true;
+ return Smi::kMaxValue;
+ }
+ if (result < Smi::kMinValue) {
+ *overflow = true;
+ return Smi::kMinValue;
+ }
+ } else {
+ if (result > kMaxInt) {
+ *overflow = true;
+ return kMaxInt;
+ }
+ if (result < kMinInt) {
+ *overflow = true;
+ return kMinInt;
+ }
}
return static_cast<int32_t>(result);
}
-static int32_t AddWithoutOverflow(int32_t a, int32_t b, bool* overflow) {
+static int32_t AddWithoutOverflow(Representation r,
+ int32_t a,
+ int32_t b,
+ bool* overflow) {
int64_t result = static_cast<int64_t>(a) + static_cast<int64_t>(b);
- return ConvertAndSetOverflow(result, overflow);
+ return ConvertAndSetOverflow(r, result, overflow);
}
-static int32_t SubWithoutOverflow(int32_t a, int32_t b, bool* overflow) {
+static int32_t SubWithoutOverflow(Representation r,
+ int32_t a,
+ int32_t b,
+ bool* overflow) {
int64_t result = static_cast<int64_t>(a) - static_cast<int64_t>(b);
- return ConvertAndSetOverflow(result, overflow);
+ return ConvertAndSetOverflow(r, result, overflow);
}
-static int32_t MulWithoutOverflow(int32_t a, int32_t b, bool* overflow) {
+static int32_t MulWithoutOverflow(const Representation& r,
+ int32_t a,
+ int32_t b,
+ bool* overflow) {
int64_t result = static_cast<int64_t>(a) * static_cast<int64_t>(b);
- return ConvertAndSetOverflow(result, overflow);
+ return ConvertAndSetOverflow(r, result, overflow);
}
void Range::AddConstant(int32_t value) {
if (value == 0) return;
bool may_overflow = false; // Overflow is ignored here.
- lower_ = AddWithoutOverflow(lower_, value, &may_overflow);
- upper_ = AddWithoutOverflow(upper_, value, &may_overflow);
+ Representation r = Representation::Integer32();
+ lower_ = AddWithoutOverflow(r, lower_, value, &may_overflow);
+ upper_ = AddWithoutOverflow(r, upper_, value, &may_overflow);
#ifdef DEBUG
Verify();
#endif
}
-bool Range::AddAndCheckOverflow(Range* other) {
+bool Range::AddAndCheckOverflow(const Representation& r, Range* other) {
bool may_overflow = false;
- lower_ = AddWithoutOverflow(lower_, other->lower(), &may_overflow);
- upper_ = AddWithoutOverflow(upper_, other->upper(), &may_overflow);
+ lower_ = AddWithoutOverflow(r, lower_, other->lower(), &may_overflow);
+ upper_ = AddWithoutOverflow(r, upper_, other->upper(), &may_overflow);
KeepOrder();
#ifdef DEBUG
Verify();
}
-bool Range::SubAndCheckOverflow(Range* other) {
+bool Range::SubAndCheckOverflow(const Representation& r, Range* other) {
bool may_overflow = false;
- lower_ = SubWithoutOverflow(lower_, other->upper(), &may_overflow);
- upper_ = SubWithoutOverflow(upper_, other->lower(), &may_overflow);
+ lower_ = SubWithoutOverflow(r, lower_, other->upper(), &may_overflow);
+ upper_ = SubWithoutOverflow(r, upper_, other->lower(), &may_overflow);
KeepOrder();
#ifdef DEBUG
Verify();
#endif
-bool Range::MulAndCheckOverflow(Range* other) {
+bool Range::MulAndCheckOverflow(const Representation& r, Range* other) {
bool may_overflow = false;
- int v1 = MulWithoutOverflow(lower_, other->lower(), &may_overflow);
- int v2 = MulWithoutOverflow(lower_, other->upper(), &may_overflow);
- int v3 = MulWithoutOverflow(upper_, other->lower(), &may_overflow);
- int v4 = MulWithoutOverflow(upper_, other->upper(), &may_overflow);
+ int v1 = MulWithoutOverflow(r, lower_, other->lower(), &may_overflow);
+ int v2 = MulWithoutOverflow(r, lower_, other->upper(), &may_overflow);
+ int v3 = MulWithoutOverflow(r, upper_, other->lower(), &may_overflow);
+ int v4 = MulWithoutOverflow(r, upper_, other->upper(), &may_overflow);
lower_ = Min(Min(v1, v2), Min(v3, v4));
upper_ = Max(Max(v1, v2), Max(v3, v4));
#ifdef DEBUG
HValue* HBitwise::Canonicalize() {
- if (!representation().IsInteger32()) return this;
+ if (!representation().IsSmiOrInteger32()) return this;
// If x is an int32, then x & -1 == x, x | 0 == x and x ^ 0 == x.
int32_t nop_constant = (op() == Token::BIT_AND) ? -1 : 0;
if (left()->EqualsInteger32Constant(nop_constant) &&
// If the input is integer32 then we replace the floor instruction
// with its input.
- if (val->representation().IsInteger32()) return val;
+ if (val->representation().IsSmiOrInteger32()) return val;
if (val->IsDiv() && (val->UseCount() == 1)) {
HDiv* hdiv = HDiv::cast(val);
HValue* new_left = SimplifiedDividendForMathFloorOfDiv(left);
if (new_left == NULL &&
hdiv->observed_input_representation(1).IsSmiOrInteger32()) {
- new_left = new(block()->zone())
- HChange(left, Representation::Integer32(), false, false);
+ new_left = new(block()->zone()) HChange(
+ left, Representation::Integer32(), false, false, false);
HChange::cast(new_left)->InsertBefore(this);
}
HValue* new_right =
CpuFeatures::IsSupported(SUDIV) &&
#endif
hdiv->observed_input_representation(2).IsSmiOrInteger32()) {
- new_right = new(block()->zone())
- HChange(right, Representation::Integer32(), false, false);
+ new_right = new(block()->zone()) HChange(
+ right, Representation::Integer32(), false, false, false);
HChange::cast(new_right)->InsertBefore(this);
}
Range* HValue::InferRange(Zone* zone) {
Range* result;
- if (type().IsSmi()) {
+ if (representation().IsSmi() || type().IsSmi()) {
result = new(zone) Range(Smi::kMinValue, Smi::kMaxValue);
result->set_can_be_minus_zero(false);
} else {
Range* HChange::InferRange(Zone* zone) {
Range* input_range = value()->range();
- if (from().IsInteger32() &&
- to().IsSmiOrTagged() &&
- !value()->CheckFlag(HInstruction::kUint32) &&
- input_range != NULL && input_range->IsInSmiRange()) {
+ if (from().IsInteger32() && !value()->CheckFlag(HInstruction::kUint32) &&
+ (to().IsSmi() ||
+ (to().IsTagged() &&
+ input_range != NULL &&
+ input_range->IsInSmiRange()))) {
set_type(HType::Smi());
ClearGVNFlag(kChangesNewSpacePromotion);
}
? input_range->Copy(zone)
: HValue::InferRange(zone);
result->set_can_be_minus_zero(!to().IsSmiOrInteger32() ||
- !CheckFlag(kAllUsesTruncatingToInt32));
+ !(CheckFlag(kAllUsesTruncatingToInt32) ||
+ CheckFlag(kAllUsesTruncatingToSmi)));
+ if (to().IsSmi()) result->ClampToSmi();
return result;
}
Range* HAdd::InferRange(Zone* zone) {
- if (representation().IsInteger32()) {
+ Representation r = representation();
+ if (r.IsSmiOrInteger32()) {
Range* a = left()->range();
Range* b = right()->range();
Range* res = a->Copy(zone);
- if (!res->AddAndCheckOverflow(b) ||
- CheckFlag(kAllUsesTruncatingToInt32)) {
+ if (!res->AddAndCheckOverflow(r, b) ||
+ (r.IsInteger32() && CheckFlag(kAllUsesTruncatingToInt32)) ||
+ (r.IsSmi() && CheckFlag(kAllUsesTruncatingToSmi))) {
ClearFlag(kCanOverflow);
}
- res->set_can_be_minus_zero(!CheckFlag(kAllUsesTruncatingToInt32) &&
+ res->set_can_be_minus_zero(!CheckFlag(kAllUsesTruncatingToSmi) &&
+ !CheckFlag(kAllUsesTruncatingToInt32) &&
a->CanBeMinusZero() && b->CanBeMinusZero());
return res;
} else {
Range* HSub::InferRange(Zone* zone) {
- if (representation().IsInteger32()) {
+ Representation r = representation();
+ if (r.IsSmiOrInteger32()) {
Range* a = left()->range();
Range* b = right()->range();
Range* res = a->Copy(zone);
- if (!res->SubAndCheckOverflow(b) ||
- CheckFlag(kAllUsesTruncatingToInt32)) {
+ if (!res->SubAndCheckOverflow(r, b) ||
+ (r.IsInteger32() && CheckFlag(kAllUsesTruncatingToInt32)) ||
+ (r.IsSmi() && CheckFlag(kAllUsesTruncatingToSmi))) {
ClearFlag(kCanOverflow);
}
- res->set_can_be_minus_zero(!CheckFlag(kAllUsesTruncatingToInt32) &&
+ res->set_can_be_minus_zero(!CheckFlag(kAllUsesTruncatingToSmi) &&
+ !CheckFlag(kAllUsesTruncatingToInt32) &&
a->CanBeMinusZero() && b->CanBeZero());
return res;
} else {
Range* HMul::InferRange(Zone* zone) {
- if (representation().IsInteger32()) {
+ Representation r = representation();
+ if (r.IsSmiOrInteger32()) {
Range* a = left()->range();
Range* b = right()->range();
Range* res = a->Copy(zone);
- if (!res->MulAndCheckOverflow(b)) {
+ if (!res->MulAndCheckOverflow(r, b)) {
// Clearing the kCanOverflow flag when kAllUsesAreTruncatingToInt32
// would be wrong, because truncated integer multiplication is too
// precise and therefore not the same as converting to Double and back.
ClearFlag(kCanOverflow);
}
- res->set_can_be_minus_zero(!CheckFlag(kAllUsesTruncatingToInt32) &&
+ res->set_can_be_minus_zero(!CheckFlag(kAllUsesTruncatingToSmi) &&
+ !CheckFlag(kAllUsesTruncatingToInt32) &&
((a->CanBeZero() && b->CanBeNegative()) ||
(a->CanBeNegative() && b->CanBeZero())));
return res;
Range* HMathMinMax::InferRange(Zone* zone) {
- if (representation().IsInteger32()) {
+ if (representation().IsSmiOrInteger32()) {
Range* a = left()->range();
Range* b = right()->range();
Range* res = a->Copy(zone);
// Compute a conservative approximation of truncating uses before inferring
// representations. The proper, exact computation will be done later, when
// inserting representation changes.
+ SetFlag(kTruncatingToSmi);
SetFlag(kTruncatingToInt32);
for (HUseIterator it(uses()); !it.Done(); it.Advance()) {
HValue* value = it.value();
PrintF("#%d Phi is used by real #%d %s as %s\n",
id(), value->id(), value->Mnemonic(), rep.Mnemonic());
}
- if (!value->IsSimulate() && !value->CheckFlag(kTruncatingToInt32)) {
- ClearFlag(kTruncatingToInt32);
+ if (!value->IsSimulate()) {
+ if (!value->CheckFlag(kTruncatingToSmi)) {
+ ClearFlag(kTruncatingToSmi);
+ }
+ if (!value->CheckFlag(kTruncatingToInt32)) {
+ ClearFlag(kTruncatingToInt32);
+ }
}
}
}
void HConstant::Initialize(Representation r) {
if (r.IsNone()) {
- if (has_smi_value_) {
+ if (has_smi_value_ && kSmiValueSize == 31) {
r = Representation::Smi();
} else if (has_int32_value_) {
r = Representation::Integer32();
ASSERT(CheckFlag(kFlexibleRepresentation));
Representation new_rep = RepresentationFromInputs();
UpdateRepresentation(new_rep, h_infer, "inputs");
- // When the operation has information about its own output type, don't look
- // at uses.
- if (!observed_output_representation_.IsNone()) return;
- new_rep = RepresentationFromUses();
- UpdateRepresentation(new_rep, h_infer, "uses");
- new_rep = RepresentationFromUseRequirements();
- if (new_rep.fits_into(Representation::Integer32())) {
- UpdateRepresentation(new_rep, h_infer, "use requirements");
+ if (observed_output_representation_.IsNone()) {
+ new_rep = RepresentationFromUses();
+ UpdateRepresentation(new_rep, h_infer, "uses");
+ } else {
+ new_rep = RepresentationFromOutput();
+ UpdateRepresentation(new_rep, h_infer, "output");
}
-}
-
-bool HBinaryOperation::IgnoreObservedOutputRepresentation(
- Representation current_rep) {
- return observed_output_representation_.IsDouble() &&
- current_rep.IsInteger32() &&
- // Mul in Integer32 mode would be too precise.
- !this->IsMul() &&
- CheckUsesForFlag(kTruncatingToInt32);
+ if (representation().IsSmi() && HasNonSmiUse()) {
+ UpdateRepresentation(
+ Representation::Integer32(), h_infer, "use requirements");
+ }
}
// the currently assumed output representation.
Representation rep = representation();
for (int i = 1; i <= 2; ++i) {
- Representation input_rep = observed_input_representation(i);
- if (input_rep.is_more_general_than(rep)) rep = input_rep;
+ rep = rep.generalize(observed_input_representation(i));
}
// If any of the actual input representation is more general than what we
// have so far but not Tagged, use that representation instead.
Representation left_rep = left()->representation();
Representation right_rep = right()->representation();
+ if (!left_rep.IsTagged()) rep = rep.generalize(left_rep);
+ if (!right_rep.IsTagged()) rep = rep.generalize(right_rep);
- if (left_rep.is_more_general_than(rep) && !left_rep.IsTagged()) {
- rep = left_rep;
- }
- if (right_rep.is_more_general_than(rep) && !right_rep.IsTagged()) {
- rep = right_rep;
- }
+ return rep;
+}
+
+
+bool HBinaryOperation::IgnoreObservedOutputRepresentation(
+ Representation current_rep) {
+ return ((current_rep.IsInteger32() && CheckUsesForFlag(kTruncatingToInt32)) ||
+ (current_rep.IsSmi() && CheckUsesForFlag(kTruncatingToSmi))) &&
+ // Mul in Integer32 mode would be too precise.
+ !this->IsMul();
+}
+
+
+Representation HBinaryOperation::RepresentationFromOutput() {
+ Representation rep = representation();
// Consider observed output representation, but ignore it if it's Double,
// this instruction is not a division, and all its uses are truncating
// to Integer32.
if (observed_output_representation_.is_more_general_than(rep) &&
!IgnoreObservedOutputRepresentation(rep)) {
- rep = observed_output_representation_;
+ return observed_output_representation_;
}
- return rep;
+ return Representation::None();
}
HValue* HUnaryMathOperation::EnsureAndPropagateNotMinusZero(
BitVector* visited) {
visited->Add(id());
- if (representation().IsInteger32() &&
- !value()->representation().IsInteger32()) {
+ if (representation().IsSmiOrInteger32() &&
+ !value()->representation().Equals(representation())) {
if (value()->range() == NULL || value()->range()->CanBeMinusZero()) {
SetFlag(kBailoutOnMinusZero);
}
}
- if (RequiredInputRepresentation(0).IsInteger32() &&
- representation().IsInteger32()) {
+ if (RequiredInputRepresentation(0).IsSmiOrInteger32() &&
+ representation().Equals(RequiredInputRepresentation(0))) {
return value();
}
return NULL;
}
-
HValue* HChange::EnsureAndPropagateNotMinusZero(BitVector* visited) {
visited->Add(id());
- if (from().IsInteger32()) return NULL;
+ if (from().IsSmiOrInteger32()) return NULL;
if (CanTruncateToInt32()) return NULL;
if (value()->range() == NULL || value()->range()->CanBeMinusZero()) {
SetFlag(kBailoutOnMinusZero);
}
- ASSERT(!from().IsInteger32() || !to().IsInteger32());
+ ASSERT(!from().IsSmiOrInteger32() || !to().IsSmiOrInteger32());
return NULL;
}
}
if (value()->IsChange()) {
- if (HChange::cast(value())->from().IsInteger32()) {
+ if (HChange::cast(value())->from().IsSmiOrInteger32()) {
return false;
}
if (HChange::cast(value())->value()->type().IsSmi()) {
}
-#define H_CONSTANT_INT32(val) \
-new(zone) HConstant(static_cast<int32_t>(val), Representation::Integer32())
+#define H_CONSTANT_INT(val) \
+new(zone) HConstant(static_cast<int32_t>(val))
#define H_CONSTANT_DOUBLE(val) \
new(zone) HConstant(static_cast<double>(val), Representation::Double())
if ((c_left->HasNumberValue() && c_right->HasNumberValue())) { \
double double_res = c_left->DoubleValue() op c_right->DoubleValue(); \
if (TypeInfo::IsInt32Double(double_res)) { \
- return H_CONSTANT_INT32(double_res); \
+ return H_CONSTANT_INT(double_res); \
} \
return H_CONSTANT_DOUBLE(double_res); \
} \
if ((res == 0) && (dividend < 0)) {
return H_CONSTANT_DOUBLE(-0.0);
}
- return H_CONSTANT_INT32(res);
+ return H_CONSTANT_INT(res);
}
}
}
if (c_right->DoubleValue() != 0) {
double double_res = c_left->DoubleValue() / c_right->DoubleValue();
if (TypeInfo::IsInt32Double(double_res)) {
- return H_CONSTANT_INT32(double_res);
+ return H_CONSTANT_INT(double_res);
}
return H_CONSTANT_DOUBLE(double_res);
} else {
result = 0; // Please the compiler.
UNREACHABLE();
}
- return H_CONSTANT_INT32(result);
+ return H_CONSTANT_INT(result);
}
}
return new(zone) HBitwise(op, context, left, right);
HConstant* c_left = HConstant::cast(left); \
HConstant* c_right = HConstant::cast(right); \
if ((c_left->HasNumberValue() && c_right->HasNumberValue())) { \
- return H_CONSTANT_INT32(result); \
+ return H_CONSTANT_INT(result); \
} \
} \
return new(zone) HInstr(context, left, right); \
if ((right_val == 0) && (left_val < 0)) {
return H_CONSTANT_DOUBLE(static_cast<uint32_t>(left_val));
}
- return H_CONSTANT_INT32(static_cast<uint32_t>(left_val) >> right_val);
+ return H_CONSTANT_INT(static_cast<uint32_t>(left_val) >> right_val);
}
}
return new(zone) HShr(context, left, right);
}
-#undef H_CONSTANT_INT32
+#undef H_CONSTANT_INT
#undef H_CONSTANT_DOUBLE
continue;
} else if (operand->HasDoubleValue()) {
HConstant* integer_input =
- new(graph->zone()) HConstant(DoubleToInt32(operand->DoubleValue()),
- Representation::Integer32());
+ new(graph->zone()) HConstant(DoubleToInt32(operand->DoubleValue()));
integer_input->InsertAfter(operand);
SetOperandAt(i, integer_input);
} else if (operand == graph->GetConstantTrue()) {
HValue* use = it.value();
if (use->IsBinaryOperation()) {
HBinaryOperation::cast(use)->set_observed_input_representation(
- it.index(), Representation::Integer32());
+ it.index(), Representation::Smi());
}
}
}
}
+bool HValue::HasNonSmiUse() {
+ for (HUseIterator it(uses()); !it.Done(); it.Advance()) {
+ // We check for observed_input_representation elsewhere.
+ Representation use_rep =
+ it.value()->RequiredInputRepresentation(it.index());
+ if (!use_rep.IsNone() && !use_rep.IsSmi()) return true;
+ }
+ return false;
+}
+
+
// Node-specific verification code is only included in debug mode.
#ifdef DEBUG
void AddConstant(int32_t value);
void Sar(int32_t value);
void Shl(int32_t value);
- bool AddAndCheckOverflow(Range* other);
- bool SubAndCheckOverflow(Range* other);
- bool MulAndCheckOverflow(Range* other);
+ bool AddAndCheckOverflow(const Representation& r, Range* other);
+ bool SubAndCheckOverflow(const Representation& r, Range* other);
+ bool MulAndCheckOverflow(const Representation& r, Range* other);
private:
int32_t lower_;
kIsArguments,
kTruncatingToInt32,
kAllUsesTruncatingToInt32,
+ kTruncatingToSmi,
+ kAllUsesTruncatingToSmi,
// Set after an instruction is killed.
kIsDead,
// Instructions that are allowed to produce full range unsigned integer
HUseIterator uses() const { return HUseIterator(use_list_); }
virtual bool EmitAtUses() { return false; }
+
Representation representation() const { return representation_; }
void ChangeRepresentation(Representation r) {
ASSERT(CheckFlag(kFlexibleRepresentation));
}
Representation RepresentationFromUses();
Representation RepresentationFromUseRequirements();
+ bool HasNonSmiUse();
virtual void UpdateRepresentation(Representation new_rep,
HInferRepresentationPhase* h_infer,
const char* reason);
public:
HChange(HValue* value,
Representation to,
- bool is_truncating,
+ bool is_truncating_to_smi,
+ bool is_truncating_to_int32,
bool allow_undefined_as_nan)
: HUnaryOperation(value) {
ASSERT(!value->representation().IsNone());
set_representation(to);
SetFlag(kUseGVN);
if (allow_undefined_as_nan) SetFlag(kAllowUndefinedAsNaN);
- if (is_truncating) SetFlag(kTruncatingToInt32);
+ if (is_truncating_to_smi) SetFlag(kTruncatingToSmi);
+ if (is_truncating_to_int32) SetFlag(kTruncatingToInt32);
if (value->representation().IsSmi() || value->type().IsSmi()) {
set_type(HType::Smi());
} else {
switch (op) {
case kMathFloor:
case kMathRound:
+ // TODO(verwaest): Set representation to flexible int starting as smi.
set_representation(Representation::Integer32());
break;
case kMathAbs:
}
virtual Representation KnownOptimalRepresentation() {
- if (HasSmiValue()) return Representation::Smi();
+ if (HasSmiValue() && kSmiValueSize == 31) return Representation::Smi();
if (HasInteger32Value()) return Representation::Integer32();
if (HasNumberValue()) return Representation::Double();
return Representation::Tagged();
// Otherwise, if there is only one use of the right operand, it would be
// better off on the left for platforms that only have 2-arg arithmetic
// ops (e.g ia32, x64) that clobber the left operand.
- return (right()->UseCount() == 1);
+ return right()->UseCount() == 1;
}
HValue* BetterLeftOperand() {
return observed_input_representation_[index - 1];
}
- virtual void InferRepresentation(HInferRepresentationPhase* h_infer);
- virtual Representation RepresentationFromInputs();
- virtual void AssumeRepresentation(Representation r);
-
virtual void UpdateRepresentation(Representation new_rep,
HInferRepresentationPhase* h_infer,
const char* reason) {
- // By default, binary operations don't handle Smis.
- if (new_rep.IsSmi()) {
- new_rep = Representation::Integer32();
- }
- HValue::UpdateRepresentation(new_rep, h_infer, reason);
+ Representation rep = !FLAG_smi_binop && new_rep.IsSmi()
+ ? Representation::Integer32() : new_rep;
+ HValue::UpdateRepresentation(rep, h_infer, reason);
}
+ virtual void InferRepresentation(HInferRepresentationPhase* h_infer);
+ virtual Representation RepresentationFromInputs();
+ Representation RepresentationFromOutput();
+ virtual void AssumeRepresentation(Representation r);
+
virtual bool IsCommutative() const { return false; }
virtual void PrintDataTo(StringStream* stream);
+ virtual Representation RequiredInputRepresentation(int index) {
+ if (index == 0) return Representation::Tagged();
+ return representation();
+ }
+
DECLARE_ABSTRACT_INSTRUCTION(BinaryOperation)
private:
SetAllSideEffects();
}
- virtual Representation RequiredInputRepresentation(int index) {
- return index == 0
- ? Representation::Tagged()
- : representation();
- }
-
virtual void RepresentationChanged(Representation to) {
if (!to.IsTagged()) {
- ASSERT(to.IsInteger32());
+ ASSERT(to.IsSmiOrInteger32());
ClearAllSideEffects();
SetFlag(kUseGVN);
} else {
HInferRepresentationPhase* h_infer,
const char* reason) {
// We only generate either int32 or generic tagged bitwise operations.
- if (new_rep.IsSmi() || new_rep.IsDouble()) {
- new_rep = Representation::Integer32();
- }
- HValue::UpdateRepresentation(new_rep, h_infer, reason);
+ if (new_rep.IsDouble()) new_rep = Representation::Integer32();
+ HBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
+ }
+
+ virtual Representation observed_input_representation(int index) {
+ Representation r = HBinaryOperation::observed_input_representation(index);
+ if (r.IsDouble()) return Representation::Integer32();
+ return r;
}
virtual void initialize_output_representation(Representation observed) {
}
virtual HType CalculateInferredType();
- virtual Representation RequiredInputRepresentation(int index) {
- return index == 0
- ? Representation::Tagged()
- : representation();
- }
DECLARE_ABSTRACT_INSTRUCTION(ArithmeticBinaryOperation)
return !representation().IsTagged();
}
+ virtual void UpdateRepresentation(Representation new_rep,
+ HInferRepresentationPhase* h_infer,
+ const char* reason) {
+ if (new_rep.IsSmi()) new_rep = Representation::Integer32();
+ HArithmeticBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
+ }
+
DECLARE_CONCRETE_INSTRUCTION(Mul)
protected:
virtual HValue* Canonicalize();
+ virtual void UpdateRepresentation(Representation new_rep,
+ HInferRepresentationPhase* h_infer,
+ const char* reason) {
+ if (new_rep.IsSmi()) new_rep = Representation::Integer32();
+ HArithmeticBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
+ }
+
DECLARE_CONCRETE_INSTRUCTION(Mod)
protected:
virtual HValue* Canonicalize();
+ virtual void UpdateRepresentation(Representation new_rep,
+ HInferRepresentationPhase* h_infer,
+ const char* reason) {
+ if (new_rep.IsSmi()) new_rep = Representation::Integer32();
+ HArithmeticBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
+ }
+
DECLARE_CONCRETE_INSTRUCTION(Div)
protected:
virtual Representation RepresentationFromInputs() {
Representation left_rep = left()->representation();
Representation right_rep = right()->representation();
- if ((left_rep.IsNone() || left_rep.IsInteger32()) &&
- (right_rep.IsNone() || right_rep.IsInteger32())) {
- return Representation::Integer32();
- }
- return Representation::Double();
+ Representation result = Representation::Smi();
+ result = result.generalize(left_rep);
+ result = result.generalize(right_rep);
+ if (result.IsTagged()) return Representation::Double();
+ return result;
}
virtual bool IsCommutative() const { return true; }
HBitwise(Token::Value op, HValue* context, HValue* left, HValue* right)
: HBitwiseBinaryOperation(context, left, right), op_(op) {
ASSERT(op == Token::BIT_AND || op == Token::BIT_OR || op == Token::BIT_XOR);
+ // BIT_AND with a smi-range positive value will always unset the
+ // entire sign-extension of the smi-sign.
+ if (op == Token::BIT_AND &&
+ ((left->IsConstant() &&
+ left->representation().IsSmi() &&
+ HConstant::cast(left)->Integer32Value() >= 0) ||
+ (right->IsConstant() &&
+ right->representation().IsSmi() &&
+ HConstant::cast(right)->Integer32Value() >= 0))) {
+ SetFlag(kTruncatingToSmi);
+ // BIT_OR with a smi-range negative value will always set the entire
+ // sign-extension of the smi-sign.
+ } else if (op == Token::BIT_OR &&
+ ((left->IsConstant() &&
+ left->representation().IsSmi() &&
+ HConstant::cast(left)->Integer32Value() < 0) ||
+ (right->IsConstant() &&
+ right->representation().IsSmi() &&
+ HConstant::cast(right)->Integer32Value() < 0))) {
+ SetFlag(kTruncatingToSmi);
+ }
}
Token::Value op_;
virtual Range* InferRange(Zone* zone);
+ virtual void UpdateRepresentation(Representation new_rep,
+ HInferRepresentationPhase* h_infer,
+ const char* reason) {
+ if (new_rep.IsSmi()) new_rep = Representation::Integer32();
+ HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
+ }
+
DECLARE_CONCRETE_INSTRUCTION(Shl)
protected:
virtual Range* InferRange(Zone* zone);
+ virtual void UpdateRepresentation(Representation new_rep,
+ HInferRepresentationPhase* h_infer,
+ const char* reason) {
+ if (new_rep.IsSmi()) new_rep = Representation::Integer32();
+ HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
+ }
+
DECLARE_CONCRETE_INSTRUCTION(Shr)
protected:
virtual Range* InferRange(Zone* zone);
+ virtual void UpdateRepresentation(Representation new_rep,
+ HInferRepresentationPhase* h_infer,
+ const char* reason) {
+ if (new_rep.IsSmi()) new_rep = Representation::Integer32();
+ HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
+ }
+
DECLARE_CONCRETE_INSTRUCTION(Sar)
protected:
ChangeRepresentation(Representation::Integer32());
}
+ virtual void UpdateRepresentation(Representation new_rep,
+ HInferRepresentationPhase* h_infer,
+ const char* reason) {
+ if (new_rep.IsSmi()) new_rep = Representation::Integer32();
+ HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
+ }
+
DECLARE_CONCRETE_INSTRUCTION(Ror)
protected:
// int32-to-tagged and int32-to-double.
Representation from = change->value()->representation();
ASSERT(from.Equals(change->from()));
- if (from.IsInteger32()) {
+ if (from.IsSmiOrInteger32()) {
ASSERT(change->to().IsTagged() ||
change->to().IsDouble() ||
- change->to().IsSmi());
+ change->to().IsSmiOrInteger32());
ASSERT(visited_.IsEmpty());
PropagateMinusZeroChecks(change->value());
visited_.Clear();
// information we treat constants like normal instructions and insert the
// change instructions for them.
HInstruction* new_value = NULL;
- bool is_truncating = use_value->CheckFlag(HValue::kTruncatingToInt32);
+ bool is_truncating_to_smi = use_value->CheckFlag(HValue::kTruncatingToSmi);
+ bool is_truncating_to_int = use_value->CheckFlag(HValue::kTruncatingToInt32);
bool allow_undefined_as_nan =
use_value->CheckFlag(HValue::kAllowUndefinedAsNaN);
if (value->IsConstant()) {
HConstant* constant = HConstant::cast(value);
// Try to create a new copy of the constant with the new representation.
- if (is_truncating && to.IsInteger32()) {
+ if (is_truncating_to_int && to.IsInteger32()) {
Maybe<HConstant*> res = constant->CopyToTruncatedInt32(graph()->zone());
if (res.has_value) new_value = res.value;
} else {
if (new_value == NULL) {
new_value = new(graph()->zone()) HChange(value, to,
- is_truncating,
+ is_truncating_to_smi,
+ is_truncating_to_int,
allow_undefined_as_nan);
}
HPhi* phi = phi_list->at(i);
if (phi->representation().IsInteger32()) {
phi->SetFlag(HValue::kTruncatingToInt32);
+ } else if (phi->representation().IsSmi()) {
+ phi->SetFlag(HValue::kTruncatingToSmi);
}
}
HValue* use = it.value();
Representation input_representation =
use->RequiredInputRepresentation(it.index());
- if (!input_representation.IsInteger32() ||
- !use->CheckFlag(HValue::kTruncatingToInt32)) {
+ if ((phi->representation().IsInteger32() &&
+ !(input_representation.IsInteger32() &&
+ use->CheckFlag(HValue::kTruncatingToInt32))) ||
+ (phi->representation().IsSmi() &&
+ !(input_representation.IsSmi() ||
+ use->CheckFlag(HValue::kTruncatingToSmi)))) {
if (FLAG_trace_representation) {
PrintF("#%d Phi is not truncating because of #%d %s\n",
phi->id(), it.value()->id(), it.value()->Mnemonic());
}
phi->ClearFlag(HValue::kTruncatingToInt32);
+ phi->ClearFlag(HValue::kTruncatingToSmi);
worklist.Add(phi, zone());
break;
}
for (int i = 0; i < current->OperandCount(); ++i) {
HValue* input = current->OperandAt(i);
if (input->IsPhi() &&
- input->representation().IsInteger32() &&
- input->CheckFlag(HValue::kTruncatingToInt32)) {
+ ((input->representation().IsInteger32() &&
+ input->CheckFlag(HValue::kTruncatingToInt32)) ||
+ (input->representation().IsSmi() &&
+ input->CheckFlag(HValue::kTruncatingToSmi)))) {
if (FLAG_trace_representation) {
PrintF("#%d Phi is not truncating because of #%d %s\n",
input->id(), current->id(), current->Mnemonic());
}
input->ClearFlag(HValue::kTruncatingToInt32);
+ input->ClearFlag(HValue::kTruncatingToSmi);
worklist.Add(HPhi::cast(input), zone());
}
}
base_size += AllocationMemento::kSize;
}
- if (IsFastDoubleElementsKind(kind_)) {
- base_size += FixedDoubleArray::kHeaderSize;
- } else {
- base_size += FixedArray::kHeaderSize;
- }
+ STATIC_ASSERT(FixedDoubleArray::kHeaderSize == FixedArray::kHeaderSize);
+ base_size += FixedArray::kHeaderSize;
HInstruction* elements_size_value =
builder()->Add<HConstant>(elements_size());
environment()->LookupContext(),
current_index,
graph()->GetConstant1());
- new_index->AssumeRepresentation(Representation::Integer32());
PushAndAdd(new_index);
body_exit = current_block();
}
}
-int LCodeGen::ToInteger32(LConstantOperand* op) const {
+int32_t LCodeGen::ToInteger32(LConstantOperand* op) const {
+ return ToRepresentation(op, Representation::Integer32());
+}
+
+
+int32_t LCodeGen::ToRepresentation(LConstantOperand* op,
+ const Representation& r) const {
HConstant* constant = chunk_->LookupConstant(op);
- return constant->Integer32Value();
+ int32_t value = constant->Integer32Value();
+ if (r.IsInteger32()) return value;
+ ASSERT(r.IsSmiOrTagged());
+ return reinterpret_cast<int32_t>(Smi::FromInt(value));
}
__ imul(left, left, constant);
}
} else {
+ if (instr->hydrogen()->representation().IsSmi()) {
+ __ SmiUntag(left);
+ }
__ imul(left, ToOperand(right));
}
ASSERT(left->IsRegister());
if (right->IsConstantOperand()) {
- int right_operand = ToInteger32(LConstantOperand::cast(right));
+ int right_operand = ToRepresentation(LConstantOperand::cast(right),
+ instr->hydrogen()->representation());
switch (instr->op()) {
case Token::BIT_AND:
__ and_(ToRegister(left), right_operand);
ASSERT(left->Equals(instr->result()));
if (right->IsConstantOperand()) {
- __ sub(ToOperand(left), ToInteger32Immediate(right));
+ __ sub(ToOperand(left),
+ ToImmediate(right, instr->hydrogen()->representation()));
} else {
__ sub(ToRegister(left), ToOperand(right));
}
if (LAddI::UseLea(instr->hydrogen()) && !left->Equals(instr->result())) {
if (right->IsConstantOperand()) {
- int32_t offset = ToInteger32(LConstantOperand::cast(right));
+ int32_t offset = ToRepresentation(LConstantOperand::cast(right),
+ instr->hydrogen()->representation());
__ lea(ToRegister(instr->result()), MemOperand(ToRegister(left), offset));
} else {
Operand address(ToRegister(left), ToRegister(right), times_1, 0);
}
} else {
if (right->IsConstantOperand()) {
- __ add(ToOperand(left), ToInteger32Immediate(right));
+ __ add(ToOperand(left),
+ ToImmediate(right, instr->hydrogen()->representation()));
} else {
__ add(ToRegister(left), ToOperand(right));
}
LOperand* right = instr->right();
ASSERT(left->Equals(instr->result()));
HMathMinMax::Operation operation = instr->hydrogen()->operation();
- if (instr->hydrogen()->representation().IsInteger32()) {
+ if (instr->hydrogen()->representation().IsSmiOrInteger32()) {
Label return_left;
Condition condition = (operation == HMathMinMax::kMathMin)
? less_equal
: greater_equal;
if (right->IsConstantOperand()) {
Operand left_op = ToOperand(left);
- Immediate right_imm = ToInteger32Immediate(right);
- __ cmp(left_op, right_imm);
+ Immediate immediate = ToImmediate(LConstantOperand::cast(instr->right()),
+ instr->hydrogen()->representation());
+ __ cmp(left_op, immediate);
__ j(condition, &return_left, Label::kNear);
- __ mov(left_op, right_imm);
+ __ mov(left_op, immediate);
} else {
Register left_reg = ToRegister(left);
Operand right_op = ToOperand(right);
__ j(parity_even, instr->FalseLabel(chunk_));
} else {
if (right->IsConstantOperand()) {
- int32_t const_value = ToInteger32(LConstantOperand::cast(right));
- if (instr->hydrogen_value()->representation().IsSmi()) {
- __ cmp(ToOperand(left), Immediate(Smi::FromInt(const_value)));
- } else {
- __ cmp(ToOperand(left), Immediate(const_value));
- }
+ __ cmp(ToOperand(left),
+ ToImmediate(right, instr->hydrogen()->representation()));
} else if (left->IsConstantOperand()) {
- int32_t const_value = ToInteger32(LConstantOperand::cast(left));
- if (instr->hydrogen_value()->representation().IsSmi()) {
- __ cmp(ToOperand(right), Immediate(Smi::FromInt(const_value)));
- } else {
- __ cmp(ToOperand(right), Immediate(const_value));
- }
+ __ cmp(ToOperand(right),
+ ToImmediate(left, instr->hydrogen()->representation()));
// We transposed the operands. Reverse the condition.
cc = ReverseCondition(cc);
} else {
if (instr->hydrogen()->skip_check() && !FLAG_debug_code) return;
if (instr->index()->IsConstantOperand()) {
- int constant_index =
- ToInteger32(LConstantOperand::cast(instr->index()));
- if (instr->hydrogen()->length()->representation().IsSmi()) {
- __ cmp(ToOperand(instr->length()),
- Immediate(Smi::FromInt(constant_index)));
- } else {
- __ cmp(ToOperand(instr->length()), Immediate(constant_index));
- }
+ Immediate immediate =
+ ToImmediate(LConstantOperand::cast(instr->index()),
+ instr->hydrogen()->length()->representation());
+ __ cmp(ToOperand(instr->length()), immediate);
Condition condition =
instr->hydrogen()->allow_equality() ? below : below_equal;
ApplyCheckIf(condition, instr);
__ mov(operand, ToRegister(instr->value()));
} else {
LConstantOperand* operand_value = LConstantOperand::cast(instr->value());
- if (IsInteger32(operand_value)) {
- Smi* smi_value = Smi::FromInt(ToInteger32(operand_value));
- __ mov(operand, Immediate(smi_value));
+ if (IsSmi(operand_value)) {
+ Immediate immediate = ToImmediate(operand_value, Representation::Smi());
+ __ mov(operand, immediate);
} else {
+ ASSERT(!IsInteger32(operand_value));
Handle<Object> handle_value = ToHandle(operand_value);
__ mov(operand, handle_value);
}
// DoStringCharCodeAt above.
STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue);
if (instr->index()->IsConstantOperand()) {
- int const_index = ToInteger32(LConstantOperand::cast(instr->index()));
- __ push(Immediate(Smi::FromInt(const_index)));
+ Immediate immediate = ToImmediate(LConstantOperand::cast(instr->index()),
+ Representation::Smi());
+ __ push(immediate);
} else {
Register index = ToRegister(instr->index());
__ SmiTag(index);
bool IsInteger32(LConstantOperand* op) const;
bool IsSmi(LConstantOperand* op) const;
- Immediate ToInteger32Immediate(LOperand* op) const {
- return Immediate(ToInteger32(LConstantOperand::cast(op)));
- }
- Immediate ToSmiImmediate(LOperand* op) const {
- return Immediate(Smi::FromInt(ToInteger32(LConstantOperand::cast(op))));
+ Immediate ToImmediate(LOperand* op, const Representation& r) const {
+ return Immediate(ToRepresentation(LConstantOperand::cast(op), r));
}
double ToDouble(LConstantOperand* op) const;
Register ToRegister(int index) const;
XMMRegister ToDoubleRegister(int index) const;
X87Register ToX87Register(int index) const;
- int ToInteger32(LConstantOperand* op) const;
+ int ToRepresentation(LConstantOperand* op, const Representation& r) const;
+ int32_t ToInteger32(LConstantOperand* op) const;
Operand BuildFastArrayOperand(LOperand* elements_pointer,
LOperand* key,
LConstantOperand* constant_source = LConstantOperand::cast(source);
if (destination->IsRegister()) {
Register dst = cgen_->ToRegister(destination);
- if (cgen_->IsSmi(constant_source)) {
- __ Set(dst, cgen_->ToSmiImmediate(constant_source));
- } else if (cgen_->IsInteger32(constant_source)) {
- __ Set(dst, cgen_->ToInteger32Immediate(constant_source));
+ Representation r = cgen_->IsSmi(constant_source)
+ ? Representation::Smi() : Representation::Integer32();
+ if (cgen_->IsInteger32(constant_source)) {
+ __ Set(dst, cgen_->ToImmediate(constant_source, r));
} else {
__ LoadObject(dst, cgen_->ToHandle(constant_source));
}
} else {
ASSERT(destination->IsStackSlot());
Operand dst = cgen_->ToOperand(destination);
- if (cgen_->IsSmi(constant_source)) {
- __ Set(dst, cgen_->ToSmiImmediate(constant_source));
- } else if (cgen_->IsInteger32(constant_source)) {
- __ Set(dst, cgen_->ToInteger32Immediate(constant_source));
+ Representation r = cgen_->IsSmi(constant_source)
+ ? Representation::Smi() : Representation::Integer32();
+ if (cgen_->IsInteger32(constant_source)) {
+ __ Set(dst, cgen_->ToImmediate(constant_source, r));
} else {
Register tmp = EnsureTempRegister();
__ LoadObject(tmp, cgen_->ToHandle(constant_source));
op == Token::SUB);
HValue* left = instr->left();
HValue* right = instr->right();
- ASSERT(left->representation().IsSmiOrTagged());
- ASSERT(right->representation().IsSmiOrTagged());
+ ASSERT(left->representation().IsTagged());
+ ASSERT(right->representation().IsTagged());
LOperand* context = UseFixed(instr->context(), esi);
LOperand* left_operand = UseFixed(left, edx);
LOperand* right_operand = UseFixed(right, eax);
LInstruction* LChunkBuilder::DoBitwise(HBitwise* instr) {
- if (instr->representation().IsInteger32()) {
- ASSERT(instr->left()->representation().IsInteger32());
- ASSERT(instr->right()->representation().IsInteger32());
+ if (instr->representation().IsSmiOrInteger32()) {
+ ASSERT(instr->left()->representation().IsSmiOrInteger32());
+ ASSERT(instr->right()->representation().Equals(
+ instr->left()->representation()));
LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
LOperand* right = UseOrConstantAtStart(instr->BetterRightOperand());
LInstruction* LChunkBuilder::DoDiv(HDiv* instr) {
if (instr->representation().IsDouble()) {
return DoArithmeticD(Token::DIV, instr);
- } else if (instr->representation().IsInteger32()) {
+ } else if (instr->representation().IsSmiOrInteger32()) {
+ ASSERT(instr->left()->representation().Equals(instr->representation()));
+ ASSERT(instr->right()->representation().Equals(instr->representation()));
if (instr->HasPowerOf2Divisor()) {
ASSERT(!instr->CheckFlag(HValue::kCanBeDivByZero));
LOperand* value = UseRegisterAtStart(instr->left());
LDivI* result = new(zone()) LDivI(dividend, divisor, temp);
return AssignEnvironment(DefineFixed(result, eax));
} else {
- ASSERT(instr->representation().IsSmiOrTagged());
+ ASSERT(instr->representation().IsTagged());
return DoArithmeticT(Token::DIV, instr);
}
}
LInstruction* LChunkBuilder::DoMod(HMod* instr) {
HValue* left = instr->left();
HValue* right = instr->right();
- if (instr->representation().IsInteger32()) {
- ASSERT(left->representation().IsInteger32());
- ASSERT(right->representation().IsInteger32());
+ if (instr->representation().IsSmiOrInteger32()) {
+ ASSERT(left->representation().IsSmiOrInteger32());
+ ASSERT(right->representation().Equals(left->representation()));
+
if (instr->HasPowerOf2Divisor()) {
ASSERT(!right->CanBeZero());
LModI* mod = new(zone()) LModI(UseRegisterAtStart(left),
LInstruction* LChunkBuilder::DoMul(HMul* instr) {
- if (instr->representation().IsInteger32()) {
- ASSERT(instr->left()->representation().IsInteger32());
- ASSERT(instr->right()->representation().IsInteger32());
+ if (instr->representation().IsSmiOrInteger32()) {
+ ASSERT(instr->left()->representation().Equals(instr->representation()));
+ ASSERT(instr->right()->representation().Equals(instr->representation()));
LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
LOperand* right = UseOrConstant(instr->BetterRightOperand());
LOperand* temp = NULL;
} else if (instr->representation().IsDouble()) {
return DoArithmeticD(Token::MUL, instr);
} else {
- ASSERT(instr->representation().IsSmiOrTagged());
+ ASSERT(instr->representation().IsTagged());
return DoArithmeticT(Token::MUL, instr);
}
}
LInstruction* LChunkBuilder::DoSub(HSub* instr) {
- if (instr->representation().IsInteger32()) {
- ASSERT(instr->left()->representation().IsInteger32());
- ASSERT(instr->right()->representation().IsInteger32());
+ if (instr->representation().IsSmiOrInteger32()) {
+ ASSERT(instr->left()->representation().IsSmiOrInteger32());
+ ASSERT(instr->right()->representation().Equals(
+ instr->left()->representation()));
LOperand* left = UseRegisterAtStart(instr->left());
LOperand* right = UseOrConstantAtStart(instr->right());
LSubI* sub = new(zone()) LSubI(left, right);
LInstruction* LChunkBuilder::DoAdd(HAdd* instr) {
- if (instr->representation().IsInteger32()) {
+ if (instr->representation().IsSmiOrInteger32()) {
+ ASSERT(instr->left()->representation().IsSmiOrInteger32());
+ ASSERT(instr->right()->representation().Equals(
+ instr->left()->representation()));
// Check to see if it would be advantageous to use an lea instruction rather
// than an add. This is the case when no overflow check is needed and there
// are multiple uses of the add's inputs, so using a 3-register add will
// preserve all input values for later uses.
bool use_lea = LAddI::UseLea(instr);
- ASSERT(instr->left()->representation().IsInteger32());
- ASSERT(instr->right()->representation().IsInteger32());
LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
HValue* right_candidate = instr->BetterRightOperand();
LOperand* right = use_lea
LInstruction* LChunkBuilder::DoMathMinMax(HMathMinMax* instr) {
LOperand* left = NULL;
LOperand* right = NULL;
- if (instr->representation().IsInteger32()) {
- ASSERT(instr->left()->representation().IsInteger32());
- ASSERT(instr->right()->representation().IsInteger32());
+ if (instr->representation().IsSmiOrInteger32()) {
+ ASSERT(instr->left()->representation().IsSmiOrInteger32());
+ ASSERT(instr->right()->representation().Equals(
+ instr->left()->representation()));
left = UseRegisterAtStart(instr->BetterLeftOperand());
right = UseOrConstantAtStart(instr->BetterRightOperand());
} else {
LInstruction* LChunkBuilder::DoLoadKeyed(HLoadKeyed* instr) {
- ASSERT(instr->key()->representation().IsInteger32() ||
- instr->key()->representation().IsSmi());
+ ASSERT(instr->key()->representation().IsSmiOrInteger32());
ElementsKind elements_kind = instr->elements_kind();
bool clobbers_key = ExternalArrayOpRequiresTemp(
instr->key()->representation(), elements_kind);
Representation Representation::FromType(TypeInfo info) {
if (info.IsUninitialized()) return Representation::None();
- // TODO(verwaest): Return Smi rather than Integer32.
- if (info.IsSmi()) return Representation::Integer32();
+ if (info.IsSmi()) return Representation::Smi();
if (info.IsInteger32()) return Representation::Integer32();
if (info.IsDouble()) return Representation::Double();
if (info.IsNumber()) return Representation::Double();
Representation Representation::FromType(Handle<Type> type) {
if (type->Is(Type::None())) return Representation::None();
+ if (type->Is(Type::Smi())) return Representation::Smi();
if (type->Is(Type::Signed32())) return Representation::Integer32();
if (type->Is(Type::Number())) return Representation::Double();
return Representation::Tagged();
}
-int LCodeGen::ToInteger32(LConstantOperand* op) const {
+int32_t LCodeGen::ToInteger32(LConstantOperand* op) const {
HConstant* constant = chunk_->LookupConstant(op);
return constant->Integer32Value();
}
__ imull(left, left, Immediate(right_value));
}
} else if (right->IsStackSlot()) {
- __ imull(left, ToOperand(right));
+ if (instr->hydrogen_value()->representation().IsSmi()) {
+ __ SmiToInteger32(left, left);
+ __ imul(left, ToOperand(right));
+ } else {
+ __ imull(left, ToOperand(right));
+ }
} else {
- __ imull(left, ToRegister(right));
+ if (instr->hydrogen_value()->representation().IsSmi()) {
+ __ SmiToInteger32(left, left);
+ __ imul(left, ToRegister(right));
+ } else {
+ __ imull(left, ToRegister(right));
+ }
}
if (can_overflow) {
} else if (right->IsStackSlot()) {
switch (instr->op()) {
case Token::BIT_AND:
- __ andl(ToRegister(left), ToOperand(right));
+ __ and_(ToRegister(left), ToOperand(right));
break;
case Token::BIT_OR:
- __ orl(ToRegister(left), ToOperand(right));
+ __ or_(ToRegister(left), ToOperand(right));
break;
case Token::BIT_XOR:
- __ xorl(ToRegister(left), ToOperand(right));
+ __ xor_(ToRegister(left), ToOperand(right));
break;
default:
UNREACHABLE();
ASSERT(right->IsRegister());
switch (instr->op()) {
case Token::BIT_AND:
- __ andl(ToRegister(left), ToRegister(right));
+ __ and_(ToRegister(left), ToRegister(right));
break;
case Token::BIT_OR:
- __ orl(ToRegister(left), ToRegister(right));
+ __ or_(ToRegister(left), ToRegister(right));
break;
case Token::BIT_XOR:
- __ xorl(ToRegister(left), ToRegister(right));
+ __ xor_(ToRegister(left), ToRegister(right));
break;
default:
UNREACHABLE();
__ subl(ToRegister(left),
Immediate(ToInteger32(LConstantOperand::cast(right))));
} else if (right->IsRegister()) {
- __ subl(ToRegister(left), ToRegister(right));
+ if (instr->hydrogen_value()->representation().IsSmi()) {
+ __ subq(ToRegister(left), ToRegister(right));
+ } else {
+ __ subl(ToRegister(left), ToRegister(right));
+ }
} else {
- __ subl(ToRegister(left), ToOperand(right));
+ if (instr->hydrogen_value()->representation().IsSmi()) {
+ __ subq(ToRegister(left), ToOperand(right));
+ } else {
+ __ subl(ToRegister(left), ToOperand(right));
+ }
}
if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
MemOperand(ToRegister(left), offset));
} else {
Operand address(ToRegister(left), ToRegister(right), times_1, 0);
- __ leal(ToRegister(instr->result()), address);
+ if (instr->hydrogen()->representation().IsSmi()) {
+ __ lea(ToRegister(instr->result()), address);
+ } else {
+ __ leal(ToRegister(instr->result()), address);
+ }
}
} else {
if (right->IsConstantOperand()) {
__ addl(ToRegister(left),
Immediate(ToInteger32(LConstantOperand::cast(right))));
} else if (right->IsRegister()) {
- __ addl(ToRegister(left), ToRegister(right));
+ if (instr->hydrogen_value()->representation().IsSmi()) {
+ __ addq(ToRegister(left), ToRegister(right));
+ } else {
+ __ addl(ToRegister(left), ToRegister(right));
+ }
} else {
- __ addl(ToRegister(left), ToOperand(right));
+ if (instr->hydrogen_value()->representation().IsSmi()) {
+ __ addq(ToRegister(left), ToOperand(right));
+ } else {
+ __ addl(ToRegister(left), ToOperand(right));
+ }
}
if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
DeoptimizeIf(overflow, instr->environment());
XMMRegister ToDoubleRegister(LOperand* op) const;
bool IsInteger32Constant(LConstantOperand* op) const;
bool IsSmiConstant(LConstantOperand* op) const;
- int ToInteger32(LConstantOperand* op) const;
+ int ToRepresentation(LConstantOperand* op, const Representation& r) const;
+ int32_t ToInteger32(LConstantOperand* op) const;
Smi* ToSmi(LConstantOperand* op) const;
double ToDouble(LConstantOperand* op) const;
bool IsTaggedConstant(LConstantOperand* op) const;
op == Token::SUB);
HValue* left = instr->left();
HValue* right = instr->right();
- ASSERT(left->representation().IsSmiOrTagged());
- ASSERT(right->representation().IsSmiOrTagged());
+ ASSERT(left->representation().IsTagged());
+ ASSERT(right->representation().IsTagged());
LOperand* left_operand = UseFixed(left, rdx);
LOperand* right_operand = UseFixed(right, rax);
LArithmeticT* result =
LInstruction* LChunkBuilder::DoBitwise(HBitwise* instr) {
- if (instr->representation().IsInteger32()) {
- ASSERT(instr->left()->representation().IsInteger32());
- ASSERT(instr->right()->representation().IsInteger32());
+ if (instr->representation().IsSmiOrInteger32()) {
+ ASSERT(instr->left()->representation().Equals(instr->representation()));
+ ASSERT(instr->right()->representation().Equals(instr->representation()));
LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
LOperand* right = UseOrConstantAtStart(instr->BetterRightOperand());
return DefineSameAsFirst(new(zone()) LBitI(left, right));
} else {
- ASSERT(instr->representation().IsSmiOrTagged());
- ASSERT(instr->left()->representation().IsSmiOrTagged());
- ASSERT(instr->right()->representation().IsSmiOrTagged());
+ ASSERT(instr->representation().IsTagged());
+ ASSERT(instr->left()->representation().IsTagged());
+ ASSERT(instr->right()->representation().IsTagged());
LOperand* left = UseFixed(instr->left(), rdx);
LOperand* right = UseFixed(instr->right(), rax);
LInstruction* LChunkBuilder::DoDiv(HDiv* instr) {
if (instr->representation().IsDouble()) {
return DoArithmeticD(Token::DIV, instr);
- } else if (instr->representation().IsInteger32()) {
+ } else if (instr->representation().IsSmiOrInteger32()) {
+ ASSERT(instr->left()->representation().Equals(instr->representation()));
+ ASSERT(instr->right()->representation().Equals(instr->representation()));
if (instr->HasPowerOf2Divisor()) {
ASSERT(!instr->CheckFlag(HValue::kCanBeDivByZero));
LOperand* value = UseRegisterAtStart(instr->left());
LDivI* result = new(zone()) LDivI(dividend, divisor, temp);
return AssignEnvironment(DefineFixed(result, rax));
} else {
- ASSERT(instr->representation().IsSmiOrTagged());
+ ASSERT(instr->representation().IsTagged());
return DoArithmeticT(Token::DIV, instr);
}
}
LInstruction* LChunkBuilder::DoMod(HMod* instr) {
HValue* left = instr->left();
HValue* right = instr->right();
- if (instr->representation().IsInteger32()) {
- ASSERT(left->representation().IsInteger32());
- ASSERT(right->representation().IsInteger32());
+ if (instr->representation().IsSmiOrInteger32()) {
+ ASSERT(left->representation().Equals(instr->representation()));
+ ASSERT(right->representation().Equals(instr->representation()));
if (instr->HasPowerOf2Divisor()) {
ASSERT(!right->CanBeZero());
LModI* mod = new(zone()) LModI(UseRegisterAtStart(left),
? AssignEnvironment(result)
: result;
}
- } else if (instr->representation().IsSmiOrTagged()) {
+ } else if (instr->representation().IsTagged()) {
return DoArithmeticT(Token::MOD, instr);
} else {
ASSERT(instr->representation().IsDouble());
LInstruction* LChunkBuilder::DoMul(HMul* instr) {
- if (instr->representation().IsInteger32()) {
- ASSERT(instr->left()->representation().IsInteger32());
- ASSERT(instr->right()->representation().IsInteger32());
+ if (instr->representation().IsSmiOrInteger32()) {
+ ASSERT(instr->left()->representation().Equals(instr->representation()));
+ ASSERT(instr->right()->representation().Equals(instr->representation()));
LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
LOperand* right = UseOrConstant(instr->BetterRightOperand());
LMulI* mul = new(zone()) LMulI(left, right);
} else if (instr->representation().IsDouble()) {
return DoArithmeticD(Token::MUL, instr);
} else {
- ASSERT(instr->representation().IsSmiOrTagged());
+ ASSERT(instr->representation().IsTagged());
return DoArithmeticT(Token::MUL, instr);
}
}
LInstruction* LChunkBuilder::DoSub(HSub* instr) {
- if (instr->representation().IsInteger32()) {
- ASSERT(instr->left()->representation().IsInteger32());
- ASSERT(instr->right()->representation().IsInteger32());
+ if (instr->representation().IsSmiOrInteger32()) {
+ ASSERT(instr->left()->representation().Equals(instr->representation()));
+ ASSERT(instr->right()->representation().Equals(instr->representation()));
LOperand* left = UseRegisterAtStart(instr->left());
LOperand* right = UseOrConstantAtStart(instr->right());
LSubI* sub = new(zone()) LSubI(left, right);
} else if (instr->representation().IsDouble()) {
return DoArithmeticD(Token::SUB, instr);
} else {
- ASSERT(instr->representation().IsSmiOrTagged());
+ ASSERT(instr->representation().IsTagged());
return DoArithmeticT(Token::SUB, instr);
}
}
LInstruction* LChunkBuilder::DoAdd(HAdd* instr) {
- if (instr->representation().IsInteger32()) {
+ if (instr->representation().IsSmiOrInteger32()) {
// Check to see if it would be advantageous to use an lea instruction rather
// than an add. This is the case when no overflow check is needed and there
// are multiple uses of the add's inputs, so using a 3-register add will
// preserve all input values for later uses.
bool use_lea = LAddI::UseLea(instr);
- ASSERT(instr->left()->representation().IsInteger32());
- ASSERT(instr->right()->representation().IsInteger32());
+ ASSERT(instr->left()->representation().Equals(instr->representation()));
+ ASSERT(instr->right()->representation().Equals(instr->representation()));
LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
HValue* right_candidate = instr->BetterRightOperand();
LOperand* right = use_lea
} else if (instr->representation().IsDouble()) {
return DoArithmeticD(Token::ADD, instr);
} else {
- ASSERT(instr->representation().IsSmiOrTagged());
+ ASSERT(instr->representation().IsTagged());
return DoArithmeticT(Token::ADD, instr);
}
return NULL;