Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
Public Member Functions | Static Public Member Functions | List of all members
dart::BinaryIntegerOpInstr Class Reference

#include <il.h>

Inheritance diagram for dart::BinaryIntegerOpInstr:
dart::TemplateDefinition< 2, NoThrow, Pure > dart::BinaryInt32OpInstr dart::BinaryInt64OpInstr dart::BinarySmiOpInstr dart::BinaryUint32OpInstr dart::ShiftIntegerOpInstr dart::ShiftInt64OpInstr dart::ShiftUint32OpInstr dart::SpeculativeShiftInt64OpInstr dart::SpeculativeShiftUint32OpInstr

Public Member Functions

 BinaryIntegerOpInstr (Token::Kind op_kind, Value *left, Value *right, intptr_t deopt_id)
 
Token::Kind op_kind () const
 
Valueleft () const
 
Valueright () const
 
bool can_overflow () const
 
void set_can_overflow (bool overflow)
 
bool is_truncating () const
 
void mark_truncating ()
 
bool RightIsNonZero () const
 
bool RightIsPowerOfTwoConstant () const
 
virtual DefinitionCanonicalize (FlowGraph *flow_graph)
 
virtual bool AttributesEqual (const Instruction &other) const
 
virtual intptr_t DeoptimizationTarget () const
 
virtual void InferRange (RangeAnalysis *analysis, Range *range)
 
- Public Member Functions inherited from dart::TemplateDefinition< 2, NoThrow, Pure >
 TemplateDefinition (intptr_t deopt_id=DeoptId::kNone)
 
 TemplateDefinition (const InstructionSource &source, intptr_t deopt_id=DeoptId::kNone)
 
virtual intptr_t InputCount () const
 
virtual ValueInputAt (intptr_t i) const
 
virtual bool MayThrow () const
 

Static Public Member Functions

static BinaryIntegerOpInstrMake (Representation representation, Token::Kind op_kind, Value *left, Value *right, intptr_t deopt_id, SpeculativeMode speculative_mode=kGuardInputs)
 
static BinaryIntegerOpInstrMake (Representation representation, Token::Kind op_kind, Value *left, Value *right, intptr_t deopt_id, bool can_overflow, bool is_truncating, Range *range, SpeculativeMode speculative_mode=kGuardInputs)
 

Additional Inherited Members

- Public Types inherited from dart::TemplateDefinition< 2, NoThrow, Pure >
using BaseClass = typename Pure< Definition, PureDefinition >::Base
 
- Protected Attributes inherited from dart::TemplateDefinition< 2, NoThrow, Pure >
EmbeddedArray< Value *, Ninputs_
 

Detailed Description

Definition at line 9315 of file il.h.

Constructor & Destructor Documentation

◆ BinaryIntegerOpInstr()

dart::BinaryIntegerOpInstr::BinaryIntegerOpInstr ( Token::Kind  op_kind,
Value left,
Value right,
intptr_t  deopt_id 
)
inline

Definition at line 9317 of file il.h.

9321 : TemplateDefinition(deopt_id),
9322 op_kind_(op_kind),
9323 can_overflow_(true),
9324 is_truncating_(false) {
9325 SetInputAt(0, left);
9326 SetInputAt(1, right);
9327 }
Value * right() const
Definition il.h:9350
Token::Kind op_kind() const
Definition il.h:9348
Value * left() const
Definition il.h:9349
TemplateDefinition(intptr_t deopt_id=DeoptId::kNone)
Definition il.h:2731

Member Function Documentation

◆ AttributesEqual()

bool dart::BinaryIntegerOpInstr::AttributesEqual ( const Instruction other) const
virtual

Reimplemented in dart::BinaryInt64OpInstr.

Definition at line 1111 of file il.cc.

1111 {
1112 ASSERT(other.tag() == tag());
1113 auto const other_op = other.AsBinaryIntegerOp();
1114 return (op_kind() == other_op->op_kind()) &&
1115 (can_overflow() == other_op->can_overflow()) &&
1116 (is_truncating() == other_op->is_truncating());
1117}
bool can_overflow() const
Definition il.h:9352
bool is_truncating() const
Definition il.h:9358
#define ASSERT(E)

◆ can_overflow()

bool dart::BinaryIntegerOpInstr::can_overflow ( ) const
inline

Definition at line 9352 of file il.h.

9352{ return can_overflow_; }

◆ Canonicalize()

Definition * dart::BinaryIntegerOpInstr::Canonicalize ( FlowGraph flow_graph)
virtual

Definition at line 2400 of file il.cc.

