Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
1c67ddc
Store variables on the stack in warp scripts
adazem009 Aug 17, 2025
a2e4ee1
Enable ValueType bitmasking
adazem009 Aug 17, 2025
269e011
Store list types locally in warp scripts
adazem009 Aug 17, 2025
00b98b9
Variable & list optimizations
adazem009 Aug 18, 2025
0a06c6c
Optimize list type info
adazem009 Aug 18, 2025
f116437
Use PHI node in get list item instruction
adazem009 Aug 18, 2025
c848360
Fix new type in list type update
adazem009 Aug 19, 2025
01006dc
Optimize list index range check
adazem009 Aug 19, 2025
e5f03c3
Optimize list type update
adazem009 Aug 19, 2025
878dfe0
Do not assume appendEmpty() returns numbers
adazem009 Aug 19, 2025
13f7fae
LLVMBuildUtils: Add missing checks for runtime list info
adazem009 Aug 19, 2025
492ccb0
Fix list insert index range check
adazem009 Aug 19, 2025
a47a612
Clean up Lists::getIndex()
adazem009 Aug 19, 2025
04c305a
Rewrite list type assumptions
adazem009 Aug 19, 2025
cdfacf7
Restore list replace type assumption
adazem009 Aug 19, 2025
6b7770b
Add expectations for list index in range branches
adazem009 Aug 20, 2025
e505c20
Refactor LLVM optimization pipeline
adazem009 Aug 20, 2025
8e43154
Fix delete this clone stopping behavior
adazem009 Aug 20, 2025
386559c
Add stop without sync instruction
adazem009 Aug 20, 2025
478a8dd
Compiler: Add createStopWithoutSync() method
adazem009 Aug 20, 2025
bb27299
Do not synchronize stopped scripts after delete this clone block
adazem009 Aug 20, 2025
1acbafe
LLVMCoroutine: Fix uninitialized local in resume
adazem009 Aug 20, 2025
8e42c38
LLVMCodeBuilder: Fix a typo in code analyzer comment
adazem009 Aug 20, 2025
6173c34
Compiler: Update docs for add function call methods
adazem009 Aug 20, 2025
4521382
Add initial LLVM integer value support
adazem009 Aug 25, 2025
78f993b
Use ValueData struct for local variables
adazem009 Aug 25, 2025
f28ddd4
Add integer support for local variables
adazem009 Aug 25, 2025
5cf8bfd
Add integer support to control instructions
adazem009 Aug 25, 2025
54c7f07
Add integer support to math instructions
adazem009 Aug 26, 2025
a84e99b
Make LLVM integer support optional
adazem009 Aug 26, 2025
27b7a03
Disable optional optimizations in minimal unit tests
adazem009 Aug 26, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/utests-minimal.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
submodules: true

- name: Configure CMake
run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DLIBSCRATCHCPP_BUILD_UNIT_TESTS=ON -DLIBSCRATCHCPP_ENABLE_SANITIZER=ON -DLIBSCRATCHCPP_AUDIO_SUPPORT=OFF -DLIBSCRATCHCPP_NETWORK_SUPPORT=OFF
run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DLIBSCRATCHCPP_BUILD_UNIT_TESTS=ON -DLIBSCRATCHCPP_ENABLE_SANITIZER=ON -DLIBSCRATCHCPP_AUDIO_SUPPORT=OFF -DLIBSCRATCHCPP_NETWORK_SUPPORT=OFF -DLIBSCRATCHCPP_ENABLE_CODE_ANALYZER=OFF -DLIBSCRATCHCPP_LLVM_INTEGER_SUPPORT=OFF

- name: Build
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} -j$(nproc --all)
Expand Down
5 changes: 5 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ option(LIBSCRATCHCPP_BUILD_UNIT_TESTS "Build unit tests" ON)
option(LIBSCRATCHCPP_NETWORK_SUPPORT "Support for downloading projects" ON)
option(LIBSCRATCHCPP_PRINT_LLVM_IR "Print LLVM IR of compiled Scratch scripts (for debugging)" OFF)
option(LIBSCRATCHCPP_ENABLE_CODE_ANALYZER "Analyze Scratch scripts to enable various optimizations" ON)
option(LIBSCRATCHCPP_LLVM_INTEGER_SUPPORT "Use integers when possible to enable various optimizations" ON)
option(LIBSCRATCHCPP_ENABLE_SANITIZER "Enable sanitizer to detect memory issues" OFF)

if (LIBSCRATCHCPP_ENABLE_SANITIZER)
Expand Down Expand Up @@ -126,6 +127,10 @@ if(LIBSCRATCHCPP_ENABLE_CODE_ANALYZER)
target_compile_definitions(scratchcpp PRIVATE ENABLE_CODE_ANALYZER)
endif()

