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
44 changes: 41 additions & 3 deletions src/engine/internal/llvm/llvmbuildutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
#include <scratchcpp/list.h>
#include <scratchcpp/blockprototype.h>
#include <scratchcpp/compiler.h>
#include <scratchcpp/iengine.h>
#include <scratchcpp/costume.h>

#include "llvmbuildutils.h"
#include "llvmfunctions.h"
Expand Down Expand Up @@ -39,6 +41,35 @@ LLVMBuildUtils::LLVMBuildUtils(LLVMCompilerContext *ctx, llvm::IRBuilder<> &buil
initTypes();
createVariableMap();
createListMap();

// Find unsafe numeric string constants in costume and sound names
if (m_target) {
IEngine *engine = m_target->engine();

if (engine) {
auto checkConstant = [this](const std::string &str) {
Value stringValue(str);
Value numberValue(stringValue.toDouble());

if (stringValue.isValidNumber() && str == numberValue.toString())
m_unsafeConstants.insert(str);
};

const auto &targets = engine->targets();
bool found = false;

for (const auto &target : targets) {
const auto &costumes = target->costumes();
const auto &sounds = target->sounds();

for (const auto &costume : costumes)
checkConstant(costume->name());

for (const auto &sound : sounds)
checkConstant(sound->name());
}
}
}
}

void LLVMBuildUtils::init(llvm::Function *function, BlockPrototype *procedurePrototype, bool warp, const std::vector<std::shared_ptr<LLVMRegister>> &regs)
Expand Down Expand Up @@ -429,13 +460,20 @@ std::vector<LLVMLoop> &LLVMBuildUtils::loops()
return m_loops;
}

Compiler::StaticType LLVMBuildUtils::optimizeRegisterType(const LLVMRegister *reg)
Compiler::StaticType LLVMBuildUtils::optimizeRegisterType(const LLVMRegister *reg) const
{
Compiler::StaticType ret = reg->type();

// Optimize string constants that represent numbers
if (reg->isConst() && reg->type() == Compiler::StaticType::String && reg->constValue().isValidNumber())
ret = Compiler::StaticType::Number;
if (reg->isConst() && reg->type() == Compiler::StaticType::String) {
const Value &value = reg->constValue();
Value numberValue(value.toDouble());
std::string str = value.toString();

// Apply this optimization only if the number matches the string and the constant is safe
if (value.isValidNumber() && numberValue.toString() == str && m_unsafeConstants.find(str) == m_unsafeConstants.cend())
ret = Compiler::StaticType::Number;
}

return ret;
}
Expand Down
5 changes: 4 additions & 1 deletion src/engine/internal/llvm/llvmbuildutils.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,8 @@ class LLVMBuildUtils
std::vector<LLVMIfStatement> &ifStatements();
std::vector<LLVMLoop> &loops();

static Compiler::StaticType optimizeRegisterType(const LLVMRegister *reg);
Compiler::StaticType optimizeRegisterType(const LLVMRegister *reg) const;

static Compiler::StaticType mapType(ValueType type);
static ValueType mapType(Compiler::StaticType type);
static bool isSingleType(Compiler::StaticType type);
Expand Down Expand Up @@ -161,6 +162,8 @@ class LLVMBuildUtils
bool m_warp = false;
Compiler::CodeType m_codeType = Compiler::CodeType::Script;

std::unordered_set<std::string> m_unsafeConstants;

llvm::Value *m_executionContextPtr = nullptr;
llvm::Value *m_targetPtr = nullptr;
llvm::Value *m_targetVariables = nullptr;
Expand Down
7 changes: 6 additions & 1 deletion src/engine/internal/llvm/llvmcodeanalyzer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ static const std::unordered_set<LLVMInstruction::Type> BEGIN_LOOP_INSTRUCTIONS =

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

LLVMCodeAnalyzer::LLVMCodeAnalyzer(const LLVMBuildUtils &utils) :
m_utils(utils)
{
}

void LLVMCodeAnalyzer::analyzeScript(const LLVMInstructionList &script) const
{
std::unordered_set<LLVMInstruction *> typeAssignedInstructions;
Expand Down Expand Up @@ -289,5 +294,5 @@ Compiler::StaticType LLVMCodeAnalyzer::writeType(LLVMInstruction *ins) const
}
}