2400 {
2401 // If range analysis has already determined a single possible value for
2402 // this operation, then replace it if possible.
2403 if (RangeUtils::IsSingleton(range()) && CanReplaceWithConstant()) {
2404 const auto& value =
2405 Integer::Handle(Integer::NewCanonical(range()->Singleton()));
2406 auto* const replacement =
2407 flow_graph->TryCreateConstantReplacementFor(this, value);
2408 if (replacement != this) {
2409 return replacement;
2410 }
2411 }
2412
2413 // If both operands are constants evaluate this expression. Might
2414 // occur due to load forwarding after constant propagation pass
2415 // have already been run.
2416
2417 if (left()->BindsToConstant() && right()->BindsToConstant()) {
2419 left()->BoundConstant(), right()->BoundConstant(), op_kind(),
2420 is_truncating(), representation(), Thread::Current()));
2421
2422 if (!result.IsNull()) {
2423 return flow_graph->TryCreateConstantReplacementFor(this, result);
2424 }
2425 }
2426
2427 if (left()->BindsToConstant() && !right()->BindsToConstant() &&
2429 Value* l = left();
2430 Value* r = right();
2431 SetInputAt(0, r);
2432 SetInputAt(1, l);
2433 }
2434
2435 int64_t rhs;
2436 if (!Evaluator::ToIntegerConstant(right(), &rhs)) {
2437 return this;
2438 }
2439
2440 if (is_truncating()) {
2441 switch (op_kind()) {
2442 case Token::kMUL:
2443 case Token::kSUB:
2444 case Token::kADD:
2445 case Token::kBIT_AND:
2446 case Token::kBIT_OR:
2447 case Token::kBIT_XOR:
2448 rhs = Evaluator::TruncateTo(rhs, representation());
2449 break;
2450 default:
2451 break;
2452 }
2453 }
2454
2455 if (IsBinaryUint32Op() && HasUnmatchedInputRepresentations()) {
2456 // Canonicalization may eliminate instruction and loose truncation,
2457 // so it is illegal to canonicalize truncating uint32 instruction
2458 // until all conversions for its inputs are inserted.
2459 return this;
2460 }
2461
2462 switch (op_kind()) {
2463 case Token::kMUL:
2464 if (rhs == 1) {
2465 return left()->definition();
2466 } else if (rhs == 0) {
2467 return right()->definition();
2468 } else if ((rhs > 0) && Utils::IsPowerOfTwo(rhs)) {
2469 const int64_t shift_amount = Utils::ShiftForPowerOfTwo(rhs);
2470 const Representation shift_amount_rep =
2471 (SpeculativeModeOfInputs() == kNotSpeculative) ? kUnboxedInt64
2472 : kTagged;
2473 ConstantInstr* constant_shift_amount = flow_graph->GetConstant(
2474 Smi::Handle(Smi::New(shift_amount)), shift_amount_rep);
2476 representation(), Token::kSHL, left()->CopyWithType(),
2477 new Value(constant_shift_amount), GetDeoptId(), can_overflow(),
2478 is_truncating(), range(), SpeculativeModeOfInputs());
2479 if (shift != nullptr) {
2480 // Assign a range to the shift factor, just in case range
2481 // analysis no longer runs after this rewriting.
2482 if (auto shift_with_range = shift->AsShiftIntegerOp()) {
2483 shift_with_range->set_shift_range(
2484 new Range(RangeBoundary::FromConstant(shift_amount),
2485 RangeBoundary::FromConstant(shift_amount)));
2486 }
2487 if (!MayThrow()) {
2488 ASSERT(!shift->MayThrow());
2489 }
2490 if (!CanDeoptimize()) {
2491 ASSERT(!shift->CanDeoptimize());
2492 }
2493 flow_graph->InsertBefore(this, shift, env(), FlowGraph::kValue);
2494 return shift;
2495 }
2496 }
2497
2498 break;
2499 case Token::kADD:
2500 if (rhs == 0) {
2501 return left()->definition();
2502 }
2503 break;
2504 case Token::kBIT_AND:
2505 if (rhs == 0) {
2506 return right()->definition();
2507 } else if (rhs == RepresentationMask(representation())) {
2508 return left()->definition();
2509 }
2510 break;
2511 case Token::kBIT_OR:
2512 if (rhs == 0) {
2513 return left()->definition();
2514 } else if (rhs == RepresentationMask(representation())) {
2515 return right()->definition();
2516 }
2517 break;
2518 case Token::kBIT_XOR:
2519 if (rhs == 0) {
2520 return left()->definition();
2521 } else if (rhs == RepresentationMask(representation())) {
2522 UnaryIntegerOpInstr* bit_not = UnaryIntegerOpInstr::Make(
2523 representation(), Token::kBIT_NOT, left()->CopyWithType(),
2524 GetDeoptId(), SpeculativeModeOfInputs(), range());
2525 if (bit_not != nullptr) {
2526 flow_graph->InsertBefore(this, bit_not, env(), FlowGraph::kValue);
2527 return bit_not;
2528 }
2529 }
2530 break;
2531
2532 case Token::kSUB:
2533 if (rhs == 0) {
2534 return left()->definition();
2535 }
2536 break;
2537
2538 case Token::kTRUNCDIV:
2539 if (rhs == 1) {
2540 return left()->definition();
2541 } else if (rhs == -1) {
2542 UnaryIntegerOpInstr* negation = UnaryIntegerOpInstr::Make(
2543 representation(), Token::kNEGATE, left()->CopyWithType(),
2544 GetDeoptId(), SpeculativeModeOfInputs(), range());
2545 if (negation != nullptr) {
2546 flow_graph->InsertBefore(this, negation, env(), FlowGraph::kValue);
2547 return negation;
2548 }
2549 }
2550 break;
2551
2552 case Token::kMOD:
2553 if (std::abs(rhs) == 1) {
2554 return flow_graph->TryCreateConstantReplacementFor(this,
2555 Object::smi_zero());
2556 }
2557 break;
2558
2559 case Token::kUSHR:
2560 if (rhs >= kBitsPerInt64) {
2561 return flow_graph->TryCreateConstantReplacementFor(this,
2562 Object::smi_zero());
2563 }
2565 case Token::kSHR:
2566 if (rhs == 0) {
2567 return left()->definition();
2568 } else if (rhs < 0) {
2569 // Instruction will always throw on negative rhs operand.
2570 if (!CanDeoptimize()) {
2571 // For non-speculative operations (no deopt), let
2572 // the code generator deal with throw on slowpath.
2573 break;
2574 }
2575 ASSERT(GetDeoptId() != DeoptId::kNone);
2576 DeoptimizeInstr* deopt =
2577 new DeoptimizeInstr(ICData::kDeoptBinarySmiOp, GetDeoptId());
2578 flow_graph->InsertBefore(this, deopt, env(), FlowGraph::kEffect);
2579 // Replace with zero since it always throws.
2580 return flow_graph->TryCreateConstantReplacementFor(this,
2581 Object::smi_zero());
2582 }
2583 break;
2584
2585 case Token::kSHL: {
2586 const intptr_t result_bits = RepresentationBits(representation());
2587 if (rhs == 0) {
2588 return left()->definition();
2589 } else if ((rhs >= kBitsPerInt64) ||
2590 ((rhs >= result_bits) && is_truncating())) {
2591 return flow_graph->TryCreateConstantReplacementFor(this,
2592 Object::smi_zero());
2593 } else if ((rhs < 0) || ((rhs >= result_bits) && !is_truncating())) {
2594 // Instruction will always throw on negative rhs operand or
2595 // deoptimize on large rhs operand.
2596 if (!CanDeoptimize()) {
2597 // For non-speculative operations (no deopt), let
2598 // the code generator deal with throw on slowpath.
2599 break;
2600 }
2601 ASSERT(GetDeoptId() != DeoptId::kNone);
2602 DeoptimizeInstr* deopt =
2603 new DeoptimizeInstr(ICData::kDeoptBinarySmiOp, GetDeoptId());
2604 flow_graph->InsertBefore(this, deopt, env(), FlowGraph::kEffect);
2605 // Replace with zero since it overshifted or always throws.
2606 return flow_graph->TryCreateConstantReplacementFor(this,
2607 Object::smi_zero());
2608 }
2609 break;
2610 }
2611
2612 default:
2613 break;
2614 }
2615
2616 return this;
2617}
static BinaryIntegerOpInstr * Make(Representation representation, Token::Kind op_kind, Value *left, Value *right, intptr_t deopt_id, SpeculativeMode speculative_mode=kGuardInputs)
Definition il.cc:2284
BinaryIntegerOpInstr(Token::Kind op_kind, Value *left, Value *right, intptr_t deopt_id)
Definition il.h:9317
static constexpr intptr_t kNone
Definition deopt_id.h:27
static int64_t TruncateTo(int64_t v, Representation r)
Definition evaluator.cc:81
static IntegerPtr BinaryIntegerEvaluate(const Object &left, const Object &right, Token::Kind token_kind, bool is_truncating, Representation representation, Thread *thread)
Definition evaluator.cc:99
static bool ToIntegerConstant(Value *value, int64_t *result)
Definition evaluator.cc:281
static IntegerPtr NewCanonical(const String &str)
Definition object.cc:23078
static Object & Handle()
Definition object.h:407
static RangeBoundary FromConstant(int64_t val)
static bool IsSingleton(Range *range)
static SmiPtr New(intptr_t value)
Definition object.h:9985
static Thread * Current()
Definition thread.h:361
static UnaryIntegerOpInstr * Make(Representation representation, Token::Kind op_kind, Value *value, intptr_t deopt_id, SpeculativeMode speculative_mode, Range *range)
Definition il.cc:2248
static constexpr int ShiftForPowerOfTwo(T x)
Definition utils.h:66
static constexpr bool IsPowerOfTwo(T x)
Definition utils.h:61
Definition * definition() const
Definition il.h:103
uint8_t value
GAsyncResult * result
static int64_t RepresentationMask(Representation r)
Definition il.cc:2140
Representation
Definition locations.h:66
static intptr_t RepresentationBits(Representation r)
Definition il.cc:2125
static bool IsCommutative(Token::Kind op)
Definition il.cc:2231
constexpr intptr_t kBitsPerInt64
Definition globals.h:467
Definition __init__.py:1
#define FALL_THROUGH
Definition globals.h:15

