Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 2 additions & 2 deletions include/scratchcpp/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ class LIBSCRATCHCPP_EXPORT Compiler
using Args = std::vector<CompilerValue *>;

Compiler(CompilerContext *ctx);
Compiler(IEngine *engine, Target *target);
Compiler(IEngine *engine, Target *target, const std::unordered_set<std::string> &unsafeConstants = {});
Compiler(const Compiler &) = delete;

IEngine *engine() const;
Expand Down Expand Up @@ -164,7 +164,7 @@ class LIBSCRATCHCPP_EXPORT Compiler

const std::unordered_set<std::string> &unsupportedBlocks() const;

static std::shared_ptr<CompilerContext> createContext(IEngine *engine, Target *target);
static std::shared_ptr<CompilerContext> createContext(IEngine *engine, Target *target, const std::unordered_set<std::string> &unsafeConstants);

private:
spimpl::unique_impl_ptr<CompilerPrivate> impl;
Expand Down
6 changes: 5 additions & 1 deletion include/scratchcpp/compilercontext.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

#pragma once

#include <unordered_set>

#include "global.h"
#include "spimpl.h"

Expand All @@ -16,13 +18,15 @@ class CompilerContextPrivate;
class LIBSCRATCHCPP_EXPORT CompilerContext
{
public:
CompilerContext(IEngine *engine, Target *target);
CompilerContext(IEngine *engine, Target *target, const std::unordered_set<std::string> &unsafeConstants = {});
CompilerContext(const CompilerContext &) = delete;
virtual ~CompilerContext() { }

IEngine *engine() const;
Target *target() const;

const std::unordered_set<std::string> &unsafeConstants() const;

/*!
* Optimizes compiled scripts ahead of time.
* \see Compiler#preoptimize()
Expand Down
6 changes: 1 addition & 5 deletions src/engine/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,6 @@ target_sources(scratchcpp
thread_p.h
internal/engine.cpp
internal/engine.h
internal/icodebuilder.h
internal/icodebuilderfactory.h
internal/codebuilderfactory.cpp
internal/codebuilderfactory.h
internal/clock.cpp
internal/clock.h
internal/iclock.h
Expand All @@ -44,4 +40,4 @@ target_sources(scratchcpp
internal/randomgenerator.cpp
)

add_subdirectory(internal/llvm)
add_subdirectory(internal/codegen)
12 changes: 6 additions & 6 deletions src/engine/compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
#include <scratchcpp/inputvalue.h>

#include "compiler_p.h"
#include "internal/icodebuilderfactory.h"
#include "internal/icodebuilder.h"
#include "internal/codegen/icodebuilderfactory.h"
#include "internal/codegen/icodebuilder.h"

using namespace libscratchcpp;

Expand All @@ -20,8 +20,8 @@ Compiler::Compiler(CompilerContext *ctx) :
}

/*! Constructs Compiler using a new context for the given target. */
Compiler::Compiler(IEngine *engine, Target *target) :
impl(spimpl::make_unique_impl<CompilerPrivate>(engine, target))
Compiler::Compiler(IEngine *engine, Target *target, const std::unordered_set<std::string> &unsafeConstants) :
impl(spimpl::make_unique_impl<CompilerPrivate>(engine, target, unsafeConstants))
{
}

Expand Down Expand Up @@ -751,8 +751,8 @@ const std::unordered_set<std::string> &Compiler::unsupportedBlocks() const
}

/*! Creates a compiler context for the given target. */
std::shared_ptr<CompilerContext> Compiler::createContext(IEngine *engine, Target *target)
std::shared_ptr<CompilerContext> Compiler::createContext(IEngine *engine, Target *target, const std::unordered_set<std::string> &unsafeConstants)
{
CompilerPrivate::initBuilderFactory();
return CompilerPrivate::builderFactory()->createCtx(engine, target);
return CompilerPrivate::builderFactory()->createCtx(engine, target, unsafeConstants);
}
8 changes: 4 additions & 4 deletions src/engine/compiler_p.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@

#include "compiler_p.h"

#include "internal/codebuilderfactory.h"
#include "internal/icodebuilder.h"
#include "internal/codegen/codebuilderfactory.h"
#include "internal/codegen/icodebuilder.h"

