-
Notifications
You must be signed in to change notification settings - Fork 7
Expand file tree
/
Copy pathprocedures.cpp
More file actions
113 lines (87 loc) · 3.98 KB
/
procedures.cpp
File metadata and controls
113 lines (87 loc) · 3.98 KB
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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
// SPDX-License-Identifier: Apache-2.0
#include <scratchcpp/blockprototype.h>
#include "procedures.h"
#include "../llvminstruction.h"
#include "../llvmbuildutils.h"
#include "../llvmcompilercontext.h"
using namespace libscratchcpp;
using namespace libscratchcpp::llvmins;
ProcessResult Procedures::process(LLVMInstruction *ins)
{
ProcessResult ret(true, ins);
switch (ins->type) {
case LLVMInstruction::Type::CallProcedure:
ret.next = buildCallProcedure(ins);
break;
case LLVMInstruction::Type::ProcedureArg:
ret.next = buildProcedureArg(ins);
break;
default:
ret.match = false;
break;
}
return ret;
}
LLVMInstruction *Procedures::buildCallProcedure(LLVMInstruction *ins)
{
llvm::LLVMContext &llvmCtx = m_utils.llvmCtx();
llvm::Function *function = m_utils.function();
assert(ins->procedurePrototype);
assert(ins->args.size() == ins->procedurePrototype->argumentTypes().size());
m_utils.syncVariables();
std::string name = m_utils.scriptFunctionName(ins->procedurePrototype);
llvm::FunctionType *type = m_utils.scriptFunctionType(ins->procedurePrototype);
std::vector<llvm::Value *> args;
m_utils.compilerCtx()->addUsedProcedure(ins->procedurePrototype, name);
llvm::FunctionType *funcType = m_utils.scriptFunctionType(nullptr);
int passArgCount = funcType->getNumParams();
for (size_t i = 0; i < passArgCount; i++)
args.push_back(function->getArg(i));
// Add warp arg
if (m_utils.warp())
args.push_back(m_builder.getInt1(true));
else
args.push_back(m_utils.procedurePrototype() ? m_utils.warpArg() : m_builder.getInt1(false));
// Add procedure args
for (const auto &arg : ins->args) {
if (m_utils.isSingleType(arg.first))
args.push_back(m_utils.castValue(arg.second, arg.first));
else
args.push_back(m_utils.createValue(arg.second));
}
// Call the procedure
llvm::Value *handle = m_builder.CreateCall(m_utils.functions().resolveFunction(name, type), args);
// Check for end thread sentinel value
llvm::BasicBlock *nextBranch = llvm::BasicBlock::Create(llvmCtx, "", function);
llvm::Value *endThread = m_builder.CreateICmpEQ(handle, m_utils.threadEndSentinel());
m_builder.CreateCondBr(endThread, m_utils.endThreadBranch(), nextBranch);
m_builder.SetInsertPoint(nextBranch);
if (!m_utils.warp() && !ins->procedurePrototype->warp()) {
// Handle suspend
llvm::BasicBlock *suspendBranch = llvm::BasicBlock::Create(llvmCtx, "", function);
llvm::BasicBlock *nextBranch = llvm::BasicBlock::Create(llvmCtx, "", function);
m_builder.CreateCondBr(m_builder.CreateIsNull(handle), nextBranch, suspendBranch);
m_builder.SetInsertPoint(suspendBranch);
m_utils.createSuspend();
llvm::Value *done = m_builder.CreateCall(m_utils.compilerCtx()->coroutineResumeFunction(), { handle });
m_builder.CreateCondBr(done, nextBranch, suspendBranch);
m_builder.SetInsertPoint(nextBranch);
// The thread could be stopped from the coroutine
llvm::BasicBlock *afterResumeBranch = llvm::BasicBlock::Create(llvmCtx, "", function);
llvm::Value *isFinished = m_builder.CreateCall(m_utils.functions().resolve_llvm_is_thread_finished(), m_utils.executionContextPtr());
m_builder.CreateCondBr(isFinished, m_utils.endThreadBranch(), afterResumeBranch);
m_builder.SetInsertPoint(afterResumeBranch);
}
m_utils.reloadVariables();
m_utils.reloadLists();
return ins->next;
}
LLVMInstruction *Procedures::buildProcedureArg(LLVMInstruction *ins)
{
assert(m_utils.procedurePrototype());
llvm::FunctionType *funcType = m_utils.scriptFunctionType(nullptr);
int passArgCount = funcType->getNumParams();
llvm::Value *arg = m_utils.function()->getArg(passArgCount + 1 + ins->procedureArgIndex); // omit warp arg
ins->functionReturnReg->value = arg;
return ins->next;
}