Skip to content

Commit 8d82978

Browse files
committed
Move code analyzer out from llvm
1 parent d356a80 commit 8d82978

14 files changed

Lines changed: 1054 additions & 1112 deletions

‎src/engine/internal/codegen/CMakeLists.txt‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ target_sources(scratchcpp
99
instructionlistbase.cpp
1010
instructionlistbase.h
1111
instructionlist.h
12+
codeanalyzer.cpp
13+
codeanalyzer.h
14+
optimizationutils.cpp
15+
optimizationutils.h
1216
)
1317

1418
add_subdirectory(llvm)

src/engine/internal/codegen/llvm/llvmcodeanalyzer.cpp renamed to src/engine/internal/codegen/codeanalyzer.cpp

Lines changed: 42 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,29 @@
11
// SPDX-License-Identifier: Apache-2.0
22

3-
#include "llvmcodeanalyzer.h"
4-
#include "llvminstructionlist.h"
5-
#include "llvminstruction.h"
6-
#include "llvmbuildutils.h"
3+
#include <scratchcpp/compilervalue.h>
4+
5+
#include "codeanalyzer.h"
6+
#include "instructionlistbase.h"
7+
#include "instructionbase.h"
8+
#include "optimizationutils.h"
79

810
using namespace libscratchcpp;
911

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

13-
static const std::unordered_set<LLVMInstruction::Type> LIST_WRITE_INSTRUCTIONS = { LLVMInstruction::Type::AppendToList, LLVMInstruction::Type::InsertToList, LLVMInstruction::Type::ListReplace };
15+
static const std::unordered_set<InstructionBase::Type> LIST_WRITE_INSTRUCTIONS = { InstructionBase::Type::AppendToList, InstructionBase::Type::InsertToList, InstructionBase::Type::ListReplace };
1416

15-
LLVMCodeAnalyzer::LLVMCodeAnalyzer(const LLVMBuildUtils &utils) :
16-
m_utils(utils)
17+
CodeAnalyzer::CodeAnalyzer(CompilerContext *ctx) :
18+
m_ctx(ctx)
1719
{
1820
}
1921

20-
void LLVMCodeAnalyzer::analyzeScript(const LLVMInstructionList &script) const
22+
void CodeAnalyzer::analyzeScript(const InstructionListBase &script) const
2123
{
22-
std::unordered_set<LLVMInstruction *> typeAssignedInstructions;
24+
std::unordered_set<InstructionBase *> typeAssignedInstructions;
2325
std::vector<std::unique_ptr<Branch>> branches;
24-
LLVMInstruction *ins = script.first();
26+
InstructionBase *ins = script.first();
2527

2628
auto topBranch = std::make_unique<Branch>();
2729
topBranch->start = ins;
@@ -148,14 +150,14 @@ void LLVMCodeAnalyzer::analyzeScript(const LLVMInstructionList &script) const
148150
typeAssignedInstructions.insert(ins);
149151
}
150152

151-
ins = ins->getNext();
153+
ins = ins->next;
152154
}
153155

154156
assert(branches.size() == 1);
155157
assert(branches.back().get() == topBranchPtr);
156158
}
157159

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

@@ -182,7 +184,7 @@ void LLVMCodeAnalyzer::updateVariableType(Branch *branch, LLVMInstruction *ins,
182184
}
183185
}
184186

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

@@ -211,7 +213,7 @@ void LLVMCodeAnalyzer::updateListType(Branch *branch, LLVMInstruction *ins, std:
211213
}
212214
}
213215