using namespace libscratchcpp;

Expand All @@ -17,8 +17,8 @@ CompilerPrivate::CompilerPrivate(CompilerContext *ctx) :
initBuilderFactory();
}

CompilerPrivate::CompilerPrivate(IEngine *engine, Target *target) :
ctxPtr(Compiler::createContext(engine, target)),
CompilerPrivate::CompilerPrivate(IEngine *engine, Target *target, const std::unordered_set<std::string> &unsafeConstants) :
ctxPtr(Compiler::createContext(engine, target, unsafeConstants)),
ctx(ctxPtr.get())
{
initBuilderFactory();
Expand Down
2 changes: 1 addition & 1 deletion src/engine/compiler_p.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class LIBSCRATCHCPP_TEST_EXPORT CompilerPrivate
};

CompilerPrivate(CompilerContext *ctx);
CompilerPrivate(IEngine *engine, Target *target);
CompilerPrivate(IEngine *engine, Target *target, const std::unordered_set<std::string> &unsafeConstants);

static void initBuilderFactory();

Expand Down
10 changes: 8 additions & 2 deletions src/engine/compilercontext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
using namespace libscratchcpp;

/*! Constructs CompilerContext. */
CompilerContext::CompilerContext(IEngine *engine, Target *target) :
impl(spimpl::make_unique_impl<CompilerContextPrivate>(engine, target))
CompilerContext::CompilerContext(IEngine *engine, Target *target, const std::unordered_set<std::string> &unsafeConstants) :
impl(spimpl::make_unique_impl<CompilerContextPrivate>(engine, target, unsafeConstants))
{
}

Expand All @@ -23,3 +23,9 @@ Target *CompilerContext::target() const
{
return impl->target;
}

/*! Returns the list of unsafe constants (used internally during optimization). */
const std::unordered_set<std::string> &CompilerContext::unsafeConstants() const
{
return impl->unsafeConstants;
}
5 changes: 3 additions & 2 deletions src/engine/compilercontext_p.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@

using namespace libscratchcpp;

CompilerContextPrivate::CompilerContextPrivate(IEngine *engine, Target *target) :
CompilerContextPrivate::CompilerContextPrivate(IEngine *engine, Target *target, const std::unordered_set<std::string> &unsafeConstants) :
engine(engine),
target(target)
target(target),
unsafeConstants(unsafeConstants)
{
}
6 changes: 5 additions & 1 deletion src/engine/compilercontext_p.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

#pragma once

#include <unordered_set>
#include <string>

namespace libscratchcpp
{

Expand All @@ -10,10 +13,11 @@ class Target;

struct CompilerContextPrivate
{
CompilerContextPrivate(IEngine *engine, Target *target);
CompilerContextPrivate(IEngine *engine, Target *target, const std::unordered_set<std::string> &unsafeConstants);

IEngine *engine = nullptr;
Target *target = nullptr;
const std::unordered_set<std::string> unsafeConstants;
};

} // namespace libscratchcpp
18 changes: 18 additions & 0 deletions src/engine/internal/codegen/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
target_sources(scratchcpp
PRIVATE
icodebuilder.h
icodebuilderfactory.h
codebuilderfactory.cpp
codebuilderfactory.h
instructionbase.h
instruction.h
instructionlistbase.cpp
instructionlistbase.h
instructionlist.h
codeanalyzer.cpp
codeanalyzer.h
optimizationutils.cpp
optimizationutils.h
)

add_subdirectory(llvm)
Original file line number Diff line number Diff line change
@@ -1,27 +1,29 @@
// SPDX-License-Identifier: Apache-2.0

#include "llvmcodeanalyzer.h"
#include "llvminstructionlist.h"
#include "llvminstruction.h"
#include "llvmbuildutils.h"
#include <scratchcpp/compilervalue.h>

#include "codeanalyzer.h"
#include "instructionlistbase.h"
#include "instructionbase.h"
#include "optimizationutils.h"

using namespace libscratchcpp;

