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/conversions-inl.h" 13#include "src/type-cache.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), 38 jsgraph_(jsgraph), 39 type_cache_(TypeCache::Get()) {} 40 41SimplifiedOperatorReducer::~SimplifiedOperatorReducer() {} 42 43 44Reduction SimplifiedOperatorReducer::Reduce(Node* node) { 45 switch (node->opcode()) { 46 case IrOpcode::kBooleanNot: { 47 HeapObjectMatcher m(node->InputAt(0)); 48 if (m.HasValue()) { 49 return Replace(jsgraph()->BooleanConstant(!m.Value()->BooleanValue())); 50 } 51 if (m.IsBooleanNot()) return Replace(m.InputAt(0)); 52 break; 53 } 54 case IrOpcode::kChangeBitToTagged: { 55 Int32Matcher m(node->InputAt(0)); 56 if (m.Is(0)) return Replace(jsgraph()->FalseConstant()); 57 if (m.Is(1)) return Replace(jsgraph()->TrueConstant()); 58 if (m.IsChangeTaggedToBit()) return Replace(m.InputAt(0)); 59 break; 60 } 61 case IrOpcode::kChangeTaggedToBit: { 62 HeapObjectMatcher m(node->InputAt(0)); 63 if (m.HasValue()) return ReplaceInt32(m.Value()->BooleanValue()); 64 if (m.IsChangeBitToTagged()) return Replace(m.InputAt(0)); 65 break; 66 } 67 case IrOpcode::kChangeFloat64ToTagged: { 68 Float64Matcher m(node->InputAt(0)); 69 if (m.HasValue()) return ReplaceNumber(m.Value()); 70 if (m.IsChangeTaggedToFloat64()) return Replace(m.node()->InputAt(0)); 71 break; 72 } 73 case IrOpcode::kChangeInt31ToTaggedSigned: 74 case IrOpcode::kChangeInt32ToTagged: { 75 Int32Matcher m(node->InputAt(0)); 76 if (m.HasValue()) return ReplaceNumber(m.Value()); 77 if (m.IsChangeTaggedToInt32() || m.IsChangeTaggedSignedToInt32()) { 78 return Replace(m.InputAt(0)); 79 } 80 break; 81 } 82 case IrOpcode::kChangeTaggedToFloat64: 83 case IrOpcode::kTruncateTaggedToFloat64: { 84 NumberMatcher m(node->InputAt(0)); 85 if (m.HasValue()) return ReplaceFloat64(m.Value()); 86 if (m.IsChangeFloat64ToTagged()) return Replace(m.node()->InputAt(0)); 87 if (m.IsChangeInt31ToTaggedSigned() || m.IsChangeInt32ToTagged()) { 88 return Change(node, machine()->ChangeInt32ToFloat64(), m.InputAt(0)); 89 } 90 if (m.IsChangeUint32ToTagged()) { 91 return Change(node, machine()->ChangeUint32ToFloat64(), m.InputAt(0)); 92 } 93 break; 94 } 95 case IrOpcode::kChangeTaggedToInt32: { 96 NumberMatcher m(node->InputAt(0)); 97 if (m.HasValue()) return ReplaceInt32(DoubleToInt32(m.Value())); 98 if (m.IsChangeFloat64ToTagged()) { 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()) { 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()) { 128 return Change(node, machine()->TruncateFloat64ToWord32(), m.InputAt(0)); 129 } 130 break; 131 } 132 case IrOpcode::kCheckTaggedPointer: { 133 Node* const input = node->InputAt(0); 134 if (DecideObjectIsSmi(input) == Decision::kFalse) { 135 ReplaceWithValue(node, input); 136 return Replace(input); 137 } 138 break; 139 } 140 case IrOpcode::kCheckTaggedSigned: { 141 Node* const input = node->InputAt(0); 142 if (DecideObjectIsSmi(input) == Decision::kTrue) { 143 ReplaceWithValue(node, input); 144 return Replace(input); 145 } 146 break; 147 } 148 case IrOpcode::kObjectIsSmi: { 149 Node* const input = node->InputAt(0); 150 switch (DecideObjectIsSmi(input)) { 151 case Decision::kTrue: 152 return ReplaceBoolean(true); 153 case Decision::kFalse: 154 return ReplaceBoolean(false); 155 case Decision::kUnknown: 156 break; 157 } 158 break; 159 } 160 case IrOpcode::kNumberAbs: { 161 NumberMatcher m(node->InputAt(0)); 162 if (m.HasValue()) return ReplaceNumber(std::fabs(m.Value())); 163 break; 164 } 165 case IrOpcode::kNumberCeil: 166 case IrOpcode::kNumberFloor: 167 case IrOpcode::kNumberRound: 168 case IrOpcode::kNumberTrunc: { 169 Node* const input = NodeProperties::GetValueInput(node, 0); 170 Type* const input_type = NodeProperties::GetType(input); 171 if (input_type->Is(type_cache_.kIntegerOrMinusZeroOrNaN)) { 172 return Replace(input); 173 } 174 break; 175 } 176 case IrOpcode::kReferenceEqual: 177 return ReduceReferenceEqual(node); 178 case IrOpcode::kTypeGuard: 179 return ReduceTypeGuard(node); 180 default: 181 break; 182 } 183 return NoChange(); 184} 185 186Reduction SimplifiedOperatorReducer::ReduceReferenceEqual(Node* node) { 187 DCHECK_EQ(IrOpcode::kReferenceEqual, node->opcode()); 188 Node* const left = NodeProperties::GetValueInput(node, 0); 189 Node* const right = NodeProperties::GetValueInput(node, 1); 190 HeapObjectMatcher match_left(left); 191 HeapObjectMatcher match_right(right); 192 if (match_left.HasValue() && match_right.HasValue()) { 193 if (match_left.Value().is_identical_to(match_right.Value())) { 194 return Replace(jsgraph()->TrueConstant()); 195 } else { 196 return Replace(jsgraph()->FalseConstant()); 197 } 198 } 199 return NoChange(); 200} 201 202Reduction SimplifiedOperatorReducer::ReduceTypeGuard(Node* node) { 203 DCHECK_EQ(IrOpcode::kTypeGuard, node->opcode()); 204 Node* const input = NodeProperties::GetValueInput(node, 0); 205 Type* const input_type = NodeProperties::GetTypeOrAny(input); 206 Type* const guard_type = TypeOf(node->op()); 207 if (input_type->Is(guard_type)) return Replace(input); 208 return NoChange(); 209} 210 211Reduction SimplifiedOperatorReducer::Change(Node* node, const Operator* op, 212 Node* a) { 213 DCHECK_EQ(node->InputCount(), OperatorProperties::GetTotalInputCount(op)); 214 DCHECK_LE(1, node->InputCount()); 215 node->ReplaceInput(0, a); 216 NodeProperties::ChangeOp(node, op); 217 return Changed(node); 218} 219 220Reduction SimplifiedOperatorReducer::ReplaceBoolean(bool value) { 221 return Replace(jsgraph()->BooleanConstant(value)); 222} 223 224Reduction SimplifiedOperatorReducer::ReplaceFloat64(double value) { 225 return Replace(jsgraph()->Float64Constant(value)); 226} 227 228 229Reduction SimplifiedOperatorReducer::ReplaceInt32(int32_t value) { 230 return Replace(jsgraph()->Int32Constant(value)); 231} 232 233 234Reduction SimplifiedOperatorReducer::ReplaceNumber(double value) { 235 return Replace(jsgraph()->Constant(value)); 236} 237 238 239Reduction SimplifiedOperatorReducer::ReplaceNumber(int32_t value) { 240 return Replace(jsgraph()->Constant(value)); 241} 242 243 244Graph* SimplifiedOperatorReducer::graph() const { return jsgraph()->graph(); } 245 246 247MachineOperatorBuilder* SimplifiedOperatorReducer::machine() const { 248 return jsgraph()->machine(); 249} 250 251} // namespace compiler 252} // namespace internal 253} // namespace v8 254