if(LIBSCRATCHCPP_LLVM_INTEGER_SUPPORT)
target_compile_definitions(scratchcpp PRIVATE LLVM_INTEGER_SUPPORT)
endif()

# Macros
target_compile_definitions(scratchcpp PRIVATE LIBSCRATCHCPP_LIBRARY)
target_compile_definitions(scratchcpp PRIVATE LIBSCRATCHCPP_VERSION="${PROJECT_VERSION}")
Expand Down
1 change: 1 addition & 0 deletions include/scratchcpp/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ class LIBSCRATCHCPP_EXPORT Compiler

void createYield();
void createStop();
void createStopWithoutSync();

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

Expand Down
12 changes: 8 additions & 4 deletions include/scratchcpp/valuedata.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <string>

#include "global.h"
#include "enum_bitmask.h"

namespace libscratchcpp
{
Expand All @@ -13,12 +14,15 @@ struct StringPtr;

enum class LIBSCRATCHCPP_EXPORT ValueType
{
Number = 0,
Bool = 1,
String = 2,
Pointer = 3
Void = 0,
Number = 1 << 0,
Bool = 1 << 1,
String = 1 << 2,
Pointer = 1 << 3
};

constexpr bool enable_enum_bitmask(ValueType);

extern "C"
{
/*! \brief The ValueData struct holds the data of Value. It's used in compiled Scratch code for better performance. */
Expand Down
18 changes: 14 additions & 4 deletions src/blocks/controlblocks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,10 @@ CompilerValue *ControlBlocks::compileCreateCloneOf(Compiler *compiler)

CompilerValue *ControlBlocks::compileDeleteThisClone(Compiler *compiler)
{
compiler->addTargetFunctionCall("control_delete_this_clone");
CompilerValue *deleted = compiler->addTargetFunctionCall("control_delete_this_clone", Compiler::StaticType::Bool);
compiler->beginIfStatement(deleted);
compiler->createStopWithoutSync(); // sync happens before the function call
compiler->endIf();
return nullptr;
}

Expand Down Expand Up @@ -234,10 +237,17 @@ extern "C" void control_create_clone(ExecutionContext *ctx, const StringPtr *spr
}
}

extern "C" void control_delete_this_clone(Target *target)
extern "C" bool control_delete_this_clone(Target *target)
{
if (!target->isStage()) {
target->engine()->stopTarget(target, nullptr);
static_cast<Sprite *>(target)->deleteClone();
Sprite *sprite = static_cast<Sprite *>(target);

if (sprite->isClone()) {
target->engine()->stopTarget(target, nullptr);
sprite->deleteClone();
return true;
}
}

return false;
}
16 changes: 13 additions & 3 deletions src/engine/compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ void Compiler::preoptimize()

/*!
* Adds a call to the given function.\n
* For example: extern "C" bool some_block(double arg1, const char *arg2)
* For example: extern "C" bool some_block(double arg1, const StringPtr *arg2)
*/
CompilerValue *Compiler::addFunctionCall(const std::string &functionName, StaticType returnType, const ArgTypes &argTypes, const Args &args)
{
Expand All @@ -146,7 +146,7 @@ CompilerValue *Compiler::addFunctionCall(const std::string &functionName, Static

/*!
* Adds a call to the given function with a target parameter.\n
* For example: extern "C" bool some_block(Target *target, double arg1, const char *arg2)
* For example: extern "C" bool some_block(Target *target, double arg1, const StringPtr *arg2)
*/
CompilerValue *Compiler::addTargetFunctionCall(const std::string &functionName, StaticType returnType, const ArgTypes &argTypes, const Args &args)
{
Expand All @@ -156,7 +156,7 @@ CompilerValue *Compiler::addTargetFunctionCall(const std::string &functionName,

/*!
* Adds a call to the given function with an execution context parameter.\n
* For example: extern "C" bool some_block(ExecutionContext *ctx, double arg1, const char *arg2)
* For example: extern "C" bool some_block(ExecutionContext *ctx, double arg1, const StringPtr *arg2)
*/
CompilerValue *Compiler::addFunctionCallWithCtx(const std::string &functionName, StaticType returnType, const ArgTypes &argTypes, const Args &args)
{
Expand Down Expand Up @@ -705,6 +705,16 @@ void Compiler::createStop()
impl->builder->createStop();
}

/*!
* Creates a stop script without synchronization instruction.\n
* Use this if synchronization is not possible at the stop point.
* \note Only use this when everything is synchronized, e. g. after a function call.
*/
void Compiler::createStopWithoutSync()
{
impl->builder->createStopWithoutSync();
}

/*! Creates a call to the procedure with the given prototype. */
void Compiler::createProcedureCall(BlockPrototype *prototype, const libscratchcpp::Compiler::Args &args)
{
Expand Down
1 change: 1 addition & 0 deletions src/engine/internal/icodebuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ class ICodeBuilder
virtual void yield() = 0;

virtual void createStop() = 0;
virtual void createStopWithoutSync() = 0;

virtual void createProcedureCall(BlockPrototype *prototype, const Compiler::Args &args) = 0;
};
Expand Down
1 change: 1 addition & 0 deletions src/engine/internal/llvm/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ target_sources(scratchcpp
llvmloop.h
llvmcoroutine.cpp
llvmcoroutine.h
llvmlocalvariableinfo.h
llvmvariableptr.h
llvmlistptr.h
llvmtypes.cpp
Expand Down
14 changes: 14 additions & 0 deletions src/engine/internal/llvm/instructions/control.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ ProcessResult Control::process(LLVMInstruction *ins)
ret.next = buildStop(ins);
break;

case LLVMInstruction::Type::StopWithoutSync:
ret.next = buildStopWithoutSync(ins);
break;

default:
ret.match = false;
break;
Expand Down Expand Up @@ -88,6 +92,8 @@ LLVMInstruction *Control::buildSelect(LLVMInstruction *ins)
}

ins->functionReturnReg->value = m_builder.CreateSelect(cond, trueValue, falseValue);
ins->functionReturnReg->isInt = m_builder.CreateSelect(cond, arg2.second->isInt, arg3.second->isInt);
ins->functionReturnReg->intValue = m_builder.CreateSelect(cond, arg2.second->intValue, arg3.second->intValue);
return ins->next;
}

Expand Down Expand Up @@ -241,6 +247,8 @@ LLVMInstruction *Control::buildLoopIndex(LLVMInstruction *ins)
LLVMLoop &loop = m_utils.loops().back();
llvm::Value *index = m_builder.CreateLoad(m_builder.getInt64Ty(), loop.index);
ins->functionReturnReg->value = m_builder.CreateUIToFP(index, m_builder.getDoubleTy());
ins->functionReturnReg->intValue = index;
ins->functionReturnReg->isInt = m_builder.getInt1(true);

return ins->next;
}
Expand Down Expand Up @@ -336,6 +344,12 @@ LLVMInstruction *Control::buildEndLoop(LLVMInstruction *ins)
}

LLVMInstruction *Control::buildStop(LLVMInstruction *ins)
{
m_utils.syncVariables();
return buildStopWithoutSync(ins);
}

LLVMInstruction *Control::buildStopWithoutSync(LLVMInstruction *ins)
{
m_utils.freeScopeHeap();
m_builder.CreateBr(m_utils.endBranch());
Expand Down
1 change: 1 addition & 0 deletions src/engine/internal/llvm/instructions/control.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ class Control : public InstructionGroup
LLVMInstruction *buildBeginLoopCondition(LLVMInstruction *ins);
LLVMInstruction *buildEndLoop(LLVMInstruction *ins);
LLVMInstruction *buildStop(LLVMInstruction *ins);
LLVMInstruction *buildStopWithoutSync(LLVMInstruction *ins);
};

} // namespace libscratchcpp::llvmins
2 changes: 1 addition & 1 deletion src/engine/internal/llvm/instructions/functions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ LLVMInstruction *Functions::buildFunctionCall(LLVMInstruction *ins)
std::vector<llvm::Value *> args;

// Variables must be synchronized because the function can read them
m_utils.syncVariables(m_utils.targetVariables());
m_utils.syncVariables();

// Add execution context arg
if (ins->functionCtxArg) {
Expand Down
13 changes: 11 additions & 2 deletions src/engine/internal/llvm/instructions/instructionbuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,14 @@
#include "variables.h"
#include "lists.h"
#include "procedures.h"
#include "../llvminstruction.h"
#include "../llvmbuildutils.h"

using namespace libscratchcpp;
using namespace libscratchcpp::llvmins;

InstructionBuilder::InstructionBuilder(LLVMBuildUtils &utils)
InstructionBuilder::InstructionBuilder(LLVMBuildUtils &utils) :
m_utils(utils)
{
// Create groups
m_groups.push_back(std::make_shared<Functions>(utils));
Expand All @@ -34,8 +37,14 @@ LLVMInstruction *InstructionBuilder::process(LLVMInstruction *ins)
for (const auto &group : m_groups) {
ProcessResult result = group->process(ins);

if (result.match)
if (result.match) {
#ifndef LLVM_INTEGER_SUPPORT
if (ins->functionReturnReg)
ins->functionReturnReg->isInt = m_utils.builder().getInt1(false);
#endif

return result.next;
}
}

assert(false); // instruction not found
Expand Down
1 change: 1 addition & 0 deletions src/engine/internal/llvm/instructions/instructionbuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ class InstructionBuilder
LLVMInstruction *process(LLVMInstruction *ins);

private:
LLVMBuildUtils &m_utils;
std::vector<std::shared_ptr<InstructionGroup>> m_groups;
};

Expand Down
Loading