5 #include "src/torque/csa-generator.h" 7 #include "src/torque/type-oracle.h" 8 #include "src/torque/utils.h" 14 base::Optional<Stack<std::string>> CSAGenerator::EmitGraph(
15 Stack<std::string> parameters) {
16 for (Block* block : cfg_.blocks()) {
17 out_ <<
" compiler::CodeAssemblerParameterizedLabel<";
18 PrintCommaSeparatedList(out_, block->InputTypes(), [](
const Type* t) {
19 return t->GetGeneratedTNodeTypeName();
21 out_ <<
"> " << BlockName(block) <<
"(&ca_, compiler::CodeAssemblerLabel::" 22 << (block->IsDeferred() ?
"kDeferred" :
"kNonDeferred") <<
");\n";
25 EmitInstruction(GotoInstruction{cfg_.start()}, ¶meters);
26 for (Block* block : cfg_.blocks()) {
27 if (cfg_.end() && *cfg_.end() == block)
continue;
28 out_ <<
"\n if (" << BlockName(block) <<
".is_used()) {\n";
34 return EmitBlock(*cfg_.end());
39 Stack<std::string> CSAGenerator::EmitBlock(
const Block* block) {
40 Stack<std::string> stack;
41 for (
const Type* t : block->InputTypes()) {
42 stack.Push(FreshNodeName());
43 out_ <<
" compiler::TNode<" << t->GetGeneratedTNodeTypeName() <<
"> " 44 << stack.Top() <<
";\n";
46 out_ <<
" ca_.Bind(&" << BlockName(block);
47 for (
const std::string& name : stack) {
48 out_ <<
", &" << name;
51 for (
const Instruction& instruction : block->instructions()) {
52 EmitInstruction(instruction, &stack);
57 void CSAGenerator::EmitInstruction(
const Instruction& instruction,
58 Stack<std::string>* stack) {
59 switch (instruction.kind()) {
60 #define ENUM_ITEM(T) \ 61 case InstructionKind::k##T: \ 62 return EmitInstruction(instruction.Cast<T>(), stack); 63 TORQUE_INSTRUCTION_LIST(ENUM_ITEM)
68 void CSAGenerator::EmitInstruction(
const PeekInstruction& instruction,
69 Stack<std::string>* stack) {
70 stack->Push(stack->Peek(instruction.slot));
73 void CSAGenerator::EmitInstruction(
const PokeInstruction& instruction,
74 Stack<std::string>* stack) {
75 stack->Poke(instruction.slot, stack->Top());
79 void CSAGenerator::EmitInstruction(
const DeleteRangeInstruction& instruction,
80 Stack<std::string>* stack) {
81 stack->DeleteRange(instruction.range);
84 void CSAGenerator::EmitInstruction(
85 const PushUninitializedInstruction& instruction,
86 Stack<std::string>* stack) {
90 stack->Push(
"ca_.Uninitialized<" +
91 instruction.type->GetGeneratedTNodeTypeName() +
">()");
94 void CSAGenerator::EmitInstruction(
95 const PushCodePointerInstruction& instruction, Stack<std::string>* stack) {
97 "ca_.UncheckedCast<Code>(ca_.HeapConstant(Builtins::CallableFor(ca_." 98 "isolate(), Builtins::k" +
99 instruction.external_name +
").code()))");
102 void CSAGenerator::EmitInstruction(
103 const NamespaceConstantInstruction& instruction,
104 Stack<std::string>* stack) {
105 const Type* type = instruction.constant->type();
106 std::vector<std::string> results;
107 for (
const Type* lowered : LowerType(type)) {
108 results.push_back(FreshNodeName());
109 stack->Push(results.back());
110 out_ <<
" compiler::TNode<" << lowered->GetGeneratedTNodeTypeName()
111 <<
"> " << stack->Top() <<
";\n";
112 out_ <<
" USE(" << stack->Top() <<
");\n";
115 if (type->IsStructType()) {
117 PrintCommaSeparatedList(out_, results);
119 }
else if (results.size() == 1) {
120 out_ << results[0] <<
" = ";
122 out_ << instruction.constant->ExternalAssemblerName() <<
"(state_)." 123 << instruction.constant->constant_name() <<
"()";
124 if (type->IsStructType()) {
125 out_ <<
".Flatten();\n";
131 void CSAGenerator::ProcessArgumentsCommon(
132 const TypeVector& parameter_types, std::vector<std::string>* args,
133 std::vector<std::string>* constexpr_arguments, Stack<std::string>* stack) {
134 for (
auto it = parameter_types.rbegin(); it != parameter_types.rend(); ++it) {
135 const Type* type = *it;
137 if (type->IsConstexpr()) {
138 args->push_back(std::move(constexpr_arguments->back()));
139 constexpr_arguments->pop_back();
142 size_t slot_count = LoweredSlotCount(type);
143 VisitResult arg = VisitResult(type, stack->TopRange(slot_count));
144 EmitCSAValue(arg, *stack, s);
145 args->push_back(s.str());
146 stack->PopMany(slot_count);
149 std::reverse(args->begin(), args->end());
152 void CSAGenerator::EmitInstruction(
const CallIntrinsicInstruction& instruction,
153 Stack<std::string>* stack) {
154 std::vector<std::string> constexpr_arguments =
155 instruction.constexpr_arguments;
156 std::vector<std::string> args;
157 TypeVector parameter_types =
158 instruction.intrinsic->signature().parameter_types.types;
159 ProcessArgumentsCommon(parameter_types, &args, &constexpr_arguments, stack);
161 Stack<std::string> pre_call_stack = *stack;
162 const Type* return_type = instruction.intrinsic->signature().return_type;
163 std::vector<std::string> results;
164 for (
const Type* type : LowerType(return_type)) {
165 results.push_back(FreshNodeName());
166 stack->Push(results.back());
167 out_ <<
" compiler::TNode<" << type->GetGeneratedTNodeTypeName() <<
"> " 168 << stack->Top() <<
";\n";
169 out_ <<
" USE(" << stack->Top() <<
");\n";
173 if (return_type->IsStructType()) {
175 PrintCommaSeparatedList(out_, results);
178 if (results.size() == 1) {
179 out_ << results[0] <<
" = ";
183 if (instruction.intrinsic->ExternalName() ==
"%RawCast") {
184 if (!return_type->IsSubtypeOf(TypeOracle::GetObjectType())) {
185 ReportError(
"%RawCast must cast to subtype of Object");
187 out_ <<
"TORQUE_CAST";
189 ReportError(
"no built in intrinsic with name " +
190 instruction.intrinsic->ExternalName());
194 PrintCommaSeparatedList(out_, args);
195 if (return_type->IsStructType()) {
196 out_ <<
").Flatten();\n";
202 void CSAGenerator::EmitInstruction(
const CallCsaMacroInstruction& instruction,
203 Stack<std::string>* stack) {
204 std::vector<std::string> constexpr_arguments =
205 instruction.constexpr_arguments;
206 std::vector<std::string> args;
207 TypeVector parameter_types =
208 instruction.macro->signature().parameter_types.types;
209 ProcessArgumentsCommon(parameter_types, &args, &constexpr_arguments, stack);
211 Stack<std::string> pre_call_stack = *stack;
212 const Type* return_type = instruction.macro->signature().return_type;
213 std::vector<std::string> results;
214 for (
const Type* type : LowerType(return_type)) {
215 results.push_back(FreshNodeName());
216 stack->Push(results.back());
217 out_ <<
" compiler::TNode<" << type->GetGeneratedTNodeTypeName() <<
"> " 218 << stack->Top() <<
";\n";
219 out_ <<
" USE(" << stack->Top() <<
");\n";
221 std::string catch_name =
222 PreCallableExceptionPreparation(instruction.catch_block);
224 if (return_type->IsStructType()) {
226 PrintCommaSeparatedList(out_, results);
229 if (results.size() == 1) {
230 out_ << results[0] <<
" = ca_.UncheckedCast<" 231 << return_type->GetGeneratedTNodeTypeName() <<
">(";
234 out_ << instruction.macro->external_assembler_name() <<
"(state_)." 235 << instruction.macro->ExternalName() <<
"(";
236 PrintCommaSeparatedList(out_, args);
237 if (return_type->IsStructType()) {
238 out_ <<
").Flatten();\n";
240 if (results.size() == 1) out_ <<
")";
243 PostCallableExceptionPreparation(catch_name, return_type,
244 instruction.catch_block, &pre_call_stack);
247 void CSAGenerator::EmitInstruction(
248 const CallCsaMacroAndBranchInstruction& instruction,
249 Stack<std::string>* stack) {
250 std::vector<std::string> constexpr_arguments =
251 instruction.constexpr_arguments;
252 std::vector<std::string> args;
253 TypeVector parameter_types =
254 instruction.macro->signature().parameter_types.types;
255 ProcessArgumentsCommon(parameter_types, &args, &constexpr_arguments, stack);
257 Stack<std::string> pre_call_stack = *stack;
258 std::vector<std::string> results;
259 const Type* return_type = instruction.macro->signature().return_type;
260 if (return_type != TypeOracle::GetNeverType()) {
261 for (
const Type* type :
262 LowerType(instruction.macro->signature().return_type)) {
263 results.push_back(FreshNodeName());
264 out_ <<
" compiler::TNode<" << type->GetGeneratedTNodeTypeName()
265 <<
"> " << results.back() <<
";\n";
266 out_ <<
" USE(" << results.back() <<
");\n";
270 std::vector<std::string> label_names;
271 std::vector<std::vector<std::string>> var_names;
272 const LabelDeclarationVector& labels = instruction.macro->signature().labels;
273 DCHECK_EQ(labels.size(), instruction.label_blocks.size());
274 for (
size_t i = 0;
i < labels.size(); ++
i) {
275 TypeVector label_parameters = labels[
i].types;
276 label_names.push_back(
"label" + std::to_string(
i));
277 var_names.push_back({});
278 for (
size_t j = 0; j < label_parameters.size(); ++j) {
279 var_names[
i].push_back(
"result_" + std::to_string(
i) +
"_" +
281 out_ <<
" compiler::TypedCodeAssemblerVariable<" 282 << label_parameters[j]->GetGeneratedTNodeTypeName() <<
"> " 283 << var_names[
i][j] <<
"(&ca_);\n";
285 out_ <<
" compiler::CodeAssemblerLabel " << label_names[
i]
289 std::string catch_name =
290 PreCallableExceptionPreparation(instruction.catch_block);
292 if (results.size() == 1) {
293 out_ << results[0] <<
" = ";
294 }
else if (results.size() > 1) {
296 PrintCommaSeparatedList(out_, results);
299 out_ << instruction.macro->external_assembler_name() <<
"(state_)." 300 << instruction.macro->ExternalName() <<
"(";
301 PrintCommaSeparatedList(out_, args);
302 bool first = args.empty();
303 for (
size_t i = 0;
i < label_names.size(); ++
i) {
304 if (!first) out_ <<
", ";
305 out_ <<
"&" << label_names[
i];
307 for (
size_t j = 0; j < var_names[
i].size(); ++j) {
308 out_ <<
", &" << var_names[
i][j];
311 if (return_type->IsStructType()) {
312 out_ <<
").Flatten();\n";
317 PostCallableExceptionPreparation(catch_name, return_type,
318 instruction.catch_block, &pre_call_stack);
320 if (instruction.return_continuation) {
321 out_ <<
" ca_.Goto(&" << BlockName(*instruction.return_continuation);
322 for (
const std::string& value : *stack) {
323 out_ <<
", " << value;
325 for (
const std::string& result : results) {
326 out_ <<
", " << result;
330 for (
size_t i = 0;
i < label_names.size(); ++
i) {
331 out_ <<
" if (" << label_names[
i] <<
".is_used()) {\n";
332 out_ <<
" ca_.Bind(&" << label_names[
i] <<
");\n";
333 out_ <<
" ca_.Goto(&" << BlockName(instruction.label_blocks[
i]);
334 for (
const std::string& value : *stack) {
335 out_ <<
", " << value;
337 for (
const std::string& var : var_names[
i]) {
338 out_ <<
", " << var <<
".value()";
346 void CSAGenerator::EmitInstruction(
const CallBuiltinInstruction& instruction,
347 Stack<std::string>* stack) {
348 std::vector<std::string> arguments = stack->PopMany(instruction.argc);
349 std::vector<const Type*> result_types =
350 LowerType(instruction.builtin->signature().return_type);
351 if (instruction.is_tailcall) {
352 out_ <<
" CodeStubAssembler(state_).TailCallBuiltin(Builtins::k" 353 << instruction.builtin->ExternalName() <<
", ";
354 PrintCommaSeparatedList(out_, arguments);
357 std::string result_name = FreshNodeName();
358 if (result_types.size() == 1) {
359 out_ <<
" compiler::TNode<" 360 << result_types[0]->GetGeneratedTNodeTypeName() <<
"> " 361 << result_name <<
";\n";
363 std::string catch_name =
364 PreCallableExceptionPreparation(instruction.catch_block);
365 Stack<std::string> pre_call_stack = *stack;
366 if (result_types.size() == 1) {
367 std::string generated_type = result_types[0]->GetGeneratedTNodeTypeName();
368 stack->Push(result_name);
369 out_ <<
" " << result_name <<
" = ";
370 if (generated_type !=
"Object") out_ <<
"TORQUE_CAST(";
371 out_ <<
"CodeStubAssembler(state_).CallBuiltin(Builtins::k" 372 << instruction.builtin->ExternalName() <<
", ";
373 PrintCommaSeparatedList(out_, arguments);
374 if (generated_type !=
"Object") out_ <<
")";
376 out_ <<
" USE(" << result_name <<
");\n";
378 DCHECK_EQ(0, result_types.size());
381 out_ <<
" CodeStubAssembler(state_).CallBuiltin(Builtins::k" 382 << instruction.builtin->ExternalName() <<
", ";
383 PrintCommaSeparatedList(out_, arguments);
386 PostCallableExceptionPreparation(
388 result_types.size() == 0 ? TypeOracle::GetVoidType() : result_types[0],
389 instruction.catch_block, &pre_call_stack);
393 void CSAGenerator::EmitInstruction(
394 const CallBuiltinPointerInstruction& instruction,
395 Stack<std::string>* stack) {
396 std::vector<std::string> function_and_arguments =
397 stack->PopMany(1 + instruction.argc);
398 std::vector<const Type*> result_types =
399 LowerType(instruction.type->return_type());
400 if (result_types.size() != 1) {
401 ReportError(
"builtins must have exactly one result");
403 if (instruction.is_tailcall) {
405 "CodeStubAssembler(state_).TailCallBuiltin(Builtins::CallableFor(" 407 "ExampleBuiltinForTorqueFunctionPointerType(" 408 << instruction.type->function_pointer_type_id() <<
")).descriptor(), ";
409 PrintCommaSeparatedList(out_, function_and_arguments);
412 stack->Push(FreshNodeName());
413 std::string generated_type = result_types[0]->GetGeneratedTNodeTypeName();
414 out_ <<
" compiler::TNode<" << generated_type <<
"> " << stack->Top()
416 if (generated_type !=
"Object") out_ <<
"TORQUE_CAST(";
417 out_ <<
"CodeStubAssembler(state_).CallStub(Builtins::CallableFor(ca_." 419 "ExampleBuiltinForTorqueFunctionPointerType(" 420 << instruction.type->function_pointer_type_id() <<
")).descriptor(), ";
421 PrintCommaSeparatedList(out_, function_and_arguments);
423 if (generated_type !=
"Object") out_ <<
")";
425 out_ <<
" USE(" << stack->Top() <<
");\n";
429 std::string CSAGenerator::PreCallableExceptionPreparation(
430 base::Optional<Block*> catch_block) {
431 std::string catch_name;
433 catch_name = FreshCatchName();
434 out_ <<
" compiler::CodeAssemblerExceptionHandlerLabel " << catch_name
435 <<
"_label(&ca_, compiler::CodeAssemblerLabel::kDeferred);\n";
436 out_ <<
" { compiler::CodeAssemblerScopedExceptionHandler s(&ca_, &" 437 << catch_name <<
"_label);\n";
442 void CSAGenerator::PostCallableExceptionPreparation(
443 const std::string& catch_name,
const Type* return_type,
444 base::Optional<Block*> catch_block, Stack<std::string>* stack) {
446 std::string block_name = BlockName(*catch_block);
448 out_ <<
" if (" << catch_name <<
"_label.is_used()) {\n";
449 out_ <<
" compiler::CodeAssemblerLabel " << catch_name
451 if (!return_type->IsNever()) {
452 out_ <<
" ca_.Goto(&" << catch_name <<
"_skip);\n";
454 out_ <<
" compiler::TNode<Object> " << catch_name
455 <<
"_exception_object;\n";
456 out_ <<
" ca_.Bind(&" << catch_name <<
"_label, &" << catch_name
457 <<
"_exception_object);\n";
458 out_ <<
" ca_.Goto(&" << block_name;
459 for (
size_t i = 0;
i < stack->Size(); ++
i) {
460 out_ <<
", " << stack->begin()[
i];
462 out_ <<
", " << catch_name <<
"_exception_object);\n";
463 if (!return_type->IsNever()) {
464 out_ <<
" ca_.Bind(&" << catch_name <<
"_skip);\n";
470 void CSAGenerator::EmitInstruction(
const CallRuntimeInstruction& instruction,
471 Stack<std::string>* stack) {
472 std::vector<std::string> arguments = stack->PopMany(instruction.argc);
473 const Type* return_type =
474 instruction.runtime_function->signature().return_type;
475 std::vector<const Type*> result_types;
476 if (return_type != TypeOracle::GetNeverType()) {
477 result_types = LowerType(return_type);
479 if (result_types.size() > 1) {
480 ReportError(
"runtime function must have at most one result");
482 if (instruction.is_tailcall) {
483 out_ <<
" CodeStubAssembler(state_).TailCallRuntime(Runtime::k" 484 << instruction.runtime_function->ExternalName() <<
", ";
485 PrintCommaSeparatedList(out_, arguments);
488 std::string result_name = FreshNodeName();
489 if (result_types.size() == 1) {
490 out_ <<
" compiler::TNode<" 491 << result_types[0]->GetGeneratedTNodeTypeName() <<
"> " 492 << result_name <<
";\n";
494 std::string catch_name =
495 PreCallableExceptionPreparation(instruction.catch_block);
496 Stack<std::string> pre_call_stack = *stack;
497 if (result_types.size() == 1) {
498 stack->Push(result_name);
499 out_ <<
" " << result_name
500 <<
" = TORQUE_CAST(CodeStubAssembler(state_).CallRuntime(Runtime::k" 501 << instruction.runtime_function->ExternalName() <<
", ";
502 PrintCommaSeparatedList(out_, arguments);
504 out_ <<
" USE(" << result_name <<
");\n";
506 DCHECK_EQ(0, result_types.size());
507 out_ <<
" CodeStubAssembler(state_).CallRuntime(Runtime::k" 508 << instruction.runtime_function->ExternalName() <<
", ";
509 PrintCommaSeparatedList(out_, arguments);
511 if (return_type == TypeOracle::GetNeverType()) {
512 out_ <<
" CodeStubAssembler(state_).Unreachable();\n";
514 DCHECK(return_type == TypeOracle::GetVoidType());
517 PostCallableExceptionPreparation(catch_name, return_type,
518 instruction.catch_block, &pre_call_stack);
522 void CSAGenerator::EmitInstruction(
const BranchInstruction& instruction,
523 Stack<std::string>* stack) {
524 out_ <<
" ca_.Branch(" << stack->Pop() <<
", &" 525 << BlockName(instruction.if_true) <<
", &" 526 << BlockName(instruction.if_false);
527 for (
const std::string& value : *stack) {
528 out_ <<
", " << value;
533 void CSAGenerator::EmitInstruction(
534 const ConstexprBranchInstruction& instruction, Stack<std::string>* stack) {
535 out_ <<
" if (" << instruction.condition <<
") {\n";
536 out_ <<
" ca_.Goto(&" << BlockName(instruction.if_true);
537 for (
const std::string& value : *stack) {
538 out_ <<
", " << value;
541 out_ <<
" } else {\n";
542 out_ <<
" ca_.Goto(&" << BlockName(instruction.if_false);
543 for (
const std::string& value : *stack) {
544 out_ <<
", " << value;
551 void CSAGenerator::EmitInstruction(
const GotoInstruction& instruction,
552 Stack<std::string>* stack) {
553 out_ <<
" ca_.Goto(&" << BlockName(instruction.destination);
554 for (
const std::string& value : *stack) {
555 out_ <<
", " << value;
560 void CSAGenerator::EmitInstruction(
const GotoExternalInstruction& instruction,
561 Stack<std::string>* stack) {
562 for (
auto it = instruction.variable_names.rbegin();
563 it != instruction.variable_names.rend(); ++it) {
564 out_ <<
" *" << *it <<
" = " << stack->Pop() <<
";\n";
566 out_ <<
" ca_.Goto(" << instruction.destination <<
");\n";
569 void CSAGenerator::EmitInstruction(
const ReturnInstruction& instruction,
570 Stack<std::string>* stack) {
571 if (*linkage_ == Builtin::kVarArgsJavaScript) {
572 out_ <<
" " << ARGUMENTS_VARIABLE_STRING <<
"->PopAndReturn(";
574 out_ <<
" CodeStubAssembler(state_).Return(";
576 out_ << stack->Pop() <<
");\n";
579 void CSAGenerator::EmitInstruction(
580 const PrintConstantStringInstruction& instruction,
581 Stack<std::string>* stack) {
582 out_ <<
" CodeStubAssembler(state_).Print(" 583 << StringLiteralQuote(instruction.message) <<
");\n";
586 void CSAGenerator::EmitInstruction(
const AbortInstruction& instruction,
587 Stack<std::string>* stack) {
588 switch (instruction.kind) {
589 case AbortInstruction::Kind::kUnreachable:
590 DCHECK(instruction.message.empty());
591 out_ <<
" CodeStubAssembler(state_).Unreachable();\n";
593 case AbortInstruction::Kind::kDebugBreak:
594 DCHECK(instruction.message.empty());
595 out_ <<
" CodeStubAssembler(state_).DebugBreak();\n";
597 case AbortInstruction::Kind::kAssertionFailure: {
599 StringLiteralQuote(SourceFileMap::GetSource(instruction.pos.source));
600 out_ <<
" CodeStubAssembler(state_).FailAssert(" 601 << StringLiteralQuote(instruction.message) <<
", " << file <<
", " 602 << instruction.pos.line + 1 <<
");\n";
608 void CSAGenerator::EmitInstruction(
const UnsafeCastInstruction& instruction,
609 Stack<std::string>* stack) {
610 stack->Poke(stack->AboveTop() - 1,
611 "ca_.UncheckedCast<" +
612 instruction.destination_type->GetGeneratedTNodeTypeName() +
613 ">(" + stack->Top() +
")");
617 void CSAGenerator::EmitCSAValue(VisitResult result,
618 const Stack<std::string>& values,
620 if (!result.IsOnStack()) {
621 out << result.constexpr_value();
622 }
else if (
auto* struct_type = StructType::DynamicCast(result.type())) {
623 out << struct_type->GetGeneratedTypeName() <<
"{";
625 for (
auto& field : struct_type->fields()) {
630 EmitCSAValue(ProjectStructField(result, field.name), values, out);
634 DCHECK_EQ(1, result.stack_range().Size());
635 out <<
"TNode<" << result.type()->GetGeneratedTNodeTypeName() <<
">{" 636 << values.Peek(result.stack_range().begin()) <<
"}";