Skip to content

Commit d80df92

Browse files
committed
Add stop thread LLVM instruction
1 parent 5c402bb commit d80df92

File tree

14 files changed

+244
-21
lines changed

14 files changed

+244
-21
lines changed

src/engine/internal/icodebuilder.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ class ICodeBuilder
9999
virtual void yield() = 0;
100100

101101
virtual void createStop() = 0;
102+
virtual void createThreadStop() = 0;
102103
virtual void createStopWithoutSync() = 0;
103104

104105
virtual void createProcedureCall(BlockPrototype *prototype, const Compiler::Args &args) = 0;

src/engine/internal/llvm/instructions/control.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,10 @@ ProcessResult Control::process(LLVMInstruction *ins)
6060
ret.next = buildStop(ins);
6161
break;
6262

63+
case LLVMInstruction::Type::ThreadStop:
64+
ret.next = buildThreadStop(ins);
65+
break;
66+
6367
case LLVMInstruction::Type::StopWithoutSync:
6468
ret.next = buildStopWithoutSync(ins);
6569
break;
@@ -340,6 +344,17 @@ LLVMInstruction *Control::buildStop(LLVMInstruction *ins)
340344
return buildStopWithoutSync(ins);
341345
}
342346

347+
LLVMInstruction *Control::buildThreadStop(LLVMInstruction *ins)
348+
{
349+
m_utils.syncVariables();
350+
m_builder.CreateBr(m_utils.endThreadBranch());
351+
352+
llvm::BasicBlock *nextBranch = llvm::BasicBlock::Create(m_utils.llvmCtx(), "", m_utils.function());
353+
m_builder.SetInsertPoint(nextBranch);
354+
355+
return ins->next;
356+
}
357+
343358
LLVMInstruction *Control::buildStopWithoutSync(LLVMInstruction *ins)
344359
{
345360
m_builder.CreateBr(m_utils.endBranch());

src/engine/internal/llvm/instructions/control.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ class Control : public InstructionGroup
2727
LLVMInstruction *buildBeginLoopCondition(LLVMInstruction *ins);
2828
LLVMInstruction *buildEndLoop(LLVMInstruction *ins);
2929
LLVMInstruction *buildStop(LLVMInstruction *ins);
30+
LLVMInstruction *buildThreadStop(LLVMInstruction *ins);
3031
LLVMInstruction *buildStopWithoutSync(LLVMInstruction *ins);
3132
};
3233

src/engine/internal/llvm/instructions/procedures.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,17 @@ LLVMInstruction *Procedures::buildCallProcedure(LLVMInstruction *ins)
6666
args.push_back(m_utils.createValue(arg.second));
6767
}
6868

69+
// Call the procedure
6970
llvm::Value *handle = m_builder.CreateCall(m_utils.functions().resolveFunction(name, type), args);
7071