214-
void LLVMCodeAnalyzer::mergeVariableTypes(Branch *branch, Branch *previousBranch) const
216+
void CodeAnalyzer::mergeVariableTypes(Branch *branch, Branch *previousBranch) const
215217
{
216218
for (const auto &[var, type] : branch->variableTypes) {
217219
auto it = previousBranch->variableTypes.find(var);
@@ -223,13 +225,13 @@ void LLVMCodeAnalyzer::mergeVariableTypes(Branch *branch, Branch *previousBranch
223225
}
224226
}
225227

226-
void LLVMCodeAnalyzer::overrideVariableTypes(Branch *branch, Branch *previousBranch) const
228+
void CodeAnalyzer::overrideVariableTypes(Branch *branch, Branch *previousBranch) const
227229
{
228230
for (const auto &[var, type] : branch->variableTypes)
229231
previousBranch->variableTypes[var] = type;
230232
}
231233

232-
void LLVMCodeAnalyzer::mergeListTypes(Branch *branch, Branch *previousBranch, bool firstUnknown) const
234+
void CodeAnalyzer::mergeListTypes(Branch *branch, Branch *previousBranch, bool firstUnknown) const
233235
{
234236
for (const auto &[list, type] : branch->listTypes) {
235237
auto it = previousBranch->listTypes.find(list);
@@ -241,69 +243,69 @@ void LLVMCodeAnalyzer::mergeListTypes(Branch *branch, Branch *previousBranch, bo
241243
}
242244
}
243245

244-
bool LLVMCodeAnalyzer::isLoopStart(const LLVMInstruction *ins) const
246+
bool CodeAnalyzer::isLoopStart(const InstructionBase *ins) const
245247
{
246248
return (BEGIN_LOOP_INSTRUCTIONS.find(ins->type) != BEGIN_LOOP_INSTRUCTIONS.cend());
247249
}
248250

249-
bool LLVMCodeAnalyzer::isLoopEnd(const LLVMInstruction *ins) const
251+
bool CodeAnalyzer::isLoopEnd(const InstructionBase *ins) const
250252
{
251-
return (ins->type == LLVMInstruction::Type::EndLoop);
253+
return (ins->type == InstructionBase::Type::EndLoop);
252254
}
253255

254-
bool LLVMCodeAnalyzer::isIfStart(const LLVMInstruction *ins) const
256+
bool CodeAnalyzer::isIfStart(const InstructionBase *ins) const
255257
{
256-
return (ins->type == LLVMInstruction::Type::BeginIf);
258+
return (ins->type == InstructionBase::Type::BeginIf);
257259
}
258260

259-
bool LLVMCodeAnalyzer::isElse(const LLVMInstruction *ins) const
261+
bool CodeAnalyzer::isElse(const InstructionBase *ins) const
260262
{
261-
return (ins->type == LLVMInstruction::Type::BeginElse);
263+
return (ins->type == InstructionBase::Type::BeginElse);
262264
}
263265

264-
bool LLVMCodeAnalyzer::isIfEnd(const LLVMInstruction *ins) const
266+
bool CodeAnalyzer::isIfEnd(const InstructionBase *ins) const
265267
{
266-
return (ins->type == LLVMInstruction::Type::EndIf);
268+
return (ins->type == InstructionBase::Type::EndIf);
267269
}
268270

269-
bool LLVMCodeAnalyzer::isVariableRead(const LLVMInstruction *ins) const
271+
bool CodeAnalyzer::isVariableRead(const InstructionBase *ins) const
270272
{
271-
return (ins->type == LLVMInstruction::Type::ReadVariable);
273+
return (ins->type == InstructionBase::Type::ReadVariable);
272274
}
273275

274-
bool LLVMCodeAnalyzer::isVariableWrite(const LLVMInstruction *ins) const
276+
bool CodeAnalyzer::isVariableWrite(const InstructionBase *ins) const
275277
{
276-
return (ins->type == LLVMInstruction::Type::WriteVariable);
278+
return (ins->type == InstructionBase::Type::WriteVariable);
277279
}
278280

279-
bool LLVMCodeAnalyzer::isListRead(const LLVMInstruction *ins) const
281+
bool CodeAnalyzer::isListRead(const InstructionBase *ins) const
280282
{
281-
return (ins->type == LLVMInstruction::Type::GetListItem);
283+
return (ins->type == InstructionBase::Type::GetListItem);
282284
}
283285

284-
bool LLVMCodeAnalyzer::isListWrite(const LLVMInstruction *ins) const
286+
bool CodeAnalyzer::isListWrite(const InstructionBase *ins) const
285287
{
286288
return (LIST_WRITE_INSTRUCTIONS.find(ins->type) != LIST_WRITE_INSTRUCTIONS.cend());
287289
}
288290

289-
bool LLVMCodeAnalyzer::isListClear(const LLVMInstruction *ins) const
291+
bool CodeAnalyzer::isListClear(const InstructionBase *ins) const
290292
{
291-
return (ins->type == LLVMInstruction::Type::ClearList);
293+
return (ins->type == InstructionBase::Type::ClearList);
292294
}
293295

294-
bool LLVMCodeAnalyzer::isProcedureCall(const LLVMInstruction *ins) const
296+
bool CodeAnalyzer::isProcedureCall(const InstructionBase *ins) const
295297
{
296-
return (ins->type == LLVMInstruction::Type::CallProcedure);
298+
return (ins->type == InstructionBase::Type::CallProcedure);
297299
}
298300

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

306-
Compiler::StaticType ret = m_utils.optimizeRegisterType(argReg);
308+
Compiler::StaticType ret = OptimizationUtils::optimizeValueType(m_ctx, argValue);
307309
arg.first = ret; // store the return type in the value argument
308310
return ret;
309311
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
3+
#pragma once
4+
5+
#include <scratchcpp/compiler.h>
6+
#include <unordered_map>
7+
8+
#include "test_export.h"
9+
10+
namespace libscratchcpp
11+
{
12+
13+
class InstructionListBase;
14+
class InstructionBase;
15+
16+
class LIBSCRATCHCPP_TEST_EXPORT CodeAnalyzer
17+
{
18+
public:
19+
CodeAnalyzer(CompilerContext *ctx);
20+
CodeAnalyzer(const CodeAnalyzer &) = delete;
21+
22+
void analyzeScript(const InstructionListBase &script) const;
23+
24+
private:
25+
struct Branch
26+
{
27+
InstructionBase *start = nullptr;
28+
bool typeChanges = false;
29+
std::unordered_map<Variable *, Compiler::StaticType> variableTypes;
30+
std::unordered_map<List *, Compiler::StaticType> listTypes;
31+
32+
std::unique_ptr<Branch> elseBranch;
33+
bool isAtElse = false; // whether we're currently processing the else branch
34+
};
35+
36+
void updateVariableType(Branch *branch, InstructionBase *ins, std::unordered_set<InstructionBase *> &typeAssignedInstructions, bool isWrite) const;
37+
void updateListType(Branch *branch, InstructionBase *ins, std::unordered_set<InstructionBase *> &typeAssignedInstructions, bool isWrite) const;
38+
39+
void mergeVariableTypes(Branch *branch, Branch *previousBranch) const;
40+
void overrideVariableTypes(Branch *branch, Branch *previousBranch) const;
41+
void mergeListTypes(Branch *branch, Branch *previousBranch, bool firstUnknown) const;
42+
43+
bool isLoopStart(const InstructionBase *ins) const;
44+
bool isLoopEnd(const InstructionBase *ins) const;
45+
bool isIfStart(const InstructionBase *ins) const;
46+
bool isElse(const InstructionBase *ins) const;
47+
bool isIfEnd(const InstructionBase *ins) const;
48+
49+
bool isVariableRead(const InstructionBase *ins) const;
50+
bool isVariableWrite(const InstructionBase *ins) const;
51+
52+
bool isListRead(const InstructionBase *ins) const;
53+
bool isListWrite(const InstructionBase *ins) const;
54+
bool isListClear(const InstructionBase *ins) const;
55+
56+
bool isProcedureCall(const InstructionBase *ins) const;
57+
58+
Compiler::StaticType writeType(InstructionBase *ins) const;
59+
60+
private:
61+
CompilerContext *m_ctx;
62+
};
63+
64+
} // namespace libscratchcpp

‎src/engine/internal/codegen/llvm/CMakeLists.txt‎

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@ target_sources(scratchcpp
22
PRIVATE
33
llvmbuildutils.cpp
44
llvmbuildutils.h
5-
llvmcodeanalyzer.cpp
6-
llvmcodeanalyzer.h
75
llvmcodebuilder.cpp
86
llvmcodebuilder.h
97
llvmregister.h

‎src/engine/internal/codegen/llvm/llvmbuildutils.cpp‎

Lines changed: 3 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "llvmcompilercontext.h"
1414
#include "llvmregister.h"
1515
#include "llvminstruction.h"
16+
#include "../optimizationutils.h"
1617

1718
using namespace libscratchcpp;
1819

@@ -68,7 +69,8 @@ void LLVMBuildUtils::init(llvm::Function *function, BlockPrototype *procedurePro
6869
// Init registers
6970
for (auto reg : regs) {
7071
#ifdef LLVM_INTEGER_SUPPORT
71-
bool isIntConst = (reg->isConst() && optimizeRegisterType(reg.get()) == Compiler::StaticType::Number && reg->constValue().toDouble() == std::floor(reg->constValue().toDouble()));
72+
bool isIntConst =
73+
(reg->isConst() && OptimizationUtils::optimizeValueType(m_ctx, reg.get()) == Compiler::StaticType::Number && reg->constValue().toDouble() == std::floor(reg->constValue().toDouble()));
7274
reg->isInt = m_builder.getInt1(isIntConst);
7375
#else
7476
reg->isInt = m_builder.getInt1(false);
@@ -482,26 +484,6 @@ std::vector<LLVMLoop> &LLVMBuildUtils::loops()
482484
return m_loops;
483485
}
484486

485-
Compiler::StaticType LLVMBuildUtils::optimizeRegisterType(const LLVMRegister *reg) const
486-
{
487-
Compiler::StaticType ret = reg->type();
488-
489-
// Optimize string constants that represent numbers
490-
if (reg->isConst() && reg->type() == Compiler::StaticType::String) {
491-
const Value &value = reg->constValue();
492-
Value numberValue(value.toDouble());
493-
std::string str = value.toString();
494-
495-
// Apply this optimization only if the number matches the string and the constant is safe
496-
const auto &unsafeConstants = m_ctx->unsafeConstants();
497-
498-
if (value.isValidNumber() && numberValue.toString() == str && unsafeConstants.find(str) == unsafeConstants.cend())
499-
ret = Compiler::StaticType::Number;
500-
}
501-
502-
return ret;
503-
}
504-
505487
Compiler::StaticType LLVMBuildUtils::mapType(ValueType type)
506488
{
507489
assert(TYPE_MAP.find(type) != TYPE_MAP.cend());

‎src/engine/internal/codegen/llvm/llvmbuildutils.h‎

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,6 @@ class LIBSCRATCHCPP_TEST_EXPORT LLVMBuildUtils
8787
std::vector<LLVMIfStatement> &ifStatements();
8888
std::vector<LLVMLoop> &loops();
8989

90-
Compiler::StaticType optimizeRegisterType(const LLVMRegister *reg) const;
91-
9290
static Compiler::StaticType mapType(ValueType type);
9391
static ValueType mapType(Compiler::StaticType type);
9492
static bool isSingleType(Compiler::StaticType type);

‎src/engine/internal/codegen/llvm/llvmcodeanalyzer.h‎

Lines changed: 0 additions & 64 deletions
This file was deleted.

‎src/engine/internal/codegen/llvm/llvmcodebuilder.cpp‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +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),
31+
m_codeAnalyzer(ctx),
3232
m_procedurePrototype(procedurePrototype),
3333
m_defaultWarp(procedurePrototype ? procedurePrototype->warp() : false),
3434
m_warp(m_defaultWarp),

0 commit comments

Comments
 (0)