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/simplified-operator-reducer.h" 6 7#include "src/compiler/common-operator.h" 8#include "src/compiler/js-graph.h" 9#include "src/compiler/js-heap-broker.h" 10#include "src/compiler/machine-operator.h" 11#include "src/compiler/node-matchers.h" 12#include "src/compiler/opcodes.h" 13#include "src/compiler/operator-properties.h" 14#include "src/compiler/simplified-operator.h" 15#include "src/compiler/type-cache.h" 16#include "src/numbers/conversions-inl.h" 17 18namespace v8 { 19namespace internal { 20namespace compiler { 21 22namespace { 23 24Decision DecideObjectIsSmi(Node* const input) { 25 NumberMatcher m(input); 26 if (m.HasResolvedValue()) { 27 return IsSmiDouble(m.ResolvedValue()) ? Decision::kTrue : Decision::kFalse; 28 } 29 if (m.IsAllocate()) return Decision::kFalse; 30 if (m.IsChangeBitToTagged()) return Decision::kFalse; 31 if (m.IsChangeInt31ToTaggedSigned()) return Decision::kTrue; 32 if (m.IsHeapConstant()) return Decision::kFalse; 33 return Decision::kUnknown; 34} 35 36} // namespace 37 38SimplifiedOperatorReducer::SimplifiedOperatorReducer( 39 Editor* editor, JSGraph* jsgraph, JSHeapBroker* broker, 40 BranchSemantics branch_semantics) 41 : AdvancedReducer(editor), 42 jsgraph_(jsgraph), 43 broker_(broker), 44 branch_semantics_(branch_semantics) {} 45 46SimplifiedOperatorReducer::~SimplifiedOperatorReducer() = default; 47 48 49Reduction SimplifiedOperatorReducer::Reduce(Node* node) { 50 switch (node->opcode()) { 51 case IrOpcode::kBooleanNot: { 52 HeapObjectMatcher m(node->InputAt(0)); 53 if (m.Is(factory()->true_value())) return ReplaceBoolean(false); 54 if (m.Is(factory()->false_value())) return ReplaceBoolean(true); 55 if (m.IsBooleanNot()) return Replace(m.InputAt(0)); 56 break; 57 } 58 case IrOpcode::kChangeBitToTagged: { 59 Int32Matcher m(node->InputAt(0)); 60 if (m.Is(0)) return Replace(jsgraph()->FalseConstant()); 61 if (m.Is(1)) return Replace(jsgraph()->TrueConstant()); 62 if (m.IsChangeTaggedToBit()) return Replace(m.InputAt(0)); 63 break; 64 } 65 case IrOpcode::kChangeTaggedToBit: { 66 HeapObjectMatcher m(node->InputAt(0)); 67 if (m.HasResolvedValue()) { 68 base::Optional<bool> maybe_result = 69 m.Ref(broker()).TryGetBooleanValue(); 70 if (maybe_result.has_value()) return ReplaceInt32(*maybe_result); 71 } 72 if (m.IsChangeBitToTagged()) return Replace(m.InputAt(0)); 73 break; 74 } 75 case IrOpcode::kChangeFloat64ToTagged: { 76 Float64Matcher m(node->InputAt(0)); 77 if (m.HasResolvedValue()) return ReplaceNumber(m.ResolvedValue()); 78 if (m.IsChangeTaggedToFloat64()) return Replace(m.node()->InputAt(0)); 79 break; 80 } 81 case IrOpcode::kChangeInt31ToTaggedSigned: 82 case IrOpcode::kChangeInt32ToTagged: { 83 Int32Matcher m(node->InputAt(0)); 84 if (m.HasResolvedValue()) return ReplaceNumber(m.ResolvedValue()); 85 if (m.IsChangeTaggedSignedToInt32()) { 86 return Replace(m.InputAt(0)); 87 } 88 break; 89 } 90 case IrOpcode::kChangeTaggedToFloat64: 91 case IrOpcode::kTruncateTaggedToFloat64: { 92 NumberMatcher m(node->InputAt(0)); 93 if (m.HasResolvedValue()) return ReplaceFloat64(m.ResolvedValue()); 94 if (m.IsChangeFloat64ToTagged() || m.IsChangeFloat64ToTaggedPointer()) { 95 return Replace(m.node()->InputAt(0)); 96 } 97 if (m.IsChangeInt31ToTaggedSigned() || m.IsChangeInt32ToTagged()) { 98 return Change(node, machine()->ChangeInt32ToFloat64(), m.InputAt(0)); 99 } 100 if (m.IsChangeUint32ToTagged()) { 101 return Change(node, machine()->ChangeUint32ToFloat64(), m.InputAt(0)); 102 } 103 break; 104 } 105 case IrOpcode::kChangeTaggedSignedToInt32: 106 case IrOpcode::kChangeTaggedToInt32: { 107 NumberMatcher m(node->InputAt(0)); 108 if (m.HasResolvedValue()) 109 return ReplaceInt32(DoubleToInt32(m.ResolvedValue())); 110 if (m.IsChangeFloat64ToTagged() || m.IsChangeFloat64ToTaggedPointer()) { 111 return Change(node, machine()->ChangeFloat64ToInt32(), m.InputAt(0)); 112 } 113 if (m.IsChangeInt31ToTaggedSigned() || m.IsChangeInt32ToTagged()) { 114 return Replace(m.InputAt(0)); 115 } 116 break; 117 } 118 case IrOpcode::kChangeTaggedToUint32: { 119 NumberMatcher m(node->InputAt(0)); 120 if (m.HasResolvedValue()) 121 return ReplaceUint32(DoubleToUint32(m.ResolvedValue())); 122 if (m.IsChangeFloat64ToTagged() || m.IsChangeFloat64ToTaggedPointer()) { 123 return Change(node, machine()->ChangeFloat64ToUint32(), m.InputAt(0)); 124 } 125 if (m.IsChangeUint32ToTagged()) return Replace(m.InputAt(0)); 126 break; 127 } 128 case IrOpcode::kChangeUint32ToTagged: { 129 Uint32Matcher m(node->InputAt(0)); 130 if (m.HasResolvedValue()) 131 return ReplaceNumber(FastUI2D(m.ResolvedValue())); 132 break; 133 } 134 case IrOpcode::kTruncateTaggedToWord32: { 135 NumberMatcher m(node->InputAt(0)); 136 if (m.HasResolvedValue()) 137 return ReplaceInt32(DoubleToInt32(m.ResolvedValue())); 138 if (m.IsChangeInt31ToTaggedSigned() || m.IsChangeInt32ToTagged() || 139 m.IsChangeUint32ToTagged()) { 140 return Replace(m.InputAt(0)); 141 } 142 if (m.IsChangeFloat64ToTagged() || m.IsChangeFloat64ToTaggedPointer()) { 143 return Change(node, machine()->TruncateFloat64ToWord32(), m.InputAt(0)); 144 } 145 break; 146 } 147 case IrOpcode::kCheckedFloat64ToInt32: { 148 Float64Matcher m(node->InputAt(0)); 149 if (m.HasResolvedValue() && IsInt32Double(m.ResolvedValue())) { 150 Node* value = 151 jsgraph()->Int32Constant(static_cast<int32_t>(m.ResolvedValue())); 152 ReplaceWithValue(node, value); 153 return Replace(value); 154 } 155 break; 156 } 157 case IrOpcode::kCheckedTaggedToArrayIndex: 158 case IrOpcode::kCheckedTaggedToInt32: 159 case IrOpcode::kCheckedTaggedSignedToInt32: { 160 NodeMatcher m(node->InputAt(0)); 161 if (m.IsConvertTaggedHoleToUndefined()) { 162 node->ReplaceInput(0, m.InputAt(0)); 163 return Changed(node); 164 } 165 break; 166 } 167 case IrOpcode::kCheckIf: { 168 HeapObjectMatcher m(node->InputAt(0)); 169 if (m.Is(factory()->true_value())) { 170 Node* const effect = NodeProperties::GetEffectInput(node); 171 return Replace(effect); 172 } 173 break; 174 } 175 case IrOpcode::kCheckNumber: { 176 NodeMatcher m(node->InputAt(0)); 177 if (m.IsConvertTaggedHoleToUndefined()) { 178 node->ReplaceInput(0, m.InputAt(0)); 179 return Changed(node); 180 } 181 break; 182 } 183 case IrOpcode::kCheckHeapObject: { 184 Node* const input = node->InputAt(0); 185 if (DecideObjectIsSmi(input) == Decision::kFalse) { 186 ReplaceWithValue(node, input); 187 return Replace(input); 188 } 189 NodeMatcher m(input); 190 if (m.IsCheckHeapObject()) { 191 ReplaceWithValue(node, input); 192 return Replace(input); 193 } 194 break; 195 } 196 case IrOpcode::kCheckSmi: { 197 Node* const input = node->InputAt(0); 198 if (DecideObjectIsSmi(input) == Decision::kTrue) { 199 ReplaceWithValue(node, input); 200 return Replace(input); 201 } 202 NodeMatcher m(input); 203 if (m.IsCheckSmi()) { 204 ReplaceWithValue(node, input); 205 return Replace(input); 206 } else if (m.IsConvertTaggedHoleToUndefined()) { 207 node->ReplaceInput(0, m.InputAt(0)); 208 return Changed(node); 209 } 210 break; 211 } 212 case IrOpcode::kObjectIsSmi: { 213 Node* const input = node->InputAt(0); 214 switch (DecideObjectIsSmi(input)) { 215 case Decision::kTrue: 216 return ReplaceBoolean(true); 217 case Decision::kFalse: 218 return ReplaceBoolean(false); 219 case Decision::kUnknown: 220 break; 221 } 222 break; 223 } 224 case IrOpcode::kNumberAbs: { 225 NumberMatcher m(node->InputAt(0)); 226 if (m.HasResolvedValue()) 227 return ReplaceNumber(std::fabs(m.ResolvedValue())); 228 break; 229 } 230 case IrOpcode::kReferenceEqual: { 231 HeapObjectBinopMatcher m(node); 232 if (m.left().node() == m.right().node()) return ReplaceBoolean(true); 233 break; 234 } 235 case IrOpcode::kCheckedInt32Add: { 236 // (x + a) + b => x + (a + b) where a and b are constants and have the 237 // same sign. 238 Int32BinopMatcher m(node); 239 if (m.right().HasResolvedValue()) { 240 Node* checked_int32_add = m.left().node(); 241 if (checked_int32_add->opcode() == IrOpcode::kCheckedInt32Add) { 242 Int32BinopMatcher n(checked_int32_add); 243 if (n.right().HasResolvedValue() && 244 (n.right().ResolvedValue() >= 0) == 245 (m.right().ResolvedValue() >= 0)) { 246 int32_t val; 247 bool overflow = base::bits::SignedAddOverflow32( 248 n.right().ResolvedValue(), m.right().ResolvedValue(), &val); 249 if (!overflow) { 250 bool has_no_other_uses = true; 251 for (Edge edge : checked_int32_add->use_edges()) { 252 if (!edge.from()->IsDead() && edge.from() != node) { 253 has_no_other_uses = false; 254 break; 255 } 256 } 257 if (has_no_other_uses) { 258 node->ReplaceInput(0, n.left().node()); 259 node->ReplaceInput(1, jsgraph()->Int32Constant(val)); 260 RelaxEffectsAndControls(checked_int32_add); 261 return Changed(node); 262 } 263 } 264 } 265 } 266 } 267 break; 268 } 269 default: 270 break; 271 } 272 return NoChange(); 273} 274 275Reduction SimplifiedOperatorReducer::Change(Node* node, const Operator* op, 276 Node* a) { 277 DCHECK_EQ(node->InputCount(), OperatorProperties::GetTotalInputCount(op)); 278 DCHECK_LE(1, node->InputCount()); 279 node->ReplaceInput(0, a); 280 NodeProperties::ChangeOp(node, op); 281 return Changed(node); 282} 283 284Reduction SimplifiedOperatorReducer::ReplaceBoolean(bool value) { 285 if (branch_semantics_ == BranchSemantics::kJS) { 286 return Replace(jsgraph()->BooleanConstant(value)); 287 } else { 288 return ReplaceInt32(value); 289 } 290} 291 292Reduction SimplifiedOperatorReducer::ReplaceFloat64(double value) { 293 return Replace(jsgraph()->Float64Constant(value)); 294} 295 296 297Reduction SimplifiedOperatorReducer::ReplaceInt32(int32_t value) { 298 return Replace(jsgraph()->Int32Constant(value)); 299} 300 301 302Reduction SimplifiedOperatorReducer::ReplaceNumber(double value) { 303 return Replace(jsgraph()->Constant(value)); 304} 305 306 307Reduction SimplifiedOperatorReducer::ReplaceNumber(int32_t value) { 308 return Replace(jsgraph()->Constant(value)); 309} 310 311Factory* SimplifiedOperatorReducer::factory() const { 312 return jsgraph()->isolate()->factory(); 313} 314 315Graph* SimplifiedOperatorReducer::graph() const { return jsgraph()->graph(); } 316 317MachineOperatorBuilder* SimplifiedOperatorReducer::machine() const { 318 return jsgraph()->machine(); 319} 320 321SimplifiedOperatorBuilder* SimplifiedOperatorReducer::simplified() const { 322 return jsgraph()->simplified(); 323} 324 325} // namespace compiler 326} // namespace internal 327} // namespace v8 328