Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LLVM: Implement list blocks #612

Merged
merged 20 commits into from
Dec 29, 2024
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
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ if (LIBSCRATCHCPP_USE_LLVM)
include/scratchcpp/dev/compiler.h
include/scratchcpp/dev/compilervalue.h
include/scratchcpp/dev/compilerconstant.h
include/scratchcpp/dev/compilerlocalvariable.h
include/scratchcpp/dev/executablecode.h
include/scratchcpp/dev/executioncontext.h
include/scratchcpp/dev/promise.h
Expand Down
6 changes: 6 additions & 0 deletions include/scratchcpp/dev/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ class Target;
class ExecutableCode;
class CompilerValue;
class CompilerConstant;
class CompilerLocalVariable;
class Variable;
class List;
class Input;
Expand Down Expand Up @@ -52,6 +53,7 @@ class LIBSCRATCHCPP_EXPORT Compiler
CompilerValue *addFunctionCallWithCtx(const std::string &functionName, StaticType returnType = StaticType::Void, const ArgTypes &argTypes = {}, const Args &args = {});
CompilerConstant *addConstValue(const Value &value);
CompilerValue *addLoopIndex();
CompilerValue *addLocalVariableValue(CompilerLocalVariable *variable);
CompilerValue *addVariableValue(Variable *variable);
CompilerValue *addListContents(List *list);
CompilerValue *addListItem(List *list, CompilerValue *index);
Expand All @@ -66,6 +68,7 @@ class LIBSCRATCHCPP_EXPORT Compiler
CompilerValue *createDiv(CompilerValue *operand1, CompilerValue *operand2);

CompilerValue *createRandom(CompilerValue *from, CompilerValue *to);
CompilerValue *createRandomInt(CompilerValue *from, CompilerValue *to);

CompilerValue *createCmpEQ(CompilerValue *operand1, CompilerValue *operand2);
CompilerValue *createCmpGT(CompilerValue *operand1, CompilerValue *operand2);
Expand Down Expand Up @@ -94,6 +97,9 @@ class LIBSCRATCHCPP_EXPORT Compiler

CompilerValue *createSelect(CompilerValue *cond, CompilerValue *trueValue, CompilerValue *falseValue, Compiler::StaticType valueType);

CompilerLocalVariable *createLocalVariable(Compiler::StaticType type);
void createLocalVariableWrite(CompilerLocalVariable *variable, CompilerValue *value);

void createVariableWrite(Variable *variable, CompilerValue *value);

void createListClear(List *list);
Expand Down
26 changes: 26 additions & 0 deletions include/scratchcpp/dev/compilerlocalvariable.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// SPDX-License-Identifier: Apache-2.0

#pragma once

#include "compiler.h"

namespace libscratchcpp
{

class CompilerLocalVariablePrivate;

/*! \brief The CompilerLocalVariable class represents a statically typed local variable in compiled code. */
class LIBSCRATCHCPP_EXPORT CompilerLocalVariable
{
public:
CompilerLocalVariable(CompilerValue *ptr);
CompilerLocalVariable(const CompilerLocalVariable &) = delete;

CompilerValue *ptr() const;
Compiler::StaticType type() const;

private:
spimpl::unique_impl_ptr<CompilerLocalVariablePrivate> impl;
};

} // namespace libscratchcpp
2 changes: 1 addition & 1 deletion include/scratchcpp/dev/test/scriptbuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ class LIBSCRATCHCPP_EXPORT ScriptBuilder
~ScriptBuilder();

void addBlock(const std::string &opcode);
void addReporterBlock(const std::string &opcode);
void captureBlockReturnValue();

void addValueInput(const std::string &name, const Value &value);
Expand All @@ -47,6 +46,7 @@ class LIBSCRATCHCPP_EXPORT ScriptBuilder
void addEntityField(const std::string &name, std::shared_ptr<Entity> entity);

