Line data Source code
1 : // Copyright 2018 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/torque/cfg.h"
6 :
7 : #include "src/torque/type-oracle.h"
8 :
9 : namespace v8 {
10 : namespace internal {
11 : namespace torque {
12 :
13 7648 : void Block::SetInputTypes(const Stack<const Type*>& input_types) {
14 7648 : if (!input_types_) {
15 : input_types_ = input_types;
16 : return;
17 4709 : } else if (*input_types_ == input_types) {
18 : return;
19 : }
20 :
21 : DCHECK_EQ(input_types.Size(), input_types_->Size());
22 : Stack<const Type*> merged_types;
23 : bool widened = false;
24 : auto c2_iterator = input_types.begin();
25 11876 : for (const Type* c1 : *input_types_) {
26 5753 : const Type* merged_type = TypeOracle::GetUnionType(c1, *c2_iterator++);
27 5753 : if (!merged_type->IsSubtypeOf(c1)) {
28 : widened = true;
29 : }
30 : merged_types.Push(merged_type);
31 : }
32 370 : if (merged_types.Size() == input_types_->Size()) {
33 370 : if (widened) {
34 : input_types_ = merged_types;
35 331 : Retype();
36 : }
37 : return;
38 : }
39 :
40 0 : std::stringstream error;
41 0 : error << "incompatible types at branch:\n";
42 0 : for (intptr_t i = std::max(input_types_->Size(), input_types.Size()) - 1;
43 0 : i >= 0; --i) {
44 : base::Optional<const Type*> left;
45 : base::Optional<const Type*> right;
46 0 : if (static_cast<size_t>(i) < input_types.Size()) {
47 : left = input_types.Peek(BottomOffset{static_cast<size_t>(i)});
48 : }
49 0 : if (static_cast<size_t>(i) < input_types_->Size()) {
50 : right = input_types_->Peek(BottomOffset{static_cast<size_t>(i)});
51 : }
52 0 : if (left && right && *left == *right) {
53 0 : error << **left << "\n";
54 : } else {
55 0 : if (left) {
56 0 : error << **left;
57 : } else {
58 0 : error << "/*missing*/";
59 : }
60 0 : error << " => ";
61 0 : if (right) {
62 0 : error << **right;
63 : } else {
64 0 : error << "/*missing*/";
65 : }
66 0 : error << "\n";
67 : }
68 : }
69 0 : ReportError(error.str());
70 : }
71 :
72 6411 : void CfgAssembler::Bind(Block* block) {
73 : DCHECK(current_block_->IsComplete());
74 : DCHECK(block->instructions().empty());
75 : DCHECK(block->HasInputTypes());
76 6411 : current_block_ = block;
77 : current_stack_ = block->InputTypes();
78 : cfg_.PlaceBlock(block);
79 6411 : }
80 :
81 2806 : void CfgAssembler::Goto(Block* block) {
82 2806 : if (block->HasInputTypes()) {
83 : DropTo(block->InputTypes().AboveTop());
84 : }
85 8418 : Emit(GotoInstruction{block});
86 2806 : }
87 :
88 1703 : StackRange CfgAssembler::Goto(Block* block, size_t preserved_slots) {
89 : DCHECK(block->HasInputTypes());
90 : DCHECK_GE(CurrentStack().Size(), block->InputTypes().Size());
91 5109 : Emit(DeleteRangeInstruction{
92 : StackRange{block->InputTypes().AboveTop() - preserved_slots,
93 1703 : CurrentStack().AboveTop() - preserved_slots}});
94 : StackRange preserved_slot_range = TopRange(preserved_slots);
95 5109 : Emit(GotoInstruction{block});
96 1703 : return preserved_slot_range;
97 : }
98 :
99 836 : void CfgAssembler::Branch(Block* if_true, Block* if_false) {
100 2508 : Emit(BranchInstruction{if_true, if_false});
101 836 : }
102 :
103 : // Delete the specified range of slots, moving upper slots to fill the gap.
104 57548 : void CfgAssembler::DeleteRange(StackRange range) {
105 : DCHECK_LE(range.end(), current_stack_.AboveTop());
106 57548 : if (range.Size() == 0) return;
107 24018 : Emit(DeleteRangeInstruction{range});
108 : }
109 :
110 31242 : void CfgAssembler::DropTo(BottomOffset new_level) {
111 32222 : DeleteRange(StackRange{new_level, CurrentStack().AboveTop()});
112 31242 : }
113 :
114 18790 : StackRange CfgAssembler::Peek(StackRange range,
115 : base::Optional<const Type*> type) {
116 : std::vector<const Type*> lowered_types;
117 18790 : if (type) {
118 37580 : lowered_types = LowerType(*type);
119 : DCHECK_EQ(lowered_types.size(), range.Size());
120 : }
121 59820 : for (size_t i = 0; i < range.Size(); ++i) {
122 102575 : Emit(PeekInstruction{
123 : range.begin() + i,
124 20515 : type ? lowered_types[i] : base::Optional<const Type*>{}});
125 : }
126 18790 : return TopRange(range.Size());
127 : }
128 :
129 586 : void CfgAssembler::Poke(StackRange destination, StackRange origin,
130 : base::Optional<const Type*> type) {
131 : DCHECK_EQ(destination.Size(), origin.Size());
132 : DCHECK_LE(destination.end(), origin.begin());
133 : DCHECK_EQ(origin.end(), CurrentStack().AboveTop());
134 : std::vector<const Type*> lowered_types;
135 586 : if (type) {
136 1172 : lowered_types = LowerType(*type);
137 : DCHECK_EQ(lowered_types.size(), origin.Size());
138 : }
139 1184 : for (intptr_t i = origin.Size() - 1; i >= 0; --i) {
140 3588 : Emit(PokeInstruction{
141 : destination.begin() + i,
142 598 : type ? lowered_types[i] : base::Optional<const Type*>{}});
143 : }
144 586 : }
145 :
146 0 : void CfgAssembler::Print(std::string s) {
147 0 : Emit(PrintConstantStringInstruction{std::move(s)});
148 0 : }
149 :
150 0 : void CfgAssembler::AssertionFailure(std::string message) {
151 0 : Emit(AbortInstruction{AbortInstruction::Kind::kAssertionFailure,
152 0 : std::move(message)});
153 0 : }
154 :
155 0 : void CfgAssembler::Unreachable() {
156 0 : Emit(AbortInstruction{AbortInstruction::Kind::kUnreachable});
157 0 : }
158 :
159 0 : void CfgAssembler::DebugBreak() {
160 0 : Emit(AbortInstruction{AbortInstruction::Kind::kDebugBreak});
161 0 : }
162 :
163 : } // namespace torque
164 : } // namespace internal
165 59456 : } // namespace v8
|