| File: | out/../deps/v8/src/compiler/common-operator.cc |
| Warning: | line 241, column 13 Assigned value is garbage or undefined |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 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/common-operator.h" | |||
| 6 | ||||
| 7 | #include "src/base/lazy-instance.h" | |||
| 8 | #include "src/compiler/linkage.h" | |||
| 9 | #include "src/compiler/node.h" | |||
| 10 | #include "src/compiler/opcodes.h" | |||
| 11 | #include "src/compiler/operator.h" | |||
| 12 | #include "src/handles/handles-inl.h" | |||
| 13 | #include "src/zone/zone.h" | |||
| 14 | ||||
| 15 | namespace v8 { | |||
| 16 | namespace internal { | |||
| 17 | namespace compiler { | |||
| 18 | ||||
| 19 | std::ostream& operator<<(std::ostream& os, BranchHint hint) { | |||
| 20 | switch (hint) { | |||
| 21 | case BranchHint::kNone: | |||
| 22 | return os << "None"; | |||
| 23 | case BranchHint::kTrue: | |||
| 24 | return os << "True"; | |||
| 25 | case BranchHint::kFalse: | |||
| 26 | return os << "False"; | |||
| 27 | } | |||
| 28 | UNREACHABLE()V8_Fatal("unreachable code"); | |||
| 29 | } | |||
| 30 | ||||
| 31 | std::ostream& operator<<(std::ostream& os, TrapId trap_id) { | |||
| 32 | switch (trap_id) { | |||
| 33 | #define TRAP_CASE(Name) \ | |||
| 34 | case TrapId::k##Name: \ | |||
| 35 | return os << #Name; | |||
| 36 | FOREACH_WASM_TRAPREASON(TRAP_CASE)TRAP_CASE(TrapUnreachable) TRAP_CASE(TrapMemOutOfBounds) TRAP_CASE (TrapUnalignedAccess) TRAP_CASE(TrapDivByZero) TRAP_CASE(TrapDivUnrepresentable ) TRAP_CASE(TrapRemByZero) TRAP_CASE(TrapFloatUnrepresentable ) TRAP_CASE(TrapFuncSigMismatch) TRAP_CASE(TrapDataSegmentOutOfBounds ) TRAP_CASE(TrapElemSegmentDropped) TRAP_CASE(TrapTableOutOfBounds ) TRAP_CASE(TrapRethrowNull) TRAP_CASE(TrapNullDereference) TRAP_CASE (TrapIllegalCast) TRAP_CASE(TrapArrayOutOfBounds) TRAP_CASE(TrapArrayTooLarge ) | |||
| 37 | #undef TRAP_CASE | |||
| 38 | case TrapId::kInvalid: | |||
| 39 | return os << "Invalid"; | |||
| 40 | } | |||
| 41 | UNREACHABLE()V8_Fatal("unreachable code"); | |||
| 42 | } | |||
| 43 | ||||
| 44 | TrapId TrapIdOf(const Operator* const op) { | |||
| 45 | DCHECK(op->opcode() == IrOpcode::kTrapIf ||((void) 0) | |||
| 46 | op->opcode() == IrOpcode::kTrapUnless)((void) 0); | |||
| 47 | return OpParameter<TrapId>(op); | |||
| 48 | } | |||
| 49 | ||||
| 50 | BranchHint BranchHintOf(const Operator* const op) { | |||
| 51 | switch (op->opcode()) { | |||
| 52 | case IrOpcode::kIfValue: | |||
| 53 | return IfValueParametersOf(op).hint(); | |||
| 54 | case IrOpcode::kIfDefault: | |||
| 55 | case IrOpcode::kBranch: | |||
| 56 | return OpParameter<BranchHint>(op); | |||
| 57 | default: | |||
| 58 | UNREACHABLE()V8_Fatal("unreachable code"); | |||
| 59 | } | |||
| 60 | } | |||
| 61 | ||||
| 62 | int ValueInputCountOfReturn(Operator const* const op) { | |||
| 63 | DCHECK_EQ(IrOpcode::kReturn, op->opcode())((void) 0); | |||
| 64 | // Return nodes have a hidden input at index 0 which we ignore in the value | |||
| 65 | // input count. | |||
| 66 | return op->ValueInputCount() - 1; | |||
| 67 | } | |||
| 68 | ||||
| 69 | bool operator==(DeoptimizeParameters lhs, DeoptimizeParameters rhs) { | |||
| 70 | return lhs.reason() == rhs.reason() && lhs.feedback() == rhs.feedback(); | |||
| 71 | } | |||
| 72 | ||||
| 73 | bool operator!=(DeoptimizeParameters lhs, DeoptimizeParameters rhs) { | |||
| 74 | return !(lhs == rhs); | |||
| 75 | } | |||
| 76 | ||||
| 77 | size_t hash_value(DeoptimizeParameters p) { | |||
| 78 | FeedbackSource::Hash feebdack_hash; | |||
| 79 | return base::hash_combine(p.reason(), feebdack_hash(p.feedback())); | |||
| 80 | } | |||
| 81 | ||||
| 82 | std::ostream& operator<<(std::ostream& os, DeoptimizeParameters p) { | |||
| 83 | return os << p.reason() << ", " << p.feedback(); | |||
| 84 | } | |||
| 85 | ||||
| 86 | DeoptimizeParameters const& DeoptimizeParametersOf(Operator const* const op) { | |||
| 87 | DCHECK(op->opcode() == IrOpcode::kDeoptimize ||((void) 0) | |||
| 88 | op->opcode() == IrOpcode::kDeoptimizeIf ||((void) 0) | |||
| 89 | op->opcode() == IrOpcode::kDeoptimizeUnless)((void) 0); | |||
| 90 | return OpParameter<DeoptimizeParameters>(op); | |||
| 91 | } | |||
| 92 | ||||
| 93 | const Operator* CommonOperatorBuilder::DelayedStringConstant( | |||
| 94 | const StringConstantBase* str) { | |||
| 95 | return zone()->New<Operator1<const StringConstantBase*>>( | |||
| 96 | IrOpcode::kDelayedStringConstant, Operator::kPure, | |||
| 97 | "DelayedStringConstant", 0, 0, 0, 1, 0, 0, str); | |||
| 98 | } | |||
| 99 | ||||
| 100 | bool operator==(SelectParameters const& lhs, SelectParameters const& rhs) { | |||
| 101 | return lhs.representation() == rhs.representation() && | |||
| 102 | lhs.hint() == rhs.hint(); | |||
| 103 | } | |||
| 104 | ||||
| 105 | ||||
| 106 | bool operator!=(SelectParameters const& lhs, SelectParameters const& rhs) { | |||
| 107 | return !(lhs == rhs); | |||
| 108 | } | |||
| 109 | ||||
| 110 | ||||
| 111 | size_t hash_value(SelectParameters const& p) { | |||
| 112 | return base::hash_combine(p.representation(), p.hint()); | |||
| 113 | } | |||
| 114 | ||||
| 115 | ||||
| 116 | std::ostream& operator<<(std::ostream& os, SelectParameters const& p) { | |||
| 117 | return os << p.representation() << ", " << p.hint(); | |||
| 118 | } | |||
| 119 | ||||
| 120 | ||||
| 121 | SelectParameters const& SelectParametersOf(const Operator* const op) { | |||
| 122 | DCHECK_EQ(IrOpcode::kSelect, op->opcode())((void) 0); | |||
| 123 | return OpParameter<SelectParameters>(op); | |||
| 124 | } | |||
| 125 | ||||
| 126 | CallDescriptor const* CallDescriptorOf(const Operator* const op) { | |||
| 127 | DCHECK(op->opcode() == IrOpcode::kCall ||((void) 0) | |||
| 128 | op->opcode() == IrOpcode::kTailCall)((void) 0); | |||
| 129 | return OpParameter<CallDescriptor const*>(op); | |||
| 130 | } | |||
| 131 | ||||
| 132 | size_t ProjectionIndexOf(const Operator* const op) { | |||
| 133 | DCHECK_EQ(IrOpcode::kProjection, op->opcode())((void) 0); | |||
| 134 | return OpParameter<size_t>(op); | |||
| 135 | } | |||
| 136 | ||||
| 137 | ||||
| 138 | MachineRepresentation PhiRepresentationOf(const Operator* const op) { | |||
| 139 | DCHECK_EQ(IrOpcode::kPhi, op->opcode())((void) 0); | |||
| 140 | return OpParameter<MachineRepresentation>(op); | |||
| 141 | } | |||
| 142 | ||||
| 143 | MachineRepresentation LoopExitValueRepresentationOf(const Operator* const op) { | |||
| 144 | DCHECK_EQ(IrOpcode::kLoopExitValue, op->opcode())((void) 0); | |||
| 145 | return OpParameter<MachineRepresentation>(op); | |||
| 146 | } | |||
| 147 | ||||
| 148 | int ParameterIndexOf(const Operator* const op) { | |||
| 149 | DCHECK_EQ(IrOpcode::kParameter, op->opcode())((void) 0); | |||
| 150 | return OpParameter<ParameterInfo>(op).index(); | |||
| 151 | } | |||
| 152 | ||||
| 153 | ||||
| 154 | const ParameterInfo& ParameterInfoOf(const Operator* const op) { | |||
| 155 | DCHECK_EQ(IrOpcode::kParameter, op->opcode())((void) 0); | |||
| 156 | return OpParameter<ParameterInfo>(op); | |||
| 157 | } | |||
| 158 | ||||
| 159 | ||||
| 160 | bool operator==(ParameterInfo const& lhs, ParameterInfo const& rhs) { | |||
| 161 | return lhs.index() == rhs.index(); | |||
| 162 | } | |||
| 163 | ||||
| 164 | ||||
| 165 | bool operator!=(ParameterInfo const& lhs, ParameterInfo const& rhs) { | |||
| 166 | return !(lhs == rhs); | |||
| 167 | } | |||
| 168 | ||||
| 169 | ||||
| 170 | size_t hash_value(ParameterInfo const& p) { return p.index(); } | |||
| 171 | ||||
| 172 | ||||
| 173 | std::ostream& operator<<(std::ostream& os, ParameterInfo const& i) { | |||
| 174 | os << i.index(); | |||
| 175 | if (i.debug_name()) os << ", debug name: " << i.debug_name(); | |||
| 176 | return os; | |||
| 177 | } | |||
| 178 | ||||
| 179 | std::ostream& operator<<(std::ostream& os, ObjectStateInfo const& i) { | |||
| 180 | return os << "id:" << i.object_id() << ", size:" << i.size(); | |||
| 181 | } | |||
| 182 | ||||
| 183 | size_t hash_value(ObjectStateInfo const& p) { | |||
| 184 | return base::hash_combine(p.object_id(), p.size()); | |||
| 185 | } | |||
| 186 | ||||
| 187 | std::ostream& operator<<(std::ostream& os, TypedObjectStateInfo const& i) { | |||
| 188 | return os << "id:" << i.object_id() << ", " << i.machine_types(); | |||
| 189 | } | |||
| 190 | ||||
| 191 | size_t hash_value(TypedObjectStateInfo const& p) { | |||
| 192 | return base::hash_combine(p.object_id(), p.machine_types()); | |||
| 193 | } | |||
| 194 | ||||
| 195 | bool operator==(RelocatablePtrConstantInfo const& lhs, | |||
| 196 | RelocatablePtrConstantInfo const& rhs) { | |||
| 197 | return lhs.rmode() == rhs.rmode() && lhs.value() == rhs.value() && | |||
| 198 | lhs.type() == rhs.type(); | |||
| 199 | } | |||
| 200 | ||||
| 201 | bool operator!=(RelocatablePtrConstantInfo const& lhs, | |||
| 202 | RelocatablePtrConstantInfo const& rhs) { | |||
| 203 | return !(lhs == rhs); | |||
| 204 | } | |||
| 205 | ||||
| 206 | size_t hash_value(RelocatablePtrConstantInfo const& p) { | |||
| 207 | return base::hash_combine(p.value(), int8_t{p.rmode()}, p.type()); | |||
| 208 | } | |||
| 209 | ||||
| 210 | std::ostream& operator<<(std::ostream& os, | |||
| 211 | RelocatablePtrConstantInfo const& p) { | |||
| 212 | return os << p.value() << ", " << static_cast<int>(p.rmode()) << ", " | |||
| 213 | << p.type(); | |||
| 214 | } | |||
| 215 | ||||
| 216 | SparseInputMask::InputIterator::InputIterator( | |||
| 217 | SparseInputMask::BitMaskType bit_mask, Node* parent) | |||
| 218 | : bit_mask_(bit_mask), parent_(parent), real_index_(0) { | |||
| 219 | #if DEBUG | |||
| 220 | if (bit_mask_ != SparseInputMask::kDenseBitMask) { | |||
| 221 | DCHECK_EQ(base::bits::CountPopulation(bit_mask_) -((void) 0) | |||
| 222 | base::bits::CountPopulation(kEndMarker),((void) 0) | |||
| 223 | parent->InputCount())((void) 0); | |||
| 224 | } | |||
| 225 | #endif | |||
| 226 | } | |||
| 227 | ||||
| 228 | void SparseInputMask::InputIterator::Advance() { | |||
| 229 | DCHECK(!IsEnd())((void) 0); | |||
| 230 | ||||
| 231 | if (IsReal()) { | |||
| 232 | ++real_index_; | |||
| 233 | } | |||
| 234 | bit_mask_ >>= 1; | |||
| 235 | } | |||
| 236 | ||||
| 237 | size_t SparseInputMask::InputIterator::AdvanceToNextRealOrEnd() { | |||
| 238 | DCHECK_NE(bit_mask_, SparseInputMask::kDenseBitMask)((void) 0); | |||
| 239 | ||||
| 240 | size_t count = base::bits::CountTrailingZeros(bit_mask_); | |||
| ||||
| 241 | bit_mask_ >>= count; | |||
| ||||
| 242 | DCHECK(IsReal() || IsEnd())((void) 0); | |||
| 243 | return count; | |||
| 244 | } | |||
| 245 | ||||
| 246 | Node* SparseInputMask::InputIterator::GetReal() const { | |||
| 247 | DCHECK(IsReal())((void) 0); | |||
| 248 | return parent_->InputAt(real_index_); | |||
| 249 | } | |||
| 250 | ||||
| 251 | bool SparseInputMask::InputIterator::IsReal() const { | |||
| 252 | return bit_mask_ == SparseInputMask::kDenseBitMask || | |||
| 253 | (bit_mask_ & kEntryMask); | |||
| 254 | } | |||
| 255 | ||||
| 256 | bool SparseInputMask::InputIterator::IsEnd() const { | |||
| 257 | return (bit_mask_ == kEndMarker) || | |||
| 258 | (bit_mask_ == SparseInputMask::kDenseBitMask && | |||
| 259 | real_index_ >= parent_->InputCount()); | |||
| 260 | } | |||
| 261 | ||||
| 262 | int SparseInputMask::CountReal() const { | |||
| 263 | DCHECK(!IsDense())((void) 0); | |||
| 264 | return base::bits::CountPopulation(bit_mask_) - | |||
| 265 | base::bits::CountPopulation(kEndMarker); | |||
| 266 | } | |||
| 267 | ||||
| 268 | SparseInputMask::InputIterator SparseInputMask::IterateOverInputs(Node* node) { | |||
| 269 | DCHECK(IsDense() || CountReal() == node->InputCount())((void) 0); | |||
| 270 | return InputIterator(bit_mask_, node); | |||
| 271 | } | |||
| 272 | ||||
| 273 | bool operator==(SparseInputMask const& lhs, SparseInputMask const& rhs) { | |||
| 274 | return lhs.mask() == rhs.mask(); | |||
| 275 | } | |||
| 276 | ||||
| 277 | bool operator!=(SparseInputMask const& lhs, SparseInputMask const& rhs) { | |||
| 278 | return !(lhs == rhs); | |||
| 279 | } | |||
| 280 | ||||
| 281 | size_t hash_value(SparseInputMask const& p) { | |||
| 282 | return base::hash_value(p.mask()); | |||
| 283 | } | |||
| 284 | ||||
| 285 | std::ostream& operator<<(std::ostream& os, SparseInputMask const& p) { | |||
| 286 | if (p.IsDense()) { | |||
| 287 | return os << "dense"; | |||
| 288 | } else { | |||
| 289 | SparseInputMask::BitMaskType mask = p.mask(); | |||
| 290 | DCHECK_NE(mask, SparseInputMask::kDenseBitMask)((void) 0); | |||
| 291 | ||||
| 292 | os << "sparse:"; | |||
| 293 | ||||
| 294 | while (mask != SparseInputMask::kEndMarker) { | |||
| 295 | if (mask & SparseInputMask::kEntryMask) { | |||
| 296 | os << "^"; | |||
| 297 | } else { | |||
| 298 | os << "."; | |||
| 299 | } | |||
| 300 | mask >>= 1; | |||
| 301 | } | |||
| 302 | return os; | |||
| 303 | } | |||
| 304 | } | |||
| 305 | ||||
| 306 | bool operator==(TypedStateValueInfo const& lhs, | |||
| 307 | TypedStateValueInfo const& rhs) { | |||
| 308 | return lhs.machine_types() == rhs.machine_types() && | |||
| 309 | lhs.sparse_input_mask() == rhs.sparse_input_mask(); | |||
| 310 | } | |||
| 311 | ||||
| 312 | bool operator!=(TypedStateValueInfo const& lhs, | |||
| 313 | TypedStateValueInfo const& rhs) { | |||
| 314 | return !(lhs == rhs); | |||
| 315 | } | |||
| 316 | ||||
| 317 | size_t hash_value(TypedStateValueInfo const& p) { | |||
| 318 | return base::hash_combine(p.machine_types(), p.sparse_input_mask()); | |||
| 319 | } | |||
| 320 | ||||
| 321 | std::ostream& operator<<(std::ostream& os, TypedStateValueInfo const& p) { | |||
| 322 | return os << p.machine_types() << ", " << p.sparse_input_mask(); | |||
| 323 | } | |||
| 324 | ||||
| 325 | size_t hash_value(RegionObservability observability) { | |||
| 326 | return static_cast<size_t>(observability); | |||
| 327 | } | |||
| 328 | ||||
| 329 | std::ostream& operator<<(std::ostream& os, RegionObservability observability) { | |||
| 330 | switch (observability) { | |||
| 331 | case RegionObservability::kObservable: | |||
| 332 | return os << "observable"; | |||
| 333 | case RegionObservability::kNotObservable: | |||
| 334 | return os << "not-observable"; | |||
| 335 | } | |||
| 336 | UNREACHABLE()V8_Fatal("unreachable code"); | |||
| 337 | } | |||
| 338 | ||||
| 339 | RegionObservability RegionObservabilityOf(Operator const* op) { | |||
| 340 | DCHECK_EQ(IrOpcode::kBeginRegion, op->opcode())((void) 0); | |||
| 341 | return OpParameter<RegionObservability>(op); | |||
| 342 | } | |||
| 343 | ||||
| 344 | Type TypeGuardTypeOf(Operator const* op) { | |||
| 345 | DCHECK_EQ(IrOpcode::kTypeGuard, op->opcode())((void) 0); | |||
| 346 | return OpParameter<Type>(op); | |||
| 347 | } | |||
| 348 | ||||
| 349 | std::ostream& operator<<(std::ostream& os, | |||
| 350 | const ZoneVector<MachineType>* types) { | |||
| 351 | // Print all the MachineTypes, separated by commas. | |||
| 352 | bool first = true; | |||
| 353 | for (MachineType elem : *types) { | |||
| 354 | if (!first) { | |||
| 355 | os << ", "; | |||
| 356 | } | |||
| 357 | first = false; | |||
| 358 | os << elem; | |||
| 359 | } | |||
| 360 | return os; | |||
| 361 | } | |||
| 362 | ||||
| 363 | int OsrValueIndexOf(Operator const* op) { | |||
| 364 | DCHECK_EQ(IrOpcode::kOsrValue, op->opcode())((void) 0); | |||
| 365 | return OpParameter<int>(op); | |||
| 366 | } | |||
| 367 | ||||
| 368 | SparseInputMask SparseInputMaskOf(Operator const* op) { | |||
| 369 | DCHECK(op->opcode() == IrOpcode::kStateValues ||((void) 0) | |||
| 370 | op->opcode() == IrOpcode::kTypedStateValues)((void) 0); | |||
| 371 | ||||
| 372 | if (op->opcode() == IrOpcode::kTypedStateValues) { | |||
| 373 | return OpParameter<TypedStateValueInfo>(op).sparse_input_mask(); | |||
| 374 | } | |||
| 375 | return OpParameter<SparseInputMask>(op); | |||
| 376 | } | |||
| 377 | ||||
| 378 | ZoneVector<MachineType> const* MachineTypesOf(Operator const* op) { | |||
| 379 | DCHECK(op->opcode() == IrOpcode::kTypedObjectState ||((void) 0) | |||
| 380 | op->opcode() == IrOpcode::kTypedStateValues)((void) 0); | |||
| 381 | ||||
| 382 | if (op->opcode() == IrOpcode::kTypedStateValues) { | |||
| 383 | return OpParameter<TypedStateValueInfo>(op).machine_types(); | |||
| 384 | } | |||
| 385 | return OpParameter<TypedObjectStateInfo>(op).machine_types(); | |||
| 386 | } | |||
| 387 | ||||
| 388 | V8_EXPORT_PRIVATE bool operator==(IfValueParameters const& l, | |||
| 389 | IfValueParameters const& r) { | |||
| 390 | return l.value() == r.value() && | |||
| 391 | l.comparison_order() == r.comparison_order() && l.hint() == r.hint(); | |||
| 392 | } | |||
| 393 | ||||
| 394 | size_t hash_value(IfValueParameters const& p) { | |||
| 395 | return base::hash_combine(p.value(), p.comparison_order(), p.hint()); | |||
| 396 | } | |||
| 397 | ||||
| 398 | V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& out, | |||
| 399 | IfValueParameters const& p) { | |||
| 400 | out << p.value() << " (order " << p.comparison_order() << ", hint " | |||
| 401 | << p.hint() << ")"; | |||
| 402 | return out; | |||
| 403 | } | |||
| 404 | ||||
| 405 | IfValueParameters const& IfValueParametersOf(const Operator* op) { | |||
| 406 | DCHECK(op->opcode() == IrOpcode::kIfValue)((void) 0); | |||
| 407 | return OpParameter<IfValueParameters>(op); | |||
| 408 | } | |||
| 409 | ||||
| 410 | V8_EXPORT_PRIVATE bool operator==(const SLVerifierHintParameters& p1, | |||
| 411 | const SLVerifierHintParameters& p2) { | |||
| 412 | return p1.semantics() == p2.semantics() && | |||
| 413 | p1.override_output_type() == p2.override_output_type(); | |||
| 414 | } | |||
| 415 | ||||
| 416 | size_t hash_value(const SLVerifierHintParameters& p) { | |||
| 417 | return base::hash_combine( | |||
| 418 | p.semantics(), | |||
| 419 | p.override_output_type() ? hash_value(*p.override_output_type()) : 0); | |||
| 420 | } | |||
| 421 | ||||
| 422 | V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& out, | |||
| 423 | const SLVerifierHintParameters& p) { | |||
| 424 | if (p.semantics()) { | |||
| 425 | p.semantics()->PrintTo(out); | |||
| 426 | } else { | |||
| 427 | out << "nullptr"; | |||
| 428 | } | |||
| 429 | out << ", "; | |||
| 430 | if (const auto& t = p.override_output_type()) { | |||
| 431 | t->PrintTo(out); | |||
| 432 | } else { | |||
| 433 | out << ", nullopt"; | |||
| 434 | } | |||
| 435 | return out; | |||
| 436 | } | |||
| 437 | ||||
| 438 | const SLVerifierHintParameters& SLVerifierHintParametersOf(const Operator* op) { | |||
| 439 | DCHECK_EQ(op->opcode(), IrOpcode::kSLVerifierHint)((void) 0); | |||
| 440 | return OpParameter<SLVerifierHintParameters>(op); | |||
| 441 | } | |||
| 442 | ||||
| 443 | #define COMMON_CACHED_OP_LIST(V) \ | |||
| 444 | V(Plug, Operator::kNoProperties, 0, 0, 0, 1, 0, 0) \ | |||
| 445 | V(Dead, Operator::kFoldable, 0, 0, 0, 1, 1, 1) \ | |||
| 446 | V(Unreachable, Operator::kFoldable, 0, 1, 1, 1, 1, 0) \ | |||
| 447 | V(IfTrue, Operator::kKontrol, 0, 0, 1, 0, 0, 1) \ | |||
| 448 | V(IfFalse, Operator::kKontrol, 0, 0, 1, 0, 0, 1) \ | |||
| 449 | V(IfSuccess, Operator::kKontrol, 0, 0, 1, 0, 0, 1) \ | |||
| 450 | V(IfException, Operator::kKontrol, 0, 1, 1, 1, 1, 1) \ | |||
| 451 | V(Throw, Operator::kKontrol, 0, 1, 1, 0, 0, 1) \ | |||
| 452 | V(Terminate, Operator::kKontrol, 0, 1, 1, 0, 0, 1) \ | |||
| 453 | V(LoopExit, Operator::kKontrol, 0, 0, 2, 0, 0, 1) \ | |||
| 454 | V(LoopExitEffect, Operator::kNoThrow, 0, 1, 1, 0, 1, 0) \ | |||
| 455 | V(Checkpoint, Operator::kKontrol, 0, 1, 1, 0, 1, 0) \ | |||
| 456 | V(FinishRegion, Operator::kKontrol, 1, 1, 0, 1, 1, 0) \ | |||
| 457 | V(Retain, Operator::kKontrol, 1, 1, 0, 0, 1, 0) | |||
| 458 | ||||
| 459 | #define CACHED_LOOP_EXIT_VALUE_LIST(V)V(kTagged) V(kTagged) | |||
| 460 | ||||
| 461 | #define CACHED_BRANCH_LIST(V) \ | |||
| 462 | V(None) \ | |||
| 463 | V(True) \ | |||
| 464 | V(False) | |||
| 465 | ||||
| 466 | #define CACHED_RETURN_LIST(V) \ | |||
| 467 | V(1) \ | |||
| 468 | V(2) \ | |||
| 469 | V(3) \ | |||
| 470 | V(4) | |||
| 471 | ||||
| 472 | #define CACHED_END_LIST(V) \ | |||
| 473 | V(1) \ | |||
| 474 | V(2) \ | |||
| 475 | V(3) \ | |||
| 476 | V(4) \ | |||
| 477 | V(5) \ | |||
| 478 | V(6) \ | |||
| 479 | V(7) \ | |||
| 480 | V(8) | |||
| 481 | ||||
| 482 | ||||
| 483 | #define CACHED_EFFECT_PHI_LIST(V) \ | |||
| 484 | V(1) \ | |||
| 485 | V(2) \ | |||
| 486 | V(3) \ | |||
| 487 | V(4) \ | |||
| 488 | V(5) \ | |||
| 489 | V(6) | |||
| 490 | ||||
| 491 | #define CACHED_INDUCTION_VARIABLE_PHI_LIST(V) \ | |||
| 492 | V(4) \ | |||
| 493 | V(5) \ | |||
| 494 | V(6) \ | |||
| 495 | V(7) | |||
| 496 | ||||
| 497 | #define CACHED_LOOP_LIST(V) \ | |||
| 498 | V(1) \ | |||
| 499 | V(2) | |||
| 500 | ||||
| 501 | ||||
| 502 | #define CACHED_MERGE_LIST(V) \ | |||
| 503 | V(1) \ | |||
| 504 | V(2) \ | |||
| 505 | V(3) \ | |||
| 506 | V(4) \ | |||
| 507 | V(5) \ | |||
| 508 | V(6) \ | |||
| 509 | V(7) \ | |||
| 510 | V(8) | |||
| 511 | ||||
| 512 | #define CACHED_DEOPTIMIZE_LIST(V) \ | |||
| 513 | V(MinusZero) \ | |||
| 514 | V(WrongMap) \ | |||
| 515 | V(InsufficientTypeFeedbackForGenericKeyedAccess) \ | |||
| 516 | V(InsufficientTypeFeedbackForGenericNamedAccess) | |||
| 517 | ||||
| 518 | #define CACHED_DEOPTIMIZE_IF_LIST(V) \ | |||
| 519 | V(DivisionByZero) \ | |||
| 520 | V(Hole) \ | |||
| 521 | V(MinusZero) \ | |||
| 522 | V(Overflow) \ | |||
| 523 | V(Smi) | |||
| 524 | ||||
| 525 | #define CACHED_DEOPTIMIZE_UNLESS_LIST(V) \ | |||
| 526 | V(LostPrecision) \ | |||
| 527 | V(LostPrecisionOrNaN) \ | |||
| 528 | V(NotAHeapNumber) \ | |||
| 529 | V(NotANumberOrOddball) \ | |||
| 530 | V(NotASmi) \ | |||
| 531 | V(OutOfBounds) \ | |||
| 532 | V(WrongInstanceType) \ | |||
| 533 | V(WrongMap) | |||
| 534 | ||||
| 535 | #define CACHED_TRAP_IF_LIST(V) \ | |||
| 536 | V(TrapDivUnrepresentable) \ | |||
| 537 | V(TrapFloatUnrepresentable) | |||
| 538 | ||||
| 539 | // The reason for a trap. | |||
| 540 | #define CACHED_TRAP_UNLESS_LIST(V) \ | |||
| 541 | V(TrapUnreachable) \ | |||
| 542 | V(TrapMemOutOfBounds) \ | |||
| 543 | V(TrapDivByZero) \ | |||
| 544 | V(TrapDivUnrepresentable) \ | |||
| 545 | V(TrapRemByZero) \ | |||
| 546 | V(TrapFloatUnrepresentable) \ | |||
| 547 | V(TrapTableOutOfBounds) \ | |||
| 548 | V(TrapFuncSigMismatch) | |||
| 549 | ||||
| 550 | #define CACHED_PARAMETER_LIST(V) \ | |||
| 551 | V(0) \ | |||
| 552 | V(1) \ | |||
| 553 | V(2) \ | |||
| 554 | V(3) \ | |||
| 555 | V(4) \ | |||
| 556 | V(5) \ | |||
| 557 | V(6) | |||
| 558 | ||||
| 559 | ||||
| 560 | #define CACHED_PHI_LIST(V) \ | |||
| 561 | V(kTagged, 1) \ | |||
| 562 | V(kTagged, 2) \ | |||
| 563 | V(kTagged, 3) \ | |||
| 564 | V(kTagged, 4) \ | |||
| 565 | V(kTagged, 5) \ | |||
| 566 | V(kTagged, 6) \ | |||
| 567 | V(kBit, 2) \ | |||
| 568 | V(kFloat64, 2) \ | |||
| 569 | V(kWord32, 2) | |||
| 570 | ||||
| 571 | ||||
| 572 | #define CACHED_PROJECTION_LIST(V) \ | |||
| 573 | V(0) \ | |||
| 574 | V(1) | |||
| 575 | ||||
| 576 | ||||
| 577 | #define CACHED_STATE_VALUES_LIST(V) \ | |||
| 578 | V(0) \ | |||
| 579 | V(1) \ | |||
| 580 | V(2) \ | |||
| 581 | V(3) \ | |||
| 582 | V(4) \ | |||
| 583 | V(5) \ | |||
| 584 | V(6) \ | |||
| 585 | V(7) \ | |||
| 586 | V(8) \ | |||
| 587 | V(10) \ | |||
| 588 | V(11) \ | |||
| 589 | V(12) \ | |||
| 590 | V(13) \ | |||
| 591 | V(14) | |||
| 592 | ||||
| 593 | ||||
| 594 | struct CommonOperatorGlobalCache final { | |||
| 595 | #define CACHED(Name, properties, value_input_count, effect_input_count, \ | |||
| 596 | control_input_count, value_output_count, effect_output_count, \ | |||
| 597 | control_output_count) \ | |||
| 598 | struct Name##Operator final : public Operator { \ | |||
| 599 | Name##Operator() \ | |||
| 600 | : Operator(IrOpcode::k##Name, properties, #Name, value_input_count, \ | |||
| 601 | effect_input_count, control_input_count, \ | |||
| 602 | value_output_count, effect_output_count, \ | |||
| 603 | control_output_count) {} \ | |||
| 604 | }; \ | |||
| 605 | Name##Operator k##Name##Operator; | |||
| 606 | COMMON_CACHED_OP_LIST(CACHED) | |||
| 607 | #undef CACHED | |||
| 608 | ||||
| 609 | template <size_t kInputCount> | |||
| 610 | struct EndOperator final : public Operator { | |||
| 611 | EndOperator() | |||
| 612 | : Operator( // -- | |||
| 613 | IrOpcode::kEnd, Operator::kKontrol, // opcode | |||
| 614 | "End", // name | |||
| 615 | 0, 0, kInputCount, 0, 0, 0) {} // counts | |||
| 616 | }; | |||
| 617 | #define CACHED_END(input_count) \ | |||
| 618 | EndOperator<input_count> kEnd##input_count##Operator; | |||
| 619 | CACHED_END_LIST(CACHED_END) | |||
| 620 | #undef CACHED_END | |||
| 621 | ||||
| 622 | template <size_t kValueInputCount> | |||
| 623 | struct ReturnOperator final : public Operator { | |||
| 624 | ReturnOperator() | |||
| 625 | : Operator( // -- | |||
| 626 | IrOpcode::kReturn, Operator::kNoThrow, // opcode | |||
| 627 | "Return", // name | |||
| 628 | kValueInputCount + 1, 1, 1, 0, 0, 1) {} // counts | |||
| 629 | }; | |||
| 630 | #define CACHED_RETURN(value_input_count) \ | |||
| 631 | ReturnOperator<value_input_count> kReturn##value_input_count##Operator; | |||
| 632 | CACHED_RETURN_LIST(CACHED_RETURN) | |||
| 633 | #undef CACHED_RETURN | |||
| 634 | ||||
| 635 | template <BranchHint hint> | |||
| 636 | struct BranchOperator final : public Operator1<BranchHint> { | |||
| 637 | BranchOperator() | |||
| 638 | : Operator1<BranchHint>( // -- | |||
| 639 | IrOpcode::kBranch, Operator::kKontrol, // opcode | |||
| 640 | "Branch", // name | |||
| 641 | 1, 0, 1, 0, 0, 2, // counts | |||
| 642 | hint) {} // parameter | |||
| 643 | }; | |||
| 644 | #define CACHED_BRANCH(Hint) \ | |||
| 645 | BranchOperator<BranchHint::k##Hint> kBranch##Hint##Operator; | |||
| 646 | CACHED_BRANCH_LIST(CACHED_BRANCH) | |||
| 647 | #undef CACHED_BRANCH | |||
| 648 | ||||
| 649 | template <int kEffectInputCount> | |||
| 650 | struct EffectPhiOperator final : public Operator { | |||
| 651 | EffectPhiOperator() | |||
| 652 | : Operator( // -- | |||
| 653 | IrOpcode::kEffectPhi, Operator::kKontrol, // opcode | |||
| 654 | "EffectPhi", // name | |||
| 655 | 0, kEffectInputCount, 1, 0, 1, 0) {} // counts | |||
| 656 | }; | |||
| 657 | #define CACHED_EFFECT_PHI(input_count) \ | |||
| 658 | EffectPhiOperator<input_count> kEffectPhi##input_count##Operator; | |||
| 659 | CACHED_EFFECT_PHI_LIST(CACHED_EFFECT_PHI) | |||
| 660 | #undef CACHED_EFFECT_PHI | |||
| 661 | ||||
| 662 | template <RegionObservability kRegionObservability> | |||
| 663 | struct BeginRegionOperator final : public Operator1<RegionObservability> { | |||
| 664 | BeginRegionOperator() | |||
| 665 | : Operator1<RegionObservability>( // -- | |||
| 666 | IrOpcode::kBeginRegion, Operator::kKontrol, // opcode | |||
| 667 | "BeginRegion", // name | |||
| 668 | 0, 1, 0, 0, 1, 0, // counts | |||
| 669 | kRegionObservability) {} // parameter | |||
| 670 | }; | |||
| 671 | BeginRegionOperator<RegionObservability::kObservable> | |||
| 672 | kBeginRegionObservableOperator; | |||
| 673 | BeginRegionOperator<RegionObservability::kNotObservable> | |||
| 674 | kBeginRegionNotObservableOperator; | |||
| 675 | ||||
| 676 | template <size_t kInputCount> | |||
| 677 | struct LoopOperator final : public Operator { | |||
| 678 | LoopOperator() | |||
| 679 | : Operator( // -- | |||
| 680 | IrOpcode::kLoop, Operator::kKontrol, // opcode | |||
| 681 | "Loop", // name | |||
| 682 | 0, 0, kInputCount, 0, 0, 1) {} // counts | |||
| 683 | }; | |||
| 684 | #define CACHED_LOOP(input_count) \ | |||
| 685 | LoopOperator<input_count> kLoop##input_count##Operator; | |||
| 686 | CACHED_LOOP_LIST(CACHED_LOOP) | |||
| 687 | #undef CACHED_LOOP | |||
| 688 | ||||
| 689 | template <size_t kInputCount> | |||
| 690 | struct MergeOperator final : public Operator { | |||
| 691 | MergeOperator() | |||
| 692 | : Operator( // -- | |||
| 693 | IrOpcode::kMerge, Operator::kKontrol, // opcode | |||
| 694 | "Merge", // name | |||
| 695 | 0, 0, kInputCount, 0, 0, 1) {} // counts | |||
| 696 | }; | |||
| 697 | #define CACHED_MERGE(input_count) \ | |||
| 698 | MergeOperator<input_count> kMerge##input_count##Operator; | |||
| 699 | CACHED_MERGE_LIST(CACHED_MERGE) | |||
| 700 | #undef CACHED_MERGE | |||
| 701 | ||||
| 702 | template <MachineRepresentation kRep> | |||
| 703 | struct LoopExitValueOperator final : public Operator1<MachineRepresentation> { | |||
| 704 | LoopExitValueOperator() | |||
| 705 | : Operator1<MachineRepresentation>(IrOpcode::kLoopExitValue, | |||
| 706 | Operator::kPure, "LoopExitValue", 1, | |||
| 707 | 0, 1, 1, 0, 0, kRep) {} | |||
| 708 | }; | |||
| 709 | #define CACHED_LOOP_EXIT_VALUE(rep) \ | |||
| 710 | LoopExitValueOperator<MachineRepresentation::rep> \ | |||
| 711 | kLoopExitValue##rep##Operator; | |||
| 712 | CACHED_LOOP_EXIT_VALUE_LIST(CACHED_LOOP_EXIT_VALUE)CACHED_LOOP_EXIT_VALUE(kTagged) | |||
| 713 | #undef CACHED_LOOP_EXIT_VALUE | |||
| 714 | ||||
| 715 | template <DeoptimizeReason kReason> | |||
| 716 | struct DeoptimizeOperator final : public Operator1<DeoptimizeParameters> { | |||
| 717 | DeoptimizeOperator() | |||
| 718 | : Operator1<DeoptimizeParameters>( // -- | |||
| 719 | IrOpcode::kDeoptimize, // opcode | |||
| 720 | Operator::kFoldable | Operator::kNoThrow, // properties | |||
| 721 | "Deoptimize", // name | |||
| 722 | 1, 1, 1, 0, 0, 1, // counts | |||
| 723 | DeoptimizeParameters(kReason, FeedbackSource())) {} | |||
| 724 | }; | |||
| 725 | #define CACHED_DEOPTIMIZE(Reason) \ | |||
| 726 | DeoptimizeOperator<DeoptimizeReason::k##Reason> kDeoptimize##Reason##Operator; | |||
| 727 | CACHED_DEOPTIMIZE_LIST(CACHED_DEOPTIMIZE) | |||
| 728 | #undef CACHED_DEOPTIMIZE | |||
| 729 | ||||
| 730 | template <DeoptimizeReason kReason> | |||
| 731 | struct DeoptimizeIfOperator final : public Operator1<DeoptimizeParameters> { | |||
| 732 | DeoptimizeIfOperator() | |||
| 733 | : Operator1<DeoptimizeParameters>( // -- | |||
| 734 | IrOpcode::kDeoptimizeIf, // opcode | |||
| 735 | Operator::kFoldable | Operator::kNoThrow, // properties | |||
| 736 | "DeoptimizeIf", // name | |||
| 737 | 2, 1, 1, 0, 1, 1, // counts | |||
| 738 | DeoptimizeParameters(kReason, FeedbackSource())) {} | |||
| 739 | }; | |||
| 740 | #define CACHED_DEOPTIMIZE_IF(Reason) \ | |||
| 741 | DeoptimizeIfOperator<DeoptimizeReason::k##Reason> \ | |||
| 742 | kDeoptimizeIf##Reason##Operator; | |||
| 743 | CACHED_DEOPTIMIZE_IF_LIST(CACHED_DEOPTIMIZE_IF) | |||
| 744 | #undef CACHED_DEOPTIMIZE_IF | |||
| 745 | ||||
| 746 | template <DeoptimizeReason kReason> | |||
| 747 | struct DeoptimizeUnlessOperator final | |||
| 748 | : public Operator1<DeoptimizeParameters> { | |||
| 749 | DeoptimizeUnlessOperator() | |||
| 750 | : Operator1<DeoptimizeParameters>( // -- | |||
| 751 | IrOpcode::kDeoptimizeUnless, // opcode | |||
| 752 | Operator::kFoldable | Operator::kNoThrow, // properties | |||
| 753 | "DeoptimizeUnless", // name | |||
| 754 | 2, 1, 1, 0, 1, 1, // counts | |||
| 755 | DeoptimizeParameters(kReason, FeedbackSource())) {} | |||
| 756 | }; | |||
| 757 | #define CACHED_DEOPTIMIZE_UNLESS(Reason) \ | |||
| 758 | DeoptimizeUnlessOperator<DeoptimizeReason::k##Reason> \ | |||
| 759 | kDeoptimizeUnless##Reason##Operator; | |||
| 760 | CACHED_DEOPTIMIZE_UNLESS_LIST(CACHED_DEOPTIMIZE_UNLESS) | |||
| 761 | #undef CACHED_DEOPTIMIZE_UNLESS | |||
| 762 | ||||
| 763 | template <TrapId trap_id> | |||
| 764 | struct TrapIfOperator final : public Operator1<TrapId> { | |||
| 765 | TrapIfOperator() | |||
| 766 | : Operator1<TrapId>( // -- | |||
| 767 | IrOpcode::kTrapIf, // opcode | |||
| 768 | Operator::kFoldable | Operator::kNoThrow, // properties | |||
| 769 | "TrapIf", // name | |||
| 770 | 1, 1, 1, 0, 0, 1, // counts | |||
| 771 | trap_id) {} // parameter | |||
| 772 | }; | |||
| 773 | #define CACHED_TRAP_IF(Trap) \ | |||
| 774 | TrapIfOperator<TrapId::k##Trap> kTrapIf##Trap##Operator; | |||
| 775 | CACHED_TRAP_IF_LIST(CACHED_TRAP_IF) | |||
| 776 | #undef CACHED_TRAP_IF | |||
| 777 | ||||
| 778 | template <TrapId trap_id> | |||
| 779 | struct TrapUnlessOperator final : public Operator1<TrapId> { | |||
| 780 | TrapUnlessOperator() | |||
| 781 | : Operator1<TrapId>( // -- | |||
| 782 | IrOpcode::kTrapUnless, // opcode | |||
| 783 | Operator::kFoldable | Operator::kNoThrow, // properties | |||
| 784 | "TrapUnless", // name | |||
| 785 | 1, 1, 1, 0, 0, 1, // counts | |||
| 786 | trap_id) {} // parameter | |||
| 787 | }; | |||
| 788 | #define CACHED_TRAP_UNLESS(Trap) \ | |||
| 789 | TrapUnlessOperator<TrapId::k##Trap> kTrapUnless##Trap##Operator; | |||
| 790 | CACHED_TRAP_UNLESS_LIST(CACHED_TRAP_UNLESS) | |||
| 791 | #undef CACHED_TRAP_UNLESS | |||
| 792 | ||||
| 793 | template <MachineRepresentation kRep, int kInputCount> | |||
| 794 | struct PhiOperator final : public Operator1<MachineRepresentation> { | |||
| 795 | PhiOperator() | |||
| 796 | : Operator1<MachineRepresentation>( //-- | |||
| 797 | IrOpcode::kPhi, Operator::kPure, // opcode | |||
| 798 | "Phi", // name | |||
| 799 | kInputCount, 0, 1, 1, 0, 0, // counts | |||
| 800 | kRep) {} // parameter | |||
| 801 | }; | |||
| 802 | #define CACHED_PHI(rep, input_count) \ | |||
| 803 | PhiOperator<MachineRepresentation::rep, input_count> \ | |||
| 804 | kPhi##rep##input_count##Operator; | |||
| 805 | CACHED_PHI_LIST(CACHED_PHI) | |||
| 806 | #undef CACHED_PHI | |||
| 807 | ||||
| 808 | template <int kInputCount> | |||
| 809 | struct InductionVariablePhiOperator final : public Operator { | |||
| 810 | InductionVariablePhiOperator() | |||
| 811 | : Operator( //-- | |||
| 812 | IrOpcode::kInductionVariablePhi, Operator::kPure, // opcode | |||
| 813 | "InductionVariablePhi", // name | |||
| 814 | kInputCount, 0, 1, 1, 0, 0) {} // counts | |||
| 815 | }; | |||
| 816 | #define CACHED_INDUCTION_VARIABLE_PHI(input_count) \ | |||
| 817 | InductionVariablePhiOperator<input_count> \ | |||
| 818 | kInductionVariablePhi##input_count##Operator; | |||
| 819 | CACHED_INDUCTION_VARIABLE_PHI_LIST(CACHED_INDUCTION_VARIABLE_PHI) | |||
| 820 | #undef CACHED_INDUCTION_VARIABLE_PHI | |||
| 821 | ||||
| 822 | template <int kIndex> | |||
| 823 | struct ParameterOperator final : public Operator1<ParameterInfo> { | |||
| 824 | ParameterOperator() | |||
| 825 | : Operator1<ParameterInfo>( // -- | |||
| 826 | IrOpcode::kParameter, Operator::kPure, // opcode | |||
| 827 | "Parameter", // name | |||
| 828 | 1, 0, 0, 1, 0, 0, // counts, | |||
| 829 | ParameterInfo(kIndex, nullptr)) {} // parameter and name | |||
| 830 | }; | |||
| 831 | #define CACHED_PARAMETER(index) \ | |||
| 832 | ParameterOperator<index> kParameter##index##Operator; | |||
| 833 | CACHED_PARAMETER_LIST(CACHED_PARAMETER) | |||
| 834 | #undef CACHED_PARAMETER | |||
| 835 | ||||
| 836 | template <size_t kIndex> | |||
| 837 | struct ProjectionOperator final : public Operator1<size_t> { | |||
| 838 | ProjectionOperator() | |||
| 839 | : Operator1<size_t>( // -- | |||
| 840 | IrOpcode::kProjection, // opcode | |||
| 841 | Operator::kPure, // flags | |||
| 842 | "Projection", // name | |||
| 843 | 1, 0, 1, 1, 0, 0, // counts, | |||
| 844 | kIndex) {} // parameter | |||
| 845 | }; | |||
| 846 | #define CACHED_PROJECTION(index) \ | |||
| 847 | ProjectionOperator<index> kProjection##index##Operator; | |||
| 848 | CACHED_PROJECTION_LIST(CACHED_PROJECTION) | |||
| 849 | #undef CACHED_PROJECTION | |||
| 850 | ||||
| 851 | template <int kInputCount> | |||
| 852 | struct StateValuesOperator final : public Operator1<SparseInputMask> { | |||
| 853 | StateValuesOperator() | |||
| 854 | : Operator1<SparseInputMask>( // -- | |||
| 855 | IrOpcode::kStateValues, // opcode | |||
| 856 | Operator::kPure, // flags | |||
| 857 | "StateValues", // name | |||
| 858 | kInputCount, 0, 0, 1, 0, 0, // counts | |||
| 859 | SparseInputMask::Dense()) {} // parameter | |||
| 860 | }; | |||
| 861 | #define CACHED_STATE_VALUES(input_count) \ | |||
| 862 | StateValuesOperator<input_count> kStateValues##input_count##Operator; | |||
| 863 | CACHED_STATE_VALUES_LIST(CACHED_STATE_VALUES) | |||
| 864 | #undef CACHED_STATE_VALUES | |||
| 865 | }; | |||
| 866 | ||||
| 867 | namespace { | |||
| 868 | DEFINE_LAZY_LEAKY_OBJECT_GETTER(CommonOperatorGlobalCache,CommonOperatorGlobalCache* GetCommonOperatorGlobalCache() { static ::v8::base::LeakyObject<CommonOperatorGlobalCache> object {}; return object.get(); } | |||
| 869 | GetCommonOperatorGlobalCache)CommonOperatorGlobalCache* GetCommonOperatorGlobalCache() { static ::v8::base::LeakyObject<CommonOperatorGlobalCache> object {}; return object.get(); } | |||
| 870 | } // namespace | |||
| 871 | ||||
| 872 | CommonOperatorBuilder::CommonOperatorBuilder(Zone* zone) | |||
| 873 | : cache_(*GetCommonOperatorGlobalCache()), zone_(zone) {} | |||
| 874 | ||||
| 875 | #define CACHED(Name, properties, value_input_count, effect_input_count, \ | |||
| 876 | control_input_count, value_output_count, effect_output_count, \ | |||
| 877 | control_output_count) \ | |||
| 878 | const Operator* CommonOperatorBuilder::Name() { \ | |||
| 879 | return &cache_.k##Name##Operator; \ | |||
| 880 | } | |||
| 881 | COMMON_CACHED_OP_LIST(CACHED) | |||
| 882 | #undef CACHED | |||
| 883 | ||||
| 884 | ||||
| 885 | const Operator* CommonOperatorBuilder::End(size_t control_input_count) { | |||
| 886 | switch (control_input_count) { | |||
| 887 | #define CACHED_END(input_count) \ | |||
| 888 | case input_count: \ | |||
| 889 | return &cache_.kEnd##input_count##Operator; | |||
| 890 | CACHED_END_LIST(CACHED_END) | |||
| 891 | #undef CACHED_END | |||
| 892 | default: | |||
| 893 | break; | |||
| 894 | } | |||
| 895 | // Uncached. | |||
| 896 | return zone()->New<Operator>( //-- | |||
| 897 | IrOpcode::kEnd, Operator::kKontrol, // opcode | |||
| 898 | "End", // name | |||
| 899 | 0, 0, control_input_count, 0, 0, 0); // counts | |||
| 900 | } | |||
| 901 | ||||
| 902 | const Operator* CommonOperatorBuilder::Return(int value_input_count) { | |||
| 903 | switch (value_input_count) { | |||
| 904 | #define CACHED_RETURN(input_count) \ | |||
| 905 | case input_count: \ | |||
| 906 | return &cache_.kReturn##input_count##Operator; | |||
| 907 | CACHED_RETURN_LIST(CACHED_RETURN) | |||
| 908 | #undef CACHED_RETURN | |||
| 909 | default: | |||
| 910 | break; | |||
| 911 | } | |||
| 912 | // Uncached. | |||
| 913 | return zone()->New<Operator>( //-- | |||
| 914 | IrOpcode::kReturn, Operator::kNoThrow, // opcode | |||
| 915 | "Return", // name | |||
| 916 | value_input_count + 1, 1, 1, 0, 0, 1); // counts | |||
| 917 | } | |||
| 918 | ||||
| 919 | const Operator* CommonOperatorBuilder::StaticAssert(const char* source) { | |||
| 920 | return zone()->New<Operator1<const char*>>( | |||
| 921 | IrOpcode::kStaticAssert, Operator::kFoldable, "StaticAssert", 1, 1, 0, 0, | |||
| 922 | 1, 0, source); | |||
| 923 | } | |||
| 924 | ||||
| 925 | const Operator* CommonOperatorBuilder::SLVerifierHint( | |||
| 926 | const Operator* semantics, | |||
| 927 | const base::Optional<Type>& override_output_type) { | |||
| 928 | return zone()->New<Operator1<SLVerifierHintParameters>>( | |||
| 929 | IrOpcode::kSLVerifierHint, Operator::kNoProperties, "SLVerifierHint", 1, | |||
| 930 | 0, 0, 1, 0, 0, SLVerifierHintParameters(semantics, override_output_type)); | |||
| 931 | } | |||
| 932 | ||||
| 933 | const Operator* CommonOperatorBuilder::Branch(BranchHint hint) { | |||
| 934 | #define CACHED_BRANCH(Hint) \ | |||
| 935 | if (hint == BranchHint::k##Hint) { \ | |||
| 936 | return &cache_.kBranch##Hint##Operator; \ | |||
| 937 | } | |||
| 938 | CACHED_BRANCH_LIST(CACHED_BRANCH) | |||
| 939 | #undef CACHED_BRANCH | |||
| 940 | UNREACHABLE()V8_Fatal("unreachable code"); | |||
| 941 | } | |||
| 942 | ||||
| 943 | const Operator* CommonOperatorBuilder::Deoptimize( | |||
| 944 | DeoptimizeReason reason, FeedbackSource const& feedback) { | |||
| 945 | #define CACHED_DEOPTIMIZE(Reason) \ | |||
| 946 | if (reason == DeoptimizeReason::k##Reason && !feedback.IsValid()) { \ | |||
| 947 | return &cache_.kDeoptimize##Reason##Operator; \ | |||
| 948 | } | |||
| 949 | CACHED_DEOPTIMIZE_LIST(CACHED_DEOPTIMIZE) | |||
| 950 | #undef CACHED_DEOPTIMIZE | |||
| 951 | // Uncached | |||
| 952 | DeoptimizeParameters parameter(reason, feedback); | |||
| 953 | return zone()->New<Operator1<DeoptimizeParameters>>( // -- | |||
| 954 | IrOpcode::kDeoptimize, // opcodes | |||
| 955 | Operator::kFoldable | Operator::kNoThrow, // properties | |||
| 956 | "Deoptimize", // name | |||
| 957 | 1, 1, 1, 0, 0, 1, // counts | |||
| 958 | parameter); // parameter | |||
| 959 | } | |||
| 960 | ||||
| 961 | const Operator* CommonOperatorBuilder::DeoptimizeIf( | |||
| 962 | DeoptimizeReason reason, FeedbackSource const& feedback) { | |||
| 963 | #define CACHED_DEOPTIMIZE_IF(Reason) \ | |||
| 964 | if (reason == DeoptimizeReason::k##Reason && !feedback.IsValid()) { \ | |||
| 965 | return &cache_.kDeoptimizeIf##Reason##Operator; \ | |||
| 966 | } | |||
| 967 | CACHED_DEOPTIMIZE_IF_LIST(CACHED_DEOPTIMIZE_IF) | |||
| 968 | #undef CACHED_DEOPTIMIZE_IF | |||
| 969 | // Uncached | |||
| 970 | DeoptimizeParameters parameter(reason, feedback); | |||
| 971 | return zone()->New<Operator1<DeoptimizeParameters>>( // -- | |||
| 972 | IrOpcode::kDeoptimizeIf, // opcode | |||
| 973 | Operator::kFoldable | Operator::kNoThrow, // properties | |||
| 974 | "DeoptimizeIf", // name | |||
| 975 | 2, 1, 1, 0, 1, 1, // counts | |||
| 976 | parameter); // parameter | |||
| 977 | } | |||
| 978 | ||||
| 979 | const Operator* CommonOperatorBuilder::DeoptimizeUnless( | |||
| 980 | DeoptimizeReason reason, FeedbackSource const& feedback) { | |||
| 981 | #define CACHED_DEOPTIMIZE_UNLESS(Reason) \ | |||
| 982 | if (reason == DeoptimizeReason::k##Reason && !feedback.IsValid()) { \ | |||
| 983 | return &cache_.kDeoptimizeUnless##Reason##Operator; \ | |||
| 984 | } | |||
| 985 | CACHED_DEOPTIMIZE_UNLESS_LIST(CACHED_DEOPTIMIZE_UNLESS) | |||
| 986 | #undef CACHED_DEOPTIMIZE_UNLESS | |||
| 987 | // Uncached | |||
| 988 | DeoptimizeParameters parameter(reason, feedback); | |||
| 989 | return zone()->New<Operator1<DeoptimizeParameters>>( // -- | |||
| 990 | IrOpcode::kDeoptimizeUnless, // opcode | |||
| 991 | Operator::kFoldable | Operator::kNoThrow, // properties | |||
| 992 | "DeoptimizeUnless", // name | |||
| 993 | 2, 1, 1, 0, 1, 1, // counts | |||
| 994 | parameter); // parameter | |||
| 995 | } | |||
| 996 | ||||
| 997 | const Operator* CommonOperatorBuilder::TrapIf(TrapId trap_id) { | |||
| 998 | switch (trap_id) { | |||
| 999 | #define CACHED_TRAP_IF(Trap) \ | |||
| 1000 | case TrapId::k##Trap: \ | |||
| 1001 | return &cache_.kTrapIf##Trap##Operator; | |||
| 1002 | CACHED_TRAP_IF_LIST(CACHED_TRAP_IF) | |||
| 1003 | #undef CACHED_TRAP_IF | |||
| 1004 | default: | |||
| 1005 | break; | |||
| 1006 | } | |||
| 1007 | // Uncached | |||
| 1008 | return zone()->New<Operator1<TrapId>>( // -- | |||
| 1009 | IrOpcode::kTrapIf, // opcode | |||
| 1010 | Operator::kFoldable | Operator::kNoThrow, // properties | |||
| 1011 | "TrapIf", // name | |||
| 1012 | 1, 1, 1, 0, 0, 1, // counts | |||
| 1013 | trap_id); // parameter | |||
| 1014 | } | |||
| 1015 | ||||
| 1016 | const Operator* CommonOperatorBuilder::TrapUnless(TrapId trap_id) { | |||
| 1017 | switch (trap_id) { | |||
| 1018 | #define CACHED_TRAP_UNLESS(Trap) \ | |||
| 1019 | case TrapId::k##Trap: \ | |||
| 1020 | return &cache_.kTrapUnless##Trap##Operator; | |||
| 1021 | CACHED_TRAP_UNLESS_LIST(CACHED_TRAP_UNLESS) | |||
| 1022 | #undef CACHED_TRAP_UNLESS | |||
| 1023 | default: | |||
| 1024 | break; | |||
| 1025 | } | |||
| 1026 | // Uncached | |||
| 1027 | return zone()->New<Operator1<TrapId>>( // -- | |||
| 1028 | IrOpcode::kTrapUnless, // opcode | |||
| 1029 | Operator::kFoldable | Operator::kNoThrow, // properties | |||
| 1030 | "TrapUnless", // name | |||
| 1031 | 1, 1, 1, 0, 0, 1, // counts | |||
| 1032 | trap_id); // parameter | |||
| 1033 | } | |||
| 1034 | ||||
| 1035 | const Operator* CommonOperatorBuilder::Switch(size_t control_output_count) { | |||
| 1036 | return zone()->New<Operator>( // -- | |||
| 1037 | IrOpcode::kSwitch, Operator::kKontrol, // opcode | |||
| 1038 | "Switch", // name | |||
| 1039 | 1, 0, 1, 0, 0, control_output_count); // counts | |||
| 1040 | } | |||
| 1041 | ||||
| 1042 | const Operator* CommonOperatorBuilder::IfValue(int32_t index, | |||
| 1043 | int32_t comparison_order, | |||
| 1044 | BranchHint hint) { | |||
| 1045 | return zone()->New<Operator1<IfValueParameters>>( // -- | |||
| 1046 | IrOpcode::kIfValue, Operator::kKontrol, // opcode | |||
| 1047 | "IfValue", // name | |||
| 1048 | 0, 0, 1, 0, 0, 1, // counts | |||
| 1049 | IfValueParameters(index, comparison_order, hint)); // parameter | |||
| 1050 | } | |||
| 1051 | ||||
| 1052 | const Operator* CommonOperatorBuilder::IfDefault(BranchHint hint) { | |||
| 1053 | return zone()->New<Operator1<BranchHint>>( // -- | |||
| 1054 | IrOpcode::kIfDefault, Operator::kKontrol, // opcode | |||
| 1055 | "IfDefault", // name | |||
| 1056 | 0, 0, 1, 0, 0, 1, // counts | |||
| 1057 | hint); // parameter | |||
| 1058 | } | |||
| 1059 | ||||
| 1060 | const Operator* CommonOperatorBuilder::Start(int value_output_count) { | |||
| 1061 | return zone()->New<Operator>( // -- | |||
| 1062 | IrOpcode::kStart, Operator::kFoldable | Operator::kNoThrow, // opcode | |||
| 1063 | "Start", // name | |||
| 1064 | 0, 0, 0, value_output_count, 1, 1); // counts | |||
| 1065 | } | |||
| 1066 | ||||
| 1067 | ||||
| 1068 | const Operator* CommonOperatorBuilder::Loop(int control_input_count) { | |||
| 1069 | switch (control_input_count) { | |||
| 1070 | #define CACHED_LOOP(input_count) \ | |||
| 1071 | case input_count: \ | |||
| 1072 | return &cache_.kLoop##input_count##Operator; | |||
| 1073 | CACHED_LOOP_LIST(CACHED_LOOP) | |||
| 1074 | #undef CACHED_LOOP | |||
| 1075 | default: | |||
| 1076 | break; | |||
| 1077 | } | |||
| 1078 | // Uncached. | |||
| 1079 | return zone()->New<Operator>( // -- | |||
| 1080 | IrOpcode::kLoop, Operator::kKontrol, // opcode | |||
| 1081 | "Loop", // name | |||
| 1082 | 0, 0, control_input_count, 0, 0, 1); // counts | |||
| 1083 | } | |||
| 1084 | ||||
| 1085 | ||||
| 1086 | const Operator* CommonOperatorBuilder::Merge(int control_input_count) { | |||
| 1087 | switch (control_input_count) { | |||
| 1088 | #define CACHED_MERGE(input_count) \ | |||
| 1089 | case input_count: \ | |||
| 1090 | return &cache_.kMerge##input_count##Operator; | |||
| 1091 | CACHED_MERGE_LIST(CACHED_MERGE) | |||
| 1092 | #undef CACHED_MERGE | |||
| 1093 | default: | |||
| 1094 | break; | |||
| 1095 | } | |||
| 1096 | // Uncached. | |||
| 1097 | return zone()->New<Operator>( // -- | |||
| 1098 | IrOpcode::kMerge, Operator::kKontrol, // opcode | |||
| 1099 | "Merge", // name | |||
| 1100 | 0, 0, control_input_count, 0, 0, 1); // counts | |||
| 1101 | } | |||
| 1102 | ||||
| 1103 | const Operator* CommonOperatorBuilder::LoopExitValue( | |||
| 1104 | MachineRepresentation rep) { | |||
| 1105 | switch (rep) { | |||
| 1106 | #define CACHED_LOOP_EXIT_VALUE(kRep) \ | |||
| 1107 | case MachineRepresentation::kRep: \ | |||
| 1108 | return &cache_.kLoopExitValue##kRep##Operator; | |||
| 1109 | ||||
| 1110 | CACHED_LOOP_EXIT_VALUE_LIST(CACHED_LOOP_EXIT_VALUE)CACHED_LOOP_EXIT_VALUE(kTagged) | |||
| 1111 | #undef CACHED_LOOP_EXIT_VALUE | |||
| 1112 | default: | |||
| 1113 | // Uncached. | |||
| 1114 | return zone()->New<Operator1<MachineRepresentation>>( // -- | |||
| 1115 | IrOpcode::kLoopExitValue, Operator::kPure, // opcode | |||
| 1116 | "LoopExitValue", // name | |||
| 1117 | 1, 0, 1, 1, 0, 0, // counts | |||
| 1118 | rep); // parameter | |||
| 1119 | } | |||
| 1120 | } | |||
| 1121 | ||||
| 1122 | const Operator* CommonOperatorBuilder::Parameter(int index, | |||
| 1123 | const char* debug_name) { | |||
| 1124 | if (!debug_name) { | |||
| 1125 | switch (index) { | |||
| 1126 | #define CACHED_PARAMETER(index) \ | |||
| 1127 | case index: \ | |||
| 1128 | return &cache_.kParameter##index##Operator; | |||
| 1129 | CACHED_PARAMETER_LIST(CACHED_PARAMETER) | |||
| 1130 | #undef CACHED_PARAMETER | |||
| 1131 | default: | |||
| 1132 | break; | |||
| 1133 | } | |||
| 1134 | } | |||
| 1135 | // Uncached. | |||
| 1136 | return zone()->New<Operator1<ParameterInfo>>( // -- | |||
| 1137 | IrOpcode::kParameter, Operator::kPure, // opcode | |||
| 1138 | "Parameter", // name | |||
| 1139 | 1, 0, 0, 1, 0, 0, // counts | |||
| 1140 | ParameterInfo(index, debug_name)); // parameter info | |||
| 1141 | } | |||
| 1142 | ||||
| 1143 | const Operator* CommonOperatorBuilder::OsrValue(int index) { | |||
| 1144 | return zone()->New<Operator1<int>>( // -- | |||
| 1145 | IrOpcode::kOsrValue, Operator::kNoProperties, // opcode | |||
| 1146 | "OsrValue", // name | |||
| 1147 | 0, 0, 1, 1, 0, 0, // counts | |||
| 1148 | index); // parameter | |||
| 1149 | } | |||
| 1150 | ||||
| 1151 | const Operator* CommonOperatorBuilder::Int32Constant(int32_t value) { | |||
| 1152 | return zone()->New<Operator1<int32_t>>( // -- | |||
| 1153 | IrOpcode::kInt32Constant, Operator::kPure, // opcode | |||
| 1154 | "Int32Constant", // name | |||
| 1155 | 0, 0, 0, 1, 0, 0, // counts | |||
| 1156 | value); // parameter | |||
| 1157 | } | |||
| 1158 | ||||
| 1159 | ||||
| 1160 | const Operator* CommonOperatorBuilder::Int64Constant(int64_t value) { | |||
| 1161 | return zone()->New<Operator1<int64_t>>( // -- | |||
| 1162 | IrOpcode::kInt64Constant, Operator::kPure, // opcode | |||
| 1163 | "Int64Constant", // name | |||
| 1164 | 0, 0, 0, 1, 0, 0, // counts | |||
| 1165 | value); // parameter | |||
| 1166 | } | |||
| 1167 | ||||
| 1168 | const Operator* CommonOperatorBuilder::TaggedIndexConstant(int32_t value) { | |||
| 1169 | return zone()->New<Operator1<int32_t>>( // -- | |||
| 1170 | IrOpcode::kTaggedIndexConstant, Operator::kPure, // opcode | |||
| 1171 | "TaggedIndexConstant", // name | |||
| 1172 | 0, 0, 0, 1, 0, 0, // counts | |||
| 1173 | value); // parameter | |||
| 1174 | } | |||
| 1175 | ||||
| 1176 | const Operator* CommonOperatorBuilder::Float32Constant(volatile float value) { | |||
| 1177 | return zone()->New<Operator1<float>>( // -- | |||
| 1178 | IrOpcode::kFloat32Constant, Operator::kPure, // opcode | |||
| 1179 | "Float32Constant", // name | |||
| 1180 | 0, 0, 0, 1, 0, 0, // counts | |||
| 1181 | value); // parameter | |||
| 1182 | } | |||
| 1183 | ||||
| 1184 | ||||
| 1185 | const Operator* CommonOperatorBuilder::Float64Constant(volatile double value) { | |||
| 1186 | return zone()->New<Operator1<double>>( // -- | |||
| 1187 | IrOpcode::kFloat64Constant, Operator::kPure, // opcode | |||
| 1188 | "Float64Constant", // name | |||
| 1189 | 0, 0, 0, 1, 0, 0, // counts | |||
| 1190 | value); // parameter | |||
| 1191 | } | |||
| 1192 | ||||
| 1193 | ||||
| 1194 | const Operator* CommonOperatorBuilder::ExternalConstant( | |||
| 1195 | const ExternalReference& value) { | |||
| 1196 | return zone()->New<Operator1<ExternalReference>>( // -- | |||
| 1197 | IrOpcode::kExternalConstant, Operator::kPure, // opcode | |||
| 1198 | "ExternalConstant", // name | |||
| 1199 | 0, 0, 0, 1, 0, 0, // counts | |||
| 1200 | value); // parameter | |||
| 1201 | } | |||
| 1202 | ||||
| 1203 | ||||
| 1204 | const Operator* CommonOperatorBuilder::NumberConstant(volatile double value) { | |||
| 1205 | return zone()->New<Operator1<double>>( // -- | |||
| 1206 | IrOpcode::kNumberConstant, Operator::kPure, // opcode | |||
| 1207 | "NumberConstant", // name | |||
| 1208 | 0, 0, 0, 1, 0, 0, // counts | |||
| 1209 | value); // parameter | |||
| 1210 | } | |||
| 1211 | ||||
| 1212 | const Operator* CommonOperatorBuilder::PointerConstant(intptr_t value) { | |||
| 1213 | return zone()->New<Operator1<intptr_t>>( // -- | |||
| 1214 | IrOpcode::kPointerConstant, Operator::kPure, // opcode | |||
| 1215 | "PointerConstant", // name | |||
| 1216 | 0, 0, 0, 1, 0, 0, // counts | |||
| 1217 | value); // parameter | |||
| 1218 | } | |||
| 1219 | ||||
| 1220 | const Operator* CommonOperatorBuilder::HeapConstant( | |||
| 1221 | const Handle<HeapObject>& value) { | |||
| 1222 | return zone()->New<Operator1<Handle<HeapObject>>>( // -- | |||
| 1223 | IrOpcode::kHeapConstant, Operator::kPure, // opcode | |||
| 1224 | "HeapConstant", // name | |||
| 1225 | 0, 0, 0, 1, 0, 0, // counts | |||
| 1226 | value); // parameter | |||
| 1227 | } | |||
| 1228 | ||||
| 1229 | const Operator* CommonOperatorBuilder::CompressedHeapConstant( | |||
| 1230 | const Handle<HeapObject>& value) { | |||
| 1231 | return zone()->New<Operator1<Handle<HeapObject>>>( // -- | |||
| 1232 | IrOpcode::kCompressedHeapConstant, Operator::kPure, // opcode | |||
| 1233 | "CompressedHeapConstant", // name | |||
| 1234 | 0, 0, 0, 1, 0, 0, // counts | |||
| 1235 | value); // parameter | |||
| 1236 | } | |||
| 1237 | ||||
| 1238 | Handle<HeapObject> HeapConstantOf(const Operator* op) { | |||
| 1239 | DCHECK(IrOpcode::kHeapConstant == op->opcode() ||((void) 0) | |||
| 1240 | IrOpcode::kCompressedHeapConstant == op->opcode())((void) 0); | |||
| 1241 | return OpParameter<Handle<HeapObject>>(op); | |||
| 1242 | } | |||
| 1243 | ||||
| 1244 | const StringConstantBase* StringConstantBaseOf(const Operator* op) { | |||
| 1245 | DCHECK_EQ(IrOpcode::kDelayedStringConstant, op->opcode())((void) 0); | |||
| 1246 | return OpParameter<const StringConstantBase*>(op); | |||
| 1247 | } | |||
| 1248 | ||||
| 1249 | const char* StaticAssertSourceOf(const Operator* op) { | |||
| 1250 | DCHECK_EQ(IrOpcode::kStaticAssert, op->opcode())((void) 0); | |||
| 1251 | return OpParameter<const char*>(op); | |||
| 1252 | } | |||
| 1253 | ||||
| 1254 | const Operator* CommonOperatorBuilder::RelocatableInt32Constant( | |||
| 1255 | int32_t value, RelocInfo::Mode rmode) { | |||
| 1256 | return zone()->New<Operator1<RelocatablePtrConstantInfo>>( // -- | |||
| 1257 | IrOpcode::kRelocatableInt32Constant, Operator::kPure, // opcode | |||
| 1258 | "RelocatableInt32Constant", // name | |||
| 1259 | 0, 0, 0, 1, 0, 0, // counts | |||
| 1260 | RelocatablePtrConstantInfo(value, rmode)); // parameter | |||
| 1261 | } | |||
| 1262 | ||||
| 1263 | const Operator* CommonOperatorBuilder::RelocatableInt64Constant( | |||
| 1264 | int64_t value, RelocInfo::Mode rmode) { | |||
| 1265 | return zone()->New<Operator1<RelocatablePtrConstantInfo>>( // -- | |||
| 1266 | IrOpcode::kRelocatableInt64Constant, Operator::kPure, // opcode | |||
| 1267 | "RelocatableInt64Constant", // name | |||
| 1268 | 0, 0, 0, 1, 0, 0, // counts | |||
| 1269 | RelocatablePtrConstantInfo(value, rmode)); // parameter | |||
| 1270 | } | |||
| 1271 | ||||
| 1272 | const Operator* CommonOperatorBuilder::ObjectId(uint32_t object_id) { | |||
| 1273 | return zone()->New<Operator1<uint32_t>>( // -- | |||
| 1274 | IrOpcode::kObjectId, Operator::kPure, // opcode | |||
| 1275 | "ObjectId", // name | |||
| 1276 | 0, 0, 0, 1, 0, 0, // counts | |||
| 1277 | object_id); // parameter | |||
| 1278 | } | |||
| 1279 | ||||
| 1280 | const Operator* CommonOperatorBuilder::Select(MachineRepresentation rep, | |||
| 1281 | BranchHint hint) { | |||
| 1282 | return zone()->New<Operator1<SelectParameters>>( // -- | |||
| 1283 | IrOpcode::kSelect, Operator::kPure, // opcode | |||
| 1284 | "Select", // name | |||
| 1285 | 3, 0, 0, 1, 0, 0, // counts | |||
| 1286 | SelectParameters(rep, hint)); // parameter | |||
| 1287 | } | |||
| 1288 | ||||
| 1289 | ||||
| 1290 | const Operator* CommonOperatorBuilder::Phi(MachineRepresentation rep, | |||
| 1291 | int value_input_count) { | |||
| 1292 | DCHECK_LT(0, value_input_count)((void) 0); // Disallow empty phis. | |||
| 1293 | #define CACHED_PHI(kRep, kValueInputCount) \ | |||
| 1294 | if (MachineRepresentation::kRep == rep && \ | |||
| 1295 | kValueInputCount == value_input_count) { \ | |||
| 1296 | return &cache_.kPhi##kRep##kValueInputCount##Operator; \ | |||
| 1297 | } | |||
| 1298 | CACHED_PHI_LIST(CACHED_PHI) | |||
| 1299 | #undef CACHED_PHI | |||
| 1300 | // Uncached. | |||
| 1301 | return zone()->New<Operator1<MachineRepresentation>>( // -- | |||
| 1302 | IrOpcode::kPhi, Operator::kPure, // opcode | |||
| 1303 | "Phi", // name | |||
| 1304 | value_input_count, 0, 1, 1, 0, 0, // counts | |||
| 1305 | rep); // parameter | |||
| 1306 | } | |||
| 1307 | ||||
| 1308 | const Operator* CommonOperatorBuilder::TypeGuard(Type type) { | |||
| 1309 | return zone()->New<Operator1<Type>>( // -- | |||
| 1310 | IrOpcode::kTypeGuard, Operator::kPure, // opcode | |||
| 1311 | "TypeGuard", // name | |||
| 1312 | 1, 1, 1, 1, 1, 0, // counts | |||
| 1313 | type); // parameter | |||
| 1314 | } | |||
| 1315 | ||||
| 1316 | const Operator* CommonOperatorBuilder::FoldConstant() { | |||
| 1317 | return zone()->New<Operator>( // -- | |||
| 1318 | IrOpcode::kFoldConstant, Operator::kPure, // opcode | |||
| 1319 | "FoldConstant", // name | |||
| 1320 | 2, 0, 0, 1, 0, 0); // counts | |||
| 1321 | } | |||
| 1322 | ||||
| 1323 | const Operator* CommonOperatorBuilder::EffectPhi(int effect_input_count) { | |||
| 1324 | DCHECK_LT(0, effect_input_count)((void) 0); // Disallow empty effect phis. | |||
| 1325 | switch (effect_input_count) { | |||
| 1326 | #define CACHED_EFFECT_PHI(input_count) \ | |||
| 1327 | case input_count: \ | |||
| 1328 | return &cache_.kEffectPhi##input_count##Operator; | |||
| 1329 | CACHED_EFFECT_PHI_LIST(CACHED_EFFECT_PHI) | |||
| 1330 | #undef CACHED_EFFECT_PHI | |||
| 1331 | default: | |||
| 1332 | break; | |||
| 1333 | } | |||
| 1334 | // Uncached. | |||
| 1335 | return zone()->New<Operator>( // -- | |||
| 1336 | IrOpcode::kEffectPhi, Operator::kKontrol, // opcode | |||
| 1337 | "EffectPhi", // name | |||
| 1338 | 0, effect_input_count, 1, 0, 1, 0); // counts | |||
| 1339 | } | |||
| 1340 | ||||
| 1341 | const Operator* CommonOperatorBuilder::InductionVariablePhi(int input_count) { | |||
| 1342 | DCHECK_LE(4, input_count)((void) 0); // There must be always the entry, backedge, | |||
| 1343 | // increment and at least one bound. | |||
| 1344 | switch (input_count) { | |||
| 1345 | #define CACHED_INDUCTION_VARIABLE_PHI(input_count) \ | |||
| 1346 | case input_count: \ | |||
| 1347 | return &cache_.kInductionVariablePhi##input_count##Operator; | |||
| 1348 | CACHED_INDUCTION_VARIABLE_PHI_LIST(CACHED_INDUCTION_VARIABLE_PHI) | |||
| 1349 | #undef CACHED_INDUCTION_VARIABLE_PHI | |||
| 1350 | default: | |||
| 1351 | break; | |||
| 1352 | } | |||
| 1353 | // Uncached. | |||
| 1354 | return zone()->New<Operator>( // -- | |||
| 1355 | IrOpcode::kInductionVariablePhi, Operator::kPure, // opcode | |||
| 1356 | "InductionVariablePhi", // name | |||
| 1357 | input_count, 0, 1, 1, 0, 0); // counts | |||
| 1358 | } | |||
| 1359 | ||||
| 1360 | const Operator* CommonOperatorBuilder::BeginRegion( | |||
| 1361 | RegionObservability region_observability) { | |||
| 1362 | switch (region_observability) { | |||
| 1363 | case RegionObservability::kObservable: | |||
| 1364 | return &cache_.kBeginRegionObservableOperator; | |||
| 1365 | case RegionObservability::kNotObservable: | |||
| 1366 | return &cache_.kBeginRegionNotObservableOperator; | |||
| 1367 | } | |||
| 1368 | UNREACHABLE()V8_Fatal("unreachable code"); | |||
| 1369 | } | |||
| 1370 | ||||
| 1371 | const Operator* CommonOperatorBuilder::StateValues(int arguments, | |||
| 1372 | SparseInputMask bitmask) { | |||
| 1373 | if (bitmask.IsDense()) { | |||
| 1374 | switch (arguments) { | |||
| 1375 | #define CACHED_STATE_VALUES(arguments) \ | |||
| 1376 | case arguments: \ | |||
| 1377 | return &cache_.kStateValues##arguments##Operator; | |||
| 1378 | CACHED_STATE_VALUES_LIST(CACHED_STATE_VALUES) | |||
| 1379 | #undef CACHED_STATE_VALUES | |||
| 1380 | default: | |||
| 1381 | break; | |||
| 1382 | } | |||
| 1383 | } | |||
| 1384 | ||||
| 1385 | #if DEBUG | |||
| 1386 | DCHECK(bitmask.IsDense() || bitmask.CountReal() == arguments)((void) 0); | |||
| 1387 | #endif | |||
| 1388 | ||||
| 1389 | // Uncached. | |||
| 1390 | return zone()->New<Operator1<SparseInputMask>>( // -- | |||
| 1391 | IrOpcode::kStateValues, Operator::kPure, // opcode | |||
| 1392 | "StateValues", // name | |||
| 1393 | arguments, 0, 0, 1, 0, 0, // counts | |||
| 1394 | bitmask); // parameter | |||
| 1395 | } | |||
| 1396 | ||||
| 1397 | const Operator* CommonOperatorBuilder::TypedStateValues( | |||
| 1398 | const ZoneVector<MachineType>* types, SparseInputMask bitmask) { | |||
| 1399 | #if DEBUG | |||
| 1400 | DCHECK(bitmask.IsDense() ||((void) 0) | |||
| 1401 | bitmask.CountReal() == static_cast<int>(types->size()))((void) 0); | |||
| 1402 | #endif | |||
| 1403 | ||||
| 1404 | return zone()->New<Operator1<TypedStateValueInfo>>( // -- | |||
| 1405 | IrOpcode::kTypedStateValues, Operator::kPure, // opcode | |||
| 1406 | "TypedStateValues", // name | |||
| 1407 | static_cast<int>(types->size()), 0, 0, 1, 0, 0, // counts | |||
| 1408 | TypedStateValueInfo(types, bitmask)); // parameters | |||
| 1409 | } | |||
| 1410 | ||||
| 1411 | const Operator* CommonOperatorBuilder::ArgumentsElementsState( | |||
| 1412 | ArgumentsStateType type) { | |||
| 1413 | return zone()->New<Operator1<ArgumentsStateType>>( // -- | |||
| 1414 | IrOpcode::kArgumentsElementsState, Operator::kPure, // opcode | |||
| 1415 | "ArgumentsElementsState", // name | |||
| 1416 | 0, 0, 0, 1, 0, 0, // counts | |||
| 1417 | type); // parameter | |||
| 1418 | } | |||
| 1419 | ||||
| 1420 | const Operator* CommonOperatorBuilder::ArgumentsLengthState() { | |||
| 1421 | return zone()->New<Operator>( // -- | |||
| 1422 | IrOpcode::kArgumentsLengthState, Operator::kPure, // opcode | |||
| 1423 | "ArgumentsLengthState", // name | |||
| 1424 | 0, 0, 0, 1, 0, 0); // counts | |||
| 1425 | } | |||
| 1426 | ||||
| 1427 | ArgumentsStateType ArgumentsStateTypeOf(Operator const* op) { | |||
| 1428 | DCHECK(op->opcode() == IrOpcode::kArgumentsElementsState)((void) 0); | |||
| 1429 | return OpParameter<ArgumentsStateType>(op); | |||
| 1430 | } | |||
| 1431 | ||||
| 1432 | const Operator* CommonOperatorBuilder::ObjectState(uint32_t object_id, | |||
| 1433 | int pointer_slots) { | |||
| 1434 | return zone()->New<Operator1<ObjectStateInfo>>( // -- | |||
| 1435 | IrOpcode::kObjectState, Operator::kPure, // opcode | |||
| 1436 | "ObjectState", // name | |||
| 1437 | pointer_slots, 0, 0, 1, 0, 0, // counts | |||
| 1438 | ObjectStateInfo{object_id, pointer_slots}); // parameter | |||
| 1439 | } | |||
| 1440 | ||||
| 1441 | const Operator* CommonOperatorBuilder::TypedObjectState( | |||
| 1442 | uint32_t object_id, const ZoneVector<MachineType>* types) { | |||
| 1443 | return zone()->New<Operator1<TypedObjectStateInfo>>( // -- | |||
| 1444 | IrOpcode::kTypedObjectState, Operator::kPure, // opcode | |||
| 1445 | "TypedObjectState", // name | |||
| 1446 | static_cast<int>(types->size()), 0, 0, 1, 0, 0, // counts | |||
| 1447 | TypedObjectStateInfo(object_id, types)); // parameter | |||
| 1448 | } | |||
| 1449 | ||||
| 1450 | uint32_t ObjectIdOf(Operator const* op) { | |||
| 1451 | switch (op->opcode()) { | |||
| 1452 | case IrOpcode::kObjectState: | |||
| 1453 | return OpParameter<ObjectStateInfo>(op).object_id(); | |||
| 1454 | case IrOpcode::kTypedObjectState: | |||
| 1455 | return OpParameter<TypedObjectStateInfo>(op).object_id(); | |||
| 1456 | case IrOpcode::kObjectId: | |||
| 1457 | return OpParameter<uint32_t>(op); | |||
| 1458 | default: | |||
| 1459 | UNREACHABLE()V8_Fatal("unreachable code"); | |||
| 1460 | } | |||
| 1461 | } | |||
| 1462 | ||||
| 1463 | MachineRepresentation DeadValueRepresentationOf(Operator const* op) { | |||
| 1464 | DCHECK_EQ(IrOpcode::kDeadValue, op->opcode())((void) 0); | |||
| 1465 | return OpParameter<MachineRepresentation>(op); | |||
| 1466 | } | |||
| 1467 | ||||
| 1468 | const Operator* CommonOperatorBuilder::FrameState( | |||
| 1469 | BytecodeOffset bailout_id, OutputFrameStateCombine state_combine, | |||
| 1470 | const FrameStateFunctionInfo* function_info) { | |||
| 1471 | FrameStateInfo state_info(bailout_id, state_combine, function_info); | |||
| 1472 | return zone()->New<Operator1<FrameStateInfo>>( // -- | |||
| 1473 | IrOpcode::kFrameState, Operator::kPure, // opcode | |||
| 1474 | "FrameState", // name | |||
| 1475 | 5, 0, 0, 1, 0, 0, // counts | |||
| 1476 | state_info); // parameter | |||
| 1477 | } | |||
| 1478 | ||||
| 1479 | const Operator* CommonOperatorBuilder::Call( | |||
| 1480 | const CallDescriptor* call_descriptor) { | |||
| 1481 | class CallOperator final : public Operator1<const CallDescriptor*> { | |||
| 1482 | public: | |||
| 1483 | explicit CallOperator(const CallDescriptor* call_descriptor) | |||
| 1484 | : Operator1<const CallDescriptor*>( | |||
| 1485 | IrOpcode::kCall, call_descriptor->properties(), "Call", | |||
| 1486 | call_descriptor->InputCount() + | |||
| 1487 | call_descriptor->FrameStateCount(), | |||
| 1488 | Operator::ZeroIfPure(call_descriptor->properties()), | |||
| 1489 | Operator::ZeroIfEliminatable(call_descriptor->properties()), | |||
| 1490 | call_descriptor->ReturnCount(), | |||
| 1491 | Operator::ZeroIfPure(call_descriptor->properties()), | |||
| 1492 | Operator::ZeroIfNoThrow(call_descriptor->properties()), | |||
| 1493 | call_descriptor) {} | |||
| 1494 | ||||
| 1495 | void PrintParameter(std::ostream& os, | |||
| 1496 | PrintVerbosity verbose) const override { | |||
| 1497 | os << "[" << *parameter() << "]"; | |||
| 1498 | } | |||
| 1499 | }; | |||
| 1500 | return zone()->New<CallOperator>(call_descriptor); | |||
| 1501 | } | |||
| 1502 | ||||
| 1503 | const Operator* CommonOperatorBuilder::TailCall( | |||
| 1504 | const CallDescriptor* call_descriptor) { | |||
| 1505 | class TailCallOperator final : public Operator1<const CallDescriptor*> { | |||
| 1506 | public: | |||
| 1507 | explicit TailCallOperator(const CallDescriptor* call_descriptor) | |||
| 1508 | : Operator1<const CallDescriptor*>( | |||
| 1509 | IrOpcode::kTailCall, | |||
| 1510 | call_descriptor->properties() | Operator::kNoThrow, "TailCall", | |||
| 1511 | call_descriptor->InputCount() + | |||
| 1512 | call_descriptor->FrameStateCount(), | |||
| 1513 | 1, 1, 0, 0, 1, call_descriptor) {} | |||
| 1514 | ||||
| 1515 | void PrintParameter(std::ostream& os, | |||
| 1516 | PrintVerbosity verbose) const override { | |||
| 1517 | os << "[" << *parameter() << "]"; | |||
| 1518 | } | |||
| 1519 | }; | |||
| 1520 | return zone()->New<TailCallOperator>(call_descriptor); | |||
| 1521 | } | |||
| 1522 | ||||
| 1523 | const Operator* CommonOperatorBuilder::Projection(size_t index) { | |||
| 1524 | switch (index) { | |||
| 1525 | #define CACHED_PROJECTION(index) \ | |||
| 1526 | case index: \ | |||
| 1527 | return &cache_.kProjection##index##Operator; | |||
| 1528 | CACHED_PROJECTION_LIST(CACHED_PROJECTION) | |||
| 1529 | #undef CACHED_PROJECTION | |||
| 1530 | default: | |||
| 1531 | break; | |||
| 1532 | } | |||
| 1533 | // Uncached. | |||
| 1534 | return zone()->New<Operator1<size_t>>( // -- | |||
| 1535 | IrOpcode::kProjection, // opcode | |||
| 1536 | Operator::kPure, // flags | |||
| 1537 | "Projection", // name | |||
| 1538 | 1, 0, 1, 1, 0, 0, // counts | |||
| 1539 | index); // parameter | |||
| 1540 | } | |||
| 1541 | ||||
| 1542 | ||||
| 1543 | const Operator* CommonOperatorBuilder::ResizeMergeOrPhi(const Operator* op, | |||
| 1544 | int size) { | |||
| 1545 | if (op->opcode() == IrOpcode::kPhi) { | |||
| 1546 | return Phi(PhiRepresentationOf(op), size); | |||
| 1547 | } else if (op->opcode() == IrOpcode::kEffectPhi) { | |||
| 1548 | return EffectPhi(size); | |||
| 1549 | } else if (op->opcode() == IrOpcode::kMerge) { | |||
| 1550 | return Merge(size); | |||
| 1551 | } else if (op->opcode() == IrOpcode::kLoop) { | |||
| 1552 | return Loop(size); | |||
| 1553 | } else { | |||
| 1554 | UNREACHABLE()V8_Fatal("unreachable code"); | |||
| 1555 | } | |||
| 1556 | } | |||
| 1557 | ||||
| 1558 | const FrameStateFunctionInfo* | |||
| 1559 | CommonOperatorBuilder::CreateFrameStateFunctionInfo( | |||
| 1560 | FrameStateType type, int parameter_count, int local_count, | |||
| 1561 | Handle<SharedFunctionInfo> shared_info) { | |||
| 1562 | return zone()->New<FrameStateFunctionInfo>(type, parameter_count, local_count, | |||
| 1563 | shared_info); | |||
| 1564 | } | |||
| 1565 | ||||
| 1566 | #if V8_ENABLE_WEBASSEMBLY1 | |||
| 1567 | const FrameStateFunctionInfo* | |||
| 1568 | CommonOperatorBuilder::CreateJSToWasmFrameStateFunctionInfo( | |||
| 1569 | FrameStateType type, int parameter_count, int local_count, | |||
| 1570 | Handle<SharedFunctionInfo> shared_info, | |||
| 1571 | const wasm::FunctionSig* signature) { | |||
| 1572 | DCHECK_EQ(type, FrameStateType::kJSToWasmBuiltinContinuation)((void) 0); | |||
| 1573 | DCHECK_NOT_NULL(signature)((void) 0); | |||
| 1574 | return zone()->New<JSToWasmFrameStateFunctionInfo>( | |||
| 1575 | type, parameter_count, local_count, shared_info, signature); | |||
| 1576 | } | |||
| 1577 | #endif // V8_ENABLE_WEBASSEMBLY | |||
| 1578 | ||||
| 1579 | const Operator* CommonOperatorBuilder::DeadValue(MachineRepresentation rep) { | |||
| 1580 | return zone()->New<Operator1<MachineRepresentation>>( // -- | |||
| 1581 | IrOpcode::kDeadValue, Operator::kPure, // opcode | |||
| 1582 | "DeadValue", // name | |||
| 1583 | 1, 0, 0, 1, 0, 0, // counts | |||
| 1584 | rep); // parameter | |||
| 1585 | } | |||
| 1586 | ||||
| 1587 | const FrameStateInfo& FrameStateInfoOf(const Operator* op) { | |||
| 1588 | DCHECK_EQ(IrOpcode::kFrameState, op->opcode())((void) 0); | |||
| 1589 | return OpParameter<FrameStateInfo>(op); | |||
| 1590 | } | |||
| 1591 | ||||
| 1592 | #undef COMMON_CACHED_OP_LIST | |||
| 1593 | #undef CACHED_BRANCH_LIST | |||
| 1594 | #undef CACHED_RETURN_LIST | |||
| 1595 | #undef CACHED_END_LIST | |||
| 1596 | #undef CACHED_EFFECT_PHI_LIST | |||
| 1597 | #undef CACHED_INDUCTION_VARIABLE_PHI_LIST | |||
| 1598 | #undef CACHED_LOOP_LIST | |||
| 1599 | #undef CACHED_MERGE_LIST | |||
| 1600 | #undef CACHED_DEOPTIMIZE_LIST | |||
| 1601 | #undef CACHED_DEOPTIMIZE_IF_LIST | |||
| 1602 | #undef CACHED_DEOPTIMIZE_UNLESS_LIST | |||
| 1603 | #undef CACHED_TRAP_IF_LIST | |||
| 1604 | #undef CACHED_TRAP_UNLESS_LIST | |||
| 1605 | #undef CACHED_PARAMETER_LIST | |||
| 1606 | #undef CACHED_PHI_LIST | |||
| 1607 | #undef CACHED_PROJECTION_LIST | |||
| 1608 | #undef CACHED_STATE_VALUES_LIST | |||
| 1609 | ||||
| 1610 | } // namespace compiler | |||
| 1611 | } // namespace internal | |||
| 1612 | } // namespace v8 |
| 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 | #ifndef V8_BASE_BITS_H_ |
| 6 | #define V8_BASE_BITS_H_ |
| 7 | |
| 8 | #include <stdint.h> |
| 9 | #include <type_traits> |
| 10 | |
| 11 | #include "src/base/base-export.h" |
| 12 | #include "src/base/macros.h" |
| 13 | #if V8_CC_MSVC |
| 14 | #include <intrin.h> |
| 15 | #endif |
| 16 | #if V8_OS_WIN32 |
| 17 | #include "src/base/win32-headers.h" |
| 18 | #endif |
| 19 | |
| 20 | namespace v8 { |
| 21 | namespace base { |
| 22 | namespace bits { |
| 23 | |
| 24 | // CountPopulation(value) returns the number of bits set in |value|. |
| 25 | template <typename T> |
| 26 | constexpr inline |
| 27 | typename std::enable_if<std::is_unsigned<T>::value && sizeof(T) <= 8, |
| 28 | unsigned>::type |
| 29 | CountPopulation(T value) { |
| 30 | STATIC_ASSERT(sizeof(T) <= 8)static_assert(sizeof(T) <= 8, "sizeof(T) <= 8"); |
| 31 | #if V8_HAS_BUILTIN_POPCOUNT(1) |
| 32 | return sizeof(T) == 8 ? __builtin_popcountll(static_cast<uint64_t>(value)) |
| 33 | : __builtin_popcount(static_cast<uint32_t>(value)); |
| 34 | #else |
| 35 | // Fall back to divide-and-conquer popcount (see "Hacker's Delight" by Henry |
| 36 | // S. Warren, Jr.), chapter 5-1. |
| 37 | constexpr uint64_t mask[] = {0x5555555555555555, 0x3333333333333333, |
| 38 | 0x0f0f0f0f0f0f0f0f}; |
| 39 | // Start with 64 buckets of 1 bits, holding values from [0,1]. |
| 40 | value = ((value >> 1) & mask[0]) + (value & mask[0]); |
| 41 | // Having 32 buckets of 2 bits, holding values from [0,2] now. |
| 42 | value = ((value >> 2) & mask[1]) + (value & mask[1]); |
| 43 | // Having 16 buckets of 4 bits, holding values from [0,4] now. |
| 44 | value = ((value >> 4) & mask[2]) + (value & mask[2]); |
| 45 | // Having 8 buckets of 8 bits, holding values from [0,8] now. |
| 46 | // From this point on, the buckets are bigger than the number of bits |
| 47 | // required to hold the values, and the buckets are bigger the maximum |
| 48 | // result, so there's no need to mask value anymore, since there's no |
| 49 | // more risk of overflow between buckets. |
| 50 | if (sizeof(T) > 1) value = (value >> (sizeof(T) > 1 ? 8 : 0)) + value; |
| 51 | // Having 4 buckets of 16 bits, holding values from [0,16] now. |
| 52 | if (sizeof(T) > 2) value = (value >> (sizeof(T) > 2 ? 16 : 0)) + value; |
| 53 | // Having 2 buckets of 32 bits, holding values from [0,32] now. |
| 54 | if (sizeof(T) > 4) value = (value >> (sizeof(T) > 4 ? 32 : 0)) + value; |
| 55 | // Having 1 buckets of 64 bits, holding values from [0,64] now. |
| 56 | return static_cast<unsigned>(value & 0xff); |
| 57 | #endif |
| 58 | } |
| 59 | |
| 60 | // ReverseBits(value) returns |value| in reverse bit order. |
| 61 | template <typename T> |
| 62 | T ReverseBits(T value) { |
| 63 | STATIC_ASSERT((sizeof(value) == 1) || (sizeof(value) == 2) ||static_assert((sizeof(value) == 1) || (sizeof(value) == 2) || (sizeof(value) == 4) || (sizeof(value) == 8), "(sizeof(value) == 1) || (sizeof(value) == 2) || (sizeof(value) == 4) || (sizeof(value) == 8)" ) |
| 64 | (sizeof(value) == 4) || (sizeof(value) == 8))static_assert((sizeof(value) == 1) || (sizeof(value) == 2) || (sizeof(value) == 4) || (sizeof(value) == 8), "(sizeof(value) == 1) || (sizeof(value) == 2) || (sizeof(value) == 4) || (sizeof(value) == 8)" ); |
| 65 | T result = 0; |
| 66 | for (unsigned i = 0; i < (sizeof(value) * 8); i++) { |
| 67 | result = (result << 1) | (value & 1); |
| 68 | value >>= 1; |
| 69 | } |
| 70 | return result; |
| 71 | } |
| 72 | |
| 73 | // CountLeadingZeros(value) returns the number of zero bits following the most |
| 74 | // significant 1 bit in |value| if |value| is non-zero, otherwise it returns |
| 75 | // {sizeof(T) * 8}. |
| 76 | template <typename T, unsigned bits = sizeof(T) * 8> |
| 77 | inline constexpr |
| 78 | typename std::enable_if<std::is_unsigned<T>::value && sizeof(T) <= 8, |
| 79 | unsigned>::type |
| 80 | CountLeadingZeros(T value) { |
| 81 | static_assert(bits > 0, "invalid instantiation"); |
| 82 | #if V8_HAS_BUILTIN_CLZ(1) |
| 83 | return value == 0 |
| 84 | ? bits |
| 85 | : bits == 64 |
| 86 | ? __builtin_clzll(static_cast<uint64_t>(value)) |
| 87 | : __builtin_clz(static_cast<uint32_t>(value)) - (32 - bits); |
| 88 | #else |
| 89 | // Binary search algorithm taken from "Hacker's Delight" (by Henry S. Warren, |
| 90 | // Jr.), figures 5-11 and 5-12. |
| 91 | if (bits == 1) return static_cast<unsigned>(value) ^ 1; |
| 92 | T upper_half = value >> (bits / 2); |
| 93 | T next_value = upper_half != 0 ? upper_half : value; |
| 94 | unsigned add = upper_half != 0 ? 0 : bits / 2; |
| 95 | constexpr unsigned next_bits = bits == 1 ? 1 : bits / 2; |
| 96 | return CountLeadingZeros<T, next_bits>(next_value) + add; |
| 97 | #endif |
| 98 | } |
| 99 | |
| 100 | inline constexpr unsigned CountLeadingZeros32(uint32_t value) { |
| 101 | return CountLeadingZeros(value); |
| 102 | } |
| 103 | inline constexpr unsigned CountLeadingZeros64(uint64_t value) { |
| 104 | return CountLeadingZeros(value); |
| 105 | } |
| 106 | |
| 107 | // CountTrailingZeros(value) returns the number of zero bits preceding the |
| 108 | // least significant 1 bit in |value| if |value| is non-zero, otherwise it |
| 109 | // returns {sizeof(T) * 8}. |
| 110 | // See CountTrailingZerosNonZero for an optimized version for the case that |
| 111 | // |value| is guaranteed to be non-zero. |
| 112 | template <typename T, unsigned bits = sizeof(T) * 8> |
| 113 | inline constexpr |
| 114 | typename std::enable_if<std::is_integral<T>::value && sizeof(T) <= 8, |
| 115 | unsigned>::type |
| 116 | CountTrailingZeros(T value) { |
| 117 | #if V8_HAS_BUILTIN_CTZ(1) |
| 118 | return value == 0 ? bits |
| 119 | : bits == 64 ? __builtin_ctzll(static_cast<uint64_t>(value)) |
| 120 | : __builtin_ctz(static_cast<uint32_t>(value)); |
| 121 | #else |
| 122 | // Fall back to popcount (see "Hacker's Delight" by Henry S. Warren, Jr.), |
| 123 | // chapter 5-4. On x64, since is faster than counting in a loop and faster |
| 124 | // than doing binary search. |
| 125 | using U = typename std::make_unsigned<T>::type; |
| 126 | U u = value; |
| 127 | return CountPopulation(static_cast<U>(~u & (u - 1u))); |
| 128 | #endif |
| 129 | } |
| 130 | |
| 131 | inline constexpr unsigned CountTrailingZeros32(uint32_t value) { |
| 132 | return CountTrailingZeros(value); |
| 133 | } |
| 134 | inline constexpr unsigned CountTrailingZeros64(uint64_t value) { |
| 135 | return CountTrailingZeros(value); |
| 136 | } |
| 137 | |
| 138 | // CountTrailingZerosNonZero(value) returns the number of zero bits preceding |
| 139 | // the least significant 1 bit in |value| if |value| is non-zero, otherwise the |
| 140 | // behavior is undefined. |
| 141 | // See CountTrailingZeros for an alternative version that allows |value| == 0. |
| 142 | template <typename T, unsigned bits = sizeof(T) * 8> |
| 143 | inline constexpr |
| 144 | typename std::enable_if<std::is_integral<T>::value && sizeof(T) <= 8, |
| 145 | unsigned>::type |
| 146 | CountTrailingZerosNonZero(T value) { |
| 147 | DCHECK_NE(0, value)((void) 0); |
| 148 | #if V8_HAS_BUILTIN_CTZ(1) |
| 149 | return bits == 64 ? __builtin_ctzll(static_cast<uint64_t>(value)) |
| 150 | : __builtin_ctz(static_cast<uint32_t>(value)); |
| 151 | #else |
| 152 | return CountTrailingZeros<T, bits>(value); |
| 153 | #endif |
| 154 | } |
| 155 | |
| 156 | // Returns true iff |value| is a power of 2. |
| 157 | template <typename T, |
| 158 | typename = typename std::enable_if<std::is_integral<T>::value || |
| 159 | std::is_enum<T>::value>::type> |
| 160 | constexpr inline bool IsPowerOfTwo(T value) { |
| 161 | return value > 0 && (value & (value - 1)) == 0; |
| 162 | } |
| 163 | |
| 164 | // Identical to {CountTrailingZeros}, but only works for powers of 2. |
| 165 | template <typename T, |
| 166 | typename = typename std::enable_if<std::is_integral<T>::value>::type> |
| 167 | inline constexpr int WhichPowerOfTwo(T value) { |
| 168 | DCHECK(IsPowerOfTwo(value))((void) 0); |
| 169 | #if V8_HAS_BUILTIN_CTZ(1) |
| 170 | STATIC_ASSERT(sizeof(T) <= 8)static_assert(sizeof(T) <= 8, "sizeof(T) <= 8"); |
| 171 | return sizeof(T) == 8 ? __builtin_ctzll(static_cast<uint64_t>(value)) |
| 172 | : __builtin_ctz(static_cast<uint32_t>(value)); |
| 173 | #else |
| 174 | // Fall back to popcount (see "Hacker's Delight" by Henry S. Warren, Jr.), |
| 175 | // chapter 5-4. On x64, since is faster than counting in a loop and faster |
| 176 | // than doing binary search. |
| 177 | using U = typename std::make_unsigned<T>::type; |
| 178 | U u = value; |
| 179 | return CountPopulation(static_cast<U>(u - 1)); |
| 180 | #endif |
| 181 | } |
| 182 | |
| 183 | // RoundUpToPowerOfTwo32(value) returns the smallest power of two which is |
| 184 | // greater than or equal to |value|. If you pass in a |value| that is already a |
| 185 | // power of two, it is returned as is. |value| must be less than or equal to |
| 186 | // 0x80000000u. Uses computation based on leading zeros if we have compiler |
| 187 | // support for that. Falls back to the implementation from "Hacker's Delight" by |
| 188 | // Henry S. Warren, Jr., figure 3-3, page 48, where the function is called clp2. |
| 189 | V8_BASE_EXPORT uint32_t RoundUpToPowerOfTwo32(uint32_t value); |
| 190 | // Same for 64 bit integers. |value| must be <= 2^63 |
| 191 | V8_BASE_EXPORT uint64_t RoundUpToPowerOfTwo64(uint64_t value); |
| 192 | // Same for size_t integers. |
| 193 | inline size_t RoundUpToPowerOfTwo(size_t value) { |
| 194 | if (sizeof(size_t) == sizeof(uint64_t)) { |
| 195 | return RoundUpToPowerOfTwo64(value); |
| 196 | } else { |
| 197 | // Without windows.h included this line triggers a truncation warning on |
| 198 | // 64-bit builds. Presumably windows.h disables the relevant warning. |
| 199 | return RoundUpToPowerOfTwo32(static_cast<uint32_t>(value)); |
| 200 | } |
| 201 | } |
| 202 | |
| 203 | // RoundDownToPowerOfTwo32(value) returns the greatest power of two which is |
| 204 | // less than or equal to |value|. If you pass in a |value| that is already a |
| 205 | // power of two, it is returned as is. |
| 206 | inline uint32_t RoundDownToPowerOfTwo32(uint32_t value) { |
| 207 | if (value > 0x80000000u) return 0x80000000u; |
| 208 | uint32_t result = RoundUpToPowerOfTwo32(value); |
| 209 | if (result > value) result >>= 1; |
| 210 | return result; |
| 211 | } |
| 212 | |
| 213 | |
| 214 | // Precondition: 0 <= shift < 32 |
| 215 | inline constexpr uint32_t RotateRight32(uint32_t value, uint32_t shift) { |
| 216 | return (value >> shift) | (value << ((32 - shift) & 31)); |
| 217 | } |
| 218 | |
| 219 | // Precondition: 0 <= shift < 32 |
| 220 | inline constexpr uint32_t RotateLeft32(uint32_t value, uint32_t shift) { |
| 221 | return (value << shift) | (value >> ((32 - shift) & 31)); |
| 222 | } |
| 223 | |
| 224 | // Precondition: 0 <= shift < 64 |
| 225 | inline constexpr uint64_t RotateRight64(uint64_t value, uint64_t shift) { |
| 226 | return (value >> shift) | (value << ((64 - shift) & 63)); |
| 227 | } |
| 228 | |
| 229 | // Precondition: 0 <= shift < 64 |
| 230 | inline constexpr uint64_t RotateLeft64(uint64_t value, uint64_t shift) { |
| 231 | return (value << shift) | (value >> ((64 - shift) & 63)); |
| 232 | } |
| 233 | |
| 234 | // SignedAddOverflow32(lhs,rhs,val) performs a signed summation of |lhs| and |
| 235 | // |rhs| and stores the result into the variable pointed to by |val| and |
| 236 | // returns true if the signed summation resulted in an overflow. |
| 237 | inline bool SignedAddOverflow32(int32_t lhs, int32_t rhs, int32_t* val) { |
| 238 | #if V8_HAS_BUILTIN_SADD_OVERFLOW(1) |
| 239 | return __builtin_sadd_overflow(lhs, rhs, val); |
| 240 | #else |
| 241 | uint32_t res = static_cast<uint32_t>(lhs) + static_cast<uint32_t>(rhs); |
| 242 | *val = bit_cast<int32_t>(res); |
| 243 | return ((res ^ lhs) & (res ^ rhs) & (1U << 31)) != 0; |
| 244 | #endif |
| 245 | } |
| 246 | |
| 247 | |
| 248 | // SignedSubOverflow32(lhs,rhs,val) performs a signed subtraction of |lhs| and |
| 249 | // |rhs| and stores the result into the variable pointed to by |val| and |
| 250 | // returns true if the signed subtraction resulted in an overflow. |
| 251 | inline bool SignedSubOverflow32(int32_t lhs, int32_t rhs, int32_t* val) { |
| 252 | #if V8_HAS_BUILTIN_SSUB_OVERFLOW(1) |
| 253 | return __builtin_ssub_overflow(lhs, rhs, val); |
| 254 | #else |
| 255 | uint32_t res = static_cast<uint32_t>(lhs) - static_cast<uint32_t>(rhs); |
| 256 | *val = bit_cast<int32_t>(res); |
| 257 | return ((res ^ lhs) & (res ^ ~rhs) & (1U << 31)) != 0; |
| 258 | #endif |
| 259 | } |
| 260 | |
| 261 | // SignedMulOverflow32(lhs,rhs,val) performs a signed multiplication of |lhs| |
| 262 | // and |rhs| and stores the result into the variable pointed to by |val| and |
| 263 | // returns true if the signed multiplication resulted in an overflow. |
| 264 | V8_BASE_EXPORT bool SignedMulOverflow32(int32_t lhs, int32_t rhs, int32_t* val); |
| 265 | |
| 266 | // SignedAddOverflow64(lhs,rhs,val) performs a signed summation of |lhs| and |
| 267 | // |rhs| and stores the result into the variable pointed to by |val| and |
| 268 | // returns true if the signed summation resulted in an overflow. |
| 269 | inline bool SignedAddOverflow64(int64_t lhs, int64_t rhs, int64_t* val) { |
| 270 | uint64_t res = static_cast<uint64_t>(lhs) + static_cast<uint64_t>(rhs); |
| 271 | *val = bit_cast<int64_t>(res); |
| 272 | return ((res ^ lhs) & (res ^ rhs) & (1ULL << 63)) != 0; |
| 273 | } |
| 274 | |
| 275 | |
| 276 | // SignedSubOverflow64(lhs,rhs,val) performs a signed subtraction of |lhs| and |
| 277 | // |rhs| and stores the result into the variable pointed to by |val| and |
| 278 | // returns true if the signed subtraction resulted in an overflow. |
| 279 | inline bool SignedSubOverflow64(int64_t lhs, int64_t rhs, int64_t* val) { |
| 280 | uint64_t res = static_cast<uint64_t>(lhs) - static_cast<uint64_t>(rhs); |
| 281 | *val = bit_cast<int64_t>(res); |
| 282 | return ((res ^ lhs) & (res ^ ~rhs) & (1ULL << 63)) != 0; |
| 283 | } |
| 284 | |
| 285 | // SignedMulHigh32(lhs, rhs) multiplies two signed 32-bit values |lhs| and |
| 286 | // |rhs|, extracts the most significant 32 bits of the result, and returns |
| 287 | // those. |
| 288 | V8_BASE_EXPORT int32_t SignedMulHigh32(int32_t lhs, int32_t rhs); |
| 289 | |
| 290 | // SignedMulHighAndAdd32(lhs, rhs, acc) multiplies two signed 32-bit values |
| 291 | // |lhs| and |rhs|, extracts the most significant 32 bits of the result, and |
| 292 | // adds the accumulate value |acc|. |
| 293 | V8_BASE_EXPORT int32_t SignedMulHighAndAdd32(int32_t lhs, int32_t rhs, |
| 294 | int32_t acc); |
| 295 | |
| 296 | // SignedDiv32(lhs, rhs) divides |lhs| by |rhs| and returns the quotient |
| 297 | // truncated to int32. If |rhs| is zero, then zero is returned. If |lhs| |
| 298 | // is minint and |rhs| is -1, it returns minint. |
| 299 | V8_BASE_EXPORT int32_t SignedDiv32(int32_t lhs, int32_t rhs); |
| 300 | |
| 301 | // SignedMod32(lhs, rhs) divides |lhs| by |rhs| and returns the remainder |
| 302 | // truncated to int32. If either |rhs| is zero or |lhs| is minint and |rhs| |
| 303 | // is -1, it returns zero. |
| 304 | V8_BASE_EXPORT int32_t SignedMod32(int32_t lhs, int32_t rhs); |
| 305 | |
| 306 | // UnsignedAddOverflow32(lhs,rhs,val) performs an unsigned summation of |lhs| |
| 307 | // and |rhs| and stores the result into the variable pointed to by |val| and |
| 308 | // returns true if the unsigned summation resulted in an overflow. |
| 309 | inline bool UnsignedAddOverflow32(uint32_t lhs, uint32_t rhs, uint32_t* val) { |
| 310 | #if V8_HAS_BUILTIN_SADD_OVERFLOW(1) |
| 311 | return __builtin_uadd_overflow(lhs, rhs, val); |
| 312 | #else |
| 313 | *val = lhs + rhs; |
| 314 | return *val < (lhs | rhs); |
| 315 | #endif |
| 316 | } |
| 317 | |
| 318 | |
| 319 | // UnsignedDiv32(lhs, rhs) divides |lhs| by |rhs| and returns the quotient |
| 320 | // truncated to uint32. If |rhs| is zero, then zero is returned. |
| 321 | inline uint32_t UnsignedDiv32(uint32_t lhs, uint32_t rhs) { |
| 322 | return rhs ? lhs / rhs : 0u; |
| 323 | } |
| 324 | |
| 325 | |
| 326 | // UnsignedMod32(lhs, rhs) divides |lhs| by |rhs| and returns the remainder |
| 327 | // truncated to uint32. If |rhs| is zero, then zero is returned. |
| 328 | inline uint32_t UnsignedMod32(uint32_t lhs, uint32_t rhs) { |
| 329 | return rhs ? lhs % rhs : 0u; |
| 330 | } |
| 331 | |
| 332 | // Wraparound integer arithmetic without undefined behavior. |
| 333 | |
| 334 | inline int32_t WraparoundAdd32(int32_t lhs, int32_t rhs) { |
| 335 | return static_cast<int32_t>(static_cast<uint32_t>(lhs) + |
| 336 | static_cast<uint32_t>(rhs)); |
| 337 | } |
| 338 | |
| 339 | inline int32_t WraparoundNeg32(int32_t x) { |
| 340 | return static_cast<int32_t>(-static_cast<uint32_t>(x)); |
| 341 | } |
| 342 | |
| 343 | // SignedSaturatedAdd64(lhs, rhs) adds |lhs| and |rhs|, |
| 344 | // checks and returns the result. |
| 345 | V8_BASE_EXPORT int64_t SignedSaturatedAdd64(int64_t lhs, int64_t rhs); |
| 346 | |
| 347 | // SignedSaturatedSub64(lhs, rhs) subtracts |lhs| by |rhs|, |
| 348 | // checks and returns the result. |
| 349 | V8_BASE_EXPORT int64_t SignedSaturatedSub64(int64_t lhs, int64_t rhs); |
| 350 | |
| 351 | } // namespace bits |
| 352 | } // namespace base |
| 353 | } // namespace v8 |
| 354 | |
| 355 | #endif // V8_BASE_BITS_H_ |