◆ DeoptimizationTarget()

virtual intptr_t dart::BinaryIntegerOpInstr::DeoptimizationTarget ( ) const
inlinevirtual

Definition at line 9376 of file il.h.

9376{ return GetDeoptId(); }

◆ InferRange()

void dart::BinaryIntegerOpInstr::InferRange ( RangeAnalysis analysis,
Range range 
)
virtual

Reimplemented in dart::BinarySmiOpInstr, and dart::ShiftIntegerOpInstr.

Definition at line 3034 of file range_analysis.cc.

3034 {
3035 auto const left_size =
3036 RepresentationToRangeSize(RequiredInputRepresentation(0));
3037 auto const right_size =
3038 RepresentationToRangeSize(RequiredInputRepresentation(1));
3039 InferRangeHelper(GetInputRange(analysis, left_size, left()),
3040 GetInputRange(analysis, right_size, right()), range);
3041}
static const Range * GetInputRange(RangeAnalysis *analysis, RangeBoundary::RangeSize size, Value *input)
static RangeBoundary::RangeSize RepresentationToRangeSize(Representation r)

◆ is_truncating()

bool dart::BinaryIntegerOpInstr::is_truncating ( ) const
inline

Definition at line 9358 of file il.h.

9358{ return is_truncating_; }