return LLVMBuildUtils::optimizeRegisterType(argReg);
return m_utils.optimizeRegisterType(argReg);
}
6 changes: 6 additions & 0 deletions src/engine/internal/llvm/llvmcodeanalyzer.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,16 @@
namespace libscratchcpp
{

class LLVMBuildUtils;
class LLVMInstructionList;
class LLVMInstruction;

class LLVMCodeAnalyzer
{
public:
LLVMCodeAnalyzer(const LLVMBuildUtils &utils);
LLVMCodeAnalyzer(const LLVMCodeAnalyzer &) = delete;

void analyzeScript(const LLVMInstructionList &script) const;

private:
Expand Down Expand Up @@ -50,6 +54,8 @@ class LLVMCodeAnalyzer
bool isProcedureCall(const LLVMInstruction *ins) const;

Compiler::StaticType writeType(LLVMInstruction *ins) const;

const LLVMBuildUtils &m_utils;
};

} // namespace libscratchcpp
1 change: 1 addition & 0 deletions src/engine/internal/llvm/llvmcodebuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ LLVMCodeBuilder::LLVMCodeBuilder(LLVMCompilerContext *ctx, BlockPrototype *proce
m_module(ctx->module()),
m_builder(m_llvmCtx),
m_utils(ctx, m_builder, codeType),
m_codeAnalyzer(m_utils),
m_procedurePrototype(procedurePrototype),
m_defaultWarp(procedurePrototype ? procedurePrototype->warp() : false),
m_warp(m_defaultWarp),
Expand Down
3 changes: 3 additions & 0 deletions test/blocks/control_blocks_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ using namespace libscratchcpp;
using namespace libscratchcpp::test;

using ::testing::Return;
using ::testing::ReturnRef;
using ::testing::SaveArg;
using ::testing::_;

Expand All @@ -35,6 +36,8 @@ class ControlBlocksTest : public testing::Test
m_engine = m_project.engine().get();
m_extension->registerBlocks(m_engine);
registerBlocks(m_engine, m_extension.get());

EXPECT_CALL(m_engineMock, targets()).WillRepeatedly(ReturnRef(m_engine->targets()));
}

std::unique_ptr<IExtension> m_extension;
Expand Down
3 changes: 3 additions & 0 deletions test/blocks/event_blocks_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ using namespace libscratchcpp;
using namespace libscratchcpp::test;

using ::testing::Return;
using ::testing::ReturnRef;

class EventBlocksTest : public testing::Test
{
Expand All @@ -29,6 +30,8 @@ class EventBlocksTest : public testing::Test
m_extension = std::make_unique<EventBlocks>();
m_engine = m_project.engine().get();
m_extension->registerBlocks(m_engine);

EXPECT_CALL(m_engineMock, targets()).WillRepeatedly(ReturnRef(m_engine->targets()));
}

std::unique_ptr<IExtension> m_extension;
Expand Down
3 changes: 3 additions & 0 deletions test/blocks/looks_blocks_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ using namespace libscratchcpp;
using namespace libscratchcpp::test;

using ::testing::Return;
using ::testing::ReturnRef;
using ::testing::ReturnArg;
using ::testing::_;

Expand All @@ -36,6 +37,8 @@ class LooksBlocksTest : public testing::Test
m_extension->registerBlocks(m_engine);
m_extension->onInit(m_engine);

EXPECT_CALL(m_engineMock, targets()).WillRepeatedly(ReturnRef(m_engine->targets()));

// Create and register fake graphic effects
auto colorEffect = std::make_shared<GraphicsEffectMock>();
auto fisheyeEffect = std::make_shared<GraphicsEffectMock>();
Expand Down
3 changes: 3 additions & 0 deletions test/blocks/motion_blocks_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ using namespace libscratchcpp;
using namespace libscratchcpp::test;

using ::testing::Return;
using ::testing::ReturnRef;

class MotionBlocksTest : public testing::Test
{
Expand All @@ -29,6 +30,8 @@ class MotionBlocksTest : public testing::Test
m_extension = std::make_unique<MotionBlocks>();
m_engine = m_project.engine().get();
m_extension->registerBlocks(m_engine);

EXPECT_CALL(m_engineMock, targets()).WillRepeatedly(ReturnRef(m_engine->targets()));
}

std::unique_ptr<IExtension> m_extension;
Expand Down
2 changes: 2 additions & 0 deletions test/blocks/sensing_blocks_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ class SensingBlocksTest : public testing::Test
EXPECT_CALL(m_audioInput, audioLoudness()).WillRepeatedly(Return(m_audioLoudness));

SensingBlocks::clock = &m_clock;

EXPECT_CALL(m_engineMock, targets()).WillRepeatedly(ReturnRef(m_engine->targets()));
}

void TearDown() override
Expand Down
Loading