72+
// Check for end thread sentinel value
73+
llvm::BasicBlock *nextBranch = llvm::BasicBlock::Create(llvmCtx, "", function);
74+
llvm::Value *endThread = m_builder.CreateICmpEQ(handle, m_utils.threadEndSentinel());
75+
m_builder.CreateCondBr(endThread, m_utils.endThreadBranch(), nextBranch);
76+
m_builder.SetInsertPoint(nextBranch);
77+
7178
if (!m_utils.warp() && !ins->procedurePrototype->warp()) {
79+
// Handle suspend
7280
llvm::BasicBlock *suspendBranch = llvm::BasicBlock::Create(llvmCtx, "", function);
7381
llvm::BasicBlock *nextBranch = llvm::BasicBlock::Create(llvmCtx, "", function);
7482
m_builder.CreateCondBr(m_builder.CreateIsNull(handle), nextBranch, suspendBranch);

src/engine/internal/llvm/llvmbuildutils.cpp

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -161,8 +161,9 @@ void LLVMBuildUtils::init(llvm::Function *function, BlockPrototype *procedurePro
161161
reloadVariables();
162162
reloadLists();
163163

164-
// Create end branch
164+
// Create end branches
165165
m_endBranch = llvm::BasicBlock::Create(m_llvmCtx, "end", m_function);
166+
m_endThreadBranch = llvm::BasicBlock::Create(m_llvmCtx, "endThread", m_function);
166167
}
167168

168169
void LLVMBuildUtils::end(LLVMInstruction *lastInstruction, LLVMRegister *lastConstant)
@@ -184,9 +185,9 @@ void LLVMBuildUtils::end(LLVMInstruction *lastInstruction, LLVMRegister *lastCon
184185
syncVariables();
185186
m_builder.CreateBr(m_endBranch);
186187

188+
// End branch
187189
m_builder.SetInsertPoint(m_endBranch);
188190

189-
// End the script function
190191
llvm::PointerType *pointerType = llvm::PointerType::get(llvm::Type::getInt8Ty(m_llvmCtx), 0);
191192

192193
switch (m_codeType) {
@@ -216,6 +217,31 @@ void LLVMBuildUtils::end(LLVMInstruction *lastInstruction, LLVMRegister *lastCon
216217
m_builder.CreateRet(castValue(lastConstant, Compiler::StaticType::Bool));
217218
break;
218219
}
220+
221+
// Thread end branch (stop the entire thread, including procedure callers)
222+
m_builder.SetInsertPoint(m_endThreadBranch);
223+
224+
switch (m_codeType) {
225+
case Compiler::CodeType::Script:
226+
// Return a sentinel value (special pointer) to terminate any procedure callers
227+
if (m_warp)
228+
m_builder.CreateRet(threadEndSentinel());
229+
else if (m_procedurePrototype)
230+
m_coroutine->endWithSentinel(threadEndSentinel());
231+
else {
232+
// There's no need to return the sentinel value in standard scripts because they don't have any callers
233+
m_coroutine->endWithSentinel(threadEndSentinel());
234+
// m_coroutine->end();
235+
}
236+
237+
break;
238+
239+
case Compiler::CodeType::Reporter:
240+
case Compiler::CodeType::HatPredicate:
241+
// Procedures cannot be called by these scripts, so we don't have to return the sentinel value
242+
m_builder.CreateBr(m_endBranch);
243+
break;
244+
}
219245
}
220246

221247
LLVMCompilerContext *LLVMBuildUtils::compilerCtx() const
@@ -323,6 +349,17 @@ llvm::BasicBlock *LLVMBuildUtils::endBranch() const
323349
return m_endBranch;
324350
}
325351

352+
llvm::BasicBlock *LLVMBuildUtils::endThreadBranch() const
353+
{
354+
return m_endThreadBranch;
355+
}
356+
357+
llvm::Value *LLVMBuildUtils::threadEndSentinel() const
358+
{
359+
llvm::PointerType *pointerType = llvm::PointerType::get(llvm::Type::getInt8Ty(m_llvmCtx), 0);
360+
return m_builder.CreateIntToPtr(m_builder.getInt64(1), pointerType, "threadEndSentinel");
361+
}
362+
326363
BlockPrototype *LLVMBuildUtils::procedurePrototype() const
327364
{
328365
return m_procedurePrototype;

src/engine/internal/llvm/llvmbuildutils.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@ class LIBSCRATCHCPP_TEST_EXPORT LLVMBuildUtils
5656
size_t stringCount() const;
5757

5858
llvm::BasicBlock *endBranch() const;
59+
llvm::BasicBlock *endThreadBranch() const;
60+
61+
llvm::Value *threadEndSentinel() const;
5962

6063
BlockPrototype *procedurePrototype() const;
6164
bool warp() const;
@@ -166,6 +169,7 @@ class LIBSCRATCHCPP_TEST_EXPORT LLVMBuildUtils
166169
llvm::Value *m_functionIdValue = nullptr;
167170

168171
llvm::BasicBlock *m_endBranch = nullptr;
172+
llvm::BasicBlock *m_endThreadBranch = nullptr;
169173

170174
llvm::StructType *m_valueDataType = nullptr;
171175
llvm::StructType *m_stringPtrType = nullptr;

src/engine/internal/llvm/llvmcodebuilder.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -567,6 +567,12 @@ void LLVMCodeBuilder::createStop()
567567
m_instructions.addInstruction(ins);
568568
}
569569

570+
void LLVMCodeBuilder::createThreadStop()
571+
{
572+
auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ThreadStop, m_loopCondition);
573+
m_instructions.addInstruction(ins);
574+
}
575+
570576
void LLVMCodeBuilder::createStopWithoutSync()
571577
{
572578
auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::StopWithoutSync, m_loopCondition);

src/engine/internal/llvm/llvmcodebuilder.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ class LIBSCRATCHCPP_TEST_EXPORT LLVMCodeBuilder : public ICodeBuilder
113113
void yield() override;
114114

115115
void createStop() override;
116+
void createThreadStop() override;
116117
void createStopWithoutSync() override;
117118

118119
void createProcedureCall(BlockPrototype *prototype, const Compiler::Args &args) override;

