Home | History | Annotate | Download | only in compiler
      1 // Copyright 2014 the V8 project authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "src/compiler/change-lowering.h"
      6 #include "src/compiler/machine-operator.h"
      7 
      8 #include "src/compiler/js-graph.h"
      9 
     10 namespace v8 {
     11 namespace internal {
     12 namespace compiler {
     13 
     14 ChangeLowering::~ChangeLowering() {}
     15 
     16 
     17 Reduction ChangeLowering::Reduce(Node* node) {
     18   Node* control = graph()->start();
     19   switch (node->opcode()) {
     20     case IrOpcode::kChangeBitToBool:
     21       return ChangeBitToBool(node->InputAt(0), control);
     22     case IrOpcode::kChangeBoolToBit:
     23       return ChangeBoolToBit(node->InputAt(0));
     24     case IrOpcode::kChangeFloat64ToTagged:
     25       return ChangeFloat64ToTagged(node->InputAt(0), control);
     26     case IrOpcode::kChangeInt32ToTagged:
     27       return ChangeInt32ToTagged(node->InputAt(0), control);
     28     case IrOpcode::kChangeTaggedToFloat64:
     29       return ChangeTaggedToFloat64(node->InputAt(0), control);
     30     case IrOpcode::kChangeTaggedToInt32:
     31       return ChangeTaggedToUI32(node->InputAt(0), control, kSigned);
     32     case IrOpcode::kChangeTaggedToUint32:
     33       return ChangeTaggedToUI32(node->InputAt(0), control, kUnsigned);
     34     case IrOpcode::kChangeUint32ToTagged:
     35       return ChangeUint32ToTagged(node->InputAt(0), control);
     36     default:
     37       return NoChange();
     38   }
     39   UNREACHABLE();
     40   return NoChange();
     41 }
     42 
     43 
     44 Node* ChangeLowering::HeapNumberValueIndexConstant() {
     45   STATIC_ASSERT(HeapNumber::kValueOffset % kPointerSize == 0);
     46   const int heap_number_value_offset =
     47       ((HeapNumber::kValueOffset / kPointerSize) * (machine()->Is64() ? 8 : 4));
     48   return jsgraph()->Int32Constant(heap_number_value_offset - kHeapObjectTag);
     49 }
     50 
     51 
     52 Node* ChangeLowering::SmiMaxValueConstant() {
     53   const int smi_value_size = machine()->Is32() ? SmiTagging<4>::SmiValueSize()
     54                                                : SmiTagging<8>::SmiValueSize();
     55   return jsgraph()->Int32Constant(
     56       -(static_cast<int>(0xffffffffu << (smi_value_size - 1)) + 1));
     57 }
     58 
     59 
     60 Node* ChangeLowering::SmiShiftBitsConstant() {
     61   const int smi_shift_size = machine()->Is32() ? SmiTagging<4>::SmiShiftSize()
     62                                                : SmiTagging<8>::SmiShiftSize();
     63   return jsgraph()->Int32Constant(smi_shift_size + kSmiTagSize);
     64 }
     65 
     66 
     67 Node* ChangeLowering::AllocateHeapNumberWithValue(Node* value, Node* control) {
     68   // The AllocateHeapNumber() runtime function does not use the context, so we
     69   // can safely pass in Smi zero here.
     70   Node* context = jsgraph()->ZeroConstant();
     71   Node* effect = graph()->NewNode(common()->ValueEffect(1), value);
     72   const Runtime::Function* function =
     73       Runtime::FunctionForId(Runtime::kAllocateHeapNumber);
     74   DCHECK_EQ(0, function->nargs);
     75   CallDescriptor* desc = linkage()->GetRuntimeCallDescriptor(
     76       function->function_id, 0, Operator::kNoProperties);
     77   Node* heap_number = graph()->NewNode(
     78       common()->Call(desc), jsgraph()->CEntryStubConstant(),
     79       jsgraph()->ExternalConstant(ExternalReference(function, isolate())),
     80       jsgraph()->Int32Constant(function->nargs), context, effect, control);
     81   Node* store = graph()->NewNode(
     82       machine()->Store(StoreRepresentation(kMachFloat64, kNoWriteBarrier)),
     83       heap_number, HeapNumberValueIndexConstant(), value, heap_number, control);
     84   return graph()->NewNode(common()->Finish(1), heap_number, store);
     85 }
     86 
     87 
     88 Node* ChangeLowering::ChangeSmiToInt32(Node* value) {
     89   value = graph()->NewNode(machine()->WordSar(), value, SmiShiftBitsConstant());
     90   if (machine()->Is64()) {
     91     value = graph()->NewNode(machine()->TruncateInt64ToInt32(), value);
     92   }
     93   return value;
     94 }
     95 
     96 
     97 Node* ChangeLowering::LoadHeapNumberValue(Node* value, Node* control) {
     98   return graph()->NewNode(machine()->Load(kMachFloat64), value,
     99                           HeapNumberValueIndexConstant(),
    100                           graph()->NewNode(common()->ControlEffect(), control));
    101 }
    102 
    103 
    104 Reduction ChangeLowering::ChangeBitToBool(Node* val, Node* control) {
    105   Node* branch = graph()->NewNode(common()->Branch(), val, control);
    106 
    107   Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
    108   Node* true_value = jsgraph()->TrueConstant();
    109 
    110   Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
    111   Node* false_value = jsgraph()->FalseConstant();
    112 
    113   Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
    114   Node* phi = graph()->NewNode(
    115       common()->Phi(static_cast<MachineType>(kTypeBool | kRepTagged), 2),
    116       true_value, false_value, merge);
    117 
    118   return Replace(phi);
    119 }
    120 
    121 
    122 Reduction ChangeLowering::ChangeBoolToBit(Node* val) {
    123   return Replace(
    124       graph()->NewNode(machine()->WordEqual(), val, jsgraph()->TrueConstant()));
    125 }
    126 
    127 
    128 Reduction ChangeLowering::ChangeFloat64ToTagged(Node* val, Node* control) {
    129   return Replace(AllocateHeapNumberWithValue(val, control));
    130 }
    131 
    132 
    133 Reduction ChangeLowering::ChangeInt32ToTagged(Node* val, Node* control) {
    134   if (machine()->Is64()) {
    135     return Replace(
    136         graph()->NewNode(machine()->Word64Shl(),
    137                          graph()->NewNode(machine()->ChangeInt32ToInt64(), val),
    138                          SmiShiftBitsConstant()));
    139   }
    140 
    141   Node* add = graph()->NewNode(machine()->Int32AddWithOverflow(), val, val);
    142   Node* ovf = graph()->NewNode(common()->Projection(1), add);
    143 
    144   Node* branch = graph()->NewNode(common()->Branch(), ovf, control);
    145 
    146   Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
    147   Node* heap_number = AllocateHeapNumberWithValue(
    148       graph()->NewNode(machine()->ChangeInt32ToFloat64(), val), if_true);
    149 
    150   Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
    151   Node* smi = graph()->NewNode(common()->Projection(0), add);
    152 
    153   Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
    154   Node* phi = graph()->NewNode(common()->Phi(kMachAnyTagged, 2), heap_number,
    155                                smi, merge);
    156 
    157   return Replace(phi);
    158 }
    159 
    160 
    161 Reduction ChangeLowering::ChangeTaggedToUI32(Node* val, Node* control,
    162                                              Signedness signedness) {
    163   STATIC_ASSERT(kSmiTag == 0);
    164   STATIC_ASSERT(kSmiTagMask == 1);
    165 
    166   Node* tag = graph()->NewNode(machine()->WordAnd(), val,
    167                                jsgraph()->Int32Constant(kSmiTagMask));
    168   Node* branch = graph()->NewNode(common()->Branch(), tag, control);
    169 
    170   Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
    171   const Operator* op = (signedness == kSigned)
    172                            ? machine()->ChangeFloat64ToInt32()
    173                            : machine()->ChangeFloat64ToUint32();
    174   Node* change = graph()->NewNode(op, LoadHeapNumberValue(val, if_true));
    175 
    176   Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
    177   Node* number = ChangeSmiToInt32(val);
    178 
    179   Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
    180   Node* phi = graph()->NewNode(
    181       common()->Phi((signedness == kSigned) ? kMachInt32 : kMachUint32, 2),
    182       change, number, merge);
    183 
    184   return Replace(phi);
    185 }
    186 
    187 
    188 Reduction ChangeLowering::ChangeTaggedToFloat64(Node* val, Node* control) {
    189   STATIC_ASSERT(kSmiTag == 0);
    190   STATIC_ASSERT(kSmiTagMask == 1);
    191 
    192   Node* tag = graph()->NewNode(machine()->WordAnd(), val,
    193                                jsgraph()->Int32Constant(kSmiTagMask));
    194   Node* branch = graph()->NewNode(common()->Branch(), tag, control);
    195 
    196   Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
    197   Node* load = LoadHeapNumberValue(val, if_true);
    198 
    199   Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
    200   Node* number = graph()->NewNode(machine()->ChangeInt32ToFloat64(),
    201                                   ChangeSmiToInt32(val));
    202 
    203   Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
    204   Node* phi =
    205       graph()->NewNode(common()->Phi(kMachFloat64, 2), load, number, merge);
    206 
    207   return Replace(phi);
    208 }
    209 
    210 
    211 Reduction ChangeLowering::ChangeUint32ToTagged(Node* val, Node* control) {
    212   STATIC_ASSERT(kSmiTag == 0);
    213   STATIC_ASSERT(kSmiTagMask == 1);
    214 
    215   Node* cmp = graph()->NewNode(machine()->Uint32LessThanOrEqual(), val,
    216                                SmiMaxValueConstant());
    217   Node* branch = graph()->NewNode(common()->Branch(), cmp, control);
    218 
    219   Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
    220   Node* smi = graph()->NewNode(
    221       machine()->WordShl(),
    222       machine()->Is64()
    223           ? graph()->NewNode(machine()->ChangeUint32ToUint64(), val)
    224           : val,
    225       SmiShiftBitsConstant());
    226 
    227   Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
    228   Node* heap_number = AllocateHeapNumberWithValue(
    229       graph()->NewNode(machine()->ChangeUint32ToFloat64(), val), if_false);
    230 
    231   Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
    232   Node* phi = graph()->NewNode(common()->Phi(kMachAnyTagged, 2), smi,
    233                                heap_number, merge);
    234 
    235   return Replace(phi);
    236 }
    237 
    238 
    239 Isolate* ChangeLowering::isolate() const { return jsgraph()->isolate(); }
    240 
    241 
    242 Graph* ChangeLowering::graph() const { return jsgraph()->graph(); }
    243 
    244 
    245 CommonOperatorBuilder* ChangeLowering::common() const {
    246   return jsgraph()->common();
    247 }
    248 
    249 
    250 MachineOperatorBuilder* ChangeLowering::machine() const {
    251   return jsgraph()->machine();
    252 }
    253 
    254 }  // namespace compiler
    255 }  // namespace internal
    256 }  // namespace v8
    257