std::shared_ptr<Block> currentBlock();
std::shared_ptr<Block> takeBlock();

void build();
void run();
Expand Down
193 changes: 193 additions & 0 deletions src/dev/blocks/listblocks.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
// SPDX-License-Identifier: Apache-2.0

#include <scratchcpp/iengine.h>
#include <scratchcpp/dev/compiler.h>
#include <scratchcpp/dev/compilerconstant.h>
#include <scratchcpp/field.h>
#include <scratchcpp/list.h>

#include "listblocks.h"

using namespace libscratchcpp;
Expand All @@ -16,4 +22,191 @@ std::string ListBlocks::description() const

void ListBlocks::registerBlocks(IEngine *engine)
{
engine->addCompileFunction(this, "data_addtolist", &compileAddToList);
engine->addCompileFunction(this, "data_deleteoflist", &compileDeleteOfList);
engine->addCompileFunction(this, "data_deletealloflist", &compileDeleteAllOfList);
engine->addCompileFunction(this, "data_insertatlist", &compileInsertAtList);
engine->addCompileFunction(this, "data_replaceitemoflist", &compileReplaceItemOfList);
engine->addCompileFunction(this, "data_itemoflist", &compileItemOfList);
engine->addCompileFunction(this, "data_itemnumoflist", &compileItemNumOfList);
engine->addCompileFunction(this, "data_lengthoflist", &compileLengthOfList);
engine->addCompileFunction(this, "data_listcontainsitem", &compileListContainsItem);
}

CompilerValue *ListBlocks::compileAddToList(Compiler *compiler)
{
auto list = compiler->field("LIST")->valuePtr();
assert(list);

if (list)
compiler->createListAppend(static_cast<List *>(list.get()), compiler->addInput("ITEM"));

return nullptr;
}

CompilerValue *ListBlocks::getListIndex(Compiler *compiler, CompilerValue *input, List *list, CompilerValue *listSize)
{
CompilerLocalVariable *ret = compiler->createLocalVariable(Compiler::StaticType::Number);

CompilerValue *isRandom1 = compiler->createCmpEQ(input, compiler->addConstValue("random"));
CompilerValue *isRandom2 = compiler->createCmpEQ(input, compiler->addConstValue("any"));
CompilerValue *isRandom = compiler->createOr(isRandom1, isRandom2);

compiler->beginIfStatement(isRandom);
{
CompilerValue *random = compiler->createRandomInt(compiler->addConstValue(1), listSize);
compiler->createLocalVariableWrite(ret, random);
}
compiler->beginElseBranch();
{
CompilerValue *isLast = compiler->createCmpEQ(input, compiler->addConstValue("last"));
compiler->createLocalVariableWrite(ret, compiler->createSelect(isLast, listSize, input, Compiler::StaticType::Number));
}
compiler->endIf();

return compiler->addLocalVariableValue(ret);
}

CompilerValue *ListBlocks::compileDeleteOfList(Compiler *compiler)
{
List *list = static_cast<List *>(compiler->field("LIST")->valuePtr().get());
assert(list);

if (list) {
CompilerValue *index = compiler->addInput("INDEX");
CompilerValue *cond = compiler->createCmpEQ(index, compiler->addConstValue("all"));
compiler->beginIfStatement(cond);
{
compiler->createListClear(list);
}
compiler->beginElseBranch();
{
CompilerValue *min = compiler->addConstValue(-1);
CompilerValue *max = compiler->addListSize(list);
index = getListIndex(compiler, index, list, max);
index = compiler->createSub(index, compiler->addConstValue(1));
cond = compiler->createAnd(compiler->createCmpGT(index, min), compiler->createCmpLT(index, max));
compiler->beginIfStatement(cond);
{
compiler->createListRemove(list, index);
}
compiler->endIf();
}
compiler->endIf();
}

return nullptr;
}