// NOTE: The loop condition in repeat until and while loops is considered a part of the loop body
static const std::unordered_set<LLVMInstruction::Type> BEGIN_LOOP_INSTRUCTIONS = { LLVMInstruction::Type::BeginRepeatLoop, LLVMInstruction::Type::BeginLoopCondition };
static const std::unordered_set<InstructionBase::Type> BEGIN_LOOP_INSTRUCTIONS = { InstructionBase::Type::BeginRepeatLoop, InstructionBase::Type::BeginLoopCondition };

static const std::unordered_set<LLVMInstruction::Type> LIST_WRITE_INSTRUCTIONS = { LLVMInstruction::Type::AppendToList, LLVMInstruction::Type::InsertToList, LLVMInstruction::Type::ListReplace };
static const std::unordered_set<InstructionBase::Type> LIST_WRITE_INSTRUCTIONS = { InstructionBase::Type::AppendToList, InstructionBase::Type::InsertToList, InstructionBase::Type::ListReplace };

LLVMCodeAnalyzer::LLVMCodeAnalyzer(const LLVMBuildUtils &utils) :
m_utils(utils)
CodeAnalyzer::CodeAnalyzer(CompilerContext *ctx) :
m_ctx(ctx)
{
}

void LLVMCodeAnalyzer::analyzeScript(const LLVMInstructionList &script) const
void CodeAnalyzer::analyzeScript(const InstructionListBase &script) const
{
std::unordered_set<LLVMInstruction *> typeAssignedInstructions;
std::unordered_set<InstructionBase *> typeAssignedInstructions;
std::vector<std::unique_ptr<Branch>> branches;
LLVMInstruction *ins = script.first();
InstructionBase *ins = script.first();

auto topBranch = std::make_unique<Branch>();
topBranch->start = ins;
Expand Down Expand Up @@ -155,7 +157,7 @@ void LLVMCodeAnalyzer::analyzeScript(const LLVMInstructionList &script) const
assert(branches.back().get() == topBranchPtr);
}

void LLVMCodeAnalyzer::updateVariableType(Branch *branch, LLVMInstruction *ins, std::unordered_set<LLVMInstruction *> &typeAssignedInstructions, bool isWrite) const
void CodeAnalyzer::updateVariableType(Branch *branch, InstructionBase *ins, std::unordered_set<InstructionBase *> &typeAssignedInstructions, bool isWrite) const
{
auto it = branch->variableTypes.find(ins->targetVariable);

Expand All @@ -182,7 +184,7 @@ void LLVMCodeAnalyzer::updateVariableType(Branch *branch, LLVMInstruction *ins,
}
}

void LLVMCodeAnalyzer::updateListType(Branch *branch, LLVMInstruction *ins, std::unordered_set<LLVMInstruction *> &typeAssignedInstructions, bool isWrite) const
void CodeAnalyzer::updateListType(Branch *branch, InstructionBase *ins, std::unordered_set<InstructionBase *> &typeAssignedInstructions, bool isWrite) const
{
auto it = branch->listTypes.find(ins->targetList);

Expand Down Expand Up @@ -211,7 +213,7 @@ void LLVMCodeAnalyzer::updateListType(Branch *branch, LLVMInstruction *ins, std:
}
}