◆ left()

Value * dart::BinaryIntegerOpInstr::left ( ) const
inline

Definition at line 9349 of file il.h.

9349{ return inputs_[0]; }
EmbeddedArray< Value *, N > inputs_
Definition il.h:2744

◆ Make() [1/2]

BinaryIntegerOpInstr * dart::BinaryIntegerOpInstr::Make ( Representation  representation,
Token::Kind  op_kind,
Value left,
Value right,
intptr_t  deopt_id,
bool  can_overflow,
bool  is_truncating,
Range range,
SpeculativeMode  speculative_mode = kGuardInputs 
)
static

Definition at line 2357 of file il.cc.

2366 {
2368 representation, op_kind, left, right, deopt_id, speculative_mode);
2369 if (op == nullptr) {
2370 return nullptr;
2371 }
2372 if (!Range::IsUnknown(range)) {
2373 op->set_range(*range);
2374 }
2375
2376 op->set_can_overflow(can_overflow);
2377 if (is_truncating) {
2378 op->mark_truncating();
2379 }
2380
2381 return op;
2382}
static bool IsUnknown(const Range *other)

◆ Make() [2/2]

BinaryIntegerOpInstr * dart::BinaryIntegerOpInstr::Make ( Representation  representation,
Token::Kind  op_kind,
Value left,
Value right,
intptr_t  deopt_id,
SpeculativeMode  speculative_mode = kGuardInputs 
)
static

Definition at line 2284 of file il.cc.

