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 10namespace v8 { 11namespace internal { 12namespace compiler { 13 14ChangeLowering::~ChangeLowering() {} 15 16 17Reduction 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 44Node* 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 52Node* 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 60Node* 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 67Node* 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 88Node* 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 97Node* 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 104Reduction 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 122Reduction ChangeLowering::ChangeBoolToBit(Node* val) { 123 return Replace( 124 graph()->NewNode(machine()->WordEqual(), val, jsgraph()->TrueConstant())); 125} 126 127 128Reduction ChangeLowering::ChangeFloat64ToTagged(Node* val, Node* control) { 129 return Replace(AllocateHeapNumberWithValue(val, control)); 130} 131 132 133Reduction 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 161Reduction 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 188Reduction 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 211Reduction 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 239Isolate* ChangeLowering::isolate() const { return jsgraph()->isolate(); } 240 241 242Graph* ChangeLowering::graph() const { return jsgraph()->graph(); } 243 244 245CommonOperatorBuilder* ChangeLowering::common() const { 246 return jsgraph()->common(); 247} 248 249 250MachineOperatorBuilder* ChangeLowering::machine() const { 251 return jsgraph()->machine(); 252} 253 254} // namespace compiler 255} // namespace internal 256} // namespace v8 257