void LLVMCodeAnalyzer::mergeVariableTypes(Branch *branch, Branch *previousBranch) const
void CodeAnalyzer::mergeVariableTypes(Branch *branch, Branch *previousBranch) const
{
for (const auto &[var, type] : branch->variableTypes) {
auto it = previousBranch->variableTypes.find(var);
Expand All @@ -223,13 +225,13 @@ void LLVMCodeAnalyzer::mergeVariableTypes(Branch *branch, Branch *previousBranch
}
}

void LLVMCodeAnalyzer::overrideVariableTypes(Branch *branch, Branch *previousBranch) const
void CodeAnalyzer::overrideVariableTypes(Branch *branch, Branch *previousBranch) const
{
for (const auto &[var, type] : branch->variableTypes)
previousBranch->variableTypes[var] = type;
}

void LLVMCodeAnalyzer::mergeListTypes(Branch *branch, Branch *previousBranch, bool firstUnknown) const
void CodeAnalyzer::mergeListTypes(Branch *branch, Branch *previousBranch, bool firstUnknown) const
{
for (const auto &[list, type] : branch->listTypes) {
auto it = previousBranch->listTypes.find(list);
Expand All @@ -241,69 +243,69 @@ void LLVMCodeAnalyzer::mergeListTypes(Branch *branch, Branch *previousBranch, bo
}
}

bool LLVMCodeAnalyzer::isLoopStart(const LLVMInstruction *ins) const
bool CodeAnalyzer::isLoopStart(const InstructionBase *ins) const
{
return (BEGIN_LOOP_INSTRUCTIONS.find(ins->type) != BEGIN_LOOP_INSTRUCTIONS.cend());
}

bool LLVMCodeAnalyzer::isLoopEnd(const LLVMInstruction *ins) const
bool CodeAnalyzer::isLoopEnd(const InstructionBase *ins) const
{
return (ins->type == LLVMInstruction::Type::EndLoop);
return (ins->type == InstructionBase::Type::EndLoop);
}

bool LLVMCodeAnalyzer::isIfStart(const LLVMInstruction *ins) const
bool CodeAnalyzer::isIfStart(const InstructionBase *ins) const
{
return (ins->type == LLVMInstruction::Type::BeginIf);
return (ins->type == InstructionBase::Type::BeginIf);
}

bool LLVMCodeAnalyzer::isElse(const LLVMInstruction *ins) const
bool CodeAnalyzer::isElse(const InstructionBase *ins) const
{
return (ins->type == LLVMInstruction::Type::BeginElse);
return (ins->type == InstructionBase::Type::BeginElse);
}

bool LLVMCodeAnalyzer::isIfEnd(const LLVMInstruction *ins) const
bool CodeAnalyzer::isIfEnd(const InstructionBase *ins) const
{
return (ins->type == LLVMInstruction::Type::EndIf);
return (ins->type == InstructionBase::Type::EndIf);
}

bool LLVMCodeAnalyzer::isVariableRead(const LLVMInstruction *ins) const
bool CodeAnalyzer::isVariableRead(const InstructionBase *ins) const
{
return (ins->type == LLVMInstruction::Type::ReadVariable);
return (ins->type == InstructionBase::Type::ReadVariable);
}

bool LLVMCodeAnalyzer::isVariableWrite(const LLVMInstruction *ins) const
bool CodeAnalyzer::isVariableWrite(const InstructionBase *ins) const
{
return (ins->type == LLVMInstruction::Type::WriteVariable);
return (ins->type == InstructionBase::Type::WriteVariable);
}

bool LLVMCodeAnalyzer::isListRead(const LLVMInstruction *ins) const
bool CodeAnalyzer::isListRead(const InstructionBase *ins) const
{
return (ins->type == LLVMInstruction::Type::GetListItem);
return (ins->type == InstructionBase::Type::GetListItem);
}

bool LLVMCodeAnalyzer::isListWrite(const LLVMInstruction *ins) const
bool CodeAnalyzer::isListWrite(const InstructionBase *ins) const
{
return (LIST_WRITE_INSTRUCTIONS.find(ins->type) != LIST_WRITE_INSTRUCTIONS.cend());
}

bool LLVMCodeAnalyzer::isListClear(const LLVMInstruction *ins) const
bool CodeAnalyzer::isListClear(const InstructionBase *ins) const
{
return (ins->type == LLVMInstruction::Type::ClearList);
return (ins->type == InstructionBase::Type::ClearList);
}

bool LLVMCodeAnalyzer::isProcedureCall(const LLVMInstruction *ins) const
bool CodeAnalyzer::isProcedureCall(const InstructionBase *ins) const
{
return (ins->type == LLVMInstruction::Type::CallProcedure);
return (ins->type == InstructionBase::Type::CallProcedure);
}

Compiler::StaticType LLVMCodeAnalyzer::writeType(LLVMInstruction *ins) const
Compiler::StaticType CodeAnalyzer::writeType(InstructionBase *ins) const
{
assert(ins);
assert(!ins->args.empty());
auto &arg = ins->args.back(); // value is always the last argument in variable/list write instructions
const LLVMRegister *argReg = arg.second;
const CompilerValue *argValue = arg.second;

Compiler::StaticType ret = m_utils.optimizeRegisterType(argReg);
Compiler::StaticType ret = OptimizationUtils::optimizeValueType(m_ctx, argValue);
arg.first = ret; // store the return type in the value argument
return ret;
}
Loading
Loading