CompilerValue *ListBlocks::compileDeleteAllOfList(Compiler *compiler)
{
auto list = compiler->field("LIST")->valuePtr();
assert(list);

if (list)
compiler->createListClear(static_cast<List *>(list.get()));

return nullptr;
}

CompilerValue *ListBlocks::compileInsertAtList(Compiler *compiler)
{
List *list = static_cast<List *>(compiler->field("LIST")->valuePtr().get());
assert(list);

if (list) {
CompilerValue *index = compiler->addInput("INDEX");
CompilerValue *min = compiler->addConstValue(-1);
CompilerValue *max = compiler->createAdd(compiler->addListSize(list), compiler->addConstValue(1));
index = getListIndex(compiler, index, list, max);
index = compiler->createSub(index, compiler->addConstValue(1));
CompilerValue *cond = compiler->createAnd(compiler->createCmpGT(index, min), compiler->createCmpLT(index, max));
compiler->beginIfStatement(cond);
{
CompilerValue *item = compiler->addInput("ITEM");
compiler->createListInsert(list, index, item);
}
compiler->endIf();
}

return nullptr;
}

CompilerValue *ListBlocks::compileReplaceItemOfList(Compiler *compiler)
{
List *list = static_cast<List *>(compiler->field("LIST")->valuePtr().get());
assert(list);

if (list) {
CompilerValue *index = compiler->addInput("INDEX");
CompilerValue *min = compiler->addConstValue(-1);
CompilerValue *max = compiler->addListSize(list);
index = getListIndex(compiler, index, list, max);
index = compiler->createSub(index, compiler->addConstValue(1));
CompilerValue *cond = compiler->createAnd(compiler->createCmpGT(index, min), compiler->createCmpLT(index, max));
compiler->beginIfStatement(cond);
{
CompilerValue *item = compiler->addInput("ITEM");
compiler->createListReplace(list, index, item);
}
compiler->endIf();
}

return nullptr;
}

CompilerValue *ListBlocks::compileItemOfList(Compiler *compiler)
{
List *list = static_cast<List *>(compiler->field("LIST")->valuePtr().get());
assert(list);

if (list) {
CompilerValue *index = compiler->addInput("INDEX");
CompilerValue *min = compiler->addConstValue(-1);
CompilerValue *max = compiler->addListSize(list);
index = getListIndex(compiler, index, list, max);
index = compiler->createSub(index, compiler->addConstValue(1));
CompilerValue *cond = compiler->createAnd(compiler->createCmpGT(index, min), compiler->createCmpLT(index, max));
CompilerValue *item = compiler->addListItem(list, index);
return compiler->createSelect(cond, item, compiler->addConstValue(Value()), Compiler::StaticType::Unknown);
}

return nullptr;
}

CompilerValue *ListBlocks::compileItemNumOfList(Compiler *compiler)
{
List *list = static_cast<List *>(compiler->field("LIST")->valuePtr().get());
assert(list);

if (list) {
CompilerValue *item = compiler->addInput("ITEM");
return compiler->createAdd(compiler->addListItemIndex(list, item), compiler->addConstValue(1));
}

return nullptr;
}

CompilerValue *ListBlocks::compileLengthOfList(Compiler *compiler)
{
List *list = static_cast<List *>(compiler->field("LIST")->valuePtr().get());
assert(list);

if (list)
return compiler->addListSize(list);

return nullptr;
}

