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