Skip to content

Commit 2094a7a

Browse files
authored
Merge pull request #656 from scratchcpp/refactor_numeric_string_constant_optimization
Refactor numeric string constant optimization
2 parents d6c16ea + d0d6ca9 commit 2094a7a

15 files changed

+511
-237
lines changed

src/engine/internal/llvm/llvmbuildutils.cpp

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
#include <scratchcpp/list.h>
66
#include <scratchcpp/blockprototype.h>
77
#include <scratchcpp/compiler.h>
8+
#include <scratchcpp/iengine.h>
9+
#include <scratchcpp/costume.h>
810

911
#include "llvmbuildutils.h"
1012
#include "llvmfunctions.h"
@@ -40,6 +42,35 @@ LLVMBuildUtils::LLVMBuildUtils(LLVMCompilerContext *ctx, llvm::IRBuilder<> &buil
4042
initTypes();
4143
createVariableMap();
4244
createListMap();
45+
46+
// Find unsafe numeric string constants in costume and sound names
47+
if (m_target) {
48+
IEngine *engine = m_target->engine();
49+
50+
if (engine) {
51+
auto checkConstant = [this](const std::string &str) {
52+
Value stringValue(str);
53+
Value numberValue(stringValue.toDouble());
54+
55+
if (stringValue.isValidNumber() && str == numberValue.toString())
56+
m_unsafeConstants.insert(str);
57+
};
58+
59+
const auto &targets = engine->targets();
60+
bool found = false;
61+
62+
for (const auto &target : targets) {
63+
const auto &costumes = target->costumes();
64+
const auto &sounds = target->sounds();
65+
66+
for (const auto &costume : costumes)
67+
checkConstant(costume->name());
68+
69+
for (const auto &sound : sounds)
70+
checkConstant(sound->name());
71+
}
72+
}
73+
}
4374
}
4475

4576
void LLVMBuildUtils::init(llvm::Function *function, BlockPrototype *procedurePrototype, bool warp, const std::vector<std::shared_ptr<LLVMRegister>> &regs)
@@ -423,13 +454,20 @@ std::vector<LLVMLoop> &LLVMBuildUtils::loops()
423454
return m_loops;
424455
}
425456

426-
Compiler::StaticType LLVMBuildUtils::optimizeRegisterType(const LLVMRegister *reg)
457+
Compiler::StaticType LLVMBuildUtils::optimizeRegisterType(const LLVMRegister *reg) const
427458
{
428459
Compiler::StaticType ret = reg->type();
429460

430461
// Optimize string constants that represent numbers
431-
if (reg->isConst() && reg->type() == Compiler::StaticType::String && reg->constValue().isValidNumber())
432-
ret = Compiler::StaticType::Number;
462+
if (reg->isConst() && reg->type() == Compiler::StaticType::String) {
463+
const Value &value = reg->constValue();
464+
Value numberValue(value.toDouble());
465+
std::string str = value.toString();
466+
467+
// Apply this optimization only if the number matches the string and the constant is safe
468+
if (value.isValidNumber() && numberValue.toString() == str && m_unsafeConstants.find(str) == m_unsafeConstants.cend())
469+
ret = Compiler::StaticType::Number;
470+
}
433471

434472
return ret;
435473
}

src/engine/internal/llvm/llvmbuildutils.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,8 @@ class LLVMBuildUtils
8282
std::vector<LLVMIfStatement> &ifStatements();
8383
std::vector<LLVMLoop> &loops();
8484

85-
static Compiler::StaticType optimizeRegisterType(const LLVMRegister *reg);
85+
Compiler::StaticType optimizeRegisterType(const LLVMRegister *reg) const;
86+
8687
static Compiler::StaticType mapType(ValueType type);
8788
static ValueType mapType(Compiler::StaticType type);
8889
static bool isSingleType(Compiler::StaticType type);
@@ -173,6 +174,8 @@ class LLVMBuildUtils
173174
bool m_warp = false;
174175
Compiler::CodeType m_codeType = Compiler::CodeType::Script;
175176

177+
std::unordered_set<std::string> m_unsafeConstants;
178+
176179
llvm::Value *m_executionContextPtr = nullptr;
177180
llvm::Value *m_targetPtr = nullptr;
178181
llvm::Value *m_targetVariables = nullptr;

src/engine/internal/llvm/llvmcodeanalyzer.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ static const std::unordered_set<LLVMInstruction::Type> BEGIN_LOOP_INSTRUCTIONS =
1212

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

15+
LLVMCodeAnalyzer::LLVMCodeAnalyzer(const LLVMBuildUtils &utils) :
16+
m_utils(utils)
17+
{
18+
}
19+
1520
void LLVMCodeAnalyzer::analyzeScript(const LLVMInstructionList &script) const
1621
{
1722
std::unordered_set<LLVMInstruction *> typeAssignedInstructions;
@@ -289,5 +294,5 @@ Compiler::StaticType LLVMCodeAnalyzer::writeType(LLVMInstruction *ins) const
289294
}
290295
}
291296

