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/js-graph.h" 8#include "src/compiler/machine-operator.h" 9#include "src/compiler/node-matchers.h" 10#include "src/compiler/operator-properties.h" 11#include "src/compiler/simplified-operator.h" 12#include "src/compiler/type-cache.h" 13#include "src/conversions-inl.h" 14 15namespace v8 { 16namespace internal { 17namespace compiler { 18 19namespace { 20 21Decision DecideObjectIsSmi(Node* const input) { 22 NumberMatcher m(input); 23 if (m.HasValue()) { 24 return IsSmiDouble(m.Value()) ? Decision::kTrue : Decision::kFalse; 25 } 26 if (m.IsAllocate()) return Decision::kFalse; 27 if (m.IsChangeBitToTagged()) return Decision::kFalse; 28 if (m.IsChangeInt31ToTaggedSigned()) return Decision::kTrue; 29 if (m.IsHeapConstant()) return Decision::kFalse; 30 return Decision::kUnknown; 31} 32 33} // namespace 34 35SimplifiedOperatorReducer::SimplifiedOperatorReducer(Editor* editor, 36 JSGraph* jsgraph) 37 : AdvancedReducer(editor), jsgraph_(jsgraph) {} 38 39SimplifiedOperatorReducer::~SimplifiedOperatorReducer() {} 40 41 42Reduction SimplifiedOperatorReducer::Reduce(Node* node) { 43 switch (node->opcode()) { 44 case IrOpcode::kBooleanNot: { 45 HeapObjectMatcher m(node->InputAt(0)); 46 if (m.Is(factory()->true_value())) return ReplaceBoolean(false); 47 if (m.Is(factory()->false_value())) return ReplaceBoolean(true); 48 if (m.IsBooleanNot()) return Replace(m.InputAt(0)); 49 break; 50 } 51 case IrOpcode::kChangeBitToTagged: { 52 Int32Matcher m(node->InputAt(0)); 53 if (m.Is(0)) return Replace(jsgraph()->FalseConstant()); 54 if (m.Is(1)) return Replace(jsgraph()->TrueConstant()); 55 if (m.IsChangeTaggedToBit()) return Replace(m.InputAt(0)); 56 break; 57 } 58 case IrOpcode::kChangeTaggedToBit: { 59 HeapObjectMatcher m(node->InputAt(0)); 60 if (m.HasValue()) return ReplaceInt32(m.Value()->BooleanValue()); 61 if (m.IsChangeBitToTagged()) return Replace(m.InputAt(0)); 62 break; 63 } 64 case IrOpcode::kChangeFloat64ToTagged: { 65 Float64Matcher m(node->InputAt(0)); 66 if (m.HasValue()) return ReplaceNumber(m.Value()); 67 if (m.IsChangeTaggedToFloat64()) return Replace(m.node()->InputAt(0)); 68 break; 69 } 70 case IrOpcode::kChangeInt31ToTaggedSigned: 71 case IrOpcode::kChangeInt32ToTagged: { 72 Int32Matcher m(node->InputAt(0)); 73 if (m.HasValue()) return ReplaceNumber(m.Value()); 74 if (m.IsChangeTaggedToInt32() || m.IsChangeTaggedSignedToInt32()) { 75 return Replace(m.InputAt(0)); 76 } 77 break; 78 } 79 case IrOpcode::kChangeTaggedToFloat64: 80 case IrOpcode::kTruncateTaggedToFloat64: { 81 NumberMatcher m(node->InputAt(0)); 82 if (m.HasValue()) return ReplaceFloat64(m.Value()); 83 if (m.IsChangeFloat64ToTagged() || m.IsChangeFloat64ToTaggedPointer()) { 84 return Replace(m.node()->InputAt(0)); 85 } 86 if (m.IsChangeInt31ToTaggedSigned() || m.IsChangeInt32ToTagged()) { 87 return Change(node, machine()->ChangeInt32ToFloat64(), m.InputAt(0)); 88 } 89 if (m.IsChangeUint32ToTagged()) { 90 return Change(node, machine()->ChangeUint32ToFloat64(), m.InputAt(0)); 91 } 92 break; 93 } 94 case IrOpcode::kChangeTaggedSignedToInt32: 95 case IrOpcode::kChangeTaggedToInt32: { 96 NumberMatcher m(node->InputAt(0)); 97 if (m.HasValue()) return ReplaceInt32(DoubleToInt32(m.Value())); 98 if (m.IsChangeFloat64ToTagged() || m.IsChangeFloat64ToTaggedPointer()) { 99 return Change(node, machine()->ChangeFloat64ToInt32(), m.InputAt(0)); 100 } 101 if (m.IsChangeInt31ToTaggedSigned() || m.IsChangeInt32ToTagged()) { 102 return Replace(m.InputAt(0)); 103 } 104 break; 105 } 106 case IrOpcode::kChangeTaggedToUint32: { 107 NumberMatcher m(node->InputAt(0)); 108 if (m.HasValue()) return ReplaceUint32(DoubleToUint32(m.Value())); 109 if (m.IsChangeFloat64ToTagged() || m.IsChangeFloat64ToTaggedPointer()) { 110 return Change(node, machine()->ChangeFloat64ToUint32(), m.InputAt(0)); 111 } 112 if (m.IsChangeUint32ToTagged()) return Replace(m.InputAt(0)); 113 break; 114 } 115 case IrOpcode::kChangeUint32ToTagged: { 116 Uint32Matcher m(node->InputAt(0)); 117 if (m.HasValue()) return ReplaceNumber(FastUI2D(m.Value())); 118 break; 119 } 120 case IrOpcode::kTruncateTaggedToWord32: { 121 NumberMatcher m(node->InputAt(0)); 122 if (m.HasValue()) return ReplaceInt32(DoubleToInt32(m.Value())); 123 if (m.IsChangeInt31ToTaggedSigned() || m.IsChangeInt32ToTagged() || 124 m.IsChangeUint32ToTagged()) { 125 return Replace(m.InputAt(0)); 126 } 127 if (m.IsChangeFloat64ToTagged() || m.IsChangeFloat64ToTaggedPointer()) { 128 return Change(node, machine()->TruncateFloat64ToWord32(), m.InputAt(0)); 129 } 130 break; 131 } 132 case IrOpcode::kCheckedFloat64ToInt32: { 133 Float64Matcher m(node->InputAt(0)); 134 if (m.HasValue() && IsInt32Double(m.Value())) { 135 Node* value = jsgraph()->Int32Constant(static_cast<int32_t>(m.Value())); 136 ReplaceWithValue(node, value); 137 return Replace(value); 138 } 139 break; 140 } 141 case IrOpcode::kCheckedTaggedToInt32: 142 case IrOpcode::kCheckedTaggedSignedToInt32: { 143 NodeMatcher m(node->InputAt(0)); 144 if (m.IsConvertTaggedHoleToUndefined()) { 145 node->ReplaceInput(0, m.InputAt(0)); 146 return Changed(node); 147 } 148 break; 149 } 150 case IrOpcode::kCheckIf: { 151 HeapObjectMatcher m(node->InputAt(0)); 152 if (m.Is(factory()->true_value())) { 153 Node* const effect = NodeProperties::GetEffectInput(node); 154 return Replace(effect); 155 } 156 break; 157 } 158 case IrOpcode::kCheckNumber: { 159 NodeMatcher m(node->InputAt(0)); 160 if (m.IsConvertTaggedHoleToUndefined()) { 161 node->ReplaceInput(0, m.InputAt(0)); 162 return Changed(node); 163 } 164 break; 165 } 166 case IrOpcode::kCheckHeapObject: { 167 Node* const input = node->InputAt(0); 168 if (DecideObjectIsSmi(input) == Decision::kFalse) { 169 ReplaceWithValue(node, input); 170 return Replace(input); 171 } 172 NodeMatcher m(input); 173 if (m.IsCheckHeapObject()) { 174 ReplaceWithValue(node, input); 175 return Replace(input); 176 } 177 break; 178 } 179 case IrOpcode::kCheckSmi: { 180 Node* const input = node->InputAt(0); 181 if (DecideObjectIsSmi(input) == Decision::kTrue) { 182 ReplaceWithValue(node, input); 183 return Replace(input); 184 } 185 NodeMatcher m(input); 186 if (m.IsCheckSmi()) { 187 ReplaceWithValue(node, input); 188 return Replace(input); 189 } else if (m.IsConvertTaggedHoleToUndefined()) { 190 node->ReplaceInput(0, m.InputAt(0)); 191 return Changed(node); 192 } 193 break; 194 } 195 case IrOpcode::kObjectIsSmi: { 196 Node* const input = node->InputAt(0); 197 switch (DecideObjectIsSmi(input)) { 198 case Decision::kTrue: 199 return ReplaceBoolean(true); 200 case Decision::kFalse: 201 return ReplaceBoolean(false); 202 case Decision::kUnknown: 203 break; 204 } 205 break; 206 } 207 case IrOpcode::kNumberAbs: { 208 NumberMatcher m(node->InputAt(0)); 209 if (m.HasValue()) return ReplaceNumber(std::fabs(m.Value())); 210 break; 211 } 212 case IrOpcode::kReferenceEqual: { 213 HeapObjectBinopMatcher m(node); 214 if (m.left().node() == m.right().node()) return ReplaceBoolean(true); 215 break; 216 } 217 default: 218 break; 219 } 220 return NoChange(); 221} 222 223Reduction SimplifiedOperatorReducer::Change(Node* node, const Operator* op, 224 Node* a) { 225 DCHECK_EQ(node->InputCount(), OperatorProperties::GetTotalInputCount(op)); 226 DCHECK_LE(1, node->InputCount()); 227 node->ReplaceInput(0, a); 228 NodeProperties::ChangeOp(node, op); 229 return Changed(node); 230} 231 232Reduction SimplifiedOperatorReducer::ReplaceBoolean(bool value) { 233 return Replace(jsgraph()->BooleanConstant(value)); 234} 235 236Reduction SimplifiedOperatorReducer::ReplaceFloat64(double value) { 237 return Replace(jsgraph()->Float64Constant(value)); 238} 239 240 241Reduction SimplifiedOperatorReducer::ReplaceInt32(int32_t value) { 242 return Replace(jsgraph()->Int32Constant(value)); 243} 244 245 246Reduction SimplifiedOperatorReducer::ReplaceNumber(double value) { 247 return Replace(jsgraph()->Constant(value)); 248} 249 250 251Reduction SimplifiedOperatorReducer::ReplaceNumber(int32_t value) { 252 return Replace(jsgraph()->Constant(value)); 253} 254 255Factory* SimplifiedOperatorReducer::factory() const { 256 return isolate()->factory(); 257} 258 259Graph* SimplifiedOperatorReducer::graph() const { return jsgraph()->graph(); } 260 261Isolate* SimplifiedOperatorReducer::isolate() const { 262 return jsgraph()->isolate(); 263} 264 265MachineOperatorBuilder* SimplifiedOperatorReducer::machine() const { 266 return jsgraph()->machine(); 267} 268 269} // namespace compiler 270} // namespace internal 271} // namespace v8 272