src/engine/internal/llvm/llvmcoroutine.cpp

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -35,15 +35,23 @@ LLVMCoroutine::LLVMCoroutine(llvm::Module *module, llvm::IRBuilder<> *builder, l
3535

3636
// Begin
3737
m_handle = builder->CreateCall(coroBegin, { coroIdRet, alloc });
38+
3839
m_didSuspendVar = builder->CreateAlloca(builder->getInt1Ty(), nullptr, "didSuspend");
3940
builder->CreateStore(builder->getInt1(false), m_didSuspendVar);
41+
42+
m_sentinelVar = builder->CreateAlloca(pointerType, nullptr, "sentinel");
43+
builder->CreateStore(nullPointer, m_sentinelVar);
44+
4045
llvm::BasicBlock *entry = builder->GetInsertBlock();
4146

4247
// Create suspend branch
4348
m_suspendBlock = llvm::BasicBlock::Create(ctx, "suspend", func);
4449
builder->SetInsertPoint(m_suspendBlock);
50+
51+
llvm::Value *sentinelValue = builder->CreateLoad(pointerType, m_sentinelVar);
52+
llvm::Value *sentinelIsNull = builder->CreateIsNull(sentinelValue);
4553
builder->CreateCall(coroEnd, { m_handle, builder->getInt1(false), llvm::ConstantTokenNone::get(ctx) });
46-
builder->CreateRet(m_handle);
54+
builder->CreateRet(builder->CreateSelect(sentinelIsNull, m_handle, sentinelValue));
4755

4856
// Create free branches
4957
m_freeMemRetBlock = llvm::BasicBlock::Create(ctx, "freeMemRet", func);
@@ -63,6 +71,15 @@ LLVMCoroutine::LLVMCoroutine(llvm::Module *module, llvm::IRBuilder<> *builder, l
6371
llvm::Value *needFree = builder->CreateIsNotNull(mem);
6472
builder->CreateCondBr(needFree, freeBranch, m_suspendBlock);
6573

74+
// Create final suspend point
75+
m_finalSuspendBlock = llvm::BasicBlock::Create(ctx, "finalSuspend", m_function);
76+
77+
m_builder->SetInsertPoint(m_finalSuspendBlock);
78+
llvm::Value *suspendResult = m_builder->CreateCall(llvm::Intrinsic::getDeclaration(m_module, llvm::Intrinsic::coro_suspend), { llvm::ConstantTokenNone::get(ctx), m_builder->getInt1(true) });
79+
llvm::SwitchInst *sw = m_builder->CreateSwitch(suspendResult, m_suspendBlock, 2);
80+
sw->addCase(m_builder->getInt8(0), m_freeMemRetBlock);
81+
sw->addCase(m_builder->getInt8(1), m_cleanupBlock);
82+
6683
builder->SetInsertPoint(entry);
6784
}
6885

@@ -135,20 +152,11 @@ llvm::Value *LLVMCoroutine::createResume(llvm::Module *module, llvm::IRBuilder<>
135152

136153
void LLVMCoroutine::end()
137154
{
138-
llvm::LLVMContext &ctx = m_builder->getContext();
139-
140-
// Add final suspend point
141-
llvm::BasicBlock *endBranch = llvm::BasicBlock::Create(ctx, "end", m_function);
142-
llvm::BasicBlock *finalSuspendBranch = llvm::BasicBlock::Create(ctx, "finalSuspend", m_function);
143-
m_builder->CreateCondBr(m_builder->CreateLoad(m_builder->getInt1Ty(), m_didSuspendVar), finalSuspendBranch, endBranch);
144-
145-
m_builder->SetInsertPoint(finalSuspendBranch);
146-
llvm::Value *suspendResult = m_builder->CreateCall(llvm::Intrinsic::getDeclaration(m_module, llvm::Intrinsic::coro_suspend), { llvm::ConstantTokenNone::get(ctx), m_builder->getInt1(true) });
147-
llvm::SwitchInst *sw = m_builder->CreateSwitch(suspendResult, m_suspendBlock, 2);
148-
sw->addCase(m_builder->getInt8(0), endBranch); // unreachable
149-
sw->addCase(m_builder->getInt8(1), m_cleanupBlock);
155+
m_builder->CreateCondBr(m_builder->CreateLoad(m_builder->getInt1Ty(), m_didSuspendVar), m_finalSuspendBlock, m_freeMemRetBlock);
156+
}
150157

151-
// Jump to "free and return" branch
152-
m_builder->SetInsertPoint(endBranch);
153-
m_builder->CreateBr(m_freeMemRetBlock);
158+
void LLVMCoroutine::endWithSentinel(llvm::Value *sentinel)
159+
{
160+
m_builder->CreateStore(sentinel, m_sentinelVar);
161+
end();
154162
}

src/engine/internal/llvm/llvmcoroutine.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,16 +24,19 @@ class LLVMCoroutine
2424
void createSuspend();
2525
static llvm::Value *createResume(llvm::Module *module, llvm::IRBuilder<> *builder, llvm::Function *function, llvm::Value *coroHandle);
2626
void end();
27+
void endWithSentinel(llvm::Value *sentinel);
2728

2829
private:
2930
llvm::Module *m_module = nullptr;
3031
llvm::IRBuilder<> *m_builder = nullptr;
3132
llvm::Function *m_function = nullptr;
3233
llvm::Value *m_handle = nullptr;
3334
llvm::BasicBlock *m_suspendBlock = nullptr;
35+
llvm::BasicBlock *m_finalSuspendBlock = nullptr;
3436
llvm::BasicBlock *m_cleanupBlock = nullptr;
3537
llvm::BasicBlock *m_freeMemRetBlock = nullptr;
3638
llvm::Value *m_didSuspendVar = nullptr;
39+
llvm::Value *m_sentinelVar = nullptr;
3740
};
3841

3942
} // namespace libscratchcpp

0 commit comments

Comments
 (0)