292-
return LLVMBuildUtils::optimizeRegisterType(argReg);
297+
return m_utils.optimizeRegisterType(argReg);
293298
}

src/engine/internal/llvm/llvmcodeanalyzer.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,16 @@
88
namespace libscratchcpp
99
{
1010

11+
class LLVMBuildUtils;
1112
class LLVMInstructionList;
1213
class LLVMInstruction;
1314

1415
class LLVMCodeAnalyzer
1516
{
1617
public:
18+
LLVMCodeAnalyzer(const LLVMBuildUtils &utils);
19+
LLVMCodeAnalyzer(const LLVMCodeAnalyzer &) = delete;
20+
1721
void analyzeScript(const LLVMInstructionList &script) const;
1822

1923
private:
@@ -50,6 +54,8 @@ class LLVMCodeAnalyzer
5054
bool isProcedureCall(const LLVMInstruction *ins) const;
5155

5256
Compiler::StaticType writeType(LLVMInstruction *ins) const;
57+
58+
const LLVMBuildUtils &m_utils;
5359
};
5460

5561
} // namespace libscratchcpp

src/engine/internal/llvm/llvmcodebuilder.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ LLVMCodeBuilder::LLVMCodeBuilder(LLVMCompilerContext *ctx, BlockPrototype *proce
2828
m_module(ctx->module()),
2929
m_builder(m_llvmCtx),
3030
m_utils(ctx, m_builder, codeType),
31+
m_codeAnalyzer(m_utils),
3132
m_procedurePrototype(procedurePrototype),
3233
m_defaultWarp(procedurePrototype ? procedurePrototype->warp() : false),
3334
m_warp(m_defaultWarp),

test/blocks/control_blocks_test.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ using namespace libscratchcpp;
2323
using namespace libscratchcpp::test;
2424

2525
using ::testing::Return;
26+
using ::testing::ReturnRef;
2627
using ::testing::SaveArg;
2728
using ::testing::_;
2829

@@ -35,6 +36,8 @@ class ControlBlocksTest : public testing::Test
3536
m_engine = m_project.engine().get();
3637
m_extension->registerBlocks(m_engine);
3738
registerBlocks(m_engine, m_extension.get());
39+
40+
EXPECT_CALL(m_engineMock, targets()).WillRepeatedly(ReturnRef(m_engine->targets()));
3841
}
3942

4043
std::unique_ptr<IExtension> m_extension;

test/blocks/event_blocks_test.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ using namespace libscratchcpp;
2020
using namespace libscratchcpp::test;
2121

2222
using ::testing::Return;
23+
using ::testing::ReturnRef;
2324

2425
class EventBlocksTest : public testing::Test
2526
{
@@ -29,6 +30,8 @@ class EventBlocksTest : public testing::Test
2930
m_extension = std::make_unique<EventBlocks>();
3031
m_engine = m_project.engine().get();
3132
m_extension->registerBlocks(m_engine);
33+
34+
EXPECT_CALL(m_engineMock, targets()).WillRepeatedly(ReturnRef(m_engine->targets()));
3235
}
3336

3437
std::unique_ptr<IExtension> m_extension;

test/blocks/looks_blocks_test.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ using namespace libscratchcpp;
2323
using namespace libscratchcpp::test;
2424

2525
using ::testing::Return;
26+
using ::testing::ReturnRef;
2627
using ::testing::ReturnArg;
2728
using ::testing::_;
2829

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

40+
EXPECT_CALL(m_engineMock, targets()).WillRepeatedly(ReturnRef(m_engine->targets()));
41+
3942
// Create and register fake graphic effects
4043
auto colorEffect = std::make_shared<GraphicsEffectMock>();
4144
auto fisheyeEffect = std::make_shared<GraphicsEffectMock>();

test/blocks/motion_blocks_test.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ using namespace libscratchcpp;
2020
using namespace libscratchcpp::test;
2121

2222
using ::testing::Return;
23+
using ::testing::ReturnRef;
2324

2425
class MotionBlocksTest : public testing::Test
2526
{
@@ -29,6 +30,8 @@ class MotionBlocksTest : public testing::Test
2930
m_extension = std::make_unique<MotionBlocks>();
3031
m_engine = m_project.engine().get();
3132
m_extension->registerBlocks(m_engine);
33+
34+
EXPECT_CALL(m_engineMock, targets()).WillRepeatedly(ReturnRef(m_engine->targets()));
3235
}
3336

3437
std::unique_ptr<IExtension> m_extension;

test/blocks/sensing_blocks_test.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ class SensingBlocksTest : public testing::Test
4747
EXPECT_CALL(m_audioInput, audioLoudness()).WillRepeatedly(Return(m_audioLoudness));
4848

4949
SensingBlocks::clock = &m_clock;
50+
51+
EXPECT_CALL(m_engineMock, targets()).WillRepeatedly(ReturnRef(m_engine->targets()));
5052
}
5153

5254
void TearDown() override

0 commit comments

Comments
 (0)