CompilerValue *ListBlocks::compileListContainsItem(Compiler *compiler)
{
List *list = static_cast<List *>(compiler->field("LIST")->valuePtr().get());
assert(list);

if (list) {
CompilerValue *item = compiler->addInput("ITEM");
return compiler->addListContains(list, item);
}

return nullptr;
}
14 changes: 14 additions & 0 deletions src/dev/blocks/listblocks.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,27 @@
namespace libscratchcpp
{

class List;

class ListBlocks : public IExtension
{
public:
std::string name() const override;
std::string description() const override;

void registerBlocks(IEngine *engine) override;

private:
static CompilerValue *compileAddToList(Compiler *compiler);
static CompilerValue *getListIndex(Compiler *compiler, CompilerValue *input, List *list, CompilerValue *listSize);
static CompilerValue *compileDeleteOfList(Compiler *compiler);
static CompilerValue *compileDeleteAllOfList(Compiler *compiler);
static CompilerValue *compileInsertAtList(Compiler *compiler);
static CompilerValue *compileReplaceItemOfList(Compiler *compiler);
static CompilerValue *compileItemOfList(Compiler *compiler);
static CompilerValue *compileItemNumOfList(Compiler *compiler);
static CompilerValue *compileLengthOfList(Compiler *compiler);
static CompilerValue *compileListContainsItem(Compiler *compiler);
};

} // namespace libscratchcpp
3 changes: 3 additions & 0 deletions src/dev/engine/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ target_sources(scratchcpp
compilerconstant.cpp
compilerconstant_p.cpp
compilerconstant_p.h
compilerlocalvariable.cpp
compilerlocalvariable_p.cpp
compilerlocalvariable_p.h
executioncontext.cpp
executioncontext_p.cpp
executioncontext_p.h
Expand Down
27 changes: 27 additions & 0 deletions src/dev/engine/compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,12 @@ CompilerValue *Compiler::addLoopIndex()
return impl->builder->addLoopIndex();
}

/*! Adds the value of the given local variable to the code. */
CompilerValue *Compiler::addLocalVariableValue(CompilerLocalVariable *variable)
{
return impl->builder->addLocalVariableValue(variable);
}

/*! Adds the value of the given variable to the code. */
CompilerValue *Compiler::addVariableValue(Variable *variable)
{
Expand Down Expand Up @@ -199,6 +205,15 @@ CompilerValue *Compiler::createRandom(CompilerValue *from, CompilerValue *to)
return impl->builder->createRandom(from, to);
}

/*!
* Creates a random integer instruction.
* \note Infinity or NaN results in undefined behavior.
*/
CompilerValue *Compiler::createRandomInt(CompilerValue *from, CompilerValue *to)
{
return impl->builder->createRandomInt(from, to);
}

/*! Creates an equality comparison instruction. */
CompilerValue *Compiler::createCmpEQ(CompilerValue *operand1, CompilerValue *operand2)
{
Expand Down Expand Up @@ -337,6 +352,18 @@ CompilerValue *Compiler::createSelect(CompilerValue *cond, CompilerValue *trueVa
return impl->builder->createSelect(cond, trueValue, falseValue, valueType);
}

/*! Creates a local variable with the given type. */
CompilerLocalVariable *Compiler::createLocalVariable(StaticType type)
{
return impl->builder->createLocalVariable(type);
}

/*! Creates a local variable write operation. */
void Compiler::createLocalVariableWrite(CompilerLocalVariable *variable, CompilerValue *value)
{
impl->builder->createLocalVariableWrite(variable, value);
}

/*! Creates a variable write operation. */
void Compiler::createVariableWrite(Variable *variable, CompilerValue *value)
{
Expand Down
23 changes: 23 additions & 0 deletions src/dev/engine/compilerlocalvariable.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// SPDX-License-Identifier: Apache-2.0

#include <scratchcpp/dev/compilerlocalvariable.h>
#include <scratchcpp/dev/compilervalue.h>

#include "compilerlocalvariable_p.h"

using namespace libscratchcpp;

CompilerLocalVariable::CompilerLocalVariable(CompilerValue *ptr) :
impl(spimpl::make_unique_impl<CompilerLocalVariablePrivate>(ptr))
{
}

CompilerValue *CompilerLocalVariable::ptr() const
{
return impl->ptr;
}

Compiler::StaticType CompilerLocalVariable::type() const
{
return impl->ptr->type();
}
Loading
Loading