2290 {
2291 BinaryIntegerOpInstr* op = nullptr;
2292 Range* right_range = nullptr;
2293 switch (op_kind) {
2294 case Token::kMOD:
2295 case Token::kTRUNCDIV:
2296 if (representation != kTagged) break;
2298 case Token::kSHL:
2299 case Token::kSHR:
2300 case Token::kUSHR:
2301 if (auto const const_def = right->definition()->AsConstant()) {
2302 right_range = new Range();
2303 const_def->InferRange(nullptr, right_range);
2304 }
2305 break;
2306 default:
2307 break;
2308 }
2309 switch (representation) {
2310 case kTagged:
2311 op = new BinarySmiOpInstr(op_kind, left, right, deopt_id, right_range);
2312 break;
2313 case kUnboxedInt32:
2315 return nullptr;
2316 }
2317 op = new BinaryInt32OpInstr(op_kind, left, right, deopt_id);
2318 break;
2319 case kUnboxedUint32:
2320 if ((op_kind == Token::kSHL) || (op_kind == Token::kSHR) ||
2321 (op_kind == Token::kUSHR)) {
2322 if (speculative_mode == kNotSpeculative) {
2323 op = new ShiftUint32OpInstr(op_kind, left, right, deopt_id,
2324 right_range);
2325 } else {
2326 op = new SpeculativeShiftUint32OpInstr(op_kind, left, right, deopt_id,
2327 right_range);
2328 }
2329 } else {
2330 op = new BinaryUint32OpInstr(op_kind, left, right, deopt_id);
2331 }
2332 break;
2333 case kUnboxedInt64:
2334 if ((op_kind == Token::kSHL) || (op_kind == Token::kSHR) ||
2335 (op_kind == Token::kUSHR)) {
2336 if (speculative_mode == kNotSpeculative) {
2337 op = new ShiftInt64OpInstr(op_kind, left, right, deopt_id,
2338 right_range);
2339 } else {
2340 op = new SpeculativeShiftInt64OpInstr(op_kind, left, right, deopt_id,
2341 right_range);
2342 }
2343 } else {
2344 op = new BinaryInt64OpInstr(op_kind, left, right, deopt_id,
2345 speculative_mode);
2346 }
2347 break;
2348 default:
2349 UNREACHABLE();
2350 return nullptr;
2351 }
2352
2353 ASSERT(op->representation() == representation);
2354 return op;
2355}
#define UNREACHABLE()
Definition assert.h:248
static bool IsSupported(Token::Kind op_kind, Value *left, Value *right)
Definition il.h:9449

◆ mark_truncating()

void dart::BinaryIntegerOpInstr::mark_truncating ( )
inline

Definition at line 9359 of file il.h.

9359 {
9360 is_truncating_ = true;
9361 set_can_overflow(false);
9362 }
void set_can_overflow(bool overflow)
Definition il.h:9353

◆ op_kind()

Token::Kind dart::BinaryIntegerOpInstr::op_kind ( ) const
inline

Definition at line 9348 of file il.h.

9348{ return op_kind_; }

◆ right()

Value * dart::BinaryIntegerOpInstr::right ( ) const
inline

Definition at line 9350 of file il.h.

9350{ return inputs_[1]; }

◆ RightIsNonZero()

bool dart::BinaryIntegerOpInstr::RightIsNonZero ( ) const

Definition at line 2107 of file il.cc.

2107 {
2108 if (right()->BindsToConstant()) {
2109 const auto& constant = right()->BoundConstant();
2110 if (!constant.IsInteger()) return false;
2111 return Integer::Cast(constant).AsInt64Value() != 0;
2112 }
2113 return !RangeUtils::CanBeZero(right()->definition()->range());
2114}
static bool CanBeZero(Range *range)
const Object & BoundConstant() const
Definition il.cc:1199

◆ RightIsPowerOfTwoConstant()

bool dart::BinaryIntegerOpInstr::RightIsPowerOfTwoConstant ( ) const

Definition at line 2116 of file il.cc.

2116 {
2117 if (!right()->BindsToConstant()) return false;
2118 const Object& constant = right()->BoundConstant();
2119 if (!constant.IsSmi()) return false;
2120 const intptr_t int_value = Smi::Cast(constant).Value();
2121 ASSERT(int_value != kIntptrMin);
2122 return Utils::IsPowerOfTwo(Utils::Abs(int_value));
2123}
static T Abs(T x)
Definition utils.h:34
constexpr intptr_t kIntptrMin
Definition globals.h:556

◆ set_can_overflow()

void dart::BinaryIntegerOpInstr::set_can_overflow ( bool  overflow)
inline

Definition at line 9353 of file il.h.

9353 {
9354 ASSERT(!is_truncating_ || !overflow);
9355 can_overflow_ = overflow;
9356 }

The documentation for this class was generated from the following files: