1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
|
// Copyright 2022 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_COMPILER_TURBOSHAFT_SELECT_LOWERING_REDUCER_H_
#define V8_COMPILER_TURBOSHAFT_SELECT_LOWERING_REDUCER_H_
#include "src/base/vector.h"
#include "src/compiler/common-operator.h"
#include "src/compiler/turboshaft/assembler.h"
#include "src/compiler/turboshaft/operations.h"
namespace v8::internal::compiler::turboshaft {
// Lowers Select operations to diamonds.
//
// A Select is conceptually somewhat similar to a ternary if:
//
// res = Select(cond, val_true, val_false)
//
// means:
//
// res = cond ? val_true : val_false
//
// SelectLoweringReducer lowers such operations into:
//
// if (cond) {
// res = val_true
// } else {
// res = val_false
// }
template <class Next>
class SelectLoweringReducer : public Next {
public:
using Next::Asm;
OpIndex ReduceSelect(OpIndex cond, OpIndex vtrue, OpIndex vfalse,
RegisterRepresentation rep, BranchHint hint,
SelectOp::Implementation implem) {
if (implem == SelectOp::Implementation::kCMove) {
// We do not lower Select operations that should be implemented with
// CMove.
return Next::ReduceSelect(cond, vtrue, vfalse, rep, hint, implem);
}
Block* true_block = Asm().NewBlock(Block::Kind::kBranchTarget);
Block* false_block = Asm().NewBlock(Block::Kind::kBranchTarget);
Block* merge_block = Asm().NewBlock(Block::Kind::kMerge);
if (hint == BranchHint::kTrue) {
false_block->SetDeferred(true);
} else if (hint == BranchHint::kFalse) {
true_block->SetDeferred(true);
}
Asm().Branch(cond, true_block, false_block);
// Note that it's possible that other reducers of the stack optimizes the
// Branch that we just introduced into a Goto (if its condition is already
// known). Thus, we check the return values of Bind, and only insert the
// Gotos if Bind was successful: if not, then it means that the block
// ({true_block} or {false_block}) isn't reachable because the Branch was
// optimized to a Goto.
bool has_true_block = false;
bool has_false_block = false;
if (Asm().Bind(true_block)) {
has_true_block = true;
Asm().Goto(merge_block);
}
if (Asm().Bind(false_block)) {
has_false_block = true;
Asm().Goto(merge_block);
}
Asm().BindReachable(merge_block);
if (has_true_block && has_false_block) {
return Asm().Phi(base::VectorOf({vtrue, vfalse}), rep);
} else if (has_true_block) {
return vtrue;
} else {
DCHECK(has_false_block);
return vfalse;
}
}
};
} // namespace v8::internal::compiler::turboshaft
#endif // V8_COMPILER_TURBOSHAFT_SELECT_LOWERING_REDUCER_H_
|