From f850bcc7502701df04f169a3acd8baf08b3f872a Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Mon, 5 May 2025 13:44:43 +0200 Subject: [PATCH 01/79] Remove llvmprocedure.h --- src/engine/internal/llvm/CMakeLists.txt | 1 - src/engine/internal/llvm/llvmprocedure.h | 14 -------------- 2 files changed, 15 deletions(-) delete mode 100644 src/engine/internal/llvm/llvmprocedure.h diff --git a/src/engine/internal/llvm/CMakeLists.txt b/src/engine/internal/llvm/CMakeLists.txt index 01520d08a..1b0a3176c 100644 --- a/src/engine/internal/llvm/CMakeLists.txt +++ b/src/engine/internal/llvm/CMakeLists.txt @@ -11,7 +11,6 @@ target_sources(scratchcpp llvmcoroutine.h llvmvariableptr.h llvmlistptr.h - llvmprocedure.h llvmtypes.cpp llvmtypes.h llvmfunctions.cpp diff --git a/src/engine/internal/llvm/llvmprocedure.h b/src/engine/internal/llvm/llvmprocedure.h deleted file mode 100644 index 7cb576794..000000000 --- a/src/engine/internal/llvm/llvmprocedure.h +++ /dev/null @@ -1,14 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 - -#pragma once - -namespace libscratchcpp -{ - -struct LLVMProcedure -{ - // TODO: Implement procedures - bool warp = false; -}; - -} // namespace libscratchcpp From de624f17b6559d03f2b46a75c518efe8aca590ba Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Tue, 22 Jul 2025 18:24:23 +0200 Subject: [PATCH 02/79] LLVMCodeBuilder: Mark m_instruction as deprecated This variable will become obsolete after we switch to linked list. --- src/engine/internal/llvm/llvmcodebuilder.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/internal/llvm/llvmcodebuilder.h b/src/engine/internal/llvm/llvmcodebuilder.h index 68bb517ea..cc533b685 100644 --- a/src/engine/internal/llvm/llvmcodebuilder.h +++ b/src/engine/internal/llvm/llvmcodebuilder.h @@ -234,7 +234,7 @@ class LLVMCodeBuilder : public ICodeBuilder llvm::StructType *m_stringPtrType = nullptr; llvm::FunctionType *m_resumeFuncType = nullptr; - std::vector> m_instructions; + [[deprecated]] std::vector> m_instructions; // TODO: Remove this std::vector> m_regs; std::vector> m_localVars; LLVMRegister *m_lastConstValue = nullptr; // for reporters and hat predicates From 6330ed6fea3747a8b48fb59040875928d54252f2 Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Tue, 22 Jul 2025 19:14:53 +0200 Subject: [PATCH 03/79] Add LLVMInstructionList class --- src/engine/internal/llvm/CMakeLists.txt | 2 + src/engine/internal/llvm/llvminstruction.h | 4 + .../internal/llvm/llvminstructionlist.cpp | 35 ++++ .../internal/llvm/llvminstructionlist.h | 28 +++ test/llvm/CMakeLists.txt | 1 + test/llvm/llvminstructionlist_test.cpp | 182 ++++++++++++++++++ 6 files changed, 252 insertions(+) create mode 100644 src/engine/internal/llvm/llvminstructionlist.cpp create mode 100644 src/engine/internal/llvm/llvminstructionlist.h create mode 100644 test/llvm/llvminstructionlist_test.cpp diff --git a/src/engine/internal/llvm/CMakeLists.txt b/src/engine/internal/llvm/CMakeLists.txt index 1b0a3176c..3fcb3d797 100644 --- a/src/engine/internal/llvm/CMakeLists.txt +++ b/src/engine/internal/llvm/CMakeLists.txt @@ -5,6 +5,8 @@ target_sources(scratchcpp llvmregister.h llvmconstantregister.h llvminstruction.h + llvminstructionlist.cpp + llvminstructionlist.h llvmifstatement.h llvmloop.h llvmcoroutine.cpp diff --git a/src/engine/internal/llvm/llvminstruction.h b/src/engine/internal/llvm/llvminstruction.h index 11c6ad316..1116b347f 100644 --- a/src/engine/internal/llvm/llvminstruction.h +++ b/src/engine/internal/llvm/llvminstruction.h @@ -100,6 +100,10 @@ struct LLVMInstruction size_t procedureArgIndex = 0; LLVMLoopScope *loopScope = nullptr; bool loopCondition = false; // whether the instruction is part of a loop condition + + // Linked list + LLVMInstruction *previous = nullptr; + LLVMInstruction *next = nullptr; }; } // namespace libscratchcpp diff --git a/src/engine/internal/llvm/llvminstructionlist.cpp b/src/engine/internal/llvm/llvminstructionlist.cpp new file mode 100644 index 000000000..1f4fbe6ab --- /dev/null +++ b/src/engine/internal/llvm/llvminstructionlist.cpp @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: Apache-2.0 + +#include + +#include "llvminstructionlist.h" +#include "llvminstruction.h" + +using namespace libscratchcpp; + +LLVMInstruction *LLVMInstructionList::first() +{ + return m_first.get(); +} + +LLVMInstruction *LLVMInstructionList::last() +{ + return m_last.get(); +} + +void LLVMInstructionList::addInstruction(std::shared_ptr ins) +{ + if (!(m_first && m_last)) { + assert(!m_first && !m_last); + + m_first = ins; + m_last = ins; + + ins->previous = nullptr; + ins->next = nullptr; + } else { + m_last->next = ins.get(); + ins->previous = m_last.get(); + m_last = ins; + } +} diff --git a/src/engine/internal/llvm/llvminstructionlist.h b/src/engine/internal/llvm/llvminstructionlist.h new file mode 100644 index 000000000..82036555b --- /dev/null +++ b/src/engine/internal/llvm/llvminstructionlist.h @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include + +namespace libscratchcpp +{ + +struct LLVMInstruction; + +class LLVMInstructionList +{ + public: + LLVMInstructionList() = default; + LLVMInstructionList(const LLVMInstructionList &) = delete; + + LLVMInstruction *first(); + LLVMInstruction *last(); + + void addInstruction(std::shared_ptr ins); + + private: + std::shared_ptr m_first; + std::shared_ptr m_last; +}; + +} // namespace libscratchcpp diff --git a/test/llvm/CMakeLists.txt b/test/llvm/CMakeLists.txt index abfc4d982..02337d23f 100644 --- a/test/llvm/CMakeLists.txt +++ b/test/llvm/CMakeLists.txt @@ -19,6 +19,7 @@ add_executable( llvmexecutioncontext_test.cpp llvmexecutablecode_test.cpp llvmcodebuilder_test.cpp + llvminstructionlist_test.cpp ) target_link_libraries( diff --git a/test/llvm/llvminstructionlist_test.cpp b/test/llvm/llvminstructionlist_test.cpp new file mode 100644 index 000000000..ec5851791 --- /dev/null +++ b/test/llvm/llvminstructionlist_test.cpp @@ -0,0 +1,182 @@ +#include +#include +#include +#include + +using namespace libscratchcpp; + +TEST(LLVMInstructionListTest, EmptyList_First) +{ + LLVMInstructionList list; + ASSERT_EQ(list.first(), nullptr); +} + +TEST(LLVMInstructionListTest, EmptyList_Last) +{ + LLVMInstructionList list; + ASSERT_EQ(list.last(), nullptr); +} + +TEST(LLVMInstructionListTest, AddSingleInstruction_First) +{ + LLVMInstructionList list; + auto ins = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(ins); + + ASSERT_EQ(list.first(), ins.get()); +} + +TEST(LLVMInstructionListTest, AddSingleInstruction_Last) +{ + LLVMInstructionList list; + auto ins = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(ins); + + ASSERT_EQ(list.last(), ins.get()); +} + +TEST(LLVMInstructionListTest, AddSingleInstruction_Previous) +{ + LLVMInstructionList list; + auto ins = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(ins); + + ASSERT_EQ(ins->previous, nullptr); +} + +TEST(LLVMInstructionListTest, AddSingleInstruction_Next) +{ + LLVMInstructionList list; + auto ins = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(ins); + + ASSERT_EQ(ins->next, nullptr); +} + +TEST(LLVMInstructionListTest, AddMultipleInstructions_First) +{ + LLVMInstructionList list; + + auto ins1 = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(ins1); + + auto ins2 = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(ins2); + + auto ins3 = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(ins3); + + ASSERT_EQ(list.first(), ins1.get()); +} + +TEST(LLVMInstructionListTest, AddMultipleInstructions_Last) +{ + LLVMInstructionList list; + + auto ins1 = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(ins1); + + auto ins2 = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(ins2); + + auto ins3 = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(ins3); + + ASSERT_EQ(list.last(), ins3.get()); +} + +TEST(LLVMInstructionListTest, AddMultipleInstructions_PreviousOfFirst) +{ + LLVMInstructionList list; + + auto ins1 = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(ins1); + + auto ins2 = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(ins2); + + auto ins3 = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(ins3); + + ASSERT_EQ(ins1->previous, nullptr); +} + +TEST(LLVMInstructionListTest, AddMultipleInstructions_NextOfFirst) +{ + LLVMInstructionList list; + + auto ins1 = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(ins1); + + auto ins2 = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(ins2); + + auto ins3 = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(ins3); + + ASSERT_EQ(ins1->next, ins2.get()); +} + +TEST(LLVMInstructionListTest, AddMultipleInstructions_PreviousOfMiddle) +{ + LLVMInstructionList list; + + auto ins1 = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(ins1); + + auto ins2 = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(ins2); + + auto ins3 = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(ins3); + + ASSERT_EQ(ins2->previous, ins1.get()); +} + +TEST(LLVMInstructionListTest, AddMultipleInstructions_NextOfMiddle) +{ + LLVMInstructionList list; + + auto ins1 = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(ins1); + + auto ins2 = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(ins2); + + auto ins3 = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(ins3); + + ASSERT_EQ(ins2->next, ins3.get()); +} + +TEST(LLVMInstructionListTest, AddMultipleInstructions_PreviousOfLast) +{ + LLVMInstructionList list; + + auto ins1 = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(ins1); + + auto ins2 = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(ins2); + + auto ins3 = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(ins3); + + ASSERT_EQ(ins3->previous, ins2.get()); +} + +TEST(LLVMInstructionListTest, AddMultipleInstructions_NextOfLast) +{ + LLVMInstructionList list; + + auto ins1 = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(ins1); + + auto ins2 = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(ins2); + + auto ins3 = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(ins3); + + ASSERT_EQ(ins3->next, nullptr); +} From 142e7e563f03d976ff77c24cc69d7677f370ec40 Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Tue, 22 Jul 2025 19:17:01 +0200 Subject: [PATCH 04/79] LLVMCodeBuilder: Rename m_instructions --- src/engine/internal/llvm/llvmcodebuilder.cpp | 80 ++++++++++---------- src/engine/internal/llvm/llvmcodebuilder.h | 2 +- 2 files changed, 41 insertions(+), 41 deletions(-) diff --git a/src/engine/internal/llvm/llvmcodebuilder.cpp b/src/engine/internal/llvm/llvmcodebuilder.cpp index e0e44e72b..ac8039fc8 100644 --- a/src/engine/internal/llvm/llvmcodebuilder.cpp +++ b/src/engine/internal/llvm/llvmcodebuilder.cpp @@ -53,11 +53,11 @@ std::shared_ptr LLVMCodeBuilder::finalize() { if (!m_warp) { // Do not create coroutine if there are no yield instructions nor non-warp procedure calls - auto it = std::find_if(m_instructions.begin(), m_instructions.end(), [](const std::shared_ptr &step) { + auto it = std::find_if(m_instructionList.begin(), m_instructionList.end(), [](const std::shared_ptr &step) { return step->type == LLVMInstruction::Type::Yield || (step->type == LLVMInstruction::Type::CallProcedure && step->procedurePrototype && !step->procedurePrototype->warp()); }); - if (it == m_instructions.end()) + if (it == m_instructionList.end()) m_warp = true; // Only create coroutines in scripts @@ -153,7 +153,7 @@ std::shared_ptr LLVMCodeBuilder::finalize() pushScopeLevel(); // Execute recorded steps - for (const auto insPtr : m_instructions) { + for (const auto insPtr : m_instructionList) { const LLVMInstruction &step = *insPtr; switch (step.type) { @@ -1340,8 +1340,8 @@ std::shared_ptr LLVMCodeBuilder::finalize() case Compiler::CodeType::Reporter: { // Use last instruction return value (or last constant) and create a ValueData instance - assert(!m_instructions.empty() || m_lastConstValue); - LLVMRegister *ret = m_instructions.empty() ? m_lastConstValue : m_instructions.back()->functionReturnReg; + assert(!m_instructionList.empty() || m_lastConstValue); + LLVMRegister *ret = m_instructionList.empty() ? m_lastConstValue : m_instructionList.back()->functionReturnReg; llvm::Value *copy = createNewValue(ret); m_builder.CreateRet(m_builder.CreateLoad(m_valueDataType, copy)); break; @@ -1349,12 +1349,12 @@ std::shared_ptr LLVMCodeBuilder::finalize() case Compiler::CodeType::HatPredicate: // Use last instruction return value (or last constant) - assert(!m_instructions.empty() || m_lastConstValue); + assert(!m_instructionList.empty() || m_lastConstValue); - if (m_instructions.empty()) + if (m_instructionList.empty()) m_builder.CreateRet(castValue(m_lastConstValue, Compiler::StaticType::Bool)); else - m_builder.CreateRet(castValue(m_instructions.back()->functionReturnReg, Compiler::StaticType::Bool)); + m_builder.CreateRet(castValue(m_instructionList.back()->functionReturnReg, Compiler::StaticType::Bool)); break; } @@ -1394,25 +1394,25 @@ CompilerValue *LLVMCodeBuilder::addFunctionCall(const std::string &functionName, auto reg = std::make_shared(returnType); reg->isRawValue = true; ins->functionReturnReg = reg.get(); - m_instructions.push_back(ins); + m_instructionList.push_back(ins); return addReg(reg, ins); } - m_instructions.push_back(ins); + m_instructionList.push_back(ins); return nullptr; } CompilerValue *LLVMCodeBuilder::addTargetFunctionCall(const std::string &functionName, Compiler::StaticType returnType, const Compiler::ArgTypes &argTypes, const Compiler::Args &args) { CompilerValue *ret = addFunctionCall(functionName, returnType, argTypes, args); - m_instructions.back()->functionTargetArg = true; + m_instructionList.back()->functionTargetArg = true; return ret; } CompilerValue *LLVMCodeBuilder::addFunctionCallWithCtx(const std::string &functionName, Compiler::StaticType returnType, const Compiler::ArgTypes &argTypes, const Compiler::Args &args) { CompilerValue *ret = addFunctionCall(functionName, returnType, argTypes, args); - m_instructions.back()->functionCtxArg = true; + m_instructionList.back()->functionCtxArg = true; return ret; } @@ -1456,8 +1456,8 @@ CompilerValue *LLVMCodeBuilder::addVariableValue(Variable *variable) ret->isRawValue = false; ins->functionReturnReg = ret.get(); - m_instructions.push_back(ins); - m_variableInstructions.push_back(m_instructions.back()); + m_instructionList.push_back(ins); + m_variableInstructions.push_back(m_instructionList.back()); return addReg(ret, ins); } @@ -1486,8 +1486,8 @@ CompilerValue *LLVMCodeBuilder::addListItem(List *list, CompilerValue *index) ret->isRawValue = false; ins->functionReturnReg = ret.get(); - m_instructions.push_back(ins); - m_listInstructions.push_back(m_instructions.back()); + m_instructionList.push_back(ins); + m_listInstructions.push_back(m_instructionList.back()); return addReg(ret, ins); } @@ -1500,7 +1500,7 @@ CompilerValue *LLVMCodeBuilder::addListItemIndex(List *list, CompilerValue *item m_listPtrs[list] = LLVMListPtr(); auto ret = createOp(ins, Compiler::StaticType::Number, Compiler::StaticType::Unknown, { item }); - m_listInstructions.push_back(m_instructions.back()); + m_listInstructions.push_back(m_instructionList.back()); return ret; } @@ -1513,7 +1513,7 @@ CompilerValue *LLVMCodeBuilder::addListContains(List *list, CompilerValue *item) m_listPtrs[list] = LLVMListPtr(); auto ret = createOp(ins, Compiler::StaticType::Bool, Compiler::StaticType::Unknown, { item }); - m_listInstructions.push_back(m_instructions.back()); + m_listInstructions.push_back(m_instructionList.back()); return ret; } @@ -1549,7 +1549,7 @@ CompilerValue *LLVMCodeBuilder::addProcedureArgument(const std::string &name) ins->functionReturnReg = ret.get(); ins->procedureArgIndex = index; - m_instructions.push_back(ins); + m_instructionList.push_back(ins); return addReg(ret, ins); } @@ -1737,10 +1737,10 @@ void LLVMCodeBuilder::createVariableWrite(Variable *variable, CompilerValue *val if (m_loopScope >= 0) { auto scope = m_loopScopes[m_loopScope]; - m_variablePtrs[variable].loopVariableWrites[scope.get()].push_back(m_instructions.back()); + m_variablePtrs[variable].loopVariableWrites[scope.get()].push_back(m_instructionList.back()); } - m_variableInstructions.push_back(m_instructions.back()); + m_variableInstructions.push_back(m_instructionList.back()); } void LLVMCodeBuilder::createListClear(List *list) @@ -1774,10 +1774,10 @@ void LLVMCodeBuilder::createListAppend(List *list, CompilerValue *item) if (m_loopScope >= 0) { auto scope = m_loopScopes[m_loopScope]; - m_listPtrs[list].loopListWrites[scope.get()].push_back(m_instructions.back()); + m_listPtrs[list].loopListWrites[scope.get()].push_back(m_instructionList.back()); } - m_listInstructions.push_back(m_instructions.back()); + m_listInstructions.push_back(m_instructionList.back()); } void LLVMCodeBuilder::createListInsert(List *list, CompilerValue *index, CompilerValue *item) @@ -1791,10 +1791,10 @@ void LLVMCodeBuilder::createListInsert(List *list, CompilerValue *index, Compile if (m_loopScope >= 0) { auto scope = m_loopScopes[m_loopScope]; - m_listPtrs[list].loopListWrites[scope.get()].push_back(m_instructions.back()); + m_listPtrs[list].loopListWrites[scope.get()].push_back(m_instructionList.back()); } - m_listInstructions.push_back(m_instructions.back()); + m_listInstructions.push_back(m_instructionList.back()); } void LLVMCodeBuilder::createListReplace(List *list, CompilerValue *index, CompilerValue *item) @@ -1808,27 +1808,27 @@ void LLVMCodeBuilder::createListReplace(List *list, CompilerValue *index, Compil if (m_loopScope >= 0) { auto scope = m_loopScopes[m_loopScope]; - m_listPtrs[list].loopListWrites[scope.get()].push_back(m_instructions.back()); + m_listPtrs[list].loopListWrites[scope.get()].push_back(m_instructionList.back()); } - m_listInstructions.push_back(m_instructions.back()); + m_listInstructions.push_back(m_instructionList.back()); } void LLVMCodeBuilder::beginIfStatement(CompilerValue *cond) { auto ins = std::make_shared(LLVMInstruction::Type::BeginIf, currentLoopScope(), m_loopCondition); ins->args.push_back({ Compiler::StaticType::Bool, dynamic_cast(cond) }); - m_instructions.push_back(ins); + m_instructionList.push_back(ins); } void LLVMCodeBuilder::beginElseBranch() { - m_instructions.push_back(std::make_shared(LLVMInstruction::Type::BeginElse, currentLoopScope(), m_loopCondition)); + m_instructionList.push_back(std::make_shared(LLVMInstruction::Type::BeginElse, currentLoopScope(), m_loopCondition)); } void LLVMCodeBuilder::endIf() { - m_instructions.push_back(std::make_shared(LLVMInstruction::Type::EndIf, currentLoopScope(), m_loopCondition)); + m_instructionList.push_back(std::make_shared(LLVMInstruction::Type::EndIf, currentLoopScope(), m_loopCondition)); } void LLVMCodeBuilder::beginRepeatLoop(CompilerValue *count) @@ -1837,7 +1837,7 @@ void LLVMCodeBuilder::beginRepeatLoop(CompilerValue *count) auto ins = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, currentLoopScope(), m_loopCondition); ins->args.push_back({ Compiler::StaticType::Number, dynamic_cast(count) }); - m_instructions.push_back(ins); + m_instructionList.push_back(ins); pushLoopScope(false); } @@ -1848,7 +1848,7 @@ void LLVMCodeBuilder::beginWhileLoop(CompilerValue *cond) auto ins = std::make_shared(LLVMInstruction::Type::BeginWhileLoop, currentLoopScope(), m_loopCondition); ins->args.push_back({ Compiler::StaticType::Bool, dynamic_cast(cond) }); - m_instructions.push_back(ins); + m_instructionList.push_back(ins); pushLoopScope(false); } @@ -1859,29 +1859,29 @@ void LLVMCodeBuilder::beginRepeatUntilLoop(CompilerValue *cond) auto ins = std::make_shared(LLVMInstruction::Type::BeginRepeatUntilLoop, currentLoopScope(), m_loopCondition); ins->args.push_back({ Compiler::StaticType::Bool, dynamic_cast(cond) }); - m_instructions.push_back(ins); + m_instructionList.push_back(ins); pushLoopScope(false); } void LLVMCodeBuilder::beginLoopCondition() { assert(!m_loopCondition); - m_instructions.push_back(std::make_shared(LLVMInstruction::Type::BeginLoopCondition, currentLoopScope(), m_loopCondition)); + m_instructionList.push_back(std::make_shared(LLVMInstruction::Type::BeginLoopCondition, currentLoopScope(), m_loopCondition)); m_loopCondition = true; } void LLVMCodeBuilder::endLoop() { if (!m_warp) - m_instructions.push_back(std::make_shared(LLVMInstruction::Type::Yield, currentLoopScope(), m_loopCondition)); + m_instructionList.push_back(std::make_shared(LLVMInstruction::Type::Yield, currentLoopScope(), m_loopCondition)); - m_instructions.push_back(std::make_shared(LLVMInstruction::Type::EndLoop, currentLoopScope(), m_loopCondition)); + m_instructionList.push_back(std::make_shared(LLVMInstruction::Type::EndLoop, currentLoopScope(), m_loopCondition)); popLoopScope(); } void LLVMCodeBuilder::yield() { - m_instructions.push_back(std::make_shared(LLVMInstruction::Type::Yield, currentLoopScope(), m_loopCondition)); + m_instructionList.push_back(std::make_shared(LLVMInstruction::Type::Yield, currentLoopScope(), m_loopCondition)); if (m_loopScope >= 0) m_loopScopes[m_loopScope]->containsYield = true; @@ -1889,7 +1889,7 @@ void LLVMCodeBuilder::yield() void LLVMCodeBuilder::createStop() { - m_instructions.push_back(std::make_shared(LLVMInstruction::Type::Stop, currentLoopScope(), m_loopCondition)); + m_instructionList.push_back(std::make_shared(LLVMInstruction::Type::Stop, currentLoopScope(), m_loopCondition)); } void LLVMCodeBuilder::createProcedureCall(BlockPrototype *prototype, const Compiler::Args &args) @@ -2551,7 +2551,7 @@ bool LLVMCodeBuilder::isVarOrListTypeSafe(std::shared_ptr ins, else log.insert(ins.get()); - assert(std::find(m_instructions.begin(), m_instructions.end(), ins) != m_instructions.end()); + assert(std::find(m_instructionList.begin(), m_instructionList.end(), ins) != m_instructionList.end()); const LLVMVariablePtr *varPtr = ins->workVariable ? &m_variablePtrs.at(ins->workVariable) : nullptr; const LLVMListPtr *listPtr = ins->workList ? &m_listPtrs.at(ins->workList) : nullptr; assert((varPtr || listPtr) && !(varPtr && listPtr)); @@ -2715,7 +2715,7 @@ LLVMRegister *LLVMCodeBuilder::createOp(const LLVMInstruction &ins, Compiler::St LLVMRegister *LLVMCodeBuilder::createOp(const LLVMInstruction &ins, Compiler::StaticType retType, const Compiler::ArgTypes &argTypes, const Compiler::Args &args) { auto createdIns = std::make_shared(ins); - m_instructions.push_back(createdIns); + m_instructionList.push_back(createdIns); for (size_t i = 0; i < args.size(); i++) createdIns->args.push_back({ argTypes[i], dynamic_cast(args[i]) }); diff --git a/src/engine/internal/llvm/llvmcodebuilder.h b/src/engine/internal/llvm/llvmcodebuilder.h index cc533b685..45f0e7d83 100644 --- a/src/engine/internal/llvm/llvmcodebuilder.h +++ b/src/engine/internal/llvm/llvmcodebuilder.h @@ -234,7 +234,7 @@ class LLVMCodeBuilder : public ICodeBuilder llvm::StructType *m_stringPtrType = nullptr; llvm::FunctionType *m_resumeFuncType = nullptr; - [[deprecated]] std::vector> m_instructions; // TODO: Remove this + [[deprecated]] std::vector> m_instructionList; // TODO: Remove this std::vector> m_regs; std::vector> m_localVars; LLVMRegister *m_lastConstValue = nullptr; // for reporters and hat predicates From 7af866e70feca0d6ee337b0ae9af9166e16d8796 Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Tue, 22 Jul 2025 19:35:15 +0200 Subject: [PATCH 05/79] LLVMCodeBuilder: Store instructions in LLVMInstructionList --- src/engine/internal/llvm/llvmcodebuilder.cpp | 42 ++++++++++++++++---- src/engine/internal/llvm/llvmcodebuilder.h | 2 + 2 files changed, 36 insertions(+), 8 deletions(-) diff --git a/src/engine/internal/llvm/llvmcodebuilder.cpp b/src/engine/internal/llvm/llvmcodebuilder.cpp index ac8039fc8..78483a5cb 100644 --- a/src/engine/internal/llvm/llvmcodebuilder.cpp +++ b/src/engine/internal/llvm/llvmcodebuilder.cpp @@ -1390,6 +1390,8 @@ CompilerValue *LLVMCodeBuilder::addFunctionCall(const std::string &functionName, for (size_t i = 0; i < args.size(); i++) ins->args.push_back({ argTypes[i], dynamic_cast(args[i]) }); + m_instructions.addInstruction(ins); + if (returnType != Compiler::StaticType::Void) { auto reg = std::make_shared(returnType); reg->isRawValue = true; @@ -1456,6 +1458,7 @@ CompilerValue *LLVMCodeBuilder::addVariableValue(Variable *variable) ret->isRawValue = false; ins->functionReturnReg = ret.get(); + m_instructions.addInstruction(ins); m_instructionList.push_back(ins); m_variableInstructions.push_back(m_instructionList.back()); return addReg(ret, ins); @@ -1486,6 +1489,7 @@ CompilerValue *LLVMCodeBuilder::addListItem(List *list, CompilerValue *index) ret->isRawValue = false; ins->functionReturnReg = ret.get(); + m_instructions.addInstruction(ins); m_instructionList.push_back(ins); m_listInstructions.push_back(m_instructionList.back()); return addReg(ret, ins); @@ -1549,6 +1553,7 @@ CompilerValue *LLVMCodeBuilder::addProcedureArgument(const std::string &name) ins->functionReturnReg = ret.get(); ins->procedureArgIndex = index; + m_instructions.addInstruction(ins); m_instructionList.push_back(ins); return addReg(ret, ins); } @@ -1818,17 +1823,22 @@ void LLVMCodeBuilder::beginIfStatement(CompilerValue *cond) { auto ins = std::make_shared(LLVMInstruction::Type::BeginIf, currentLoopScope(), m_loopCondition); ins->args.push_back({ Compiler::StaticType::Bool, dynamic_cast(cond) }); + m_instructions.addInstruction(ins); m_instructionList.push_back(ins); } void LLVMCodeBuilder::beginElseBranch() { - m_instructionList.push_back(std::make_shared(LLVMInstruction::Type::BeginElse, currentLoopScope(), m_loopCondition)); + auto ins = std::make_shared(LLVMInstruction::Type::BeginElse, currentLoopScope(), m_loopCondition); + m_instructions.addInstruction(ins); + m_instructionList.push_back(ins); } void LLVMCodeBuilder::endIf() { - m_instructionList.push_back(std::make_shared(LLVMInstruction::Type::EndIf, currentLoopScope(), m_loopCondition)); + auto ins = std::make_shared(LLVMInstruction::Type::EndIf, currentLoopScope(), m_loopCondition); + m_instructions.addInstruction(ins); + m_instructionList.push_back(ins); } void LLVMCodeBuilder::beginRepeatLoop(CompilerValue *count) @@ -1837,6 +1847,7 @@ void LLVMCodeBuilder::beginRepeatLoop(CompilerValue *count) auto ins = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, currentLoopScope(), m_loopCondition); ins->args.push_back({ Compiler::StaticType::Number, dynamic_cast(count) }); + m_instructions.addInstruction(ins); m_instructionList.push_back(ins); pushLoopScope(false); } @@ -1848,6 +1859,7 @@ void LLVMCodeBuilder::beginWhileLoop(CompilerValue *cond) auto ins = std::make_shared(LLVMInstruction::Type::BeginWhileLoop, currentLoopScope(), m_loopCondition); ins->args.push_back({ Compiler::StaticType::Bool, dynamic_cast(cond) }); + m_instructions.addInstruction(ins); m_instructionList.push_back(ins); pushLoopScope(false); } @@ -1859,6 +1871,7 @@ void LLVMCodeBuilder::beginRepeatUntilLoop(CompilerValue *cond) auto ins = std::make_shared(LLVMInstruction::Type::BeginRepeatUntilLoop, currentLoopScope(), m_loopCondition); ins->args.push_back({ Compiler::StaticType::Bool, dynamic_cast(cond) }); + m_instructions.addInstruction(ins); m_instructionList.push_back(ins); pushLoopScope(false); } @@ -1866,22 +1879,32 @@ void LLVMCodeBuilder::beginRepeatUntilLoop(CompilerValue *cond) void LLVMCodeBuilder::beginLoopCondition() { assert(!m_loopCondition); - m_instructionList.push_back(std::make_shared(LLVMInstruction::Type::BeginLoopCondition, currentLoopScope(), m_loopCondition)); + + auto ins = std::make_shared(LLVMInstruction::Type::BeginLoopCondition, currentLoopScope(), m_loopCondition); + m_instructions.addInstruction(ins); + m_instructionList.push_back(ins); m_loopCondition = true; } void LLVMCodeBuilder::endLoop() { - if (!m_warp) - m_instructionList.push_back(std::make_shared(LLVMInstruction::Type::Yield, currentLoopScope(), m_loopCondition)); + if (!m_warp) { + auto ins = std::make_shared(LLVMInstruction::Type::Yield, currentLoopScope(), m_loopCondition); + m_instructions.addInstruction(ins); + m_instructionList.push_back(ins); + } - m_instructionList.push_back(std::make_shared(LLVMInstruction::Type::EndLoop, currentLoopScope(), m_loopCondition)); + auto ins = std::make_shared(LLVMInstruction::Type::EndLoop, currentLoopScope(), m_loopCondition); + m_instructions.addInstruction(ins); + m_instructionList.push_back(ins); popLoopScope(); } void LLVMCodeBuilder::yield() { - m_instructionList.push_back(std::make_shared(LLVMInstruction::Type::Yield, currentLoopScope(), m_loopCondition)); + auto ins = std::make_shared(LLVMInstruction::Type::Yield, currentLoopScope(), m_loopCondition); + m_instructions.addInstruction(ins); + m_instructionList.push_back(ins); if (m_loopScope >= 0) m_loopScopes[m_loopScope]->containsYield = true; @@ -1889,7 +1912,9 @@ void LLVMCodeBuilder::yield() void LLVMCodeBuilder::createStop() { - m_instructionList.push_back(std::make_shared(LLVMInstruction::Type::Stop, currentLoopScope(), m_loopCondition)); + auto ins = std::make_shared(LLVMInstruction::Type::Stop, currentLoopScope(), m_loopCondition); + m_instructions.addInstruction(ins); + m_instructionList.push_back(ins); } void LLVMCodeBuilder::createProcedureCall(BlockPrototype *prototype, const Compiler::Args &args) @@ -2715,6 +2740,7 @@ LLVMRegister *LLVMCodeBuilder::createOp(const LLVMInstruction &ins, Compiler::St LLVMRegister *LLVMCodeBuilder::createOp(const LLVMInstruction &ins, Compiler::StaticType retType, const Compiler::ArgTypes &argTypes, const Compiler::Args &args) { auto createdIns = std::make_shared(ins); + m_instructions.addInstruction(createdIns); m_instructionList.push_back(createdIns); for (size_t i = 0; i < args.size(); i++) diff --git a/src/engine/internal/llvm/llvmcodebuilder.h b/src/engine/internal/llvm/llvmcodebuilder.h index 45f0e7d83..fb1b1a034 100644 --- a/src/engine/internal/llvm/llvmcodebuilder.h +++ b/src/engine/internal/llvm/llvmcodebuilder.h @@ -11,6 +11,7 @@ #include "../icodebuilder.h" #include "llvminstruction.h" +#include "llvminstructionlist.h" #include "llvmcoroutine.h" #include "llvmvariableptr.h" #include "llvmlistptr.h" @@ -235,6 +236,7 @@ class LLVMCodeBuilder : public ICodeBuilder llvm::FunctionType *m_resumeFuncType = nullptr; [[deprecated]] std::vector> m_instructionList; // TODO: Remove this + LLVMInstructionList m_instructions; std::vector> m_regs; std::vector> m_localVars; LLVMRegister *m_lastConstValue = nullptr; // for reporters and hat predicates From b07f1e16315ab9c49f444839a3291e0ae7c1be42 Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Tue, 22 Jul 2025 20:22:24 +0200 Subject: [PATCH 06/79] LLVMInstructionList: Add missing const qualifiers --- src/engine/internal/llvm/llvminstructionlist.cpp | 4 ++-- src/engine/internal/llvm/llvminstructionlist.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/engine/internal/llvm/llvminstructionlist.cpp b/src/engine/internal/llvm/llvminstructionlist.cpp index 1f4fbe6ab..240afe121 100644 --- a/src/engine/internal/llvm/llvminstructionlist.cpp +++ b/src/engine/internal/llvm/llvminstructionlist.cpp @@ -7,12 +7,12 @@ using namespace libscratchcpp; -LLVMInstruction *LLVMInstructionList::first() +LLVMInstruction *LLVMInstructionList::first() const { return m_first.get(); } -LLVMInstruction *LLVMInstructionList::last() +LLVMInstruction *LLVMInstructionList::last() const { return m_last.get(); } diff --git a/src/engine/internal/llvm/llvminstructionlist.h b/src/engine/internal/llvm/llvminstructionlist.h index 82036555b..e47f4304d 100644 --- a/src/engine/internal/llvm/llvminstructionlist.h +++ b/src/engine/internal/llvm/llvminstructionlist.h @@ -15,8 +15,8 @@ class LLVMInstructionList LLVMInstructionList() = default; LLVMInstructionList(const LLVMInstructionList &) = delete; - LLVMInstruction *first(); - LLVMInstruction *last(); + LLVMInstruction *first() const; + LLVMInstruction *last() const; void addInstruction(std::shared_ptr ins); From 2edff3b16f927a2efdbba3cf52e2369955876326 Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Tue, 22 Jul 2025 20:39:39 +0200 Subject: [PATCH 07/79] LLVMInstructionList: Add containsInstruction() method --- .../internal/llvm/llvminstructionlist.cpp | 14 +++ .../internal/llvm/llvminstructionlist.h | 1 + test/llvm/llvminstructionlist_test.cpp | 93 +++++++++++++++++++ 3 files changed, 108 insertions(+) diff --git a/src/engine/internal/llvm/llvminstructionlist.cpp b/src/engine/internal/llvm/llvminstructionlist.cpp index 240afe121..75162af8b 100644 --- a/src/engine/internal/llvm/llvminstructionlist.cpp +++ b/src/engine/internal/llvm/llvminstructionlist.cpp @@ -17,6 +17,20 @@ LLVMInstruction *LLVMInstructionList::last() const return m_last.get(); } +bool LLVMInstructionList::containsInstruction(LLVMInstruction *ins) const +{ + LLVMInstruction *ptr = m_first.get(); + + while (ptr) { + if (ptr == ins) + return true; + + ptr = ptr->next; + } + + return false; +} + void LLVMInstructionList::addInstruction(std::shared_ptr ins) { if (!(m_first && m_last)) { diff --git a/src/engine/internal/llvm/llvminstructionlist.h b/src/engine/internal/llvm/llvminstructionlist.h index e47f4304d..9502ce1b9 100644 --- a/src/engine/internal/llvm/llvminstructionlist.h +++ b/src/engine/internal/llvm/llvminstructionlist.h @@ -18,6 +18,7 @@ class LLVMInstructionList LLVMInstruction *first() const; LLVMInstruction *last() const; + bool containsInstruction(LLVMInstruction *ins) const; void addInstruction(std::shared_ptr ins); private: diff --git a/test/llvm/llvminstructionlist_test.cpp b/test/llvm/llvminstructionlist_test.cpp index ec5851791..6ba920f52 100644 --- a/test/llvm/llvminstructionlist_test.cpp +++ b/test/llvm/llvminstructionlist_test.cpp @@ -17,6 +17,99 @@ TEST(LLVMInstructionListTest, EmptyList_Last) ASSERT_EQ(list.last(), nullptr); } +TEST(LLVMInstructionListTest, EmptyList_ContainsNull) +{ + LLVMInstructionList list; + ASSERT_FALSE(list.containsInstruction(nullptr)); +} + +TEST(LLVMInstructionListTest, EmptyList_Contains) +{ + LLVMInstructionList list; + auto ins = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + ASSERT_FALSE(list.containsInstruction(ins.get())); +} + +TEST(LLVMInstructionListTest, SingleInstructionList_ContainsExistent) +{ + LLVMInstructionList list; + + auto ins1 = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(ins1); + + ASSERT_TRUE(list.containsInstruction(ins1.get())); +} + +TEST(LLVMInstructionListTest, SingleInstructionList_ContainsNonExistent) +{ + LLVMInstructionList list; + + auto ins1 = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(ins1); + + auto ins = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + ASSERT_FALSE(list.containsInstruction(ins.get())); +} + +TEST(LLVMInstructionListTest, SingleInstructionList_ContainsNull) +{ + LLVMInstructionList list; + + auto ins1 = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(ins1); + + ASSERT_FALSE(list.containsInstruction(nullptr)); +} + +TEST(LLVMInstructionListTest, MultipleInstructionList_ContainsExistent) +{ + LLVMInstructionList list; + + auto ins1 = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(ins1); + + auto ins2 = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(ins2); + + auto ins3 = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(ins3); + + ASSERT_TRUE(list.containsInstruction(ins2.get())); +} + +TEST(LLVMInstructionListTest, MultipleInstructionList_ContainsNonExistent) +{ + LLVMInstructionList list; + + auto ins1 = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(ins1); + + auto ins2 = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(ins2); + + auto ins3 = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(ins3); + + auto ins = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + ASSERT_FALSE(list.containsInstruction(ins.get())); +} + +TEST(LLVMInstructionListTest, MultipleInstructionList_ContainsNull) +{ + LLVMInstructionList list; + + auto ins1 = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(ins1); + + auto ins2 = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(ins2); + + auto ins3 = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(ins3); + + ASSERT_FALSE(list.containsInstruction(nullptr)); +} + TEST(LLVMInstructionListTest, AddSingleInstruction_First) { LLVMInstructionList list; From 7db5a2a0d306f370164f850923cf895fff73e20a Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Tue, 22 Jul 2025 20:40:37 +0200 Subject: [PATCH 08/79] LLVMCodeBuilder: Use raw pointers for variable and list instructions --- src/engine/internal/llvm/llvmcodebuilder.cpp | 57 ++++++++++---------- src/engine/internal/llvm/llvmcodebuilder.h | 10 ++-- 2 files changed, 33 insertions(+), 34 deletions(-) diff --git a/src/engine/internal/llvm/llvmcodebuilder.cpp b/src/engine/internal/llvm/llvmcodebuilder.cpp index 78483a5cb..9fd9913ed 100644 --- a/src/engine/internal/llvm/llvmcodebuilder.cpp +++ b/src/engine/internal/llvm/llvmcodebuilder.cpp @@ -121,7 +121,7 @@ std::shared_ptr LLVMCodeBuilder::finalize() // If there are no write operations outside loops, initialize the stack variable now Variable *variable = var; - auto it = std::find_if(m_variableInstructions.begin(), m_variableInstructions.end(), [variable](const std::shared_ptr &ins) { + auto it = std::find_if(m_variableInstructions.begin(), m_variableInstructions.end(), [variable](const LLVMInstruction *ins) { return ins->type == LLVMInstruction::Type::WriteVariable && ins->workVariable == variable && !ins->loopScope; }); @@ -743,7 +743,7 @@ std::shared_ptr LLVMCodeBuilder::finalize() LLVMVariablePtr &varPtr = m_variablePtrs[step.workVariable]; varPtr.changed = true; - const bool safe = isVarOrListTypeSafe(insPtr, varPtr.type); + const bool safe = isVarOrListTypeSafe(insPtr.get(), varPtr.type); // Initialize stack variable on first assignment if (!varPtr.onStack) { @@ -778,7 +778,7 @@ std::shared_ptr LLVMCodeBuilder::finalize() assert(step.args.size() == 0); LLVMVariablePtr &varPtr = m_variablePtrs[step.workVariable]; - if (!isVarOrListTypeSafe(insPtr, varPtr.type)) + if (!isVarOrListTypeSafe(insPtr.get(), varPtr.type)) varPtr.type = Compiler::StaticType::Unknown; step.functionReturnReg->value = varPtr.onStack && !(step.loopCondition && !m_warp) ? varPtr.stackPtr : varPtr.heapPtr; @@ -806,7 +806,7 @@ std::shared_ptr LLVMCodeBuilder::finalize() const auto &arg = step.args[0]; LLVMListPtr &listPtr = m_listPtrs[step.workList]; - if (!isVarOrListTypeSafe(insPtr, listPtr.type)) + if (!isVarOrListTypeSafe(insPtr.get(), listPtr.type)) listPtr.type = Compiler::StaticType::Unknown; // Range check @@ -846,7 +846,7 @@ std::shared_ptr LLVMCodeBuilder::finalize() typeMap[&listPtr] = listPtr.type; } - if (!isVarOrListTypeSafe(insPtr, listPtr.type)) + if (!isVarOrListTypeSafe(insPtr.get(), listPtr.type)) listPtr.type = Compiler::StaticType::Unknown; // Check if enough space is allocated @@ -894,7 +894,7 @@ std::shared_ptr LLVMCodeBuilder::finalize() typeMap[&listPtr] = listPtr.type; } - if (!isVarOrListTypeSafe(insPtr, listPtr.type)) + if (!isVarOrListTypeSafe(insPtr.get(), listPtr.type)) listPtr.type = Compiler::StaticType::Unknown; llvm::Value *oldAllocatedSize = m_builder.CreateLoad(m_builder.getInt64Ty(), listPtr.allocatedSizePtr); @@ -933,7 +933,7 @@ std::shared_ptr LLVMCodeBuilder::finalize() Compiler::StaticType type = optimizeRegisterType(valueArg.second); LLVMListPtr &listPtr = m_listPtrs[step.workList]; - if (!isVarOrListTypeSafe(insPtr, listPtr.type)) + if (!isVarOrListTypeSafe(insPtr.get(), listPtr.type)) listPtr.type = Compiler::StaticType::Unknown; // Range check @@ -981,7 +981,7 @@ std::shared_ptr LLVMCodeBuilder::finalize() const auto &arg = step.args[0]; LLVMListPtr &listPtr = m_listPtrs[step.workList]; - if (!isVarOrListTypeSafe(insPtr, listPtr.type)) + if (!isVarOrListTypeSafe(insPtr.get(), listPtr.type)) listPtr.type = Compiler::StaticType::Unknown; llvm::Value *min = llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(0.0)); @@ -1012,7 +1012,7 @@ std::shared_ptr LLVMCodeBuilder::finalize() const auto &arg = step.args[0]; LLVMListPtr &listPtr = m_listPtrs[step.workList]; - if (!isVarOrListTypeSafe(insPtr, listPtr.type)) + if (!isVarOrListTypeSafe(insPtr.get(), listPtr.type)) listPtr.type = Compiler::StaticType::Unknown; step.functionReturnReg->value = m_builder.CreateSIToFP(getListItemIndex(listPtr, arg.second), m_builder.getDoubleTy()); @@ -1024,7 +1024,7 @@ std::shared_ptr LLVMCodeBuilder::finalize() const auto &arg = step.args[0]; LLVMListPtr &listPtr = m_listPtrs[step.workList]; - if (!isVarOrListTypeSafe(insPtr, listPtr.type)) + if (!isVarOrListTypeSafe(insPtr.get(), listPtr.type)) listPtr.type = Compiler::StaticType::Unknown; llvm::Value *index = getListItemIndex(listPtr, arg.second); @@ -1460,7 +1460,7 @@ CompilerValue *LLVMCodeBuilder::addVariableValue(Variable *variable) m_instructions.addInstruction(ins); m_instructionList.push_back(ins); - m_variableInstructions.push_back(m_instructionList.back()); + m_variableInstructions.push_back(ins.get()); return addReg(ret, ins); } @@ -1491,7 +1491,7 @@ CompilerValue *LLVMCodeBuilder::addListItem(List *list, CompilerValue *index) m_instructions.addInstruction(ins); m_instructionList.push_back(ins); - m_listInstructions.push_back(m_instructionList.back()); + m_listInstructions.push_back(ins.get()); return addReg(ret, ins); } @@ -1504,7 +1504,7 @@ CompilerValue *LLVMCodeBuilder::addListItemIndex(List *list, CompilerValue *item m_listPtrs[list] = LLVMListPtr(); auto ret = createOp(ins, Compiler::StaticType::Number, Compiler::StaticType::Unknown, { item }); - m_listInstructions.push_back(m_instructionList.back()); + m_listInstructions.push_back(m_instructions.last()); return ret; } @@ -1517,7 +1517,7 @@ CompilerValue *LLVMCodeBuilder::addListContains(List *list, CompilerValue *item) m_listPtrs[list] = LLVMListPtr(); auto ret = createOp(ins, Compiler::StaticType::Bool, Compiler::StaticType::Unknown, { item }); - m_listInstructions.push_back(m_instructionList.back()); + m_listInstructions.push_back(m_instructions.last()); return ret; } @@ -1745,7 +1745,7 @@ void LLVMCodeBuilder::createVariableWrite(Variable *variable, CompilerValue *val m_variablePtrs[variable].loopVariableWrites[scope.get()].push_back(m_instructionList.back()); } - m_variableInstructions.push_back(m_instructionList.back()); + m_variableInstructions.push_back(m_instructions.last()); } void LLVMCodeBuilder::createListClear(List *list) @@ -1782,7 +1782,7 @@ void LLVMCodeBuilder::createListAppend(List *list, CompilerValue *item) m_listPtrs[list].loopListWrites[scope.get()].push_back(m_instructionList.back()); } - m_listInstructions.push_back(m_instructionList.back()); + m_listInstructions.push_back(m_instructions.last()); } void LLVMCodeBuilder::createListInsert(List *list, CompilerValue *index, CompilerValue *item) @@ -1799,7 +1799,7 @@ void LLVMCodeBuilder::createListInsert(List *list, CompilerValue *index, Compile m_listPtrs[list].loopListWrites[scope.get()].push_back(m_instructionList.back()); } - m_listInstructions.push_back(m_instructionList.back()); + m_listInstructions.push_back(m_instructions.last()); } void LLVMCodeBuilder::createListReplace(List *list, CompilerValue *index, CompilerValue *item) @@ -1816,7 +1816,7 @@ void LLVMCodeBuilder::createListReplace(List *list, CompilerValue *index, Compil m_listPtrs[list].loopListWrites[scope.get()].push_back(m_instructionList.back()); } - m_listInstructions.push_back(m_instructionList.back()); + m_listInstructions.push_back(m_instructions.last()); } void LLVMCodeBuilder::beginIfStatement(CompilerValue *cond) @@ -2528,14 +2528,14 @@ void LLVMCodeBuilder::updateListDataPtr(const LLVMListPtr &listPtr) m_builder.CreateStore(m_builder.getInt1(false), listPtr.dataPtrDirty); } -bool LLVMCodeBuilder::isVarOrListTypeSafe(std::shared_ptr ins, Compiler::StaticType expectedType) const +bool LLVMCodeBuilder::isVarOrListTypeSafe(LLVMInstruction *ins, Compiler::StaticType expectedType) const { std::unordered_set processed; int counter = 0; return isVarOrListTypeSafe(ins, expectedType, processed, counter); } -bool LLVMCodeBuilder::isVarOrListTypeSafe(std::shared_ptr ins, Compiler::StaticType expectedType, std::unordered_set &log, int &c) const +bool LLVMCodeBuilder::isVarOrListTypeSafe(LLVMInstruction *ins, Compiler::StaticType expectedType, std::unordered_set &log, int &c) const { /* * The main part of the loop type analyzer. @@ -2571,12 +2571,12 @@ bool LLVMCodeBuilder::isVarOrListTypeSafe(std::shared_ptr ins, * * Increment counter to ignore last n write operations. */ - if (log.find(ins.get()) != log.cend()) + if (log.find(ins) != log.cend()) c++; else - log.insert(ins.get()); + log.insert(ins); - assert(std::find(m_instructionList.begin(), m_instructionList.end(), ins) != m_instructionList.end()); + assert(m_instructions.containsInstruction(ins)); const LLVMVariablePtr *varPtr = ins->workVariable ? &m_variablePtrs.at(ins->workVariable) : nullptr; const LLVMListPtr *listPtr = ins->workList ? &m_listPtrs.at(ins->workList) : nullptr; assert((varPtr || listPtr) && !(varPtr && listPtr)); @@ -2590,7 +2590,7 @@ bool LLVMCodeBuilder::isVarOrListTypeSafe(std::shared_ptr ins, if (scope->containsYield && !m_warp) return false; - std::shared_ptr write; + LLVMInstruction *write = nullptr; const auto &instructions = varPtr ? m_variableInstructions : m_listInstructions; // Find this instruction @@ -2646,7 +2646,7 @@ bool LLVMCodeBuilder::isVarOrListTypeSafe(std::shared_ptr ins, } // Get all write operations in all loop scopes (from the root loop scope) - std::vector> lastWrites; + std::vector lastWrites; while (checkScope) { auto it = loopWrites.find(checkScope); @@ -2656,7 +2656,7 @@ bool LLVMCodeBuilder::isVarOrListTypeSafe(std::shared_ptr ins, const auto &writes = it->second; for (auto w : writes) - lastWrites.push_back(w); + lastWrites.push_back(w.get()); } if (checkScope->childScopes.empty()) @@ -2693,8 +2693,7 @@ bool LLVMCodeBuilder::isVarOrListTypeSafe(std::shared_ptr ins, return false; } -bool LLVMCodeBuilder::isVarOrListWriteResultTypeSafe(std::shared_ptr ins, Compiler::StaticType expectedType, bool ignoreSavedType, std::unordered_set &log, int &c) - const +bool LLVMCodeBuilder::isVarOrListWriteResultTypeSafe(LLVMInstruction *ins, Compiler::StaticType expectedType, bool ignoreSavedType, std::unordered_set &log, int &c) const { const LLVMVariablePtr *varPtr = ins->workVariable ? &m_variablePtrs.at(ins->workVariable) : nullptr; const LLVMListPtr *listPtr = ins->workList ? &m_listPtrs.at(ins->workList) : nullptr; @@ -2705,7 +2704,7 @@ bool LLVMCodeBuilder::isVarOrListWriteResultTypeSafe(std::shared_ptrinstruction; if (argIns && (argIns->type == LLVMInstruction::Type::ReadVariable || argIns->type == LLVMInstruction::Type::GetListItem)) - return isVarOrListTypeSafe(argIns, expectedType, log, c); + return isVarOrListTypeSafe(argIns.get(), expectedType, log, c); // Check written type const bool typeMatches = (optimizeRegisterType(arg) == expectedType); diff --git a/src/engine/internal/llvm/llvmcodebuilder.h b/src/engine/internal/llvm/llvmcodebuilder.h index fb1b1a034..cef8c9f4f 100644 --- a/src/engine/internal/llvm/llvmcodebuilder.h +++ b/src/engine/internal/llvm/llvmcodebuilder.h @@ -154,9 +154,9 @@ class LLVMCodeBuilder : public ICodeBuilder void reloadVariables(llvm::Value *targetVariables); void reloadLists(); void updateListDataPtr(const LLVMListPtr &listPtr); - bool isVarOrListTypeSafe(std::shared_ptr ins, Compiler::StaticType expectedType) const; - bool isVarOrListTypeSafe(std::shared_ptr ins, Compiler::StaticType expectedType, std::unordered_set &log, int &c) const; - bool isVarOrListWriteResultTypeSafe(std::shared_ptr ins, Compiler::StaticType expectedType, bool ignoreSavedType, std::unordered_set &log, int &c) const; + bool isVarOrListTypeSafe(LLVMInstruction *ins, Compiler::StaticType expectedType) const; + bool isVarOrListTypeSafe(LLVMInstruction *ins, Compiler::StaticType expectedType, std::unordered_set &log, int &c) const; + bool isVarOrListWriteResultTypeSafe(LLVMInstruction *ins, Compiler::StaticType expectedType, bool ignoreSavedType, std::unordered_set &log, int &c) const; LLVMRegister *createOp(LLVMInstruction::Type type, Compiler::StaticType retType, Compiler::StaticType argType, const Compiler::Args &args); LLVMRegister *createOp(LLVMInstruction::Type type, Compiler::StaticType retType, const Compiler::ArgTypes &argTypes = {}, const Compiler::Args &args = {}); @@ -251,8 +251,8 @@ class LLVMCodeBuilder : public ICodeBuilder long m_loopScopeCounter = 0; // replacement for m_loopScopes size in build phase std::vector m_loopScopeTree; bool m_loopCondition = false; // whether we're currently compiling a loop condition - std::vector> m_variableInstructions; - std::vector> m_listInstructions; + std::vector m_variableInstructions; + std::vector m_listInstructions; std::vector> m_stringHeap; // scopes std::shared_ptr m_output; From b00c6da57815ba8d1eac69df5010a62489793395 Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Tue, 22 Jul 2025 20:51:10 +0200 Subject: [PATCH 09/79] LLVMCodeBuilder: Read instructions from m_instructions --- src/engine/internal/llvm/llvmcodebuilder.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/engine/internal/llvm/llvmcodebuilder.cpp b/src/engine/internal/llvm/llvmcodebuilder.cpp index 9fd9913ed..519194504 100644 --- a/src/engine/internal/llvm/llvmcodebuilder.cpp +++ b/src/engine/internal/llvm/llvmcodebuilder.cpp @@ -153,7 +153,7 @@ std::shared_ptr LLVMCodeBuilder::finalize() pushScopeLevel(); // Execute recorded steps - for (const auto insPtr : m_instructionList) { + for (LLVMInstruction *insPtr = m_instructions.first(); insPtr; insPtr = insPtr->next) { const LLVMInstruction &step = *insPtr; switch (step.type) { @@ -743,7 +743,7 @@ std::shared_ptr LLVMCodeBuilder::finalize() LLVMVariablePtr &varPtr = m_variablePtrs[step.workVariable]; varPtr.changed = true; - const bool safe = isVarOrListTypeSafe(insPtr.get(), varPtr.type); + const bool safe = isVarOrListTypeSafe(insPtr, varPtr.type); // Initialize stack variable on first assignment if (!varPtr.onStack) { @@ -778,7 +778,7 @@ std::shared_ptr LLVMCodeBuilder::finalize() assert(step.args.size() == 0); LLVMVariablePtr &varPtr = m_variablePtrs[step.workVariable]; - if (!isVarOrListTypeSafe(insPtr.get(), varPtr.type)) + if (!isVarOrListTypeSafe(insPtr, varPtr.type)) varPtr.type = Compiler::StaticType::Unknown; step.functionReturnReg->value = varPtr.onStack && !(step.loopCondition && !m_warp) ? varPtr.stackPtr : varPtr.heapPtr; @@ -806,7 +806,7 @@ std::shared_ptr LLVMCodeBuilder::finalize() const auto &arg = step.args[0]; LLVMListPtr &listPtr = m_listPtrs[step.workList]; - if (!isVarOrListTypeSafe(insPtr.get(), listPtr.type)) + if (!isVarOrListTypeSafe(insPtr, listPtr.type)) listPtr.type = Compiler::StaticType::Unknown; // Range check @@ -846,7 +846,7 @@ std::shared_ptr LLVMCodeBuilder::finalize() typeMap[&listPtr] = listPtr.type; } - if (!isVarOrListTypeSafe(insPtr.get(), listPtr.type)) + if (!isVarOrListTypeSafe(insPtr, listPtr.type)) listPtr.type = Compiler::StaticType::Unknown; // Check if enough space is allocated @@ -894,7 +894,7 @@ std::shared_ptr LLVMCodeBuilder::finalize() typeMap[&listPtr] = listPtr.type; } - if (!isVarOrListTypeSafe(insPtr.get(), listPtr.type)) + if (!isVarOrListTypeSafe(insPtr, listPtr.type)) listPtr.type = Compiler::StaticType::Unknown; llvm::Value *oldAllocatedSize = m_builder.CreateLoad(m_builder.getInt64Ty(), listPtr.allocatedSizePtr); @@ -933,7 +933,7 @@ std::shared_ptr LLVMCodeBuilder::finalize() Compiler::StaticType type = optimizeRegisterType(valueArg.second); LLVMListPtr &listPtr = m_listPtrs[step.workList]; - if (!isVarOrListTypeSafe(insPtr.get(), listPtr.type)) + if (!isVarOrListTypeSafe(insPtr, listPtr.type)) listPtr.type = Compiler::StaticType::Unknown; // Range check @@ -981,7 +981,7 @@ std::shared_ptr LLVMCodeBuilder::finalize() const auto &arg = step.args[0]; LLVMListPtr &listPtr = m_listPtrs[step.workList]; - if (!isVarOrListTypeSafe(insPtr.get(), listPtr.type)) + if (!isVarOrListTypeSafe(insPtr, listPtr.type)) listPtr.type = Compiler::StaticType::Unknown; llvm::Value *min = llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(0.0)); @@ -1012,7 +1012,7 @@ std::shared_ptr LLVMCodeBuilder::finalize() const auto &arg = step.args[0]; LLVMListPtr &listPtr = m_listPtrs[step.workList]; - if (!isVarOrListTypeSafe(insPtr.get(), listPtr.type)) + if (!isVarOrListTypeSafe(insPtr, listPtr.type)) listPtr.type = Compiler::StaticType::Unknown; step.functionReturnReg->value = m_builder.CreateSIToFP(getListItemIndex(listPtr, arg.second), m_builder.getDoubleTy()); @@ -1024,7 +1024,7 @@ std::shared_ptr LLVMCodeBuilder::finalize() const auto &arg = step.args[0]; LLVMListPtr &listPtr = m_listPtrs[step.workList]; - if (!isVarOrListTypeSafe(insPtr.get(), listPtr.type)) + if (!isVarOrListTypeSafe(insPtr, listPtr.type)) listPtr.type = Compiler::StaticType::Unknown; llvm::Value *index = getListItemIndex(listPtr, arg.second); From b0b8c7e238130bfd39277474da4c406e8734f2f9 Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Tue, 22 Jul 2025 21:05:02 +0200 Subject: [PATCH 10/79] LLVMInstructionList: Add predicate-based contains method --- .../internal/llvm/llvminstructionlist.cpp | 14 +++++ .../internal/llvm/llvminstructionlist.h | 3 + test/llvm/llvminstructionlist_test.cpp | 60 +++++++++++++++++++ 3 files changed, 77 insertions(+) diff --git a/src/engine/internal/llvm/llvminstructionlist.cpp b/src/engine/internal/llvm/llvminstructionlist.cpp index 75162af8b..f8ad62efb 100644 --- a/src/engine/internal/llvm/llvminstructionlist.cpp +++ b/src/engine/internal/llvm/llvminstructionlist.cpp @@ -31,6 +31,20 @@ bool LLVMInstructionList::containsInstruction(LLVMInstruction *ins) const return false; } +bool LLVMInstructionList::containsInstruction(std::function func) const +{ + LLVMInstruction *ptr = m_first.get(); + + while (ptr) { + if (func(ptr)) + return true; + + ptr = ptr->next; + } + + return false; +} + void LLVMInstructionList::addInstruction(std::shared_ptr ins) { if (!(m_first && m_last)) { diff --git a/src/engine/internal/llvm/llvminstructionlist.h b/src/engine/internal/llvm/llvminstructionlist.h index 9502ce1b9..54dd4b7fc 100644 --- a/src/engine/internal/llvm/llvminstructionlist.h +++ b/src/engine/internal/llvm/llvminstructionlist.h @@ -3,6 +3,7 @@ #pragma once #include +#include namespace libscratchcpp { @@ -19,6 +20,8 @@ class LLVMInstructionList LLVMInstruction *last() const; bool containsInstruction(LLVMInstruction *ins) const; + bool containsInstruction(std::function func) const; + void addInstruction(std::shared_ptr ins); private: diff --git a/test/llvm/llvminstructionlist_test.cpp b/test/llvm/llvminstructionlist_test.cpp index 6ba920f52..902b008b0 100644 --- a/test/llvm/llvminstructionlist_test.cpp +++ b/test/llvm/llvminstructionlist_test.cpp @@ -23,6 +23,13 @@ TEST(LLVMInstructionListTest, EmptyList_ContainsNull) ASSERT_FALSE(list.containsInstruction(nullptr)); } +TEST(LLVMInstructionListTest, EmptyList_ContainsFunc) +{ + LLVMInstructionList list; + auto ins = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + ASSERT_FALSE(list.containsInstruction([](const LLVMInstruction *) { return true; })); +} + TEST(LLVMInstructionListTest, EmptyList_Contains) { LLVMInstructionList list; @@ -61,6 +68,27 @@ TEST(LLVMInstructionListTest, SingleInstructionList_ContainsNull) ASSERT_FALSE(list.containsInstruction(nullptr)); } +TEST(LLVMInstructionListTest, SingleInstructionList_ContainsFuncTrue) +{ + LLVMInstructionList list; + + auto ins1 = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(ins1); + + ASSERT_TRUE(list.containsInstruction([](const LLVMInstruction *) { return true; })); +} + +TEST(LLVMInstructionListTest, SingleInstructionList_ContainsFuncFalse) +{ + LLVMInstructionList list; + + auto ins1 = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(ins1); + + auto ins = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + ASSERT_FALSE(list.containsInstruction([](const LLVMInstruction *) { return false; })); +} + TEST(LLVMInstructionListTest, MultipleInstructionList_ContainsExistent) { LLVMInstructionList list; @@ -110,6 +138,38 @@ TEST(LLVMInstructionListTest, MultipleInstructionList_ContainsNull) ASSERT_FALSE(list.containsInstruction(nullptr)); } +TEST(LLVMInstructionListTest, MultipleInstructionList_ContainsExistentFunc) +{ + LLVMInstructionList list; + + auto ins1 = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(ins1); + + auto ins2 = std::make_shared(LLVMInstruction::Type::Stop, nullptr, false); + list.addInstruction(ins2); + + auto ins3 = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(ins3); + + ASSERT_TRUE(list.containsInstruction([](const LLVMInstruction *ins) { return ins->type == LLVMInstruction::Type::Stop; })); +} + +TEST(LLVMInstructionListTest, MultipleInstructionList_ContainsNonExistentFunc) +{ + LLVMInstructionList list; + + auto ins1 = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(ins1); + + auto ins2 = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(ins2); + + auto ins3 = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(ins3); + + ASSERT_FALSE(list.containsInstruction([](const LLVMInstruction *ins) { return ins->type == LLVMInstruction::Type::Stop; })); +} + TEST(LLVMInstructionListTest, AddSingleInstruction_First) { LLVMInstructionList list; From 207b328019fe494060a751729b6f370884c99391 Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Tue, 22 Jul 2025 21:11:11 +0200 Subject: [PATCH 11/79] LLVMInstructionList: Add empty() method --- .../internal/llvm/llvminstructionlist.h | 2 ++ test/llvm/llvminstructionlist_test.cpp | 31 +++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/src/engine/internal/llvm/llvminstructionlist.h b/src/engine/internal/llvm/llvminstructionlist.h index 54dd4b7fc..e7cadb9c4 100644 --- a/src/engine/internal/llvm/llvminstructionlist.h +++ b/src/engine/internal/llvm/llvminstructionlist.h @@ -19,6 +19,8 @@ class LLVMInstructionList LLVMInstruction *first() const; LLVMInstruction *last() const; + bool empty() const { return !first(); } + bool containsInstruction(LLVMInstruction *ins) const; bool containsInstruction(std::function func) const; diff --git a/test/llvm/llvminstructionlist_test.cpp b/test/llvm/llvminstructionlist_test.cpp index 902b008b0..7cc125846 100644 --- a/test/llvm/llvminstructionlist_test.cpp +++ b/test/llvm/llvminstructionlist_test.cpp @@ -17,6 +17,12 @@ TEST(LLVMInstructionListTest, EmptyList_Last) ASSERT_EQ(list.last(), nullptr); } +TEST(LLVMInstructionListTest, EmptyList_Empty) +{ + LLVMInstructionList list; + ASSERT_TRUE(list.empty()); +} + TEST(LLVMInstructionListTest, EmptyList_ContainsNull) { LLVMInstructionList list; @@ -188,6 +194,15 @@ TEST(LLVMInstructionListTest, AddSingleInstruction_Last) ASSERT_EQ(list.last(), ins.get()); } +TEST(LLVMInstructionListTest, AddSingleInstruction_Empty) +{ + LLVMInstructionList list; + auto ins = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(ins); + + ASSERT_FALSE(list.empty()); +} + TEST(LLVMInstructionListTest, AddSingleInstruction_Previous) { LLVMInstructionList list; @@ -238,6 +253,22 @@ TEST(LLVMInstructionListTest, AddMultipleInstructions_Last) ASSERT_EQ(list.last(), ins3.get()); } +TEST(LLVMInstructionListTest, AddMultipleInstructions_Empty) +{ + LLVMInstructionList list; + + auto ins1 = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(ins1); + + auto ins2 = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(ins2); + + auto ins3 = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(ins3); + + ASSERT_FALSE(list.empty()); +} + TEST(LLVMInstructionListTest, AddMultipleInstructions_PreviousOfFirst) { LLVMInstructionList list; From 80032ee4b95c999e0a55de79635d454aa26e51f9 Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Tue, 22 Jul 2025 21:18:54 +0200 Subject: [PATCH 12/79] Use raw pointers for loop var/list write instructions --- src/engine/internal/llvm/llvmcodebuilder.cpp | 10 +++++----- src/engine/internal/llvm/llvmlistptr.h | 2 +- src/engine/internal/llvm/llvmvariableptr.h | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/engine/internal/llvm/llvmcodebuilder.cpp b/src/engine/internal/llvm/llvmcodebuilder.cpp index 519194504..b64deaf75 100644 --- a/src/engine/internal/llvm/llvmcodebuilder.cpp +++ b/src/engine/internal/llvm/llvmcodebuilder.cpp @@ -1742,7 +1742,7 @@ void LLVMCodeBuilder::createVariableWrite(Variable *variable, CompilerValue *val if (m_loopScope >= 0) { auto scope = m_loopScopes[m_loopScope]; - m_variablePtrs[variable].loopVariableWrites[scope.get()].push_back(m_instructionList.back()); + m_variablePtrs[variable].loopVariableWrites[scope.get()].push_back(m_instructions.last()); } m_variableInstructions.push_back(m_instructions.last()); @@ -1779,7 +1779,7 @@ void LLVMCodeBuilder::createListAppend(List *list, CompilerValue *item) if (m_loopScope >= 0) { auto scope = m_loopScopes[m_loopScope]; - m_listPtrs[list].loopListWrites[scope.get()].push_back(m_instructionList.back()); + m_listPtrs[list].loopListWrites[scope.get()].push_back(m_instructions.last()); } m_listInstructions.push_back(m_instructions.last()); @@ -1796,7 +1796,7 @@ void LLVMCodeBuilder::createListInsert(List *list, CompilerValue *index, Compile if (m_loopScope >= 0) { auto scope = m_loopScopes[m_loopScope]; - m_listPtrs[list].loopListWrites[scope.get()].push_back(m_instructionList.back()); + m_listPtrs[list].loopListWrites[scope.get()].push_back(m_instructions.last()); } m_listInstructions.push_back(m_instructions.last()); @@ -1813,7 +1813,7 @@ void LLVMCodeBuilder::createListReplace(List *list, CompilerValue *index, Compil if (m_loopScope >= 0) { auto scope = m_loopScopes[m_loopScope]; - m_listPtrs[list].loopListWrites[scope.get()].push_back(m_instructionList.back()); + m_listPtrs[list].loopListWrites[scope.get()].push_back(m_instructions.last()); } m_listInstructions.push_back(m_instructions.last()); @@ -2656,7 +2656,7 @@ bool LLVMCodeBuilder::isVarOrListTypeSafe(LLVMInstruction *ins, Compiler::Static const auto &writes = it->second; for (auto w : writes) - lastWrites.push_back(w.get()); + lastWrites.push_back(w); } if (checkScope->childScopes.empty()) diff --git a/src/engine/internal/llvm/llvmlistptr.h b/src/engine/internal/llvm/llvmlistptr.h index 99fc74a37..2dd758696 100644 --- a/src/engine/internal/llvm/llvmlistptr.h +++ b/src/engine/internal/llvm/llvmlistptr.h @@ -28,7 +28,7 @@ struct LLVMListPtr Compiler::StaticType type = Compiler::StaticType::Unknown; // Used in build phase to check the type safety of lists in loops - std::unordered_map>> loopListWrites; // loop scope, write instructions + std::unordered_map> loopListWrites; // loop scope, write instructions }; } // namespace libscratchcpp diff --git a/src/engine/internal/llvm/llvmvariableptr.h b/src/engine/internal/llvm/llvmvariableptr.h index 88ddcc03f..9907a5aa8 100644 --- a/src/engine/internal/llvm/llvmvariableptr.h +++ b/src/engine/internal/llvm/llvmvariableptr.h @@ -27,7 +27,7 @@ struct LLVMVariablePtr bool changed = false; // Used in build phase to check the type safety of variables in loops - std::unordered_map>> loopVariableWrites; // loop scope, write instructions + std::unordered_map> loopVariableWrites; // loop scope, write instructions }; } // namespace libscratchcpp From 7d80b2022d8bf136aedec2dd20d3f1c698fd3e40 Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Tue, 22 Jul 2025 21:20:46 +0200 Subject: [PATCH 13/79] LLVMCodeBuilder: Drop m_instructionList --- src/engine/internal/llvm/llvmcodebuilder.cpp | 40 ++++++-------------- src/engine/internal/llvm/llvmcodebuilder.h | 1 - 2 files changed, 11 insertions(+), 30 deletions(-) diff --git a/src/engine/internal/llvm/llvmcodebuilder.cpp b/src/engine/internal/llvm/llvmcodebuilder.cpp index b64deaf75..b61a477b3 100644 --- a/src/engine/internal/llvm/llvmcodebuilder.cpp +++ b/src/engine/internal/llvm/llvmcodebuilder.cpp @@ -53,12 +53,11 @@ std::shared_ptr LLVMCodeBuilder::finalize() { if (!m_warp) { // Do not create coroutine if there are no yield instructions nor non-warp procedure calls - auto it = std::find_if(m_instructionList.begin(), m_instructionList.end(), [](const std::shared_ptr &step) { - return step->type == LLVMInstruction::Type::Yield || (step->type == LLVMInstruction::Type::CallProcedure && step->procedurePrototype && !step->procedurePrototype->warp()); - }); - - if (it == m_instructionList.end()) + if (!m_instructions.containsInstruction([](const LLVMInstruction *step) { + return step->type == LLVMInstruction::Type::Yield || (step->type == LLVMInstruction::Type::CallProcedure && step->procedurePrototype && !step->procedurePrototype->warp()); + })) { m_warp = true; + } // Only create coroutines in scripts if (m_codeType != Compiler::CodeType::Script) @@ -1340,8 +1339,8 @@ std::shared_ptr LLVMCodeBuilder::finalize() case Compiler::CodeType::Reporter: { // Use last instruction return value (or last constant) and create a ValueData instance - assert(!m_instructionList.empty() || m_lastConstValue); - LLVMRegister *ret = m_instructionList.empty() ? m_lastConstValue : m_instructionList.back()->functionReturnReg; + assert(!m_instructions.empty() || m_lastConstValue); + LLVMRegister *ret = m_instructions.empty() ? m_lastConstValue : m_instructions.last()->functionReturnReg; llvm::Value *copy = createNewValue(ret); m_builder.CreateRet(m_builder.CreateLoad(m_valueDataType, copy)); break; @@ -1349,12 +1348,12 @@ std::shared_ptr LLVMCodeBuilder::finalize() case Compiler::CodeType::HatPredicate: // Use last instruction return value (or last constant) - assert(!m_instructionList.empty() || m_lastConstValue); + assert(!m_instructions.empty() || m_lastConstValue); - if (m_instructionList.empty()) + if (m_instructions.empty()) m_builder.CreateRet(castValue(m_lastConstValue, Compiler::StaticType::Bool)); else - m_builder.CreateRet(castValue(m_instructionList.back()->functionReturnReg, Compiler::StaticType::Bool)); + m_builder.CreateRet(castValue(m_instructions.last()->functionReturnReg, Compiler::StaticType::Bool)); break; } @@ -1396,25 +1395,23 @@ CompilerValue *LLVMCodeBuilder::addFunctionCall(const std::string &functionName, auto reg = std::make_shared(returnType); reg->isRawValue = true; ins->functionReturnReg = reg.get(); - m_instructionList.push_back(ins); return addReg(reg, ins); } - m_instructionList.push_back(ins); return nullptr; } CompilerValue *LLVMCodeBuilder::addTargetFunctionCall(const std::string &functionName, Compiler::StaticType returnType, const Compiler::ArgTypes &argTypes, const Compiler::Args &args) { CompilerValue *ret = addFunctionCall(functionName, returnType, argTypes, args); - m_instructionList.back()->functionTargetArg = true; + m_instructions.last()->functionTargetArg = true; return ret; } CompilerValue *LLVMCodeBuilder::addFunctionCallWithCtx(const std::string &functionName, Compiler::StaticType returnType, const Compiler::ArgTypes &argTypes, const Compiler::Args &args) { CompilerValue *ret = addFunctionCall(functionName, returnType, argTypes, args); - m_instructionList.back()->functionCtxArg = true; + m_instructions.last()->functionCtxArg = true; return ret; } @@ -1459,7 +1456,6 @@ CompilerValue *LLVMCodeBuilder::addVariableValue(Variable *variable) ins->functionReturnReg = ret.get(); m_instructions.addInstruction(ins); - m_instructionList.push_back(ins); m_variableInstructions.push_back(ins.get()); return addReg(ret, ins); } @@ -1490,7 +1486,6 @@ CompilerValue *LLVMCodeBuilder::addListItem(List *list, CompilerValue *index) ins->functionReturnReg = ret.get(); m_instructions.addInstruction(ins); - m_instructionList.push_back(ins); m_listInstructions.push_back(ins.get()); return addReg(ret, ins); } @@ -1554,7 +1549,6 @@ CompilerValue *LLVMCodeBuilder::addProcedureArgument(const std::string &name) ins->procedureArgIndex = index; m_instructions.addInstruction(ins); - m_instructionList.push_back(ins); return addReg(ret, ins); } @@ -1824,21 +1818,18 @@ void LLVMCodeBuilder::beginIfStatement(CompilerValue *cond) auto ins = std::make_shared(LLVMInstruction::Type::BeginIf, currentLoopScope(), m_loopCondition); ins->args.push_back({ Compiler::StaticType::Bool, dynamic_cast(cond) }); m_instructions.addInstruction(ins); - m_instructionList.push_back(ins); } void LLVMCodeBuilder::beginElseBranch() { auto ins = std::make_shared(LLVMInstruction::Type::BeginElse, currentLoopScope(), m_loopCondition); m_instructions.addInstruction(ins); - m_instructionList.push_back(ins); } void LLVMCodeBuilder::endIf() { auto ins = std::make_shared(LLVMInstruction::Type::EndIf, currentLoopScope(), m_loopCondition); m_instructions.addInstruction(ins); - m_instructionList.push_back(ins); } void LLVMCodeBuilder::beginRepeatLoop(CompilerValue *count) @@ -1848,7 +1839,6 @@ void LLVMCodeBuilder::beginRepeatLoop(CompilerValue *count) auto ins = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, currentLoopScope(), m_loopCondition); ins->args.push_back({ Compiler::StaticType::Number, dynamic_cast(count) }); m_instructions.addInstruction(ins); - m_instructionList.push_back(ins); pushLoopScope(false); } @@ -1860,7 +1850,6 @@ void LLVMCodeBuilder::beginWhileLoop(CompilerValue *cond) auto ins = std::make_shared(LLVMInstruction::Type::BeginWhileLoop, currentLoopScope(), m_loopCondition); ins->args.push_back({ Compiler::StaticType::Bool, dynamic_cast(cond) }); m_instructions.addInstruction(ins); - m_instructionList.push_back(ins); pushLoopScope(false); } @@ -1872,7 +1861,6 @@ void LLVMCodeBuilder::beginRepeatUntilLoop(CompilerValue *cond) auto ins = std::make_shared(LLVMInstruction::Type::BeginRepeatUntilLoop, currentLoopScope(), m_loopCondition); ins->args.push_back({ Compiler::StaticType::Bool, dynamic_cast(cond) }); m_instructions.addInstruction(ins); - m_instructionList.push_back(ins); pushLoopScope(false); } @@ -1882,7 +1870,6 @@ void LLVMCodeBuilder::beginLoopCondition() auto ins = std::make_shared(LLVMInstruction::Type::BeginLoopCondition, currentLoopScope(), m_loopCondition); m_instructions.addInstruction(ins); - m_instructionList.push_back(ins); m_loopCondition = true; } @@ -1891,12 +1878,10 @@ void LLVMCodeBuilder::endLoop() if (!m_warp) { auto ins = std::make_shared(LLVMInstruction::Type::Yield, currentLoopScope(), m_loopCondition); m_instructions.addInstruction(ins); - m_instructionList.push_back(ins); } auto ins = std::make_shared(LLVMInstruction::Type::EndLoop, currentLoopScope(), m_loopCondition); m_instructions.addInstruction(ins); - m_instructionList.push_back(ins); popLoopScope(); } @@ -1904,7 +1889,6 @@ void LLVMCodeBuilder::yield() { auto ins = std::make_shared(LLVMInstruction::Type::Yield, currentLoopScope(), m_loopCondition); m_instructions.addInstruction(ins); - m_instructionList.push_back(ins); if (m_loopScope >= 0) m_loopScopes[m_loopScope]->containsYield = true; @@ -1914,7 +1898,6 @@ void LLVMCodeBuilder::createStop() { auto ins = std::make_shared(LLVMInstruction::Type::Stop, currentLoopScope(), m_loopCondition); m_instructions.addInstruction(ins); - m_instructionList.push_back(ins); } void LLVMCodeBuilder::createProcedureCall(BlockPrototype *prototype, const Compiler::Args &args) @@ -2740,7 +2723,6 @@ LLVMRegister *LLVMCodeBuilder::createOp(const LLVMInstruction &ins, Compiler::St { auto createdIns = std::make_shared(ins); m_instructions.addInstruction(createdIns); - m_instructionList.push_back(createdIns); for (size_t i = 0; i < args.size(); i++) createdIns->args.push_back({ argTypes[i], dynamic_cast(args[i]) }); diff --git a/src/engine/internal/llvm/llvmcodebuilder.h b/src/engine/internal/llvm/llvmcodebuilder.h index cef8c9f4f..a3b71b2e6 100644 --- a/src/engine/internal/llvm/llvmcodebuilder.h +++ b/src/engine/internal/llvm/llvmcodebuilder.h @@ -235,7 +235,6 @@ class LLVMCodeBuilder : public ICodeBuilder llvm::StructType *m_stringPtrType = nullptr; llvm::FunctionType *m_resumeFuncType = nullptr; - [[deprecated]] std::vector> m_instructionList; // TODO: Remove this LLVMInstructionList m_instructions; std::vector> m_regs; std::vector> m_localVars; From 0a813197bd793a647f28b13f09922bb98c815995 Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Tue, 22 Jul 2025 21:32:59 +0200 Subject: [PATCH 14/79] Ensure LLVM instructions are not deleted --- src/engine/internal/llvm/llvminstruction.h | 1 + src/engine/internal/llvm/llvminstructionlist.cpp | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/engine/internal/llvm/llvminstruction.h b/src/engine/internal/llvm/llvminstruction.h index 1116b347f..091539bbc 100644 --- a/src/engine/internal/llvm/llvminstruction.h +++ b/src/engine/internal/llvm/llvminstruction.h @@ -104,6 +104,7 @@ struct LLVMInstruction // Linked list LLVMInstruction *previous = nullptr; LLVMInstruction *next = nullptr; + std::shared_ptr _next; // ensure items are not deleted }; } // namespace libscratchcpp diff --git a/src/engine/internal/llvm/llvminstructionlist.cpp b/src/engine/internal/llvm/llvminstructionlist.cpp index f8ad62efb..61b8d6c38 100644 --- a/src/engine/internal/llvm/llvminstructionlist.cpp +++ b/src/engine/internal/llvm/llvminstructionlist.cpp @@ -55,8 +55,10 @@ void LLVMInstructionList::addInstruction(std::shared_ptr ins) ins->previous = nullptr; ins->next = nullptr; + ins->_next = nullptr; } else { m_last->next = ins.get(); + m_last->_next = ins; ins->previous = m_last.get(); m_last = ins; } From b419577f4b41c74596f9408cc5440e1ba6f15f5a Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Wed, 23 Jul 2025 13:04:47 +0200 Subject: [PATCH 15/79] LLVMCodeBuilder: Store variable pointer in LLVMVariablePtr --- src/engine/internal/llvm/llvmcodebuilder.cpp | 8 ++++++-- src/engine/internal/llvm/llvmvariableptr.h | 1 + 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/engine/internal/llvm/llvmcodebuilder.cpp b/src/engine/internal/llvm/llvmcodebuilder.cpp index b61a477b3..f39ad6653 100644 --- a/src/engine/internal/llvm/llvmcodebuilder.cpp +++ b/src/engine/internal/llvm/llvmcodebuilder.cpp @@ -1448,8 +1448,10 @@ CompilerValue *LLVMCodeBuilder::addVariableValue(Variable *variable) auto ins = std::make_shared(LLVMInstruction::Type::ReadVariable, currentLoopScope(), m_loopCondition); ins->workVariable = variable; - if (m_variablePtrs.find(variable) == m_variablePtrs.cend()) + if (m_variablePtrs.find(variable) == m_variablePtrs.cend()) { m_variablePtrs[variable] = LLVMVariablePtr(); + m_variablePtrs[variable].var = variable; + } auto ret = std::make_shared(Compiler::StaticType::Unknown); ret->isRawValue = false; @@ -1731,8 +1733,10 @@ void LLVMCodeBuilder::createVariableWrite(Variable *variable, CompilerValue *val ins.workVariable = variable; createOp(ins, Compiler::StaticType::Void, Compiler::StaticType::Unknown, { value }); - if (m_variablePtrs.find(variable) == m_variablePtrs.cend()) + if (m_variablePtrs.find(variable) == m_variablePtrs.cend()) { m_variablePtrs[variable] = LLVMVariablePtr(); + m_variablePtrs[variable].var = variable; + } if (m_loopScope >= 0) { auto scope = m_loopScopes[m_loopScope]; diff --git a/src/engine/internal/llvm/llvmvariableptr.h b/src/engine/internal/llvm/llvmvariableptr.h index 9907a5aa8..b6da2a30c 100644 --- a/src/engine/internal/llvm/llvmvariableptr.h +++ b/src/engine/internal/llvm/llvmvariableptr.h @@ -20,6 +20,7 @@ class LLVMInstruction; struct LLVMVariablePtr { + Variable *var = nullptr; llvm::Value *stackPtr = nullptr; llvm::Value *heapPtr = nullptr; Compiler::StaticType type = Compiler::StaticType::Unknown; From da3803954ca267aa39767e7aee7e879849e43a4a Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Wed, 23 Jul 2025 13:05:40 +0200 Subject: [PATCH 16/79] Implement variableTypeChanges() for basic cases --- src/engine/internal/llvm/CMakeLists.txt | 2 + src/engine/internal/llvm/llvmloopanalyzer.cpp | 62 ++ src/engine/internal/llvm/llvmloopanalyzer.h | 22 + test/llvm/CMakeLists.txt | 1 + .../variabletypechanges_test.cpp | 570 ++++++++++++++++++ 5 files changed, 657 insertions(+) create mode 100644 src/engine/internal/llvm/llvmloopanalyzer.cpp create mode 100644 src/engine/internal/llvm/llvmloopanalyzer.h create mode 100644 test/llvm/loop_analyzer/variabletypechanges_test.cpp diff --git a/src/engine/internal/llvm/CMakeLists.txt b/src/engine/internal/llvm/CMakeLists.txt index 3fcb3d797..fb0617f42 100644 --- a/src/engine/internal/llvm/CMakeLists.txt +++ b/src/engine/internal/llvm/CMakeLists.txt @@ -17,6 +17,8 @@ target_sources(scratchcpp llvmtypes.h llvmfunctions.cpp llvmloopscope.h + llvmloopanalyzer.cpp + llvmloopanalyzer.h llvmcompilercontext.cpp llvmcompilercontext.h llvmexecutablecode.cpp diff --git a/src/engine/internal/llvm/llvmloopanalyzer.cpp b/src/engine/internal/llvm/llvmloopanalyzer.cpp new file mode 100644 index 000000000..21015b7db --- /dev/null +++ b/src/engine/internal/llvm/llvmloopanalyzer.cpp @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: Apache-2.0 + +#include "llvmloopanalyzer.h" +#include "llvminstruction.h" +#include "llvmvariableptr.h" + +using namespace libscratchcpp; + +bool LLVMLoopAnalyzer::variableTypeChanges(LLVMVariablePtr *varPtr, LLVMInstruction *loopBody, Compiler::StaticType preLoopType) const +{ + if (!varPtr || !loopBody) + return false; + + if (preLoopType == Compiler::StaticType::Unknown) + return true; + + // Find the last write instruction + LLVMInstruction *lastVarWrite = nullptr; + LLVMInstruction *ins = loopBody; + + while (ins && ins->type != LLVMInstruction::Type::EndLoop) { + // TODO: Handle nested loops + if (ins->type == LLVMInstruction::Type::WriteVariable && ins->workVariable == varPtr->var) + lastVarWrite = ins; + + ins = ins->next; + } + + // Loops must always have an end instruction + assert(ins); + + // Check the last write instruction, if any + return lastVarWrite ? !typesMatch(lastVarWrite, preLoopType) : false; +} + +Compiler::StaticType LLVMLoopAnalyzer::optimizeRegisterType(LLVMRegister *reg) const +{ + // TODO: Move this method out if it's used in LLVMCodeBuilder too + assert(reg); + + 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; + + return ret; +} + +bool LLVMLoopAnalyzer::typesMatch(LLVMInstruction *ins, Compiler::StaticType expectedType) const +{ + assert(ins); + assert(!ins->args.empty()); + const auto arg = ins->args.back().second; // value is always the last argument in variable/list write instructions + auto argIns = arg->instruction; + + // TODO: Handle cross-variable dependencies + /*if (argIns && (argIns->type == LLVMInstruction::Type::ReadVariable || argIns->type == LLVMInstruction::Type::GetListItem)) + return isVarOrListTypeSafe(argIns.get(), expectedType, log, c);*/ + + return (optimizeRegisterType(arg) == expectedType); +} diff --git a/src/engine/internal/llvm/llvmloopanalyzer.h b/src/engine/internal/llvm/llvmloopanalyzer.h new file mode 100644 index 000000000..f5a4e8757 --- /dev/null +++ b/src/engine/internal/llvm/llvmloopanalyzer.h @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: Apache-2.0 + +#include + +namespace libscratchcpp +{ + +struct LLVMVariablePtr; +struct LLVMInstruction; +struct LLVMRegister; + +class LLVMLoopAnalyzer +{ + public: + bool variableTypeChanges(LLVMVariablePtr *varPtr, LLVMInstruction *loopBody, Compiler::StaticType preLoopType) const; + + private: + Compiler::StaticType optimizeRegisterType(LLVMRegister *reg) const; + bool typesMatch(LLVMInstruction *ins, Compiler::StaticType expectedType) const; +}; + +} // namespace libscratchcpp diff --git a/test/llvm/CMakeLists.txt b/test/llvm/CMakeLists.txt index 02337d23f..52e13a809 100644 --- a/test/llvm/CMakeLists.txt +++ b/test/llvm/CMakeLists.txt @@ -20,6 +20,7 @@ add_executable( llvmexecutablecode_test.cpp llvmcodebuilder_test.cpp llvminstructionlist_test.cpp + loop_analyzer/variabletypechanges_test.cpp ) target_link_libraries( diff --git a/test/llvm/loop_analyzer/variabletypechanges_test.cpp b/test/llvm/loop_analyzer/variabletypechanges_test.cpp new file mode 100644 index 000000000..c52dbe80a --- /dev/null +++ b/test/llvm/loop_analyzer/variabletypechanges_test.cpp @@ -0,0 +1,570 @@ +#include +#include +#include +#include +#include +#include +#include + +using namespace libscratchcpp; + +TEST(LLVMLoopAnalyzer_VariableTypeChanges, NullParams) +{ + LLVMLoopAnalyzer analyzer; + ASSERT_FALSE(analyzer.variableTypeChanges(nullptr, nullptr, Compiler::StaticType::Number)); +} + +TEST(LLVMLoopAnalyzer_VariableTypeChanges, NullVariable) +{ + LLVMLoopAnalyzer analyzer; + + LLVMInstruction funcCall(LLVMInstruction::Type::FunctionCall, nullptr, false); + LLVMInstruction end(LLVMInstruction::Type::EndLoop, nullptr, false); + funcCall.next = &end; + end.previous = &funcCall; + + ASSERT_FALSE(analyzer.variableTypeChanges(nullptr, &funcCall, Compiler::StaticType::Number)); +} + +TEST(LLVMLoopAnalyzer_VariableTypeChanges, NullLoopBody) +{ + LLVMLoopAnalyzer analyzer; + LLVMVariablePtr varPtr; + ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, nullptr, Compiler::StaticType::Number)); +} + +TEST(LLVMLoopAnalyzer_VariableTypeChanges, EmptyLoop) +{ + LLVMLoopAnalyzer analyzer; + LLVMVariablePtr varPtr; + LLVMInstruction ins(LLVMInstruction::Type::EndLoop, nullptr, false); + + ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, &ins, Compiler::StaticType::Number)); +} + +TEST(LLVMLoopAnalyzer_VariableTypeChanges, EmptyLoopUnknownType) +{ + LLVMLoopAnalyzer analyzer; + LLVMVariablePtr varPtr; + LLVMInstruction ins(LLVMInstruction::Type::EndLoop, nullptr, false); + + // Always returns true for unknown type + ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, &ins, Compiler::StaticType::Unknown)); +} + +TEST(LLVMLoopAnalyzer_VariableTypeChanges, NoWriteOperations) +{ + LLVMLoopAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(funcCall); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(end); + + ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, funcCall.get(), Compiler::StaticType::Number)); +} + +TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteSameTypeNumber) +{ + LLVMLoopAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + auto setVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::Number, 1.25); + setVar->workVariable = &var; + setVar->args.push_back({ Compiler::StaticType::Unknown, &value }); + list.addInstruction(setVar); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(end); + + ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, setVar.get(), Compiler::StaticType::Number)); +} + +TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteSameTypeBool) +{ + LLVMLoopAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + auto setVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::Bool, true); + setVar->workVariable = &var; + setVar->args.push_back({ Compiler::StaticType::Unknown, &value }); + list.addInstruction(setVar); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(end); + + ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, setVar.get(), Compiler::StaticType::Bool)); +} + +TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteSameTypeString) +{ + LLVMLoopAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + auto setVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::String, "test"); + setVar->workVariable = &var; + setVar->args.push_back({ Compiler::StaticType::Unknown, &value }); + list.addInstruction(setVar); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(end); + + ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, setVar.get(), Compiler::StaticType::String)); +} + +TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteStringOptimization) +{ + LLVMLoopAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + auto setVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::String, "1.25"); + setVar->workVariable = &var; + setVar->args.push_back({ Compiler::StaticType::Unknown, &value }); + list.addInstruction(setVar); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(end); + + // Although string is assigned, it's constant and represents a number + ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, setVar.get(), Compiler::StaticType::Number)); +} + +TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteMultipleVariables) +{ + LLVMLoopAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var1("", ""); + Variable var2("", ""); + varPtr.var = &var1; + + // Set var1 + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 6); + setVar1->workVariable = &var1; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(setVar1); + + // Set var2 + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::String, "test"); + setVar2->workVariable = &var2; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + list.addInstruction(setVar2); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(end); + + ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, setVar1.get(), Compiler::StaticType::Number)); +} + +TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteFromUnknownType) +{ + LLVMLoopAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + auto setVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMRegister value(Compiler::StaticType::Unknown); + setVar->workVariable = &var; + setVar->args.push_back({ Compiler::StaticType::Unknown, &value }); + list.addInstruction(setVar); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(end); + + // Always returns true for unknown type + ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, setVar.get(), Compiler::StaticType::Number)); +} + +TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteToUnknownType) +{ + LLVMLoopAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + auto setVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::Number, 5); + setVar->workVariable = &var; + setVar->args.push_back({ Compiler::StaticType::Unknown, &value }); + list.addInstruction(setVar); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(end); + + // Always returns true for unknown type + ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, setVar.get(), Compiler::StaticType::Unknown)); +} + +TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteUnknownToUnknownType) +{ + LLVMLoopAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + auto setVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMRegister value(Compiler::StaticType::Unknown); + setVar->workVariable = &var; + setVar->args.push_back({ Compiler::StaticType::Unknown, &value }); + list.addInstruction(setVar); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(end); + + // Always returns true for unknown type + ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, setVar.get(), Compiler::StaticType::Unknown)); +} + +TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteDifferentTypeNumberToString) +{ + LLVMLoopAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + auto setVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::String, "test"); + setVar->workVariable = &var; + setVar->args.push_back({ Compiler::StaticType::Unknown, &value }); + list.addInstruction(setVar); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(end); + + ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, setVar.get(), Compiler::StaticType::Number)); +} + +TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteDifferentTypeStringToNumber) +{ + LLVMLoopAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + auto setVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::Number, 5.8); + setVar->workVariable = &var; + setVar->args.push_back({ Compiler::StaticType::Unknown, &value }); + list.addInstruction(setVar); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(end); + + ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, setVar.get(), Compiler::StaticType::String)); +} + +TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteDifferentTypeNumberToBool) +{ + LLVMLoopAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + auto setVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::Bool, true); + setVar->workVariable = &var; + setVar->args.push_back({ Compiler::StaticType::Unknown, &value }); + list.addInstruction(setVar); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(end); + + ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, setVar.get(), Compiler::StaticType::Number)); +} + +TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteDifferentTypeBoolToNumber) +{ + LLVMLoopAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + auto setVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::Number, 1); + setVar->workVariable = &var; + setVar->args.push_back({ Compiler::StaticType::Unknown, &value }); + list.addInstruction(setVar); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(end); + + ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, setVar.get(), Compiler::StaticType::Bool)); +} + +TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteDifferentTypeBoolToString) +{ + LLVMLoopAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + auto setVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::String, "abc"); + setVar->workVariable = &var; + setVar->args.push_back({ Compiler::StaticType::Unknown, &value }); + list.addInstruction(setVar); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(end); + + ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, setVar.get(), Compiler::StaticType::Bool)); +} + +TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteDifferentTypeStringToBool) +{ + LLVMLoopAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + auto setVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::Bool, false); + setVar->workVariable = &var; + setVar->args.push_back({ Compiler::StaticType::Unknown, &value }); + list.addInstruction(setVar); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(end); + + ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, setVar.get(), Compiler::StaticType::String)); +} + +TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesSameTypeNumber) +{ + LLVMLoopAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + // First write: string "abc" (incompatible with Number) + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::String, "abc"); + setVar1->workVariable = &var; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(setVar1); + + // Second write: number 5.25 (compatible with Number pre-loop type) + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::Number, 5.25); + setVar2->workVariable = &var; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + list.addInstruction(setVar2); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(end); + + // Should return false because final assignment is compatible with pre-loop Number type + ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, setVar1.get(), Compiler::StaticType::Number)); +} + +TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesSameTypeString) +{ + LLVMLoopAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + // First write: number 42 (incompatible with String) + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 42); + setVar1->workVariable = &var; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(setVar1); + + // Second write: string "hello" (compatible with String pre-loop type) + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::String, "hello"); + setVar2->workVariable = &var; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + list.addInstruction(setVar2); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(end); + + // Should return false because final assignment is compatible with pre-loop String type + ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, setVar1.get(), Compiler::StaticType::String)); +} + +TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesSameTypeUnknown) +{ + LLVMLoopAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + // First write: unknown type + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMRegister value1(Compiler::StaticType::Unknown); + setVar1->workVariable = &var; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(setVar1); + + // Second write: string "hello" (compatible with String pre-loop type) + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::String, "hello"); + setVar2->workVariable = &var; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + list.addInstruction(setVar2); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(end); + + // Should return false because final assignment is compatible with pre-loop String type + ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, setVar1.get(), Compiler::StaticType::String)); +} + +TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesWithStringOptimization) +{ + LLVMLoopAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + // First write: string "abc" (incompatible with Number) + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::String, "abc"); + setVar1->workVariable = &var; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(setVar1); + + // Second write: string "3.14" (optimized to Number, compatible with pre-loop type) + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::String, "3.14"); + setVar2->workVariable = &var; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + list.addInstruction(setVar2); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(end); + + // Should return false because final assignment is optimized to Number type + ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, setVar1.get(), Compiler::StaticType::Number)); +} + +TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesNumberToString) +{ + LLVMLoopAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + // First write: number 42 (compatible with Number) + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 42); + setVar1->workVariable = &var; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(setVar1); + + // Second write: string "hello" (incompatible with Number pre-loop type) + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::String, "hello"); + setVar2->workVariable = &var; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + list.addInstruction(setVar2); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(end); + + // Should return true because final assignment is incompatible with pre-loop Number type + ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, setVar1.get(), Compiler::StaticType::Number)); +} + +TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesBoolToNumber) +{ + LLVMLoopAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + auto setVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::Number, 42.5); + setVar->workVariable = &var; + setVar->args.push_back({ Compiler::StaticType::Unknown, &value }); + list.addInstruction(setVar); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(end); + + ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, setVar.get(), Compiler::StaticType::Bool)); +} + +TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesBoolToString) +{ + LLVMLoopAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + auto setVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::String, "hello"); + setVar->workVariable = &var; + setVar->args.push_back({ Compiler::StaticType::Unknown, &value }); + list.addInstruction(setVar); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(end); + + ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, setVar.get(), Compiler::StaticType::Bool)); +} + +TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesBoolToStringNumberOptimization) +{ + LLVMLoopAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + auto setVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::String, "3.14"); + setVar->workVariable = &var; + setVar->args.push_back({ Compiler::StaticType::Unknown, &value }); + list.addInstruction(setVar); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(end); + + // String "3.14" gets optimized to Number, which is still different from Bool + ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, setVar.get(), Compiler::StaticType::Bool)); +} + +// TODO: Handle nested loops +// TODO: Handle cross-variable dependencies From 5c9f495d9d15888883e0161a8d4f1e18c138f08a Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Wed, 23 Jul 2025 16:46:50 +0200 Subject: [PATCH 17/79] LLVMLoopAnalyzer: Implement nested loops in variableTypeChanges() --- src/engine/internal/llvm/llvmloopanalyzer.cpp | 80 ++- src/engine/internal/llvm/llvmloopanalyzer.h | 4 + .../variabletypechanges_test.cpp | 468 ++++++++++++++++-- 3 files changed, 514 insertions(+), 38 deletions(-) diff --git a/src/engine/internal/llvm/llvmloopanalyzer.cpp b/src/engine/internal/llvm/llvmloopanalyzer.cpp index 21015b7db..97b0b1785 100644 --- a/src/engine/internal/llvm/llvmloopanalyzer.cpp +++ b/src/engine/internal/llvm/llvmloopanalyzer.cpp @@ -6,6 +6,9 @@ using namespace libscratchcpp; +static const std::unordered_set + BEGIN_LOOP_INSTRUCTIONS = { LLVMInstruction::Type::BeginRepeatLoop, LLVMInstruction::Type::BeginWhileLoop, LLVMInstruction::Type::BeginRepeatUntilLoop }; + bool LLVMLoopAnalyzer::variableTypeChanges(LLVMVariablePtr *varPtr, LLVMInstruction *loopBody, Compiler::StaticType preLoopType) const { if (!varPtr || !loopBody) @@ -14,23 +17,80 @@ bool LLVMLoopAnalyzer::variableTypeChanges(LLVMVariablePtr *varPtr, LLVMInstruct if (preLoopType == Compiler::StaticType::Unknown) return true; - // Find the last write instruction - LLVMInstruction *lastVarWrite = nullptr; - LLVMInstruction *ins = loopBody; + // Find loop end + LLVMInstruction *ins = loopBody->next; + int loopLevel = 0; - while (ins && ins->type != LLVMInstruction::Type::EndLoop) { - // TODO: Handle nested loops - if (ins->type == LLVMInstruction::Type::WriteVariable && ins->workVariable == varPtr->var) - lastVarWrite = ins; + while (ins && !(isLoopEnd(ins) && loopLevel == 0)) { + if (isLoopStart(ins)) + loopLevel++; + else if (isLoopEnd(ins)) { + assert(loopLevel > 0); + loopLevel--; + } ins = ins->next; } // Loops must always have an end instruction - assert(ins); + if (!ins) { + assert(false); + return true; + } - // Check the last write instruction, if any - return lastVarWrite ? !typesMatch(lastVarWrite, preLoopType) : false; + return variableTypeChangesFromEnd(varPtr, ins, preLoopType); +} + +bool LLVMLoopAnalyzer::variableTypeChangesFromEnd(LLVMVariablePtr *varPtr, LLVMInstruction *loopEnd, Compiler::StaticType preLoopType) const +{ + // Find the last write instruction + LLVMInstruction *ins = loopEnd->previous; + + while (ins && !isLoopStart(ins)) { + if (isLoopEnd(ins)) { + // Nested loop + if (variableTypeChangesFromEnd(varPtr, ins, preLoopType)) + return true; + + // Skip the loop + int loopLevel = 0; + ins = ins->previous; + + while (ins && !(isLoopStart(ins) && loopLevel == 0)) { + if (isLoopStart(ins)) { + assert(loopLevel > 0); + loopLevel--; + } + + if (isLoopEnd(ins)) + loopLevel++; + + ins = ins->previous; + }; + + if (!ins) { + assert(false); + return true; + } + } else if (ins->type == LLVMInstruction::Type::WriteVariable && ins->workVariable == varPtr->var) { + // Variable write instruction + return !typesMatch(ins, preLoopType); + } + + ins = ins->previous; + } + + return false; +} + +bool LLVMLoopAnalyzer::isLoopStart(LLVMInstruction *ins) const +{ + return (BEGIN_LOOP_INSTRUCTIONS.find(ins->type) != BEGIN_LOOP_INSTRUCTIONS.cend()); +} + +bool LLVMLoopAnalyzer::isLoopEnd(LLVMInstruction *ins) const +{ + return (ins->type == LLVMInstruction::Type::EndLoop); } Compiler::StaticType LLVMLoopAnalyzer::optimizeRegisterType(LLVMRegister *reg) const diff --git a/src/engine/internal/llvm/llvmloopanalyzer.h b/src/engine/internal/llvm/llvmloopanalyzer.h index f5a4e8757..9d8c11dca 100644 --- a/src/engine/internal/llvm/llvmloopanalyzer.h +++ b/src/engine/internal/llvm/llvmloopanalyzer.h @@ -15,6 +15,10 @@ class LLVMLoopAnalyzer bool variableTypeChanges(LLVMVariablePtr *varPtr, LLVMInstruction *loopBody, Compiler::StaticType preLoopType) const; private: + bool variableTypeChangesFromEnd(LLVMVariablePtr *varPtr, LLVMInstruction *loopEnd, Compiler::StaticType preLoopType) const; + bool isLoopStart(LLVMInstruction *ins) const; + bool isLoopEnd(LLVMInstruction *ins) const; + Compiler::StaticType optimizeRegisterType(LLVMRegister *reg) const; bool typesMatch(LLVMInstruction *ins, Compiler::StaticType expectedType) const; }; diff --git a/test/llvm/loop_analyzer/variabletypechanges_test.cpp b/test/llvm/loop_analyzer/variabletypechanges_test.cpp index c52dbe80a..c29534ac4 100644 --- a/test/llvm/loop_analyzer/variabletypechanges_test.cpp +++ b/test/llvm/loop_analyzer/variabletypechanges_test.cpp @@ -37,19 +37,31 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, EmptyLoop) { LLVMLoopAnalyzer analyzer; LLVMVariablePtr varPtr; - LLVMInstruction ins(LLVMInstruction::Type::EndLoop, nullptr, false); + LLVMInstructionList list; + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(start); - ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, &ins, Compiler::StaticType::Number)); + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(end); + + ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Number)); } TEST(LLVMLoopAnalyzer_VariableTypeChanges, EmptyLoopUnknownType) { LLVMLoopAnalyzer analyzer; LLVMVariablePtr varPtr; - LLVMInstruction ins(LLVMInstruction::Type::EndLoop, nullptr, false); + LLVMInstructionList list; + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(start); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(end); // Always returns true for unknown type - ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, &ins, Compiler::StaticType::Unknown)); + ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Unknown)); } TEST(LLVMLoopAnalyzer_VariableTypeChanges, NoWriteOperations) @@ -58,13 +70,16 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, NoWriteOperations) LLVMInstructionList list; LLVMVariablePtr varPtr; + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(start); + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); list.addInstruction(funcCall); auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, funcCall.get(), Compiler::StaticType::Number)); + ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Number)); } TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteSameTypeNumber) @@ -75,6 +90,9 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteSameTypeNumber) Variable var("", ""); varPtr.var = &var; + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(start); + auto setVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); LLVMConstantRegister value(Compiler::StaticType::Number, 1.25); setVar->workVariable = &var; @@ -84,7 +102,7 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteSameTypeNumber) auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, setVar.get(), Compiler::StaticType::Number)); + ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Number)); } TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteSameTypeBool) @@ -95,6 +113,9 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteSameTypeBool) Variable var("", ""); varPtr.var = &var; + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(start); + auto setVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); LLVMConstantRegister value(Compiler::StaticType::Bool, true); setVar->workVariable = &var; @@ -104,7 +125,7 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteSameTypeBool) auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, setVar.get(), Compiler::StaticType::Bool)); + ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Bool)); } TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteSameTypeString) @@ -115,6 +136,9 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteSameTypeString) Variable var("", ""); varPtr.var = &var; + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(start); + auto setVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); LLVMConstantRegister value(Compiler::StaticType::String, "test"); setVar->workVariable = &var; @@ -124,7 +148,7 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteSameTypeString) auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, setVar.get(), Compiler::StaticType::String)); + ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::String)); } TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteStringOptimization) @@ -135,6 +159,9 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteStringOptimization) Variable var("", ""); varPtr.var = &var; + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(start); + auto setVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); LLVMConstantRegister value(Compiler::StaticType::String, "1.25"); setVar->workVariable = &var; @@ -145,7 +172,7 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteStringOptimization) list.addInstruction(end); // Although string is assigned, it's constant and represents a number - ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, setVar.get(), Compiler::StaticType::Number)); + ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Number)); } TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteMultipleVariables) @@ -157,6 +184,9 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteMultipleVariables) Variable var2("", ""); varPtr.var = &var1; + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(start); + // Set var1 auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); LLVMConstantRegister value1(Compiler::StaticType::Number, 6); @@ -174,7 +204,7 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteMultipleVariables) auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, setVar1.get(), Compiler::StaticType::Number)); + ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Number)); } TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteFromUnknownType) @@ -185,6 +215,9 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteFromUnknownType) Variable var("", ""); varPtr.var = &var; + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(start); + auto setVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); LLVMRegister value(Compiler::StaticType::Unknown); setVar->workVariable = &var; @@ -195,7 +228,7 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteFromUnknownType) list.addInstruction(end); // Always returns true for unknown type - ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, setVar.get(), Compiler::StaticType::Number)); + ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Number)); } TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteToUnknownType) @@ -206,6 +239,9 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteToUnknownType) Variable var("", ""); varPtr.var = &var; + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(start); + auto setVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); LLVMConstantRegister value(Compiler::StaticType::Number, 5); setVar->workVariable = &var; @@ -216,7 +252,7 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteToUnknownType) list.addInstruction(end); // Always returns true for unknown type - ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, setVar.get(), Compiler::StaticType::Unknown)); + ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Unknown)); } TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteUnknownToUnknownType) @@ -227,6 +263,9 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteUnknownToUnknownType) Variable var("", ""); varPtr.var = &var; + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(start); + auto setVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); LLVMRegister value(Compiler::StaticType::Unknown); setVar->workVariable = &var; @@ -237,7 +276,7 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteUnknownToUnknownType) list.addInstruction(end); // Always returns true for unknown type - ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, setVar.get(), Compiler::StaticType::Unknown)); + ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Unknown)); } TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteDifferentTypeNumberToString) @@ -248,6 +287,9 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteDifferentTypeNumberToStrin Variable var("", ""); varPtr.var = &var; + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(start); + auto setVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); LLVMConstantRegister value(Compiler::StaticType::String, "test"); setVar->workVariable = &var; @@ -257,7 +299,7 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteDifferentTypeNumberToStrin auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, setVar.get(), Compiler::StaticType::Number)); + ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Number)); } TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteDifferentTypeStringToNumber) @@ -268,6 +310,9 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteDifferentTypeStringToNumbe Variable var("", ""); varPtr.var = &var; + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(start); + auto setVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); LLVMConstantRegister value(Compiler::StaticType::Number, 5.8); setVar->workVariable = &var; @@ -277,7 +322,7 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteDifferentTypeStringToNumbe auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, setVar.get(), Compiler::StaticType::String)); + ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::String)); } TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteDifferentTypeNumberToBool) @@ -288,6 +333,9 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteDifferentTypeNumberToBool) Variable var("", ""); varPtr.var = &var; + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(start); + auto setVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); LLVMConstantRegister value(Compiler::StaticType::Bool, true); setVar->workVariable = &var; @@ -297,7 +345,7 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteDifferentTypeNumberToBool) auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, setVar.get(), Compiler::StaticType::Number)); + ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Number)); } TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteDifferentTypeBoolToNumber) @@ -308,6 +356,9 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteDifferentTypeBoolToNumber) Variable var("", ""); varPtr.var = &var; + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(start); + auto setVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); LLVMConstantRegister value(Compiler::StaticType::Number, 1); setVar->workVariable = &var; @@ -317,7 +368,7 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteDifferentTypeBoolToNumber) auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, setVar.get(), Compiler::StaticType::Bool)); + ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Bool)); } TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteDifferentTypeBoolToString) @@ -328,6 +379,9 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteDifferentTypeBoolToString) Variable var("", ""); varPtr.var = &var; + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(start); + auto setVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); LLVMConstantRegister value(Compiler::StaticType::String, "abc"); setVar->workVariable = &var; @@ -337,7 +391,7 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteDifferentTypeBoolToString) auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, setVar.get(), Compiler::StaticType::Bool)); + ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Bool)); } TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteDifferentTypeStringToBool) @@ -348,6 +402,9 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteDifferentTypeStringToBool) Variable var("", ""); varPtr.var = &var; + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(start); + auto setVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); LLVMConstantRegister value(Compiler::StaticType::Bool, false); setVar->workVariable = &var; @@ -357,7 +414,7 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteDifferentTypeStringToBool) auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, setVar.get(), Compiler::StaticType::String)); + ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::String)); } TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesSameTypeNumber) @@ -368,6 +425,9 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesSameTypeNumber) Variable var("", ""); varPtr.var = &var; + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(start); + // First write: string "abc" (incompatible with Number) auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); LLVMConstantRegister value1(Compiler::StaticType::String, "abc"); @@ -386,7 +446,7 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesSameTypeNumber) list.addInstruction(end); // Should return false because final assignment is compatible with pre-loop Number type - ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, setVar1.get(), Compiler::StaticType::Number)); + ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Number)); } TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesSameTypeString) @@ -397,6 +457,9 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesSameTypeString) Variable var("", ""); varPtr.var = &var; + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(start); + // First write: number 42 (incompatible with String) auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); LLVMConstantRegister value1(Compiler::StaticType::Number, 42); @@ -415,7 +478,7 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesSameTypeString) list.addInstruction(end); // Should return false because final assignment is compatible with pre-loop String type - ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, setVar1.get(), Compiler::StaticType::String)); + ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::String)); } TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesSameTypeUnknown) @@ -426,6 +489,9 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesSameTypeUnknown) Variable var("", ""); varPtr.var = &var; + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(start); + // First write: unknown type auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); LLVMRegister value1(Compiler::StaticType::Unknown); @@ -444,7 +510,7 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesSameTypeUnknown) list.addInstruction(end); // Should return false because final assignment is compatible with pre-loop String type - ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, setVar1.get(), Compiler::StaticType::String)); + ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::String)); } TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesWithStringOptimization) @@ -455,6 +521,9 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesWithStringOptimization) Variable var("", ""); varPtr.var = &var; + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(start); + // First write: string "abc" (incompatible with Number) auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); LLVMConstantRegister value1(Compiler::StaticType::String, "abc"); @@ -473,7 +542,7 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesWithStringOptimization) list.addInstruction(end); // Should return false because final assignment is optimized to Number type - ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, setVar1.get(), Compiler::StaticType::Number)); + ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Number)); } TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesNumberToString) @@ -484,6 +553,9 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesNumberToString) Variable var("", ""); varPtr.var = &var; + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(start); + // First write: number 42 (compatible with Number) auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); LLVMConstantRegister value1(Compiler::StaticType::Number, 42); @@ -502,7 +574,7 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesNumberToString) list.addInstruction(end); // Should return true because final assignment is incompatible with pre-loop Number type - ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, setVar1.get(), Compiler::StaticType::Number)); + ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Number)); } TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesBoolToNumber) @@ -513,6 +585,9 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesBoolToNumber) Variable var("", ""); varPtr.var = &var; + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(start); + auto setVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); LLVMConstantRegister value(Compiler::StaticType::Number, 42.5); setVar->workVariable = &var; @@ -522,7 +597,7 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesBoolToNumber) auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, setVar.get(), Compiler::StaticType::Bool)); + ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Bool)); } TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesBoolToString) @@ -533,6 +608,9 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesBoolToString) Variable var("", ""); varPtr.var = &var; + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(start); + auto setVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); LLVMConstantRegister value(Compiler::StaticType::String, "hello"); setVar->workVariable = &var; @@ -542,7 +620,7 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesBoolToString) auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, setVar.get(), Compiler::StaticType::Bool)); + ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Bool)); } TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesBoolToStringNumberOptimization) @@ -553,6 +631,9 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesBoolToStringNumberOptim Variable var("", ""); varPtr.var = &var; + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(start); + auto setVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); LLVMConstantRegister value(Compiler::StaticType::String, "3.14"); setVar->workVariable = &var; @@ -563,8 +644,339 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesBoolToStringNumberOptim list.addInstruction(end); // String "3.14" gets optimized to Number, which is still different from Bool - ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, setVar.get(), Compiler::StaticType::Bool)); + ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Bool)); +} + +TEST(LLVMLoopAnalyzer_VariableTypeChanges, NestedLoopWithTypeChange) +{ + LLVMLoopAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + // Outer loop begin + auto outerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(outerLoop); + + // Variable write inside outer loop + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 5); + setVar1->workVariable = &var; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(setVar1); + + // Inner loop begin + auto innerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(innerLoop); + + // Variable write inside inner loop + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::String, "test"); + setVar2->workVariable = &var; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + list.addInstruction(setVar2); + + // Inner loop end + auto innerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(innerEnd); + + // Outer loop end + auto outerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(outerEnd); + + ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, outerLoop.get(), Compiler::StaticType::Number)); +} + +TEST(LLVMLoopAnalyzer_VariableTypeChanges, NestedLoopWithoutTypeChange) +{ + LLVMLoopAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + // Outer loop begin + auto outerLoop = std::make_shared(LLVMInstruction::Type::BeginWhileLoop, nullptr, false); + list.addInstruction(outerLoop); + + // Variable write inside outer loop + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 5); + setVar1->workVariable = &var; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(setVar1); + + // Inner loop begin + auto innerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(innerLoop); + + // Variable write inside inner loop + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::Number, 2.5); + setVar2->workVariable = &var; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + list.addInstruction(setVar2); + + // Inner loop end + auto innerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(innerEnd); + + // Outer loop end + auto outerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(outerEnd); + + ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, outerLoop.get(), Compiler::StaticType::Number)); +} + +TEST(LLVMLoopAnalyzer_VariableTypeChanges, NestedLoopTypeChangesButResets) +{ + LLVMLoopAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + // Outer loop begin + auto outerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(outerLoop); + + // Variable write inside outer loop + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 5); + setVar1->workVariable = &var; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(setVar1); + + // Inner loop begin + auto innerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatUntilLoop, nullptr, false); + list.addInstruction(innerLoop); + + // Variable write inside inner loop + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::String, "test"); + setVar2->workVariable = &var; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + list.addInstruction(setVar2); + + // Inner loop end + auto innerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(innerEnd); + + // Variable write after inner loop - resets type + auto setVar3 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value3(Compiler::StaticType::Number, 2); + setVar3->workVariable = &var; + setVar3->args.push_back({ Compiler::StaticType::Unknown, &value3 }); + list.addInstruction(setVar3); + + // Outer loop end + auto outerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(outerEnd); + + ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, outerLoop.get(), Compiler::StaticType::Number)); +} + +TEST(LLVMLoopAnalyzer_VariableTypeChanges, NestedLoopTypeChangesAndDoesNotReset) +{ + LLVMLoopAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + // Outer loop begin + auto outerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(outerLoop); + + // Variable write inside outer loop + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 5); + setVar1->workVariable = &var; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(setVar1); + + // Inner loop begin + auto innerLoop = std::make_shared(LLVMInstruction::Type::BeginWhileLoop, nullptr, false); + list.addInstruction(innerLoop); + + // Variable write inside inner loop + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::String, "test"); + setVar2->workVariable = &var; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + list.addInstruction(setVar2); + + // Inner loop end + auto innerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(innerEnd); + + // Variable write after inner loop - keeps the different type + auto setVar3 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value3(Compiler::StaticType::String, "abc"); + setVar3->workVariable = &var; + setVar3->args.push_back({ Compiler::StaticType::Unknown, &value3 }); + list.addInstruction(setVar3); + + // Outer loop end + auto outerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(outerEnd); + + ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, outerLoop.get(), Compiler::StaticType::Number)); +} + +TEST(LLVMLoopAnalyzer_VariableTypeChanges, NestedLoopWithTypeChangeBeforeLoop) +{ + LLVMLoopAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + // Outer loop begin + auto outerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatUntilLoop, nullptr, false); + list.addInstruction(outerLoop); + + // Variable write inside outer loop + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::String, "test"); + setVar1->workVariable = &var; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(setVar1); + + // Inner loop begin + auto innerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(innerLoop); + + // Variable write inside inner loop + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::Number, 5); + setVar2->workVariable = &var; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + list.addInstruction(setVar2); + + // Inner loop end + auto innerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(innerEnd); + + // Outer loop end + auto outerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(outerEnd); + + // Returns true because loops can be skipped + ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, outerLoop.get(), Compiler::StaticType::Number)); +} + +TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleNestedLoopsWithTypeChange) +{ + LLVMLoopAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + // Outer loop begin + auto outerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(outerLoop); + + // Variable write inside outer loop + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 5); + setVar1->workVariable = &var; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(setVar1); + + // Inner loop 1 begin + auto innerLoop1 = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(innerLoop1); + + // Variable write inside inner loop 1 + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::Number, 2.75); + setVar2->workVariable = &var; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + list.addInstruction(setVar2); + + // Inner loop 2 begin + auto innerLoop2 = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(innerLoop2); + + // Variable write inside inner loop 2 + auto setVar3 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value3(Compiler::StaticType::String, "abc"); + setVar3->workVariable = &var; + setVar3->args.push_back({ Compiler::StaticType::Unknown, &value3 }); + list.addInstruction(setVar3); + + // Inner loop 2 end + auto innerEnd2 = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(innerEnd2); + + // Inner loop 1 end + auto innerEnd1 = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(innerEnd1); + + // Outer loop end + auto outerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(outerEnd); + + ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, outerLoop.get(), Compiler::StaticType::Number)); +} + +TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleNestedLoopsWithTypeChangeButTypeReset) +{ + LLVMLoopAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + // Outer loop begin + auto outerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(outerLoop); + + // Variable write inside outer loop + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 5); + setVar1->workVariable = &var; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(setVar1); + + // Inner loop 1 begin + auto innerLoop1 = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(innerLoop1); + + // Inner loop 2 begin + auto innerLoop2 = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(innerLoop2); + + // Variable write inside inner loop 2 + auto setVar3 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value3(Compiler::StaticType::String, "abc"); + setVar3->workVariable = &var; + setVar3->args.push_back({ Compiler::StaticType::Unknown, &value3 }); + list.addInstruction(setVar3); + + // Inner loop 2 end + auto innerEnd2 = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(innerEnd2); + + // Variable write inside inner loop 1 - resets type + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::Number, 2.75); + setVar2->workVariable = &var; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + list.addInstruction(setVar2); + + // Inner loop 1 end + auto innerEnd1 = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(innerEnd1); + + // Outer loop end + auto outerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(outerEnd); + + ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, outerLoop.get(), Compiler::StaticType::Number)); } -// TODO: Handle nested loops // TODO: Handle cross-variable dependencies From 5b0c7701706f8f4b7be9f857934e76ebf84e4359 Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Wed, 23 Jul 2025 17:50:20 +0200 Subject: [PATCH 18/79] LLVMLoopAnalyzer: Handle if statements in variableTypeChanges() --- src/engine/internal/llvm/llvmloopanalyzer.cpp | 35 +++-- src/engine/internal/llvm/llvmloopanalyzer.h | 3 + .../variabletypechanges_test.cpp | 122 ++++++++++++++++++ 3 files changed, 150 insertions(+), 10 deletions(-) diff --git a/src/engine/internal/llvm/llvmloopanalyzer.cpp b/src/engine/internal/llvm/llvmloopanalyzer.cpp index 97b0b1785..7ae76cfb5 100644 --- a/src/engine/internal/llvm/llvmloopanalyzer.cpp +++ b/src/engine/internal/llvm/llvmloopanalyzer.cpp @@ -47,23 +47,23 @@ bool LLVMLoopAnalyzer::variableTypeChangesFromEnd(LLVMVariablePtr *varPtr, LLVMI LLVMInstruction *ins = loopEnd->previous; while (ins && !isLoopStart(ins)) { - if (isLoopEnd(ins)) { - // Nested loop + if (isLoopEnd(ins) || isIfEnd(ins) || isElse(ins)) { + // Nested loop or if statement if (variableTypeChangesFromEnd(varPtr, ins, preLoopType)) return true; - // Skip the loop - int loopLevel = 0; + // Skip the loop or if statement + int level = 0; ins = ins->previous; - while (ins && !(isLoopStart(ins) && loopLevel == 0)) { - if (isLoopStart(ins)) { - assert(loopLevel > 0); - loopLevel--; + while (ins && !((isLoopStart(ins) || isIfStart(ins) || isElse(ins)) && level == 0)) { + if (isLoopStart(ins) || isIfStart(ins)) { + assert(level > 0); + level--; } - if (isLoopEnd(ins)) - loopLevel++; + if (isLoopEnd(ins) || isIfEnd(ins) || isElse(ins)) + level++; ins = ins->previous; }; @@ -93,6 +93,21 @@ bool LLVMLoopAnalyzer::isLoopEnd(LLVMInstruction *ins) const return (ins->type == LLVMInstruction::Type::EndLoop); } +bool LLVMLoopAnalyzer::isIfStart(LLVMInstruction *ins) const +{ + return (ins->type == LLVMInstruction::Type::BeginIf); +} + +bool LLVMLoopAnalyzer::isElse(LLVMInstruction *ins) const +{ + return (ins->type == LLVMInstruction::Type::BeginElse); +} + +bool LLVMLoopAnalyzer::isIfEnd(LLVMInstruction *ins) const +{ + return (ins->type == LLVMInstruction::Type::EndIf); +} + Compiler::StaticType LLVMLoopAnalyzer::optimizeRegisterType(LLVMRegister *reg) const { // TODO: Move this method out if it's used in LLVMCodeBuilder too diff --git a/src/engine/internal/llvm/llvmloopanalyzer.h b/src/engine/internal/llvm/llvmloopanalyzer.h index 9d8c11dca..27d81310d 100644 --- a/src/engine/internal/llvm/llvmloopanalyzer.h +++ b/src/engine/internal/llvm/llvmloopanalyzer.h @@ -18,6 +18,9 @@ class LLVMLoopAnalyzer bool variableTypeChangesFromEnd(LLVMVariablePtr *varPtr, LLVMInstruction *loopEnd, Compiler::StaticType preLoopType) const; bool isLoopStart(LLVMInstruction *ins) const; bool isLoopEnd(LLVMInstruction *ins) const; + bool isIfStart(LLVMInstruction *ins) const; + bool isElse(LLVMInstruction *ins) const; + bool isIfEnd(LLVMInstruction *ins) const; Compiler::StaticType optimizeRegisterType(LLVMRegister *reg) const; bool typesMatch(LLVMInstruction *ins, Compiler::StaticType expectedType) const; diff --git a/test/llvm/loop_analyzer/variabletypechanges_test.cpp b/test/llvm/loop_analyzer/variabletypechanges_test.cpp index c29534ac4..8ddad8879 100644 --- a/test/llvm/loop_analyzer/variabletypechanges_test.cpp +++ b/test/llvm/loop_analyzer/variabletypechanges_test.cpp @@ -647,6 +647,128 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesBoolToStringNumberOptim ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Bool)); } +TEST(LLVMLoopAnalyzer_VariableTypeChanges, TypeChangeInIfBranch) +{ + LLVMLoopAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(start); + + auto ifStart = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + list.addInstruction(ifStart); + + // First write - changes type + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::String, "test"); + setVar1->workVariable = &var; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(setVar1); + + auto elseStart = std::make_shared(LLVMInstruction::Type::BeginElse, nullptr, false); + list.addInstruction(elseStart); + + // Second write - does not change type + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::Number, 42); + setVar2->workVariable = &var; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + list.addInstruction(setVar2); + + auto ifEnd = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + list.addInstruction(ifEnd); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(end); + + // Returns true because the type-changing branch might run + ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Number)); +} + +TEST(LLVMLoopAnalyzer_VariableTypeChanges, TypeChangeInElseBranch) +{ + LLVMLoopAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(start); + + auto ifStart = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + list.addInstruction(ifStart); + + // First write - does not change type + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 42); + setVar1->workVariable = &var; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(setVar1); + + auto elseStart = std::make_shared(LLVMInstruction::Type::BeginElse, nullptr, false); + list.addInstruction(elseStart); + + // Second write - changes type + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::String, "test"); + setVar2->workVariable = &var; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + list.addInstruction(setVar2); + + auto ifEnd = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + list.addInstruction(ifEnd); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(end); + + // Returns true because the type-changing branch might run + ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Number)); +} + +TEST(LLVMLoopAnalyzer_VariableTypeChanges, IfElseWithoutTypeChange) +{ + LLVMLoopAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(start); + + auto ifStart = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + list.addInstruction(ifStart); + + // First write - does not change type + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 42); + setVar1->workVariable = &var; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(setVar1); + + auto elseStart = std::make_shared(LLVMInstruction::Type::BeginElse, nullptr, false); + list.addInstruction(elseStart); + + // Second write - does not change type + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::Number, 1.25); + setVar2->workVariable = &var; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + list.addInstruction(setVar2); + + auto ifEnd = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + list.addInstruction(ifEnd); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(end); + + ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Number)); +} + TEST(LLVMLoopAnalyzer_VariableTypeChanges, NestedLoopWithTypeChange) { LLVMLoopAnalyzer analyzer; From 9c43261348e08bbd2c5f450b21a2a091e58933e4 Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Thu, 24 Jul 2025 14:47:09 +0200 Subject: [PATCH 19/79] LLVMLoopAnalyzer: Fix null variable test case for variableTypeChanges() --- .../loop_analyzer/variabletypechanges_test.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/test/llvm/loop_analyzer/variabletypechanges_test.cpp b/test/llvm/loop_analyzer/variabletypechanges_test.cpp index 8ddad8879..abfa95a7d 100644 --- a/test/llvm/loop_analyzer/variabletypechanges_test.cpp +++ b/test/llvm/loop_analyzer/variabletypechanges_test.cpp @@ -17,13 +17,18 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, NullParams) TEST(LLVMLoopAnalyzer_VariableTypeChanges, NullVariable) { LLVMLoopAnalyzer analyzer; + LLVMInstructionList list; - LLVMInstruction funcCall(LLVMInstruction::Type::FunctionCall, nullptr, false); - LLVMInstruction end(LLVMInstruction::Type::EndLoop, nullptr, false); - funcCall.next = &end; - end.previous = &funcCall; + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(start); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(funcCall); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(end); - ASSERT_FALSE(analyzer.variableTypeChanges(nullptr, &funcCall, Compiler::StaticType::Number)); + ASSERT_FALSE(analyzer.variableTypeChanges(nullptr, start.get(), Compiler::StaticType::Number)); } TEST(LLVMLoopAnalyzer_VariableTypeChanges, NullLoopBody) From 33b37d6932537abf7cee0f42a767a37e3ba19f78 Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Thu, 24 Jul 2025 14:49:42 +0200 Subject: [PATCH 20/79] LLVMLoopAnalyzer: Get write value type from a separate method --- src/engine/internal/llvm/llvmloopanalyzer.cpp | 11 ++++++++--- src/engine/internal/llvm/llvmloopanalyzer.h | 1 + 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/engine/internal/llvm/llvmloopanalyzer.cpp b/src/engine/internal/llvm/llvmloopanalyzer.cpp index 7ae76cfb5..ce38d4f08 100644 --- a/src/engine/internal/llvm/llvmloopanalyzer.cpp +++ b/src/engine/internal/llvm/llvmloopanalyzer.cpp @@ -122,16 +122,21 @@ Compiler::StaticType LLVMLoopAnalyzer::optimizeRegisterType(LLVMRegister *reg) c return ret; } -bool LLVMLoopAnalyzer::typesMatch(LLVMInstruction *ins, Compiler::StaticType expectedType) const +Compiler::StaticType LLVMLoopAnalyzer::writeValueType(LLVMInstruction *ins) const { assert(ins); assert(!ins->args.empty()); const auto arg = ins->args.back().second; // value is always the last argument in variable/list write instructions - auto argIns = arg->instruction; + return optimizeRegisterType(arg); +} + +bool LLVMLoopAnalyzer::typesMatch(LLVMInstruction *ins, Compiler::StaticType expectedType) const +{ + // auto argIns = arg->instruction; // TODO: Handle cross-variable dependencies /*if (argIns && (argIns->type == LLVMInstruction::Type::ReadVariable || argIns->type == LLVMInstruction::Type::GetListItem)) return isVarOrListTypeSafe(argIns.get(), expectedType, log, c);*/ - return (optimizeRegisterType(arg) == expectedType); + return (writeValueType(ins) == expectedType); } diff --git a/src/engine/internal/llvm/llvmloopanalyzer.h b/src/engine/internal/llvm/llvmloopanalyzer.h index 27d81310d..346d00533 100644 --- a/src/engine/internal/llvm/llvmloopanalyzer.h +++ b/src/engine/internal/llvm/llvmloopanalyzer.h @@ -23,6 +23,7 @@ class LLVMLoopAnalyzer bool isIfEnd(LLVMInstruction *ins) const; Compiler::StaticType optimizeRegisterType(LLVMRegister *reg) const; + Compiler::StaticType writeValueType(LLVMInstruction *ins) const; bool typesMatch(LLVMInstruction *ins, Compiler::StaticType expectedType) const; }; From 2d6dc53028f5ad07a4866cdcee399770b3e58156 Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Thu, 24 Jul 2025 15:10:17 +0200 Subject: [PATCH 21/79] LLVMLoopAnalyzer -> LLVMTypeAnalyzer --- src/engine/internal/llvm/CMakeLists.txt | 4 +- ...mloopanalyzer.cpp => llvmtypeanalyzer.cpp} | 26 +- ...{llvmloopanalyzer.h => llvmtypeanalyzer.h} | 6 +- test/llvm/CMakeLists.txt | 2 +- .../variabletypechangesinloop_test.cpp} | 230 +++++++++--------- 5 files changed, 134 insertions(+), 134 deletions(-) rename src/engine/internal/llvm/{llvmloopanalyzer.cpp => llvmtypeanalyzer.cpp} (78%) rename src/engine/internal/llvm/{llvmloopanalyzer.h => llvmtypeanalyzer.h} (71%) rename test/llvm/{loop_analyzer/variabletypechanges_test.cpp => type_analyzer/variabletypechangesinloop_test.cpp} (82%) diff --git a/src/engine/internal/llvm/CMakeLists.txt b/src/engine/internal/llvm/CMakeLists.txt index fb0617f42..afdcee564 100644 --- a/src/engine/internal/llvm/CMakeLists.txt +++ b/src/engine/internal/llvm/CMakeLists.txt @@ -17,8 +17,8 @@ target_sources(scratchcpp llvmtypes.h llvmfunctions.cpp llvmloopscope.h - llvmloopanalyzer.cpp - llvmloopanalyzer.h + llvmtypeanalyzer.cpp + llvmtypeanalyzer.h llvmcompilercontext.cpp llvmcompilercontext.h llvmexecutablecode.cpp diff --git a/src/engine/internal/llvm/llvmloopanalyzer.cpp b/src/engine/internal/llvm/llvmtypeanalyzer.cpp similarity index 78% rename from src/engine/internal/llvm/llvmloopanalyzer.cpp rename to src/engine/internal/llvm/llvmtypeanalyzer.cpp index ce38d4f08..e043111db 100644 --- a/src/engine/internal/llvm/llvmloopanalyzer.cpp +++ b/src/engine/internal/llvm/llvmtypeanalyzer.cpp @@ -1,6 +1,6 @@ // SPDX-License-Identifier: Apache-2.0 -#include "llvmloopanalyzer.h" +#include "llvmtypeanalyzer.h" #include "llvminstruction.h" #include "llvmvariableptr.h" @@ -9,7 +9,7 @@ using namespace libscratchcpp; static const std::unordered_set BEGIN_LOOP_INSTRUCTIONS = { LLVMInstruction::Type::BeginRepeatLoop, LLVMInstruction::Type::BeginWhileLoop, LLVMInstruction::Type::BeginRepeatUntilLoop }; -bool LLVMLoopAnalyzer::variableTypeChanges(LLVMVariablePtr *varPtr, LLVMInstruction *loopBody, Compiler::StaticType preLoopType) const +bool LLVMTypeAnalyzer::variableTypeChangesInLoop(LLVMVariablePtr *varPtr, LLVMInstruction *loopBody, Compiler::StaticType preLoopType) const { if (!varPtr || !loopBody) return false; @@ -38,10 +38,10 @@ bool LLVMLoopAnalyzer::variableTypeChanges(LLVMVariablePtr *varPtr, LLVMInstruct return true; } - return variableTypeChangesFromEnd(varPtr, ins, preLoopType); + return variableTypeChangesInLoopFromEnd(varPtr, ins, preLoopType); } -bool LLVMLoopAnalyzer::variableTypeChangesFromEnd(LLVMVariablePtr *varPtr, LLVMInstruction *loopEnd, Compiler::StaticType preLoopType) const +bool LLVMTypeAnalyzer::variableTypeChangesInLoopFromEnd(LLVMVariablePtr *varPtr, LLVMInstruction *loopEnd, Compiler::StaticType preLoopType) const { // Find the last write instruction LLVMInstruction *ins = loopEnd->previous; @@ -49,7 +49,7 @@ bool LLVMLoopAnalyzer::variableTypeChangesFromEnd(LLVMVariablePtr *varPtr, LLVMI while (ins && !isLoopStart(ins)) { if (isLoopEnd(ins) || isIfEnd(ins) || isElse(ins)) { // Nested loop or if statement - if (variableTypeChangesFromEnd(varPtr, ins, preLoopType)) + if (variableTypeChangesInLoopFromEnd(varPtr, ins, preLoopType)) return true; // Skip the loop or if statement @@ -83,32 +83,32 @@ bool LLVMLoopAnalyzer::variableTypeChangesFromEnd(LLVMVariablePtr *varPtr, LLVMI return false; } -bool LLVMLoopAnalyzer::isLoopStart(LLVMInstruction *ins) const +bool LLVMTypeAnalyzer::isLoopStart(LLVMInstruction *ins) const { return (BEGIN_LOOP_INSTRUCTIONS.find(ins->type) != BEGIN_LOOP_INSTRUCTIONS.cend()); } -bool LLVMLoopAnalyzer::isLoopEnd(LLVMInstruction *ins) const +bool LLVMTypeAnalyzer::isLoopEnd(LLVMInstruction *ins) const { return (ins->type == LLVMInstruction::Type::EndLoop); } -bool LLVMLoopAnalyzer::isIfStart(LLVMInstruction *ins) const +bool LLVMTypeAnalyzer::isIfStart(LLVMInstruction *ins) const { return (ins->type == LLVMInstruction::Type::BeginIf); } -bool LLVMLoopAnalyzer::isElse(LLVMInstruction *ins) const +bool LLVMTypeAnalyzer::isElse(LLVMInstruction *ins) const { return (ins->type == LLVMInstruction::Type::BeginElse); } -bool LLVMLoopAnalyzer::isIfEnd(LLVMInstruction *ins) const +bool LLVMTypeAnalyzer::isIfEnd(LLVMInstruction *ins) const { return (ins->type == LLVMInstruction::Type::EndIf); } -Compiler::StaticType LLVMLoopAnalyzer::optimizeRegisterType(LLVMRegister *reg) const +Compiler::StaticType LLVMTypeAnalyzer::optimizeRegisterType(LLVMRegister *reg) const { // TODO: Move this method out if it's used in LLVMCodeBuilder too assert(reg); @@ -122,7 +122,7 @@ Compiler::StaticType LLVMLoopAnalyzer::optimizeRegisterType(LLVMRegister *reg) c return ret; } -Compiler::StaticType LLVMLoopAnalyzer::writeValueType(LLVMInstruction *ins) const +Compiler::StaticType LLVMTypeAnalyzer::writeValueType(LLVMInstruction *ins) const { assert(ins); assert(!ins->args.empty()); @@ -130,7 +130,7 @@ Compiler::StaticType LLVMLoopAnalyzer::writeValueType(LLVMInstruction *ins) cons return optimizeRegisterType(arg); } -bool LLVMLoopAnalyzer::typesMatch(LLVMInstruction *ins, Compiler::StaticType expectedType) const +bool LLVMTypeAnalyzer::typesMatch(LLVMInstruction *ins, Compiler::StaticType expectedType) const { // auto argIns = arg->instruction; diff --git a/src/engine/internal/llvm/llvmloopanalyzer.h b/src/engine/internal/llvm/llvmtypeanalyzer.h similarity index 71% rename from src/engine/internal/llvm/llvmloopanalyzer.h rename to src/engine/internal/llvm/llvmtypeanalyzer.h index 346d00533..8049a5035 100644 --- a/src/engine/internal/llvm/llvmloopanalyzer.h +++ b/src/engine/internal/llvm/llvmtypeanalyzer.h @@ -9,13 +9,13 @@ struct LLVMVariablePtr; struct LLVMInstruction; struct LLVMRegister; -class LLVMLoopAnalyzer +class LLVMTypeAnalyzer { public: - bool variableTypeChanges(LLVMVariablePtr *varPtr, LLVMInstruction *loopBody, Compiler::StaticType preLoopType) const; + bool variableTypeChangesInLoop(LLVMVariablePtr *varPtr, LLVMInstruction *loopBody, Compiler::StaticType preLoopType) const; private: - bool variableTypeChangesFromEnd(LLVMVariablePtr *varPtr, LLVMInstruction *loopEnd, Compiler::StaticType preLoopType) const; + bool variableTypeChangesInLoopFromEnd(LLVMVariablePtr *varPtr, LLVMInstruction *loopEnd, Compiler::StaticType preLoopType) const; bool isLoopStart(LLVMInstruction *ins) const; bool isLoopEnd(LLVMInstruction *ins) const; bool isIfStart(LLVMInstruction *ins) const; diff --git a/test/llvm/CMakeLists.txt b/test/llvm/CMakeLists.txt index 52e13a809..bc1ccc75f 100644 --- a/test/llvm/CMakeLists.txt +++ b/test/llvm/CMakeLists.txt @@ -20,7 +20,7 @@ add_executable( llvmexecutablecode_test.cpp llvmcodebuilder_test.cpp llvminstructionlist_test.cpp - loop_analyzer/variabletypechanges_test.cpp + type_analyzer/variabletypechangesinloop_test.cpp ) target_link_libraries( diff --git a/test/llvm/loop_analyzer/variabletypechanges_test.cpp b/test/llvm/type_analyzer/variabletypechangesinloop_test.cpp similarity index 82% rename from test/llvm/loop_analyzer/variabletypechanges_test.cpp rename to test/llvm/type_analyzer/variabletypechangesinloop_test.cpp index abfa95a7d..c5befa24e 100644 --- a/test/llvm/loop_analyzer/variabletypechanges_test.cpp +++ b/test/llvm/type_analyzer/variabletypechangesinloop_test.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include #include #include @@ -8,15 +8,15 @@ using namespace libscratchcpp; -TEST(LLVMLoopAnalyzer_VariableTypeChanges, NullParams) +TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, NullParams) { - LLVMLoopAnalyzer analyzer; - ASSERT_FALSE(analyzer.variableTypeChanges(nullptr, nullptr, Compiler::StaticType::Number)); + LLVMTypeAnalyzer analyzer; + ASSERT_FALSE(analyzer.variableTypeChangesInLoop(nullptr, nullptr, Compiler::StaticType::Number)); } -TEST(LLVMLoopAnalyzer_VariableTypeChanges, NullVariable) +TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, NullVariable) { - LLVMLoopAnalyzer analyzer; + LLVMTypeAnalyzer analyzer; LLVMInstructionList list; auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); @@ -28,19 +28,19 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, NullVariable) auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_FALSE(analyzer.variableTypeChanges(nullptr, start.get(), Compiler::StaticType::Number)); + ASSERT_FALSE(analyzer.variableTypeChangesInLoop(nullptr, start.get(), Compiler::StaticType::Number)); } -TEST(LLVMLoopAnalyzer_VariableTypeChanges, NullLoopBody) +TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, NullLoopBody) { - LLVMLoopAnalyzer analyzer; + LLVMTypeAnalyzer analyzer; LLVMVariablePtr varPtr; - ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, nullptr, Compiler::StaticType::Number)); + ASSERT_FALSE(analyzer.variableTypeChangesInLoop(&varPtr, nullptr, Compiler::StaticType::Number)); } -TEST(LLVMLoopAnalyzer_VariableTypeChanges, EmptyLoop) +TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, EmptyLoop) { - LLVMLoopAnalyzer analyzer; + LLVMTypeAnalyzer analyzer; LLVMVariablePtr varPtr; LLVMInstructionList list; @@ -50,12 +50,12 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, EmptyLoop) auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Number)); + ASSERT_FALSE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Number)); } -TEST(LLVMLoopAnalyzer_VariableTypeChanges, EmptyLoopUnknownType) +TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, EmptyLoopUnknownType) { - LLVMLoopAnalyzer analyzer; + LLVMTypeAnalyzer analyzer; LLVMVariablePtr varPtr; LLVMInstructionList list; @@ -66,12 +66,12 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, EmptyLoopUnknownType) list.addInstruction(end); // Always returns true for unknown type - ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Unknown)); + ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Unknown)); } -TEST(LLVMLoopAnalyzer_VariableTypeChanges, NoWriteOperations) +TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, NoWriteOperations) { - LLVMLoopAnalyzer analyzer; + LLVMTypeAnalyzer analyzer; LLVMInstructionList list; LLVMVariablePtr varPtr; @@ -84,12 +84,12 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, NoWriteOperations) auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Number)); + ASSERT_FALSE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Number)); } -TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteSameTypeNumber) +TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteSameTypeNumber) { - LLVMLoopAnalyzer analyzer; + LLVMTypeAnalyzer analyzer; LLVMInstructionList list; LLVMVariablePtr varPtr; Variable var("", ""); @@ -107,12 +107,12 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteSameTypeNumber) auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Number)); + ASSERT_FALSE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Number)); } -TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteSameTypeBool) +TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteSameTypeBool) { - LLVMLoopAnalyzer analyzer; + LLVMTypeAnalyzer analyzer; LLVMInstructionList list; LLVMVariablePtr varPtr; Variable var("", ""); @@ -130,12 +130,12 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteSameTypeBool) auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Bool)); + ASSERT_FALSE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Bool)); } -TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteSameTypeString) +TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteSameTypeString) { - LLVMLoopAnalyzer analyzer; + LLVMTypeAnalyzer analyzer; LLVMInstructionList list; LLVMVariablePtr varPtr; Variable var("", ""); @@ -153,12 +153,12 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteSameTypeString) auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::String)); + ASSERT_FALSE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::String)); } -TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteStringOptimization) +TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteStringOptimization) { - LLVMLoopAnalyzer analyzer; + LLVMTypeAnalyzer analyzer; LLVMInstructionList list; LLVMVariablePtr varPtr; Variable var("", ""); @@ -177,12 +177,12 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteStringOptimization) list.addInstruction(end); // Although string is assigned, it's constant and represents a number - ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Number)); + ASSERT_FALSE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Number)); } -TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteMultipleVariables) +TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteMultipleVariables) { - LLVMLoopAnalyzer analyzer; + LLVMTypeAnalyzer analyzer; LLVMInstructionList list; LLVMVariablePtr varPtr; Variable var1("", ""); @@ -209,12 +209,12 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteMultipleVariables) auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Number)); + ASSERT_FALSE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Number)); } -TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteFromUnknownType) +TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteFromUnknownType) { - LLVMLoopAnalyzer analyzer; + LLVMTypeAnalyzer analyzer; LLVMInstructionList list; LLVMVariablePtr varPtr; Variable var("", ""); @@ -233,12 +233,12 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteFromUnknownType) list.addInstruction(end); // Always returns true for unknown type - ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Number)); + ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Number)); } -TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteToUnknownType) +TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteToUnknownType) { - LLVMLoopAnalyzer analyzer; + LLVMTypeAnalyzer analyzer; LLVMInstructionList list; LLVMVariablePtr varPtr; Variable var("", ""); @@ -257,12 +257,12 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteToUnknownType) list.addInstruction(end); // Always returns true for unknown type - ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Unknown)); + ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Unknown)); } -TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteUnknownToUnknownType) +TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteUnknownToUnknownType) { - LLVMLoopAnalyzer analyzer; + LLVMTypeAnalyzer analyzer; LLVMInstructionList list; LLVMVariablePtr varPtr; Variable var("", ""); @@ -281,12 +281,12 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteUnknownToUnknownType) list.addInstruction(end); // Always returns true for unknown type - ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Unknown)); + ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Unknown)); } -TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteDifferentTypeNumberToString) +TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteDifferentTypeNumberToString) { - LLVMLoopAnalyzer analyzer; + LLVMTypeAnalyzer analyzer; LLVMInstructionList list; LLVMVariablePtr varPtr; Variable var("", ""); @@ -304,12 +304,12 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteDifferentTypeNumberToStrin auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Number)); + ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Number)); } -TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteDifferentTypeStringToNumber) +TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteDifferentTypeStringToNumber) { - LLVMLoopAnalyzer analyzer; + LLVMTypeAnalyzer analyzer; LLVMInstructionList list; LLVMVariablePtr varPtr; Variable var("", ""); @@ -327,12 +327,12 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteDifferentTypeStringToNumbe auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::String)); + ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::String)); } -TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteDifferentTypeNumberToBool) +TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteDifferentTypeNumberToBool) { - LLVMLoopAnalyzer analyzer; + LLVMTypeAnalyzer analyzer; LLVMInstructionList list; LLVMVariablePtr varPtr; Variable var("", ""); @@ -350,12 +350,12 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteDifferentTypeNumberToBool) auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Number)); + ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Number)); } -TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteDifferentTypeBoolToNumber) +TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteDifferentTypeBoolToNumber) { - LLVMLoopAnalyzer analyzer; + LLVMTypeAnalyzer analyzer; LLVMInstructionList list; LLVMVariablePtr varPtr; Variable var("", ""); @@ -373,12 +373,12 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteDifferentTypeBoolToNumber) auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Bool)); + ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Bool)); } -TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteDifferentTypeBoolToString) +TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteDifferentTypeBoolToString) { - LLVMLoopAnalyzer analyzer; + LLVMTypeAnalyzer analyzer; LLVMInstructionList list; LLVMVariablePtr varPtr; Variable var("", ""); @@ -396,12 +396,12 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteDifferentTypeBoolToString) auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Bool)); + ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Bool)); } -TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteDifferentTypeStringToBool) +TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteDifferentTypeStringToBool) { - LLVMLoopAnalyzer analyzer; + LLVMTypeAnalyzer analyzer; LLVMInstructionList list; LLVMVariablePtr varPtr; Variable var("", ""); @@ -419,12 +419,12 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteDifferentTypeStringToBool) auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::String)); + ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::String)); } -TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesSameTypeNumber) +TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, MultipleWritesSameTypeNumber) { - LLVMLoopAnalyzer analyzer; + LLVMTypeAnalyzer analyzer; LLVMInstructionList list; LLVMVariablePtr varPtr; Variable var("", ""); @@ -451,12 +451,12 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesSameTypeNumber) list.addInstruction(end); // Should return false because final assignment is compatible with pre-loop Number type - ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Number)); + ASSERT_FALSE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Number)); } -TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesSameTypeString) +TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, MultipleWritesSameTypeString) { - LLVMLoopAnalyzer analyzer; + LLVMTypeAnalyzer analyzer; LLVMInstructionList list; LLVMVariablePtr varPtr; Variable var("", ""); @@ -483,12 +483,12 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesSameTypeString) list.addInstruction(end); // Should return false because final assignment is compatible with pre-loop String type - ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::String)); + ASSERT_FALSE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::String)); } -TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesSameTypeUnknown) +TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, MultipleWritesSameTypeUnknown) { - LLVMLoopAnalyzer analyzer; + LLVMTypeAnalyzer analyzer; LLVMInstructionList list; LLVMVariablePtr varPtr; Variable var("", ""); @@ -515,12 +515,12 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesSameTypeUnknown) list.addInstruction(end); // Should return false because final assignment is compatible with pre-loop String type - ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::String)); + ASSERT_FALSE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::String)); } -TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesWithStringOptimization) +TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, MultipleWritesWithStringOptimization) { - LLVMLoopAnalyzer analyzer; + LLVMTypeAnalyzer analyzer; LLVMInstructionList list; LLVMVariablePtr varPtr; Variable var("", ""); @@ -547,12 +547,12 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesWithStringOptimization) list.addInstruction(end); // Should return false because final assignment is optimized to Number type - ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Number)); + ASSERT_FALSE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Number)); } -TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesNumberToString) +TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, MultipleWritesNumberToString) { - LLVMLoopAnalyzer analyzer; + LLVMTypeAnalyzer analyzer; LLVMInstructionList list; LLVMVariablePtr varPtr; Variable var("", ""); @@ -579,12 +579,12 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesNumberToString) list.addInstruction(end); // Should return true because final assignment is incompatible with pre-loop Number type - ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Number)); + ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Number)); } -TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesBoolToNumber) +TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, MultipleWritesBoolToNumber) { - LLVMLoopAnalyzer analyzer; + LLVMTypeAnalyzer analyzer; LLVMInstructionList list; LLVMVariablePtr varPtr; Variable var("", ""); @@ -602,12 +602,12 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesBoolToNumber) auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Bool)); + ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Bool)); } -TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesBoolToString) +TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, MultipleWritesBoolToString) { - LLVMLoopAnalyzer analyzer; + LLVMTypeAnalyzer analyzer; LLVMInstructionList list; LLVMVariablePtr varPtr; Variable var("", ""); @@ -625,12 +625,12 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesBoolToString) auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Bool)); + ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Bool)); } -TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesBoolToStringNumberOptimization) +TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, MultipleWritesBoolToStringNumberOptimization) { - LLVMLoopAnalyzer analyzer; + LLVMTypeAnalyzer analyzer; LLVMInstructionList list; LLVMVariablePtr varPtr; Variable var("", ""); @@ -649,12 +649,12 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesBoolToStringNumberOptim list.addInstruction(end); // String "3.14" gets optimized to Number, which is still different from Bool - ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Bool)); + ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Bool)); } -TEST(LLVMLoopAnalyzer_VariableTypeChanges, TypeChangeInIfBranch) +TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, TypeChangeInIfBranch) { - LLVMLoopAnalyzer analyzer; + LLVMTypeAnalyzer analyzer; LLVMInstructionList list; LLVMVariablePtr varPtr; Variable var("", ""); @@ -690,12 +690,12 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, TypeChangeInIfBranch) list.addInstruction(end); // Returns true because the type-changing branch might run - ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Number)); + ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Number)); } -TEST(LLVMLoopAnalyzer_VariableTypeChanges, TypeChangeInElseBranch) +TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, TypeChangeInElseBranch) { - LLVMLoopAnalyzer analyzer; + LLVMTypeAnalyzer analyzer; LLVMInstructionList list; LLVMVariablePtr varPtr; Variable var("", ""); @@ -731,12 +731,12 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, TypeChangeInElseBranch) list.addInstruction(end); // Returns true because the type-changing branch might run - ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Number)); + ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Number)); } -TEST(LLVMLoopAnalyzer_VariableTypeChanges, IfElseWithoutTypeChange) +TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, IfElseWithoutTypeChange) { - LLVMLoopAnalyzer analyzer; + LLVMTypeAnalyzer analyzer; LLVMInstructionList list; LLVMVariablePtr varPtr; Variable var("", ""); @@ -771,12 +771,12 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, IfElseWithoutTypeChange) auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Number)); + ASSERT_FALSE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Number)); } -TEST(LLVMLoopAnalyzer_VariableTypeChanges, NestedLoopWithTypeChange) +TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, NestedLoopWithTypeChange) { - LLVMLoopAnalyzer analyzer; + LLVMTypeAnalyzer analyzer; LLVMInstructionList list; LLVMVariablePtr varPtr; Variable var("", ""); @@ -812,12 +812,12 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, NestedLoopWithTypeChange) auto outerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(outerEnd); - ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, outerLoop.get(), Compiler::StaticType::Number)); + ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, outerLoop.get(), Compiler::StaticType::Number)); } -TEST(LLVMLoopAnalyzer_VariableTypeChanges, NestedLoopWithoutTypeChange) +TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, NestedLoopWithoutTypeChange) { - LLVMLoopAnalyzer analyzer; + LLVMTypeAnalyzer analyzer; LLVMInstructionList list; LLVMVariablePtr varPtr; Variable var("", ""); @@ -853,12 +853,12 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, NestedLoopWithoutTypeChange) auto outerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(outerEnd); - ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, outerLoop.get(), Compiler::StaticType::Number)); + ASSERT_FALSE(analyzer.variableTypeChangesInLoop(&varPtr, outerLoop.get(), Compiler::StaticType::Number)); } -TEST(LLVMLoopAnalyzer_VariableTypeChanges, NestedLoopTypeChangesButResets) +TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, NestedLoopTypeChangesButResets) { - LLVMLoopAnalyzer analyzer; + LLVMTypeAnalyzer analyzer; LLVMInstructionList list; LLVMVariablePtr varPtr; Variable var("", ""); @@ -901,12 +901,12 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, NestedLoopTypeChangesButResets) auto outerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(outerEnd); - ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, outerLoop.get(), Compiler::StaticType::Number)); + ASSERT_FALSE(analyzer.variableTypeChangesInLoop(&varPtr, outerLoop.get(), Compiler::StaticType::Number)); } -TEST(LLVMLoopAnalyzer_VariableTypeChanges, NestedLoopTypeChangesAndDoesNotReset) +TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, NestedLoopTypeChangesAndDoesNotReset) { - LLVMLoopAnalyzer analyzer; + LLVMTypeAnalyzer analyzer; LLVMInstructionList list; LLVMVariablePtr varPtr; Variable var("", ""); @@ -949,12 +949,12 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, NestedLoopTypeChangesAndDoesNotReset) auto outerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(outerEnd); - ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, outerLoop.get(), Compiler::StaticType::Number)); + ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, outerLoop.get(), Compiler::StaticType::Number)); } -TEST(LLVMLoopAnalyzer_VariableTypeChanges, NestedLoopWithTypeChangeBeforeLoop) +TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, NestedLoopWithTypeChangeBeforeLoop) { - LLVMLoopAnalyzer analyzer; + LLVMTypeAnalyzer analyzer; LLVMInstructionList list; LLVMVariablePtr varPtr; Variable var("", ""); @@ -991,12 +991,12 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, NestedLoopWithTypeChangeBeforeLoop) list.addInstruction(outerEnd); // Returns true because loops can be skipped - ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, outerLoop.get(), Compiler::StaticType::Number)); + ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, outerLoop.get(), Compiler::StaticType::Number)); } -TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleNestedLoopsWithTypeChange) +TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, MultipleNestedLoopsWithTypeChange) { - LLVMLoopAnalyzer analyzer; + LLVMTypeAnalyzer analyzer; LLVMInstructionList list; LLVMVariablePtr varPtr; Variable var("", ""); @@ -1047,12 +1047,12 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleNestedLoopsWithTypeChange) auto outerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(outerEnd); - ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, outerLoop.get(), Compiler::StaticType::Number)); + ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, outerLoop.get(), Compiler::StaticType::Number)); } -TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleNestedLoopsWithTypeChangeButTypeReset) +TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, MultipleNestedLoopsWithTypeChangeButTypeReset) { - LLVMLoopAnalyzer analyzer; + LLVMTypeAnalyzer analyzer; LLVMInstructionList list; LLVMVariablePtr varPtr; Variable var("", ""); @@ -1103,7 +1103,7 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleNestedLoopsWithTypeChangeButT auto outerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(outerEnd); - ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, outerLoop.get(), Compiler::StaticType::Number)); + ASSERT_FALSE(analyzer.variableTypeChangesInLoop(&varPtr, outerLoop.get(), Compiler::StaticType::Number)); } // TODO: Handle cross-variable dependencies From 26b2f6da725f0f17b54eca12451a7eb562921800 Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Thu, 24 Jul 2025 16:12:34 +0200 Subject: [PATCH 22/79] LLVMTypeAnalyzer: Implement variableType() for basic cases --- src/engine/internal/llvm/llvmtypeanalyzer.cpp | 42 + src/engine/internal/llvm/llvmtypeanalyzer.h | 1 + test/llvm/CMakeLists.txt | 1 + test/llvm/type_analyzer/variabletype_test.cpp | 994 ++++++++++++++++++ 4 files changed, 1038 insertions(+) create mode 100644 test/llvm/type_analyzer/variabletype_test.cpp diff --git a/src/engine/internal/llvm/llvmtypeanalyzer.cpp b/src/engine/internal/llvm/llvmtypeanalyzer.cpp index e043111db..f0e4c7494 100644 --- a/src/engine/internal/llvm/llvmtypeanalyzer.cpp +++ b/src/engine/internal/llvm/llvmtypeanalyzer.cpp @@ -9,6 +9,48 @@ using namespace libscratchcpp; static const std::unordered_set BEGIN_LOOP_INSTRUCTIONS = { LLVMInstruction::Type::BeginRepeatLoop, LLVMInstruction::Type::BeginWhileLoop, LLVMInstruction::Type::BeginRepeatUntilLoop }; +Compiler::StaticType LLVMTypeAnalyzer::variableType(LLVMVariablePtr *varPtr, LLVMInstruction *pos, Compiler::StaticType previousType) const +{ + if (!varPtr || !pos) + return Compiler::StaticType::Unknown; + + // Check the last write operation before the instruction + LLVMInstruction *ins = pos; + LLVMInstruction *write = nullptr; + LLVMInstruction *loopStart = nullptr; + int level = 0; + + while (ins) { + if (isLoopEnd(ins)) + level++; + else if (isLoopStart(ins)) { + level--; + + if (!loopStart) + loopStart = ins; + } else if (ins->type == LLVMInstruction::Type::WriteVariable && ins->workVariable == varPtr->var) { + if (level <= 0) { // ignore nested loops (they're handled later) + write = ins; + break; + } + } + + ins = ins->previous; + } + + if (loopStart) { + // Analyze the first loop that was found + if (variableTypeChangesInLoop(varPtr, loopStart, previousType)) + return write ? writeValueType(write) : Compiler::StaticType::Unknown; + } else if (write) { + // There wasn't any loop found, so we can just check the last write operation + return writeValueType(write); + } + + // No write operation found + return previousType; +} + bool LLVMTypeAnalyzer::variableTypeChangesInLoop(LLVMVariablePtr *varPtr, LLVMInstruction *loopBody, Compiler::StaticType preLoopType) const { if (!varPtr || !loopBody) diff --git a/src/engine/internal/llvm/llvmtypeanalyzer.h b/src/engine/internal/llvm/llvmtypeanalyzer.h index 8049a5035..86935282a 100644 --- a/src/engine/internal/llvm/llvmtypeanalyzer.h +++ b/src/engine/internal/llvm/llvmtypeanalyzer.h @@ -12,6 +12,7 @@ struct LLVMRegister; class LLVMTypeAnalyzer { public: + Compiler::StaticType variableType(LLVMVariablePtr *varPtr, LLVMInstruction *pos, Compiler::StaticType previousType) const; bool variableTypeChangesInLoop(LLVMVariablePtr *varPtr, LLVMInstruction *loopBody, Compiler::StaticType preLoopType) const; private: diff --git a/test/llvm/CMakeLists.txt b/test/llvm/CMakeLists.txt index bc1ccc75f..58f2249a6 100644 --- a/test/llvm/CMakeLists.txt +++ b/test/llvm/CMakeLists.txt @@ -21,6 +21,7 @@ add_executable( llvmcodebuilder_test.cpp llvminstructionlist_test.cpp type_analyzer/variabletypechangesinloop_test.cpp + type_analyzer/variabletype_test.cpp ) target_link_libraries( diff --git a/test/llvm/type_analyzer/variabletype_test.cpp b/test/llvm/type_analyzer/variabletype_test.cpp new file mode 100644 index 000000000..5b600e734 --- /dev/null +++ b/test/llvm/type_analyzer/variabletype_test.cpp @@ -0,0 +1,994 @@ +#include +#include +#include +#include +#include +#include +#include + +using namespace libscratchcpp; + +TEST(LLVMTypeAnalyzer_VariableType, NullParams) +{ + LLVMTypeAnalyzer analyzer; + ASSERT_EQ(analyzer.variableType(nullptr, nullptr, Compiler::StaticType::Number), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_VariableType, NullVariable) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(funcCall); + + ASSERT_EQ(analyzer.variableType(nullptr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_VariableType, NullPos) +{ + LLVMTypeAnalyzer analyzer; + LLVMVariablePtr varPtr; + ASSERT_EQ(analyzer.variableType(&varPtr, nullptr, Compiler::StaticType::Number), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_VariableType, NoWriteOperationsKnownType) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(funcCall); + + ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_VariableType, NoWriteOperationsUnknownType) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(funcCall); + + ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Unknown), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteSameTypeNumber_Before) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(start); + + auto setVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::Number, 1.25); + setVar->workVariable = &var; + setVar->args.push_back({ Compiler::StaticType::Unknown, &value }); + list.addInstruction(setVar); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(funcCall); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(end); + + ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteSameTypeNumber_After) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(start); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(funcCall); + + auto setVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::Number, 1.25); + setVar->workVariable = &var; + setVar->args.push_back({ Compiler::StaticType::Unknown, &value }); + list.addInstruction(setVar); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(end); + + ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteSameTypeBool_Before) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(start); + + auto setVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::Bool, true); + setVar->workVariable = &var; + setVar->args.push_back({ Compiler::StaticType::Unknown, &value }); + list.addInstruction(setVar); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(funcCall); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(end); + + ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Bool), Compiler::StaticType::Bool); +} + +TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteSameTypeBool_After) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(start); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(funcCall); + + auto setVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::Bool, true); + setVar->workVariable = &var; + setVar->args.push_back({ Compiler::StaticType::Unknown, &value }); + list.addInstruction(setVar); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(end); + + ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Bool), Compiler::StaticType::Bool); +} + +TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteSameTypeString_Before) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(start); + + auto setVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::String, "test"); + setVar->workVariable = &var; + setVar->args.push_back({ Compiler::StaticType::Unknown, &value }); + list.addInstruction(setVar); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(funcCall); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(end); + + ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::String), Compiler::StaticType::String); +} + +TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteSameTypeString_After) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(start); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(funcCall); + + auto setVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::String, "test"); + setVar->workVariable = &var; + setVar->args.push_back({ Compiler::StaticType::Unknown, &value }); + list.addInstruction(setVar); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(end); + + ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::String), Compiler::StaticType::String); +} + +TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteStringOptimization) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(start); + + auto setVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::String, "1.25"); + setVar->workVariable = &var; + setVar->args.push_back({ Compiler::StaticType::Unknown, &value }); + list.addInstruction(setVar); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(funcCall); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(end); + + // Although string is assigned, it's constant and represents a number + ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteMultipleVariables) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var1("", ""); + Variable var2("", ""); + varPtr.var = &var1; + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(start); + + // Set var1 + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 6); + setVar1->workVariable = &var1; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(setVar1); + + // Set var2 + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::String, "test"); + setVar2->workVariable = &var2; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + list.addInstruction(setVar2); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(funcCall); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(end); + + ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteFromUnknownType_Before) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(start); + + auto setVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMRegister value(Compiler::StaticType::Unknown); + setVar->workVariable = &var; + setVar->args.push_back({ Compiler::StaticType::Unknown, &value }); + list.addInstruction(setVar); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(funcCall); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(end); + + ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteFromUnknownType_After) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(start); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(funcCall); + + auto setVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMRegister value(Compiler::StaticType::Unknown); + setVar->workVariable = &var; + setVar->args.push_back({ Compiler::StaticType::Unknown, &value }); + list.addInstruction(setVar); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(end); + + ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteToUnknownType_Before) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(start); + + auto setVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::Number, 5); + setVar->workVariable = &var; + setVar->args.push_back({ Compiler::StaticType::Unknown, &value }); + list.addInstruction(setVar); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(funcCall); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(end); + + // The type is known because a number is assigned before the point + ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Unknown), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteToUnknownType_After) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(start); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(funcCall); + + auto setVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::Number, 5); + setVar->workVariable = &var; + setVar->args.push_back({ Compiler::StaticType::Unknown, &value }); + list.addInstruction(setVar); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(end); + + // The type is not known because a number is assigned after the point + ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Unknown), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteUnknownToUnknownType_Before) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(start); + + auto setVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMRegister value(Compiler::StaticType::Unknown); + setVar->workVariable = &var; + setVar->args.push_back({ Compiler::StaticType::Unknown, &value }); + list.addInstruction(setVar); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(funcCall); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(end); + + ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Unknown), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteUnknownToUnknownType_After) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(start); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(funcCall); + + auto setVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMRegister value(Compiler::StaticType::Unknown); + setVar->workVariable = &var; + setVar->args.push_back({ Compiler::StaticType::Unknown, &value }); + list.addInstruction(setVar); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(end); + + ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Unknown), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteDifferentTypeNumberToString_Before) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(start); + + auto setVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::String, "test"); + setVar->workVariable = &var; + setVar->args.push_back({ Compiler::StaticType::Unknown, &value }); + list.addInstruction(setVar); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(funcCall); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(end); + + ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::String); +} + +TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteDifferentTypeNumberToString_After) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(start); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(funcCall); + + auto setVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::String, "test"); + setVar->workVariable = &var; + setVar->args.push_back({ Compiler::StaticType::Unknown, &value }); + list.addInstruction(setVar); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(end); + + ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteDifferentTypeStringToNumber_After) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(start); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(funcCall); + + auto setVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::Number, 5.8); + setVar->workVariable = &var; + setVar->args.push_back({ Compiler::StaticType::Unknown, &value }); + list.addInstruction(setVar); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(end); + + ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::String), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteDifferentTypeNumberToBool_After) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(start); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(funcCall); + + auto setVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::Bool, true); + setVar->workVariable = &var; + setVar->args.push_back({ Compiler::StaticType::Unknown, &value }); + list.addInstruction(setVar); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(end); + + ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteDifferentTypeBoolToNumber_Before) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(start); + + auto setVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::Number, 1); + setVar->workVariable = &var; + setVar->args.push_back({ Compiler::StaticType::Unknown, &value }); + list.addInstruction(setVar); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(funcCall); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(end); + + ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Bool), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteDifferentTypeBoolToNumber_After) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(start); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(funcCall); + + auto setVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::Number, 1); + setVar->workVariable = &var; + setVar->args.push_back({ Compiler::StaticType::Unknown, &value }); + list.addInstruction(setVar); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(end); + + ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Bool), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteDifferentTypeBoolToString_After) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(start); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(funcCall); + + auto setVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::String, "abc"); + setVar->workVariable = &var; + setVar->args.push_back({ Compiler::StaticType::Unknown, &value }); + list.addInstruction(setVar); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(end); + + ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Bool), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteDifferentTypeStringToBool_Before) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(start); + + auto setVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::Bool, false); + setVar->workVariable = &var; + setVar->args.push_back({ Compiler::StaticType::Unknown, &value }); + list.addInstruction(setVar); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(funcCall); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(end); + + ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::String), Compiler::StaticType::Bool); +} + +TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteDifferentTypeStringToBool_After) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(start); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(funcCall); + + auto setVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::Bool, false); + setVar->workVariable = &var; + setVar->args.push_back({ Compiler::StaticType::Unknown, &value }); + list.addInstruction(setVar); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(end); + + ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::String), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_VariableType, WriteSameTypeInLoop) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(start); + + auto setVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::Number, 1.25); + setVar->workVariable = &var; + setVar->args.push_back({ Compiler::StaticType::Unknown, &value }); + list.addInstruction(setVar); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(end); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(funcCall); + + ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_VariableType, WriteDifferentTypeInLoop) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(start); + + auto setVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::String, "test"); + setVar->workVariable = &var; + setVar->args.push_back({ Compiler::StaticType::Unknown, &value }); + list.addInstruction(setVar); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(end); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(funcCall); + + // Type is not known because the loop might not run at all + ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_VariableType, OverrideDifferentTypeBeforeLoop) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 1.25); + setVar1->workVariable = &var; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(setVar1); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(start); + + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::Number, 1.25); + setVar2->workVariable = &var; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + list.addInstruction(setVar2); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(end); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(funcCall); + + ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::String), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_VariableType, OverrideUnknownTypeBeforeLoop) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 1.25); + setVar1->workVariable = &var; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(setVar1); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(start); + + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::Number, 1.25); + setVar2->workVariable = &var; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + list.addInstruction(setVar2); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(end); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(funcCall); + + ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Unknown), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_VariableType, MultipleWritesSameTypeNumber) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + // First write: string "abc" (incompatible with Number) + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::String, "abc"); + setVar1->workVariable = &var; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(setVar1); + + // Second write: number 5.25 (compatible with Number pre-loop type) + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::Number, 5.25); + setVar2->workVariable = &var; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + list.addInstruction(setVar2); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(funcCall); + + // Should return Number type because final assignment writes a number + ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_VariableType, MultipleWritesSameTypeString) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + // First write: number 42 (incompatible with String) + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 42); + setVar1->workVariable = &var; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(setVar1); + + // Second write: string "hello" (compatible with String pre-loop type) + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::String, "hello"); + setVar2->workVariable = &var; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + list.addInstruction(setVar2); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(funcCall); + + // Should return String type because final assignment writes a string + ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::String), Compiler::StaticType::String); +} + +TEST(LLVMTypeAnalyzer_VariableType, MultipleWritesSameTypeUnknown) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + // First write: unknown type + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMRegister value1(Compiler::StaticType::Unknown); + setVar1->workVariable = &var; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(setVar1); + + // Second write: string "hello" (compatible with String pre-loop type) + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::String, "hello"); + setVar2->workVariable = &var; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + list.addInstruction(setVar2); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(funcCall); + + // Should return String type because final assignment writes a string + ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::String), Compiler::StaticType::String); +} + +TEST(LLVMTypeAnalyzer_VariableType, MultipleWritesWithStringOptimization) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + // First write: string "abc" (incompatible with Number) + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::String, "abc"); + setVar1->workVariable = &var; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(setVar1); + + // Second write: string "3.14" (optimized to Number, compatible with pre-loop type) + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::String, "3.14"); + setVar2->workVariable = &var; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + list.addInstruction(setVar2); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(funcCall); + + // Should return Number type because final assignment writes a string which is optimized to Number type + ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_VariableType, MultipleWritesNumberToString) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + // First write: number 42 (compatible with Number) + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 42); + setVar1->workVariable = &var; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(setVar1); + + // Second write: string "hello" (incompatible with Number pre-loop type) + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::String, "hello"); + setVar2->workVariable = &var; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + list.addInstruction(setVar2); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(funcCall); + + // Should return String type because final assignment writes a string + ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::String); +} + +TEST(LLVMTypeAnalyzer_VariableType, MultipleWritesBoolToNumber) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + auto setVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::Number, 42.5); + setVar->workVariable = &var; + setVar->args.push_back({ Compiler::StaticType::Unknown, &value }); + list.addInstruction(setVar); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(funcCall); + + // Should return Number type because final assignment writes a number + ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Bool), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_VariableType, MultipleWritesBoolToString) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + auto setVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::String, "hello"); + setVar->workVariable = &var; + setVar->args.push_back({ Compiler::StaticType::Unknown, &value }); + list.addInstruction(setVar); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(funcCall); + + // Should return String type because final assignment writes a string + ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Bool), Compiler::StaticType::String); +} + +TEST(LLVMTypeAnalyzer_VariableType, MultipleWritesBoolToStringNumberOptimization) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + auto setVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::String, "3.14"); + setVar->workVariable = &var; + setVar->args.push_back({ Compiler::StaticType::Unknown, &value }); + list.addInstruction(setVar); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(funcCall); + + // String "3.14" gets optimized to Number, which is still different from Bool + ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Bool), Compiler::StaticType::Number); +} + +// TODO: Handle cross-variable dependencies From 2c2bf751faa847dcc3b17337bce355e55f5b1506 Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Thu, 24 Jul 2025 16:35:44 +0200 Subject: [PATCH 23/79] LLVMTypeAnalyzer: Ignore unknown pre-loop type --- src/engine/internal/llvm/llvmtypeanalyzer.cpp | 9 +++++---- .../type_analyzer/variabletypechangesinloop_test.cpp | 6 +----- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/engine/internal/llvm/llvmtypeanalyzer.cpp b/src/engine/internal/llvm/llvmtypeanalyzer.cpp index f0e4c7494..dc9ecc18d 100644 --- a/src/engine/internal/llvm/llvmtypeanalyzer.cpp +++ b/src/engine/internal/llvm/llvmtypeanalyzer.cpp @@ -56,9 +56,6 @@ bool LLVMTypeAnalyzer::variableTypeChangesInLoop(LLVMVariablePtr *varPtr, LLVMIn if (!varPtr || !loopBody) return false; - if (preLoopType == Compiler::StaticType::Unknown) - return true; - // Find loop end LLVMInstruction *ins = loopBody->next; int loopLevel = 0; @@ -180,5 +177,9 @@ bool LLVMTypeAnalyzer::typesMatch(LLVMInstruction *ins, Compiler::StaticType exp /*if (argIns && (argIns->type == LLVMInstruction::Type::ReadVariable || argIns->type == LLVMInstruction::Type::GetListItem)) return isVarOrListTypeSafe(argIns.get(), expectedType, log, c);*/ - return (writeValueType(ins) == expectedType); + if (expectedType == Compiler::StaticType::Unknown) { + // Equal unknown types are not considered a match + return false; + } else + return (writeValueType(ins) == expectedType); } diff --git a/test/llvm/type_analyzer/variabletypechangesinloop_test.cpp b/test/llvm/type_analyzer/variabletypechangesinloop_test.cpp index c5befa24e..dd782f1d1 100644 --- a/test/llvm/type_analyzer/variabletypechangesinloop_test.cpp +++ b/test/llvm/type_analyzer/variabletypechangesinloop_test.cpp @@ -65,8 +65,7 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, EmptyLoopUnknownType) auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - // Always returns true for unknown type - ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Unknown)); + ASSERT_FALSE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Unknown)); } TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, NoWriteOperations) @@ -232,7 +231,6 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteFromUnknownType) auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - // Always returns true for unknown type ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Number)); } @@ -256,7 +254,6 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteToUnknownType) auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - // Always returns true for unknown type ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Unknown)); } @@ -280,7 +277,6 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteUnknownToUnknownType auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - // Always returns true for unknown type ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Unknown)); } From ee90056f834d8e51bef225839aaad0b05e80c905 Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Fri, 25 Jul 2025 18:28:32 +0200 Subject: [PATCH 24/79] variableTypeChangesInLoop() -> variableTypeChangesInBranch() --- src/engine/internal/llvm/llvmtypeanalyzer.cpp | 90 ++- src/engine/internal/llvm/llvmtypeanalyzer.h | 5 +- test/llvm/CMakeLists.txt | 2 +- ...p => variabletypechangesinbranch_test.cpp} | 707 +++++++++++++++--- 4 files changed, 670 insertions(+), 134 deletions(-) rename test/llvm/type_analyzer/{variabletypechangesinloop_test.cpp => variabletypechangesinbranch_test.cpp} (55%) diff --git a/src/engine/internal/llvm/llvmtypeanalyzer.cpp b/src/engine/internal/llvm/llvmtypeanalyzer.cpp index dc9ecc18d..10b419595 100644 --- a/src/engine/internal/llvm/llvmtypeanalyzer.cpp +++ b/src/engine/internal/llvm/llvmtypeanalyzer.cpp @@ -40,7 +40,7 @@ Compiler::StaticType LLVMTypeAnalyzer::variableType(LLVMVariablePtr *varPtr, LLV if (loopStart) { // Analyze the first loop that was found - if (variableTypeChangesInLoop(varPtr, loopStart, previousType)) + if (variableTypeChangesInBranch(varPtr, loopStart, previousType)) return write ? writeValueType(write) : Compiler::StaticType::Unknown; } else if (write) { // There wasn't any loop found, so we can just check the last write operation @@ -51,69 +51,60 @@ Compiler::StaticType LLVMTypeAnalyzer::variableType(LLVMVariablePtr *varPtr, LLV return previousType; } -bool LLVMTypeAnalyzer::variableTypeChangesInLoop(LLVMVariablePtr *varPtr, LLVMInstruction *loopBody, Compiler::StaticType preLoopType) const +bool LLVMTypeAnalyzer::variableTypeChangesInBranch(LLVMVariablePtr *varPtr, LLVMInstruction *start, Compiler::StaticType previousType) const { - if (!varPtr || !loopBody) + if (!varPtr || !start) return false; - // Find loop end - LLVMInstruction *ins = loopBody->next; - int loopLevel = 0; + assert(isLoopStart(start) || isIfStart(start) || isElse(start)); - while (ins && !(isLoopEnd(ins) && loopLevel == 0)) { - if (isLoopStart(ins)) - loopLevel++; - else if (isLoopEnd(ins)) { - assert(loopLevel > 0); - loopLevel--; + // Find loop/if statement end or else branch + LLVMInstruction *ins = start->next; + int level = 0; + + while (ins && !((isLoopEnd(ins) || isIfEnd(ins) || isElse(ins)) && level == 0)) { + if (isLoopStart(ins) || isIfStart(ins)) + level++; + else if (isLoopEnd(ins) || isIfEnd(ins)) { + assert(level > 0); + level--; } ins = ins->next; } - // Loops must always have an end instruction if (!ins) { assert(false); return true; } - return variableTypeChangesInLoopFromEnd(varPtr, ins, preLoopType); + // Process the branch from end + return variableTypeChangesInBranchFromEnd(varPtr, ins, previousType); } -bool LLVMTypeAnalyzer::variableTypeChangesInLoopFromEnd(LLVMVariablePtr *varPtr, LLVMInstruction *loopEnd, Compiler::StaticType preLoopType) const +bool LLVMTypeAnalyzer::variableTypeChangesInBranchFromEnd(LLVMVariablePtr *varPtr, LLVMInstruction *end, Compiler::StaticType previousType) const { // Find the last write instruction - LLVMInstruction *ins = loopEnd->previous; + LLVMInstruction *ins = end->previous; - while (ins && !isLoopStart(ins)) { + while (ins && !isLoopStart(ins) && !isIfStart(ins)) { if (isLoopEnd(ins) || isIfEnd(ins) || isElse(ins)) { - // Nested loop or if statement - if (variableTypeChangesInLoopFromEnd(varPtr, ins, preLoopType)) + // Process the nested loop or if statement + if (variableTypeChangesInBranchFromEnd(varPtr, ins, previousType)) return true; - // Skip the loop or if statement - int level = 0; - ins = ins->previous; - - while (ins && !((isLoopStart(ins) || isIfStart(ins) || isElse(ins)) && level == 0)) { - if (isLoopStart(ins) || isIfStart(ins)) { - assert(level > 0); - level--; - } - - if (isLoopEnd(ins) || isIfEnd(ins) || isElse(ins)) - level++; + ins = skipBranch(ins); - ins = ins->previous; - }; + if (isElse(ins)) { + // Process if branch (the else branch is already processed) + if (variableTypeChangesInBranchFromEnd(varPtr, ins, previousType)) + return true; - if (!ins) { - assert(false); - return true; + ins = skipBranch(ins); } } else if (ins->type == LLVMInstruction::Type::WriteVariable && ins->workVariable == varPtr->var) { // Variable write instruction - return !typesMatch(ins, preLoopType); + return !typesMatch(ins, previousType); } ins = ins->previous; @@ -122,6 +113,31 @@ bool LLVMTypeAnalyzer::variableTypeChangesInLoopFromEnd(LLVMVariablePtr *varPtr, return false; } +LLVMInstruction *LLVMTypeAnalyzer::skipBranch(LLVMInstruction *pos) const +{ + int level = 0; + pos = pos->previous; + + while (pos && !((isLoopStart(pos) || isIfStart(pos)) && level == 0)) { + if (isLoopStart(pos) || isIfStart(pos)) { + assert(level > 0); + level--; + } + + if (isLoopEnd(pos) || isIfEnd(pos) || isElse(pos)) { + if (isElse(pos) && level == 0) + break; + + level++; + } + + pos = pos->previous; + }; + + assert(pos); + return pos; +} + bool LLVMTypeAnalyzer::isLoopStart(LLVMInstruction *ins) const { return (BEGIN_LOOP_INSTRUCTIONS.find(ins->type) != BEGIN_LOOP_INSTRUCTIONS.cend()); diff --git a/src/engine/internal/llvm/llvmtypeanalyzer.h b/src/engine/internal/llvm/llvmtypeanalyzer.h index 86935282a..9ba9c5ca9 100644 --- a/src/engine/internal/llvm/llvmtypeanalyzer.h +++ b/src/engine/internal/llvm/llvmtypeanalyzer.h @@ -13,10 +13,11 @@ class LLVMTypeAnalyzer { public: Compiler::StaticType variableType(LLVMVariablePtr *varPtr, LLVMInstruction *pos, Compiler::StaticType previousType) const; - bool variableTypeChangesInLoop(LLVMVariablePtr *varPtr, LLVMInstruction *loopBody, Compiler::StaticType preLoopType) const; + bool variableTypeChangesInBranch(LLVMVariablePtr *varPtr, LLVMInstruction *start, Compiler::StaticType previousType) const; private: - bool variableTypeChangesInLoopFromEnd(LLVMVariablePtr *varPtr, LLVMInstruction *loopEnd, Compiler::StaticType preLoopType) const; + bool variableTypeChangesInBranchFromEnd(LLVMVariablePtr *varPtr, LLVMInstruction *end, Compiler::StaticType previousType) const; + LLVMInstruction *skipBranch(LLVMInstruction *pos) const; bool isLoopStart(LLVMInstruction *ins) const; bool isLoopEnd(LLVMInstruction *ins) const; bool isIfStart(LLVMInstruction *ins) const; diff --git a/test/llvm/CMakeLists.txt b/test/llvm/CMakeLists.txt index 58f2249a6..70f7ecd94 100644 --- a/test/llvm/CMakeLists.txt +++ b/test/llvm/CMakeLists.txt @@ -20,7 +20,7 @@ add_executable( llvmexecutablecode_test.cpp llvmcodebuilder_test.cpp llvminstructionlist_test.cpp - type_analyzer/variabletypechangesinloop_test.cpp + type_analyzer/variabletypechangesinbranch_test.cpp type_analyzer/variabletype_test.cpp ) diff --git a/test/llvm/type_analyzer/variabletypechangesinloop_test.cpp b/test/llvm/type_analyzer/variabletypechangesinbranch_test.cpp similarity index 55% rename from test/llvm/type_analyzer/variabletypechangesinloop_test.cpp rename to test/llvm/type_analyzer/variabletypechangesinbranch_test.cpp index dd782f1d1..329c84e3f 100644 --- a/test/llvm/type_analyzer/variabletypechangesinloop_test.cpp +++ b/test/llvm/type_analyzer/variabletypechangesinbranch_test.cpp @@ -8,13 +8,13 @@ using namespace libscratchcpp; -TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, NullParams) +TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, NullParams) { LLVMTypeAnalyzer analyzer; - ASSERT_FALSE(analyzer.variableTypeChangesInLoop(nullptr, nullptr, Compiler::StaticType::Number)); + ASSERT_FALSE(analyzer.variableTypeChangesInBranch(nullptr, nullptr, Compiler::StaticType::Number)); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, NullVariable) +TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, NullVariable) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -28,17 +28,17 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, NullVariable) auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_FALSE(analyzer.variableTypeChangesInLoop(nullptr, start.get(), Compiler::StaticType::Number)); + ASSERT_FALSE(analyzer.variableTypeChangesInBranch(nullptr, start.get(), Compiler::StaticType::Number)); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, NullLoopBody) +TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, NullStartInstruction) { LLVMTypeAnalyzer analyzer; LLVMVariablePtr varPtr; - ASSERT_FALSE(analyzer.variableTypeChangesInLoop(&varPtr, nullptr, Compiler::StaticType::Number)); + ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, nullptr, Compiler::StaticType::Number)); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, EmptyLoop) +TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, EmptyLoop) { LLVMTypeAnalyzer analyzer; LLVMVariablePtr varPtr; @@ -50,10 +50,61 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, EmptyLoop) auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_FALSE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Number)); + ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Number)); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, EmptyLoopUnknownType) +TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, EmptyIfStatement) +{ + LLVMTypeAnalyzer analyzer; + LLVMVariablePtr varPtr; + LLVMInstructionList list; + + auto start = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + list.addInstruction(start); + + auto end = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + list.addInstruction(end); + + ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Number)); +} + +TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, EmptyIfElseStatement_IfBranch) +{ + LLVMTypeAnalyzer analyzer; + LLVMVariablePtr varPtr; + LLVMInstructionList list; + + auto start = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + list.addInstruction(start); + + auto elseStart = std::make_shared(LLVMInstruction::Type::BeginElse, nullptr, false); + list.addInstruction(elseStart); + + auto end = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + list.addInstruction(end); + + ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Number)); +} + +TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, EmptyIfElseStatement_ElseBranch) +{ + LLVMTypeAnalyzer analyzer; + LLVMVariablePtr varPtr; + LLVMInstructionList list; + + auto start = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + list.addInstruction(start); + + auto elseStart = std::make_shared(LLVMInstruction::Type::BeginElse, nullptr, false); + list.addInstruction(elseStart); + + auto end = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + list.addInstruction(end); + + ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, elseStart.get(), Compiler::StaticType::Number)); +} + +TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, EmptyLoopUnknownType) { LLVMTypeAnalyzer analyzer; LLVMVariablePtr varPtr; @@ -65,10 +116,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, EmptyLoopUnknownType) auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_FALSE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Unknown)); + ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Unknown)); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, NoWriteOperations) +TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, NoWriteOperations) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -83,10 +134,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, NoWriteOperations) auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_FALSE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Number)); + ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Number)); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteSameTypeNumber) +TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteSameTypeNumber) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -106,10 +157,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteSameTypeNumber) auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_FALSE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Number)); + ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Number)); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteSameTypeBool) +TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteSameTypeBool) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -129,10 +180,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteSameTypeBool) auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_FALSE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Bool)); + ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Bool)); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteSameTypeString) +TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteSameTypeString) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -152,10 +203,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteSameTypeString) auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_FALSE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::String)); + ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::String)); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteStringOptimization) +TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteStringOptimization) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -176,10 +227,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteStringOptimization) list.addInstruction(end); // Although string is assigned, it's constant and represents a number - ASSERT_FALSE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Number)); + ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Number)); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteMultipleVariables) +TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteMultipleVariables) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -208,10 +259,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteMultipleVariables) auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_FALSE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Number)); + ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Number)); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteFromUnknownType) +TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteFromUnknownType) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -231,10 +282,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteFromUnknownType) auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Number)); + ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Number)); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteToUnknownType) +TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteToUnknownType) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -254,10 +305,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteToUnknownType) auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Unknown)); + ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Unknown)); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteUnknownToUnknownType) +TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteUnknownToUnknownType) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -277,10 +328,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteUnknownToUnknownType auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Unknown)); + ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Unknown)); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteDifferentTypeNumberToString) +TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteDifferentTypeNumberToString) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -300,10 +351,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteDifferentTypeNumberT auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Number)); + ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Number)); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteDifferentTypeStringToNumber) +TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteDifferentTypeStringToNumber) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -323,10 +374,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteDifferentTypeStringT auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::String)); + ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::String)); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteDifferentTypeNumberToBool) +TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteDifferentTypeNumberToBool) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -346,10 +397,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteDifferentTypeNumberT auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Number)); + ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Number)); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteDifferentTypeBoolToNumber) +TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteDifferentTypeBoolToNumber) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -369,10 +420,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteDifferentTypeBoolToN auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Bool)); + ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Bool)); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteDifferentTypeBoolToString) +TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteDifferentTypeBoolToString) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -392,10 +443,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteDifferentTypeBoolToS auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Bool)); + ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Bool)); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteDifferentTypeStringToBool) +TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteDifferentTypeStringToBool) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -415,10 +466,56 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteDifferentTypeStringT auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::String)); + ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::String)); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, MultipleWritesSameTypeNumber) +TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteSameType_IfStatement) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + auto start = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + list.addInstruction(start); + + auto setVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::Number, 1.25); + setVar->workVariable = &var; + setVar->args.push_back({ Compiler::StaticType::Unknown, &value }); + list.addInstruction(setVar); + + auto end = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + list.addInstruction(end); + + ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Number)); +} + +TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteDifferentType_IfStatement) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + auto start = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + list.addInstruction(start); + + auto setVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::Number, 5.8); + setVar->workVariable = &var; + setVar->args.push_back({ Compiler::StaticType::Unknown, &value }); + list.addInstruction(setVar); + + auto end = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + list.addInstruction(end); + + ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::String)); +} + +TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesSameTypeNumber) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -447,10 +544,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, MultipleWritesSameTypeNumber) list.addInstruction(end); // Should return false because final assignment is compatible with pre-loop Number type - ASSERT_FALSE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Number)); + ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Number)); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, MultipleWritesSameTypeString) +TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesSameTypeString) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -479,10 +576,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, MultipleWritesSameTypeString) list.addInstruction(end); // Should return false because final assignment is compatible with pre-loop String type - ASSERT_FALSE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::String)); + ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::String)); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, MultipleWritesSameTypeUnknown) +TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesSameTypeUnknown) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -511,10 +608,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, MultipleWritesSameTypeUnknown) list.addInstruction(end); // Should return false because final assignment is compatible with pre-loop String type - ASSERT_FALSE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::String)); + ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::String)); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, MultipleWritesWithStringOptimization) +TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesWithStringOptimization) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -543,10 +640,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, MultipleWritesWithStringOptimiz list.addInstruction(end); // Should return false because final assignment is optimized to Number type - ASSERT_FALSE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Number)); + ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Number)); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, MultipleWritesNumberToString) +TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesNumberToString) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -575,10 +672,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, MultipleWritesNumberToString) list.addInstruction(end); // Should return true because final assignment is incompatible with pre-loop Number type - ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Number)); + ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Number)); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, MultipleWritesBoolToNumber) +TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesBoolToNumber) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -589,19 +686,27 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, MultipleWritesBoolToNumber) auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); list.addInstruction(start); - auto setVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); - LLVMConstantRegister value(Compiler::StaticType::Number, 42.5); - setVar->workVariable = &var; - setVar->args.push_back({ Compiler::StaticType::Unknown, &value }); - list.addInstruction(setVar); + // First write: compatible with Bool + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Bool, true); + setVar1->workVariable = &var; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(setVar1); + + // Second write: number 4.25 (incompatible with Bool pre-loop type) + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::String, 4.25); + setVar2->workVariable = &var; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + list.addInstruction(setVar2); auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Bool)); + ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Bool)); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, MultipleWritesBoolToString) +TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesBoolToString) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -612,19 +717,27 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, MultipleWritesBoolToString) auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); list.addInstruction(start); - auto setVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); - LLVMConstantRegister value(Compiler::StaticType::String, "hello"); - setVar->workVariable = &var; - setVar->args.push_back({ Compiler::StaticType::Unknown, &value }); - list.addInstruction(setVar); + // First write: compatible with Bool + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Bool, true); + setVar1->workVariable = &var; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(setVar1); + + // Second write: string "hello" (incompatible with Bool pre-loop type) + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::String, "hello"); + setVar2->workVariable = &var; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + list.addInstruction(setVar2); auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Bool)); + ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Bool)); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, MultipleWritesBoolToStringNumberOptimization) +TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesSameType_IfStatement) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -632,23 +745,228 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, MultipleWritesBoolToStringNumbe Variable var("", ""); varPtr.var = &var; - auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + auto start = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); list.addInstruction(start); - auto setVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); - LLVMConstantRegister value(Compiler::StaticType::String, "3.14"); - setVar->workVariable = &var; - setVar->args.push_back({ Compiler::StaticType::Unknown, &value }); - list.addInstruction(setVar); + // First write: string "abc" (incompatible with Number) + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::String, "abc"); + setVar1->workVariable = &var; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(setVar1); - auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + // Second write: number 5.25 (compatible with Number type) + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::Number, 5.25); + setVar2->workVariable = &var; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + list.addInstruction(setVar2); + + auto end = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + list.addInstruction(end); + + // Should return false because final assignment is compatible with Number type + ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Number)); +} + +TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesSameType_IfBranch) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + auto start = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + list.addInstruction(start); + + // First write: string "abc" (incompatible with Number) + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::String, "abc"); + setVar1->workVariable = &var; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(setVar1); + + // Second write: number 5.25 (compatible with Number type) + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::Number, 5.25); + setVar2->workVariable = &var; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + list.addInstruction(setVar2); + + auto elseStart = std::make_shared(LLVMInstruction::Type::BeginElse, nullptr, false); + list.addInstruction(elseStart); + + // Else branch write: string "test" (incompatible with Number type) + auto setVar3 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value3(Compiler::StaticType::String, "test"); + setVar3->workVariable = &var; + setVar3->args.push_back({ Compiler::StaticType::Unknown, &value3 }); + list.addInstruction(setVar3); + + auto end = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + list.addInstruction(end); + + // Should return false because final assignment is compatible with Number type + ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Number)); +} + +TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesSameType_ElseBranch) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + auto start = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + list.addInstruction(start); + + // First write: string "abc" (incompatible with Number) + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::String, "abc"); + setVar1->workVariable = &var; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(setVar1); + + auto elseStart = std::make_shared(LLVMInstruction::Type::BeginElse, nullptr, false); + list.addInstruction(elseStart); + + // Else branch first write: string "abc" (incompatible with Number) + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::String, "abc"); + setVar2->workVariable = &var; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + list.addInstruction(setVar2); + + // Else branch second write: number 5.25 (compatible with Number type) + auto setVar3 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value3(Compiler::StaticType::Number, 5.25); + setVar3->workVariable = &var; + setVar3->args.push_back({ Compiler::StaticType::Unknown, &value3 }); + list.addInstruction(setVar3); + + auto end = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + list.addInstruction(end); + + // Should return false because final assignment is compatible with Number type + ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, elseStart.get(), Compiler::StaticType::Number)); +} + +TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesDifferentTypes_IfStatement) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + auto start = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + list.addInstruction(start); + + // First write: compatible with Bool + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Bool, true); + setVar1->workVariable = &var; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(setVar1); + + // Second write: string "hello" (incompatible with Bool type) + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::String, "hello"); + setVar2->workVariable = &var; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + list.addInstruction(setVar2); + + auto end = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); list.addInstruction(end); - // String "3.14" gets optimized to Number, which is still different from Bool - ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Bool)); + ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Bool)); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, TypeChangeInIfBranch) +TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesDifferentTypes_IfBranch) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + auto start = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + list.addInstruction(start); + + // First write: compatible with Bool + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Bool, true); + setVar1->workVariable = &var; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(setVar1); + + // Second write: string "hello" (incompatible with Bool type) + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::String, "hello"); + setVar2->workVariable = &var; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + list.addInstruction(setVar2); + + auto elseStart = std::make_shared(LLVMInstruction::Type::BeginElse, nullptr, false); + list.addInstruction(elseStart); + + // Else branch write: compatible with Bool + auto setVar3 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value3(Compiler::StaticType::Bool, true); + setVar3->workVariable = &var; + setVar3->args.push_back({ Compiler::StaticType::Unknown, &value3 }); + list.addInstruction(setVar3); + + auto end = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + list.addInstruction(end); + + ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Bool)); +} + +TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesDifferentTypes_ElseBranch) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + auto start = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + list.addInstruction(start); + + // First write: compatible with Bool + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Bool, true); + setVar1->workVariable = &var; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(setVar1); + + auto elseStart = std::make_shared(LLVMInstruction::Type::BeginElse, nullptr, false); + list.addInstruction(elseStart); + + // First else branch write: compatible with Bool + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::Bool, true); + setVar2->workVariable = &var; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + list.addInstruction(setVar2); + + // Second else branch write: string "hello" (incompatible with Bool type) + auto setVar3 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value3(Compiler::StaticType::String, "hello"); + setVar3->workVariable = &var; + setVar3->args.push_back({ Compiler::StaticType::Unknown, &value3 }); + list.addInstruction(setVar3); + + auto end = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + list.addInstruction(end); + + ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, elseStart.get(), Compiler::StaticType::Bool)); +} + +TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, IfStatementInLoop_TypeChangeInIfBranch) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -686,10 +1004,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, TypeChangeInIfBranch) list.addInstruction(end); // Returns true because the type-changing branch might run - ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Number)); + ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Number)); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, TypeChangeInElseBranch) +TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, IfStatementInLoop_TypeChangeInElseBranch) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -727,10 +1045,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, TypeChangeInElseBranch) list.addInstruction(end); // Returns true because the type-changing branch might run - ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Number)); + ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Number)); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, IfElseWithoutTypeChange) +TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, IfStatementInLoop_IfElseWithoutTypeChange) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -767,10 +1085,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, IfElseWithoutTypeChange) auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_FALSE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Number)); + ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Number)); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, NestedLoopWithTypeChange) +TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, NestedLoopWithTypeChange) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -808,10 +1126,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, NestedLoopWithTypeChange) auto outerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(outerEnd); - ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, outerLoop.get(), Compiler::StaticType::Number)); + ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, outerLoop.get(), Compiler::StaticType::Number)); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, NestedLoopWithoutTypeChange) +TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, NestedLoopWithoutTypeChange) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -849,10 +1167,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, NestedLoopWithoutTypeChange) auto outerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(outerEnd); - ASSERT_FALSE(analyzer.variableTypeChangesInLoop(&varPtr, outerLoop.get(), Compiler::StaticType::Number)); + ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, outerLoop.get(), Compiler::StaticType::Number)); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, NestedLoopTypeChangesButResets) +TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, NestedLoopTypeChangesButResets) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -897,10 +1215,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, NestedLoopTypeChangesButResets) auto outerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(outerEnd); - ASSERT_FALSE(analyzer.variableTypeChangesInLoop(&varPtr, outerLoop.get(), Compiler::StaticType::Number)); + ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, outerLoop.get(), Compiler::StaticType::Number)); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, NestedLoopTypeChangesAndDoesNotReset) +TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, NestedLoopTypeChangesAndDoesNotReset) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -945,10 +1263,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, NestedLoopTypeChangesAndDoesNot auto outerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(outerEnd); - ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, outerLoop.get(), Compiler::StaticType::Number)); + ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, outerLoop.get(), Compiler::StaticType::Number)); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, NestedLoopWithTypeChangeBeforeLoop) +TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, NestedLoopWithTypeChangeBeforeLoop) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -987,10 +1305,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, NestedLoopWithTypeChangeBeforeL list.addInstruction(outerEnd); // Returns true because loops can be skipped - ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, outerLoop.get(), Compiler::StaticType::Number)); + ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, outerLoop.get(), Compiler::StaticType::Number)); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, MultipleNestedLoopsWithTypeChange) +TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleNestedLoopsWithTypeChange) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -1043,10 +1361,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, MultipleNestedLoopsWithTypeChan auto outerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(outerEnd); - ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, outerLoop.get(), Compiler::StaticType::Number)); + ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, outerLoop.get(), Compiler::StaticType::Number)); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, MultipleNestedLoopsWithTypeChangeButTypeReset) +TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleNestedLoopsWithTypeChangeButTypeReset) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -1099,7 +1417,208 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, MultipleNestedLoopsWithTypeChan auto outerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(outerEnd); - ASSERT_FALSE(analyzer.variableTypeChangesInLoop(&varPtr, outerLoop.get(), Compiler::StaticType::Number)); + ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, outerLoop.get(), Compiler::StaticType::Number)); +} + +TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleNestedIfStatementsWithTypeChange_IfBranch) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + // Outer if statement begin + auto outerIf = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + list.addInstruction(outerIf); + + // Variable write inside outer if statement + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 5); + setVar1->workVariable = &var; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(setVar1); + + // Inner if statement 1 begin + auto innerIf1 = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + list.addInstruction(innerIf1); + + // Variable write inside inner if statement 1 + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::Number, 2.75); + setVar2->workVariable = &var; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + list.addInstruction(setVar2); + + // Inner if statement 2 begin + auto innerIf2 = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + list.addInstruction(innerIf2); + + // Variable write inside inner if statement 2 + auto setVar3 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value3(Compiler::StaticType::String, "abc"); + setVar3->workVariable = &var; + setVar3->args.push_back({ Compiler::StaticType::Unknown, &value3 }); + list.addInstruction(setVar3); + + // Inner if statement 2 else branch + auto innerElse2 = std::make_shared(LLVMInstruction::Type::BeginElse, nullptr, false); + list.addInstruction(innerElse2); + + // Variable write inside inner if statement 2 else branch + auto setVar4 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value4(Compiler::StaticType::Number, 4); + setVar4->workVariable = &var; + setVar4->args.push_back({ Compiler::StaticType::Unknown, &value4 }); + list.addInstruction(setVar4); + + // Inner if statement 2 end + auto innerEnd2 = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + list.addInstruction(innerEnd2); + + // Inner if statement 1 end + auto innerEnd1 = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + list.addInstruction(innerEnd1); + + // Outer if statement end + auto outerEnd = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + list.addInstruction(outerEnd); + + ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, outerIf.get(), Compiler::StaticType::Number)); +} + +TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleNestedIfStatementsWithTypeChange_ElseBranch) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + // Outer if statement begin + auto outerIf = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + list.addInstruction(outerIf); + + // Variable write inside outer if statement + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 5); + setVar1->workVariable = &var; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(setVar1); + + // Inner if statement 1 begin + auto innerIf1 = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + list.addInstruction(innerIf1); + + // Variable write inside inner if statement 1 + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::Number, 2.75); + setVar2->workVariable = &var; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + list.addInstruction(setVar2); + + // Inner if statement 2 begin + auto innerIf2 = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + list.addInstruction(innerIf2); + + // Variable write inside inner if statement 2 + auto setVar3 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value3(Compiler::StaticType::Number, 4); + setVar3->workVariable = &var; + setVar3->args.push_back({ Compiler::StaticType::Unknown, &value3 }); + list.addInstruction(setVar3); + + // Inner if statement 2 else branch + auto innerElse2 = std::make_shared(LLVMInstruction::Type::BeginElse, nullptr, false); + list.addInstruction(innerElse2); + + // Variable write inside inner if statement 2 else branch + auto setVar4 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value4(Compiler::StaticType::String, "abc"); + setVar4->workVariable = &var; + setVar4->args.push_back({ Compiler::StaticType::Unknown, &value4 }); + list.addInstruction(setVar4); + + // Inner if statement 2 end + auto innerEnd2 = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + list.addInstruction(innerEnd2); + + // Inner if statement 1 end + auto innerEnd1 = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + list.addInstruction(innerEnd1); + + // Outer if statement end + auto outerEnd = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + list.addInstruction(outerEnd); + + ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, outerIf.get(), Compiler::StaticType::Number)); +} + +TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleNestedIfStatementsWithoutTypeChange) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + // Outer if statement begin + auto outerIf = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + list.addInstruction(outerIf); + + // Variable write inside outer if statement + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 5); + setVar1->workVariable = &var; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(setVar1); + + // Inner if statement 1 begin + auto innerIf1 = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + list.addInstruction(innerIf1); + + // Variable write inside inner if statement 1 + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::Number, 2.75); + setVar2->workVariable = &var; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + list.addInstruction(setVar2); + + // Inner if statement 2 begin + auto innerIf2 = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + list.addInstruction(innerIf2); + + // Variable write inside inner if statement 2 + auto setVar3 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value3(Compiler::StaticType::Number, 4); + setVar3->workVariable = &var; + setVar3->args.push_back({ Compiler::StaticType::Unknown, &value3 }); + list.addInstruction(setVar3); + + // Inner if statement 2 else branch + auto innerElse2 = std::make_shared(LLVMInstruction::Type::BeginElse, nullptr, false); + list.addInstruction(innerElse2); + + // Variable write inside inner if statement 2 else branch + auto setVar4 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value4(Compiler::StaticType::Number, 0); + setVar4->workVariable = &var; + setVar4->args.push_back({ Compiler::StaticType::Unknown, &value4 }); + list.addInstruction(setVar4); + + // Inner if statement 2 end + auto innerEnd2 = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + list.addInstruction(innerEnd2); + + // Inner if statement 1 end + auto innerEnd1 = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + list.addInstruction(innerEnd1); + + // Outer if statement end + auto outerEnd = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + list.addInstruction(outerEnd); + + ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, outerIf.get(), Compiler::StaticType::Number)); } // TODO: Handle cross-variable dependencies From 6cddc410507d8969de7bc20099618c191e175929 Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Fri, 25 Jul 2025 20:39:29 +0200 Subject: [PATCH 25/79] LLVMTypeAnalyzer: Handle all nested loop/if statement cases --- src/engine/internal/llvm/llvmtypeanalyzer.cpp | 113 ++- src/engine/internal/llvm/llvmtypeanalyzer.h | 5 +- test/llvm/type_analyzer/variabletype_test.cpp | 775 ++++++++++++++++++ 3 files changed, 878 insertions(+), 15 deletions(-) diff --git a/src/engine/internal/llvm/llvmtypeanalyzer.cpp b/src/engine/internal/llvm/llvmtypeanalyzer.cpp index 10b419595..4da5290a6 100644 --- a/src/engine/internal/llvm/llvmtypeanalyzer.cpp +++ b/src/engine/internal/llvm/llvmtypeanalyzer.cpp @@ -17,19 +17,23 @@ Compiler::StaticType LLVMTypeAnalyzer::variableType(LLVMVariablePtr *varPtr, LLV // Check the last write operation before the instruction LLVMInstruction *ins = pos; LLVMInstruction *write = nullptr; - LLVMInstruction *loopStart = nullptr; + LLVMInstruction *firstBranch = nullptr; + LLVMInstruction *firstElseBranch = nullptr; int level = 0; while (ins) { - if (isLoopEnd(ins)) + if (isLoopEnd(ins) || isIfEnd(ins)) level++; - else if (isLoopStart(ins)) { + else if (isLoopStart(ins) || isIfStart(ins)) { level--; - - if (!loopStart) - loopStart = ins; + firstBranch = ins; + } else if (isElse(ins)) { + // Skip if branch if coming from else + firstElseBranch = ins; + ins = skipBranch(ins); + continue; } else if (ins->type == LLVMInstruction::Type::WriteVariable && ins->workVariable == varPtr->var) { - if (level <= 0) { // ignore nested loops (they're handled later) + if (level <= 0) { // ignore nested branches (they're handled by the branch analyzer) write = ins; break; } @@ -38,12 +42,20 @@ Compiler::StaticType LLVMTypeAnalyzer::variableType(LLVMVariablePtr *varPtr, LLV ins = ins->previous; } - if (loopStart) { - // Analyze the first loop that was found - if (variableTypeChangesInBranch(varPtr, loopStart, previousType)) - return write ? writeValueType(write) : Compiler::StaticType::Unknown; + if (firstBranch) { + // Analyze the first branch and else branch + if (write) + previousType = writeValueType(write); // write operation overrides previous type + + Compiler::StaticType firstBranchType = variableTypeAfterBranch(varPtr, firstBranch, previousType); + Compiler::StaticType elseBranchType = variableTypeAfterBranch(varPtr, firstElseBranch, previousType); + + if (typesMatch(firstBranchType, elseBranchType)) + return firstBranchType; + else + return Compiler::StaticType::Unknown; } else if (write) { - // There wasn't any loop found, so we can just check the last write operation + // There wasn't any branch found, so we can just check the last write operation return writeValueType(write); } @@ -82,6 +94,72 @@ bool LLVMTypeAnalyzer::variableTypeChangesInBranch(LLVMVariablePtr *varPtr, LLVM return variableTypeChangesInBranchFromEnd(varPtr, ins, previousType); } +Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranch(LLVMVariablePtr *varPtr, LLVMInstruction *start, Compiler::StaticType previousType) const +{ + if (!varPtr || !start) + return previousType; + + assert(isLoopStart(start) || isIfStart(start) || isElse(start)); + + // Find loop/if statement end or else branch + LLVMInstruction *ins = start->next; + int level = 0; + + while (ins && !((isLoopEnd(ins) || isIfEnd(ins) || isElse(ins)) && level == 0)) { + if (isLoopStart(ins) || isIfStart(ins)) + level++; + else if (isLoopEnd(ins) || isIfEnd(ins)) { + assert(level > 0); + level--; + } + + ins = ins->next; + } + + if (!ins) { + assert(false); + return Compiler::StaticType::Unknown; + } + + // Process the branch from end + return variableTypeAfterBranchFromEnd(varPtr, ins, previousType); +} + +Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranchFromEnd(LLVMVariablePtr *varPtr, LLVMInstruction *end, Compiler::StaticType previousType) const +{ + // Find the last write instruction + LLVMInstruction *ins = end->previous; + + while (ins && !isLoopStart(ins) && !isIfStart(ins)) { + if (isLoopEnd(ins) || isIfEnd(ins) || isElse(ins)) { + // Process the nested loop or if statement + Compiler::StaticType ret = variableTypeAfterBranchFromEnd(varPtr, ins, previousType); + + if (!typesMatch(ret, previousType)) + return ret; + + ins = skipBranch(ins); + + if (isElse(ins)) { + // Process if branch (the else branch is already processed) + ret = variableTypeAfterBranchFromEnd(varPtr, ins, previousType); + + if (!typesMatch(ret, previousType)) + return ret; + + ins = skipBranch(ins); + } + } else if (ins->type == LLVMInstruction::Type::WriteVariable && ins->workVariable == varPtr->var) { + // Variable write instruction + return writeValueType(ins); + } + + ins = ins->previous; + } + + return previousType; +} + bool LLVMTypeAnalyzer::variableTypeChangesInBranchFromEnd(LLVMVariablePtr *varPtr, LLVMInstruction *end, Compiler::StaticType previousType) const { // Find the last write instruction @@ -104,7 +182,7 @@ bool LLVMTypeAnalyzer::variableTypeChangesInBranchFromEnd(LLVMVariablePtr *varPt } } else if (ins->type == LLVMInstruction::Type::WriteVariable && ins->workVariable == varPtr->var) { // Variable write instruction - return !typesMatch(ins, previousType); + return !writeTypesMatch(ins, previousType); } ins = ins->previous; @@ -185,7 +263,13 @@ Compiler::StaticType LLVMTypeAnalyzer::writeValueType(LLVMInstruction *ins) cons return optimizeRegisterType(arg); } -bool LLVMTypeAnalyzer::typesMatch(LLVMInstruction *ins, Compiler::StaticType expectedType) const +bool LLVMTypeAnalyzer::typesMatch(Compiler::StaticType a, Compiler::StaticType b) const +{ + // Equal unknown types are not considered a match + return (a == b) && (a != Compiler::StaticType::Unknown); +} + +bool LLVMTypeAnalyzer::writeTypesMatch(LLVMInstruction *ins, Compiler::StaticType expectedType) const { // auto argIns = arg->instruction; @@ -193,6 +277,7 @@ bool LLVMTypeAnalyzer::typesMatch(LLVMInstruction *ins, Compiler::StaticType exp /*if (argIns && (argIns->type == LLVMInstruction::Type::ReadVariable || argIns->type == LLVMInstruction::Type::GetListItem)) return isVarOrListTypeSafe(argIns.get(), expectedType, log, c);*/ + return typesMatch(writeValueType(ins), expectedType); if (expectedType == Compiler::StaticType::Unknown) { // Equal unknown types are not considered a match return false; diff --git a/src/engine/internal/llvm/llvmtypeanalyzer.h b/src/engine/internal/llvm/llvmtypeanalyzer.h index 9ba9c5ca9..c91d6d42e 100644 --- a/src/engine/internal/llvm/llvmtypeanalyzer.h +++ b/src/engine/internal/llvm/llvmtypeanalyzer.h @@ -16,6 +16,8 @@ class LLVMTypeAnalyzer bool variableTypeChangesInBranch(LLVMVariablePtr *varPtr, LLVMInstruction *start, Compiler::StaticType previousType) const; private: + Compiler::StaticType variableTypeAfterBranch(LLVMVariablePtr *varPtr, LLVMInstruction *start, Compiler::StaticType previousType) const; + Compiler::StaticType variableTypeAfterBranchFromEnd(LLVMVariablePtr *varPtr, LLVMInstruction *end, Compiler::StaticType previousType) const; bool variableTypeChangesInBranchFromEnd(LLVMVariablePtr *varPtr, LLVMInstruction *end, Compiler::StaticType previousType) const; LLVMInstruction *skipBranch(LLVMInstruction *pos) const; bool isLoopStart(LLVMInstruction *ins) const; @@ -26,7 +28,8 @@ class LLVMTypeAnalyzer Compiler::StaticType optimizeRegisterType(LLVMRegister *reg) const; Compiler::StaticType writeValueType(LLVMInstruction *ins) const; - bool typesMatch(LLVMInstruction *ins, Compiler::StaticType expectedType) const; + bool typesMatch(Compiler::StaticType a, Compiler::StaticType b) const; + bool writeTypesMatch(LLVMInstruction *ins, Compiler::StaticType expectedType) const; }; } // namespace libscratchcpp diff --git a/test/llvm/type_analyzer/variabletype_test.cpp b/test/llvm/type_analyzer/variabletype_test.cpp index 5b600e734..82e7ceef5 100644 --- a/test/llvm/type_analyzer/variabletype_test.cpp +++ b/test/llvm/type_analyzer/variabletype_test.cpp @@ -783,6 +783,141 @@ TEST(LLVMTypeAnalyzer_VariableType, OverrideUnknownTypeBeforeLoop) ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Unknown), Compiler::StaticType::Number); } +TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, WriteSameTypeInIfStatement) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + auto start = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + list.addInstruction(start); + + auto setVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::Number, 1.25); + setVar->workVariable = &var; + setVar->args.push_back({ Compiler::StaticType::Unknown, &value }); + list.addInstruction(setVar); + + auto end = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + list.addInstruction(end); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(funcCall); + + ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, WriteDifferentTypeInIfStatement) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + auto start = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + list.addInstruction(start); + + auto setVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::Number, 5.8); + setVar->workVariable = &var; + setVar->args.push_back({ Compiler::StaticType::Unknown, &value }); + list.addInstruction(setVar); + + auto end = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + list.addInstruction(end); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(funcCall); + + // Type is not known because the if statement might not run at all + ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::String), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_VariableType, OverrideDifferentTypeBeforeIfElseStatement) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 1.25); + setVar1->workVariable = &var; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(setVar1); + + auto start = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + list.addInstruction(start); + + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::Number, 1.25); + setVar2->workVariable = &var; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + list.addInstruction(setVar2); + + auto elseStart = std::make_shared(LLVMInstruction::Type::BeginElse, nullptr, false); + list.addInstruction(elseStart); + + auto setVar3 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value3(Compiler::StaticType::Number, 2.5); + setVar3->workVariable = &var; + setVar3->args.push_back({ Compiler::StaticType::Unknown, &value3 }); + list.addInstruction(setVar3); + + auto end = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + list.addInstruction(end); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(funcCall); + + ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::String), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_VariableType, OverrideUnknownTypeBeforeIfElseStatement) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 1.25); + setVar1->workVariable = &var; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(setVar1); + + auto start = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + list.addInstruction(start); + + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::Number, 1.25); + setVar2->workVariable = &var; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + list.addInstruction(setVar2); + + auto elseStart = std::make_shared(LLVMInstruction::Type::BeginElse, nullptr, false); + list.addInstruction(elseStart); + + auto setVar3 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value3(Compiler::StaticType::Number, 2.5); + setVar3->workVariable = &var; + setVar3->args.push_back({ Compiler::StaticType::Unknown, &value3 }); + list.addInstruction(setVar3); + + auto end = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + list.addInstruction(end); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(funcCall); + + ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Unknown), Compiler::StaticType::Number); +} + TEST(LLVMTypeAnalyzer_VariableType, MultipleWritesSameTypeNumber) { LLVMTypeAnalyzer analyzer; @@ -991,4 +1126,644 @@ TEST(LLVMTypeAnalyzer_VariableType, MultipleWritesBoolToStringNumberOptimization ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Bool), Compiler::StaticType::Number); } +TEST(LLVMTypeAnalyzer_VariableType, TypeChangeInIfBranch) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + auto ifStart = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + list.addInstruction(ifStart); + + // First write - changes type + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::String, "test"); + setVar1->workVariable = &var; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(setVar1); + + auto elseStart = std::make_shared(LLVMInstruction::Type::BeginElse, nullptr, false); + list.addInstruction(elseStart); + + // Second write - does not change type + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::Number, 42); + setVar2->workVariable = &var; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + list.addInstruction(setVar2); + + auto ifEnd = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + list.addInstruction(ifEnd); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(funcCall); + + // Returns unknown type because both branches might run + ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_VariableType, TypeChangeInElseBranch) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + auto ifStart = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + list.addInstruction(ifStart); + + // First write - does not change type + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 42); + setVar1->workVariable = &var; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(setVar1); + + auto elseStart = std::make_shared(LLVMInstruction::Type::BeginElse, nullptr, false); + list.addInstruction(elseStart); + + // Second write - changes type + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::String, "test"); + setVar2->workVariable = &var; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + list.addInstruction(setVar2); + + auto ifEnd = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + list.addInstruction(ifEnd); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(funcCall); + + // Returns unknown type because both branches might run + ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_VariableType, IfElseWithEqualTypes_SameType) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + auto ifStart = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + list.addInstruction(ifStart); + + // First write - does not change type + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 42); + setVar1->workVariable = &var; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(setVar1); + + auto elseStart = std::make_shared(LLVMInstruction::Type::BeginElse, nullptr, false); + list.addInstruction(elseStart); + + // Second write - does not change type + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::Number, 1.25); + setVar2->workVariable = &var; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + list.addInstruction(setVar2); + + auto ifEnd = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + list.addInstruction(ifEnd); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(funcCall); + + ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_VariableType, IfElseWithEqualTypes_DifferentTypes) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + auto ifStart = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + list.addInstruction(ifStart); + + // First write - changes type to string + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::String, "Lorem"); + setVar1->workVariable = &var; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(setVar1); + + auto elseStart = std::make_shared(LLVMInstruction::Type::BeginElse, nullptr, false); + list.addInstruction(elseStart); + + // Second write - changes type to string + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::String, "ipsum"); + setVar2->workVariable = &var; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + list.addInstruction(setVar2); + + auto ifEnd = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + list.addInstruction(ifEnd); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(funcCall); + + ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::String); +} + +TEST(LLVMTypeAnalyzer_VariableType, NestedLoopWithTypeChange_Before) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + // Outer loop begin + auto outerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(outerLoop); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(funcCall); + + // Variable write inside outer loop + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 5); + setVar1->workVariable = &var; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(setVar1); + + // Inner loop begin + auto innerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(innerLoop); + + // Variable write inside inner loop + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::String, "test"); + setVar2->workVariable = &var; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + list.addInstruction(setVar2); + + // Inner loop end + auto innerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(innerEnd); + + // Outer loop end + auto outerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(outerEnd); + + ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_VariableType, NestedLoopWithTypeChange_BeforeInner) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + // Outer loop begin + auto outerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(outerLoop); + + // Variable write inside outer loop + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 5); + setVar1->workVariable = &var; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(setVar1); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(funcCall); + + // Inner loop begin + auto innerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(innerLoop); + + // Variable write inside inner loop + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::String, "test"); + setVar2->workVariable = &var; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + list.addInstruction(setVar2); + + // Inner loop end + auto innerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(innerEnd); + + // Outer loop end + auto outerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(outerEnd); + + ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_VariableType, NestedLoopWithTypeChange_AfterWriteInsideInner) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + // Outer loop begin + auto outerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(outerLoop); + + // Variable write inside outer loop + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 5); + setVar1->workVariable = &var; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(setVar1); + + // Inner loop begin + auto innerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(innerLoop); + + // Variable write inside inner loop + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::String, "test"); + setVar2->workVariable = &var; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + list.addInstruction(setVar2); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(funcCall); + + // Inner loop end + auto innerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(innerEnd); + + // Outer loop end + auto outerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(outerEnd); + + ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::String); +} + +TEST(LLVMTypeAnalyzer_VariableType, NestedLoopWithTypeChange_After) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + // Outer loop begin + auto outerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(outerLoop); + + // Variable write inside outer loop + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 5); + setVar1->workVariable = &var; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(setVar1); + + // Inner loop begin + auto innerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(innerLoop); + + // Variable write inside inner loop + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::String, "test"); + setVar2->workVariable = &var; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + list.addInstruction(setVar2); + + // Inner loop end + auto innerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(innerEnd); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(funcCall); + + // Outer loop end + auto outerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(outerEnd); + + // Type is not known because the inner loop might not run at all + ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_VariableType, NestedLoopWithoutTypeChange) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + // Outer loop begin + auto outerLoop = std::make_shared(LLVMInstruction::Type::BeginWhileLoop, nullptr, false); + list.addInstruction(outerLoop); + + // Variable write inside outer loop + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 5); + setVar1->workVariable = &var; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(setVar1); + + // Inner loop begin + auto innerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(innerLoop); + + // Variable write inside inner loop + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::Number, 2.5); + setVar2->workVariable = &var; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + list.addInstruction(setVar2); + + // Inner loop end + auto innerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(innerEnd); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(funcCall); + + // Outer loop end + auto outerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(outerEnd); + + ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_VariableType, NestedLoopTypeChangesButResets) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + // Outer loop begin + auto outerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(outerLoop); + + // Variable write inside outer loop + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 5); + setVar1->workVariable = &var; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(setVar1); + + // Inner loop begin + auto innerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatUntilLoop, nullptr, false); + list.addInstruction(innerLoop); + + // Variable write inside inner loop + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::String, "test"); + setVar2->workVariable = &var; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + list.addInstruction(setVar2); + + // Inner loop end + auto innerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(innerEnd); + + // Variable write after inner loop - resets type + auto setVar3 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value3(Compiler::StaticType::Number, 2); + setVar3->workVariable = &var; + setVar3->args.push_back({ Compiler::StaticType::Unknown, &value3 }); + list.addInstruction(setVar3); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(funcCall); + + // Outer loop end + auto outerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(outerEnd); + + ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_VariableType, NestedLoopTypeChangesAndDoesNotReset) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + // Outer loop begin + auto outerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(outerLoop); + + // Variable write inside outer loop + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 5); + setVar1->workVariable = &var; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(setVar1); + + // Inner loop begin + auto innerLoop = std::make_shared(LLVMInstruction::Type::BeginWhileLoop, nullptr, false); + list.addInstruction(innerLoop); + + // Variable write inside inner loop + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::String, "test"); + setVar2->workVariable = &var; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + list.addInstruction(setVar2); + + // Inner loop end + auto innerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(innerEnd); + + // Variable write after inner loop - keeps the different type + auto setVar3 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value3(Compiler::StaticType::String, "abc"); + setVar3->workVariable = &var; + setVar3->args.push_back({ Compiler::StaticType::Unknown, &value3 }); + list.addInstruction(setVar3); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(funcCall); + + // Outer loop end + auto outerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(outerEnd); + + ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::String); +} + +TEST(LLVMTypeAnalyzer_VariableType, MultipleNestedLoopsWithTypeChange) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + // Outer loop begin + auto outerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(outerLoop); + + // Variable write inside outer loop + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 5); + setVar1->workVariable = &var; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(setVar1); + + // Inner loop 1 begin + auto innerLoop1 = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(innerLoop1); + + // Variable write inside inner loop 1 + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::Number, 2.75); + setVar2->workVariable = &var; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + list.addInstruction(setVar2); + + // Inner loop 2 begin + auto innerLoop2 = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(innerLoop2); + + // Variable write inside inner loop 2 + auto setVar3 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value3(Compiler::StaticType::String, "abc"); + setVar3->workVariable = &var; + setVar3->args.push_back({ Compiler::StaticType::Unknown, &value3 }); + list.addInstruction(setVar3); + + // Inner loop 2 end + auto innerEnd2 = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(innerEnd2); + + // Inner loop 1 end + auto innerEnd1 = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(innerEnd1); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(funcCall); + + // Outer loop end + auto outerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(outerEnd); + + ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_VariableType, MultipleNestedLoopsWithTypeChangeButTypeReset) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + // Outer loop begin + auto outerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(outerLoop); + + // Variable write inside outer loop + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 5); + setVar1->workVariable = &var; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(setVar1); + + // Inner loop 1 begin + auto innerLoop1 = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(innerLoop1); + + // Inner loop 2 begin + auto innerLoop2 = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(innerLoop2); + + // Variable write inside inner loop 2 + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::String, "abc"); + setVar2->workVariable = &var; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + list.addInstruction(setVar2); + + // Inner loop 2 end + auto innerEnd2 = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(innerEnd2); + + // Variable write inside inner loop 1 - resets type + auto setVar3 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value3(Compiler::StaticType::Number, 2.75); + setVar3->workVariable = &var; + setVar3->args.push_back({ Compiler::StaticType::Unknown, &value3 }); + list.addInstruction(setVar3); + + // Inner loop 1 end + auto innerEnd1 = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(innerEnd1); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(funcCall); + + // Outer loop end + auto outerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(outerEnd); + + ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_VariableType, SameTypeIfElseInLoopWithTypeChange) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + // Outer loop begin + auto outerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(outerLoop); + + // Inner if statement begin + auto innerIf = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + list.addInstruction(innerIf); + + // Variable write inside inner if statement if branch + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::String, "abc"); + setVar1->workVariable = &var; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(setVar1); + + // Inner if statement else branch + auto innerElse = std::make_shared(LLVMInstruction::Type::BeginElse, nullptr, false); + list.addInstruction(innerElse); + + // Variable write inside inner if statement else branch + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::String, "def"); + setVar2->workVariable = &var; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + list.addInstruction(setVar2); + + // Inner if statement end + auto innerEnd = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + list.addInstruction(innerEnd); + + // Outer loop end + auto outerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(outerEnd); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(funcCall); + + // The type always changes to string + ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::String); +} + // TODO: Handle cross-variable dependencies From 41b04d85b4c2a92ea336b2842c868a3f1e4f13b7 Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Fri, 25 Jul 2025 22:49:14 +0200 Subject: [PATCH 26/79] LLVMTypeAnalyzer: Drop variableTypeChangesInBranch() variableTypeAfterBranch() is the preferred method now --- src/engine/internal/llvm/llvmtypeanalyzer.cpp | 82 ++----- src/engine/internal/llvm/llvmtypeanalyzer.h | 4 +- test/llvm/CMakeLists.txt | 2 +- test/llvm/type_analyzer/variabletype_test.cpp | 2 +- ...t.cpp => variabletypeafterbranch_test.cpp} | 210 +++++++++--------- 5 files changed, 123 insertions(+), 177 deletions(-) rename test/llvm/type_analyzer/{variabletypechangesinbranch_test.cpp => variabletypeafterbranch_test.cpp} (84%) diff --git a/src/engine/internal/llvm/llvmtypeanalyzer.cpp b/src/engine/internal/llvm/llvmtypeanalyzer.cpp index 4da5290a6..284fa7a37 100644 --- a/src/engine/internal/llvm/llvmtypeanalyzer.cpp +++ b/src/engine/internal/llvm/llvmtypeanalyzer.cpp @@ -63,37 +63,6 @@ Compiler::StaticType LLVMTypeAnalyzer::variableType(LLVMVariablePtr *varPtr, LLV return previousType; } -bool LLVMTypeAnalyzer::variableTypeChangesInBranch(LLVMVariablePtr *varPtr, LLVMInstruction *start, Compiler::StaticType previousType) const -{ - if (!varPtr || !start) - return false; - - assert(isLoopStart(start) || isIfStart(start) || isElse(start)); - - // Find loop/if statement end or else branch - LLVMInstruction *ins = start->next; - int level = 0; - - while (ins && !((isLoopEnd(ins) || isIfEnd(ins) || isElse(ins)) && level == 0)) { - if (isLoopStart(ins) || isIfStart(ins)) - level++; - else if (isLoopEnd(ins) || isIfEnd(ins)) { - assert(level > 0); - level--; - } - - ins = ins->next; - } - - if (!ins) { - assert(false); - return true; - } - - // Process the branch from end - return variableTypeChangesInBranchFromEnd(varPtr, ins, previousType); -} - Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranch(LLVMVariablePtr *varPtr, LLVMInstruction *start, Compiler::StaticType previousType) const { if (!varPtr || !start) @@ -129,14 +98,17 @@ Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranchFromEnd(LLVMVariab { // Find the last write instruction LLVMInstruction *ins = end->previous; + bool typeMightReset = false; while (ins && !isLoopStart(ins) && !isIfStart(ins)) { if (isLoopEnd(ins) || isIfEnd(ins) || isElse(ins)) { // Process the nested loop or if statement Compiler::StaticType ret = variableTypeAfterBranchFromEnd(varPtr, ins, previousType); - if (!typesMatch(ret, previousType)) - return ret; + if (typesMatch(ret, previousType)) + typeMightReset = true; + else + return Compiler::StaticType::Unknown; ins = skipBranch(ins); @@ -144,51 +116,27 @@ Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranchFromEnd(LLVMVariab // Process if branch (the else branch is already processed) ret = variableTypeAfterBranchFromEnd(varPtr, ins, previousType); - if (!typesMatch(ret, previousType)) - return ret; + if (typesMatch(ret, previousType)) + typeMightReset = true; + else + return Compiler::StaticType::Unknown; ins = skipBranch(ins); } } else if (ins->type == LLVMInstruction::Type::WriteVariable && ins->workVariable == varPtr->var) { // Variable write instruction - return writeValueType(ins); - } - - ins = ins->previous; - } - - return previousType; -} - -bool LLVMTypeAnalyzer::variableTypeChangesInBranchFromEnd(LLVMVariablePtr *varPtr, LLVMInstruction *end, Compiler::StaticType previousType) const -{ - // Find the last write instruction - LLVMInstruction *ins = end->previous; - - while (ins && !isLoopStart(ins) && !isIfStart(ins)) { - if (isLoopEnd(ins) || isIfEnd(ins) || isElse(ins)) { - // Process the nested loop or if statement - if (variableTypeChangesInBranchFromEnd(varPtr, ins, previousType)) - return true; + Compiler::StaticType writeType = writeValueType(ins); - ins = skipBranch(ins); - - if (isElse(ins)) { - // Process if branch (the else branch is already processed) - if (variableTypeChangesInBranchFromEnd(varPtr, ins, previousType)) - return true; - - ins = skipBranch(ins); - } - } else if (ins->type == LLVMInstruction::Type::WriteVariable && ins->workVariable == varPtr->var) { - // Variable write instruction - return !writeTypesMatch(ins, previousType); + if (typesMatch(writeType, previousType)) + return writeType; + else + return typeMightReset ? Compiler::StaticType::Unknown : writeType; } ins = ins->previous; } - return false; + return previousType; } LLVMInstruction *LLVMTypeAnalyzer::skipBranch(LLVMInstruction *pos) const diff --git a/src/engine/internal/llvm/llvmtypeanalyzer.h b/src/engine/internal/llvm/llvmtypeanalyzer.h index c91d6d42e..ee29cc0db 100644 --- a/src/engine/internal/llvm/llvmtypeanalyzer.h +++ b/src/engine/internal/llvm/llvmtypeanalyzer.h @@ -13,12 +13,10 @@ class LLVMTypeAnalyzer { public: Compiler::StaticType variableType(LLVMVariablePtr *varPtr, LLVMInstruction *pos, Compiler::StaticType previousType) const; - bool variableTypeChangesInBranch(LLVMVariablePtr *varPtr, LLVMInstruction *start, Compiler::StaticType previousType) const; + Compiler::StaticType variableTypeAfterBranch(LLVMVariablePtr *varPtr, LLVMInstruction *start, Compiler::StaticType previousType) const; private: - Compiler::StaticType variableTypeAfterBranch(LLVMVariablePtr *varPtr, LLVMInstruction *start, Compiler::StaticType previousType) const; Compiler::StaticType variableTypeAfterBranchFromEnd(LLVMVariablePtr *varPtr, LLVMInstruction *end, Compiler::StaticType previousType) const; - bool variableTypeChangesInBranchFromEnd(LLVMVariablePtr *varPtr, LLVMInstruction *end, Compiler::StaticType previousType) const; LLVMInstruction *skipBranch(LLVMInstruction *pos) const; bool isLoopStart(LLVMInstruction *ins) const; bool isLoopEnd(LLVMInstruction *ins) const; diff --git a/test/llvm/CMakeLists.txt b/test/llvm/CMakeLists.txt index 70f7ecd94..0ba3385a7 100644 --- a/test/llvm/CMakeLists.txt +++ b/test/llvm/CMakeLists.txt @@ -20,7 +20,7 @@ add_executable( llvmexecutablecode_test.cpp llvmcodebuilder_test.cpp llvminstructionlist_test.cpp - type_analyzer/variabletypechangesinbranch_test.cpp + type_analyzer/variabletypeafterbranch_test.cpp type_analyzer/variabletype_test.cpp ) diff --git a/test/llvm/type_analyzer/variabletype_test.cpp b/test/llvm/type_analyzer/variabletype_test.cpp index 82e7ceef5..992d54f52 100644 --- a/test/llvm/type_analyzer/variabletype_test.cpp +++ b/test/llvm/type_analyzer/variabletype_test.cpp @@ -1763,7 +1763,7 @@ TEST(LLVMTypeAnalyzer_VariableType, SameTypeIfElseInLoopWithTypeChange) list.addInstruction(funcCall); // The type always changes to string - ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::String); + ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown); } // TODO: Handle cross-variable dependencies diff --git a/test/llvm/type_analyzer/variabletypechangesinbranch_test.cpp b/test/llvm/type_analyzer/variabletypeafterbranch_test.cpp similarity index 84% rename from test/llvm/type_analyzer/variabletypechangesinbranch_test.cpp rename to test/llvm/type_analyzer/variabletypeafterbranch_test.cpp index 329c84e3f..334becb8a 100644 --- a/test/llvm/type_analyzer/variabletypechangesinbranch_test.cpp +++ b/test/llvm/type_analyzer/variabletypeafterbranch_test.cpp @@ -8,13 +8,13 @@ using namespace libscratchcpp; -TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, NullParams) +TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, NullParams) { LLVMTypeAnalyzer analyzer; - ASSERT_FALSE(analyzer.variableTypeChangesInBranch(nullptr, nullptr, Compiler::StaticType::Number)); + ASSERT_EQ(analyzer.variableTypeAfterBranch(nullptr, nullptr, Compiler::StaticType::Number), Compiler::StaticType::Number); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, NullVariable) +TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, NullVariable) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -28,17 +28,17 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, NullVariable) auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_FALSE(analyzer.variableTypeChangesInBranch(nullptr, start.get(), Compiler::StaticType::Number)); + ASSERT_EQ(analyzer.variableTypeAfterBranch(nullptr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, NullStartInstruction) +TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, NullStartInstruction) { LLVMTypeAnalyzer analyzer; LLVMVariablePtr varPtr; - ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, nullptr, Compiler::StaticType::Number)); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, nullptr, Compiler::StaticType::Number), Compiler::StaticType::Number); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, EmptyLoop) +TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, EmptyLoop) { LLVMTypeAnalyzer analyzer; LLVMVariablePtr varPtr; @@ -50,10 +50,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, EmptyLoop) auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Number)); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, EmptyIfStatement) +TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, EmptyIfStatement) { LLVMTypeAnalyzer analyzer; LLVMVariablePtr varPtr; @@ -65,10 +65,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, EmptyIfStatement) auto end = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); list.addInstruction(end); - ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Number)); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, EmptyIfElseStatement_IfBranch) +TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, EmptyIfElseStatement_IfBranch) { LLVMTypeAnalyzer analyzer; LLVMVariablePtr varPtr; @@ -83,10 +83,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, EmptyIfElseStatement_IfBranch auto end = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); list.addInstruction(end); - ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Number)); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, EmptyIfElseStatement_ElseBranch) +TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, EmptyIfElseStatement_ElseBranch) { LLVMTypeAnalyzer analyzer; LLVMVariablePtr varPtr; @@ -101,10 +101,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, EmptyIfElseStatement_ElseBran auto end = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); list.addInstruction(end); - ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, elseStart.get(), Compiler::StaticType::Number)); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, elseStart.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, EmptyLoopUnknownType) +TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, EmptyLoopUnknownType) { LLVMTypeAnalyzer analyzer; LLVMVariablePtr varPtr; @@ -116,10 +116,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, EmptyLoopUnknownType) auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Unknown)); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Unknown), Compiler::StaticType::Unknown); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, NoWriteOperations) +TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, NoWriteOperations) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -134,10 +134,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, NoWriteOperations) auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Number)); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteSameTypeNumber) +TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteSameTypeNumber) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -157,10 +157,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteSameTypeNumber) auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Number)); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteSameTypeBool) +TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteSameTypeBool) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -180,10 +180,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteSameTypeBool) auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Bool)); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Bool), Compiler::StaticType::Bool); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteSameTypeString) +TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteSameTypeString) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -203,10 +203,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteSameTypeString) auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::String)); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::String), Compiler::StaticType::String); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteStringOptimization) +TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteStringOptimization) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -227,10 +227,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteStringOptimization list.addInstruction(end); // Although string is assigned, it's constant and represents a number - ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Number)); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteMultipleVariables) +TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteMultipleVariables) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -259,10 +259,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteMultipleVariables) auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Number)); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteFromUnknownType) +TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteFromUnknownType) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -282,10 +282,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteFromUnknownType) auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Number)); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteToUnknownType) +TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteToUnknownType) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -305,10 +305,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteToUnknownType) auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Unknown)); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Unknown), Compiler::StaticType::Number); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteUnknownToUnknownType) +TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteUnknownToUnknownType) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -328,10 +328,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteUnknownToUnknownTy auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Unknown)); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Unknown), Compiler::StaticType::Unknown); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteDifferentTypeNumberToString) +TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteDifferentTypeNumberToString) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -351,10 +351,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteDifferentTypeNumbe auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Number)); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::String); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteDifferentTypeStringToNumber) +TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteDifferentTypeStringToNumber) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -374,10 +374,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteDifferentTypeStrin auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::String)); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::String), Compiler::StaticType::Number); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteDifferentTypeNumberToBool) +TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteDifferentTypeNumberToBool) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -397,10 +397,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteDifferentTypeNumbe auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Number)); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Bool); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteDifferentTypeBoolToNumber) +TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteDifferentTypeBoolToNumber) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -420,10 +420,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteDifferentTypeBoolT auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Bool)); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Bool), Compiler::StaticType::Number); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteDifferentTypeBoolToString) +TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteDifferentTypeBoolToString) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -443,10 +443,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteDifferentTypeBoolT auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Bool)); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Bool), Compiler::StaticType::String); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteDifferentTypeStringToBool) +TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteDifferentTypeStringToBool) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -466,10 +466,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteDifferentTypeStrin auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::String)); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::String), Compiler::StaticType::Bool); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteSameType_IfStatement) +TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteSameType_IfStatement) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -489,10 +489,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteSameType_IfStateme auto end = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); list.addInstruction(end); - ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Number)); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteDifferentType_IfStatement) +TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteDifferentType_IfStatement) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -512,10 +512,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteDifferentType_IfSt auto end = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); list.addInstruction(end); - ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::String)); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::String), Compiler::StaticType::Number); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesSameTypeNumber) +TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesSameTypeNumber) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -544,10 +544,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesSameTypeNumber) list.addInstruction(end); // Should return false because final assignment is compatible with pre-loop Number type - ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Number)); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesSameTypeString) +TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesSameTypeString) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -576,10 +576,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesSameTypeString) list.addInstruction(end); // Should return false because final assignment is compatible with pre-loop String type - ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::String)); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::String), Compiler::StaticType::String); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesSameTypeUnknown) +TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesSameTypeUnknown) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -608,10 +608,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesSameTypeUnknown list.addInstruction(end); // Should return false because final assignment is compatible with pre-loop String type - ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::String)); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::String), Compiler::StaticType::String); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesWithStringOptimization) +TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesWithStringOptimization) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -640,10 +640,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesWithStringOptim list.addInstruction(end); // Should return false because final assignment is optimized to Number type - ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Number)); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesNumberToString) +TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesNumberToString) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -672,10 +672,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesNumberToString) list.addInstruction(end); // Should return true because final assignment is incompatible with pre-loop Number type - ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Number)); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::String); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesBoolToNumber) +TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesBoolToNumber) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -703,10 +703,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesBoolToNumber) auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Bool)); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Bool), Compiler::StaticType::Number); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesBoolToString) +TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesBoolToString) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -734,10 +734,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesBoolToString) auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Bool)); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Bool), Compiler::StaticType::String); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesSameType_IfStatement) +TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesSameType_IfStatement) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -766,10 +766,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesSameType_IfStat list.addInstruction(end); // Should return false because final assignment is compatible with Number type - ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Number)); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesSameType_IfBranch) +TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesSameType_IfBranch) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -808,10 +808,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesSameType_IfBran list.addInstruction(end); // Should return false because final assignment is compatible with Number type - ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Number)); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesSameType_ElseBranch) +TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesSameType_ElseBranch) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -850,10 +850,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesSameType_ElseBr list.addInstruction(end); // Should return false because final assignment is compatible with Number type - ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, elseStart.get(), Compiler::StaticType::Number)); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, elseStart.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesDifferentTypes_IfStatement) +TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesDifferentTypes_IfStatement) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -881,10 +881,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesDifferentTypes_ auto end = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); list.addInstruction(end); - ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Bool)); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Bool), Compiler::StaticType::String); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesDifferentTypes_IfBranch) +TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesDifferentTypes_IfBranch) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -922,10 +922,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesDifferentTypes_ auto end = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); list.addInstruction(end); - ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Bool)); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Bool), Compiler::StaticType::String); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesDifferentTypes_ElseBranch) +TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesDifferentTypes_ElseBranch) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -963,10 +963,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesDifferentTypes_ auto end = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); list.addInstruction(end); - ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, elseStart.get(), Compiler::StaticType::Bool)); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, elseStart.get(), Compiler::StaticType::Bool), Compiler::StaticType::String); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, IfStatementInLoop_TypeChangeInIfBranch) +TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, IfStatementInLoop_TypeChangeInIfBranch) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -1003,11 +1003,11 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, IfStatementInLoop_TypeChangeI auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - // Returns true because the type-changing branch might run - ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Number)); + // Returns unknown type because the type-changing branch might or might not run + ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, IfStatementInLoop_TypeChangeInElseBranch) +TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, IfStatementInLoop_TypeChangeInElseBranch) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -1044,11 +1044,11 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, IfStatementInLoop_TypeChangeI auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - // Returns true because the type-changing branch might run - ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Number)); + // Returns unknown type because the type-changing branch might or might not run + ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, IfStatementInLoop_IfElseWithoutTypeChange) +TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, IfStatementInLoop_IfElseWithoutTypeChange) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -1085,10 +1085,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, IfStatementInLoop_IfElseWitho auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Number)); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, NestedLoopWithTypeChange) +TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, NestedLoopWithTypeChange) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -1126,10 +1126,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, NestedLoopWithTypeChange) auto outerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(outerEnd); - ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, outerLoop.get(), Compiler::StaticType::Number)); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, outerLoop.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, NestedLoopWithoutTypeChange) +TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, NestedLoopWithoutTypeChange) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -1167,10 +1167,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, NestedLoopWithoutTypeChange) auto outerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(outerEnd); - ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, outerLoop.get(), Compiler::StaticType::Number)); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, outerLoop.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, NestedLoopTypeChangesButResets) +TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, NestedLoopTypeChangesButResets) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -1215,10 +1215,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, NestedLoopTypeChangesButReset auto outerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(outerEnd); - ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, outerLoop.get(), Compiler::StaticType::Number)); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, outerLoop.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, NestedLoopTypeChangesAndDoesNotReset) +TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, NestedLoopTypeChangesAndDoesNotReset) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -1263,10 +1263,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, NestedLoopTypeChangesAndDoesN auto outerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(outerEnd); - ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, outerLoop.get(), Compiler::StaticType::Number)); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, outerLoop.get(), Compiler::StaticType::Number), Compiler::StaticType::String); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, NestedLoopWithTypeChangeBeforeLoop) +TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, NestedLoopWithTypeChangeBeforeLoop) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -1304,11 +1304,11 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, NestedLoopWithTypeChangeBefor auto outerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(outerEnd); - // Returns true because loops can be skipped - ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, outerLoop.get(), Compiler::StaticType::Number)); + // Returns unknown type because loops can be skipped + ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, outerLoop.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleNestedLoopsWithTypeChange) +TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleNestedLoopsWithTypeChange) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -1361,10 +1361,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleNestedLoopsWithTypeCh auto outerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(outerEnd); - ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, outerLoop.get(), Compiler::StaticType::Number)); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, outerLoop.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleNestedLoopsWithTypeChangeButTypeReset) +TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleNestedLoopsWithTypeChangeButTypeReset) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -1417,10 +1417,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleNestedLoopsWithTypeCh auto outerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(outerEnd); - ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, outerLoop.get(), Compiler::StaticType::Number)); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, outerLoop.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleNestedIfStatementsWithTypeChange_IfBranch) +TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleNestedIfStatementsWithTypeChange_IfBranch) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -1484,10 +1484,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleNestedIfStatementsWit auto outerEnd = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); list.addInstruction(outerEnd); - ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, outerIf.get(), Compiler::StaticType::Number)); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, outerIf.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleNestedIfStatementsWithTypeChange_ElseBranch) +TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleNestedIfStatementsWithTypeChange_ElseBranch) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -1551,10 +1551,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleNestedIfStatementsWit auto outerEnd = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); list.addInstruction(outerEnd); - ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, outerIf.get(), Compiler::StaticType::Number)); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, outerIf.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleNestedIfStatementsWithoutTypeChange) +TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleNestedIfStatementsWithoutTypeChange) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -1618,7 +1618,7 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleNestedIfStatementsWit auto outerEnd = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); list.addInstruction(outerEnd); - ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, outerIf.get(), Compiler::StaticType::Number)); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, outerIf.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); } // TODO: Handle cross-variable dependencies From bcf26d7f888bc94acf717ba6314e97f7d9c23781 Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Fri, 25 Jul 2025 22:50:44 +0200 Subject: [PATCH 27/79] LLVMTypeAnalyzer: Fix type mismatch in MultipleWritesBoolToNumber test --- test/llvm/type_analyzer/variabletypeafterbranch_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/llvm/type_analyzer/variabletypeafterbranch_test.cpp b/test/llvm/type_analyzer/variabletypeafterbranch_test.cpp index 334becb8a..4bde29c44 100644 --- a/test/llvm/type_analyzer/variabletypeafterbranch_test.cpp +++ b/test/llvm/type_analyzer/variabletypeafterbranch_test.cpp @@ -695,7 +695,7 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesBoolToNumber) // Second write: number 4.25 (incompatible with Bool pre-loop type) auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); - LLVMConstantRegister value2(Compiler::StaticType::String, 4.25); + LLVMConstantRegister value2(Compiler::StaticType::Number, 4.25); setVar2->workVariable = &var; setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); list.addInstruction(setVar2); From 8698a95406f8f74b55d6b13d007fe6f23e548931 Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Fri, 25 Jul 2025 23:35:45 +0200 Subject: [PATCH 28/79] LLVMTypeAnalyzer: Support more edge cases --- src/engine/internal/llvm/llvmtypeanalyzer.cpp | 29 ++-- src/engine/internal/llvm/llvmtypeanalyzer.h | 2 +- .../variabletypeafterbranch_test.cpp | 144 ++++++++++++++++++ 3 files changed, 164 insertions(+), 11 deletions(-) diff --git a/src/engine/internal/llvm/llvmtypeanalyzer.cpp b/src/engine/internal/llvm/llvmtypeanalyzer.cpp index 284fa7a37..d59577a5b 100644 --- a/src/engine/internal/llvm/llvmtypeanalyzer.cpp +++ b/src/engine/internal/llvm/llvmtypeanalyzer.cpp @@ -91,10 +91,11 @@ Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranch(LLVMVariablePtr * } // Process the branch from end - return variableTypeAfterBranchFromEnd(varPtr, ins, previousType); + bool write = false; // only used internally (the compiler doesn't need this) + return variableTypeAfterBranchFromEnd(varPtr, ins, previousType, write); } -Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranchFromEnd(LLVMVariablePtr *varPtr, LLVMInstruction *end, Compiler::StaticType previousType) const +Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranchFromEnd(LLVMVariablePtr *varPtr, LLVMInstruction *end, Compiler::StaticType previousType, bool &write) const { // Find the last write instruction LLVMInstruction *ins = end->previous; @@ -103,22 +104,28 @@ Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranchFromEnd(LLVMVariab while (ins && !isLoopStart(ins) && !isIfStart(ins)) { if (isLoopEnd(ins) || isIfEnd(ins) || isElse(ins)) { // Process the nested loop or if statement - Compiler::StaticType ret = variableTypeAfterBranchFromEnd(varPtr, ins, previousType); + Compiler::StaticType ret = variableTypeAfterBranchFromEnd(varPtr, ins, previousType, write); - if (typesMatch(ret, previousType)) - typeMightReset = true; - else + if (typesMatch(ret, previousType)) { + if (write) + typeMightReset = true; + } else return Compiler::StaticType::Unknown; ins = skipBranch(ins); if (isElse(ins)) { // Process if branch (the else branch is already processed) - ret = variableTypeAfterBranchFromEnd(varPtr, ins, previousType); + ret = variableTypeAfterBranchFromEnd(varPtr, ins, previousType, write); - if (typesMatch(ret, previousType)) - typeMightReset = true; - else + if (typesMatch(ret, previousType)) { + if (write) { + if (typeMightReset) + return previousType; + + typeMightReset = true; + } + } else return Compiler::StaticType::Unknown; ins = skipBranch(ins); @@ -126,6 +133,7 @@ Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranchFromEnd(LLVMVariab } else if (ins->type == LLVMInstruction::Type::WriteVariable && ins->workVariable == varPtr->var) { // Variable write instruction Compiler::StaticType writeType = writeValueType(ins); + write = true; if (typesMatch(writeType, previousType)) return writeType; @@ -136,6 +144,7 @@ Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranchFromEnd(LLVMVariab ins = ins->previous; } + write = false; return previousType; } diff --git a/src/engine/internal/llvm/llvmtypeanalyzer.h b/src/engine/internal/llvm/llvmtypeanalyzer.h index ee29cc0db..a8376a364 100644 --- a/src/engine/internal/llvm/llvmtypeanalyzer.h +++ b/src/engine/internal/llvm/llvmtypeanalyzer.h @@ -16,7 +16,7 @@ class LLVMTypeAnalyzer Compiler::StaticType variableTypeAfterBranch(LLVMVariablePtr *varPtr, LLVMInstruction *start, Compiler::StaticType previousType) const; private: - Compiler::StaticType variableTypeAfterBranchFromEnd(LLVMVariablePtr *varPtr, LLVMInstruction *end, Compiler::StaticType previousType) const; + Compiler::StaticType variableTypeAfterBranchFromEnd(LLVMVariablePtr *varPtr, LLVMInstruction *end, Compiler::StaticType previousType, bool &write) const; LLVMInstruction *skipBranch(LLVMInstruction *pos) const; bool isLoopStart(LLVMInstruction *ins) const; bool isLoopEnd(LLVMInstruction *ins) const; diff --git a/test/llvm/type_analyzer/variabletypeafterbranch_test.cpp b/test/llvm/type_analyzer/variabletypeafterbranch_test.cpp index 4bde29c44..8fcf5fc0f 100644 --- a/test/llvm/type_analyzer/variabletypeafterbranch_test.cpp +++ b/test/llvm/type_analyzer/variabletypeafterbranch_test.cpp @@ -1308,6 +1308,150 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, NestedLoopWithTypeChangeBeforeLoo ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, outerLoop.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown); } +TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, IfStatementInLoopWithTypeChangeBeforeLoop_TypeChangeInIfBranch) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + // Outer loop begin + auto outerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatUntilLoop, nullptr, false); + list.addInstruction(outerLoop); + + // Variable write inside outer loop + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::String, "test"); + setVar1->workVariable = &var; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(setVar1); + + // Inner if statement begin + auto innerIf = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + list.addInstruction(innerIf); + + // Variable write inside inner if statement if branch + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::Number, 5); + setVar2->workVariable = &var; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + list.addInstruction(setVar2); + + // Inner if statement else branch begin + auto innerElse = std::make_shared(LLVMInstruction::Type::BeginElse, nullptr, false); + list.addInstruction(innerElse); + + // Inner if statement end + auto innerEnd = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + list.addInstruction(innerEnd); + + // Outer loop end + auto outerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(outerEnd); + + // Returns unknown type because if statements can be skipped + ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, outerLoop.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, IfStatementInLoopWithTypeChangeBeforeLoop_TypeChangeInElseBranch) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + // Outer loop begin + auto outerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatUntilLoop, nullptr, false); + list.addInstruction(outerLoop); + + // Variable write inside outer loop + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::String, "test"); + setVar1->workVariable = &var; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(setVar1); + + // Inner if statement begin + auto innerIf = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + list.addInstruction(innerIf); + + // Inner if statement else branch begin + auto innerElse = std::make_shared(LLVMInstruction::Type::BeginElse, nullptr, false); + list.addInstruction(innerElse); + + // Variable write inside inner if statement else branch + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::Number, 5); + setVar2->workVariable = &var; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + list.addInstruction(setVar2); + + // Inner if statement end + auto innerEnd = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + list.addInstruction(innerEnd); + + // Outer loop end + auto outerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(outerEnd); + + // Returns unknown type because if statements can be skipped + ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, outerLoop.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, IfStatementInLoopWithTypeChangeBeforeLoop_TypeChangeInBothBranches) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + // Outer loop begin + auto outerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatUntilLoop, nullptr, false); + list.addInstruction(outerLoop); + + // Variable write inside outer loop + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::String, "test"); + setVar1->workVariable = &var; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(setVar1); + + // Inner if statement begin + auto innerIf = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + list.addInstruction(innerIf); + + auto setVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::Number, 5); + setVar->workVariable = &var; + setVar->args.push_back({ Compiler::StaticType::Unknown, &value }); + list.addInstruction(setVar); + + // Inner if statement else branch begin + auto innerElse = std::make_shared(LLVMInstruction::Type::BeginElse, nullptr, false); + list.addInstruction(innerElse); + + // Variable write inside inner if statement else branch + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::Number, 5); + setVar2->workVariable = &var; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + list.addInstruction(setVar2); + + // Inner if statement end + auto innerEnd = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + list.addInstruction(innerEnd); + + // Outer loop end + auto outerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(outerEnd); + + // Returns number type because the type always changes to number + ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, outerLoop.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); +} + TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleNestedLoopsWithTypeChange) { LLVMTypeAnalyzer analyzer; From 54400ded319fbd811ca07dc60aedd2f9d1b71f9f Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Fri, 25 Jul 2025 23:38:09 +0200 Subject: [PATCH 29/79] LLVMTypeAnalyzer: Remove leftover dead code --- src/engine/internal/llvm/llvmtypeanalyzer.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/engine/internal/llvm/llvmtypeanalyzer.cpp b/src/engine/internal/llvm/llvmtypeanalyzer.cpp index d59577a5b..c217ada5c 100644 --- a/src/engine/internal/llvm/llvmtypeanalyzer.cpp +++ b/src/engine/internal/llvm/llvmtypeanalyzer.cpp @@ -235,9 +235,4 @@ bool LLVMTypeAnalyzer::writeTypesMatch(LLVMInstruction *ins, Compiler::StaticTyp return isVarOrListTypeSafe(argIns.get(), expectedType, log, c);*/ return typesMatch(writeValueType(ins), expectedType); - if (expectedType == Compiler::StaticType::Unknown) { - // Equal unknown types are not considered a match - return false; - } else - return (writeValueType(ins) == expectedType); } From 5b94db0aa790c24d284af46ad3cd01f6e4600bf0 Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Sat, 26 Jul 2025 11:15:02 +0200 Subject: [PATCH 30/79] LLVMTypeAnalyzer: Fix some test case names --- test/llvm/type_analyzer/variabletype_test.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/llvm/type_analyzer/variabletype_test.cpp b/test/llvm/type_analyzer/variabletype_test.cpp index 992d54f52..15a852870 100644 --- a/test/llvm/type_analyzer/variabletype_test.cpp +++ b/test/llvm/type_analyzer/variabletype_test.cpp @@ -783,7 +783,7 @@ TEST(LLVMTypeAnalyzer_VariableType, OverrideUnknownTypeBeforeLoop) ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Unknown), Compiler::StaticType::Number); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, WriteSameTypeInIfStatement) +TEST(LLVMTypeAnalyzer_VariableType, WriteSameTypeInIfStatement) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; @@ -809,7 +809,7 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, WriteSameTypeInIfStatement) ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); } -TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, WriteDifferentTypeInIfStatement) +TEST(LLVMTypeAnalyzer_VariableType, WriteDifferentTypeInIfStatement) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; From ea7c9b7a08cc3bf94f655a03937281f3411d6dfe Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Sat, 26 Jul 2025 11:16:52 +0200 Subject: [PATCH 31/79] LLVMTypeAnalyzer: Ignore writes after pos in if statements --- src/engine/internal/llvm/llvmtypeanalyzer.cpp | 15 ++- test/llvm/type_analyzer/variabletype_test.cpp | 115 ++++++++++++++++++ 2 files changed, 128 insertions(+), 2 deletions(-) diff --git a/src/engine/internal/llvm/llvmtypeanalyzer.cpp b/src/engine/internal/llvm/llvmtypeanalyzer.cpp index c217ada5c..d960d7f28 100644 --- a/src/engine/internal/llvm/llvmtypeanalyzer.cpp +++ b/src/engine/internal/llvm/llvmtypeanalyzer.cpp @@ -19,12 +19,16 @@ Compiler::StaticType LLVMTypeAnalyzer::variableType(LLVMVariablePtr *varPtr, LLV LLVMInstruction *write = nullptr; LLVMInstruction *firstBranch = nullptr; LLVMInstruction *firstElseBranch = nullptr; + LLVMInstruction *ourBranch = nullptr; int level = 0; while (ins) { if (isLoopEnd(ins) || isIfEnd(ins)) level++; else if (isLoopStart(ins) || isIfStart(ins)) { + if (!ourBranch && level == 0) + ourBranch = ins; + level--; firstBranch = ins; } else if (isElse(ins)) { @@ -44,11 +48,18 @@ Compiler::StaticType LLVMTypeAnalyzer::variableType(LLVMVariablePtr *varPtr, LLV if (firstBranch) { // Analyze the first branch and else branch + bool ignoreWriteAfterPos = (isIfStart(firstBranch) && firstBranch == ourBranch); + if (write) previousType = writeValueType(write); // write operation overrides previous type - Compiler::StaticType firstBranchType = variableTypeAfterBranch(varPtr, firstBranch, previousType); - Compiler::StaticType elseBranchType = variableTypeAfterBranch(varPtr, firstElseBranch, previousType); + Compiler::StaticType firstBranchType = previousType; + Compiler::StaticType elseBranchType = previousType; + + if (!ignoreWriteAfterPos) { + firstBranchType = variableTypeAfterBranch(varPtr, firstBranch, previousType); + elseBranchType = variableTypeAfterBranch(varPtr, firstElseBranch, previousType); + } if (typesMatch(firstBranchType, elseBranchType)) return firstBranchType; diff --git a/test/llvm/type_analyzer/variabletype_test.cpp b/test/llvm/type_analyzer/variabletype_test.cpp index 15a852870..fbb837ed0 100644 --- a/test/llvm/type_analyzer/variabletype_test.cpp +++ b/test/llvm/type_analyzer/variabletype_test.cpp @@ -666,6 +666,121 @@ TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteDifferentTypeStringToBool_Af ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::String), Compiler::StaticType::Unknown); } +TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteDifferentType_BeforeAndAfter) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(start); + + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::String, "test"); + setVar1->workVariable = &var; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(setVar1); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(funcCall); + + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::Bool, true); + setVar2->workVariable = &var; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + list.addInstruction(setVar2); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(end); + + ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::String); +} + +TEST(LLVMTypeAnalyzer_VariableType, IfStatement_SingleWriteDifferentType_Before) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + auto start = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + list.addInstruction(start); + + auto setVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::String, "test"); + setVar->workVariable = &var; + setVar->args.push_back({ Compiler::StaticType::Unknown, &value }); + list.addInstruction(setVar); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(funcCall); + + auto end = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + list.addInstruction(end); + + ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::String); +} + +TEST(LLVMTypeAnalyzer_VariableType, IfStatement_SingleWriteDifferentType_After_IfBranch) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + auto start = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + list.addInstruction(start); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(funcCall); + + auto setVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::String, "test"); + setVar->workVariable = &var; + setVar->args.push_back({ Compiler::StaticType::Unknown, &value }); + list.addInstruction(setVar); + + auto end = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + list.addInstruction(end); + + // Since this isn't a loop, the write after the point doesn't affect the type + ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_VariableType, IfStatement_SingleWriteDifferentType_After_ElseBranch) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + LLVMVariablePtr varPtr; + Variable var("", ""); + varPtr.var = &var; + + auto start = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + list.addInstruction(start); + + auto elseStart = std::make_shared(LLVMInstruction::Type::BeginElse, nullptr, false); + list.addInstruction(elseStart); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(funcCall); + + auto setVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::String, "test"); + setVar->workVariable = &var; + setVar->args.push_back({ Compiler::StaticType::Unknown, &value }); + list.addInstruction(setVar); + + auto end = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + list.addInstruction(end); + + // Since this isn't a loop, the write after the point doesn't affect the type + ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); +} + TEST(LLVMTypeAnalyzer_VariableType, WriteSameTypeInLoop) { LLVMTypeAnalyzer analyzer; From ad367dc6ab7ca5d5a23e420cc0b4eb6ee7aee742 Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Sat, 26 Jul 2025 11:21:48 +0200 Subject: [PATCH 32/79] LLVMTypeAnalyzer: Use isVariableWrite() to check variable writes --- src/engine/internal/llvm/llvmtypeanalyzer.cpp | 9 +++++++-- src/engine/internal/llvm/llvmtypeanalyzer.h | 1 + 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/engine/internal/llvm/llvmtypeanalyzer.cpp b/src/engine/internal/llvm/llvmtypeanalyzer.cpp index d960d7f28..a636f26c7 100644 --- a/src/engine/internal/llvm/llvmtypeanalyzer.cpp +++ b/src/engine/internal/llvm/llvmtypeanalyzer.cpp @@ -36,7 +36,7 @@ Compiler::StaticType LLVMTypeAnalyzer::variableType(LLVMVariablePtr *varPtr, LLV firstElseBranch = ins; ins = skipBranch(ins); continue; - } else if (ins->type == LLVMInstruction::Type::WriteVariable && ins->workVariable == varPtr->var) { + } else if (isVariableWrite(ins, varPtr)) { if (level <= 0) { // ignore nested branches (they're handled by the branch analyzer) write = ins; break; @@ -141,7 +141,7 @@ Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranchFromEnd(LLVMVariab ins = skipBranch(ins); } - } else if (ins->type == LLVMInstruction::Type::WriteVariable && ins->workVariable == varPtr->var) { + } else if (isVariableWrite(ins, varPtr)) { // Variable write instruction Compiler::StaticType writeType = writeValueType(ins); write = true; @@ -209,6 +209,11 @@ bool LLVMTypeAnalyzer::isIfEnd(LLVMInstruction *ins) const return (ins->type == LLVMInstruction::Type::EndIf); } +bool LLVMTypeAnalyzer::isVariableWrite(LLVMInstruction *ins, LLVMVariablePtr *varPtr) const +{ + return (ins->type == LLVMInstruction::Type::WriteVariable && ins->workVariable == varPtr->var); +} + Compiler::StaticType LLVMTypeAnalyzer::optimizeRegisterType(LLVMRegister *reg) const { // TODO: Move this method out if it's used in LLVMCodeBuilder too diff --git a/src/engine/internal/llvm/llvmtypeanalyzer.h b/src/engine/internal/llvm/llvmtypeanalyzer.h index a8376a364..0af4e3ff0 100644 --- a/src/engine/internal/llvm/llvmtypeanalyzer.h +++ b/src/engine/internal/llvm/llvmtypeanalyzer.h @@ -23,6 +23,7 @@ class LLVMTypeAnalyzer bool isIfStart(LLVMInstruction *ins) const; bool isElse(LLVMInstruction *ins) const; bool isIfEnd(LLVMInstruction *ins) const; + bool isVariableWrite(LLVMInstruction *ins, LLVMVariablePtr *varPtr) const; Compiler::StaticType optimizeRegisterType(LLVMRegister *reg) const; Compiler::StaticType writeValueType(LLVMInstruction *ins) const; From 3f4d19feee161b5453dcb7dee111170dcc5d8dee Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Sat, 26 Jul 2025 11:50:40 +0200 Subject: [PATCH 33/79] LLVMTypeAnalyzer: Use Variable instead of LLVMVariablePtr --- src/engine/internal/llvm/llvmtypeanalyzer.cpp | 29 +-- src/engine/internal/llvm/llvmtypeanalyzer.h | 9 +- test/llvm/type_analyzer/variabletype_test.cpp | 241 +++++------------- .../variabletypeafterbranch_test.cpp | 209 +++++---------- 4 files changed, 140 insertions(+), 348 deletions(-) diff --git a/src/engine/internal/llvm/llvmtypeanalyzer.cpp b/src/engine/internal/llvm/llvmtypeanalyzer.cpp index a636f26c7..fa295e6be 100644 --- a/src/engine/internal/llvm/llvmtypeanalyzer.cpp +++ b/src/engine/internal/llvm/llvmtypeanalyzer.cpp @@ -2,16 +2,15 @@ #include "llvmtypeanalyzer.h" #include "llvminstruction.h" -#include "llvmvariableptr.h" using namespace libscratchcpp; static const std::unordered_set BEGIN_LOOP_INSTRUCTIONS = { LLVMInstruction::Type::BeginRepeatLoop, LLVMInstruction::Type::BeginWhileLoop, LLVMInstruction::Type::BeginRepeatUntilLoop }; -Compiler::StaticType LLVMTypeAnalyzer::variableType(LLVMVariablePtr *varPtr, LLVMInstruction *pos, Compiler::StaticType previousType) const +Compiler::StaticType LLVMTypeAnalyzer::variableType(Variable *var, LLVMInstruction *pos, Compiler::StaticType previousType) const { - if (!varPtr || !pos) + if (!var || !pos) return Compiler::StaticType::Unknown; // Check the last write operation before the instruction @@ -36,7 +35,7 @@ Compiler::StaticType LLVMTypeAnalyzer::variableType(LLVMVariablePtr *varPtr, LLV firstElseBranch = ins; ins = skipBranch(ins); continue; - } else if (isVariableWrite(ins, varPtr)) { + } else if (isVariableWrite(ins, var)) { if (level <= 0) { // ignore nested branches (they're handled by the branch analyzer) write = ins; break; @@ -57,8 +56,8 @@ Compiler::StaticType LLVMTypeAnalyzer::variableType(LLVMVariablePtr *varPtr, LLV Compiler::StaticType elseBranchType = previousType; if (!ignoreWriteAfterPos) { - firstBranchType = variableTypeAfterBranch(varPtr, firstBranch, previousType); - elseBranchType = variableTypeAfterBranch(varPtr, firstElseBranch, previousType); + firstBranchType = variableTypeAfterBranch(var, firstBranch, previousType); + elseBranchType = variableTypeAfterBranch(var, firstElseBranch, previousType); } if (typesMatch(firstBranchType, elseBranchType)) @@ -74,9 +73,9 @@ Compiler::StaticType LLVMTypeAnalyzer::variableType(LLVMVariablePtr *varPtr, LLV return previousType; } -Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranch(LLVMVariablePtr *varPtr, LLVMInstruction *start, Compiler::StaticType previousType) const +Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranch(Variable *var, LLVMInstruction *start, Compiler::StaticType previousType) const { - if (!varPtr || !start) + if (!var || !start) return previousType; assert(isLoopStart(start) || isIfStart(start) || isElse(start)); @@ -103,10 +102,10 @@ Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranch(LLVMVariablePtr * // Process the branch from end bool write = false; // only used internally (the compiler doesn't need this) - return variableTypeAfterBranchFromEnd(varPtr, ins, previousType, write); + return variableTypeAfterBranchFromEnd(var, ins, previousType, write); } -Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranchFromEnd(LLVMVariablePtr *varPtr, LLVMInstruction *end, Compiler::StaticType previousType, bool &write) const +Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranchFromEnd(Variable *var, LLVMInstruction *end, Compiler::StaticType previousType, bool &write) const { // Find the last write instruction LLVMInstruction *ins = end->previous; @@ -115,7 +114,7 @@ Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranchFromEnd(LLVMVariab while (ins && !isLoopStart(ins) && !isIfStart(ins)) { if (isLoopEnd(ins) || isIfEnd(ins) || isElse(ins)) { // Process the nested loop or if statement - Compiler::StaticType ret = variableTypeAfterBranchFromEnd(varPtr, ins, previousType, write); + Compiler::StaticType ret = variableTypeAfterBranchFromEnd(var, ins, previousType, write); if (typesMatch(ret, previousType)) { if (write) @@ -127,7 +126,7 @@ Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranchFromEnd(LLVMVariab if (isElse(ins)) { // Process if branch (the else branch is already processed) - ret = variableTypeAfterBranchFromEnd(varPtr, ins, previousType, write); + ret = variableTypeAfterBranchFromEnd(var, ins, previousType, write); if (typesMatch(ret, previousType)) { if (write) { @@ -141,7 +140,7 @@ Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranchFromEnd(LLVMVariab ins = skipBranch(ins); } - } else if (isVariableWrite(ins, varPtr)) { + } else if (isVariableWrite(ins, var)) { // Variable write instruction Compiler::StaticType writeType = writeValueType(ins); write = true; @@ -209,9 +208,9 @@ bool LLVMTypeAnalyzer::isIfEnd(LLVMInstruction *ins) const return (ins->type == LLVMInstruction::Type::EndIf); } -bool LLVMTypeAnalyzer::isVariableWrite(LLVMInstruction *ins, LLVMVariablePtr *varPtr) const +bool LLVMTypeAnalyzer::isVariableWrite(LLVMInstruction *ins, Variable *var) const { - return (ins->type == LLVMInstruction::Type::WriteVariable && ins->workVariable == varPtr->var); + return (ins->type == LLVMInstruction::Type::WriteVariable && ins->workVariable == var); } Compiler::StaticType LLVMTypeAnalyzer::optimizeRegisterType(LLVMRegister *reg) const diff --git a/src/engine/internal/llvm/llvmtypeanalyzer.h b/src/engine/internal/llvm/llvmtypeanalyzer.h index 0af4e3ff0..3cb4cc4e1 100644 --- a/src/engine/internal/llvm/llvmtypeanalyzer.h +++ b/src/engine/internal/llvm/llvmtypeanalyzer.h @@ -5,25 +5,24 @@ namespace libscratchcpp { -struct LLVMVariablePtr; struct LLVMInstruction; struct LLVMRegister; class LLVMTypeAnalyzer { public: - Compiler::StaticType variableType(LLVMVariablePtr *varPtr, LLVMInstruction *pos, Compiler::StaticType previousType) const; - Compiler::StaticType variableTypeAfterBranch(LLVMVariablePtr *varPtr, LLVMInstruction *start, Compiler::StaticType previousType) const; + Compiler::StaticType variableType(Variable *var, LLVMInstruction *pos, Compiler::StaticType previousType) const; + Compiler::StaticType variableTypeAfterBranch(Variable *var, LLVMInstruction *start, Compiler::StaticType previousType) const; private: - Compiler::StaticType variableTypeAfterBranchFromEnd(LLVMVariablePtr *varPtr, LLVMInstruction *end, Compiler::StaticType previousType, bool &write) const; + Compiler::StaticType variableTypeAfterBranchFromEnd(Variable *var, LLVMInstruction *end, Compiler::StaticType previousType, bool &write) const; LLVMInstruction *skipBranch(LLVMInstruction *pos) const; bool isLoopStart(LLVMInstruction *ins) const; bool isLoopEnd(LLVMInstruction *ins) const; bool isIfStart(LLVMInstruction *ins) const; bool isElse(LLVMInstruction *ins) const; bool isIfEnd(LLVMInstruction *ins) const; - bool isVariableWrite(LLVMInstruction *ins, LLVMVariablePtr *varPtr) const; + bool isVariableWrite(LLVMInstruction *ins, Variable *var) const; Compiler::StaticType optimizeRegisterType(LLVMRegister *reg) const; Compiler::StaticType writeValueType(LLVMInstruction *ins) const; diff --git a/test/llvm/type_analyzer/variabletype_test.cpp b/test/llvm/type_analyzer/variabletype_test.cpp index fbb837ed0..65037f605 100644 --- a/test/llvm/type_analyzer/variabletype_test.cpp +++ b/test/llvm/type_analyzer/variabletype_test.cpp @@ -1,6 +1,5 @@ #include #include -#include #include #include #include @@ -28,41 +27,39 @@ TEST(LLVMTypeAnalyzer_VariableType, NullVariable) TEST(LLVMTypeAnalyzer_VariableType, NullPos) { LLVMTypeAnalyzer analyzer; - LLVMVariablePtr varPtr; - ASSERT_EQ(analyzer.variableType(&varPtr, nullptr, Compiler::StaticType::Number), Compiler::StaticType::Unknown); + Variable var("", ""); + ASSERT_EQ(analyzer.variableType(&var, nullptr, Compiler::StaticType::Number), Compiler::StaticType::Unknown); } TEST(LLVMTypeAnalyzer_VariableType, NoWriteOperationsKnownType) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; + Variable var("", ""); auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); list.addInstruction(funcCall); - ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); + ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); } TEST(LLVMTypeAnalyzer_VariableType, NoWriteOperationsUnknownType) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; + Variable var("", ""); auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); list.addInstruction(funcCall); - ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Unknown), Compiler::StaticType::Unknown); + ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Unknown), Compiler::StaticType::Unknown); } TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteSameTypeNumber_Before) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); list.addInstruction(start); @@ -79,16 +76,14 @@ TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteSameTypeNumber_Before) auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); + ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); } TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteSameTypeNumber_After) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); list.addInstruction(start); @@ -105,16 +100,14 @@ TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteSameTypeNumber_After) auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); + ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); } TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteSameTypeBool_Before) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); list.addInstruction(start); @@ -131,16 +124,14 @@ TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteSameTypeBool_Before) auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Bool), Compiler::StaticType::Bool); + ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Bool), Compiler::StaticType::Bool); } TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteSameTypeBool_After) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); list.addInstruction(start); @@ -157,16 +148,14 @@ TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteSameTypeBool_After) auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Bool), Compiler::StaticType::Bool); + ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Bool), Compiler::StaticType::Bool); } TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteSameTypeString_Before) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); list.addInstruction(start); @@ -183,16 +172,14 @@ TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteSameTypeString_Before) auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::String), Compiler::StaticType::String); + ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::String), Compiler::StaticType::String); } TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteSameTypeString_After) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); list.addInstruction(start); @@ -209,16 +196,14 @@ TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteSameTypeString_After) auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::String), Compiler::StaticType::String); + ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::String), Compiler::StaticType::String); } TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteStringOptimization) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); list.addInstruction(start); @@ -236,17 +221,15 @@ TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteStringOptimization) list.addInstruction(end); // Although string is assigned, it's constant and represents a number - ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); + ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); } TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteMultipleVariables) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var1("", ""); Variable var2("", ""); - varPtr.var = &var1; auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); list.addInstruction(start); @@ -271,16 +254,14 @@ TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteMultipleVariables) auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); + ASSERT_EQ(analyzer.variableType(&var1, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); } TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteFromUnknownType_Before) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); list.addInstruction(start); @@ -297,16 +278,14 @@ TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteFromUnknownType_Before) auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown); + ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown); } TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteFromUnknownType_After) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); list.addInstruction(start); @@ -323,16 +302,14 @@ TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteFromUnknownType_After) auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown); + ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown); } TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteToUnknownType_Before) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); list.addInstruction(start); @@ -350,16 +327,14 @@ TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteToUnknownType_Before) list.addInstruction(end); // The type is known because a number is assigned before the point - ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Unknown), Compiler::StaticType::Number); + ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Unknown), Compiler::StaticType::Number); } TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteToUnknownType_After) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); list.addInstruction(start); @@ -377,16 +352,14 @@ TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteToUnknownType_After) list.addInstruction(end); // The type is not known because a number is assigned after the point - ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Unknown), Compiler::StaticType::Unknown); + ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Unknown), Compiler::StaticType::Unknown); } TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteUnknownToUnknownType_Before) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); list.addInstruction(start); @@ -403,16 +376,14 @@ TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteUnknownToUnknownType_Before) auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Unknown), Compiler::StaticType::Unknown); + ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Unknown), Compiler::StaticType::Unknown); } TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteUnknownToUnknownType_After) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); list.addInstruction(start); @@ -429,16 +400,14 @@ TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteUnknownToUnknownType_After) auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Unknown), Compiler::StaticType::Unknown); + ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Unknown), Compiler::StaticType::Unknown); } TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteDifferentTypeNumberToString_Before) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); list.addInstruction(start); @@ -455,16 +424,14 @@ TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteDifferentTypeNumberToString_ auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::String); + ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::String); } TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteDifferentTypeNumberToString_After) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); list.addInstruction(start); @@ -481,16 +448,14 @@ TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteDifferentTypeNumberToString_ auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown); + ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown); } TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteDifferentTypeStringToNumber_After) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); list.addInstruction(start); @@ -507,16 +472,14 @@ TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteDifferentTypeStringToNumber_ auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::String), Compiler::StaticType::Unknown); + ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::String), Compiler::StaticType::Unknown); } TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteDifferentTypeNumberToBool_After) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); list.addInstruction(start); @@ -533,16 +496,14 @@ TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteDifferentTypeNumberToBool_Af auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown); + ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown); } TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteDifferentTypeBoolToNumber_Before) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); list.addInstruction(start); @@ -559,16 +520,14 @@ TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteDifferentTypeBoolToNumber_Be auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Bool), Compiler::StaticType::Number); + ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Bool), Compiler::StaticType::Number); } TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteDifferentTypeBoolToNumber_After) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); list.addInstruction(start); @@ -585,16 +544,14 @@ TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteDifferentTypeBoolToNumber_Af auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Bool), Compiler::StaticType::Unknown); + ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Bool), Compiler::StaticType::Unknown); } TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteDifferentTypeBoolToString_After) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); list.addInstruction(start); @@ -611,16 +568,14 @@ TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteDifferentTypeBoolToString_Af auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Bool), Compiler::StaticType::Unknown); + ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Bool), Compiler::StaticType::Unknown); } TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteDifferentTypeStringToBool_Before) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); list.addInstruction(start); @@ -637,16 +592,14 @@ TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteDifferentTypeStringToBool_Be auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::String), Compiler::StaticType::Bool); + ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::String), Compiler::StaticType::Bool); } TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteDifferentTypeStringToBool_After) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); list.addInstruction(start); @@ -663,16 +616,14 @@ TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteDifferentTypeStringToBool_Af auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::String), Compiler::StaticType::Unknown); + ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::String), Compiler::StaticType::Unknown); } TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteDifferentType_BeforeAndAfter) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); list.addInstruction(start); @@ -695,16 +646,14 @@ TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteDifferentType_BeforeAndAfter auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::String); + ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::String); } TEST(LLVMTypeAnalyzer_VariableType, IfStatement_SingleWriteDifferentType_Before) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; auto start = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); list.addInstruction(start); @@ -721,16 +670,14 @@ TEST(LLVMTypeAnalyzer_VariableType, IfStatement_SingleWriteDifferentType_Before) auto end = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); list.addInstruction(end); - ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::String); + ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::String); } TEST(LLVMTypeAnalyzer_VariableType, IfStatement_SingleWriteDifferentType_After_IfBranch) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; auto start = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); list.addInstruction(start); @@ -748,16 +695,14 @@ TEST(LLVMTypeAnalyzer_VariableType, IfStatement_SingleWriteDifferentType_After_I list.addInstruction(end); // Since this isn't a loop, the write after the point doesn't affect the type - ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); + ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); } TEST(LLVMTypeAnalyzer_VariableType, IfStatement_SingleWriteDifferentType_After_ElseBranch) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; auto start = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); list.addInstruction(start); @@ -778,16 +723,14 @@ TEST(LLVMTypeAnalyzer_VariableType, IfStatement_SingleWriteDifferentType_After_E list.addInstruction(end); // Since this isn't a loop, the write after the point doesn't affect the type - ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); + ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); } TEST(LLVMTypeAnalyzer_VariableType, WriteSameTypeInLoop) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); list.addInstruction(start); @@ -804,16 +747,14 @@ TEST(LLVMTypeAnalyzer_VariableType, WriteSameTypeInLoop) auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); list.addInstruction(funcCall); - ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); + ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); } TEST(LLVMTypeAnalyzer_VariableType, WriteDifferentTypeInLoop) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); list.addInstruction(start); @@ -831,16 +772,14 @@ TEST(LLVMTypeAnalyzer_VariableType, WriteDifferentTypeInLoop) list.addInstruction(funcCall); // Type is not known because the loop might not run at all - ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown); + ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown); } TEST(LLVMTypeAnalyzer_VariableType, OverrideDifferentTypeBeforeLoop) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); LLVMConstantRegister value1(Compiler::StaticType::Number, 1.25); @@ -863,16 +802,14 @@ TEST(LLVMTypeAnalyzer_VariableType, OverrideDifferentTypeBeforeLoop) auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); list.addInstruction(funcCall); - ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::String), Compiler::StaticType::Number); + ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::String), Compiler::StaticType::Number); } TEST(LLVMTypeAnalyzer_VariableType, OverrideUnknownTypeBeforeLoop) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); LLVMConstantRegister value1(Compiler::StaticType::Number, 1.25); @@ -895,16 +832,14 @@ TEST(LLVMTypeAnalyzer_VariableType, OverrideUnknownTypeBeforeLoop) auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); list.addInstruction(funcCall); - ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Unknown), Compiler::StaticType::Number); + ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Unknown), Compiler::StaticType::Number); } TEST(LLVMTypeAnalyzer_VariableType, WriteSameTypeInIfStatement) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; auto start = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); list.addInstruction(start); @@ -921,16 +856,14 @@ TEST(LLVMTypeAnalyzer_VariableType, WriteSameTypeInIfStatement) auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); list.addInstruction(funcCall); - ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); + ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); } TEST(LLVMTypeAnalyzer_VariableType, WriteDifferentTypeInIfStatement) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; auto start = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); list.addInstruction(start); @@ -948,16 +881,14 @@ TEST(LLVMTypeAnalyzer_VariableType, WriteDifferentTypeInIfStatement) list.addInstruction(funcCall); // Type is not known because the if statement might not run at all - ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::String), Compiler::StaticType::Unknown); + ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::String), Compiler::StaticType::Unknown); } TEST(LLVMTypeAnalyzer_VariableType, OverrideDifferentTypeBeforeIfElseStatement) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); LLVMConstantRegister value1(Compiler::StaticType::Number, 1.25); @@ -989,16 +920,14 @@ TEST(LLVMTypeAnalyzer_VariableType, OverrideDifferentTypeBeforeIfElseStatement) auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); list.addInstruction(funcCall); - ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::String), Compiler::StaticType::Number); + ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::String), Compiler::StaticType::Number); } TEST(LLVMTypeAnalyzer_VariableType, OverrideUnknownTypeBeforeIfElseStatement) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); LLVMConstantRegister value1(Compiler::StaticType::Number, 1.25); @@ -1030,16 +959,14 @@ TEST(LLVMTypeAnalyzer_VariableType, OverrideUnknownTypeBeforeIfElseStatement) auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); list.addInstruction(funcCall); - ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Unknown), Compiler::StaticType::Number); + ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Unknown), Compiler::StaticType::Number); } TEST(LLVMTypeAnalyzer_VariableType, MultipleWritesSameTypeNumber) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; // First write: string "abc" (incompatible with Number) auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); @@ -1059,16 +986,14 @@ TEST(LLVMTypeAnalyzer_VariableType, MultipleWritesSameTypeNumber) list.addInstruction(funcCall); // Should return Number type because final assignment writes a number - ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); + ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); } TEST(LLVMTypeAnalyzer_VariableType, MultipleWritesSameTypeString) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; // First write: number 42 (incompatible with String) auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); @@ -1088,16 +1013,14 @@ TEST(LLVMTypeAnalyzer_VariableType, MultipleWritesSameTypeString) list.addInstruction(funcCall); // Should return String type because final assignment writes a string - ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::String), Compiler::StaticType::String); + ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::String), Compiler::StaticType::String); } TEST(LLVMTypeAnalyzer_VariableType, MultipleWritesSameTypeUnknown) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; // First write: unknown type auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); @@ -1117,16 +1040,14 @@ TEST(LLVMTypeAnalyzer_VariableType, MultipleWritesSameTypeUnknown) list.addInstruction(funcCall); // Should return String type because final assignment writes a string - ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::String), Compiler::StaticType::String); + ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::String), Compiler::StaticType::String); } TEST(LLVMTypeAnalyzer_VariableType, MultipleWritesWithStringOptimization) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; // First write: string "abc" (incompatible with Number) auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); @@ -1146,16 +1067,14 @@ TEST(LLVMTypeAnalyzer_VariableType, MultipleWritesWithStringOptimization) list.addInstruction(funcCall); // Should return Number type because final assignment writes a string which is optimized to Number type - ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); + ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); } TEST(LLVMTypeAnalyzer_VariableType, MultipleWritesNumberToString) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; // First write: number 42 (compatible with Number) auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); @@ -1175,16 +1094,14 @@ TEST(LLVMTypeAnalyzer_VariableType, MultipleWritesNumberToString) list.addInstruction(funcCall); // Should return String type because final assignment writes a string - ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::String); + ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::String); } TEST(LLVMTypeAnalyzer_VariableType, MultipleWritesBoolToNumber) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; auto setVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); LLVMConstantRegister value(Compiler::StaticType::Number, 42.5); @@ -1196,16 +1113,14 @@ TEST(LLVMTypeAnalyzer_VariableType, MultipleWritesBoolToNumber) list.addInstruction(funcCall); // Should return Number type because final assignment writes a number - ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Bool), Compiler::StaticType::Number); + ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Bool), Compiler::StaticType::Number); } TEST(LLVMTypeAnalyzer_VariableType, MultipleWritesBoolToString) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; auto setVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); LLVMConstantRegister value(Compiler::StaticType::String, "hello"); @@ -1217,16 +1132,14 @@ TEST(LLVMTypeAnalyzer_VariableType, MultipleWritesBoolToString) list.addInstruction(funcCall); // Should return String type because final assignment writes a string - ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Bool), Compiler::StaticType::String); + ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Bool), Compiler::StaticType::String); } TEST(LLVMTypeAnalyzer_VariableType, MultipleWritesBoolToStringNumberOptimization) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; auto setVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); LLVMConstantRegister value(Compiler::StaticType::String, "3.14"); @@ -1238,16 +1151,14 @@ TEST(LLVMTypeAnalyzer_VariableType, MultipleWritesBoolToStringNumberOptimization list.addInstruction(funcCall); // String "3.14" gets optimized to Number, which is still different from Bool - ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Bool), Compiler::StaticType::Number); + ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Bool), Compiler::StaticType::Number); } TEST(LLVMTypeAnalyzer_VariableType, TypeChangeInIfBranch) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; auto ifStart = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); list.addInstruction(ifStart); @@ -1276,16 +1187,14 @@ TEST(LLVMTypeAnalyzer_VariableType, TypeChangeInIfBranch) list.addInstruction(funcCall); // Returns unknown type because both branches might run - ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown); + ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown); } TEST(LLVMTypeAnalyzer_VariableType, TypeChangeInElseBranch) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; auto ifStart = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); list.addInstruction(ifStart); @@ -1314,16 +1223,14 @@ TEST(LLVMTypeAnalyzer_VariableType, TypeChangeInElseBranch) list.addInstruction(funcCall); // Returns unknown type because both branches might run - ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown); + ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown); } TEST(LLVMTypeAnalyzer_VariableType, IfElseWithEqualTypes_SameType) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; auto ifStart = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); list.addInstruction(ifStart); @@ -1351,16 +1258,14 @@ TEST(LLVMTypeAnalyzer_VariableType, IfElseWithEqualTypes_SameType) auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); list.addInstruction(funcCall); - ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); + ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); } TEST(LLVMTypeAnalyzer_VariableType, IfElseWithEqualTypes_DifferentTypes) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; auto ifStart = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); list.addInstruction(ifStart); @@ -1388,16 +1293,14 @@ TEST(LLVMTypeAnalyzer_VariableType, IfElseWithEqualTypes_DifferentTypes) auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); list.addInstruction(funcCall); - ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::String); + ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::String); } TEST(LLVMTypeAnalyzer_VariableType, NestedLoopWithTypeChange_Before) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; // Outer loop begin auto outerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); @@ -1432,16 +1335,14 @@ TEST(LLVMTypeAnalyzer_VariableType, NestedLoopWithTypeChange_Before) auto outerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(outerEnd); - ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown); + ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown); } TEST(LLVMTypeAnalyzer_VariableType, NestedLoopWithTypeChange_BeforeInner) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; // Outer loop begin auto outerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); @@ -1476,16 +1377,14 @@ TEST(LLVMTypeAnalyzer_VariableType, NestedLoopWithTypeChange_BeforeInner) auto outerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(outerEnd); - ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); + ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); } TEST(LLVMTypeAnalyzer_VariableType, NestedLoopWithTypeChange_AfterWriteInsideInner) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; // Outer loop begin auto outerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); @@ -1520,16 +1419,14 @@ TEST(LLVMTypeAnalyzer_VariableType, NestedLoopWithTypeChange_AfterWriteInsideInn auto outerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(outerEnd); - ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::String); + ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::String); } TEST(LLVMTypeAnalyzer_VariableType, NestedLoopWithTypeChange_After) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; // Outer loop begin auto outerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); @@ -1565,16 +1462,14 @@ TEST(LLVMTypeAnalyzer_VariableType, NestedLoopWithTypeChange_After) list.addInstruction(outerEnd); // Type is not known because the inner loop might not run at all - ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown); + ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown); } TEST(LLVMTypeAnalyzer_VariableType, NestedLoopWithoutTypeChange) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; // Outer loop begin auto outerLoop = std::make_shared(LLVMInstruction::Type::BeginWhileLoop, nullptr, false); @@ -1609,16 +1504,14 @@ TEST(LLVMTypeAnalyzer_VariableType, NestedLoopWithoutTypeChange) auto outerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(outerEnd); - ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); + ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); } TEST(LLVMTypeAnalyzer_VariableType, NestedLoopTypeChangesButResets) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; // Outer loop begin auto outerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); @@ -1660,16 +1553,14 @@ TEST(LLVMTypeAnalyzer_VariableType, NestedLoopTypeChangesButResets) auto outerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(outerEnd); - ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); + ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); } TEST(LLVMTypeAnalyzer_VariableType, NestedLoopTypeChangesAndDoesNotReset) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; // Outer loop begin auto outerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); @@ -1711,16 +1602,14 @@ TEST(LLVMTypeAnalyzer_VariableType, NestedLoopTypeChangesAndDoesNotReset) auto outerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(outerEnd); - ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::String); + ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::String); } TEST(LLVMTypeAnalyzer_VariableType, MultipleNestedLoopsWithTypeChange) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; // Outer loop begin auto outerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); @@ -1770,16 +1659,14 @@ TEST(LLVMTypeAnalyzer_VariableType, MultipleNestedLoopsWithTypeChange) auto outerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(outerEnd); - ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown); + ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown); } TEST(LLVMTypeAnalyzer_VariableType, MultipleNestedLoopsWithTypeChangeButTypeReset) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; // Outer loop begin auto outerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); @@ -1829,16 +1716,14 @@ TEST(LLVMTypeAnalyzer_VariableType, MultipleNestedLoopsWithTypeChangeButTypeRese auto outerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(outerEnd); - ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); + ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); } TEST(LLVMTypeAnalyzer_VariableType, SameTypeIfElseInLoopWithTypeChange) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; // Outer loop begin auto outerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); @@ -1878,7 +1763,7 @@ TEST(LLVMTypeAnalyzer_VariableType, SameTypeIfElseInLoopWithTypeChange) list.addInstruction(funcCall); // The type always changes to string - ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown); + ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown); } // TODO: Handle cross-variable dependencies diff --git a/test/llvm/type_analyzer/variabletypeafterbranch_test.cpp b/test/llvm/type_analyzer/variabletypeafterbranch_test.cpp index 8fcf5fc0f..dc3db5153 100644 --- a/test/llvm/type_analyzer/variabletypeafterbranch_test.cpp +++ b/test/llvm/type_analyzer/variabletypeafterbranch_test.cpp @@ -1,6 +1,5 @@ #include #include -#include #include #include #include @@ -34,14 +33,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, NullVariable) TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, NullStartInstruction) { LLVMTypeAnalyzer analyzer; - LLVMVariablePtr varPtr; - ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, nullptr, Compiler::StaticType::Number), Compiler::StaticType::Number); + Variable var("", ""); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, nullptr, Compiler::StaticType::Number), Compiler::StaticType::Number); } TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, EmptyLoop) { LLVMTypeAnalyzer analyzer; - LLVMVariablePtr varPtr; + Variable var("", ""); LLVMInstructionList list; auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); @@ -50,13 +49,13 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, EmptyLoop) auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); } TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, EmptyIfStatement) { LLVMTypeAnalyzer analyzer; - LLVMVariablePtr varPtr; + Variable var("", ""); LLVMInstructionList list; auto start = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); @@ -65,13 +64,13 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, EmptyIfStatement) auto end = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); list.addInstruction(end); - ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); } TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, EmptyIfElseStatement_IfBranch) { LLVMTypeAnalyzer analyzer; - LLVMVariablePtr varPtr; + Variable var("", ""); LLVMInstructionList list; auto start = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); @@ -83,13 +82,13 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, EmptyIfElseStatement_IfBranch) auto end = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); list.addInstruction(end); - ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); } TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, EmptyIfElseStatement_ElseBranch) { LLVMTypeAnalyzer analyzer; - LLVMVariablePtr varPtr; + Variable var("", ""); LLVMInstructionList list; auto start = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); @@ -101,13 +100,13 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, EmptyIfElseStatement_ElseBranch) auto end = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); list.addInstruction(end); - ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, elseStart.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, elseStart.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); } TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, EmptyLoopUnknownType) { LLVMTypeAnalyzer analyzer; - LLVMVariablePtr varPtr; + Variable var("", ""); LLVMInstructionList list; auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); @@ -116,14 +115,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, EmptyLoopUnknownType) auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Unknown), Compiler::StaticType::Unknown); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::Unknown), Compiler::StaticType::Unknown); } TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, NoWriteOperations) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; + Variable var("", ""); auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); list.addInstruction(start); @@ -134,16 +133,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, NoWriteOperations) auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); } TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteSameTypeNumber) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); list.addInstruction(start); @@ -157,16 +154,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteSameTypeNumber) auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); } TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteSameTypeBool) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); list.addInstruction(start); @@ -180,16 +175,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteSameTypeBool) auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Bool), Compiler::StaticType::Bool); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::Bool), Compiler::StaticType::Bool); } TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteSameTypeString) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); list.addInstruction(start); @@ -203,16 +196,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteSameTypeString) auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::String), Compiler::StaticType::String); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::String), Compiler::StaticType::String); } TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteStringOptimization) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); list.addInstruction(start); @@ -227,17 +218,15 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteStringOptimization) list.addInstruction(end); // Although string is assigned, it's constant and represents a number - ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); } TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteMultipleVariables) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var1("", ""); Variable var2("", ""); - varPtr.var = &var1; auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); list.addInstruction(start); @@ -259,16 +248,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteMultipleVariables) auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&var1, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); } TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteFromUnknownType) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); list.addInstruction(start); @@ -282,16 +269,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteFromUnknownType) auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown); } TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteToUnknownType) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); list.addInstruction(start); @@ -305,16 +290,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteToUnknownType) auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Unknown), Compiler::StaticType::Number); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::Unknown), Compiler::StaticType::Number); } TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteUnknownToUnknownType) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); list.addInstruction(start); @@ -328,16 +311,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteUnknownToUnknownType) auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Unknown), Compiler::StaticType::Unknown); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::Unknown), Compiler::StaticType::Unknown); } TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteDifferentTypeNumberToString) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); list.addInstruction(start); @@ -351,16 +332,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteDifferentTypeNumberToS auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::String); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::Number), Compiler::StaticType::String); } TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteDifferentTypeStringToNumber) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); list.addInstruction(start); @@ -374,16 +353,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteDifferentTypeStringToN auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::String), Compiler::StaticType::Number); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::String), Compiler::StaticType::Number); } TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteDifferentTypeNumberToBool) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); list.addInstruction(start); @@ -397,16 +374,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteDifferentTypeNumberToB auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Bool); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Bool); } TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteDifferentTypeBoolToNumber) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); list.addInstruction(start); @@ -420,16 +395,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteDifferentTypeBoolToNum auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Bool), Compiler::StaticType::Number); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::Bool), Compiler::StaticType::Number); } TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteDifferentTypeBoolToString) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); list.addInstruction(start); @@ -443,16 +416,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteDifferentTypeBoolToStr auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Bool), Compiler::StaticType::String); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::Bool), Compiler::StaticType::String); } TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteDifferentTypeStringToBool) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); list.addInstruction(start); @@ -466,16 +437,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteDifferentTypeStringToB auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::String), Compiler::StaticType::Bool); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::String), Compiler::StaticType::Bool); } TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteSameType_IfStatement) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; auto start = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); list.addInstruction(start); @@ -489,16 +458,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteSameType_IfStatement) auto end = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); list.addInstruction(end); - ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); } TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteDifferentType_IfStatement) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; auto start = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); list.addInstruction(start); @@ -512,16 +479,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteDifferentType_IfStatem auto end = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); list.addInstruction(end); - ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::String), Compiler::StaticType::Number); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::String), Compiler::StaticType::Number); } TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesSameTypeNumber) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); list.addInstruction(start); @@ -544,16 +509,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesSameTypeNumber) list.addInstruction(end); // Should return false because final assignment is compatible with pre-loop Number type - ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); } TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesSameTypeString) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); list.addInstruction(start); @@ -576,16 +539,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesSameTypeString) list.addInstruction(end); // Should return false because final assignment is compatible with pre-loop String type - ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::String), Compiler::StaticType::String); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::String), Compiler::StaticType::String); } TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesSameTypeUnknown) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); list.addInstruction(start); @@ -608,16 +569,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesSameTypeUnknown) list.addInstruction(end); // Should return false because final assignment is compatible with pre-loop String type - ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::String), Compiler::StaticType::String); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::String), Compiler::StaticType::String); } TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesWithStringOptimization) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); list.addInstruction(start); @@ -640,16 +599,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesWithStringOptimizat list.addInstruction(end); // Should return false because final assignment is optimized to Number type - ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); } TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesNumberToString) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); list.addInstruction(start); @@ -672,16 +629,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesNumberToString) list.addInstruction(end); // Should return true because final assignment is incompatible with pre-loop Number type - ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::String); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::Number), Compiler::StaticType::String); } TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesBoolToNumber) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); list.addInstruction(start); @@ -703,16 +658,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesBoolToNumber) auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Bool), Compiler::StaticType::Number); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::Bool), Compiler::StaticType::Number); } TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesBoolToString) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); list.addInstruction(start); @@ -734,16 +687,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesBoolToString) auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Bool), Compiler::StaticType::String); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::Bool), Compiler::StaticType::String); } TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesSameType_IfStatement) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; auto start = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); list.addInstruction(start); @@ -766,16 +717,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesSameType_IfStatemen list.addInstruction(end); // Should return false because final assignment is compatible with Number type - ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); } TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesSameType_IfBranch) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; auto start = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); list.addInstruction(start); @@ -808,16 +757,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesSameType_IfBranch) list.addInstruction(end); // Should return false because final assignment is compatible with Number type - ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); } TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesSameType_ElseBranch) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; auto start = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); list.addInstruction(start); @@ -850,16 +797,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesSameType_ElseBranch list.addInstruction(end); // Should return false because final assignment is compatible with Number type - ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, elseStart.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, elseStart.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); } TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesDifferentTypes_IfStatement) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; auto start = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); list.addInstruction(start); @@ -881,16 +826,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesDifferentTypes_IfSt auto end = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); list.addInstruction(end); - ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Bool), Compiler::StaticType::String); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::Bool), Compiler::StaticType::String); } TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesDifferentTypes_IfBranch) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; auto start = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); list.addInstruction(start); @@ -922,16 +865,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesDifferentTypes_IfBr auto end = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); list.addInstruction(end); - ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Bool), Compiler::StaticType::String); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::Bool), Compiler::StaticType::String); } TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesDifferentTypes_ElseBranch) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; auto start = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); list.addInstruction(start); @@ -963,16 +904,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesDifferentTypes_Else auto end = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); list.addInstruction(end); - ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, elseStart.get(), Compiler::StaticType::Bool), Compiler::StaticType::String); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, elseStart.get(), Compiler::StaticType::Bool), Compiler::StaticType::String); } TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, IfStatementInLoop_TypeChangeInIfBranch) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); list.addInstruction(start); @@ -1004,16 +943,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, IfStatementInLoop_TypeChangeInIfB list.addInstruction(end); // Returns unknown type because the type-changing branch might or might not run - ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown); } TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, IfStatementInLoop_TypeChangeInElseBranch) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); list.addInstruction(start); @@ -1045,16 +982,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, IfStatementInLoop_TypeChangeInEls list.addInstruction(end); // Returns unknown type because the type-changing branch might or might not run - ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown); } TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, IfStatementInLoop_IfElseWithoutTypeChange) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); list.addInstruction(start); @@ -1085,16 +1020,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, IfStatementInLoop_IfElseWithoutTy auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(end); - ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); } TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, NestedLoopWithTypeChange) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; // Outer loop begin auto outerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); @@ -1126,16 +1059,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, NestedLoopWithTypeChange) auto outerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(outerEnd); - ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, outerLoop.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, outerLoop.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown); } TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, NestedLoopWithoutTypeChange) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; // Outer loop begin auto outerLoop = std::make_shared(LLVMInstruction::Type::BeginWhileLoop, nullptr, false); @@ -1167,16 +1098,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, NestedLoopWithoutTypeChange) auto outerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(outerEnd); - ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, outerLoop.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, outerLoop.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); } TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, NestedLoopTypeChangesButResets) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; // Outer loop begin auto outerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); @@ -1215,16 +1144,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, NestedLoopTypeChangesButResets) auto outerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(outerEnd); - ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, outerLoop.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, outerLoop.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); } TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, NestedLoopTypeChangesAndDoesNotReset) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; // Outer loop begin auto outerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); @@ -1263,16 +1190,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, NestedLoopTypeChangesAndDoesNotRe auto outerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(outerEnd); - ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, outerLoop.get(), Compiler::StaticType::Number), Compiler::StaticType::String); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, outerLoop.get(), Compiler::StaticType::Number), Compiler::StaticType::String); } TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, NestedLoopWithTypeChangeBeforeLoop) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; // Outer loop begin auto outerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatUntilLoop, nullptr, false); @@ -1305,16 +1230,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, NestedLoopWithTypeChangeBeforeLoo list.addInstruction(outerEnd); // Returns unknown type because loops can be skipped - ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, outerLoop.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, outerLoop.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown); } TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, IfStatementInLoopWithTypeChangeBeforeLoop_TypeChangeInIfBranch) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; // Outer loop begin auto outerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatUntilLoop, nullptr, false); @@ -1351,16 +1274,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, IfStatementInLoopWithTypeChangeBe list.addInstruction(outerEnd); // Returns unknown type because if statements can be skipped - ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, outerLoop.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, outerLoop.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown); } TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, IfStatementInLoopWithTypeChangeBeforeLoop_TypeChangeInElseBranch) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; // Outer loop begin auto outerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatUntilLoop, nullptr, false); @@ -1397,16 +1318,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, IfStatementInLoopWithTypeChangeBe list.addInstruction(outerEnd); // Returns unknown type because if statements can be skipped - ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, outerLoop.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, outerLoop.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown); } TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, IfStatementInLoopWithTypeChangeBeforeLoop_TypeChangeInBothBranches) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; // Outer loop begin auto outerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatUntilLoop, nullptr, false); @@ -1449,16 +1368,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, IfStatementInLoopWithTypeChangeBe list.addInstruction(outerEnd); // Returns number type because the type always changes to number - ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, outerLoop.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, outerLoop.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); } TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleNestedLoopsWithTypeChange) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; // Outer loop begin auto outerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); @@ -1505,16 +1422,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleNestedLoopsWithTypeChange auto outerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(outerEnd); - ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, outerLoop.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, outerLoop.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown); } TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleNestedLoopsWithTypeChangeButTypeReset) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; // Outer loop begin auto outerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); @@ -1561,16 +1476,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleNestedLoopsWithTypeChange auto outerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); list.addInstruction(outerEnd); - ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, outerLoop.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, outerLoop.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); } TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleNestedIfStatementsWithTypeChange_IfBranch) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; // Outer if statement begin auto outerIf = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); @@ -1628,16 +1541,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleNestedIfStatementsWithTyp auto outerEnd = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); list.addInstruction(outerEnd); - ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, outerIf.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, outerIf.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown); } TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleNestedIfStatementsWithTypeChange_ElseBranch) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; // Outer if statement begin auto outerIf = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); @@ -1695,16 +1606,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleNestedIfStatementsWithTyp auto outerEnd = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); list.addInstruction(outerEnd); - ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, outerIf.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, outerIf.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown); } TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleNestedIfStatementsWithoutTypeChange) { LLVMTypeAnalyzer analyzer; LLVMInstructionList list; - LLVMVariablePtr varPtr; Variable var("", ""); - varPtr.var = &var; // Outer if statement begin auto outerIf = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); @@ -1762,7 +1671,7 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleNestedIfStatementsWithout auto outerEnd = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); list.addInstruction(outerEnd); - ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, outerIf.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); + ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, outerIf.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); } // TODO: Handle cross-variable dependencies From e8b26f5f2c66d3c29b13eb705d121ac23fe85f65 Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Sat, 26 Jul 2025 13:13:05 +0200 Subject: [PATCH 34/79] Revert "LLVMCodeBuilder: Store variable pointer in LLVMVariablePtr" This reverts commit b419577f4b41c74596f9408cc5440e1ba6f15f5a. --- src/engine/internal/llvm/llvmcodebuilder.cpp | 8 ++------ src/engine/internal/llvm/llvmvariableptr.h | 1 - 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/engine/internal/llvm/llvmcodebuilder.cpp b/src/engine/internal/llvm/llvmcodebuilder.cpp index f39ad6653..b61a477b3 100644 --- a/src/engine/internal/llvm/llvmcodebuilder.cpp +++ b/src/engine/internal/llvm/llvmcodebuilder.cpp @@ -1448,10 +1448,8 @@ CompilerValue *LLVMCodeBuilder::addVariableValue(Variable *variable) auto ins = std::make_shared(LLVMInstruction::Type::ReadVariable, currentLoopScope(), m_loopCondition); ins->workVariable = variable; - if (m_variablePtrs.find(variable) == m_variablePtrs.cend()) { + if (m_variablePtrs.find(variable) == m_variablePtrs.cend()) m_variablePtrs[variable] = LLVMVariablePtr(); - m_variablePtrs[variable].var = variable; - } auto ret = std::make_shared(Compiler::StaticType::Unknown); ret->isRawValue = false; @@ -1733,10 +1731,8 @@ void LLVMCodeBuilder::createVariableWrite(Variable *variable, CompilerValue *val ins.workVariable = variable; createOp(ins, Compiler::StaticType::Void, Compiler::StaticType::Unknown, { value }); - if (m_variablePtrs.find(variable) == m_variablePtrs.cend()) { + if (m_variablePtrs.find(variable) == m_variablePtrs.cend()) m_variablePtrs[variable] = LLVMVariablePtr(); - m_variablePtrs[variable].var = variable; - } if (m_loopScope >= 0) { auto scope = m_loopScopes[m_loopScope]; diff --git a/src/engine/internal/llvm/llvmvariableptr.h b/src/engine/internal/llvm/llvmvariableptr.h index b6da2a30c..9907a5aa8 100644 --- a/src/engine/internal/llvm/llvmvariableptr.h +++ b/src/engine/internal/llvm/llvmvariableptr.h @@ -20,7 +20,6 @@ class LLVMInstruction; struct LLVMVariablePtr { - Variable *var = nullptr; llvm::Value *stackPtr = nullptr; llvm::Value *heapPtr = nullptr; Compiler::StaticType type = Compiler::StaticType::Unknown; From e89f882967d3397b2bbe08c0d3a519b8f079cc03 Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Sat, 26 Jul 2025 13:32:25 +0200 Subject: [PATCH 35/79] LLVMTypeAnalyzer: Handle cross-variable dependencies --- src/engine/internal/llvm/llvmtypeanalyzer.cpp | 100 ++- src/engine/internal/llvm/llvmtypeanalyzer.h | 14 +- test/llvm/type_analyzer/variabletype_test.cpp | 388 ++++++++++- .../variabletypeafterbranch_test.cpp | 616 +++++++++++++++++- 4 files changed, 1091 insertions(+), 27 deletions(-) diff --git a/src/engine/internal/llvm/llvmtypeanalyzer.cpp b/src/engine/internal/llvm/llvmtypeanalyzer.cpp index fa295e6be..5072eb22d 100644 --- a/src/engine/internal/llvm/llvmtypeanalyzer.cpp +++ b/src/engine/internal/llvm/llvmtypeanalyzer.cpp @@ -9,10 +9,39 @@ static const std::unordered_set BEGIN_LOOP_INSTRUCTIONS = { LLVMInstruction::Type::BeginRepeatLoop, LLVMInstruction::Type::BeginWhileLoop, LLVMInstruction::Type::BeginRepeatUntilLoop }; Compiler::StaticType LLVMTypeAnalyzer::variableType(Variable *var, LLVMInstruction *pos, Compiler::StaticType previousType) const +{ + InstructionSet visitedInstructions; + return variableType(var, pos, previousType, visitedInstructions); +} + +Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranch(Variable *var, LLVMInstruction *start, Compiler::StaticType previousType) const +{ + InstructionSet visitedInstructions; + return variableTypeAfterBranch(var, start, previousType, visitedInstructions); +} + +Compiler::StaticType LLVMTypeAnalyzer::variableType(Variable *var, LLVMInstruction *pos, Compiler::StaticType previousType, InstructionSet &visitedInstructions) const { if (!var || !pos) return Compiler::StaticType::Unknown; + /* + * If the given instruction has already been processed, + * it means there's a case like this: + * x = x + * + * or this: + * x = y + * ... + * y = x + */ + if (visitedInstructions.find(pos) != visitedInstructions.cend()) { + // Circular dependencies are rare (and bad) so don't optimize them + return Compiler::StaticType::Unknown; + } + + visitedInstructions.insert(pos); + // Check the last write operation before the instruction LLVMInstruction *ins = pos; LLVMInstruction *write = nullptr; @@ -35,7 +64,7 @@ Compiler::StaticType LLVMTypeAnalyzer::variableType(Variable *var, LLVMInstructi firstElseBranch = ins; ins = skipBranch(ins); continue; - } else if (isVariableWrite(ins, var)) { + } else if (isVariableWrite(ins, var) && !isWriteNoOp(ins)) { if (level <= 0) { // ignore nested branches (they're handled by the branch analyzer) write = ins; break; @@ -50,14 +79,14 @@ Compiler::StaticType LLVMTypeAnalyzer::variableType(Variable *var, LLVMInstructi bool ignoreWriteAfterPos = (isIfStart(firstBranch) && firstBranch == ourBranch); if (write) - previousType = writeValueType(write); // write operation overrides previous type + previousType = writeValueType(write, visitedInstructions); // write operation overrides previous type Compiler::StaticType firstBranchType = previousType; Compiler::StaticType elseBranchType = previousType; if (!ignoreWriteAfterPos) { - firstBranchType = variableTypeAfterBranch(var, firstBranch, previousType); - elseBranchType = variableTypeAfterBranch(var, firstElseBranch, previousType); + firstBranchType = variableTypeAfterBranch(var, firstBranch, previousType, visitedInstructions); + elseBranchType = variableTypeAfterBranch(var, firstElseBranch, previousType, visitedInstructions); } if (typesMatch(firstBranchType, elseBranchType)) @@ -66,14 +95,14 @@ Compiler::StaticType LLVMTypeAnalyzer::variableType(Variable *var, LLVMInstructi return Compiler::StaticType::Unknown; } else if (write) { // There wasn't any branch found, so we can just check the last write operation - return writeValueType(write); + return writeValueType(write, visitedInstructions); } // No write operation found return previousType; } -Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranch(Variable *var, LLVMInstruction *start, Compiler::StaticType previousType) const +Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranch(Variable *var, LLVMInstruction *start, Compiler::StaticType previousType, InstructionSet &visitedInstructions) const { if (!var || !start) return previousType; @@ -102,10 +131,10 @@ Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranch(Variable *var, LL // Process the branch from end bool write = false; // only used internally (the compiler doesn't need this) - return variableTypeAfterBranchFromEnd(var, ins, previousType, write); + return variableTypeAfterBranchFromEnd(var, ins, previousType, write, visitedInstructions); } -Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranchFromEnd(Variable *var, LLVMInstruction *end, Compiler::StaticType previousType, bool &write) const +Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranchFromEnd(Variable *var, LLVMInstruction *end, Compiler::StaticType previousType, bool &write, InstructionSet &visitedInstructions) const { // Find the last write instruction LLVMInstruction *ins = end->previous; @@ -114,7 +143,7 @@ Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranchFromEnd(Variable * while (ins && !isLoopStart(ins) && !isIfStart(ins)) { if (isLoopEnd(ins) || isIfEnd(ins) || isElse(ins)) { // Process the nested loop or if statement - Compiler::StaticType ret = variableTypeAfterBranchFromEnd(var, ins, previousType, write); + Compiler::StaticType ret = variableTypeAfterBranchFromEnd(var, ins, previousType, write, visitedInstructions); if (typesMatch(ret, previousType)) { if (write) @@ -126,7 +155,7 @@ Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranchFromEnd(Variable * if (isElse(ins)) { // Process if branch (the else branch is already processed) - ret = variableTypeAfterBranchFromEnd(var, ins, previousType, write); + ret = variableTypeAfterBranchFromEnd(var, ins, previousType, write, visitedInstructions); if (typesMatch(ret, previousType)) { if (write) { @@ -140,9 +169,9 @@ Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranchFromEnd(Variable * ins = skipBranch(ins); } - } else if (isVariableWrite(ins, var)) { + } else if (isVariableWrite(ins, var) && !isWriteNoOp(ins)) { // Variable write instruction - Compiler::StaticType writeType = writeValueType(ins); + Compiler::StaticType writeType = writeValueType(ins, visitedInstructions); write = true; if (typesMatch(writeType, previousType)) @@ -208,6 +237,11 @@ bool LLVMTypeAnalyzer::isIfEnd(LLVMInstruction *ins) const return (ins->type == LLVMInstruction::Type::EndIf); } +bool LLVMTypeAnalyzer::isVariableRead(LLVMInstruction *ins) const +{ + return (ins->type == LLVMInstruction::Type::ReadVariable); +} + bool LLVMTypeAnalyzer::isVariableWrite(LLVMInstruction *ins, Variable *var) const { return (ins->type == LLVMInstruction::Type::WriteVariable && ins->workVariable == var); @@ -227,12 +261,40 @@ Compiler::StaticType LLVMTypeAnalyzer::optimizeRegisterType(LLVMRegister *reg) c return ret; } -Compiler::StaticType LLVMTypeAnalyzer::writeValueType(LLVMInstruction *ins) const +bool LLVMTypeAnalyzer::isWriteNoOp(LLVMInstruction *ins) const { assert(ins); assert(!ins->args.empty()); const auto arg = ins->args.back().second; // value is always the last argument in variable/list write instructions - return optimizeRegisterType(arg); + + if (arg->instruction) { + // TODO: Handle list item + if (isVariableRead(arg->instruction.get())) { + // Self-assignment is a no-op + return (ins->workVariable == arg->instruction->workVariable); + } + } + + return false; +} + +Compiler::StaticType LLVMTypeAnalyzer::writeValueType(LLVMInstruction *ins, InstructionSet &visitedInstructions) const +{ + assert(ins); + assert(!ins->args.empty()); + const auto arg = ins->args.back().second; // value is always the last argument in variable/list write instructions + + if (arg->instruction) { + // TODO: Handle list item + if (isVariableRead(arg->instruction.get())) { + // If this is a variable read instruction, recursively get the variable type + return variableType(arg->instruction->workVariable, arg->instruction.get(), Compiler::StaticType::Unknown, visitedInstructions); + } else { + // TODO: Use the instruction return register + return optimizeRegisterType(arg); + } + } else + return optimizeRegisterType(arg); } bool LLVMTypeAnalyzer::typesMatch(Compiler::StaticType a, Compiler::StaticType b) const @@ -241,13 +303,7 @@ bool LLVMTypeAnalyzer::typesMatch(Compiler::StaticType a, Compiler::StaticType b return (a == b) && (a != Compiler::StaticType::Unknown); } -bool LLVMTypeAnalyzer::writeTypesMatch(LLVMInstruction *ins, Compiler::StaticType expectedType) const +bool LLVMTypeAnalyzer::writeTypesMatch(LLVMInstruction *ins, Compiler::StaticType expectedType, InstructionSet &visitedInstructions) const { - // auto argIns = arg->instruction; - - // TODO: Handle cross-variable dependencies - /*if (argIns && (argIns->type == LLVMInstruction::Type::ReadVariable || argIns->type == LLVMInstruction::Type::GetListItem)) - return isVarOrListTypeSafe(argIns.get(), expectedType, log, c);*/ - - return typesMatch(writeValueType(ins), expectedType); + return typesMatch(writeValueType(ins, visitedInstructions), expectedType); } diff --git a/src/engine/internal/llvm/llvmtypeanalyzer.h b/src/engine/internal/llvm/llvmtypeanalyzer.h index 3cb4cc4e1..ac32565b4 100644 --- a/src/engine/internal/llvm/llvmtypeanalyzer.h +++ b/src/engine/internal/llvm/llvmtypeanalyzer.h @@ -15,19 +15,27 @@ class LLVMTypeAnalyzer Compiler::StaticType variableTypeAfterBranch(Variable *var, LLVMInstruction *start, Compiler::StaticType previousType) const; private: - Compiler::StaticType variableTypeAfterBranchFromEnd(Variable *var, LLVMInstruction *end, Compiler::StaticType previousType, bool &write) const; + using InstructionSet = std::unordered_set; + + Compiler::StaticType variableType(Variable *var, LLVMInstruction *pos, Compiler::StaticType previousType, InstructionSet &visitedInstructions) const; + Compiler::StaticType variableTypeAfterBranch(Variable *var, LLVMInstruction *start, Compiler::StaticType previousType, InstructionSet &visitedInstructions) const; + Compiler::StaticType variableTypeAfterBranchFromEnd(Variable *var, LLVMInstruction *end, Compiler::StaticType previousType, bool &write, InstructionSet &visitedInstructions) const; + LLVMInstruction *skipBranch(LLVMInstruction *pos) const; + bool isLoopStart(LLVMInstruction *ins) const; bool isLoopEnd(LLVMInstruction *ins) const; bool isIfStart(LLVMInstruction *ins) const; bool isElse(LLVMInstruction *ins) const; bool isIfEnd(LLVMInstruction *ins) const; + bool isVariableRead(LLVMInstruction *ins) const; bool isVariableWrite(LLVMInstruction *ins, Variable *var) const; Compiler::StaticType optimizeRegisterType(LLVMRegister *reg) const; - Compiler::StaticType writeValueType(LLVMInstruction *ins) const; + bool isWriteNoOp(LLVMInstruction *ins) const; + Compiler::StaticType writeValueType(LLVMInstruction *ins, InstructionSet &visitedInstructions) const; bool typesMatch(Compiler::StaticType a, Compiler::StaticType b) const; - bool writeTypesMatch(LLVMInstruction *ins, Compiler::StaticType expectedType) const; + bool writeTypesMatch(LLVMInstruction *ins, Compiler::StaticType expectedType, InstructionSet &visitedInstructions) const; }; } // namespace libscratchcpp diff --git a/test/llvm/type_analyzer/variabletype_test.cpp b/test/llvm/type_analyzer/variabletype_test.cpp index 65037f605..0bba27bc3 100644 --- a/test/llvm/type_analyzer/variabletype_test.cpp +++ b/test/llvm/type_analyzer/variabletype_test.cpp @@ -1766,4 +1766,390 @@ TEST(LLVMTypeAnalyzer_VariableType, SameTypeIfElseInLoopWithTypeChange) ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown); } -// TODO: Handle cross-variable dependencies +TEST(LLVMTypeAnalyzer_VariableType, CrossVariableDependency_SimpleAssignment) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + Variable var1("", ""), var2("", ""); + + // First write: var2 = "test" (String type) + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::String, "test"); + setVar2->workVariable = &var2; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(setVar2); + + // Second write: var1 = var2 (cross-variable dependency) + auto readVar2 = std::make_shared(LLVMInstruction::Type::ReadVariable, nullptr, false); + list.addInstruction(readVar2); + readVar2->workVariable = &var2; + + LLVMRegister var2Value(Compiler::StaticType::Unknown); + var2Value.isRawValue = false; + var2Value.instruction = readVar2; + readVar2->functionReturnReg = &var2Value; + + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + setVar1->workVariable = &var1; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &var2Value }); + list.addInstruction(setVar1); + + // Query position after the assignment + auto queryPos = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(queryPos); + + // var1 should have String type due to cross-variable dependency + ASSERT_EQ(analyzer.variableType(&var1, queryPos.get(), Compiler::StaticType::Number), Compiler::StaticType::String); +} + +TEST(LLVMTypeAnalyzer_VariableType, CrossVariableDependency_TypeMismatch) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + Variable var1("", ""), var2("", ""); + + // First write: var2 = "test" (String type) + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::String, "test"); + setVar2->workVariable = &var2; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(setVar2); + + // Second write: var1 = var2 (cross-variable dependency with type mismatch) + auto readVar2 = std::make_shared(LLVMInstruction::Type::ReadVariable, nullptr, false); + list.addInstruction(readVar2); + readVar2->workVariable = &var2; + + LLVMRegister var2Value(Compiler::StaticType::Unknown); + var2Value.isRawValue = false; + var2Value.instruction = readVar2; + readVar2->functionReturnReg = &var2Value; + + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + setVar1->workVariable = &var1; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &var2Value }); + list.addInstruction(setVar1); + + // Query position after the assignment + auto queryPos = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(queryPos); + + // var1 should have String type (different from Number previousType) + ASSERT_EQ(analyzer.variableType(&var1, queryPos.get(), Compiler::StaticType::Number), Compiler::StaticType::String); +} + +TEST(LLVMTypeAnalyzer_VariableType, CrossVariableDependency_QueryBeforeAssignment) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + Variable var1("", ""), var2("", ""); + + // Query position before any assignments + auto queryPos = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(queryPos); + + // First write: var2 = "test" (String type) - after query position + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::String, "test"); + setVar2->workVariable = &var2; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(setVar2); + + // Second write: var1 = var2 (cross-variable dependency) - after query position + auto readVar2 = std::make_shared(LLVMInstruction::Type::ReadVariable, nullptr, false); + list.addInstruction(readVar2); + readVar2->workVariable = &var2; + + LLVMRegister var2Value(Compiler::StaticType::Unknown); + var2Value.isRawValue = false; + var2Value.instruction = readVar2; + readVar2->functionReturnReg = &var2Value; + + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + setVar1->workVariable = &var1; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &var2Value }); + list.addInstruction(setVar1); + + // var1 should have the previous type since assignments are after query position + ASSERT_EQ(analyzer.variableType(&var1, queryPos.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_VariableType, CrossVariableDependency_ChainedAssignments) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + Variable var1("", ""), var2("", ""), var3("", ""); + + // First write: var3 = 42 (Number type) + auto setVar3 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 42); + setVar3->workVariable = &var3; + setVar3->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(setVar3); + + // Second write: var2 = var3 (cross-variable dependency) + auto readVar3 = std::make_shared(LLVMInstruction::Type::ReadVariable, nullptr, false); + list.addInstruction(readVar3); + readVar3->workVariable = &var3; + + LLVMRegister var3Value(Compiler::StaticType::Unknown); + var3Value.isRawValue = false; + var3Value.instruction = readVar3; + readVar3->functionReturnReg = &var3Value; + + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + setVar2->workVariable = &var2; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &var3Value }); + list.addInstruction(setVar2); + + // Third write: var1 = var2 (chained cross-variable dependency) + auto readVar2 = std::make_shared(LLVMInstruction::Type::ReadVariable, nullptr, false); + list.addInstruction(readVar2); + readVar2->workVariable = &var2; + + LLVMRegister var2Value(Compiler::StaticType::Unknown); + var2Value.isRawValue = false; + var2Value.instruction = readVar2; + readVar2->functionReturnReg = &var2Value; + + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + setVar1->workVariable = &var1; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &var2Value }); + list.addInstruction(setVar1); + + // Query position after all assignments + auto queryPos = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(queryPos); + + // var1 should have Number type through the chain var1 = var2 = var3 = 42 + ASSERT_EQ(analyzer.variableType(&var1, queryPos.get(), Compiler::StaticType::Bool), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_VariableType, CrossVariableDependency_CircularReference) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + Variable var1("", ""), var2("", ""); + + // First write: var1 = var2 (circular dependency setup) + auto readVar2 = std::make_shared(LLVMInstruction::Type::ReadVariable, nullptr, false); + list.addInstruction(readVar2); + readVar2->workVariable = &var2; + + LLVMRegister var2Value(Compiler::StaticType::Unknown); + var2Value.isRawValue = false; + var2Value.instruction = readVar2; + readVar2->functionReturnReg = &var2Value; + + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + setVar1->workVariable = &var1; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &var2Value }); + list.addInstruction(setVar1); + + // Second write: var2 = var1 (completes circular dependency) + auto readVar1 = std::make_shared(LLVMInstruction::Type::ReadVariable, nullptr, false); + list.addInstruction(readVar1); + readVar1->workVariable = &var1; + + LLVMRegister var1Value(Compiler::StaticType::Unknown); + var1Value.isRawValue = false; + var1Value.instruction = readVar1; + readVar1->functionReturnReg = &var1Value; + + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + setVar2->workVariable = &var2; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &var1Value }); + list.addInstruction(setVar2); + + // Query position after circular assignments + auto queryPos = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(queryPos); + + // Should return Unknown due to circular dependency + ASSERT_EQ(analyzer.variableType(&var1, queryPos.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_VariableType, CrossVariableDependency_InIfStatement_QueryInside) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + Variable var1("", ""), var2("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + list.addInstruction(start); + + // First write: var2 = 3.14 (Number type) + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 3.14); + setVar2->workVariable = &var2; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(setVar2); + + // Second write: var1 = var2 (cross-variable dependency in if statement) + auto readVar2 = std::make_shared(LLVMInstruction::Type::ReadVariable, nullptr, false); + list.addInstruction(readVar2); + readVar2->workVariable = &var2; + + LLVMRegister var2Value(Compiler::StaticType::Unknown); + var2Value.isRawValue = false; + var2Value.instruction = readVar2; + readVar2->functionReturnReg = &var2Value; + + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + setVar1->workVariable = &var1; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &var2Value }); + list.addInstruction(setVar1); + + // Query position inside if statement after assignments + auto queryPos = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(queryPos); + + auto end = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + list.addInstruction(end); + + // var1 should have Number type from cross-variable dependency + ASSERT_EQ(analyzer.variableType(&var1, queryPos.get(), Compiler::StaticType::String), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_VariableType, CrossVariableDependency_InIfStatement_QueryOutside) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + Variable var1("", ""), var2("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + list.addInstruction(start); + + // First write: var2 = 3.14 (Number type) + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 3.14); + setVar2->workVariable = &var2; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(setVar2); + + // Second write: var1 = var2 (cross-variable dependency in if statement) + auto readVar2 = std::make_shared(LLVMInstruction::Type::ReadVariable, nullptr, false); + list.addInstruction(readVar2); + readVar2->workVariable = &var2; + + LLVMRegister var2Value(Compiler::StaticType::Unknown); + var2Value.isRawValue = false; + var2Value.instruction = readVar2; + readVar2->functionReturnReg = &var2Value; + + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + setVar1->workVariable = &var1; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &var2Value }); + list.addInstruction(setVar1); + + auto end = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + list.addInstruction(end); + + // Query position outside if statement after it ends + auto queryPos = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(queryPos); + + // var1 should return Unknown because the write is inside an if statement that may not execute + ASSERT_EQ(analyzer.variableType(&var1, queryPos.get(), Compiler::StaticType::String), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_VariableType, SelfAssignment) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + Variable var1("", ""); + + // No-op: var1 = var1 + auto readVar1 = std::make_shared(LLVMInstruction::Type::ReadVariable, nullptr, false); + list.addInstruction(readVar1); + readVar1->workVariable = &var1; + + LLVMRegister var1Value(Compiler::StaticType::Unknown); + var1Value.isRawValue = false; + var1Value.instruction = readVar1; + readVar1->functionReturnReg = &var1Value; + + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + setVar1->workVariable = &var1; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &var1Value }); + list.addInstruction(setVar1); + + // Query position after self-assignment + auto queryPos = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(queryPos); + + // Should return the previous type because the write is a no-op + ASSERT_EQ(analyzer.variableType(&var1, queryPos.get(), Compiler::StaticType::String), Compiler::StaticType::String); +} + +TEST(LLVMTypeAnalyzer_VariableType, SelfAssignmentWithTypeChange_Before) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + Variable var1("", ""); + + // First write: var1 = 3.14 (Number type) + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 3.14); + setVar1->workVariable = &var1; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(setVar1); + + // No-op: var1 = var1 + auto readVar1 = std::make_shared(LLVMInstruction::Type::ReadVariable, nullptr, false); + list.addInstruction(readVar1); + readVar1->workVariable = &var1; + + LLVMRegister var1Value(Compiler::StaticType::Unknown); + var1Value.isRawValue = false; + var1Value.instruction = readVar1; + readVar1->functionReturnReg = &var1Value; + + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + setVar2->workVariable = &var1; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &var1Value }); + list.addInstruction(setVar2); + + // Query position after self-assignment + auto queryPos = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(queryPos); + + // Should return the previous type (number) because the write is a no-op + ASSERT_EQ(analyzer.variableType(&var1, queryPos.get(), Compiler::StaticType::String), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_VariableType, SelfAssignmentWithTypeChange_After) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + Variable var1("", ""); + + // No-op: var1 = var1 + auto readVar1 = std::make_shared(LLVMInstruction::Type::ReadVariable, nullptr, false); + list.addInstruction(readVar1); + readVar1->workVariable = &var1; + + LLVMRegister var1Value(Compiler::StaticType::Unknown); + var1Value.isRawValue = false; + var1Value.instruction = readVar1; + readVar1->functionReturnReg = &var1Value; + + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + setVar1->workVariable = &var1; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &var1Value }); + list.addInstruction(setVar1); + + // var1 = 3.14 (Number type) + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::Number, 3.14); + setVar2->workVariable = &var1; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + list.addInstruction(setVar2); + + // Query position after real assignment + auto queryPos = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(queryPos); + + // Should return number because it's assigned after the no-op + ASSERT_EQ(analyzer.variableType(&var1, queryPos.get(), Compiler::StaticType::String), Compiler::StaticType::Number); +} diff --git a/test/llvm/type_analyzer/variabletypeafterbranch_test.cpp b/test/llvm/type_analyzer/variabletypeafterbranch_test.cpp index dc3db5153..dc30be450 100644 --- a/test/llvm/type_analyzer/variabletypeafterbranch_test.cpp +++ b/test/llvm/type_analyzer/variabletypeafterbranch_test.cpp @@ -1674,4 +1674,618 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleNestedIfStatementsWithout ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, outerIf.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); } -// TODO: Handle cross-variable dependencies +TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, CrossVariableDependency_SimpleAssignment) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + Variable var1("", ""), var2("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(start); + + // First write: var2 = "test" (String type) + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::String, "test"); + setVar2->workVariable = &var2; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(setVar2); + + // Second write: var1 = var2 (cross-variable dependency) + auto readVar2 = std::make_shared(LLVMInstruction::Type::ReadVariable, nullptr, false); + list.addInstruction(readVar2); + readVar2->workVariable = &var2; + + LLVMRegister var2Value(Compiler::StaticType::Unknown); + var2Value.isRawValue = false; + var2Value.instruction = readVar2; + readVar2->functionReturnReg = &var2Value; + + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + setVar1->workVariable = &var1; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &var2Value }); + list.addInstruction(setVar1); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(end); + + // var1 should have String type due to cross-variable dependency + ASSERT_EQ(analyzer.variableTypeAfterBranch(&var1, start.get(), Compiler::StaticType::String), Compiler::StaticType::String); +} + +TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, CrossVariableDependency_TypeMismatch) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + Variable var1("", ""), var2("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(start); + + // First write: var2 = "test" (String type) + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::String, "test"); + setVar2->workVariable = &var2; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(setVar2); + + // Second write: var1 = var2 (cross-variable dependency with type mismatch) + auto readVar2 = std::make_shared(LLVMInstruction::Type::ReadVariable, nullptr, false); + list.addInstruction(readVar2); + readVar2->workVariable = &var2; + + LLVMRegister var2Value(Compiler::StaticType::Unknown); + var2Value.isRawValue = false; + var2Value.instruction = readVar2; + readVar2->functionReturnReg = &var2Value; + + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + setVar1->workVariable = &var1; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &var2Value }); + list.addInstruction(setVar1); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(end); + + // var1 should have String type (incompatible with Number pre-loop type) + ASSERT_EQ(analyzer.variableTypeAfterBranch(&var1, start.get(), Compiler::StaticType::Number), Compiler::StaticType::String); +} + +TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, CrossVariableDependency_SimpleAssignmentBeforeTypeChange) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + Variable var1("", ""), var2("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(start); + + // var1 = var2 + auto readVar2 = std::make_shared(LLVMInstruction::Type::ReadVariable, nullptr, false); + list.addInstruction(readVar2); + readVar2->workVariable = &var2; + + LLVMRegister var2Value(Compiler::StaticType::Unknown); + var2Value.isRawValue = false; + var2Value.instruction = readVar2; + readVar2->functionReturnReg = &var2Value; + + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + setVar1->workVariable = &var1; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &var2Value }); + list.addInstruction(setVar1); + + // var2 = 5.2 (type resets to number) + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::Number, 5.2); + setVar2->workVariable = &var2; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + list.addInstruction(setVar2); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(end); + + // Although the type of var2 is changed to number, it's unknown before the first iteration + ASSERT_EQ(analyzer.variableTypeAfterBranch(&var1, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, CrossVariableDependency_ChainedAssignments) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + Variable var1("", ""), var2("", ""), var3("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(start); + + // First write: var3 = 42 (Number type) + auto setVar3 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 42); + setVar3->workVariable = &var3; + setVar3->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(setVar3); + + // Second write: var2 = var3 (cross-variable dependency) + auto readVar3 = std::make_shared(LLVMInstruction::Type::ReadVariable, nullptr, false); + list.addInstruction(readVar3); + readVar3->workVariable = &var3; + + LLVMRegister var3Value(Compiler::StaticType::Unknown); + var3Value.isRawValue = false; + var3Value.instruction = readVar3; + readVar3->functionReturnReg = &var3Value; + + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + setVar2->workVariable = &var2; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &var3Value }); + list.addInstruction(setVar2); + + // Third write: var1 = var2 (chained cross-variable dependency) + auto readVar2 = std::make_shared(LLVMInstruction::Type::ReadVariable, nullptr, false); + list.addInstruction(readVar2); + readVar2->workVariable = &var2; + + LLVMRegister var2Value(Compiler::StaticType::Unknown); + var2Value.isRawValue = false; + var2Value.instruction = readVar2; + readVar2->functionReturnReg = &var2Value; + + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + setVar1->workVariable = &var1; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &var2Value }); + list.addInstruction(setVar1); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(end); + + // var1 should have Number type through the chain var1 = var2 = var3 = 42 + ASSERT_EQ(analyzer.variableTypeAfterBranch(&var1, start.get(), Compiler::StaticType::Bool), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, CrossVariableDependency_CircularReference) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + Variable var1("", ""), var2("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(start); + + // First write: var1 = var2 (circular dependency setup) + auto readVar2 = std::make_shared(LLVMInstruction::Type::ReadVariable, nullptr, false); + list.addInstruction(readVar2); + readVar2->workVariable = &var2; + + LLVMRegister var2Value(Compiler::StaticType::Unknown); + var2Value.isRawValue = false; + var2Value.instruction = readVar2; + readVar2->functionReturnReg = &var2Value; + + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + setVar1->workVariable = &var1; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &var2Value }); + list.addInstruction(setVar1); + + // Second write: var2 = var1 (completes circular dependency) + auto readVar1 = std::make_shared(LLVMInstruction::Type::ReadVariable, nullptr, false); + list.addInstruction(readVar1); + readVar1->workVariable = &var1; + + LLVMRegister var1Value(Compiler::StaticType::Unknown); + var1Value.isRawValue = false; + var1Value.instruction = readVar1; + readVar1->functionReturnReg = &var1Value; + + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + setVar2->workVariable = &var2; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &var1Value }); + list.addInstruction(setVar2); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(end); + + // Should return Unknown due to circular dependency + ASSERT_EQ(analyzer.variableTypeAfterBranch(&var1, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, CrossVariableDependency_CircularReference_KnownTypes) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + Variable var1("", ""), var2("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(start); + + // var1 is a number + auto setupVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 42); + setupVar1->workVariable = &var1; + setupVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(setupVar1); + + // var2 is a number + auto setupVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::Number, 42); + setupVar2->workVariable = &var2; + setupVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + list.addInstruction(setupVar2); + + // First write: var1 = var2 (circular dependency setup) + auto readVar2 = std::make_shared(LLVMInstruction::Type::ReadVariable, nullptr, false); + list.addInstruction(readVar2); + readVar2->workVariable = &var2; + + LLVMRegister var2Value(Compiler::StaticType::Unknown); + var2Value.isRawValue = false; + var2Value.instruction = readVar2; + readVar2->functionReturnReg = &var2Value; + + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + setVar1->workVariable = &var1; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &var2Value }); + list.addInstruction(setVar1); + + // Second write: var2 = var1 (completes circular dependency) + auto readVar1 = std::make_shared(LLVMInstruction::Type::ReadVariable, nullptr, false); + list.addInstruction(readVar1); + readVar1->workVariable = &var1; + + LLVMRegister var1Value(Compiler::StaticType::Unknown); + var1Value.isRawValue = false; + var1Value.instruction = readVar1; + readVar1->functionReturnReg = &var1Value; + + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + setVar2->workVariable = &var2; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &var1Value }); + list.addInstruction(setVar2); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(end); + + // Although there is a circular dependency, the types of both variables are known + ASSERT_EQ(analyzer.variableTypeAfterBranch(&var1, start.get(), Compiler::StaticType::String), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, CrossVariableDependency_CircularReference_FirstAssignedTypeKnown) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + Variable var1("", ""), var2("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(start); + + // var1: unknown type + + // var2 is a number + auto setupVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::Number, 42); + setupVar2->workVariable = &var2; + setupVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + list.addInstruction(setupVar2); + + // First write: var1 = var2 (circular dependency setup) + auto readVar2 = std::make_shared(LLVMInstruction::Type::ReadVariable, nullptr, false); + list.addInstruction(readVar2); + readVar2->workVariable = &var2; + + LLVMRegister var2Value(Compiler::StaticType::Unknown); + var2Value.isRawValue = false; + var2Value.instruction = readVar2; + readVar2->functionReturnReg = &var2Value; + + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + setVar1->workVariable = &var1; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &var2Value }); + list.addInstruction(setVar1); + + // Second write: var2 = var1 (completes circular dependency) + auto readVar1 = std::make_shared(LLVMInstruction::Type::ReadVariable, nullptr, false); + list.addInstruction(readVar1); + readVar1->workVariable = &var1; + + LLVMRegister var1Value(Compiler::StaticType::Unknown); + var1Value.isRawValue = false; + var1Value.instruction = readVar1; + readVar1->functionReturnReg = &var1Value; + + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + setVar2->workVariable = &var2; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &var1Value }); + list.addInstruction(setVar2); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(end); + + // Although there is a circular dependency, the type of var2 is known and this variable is assigned to var1 + ASSERT_EQ(analyzer.variableTypeAfterBranch(&var1, start.get(), Compiler::StaticType::String), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, CrossVariableDependency_CircularReference_AssignedTypeUnknown) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + Variable var1("", ""), var2("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(start); + + // var1 is a number + auto setupVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 42); + setupVar1->workVariable = &var1; + setupVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(setupVar1); + + // var2: unknown type + + // First write: var1 = var2 (circular dependency setup) + auto readVar2 = std::make_shared(LLVMInstruction::Type::ReadVariable, nullptr, false); + list.addInstruction(readVar2); + readVar2->workVariable = &var2; + + LLVMRegister var2Value(Compiler::StaticType::Unknown); + var2Value.isRawValue = false; + var2Value.instruction = readVar2; + readVar2->functionReturnReg = &var2Value; + + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + setVar1->workVariable = &var1; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &var2Value }); + list.addInstruction(setVar1); + + // Second write: var2 = var1 (completes circular dependency) + auto readVar1 = std::make_shared(LLVMInstruction::Type::ReadVariable, nullptr, false); + list.addInstruction(readVar1); + readVar1->workVariable = &var1; + + LLVMRegister var1Value(Compiler::StaticType::Unknown); + var1Value.isRawValue = false; + var1Value.instruction = readVar1; + readVar1->functionReturnReg = &var1Value; + + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + setVar2->workVariable = &var2; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &var1Value }); + list.addInstruction(setVar2); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(end); + + // The type of var2 is not known and this variable is assigned to var1 + ASSERT_EQ(analyzer.variableTypeAfterBranch(&var1, start.get(), Compiler::StaticType::String), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, CrossVariableDependency_ChainedCircularReference) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + Variable var1("", ""), var2("", ""), var3("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(start); + + // First write: var1 = var2 (circular dependency setup) + auto readVar2 = std::make_shared(LLVMInstruction::Type::ReadVariable, nullptr, false); + list.addInstruction(readVar2); + readVar2->workVariable = &var2; + + LLVMRegister var2Value(Compiler::StaticType::Unknown); + var2Value.isRawValue = false; + var2Value.instruction = readVar2; + readVar2->functionReturnReg = &var2Value; + + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + setVar1->workVariable = &var1; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &var2Value }); + list.addInstruction(setVar1); + + // Second write: var2 = var3 + auto readVar3 = std::make_shared(LLVMInstruction::Type::ReadVariable, nullptr, false); + list.addInstruction(readVar3); + readVar3->workVariable = &var3; + + LLVMRegister var3Value(Compiler::StaticType::Unknown); + var3Value.isRawValue = false; + var3Value.instruction = readVar3; + readVar3->functionReturnReg = &var3Value; + + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + setVar2->workVariable = &var2; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &var3Value }); + list.addInstruction(setVar2); + + // Third write: var3 = var1 (completes circular dependency) + auto readVar1 = std::make_shared(LLVMInstruction::Type::ReadVariable, nullptr, false); + list.addInstruction(readVar1); + readVar1->workVariable = &var1; + + LLVMRegister var1Value(Compiler::StaticType::Unknown); + var1Value.isRawValue = false; + var1Value.instruction = readVar1; + readVar1->functionReturnReg = &var1Value; + + auto setVar3 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + setVar3->workVariable = &var3; + setVar3->args.push_back({ Compiler::StaticType::Unknown, &var1Value }); + list.addInstruction(setVar3); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(end); + + // Should return Unknown due to circular dependency + ASSERT_EQ(analyzer.variableTypeAfterBranch(&var1, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, CrossVariableDependency_InIfStatement) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + Variable var1("", ""), var2("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + list.addInstruction(start); + + // First write: var2 = 3.14 (Number type) + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 3.14); + setVar2->workVariable = &var2; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(setVar2); + + // Second write: var1 = var2 (cross-variable dependency in if statement) + auto readVar2 = std::make_shared(LLVMInstruction::Type::ReadVariable, nullptr, false); + list.addInstruction(readVar2); + readVar2->workVariable = &var2; + + LLVMRegister var2Value(Compiler::StaticType::Unknown); + var2Value.isRawValue = false; + var2Value.instruction = readVar2; + readVar2->functionReturnReg = &var2Value; + + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + setVar1->workVariable = &var1; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &var2Value }); + list.addInstruction(setVar1); + + auto end = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + list.addInstruction(end); + + // var1 should have Number type from cross-variable dependency + ASSERT_EQ(analyzer.variableTypeAfterBranch(&var1, start.get(), Compiler::StaticType::String), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SelfAssignment) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + Variable var1("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(start); + + // Start if statement + auto ifStart = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + list.addInstruction(ifStart); + + // No-op: var1 = var1 + auto readVar1 = std::make_shared(LLVMInstruction::Type::ReadVariable, nullptr, false); + list.addInstruction(readVar1); + readVar1->workVariable = &var1; + + LLVMRegister var1Value(Compiler::StaticType::Unknown); + var1Value.isRawValue = false; + var1Value.instruction = readVar1; + readVar1->functionReturnReg = &var1Value; + + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + setVar1->workVariable = &var1; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &var1Value }); + list.addInstruction(setVar1); + + // End if statement + auto ifEnd = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + list.addInstruction(ifEnd); + + // End loop + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(end); + + // Should return the previous type because the write is a no-op + ASSERT_EQ(analyzer.variableTypeAfterBranch(&var1, start.get(), Compiler::StaticType::String), Compiler::StaticType::String); +} + +TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SelfAssignmentWithTypeChange_Before) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + Variable var1("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(start); + + // First write: var1 = 3.14 (Number type) + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 3.14); + setVar1->workVariable = &var1; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(setVar1); + + // Start if statement + auto ifStart = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + list.addInstruction(ifStart); + + // No-op: var1 = var1 + auto readVar1 = std::make_shared(LLVMInstruction::Type::ReadVariable, nullptr, false); + list.addInstruction(readVar1); + readVar1->workVariable = &var1; + + LLVMRegister var1Value(Compiler::StaticType::Unknown); + var1Value.isRawValue = false; + var1Value.instruction = readVar1; + readVar1->functionReturnReg = &var1Value; + + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + setVar2->workVariable = &var1; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &var1Value }); + list.addInstruction(setVar2); + + // End if statement + auto ifEnd = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + list.addInstruction(ifEnd); + + // End loop + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(end); + + // Should return the previous type (number) because the write is a no-op + ASSERT_EQ(analyzer.variableTypeAfterBranch(&var1, start.get(), Compiler::StaticType::String), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SelfAssignmentWithTypeChange_After) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + Variable var1("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(start); + + // Start if statement + auto ifStart = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + list.addInstruction(ifStart); + + // No-op: var1 = var1 + auto readVar1 = std::make_shared(LLVMInstruction::Type::ReadVariable, nullptr, false); + list.addInstruction(readVar1); + readVar1->workVariable = &var1; + + LLVMRegister var1Value(Compiler::StaticType::Unknown); + var1Value.isRawValue = false; + var1Value.instruction = readVar1; + readVar1->functionReturnReg = &var1Value; + + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + setVar1->workVariable = &var1; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &var1Value }); + list.addInstruction(setVar1); + + // End if statement + auto ifEnd = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + list.addInstruction(ifEnd); + + // var1 = 3.14 (Number type) + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::Number, 3.14); + setVar2->workVariable = &var1; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + list.addInstruction(setVar2); + + // End loop + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(end); + + // Should return number because it's assigned later in the loop + ASSERT_EQ(analyzer.variableTypeAfterBranch(&var1, start.get(), Compiler::StaticType::String), Compiler::StaticType::Number); +} From a76435b00b2be28ae7f84b3e4cdca59cb0d87242 Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Sat, 26 Jul 2025 14:13:56 +0200 Subject: [PATCH 36/79] LLVMTypeAnalyzer: Add test cases for reporters assigned to variables --- src/engine/internal/llvm/llvmtypeanalyzer.cpp | 2 +- test/llvm/type_analyzer/variabletype_test.cpp | 245 ++++++++++++++++++ .../variabletypeafterbranch_test.cpp | 224 ++++++++++++++++ 3 files changed, 470 insertions(+), 1 deletion(-) diff --git a/src/engine/internal/llvm/llvmtypeanalyzer.cpp b/src/engine/internal/llvm/llvmtypeanalyzer.cpp index 5072eb22d..aace9e486 100644 --- a/src/engine/internal/llvm/llvmtypeanalyzer.cpp +++ b/src/engine/internal/llvm/llvmtypeanalyzer.cpp @@ -290,7 +290,7 @@ Compiler::StaticType LLVMTypeAnalyzer::writeValueType(LLVMInstruction *ins, Inst // If this is a variable read instruction, recursively get the variable type return variableType(arg->instruction->workVariable, arg->instruction.get(), Compiler::StaticType::Unknown, visitedInstructions); } else { - // TODO: Use the instruction return register + // The write argument already has the instruction return type return optimizeRegisterType(arg); } } else diff --git a/test/llvm/type_analyzer/variabletype_test.cpp b/test/llvm/type_analyzer/variabletype_test.cpp index 0bba27bc3..63739f6ab 100644 --- a/test/llvm/type_analyzer/variabletype_test.cpp +++ b/test/llvm/type_analyzer/variabletype_test.cpp @@ -2153,3 +2153,248 @@ TEST(LLVMTypeAnalyzer_VariableType, SelfAssignmentWithTypeChange_After) // Should return number because it's assigned after the no-op ASSERT_EQ(analyzer.variableType(&var1, queryPos.get(), Compiler::StaticType::String), Compiler::StaticType::Number); } + +TEST(LLVMTypeAnalyzer_VariableType, InstructionReturnType_AddNumbers) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + Variable var1("", ""); + + // Create add instruction: 5 + 3 + auto addInstruction = std::make_shared(LLVMInstruction::Type::Add, nullptr, false); + LLVMConstantRegister operand1(Compiler::StaticType::Number, 5); + LLVMConstantRegister operand2(Compiler::StaticType::Number, 3); + addInstruction->args.push_back({ Compiler::StaticType::Number, &operand1 }); + addInstruction->args.push_back({ Compiler::StaticType::Number, &operand2 }); + + // Set up return register for add instruction + LLVMRegister addResult(Compiler::StaticType::Number); + addResult.isRawValue = true; + addResult.instruction = addInstruction; + addInstruction->functionReturnReg = &addResult; + list.addInstruction(addInstruction); + + // Assign add result to variable: var1 = (5 + 3) + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + setVar1->workVariable = &var1; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &addResult }); + list.addInstruction(setVar1); + + // Query position after the assignment + auto queryPos = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(queryPos); + + // var1 should have Number type from add instruction return + ASSERT_EQ(analyzer.variableType(&var1, queryPos.get(), Compiler::StaticType::String), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_VariableType, InstructionReturnType_StringConcat) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + Variable var1("", ""); + + // Create string concatenation instruction: "hello" + "world" + auto concatInstruction = std::make_shared(LLVMInstruction::Type::StringConcat, nullptr, false); + LLVMConstantRegister str1(Compiler::StaticType::String, "hello"); + LLVMConstantRegister str2(Compiler::StaticType::String, "world"); + concatInstruction->args.push_back({ Compiler::StaticType::String, &str1 }); + concatInstruction->args.push_back({ Compiler::StaticType::String, &str2 }); + + // Set up return register for concat instruction + LLVMRegister concatResult(Compiler::StaticType::String); + concatResult.isRawValue = true; + concatResult.instruction = concatInstruction; + concatInstruction->functionReturnReg = &concatResult; + list.addInstruction(concatInstruction); + + // Assign concat result to variable: var1 = ("hello" + "world") + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + setVar1->workVariable = &var1; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &concatResult }); + list.addInstruction(setVar1); + + // Query position after the assignment + auto queryPos = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(queryPos); + + // var1 should have String type from concat instruction return + ASSERT_EQ(analyzer.variableType(&var1, queryPos.get(), Compiler::StaticType::Number), Compiler::StaticType::String); +} + +TEST(LLVMTypeAnalyzer_VariableType, InstructionReturnType_MathFunction) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + Variable var1("", ""); + + // Create sqrt instruction: sqrt(16) + auto sqrtInstruction = std::make_shared(LLVMInstruction::Type::Sqrt, nullptr, false); + LLVMConstantRegister operand(Compiler::StaticType::Number, 16); + sqrtInstruction->args.push_back({ Compiler::StaticType::Number, &operand }); + + // Set up return register for sqrt instruction + LLVMRegister sqrtResult(Compiler::StaticType::Number); + sqrtResult.isRawValue = true; + sqrtResult.instruction = sqrtInstruction; + sqrtInstruction->functionReturnReg = &sqrtResult; + list.addInstruction(sqrtInstruction); + + // Assign sqrt result to variable: var1 = sqrt(16) + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + setVar1->workVariable = &var1; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &sqrtResult }); + list.addInstruction(setVar1); + + // Query position after the assignment + auto queryPos = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(queryPos); + + // var1 should have Number type from sqrt instruction return + ASSERT_EQ(analyzer.variableType(&var1, queryPos.get(), Compiler::StaticType::String), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_VariableType, InstructionReturnType_Comparison) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + Variable var1("", ""); + + // Create comparison instruction: 5 > 3 + auto cmpInstruction = std::make_shared(LLVMInstruction::Type::CmpGT, nullptr, false); + LLVMConstantRegister operand1(Compiler::StaticType::Number, 5); + LLVMConstantRegister operand2(Compiler::StaticType::Number, 3); + cmpInstruction->args.push_back({ Compiler::StaticType::Number, &operand1 }); + cmpInstruction->args.push_back({ Compiler::StaticType::Number, &operand2 }); + + // Set up return register for comparison instruction + LLVMRegister cmpResult(Compiler::StaticType::Bool); + cmpResult.isRawValue = true; + cmpResult.instruction = cmpInstruction; + cmpInstruction->functionReturnReg = &cmpResult; + list.addInstruction(cmpInstruction); + + // Assign comparison result to variable: var1 = (5 > 3) + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + setVar1->workVariable = &var1; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &cmpResult }); + list.addInstruction(setVar1); + + // Query position after the assignment + auto queryPos = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(queryPos); + + // var1 should have Bool type from comparison instruction return + ASSERT_EQ(analyzer.variableType(&var1, queryPos.get(), Compiler::StaticType::Number), Compiler::StaticType::Bool); +} + +TEST(LLVMTypeAnalyzer_VariableType, InstructionReturnType_FunctionCall) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + Variable var1("", ""); + + // Create function call instruction + auto funcInstruction = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + funcInstruction->functionName = "some_reporter_function"; + LLVMConstantRegister arg(Compiler::StaticType::Number, 42); + funcInstruction->args.push_back({ Compiler::StaticType::Number, &arg }); + + // Set up return register for function call + LLVMRegister funcResult(Compiler::StaticType::String); + funcResult.isRawValue = true; + funcResult.instruction = funcInstruction; + funcInstruction->functionReturnReg = &funcResult; + list.addInstruction(funcInstruction); + + // Assign function result to variable: var1 = some_reporter_function(42) + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + setVar1->workVariable = &var1; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &funcResult }); + list.addInstruction(setVar1); + + // Query position after the assignment + auto queryPos = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(queryPos); + + // var1 should have String type from function call return + ASSERT_EQ(analyzer.variableType(&var1, queryPos.get(), Compiler::StaticType::Number), Compiler::StaticType::String); +} + +TEST(LLVMTypeAnalyzer_VariableType, InstructionReturnType_ChainedOperations) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + Variable var1("", ""); + + // First operation: 5 + 3 + auto addInstruction = std::make_shared(LLVMInstruction::Type::Add, nullptr, false); + LLVMConstantRegister operand1(Compiler::StaticType::Number, 5); + LLVMConstantRegister operand2(Compiler::StaticType::Number, 3); + addInstruction->args.push_back({ Compiler::StaticType::Number, &operand1 }); + addInstruction->args.push_back({ Compiler::StaticType::Number, &operand2 }); + + LLVMRegister addResult(Compiler::StaticType::Number); + addResult.isRawValue = true; + addResult.instruction = addInstruction; + addInstruction->functionReturnReg = &addResult; + list.addInstruction(addInstruction); + + // Second operation: (5 + 3) * 2 + auto mulInstruction = std::make_shared(LLVMInstruction::Type::Mul, nullptr, false); + LLVMConstantRegister multiplier(Compiler::StaticType::Number, 2); + mulInstruction->args.push_back({ Compiler::StaticType::Unknown, &addResult }); + mulInstruction->args.push_back({ Compiler::StaticType::Number, &multiplier }); + + LLVMRegister mulResult(Compiler::StaticType::Number); + mulResult.isRawValue = true; + mulResult.instruction = mulInstruction; + mulInstruction->functionReturnReg = &mulResult; + list.addInstruction(mulInstruction); + + // Assign final result to variable: var1 = ((5 + 3) * 2) + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + setVar1->workVariable = &var1; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &mulResult }); + list.addInstruction(setVar1); + + // Query position after the assignment + auto queryPos = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(queryPos); + + // var1 should have Number type from chained operations + ASSERT_EQ(analyzer.variableType(&var1, queryPos.get(), Compiler::StaticType::String), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_VariableType, InstructionReturnType_QueryBeforeAssignment) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + Variable var1("", ""); + + // Query position before any operations + auto queryPos = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(queryPos); + + // Create add instruction: 5 + 3 (after query position) + auto addInstruction = std::make_shared(LLVMInstruction::Type::Add, nullptr, false); + LLVMConstantRegister operand1(Compiler::StaticType::Number, 5); + LLVMConstantRegister operand2(Compiler::StaticType::Number, 3); + addInstruction->args.push_back({ Compiler::StaticType::Number, &operand1 }); + addInstruction->args.push_back({ Compiler::StaticType::Number, &operand2 }); + + LLVMRegister addResult(Compiler::StaticType::Number); + addResult.isRawValue = true; + addResult.instruction = addInstruction; + addInstruction->functionReturnReg = &addResult; + list.addInstruction(addInstruction); + + // Assign add result to variable: var1 = (5 + 3) (after query position) + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + setVar1->workVariable = &var1; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &addResult }); + list.addInstruction(setVar1); + + // var1 should have the previous type since assignment is after query position + ASSERT_EQ(analyzer.variableType(&var1, queryPos.get(), Compiler::StaticType::String), Compiler::StaticType::String); +} diff --git a/test/llvm/type_analyzer/variabletypeafterbranch_test.cpp b/test/llvm/type_analyzer/variabletypeafterbranch_test.cpp index dc30be450..c2964dd19 100644 --- a/test/llvm/type_analyzer/variabletypeafterbranch_test.cpp +++ b/test/llvm/type_analyzer/variabletypeafterbranch_test.cpp @@ -2289,3 +2289,227 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SelfAssignmentWithTypeChange_Afte // Should return number because it's assigned later in the loop ASSERT_EQ(analyzer.variableTypeAfterBranch(&var1, start.get(), Compiler::StaticType::String), Compiler::StaticType::Number); } + +TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, InstructionReturnType_AddNumbers) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + Variable var1("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(start); + + // Create add instruction: 5 + 3 + auto addInstruction = std::make_shared(LLVMInstruction::Type::Add, nullptr, false); + LLVMConstantRegister operand1(Compiler::StaticType::Number, 5); + LLVMConstantRegister operand2(Compiler::StaticType::Number, 3); + addInstruction->args.push_back({ Compiler::StaticType::Number, &operand1 }); + addInstruction->args.push_back({ Compiler::StaticType::Number, &operand2 }); + + // Set up return register for add instruction + LLVMRegister addResult(Compiler::StaticType::Number); + addResult.isRawValue = true; + addResult.instruction = addInstruction; + addInstruction->functionReturnReg = &addResult; + list.addInstruction(addInstruction); + + // Assign add result to variable: var1 = (5 + 3) + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + setVar1->workVariable = &var1; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &addResult }); + list.addInstruction(setVar1); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(end); + + // var1 should have Number type from add instruction return + ASSERT_EQ(analyzer.variableTypeAfterBranch(&var1, start.get(), Compiler::StaticType::String), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, InstructionReturnType_StringConcat) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + Variable var1("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(start); + + // Create string concatenation instruction: "hello" + "world" + auto concatInstruction = std::make_shared(LLVMInstruction::Type::StringConcat, nullptr, false); + LLVMConstantRegister str1(Compiler::StaticType::String, "hello"); + LLVMConstantRegister str2(Compiler::StaticType::String, "world"); + concatInstruction->args.push_back({ Compiler::StaticType::String, &str1 }); + concatInstruction->args.push_back({ Compiler::StaticType::String, &str2 }); + + // Set up return register for concat instruction + LLVMRegister concatResult(Compiler::StaticType::String); + concatResult.isRawValue = true; + concatResult.instruction = concatInstruction; + concatInstruction->functionReturnReg = &concatResult; + list.addInstruction(concatInstruction); + + // Assign concat result to variable: var1 = ("hello" + "world") + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + setVar1->workVariable = &var1; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &concatResult }); + list.addInstruction(setVar1); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(end); + + // var1 should have String type from concat instruction return + ASSERT_EQ(analyzer.variableTypeAfterBranch(&var1, start.get(), Compiler::StaticType::Number), Compiler::StaticType::String); +} + +TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, InstructionReturnType_MathFunction) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + Variable var1("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(start); + + // Create sqrt instruction: sqrt(16) + auto sqrtInstruction = std::make_shared(LLVMInstruction::Type::Sqrt, nullptr, false); + LLVMConstantRegister operand(Compiler::StaticType::Number, 16); + sqrtInstruction->args.push_back({ Compiler::StaticType::Number, &operand }); + + // Set up return register for sqrt instruction + LLVMRegister sqrtResult(Compiler::StaticType::Number); + sqrtResult.isRawValue = true; + sqrtResult.instruction = sqrtInstruction; + sqrtInstruction->functionReturnReg = &sqrtResult; + list.addInstruction(sqrtInstruction); + + // Assign sqrt result to variable: var1 = sqrt(16) + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + setVar1->workVariable = &var1; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &sqrtResult }); + list.addInstruction(setVar1); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(end); + + // var1 should have Number type from sqrt instruction return + ASSERT_EQ(analyzer.variableTypeAfterBranch(&var1, start.get(), Compiler::StaticType::String), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, InstructionReturnType_Comparison) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + Variable var1("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(start); + + // Create comparison instruction: 5 > 3 + auto cmpInstruction = std::make_shared(LLVMInstruction::Type::CmpGT, nullptr, false); + LLVMConstantRegister operand1(Compiler::StaticType::Number, 5); + LLVMConstantRegister operand2(Compiler::StaticType::Number, 3); + cmpInstruction->args.push_back({ Compiler::StaticType::Number, &operand1 }); + cmpInstruction->args.push_back({ Compiler::StaticType::Number, &operand2 }); + + // Set up return register for comparison instruction + LLVMRegister cmpResult(Compiler::StaticType::Bool); + cmpResult.isRawValue = true; + cmpResult.instruction = cmpInstruction; + cmpInstruction->functionReturnReg = &cmpResult; + list.addInstruction(cmpInstruction); + + // Assign comparison result to variable: var1 = (5 > 3) + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + setVar1->workVariable = &var1; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &cmpResult }); + list.addInstruction(setVar1); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(end); + + // var1 should have Bool type from comparison instruction return + ASSERT_EQ(analyzer.variableTypeAfterBranch(&var1, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Bool); +} + +TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, InstructionReturnType_FunctionCall) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + Variable var1("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(start); + + // Create function call instruction + auto funcInstruction = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + funcInstruction->functionName = "some_reporter_function"; + LLVMConstantRegister arg(Compiler::StaticType::Number, 42); + funcInstruction->args.push_back({ Compiler::StaticType::Number, &arg }); + + // Set up return register for function call + LLVMRegister funcResult(Compiler::StaticType::String); + funcResult.isRawValue = true; + funcResult.instruction = funcInstruction; + funcInstruction->functionReturnReg = &funcResult; + list.addInstruction(funcInstruction); + + // Assign function result to variable: var1 = some_reporter_function(42) + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + setVar1->workVariable = &var1; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &funcResult }); + list.addInstruction(setVar1); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(end); + + // var1 should have String type from function call return + ASSERT_EQ(analyzer.variableTypeAfterBranch(&var1, start.get(), Compiler::StaticType::Number), Compiler::StaticType::String); +} + +TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, InstructionReturnType_ChainedOperations) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + Variable var1("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(start); + + // First operation: 5 + 3 + auto addInstruction = std::make_shared(LLVMInstruction::Type::Add, nullptr, false); + LLVMConstantRegister operand1(Compiler::StaticType::Number, 5); + LLVMConstantRegister operand2(Compiler::StaticType::Number, 3); + addInstruction->args.push_back({ Compiler::StaticType::Number, &operand1 }); + addInstruction->args.push_back({ Compiler::StaticType::Number, &operand2 }); + + LLVMRegister addResult(Compiler::StaticType::Number); + addResult.isRawValue = true; + addResult.instruction = addInstruction; + addInstruction->functionReturnReg = &addResult; + list.addInstruction(addInstruction); + + // Second operation: (5 + 3) * 2 + auto mulInstruction = std::make_shared(LLVMInstruction::Type::Mul, nullptr, false); + LLVMConstantRegister multiplier(Compiler::StaticType::Number, 2); + mulInstruction->args.push_back({ Compiler::StaticType::Unknown, &addResult }); + mulInstruction->args.push_back({ Compiler::StaticType::Number, &multiplier }); + + LLVMRegister mulResult(Compiler::StaticType::Number); + mulResult.isRawValue = true; + mulResult.instruction = mulInstruction; + mulInstruction->functionReturnReg = &mulResult; + list.addInstruction(mulInstruction); + + // Assign final result to variable: var1 = ((5 + 3) * 2) + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + setVar1->workVariable = &var1; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &mulResult }); + list.addInstruction(setVar1); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(end); + + // var1 should have Number type from chained operations + ASSERT_EQ(analyzer.variableTypeAfterBranch(&var1, start.get(), Compiler::StaticType::String), Compiler::StaticType::Number); +} From 547c5066711a86c94b7b4097e1efc8cdf98ac536 Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Sun, 27 Jul 2025 14:09:22 +0200 Subject: [PATCH 37/79] LLVMTypeAnalyzer: Move find branch end logic to branchEnd() --- src/engine/internal/llvm/llvmtypeanalyzer.cpp | 47 +++++++++++-------- src/engine/internal/llvm/llvmtypeanalyzer.h | 1 + 2 files changed, 28 insertions(+), 20 deletions(-) diff --git a/src/engine/internal/llvm/llvmtypeanalyzer.cpp b/src/engine/internal/llvm/llvmtypeanalyzer.cpp index aace9e486..487dd88d9 100644 --- a/src/engine/internal/llvm/llvmtypeanalyzer.cpp +++ b/src/engine/internal/llvm/llvmtypeanalyzer.cpp @@ -107,31 +107,14 @@ Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranch(Variable *var, LL if (!var || !start) return previousType; - assert(isLoopStart(start) || isIfStart(start) || isElse(start)); - - // Find loop/if statement end or else branch - LLVMInstruction *ins = start->next; - int level = 0; + LLVMInstruction *end = branchEnd(start); - while (ins && !((isLoopEnd(ins) || isIfEnd(ins) || isElse(ins)) && level == 0)) { - if (isLoopStart(ins) || isIfStart(ins)) - level++; - else if (isLoopEnd(ins) || isIfEnd(ins)) { - assert(level > 0); - level--; - } - - ins = ins->next; - } - - if (!ins) { - assert(false); + if (!end) return Compiler::StaticType::Unknown; - } // Process the branch from end bool write = false; // only used internally (the compiler doesn't need this) - return variableTypeAfterBranchFromEnd(var, ins, previousType, write, visitedInstructions); + return variableTypeAfterBranchFromEnd(var, end, previousType, write, visitedInstructions); } Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranchFromEnd(Variable *var, LLVMInstruction *end, Compiler::StaticType previousType, bool &write, InstructionSet &visitedInstructions) const @@ -187,6 +170,30 @@ Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranchFromEnd(Variable * return previousType; } +LLVMInstruction *LLVMTypeAnalyzer::branchEnd(LLVMInstruction *start) const +{ + assert(start); + assert(isLoopStart(start) || isIfStart(start) || isElse(start)); + + // Find loop/if statement end or else branch + LLVMInstruction *ins = start->next; + int level = 0; + + while (ins && !((isLoopEnd(ins) || isIfEnd(ins) || isElse(ins)) && level == 0)) { + if (isLoopStart(ins) || isIfStart(ins)) + level++; + else if (isLoopEnd(ins) || isIfEnd(ins)) { + assert(level > 0); + level--; + } + + ins = ins->next; + } + + assert(ins); + return ins; +} + LLVMInstruction *LLVMTypeAnalyzer::skipBranch(LLVMInstruction *pos) const { int level = 0; diff --git a/src/engine/internal/llvm/llvmtypeanalyzer.h b/src/engine/internal/llvm/llvmtypeanalyzer.h index ac32565b4..f3bd20d11 100644 --- a/src/engine/internal/llvm/llvmtypeanalyzer.h +++ b/src/engine/internal/llvm/llvmtypeanalyzer.h @@ -21,6 +21,7 @@ class LLVMTypeAnalyzer Compiler::StaticType variableTypeAfterBranch(Variable *var, LLVMInstruction *start, Compiler::StaticType previousType, InstructionSet &visitedInstructions) const; Compiler::StaticType variableTypeAfterBranchFromEnd(Variable *var, LLVMInstruction *end, Compiler::StaticType previousType, bool &write, InstructionSet &visitedInstructions) const; + LLVMInstruction *branchEnd(LLVMInstruction *start) const; LLVMInstruction *skipBranch(LLVMInstruction *pos) const; bool isLoopStart(LLVMInstruction *ins) const; From 005357a0a8087479cba03168e6130d81b79eb4fa Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Sun, 27 Jul 2025 14:14:20 +0200 Subject: [PATCH 38/79] LLVMTypeAnalyzer: skipBranch() -> branchStart() --- src/engine/internal/llvm/llvmtypeanalyzer.cpp | 28 +++++++++++-------- src/engine/internal/llvm/llvmtypeanalyzer.h | 2 +- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/src/engine/internal/llvm/llvmtypeanalyzer.cpp b/src/engine/internal/llvm/llvmtypeanalyzer.cpp index 487dd88d9..877ce84b5 100644 --- a/src/engine/internal/llvm/llvmtypeanalyzer.cpp +++ b/src/engine/internal/llvm/llvmtypeanalyzer.cpp @@ -62,7 +62,7 @@ Compiler::StaticType LLVMTypeAnalyzer::variableType(Variable *var, LLVMInstructi } else if (isElse(ins)) { // Skip if branch if coming from else firstElseBranch = ins; - ins = skipBranch(ins); + ins = branchStart(ins); continue; } else if (isVariableWrite(ins, var) && !isWriteNoOp(ins)) { if (level <= 0) { // ignore nested branches (they're handled by the branch analyzer) @@ -134,7 +134,7 @@ Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranchFromEnd(Variable * } else return Compiler::StaticType::Unknown; - ins = skipBranch(ins); + ins = branchStart(ins); if (isElse(ins)) { // Process if branch (the else branch is already processed) @@ -150,7 +150,7 @@ Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranchFromEnd(Variable * } else return Compiler::StaticType::Unknown; - ins = skipBranch(ins); + ins = branchStart(ins); } } else if (isVariableWrite(ins, var) && !isWriteNoOp(ins)) { // Variable write instruction @@ -194,29 +194,33 @@ LLVMInstruction *LLVMTypeAnalyzer::branchEnd(LLVMInstruction *start) const return ins; } -LLVMInstruction *LLVMTypeAnalyzer::skipBranch(LLVMInstruction *pos) const +LLVMInstruction *LLVMTypeAnalyzer::branchStart(LLVMInstruction *end) const { + assert(end); + assert(isLoopEnd(end) || isIfEnd(end) || isElse(end)); + + // Find loop/if statement/else branch start + LLVMInstruction *ins = end->previous; int level = 0; - pos = pos->previous; - while (pos && !((isLoopStart(pos) || isIfStart(pos)) && level == 0)) { - if (isLoopStart(pos) || isIfStart(pos)) { + while (ins && !((isLoopStart(ins) || isIfStart(ins)) && level == 0)) { + if (isLoopStart(ins) || isIfStart(ins)) { assert(level > 0); level--; } - if (isLoopEnd(pos) || isIfEnd(pos) || isElse(pos)) { - if (isElse(pos) && level == 0) + if (isLoopEnd(ins) || isIfEnd(ins) || isElse(ins)) { + if (isElse(ins) && level == 0) break; level++; } - pos = pos->previous; + ins = ins->previous; }; - assert(pos); - return pos; + assert(ins); + return ins; } bool LLVMTypeAnalyzer::isLoopStart(LLVMInstruction *ins) const diff --git a/src/engine/internal/llvm/llvmtypeanalyzer.h b/src/engine/internal/llvm/llvmtypeanalyzer.h index f3bd20d11..ed7320a77 100644 --- a/src/engine/internal/llvm/llvmtypeanalyzer.h +++ b/src/engine/internal/llvm/llvmtypeanalyzer.h @@ -22,7 +22,7 @@ class LLVMTypeAnalyzer Compiler::StaticType variableTypeAfterBranchFromEnd(Variable *var, LLVMInstruction *end, Compiler::StaticType previousType, bool &write, InstructionSet &visitedInstructions) const; LLVMInstruction *branchEnd(LLVMInstruction *start) const; - LLVMInstruction *skipBranch(LLVMInstruction *pos) const; + LLVMInstruction *branchStart(LLVMInstruction *end) const; bool isLoopStart(LLVMInstruction *ins) const; bool isLoopEnd(LLVMInstruction *ins) const; From c9342a9350577c83eb1da22da233ec5b1554c203 Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Sun, 27 Jul 2025 15:21:48 +0200 Subject: [PATCH 39/79] LLVMTypeAnalyzer: Implement listTypeAfterBranch() for basic cases --- src/engine/internal/llvm/llvmtypeanalyzer.cpp | 69 + src/engine/internal/llvm/llvmtypeanalyzer.h | 5 + test/llvm/CMakeLists.txt | 1 + .../listtypeafterbranch_test.cpp | 1670 +++++++++++++++++ 4 files changed, 1745 insertions(+) create mode 100644 test/llvm/type_analyzer/listtypeafterbranch_test.cpp diff --git a/src/engine/internal/llvm/llvmtypeanalyzer.cpp b/src/engine/internal/llvm/llvmtypeanalyzer.cpp index 877ce84b5..b4ccebb17 100644 --- a/src/engine/internal/llvm/llvmtypeanalyzer.cpp +++ b/src/engine/internal/llvm/llvmtypeanalyzer.cpp @@ -8,6 +8,8 @@ using namespace libscratchcpp; static const std::unordered_set BEGIN_LOOP_INSTRUCTIONS = { LLVMInstruction::Type::BeginRepeatLoop, LLVMInstruction::Type::BeginWhileLoop, LLVMInstruction::Type::BeginRepeatUntilLoop }; +static const std::unordered_set LIST_WRITE_INSTRUCTIONS = { LLVMInstruction::Type::AppendToList, LLVMInstruction::Type::InsertToList, LLVMInstruction::Type::ListReplace }; + Compiler::StaticType LLVMTypeAnalyzer::variableType(Variable *var, LLVMInstruction *pos, Compiler::StaticType previousType) const { InstructionSet visitedInstructions; @@ -20,6 +22,68 @@ Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranch(Variable *var, LL return variableTypeAfterBranch(var, start, previousType, visitedInstructions); } +Compiler::StaticType LLVMTypeAnalyzer::listTypeAfterBranch(List *list, LLVMInstruction *start, Compiler::StaticType previousType, bool isEmpty) const +{ + if (!list || !start) + return previousType; + + assert(isLoopStart(start) || isIfStart(start) || isElse(start)); + + InstructionSet visitedInstructions; // TODO: Handle cross-variable/list dependencies + + LLVMInstruction *ins = start->next; + LLVMInstruction *lastWrite = nullptr; + Compiler::StaticType lastWriteType = Compiler::StaticType::Unknown; + int level = 0; + + while (ins && !((isLoopEnd(ins) || isIfEnd(ins) || isElse(ins)) && level == 0)) { + if (isLoopStart(ins) || isIfStart(ins)) + level++; + else if (isLoopEnd(ins) || isIfEnd(ins)) { + assert(level > 0); + level--; + } else if (isListWrite(ins, list)) { + // List write instruction + Compiler::StaticType writeType = writeValueType(ins, visitedInstructions); + + // For non-empty lists, we can just check the write type + if (!isEmpty && !typesMatch(writeType, previousType)) { + return Compiler::StaticType::Unknown; + } + + // In empty lists, writes of the same type determine the final type + if (isEmpty) { + if (lastWrite) { + // There was a write before which means it might determine the final type + if (!typesMatch(writeType, lastWriteType)) + return Compiler::StaticType::Unknown; + } else { + // This is the first write found, it might determine the final type + lastWrite = ins; + lastWriteType = writeType; + } + } + } + + ins = ins->next; + } + + assert(ins); + + if (isEmpty) { + if (lastWrite) { + // Only writes of the same type modify the list + return lastWriteType; + } else { + // No writes to empty list found, keep the previous type + return previousType; + } + } else { + // No type conflicts found for non-empty list + return previousType; + } +} + Compiler::StaticType LLVMTypeAnalyzer::variableType(Variable *var, LLVMInstruction *pos, Compiler::StaticType previousType, InstructionSet &visitedInstructions) const { if (!var || !pos) @@ -258,6 +322,11 @@ bool LLVMTypeAnalyzer::isVariableWrite(LLVMInstruction *ins, Variable *var) cons return (ins->type == LLVMInstruction::Type::WriteVariable && ins->workVariable == var); } +bool LLVMTypeAnalyzer::isListWrite(LLVMInstruction *ins, List *list) const +{ + return (LIST_WRITE_INSTRUCTIONS.find(ins->type) != LIST_WRITE_INSTRUCTIONS.cend() && ins->workList == list); +} + Compiler::StaticType LLVMTypeAnalyzer::optimizeRegisterType(LLVMRegister *reg) const { // TODO: Move this method out if it's used in LLVMCodeBuilder too diff --git a/src/engine/internal/llvm/llvmtypeanalyzer.h b/src/engine/internal/llvm/llvmtypeanalyzer.h index ed7320a77..046b29b8b 100644 --- a/src/engine/internal/llvm/llvmtypeanalyzer.h +++ b/src/engine/internal/llvm/llvmtypeanalyzer.h @@ -14,6 +14,8 @@ class LLVMTypeAnalyzer Compiler::StaticType variableType(Variable *var, LLVMInstruction *pos, Compiler::StaticType previousType) const; Compiler::StaticType variableTypeAfterBranch(Variable *var, LLVMInstruction *start, Compiler::StaticType previousType) const; + Compiler::StaticType listTypeAfterBranch(List *list, LLVMInstruction *start, Compiler::StaticType previousType, bool isEmpty) const; + private: using InstructionSet = std::unordered_set; @@ -29,9 +31,12 @@ class LLVMTypeAnalyzer bool isIfStart(LLVMInstruction *ins) const; bool isElse(LLVMInstruction *ins) const; bool isIfEnd(LLVMInstruction *ins) const; + bool isVariableRead(LLVMInstruction *ins) const; bool isVariableWrite(LLVMInstruction *ins, Variable *var) const; + bool isListWrite(LLVMInstruction *ins, List *list) const; + Compiler::StaticType optimizeRegisterType(LLVMRegister *reg) const; bool isWriteNoOp(LLVMInstruction *ins) const; Compiler::StaticType writeValueType(LLVMInstruction *ins, InstructionSet &visitedInstructions) const; diff --git a/test/llvm/CMakeLists.txt b/test/llvm/CMakeLists.txt index 0ba3385a7..e1d005cc4 100644 --- a/test/llvm/CMakeLists.txt +++ b/test/llvm/CMakeLists.txt @@ -22,6 +22,7 @@ add_executable( llvminstructionlist_test.cpp type_analyzer/variabletypeafterbranch_test.cpp type_analyzer/variabletype_test.cpp + type_analyzer/listtypeafterbranch_test.cpp ) target_link_libraries( diff --git a/test/llvm/type_analyzer/listtypeafterbranch_test.cpp b/test/llvm/type_analyzer/listtypeafterbranch_test.cpp new file mode 100644 index 000000000..80d6258b5 --- /dev/null +++ b/test/llvm/type_analyzer/listtypeafterbranch_test.cpp @@ -0,0 +1,1670 @@ +#include +#include +#include +#include +#include +#include + +using namespace libscratchcpp; + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, NullParams) +{ + LLVMTypeAnalyzer analyzer; + ASSERT_EQ(analyzer.listTypeAfterBranch(nullptr, nullptr, Compiler::StaticType::Number, false), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, NullList) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(start); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(funcCall); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(end); + + ASSERT_EQ(analyzer.listTypeAfterBranch(nullptr, start.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, NullStartInstruction) +{ + LLVMTypeAnalyzer analyzer; + List list("", ""); + ASSERT_EQ(analyzer.listTypeAfterBranch(&list, nullptr, Compiler::StaticType::Number, false), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, EmptyLoop) +{ + LLVMTypeAnalyzer analyzer; + List list("", ""); + LLVMInstructionList instructionList; + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, EmptyIfStatement) +{ + LLVMTypeAnalyzer analyzer; + List list("", ""); + LLVMInstructionList instructionList; + + auto start = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + instructionList.addInstruction(start); + + auto end = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + instructionList.addInstruction(end); + + ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, EmptyIfElseStatement_IfBranch) +{ + LLVMTypeAnalyzer analyzer; + List list("", ""); + LLVMInstructionList instructionList; + + auto start = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + instructionList.addInstruction(start); + + auto elseStart = std::make_shared(LLVMInstruction::Type::BeginElse, nullptr, false); + instructionList.addInstruction(elseStart); + + auto end = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + instructionList.addInstruction(end); + + ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, EmptyIfElseStatement_ElseBranch) +{ + LLVMTypeAnalyzer analyzer; + List list("", ""); + LLVMInstructionList instructionList; + + auto start = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + instructionList.addInstruction(start); + + auto elseStart = std::make_shared(LLVMInstruction::Type::BeginElse, nullptr, false); + instructionList.addInstruction(elseStart); + + auto end = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + instructionList.addInstruction(end); + + ASSERT_EQ(analyzer.listTypeAfterBranch(&list, elseStart.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, EmptyLoopUnknownType) +{ + LLVMTypeAnalyzer analyzer; + List list("", ""); + LLVMInstructionList instructionList; + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Unknown, false), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, NoWriteOperations) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleAppendSameTypeNumber) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + auto appendList = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::Number, 1.25); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Unknown, &value }); + instructionList.addInstruction(appendList); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleAppendSameTypeBool) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + auto appendList = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::Bool, true); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Unknown, &value }); + instructionList.addInstruction(appendList); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Bool, false), Compiler::StaticType::Bool); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleAppendSameTypeString) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + auto appendList = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::String, "test"); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Unknown, &value }); + instructionList.addInstruction(appendList); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::String, false), Compiler::StaticType::String); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleAppendStringOptimization) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + auto appendList = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::String, "1.25"); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Unknown, &value }); + instructionList.addInstruction(appendList); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + // Although string is appended, it's constant and represents a number + ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleAppendMultipleLists) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list1("", ""); + List list2("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + // Append to list1 + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 6); + appendList1->workList = &list1; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + // Append to list2 + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::String, "test"); + appendList2->workList = &list2; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + ASSERT_EQ(analyzer.listTypeAfterBranch(&list1, start.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleAppendFromUnknownType) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + auto appendList = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMRegister value(Compiler::StaticType::Unknown); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Unknown, &value }); + instructionList.addInstruction(appendList); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleAppendToUnknownType) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + auto appendList = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::Number, 5); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Unknown, &value }); + instructionList.addInstruction(appendList); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Unknown, false), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleAppendUnknownToUnknownType) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + auto appendList = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMRegister value(Compiler::StaticType::Unknown); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Unknown, &value }); + instructionList.addInstruction(appendList); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Unknown, false), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleInsertSameType) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + auto appendList = std::make_shared(LLVMInstruction::Type::InsertToList, nullptr, false); + LLVMConstantRegister index(Compiler::StaticType::Number, 1); + LLVMConstantRegister value(Compiler::StaticType::String, "test"); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Number, &index }); + appendList->args.push_back({ Compiler::StaticType::Unknown, &value }); + instructionList.addInstruction(appendList); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::String, false), Compiler::StaticType::String); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleReplaceSameType) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + auto appendList = std::make_shared(LLVMInstruction::Type::ListReplace, nullptr, false); + LLVMConstantRegister index(Compiler::StaticType::Number, 1); + LLVMConstantRegister value(Compiler::StaticType::String, "test"); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Number, &index }); + appendList->args.push_back({ Compiler::StaticType::Unknown, &value }); + instructionList.addInstruction(appendList); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::String, false), Compiler::StaticType::String); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleAppendDifferentTypeNumberToString_Empty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + auto appendList = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::String, "test"); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Unknown, &value }); + instructionList.addInstruction(appendList); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, true), Compiler::StaticType::String); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleAppendDifferentTypeNumberToString_NonEmpty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + auto appendList = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::String, "test"); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Unknown, &value }); + instructionList.addInstruction(appendList); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleAppendDifferentTypeStringToNumber_Empty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + auto appendList = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::Number, 5.8); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Unknown, &value }); + instructionList.addInstruction(appendList); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::String, true), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleAppendDifferentTypeStringToNumber_NonEmpty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + auto appendList = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::Number, 5.8); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Unknown, &value }); + instructionList.addInstruction(appendList); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::String, false), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleAppendDifferentTypeNumberToBool_Empty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + auto appendList = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::Bool, true); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Unknown, &value }); + instructionList.addInstruction(appendList); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Bool); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleAppendDifferentTypeNumberToBool_NonEmpty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + auto appendList = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::Bool, true); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Unknown, &value }); + instructionList.addInstruction(appendList); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleAppendDifferentTypeBoolToNumber_Empty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + auto appendList = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::Number, 1); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Unknown, &value }); + instructionList.addInstruction(appendList); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Bool, true), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleAppendDifferentTypeBoolToNumber_NonEmpty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + auto appendList = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::Number, 1); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Unknown, &value }); + instructionList.addInstruction(appendList); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Bool, false), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleAppendDifferentTypeBoolToString_Empty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + auto appendList = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::String, "abc"); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Unknown, &value }); + instructionList.addInstruction(appendList); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Bool, true), Compiler::StaticType::String); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleAppendDifferentTypeBoolToString_NonEmpty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + auto appendList = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::String, "abc"); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Unknown, &value }); + instructionList.addInstruction(appendList); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Bool, false), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleAppendDifferentTypeStringToBool_Empty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + auto appendList = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::Bool, false); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Unknown, &value }); + instructionList.addInstruction(appendList); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::String, true), Compiler::StaticType::Bool); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleAppendDifferentTypeStringToBool_NonEmpty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + auto appendList = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::Bool, false); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Unknown, &value }); + instructionList.addInstruction(appendList); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::String, false), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleAppendSameType_IfStatement) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + instructionList.addInstruction(start); + + auto appendList = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::Number, 1.25); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Unknown, &value }); + instructionList.addInstruction(appendList); + + auto end = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + instructionList.addInstruction(end); + + ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleAppendDifferentType_IfStatement_Empty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + instructionList.addInstruction(start); + + auto appendList = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::Number, 5.8); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Unknown, &value }); + instructionList.addInstruction(appendList); + + auto end = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + instructionList.addInstruction(end); + + ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::String, true), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleAppendDifferentType_IfStatement_NonEmpty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + instructionList.addInstruction(start); + + auto appendList = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::Number, 5.8); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Unknown, &value }); + instructionList.addInstruction(appendList); + + auto end = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + instructionList.addInstruction(end); + + ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::String, false), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleInsertDifferentType_Empty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + auto appendList = std::make_shared(LLVMInstruction::Type::InsertToList, nullptr, false); + LLVMConstantRegister index(Compiler::StaticType::Number, 1); + LLVMConstantRegister value(Compiler::StaticType::String, "test"); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Number, &index }); + appendList->args.push_back({ Compiler::StaticType::Unknown, &value }); + instructionList.addInstruction(appendList); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + // Insert might be a no-op depending on the index + ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, true), Compiler::StaticType::String); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleInsertDifferentType_Empty_UnknownType) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + auto appendList = std::make_shared(LLVMInstruction::Type::InsertToList, nullptr, false); + LLVMConstantRegister index(Compiler::StaticType::Number, 1); + LLVMConstantRegister value(Compiler::StaticType::String, "test"); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Number, &index }); + appendList->args.push_back({ Compiler::StaticType::Unknown, &value }); + instructionList.addInstruction(appendList); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + // Insert might be a no-op depending on the index + ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Unknown, true), Compiler::StaticType::String); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleInsertDifferentType_NonEmpty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + auto appendList = std::make_shared(LLVMInstruction::Type::InsertToList, nullptr, false); + LLVMConstantRegister index(Compiler::StaticType::Number, 1); + LLVMConstantRegister value(Compiler::StaticType::String, "test"); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Number, &index }); + appendList->args.push_back({ Compiler::StaticType::Unknown, &value }); + instructionList.addInstruction(appendList); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleReplaceDifferentType_Empty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + auto appendList = std::make_shared(LLVMInstruction::Type::ListReplace, nullptr, false); + LLVMConstantRegister index(Compiler::StaticType::Number, 1); + LLVMConstantRegister value(Compiler::StaticType::String, "test"); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Number, &index }); + appendList->args.push_back({ Compiler::StaticType::Unknown, &value }); + instructionList.addInstruction(appendList); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + // Since the list is empty, it's safe to return any type + // Let's return string in this case as the replace instruction indicates that string is used later + ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, true), Compiler::StaticType::String); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleReplaceDifferentType_NonEmpty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + auto appendList = std::make_shared(LLVMInstruction::Type::ListReplace, nullptr, false); + LLVMConstantRegister index(Compiler::StaticType::Number, 1); + LLVMConstantRegister value(Compiler::StaticType::String, "test"); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Number, &index }); + appendList->args.push_back({ Compiler::StaticType::Unknown, &value }); + instructionList.addInstruction(appendList); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, MultipleAppendsDifferentTypes_Empty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + // First append: string "abc" (incompatible with Number) + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::String, "abc"); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + // Second append: number 5.25 (compatible with Number pre-loop type) + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::Number, 5.25); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + // Should return Unknown because first append creates type conflict with pre-loop Number type + ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, MultipleAppendsDifferentTypes_NonEmpty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + // First append: string "abc" (incompatible with Number) + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::String, "abc"); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + // Second append: number 5.25 (compatible with Number pre-loop type) + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::Number, 5.25); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + // Should return Unknown because first append creates type conflict with pre-loop Number type + ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, MultipleAppendsWithStringOptimization) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + // First append: number 2 (compatible with Number) + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 2); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + // Second append: string "3.14" (optimized to Number, compatible with pre-loop type) + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::String, "3.14"); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + // Should return Number because final append is optimized to Number type + ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, MultipleAppendsDifferentTypes_IfStatement) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + instructionList.addInstruction(start); + + // First append: string "abc" (incompatible with Number) + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::String, "abc"); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + // Second append: number 5.25 (compatible with Number type) + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::Number, 5.25); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + auto end = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + instructionList.addInstruction(end); + + // Should return Unknown because first append creates type conflict with Number type + ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, MultipleAppendsDifferentTypes_IfBranch) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + instructionList.addInstruction(start); + + // First append: string "abc" (incompatible with Number) + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::String, "abc"); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + // Second append: number 5.25 (compatible with Number type) + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::Number, 5.25); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + auto elseStart = std::make_shared(LLVMInstruction::Type::BeginElse, nullptr, false); + instructionList.addInstruction(elseStart); + + // Else branch append: string "test" (incompatible with Number type) + auto appendList3 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value3(Compiler::StaticType::String, "test"); + appendList3->workList = &list; + appendList3->args.push_back({ Compiler::StaticType::Unknown, &value3 }); + instructionList.addInstruction(appendList3); + + auto end = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + instructionList.addInstruction(end); + + // Should return Unknown because first append in if branch creates type conflict + ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, MultipleAppendsSameType_ElseBranch) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + instructionList.addInstruction(start); + + // First append: string "abc" (incompatible with Number) + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::String, "abc"); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + auto elseStart = std::make_shared(LLVMInstruction::Type::BeginElse, nullptr, false); + instructionList.addInstruction(elseStart); + + // Else branch first append: string "abc" (incompatible with Number) + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::String, "abc"); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + // Else branch second append: number 5.25 (compatible with Number type) + auto appendList3 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value3(Compiler::StaticType::Number, 5.25); + appendList3->workList = &list; + appendList3->args.push_back({ Compiler::StaticType::Unknown, &value3 }); + instructionList.addInstruction(appendList3); + + auto end = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + instructionList.addInstruction(end); + + // Should return Unknown because first append in else branch creates type conflict + ASSERT_EQ(analyzer.listTypeAfterBranch(&list, elseStart.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, IfStatementInLoop_TypeChangeInIfBranch) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + auto ifStart = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + instructionList.addInstruction(ifStart); + + // First append - changes type + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::String, "test"); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + auto elseStart = std::make_shared(LLVMInstruction::Type::BeginElse, nullptr, false); + instructionList.addInstruction(elseStart); + + // Second append - does not change type + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::Number, 42); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + auto ifEnd = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + instructionList.addInstruction(ifEnd); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + // Returns unknown type because the type-changing branch might or might not run + ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, IfStatementInLoop_TypeChangeInElseBranch) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + auto ifStart = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + instructionList.addInstruction(ifStart); + + // First append - does not change type + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 42); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + auto elseStart = std::make_shared(LLVMInstruction::Type::BeginElse, nullptr, false); + instructionList.addInstruction(elseStart); + + // Second append - changes type + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::String, "test"); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + auto ifEnd = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + instructionList.addInstruction(ifEnd); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + // Returns unknown type because the type-changing branch might or might not run + ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, IfStatementInLoop_IfElseWithoutTypeChange) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + auto ifStart = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + instructionList.addInstruction(ifStart); + + // First append - does not change type + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 42); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + auto elseStart = std::make_shared(LLVMInstruction::Type::BeginElse, nullptr, false); + instructionList.addInstruction(elseStart); + + // Second append - does not change type + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::Number, 1.25); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + auto ifEnd = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + instructionList.addInstruction(ifEnd); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, MultipleInsertsDifferentTypes) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + // First insert: number + auto insertList1 = std::make_shared(LLVMInstruction::Type::InsertToList, nullptr, false); + LLVMConstantRegister index1(Compiler::StaticType::Number, 1); + LLVMConstantRegister value1(Compiler::StaticType::Number, 42); + insertList1->workList = &list; + insertList1->args.push_back({ Compiler::StaticType::Number, &index1 }); + insertList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(insertList1); + + // Second insert: string (creates type conflict) + auto insertList2 = std::make_shared(LLVMInstruction::Type::InsertToList, nullptr, false); + LLVMConstantRegister index2(Compiler::StaticType::Number, 1); + LLVMConstantRegister value2(Compiler::StaticType::String, "test"); + insertList2->workList = &list; + insertList2->args.push_back({ Compiler::StaticType::Number, &index2 }); + insertList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(insertList2); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, MultipleReplacesDifferentTypes) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + // First replace: compatible with Bool + auto replaceList1 = std::make_shared(LLVMInstruction::Type::ListReplace, nullptr, false); + LLVMConstantRegister index1(Compiler::StaticType::Number, 1); + LLVMConstantRegister value1(Compiler::StaticType::Bool, true); + replaceList1->workList = &list; + replaceList1->args.push_back({ Compiler::StaticType::Number, &index1 }); + replaceList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(replaceList1); + + // Second replace: incompatible with Bool + auto replaceList2 = std::make_shared(LLVMInstruction::Type::ListReplace, nullptr, false); + LLVMConstantRegister index2(Compiler::StaticType::Number, 2); + LLVMConstantRegister value2(Compiler::StaticType::String, "test"); + replaceList2->workList = &list; + replaceList2->args.push_back({ Compiler::StaticType::Number, &index2 }); + replaceList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(replaceList2); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Bool, false), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, CombinedAppendInsertReplace_SameTypes) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + // First: append number (compatible with Number) + auto appendList = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister appendValue(Compiler::StaticType::Number, 42); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Unknown, &appendValue }); + instructionList.addInstruction(appendList); + + // Second: insert number (compatible with Number) + auto insertList = std::make_shared(LLVMInstruction::Type::InsertToList, nullptr, false); + LLVMConstantRegister insertIndex(Compiler::StaticType::Number, 1); + LLVMConstantRegister insertValue(Compiler::StaticType::Number, 5); + insertList->workList = &list; + insertList->args.push_back({ Compiler::StaticType::Number, &insertIndex }); + insertList->args.push_back({ Compiler::StaticType::Unknown, &insertValue }); + instructionList.addInstruction(insertList); + + // Third: replace with number (compatible with Number) + auto replaceList = std::make_shared(LLVMInstruction::Type::ListReplace, nullptr, false); + LLVMConstantRegister replaceIndex(Compiler::StaticType::Number, 2); + LLVMConstantRegister replaceValue(Compiler::StaticType::Number, 3.14); + replaceList->workList = &list; + replaceList->args.push_back({ Compiler::StaticType::Number, &replaceIndex }); + replaceList->args.push_back({ Compiler::StaticType::Unknown, &replaceValue }); + instructionList.addInstruction(replaceList); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + // Should return Number because only numbers are used + ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, CombinedAppendInsertReplace_TypeConflict) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + // First: append number (compatible with Number) + auto appendList = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister appendValue(Compiler::StaticType::Number, 42); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Unknown, &appendValue }); + instructionList.addInstruction(appendList); + + // Second: insert string (creates type conflict) + auto insertList = std::make_shared(LLVMInstruction::Type::InsertToList, nullptr, false); + LLVMConstantRegister insertIndex(Compiler::StaticType::Number, 0); + LLVMConstantRegister insertValue(Compiler::StaticType::String, "hello"); + insertList->workList = &list; + insertList->args.push_back({ Compiler::StaticType::Number, &insertIndex }); + insertList->args.push_back({ Compiler::StaticType::Unknown, &insertValue }); + instructionList.addInstruction(insertList); + + // Third: replace with number (still conflicted) + auto replaceList = std::make_shared(LLVMInstruction::Type::ListReplace, nullptr, false); + LLVMConstantRegister replaceIndex(Compiler::StaticType::Number, 1); + LLVMConstantRegister replaceValue(Compiler::StaticType::Number, 3.14); + replaceList->workList = &list; + replaceList->args.push_back({ Compiler::StaticType::Number, &replaceIndex }); + replaceList->args.push_back({ Compiler::StaticType::Unknown, &replaceValue }); + instructionList.addInstruction(replaceList); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + // Should return Unknown because insert created type conflict + ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, NestedLoopWithTypeChange) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + // Outer loop begin + auto outerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(outerLoop); + + // List append inside outer loop + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 5); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + // Inner loop begin + auto innerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(innerLoop); + + // List append inside inner loop (creates type conflict) + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::String, "test"); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + // Inner loop end + auto innerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(innerEnd); + + // Outer loop end + auto outerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(outerEnd); + + ASSERT_EQ(analyzer.listTypeAfterBranch(&list, outerLoop.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, NestedLoopWithoutTypeChange) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + // Outer loop begin + auto outerLoop = std::make_shared(LLVMInstruction::Type::BeginWhileLoop, nullptr, false); + instructionList.addInstruction(outerLoop); + + // List append inside outer loop + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 5); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + // Inner loop begin + auto innerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(innerLoop); + + // List append inside inner loop (same type) + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::Number, 2.5); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + // Inner loop end + auto innerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(innerEnd); + + // Outer loop end + auto outerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(outerEnd); + + ASSERT_EQ(analyzer.listTypeAfterBranch(&list, outerLoop.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, NestedLoopWithTypeChangeBeforeLoop) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + // Outer loop begin + auto outerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatUntilLoop, nullptr, false); + instructionList.addInstruction(outerLoop); + + // List append inside outer loop (creates type conflict) + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::String, "test"); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + // Inner loop begin + auto innerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(innerLoop); + + // List append inside inner loop + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::Number, 5); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + // Inner loop end + auto innerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(innerEnd); + + // Outer loop end + auto outerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(outerEnd); + + // Returns unknown type because first append creates type conflict + ASSERT_EQ(analyzer.listTypeAfterBranch(&list, outerLoop.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, IfStatementInLoopWithTypeChangeBeforeLoop_TypeChangeInIfBranch) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + // Outer loop begin + auto outerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatUntilLoop, nullptr, false); + instructionList.addInstruction(outerLoop); + + // List append inside outer loop (creates type conflict) + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::String, "test"); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + // Inner if statement begin + auto innerIf = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + instructionList.addInstruction(innerIf); + + // List append inside inner if statement if branch + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::Number, 5); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + // Inner if statement else branch begin + auto innerElse = std::make_shared(LLVMInstruction::Type::BeginElse, nullptr, false); + instructionList.addInstruction(innerElse); + + // Inner if statement end + auto innerEnd = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + instructionList.addInstruction(innerEnd); + + // Outer loop end + auto outerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(outerEnd); + + // Returns unknown type because first append already created type conflict + ASSERT_EQ(analyzer.listTypeAfterBranch(&list, outerLoop.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, MultipleNestedLoopsWithTypeChange) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + // Outer loop begin + auto outerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(outerLoop); + + // List append inside outer loop + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 5); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + // Inner loop 1 begin + auto innerLoop1 = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(innerLoop1); + + // List append inside inner loop 1 + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::Number, 2.75); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + // Inner loop 2 begin + auto innerLoop2 = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(innerLoop2); + + // List append inside inner loop 2 (creates type conflict) + auto appendList3 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value3(Compiler::StaticType::String, "abc"); + appendList3->workList = &list; + appendList3->args.push_back({ Compiler::StaticType::Unknown, &value3 }); + instructionList.addInstruction(appendList3); + + // Inner loop 2 end + auto innerEnd2 = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(innerEnd2); + + // Inner loop 1 end + auto innerEnd1 = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(innerEnd1); + + // Outer loop end + auto outerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(outerEnd); + + ASSERT_EQ(analyzer.listTypeAfterBranch(&list, outerLoop.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, MultipleNestedIfStatementsWithTypeChange_IfBranch) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + // Outer if statement begin + auto outerIf = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + instructionList.addInstruction(outerIf); + + // List append inside outer if statement + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 5); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + // Inner if statement 1 begin + auto innerIf1 = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + instructionList.addInstruction(innerIf1); + + // List append inside inner if statement 1 + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::Number, 2.75); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + // Inner if statement 2 begin + auto innerIf2 = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + instructionList.addInstruction(innerIf2); + + // List append inside inner if statement 2 (creates type conflict) + auto appendList3 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value3(Compiler::StaticType::String, "abc"); + appendList3->workList = &list; + appendList3->args.push_back({ Compiler::StaticType::Unknown, &value3 }); + instructionList.addInstruction(appendList3); + + // Inner if statement 2 else branch + auto innerElse2 = std::make_shared(LLVMInstruction::Type::BeginElse, nullptr, false); + instructionList.addInstruction(innerElse2); + + // List append inside inner if statement 2 else branch + auto appendList4 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value4(Compiler::StaticType::Number, 4); + appendList4->workList = &list; + appendList4->args.push_back({ Compiler::StaticType::Unknown, &value4 }); + instructionList.addInstruction(appendList4); + + // Inner if statement 2 end + auto innerEnd2 = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + instructionList.addInstruction(innerEnd2); + + // Inner if statement 1 end + auto innerEnd1 = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + instructionList.addInstruction(innerEnd1); + + // Outer if statement end + auto outerEnd = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + instructionList.addInstruction(outerEnd); + + ASSERT_EQ(analyzer.listTypeAfterBranch(&list, outerIf.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, MultipleNestedIfStatementsWithTypeChange_ElseBranch) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + // Outer if statement begin + auto outerIf = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + instructionList.addInstruction(outerIf); + + // List append inside outer if statement + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 5); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + // Inner if statement 1 begin + auto innerIf1 = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + instructionList.addInstruction(innerIf1); + + // List append inside inner if statement 1 + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::Number, 2.75); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + // Inner if statement 2 begin + auto innerIf2 = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + instructionList.addInstruction(innerIf2); + + // List append inside inner if statement 2 + auto appendList3 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value3(Compiler::StaticType::Number, 4); + appendList3->workList = &list; + appendList3->args.push_back({ Compiler::StaticType::Unknown, &value3 }); + instructionList.addInstruction(appendList3); + + // Inner if statement 2 else branch + auto innerElse2 = std::make_shared(LLVMInstruction::Type::BeginElse, nullptr, false); + instructionList.addInstruction(innerElse2); + + // List append inside inner if statement 2 else branch (creates type conflict) + auto appendList4 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value4(Compiler::StaticType::String, "abc"); + appendList4->workList = &list; + appendList4->args.push_back({ Compiler::StaticType::Unknown, &value4 }); + instructionList.addInstruction(appendList4); + + // Inner if statement 2 end + auto innerEnd2 = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + instructionList.addInstruction(innerEnd2); + + // Inner if statement 1 end + auto innerEnd1 = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + instructionList.addInstruction(innerEnd1); + + // Outer if statement end + auto outerEnd = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + instructionList.addInstruction(outerEnd); + + ASSERT_EQ(analyzer.listTypeAfterBranch(&list, outerIf.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, MultipleNestedIfStatementsWithoutTypeChange) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + // Outer if statement begin + auto outerIf = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + instructionList.addInstruction(outerIf); + + // List append inside outer if statement + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 5); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + // Inner if statement 1 begin + auto innerIf1 = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + instructionList.addInstruction(innerIf1); + + // List append inside inner if statement 1 + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::Number, 2.75); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + // Inner if statement 2 begin + auto innerIf2 = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + instructionList.addInstruction(innerIf2); + + // List append inside inner if statement 2 + auto appendList3 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value3(Compiler::StaticType::Number, 4); + appendList3->workList = &list; + appendList3->args.push_back({ Compiler::StaticType::Unknown, &value3 }); + instructionList.addInstruction(appendList3); + + // Inner if statement 2 else branch + auto innerElse2 = std::make_shared(LLVMInstruction::Type::BeginElse, nullptr, false); + instructionList.addInstruction(innerElse2); + + // List append inside inner if statement 2 else branch (same type) + auto appendList4 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value4(Compiler::StaticType::Number, 0); + appendList4->workList = &list; + appendList4->args.push_back({ Compiler::StaticType::Unknown, &value4 }); + instructionList.addInstruction(appendList4); + + // Inner if statement 2 end + auto innerEnd2 = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + instructionList.addInstruction(innerEnd2); + + // Inner if statement 1 end + auto innerEnd1 = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + instructionList.addInstruction(innerEnd1); + + // Outer if statement end + auto outerEnd = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + instructionList.addInstruction(outerEnd); + + ASSERT_EQ(analyzer.listTypeAfterBranch(&list, outerIf.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number); +} From f9afdfc63123ebfc0d54d4199a274c05c6f07660 Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Wed, 30 Jul 2025 12:19:43 +0200 Subject: [PATCH 40/79] LLVMTypeAnalyzer: Handle list clear instruction --- src/engine/internal/llvm/llvmtypeanalyzer.cpp | 112 +-- src/engine/internal/llvm/llvmtypeanalyzer.h | 2 + .../listtypeafterbranch_test.cpp | 703 ++++++++++++++++++ 3 files changed, 762 insertions(+), 55 deletions(-) diff --git a/src/engine/internal/llvm/llvmtypeanalyzer.cpp b/src/engine/internal/llvm/llvmtypeanalyzer.cpp index b4ccebb17..b80fa7f68 100644 --- a/src/engine/internal/llvm/llvmtypeanalyzer.cpp +++ b/src/engine/internal/llvm/llvmtypeanalyzer.cpp @@ -27,61 +27,8 @@ Compiler::StaticType LLVMTypeAnalyzer::listTypeAfterBranch(List *list, LLVMInstr if (!list || !start) return previousType; - assert(isLoopStart(start) || isIfStart(start) || isElse(start)); - - InstructionSet visitedInstructions; // TODO: Handle cross-variable/list dependencies - - LLVMInstruction *ins = start->next; - LLVMInstruction *lastWrite = nullptr; - Compiler::StaticType lastWriteType = Compiler::StaticType::Unknown; - int level = 0; - - while (ins && !((isLoopEnd(ins) || isIfEnd(ins) || isElse(ins)) && level == 0)) { - if (isLoopStart(ins) || isIfStart(ins)) - level++; - else if (isLoopEnd(ins) || isIfEnd(ins)) { - assert(level > 0); - level--; - } else if (isListWrite(ins, list)) { - // List write instruction - Compiler::StaticType writeType = writeValueType(ins, visitedInstructions); - - // For non-empty lists, we can just check the write type - if (!isEmpty && !typesMatch(writeType, previousType)) { - return Compiler::StaticType::Unknown; - } - - // In empty lists, writes of the same type determine the final type - if (isEmpty) { - if (lastWrite) { - // There was a write before which means it might determine the final type - if (!typesMatch(writeType, lastWriteType)) - return Compiler::StaticType::Unknown; - } else { - // This is the first write found, it might determine the final type - lastWrite = ins; - lastWriteType = writeType; - } - } - } - - ins = ins->next; - } - - assert(ins); - - if (isEmpty) { - if (lastWrite) { - // Only writes of the same type modify the list - return lastWriteType; - } else { - // No writes to empty list found, keep the previous type - return previousType; - } - } else { - // No type conflicts found for non-empty list - return previousType; - } + bool write = false; // only used internally (the compiler doesn't need this) + return listTypeAfterBranch(list, start, previousType, isEmpty, write); } Compiler::StaticType LLVMTypeAnalyzer::variableType(Variable *var, LLVMInstruction *pos, Compiler::StaticType previousType, InstructionSet &visitedInstructions) const @@ -234,6 +181,61 @@ Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranchFromEnd(Variable * return previousType; } +Compiler::StaticType LLVMTypeAnalyzer::listTypeAfterBranch(List *list, LLVMInstruction *start, Compiler::StaticType previousType, bool isEmpty, bool &write) const +{ + assert(isLoopStart(start) || isIfStart(start) || isElse(start)); + + InstructionSet visitedInstructions; // TODO: Handle cross-variable/list dependencies + + LLVMInstruction *ins = start->next; + write = false; + + while (ins && !(isLoopEnd(ins) || isIfEnd(ins) || isElse(ins))) { + if (isLoopStart(ins) || isIfStart(ins)) { + do { + Compiler::StaticType type = listTypeAfterBranch(list, ins, previousType, isEmpty, write); + + // If there was a write, the list is no longer empty + if (write) { + isEmpty = false; + + // The write could change the type + if (!typesMatch(type, previousType)) + return Compiler::StaticType::Unknown; + } + + // Skip the branch + ins = branchEnd(ins); + } while (isElse(ins)); // handle else branch + } else if (isListWrite(ins, list)) { + // List write instruction + Compiler::StaticType writeType = writeValueType(ins, visitedInstructions); + write = true; + + if (isEmpty) { + // In empty lists, writes of the same type determine the final type + // This is the first write found, it might determine the final type + previousType = writeType; + + // The list is no longer empty + isEmpty = false; + } else if (!typesMatch(writeType, previousType)) { + // For non-empty lists, we can just check the write type + return Compiler::StaticType::Unknown; + } + } else if (ins->type == LLVMInstruction::Type::ClearList && ins->workList == list) { + // The list is now empty + isEmpty = true; + write = false; // the write variable is only used to check if the list is still empty + } + + ins = ins->next; + } + + assert(ins); + return previousType; +} + LLVMInstruction *LLVMTypeAnalyzer::branchEnd(LLVMInstruction *start) const { assert(start); diff --git a/src/engine/internal/llvm/llvmtypeanalyzer.h b/src/engine/internal/llvm/llvmtypeanalyzer.h index 046b29b8b..187470a3d 100644 --- a/src/engine/internal/llvm/llvmtypeanalyzer.h +++ b/src/engine/internal/llvm/llvmtypeanalyzer.h @@ -23,6 +23,8 @@ class LLVMTypeAnalyzer Compiler::StaticType variableTypeAfterBranch(Variable *var, LLVMInstruction *start, Compiler::StaticType previousType, InstructionSet &visitedInstructions) const; Compiler::StaticType variableTypeAfterBranchFromEnd(Variable *var, LLVMInstruction *end, Compiler::StaticType previousType, bool &write, InstructionSet &visitedInstructions) const; + Compiler::StaticType listTypeAfterBranch(List *list, LLVMInstruction *start, Compiler::StaticType previousType, bool isEmpty, bool &write) const; + LLVMInstruction *branchEnd(LLVMInstruction *start) const; LLVMInstruction *branchStart(LLVMInstruction *end) const; diff --git a/test/llvm/type_analyzer/listtypeafterbranch_test.cpp b/test/llvm/type_analyzer/listtypeafterbranch_test.cpp index 80d6258b5..8169e875d 100644 --- a/test/llvm/type_analyzer/listtypeafterbranch_test.cpp +++ b/test/llvm/type_analyzer/listtypeafterbranch_test.cpp @@ -1668,3 +1668,706 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, MultipleNestedIfStatementsWithoutType ASSERT_EQ(analyzer.listTypeAfterBranch(&list, outerIf.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number); } + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, AppendToEmptyListInIfBranch) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + auto ifStart = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + instructionList.addInstruction(ifStart); + + // Append in if branch + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 5); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + auto ifEnd = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + instructionList.addInstruction(ifEnd); + + // Append after if statement - the list might not be empty anymore + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::String, "test"); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + // Should return Unknown because the list might not be empty when the type changes + ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, AppendToEmptyListInElseBranch) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + auto ifStart = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + instructionList.addInstruction(ifStart); + + auto elseStart = std::make_shared(LLVMInstruction::Type::BeginElse, nullptr, false); + instructionList.addInstruction(elseStart); + + // Append in else branch + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 5); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + auto ifEnd = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + instructionList.addInstruction(ifEnd); + + // Append after if statement - the list might not be empty anymore + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::String, "test"); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + // Should return Unknown because the list might not be empty when the type changes + ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, ClearListInLoop_NewTypeAfterClear_Empty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + // Clear the list in the middle of the loop + auto clearList = std::make_shared(LLVMInstruction::Type::ClearList, nullptr, false); + clearList->workList = &list; + instructionList.addInstruction(clearList); + + // Append after clear - this should set the new type + auto appendList = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::String, "test"); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Unknown, &value }); + instructionList.addInstruction(appendList); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + // Should return String because the list was empty and append sets the type + ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, true), Compiler::StaticType::String); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, ClearListInLoop_NewTypeAfterClear_NonEmpty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + // Clear the list in the middle of the loop + auto clearList = std::make_shared(LLVMInstruction::Type::ClearList, nullptr, false); + clearList->workList = &list; + instructionList.addInstruction(clearList); + + // Append after clear - this should set the new type + auto appendList = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::String, "test"); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Unknown, &value }); + instructionList.addInstruction(appendList); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + // Should return String because clear makes the list empty, then append sets the type + ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, false), Compiler::StaticType::String); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, ClearListInLoop_MultipleAppendsAfterClear) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + // Clear the list + auto clearList = std::make_shared(LLVMInstruction::Type::ClearList, nullptr, false); + clearList->workList = &list; + instructionList.addInstruction(clearList); + + // First append after clear + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 42); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + // Second append after clear (same type) + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::Number, 3.14); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + // Should return Number because all appends after clear are the same type + ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::String, false), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, ClearListInLoop_TypeConflictAfterClear) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + // Clear the list + auto clearList = std::make_shared(LLVMInstruction::Type::ClearList, nullptr, false); + clearList->workList = &list; + instructionList.addInstruction(clearList); + + // First append after clear + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 42); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + // Second append after clear (different type - creates conflict) + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::String, "test"); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + // Should return Unknown because of type conflict after clear + ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::String, false), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, ClearListInLoop_WithInsertAndReplace) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + // Clear the list + auto clearList = std::make_shared(LLVMInstruction::Type::ClearList, nullptr, false); + clearList->workList = &list; + instructionList.addInstruction(clearList); + + // Insert after clear + auto insertList = std::make_shared(LLVMInstruction::Type::InsertToList, nullptr, false); + LLVMConstantRegister insertIndex(Compiler::StaticType::Number, 0); + LLVMConstantRegister insertValue(Compiler::StaticType::Bool, true); + insertList->workList = &list; + insertList->args.push_back({ Compiler::StaticType::Number, &insertIndex }); + insertList->args.push_back({ Compiler::StaticType::Unknown, &insertValue }); + instructionList.addInstruction(insertList); + + // Replace after insert + auto replaceList = std::make_shared(LLVMInstruction::Type::ListReplace, nullptr, false); + LLVMConstantRegister replaceIndex(Compiler::StaticType::Number, 0); + LLVMConstantRegister replaceValue(Compiler::StaticType::Bool, false); + replaceList->workList = &list; + replaceList->args.push_back({ Compiler::StaticType::Number, &replaceIndex }); + replaceList->args.push_back({ Compiler::StaticType::Unknown, &replaceValue }); + instructionList.addInstruction(replaceList); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + // Should return Bool because all operations after clear use Bool type + ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Bool); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, ClearListInLoop_ConditionalClear) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + // If statement + auto ifStart = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + instructionList.addInstruction(ifStart); + + // Clear the list conditionally + auto clearList = std::make_shared(LLVMInstruction::Type::ClearList, nullptr, false); + clearList->workList = &list; + instructionList.addInstruction(clearList); + + // Append after clear + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::String, "cleared"); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + // Else branch + auto elseStart = std::make_shared(LLVMInstruction::Type::BeginElse, nullptr, false); + instructionList.addInstruction(elseStart); + + // Append without clearing + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::Number, 42); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + auto ifEnd = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + instructionList.addInstruction(ifEnd); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + // Should return Unknown due to type conflict between branches + ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, ClearListInLoop_AppendAfterClearingInIfBranch_DifferentType) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + // If statement + auto ifStart = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + instructionList.addInstruction(ifStart); + + // Clear the list + auto clearList = std::make_shared(LLVMInstruction::Type::ClearList, nullptr, false); + clearList->workList = &list; + instructionList.addInstruction(clearList); + + // End if statement + auto ifEnd = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + instructionList.addInstruction(ifEnd); + + // Append + auto appendList = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::String, "test"); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Unknown, &value }); + instructionList.addInstruction(appendList); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + // Should return Unknown because the clearing branch might or might not run + ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, ClearListInLoop_AppendAfterClearingInIfBranch_SameType) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + // If statement + auto ifStart = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + instructionList.addInstruction(ifStart); + + // Clear the list + auto clearList = std::make_shared(LLVMInstruction::Type::ClearList, nullptr, false); + clearList->workList = &list; + instructionList.addInstruction(clearList); + + // End if statement + auto ifEnd = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + instructionList.addInstruction(ifEnd); + + // Append + auto appendList = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::Number, 42); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Unknown, &value }); + instructionList.addInstruction(appendList); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + // Should return Number because there are no type conflicts + ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, ClearListInLoop_AppendAfterClearingInElseBranch_DifferentType) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + // If statement + auto ifStart = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + instructionList.addInstruction(ifStart); + + // Else branch + auto elseStart = std::make_shared(LLVMInstruction::Type::BeginElse, nullptr, false); + instructionList.addInstruction(elseStart); + + // Clear the list + auto clearList = std::make_shared(LLVMInstruction::Type::ClearList, nullptr, false); + clearList->workList = &list; + instructionList.addInstruction(clearList); + + // End if statement + auto ifEnd = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + instructionList.addInstruction(ifEnd); + + // Append + auto appendList = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::String, "test"); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Unknown, &value }); + instructionList.addInstruction(appendList); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + // Should return Unknown because the clearing branch might or might not run + ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, ClearListInLoop_AppendAfterClearingInElseBranch_SameType) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + // If statement + auto ifStart = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + instructionList.addInstruction(ifStart); + + // Else branch + auto elseStart = std::make_shared(LLVMInstruction::Type::BeginElse, nullptr, false); + instructionList.addInstruction(elseStart); + + // Clear the list + auto clearList = std::make_shared(LLVMInstruction::Type::ClearList, nullptr, false); + clearList->workList = &list; + instructionList.addInstruction(clearList); + + // End if statement + auto ifEnd = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + instructionList.addInstruction(ifEnd); + + // Append + auto appendList = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::Number, 42); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Unknown, &value }); + instructionList.addInstruction(appendList); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + // Should return Number because there are no type conflicts + ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, ClearListInLoop_MultipleClearsAndWrites) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + // First clear + auto clearList1 = std::make_shared(LLVMInstruction::Type::ClearList, nullptr, false); + clearList1->workList = &list; + instructionList.addInstruction(clearList1); + + // Append after first clear + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::String, "first"); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + // Second clear + auto clearList2 = std::make_shared(LLVMInstruction::Type::ClearList, nullptr, false); + clearList2->workList = &list; + instructionList.addInstruction(clearList2); + + // Append after second clear (different type) + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::Number, 42); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + // Should return Number because the last clear+append sequence determines the final type + ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::String, false), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, ClearListInLoop_ClearWithoutSubsequentWrite) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + // Clear the list but don't write anything after + auto clearList = std::make_shared(LLVMInstruction::Type::ClearList, nullptr, false); + clearList->workList = &list; + instructionList.addInstruction(clearList); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + // Should return previous type since no writes occurred after clear + ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Bool, false), Compiler::StaticType::Bool); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, ClearListInLoop_ClearInNestedIf) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + // Nested if statement + auto ifStart = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + instructionList.addInstruction(ifStart); + + // Clear and write in nested if + auto clearList = std::make_shared(LLVMInstruction::Type::ClearList, nullptr, false); + clearList->workList = &list; + instructionList.addInstruction(clearList); + + auto appendList = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::Bool, true); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Unknown, &value }); + instructionList.addInstruction(appendList); + + auto ifEnd = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + instructionList.addInstruction(ifEnd); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + // Should return Unknown because the type-changing branch might or might not run + ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::String, false), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, ClearListInLoop_AppendToEmptyListAndClearInIfBranch_SameType) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + auto ifStart = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + instructionList.addInstruction(ifStart); + + // Append in if branch + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 5); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + // Clear the list in if branch + auto clearList = std::make_shared(LLVMInstruction::Type::ClearList, nullptr, false); + clearList->workList = &list; + instructionList.addInstruction(clearList); + + auto ifEnd = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + instructionList.addInstruction(ifEnd); + + // Append after if statement - should change type + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::String, "test"); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + // Should return String because the list remains empty after the if statement + ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, true), Compiler::StaticType::String); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, ClearListInLoop_AppendToEmptyListAndClearInIfBranch_DifferentType) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + auto ifStart = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + instructionList.addInstruction(ifStart); + + // Append in if branch + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Bool, true); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + // Clear the list in if branch + auto clearList = std::make_shared(LLVMInstruction::Type::ClearList, nullptr, false); + clearList->workList = &list; + instructionList.addInstruction(clearList); + + auto ifEnd = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + instructionList.addInstruction(ifEnd); + + // Append after if statement - should change type + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::String, "test"); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + // Should return String because the list remains empty after the if statement + ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, true), Compiler::StaticType::String); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, ClearListInLoop_AppendToEmptyListAndClearInElseBranch_SameType) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + auto ifStart = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + instructionList.addInstruction(ifStart); + + auto elseStart = std::make_shared(LLVMInstruction::Type::BeginElse, nullptr, false); + instructionList.addInstruction(elseStart); + + // Append in else branch + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 5); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + // Clear the list in else branch + auto clearList = std::make_shared(LLVMInstruction::Type::ClearList, nullptr, false); + clearList->workList = &list; + instructionList.addInstruction(clearList); + + auto ifEnd = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + instructionList.addInstruction(ifEnd); + + // Append after if statement - should change type + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::String, "test"); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + // Should return String because the list remains empty after the if statement + ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, true), Compiler::StaticType::String); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, ClearListInLoop_AppendToEmptyListAndClearInElseBranch_DifferentType) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + auto ifStart = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + instructionList.addInstruction(ifStart); + + auto elseStart = std::make_shared(LLVMInstruction::Type::BeginElse, nullptr, false); + instructionList.addInstruction(elseStart); + + // Append in else branch + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Bool, true); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + // Clear the list in else branch + auto clearList = std::make_shared(LLVMInstruction::Type::ClearList, nullptr, false); + clearList->workList = &list; + instructionList.addInstruction(clearList); + + auto ifEnd = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + instructionList.addInstruction(ifEnd); + + // Append after if statement - should change type + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::String, "test"); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + // Should return String because the list remains empty after the if statement + ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, true), Compiler::StaticType::String); +} From ac4920e3a2dba999c5fffbedb60b699be5e79789 Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Wed, 30 Jul 2025 18:58:33 +0200 Subject: [PATCH 41/79] LLVMTypeAnalyzer: Fix else branch handling in branchStart() --- src/engine/internal/llvm/llvmtypeanalyzer.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/engine/internal/llvm/llvmtypeanalyzer.cpp b/src/engine/internal/llvm/llvmtypeanalyzer.cpp index b80fa7f68..8b6f1406b 100644 --- a/src/engine/internal/llvm/llvmtypeanalyzer.cpp +++ b/src/engine/internal/llvm/llvmtypeanalyzer.cpp @@ -269,18 +269,14 @@ LLVMInstruction *LLVMTypeAnalyzer::branchStart(LLVMInstruction *end) const LLVMInstruction *ins = end->previous; int level = 0; - while (ins && !((isLoopStart(ins) || isIfStart(ins)) && level == 0)) { + while (ins && !((isLoopStart(ins) || isIfStart(ins) || isElse(ins)) && level == 0)) { if (isLoopStart(ins) || isIfStart(ins)) { assert(level > 0); level--; } - if (isLoopEnd(ins) || isIfEnd(ins) || isElse(ins)) { - if (isElse(ins) && level == 0) - break; - + if (isLoopEnd(ins) || isIfEnd(ins)) level++; - } ins = ins->previous; }; From 9fc99eb84aa98dc0e9530f3ae7438e18430461cc Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Thu, 31 Jul 2025 13:05:53 +0200 Subject: [PATCH 42/79] LLVMTypeAnalyzer: Implement listType() for basic cases --- src/engine/internal/llvm/llvmtypeanalyzer.cpp | 140 +- src/engine/internal/llvm/llvmtypeanalyzer.h | 5 +- test/llvm/CMakeLists.txt | 1 + test/llvm/type_analyzer/listtype_test.cpp | 3119 +++++++++++++++++ 4 files changed, 3249 insertions(+), 16 deletions(-) create mode 100644 test/llvm/type_analyzer/listtype_test.cpp diff --git a/src/engine/internal/llvm/llvmtypeanalyzer.cpp b/src/engine/internal/llvm/llvmtypeanalyzer.cpp index 8b6f1406b..63b1b0c47 100644 --- a/src/engine/internal/llvm/llvmtypeanalyzer.cpp +++ b/src/engine/internal/llvm/llvmtypeanalyzer.cpp @@ -22,13 +22,105 @@ Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranch(Variable *var, LL return variableTypeAfterBranch(var, start, previousType, visitedInstructions); } +Compiler::StaticType LLVMTypeAnalyzer::listType(List *list, LLVMInstruction *pos, Compiler::StaticType previousType, bool isEmpty) const +{ + if (!list || !pos) + return Compiler::StaticType::Unknown; + + InstructionSet visitedInstructions; // TODO: Handle cross-variable/list dependencies + + LLVMInstruction *ins = pos; + LLVMInstruction *previous = nullptr; + std::pair firstBranch = { nullptr, 0 }; + std::pair lastClear = { nullptr, 0 }; + int level = 0; + + // Find a start instruction (list clear in the top level or the first instruction) + while (ins) { + if (isLoopEnd(ins) || isIfEnd(ins)) + level++; + else if (isLoopStart(ins) || isIfStart(ins) || isElse(ins)) { + if (!isElse(ins)) + level--; + + if (!firstBranch.first || level < firstBranch.second) + firstBranch = { ins, level }; + } else if (isListClear(ins, list)) { + if (!lastClear.first || level < lastClear.second) + lastClear = { ins, level }; + } + + previous = ins; + ins = ins->previous; + } + + if (firstBranch.first) { + assert(firstBranch.second == level); + + // The first branch must be above the query point level + if (firstBranch.second == 0) + firstBranch.first = nullptr; + } + + // Clear must be in the top level + if (lastClear.second != level) + lastClear.first = nullptr; + + if (lastClear.first) { + ins = lastClear.first; + isEmpty = true; + } else + ins = previous; + + // Process from the start instruction + while (ins && ins != pos) { + if (isLoopStart(ins) || isIfStart(ins)) { + do { + bool write; + Compiler::StaticType type = listTypeAfterBranch(list, ins, previousType, isEmpty, pos, write); + + // If this branch contains the query point, return the final type + if (ins == firstBranch.first) { + if (isEmpty || typesMatch(type, previousType)) + return type; + else + return Compiler::StaticType::Unknown; + } + + // If there was a write, the list is no longer empty + if (write) { + isEmpty = false; + + // The write could change the type + if (!typesMatch(type, previousType)) + previousType = type; + } + + // Skip the branch + ins = branchEnd(ins); + } while (isElse(ins)); // handle else branch + } else if (isListWrite(ins, list)) { + // List write instruction + Compiler::StaticType writeType = writeValueType(ins, visitedInstructions); + + if (!handleListWrite(writeType, previousType, isEmpty)) + return Compiler::StaticType::Unknown; + } + + ins = ins->next; + } + + assert(ins); + return previousType; +} + Compiler::StaticType LLVMTypeAnalyzer::listTypeAfterBranch(List *list, LLVMInstruction *start, Compiler::StaticType previousType, bool isEmpty) const { if (!list || !start) return previousType; bool write = false; // only used internally (the compiler doesn't need this) - return listTypeAfterBranch(list, start, previousType, isEmpty, write); + return listTypeAfterBranch(list, start, previousType, isEmpty, nullptr, write); } Compiler::StaticType LLVMTypeAnalyzer::variableType(Variable *var, LLVMInstruction *pos, Compiler::StaticType previousType, InstructionSet &visitedInstructions) const @@ -181,19 +273,23 @@ Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranchFromEnd(Variable * return previousType; } -Compiler::StaticType LLVMTypeAnalyzer::listTypeAfterBranch(List *list, LLVMInstruction *start, Compiler::StaticType previousType, bool isEmpty, bool &write) const +Compiler::StaticType LLVMTypeAnalyzer::listTypeAfterBranch(List *list, LLVMInstruction *start, Compiler::StaticType previousType, bool isEmpty, LLVMInstruction *query, bool &write) const { assert(isLoopStart(start) || isIfStart(start) || isElse(start)); InstructionSet visitedInstructions; // TODO: Handle cross-variable/list dependencies + // Query point is only relevant in if statemenets because writes after them don't affect the result + if (isLoopStart(start)) + query = nullptr; + LLVMInstruction *ins = start->next; write = false; while (ins && !(isLoopEnd(ins) || isIfEnd(ins) || isElse(ins))) { if (isLoopStart(ins) || isIfStart(ins)) { do { - Compiler::StaticType type = listTypeAfterBranch(list, ins, previousType, isEmpty, write); + Compiler::StaticType type = listTypeAfterBranch(list, ins, previousType, isEmpty, query, write); // If there was a write, the list is no longer empty if (write) { @@ -212,22 +308,14 @@ Compiler::StaticType LLVMTypeAnalyzer::listTypeAfterBranch(List *list, LLVMInstr Compiler::StaticType writeType = writeValueType(ins, visitedInstructions); write = true; - if (isEmpty) { - // In empty lists, writes of the same type determine the final type - // This is the first write found, it might determine the final type - previousType = writeType; - - // The list is no longer empty - isEmpty = false; - } else if (!typesMatch(writeType, previousType)) { - // For non-empty lists, we can just check the write type + if (!handleListWrite(writeType, previousType, isEmpty)) return Compiler::StaticType::Unknown; - } - } else if (ins->type == LLVMInstruction::Type::ClearList && ins->workList == list) { + } else if (isListClear(ins, list)) { // The list is now empty isEmpty = true; write = false; // the write variable is only used to check if the list is still empty - } + } else if (ins == query) + break; ins = ins->next; } @@ -236,6 +324,23 @@ Compiler::StaticType LLVMTypeAnalyzer::listTypeAfterBranch(List *list, LLVMInstr return previousType; } +bool LLVMTypeAnalyzer::handleListWrite(Compiler::StaticType writeType, Compiler::StaticType &previousType, bool &isEmpty) const +{ + if (isEmpty) { + // In empty lists, writes of the same type determine the final type + // This is the first write found, it might determine the final type + previousType = writeType; + + // The list is no longer empty + isEmpty = false; + } else if (!typesMatch(writeType, previousType)) { + // For non-empty lists, we can just check the write type + return false; + } + + return true; +} + LLVMInstruction *LLVMTypeAnalyzer::branchEnd(LLVMInstruction *start) const { assert(start); @@ -325,6 +430,11 @@ bool LLVMTypeAnalyzer::isListWrite(LLVMInstruction *ins, List *list) const return (LIST_WRITE_INSTRUCTIONS.find(ins->type) != LIST_WRITE_INSTRUCTIONS.cend() && ins->workList == list); } +bool LLVMTypeAnalyzer::isListClear(LLVMInstruction *ins, List *list) const +{ + return (ins->type == LLVMInstruction::Type::ClearList && ins->workList == list); +} + Compiler::StaticType LLVMTypeAnalyzer::optimizeRegisterType(LLVMRegister *reg) const { // TODO: Move this method out if it's used in LLVMCodeBuilder too diff --git a/src/engine/internal/llvm/llvmtypeanalyzer.h b/src/engine/internal/llvm/llvmtypeanalyzer.h index 187470a3d..35b497327 100644 --- a/src/engine/internal/llvm/llvmtypeanalyzer.h +++ b/src/engine/internal/llvm/llvmtypeanalyzer.h @@ -14,6 +14,7 @@ class LLVMTypeAnalyzer Compiler::StaticType variableType(Variable *var, LLVMInstruction *pos, Compiler::StaticType previousType) const; Compiler::StaticType variableTypeAfterBranch(Variable *var, LLVMInstruction *start, Compiler::StaticType previousType) const; + Compiler::StaticType listType(List *list, LLVMInstruction *pos, Compiler::StaticType previousType, bool isEmpty) const; Compiler::StaticType listTypeAfterBranch(List *list, LLVMInstruction *start, Compiler::StaticType previousType, bool isEmpty) const; private: @@ -23,7 +24,8 @@ class LLVMTypeAnalyzer Compiler::StaticType variableTypeAfterBranch(Variable *var, LLVMInstruction *start, Compiler::StaticType previousType, InstructionSet &visitedInstructions) const; Compiler::StaticType variableTypeAfterBranchFromEnd(Variable *var, LLVMInstruction *end, Compiler::StaticType previousType, bool &write, InstructionSet &visitedInstructions) const; - Compiler::StaticType listTypeAfterBranch(List *list, LLVMInstruction *start, Compiler::StaticType previousType, bool isEmpty, bool &write) const; + Compiler::StaticType listTypeAfterBranch(List *list, LLVMInstruction *start, Compiler::StaticType previousType, bool isEmpty, LLVMInstruction *query, bool &write) const; + bool handleListWrite(Compiler::StaticType writeType, Compiler::StaticType &previousType, bool &isEmpty) const; LLVMInstruction *branchEnd(LLVMInstruction *start) const; LLVMInstruction *branchStart(LLVMInstruction *end) const; @@ -38,6 +40,7 @@ class LLVMTypeAnalyzer bool isVariableWrite(LLVMInstruction *ins, Variable *var) const; bool isListWrite(LLVMInstruction *ins, List *list) const; + bool isListClear(LLVMInstruction *ins, List *list) const; Compiler::StaticType optimizeRegisterType(LLVMRegister *reg) const; bool isWriteNoOp(LLVMInstruction *ins) const; diff --git a/test/llvm/CMakeLists.txt b/test/llvm/CMakeLists.txt index e1d005cc4..95330a1d0 100644 --- a/test/llvm/CMakeLists.txt +++ b/test/llvm/CMakeLists.txt @@ -23,6 +23,7 @@ add_executable( type_analyzer/variabletypeafterbranch_test.cpp type_analyzer/variabletype_test.cpp type_analyzer/listtypeafterbranch_test.cpp + type_analyzer/listtype_test.cpp ) target_link_libraries( diff --git a/test/llvm/type_analyzer/listtype_test.cpp b/test/llvm/type_analyzer/listtype_test.cpp new file mode 100644 index 000000000..119307476 --- /dev/null +++ b/test/llvm/type_analyzer/listtype_test.cpp @@ -0,0 +1,3119 @@ +#include +#include +#include +#include +#include +#include + +using namespace libscratchcpp; + +TEST(LLVMTypeAnalyzer_ListType, NullParams) +{ + LLVMTypeAnalyzer analyzer; + ASSERT_EQ(analyzer.listType(nullptr, nullptr, Compiler::StaticType::Number, false), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListType, NullList) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + ASSERT_EQ(analyzer.listType(nullptr, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListType, NullPos) +{ + LLVMTypeAnalyzer analyzer; + List list("", ""); + ASSERT_EQ(analyzer.listType(&list, nullptr, Compiler::StaticType::Number, false), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListType, NoWriteOperationsKnownType_NonEmpty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_ListType, NoWriteOperationsKnownType_Empty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_ListType, NoWriteOperationsUnknownType_NonEmpty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Unknown, false), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListType, NoWriteOperationsUnknownType_Empty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Unknown, true), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListType, Loop_SingleWriteSameTypeNumber_Before_NonEmpty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + auto appendList = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::Number, 1.25); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Unknown, &value }); + instructionList.addInstruction(appendList); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_ListType, Loop_SingleWriteSameTypeNumber_Before_Empty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + auto appendList = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::Number, 1.25); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Unknown, &value }); + instructionList.addInstruction(appendList); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_ListType, Loop_SingleWriteStringOptimization_Empty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + auto appendList = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::String, "1.25"); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Unknown, &value }); + instructionList.addInstruction(appendList); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + // String "1.25" gets optimized to Number type + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_ListType, Loop_SingleWriteMultipleLists) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list1("", ""); + List list2("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + // Append to list1 + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 6); + appendList1->workList = &list1; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + // Append to list2 + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::String, "test"); + appendList2->workList = &list2; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + ASSERT_EQ(analyzer.listType(&list1, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_ListType, Loop_SingleWriteFromUnknownType_Before_NonEmpty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + auto appendList = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMRegister value(Compiler::StaticType::Unknown); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Unknown, &value }); + instructionList.addInstruction(appendList); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListType, Loop_SingleWriteFromUnknownType_Before_Empty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + auto appendList = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMRegister value(Compiler::StaticType::Unknown); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Unknown, &value }); + instructionList.addInstruction(appendList); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListType, Loop_SingleWriteToUnknownType_Before_Empty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + auto appendList = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::Number, 5); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Unknown, &value }); + instructionList.addInstruction(appendList); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + // The type is known because a number is appended before the point + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Unknown, true), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_ListType, Loop_SingleWriteToUnknownType_Before_NonEmpty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + auto appendList = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::Number, 5); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Unknown, &value }); + instructionList.addInstruction(appendList); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Unknown, false), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListType, Loop_SingleWriteDifferentTypeNumberToString_Before_Empty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + auto appendList = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::String, "test"); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Unknown, &value }); + instructionList.addInstruction(appendList); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::String); +} + +TEST(LLVMTypeAnalyzer_ListType, Loop_SingleWriteDifferentTypeNumberToString_Before_NonEmpty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + auto appendList = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::String, "test"); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Unknown, &value }); + instructionList.addInstruction(appendList); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListType, Loop_SingleWriteDifferentTypeBoolToNumber_Before_Empty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + auto appendList = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::Number, 1); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Unknown, &value }); + instructionList.addInstruction(appendList); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Bool, true), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_ListType, Loop_SingleWriteDifferentType_BeforeAndAfter) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::String, "test"); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::Bool, true); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListType, IfStatement_SingleWriteDifferentType_Before) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + instructionList.addInstruction(start); + + auto appendList = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::String, "test"); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Unknown, &value }); + instructionList.addInstruction(appendList); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + auto end = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + instructionList.addInstruction(end); + + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListType, IfStatement_SingleWriteDifferentType_After_IfBranch) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + instructionList.addInstruction(start); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + auto appendList = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::String, "test"); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Unknown, &value }); + instructionList.addInstruction(appendList); + + auto end = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + instructionList.addInstruction(end); + + // Since this isn't a loop, the write after the point doesn't affect the type + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_ListType, IfStatement_SingleWriteDifferentType_After_ElseBranch) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + instructionList.addInstruction(start); + + auto elseStart = std::make_shared(LLVMInstruction::Type::BeginElse, nullptr, false); + instructionList.addInstruction(elseStart); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + auto appendList = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::String, "test"); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Unknown, &value }); + instructionList.addInstruction(appendList); + + auto end = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + instructionList.addInstruction(end); + + // Since this isn't a loop, the write after the point doesn't affect the type + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_ListType, WriteSameTypeInLoop_NonEmpty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + auto appendList = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::Number, 1.25); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Unknown, &value }); + instructionList.addInstruction(appendList); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_ListType, WriteSameTypeInLoop_Empty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + auto appendList = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::Number, 1.25); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Unknown, &value }); + instructionList.addInstruction(appendList); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_ListType, WriteDifferentTypeInLoop_NonEmpty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + auto appendList = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::String, "test"); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Unknown, &value }); + instructionList.addInstruction(appendList); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + // Type is not known because the loop might not run at all + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListType, WriteDifferentTypeInLoop_Empty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + auto appendList = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::String, "test"); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Unknown, &value }); + instructionList.addInstruction(appendList); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + // Type is String because empty list can establish new type + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::String); +} + +TEST(LLVMTypeAnalyzer_ListType, ChangeTypeBeforeLoop_NonEmpty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 1.25); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::Number, 1.25); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::String, false), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListType, OverrideUnknownTypeBeforeLoop_Empty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 1.25); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::Number, 1.25); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Unknown, true), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_ListType, WriteSameTypeInIfStatement_NonEmpty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + instructionList.addInstruction(start); + + auto appendList = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::Number, 1.25); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Unknown, &value }); + instructionList.addInstruction(appendList); + + auto end = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + instructionList.addInstruction(end); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_ListType, WriteDifferentTypeInIfStatement_NonEmpty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + instructionList.addInstruction(start); + + auto appendList = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::Number, 5.8); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Unknown, &value }); + instructionList.addInstruction(appendList); + + auto end = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + instructionList.addInstruction(end); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + // Type is not known because the if statement might not run at all + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::String, false), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListType, OverrideDifferentTypeBeforeIfElseStatement_Empty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 1.25); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + auto start = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + instructionList.addInstruction(start); + + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::Number, 1.25); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + auto elseStart = std::make_shared(LLVMInstruction::Type::BeginElse, nullptr, false); + instructionList.addInstruction(elseStart); + + auto appendList3 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value3(Compiler::StaticType::Number, 2.5); + appendList3->workList = &list; + appendList3->args.push_back({ Compiler::StaticType::Unknown, &value3 }); + instructionList.addInstruction(appendList3); + + auto end = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + instructionList.addInstruction(end); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::String, true), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_ListType, OverrideUnknownTypeBeforeIfElseStatement_Empty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 1.25); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + auto start = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + instructionList.addInstruction(start); + + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::Number, 1.25); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + auto elseStart = std::make_shared(LLVMInstruction::Type::BeginElse, nullptr, false); + instructionList.addInstruction(elseStart); + + auto appendList3 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value3(Compiler::StaticType::Number, 2.5); + appendList3->workList = &list; + appendList3->args.push_back({ Compiler::StaticType::Unknown, &value3 }); + instructionList.addInstruction(appendList3); + + auto end = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + instructionList.addInstruction(end); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Unknown, true), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_ListType, MultipleWritesSameTypeNumber_NonEmpty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + // First write: string "abc" (incompatible with Number) + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::String, "abc"); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + // Second write: number 5.25 (incompatible with previous String) + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::Number, 5.25); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + // Should return Unknown type because of type conflict + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListType, MultipleWritesSameTypeString_Empty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + // First write: number 42 (establishes Number type for empty list) + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 42); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + // Second write: string "hello" (incompatible with Number) + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::String, "hello"); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + // Should return Unknown type because of type conflict + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::String, true), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListType, MultipleWritesSameTypeUnknown_Empty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + // First write: unknown type + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMRegister value1(Compiler::StaticType::Unknown); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + // Second write: string "hello" + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::String, "hello"); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + // Should return Unknown type because first write is unknown + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::String, true), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListType, MultipleWritesWithStringOptimization_Empty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + // First write: number 5 + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 5); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + // Second write: string "3.14" (optimized to Number) + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::String, "3.14"); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + // Should return Number type because the string gets optimized to number + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_ListType, MultipleWritesNumberToString_NonEmpty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + // First write: number 42 (compatible with Number) + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 42); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + // Second write: string "hello" (incompatible with Number) + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::String, "hello"); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + // Should return Unknown type because of type conflict + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListType, MultipleWritesNumberToString_Empty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + // First write: number 42 (establishes Number type for empty list) + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 42); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + // Second write: string "hello" (incompatible with Number) + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::String, "hello"); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + // Should return Unknown type because of type conflict + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListType, MultipleWritesBoolToNumber_NonEmpty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto appendList = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::Number, 42.5); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Unknown, &value }); + instructionList.addInstruction(appendList); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + // Should return Unknown type because Number conflicts with Bool + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Bool, false), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListType, MultipleWritesBoolToNumber_Empty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto appendList = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::Number, 42.5); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Unknown, &value }); + instructionList.addInstruction(appendList); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + // Should return Number type because empty list establishes new type + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Bool, true), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_ListType, MultipleWritesBoolToString_NonEmpty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto appendList = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::String, "hello"); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Unknown, &value }); + instructionList.addInstruction(appendList); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + // Should return Unknown type because String conflicts with Bool + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Bool, false), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListType, MultipleWritesBoolToString_Empty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto appendList = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::String, "hello"); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Unknown, &value }); + instructionList.addInstruction(appendList); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + // Should return String type because empty list establishes new type + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Bool, true), Compiler::StaticType::String); +} + +TEST(LLVMTypeAnalyzer_ListType, MultipleWritesBoolToStringNumberOptimization_NonEmpty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto appendList = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::String, "3.14"); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Unknown, &value }); + instructionList.addInstruction(appendList); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + // String "3.14" gets optimized to Number, which conflicts with Bool + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Bool, false), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListType, MultipleWritesBoolToStringNumberOptimization_Empty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto appendList = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::String, "3.14"); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Unknown, &value }); + instructionList.addInstruction(appendList); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + // String "3.14" gets optimized to Number type + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Bool, true), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_ListType, TypeChangeInIfBranch_NonEmpty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto ifStart = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + instructionList.addInstruction(ifStart); + + // First write - changes type + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::String, "test"); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + auto elseStart = std::make_shared(LLVMInstruction::Type::BeginElse, nullptr, false); + instructionList.addInstruction(elseStart); + + // Second write - does not change type + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::Number, 42); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + auto ifEnd = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + instructionList.addInstruction(ifEnd); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + // Returns unknown type because both branches might run + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListType, TypeChangeInIfBranch_Empty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto ifStart = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + instructionList.addInstruction(ifStart); + + // First write - changes type + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::String, "test"); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + auto elseStart = std::make_shared(LLVMInstruction::Type::BeginElse, nullptr, false); + instructionList.addInstruction(elseStart); + + // Second write - different type + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::Number, 42); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + auto ifEnd = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + instructionList.addInstruction(ifEnd); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + // Returns unknown type because different types in branches + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListType, TypeChangeInElseBranch_NonEmpty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto ifStart = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + instructionList.addInstruction(ifStart); + + // First write - does not change type + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 42); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + auto elseStart = std::make_shared(LLVMInstruction::Type::BeginElse, nullptr, false); + instructionList.addInstruction(elseStart); + + // Second write - changes type + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::String, "test"); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + auto ifEnd = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + instructionList.addInstruction(ifEnd); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + // Returns unknown type because both branches might run + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListType, TypeChangeInElseBranch_Empty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto ifStart = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + instructionList.addInstruction(ifStart); + + // First write - establishes Number type + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 42); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + auto elseStart = std::make_shared(LLVMInstruction::Type::BeginElse, nullptr, false); + instructionList.addInstruction(elseStart); + + // Second write - establishes String type + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::String, "test"); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + auto ifEnd = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + instructionList.addInstruction(ifEnd); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + // Returns unknown type because different types in branches + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListType, IfElseWithEqualTypes_SameType_NonEmpty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto ifStart = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + instructionList.addInstruction(ifStart); + + // First write - does not change type + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 42); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + auto elseStart = std::make_shared(LLVMInstruction::Type::BeginElse, nullptr, false); + instructionList.addInstruction(elseStart); + + // Second write - does not change type + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::Number, 1.25); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + auto ifEnd = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + instructionList.addInstruction(ifEnd); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_ListType, IfElseWithEqualTypes_SameType_Empty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto ifStart = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + instructionList.addInstruction(ifStart); + + // First write - establishes Number type + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 42); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + auto elseStart = std::make_shared(LLVMInstruction::Type::BeginElse, nullptr, false); + instructionList.addInstruction(elseStart); + + // Second write - establishes same Number type + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::Number, 1.25); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + auto ifEnd = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + instructionList.addInstruction(ifEnd); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_ListType, IfElseWithEqualTypes_DifferentTypes_NonEmpty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto ifStart = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + instructionList.addInstruction(ifStart); + + // First write - changes type to string + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::String, "Lorem"); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + auto elseStart = std::make_shared(LLVMInstruction::Type::BeginElse, nullptr, false); + instructionList.addInstruction(elseStart); + + // Second write - changes type to string + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::String, "ipsum"); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + auto ifEnd = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + instructionList.addInstruction(ifEnd); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListType, IfElseWithEqualTypes_DifferentTypes_Empty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto ifStart = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + instructionList.addInstruction(ifStart); + + // First write - establishes String type + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::String, "Lorem"); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + auto elseStart = std::make_shared(LLVMInstruction::Type::BeginElse, nullptr, false); + instructionList.addInstruction(elseStart); + + // Second write - establishes same String type + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::String, "ipsum"); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + auto ifEnd = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + instructionList.addInstruction(ifEnd); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::String); +} + +TEST(LLVMTypeAnalyzer_ListType, NestedLoopWithTypeChange_Before_NonEmpty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + // Outer loop begin + auto outerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(outerLoop); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + // List write inside outer loop + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 5); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + // Inner loop begin + auto innerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(innerLoop); + + // List write inside inner loop + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::String, "test"); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + // Inner loop end + auto innerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(innerEnd); + + // Outer loop end + auto outerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(outerEnd); + + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListType, NestedLoopWithTypeChange_Before_Empty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + // Outer loop begin + auto outerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(outerLoop); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + // List write inside outer loop + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 5); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + // Inner loop begin + auto innerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(innerLoop); + + // List write inside inner loop + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::String, "test"); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + // Inner loop end + auto innerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(innerEnd); + + // Outer loop end + auto outerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(outerEnd); + + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListType, NestedLoopWithTypeChange_BeforeInner_NonEmpty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + // Outer loop begin + auto outerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(outerLoop); + + // List write inside outer loop + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 5); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + // Inner loop begin + auto innerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(innerLoop); + + // List write inside inner loop + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::String, "test"); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + // Inner loop end + auto innerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(innerEnd); + + // Outer loop end + auto outerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(outerEnd); + + // Returns Unknown because a string might be added + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListType, NestedLoopWithTypeChange_BeforeInner_Empty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + // Outer loop begin + auto outerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(outerLoop); + + // List write inside outer loop + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 5); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + // Inner loop begin + auto innerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(innerLoop); + + // List write inside inner loop + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::String, "test"); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + // Inner loop end + auto innerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(innerEnd); + + // Outer loop end + auto outerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(outerEnd); + + // Returns Unknown because a string might be added + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListType, NestedLoopWithTypeChange_AfterWriteInsideInner_NonEmpty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + // Outer loop begin + auto outerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(outerLoop); + + // List write inside outer loop + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 5); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + // Inner loop begin + auto innerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(innerLoop); + + // List write inside inner loop + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::String, "test"); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + // Inner loop end + auto innerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(innerEnd); + + // Outer loop end + auto outerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(outerEnd); + + // Returns Unknown because a string might be added + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListType, NestedLoopWithTypeChange_AfterWriteInsideInner_Empty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + // Outer loop begin + auto outerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(outerLoop); + + // List write inside outer loop + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 5); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + // Inner loop begin + auto innerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(innerLoop); + + // List write inside inner loop + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::String, "test"); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + // Inner loop end + auto innerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(innerEnd); + + // Outer loop end + auto outerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(outerEnd); + + // Returns Unknown because a string might be added + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListType, NestedLoopWithTypeChange_After_NonEmpty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + // Outer loop begin + auto outerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(outerLoop); + + // List write inside outer loop + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 5); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + // Inner loop begin + auto innerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(innerLoop); + + // List write inside inner loop + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::String, "test"); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + // Inner loop end + auto innerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(innerEnd); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + // Outer loop end + auto outerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(outerEnd); + + // Type is not known because the inner loop might not run at all + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListType, NestedLoopWithTypeChange_After_Empty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + // Outer loop begin + auto outerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(outerLoop); + + // List write inside outer loop + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 5); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + // Inner loop begin + auto innerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(innerLoop); + + // List write inside inner loop + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::String, "test"); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + // Inner loop end + auto innerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(innerEnd); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + // Outer loop end + auto outerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(outerEnd); + + // Type is not known because the inner loop might not run at all + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListType, NestedLoopWithoutTypeChange_NonEmpty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + // Outer loop begin + auto outerLoop = std::make_shared(LLVMInstruction::Type::BeginWhileLoop, nullptr, false); + instructionList.addInstruction(outerLoop); + + // List write inside outer loop + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 5); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + // Inner loop begin + auto innerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(innerLoop); + + // List write inside inner loop + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::Number, 2.5); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + // Inner loop end + auto innerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(innerEnd); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + // Outer loop end + auto outerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(outerEnd); + + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_ListType, NestedLoopWithoutTypeChange_Empty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + // Outer loop begin + auto outerLoop = std::make_shared(LLVMInstruction::Type::BeginWhileLoop, nullptr, false); + instructionList.addInstruction(outerLoop); + + // List write inside outer loop + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 5); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + // Inner loop begin + auto innerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(innerLoop); + + // List write inside inner loop + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::Number, 2.5); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + // Inner loop end + auto innerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(innerEnd); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + // Outer loop end + auto outerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(outerEnd); + + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_ListType, NestedLoopTypeChangesMultipleTimes_NonEmpty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + // Outer loop begin + auto outerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(outerLoop); + + // List write inside outer loop + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 5); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + // Inner loop begin + auto innerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatUntilLoop, nullptr, false); + instructionList.addInstruction(innerLoop); + + // List write inside inner loop + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::String, "test"); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + // Inner loop end + auto innerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(innerEnd); + + // List write after inner loop + auto appendList3 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value3(Compiler::StaticType::Number, 2); + appendList3->workList = &list; + appendList3->args.push_back({ Compiler::StaticType::Unknown, &value3 }); + instructionList.addInstruction(appendList3); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + // Outer loop end + auto outerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(outerEnd); + + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListType, NestedLoopTypeChangesMultipleTimes_Empty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + // Outer loop begin + auto outerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(outerLoop); + + // List write inside outer loop + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 5); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + // Inner loop begin + auto innerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatUntilLoop, nullptr, false); + instructionList.addInstruction(innerLoop); + + // List write inside inner loop + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::String, "test"); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + // Inner loop end + auto innerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(innerEnd); + + // List write after inner loop + auto appendList3 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value3(Compiler::StaticType::Number, 2); + appendList3->workList = &list; + appendList3->args.push_back({ Compiler::StaticType::Unknown, &value3 }); + instructionList.addInstruction(appendList3); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + // Outer loop end + auto outerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(outerEnd); + + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListType, MultipleNestedLoopsWithTypeChange_NonEmpty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + // Outer loop begin + auto outerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(outerLoop); + + // List write inside outer loop + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 5); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + // Inner loop 1 begin + auto innerLoop1 = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(innerLoop1); + + // List write inside inner loop 1 + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::Number, 2.75); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + // Inner loop 2 begin + auto innerLoop2 = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(innerLoop2); + + // List write inside inner loop 2 + auto appendList3 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value3(Compiler::StaticType::String, "abc"); + appendList3->workList = &list; + appendList3->args.push_back({ Compiler::StaticType::Unknown, &value3 }); + instructionList.addInstruction(appendList3); + + // Inner loop 2 end + auto innerEnd2 = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(innerEnd2); + + // Inner loop 1 end + auto innerEnd1 = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(innerEnd1); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + // Outer loop end + auto outerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(outerEnd); + + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListType, MultipleNestedLoopsWithTypeChange_Empty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + // Outer loop begin + auto outerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(outerLoop); + + // List write inside outer loop + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 5); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + // Inner loop 1 begin + auto innerLoop1 = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(innerLoop1); + + // List write inside inner loop 1 + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::Number, 2.75); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + // Inner loop 2 begin + auto innerLoop2 = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(innerLoop2); + + // List write inside inner loop 2 + auto appendList3 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value3(Compiler::StaticType::String, "abc"); + appendList3->workList = &list; + appendList3->args.push_back({ Compiler::StaticType::Unknown, &value3 }); + instructionList.addInstruction(appendList3); + + // Inner loop 2 end + auto innerEnd2 = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(innerEnd2); + + // Inner loop 1 end + auto innerEnd1 = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(innerEnd1); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + // Outer loop end + auto outerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(outerEnd); + + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListType, MultipleNestedLoopsWithMultipleTypeChanges_NonEmpty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + // Outer loop begin + auto outerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(outerLoop); + + // List write inside outer loop + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 5); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + // Inner loop 1 begin + auto innerLoop1 = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(innerLoop1); + + // Inner loop 2 begin + auto innerLoop2 = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(innerLoop2); + + // List write inside inner loop 2 + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::String, "abc"); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + // Inner loop 2 end + auto innerEnd2 = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(innerEnd2); + + // List write inside inner loop 1 + auto appendList3 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value3(Compiler::StaticType::Number, 2.75); + appendList3->workList = &list; + appendList3->args.push_back({ Compiler::StaticType::Unknown, &value3 }); + instructionList.addInstruction(appendList3); + + // Inner loop 1 end + auto innerEnd1 = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(innerEnd1); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + // Outer loop end + auto outerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(outerEnd); + + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListType, MultipleNestedLoopsWithMultipleTypeChanges_Empty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + // Outer loop begin + auto outerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(outerLoop); + + // List write inside outer loop + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 5); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + // Inner loop 1 begin + auto innerLoop1 = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(innerLoop1); + + // Inner loop 2 begin + auto innerLoop2 = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(innerLoop2); + + // List write inside inner loop 2 + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::String, "abc"); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + // Inner loop 2 end + auto innerEnd2 = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(innerEnd2); + + // List write inside inner loop 1 + auto appendList3 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value3(Compiler::StaticType::Number, 2.75); + appendList3->workList = &list; + appendList3->args.push_back({ Compiler::StaticType::Unknown, &value3 }); + instructionList.addInstruction(appendList3); + + // Inner loop 1 end + auto innerEnd1 = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(innerEnd1); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + // Outer loop end + auto outerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(outerEnd); + + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListType, SameTypeIfElseInLoopWithTypeChange_NonEmpty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + // Outer loop begin + auto outerLoop = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(outerLoop); + + // Inner if statement begin + auto innerIf = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + instructionList.addInstruction(innerIf); + + // List write inside inner if statement if branch + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::String, "abc"); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + // Inner if statement else branch + auto innerElse = std::make_shared(LLVMInstruction::Type::BeginElse, nullptr, false); + instructionList.addInstruction(innerElse); + + // List write inside inner if statement else branch + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::String, "def"); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + // Inner if statement end + auto innerEnd = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + instructionList.addInstruction(innerEnd); + + // Outer loop end + auto outerEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(outerEnd); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + // A type conflict always occurs + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListType, InsertToList_SameType_NonEmpty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto insertList = std::make_shared(LLVMInstruction::Type::InsertToList, nullptr, false); + LLVMConstantRegister index(Compiler::StaticType::Number, 1); + LLVMConstantRegister value(Compiler::StaticType::Number, 42.5); + insertList->workList = &list; + insertList->args.push_back({ Compiler::StaticType::Number, &index }); + insertList->args.push_back({ Compiler::StaticType::Unknown, &value }); + instructionList.addInstruction(insertList); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_ListType, InsertToList_DifferentType_Empty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto insertList = std::make_shared(LLVMInstruction::Type::InsertToList, nullptr, false); + LLVMConstantRegister index(Compiler::StaticType::Number, 0); + LLVMConstantRegister value(Compiler::StaticType::String, "hello"); + insertList->workList = &list; + insertList->args.push_back({ Compiler::StaticType::Number, &index }); + insertList->args.push_back({ Compiler::StaticType::Unknown, &value }); + instructionList.addInstruction(insertList); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::String); +} + +TEST(LLVMTypeAnalyzer_ListType, InsertToList_InLoop_TypeConflict) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + auto insertList1 = std::make_shared(LLVMInstruction::Type::InsertToList, nullptr, false); + LLVMConstantRegister index1(Compiler::StaticType::Number, 0); + LLVMConstantRegister value1(Compiler::StaticType::Number, 123); + insertList1->workList = &list; + insertList1->args.push_back({ Compiler::StaticType::Number, &index1 }); + insertList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(insertList1); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + auto insertList2 = std::make_shared(LLVMInstruction::Type::InsertToList, nullptr, false); + LLVMConstantRegister index2(Compiler::StaticType::Number, 1); + LLVMConstantRegister value2(Compiler::StaticType::String, "test"); + insertList2->workList = &list; + insertList2->args.push_back({ Compiler::StaticType::Number, &index2 }); + insertList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(insertList2); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListType, ListReplace_SameType_NonEmpty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto replaceList = std::make_shared(LLVMInstruction::Type::ListReplace, nullptr, false); + LLVMConstantRegister index(Compiler::StaticType::Number, 0); + LLVMConstantRegister value(Compiler::StaticType::String, "replaced"); + replaceList->workList = &list; + replaceList->args.push_back({ Compiler::StaticType::Number, &index }); + replaceList->args.push_back({ Compiler::StaticType::Unknown, &value }); + instructionList.addInstruction(replaceList); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::String, false), Compiler::StaticType::String); +} + +TEST(LLVMTypeAnalyzer_ListType, ListReplace_DifferentType_NonEmpty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto replaceList = std::make_shared(LLVMInstruction::Type::ListReplace, nullptr, false); + LLVMConstantRegister index(Compiler::StaticType::Number, 0); + LLVMConstantRegister value(Compiler::StaticType::Bool, true); + replaceList->workList = &list; + replaceList->args.push_back({ Compiler::StaticType::Number, &index }); + replaceList->args.push_back({ Compiler::StaticType::Unknown, &value }); + instructionList.addInstruction(replaceList); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::String, false), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListType, ListReplace_WithStringOptimization) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto replaceList = std::make_shared(LLVMInstruction::Type::ListReplace, nullptr, false); + LLVMConstantRegister index(Compiler::StaticType::Number, 0); + LLVMConstantRegister value(Compiler::StaticType::String, "42.75"); + replaceList->workList = &list; + replaceList->args.push_back({ Compiler::StaticType::Number, &index }); + replaceList->args.push_back({ Compiler::StaticType::Unknown, &value }); + instructionList.addInstruction(replaceList); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + // String "42.75" gets optimized to Number type + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_ListType, MixedWriteOperations_TypeConflict) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + // Append a number + auto appendList = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 42); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList); + + // Insert a string + auto insertList = std::make_shared(LLVMInstruction::Type::InsertToList, nullptr, false); + LLVMConstantRegister index(Compiler::StaticType::Number, 0); + LLVMConstantRegister value2(Compiler::StaticType::String, "hello"); + insertList->workList = &list; + insertList->args.push_back({ Compiler::StaticType::Number, &index }); + insertList->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(insertList); + + // Replace with a boolean + auto replaceList = std::make_shared(LLVMInstruction::Type::ListReplace, nullptr, false); + LLVMConstantRegister index2(Compiler::StaticType::Number, 1); + LLVMConstantRegister value3(Compiler::StaticType::Bool, true); + replaceList->workList = &list; + replaceList->args.push_back({ Compiler::StaticType::Number, &index2 }); + replaceList->args.push_back({ Compiler::StaticType::Unknown, &value3 }); + instructionList.addInstruction(replaceList); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + // Should be Unknown due to multiple type conflicts + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListType, MixedWriteOperations_SameType) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + // Append a string + auto appendList = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::String, "hello"); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList); + + // Insert another string + auto insertList = std::make_shared(LLVMInstruction::Type::InsertToList, nullptr, false); + LLVMConstantRegister index(Compiler::StaticType::Number, 0); + LLVMConstantRegister value2(Compiler::StaticType::String, "world"); + insertList->workList = &list; + insertList->args.push_back({ Compiler::StaticType::Number, &index }); + insertList->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(insertList); + + // Replace with another string + auto replaceList = std::make_shared(LLVMInstruction::Type::ListReplace, nullptr, false); + LLVMConstantRegister index2(Compiler::StaticType::Number, 1); + LLVMConstantRegister value3(Compiler::StaticType::String, "test"); + replaceList->workList = &list; + replaceList->args.push_back({ Compiler::StaticType::Number, &index2 }); + replaceList->args.push_back({ Compiler::StaticType::Unknown, &value3 }); + instructionList.addInstruction(replaceList); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + // Should be String type since all operations use strings + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::String, false), Compiler::StaticType::String); +} + +TEST(LLVMTypeAnalyzer_ListType, ComplexMixedOperations) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + // Append a number + auto appendList = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 123); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList); + + // Insert another number + auto insertList = std::make_shared(LLVMInstruction::Type::InsertToList, nullptr, false); + LLVMConstantRegister index1(Compiler::StaticType::Number, 0); + LLVMConstantRegister value2(Compiler::StaticType::Number, 456); + insertList->workList = &list; + insertList->args.push_back({ Compiler::StaticType::Number, &index1 }); + insertList->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(insertList); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + // Replace with a string (creates type conflict) + auto replaceList = std::make_shared(LLVMInstruction::Type::ListReplace, nullptr, false); + LLVMConstantRegister index2(Compiler::StaticType::Number, 0); + LLVMConstantRegister value3(Compiler::StaticType::String, "conflict"); + replaceList->workList = &list; + replaceList->args.push_back({ Compiler::StaticType::Number, &index2 }); + replaceList->args.push_back({ Compiler::StaticType::Unknown, &value3 }); + instructionList.addInstruction(replaceList); + + // Should be Number type at the function call point, before the conflicting replace + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::String, true), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_ListType, ComplexMixedOperations_InLoop) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + // Append a number + auto appendList = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 123); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList); + + // Insert another number + auto insertList = std::make_shared(LLVMInstruction::Type::InsertToList, nullptr, false); + LLVMConstantRegister index1(Compiler::StaticType::Number, 0); + LLVMConstantRegister value2(Compiler::StaticType::Number, 456); + insertList->workList = &list; + insertList->args.push_back({ Compiler::StaticType::Number, &index1 }); + insertList->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(insertList); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + // Replace with a string (creates type conflict) + auto replaceList = std::make_shared(LLVMInstruction::Type::ListReplace, nullptr, false); + LLVMConstantRegister index2(Compiler::StaticType::Number, 0); + LLVMConstantRegister value3(Compiler::StaticType::String, "conflict"); + replaceList->workList = &list; + replaceList->args.push_back({ Compiler::StaticType::Number, &index2 }); + replaceList->args.push_back({ Compiler::StaticType::Unknown, &value3 }); + instructionList.addInstruction(replaceList); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::String, true), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListType, ClearAndRebuild_WithDifferentTypes) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + // Initial append + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::String, "initial"); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + // Clear the list + auto clearList = std::make_shared(LLVMInstruction::Type::ClearList, nullptr, false); + clearList->workList = &list; + instructionList.addInstruction(clearList); + + // Rebuild with different operations and types + auto insertList = std::make_shared(LLVMInstruction::Type::InsertToList, nullptr, false); + LLVMConstantRegister index(Compiler::StaticType::Number, 0); + LLVMConstantRegister value2(Compiler::StaticType::Bool, true); + insertList->workList = &list; + insertList->args.push_back({ Compiler::StaticType::Number, &index }); + insertList->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(insertList); + + auto replaceList = std::make_shared(LLVMInstruction::Type::ListReplace, nullptr, false); + LLVMConstantRegister index2(Compiler::StaticType::Number, 0); + LLVMConstantRegister value3(Compiler::StaticType::Bool, false); + replaceList->workList = &list; + replaceList->args.push_back({ Compiler::StaticType::Number, &index2 }); + replaceList->args.push_back({ Compiler::StaticType::Unknown, &value3 }); + instructionList.addInstruction(replaceList); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + // Should be Bool type since clear resets and all subsequent operations use booleans + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::String, false), Compiler::StaticType::Bool); +} + +TEST(LLVMTypeAnalyzer_ListType, ClearListInLoop_NewTypeAfterClear_Empty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + // Clear the list in the middle of the loop + auto clearList = std::make_shared(LLVMInstruction::Type::ClearList, nullptr, false); + clearList->workList = &list; + instructionList.addInstruction(clearList); + + // Append after clear - this should set the new type + auto appendList = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::String, "test"); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Unknown, &value }); + instructionList.addInstruction(appendList); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + // Should return String because the list was empty and append sets the type + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::String); +} + +TEST(LLVMTypeAnalyzer_ListType, ClearListInLoop_NewTypeAfterClear_NonEmpty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + // Clear the list in the middle of the loop + auto clearList = std::make_shared(LLVMInstruction::Type::ClearList, nullptr, false); + clearList->workList = &list; + instructionList.addInstruction(clearList); + + // Append after clear - this should set the new type + auto appendList = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::String, "test"); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Unknown, &value }); + instructionList.addInstruction(appendList); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + // Should return String because clear makes the list empty, then append sets the type + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::String); +} + +TEST(LLVMTypeAnalyzer_ListType, ClearListInLoop_MultipleAppendsAfterClear) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + // Clear the list + auto clearList = std::make_shared(LLVMInstruction::Type::ClearList, nullptr, false); + clearList->workList = &list; + instructionList.addInstruction(clearList); + + // First append after clear + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 42); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + // Second append after clear (same type) + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::Number, 3.14); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + // Should return Number because all appends after clear are the same type + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::String, false), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_ListType, ClearListInLoop_TypeConflictAfterClear) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + // Clear the list + auto clearList = std::make_shared(LLVMInstruction::Type::ClearList, nullptr, false); + clearList->workList = &list; + instructionList.addInstruction(clearList); + + // First append after clear + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 42); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + // Second append after clear (different type - creates conflict) + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::String, "test"); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + // Should return Unknown because of type conflict after clear + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::String, false), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListType, ClearListInLoop_WithInsertAndReplace) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + // Clear the list + auto clearList = std::make_shared(LLVMInstruction::Type::ClearList, nullptr, false); + clearList->workList = &list; + instructionList.addInstruction(clearList); + + // Insert after clear + auto insertList = std::make_shared(LLVMInstruction::Type::InsertToList, nullptr, false); + LLVMConstantRegister insertIndex(Compiler::StaticType::Number, 0); + LLVMConstantRegister insertValue(Compiler::StaticType::Bool, true); + insertList->workList = &list; + insertList->args.push_back({ Compiler::StaticType::Number, &insertIndex }); + insertList->args.push_back({ Compiler::StaticType::Unknown, &insertValue }); + instructionList.addInstruction(insertList); + + // Replace after insert + auto replaceList = std::make_shared(LLVMInstruction::Type::ListReplace, nullptr, false); + LLVMConstantRegister replaceIndex(Compiler::StaticType::Number, 0); + LLVMConstantRegister replaceValue(Compiler::StaticType::Bool, false); + replaceList->workList = &list; + replaceList->args.push_back({ Compiler::StaticType::Number, &replaceIndex }); + replaceList->args.push_back({ Compiler::StaticType::Unknown, &replaceValue }); + instructionList.addInstruction(replaceList); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + // Should return Bool because all operations after clear use Bool type + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Bool); +} + +TEST(LLVMTypeAnalyzer_ListType, ClearListInLoop_ConditionalClear) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + // If statement + auto ifStart = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + instructionList.addInstruction(ifStart); + + // Clear the list conditionally + auto clearList = std::make_shared(LLVMInstruction::Type::ClearList, nullptr, false); + clearList->workList = &list; + instructionList.addInstruction(clearList); + + // Append after clear + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::String, "cleared"); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + // Else branch + auto elseStart = std::make_shared(LLVMInstruction::Type::BeginElse, nullptr, false); + instructionList.addInstruction(elseStart); + + // Append without clearing + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::Number, 42); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + auto ifEnd = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + instructionList.addInstruction(ifEnd); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + // Should return Unknown due to type conflict between branches + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListType, ClearListInLoop_AppendAfterClearingInIfBranch_DifferentType) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + // If statement + auto ifStart = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + instructionList.addInstruction(ifStart); + + // Clear the list + auto clearList = std::make_shared(LLVMInstruction::Type::ClearList, nullptr, false); + clearList->workList = &list; + instructionList.addInstruction(clearList); + + // End if statement + auto ifEnd = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + instructionList.addInstruction(ifEnd); + + // Append + auto appendList = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::String, "test"); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Unknown, &value }); + instructionList.addInstruction(appendList); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + // Should return Unknown because the clearing branch might or might not run + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListType, ClearListInLoop_AppendAfterClearingInIfBranch_SameType) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + // If statement + auto ifStart = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + instructionList.addInstruction(ifStart); + + // Clear the list + auto clearList = std::make_shared(LLVMInstruction::Type::ClearList, nullptr, false); + clearList->workList = &list; + instructionList.addInstruction(clearList); + + // End if statement + auto ifEnd = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + instructionList.addInstruction(ifEnd); + + // Append + auto appendList = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::Number, 42); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Unknown, &value }); + instructionList.addInstruction(appendList); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + // Should return Number because there are no type conflicts + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_ListType, ClearListInLoop_AppendAfterClearingInElseBranch_DifferentType) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + // If statement + auto ifStart = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + instructionList.addInstruction(ifStart); + + // Else branch + auto elseStart = std::make_shared(LLVMInstruction::Type::BeginElse, nullptr, false); + instructionList.addInstruction(elseStart); + + // Clear the list + auto clearList = std::make_shared(LLVMInstruction::Type::ClearList, nullptr, false); + clearList->workList = &list; + instructionList.addInstruction(clearList); + + // End if statement + auto ifEnd = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + instructionList.addInstruction(ifEnd); + + // Append + auto appendList = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::String, "test"); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Unknown, &value }); + instructionList.addInstruction(appendList); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + // Should return Unknown because the clearing branch might or might not run + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListType, ClearListInLoop_AppendAfterClearingInElseBranch_SameType) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + // If statement + auto ifStart = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + instructionList.addInstruction(ifStart); + + // Else branch + auto elseStart = std::make_shared(LLVMInstruction::Type::BeginElse, nullptr, false); + instructionList.addInstruction(elseStart); + + // Clear the list + auto clearList = std::make_shared(LLVMInstruction::Type::ClearList, nullptr, false); + clearList->workList = &list; + instructionList.addInstruction(clearList); + + // End if statement + auto ifEnd = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + instructionList.addInstruction(ifEnd); + + // Append + auto appendList = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::Number, 42); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Unknown, &value }); + instructionList.addInstruction(appendList); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + // Should return Number because there are no type conflicts + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_ListType, ClearListInLoop_MultipleClearsAndWrites) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + // First clear + auto clearList1 = std::make_shared(LLVMInstruction::Type::ClearList, nullptr, false); + clearList1->workList = &list; + instructionList.addInstruction(clearList1); + + // Append after first clear + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::String, "first"); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + // Second clear + auto clearList2 = std::make_shared(LLVMInstruction::Type::ClearList, nullptr, false); + clearList2->workList = &list; + instructionList.addInstruction(clearList2); + + // Append after second clear (different type) + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::Number, 42); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + // Should return Number because the last clear+append sequence determines the final type + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::String, false), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_ListType, ClearListInLoop_ClearWithoutSubsequentWrite) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + // Clear the list but don't write anything after + auto clearList = std::make_shared(LLVMInstruction::Type::ClearList, nullptr, false); + clearList->workList = &list; + instructionList.addInstruction(clearList); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + // Should return previous type since no writes occurred after clear + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Bool, false), Compiler::StaticType::Bool); +} + +TEST(LLVMTypeAnalyzer_ListType, ClearListInLoop_ClearInNestedIf) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + // Nested if statement + auto ifStart = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + instructionList.addInstruction(ifStart); + + // Clear and write in nested if + auto clearList = std::make_shared(LLVMInstruction::Type::ClearList, nullptr, false); + clearList->workList = &list; + instructionList.addInstruction(clearList); + + auto appendList = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::Bool, true); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Unknown, &value }); + instructionList.addInstruction(appendList); + + auto ifEnd = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + instructionList.addInstruction(ifEnd); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + // Should return Unknown because the type-changing branch might or might not run + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::String, false), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListType, ClearListInLoop_AppendToEmptyListAndClearInIfBranch_SameType) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + auto ifStart = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + instructionList.addInstruction(ifStart); + + // Append in if branch + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 5); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + // Clear the list in if branch + auto clearList = std::make_shared(LLVMInstruction::Type::ClearList, nullptr, false); + clearList->workList = &list; + instructionList.addInstruction(clearList); + + auto ifEnd = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + instructionList.addInstruction(ifEnd); + + // Append after if statement - should change type + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::String, "test"); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + // Should return String because the list remains empty after the if statement + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::String); +} + +TEST(LLVMTypeAnalyzer_ListType, ClearListInLoop_AppendToEmptyListAndClearInIfBranch_DifferentType) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + auto ifStart = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + instructionList.addInstruction(ifStart); + + // Append in if branch + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Bool, true); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + // Clear the list in if branch + auto clearList = std::make_shared(LLVMInstruction::Type::ClearList, nullptr, false); + clearList->workList = &list; + instructionList.addInstruction(clearList); + + auto ifEnd = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + instructionList.addInstruction(ifEnd); + + // Append after if statement - should change type + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::String, "test"); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + // Should return String because the list remains empty after the if statement + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::String); +} + +TEST(LLVMTypeAnalyzer_ListType, ClearListInLoop_AppendToEmptyListAndClearInElseBranch_SameType) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + auto ifStart = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + instructionList.addInstruction(ifStart); + + auto elseStart = std::make_shared(LLVMInstruction::Type::BeginElse, nullptr, false); + instructionList.addInstruction(elseStart); + + // Append in else branch + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 5); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + // Clear the list in else branch + auto clearList = std::make_shared(LLVMInstruction::Type::ClearList, nullptr, false); + clearList->workList = &list; + instructionList.addInstruction(clearList); + + auto ifEnd = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + instructionList.addInstruction(ifEnd); + + // Append after if statement - should change type + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::String, "test"); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + // Should return String because the list remains empty after the if statement + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::String); +} + +TEST(LLVMTypeAnalyzer_ListType, ClearListInLoop_AppendToEmptyListAndClearInElseBranch_DifferentType) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + auto ifStart = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + instructionList.addInstruction(ifStart); + + auto elseStart = std::make_shared(LLVMInstruction::Type::BeginElse, nullptr, false); + instructionList.addInstruction(elseStart); + + // Append in else branch + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Bool, true); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + // Clear the list in else branch + auto clearList = std::make_shared(LLVMInstruction::Type::ClearList, nullptr, false); + clearList->workList = &list; + instructionList.addInstruction(clearList); + + auto ifEnd = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + instructionList.addInstruction(ifEnd); + + // Append after if statement - should change type + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::String, "test"); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + // Should return String because the list remains empty after the if statement + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::String); +} From 528d3cb5260d601d0414829c17c57131e849444e Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Thu, 31 Jul 2025 13:42:53 +0200 Subject: [PATCH 43/79] LLVMTypeAnalyzer: Fix sequential if statements/loops --- src/engine/internal/llvm/llvmtypeanalyzer.cpp | 20 +- test/llvm/type_analyzer/listtype_test.cpp | 254 ++++++++++++++++++ test/llvm/type_analyzer/variabletype_test.cpp | 127 +++++++++ 3 files changed, 393 insertions(+), 8 deletions(-) diff --git a/src/engine/internal/llvm/llvmtypeanalyzer.cpp b/src/engine/internal/llvm/llvmtypeanalyzer.cpp index 63b1b0c47..3d5273fc0 100644 --- a/src/engine/internal/llvm/llvmtypeanalyzer.cpp +++ b/src/engine/internal/llvm/llvmtypeanalyzer.cpp @@ -148,8 +148,8 @@ Compiler::StaticType LLVMTypeAnalyzer::variableType(Variable *var, LLVMInstructi // Check the last write operation before the instruction LLVMInstruction *ins = pos; LLVMInstruction *write = nullptr; - LLVMInstruction *firstBranch = nullptr; - LLVMInstruction *firstElseBranch = nullptr; + std::pair firstBranch = { nullptr, 0 }; + std::pair firstElseBranch = { nullptr, 0 }; LLVMInstruction *ourBranch = nullptr; int level = 0; @@ -160,11 +160,15 @@ Compiler::StaticType LLVMTypeAnalyzer::variableType(Variable *var, LLVMInstructi if (!ourBranch && level == 0) ourBranch = ins; + if (!firstBranch.first || level < firstBranch.second) + firstBranch = { ins, level }; + level--; - firstBranch = ins; } else if (isElse(ins)) { // Skip if branch if coming from else - firstElseBranch = ins; + if (!firstElseBranch.first || level < firstElseBranch.second) + firstElseBranch = { ins, level }; + ins = branchStart(ins); continue; } else if (isVariableWrite(ins, var) && !isWriteNoOp(ins)) { @@ -177,9 +181,9 @@ Compiler::StaticType LLVMTypeAnalyzer::variableType(Variable *var, LLVMInstructi ins = ins->previous; } - if (firstBranch) { + if (firstBranch.first) { // Analyze the first branch and else branch - bool ignoreWriteAfterPos = (isIfStart(firstBranch) && firstBranch == ourBranch); + bool ignoreWriteAfterPos = (isIfStart(firstBranch.first) && firstBranch.first == ourBranch); if (write) previousType = writeValueType(write, visitedInstructions); // write operation overrides previous type @@ -188,8 +192,8 @@ Compiler::StaticType LLVMTypeAnalyzer::variableType(Variable *var, LLVMInstructi Compiler::StaticType elseBranchType = previousType; if (!ignoreWriteAfterPos) { - firstBranchType = variableTypeAfterBranch(var, firstBranch, previousType, visitedInstructions); - elseBranchType = variableTypeAfterBranch(var, firstElseBranch, previousType, visitedInstructions); + firstBranchType = variableTypeAfterBranch(var, firstBranch.first, previousType, visitedInstructions); + elseBranchType = variableTypeAfterBranch(var, firstElseBranch.first, previousType, visitedInstructions); } if (typesMatch(firstBranchType, elseBranchType)) diff --git a/test/llvm/type_analyzer/listtype_test.cpp b/test/llvm/type_analyzer/listtype_test.cpp index 119307476..baf94722c 100644 --- a/test/llvm/type_analyzer/listtype_test.cpp +++ b/test/llvm/type_analyzer/listtype_test.cpp @@ -1306,6 +1306,260 @@ TEST(LLVMTypeAnalyzer_ListType, IfElseWithEqualTypes_DifferentTypes_Empty) ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::String); } +TEST(LLVMTypeAnalyzer_ListType, IfStatementAfterLoop_SameTypes_NonEmpty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto loopStart = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(loopStart); + + // First write - does not change type + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 5); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + auto loopEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(loopEnd); + + auto ifStart = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + instructionList.addInstruction(ifStart); + + // Second write - does not change type + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::Number, 2); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + auto ifEnd = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + instructionList.addInstruction(ifEnd); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_ListType, IfStatementAfterLoop_SameTypes_Empty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto loopStart = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(loopStart); + + // First write - establishes type for empty list + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 5); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + auto loopEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(loopEnd); + + auto ifStart = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + instructionList.addInstruction(ifStart); + + // Second write - same type + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::Number, 2); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + auto ifEnd = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + instructionList.addInstruction(ifEnd); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_ListType, IfStatementAfterLoop_DifferentTypes_NonEmpty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto loopStart = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(loopStart); + + // First write - does not change type + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 5); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + auto loopEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(loopEnd); + + auto ifStart = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + instructionList.addInstruction(ifStart); + + // Second write - changes type + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::String, "test"); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + auto ifEnd = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + instructionList.addInstruction(ifEnd); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListType, IfStatementAfterLoop_DifferentTypes_Empty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto loopStart = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(loopStart); + + // First write - establishes Number type for empty list + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 5); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + auto loopEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(loopEnd); + + auto ifStart = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + instructionList.addInstruction(ifStart); + + // Second write - adds string + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::String, "test"); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + auto ifEnd = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + instructionList.addInstruction(ifEnd); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListType, TwoIfStatements_DifferentTypes_NonEmpty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto ifStart = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + instructionList.addInstruction(ifStart); + + // First write - does not change type + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 5); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + auto elseStart = std::make_shared(LLVMInstruction::Type::BeginElse, nullptr, false); + instructionList.addInstruction(elseStart); + + // Second write - does not change type + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::Number, 4); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + auto ifEnd = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + instructionList.addInstruction(ifEnd); + + ifStart = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + instructionList.addInstruction(ifStart); + + elseStart = std::make_shared(LLVMInstruction::Type::BeginElse, nullptr, false); + instructionList.addInstruction(elseStart); + + // Third write - adds string (in else branch) + auto appendList3 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value3(Compiler::StaticType::String, "test"); + appendList3->workList = &list; + appendList3->args.push_back({ Compiler::StaticType::Unknown, &value3 }); + instructionList.addInstruction(appendList3); + + ifEnd = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + instructionList.addInstruction(ifEnd); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListType, TwoIfStatements_DifferentTypes_Empty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto ifStart = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + instructionList.addInstruction(ifStart); + + // First write - establishes Number type + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 5); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + auto elseStart = std::make_shared(LLVMInstruction::Type::BeginElse, nullptr, false); + instructionList.addInstruction(elseStart); + + // Second write - same Number type + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::Number, 4); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + auto ifEnd = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + instructionList.addInstruction(ifEnd); + + ifStart = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + instructionList.addInstruction(ifStart); + + elseStart = std::make_shared(LLVMInstruction::Type::BeginElse, nullptr, false); + instructionList.addInstruction(elseStart); + + // Third write - adds String (in else branch) + auto appendList3 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value3(Compiler::StaticType::String, "test"); + appendList3->workList = &list; + appendList3->args.push_back({ Compiler::StaticType::Unknown, &value3 }); + instructionList.addInstruction(appendList3); + + ifEnd = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + instructionList.addInstruction(ifEnd); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Unknown); +} + TEST(LLVMTypeAnalyzer_ListType, NestedLoopWithTypeChange_Before_NonEmpty) { LLVMTypeAnalyzer analyzer; diff --git a/test/llvm/type_analyzer/variabletype_test.cpp b/test/llvm/type_analyzer/variabletype_test.cpp index 63739f6ab..1d1675883 100644 --- a/test/llvm/type_analyzer/variabletype_test.cpp +++ b/test/llvm/type_analyzer/variabletype_test.cpp @@ -1296,6 +1296,133 @@ TEST(LLVMTypeAnalyzer_VariableType, IfElseWithEqualTypes_DifferentTypes) ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::String); } +TEST(LLVMTypeAnalyzer_VariableType, IfStatementAfterLoop_SameTypes) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + Variable var("", ""); + + auto loopStart = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(loopStart); + + // First write - does not change type + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 5); + setVar1->workVariable = &var; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(setVar1); + + auto loopEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(loopEnd); + + auto ifStart = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + list.addInstruction(ifStart); + + // Second write - does not change type + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::Number, 2); + setVar2->workVariable = &var; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + list.addInstruction(setVar2); + + auto ifEnd = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + list.addInstruction(ifEnd); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(funcCall); + + ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_VariableType, IfStatementAfterLoop_DifferentTypes) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + Variable var("", ""); + + auto loopStart = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + list.addInstruction(loopStart); + + // First write - does not change type + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 5); + setVar1->workVariable = &var; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(setVar1); + + auto loopEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + list.addInstruction(loopEnd); + + auto ifStart = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + list.addInstruction(ifStart); + + // Second write - changes type + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::String, "test"); + setVar2->workVariable = &var; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + list.addInstruction(setVar2); + + auto ifEnd = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + list.addInstruction(ifEnd); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(funcCall); + + ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_VariableType, TwoIfStatements_DifferentTypes) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + Variable var("", ""); + + auto ifStart = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + list.addInstruction(ifStart); + + // First write - does not change type + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 5); + setVar1->workVariable = &var; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(setVar1); + + auto elseStart = std::make_shared(LLVMInstruction::Type::BeginElse, nullptr, false); + list.addInstruction(elseStart); + + // Second write - does not change type + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::Number, 4); + setVar2->workVariable = &var; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + list.addInstruction(setVar2); + + auto ifEnd = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + list.addInstruction(ifEnd); + + ifStart = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + list.addInstruction(ifStart); + + elseStart = std::make_shared(LLVMInstruction::Type::BeginElse, nullptr, false); + list.addInstruction(elseStart); + + // Third write - changes type (in else branch) + auto setVar3 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value3(Compiler::StaticType::String, "test"); + setVar3->workVariable = &var; + setVar3->args.push_back({ Compiler::StaticType::Unknown, &value3 }); + list.addInstruction(setVar3); + + ifEnd = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + list.addInstruction(ifEnd); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + list.addInstruction(funcCall); + + ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown); +} + TEST(LLVMTypeAnalyzer_VariableType, NestedLoopWithTypeChange_Before) { LLVMTypeAnalyzer analyzer; From 5c77e1171271f1dc7785e04114acd2b92bf1730b Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Fri, 1 Aug 2025 13:33:53 +0200 Subject: [PATCH 44/79] LLVMTypeAnalyzer: Handle cross-list dependencies --- src/engine/internal/llvm/llvmtypeanalyzer.cpp | 287 ++++---- src/engine/internal/llvm/llvmtypeanalyzer.h | 34 +- test/llvm/type_analyzer/listtype_test.cpp | 634 ++++++++++++++++++ .../listtypeafterbranch_test.cpp | 305 +++++++++ 4 files changed, 1139 insertions(+), 121 deletions(-) diff --git a/src/engine/internal/llvm/llvmtypeanalyzer.cpp b/src/engine/internal/llvm/llvmtypeanalyzer.cpp index 3d5273fc0..b0d4a6c99 100644 --- a/src/engine/internal/llvm/llvmtypeanalyzer.cpp +++ b/src/engine/internal/llvm/llvmtypeanalyzer.cpp @@ -13,7 +13,8 @@ static const std::unordered_set LIST_WRITE_INSTRUCTIONS = Compiler::StaticType LLVMTypeAnalyzer::variableType(Variable *var, LLVMInstruction *pos, Compiler::StaticType previousType) const { InstructionSet visitedInstructions; - return variableType(var, pos, previousType, visitedInstructions); + std::unordered_map listTypes; + return variableType(var, pos, previousType, listTypes, visitedInstructions); } Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranch(Variable *var, LLVMInstruction *start, Compiler::StaticType previousType) const @@ -24,106 +25,22 @@ Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranch(Variable *var, LL Compiler::StaticType LLVMTypeAnalyzer::listType(List *list, LLVMInstruction *pos, Compiler::StaticType previousType, bool isEmpty) const { - if (!list || !pos) - return Compiler::StaticType::Unknown; - - InstructionSet visitedInstructions; // TODO: Handle cross-variable/list dependencies - - LLVMInstruction *ins = pos; - LLVMInstruction *previous = nullptr; - std::pair firstBranch = { nullptr, 0 }; - std::pair lastClear = { nullptr, 0 }; - int level = 0; - - // Find a start instruction (list clear in the top level or the first instruction) - while (ins) { - if (isLoopEnd(ins) || isIfEnd(ins)) - level++; - else if (isLoopStart(ins) || isIfStart(ins) || isElse(ins)) { - if (!isElse(ins)) - level--; - - if (!firstBranch.first || level < firstBranch.second) - firstBranch = { ins, level }; - } else if (isListClear(ins, list)) { - if (!lastClear.first || level < lastClear.second) - lastClear = { ins, level }; - } - - previous = ins; - ins = ins->previous; - } - - if (firstBranch.first) { - assert(firstBranch.second == level); - - // The first branch must be above the query point level - if (firstBranch.second == 0) - firstBranch.first = nullptr; - } - - // Clear must be in the top level - if (lastClear.second != level) - lastClear.first = nullptr; - - if (lastClear.first) { - ins = lastClear.first; - isEmpty = true; - } else - ins = previous; - - // Process from the start instruction - while (ins && ins != pos) { - if (isLoopStart(ins) || isIfStart(ins)) { - do { - bool write; - Compiler::StaticType type = listTypeAfterBranch(list, ins, previousType, isEmpty, pos, write); - - // If this branch contains the query point, return the final type - if (ins == firstBranch.first) { - if (isEmpty || typesMatch(type, previousType)) - return type; - else - return Compiler::StaticType::Unknown; - } - - // If there was a write, the list is no longer empty - if (write) { - isEmpty = false; - - // The write could change the type - if (!typesMatch(type, previousType)) - previousType = type; - } - - // Skip the branch - ins = branchEnd(ins); - } while (isElse(ins)); // handle else branch - } else if (isListWrite(ins, list)) { - // List write instruction - Compiler::StaticType writeType = writeValueType(ins, visitedInstructions); - - if (!handleListWrite(writeType, previousType, isEmpty)) - return Compiler::StaticType::Unknown; - } - - ins = ins->next; - } - - assert(ins); - return previousType; + InstructionSet visitedInstructions; + std::unordered_map listTypes; + return listType(list, pos, previousType, isEmpty, listTypes, visitedInstructions); } Compiler::StaticType LLVMTypeAnalyzer::listTypeAfterBranch(List *list, LLVMInstruction *start, Compiler::StaticType previousType, bool isEmpty) const { - if (!list || !start) - return previousType; - bool write = false; // only used internally (the compiler doesn't need this) - return listTypeAfterBranch(list, start, previousType, isEmpty, nullptr, write); + InstructionSet visitedInstructions; + std::unordered_map listTypes; + return listTypeAfterBranch(list, start, previousType, isEmpty, nullptr, write, listTypes, visitedInstructions); } -Compiler::StaticType LLVMTypeAnalyzer::variableType(Variable *var, LLVMInstruction *pos, Compiler::StaticType previousType, InstructionSet &visitedInstructions) const +Compiler::StaticType +LLVMTypeAnalyzer::variableType(Variable *var, LLVMInstruction *pos, Compiler::StaticType previousType, std::unordered_map listTypes, InstructionSet &visitedInstructions) + const { if (!var || !pos) return Compiler::StaticType::Unknown; @@ -186,7 +103,7 @@ Compiler::StaticType LLVMTypeAnalyzer::variableType(Variable *var, LLVMInstructi bool ignoreWriteAfterPos = (isIfStart(firstBranch.first) && firstBranch.first == ourBranch); if (write) - previousType = writeValueType(write, visitedInstructions); // write operation overrides previous type + previousType = writeValueType(write, listTypes, visitedInstructions); // write operation overrides previous type Compiler::StaticType firstBranchType = previousType; Compiler::StaticType elseBranchType = previousType; @@ -202,7 +119,7 @@ Compiler::StaticType LLVMTypeAnalyzer::variableType(Variable *var, LLVMInstructi return Compiler::StaticType::Unknown; } else if (write) { // There wasn't any branch found, so we can just check the last write operation - return writeValueType(write, visitedInstructions); + return writeValueType(write, listTypes, visitedInstructions); } // No write operation found @@ -221,10 +138,17 @@ Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranch(Variable *var, LL // Process the branch from end bool write = false; // only used internally (the compiler doesn't need this) - return variableTypeAfterBranchFromEnd(var, end, previousType, write, visitedInstructions); + std::unordered_map listTypes; + return variableTypeAfterBranchFromEnd(var, end, previousType, write, listTypes, visitedInstructions); } -Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranchFromEnd(Variable *var, LLVMInstruction *end, Compiler::StaticType previousType, bool &write, InstructionSet &visitedInstructions) const +Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranchFromEnd( + Variable *var, + LLVMInstruction *end, + Compiler::StaticType previousType, + bool &write, + std::unordered_map listTypes, + InstructionSet &visitedInstructions) const { // Find the last write instruction LLVMInstruction *ins = end->previous; @@ -233,7 +157,7 @@ Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranchFromEnd(Variable * while (ins && !isLoopStart(ins) && !isIfStart(ins)) { if (isLoopEnd(ins) || isIfEnd(ins) || isElse(ins)) { // Process the nested loop or if statement - Compiler::StaticType ret = variableTypeAfterBranchFromEnd(var, ins, previousType, write, visitedInstructions); + Compiler::StaticType ret = variableTypeAfterBranchFromEnd(var, ins, previousType, write, listTypes, visitedInstructions); if (typesMatch(ret, previousType)) { if (write) @@ -245,7 +169,7 @@ Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranchFromEnd(Variable * if (isElse(ins)) { // Process if branch (the else branch is already processed) - ret = variableTypeAfterBranchFromEnd(var, ins, previousType, write, visitedInstructions); + ret = variableTypeAfterBranchFromEnd(var, ins, previousType, write, listTypes, visitedInstructions); if (typesMatch(ret, previousType)) { if (write) { @@ -261,7 +185,7 @@ Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranchFromEnd(Variable * } } else if (isVariableWrite(ins, var) && !isWriteNoOp(ins)) { // Variable write instruction - Compiler::StaticType writeType = writeValueType(ins, visitedInstructions); + Compiler::StaticType writeType = writeValueType(ins, listTypes, visitedInstructions); write = true; if (typesMatch(writeType, previousType)) @@ -277,23 +201,134 @@ Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranchFromEnd(Variable * return previousType; } -Compiler::StaticType LLVMTypeAnalyzer::listTypeAfterBranch(List *list, LLVMInstruction *start, Compiler::StaticType previousType, bool isEmpty, LLVMInstruction *query, bool &write) const +Compiler::StaticType LLVMTypeAnalyzer:: + listType(List *list, LLVMInstruction *pos, Compiler::StaticType previousType, bool isEmpty, std::unordered_map listTypes, InstructionSet &visitedInstructions) const { - assert(isLoopStart(start) || isIfStart(start) || isElse(start)); + if (!list || !pos) + return Compiler::StaticType::Unknown; + + /* + * If the given instruction has already been processed, + * it means there's a circular dependency with an unknown type. + * See variableType() + */ + if (visitedInstructions.find(pos) != visitedInstructions.cend()) { + // Circular dependencies are rare (and bad) so don't optimize them + // TODO: The (previousType != Compiler::StaticType::Unknown) case isn't handled in tests + // Add a test case for it if you find it... + assert(previousType == Compiler::StaticType::Unknown); + return /*Compiler::StaticType::Unknown*/ previousType; + } - InstructionSet visitedInstructions; // TODO: Handle cross-variable/list dependencies + visitedInstructions.insert(pos); + listTypes[list] = previousType; - // Query point is only relevant in if statemenets because writes after them don't affect the result - if (isLoopStart(start)) - query = nullptr; + LLVMInstruction *ins = pos; + LLVMInstruction *previous = nullptr; + std::pair firstBranch = { nullptr, 0 }; + std::pair lastClear = { nullptr, 0 }; + int level = 0; - LLVMInstruction *ins = start->next; + // Find a start instruction (list clear in the top level or the first instruction) + while (ins) { + if (isLoopEnd(ins) || isIfEnd(ins)) + level++; + else if (isLoopStart(ins) || isIfStart(ins) || isElse(ins)) { + if (!isElse(ins)) + level--; + + if (!firstBranch.first || level < firstBranch.second) + firstBranch = { ins, level }; + } else if (isListClear(ins, list)) { + if (!lastClear.first || level < lastClear.second) + lastClear = { ins, level }; + } + + previous = ins; + ins = ins->previous; + } + + if (firstBranch.first) { + assert(firstBranch.second == level); + + // The first branch must be above the query point level + if (firstBranch.second == 0) + firstBranch.first = nullptr; + } + + // Clear must be in the top level + if (lastClear.second != level) + lastClear.first = nullptr; + + if (lastClear.first) { + ins = lastClear.first; + isEmpty = true; + } else + ins = previous; + + // Process from the start instruction + while (ins && ins != pos) { + if (isLoopStart(ins) || isIfStart(ins)) { + do { + bool write; + Compiler::StaticType type = listTypeAfterBranch(list, ins, previousType, isEmpty, pos, write, listTypes, visitedInstructions); + + // If this branch contains the query point, return the final type + if (ins == firstBranch.first) + return type; + + // If there was a write, the list is no longer empty + if (write) { + isEmpty = false; + + // The write could change the type + if (!typesMatch(type, previousType)) + previousType = type; + } + + // Skip the branch + ins = branchEnd(ins); + } while (isElse(ins)); // handle else branch + } else if (isListWrite(ins, list)) { + // List write instruction + Compiler::StaticType writeType = writeValueType(ins, listTypes, visitedInstructions); + + if (!handleListWrite(writeType, previousType, isEmpty)) + return Compiler::StaticType::Unknown; + } + + ins = ins->next; + } + + assert(ins); + return previousType; +} + +Compiler::StaticType LLVMTypeAnalyzer::listTypeAfterBranch( + List *list, + LLVMInstruction *start, + Compiler::StaticType previousType, + bool isEmpty, + LLVMInstruction *query, + bool &write, + std::unordered_map listTypes, + InstructionSet &visitedInstructions) const +{ write = false; + if (!list || !start) + return previousType; + + assert(isLoopStart(start) || isIfStart(start) || isElse(start)); + + bool isLoop = isLoopStart(start); + bool clearBeforeQueryPoint = false; + LLVMInstruction *ins = start->next; + while (ins && !(isLoopEnd(ins) || isIfEnd(ins) || isElse(ins))) { if (isLoopStart(ins) || isIfStart(ins)) { do { - Compiler::StaticType type = listTypeAfterBranch(list, ins, previousType, isEmpty, query, write); + Compiler::StaticType type = listTypeAfterBranch(list, ins, previousType, isEmpty, query, write, listTypes, visitedInstructions); // If there was a write, the list is no longer empty if (write) { @@ -309,7 +344,7 @@ Compiler::StaticType LLVMTypeAnalyzer::listTypeAfterBranch(List *list, LLVMInstr } while (isElse(ins)); // handle else branch } else if (isListWrite(ins, list)) { // List write instruction - Compiler::StaticType writeType = writeValueType(ins, visitedInstructions); + Compiler::StaticType writeType = writeValueType(ins, listTypes, visitedInstructions); write = true; if (!handleListWrite(writeType, previousType, isEmpty)) @@ -317,9 +352,14 @@ Compiler::StaticType LLVMTypeAnalyzer::listTypeAfterBranch(List *list, LLVMInstr } else if (isListClear(ins, list)) { // The list is now empty isEmpty = true; + clearBeforeQueryPoint = true; write = false; // the write variable is only used to check if the list is still empty - } else if (ins == query) - break; + } else if (ins == query) { + if (!isLoop || clearBeforeQueryPoint) + break; + + clearBeforeQueryPoint = false; + } ins = ins->next; } @@ -429,6 +469,11 @@ bool LLVMTypeAnalyzer::isVariableWrite(LLVMInstruction *ins, Variable *var) cons return (ins->type == LLVMInstruction::Type::WriteVariable && ins->workVariable == var); } +bool LLVMTypeAnalyzer::isListRead(LLVMInstruction *ins) const +{ + return (ins->type == LLVMInstruction::Type::GetListItem); +} + bool LLVMTypeAnalyzer::isListWrite(LLVMInstruction *ins, List *list) const { return (LIST_WRITE_INSTRUCTIONS.find(ins->type) != LIST_WRITE_INSTRUCTIONS.cend() && ins->workList == list); @@ -470,7 +515,7 @@ bool LLVMTypeAnalyzer::isWriteNoOp(LLVMInstruction *ins) const return false; } -Compiler::StaticType LLVMTypeAnalyzer::writeValueType(LLVMInstruction *ins, InstructionSet &visitedInstructions) const +Compiler::StaticType LLVMTypeAnalyzer::writeValueType(LLVMInstruction *ins, std::unordered_map listTypes, InstructionSet &visitedInstructions) const { assert(ins); assert(!ins->args.empty()); @@ -480,7 +525,17 @@ Compiler::StaticType LLVMTypeAnalyzer::writeValueType(LLVMInstruction *ins, Inst // TODO: Handle list item if (isVariableRead(arg->instruction.get())) { // If this is a variable read instruction, recursively get the variable type - return variableType(arg->instruction->workVariable, arg->instruction.get(), Compiler::StaticType::Unknown, visitedInstructions); + return variableType(arg->instruction->workVariable, arg->instruction.get(), Compiler::StaticType::Unknown, listTypes, visitedInstructions); + } else if (isListRead(arg->instruction.get())) { + // If this is a list read instruction, recursively get the list type + Compiler::StaticType type = Compiler::StaticType::Unknown; + auto it = listTypes.find(arg->instruction->workList); + + if (it != listTypes.cend()) + type = it->second; + + // NOTE: The isEmpty parameter is useless here + return listType(arg->instruction->workList, arg->instruction.get(), type, false, listTypes, visitedInstructions); } else { // The write argument already has the instruction return type return optimizeRegisterType(arg); @@ -495,7 +550,7 @@ bool LLVMTypeAnalyzer::typesMatch(Compiler::StaticType a, Compiler::StaticType b return (a == b) && (a != Compiler::StaticType::Unknown); } -bool LLVMTypeAnalyzer::writeTypesMatch(LLVMInstruction *ins, Compiler::StaticType expectedType, InstructionSet &visitedInstructions) const +bool LLVMTypeAnalyzer::writeTypesMatch(LLVMInstruction *ins, Compiler::StaticType expectedType, std::unordered_map listTypes, InstructionSet &visitedInstructions) const { - return typesMatch(writeValueType(ins, visitedInstructions), expectedType); + return typesMatch(writeValueType(ins, listTypes, visitedInstructions), expectedType); } diff --git a/src/engine/internal/llvm/llvmtypeanalyzer.h b/src/engine/internal/llvm/llvmtypeanalyzer.h index 35b497327..d5f965df7 100644 --- a/src/engine/internal/llvm/llvmtypeanalyzer.h +++ b/src/engine/internal/llvm/llvmtypeanalyzer.h @@ -1,6 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 #include +#include namespace libscratchcpp { @@ -20,11 +21,33 @@ class LLVMTypeAnalyzer private: using InstructionSet = std::unordered_set; - Compiler::StaticType variableType(Variable *var, LLVMInstruction *pos, Compiler::StaticType previousType, InstructionSet &visitedInstructions) const; + Compiler::StaticType + variableType(Variable *var, LLVMInstruction *pos, Compiler::StaticType previousType, std::unordered_map listTypes, InstructionSet &visitedInstructions) const; + Compiler::StaticType variableTypeAfterBranch(Variable *var, LLVMInstruction *start, Compiler::StaticType previousType, InstructionSet &visitedInstructions) const; - Compiler::StaticType variableTypeAfterBranchFromEnd(Variable *var, LLVMInstruction *end, Compiler::StaticType previousType, bool &write, InstructionSet &visitedInstructions) const; - Compiler::StaticType listTypeAfterBranch(List *list, LLVMInstruction *start, Compiler::StaticType previousType, bool isEmpty, LLVMInstruction *query, bool &write) const; + Compiler::StaticType variableTypeAfterBranchFromEnd( + Variable *var, + LLVMInstruction *end, + Compiler::StaticType previousType, + bool &write, + std::unordered_map listTypes, + InstructionSet &visitedInstructions) const; + + Compiler::StaticType + listType(List *list, LLVMInstruction *pos, Compiler::StaticType previousType, bool isEmpty, std::unordered_map listTypes, InstructionSet &visitedInstructions) + const; + + Compiler::StaticType listTypeAfterBranch( + List *list, + LLVMInstruction *start, + Compiler::StaticType previousType, + bool isEmpty, + LLVMInstruction *query, + bool &write, + std::unordered_map listTypes, + InstructionSet &visitedInstructions) const; + bool handleListWrite(Compiler::StaticType writeType, Compiler::StaticType &previousType, bool &isEmpty) const; LLVMInstruction *branchEnd(LLVMInstruction *start) const; @@ -39,14 +62,15 @@ class LLVMTypeAnalyzer bool isVariableRead(LLVMInstruction *ins) const; bool isVariableWrite(LLVMInstruction *ins, Variable *var) const; + bool isListRead(LLVMInstruction *ins) const; bool isListWrite(LLVMInstruction *ins, List *list) const; bool isListClear(LLVMInstruction *ins, List *list) const; Compiler::StaticType optimizeRegisterType(LLVMRegister *reg) const; bool isWriteNoOp(LLVMInstruction *ins) const; - Compiler::StaticType writeValueType(LLVMInstruction *ins, InstructionSet &visitedInstructions) const; + Compiler::StaticType writeValueType(LLVMInstruction *ins, std::unordered_map listTypes, InstructionSet &visitedInstructions) const; bool typesMatch(Compiler::StaticType a, Compiler::StaticType b) const; - bool writeTypesMatch(LLVMInstruction *ins, Compiler::StaticType expectedType, InstructionSet &visitedInstructions) const; + bool writeTypesMatch(LLVMInstruction *ins, Compiler::StaticType expectedType, std::unordered_map listTypes, InstructionSet &visitedInstructions) const; }; } // namespace libscratchcpp diff --git a/test/llvm/type_analyzer/listtype_test.cpp b/test/llvm/type_analyzer/listtype_test.cpp index baf94722c..e44cf8255 100644 --- a/test/llvm/type_analyzer/listtype_test.cpp +++ b/test/llvm/type_analyzer/listtype_test.cpp @@ -2651,6 +2651,44 @@ TEST(LLVMTypeAnalyzer_ListType, ComplexMixedOperations_InLoop) ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::String, true), Compiler::StaticType::Unknown); } +TEST(LLVMTypeAnalyzer_ListType, MultipleClearsInLoop) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + auto clearList = std::make_shared(LLVMInstruction::Type::ClearList, nullptr, false); + clearList->workList = &list; + instructionList.addInstruction(clearList); + + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::String, "test"); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + clearList = std::make_shared(LLVMInstruction::Type::ClearList, nullptr, false); + clearList->workList = &list; + instructionList.addInstruction(clearList); + + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::Number, 5); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(appendList2); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Bool, false), Compiler::StaticType::String); +} + TEST(LLVMTypeAnalyzer_ListType, ClearAndRebuild_WithDifferentTypes) { LLVMTypeAnalyzer analyzer; @@ -3371,3 +3409,599 @@ TEST(LLVMTypeAnalyzer_ListType, ClearListInLoop_AppendToEmptyListAndClearInElseB // Should return String because the list remains empty after the if statement ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::String); } + +TEST(LLVMTypeAnalyzer_ListType, CrossListDependency_SimpleRead_NonEmpty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List sourceList("source", ""); + List targetList("target", ""); + + // Establish source list type + auto clearList = std::make_shared(LLVMInstruction::Type::ClearList, nullptr, false); + clearList->workList = &sourceList; + instructionList.addInstruction(clearList); + + auto appendSource = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister sourceValue(Compiler::StaticType::String, "hello"); + appendSource->workList = &sourceList; + appendSource->args.push_back({ Compiler::StaticType::Unknown, &sourceValue }); + instructionList.addInstruction(appendSource); + + // Read from source list and write to target list + auto readSource = std::make_shared(LLVMInstruction::Type::GetListItem, nullptr, false); + auto readSourceReg = std::make_shared(Compiler::StaticType::Unknown); + readSourceReg->instruction = readSource; + readSourceReg->isRawValue = false; + readSource->functionReturnReg = readSourceReg.get(); + LLVMConstantRegister index(Compiler::StaticType::Number, 0); + readSource->workList = &sourceList; + readSource->args.push_back({ Compiler::StaticType::Number, &index }); + instructionList.addInstruction(readSource); + + auto appendTarget = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + appendTarget->workList = &targetList; + appendTarget->args.push_back({ Compiler::StaticType::Unknown, readSourceReg.get() }); + instructionList.addInstruction(appendTarget); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + ASSERT_EQ(analyzer.listType(&targetList, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListType, CrossListDependency_SimpleRead_Empty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List sourceList("source", ""); + List targetList("target", ""); + + // Establish source list type + auto clearList = std::make_shared(LLVMInstruction::Type::ClearList, nullptr, false); + clearList->workList = &sourceList; + instructionList.addInstruction(clearList); + + auto appendSource = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister sourceValue(Compiler::StaticType::Bool, true); + appendSource->workList = &sourceList; + appendSource->args.push_back({ Compiler::StaticType::Unknown, &sourceValue }); + instructionList.addInstruction(appendSource); + + // Read from source list and write to target list + auto readSource = std::make_shared(LLVMInstruction::Type::GetListItem, nullptr, false); + auto readSourceReg = std::make_shared(Compiler::StaticType::Unknown); + readSourceReg->instruction = readSource; + readSourceReg->isRawValue = false; + readSource->functionReturnReg = readSourceReg.get(); + LLVMConstantRegister index(Compiler::StaticType::Number, 0); + readSource->workList = &sourceList; + readSource->args.push_back({ Compiler::StaticType::Number, &index }); + instructionList.addInstruction(readSource); + + auto appendTarget = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + appendTarget->workList = &targetList; + appendTarget->args.push_back({ Compiler::StaticType::Unknown, readSourceReg.get() }); + instructionList.addInstruction(appendTarget); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + ASSERT_EQ(analyzer.listType(&targetList, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Bool); +} + +TEST(LLVMTypeAnalyzer_ListType, CrossListDependency_InLoop_TypeConflict) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List sourceList("source", ""); + List targetList("target", ""); + + auto loopStart = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(loopStart); + + // Clear source list + auto clearList = std::make_shared(LLVMInstruction::Type::ClearList, nullptr, false); + clearList->workList = &sourceList; + instructionList.addInstruction(clearList); + + // First iteration: append string to source + auto appendSource1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister sourceValue1(Compiler::StaticType::String, "text"); + appendSource1->workList = &sourceList; + appendSource1->args.push_back({ Compiler::StaticType::Unknown, &sourceValue1 }); + instructionList.addInstruction(appendSource1); + + // Read from source and write to target + auto readSource1 = std::make_shared(LLVMInstruction::Type::GetListItem, nullptr, false); + auto readSource1Reg = std::make_shared(Compiler::StaticType::Unknown); + readSource1Reg->instruction = readSource1; + readSource1Reg->isRawValue = false; + readSource1->functionReturnReg = readSource1Reg.get(); + LLVMConstantRegister index1(Compiler::StaticType::Number, 0); + readSource1->workList = &sourceList; + readSource1->args.push_back({ Compiler::StaticType::Number, &index1 }); + instructionList.addInstruction(readSource1); + + auto appendTarget1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + appendTarget1->workList = &targetList; + appendTarget1->args.push_back({ Compiler::StaticType::Unknown, readSource1Reg.get() }); + instructionList.addInstruction(appendTarget1); + + // Second iteration: append number to source (creates type conflict) + auto appendSource2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister sourceValue2(Compiler::StaticType::Number, 42); + appendSource2->workList = &sourceList; + appendSource2->args.push_back({ Compiler::StaticType::Unknown, &sourceValue2 }); + instructionList.addInstruction(appendSource2); + + // Read from source and write to target + auto readSource2 = std::make_shared(LLVMInstruction::Type::GetListItem, nullptr, false); + auto readSource2Reg = std::make_shared(Compiler::StaticType::Unknown); + readSource2Reg->instruction = readSource2; + readSource2Reg->isRawValue = false; + readSource2->functionReturnReg = readSource2Reg.get(); + LLVMConstantRegister index2(Compiler::StaticType::Number, 1); + readSource2->workList = &sourceList; + readSource2->args.push_back({ Compiler::StaticType::Number, &index2 }); + instructionList.addInstruction(readSource2); + + auto appendTarget2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + appendTarget2->workList = &targetList; + appendTarget2->args.push_back({ Compiler::StaticType::Unknown, readSource2Reg.get() }); + instructionList.addInstruction(appendTarget2); + + auto loopEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(loopEnd); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + ASSERT_EQ(analyzer.listType(&targetList, funcCall.get(), Compiler::StaticType::String, true), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListType, CrossListDependency_InLoop_ConsistentType_NonEmptySource) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List sourceList("source", ""); + List targetList("target", ""); + + auto loopStart = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(loopStart); + + // Append number to source + auto appendSource = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister sourceValue(Compiler::StaticType::Number, 3.14); + appendSource->workList = &sourceList; + appendSource->args.push_back({ Compiler::StaticType::Unknown, &sourceValue }); + instructionList.addInstruction(appendSource); + + // Read from source and write to target + auto readSource = std::make_shared(LLVMInstruction::Type::GetListItem, nullptr, false); + auto readSourceReg = std::make_shared(Compiler::StaticType::Unknown); + readSourceReg->instruction = readSource; + readSourceReg->isRawValue = false; + readSource->functionReturnReg = readSourceReg.get(); + LLVMConstantRegister index(Compiler::StaticType::Number, 0); + readSource->workList = &sourceList; + readSource->args.push_back({ Compiler::StaticType::Number, &index }); + instructionList.addInstruction(readSource); + + auto appendTarget = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + appendTarget->workList = &targetList; + appendTarget->args.push_back({ Compiler::StaticType::Unknown, readSourceReg.get() }); + instructionList.addInstruction(appendTarget); + + auto loopEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(loopEnd); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + ASSERT_EQ(analyzer.listType(&targetList, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListType, CrossListDependency_InLoop_ConsistentType_EmptySource) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List sourceList("source", ""); + List targetList("target", ""); + + auto clearList = std::make_shared(LLVMInstruction::Type::ClearList, nullptr, false); + clearList->workList = &sourceList; + instructionList.addInstruction(clearList); + + auto loopStart = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(loopStart); + + // Append number to source + auto appendSource = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister sourceValue(Compiler::StaticType::Number, 3.14); + appendSource->workList = &sourceList; + appendSource->args.push_back({ Compiler::StaticType::Unknown, &sourceValue }); + instructionList.addInstruction(appendSource); + + // Read from source and write to target + auto readSource = std::make_shared(LLVMInstruction::Type::GetListItem, nullptr, false); + auto readSourceReg = std::make_shared(Compiler::StaticType::Unknown); + readSourceReg->instruction = readSource; + readSourceReg->isRawValue = false; + readSource->functionReturnReg = readSourceReg.get(); + LLVMConstantRegister index(Compiler::StaticType::Number, 0); + readSource->workList = &sourceList; + readSource->args.push_back({ Compiler::StaticType::Number, &index }); + instructionList.addInstruction(readSource); + + auto appendTarget = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + appendTarget->workList = &targetList; + appendTarget->args.push_back({ Compiler::StaticType::Unknown, readSourceReg.get() }); + instructionList.addInstruction(appendTarget); + + auto loopEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(loopEnd); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + ASSERT_EQ(analyzer.listType(&targetList, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_ListType, CrossListDependency_Circular_TypeSafety) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List listA("listA", ""); + List listB("listB", ""); + + auto clearList = std::make_shared(LLVMInstruction::Type::ClearList, nullptr, false); + clearList->workList = &listA; + instructionList.addInstruction(clearList); + + clearList = std::make_shared(LLVMInstruction::Type::ClearList, nullptr, false); + clearList->workList = &listB; + instructionList.addInstruction(clearList); + + // Initialize listA with a number + auto appendA1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister valueA1(Compiler::StaticType::Number, 10); + appendA1->workList = &listA; + appendA1->args.push_back({ Compiler::StaticType::Unknown, &valueA1 }); + instructionList.addInstruction(appendA1); + + // Read from listA and write to listB + auto readA = std::make_shared(LLVMInstruction::Type::GetListItem, nullptr, false); + auto readAReg = std::make_shared(Compiler::StaticType::Unknown); + readAReg->instruction = readA; + readAReg->isRawValue = false; + readA->functionReturnReg = readAReg.get(); + LLVMConstantRegister indexA(Compiler::StaticType::Number, 0); + readA->workList = &listA; + readA->args.push_back({ Compiler::StaticType::Number, &indexA }); + instructionList.addInstruction(readA); + + auto appendB = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + appendB->workList = &listB; + appendB->args.push_back({ Compiler::StaticType::Unknown, readAReg.get() }); + instructionList.addInstruction(appendB); + + // Read from listB and write back to listA (circular dependency) + auto readB = std::make_shared(LLVMInstruction::Type::GetListItem, nullptr, false); + auto readBReg = std::make_shared(Compiler::StaticType::Unknown); + readBReg->instruction = readB; + readBReg->isRawValue = false; + readB->functionReturnReg = readBReg.get(); + LLVMConstantRegister indexB(Compiler::StaticType::Number, 0); + readB->workList = &listB; + readB->args.push_back({ Compiler::StaticType::Number, &indexB }); + instructionList.addInstruction(readB); + + auto appendA2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + appendA2->workList = &listA; + appendA2->args.push_back({ Compiler::StaticType::Unknown, readBReg.get() }); + instructionList.addInstruction(appendA2); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + ASSERT_EQ(analyzer.listType(&listA, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_ListType, CrossListDependency_Circular_TypeSafety_InLoop) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List listA("listA", ""); + List listB("listB", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + auto clearList = std::make_shared(LLVMInstruction::Type::ClearList, nullptr, false); + clearList->workList = &listA; + instructionList.addInstruction(clearList); + + clearList = std::make_shared(LLVMInstruction::Type::ClearList, nullptr, false); + clearList->workList = &listB; + instructionList.addInstruction(clearList); + + // Initialize listA with a number + auto appendA1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister valueA1(Compiler::StaticType::Number, 10); + appendA1->workList = &listA; + appendA1->args.push_back({ Compiler::StaticType::Unknown, &valueA1 }); + instructionList.addInstruction(appendA1); + + // Read from listA and write to listB + auto readA = std::make_shared(LLVMInstruction::Type::GetListItem, nullptr, false); + auto readAReg = std::make_shared(Compiler::StaticType::Unknown); + readAReg->instruction = readA; + readAReg->isRawValue = false; + readA->functionReturnReg = readAReg.get(); + LLVMConstantRegister indexA(Compiler::StaticType::Number, 0); + readA->workList = &listA; + readA->args.push_back({ Compiler::StaticType::Number, &indexA }); + instructionList.addInstruction(readA); + + auto appendB = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + appendB->workList = &listB; + appendB->args.push_back({ Compiler::StaticType::Unknown, readAReg.get() }); + instructionList.addInstruction(appendB); + + // Read from listB and write back to listA (circular dependency) + auto readB = std::make_shared(LLVMInstruction::Type::GetListItem, nullptr, false); + auto readBReg = std::make_shared(Compiler::StaticType::Unknown); + readBReg->instruction = readB; + readBReg->isRawValue = false; + readB->functionReturnReg = readBReg.get(); + LLVMConstantRegister indexB(Compiler::StaticType::Number, 0); + readB->workList = &listB; + readB->args.push_back({ Compiler::StaticType::Number, &indexB }); + instructionList.addInstruction(readB); + + auto appendA2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + appendA2->workList = &listA; + appendA2->args.push_back({ Compiler::StaticType::Unknown, readBReg.get() }); + instructionList.addInstruction(appendA2); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + ASSERT_EQ(analyzer.listType(&listA, funcCall.get(), Compiler::StaticType::String, false), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_ListType, CrossListDependency_Circular_TypeConflict) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List listA("listA", ""); + List listB("listB", ""); + + auto clearList = std::make_shared(LLVMInstruction::Type::ClearList, nullptr, false); + clearList->workList = &listA; + instructionList.addInstruction(clearList); + + clearList = std::make_shared(LLVMInstruction::Type::ClearList, nullptr, false); + clearList->workList = &listB; + instructionList.addInstruction(clearList); + + auto loopStart = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(loopStart); + + // Initialize listA with a number + auto appendA1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister valueA1(Compiler::StaticType::Number, 10); + appendA1->workList = &listA; + appendA1->args.push_back({ Compiler::StaticType::Unknown, &valueA1 }); + instructionList.addInstruction(appendA1); + + // Read from listA and write to listB + auto readA = std::make_shared(LLVMInstruction::Type::GetListItem, nullptr, false); + auto readAReg = std::make_shared(Compiler::StaticType::Unknown); + readAReg->instruction = readA; + readAReg->isRawValue = false; + readA->functionReturnReg = readAReg.get(); + LLVMConstantRegister indexA(Compiler::StaticType::Number, 0); + readA->workList = &listA; + readA->args.push_back({ Compiler::StaticType::Number, &indexA }); + instructionList.addInstruction(readA); + + auto appendB = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + appendB->workList = &listB; + appendB->args.push_back({ Compiler::StaticType::Unknown, readAReg.get() }); + instructionList.addInstruction(appendB); + + // Create type conflict by appending string to listB + auto appendB2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister valueB2(Compiler::StaticType::String, "conflict"); + appendB2->workList = &listB; + appendB2->args.push_back({ Compiler::StaticType::Unknown, &valueB2 }); + instructionList.addInstruction(appendB2); + + // Read from listB and write back to listA (circular dependency with type conflict) + auto readB = std::make_shared(LLVMInstruction::Type::GetListItem, nullptr, false); + auto readBReg = std::make_shared(Compiler::StaticType::Unknown); + readBReg->instruction = readB; + readBReg->isRawValue = false; + readB->functionReturnReg = readBReg.get(); + LLVMConstantRegister indexB(Compiler::StaticType::Number, 0); + readB->workList = &listB; + readB->args.push_back({ Compiler::StaticType::Number, &indexB }); + instructionList.addInstruction(readB); + + auto appendA2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + appendA2->workList = &listA; + appendA2->args.push_back({ Compiler::StaticType::Unknown, readBReg.get() }); + instructionList.addInstruction(appendA2); + + auto loopEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(loopEnd); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + // Should return Unknown due to circular dependency with type conflicts + ASSERT_EQ(analyzer.listType(&listA, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListType, CrossListDependency_Circular_SingleList_KnownType_Empty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto clearList = std::make_shared(LLVMInstruction::Type::ClearList, nullptr, false); + clearList->workList = &list; + instructionList.addInstruction(clearList); + + // Initialize list with a number + auto append1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 10); + append1->workList = &list; + append1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(append1); + + // Read from list and write to list + auto read = std::make_shared(LLVMInstruction::Type::GetListItem, nullptr, false); + auto readReg = std::make_shared(Compiler::StaticType::Unknown); + readReg->instruction = read; + readReg->isRawValue = false; + read->functionReturnReg = readReg.get(); + LLVMConstantRegister index(Compiler::StaticType::Number, 0); + read->workList = &list; + read->args.push_back({ Compiler::StaticType::Number, &index }); + instructionList.addInstruction(read); + + auto append2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + append2->workList = &list; + append2->args.push_back({ Compiler::StaticType::Unknown, readReg.get() }); + instructionList.addInstruction(append2); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::String, false), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_ListType, CrossListDependency_Circular_SingleList_KnownType_NonEmpty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + // Read from list and write to list + auto read = std::make_shared(LLVMInstruction::Type::GetListItem, nullptr, false); + auto readReg = std::make_shared(Compiler::StaticType::Unknown); + readReg->instruction = read; + readReg->isRawValue = false; + read->functionReturnReg = readReg.get(); + LLVMConstantRegister index(Compiler::StaticType::Number, 0); + read->workList = &list; + read->args.push_back({ Compiler::StaticType::Number, &index }); + instructionList.addInstruction(read); + + auto append2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + append2->workList = &list; + append2->args.push_back({ Compiler::StaticType::Unknown, readReg.get() }); + instructionList.addInstruction(append2); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_ListType, CrossListDependency_Circular_SingleList_UnknownType) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + // Read from list and write to list + auto read = std::make_shared(LLVMInstruction::Type::GetListItem, nullptr, false); + auto readReg = std::make_shared(Compiler::StaticType::Unknown); + readReg->instruction = read; + readReg->isRawValue = false; + read->functionReturnReg = readReg.get(); + LLVMConstantRegister index(Compiler::StaticType::Number, 0); + read->workList = &list; + read->args.push_back({ Compiler::StaticType::Number, &index }); + instructionList.addInstruction(read); + + auto append2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + append2->workList = &list; + append2->args.push_back({ Compiler::StaticType::Unknown, readReg.get() }); + instructionList.addInstruction(append2); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Unknown, false), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListType, CrossListDependency_ChainedReads_TypePropagation) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List listA("listA", ""); + List listB("listB", ""); + List listC("listC", ""); + + // Clear lists + auto clearList = std::make_shared(LLVMInstruction::Type::ClearList, nullptr, false); + clearList->workList = &listA; + instructionList.addInstruction(clearList); + + clearList = std::make_shared(LLVMInstruction::Type::ClearList, nullptr, false); + clearList->workList = &listB; + instructionList.addInstruction(clearList); + + // Initialize listA with a boolean + auto appendA = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister valueA(Compiler::StaticType::Bool, false); + appendA->workList = &listA; + appendA->args.push_back({ Compiler::StaticType::Unknown, &valueA }); + instructionList.addInstruction(appendA); + + // Read from listA and write to listB + auto readA = std::make_shared(LLVMInstruction::Type::GetListItem, nullptr, false); + auto readAReg = std::make_shared(Compiler::StaticType::Unknown); + readAReg->instruction = readA; + readAReg->isRawValue = false; + readA->functionReturnReg = readAReg.get(); + LLVMConstantRegister indexA(Compiler::StaticType::Number, 0); + readA->workList = &listA; + readA->args.push_back({ Compiler::StaticType::Number, &indexA }); + instructionList.addInstruction(readA); + + auto appendB = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + appendB->workList = &listB; + appendB->args.push_back({ Compiler::StaticType::Unknown, readAReg.get() }); + instructionList.addInstruction(appendB); + + // Read from listB and write to listC + auto readB = std::make_shared(LLVMInstruction::Type::GetListItem, nullptr, false); + auto readBReg = std::make_shared(Compiler::StaticType::Unknown); + readBReg->instruction = readB; + readBReg->isRawValue = false; + readB->functionReturnReg = readBReg.get(); + LLVMConstantRegister indexB(Compiler::StaticType::Number, 0); + readB->workList = &listB; + readB->args.push_back({ Compiler::StaticType::Number, &indexB }); + instructionList.addInstruction(readB); + + auto appendC = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + appendC->workList = &listC; + appendC->args.push_back({ Compiler::StaticType::Unknown, readBReg.get() }); + instructionList.addInstruction(appendC); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + // Type should propagate through the chain: A -> B -> C + ASSERT_EQ(analyzer.listType(&listC, funcCall.get(), Compiler::StaticType::String, true), Compiler::StaticType::Bool); +} diff --git a/test/llvm/type_analyzer/listtypeafterbranch_test.cpp b/test/llvm/type_analyzer/listtypeafterbranch_test.cpp index 8169e875d..5da22fd2e 100644 --- a/test/llvm/type_analyzer/listtypeafterbranch_test.cpp +++ b/test/llvm/type_analyzer/listtypeafterbranch_test.cpp @@ -2371,3 +2371,308 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, ClearListInLoop_AppendToEmptyListAndC // Should return String because the list remains empty after the if statement ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, true), Compiler::StaticType::String); } + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, CrossListDependency_ReadFromTypedList) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List sourceList("", ""); + List targetList("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + // Clear sourceList + auto clear = std::make_shared(LLVMInstruction::Type::ClearList, nullptr, false); + clear->workList = &sourceList; + instructionList.addInstruction(clear); + + // Set sourceList type + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 5); + appendList1->workList = &sourceList; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + // Read from sourceList + auto getItem = std::make_shared(LLVMInstruction::Type::GetListItem, nullptr, false); + LLVMConstantRegister index(Compiler::StaticType::Number, 0); + getItem->workList = &sourceList; + getItem->args.push_back({ Compiler::StaticType::Number, &index }); + auto itemRegister = std::make_shared(Compiler::StaticType::Unknown); + itemRegister->instruction = getItem; + itemRegister->isRawValue = false; + getItem->functionReturnReg = itemRegister.get(); + instructionList.addInstruction(getItem); + + // Append the read value to targetList + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + appendList2->workList = &targetList; + appendList2->args.push_back({ Compiler::StaticType::Unknown, itemRegister.get() }); + instructionList.addInstruction(appendList2); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + // Target list type depends on source list type + ASSERT_EQ(analyzer.listTypeAfterBranch(&targetList, start.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, CrossListDependency_ReadFromUnknownList) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List sourceList("", ""); + List targetList("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + // Read from sourceList + auto getItem = std::make_shared(LLVMInstruction::Type::GetListItem, nullptr, false); + LLVMConstantRegister index(Compiler::StaticType::Number, 0); + getItem->workList = &sourceList; + getItem->args.push_back({ Compiler::StaticType::Number, &index }); + auto itemRegister = std::make_shared(Compiler::StaticType::Unknown); + itemRegister->instruction = getItem; + itemRegister->isRawValue = false; + getItem->functionReturnReg = itemRegister.get(); + instructionList.addInstruction(getItem); + + // Append the read value to targetList + auto appendList = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + appendList->workList = &targetList; + appendList->args.push_back({ Compiler::StaticType::Unknown, itemRegister.get() }); + instructionList.addInstruction(appendList); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + ASSERT_EQ(analyzer.listTypeAfterBranch(&targetList, start.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, CrossListDependency_ChainedReads_KnownType) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list1("", ""); + List list2("", ""); + List list3("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + // Clear list1 + auto clear = std::make_shared(LLVMInstruction::Type::ClearList, nullptr, false); + clear->workList = &list1; + instructionList.addInstruction(clear); + + // Clear list2 + clear = std::make_shared(LLVMInstruction::Type::ClearList, nullptr, false); + clear->workList = &list2; + instructionList.addInstruction(clear); + + // Set list1 type + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 5); + appendList1->workList = &list1; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(appendList1); + + // Read from list1 + auto getItem1 = std::make_shared(LLVMInstruction::Type::GetListItem, nullptr, false); + LLVMConstantRegister index1(Compiler::StaticType::Number, 0); + getItem1->workList = &list1; + getItem1->args.push_back({ Compiler::StaticType::Number, &index1 }); + auto itemRegister1 = std::make_shared(Compiler::StaticType::Unknown); + itemRegister1->instruction = getItem1; + itemRegister1->isRawValue = false; + getItem1->functionReturnReg = itemRegister1.get(); + instructionList.addInstruction(getItem1); + + // Append to list2 + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + appendList2->workList = &list2; + appendList2->args.push_back({ Compiler::StaticType::Unknown, itemRegister1.get() }); + instructionList.addInstruction(appendList2); + + // Read from list2 + auto getItem2 = std::make_shared(LLVMInstruction::Type::GetListItem, nullptr, false); + LLVMConstantRegister index2(Compiler::StaticType::Number, 0); + getItem2->workList = &list2; + getItem2->args.push_back({ Compiler::StaticType::Number, &index2 }); + auto itemRegister2 = std::make_shared(Compiler::StaticType::Unknown); + itemRegister2->instruction = getItem2; + itemRegister2->isRawValue = false; + getItem2->functionReturnReg = itemRegister2.get(); + instructionList.addInstruction(getItem2); + + // Append to list3 + auto appendList3 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + appendList3->workList = &list3; + appendList3->args.push_back({ Compiler::StaticType::Unknown, itemRegister2.get() }); + instructionList.addInstruction(appendList3); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + ASSERT_EQ(analyzer.listTypeAfterBranch(&list3, start.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, CrossListDependency_ChainedReads_UnknownType) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list1("", ""); + List list2("", ""); + List list3("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + // Read from list1 + auto getItem1 = std::make_shared(LLVMInstruction::Type::GetListItem, nullptr, false); + LLVMConstantRegister index1(Compiler::StaticType::Number, 0); + getItem1->workList = &list1; + getItem1->args.push_back({ Compiler::StaticType::Number, &index1 }); + auto itemRegister1 = std::make_shared(Compiler::StaticType::Unknown); + itemRegister1->instruction = getItem1; + itemRegister1->isRawValue = false; + getItem1->functionReturnReg = itemRegister1.get(); + instructionList.addInstruction(getItem1); + + // Append to list2 + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + appendList2->workList = &list2; + appendList2->args.push_back({ Compiler::StaticType::Unknown, itemRegister1.get() }); + instructionList.addInstruction(appendList2); + + // Read from list2 + auto getItem2 = std::make_shared(LLVMInstruction::Type::GetListItem, nullptr, false); + LLVMConstantRegister index2(Compiler::StaticType::Number, 0); + getItem2->workList = &list2; + getItem2->args.push_back({ Compiler::StaticType::Number, &index2 }); + auto itemRegister2 = std::make_shared(Compiler::StaticType::Unknown); + itemRegister2->instruction = getItem2; + itemRegister2->isRawValue = false; + getItem2->functionReturnReg = itemRegister2.get(); + instructionList.addInstruction(getItem2); + + // Append to list3 + auto appendList3 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + appendList3->workList = &list3; + appendList3->args.push_back({ Compiler::StaticType::Unknown, itemRegister2.get() }); + instructionList.addInstruction(appendList3); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + // list3 should have Unknown type due to chained cross-list dependencies + ASSERT_EQ(analyzer.listTypeAfterBranch(&list3, start.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, CrossListDependency_ConditionalRead) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List sourceList("", ""); + List targetList("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + // If statement + auto ifStart = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + instructionList.addInstruction(ifStart); + + // Read from sourceList in if branch + auto getItem = std::make_shared(LLVMInstruction::Type::GetListItem, nullptr, false); + LLVMConstantRegister index(Compiler::StaticType::Number, 0); + getItem->workList = &sourceList; + getItem->args.push_back({ Compiler::StaticType::Number, &index }); + auto itemRegister = std::make_shared(Compiler::StaticType::Unknown); + itemRegister->instruction = getItem; + itemRegister->isRawValue = false; + getItem->functionReturnReg = itemRegister.get(); + instructionList.addInstruction(getItem); + + // Append to targetList + auto appendList = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + appendList->workList = &targetList; + appendList->args.push_back({ Compiler::StaticType::Unknown, itemRegister.get() }); + instructionList.addInstruction(appendList); + + // Else branch + auto elseStart = std::make_shared(LLVMInstruction::Type::BeginElse, nullptr, false); + instructionList.addInstruction(elseStart); + + // Direct append of constant value + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister directValue(Compiler::StaticType::Number, 42); + appendList2->workList = &targetList; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &directValue }); + instructionList.addInstruction(appendList2); + + auto ifEnd = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + instructionList.addInstruction(ifEnd); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + // Should return Unknown due to cross-list dependency and conditional execution + ASSERT_EQ(analyzer.listTypeAfterBranch(&targetList, start.get(), Compiler::StaticType::String, true), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, CrossListDependency_ReadWithInsertAndReplace) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List sourceList("", ""); + List targetList("", ""); + + auto start = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(start); + + // Read from sourceList + auto getItem = std::make_shared(LLVMInstruction::Type::GetListItem, nullptr, false); + LLVMConstantRegister index(Compiler::StaticType::Number, 0); + getItem->workList = &sourceList; + getItem->args.push_back({ Compiler::StaticType::Number, &index }); + auto itemRegister = std::make_shared(Compiler::StaticType::Unknown); + itemRegister->instruction = getItem; + itemRegister->isRawValue = false; + getItem->functionReturnReg = itemRegister.get(); + instructionList.addInstruction(getItem); + + // Insert the read value to targetList + auto insertList = std::make_shared(LLVMInstruction::Type::InsertToList, nullptr, false); + LLVMConstantRegister insertIndex(Compiler::StaticType::Number, 0); + insertList->workList = &targetList; + insertList->args.push_back({ Compiler::StaticType::Number, &insertIndex }); + insertList->args.push_back({ Compiler::StaticType::Unknown, itemRegister.get() }); + instructionList.addInstruction(insertList); + + // Replace with another read from the same list + auto getItem2 = std::make_shared(LLVMInstruction::Type::GetListItem, nullptr, false); + LLVMConstantRegister index2(Compiler::StaticType::Number, 1); + getItem2->workList = &sourceList; + getItem2->args.push_back({ Compiler::StaticType::Number, &index2 }); + auto itemRegister2 = std::make_shared(Compiler::StaticType::Unknown); + itemRegister2->instruction = getItem2; + itemRegister2->isRawValue = false; + getItem2->functionReturnReg = itemRegister2.get(); + instructionList.addInstruction(getItem2); + + auto replaceList = std::make_shared(LLVMInstruction::Type::ListReplace, nullptr, false); + LLVMConstantRegister replaceIndex(Compiler::StaticType::Number, 0); + replaceList->workList = &targetList; + replaceList->args.push_back({ Compiler::StaticType::Number, &replaceIndex }); + replaceList->args.push_back({ Compiler::StaticType::Unknown, itemRegister2.get() }); + instructionList.addInstruction(replaceList); + + auto end = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(end); + + // Should have Unknown type due to cross-list dependencies + ASSERT_EQ(analyzer.listTypeAfterBranch(&targetList, start.get(), Compiler::StaticType::String, true), Compiler::StaticType::Unknown); +} From ae4690a51c24b669c6ca69f37b3ad8e6c547ec3c Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Fri, 1 Aug 2025 15:16:43 +0200 Subject: [PATCH 45/79] Add mixed test suite for LLVMTypeAnalyzer --- test/llvm/CMakeLists.txt | 1 + test/llvm/type_analyzer/mixed_test.cpp | 492 +++++++++++++++++++++++++ 2 files changed, 493 insertions(+) create mode 100644 test/llvm/type_analyzer/mixed_test.cpp diff --git a/test/llvm/CMakeLists.txt b/test/llvm/CMakeLists.txt index 95330a1d0..e5bd2c391 100644 --- a/test/llvm/CMakeLists.txt +++ b/test/llvm/CMakeLists.txt @@ -24,6 +24,7 @@ add_executable( type_analyzer/variabletype_test.cpp type_analyzer/listtypeafterbranch_test.cpp type_analyzer/listtype_test.cpp + type_analyzer/mixed_test.cpp ) target_link_libraries( diff --git a/test/llvm/type_analyzer/mixed_test.cpp b/test/llvm/type_analyzer/mixed_test.cpp new file mode 100644 index 000000000..9ef3fc954 --- /dev/null +++ b/test/llvm/type_analyzer/mixed_test.cpp @@ -0,0 +1,492 @@ +#include +#include +#include +#include +#include +#include +#include + +using namespace libscratchcpp; + +TEST(LLVMTypeAnalyzer_MixedTest, VariableToList_SimpleTransfer_NonEmpty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + Variable sourceVar("sourceVar", ""); + List targetList("targetList", ""); + + auto clearList = std::make_shared(LLVMInstruction::Type::ClearList, nullptr, false); + clearList->workList = &targetList; + instructionList.addInstruction(clearList); + + // Write to variable + auto writeVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister varValue(Compiler::StaticType::String, "hello"); + writeVar->workVariable = &sourceVar; + writeVar->args.push_back({ Compiler::StaticType::Unknown, &varValue }); + instructionList.addInstruction(writeVar); + + // Read from variable and write to list + auto readVar = std::make_shared(LLVMInstruction::Type::ReadVariable, nullptr, false); + auto readVarReg = std::make_shared(Compiler::StaticType::Unknown); + readVar->functionReturnReg = readVarReg.get(); + readVarReg->instruction = readVar; + readVar->workVariable = &sourceVar; + instructionList.addInstruction(readVar); + + auto appendList = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + appendList->workList = &targetList; + appendList->args.push_back({ Compiler::StaticType::Unknown, readVarReg.get() }); + instructionList.addInstruction(appendList); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + // List type should match variable type + ASSERT_EQ(analyzer.listType(&targetList, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::String); +} + +TEST(LLVMTypeAnalyzer_MixedTest, ListToVariable_SimpleTransfer_Empty) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List sourceList("sourceList", ""); + Variable targetVar("targetVar", ""); + + auto clearList = std::make_shared(LLVMInstruction::Type::ClearList, nullptr, false); + clearList->workList = &sourceList; + instructionList.addInstruction(clearList); + + // Write to list + auto appendList = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister listValue(Compiler::StaticType::Bool, true); + appendList->workList = &sourceList; + appendList->args.push_back({ Compiler::StaticType::Unknown, &listValue }); + instructionList.addInstruction(appendList); + + // Read from list and write to variable + auto readList = std::make_shared(LLVMInstruction::Type::GetListItem, nullptr, false); + auto readListReg = std::make_shared(Compiler::StaticType::Unknown); + readList->functionReturnReg = readListReg.get(); + readListReg->instruction = readList; + LLVMConstantRegister index(Compiler::StaticType::Number, 0); + readList->workList = &sourceList; + readList->args.push_back({ Compiler::StaticType::Number, &index }); + instructionList.addInstruction(readList); + + auto writeVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + writeVar->workVariable = &targetVar; + writeVar->args.push_back({ Compiler::StaticType::Unknown, readListReg.get() }); + instructionList.addInstruction(writeVar); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + // Variable type should match list type + ASSERT_EQ(analyzer.variableType(&targetVar, funcCall.get(), Compiler::StaticType::String), Compiler::StaticType::Bool); +} + +TEST(LLVMTypeAnalyzer_MixedTest, CircularVarListDependency_TypeSafety) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + Variable var("var", ""); + List list("list", ""); + + // Initialize variable with number + auto writeVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 42); + writeVar1->workVariable = &var; + writeVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(writeVar1); + + // Read from variable and write to list + auto readVar = std::make_shared(LLVMInstruction::Type::ReadVariable, nullptr, false); + auto readVarReg = std::make_shared(Compiler::StaticType::Unknown); + readVar->functionReturnReg = readVarReg.get(); + readVarReg->instruction = readVar; + readVar->workVariable = &var; + instructionList.addInstruction(readVar); + + auto clearList = std::make_shared(LLVMInstruction::Type::ClearList, nullptr, false); + clearList->workList = &list; + instructionList.addInstruction(clearList); + + auto appendList = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Unknown, readVarReg.get() }); + instructionList.addInstruction(appendList); + + // Read from list and write back to variable (circular dependency) + auto readList = std::make_shared(LLVMInstruction::Type::GetListItem, nullptr, false); + auto readListReg = std::make_shared(Compiler::StaticType::Unknown); + readList->functionReturnReg = readListReg.get(); + readListReg->instruction = readList; + LLVMConstantRegister index(Compiler::StaticType::Number, 0); + readList->workList = &list; + readList->args.push_back({ Compiler::StaticType::Number, &index }); + instructionList.addInstruction(readList); + + auto writeVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + writeVar2->workVariable = &var; + writeVar2->args.push_back({ Compiler::StaticType::Unknown, readListReg.get() }); + instructionList.addInstruction(writeVar2); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + // Should handle circular dependency gracefully + ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number); + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_MixedTest, LoopWithVarListInteraction_TypeConflict) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + Variable var("var", ""); + List list("list", ""); + + auto clearList = std::make_shared(LLVMInstruction::Type::ClearList, nullptr, false); + clearList->workList = &list; + instructionList.addInstruction(clearList); + + // First iteration: write string to variable + auto writeVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::String, "text"); + writeVar1->workVariable = &var; + writeVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(writeVar1); + + auto loopStart = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(loopStart); + + // Read from variable and write to list + auto readVar = std::make_shared(LLVMInstruction::Type::ReadVariable, nullptr, false); + auto readVarReg = std::make_shared(Compiler::StaticType::Unknown); + readVar->functionReturnReg = readVarReg.get(); + readVarReg->instruction = readVar; + readVar->workVariable = &var; + instructionList.addInstruction(readVar); + + auto appendList = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Unknown, readVarReg.get() }); + instructionList.addInstruction(appendList); + + // Second iteration: write number to variable (creates type conflict) + auto writeVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::Number, 42); + writeVar2->workVariable = &var; + writeVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(writeVar2); + + auto loopEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(loopEnd); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + // Should return Unknown due to type conflict + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::String, false), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_MixedTest, ConditionalVarListTransfer_TypeConflict) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + Variable var("var", ""); + List list("list", ""); + + auto clearList = std::make_shared(LLVMInstruction::Type::ClearList, nullptr, false); + clearList->workList = &list; + instructionList.addInstruction(clearList); + + auto ifStart = std::make_shared(LLVMInstruction::Type::BeginIf, nullptr, false); + instructionList.addInstruction(ifStart); + + // If branch: write number to variable, transfer to list + auto writeVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Number, 123); + writeVar1->workVariable = &var; + writeVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(writeVar1); + + auto readVar1 = std::make_shared(LLVMInstruction::Type::ReadVariable, nullptr, false); + auto readVar1Reg = std::make_shared(Compiler::StaticType::Unknown); + readVar1->functionReturnReg = readVar1Reg.get(); + readVar1Reg->instruction = readVar1; + readVar1->workVariable = &var; + instructionList.addInstruction(readVar1); + + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, readVar1Reg.get() }); + instructionList.addInstruction(appendList1); + + auto elseStart = std::make_shared(LLVMInstruction::Type::BeginElse, nullptr, false); + instructionList.addInstruction(elseStart); + + // Else branch: write string to variable, transfer to list + auto writeVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::String, "hello"); + writeVar2->workVariable = &var; + writeVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(writeVar2); + + auto readVar2 = std::make_shared(LLVMInstruction::Type::ReadVariable, nullptr, false); + auto readVar2Reg = std::make_shared(Compiler::StaticType::Unknown); + readVar2->functionReturnReg = readVar2Reg.get(); + readVar2Reg->instruction = readVar2; + readVar2->workVariable = &var; + instructionList.addInstruction(readVar2); + + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, readVar2Reg.get() }); + instructionList.addInstruction(appendList2); + + auto ifEnd = std::make_shared(LLVMInstruction::Type::EndIf, nullptr, false); + instructionList.addInstruction(ifEnd); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + // Should return Unknown due to conditional type conflicts + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown); +} + +TEST(LLVMTypeAnalyzer_MixedTest, MultipleVarsToSingleList_TypePropagation) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + Variable var1("var1", ""); + Variable var2("var2", ""); + List list("list", ""); + + auto clearList = std::make_shared(LLVMInstruction::Type::ClearList, nullptr, false); + clearList->workList = &list; + instructionList.addInstruction(clearList); + + // Initialize first variable with boolean + auto writeVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Bool, true); + writeVar1->workVariable = &var1; + writeVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(writeVar1); + + // Initialize second variable with same type + auto writeVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::Bool, false); + writeVar2->workVariable = &var2; + writeVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(writeVar2); + + // Read from first variable and write to list + auto readVar1 = std::make_shared(LLVMInstruction::Type::ReadVariable, nullptr, false); + auto readVar1Reg = std::make_shared(Compiler::StaticType::Unknown); + readVar1->functionReturnReg = readVar1Reg.get(); + readVar1Reg->instruction = readVar1; + readVar1->workVariable = &var1; + instructionList.addInstruction(readVar1); + + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + appendList1->workList = &list; + appendList1->args.push_back({ Compiler::StaticType::Unknown, readVar1Reg.get() }); + instructionList.addInstruction(appendList1); + + // Read from second variable and write to list + auto readVar2 = std::make_shared(LLVMInstruction::Type::ReadVariable, nullptr, false); + auto readVar2Reg = std::make_shared(Compiler::StaticType::Unknown); + readVar2->functionReturnReg = readVar2Reg.get(); + readVar2Reg->instruction = readVar2; + readVar2->workVariable = &var2; + instructionList.addInstruction(readVar2); + + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + appendList2->workList = &list; + appendList2->args.push_back({ Compiler::StaticType::Unknown, readVar2Reg.get() }); + instructionList.addInstruction(appendList2); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + // List should have Bool type from both variables + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::String, false), Compiler::StaticType::Bool); +} + +TEST(LLVMTypeAnalyzer_MixedTest, SingleListToMultipleVars_TypePropagation) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List sourceList("sourceList", ""); + Variable var1("var1", ""); + Variable var2("var2", ""); + + auto clearList = std::make_shared(LLVMInstruction::Type::ClearList, nullptr, false); + clearList->workList = &sourceList; + instructionList.addInstruction(clearList); + + // Initialize list with string values + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister listValue1(Compiler::StaticType::String, "first"); + appendList1->workList = &sourceList; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &listValue1 }); + instructionList.addInstruction(appendList1); + + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister listValue2(Compiler::StaticType::String, "second"); + appendList2->workList = &sourceList; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &listValue2 }); + instructionList.addInstruction(appendList2); + + // Read first item and write to first variable + auto readList1 = std::make_shared(LLVMInstruction::Type::GetListItem, nullptr, false); + auto readList1Reg = std::make_shared(Compiler::StaticType::Unknown); + readList1->functionReturnReg = readList1Reg.get(); + readList1Reg->instruction = readList1; + LLVMConstantRegister index1(Compiler::StaticType::Number, 0); + readList1->workList = &sourceList; + readList1->args.push_back({ Compiler::StaticType::Number, &index1 }); + instructionList.addInstruction(readList1); + + auto writeVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + writeVar1->workVariable = &var1; + writeVar1->args.push_back({ Compiler::StaticType::Unknown, readList1Reg.get() }); + instructionList.addInstruction(writeVar1); + + // Read second item and write to second variable + auto readList2 = std::make_shared(LLVMInstruction::Type::GetListItem, nullptr, false); + auto readList2Reg = std::make_shared(Compiler::StaticType::Unknown); + readList2->functionReturnReg = readList2Reg.get(); + readList2Reg->instruction = readList2; + LLVMConstantRegister index2(Compiler::StaticType::Number, 1); + readList2->workList = &sourceList; + readList2->args.push_back({ Compiler::StaticType::Number, &index2 }); + instructionList.addInstruction(readList2); + + auto writeVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + writeVar2->workVariable = &var2; + writeVar2->args.push_back({ Compiler::StaticType::Unknown, readList2Reg.get() }); + instructionList.addInstruction(writeVar2); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + // Both variables should have String type from the list + ASSERT_EQ(analyzer.variableType(&var1, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::String); + ASSERT_EQ(analyzer.variableType(&var2, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::String); +} + +TEST(LLVMTypeAnalyzer_MixedTest, ComplexChain_VarToListToVar_TypePropagation) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + Variable sourceVar("sourceVar", ""); + List intermediateList("intermediateList", ""); + Variable targetVar("targetVar", ""); + + auto clearList = std::make_shared(LLVMInstruction::Type::ClearList, nullptr, false); + clearList->workList = &intermediateList; + instructionList.addInstruction(clearList); + + // Initialize source variable + auto writeSourceVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister sourceValue(Compiler::StaticType::Number, 3.14159); + writeSourceVar->workVariable = &sourceVar; + writeSourceVar->args.push_back({ Compiler::StaticType::Unknown, &sourceValue }); + instructionList.addInstruction(writeSourceVar); + + // Read from source variable and write to intermediate list + auto readSourceVar = std::make_shared(LLVMInstruction::Type::ReadVariable, nullptr, false); + auto readSourceVarReg = std::make_shared(Compiler::StaticType::Unknown); + readSourceVar->functionReturnReg = readSourceVarReg.get(); + readSourceVarReg->instruction = readSourceVar; + readSourceVar->workVariable = &sourceVar; + instructionList.addInstruction(readSourceVar); + + auto appendList = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + appendList->workList = &intermediateList; + appendList->args.push_back({ Compiler::StaticType::Unknown, readSourceVarReg.get() }); + instructionList.addInstruction(appendList); + + // Read from intermediate list and write to target variable + auto readList = std::make_shared(LLVMInstruction::Type::GetListItem, nullptr, false); + auto readListReg = std::make_shared(Compiler::StaticType::Unknown); + readList->functionReturnReg = readListReg.get(); + readListReg->instruction = readList; + LLVMConstantRegister index(Compiler::StaticType::Number, 0); + readList->workList = &intermediateList; + readList->args.push_back({ Compiler::StaticType::Number, &index }); + instructionList.addInstruction(readList); + + auto writeTargetVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + writeTargetVar->workVariable = &targetVar; + writeTargetVar->args.push_back({ Compiler::StaticType::Unknown, readListReg.get() }); + instructionList.addInstruction(writeTargetVar); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + // Type should propagate through the chain: sourceVar -> intermediateList -> targetVar + ASSERT_EQ(analyzer.variableType(&targetVar, funcCall.get(), Compiler::StaticType::String), Compiler::StaticType::Number); + ASSERT_EQ(analyzer.listType(&intermediateList, funcCall.get(), Compiler::StaticType::String, false), Compiler::StaticType::Number); +} + +TEST(LLVMTypeAnalyzer_MixedTest, NestedLoopWithMixedDependencies_TypeConflict) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + Variable var("var", ""); + List list("list", ""); + + auto outerLoopStart = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(outerLoopStart); + + // Write to variable in outer loop + auto writeVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value1(Compiler::StaticType::Bool, true); + writeVar1->workVariable = &var; + writeVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + instructionList.addInstruction(writeVar1); + + auto clearList = std::make_shared(LLVMInstruction::Type::ClearList, nullptr, false); + clearList->workList = &list; + instructionList.addInstruction(clearList); + + auto innerLoopStart = std::make_shared(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false); + instructionList.addInstruction(innerLoopStart); + + // Read from variable and write to list in inner loop + auto readVar = std::make_shared(LLVMInstruction::Type::ReadVariable, nullptr, false); + auto readVarReg = std::make_shared(Compiler::StaticType::Unknown); + readVar->functionReturnReg = readVarReg.get(); + readVarReg->instruction = readVar; + readVar->workVariable = &var; + instructionList.addInstruction(readVar); + + auto appendList = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Unknown, readVarReg.get() }); + instructionList.addInstruction(appendList); + + // Write different type to variable in inner loop (creates conflict) + auto writeVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value2(Compiler::StaticType::String, "conflict"); + writeVar2->workVariable = &var; + writeVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + instructionList.addInstruction(writeVar2); + + auto innerLoopEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(innerLoopEnd); + + auto outerLoopEnd = std::make_shared(LLVMInstruction::Type::EndLoop, nullptr, false); + instructionList.addInstruction(outerLoopEnd); + + auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, nullptr, false); + instructionList.addInstruction(funcCall); + + // Should return Unknown due to type conflicts in nested loops + ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Bool), Compiler::StaticType::Unknown); + ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Bool, false), Compiler::StaticType::Unknown); +} From bd0d45ea8ad21509d3fa887ba975f9da33c6d954 Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Fri, 1 Aug 2025 15:57:43 +0200 Subject: [PATCH 46/79] LLVMTypeAnalyzer: Add pointer const qualifiers --- src/engine/internal/llvm/llvmtypeanalyzer.cpp | 105 ++++++++++-------- src/engine/internal/llvm/llvmtypeanalyzer.h | 75 +++++++------ 2 files changed, 99 insertions(+), 81 deletions(-) diff --git a/src/engine/internal/llvm/llvmtypeanalyzer.cpp b/src/engine/internal/llvm/llvmtypeanalyzer.cpp index b0d4a6c99..bdbe20981 100644 --- a/src/engine/internal/llvm/llvmtypeanalyzer.cpp +++ b/src/engine/internal/llvm/llvmtypeanalyzer.cpp @@ -10,37 +10,40 @@ static const std::unordered_set static const std::unordered_set LIST_WRITE_INSTRUCTIONS = { LLVMInstruction::Type::AppendToList, LLVMInstruction::Type::InsertToList, LLVMInstruction::Type::ListReplace }; -Compiler::StaticType LLVMTypeAnalyzer::variableType(Variable *var, LLVMInstruction *pos, Compiler::StaticType previousType) const +Compiler::StaticType LLVMTypeAnalyzer::variableType(const Variable *var, const LLVMInstruction *pos, Compiler::StaticType previousType) const { InstructionSet visitedInstructions; - std::unordered_map listTypes; + std::unordered_map listTypes; return variableType(var, pos, previousType, listTypes, visitedInstructions); } -Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranch(Variable *var, LLVMInstruction *start, Compiler::StaticType previousType) const +Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranch(const Variable *var, const LLVMInstruction *start, Compiler::StaticType previousType) const { InstructionSet visitedInstructions; return variableTypeAfterBranch(var, start, previousType, visitedInstructions); } -Compiler::StaticType LLVMTypeAnalyzer::listType(List *list, LLVMInstruction *pos, Compiler::StaticType previousType, bool isEmpty) const +Compiler::StaticType LLVMTypeAnalyzer::listType(const List *list, const LLVMInstruction *pos, Compiler::StaticType previousType, bool isEmpty) const { InstructionSet visitedInstructions; - std::unordered_map listTypes; + std::unordered_map listTypes; return listType(list, pos, previousType, isEmpty, listTypes, visitedInstructions); } -Compiler::StaticType LLVMTypeAnalyzer::listTypeAfterBranch(List *list, LLVMInstruction *start, Compiler::StaticType previousType, bool isEmpty) const +Compiler::StaticType LLVMTypeAnalyzer::listTypeAfterBranch(const List *list, const LLVMInstruction *start, Compiler::StaticType previousType, bool isEmpty) const { bool write = false; // only used internally (the compiler doesn't need this) InstructionSet visitedInstructions; - std::unordered_map listTypes; + std::unordered_map listTypes; return listTypeAfterBranch(list, start, previousType, isEmpty, nullptr, write, listTypes, visitedInstructions); } -Compiler::StaticType -LLVMTypeAnalyzer::variableType(Variable *var, LLVMInstruction *pos, Compiler::StaticType previousType, std::unordered_map listTypes, InstructionSet &visitedInstructions) - const +Compiler::StaticType LLVMTypeAnalyzer::variableType( + const Variable *var, + const LLVMInstruction *pos, + Compiler::StaticType previousType, + std::unordered_map listTypes, + InstructionSet &visitedInstructions) const { if (!var || !pos) return Compiler::StaticType::Unknown; @@ -63,11 +66,11 @@ LLVMTypeAnalyzer::variableType(Variable *var, LLVMInstruction *pos, Compiler::St visitedInstructions.insert(pos); // Check the last write operation before the instruction - LLVMInstruction *ins = pos; - LLVMInstruction *write = nullptr; - std::pair firstBranch = { nullptr, 0 }; - std::pair firstElseBranch = { nullptr, 0 }; - LLVMInstruction *ourBranch = nullptr; + const LLVMInstruction *ins = pos; + const LLVMInstruction *write = nullptr; + std::pair firstBranch = { nullptr, 0 }; + std::pair firstElseBranch = { nullptr, 0 }; + const LLVMInstruction *ourBranch = nullptr; int level = 0; while (ins) { @@ -126,32 +129,32 @@ LLVMTypeAnalyzer::variableType(Variable *var, LLVMInstruction *pos, Compiler::St return previousType; } -Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranch(Variable *var, LLVMInstruction *start, Compiler::StaticType previousType, InstructionSet &visitedInstructions) const +Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranch(const Variable *var, const LLVMInstruction *start, Compiler::StaticType previousType, InstructionSet &visitedInstructions) const { if (!var || !start) return previousType; - LLVMInstruction *end = branchEnd(start); + const LLVMInstruction *end = branchEnd(start); if (!end) return Compiler::StaticType::Unknown; // Process the branch from end bool write = false; // only used internally (the compiler doesn't need this) - std::unordered_map listTypes; + std::unordered_map listTypes; return variableTypeAfterBranchFromEnd(var, end, previousType, write, listTypes, visitedInstructions); } Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranchFromEnd( - Variable *var, - LLVMInstruction *end, + const Variable *var, + const LLVMInstruction *end, Compiler::StaticType previousType, bool &write, - std::unordered_map listTypes, + std::unordered_map listTypes, InstructionSet &visitedInstructions) const { // Find the last write instruction - LLVMInstruction *ins = end->previous; + const LLVMInstruction *ins = end->previous; bool typeMightReset = false; while (ins && !isLoopStart(ins) && !isIfStart(ins)) { @@ -201,8 +204,13 @@ Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranchFromEnd( return previousType; } -Compiler::StaticType LLVMTypeAnalyzer:: - listType(List *list, LLVMInstruction *pos, Compiler::StaticType previousType, bool isEmpty, std::unordered_map listTypes, InstructionSet &visitedInstructions) const +Compiler::StaticType LLVMTypeAnalyzer::listType( + const List *list, + const LLVMInstruction *pos, + Compiler::StaticType previousType, + bool isEmpty, + std::unordered_map listTypes, + InstructionSet &visitedInstructions) const { if (!list || !pos) return Compiler::StaticType::Unknown; @@ -223,10 +231,10 @@ Compiler::StaticType LLVMTypeAnalyzer:: visitedInstructions.insert(pos); listTypes[list] = previousType; - LLVMInstruction *ins = pos; - LLVMInstruction *previous = nullptr; - std::pair firstBranch = { nullptr, 0 }; - std::pair lastClear = { nullptr, 0 }; + const LLVMInstruction *ins = pos; + const LLVMInstruction *previous = nullptr; + std::pair firstBranch = { nullptr, 0 }; + std::pair lastClear = { nullptr, 0 }; int level = 0; // Find a start instruction (list clear in the top level or the first instruction) @@ -305,13 +313,13 @@ Compiler::StaticType LLVMTypeAnalyzer:: } Compiler::StaticType LLVMTypeAnalyzer::listTypeAfterBranch( - List *list, - LLVMInstruction *start, + const List *list, + const LLVMInstruction *start, Compiler::StaticType previousType, bool isEmpty, - LLVMInstruction *query, + const LLVMInstruction *query, bool &write, - std::unordered_map listTypes, + std::unordered_map listTypes, InstructionSet &visitedInstructions) const { write = false; @@ -323,7 +331,7 @@ Compiler::StaticType LLVMTypeAnalyzer::listTypeAfterBranch( bool isLoop = isLoopStart(start); bool clearBeforeQueryPoint = false; - LLVMInstruction *ins = start->next; + const LLVMInstruction *ins = start->next; while (ins && !(isLoopEnd(ins) || isIfEnd(ins) || isElse(ins))) { if (isLoopStart(ins) || isIfStart(ins)) { @@ -385,7 +393,7 @@ bool LLVMTypeAnalyzer::handleListWrite(Compiler::StaticType writeType, Compiler: return true; } -LLVMInstruction *LLVMTypeAnalyzer::branchEnd(LLVMInstruction *start) const +const LLVMInstruction *LLVMTypeAnalyzer::branchEnd(const LLVMInstruction *start) const { assert(start); assert(isLoopStart(start) || isIfStart(start) || isElse(start)); @@ -409,7 +417,7 @@ LLVMInstruction *LLVMTypeAnalyzer::branchEnd(LLVMInstruction *start) const return ins; } -LLVMInstruction *LLVMTypeAnalyzer::branchStart(LLVMInstruction *end) const +const LLVMInstruction *LLVMTypeAnalyzer::branchStart(const LLVMInstruction *end) const { assert(end); assert(isLoopEnd(end) || isIfEnd(end) || isElse(end)); @@ -434,52 +442,52 @@ LLVMInstruction *LLVMTypeAnalyzer::branchStart(LLVMInstruction *end) const return ins; } -bool LLVMTypeAnalyzer::isLoopStart(LLVMInstruction *ins) const +bool LLVMTypeAnalyzer::isLoopStart(const LLVMInstruction *ins) const { return (BEGIN_LOOP_INSTRUCTIONS.find(ins->type) != BEGIN_LOOP_INSTRUCTIONS.cend()); } -bool LLVMTypeAnalyzer::isLoopEnd(LLVMInstruction *ins) const +bool LLVMTypeAnalyzer::isLoopEnd(const LLVMInstruction *ins) const { return (ins->type == LLVMInstruction::Type::EndLoop); } -bool LLVMTypeAnalyzer::isIfStart(LLVMInstruction *ins) const +bool LLVMTypeAnalyzer::isIfStart(const LLVMInstruction *ins) const { return (ins->type == LLVMInstruction::Type::BeginIf); } -bool LLVMTypeAnalyzer::isElse(LLVMInstruction *ins) const +bool LLVMTypeAnalyzer::isElse(const LLVMInstruction *ins) const { return (ins->type == LLVMInstruction::Type::BeginElse); } -bool LLVMTypeAnalyzer::isIfEnd(LLVMInstruction *ins) const +bool LLVMTypeAnalyzer::isIfEnd(const LLVMInstruction *ins) const { return (ins->type == LLVMInstruction::Type::EndIf); } -bool LLVMTypeAnalyzer::isVariableRead(LLVMInstruction *ins) const +bool LLVMTypeAnalyzer::isVariableRead(const LLVMInstruction *ins) const { return (ins->type == LLVMInstruction::Type::ReadVariable); } -bool LLVMTypeAnalyzer::isVariableWrite(LLVMInstruction *ins, Variable *var) const +bool LLVMTypeAnalyzer::isVariableWrite(const LLVMInstruction *ins, const Variable *var) const { return (ins->type == LLVMInstruction::Type::WriteVariable && ins->workVariable == var); } -bool LLVMTypeAnalyzer::isListRead(LLVMInstruction *ins) const +bool LLVMTypeAnalyzer::isListRead(const LLVMInstruction *ins) const { return (ins->type == LLVMInstruction::Type::GetListItem); } -bool LLVMTypeAnalyzer::isListWrite(LLVMInstruction *ins, List *list) const +bool LLVMTypeAnalyzer::isListWrite(const LLVMInstruction *ins, const List *list) const { return (LIST_WRITE_INSTRUCTIONS.find(ins->type) != LIST_WRITE_INSTRUCTIONS.cend() && ins->workList == list); } -bool LLVMTypeAnalyzer::isListClear(LLVMInstruction *ins, List *list) const +bool LLVMTypeAnalyzer::isListClear(const LLVMInstruction *ins, const List *list) const { return (ins->type == LLVMInstruction::Type::ClearList && ins->workList == list); } @@ -498,7 +506,7 @@ Compiler::StaticType LLVMTypeAnalyzer::optimizeRegisterType(LLVMRegister *reg) c return ret; } -bool LLVMTypeAnalyzer::isWriteNoOp(LLVMInstruction *ins) const +bool LLVMTypeAnalyzer::isWriteNoOp(const LLVMInstruction *ins) const { assert(ins); assert(!ins->args.empty()); @@ -515,7 +523,7 @@ bool LLVMTypeAnalyzer::isWriteNoOp(LLVMInstruction *ins) const return false; } -Compiler::StaticType LLVMTypeAnalyzer::writeValueType(LLVMInstruction *ins, std::unordered_map listTypes, InstructionSet &visitedInstructions) const +Compiler::StaticType LLVMTypeAnalyzer::writeValueType(const LLVMInstruction *ins, std::unordered_map listTypes, InstructionSet &visitedInstructions) const { assert(ins); assert(!ins->args.empty()); @@ -550,7 +558,8 @@ bool LLVMTypeAnalyzer::typesMatch(Compiler::StaticType a, Compiler::StaticType b return (a == b) && (a != Compiler::StaticType::Unknown); } -bool LLVMTypeAnalyzer::writeTypesMatch(LLVMInstruction *ins, Compiler::StaticType expectedType, std::unordered_map listTypes, InstructionSet &visitedInstructions) const +bool LLVMTypeAnalyzer:: + writeTypesMatch(const LLVMInstruction *ins, Compiler::StaticType expectedType, std::unordered_map listTypes, InstructionSet &visitedInstructions) const { return typesMatch(writeValueType(ins, listTypes, visitedInstructions), expectedType); } diff --git a/src/engine/internal/llvm/llvmtypeanalyzer.h b/src/engine/internal/llvm/llvmtypeanalyzer.h index d5f965df7..4244d2b8b 100644 --- a/src/engine/internal/llvm/llvmtypeanalyzer.h +++ b/src/engine/internal/llvm/llvmtypeanalyzer.h @@ -12,65 +12,74 @@ struct LLVMRegister; class LLVMTypeAnalyzer { public: - Compiler::StaticType variableType(Variable *var, LLVMInstruction *pos, Compiler::StaticType previousType) const; - Compiler::StaticType variableTypeAfterBranch(Variable *var, LLVMInstruction *start, Compiler::StaticType previousType) const; + Compiler::StaticType variableType(const Variable *var, const LLVMInstruction *pos, Compiler::StaticType previousType) const; + Compiler::StaticType variableTypeAfterBranch(const Variable *var, const LLVMInstruction *start, Compiler::StaticType previousType) const; - Compiler::StaticType listType(List *list, LLVMInstruction *pos, Compiler::StaticType previousType, bool isEmpty) const; - Compiler::StaticType listTypeAfterBranch(List *list, LLVMInstruction *start, Compiler::StaticType previousType, bool isEmpty) const; + Compiler::StaticType listType(const List *list, const LLVMInstruction *pos, Compiler::StaticType previousType, bool isEmpty) const; + Compiler::StaticType listTypeAfterBranch(const List *list, const LLVMInstruction *start, Compiler::StaticType previousType, bool isEmpty) const; private: - using InstructionSet = std::unordered_set; + using InstructionSet = std::unordered_set; - Compiler::StaticType - variableType(Variable *var, LLVMInstruction *pos, Compiler::StaticType previousType, std::unordered_map listTypes, InstructionSet &visitedInstructions) const; + Compiler::StaticType variableType( + const Variable *var, + const LLVMInstruction *pos, + Compiler::StaticType previousType, + std::unordered_map listTypes, + InstructionSet &visitedInstructions) const; - Compiler::StaticType variableTypeAfterBranch(Variable *var, LLVMInstruction *start, Compiler::StaticType previousType, InstructionSet &visitedInstructions) const; + Compiler::StaticType variableTypeAfterBranch(const Variable *var, const LLVMInstruction *start, Compiler::StaticType previousType, InstructionSet &visitedInstructions) const; Compiler::StaticType variableTypeAfterBranchFromEnd( - Variable *var, - LLVMInstruction *end, + const Variable *var, + const LLVMInstruction *end, Compiler::StaticType previousType, bool &write, - std::unordered_map listTypes, + std::unordered_map listTypes, InstructionSet &visitedInstructions) const; - Compiler::StaticType - listType(List *list, LLVMInstruction *pos, Compiler::StaticType previousType, bool isEmpty, std::unordered_map listTypes, InstructionSet &visitedInstructions) - const; + Compiler::StaticType listType( + const List *list, + const LLVMInstruction *pos, + Compiler::StaticType previousType, + bool isEmpty, + std::unordered_map listTypes, + InstructionSet &visitedInstructions) const; Compiler::StaticType listTypeAfterBranch( - List *list, - LLVMInstruction *start, + const List *list, + const LLVMInstruction *start, Compiler::StaticType previousType, bool isEmpty, - LLVMInstruction *query, + const LLVMInstruction *query, bool &write, - std::unordered_map listTypes, + std::unordered_map listTypes, InstructionSet &visitedInstructions) const; bool handleListWrite(Compiler::StaticType writeType, Compiler::StaticType &previousType, bool &isEmpty) const; - LLVMInstruction *branchEnd(LLVMInstruction *start) const; - LLVMInstruction *branchStart(LLVMInstruction *end) const; + const LLVMInstruction *branchEnd(const LLVMInstruction *start) const; + const LLVMInstruction *branchStart(const LLVMInstruction *end) const; - bool isLoopStart(LLVMInstruction *ins) const; - bool isLoopEnd(LLVMInstruction *ins) const; - bool isIfStart(LLVMInstruction *ins) const; - bool isElse(LLVMInstruction *ins) const; - bool isIfEnd(LLVMInstruction *ins) const; + bool isLoopStart(const LLVMInstruction *ins) const; + bool isLoopEnd(const LLVMInstruction *ins) const; + bool isIfStart(const LLVMInstruction *ins) const; + bool isElse(const LLVMInstruction *ins) const; + bool isIfEnd(const LLVMInstruction *ins) const; - bool isVariableRead(LLVMInstruction *ins) const; - bool isVariableWrite(LLVMInstruction *ins, Variable *var) const; + bool isVariableRead(const LLVMInstruction *ins) const; + bool isVariableWrite(const LLVMInstruction *ins, const Variable *var) const; - bool isListRead(LLVMInstruction *ins) const; - bool isListWrite(LLVMInstruction *ins, List *list) const; - bool isListClear(LLVMInstruction *ins, List *list) const; + bool isListRead(const LLVMInstruction *ins) const; + bool isListWrite(const LLVMInstruction *ins, const List *list) const; + bool isListClear(const LLVMInstruction *ins, const List *list) const; Compiler::StaticType optimizeRegisterType(LLVMRegister *reg) const; - bool isWriteNoOp(LLVMInstruction *ins) const; - Compiler::StaticType writeValueType(LLVMInstruction *ins, std::unordered_map listTypes, InstructionSet &visitedInstructions) const; + bool isWriteNoOp(const LLVMInstruction *ins) const; + Compiler::StaticType writeValueType(const LLVMInstruction *ins, std::unordered_map listTypes, InstructionSet &visitedInstructions) const; bool typesMatch(Compiler::StaticType a, Compiler::StaticType b) const; - bool writeTypesMatch(LLVMInstruction *ins, Compiler::StaticType expectedType, std::unordered_map listTypes, InstructionSet &visitedInstructions) const; + bool + writeTypesMatch(const LLVMInstruction *ins, Compiler::StaticType expectedType, std::unordered_map listTypes, InstructionSet &visitedInstructions) const; }; } // namespace libscratchcpp From 133814e2a5063ebb73eb0808b7c1c98eb04782fd Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Fri, 1 Aug 2025 16:14:30 +0200 Subject: [PATCH 47/79] LLVMTypeAnalyzer: Do not process query point in variableType() --- src/engine/internal/llvm/llvmtypeanalyzer.cpp | 2 +- test/llvm/type_analyzer/listtype_test.cpp | 15 +++++++++++++++ test/llvm/type_analyzer/variabletype_test.cpp | 15 +++++++++++++++ 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/engine/internal/llvm/llvmtypeanalyzer.cpp b/src/engine/internal/llvm/llvmtypeanalyzer.cpp index bdbe20981..3445c7834 100644 --- a/src/engine/internal/llvm/llvmtypeanalyzer.cpp +++ b/src/engine/internal/llvm/llvmtypeanalyzer.cpp @@ -66,7 +66,7 @@ Compiler::StaticType LLVMTypeAnalyzer::variableType( visitedInstructions.insert(pos); // Check the last write operation before the instruction - const LLVMInstruction *ins = pos; + const LLVMInstruction *ins = pos->previous; const LLVMInstruction *write = nullptr; std::pair firstBranch = { nullptr, 0 }; std::pair firstElseBranch = { nullptr, 0 }; diff --git a/test/llvm/type_analyzer/listtype_test.cpp b/test/llvm/type_analyzer/listtype_test.cpp index e44cf8255..54e6bc986 100644 --- a/test/llvm/type_analyzer/listtype_test.cpp +++ b/test/llvm/type_analyzer/listtype_test.cpp @@ -79,6 +79,21 @@ TEST(LLVMTypeAnalyzer_ListType, NoWriteOperationsUnknownType_Empty) ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Unknown, true), Compiler::StaticType::Unknown); } +TEST(LLVMTypeAnalyzer_ListType, QueryPointIsWrite) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList instructionList; + List list("", ""); + + auto appendList = std::make_shared(LLVMInstruction::Type::AppendToList, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::Number, 1.25); + appendList->workList = &list; + appendList->args.push_back({ Compiler::StaticType::Unknown, &value }); + instructionList.addInstruction(appendList); + + ASSERT_EQ(analyzer.listType(&list, appendList.get(), Compiler::StaticType::String, false), Compiler::StaticType::String); +} + TEST(LLVMTypeAnalyzer_ListType, Loop_SingleWriteSameTypeNumber_Before_NonEmpty) { LLVMTypeAnalyzer analyzer; diff --git a/test/llvm/type_analyzer/variabletype_test.cpp b/test/llvm/type_analyzer/variabletype_test.cpp index 1d1675883..ea7090e8a 100644 --- a/test/llvm/type_analyzer/variabletype_test.cpp +++ b/test/llvm/type_analyzer/variabletype_test.cpp @@ -55,6 +55,21 @@ TEST(LLVMTypeAnalyzer_VariableType, NoWriteOperationsUnknownType) ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Unknown), Compiler::StaticType::Unknown); } +TEST(LLVMTypeAnalyzer_VariableType, QueryPointIsWrite) +{ + LLVMTypeAnalyzer analyzer; + LLVMInstructionList list; + Variable var("", ""); + + auto setVar = std::make_shared(LLVMInstruction::Type::WriteVariable, nullptr, false); + LLVMConstantRegister value(Compiler::StaticType::Number, 1.25); + setVar->workVariable = &var; + setVar->args.push_back({ Compiler::StaticType::Unknown, &value }); + list.addInstruction(setVar); + + ASSERT_EQ(analyzer.variableType(&var, setVar.get(), Compiler::StaticType::Unknown), Compiler::StaticType::Unknown); +} + TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteSameTypeNumber_Before) { LLVMTypeAnalyzer analyzer; From 0521d0452b006d861faa2b92dc14ba3f15870dc3 Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Fri, 1 Aug 2025 16:54:43 +0200 Subject: [PATCH 48/79] Use LLVMTypeAnalyzer for static type analysis --- src/engine/internal/llvm/llvmcodebuilder.cpp | 359 +--- src/engine/internal/llvm/llvmcodebuilder.h | 9 +- src/engine/internal/llvm/llvmlistptr.h | 1 - src/engine/internal/llvm/llvmvariableptr.h | 1 - test/llvm/llvmcodebuilder_test.cpp | 1758 ++---------------- 5 files changed, 215 insertions(+), 1913 deletions(-) diff --git a/src/engine/internal/llvm/llvmcodebuilder.cpp b/src/engine/internal/llvm/llvmcodebuilder.cpp index b61a477b3..12043512d 100644 --- a/src/engine/internal/llvm/llvmcodebuilder.cpp +++ b/src/engine/internal/llvm/llvmcodebuilder.cpp @@ -116,7 +116,11 @@ std::shared_ptr LLVMCodeBuilder::finalize() // All variables are currently created on the stack and synced later (seems to be faster) // NOTE: Strings are NOT copied, only the pointer is copied - varPtr.stackPtr = m_builder.CreateAlloca(m_valueDataType); + // TODO: Restore this feature + // varPtr.stackPtr = m_builder.CreateAlloca(m_valueDataType); + varPtr.stackPtr = varPtr.heapPtr; + varPtr.onStack = false; + continue; // If there are no write operations outside loops, initialize the stack variable now Variable *variable = var; @@ -147,8 +151,6 @@ std::shared_ptr LLVMCodeBuilder::finalize() assert(m_loopScope == -1); m_loopScope = -1; - m_scopeVariables.clear(); - m_scopeLists.clear(); pushScopeLevel(); // Execute recorded steps @@ -738,14 +740,18 @@ std::shared_ptr LLVMCodeBuilder::finalize() assert(step.args.size() == 1); assert(m_variablePtrs.find(step.workVariable) != m_variablePtrs.cend()); const auto &arg = step.args[0]; - Compiler::StaticType type = optimizeRegisterType(arg.second); + Compiler::StaticType argType = optimizeRegisterType(arg.second); LLVMVariablePtr &varPtr = m_variablePtrs[step.workVariable]; - varPtr.changed = true; + varPtr.changed = true; // TODO: Handle loops and if statements - const bool safe = isVarOrListTypeSafe(insPtr, varPtr.type); + Compiler::StaticType varType = Compiler::StaticType::Unknown; + + if (m_warp) + varType = m_typeAnalyzer.variableType(step.workVariable, &step, Compiler::StaticType::Unknown); // Initialize stack variable on first assignment - if (!varPtr.onStack) { + // TODO: Use stack in the top level (outside loops and if statements) + /*if (!varPtr.onStack) { varPtr.onStack = true; varPtr.type = type; // don't care about unknown type on first assignment @@ -762,26 +768,22 @@ std::shared_ptr LLVMCodeBuilder::finalize() llvm::Value *typeField = m_builder.CreateStructGEP(m_valueDataType, varPtr.stackPtr, 1); m_builder.CreateStore(m_builder.getInt32(static_cast(mappedType)), typeField); - } - - if (!safe) - varPtr.type = Compiler::StaticType::Unknown; + }*/ - createValueStore(arg.second, varPtr.stackPtr, type, varPtr.type); - varPtr.type = type; - m_scopeVariables.back()[&varPtr] = varPtr.type; + createValueStore(arg.second, varPtr.stackPtr, argType, varType); break; } case LLVMInstruction::Type::ReadVariable: { assert(step.args.size() == 0); LLVMVariablePtr &varPtr = m_variablePtrs[step.workVariable]; + Compiler::StaticType type = Compiler::StaticType::Unknown; - if (!isVarOrListTypeSafe(insPtr, varPtr.type)) - varPtr.type = Compiler::StaticType::Unknown; + if (m_warp) + type = m_typeAnalyzer.variableType(step.workVariable, &step, Compiler::StaticType::Unknown); step.functionReturnReg->value = varPtr.onStack && !(step.loopCondition && !m_warp) ? varPtr.stackPtr : varPtr.heapPtr; - step.functionReturnReg->setType(varPtr.type); + step.functionReturnReg->setType(type); break; } @@ -795,8 +797,6 @@ std::shared_ptr LLVMCodeBuilder::finalize() llvm::Value *dataPtrDirty = m_builder.CreateLoad(m_builder.getInt1Ty(), listPtr.dataPtrDirty); llvm::Value *allocatedSize = m_builder.CreateLoad(m_builder.getInt64Ty(), listPtr.allocatedSizePtr); m_builder.CreateStore(m_builder.CreateOr(dataPtrDirty, m_builder.CreateICmpNE(allocatedSize, oldAllocatedSize)), listPtr.dataPtrDirty); - - m_scopeLists.back().erase(&listPtr); break; } @@ -805,9 +805,6 @@ std::shared_ptr LLVMCodeBuilder::finalize() const auto &arg = step.args[0]; LLVMListPtr &listPtr = m_listPtrs[step.workList]; - if (!isVarOrListTypeSafe(insPtr, listPtr.type)) - listPtr.type = Compiler::StaticType::Unknown; - // Range check llvm::Value *min = llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(0.0)); llvm::Value *size = m_builder.CreateLoad(m_builder.getInt64Ty(), listPtr.sizePtr); @@ -835,18 +832,10 @@ std::shared_ptr LLVMCodeBuilder::finalize() Compiler::StaticType type = optimizeRegisterType(arg.second); LLVMListPtr &listPtr = m_listPtrs[step.workList]; - auto &typeMap = m_scopeLists.back(); - - if (typeMap.find(&listPtr) == typeMap.cend()) { - listPtr.type = type; - typeMap[&listPtr] = listPtr.type; - } else if (listPtr.type != type) { - listPtr.type = Compiler::StaticType::Unknown; - typeMap[&listPtr] = listPtr.type; - } + Compiler::StaticType listType = Compiler::StaticType::Unknown; - if (!isVarOrListTypeSafe(insPtr, listPtr.type)) - listPtr.type = Compiler::StaticType::Unknown; + if (m_warp) + listType = m_typeAnalyzer.listType(step.workList, &step, Compiler::StaticType::Unknown, false); // Check if enough space is allocated llvm::Value *allocatedSize = m_builder.CreateLoad(m_builder.getInt64Ty(), listPtr.allocatedSizePtr); @@ -860,14 +849,14 @@ std::shared_ptr LLVMCodeBuilder::finalize() // If there's enough space, use the allocated memory m_builder.SetInsertPoint(ifBlock); llvm::Value *itemPtr = getListItem(listPtr, size); - createReusedValueStore(arg.second, itemPtr, type, listPtr.type); + createReusedValueStore(arg.second, itemPtr, type, listType); m_builder.CreateStore(m_builder.CreateAdd(size, m_builder.getInt64(1)), listPtr.sizePtr); m_builder.CreateBr(nextBlock); // Otherwise call appendEmpty() m_builder.SetInsertPoint(elseBlock); itemPtr = m_builder.CreateCall(resolve_list_append_empty(), listPtr.ptr); - createReusedValueStore(arg.second, itemPtr, type, listPtr.type); + createReusedValueStore(arg.second, itemPtr, type, listType); m_builder.CreateStore(m_builder.getInt1(true), listPtr.dataPtrDirty); m_builder.CreateBr(nextBlock); @@ -883,18 +872,10 @@ std::shared_ptr LLVMCodeBuilder::finalize() Compiler::StaticType type = optimizeRegisterType(valueArg.second); LLVMListPtr &listPtr = m_listPtrs[step.workList]; - auto &typeMap = m_scopeLists.back(); + Compiler::StaticType listType = Compiler::StaticType::Unknown; - if (typeMap.find(&listPtr) == typeMap.cend()) { - listPtr.type = type; - typeMap[&listPtr] = listPtr.type; - } else if (listPtr.type != type) { - listPtr.type = Compiler::StaticType::Unknown; - typeMap[&listPtr] = listPtr.type; - } - - if (!isVarOrListTypeSafe(insPtr, listPtr.type)) - listPtr.type = Compiler::StaticType::Unknown; + if (m_warp) + listType = m_typeAnalyzer.listType(step.workList, &step, Compiler::StaticType::Unknown, false); llvm::Value *oldAllocatedSize = m_builder.CreateLoad(m_builder.getInt64Ty(), listPtr.allocatedSizePtr); @@ -912,7 +893,7 @@ std::shared_ptr LLVMCodeBuilder::finalize() m_builder.SetInsertPoint(insertBlock); index = m_builder.CreateFPToUI(index, m_builder.getInt64Ty()); llvm::Value *itemPtr = m_builder.CreateCall(resolve_list_insert_empty(), { listPtr.ptr, index }); - createReusedValueStore(valueArg.second, itemPtr, type, listPtr.type); + createReusedValueStore(valueArg.second, itemPtr, type, listType); // Check if the allocated size changed llvm::Value *dataPtrDirty = m_builder.CreateLoad(m_builder.getInt1Ty(), listPtr.dataPtrDirty); @@ -932,8 +913,10 @@ std::shared_ptr LLVMCodeBuilder::finalize() Compiler::StaticType type = optimizeRegisterType(valueArg.second); LLVMListPtr &listPtr = m_listPtrs[step.workList]; - if (!isVarOrListTypeSafe(insPtr, listPtr.type)) - listPtr.type = Compiler::StaticType::Unknown; + Compiler::StaticType listType = Compiler::StaticType::Unknown; + + if (m_warp) + listType = m_typeAnalyzer.listType(step.workList, &step, Compiler::StaticType::Unknown, false); // Range check llvm::Value *min = llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(0.0)); @@ -949,19 +932,9 @@ std::shared_ptr LLVMCodeBuilder::finalize() m_builder.SetInsertPoint(replaceBlock); index = m_builder.CreateFPToUI(index, m_builder.getInt64Ty()); llvm::Value *itemPtr = getListItem(listPtr, index); - createValueStore(valueArg.second, itemPtr, type, listPtr.type); + createValueStore(valueArg.second, itemPtr, type, listType); m_builder.CreateBr(nextBlock); - auto &typeMap = m_scopeLists.back(); - - if (typeMap.find(&listPtr) == typeMap.cend()) { - listPtr.type = type; - typeMap[&listPtr] = listPtr.type; - } else if (listPtr.type != type) { - listPtr.type = Compiler::StaticType::Unknown; - typeMap[&listPtr] = listPtr.type; - } - m_builder.SetInsertPoint(nextBlock); break; } @@ -980,8 +953,10 @@ std::shared_ptr LLVMCodeBuilder::finalize() const auto &arg = step.args[0]; LLVMListPtr &listPtr = m_listPtrs[step.workList]; - if (!isVarOrListTypeSafe(insPtr, listPtr.type)) - listPtr.type = Compiler::StaticType::Unknown; + Compiler::StaticType listType = Compiler::StaticType::Unknown; + + if (m_warp) + listType = m_typeAnalyzer.listType(step.workList, &step, Compiler::StaticType::Unknown, false); llvm::Value *min = llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(0.0)); llvm::Value *size = m_builder.CreateLoad(m_builder.getInt64Ty(), listPtr.sizePtr); @@ -989,12 +964,12 @@ std::shared_ptr LLVMCodeBuilder::finalize() llvm::Value *index = castValue(arg.second, arg.first); llvm::Value *inRange = m_builder.CreateAnd(m_builder.CreateFCmpOGE(index, min), m_builder.CreateFCmpOLT(index, size)); - LLVMConstantRegister nullReg(listPtr.type == Compiler::StaticType::Unknown ? Compiler::StaticType::Number : listPtr.type, Value()); + LLVMConstantRegister nullReg(listType == Compiler::StaticType::Unknown ? Compiler::StaticType::Number : listType, Value()); llvm::Value *null = createValue(static_cast(&nullReg)); index = m_builder.CreateFPToUI(index, m_builder.getInt64Ty()); step.functionReturnReg->value = m_builder.CreateSelect(inRange, getListItem(listPtr, index), null); - step.functionReturnReg->setType(listPtr.type); + step.functionReturnReg->setType(listType); break; } @@ -1011,10 +986,12 @@ std::shared_ptr LLVMCodeBuilder::finalize() const auto &arg = step.args[0]; LLVMListPtr &listPtr = m_listPtrs[step.workList]; - if (!isVarOrListTypeSafe(insPtr, listPtr.type)) - listPtr.type = Compiler::StaticType::Unknown; + Compiler::StaticType listType = Compiler::StaticType::Unknown; - step.functionReturnReg->value = m_builder.CreateSIToFP(getListItemIndex(listPtr, arg.second), m_builder.getDoubleTy()); + if (m_warp) + listType = m_typeAnalyzer.listType(step.workList, &step, Compiler::StaticType::Unknown, false); + + step.functionReturnReg->value = m_builder.CreateSIToFP(getListItemIndex(listPtr, listType, arg.second), m_builder.getDoubleTy()); break; } @@ -1023,10 +1000,12 @@ std::shared_ptr LLVMCodeBuilder::finalize() const auto &arg = step.args[0]; LLVMListPtr &listPtr = m_listPtrs[step.workList]; - if (!isVarOrListTypeSafe(insPtr, listPtr.type)) - listPtr.type = Compiler::StaticType::Unknown; + Compiler::StaticType listType = Compiler::StaticType::Unknown; - llvm::Value *index = getListItemIndex(listPtr, arg.second); + if (m_warp) + listType = m_typeAnalyzer.listType(step.workList, &step, Compiler::StaticType::Unknown, false); + + llvm::Value *index = getListItemIndex(listPtr, listType, arg.second); step.functionReturnReg->value = m_builder.CreateICmpSGT(index, llvm::ConstantInt::get(m_builder.getInt64Ty(), -1, true)); break; } @@ -1058,15 +1037,6 @@ std::shared_ptr LLVMCodeBuilder::finalize() assert(!ifStatements.empty()); LLVMIfStatement &statement = ifStatements.back(); - // Restore types from parent scope - std::unordered_map parentScopeVariables = m_scopeVariables[m_scopeVariables.size() - 2]; // no reference! - popScopeLevel(); - - for (auto &[ptr, type] : parentScopeVariables) - ptr->type = type; - - pushScopeLevel(); - // Jump to the branch after the if statement assert(!statement.afterIf); statement.afterIf = llvm::BasicBlock::Create(m_llvmCtx, "", m_function); @@ -1985,41 +1955,11 @@ void LLVMCodeBuilder::createListMap() void LLVMCodeBuilder::pushScopeLevel() { - m_scopeVariables.push_back({}); - - if (m_scopeLists.empty()) { - std::unordered_map listTypes; - - for (auto &[list, listPtr] : m_listPtrs) - listTypes[&listPtr] = Compiler::StaticType::Unknown; - - m_scopeLists.push_back(listTypes); - } else - m_scopeLists.push_back(m_scopeLists.back()); - m_stringHeap.push_back({}); } void LLVMCodeBuilder::popScopeLevel() { - for (size_t i = 0; i < m_scopeVariables.size() - 1; i++) { - for (auto &[ptr, type] : m_scopeVariables[i]) { - if (ptr->type != type) - ptr->type = Compiler::StaticType::Unknown; - } - } - - m_scopeVariables.pop_back(); - - for (size_t i = 0; i < m_scopeLists.size() - 1; i++) { - for (auto &[ptr, type] : m_scopeLists[i]) { - if (ptr->type != type) - ptr->type = Compiler::StaticType::Unknown; - } - } - - m_scopeLists.pop_back(); - freeScopeHeap(); m_stringHeap.pop_back(); } @@ -2485,20 +2425,14 @@ void LLVMCodeBuilder::reloadVariables(llvm::Value *targetVariables) for (auto &[var, varPtr] : m_variablePtrs) { varPtr.onStack = false; varPtr.changed = false; - varPtr.type = Compiler::StaticType::Unknown; } } void LLVMCodeBuilder::reloadLists() { - // Reset list data dirty and list types - auto &typeMap = m_scopeLists.back(); - - for (auto &[list, listPtr] : m_listPtrs) { + // Reset list data dirty + for (auto &[list, listPtr] : m_listPtrs) m_builder.CreateStore(m_builder.getInt1(true), listPtr.dataPtrDirty); - listPtr.type = Compiler::StaticType::Unknown; - typeMap[&listPtr] = listPtr.type; - } } void LLVMCodeBuilder::updateListDataPtr(const LLVMListPtr &listPtr) @@ -2511,193 +2445,6 @@ void LLVMCodeBuilder::updateListDataPtr(const LLVMListPtr &listPtr) m_builder.CreateStore(m_builder.getInt1(false), listPtr.dataPtrDirty); } -bool LLVMCodeBuilder::isVarOrListTypeSafe(LLVMInstruction *ins, Compiler::StaticType expectedType) const -{ - std::unordered_set processed; - int counter = 0; - return isVarOrListTypeSafe(ins, expectedType, processed, counter); -} - -bool LLVMCodeBuilder::isVarOrListTypeSafe(LLVMInstruction *ins, Compiler::StaticType expectedType, std::unordered_set &log, int &c) const -{ - /* - * The main part of the loop type analyzer. - * - * This is a recursive function which is called when variable - * or list instruction is created. It checks the last write to - * the variable or list in one of the loop scopes. - * - * If the last write operation writes a value with a different - * type, it will return false, otherwise true. - * - * If the last written value is from a variable or list, this - * function is called for it to check its type safety (that's - * why it is recursive). - * - * If the variable or list had a write operation before (in - * the same, parent or child loop scope), it is checked - * recursively. - */ - - if (!ins) - return false; - - /* - * If we are processing something that has been already - * processed, it means there's a case like this: - * x = x - * - * or this: - * x = y - * ... - * y = x - * - * Increment counter to ignore last n write operations. - */ - if (log.find(ins) != log.cend()) - c++; - else - log.insert(ins); - - assert(m_instructions.containsInstruction(ins)); - const LLVMVariablePtr *varPtr = ins->workVariable ? &m_variablePtrs.at(ins->workVariable) : nullptr; - const LLVMListPtr *listPtr = ins->workList ? &m_listPtrs.at(ins->workList) : nullptr; - assert((varPtr || listPtr) && !(varPtr && listPtr)); - auto scope = ins->loopScope; - - // If we aren't in a loop, we're safe - if (!scope) - return true; - - // If the loop scope contains a suspend and this is a non-warp script, the type may change between suspend and resume - if (scope->containsYield && !m_warp) - return false; - - LLVMInstruction *write = nullptr; - const auto &instructions = varPtr ? m_variableInstructions : m_listInstructions; - - // Find this instruction - auto it = std::find(instructions.begin(), instructions.end(), ins); - assert(it != instructions.end()); - - // Find previous write instruction in this, parent or child loop scope - size_t index = it - instructions.begin(); - - if (varPtr && index > 0) { // this is only needed for variables - bool found = false; - - do { - index--; - write = instructions[index]; - const bool isWrite = (VAR_LIST_READ_INSTRUCTIONS.find(write->type) == VAR_LIST_READ_INSTRUCTIONS.cend()); - found = (write->loopScope && isWrite && write->workVariable == ins->workVariable); - } while (index > 0 && !found); - - if (found) { - // Check if the write operation is in this or child scope - auto parentScope = write->loopScope; - - while (parentScope && parentScope != scope) - parentScope = parentScope->parentScope; - - if (!parentScope) { - // Check if the write operation is in any of the parent scopes - parentScope = scope; - - do { - parentScope = parentScope->parentScope; - } while (parentScope && parentScope != write->loopScope); - } - - // If there was a write operation before this instruction (in this, parent or child scope), check it - if (parentScope) { - if (parentScope == scope) - return isVarOrListWriteResultTypeSafe(write, expectedType, true, log, c); - else - return isVarOrListTypeSafe(write, expectedType, log, c); - } - } - } - - const auto &loopWrites = varPtr ? varPtr->loopVariableWrites : listPtr->loopListWrites; - - // Find root loop scope - auto checkScope = scope; - - while (checkScope->parentScope) { - checkScope = checkScope->parentScope; - } - - // Get all write operations in all loop scopes (from the root loop scope) - std::vector lastWrites; - - while (checkScope) { - auto it = loopWrites.find(checkScope); - - if (it != loopWrites.cend()) { - assert(!it->second.empty()); - const auto &writes = it->second; - - for (auto w : writes) - lastWrites.push_back(w); - } - - if (checkScope->childScopes.empty()) - checkScope = nullptr; - else - checkScope = checkScope->childScopes.back(); - } - - // If there aren't any write operations or all of them are ignored, we're safe - if (c >= lastWrites.size()) - return true; - - if (varPtr) - write = lastWrites[lastWrites.size() - c - 1]; // Ignore last c writes - else { - // If this is a list instruction, check last write operations except current - for (long i = lastWrites.size() - c - 1; i >= 0; i--) { // Ignore last c writes - if (lastWrites[i] == ins) - continue; - - if (!isVarOrListWriteResultTypeSafe(lastWrites[i], expectedType, false, log, c)) - return false; - } - } - - bool safe = true; - - if (VAR_LIST_READ_INSTRUCTIONS.find(ins->type) == VAR_LIST_READ_INSTRUCTIONS.cend()) // write - safe = isVarOrListWriteResultTypeSafe(ins, expectedType, false, log, c); - - if (safe) - return write ? isVarOrListWriteResultTypeSafe(write, expectedType, false, log, c) : true; - else - return false; -} - -bool LLVMCodeBuilder::isVarOrListWriteResultTypeSafe(LLVMInstruction *ins, Compiler::StaticType expectedType, bool ignoreSavedType, std::unordered_set &log, int &c) const -{ - const LLVMVariablePtr *varPtr = ins->workVariable ? &m_variablePtrs.at(ins->workVariable) : nullptr; - const LLVMListPtr *listPtr = ins->workList ? &m_listPtrs.at(ins->workList) : nullptr; - assert((varPtr || listPtr) && !(varPtr && listPtr)); - - // If the write operation writes the value of another variable, recursively check its type safety - const auto arg = ins->args.back().second; // value is always the last argument - auto argIns = arg->instruction; - - if (argIns && (argIns->type == LLVMInstruction::Type::ReadVariable || argIns->type == LLVMInstruction::Type::GetListItem)) - return isVarOrListTypeSafe(argIns.get(), expectedType, log, c); - - // Check written type - const bool typeMatches = (optimizeRegisterType(arg) == expectedType); - - if (varPtr) - return typeMatches && (varPtr->type == expectedType || ignoreSavedType); - else - return typeMatches && (listPtr->type == expectedType || ignoreSavedType); -} - LLVMRegister *LLVMCodeBuilder::createOp(LLVMInstruction::Type type, Compiler::StaticType retType, Compiler::StaticType argType, const Compiler::Args &args) { return createOp({ type, currentLoopScope(), m_loopCondition }, retType, argType, args); @@ -2854,7 +2601,7 @@ llvm::Value *LLVMCodeBuilder::getListItem(const LLVMListPtr &listPtr, llvm::Valu return m_builder.CreateGEP(m_valueDataType, m_builder.CreateLoad(m_valueDataType->getPointerTo(), listPtr.dataPtr), index); } -llvm::Value *LLVMCodeBuilder::getListItemIndex(const LLVMListPtr &listPtr, LLVMRegister *item) +llvm::Value *LLVMCodeBuilder::getListItemIndex(const LLVMListPtr &listPtr, Compiler::StaticType listType, LLVMRegister *item) { llvm::Value *size = m_builder.CreateLoad(m_builder.getInt64Ty(), listPtr.sizePtr); llvm::BasicBlock *condBlock = llvm::BasicBlock::Create(m_llvmCtx, "", m_function); @@ -2876,7 +2623,7 @@ llvm::Value *LLVMCodeBuilder::getListItemIndex(const LLVMListPtr &listPtr, LLVMR // if (list[index] == item) m_builder.SetInsertPoint(bodyBlock); - LLVMRegister currentItem(listPtr.type); + LLVMRegister currentItem(listType); currentItem.isRawValue = false; currentItem.value = getListItem(listPtr, m_builder.CreateLoad(m_builder.getInt64Ty(), index)); llvm::Value *cmp = createComparison(¤tItem, item, Comparison::EQ); diff --git a/src/engine/internal/llvm/llvmcodebuilder.h b/src/engine/internal/llvm/llvmcodebuilder.h index a3b71b2e6..2ddd8e98f 100644 --- a/src/engine/internal/llvm/llvmcodebuilder.h +++ b/src/engine/internal/llvm/llvmcodebuilder.h @@ -15,6 +15,7 @@ #include "llvmcoroutine.h" #include "llvmvariableptr.h" #include "llvmlistptr.h" +#include "llvmtypeanalyzer.h" namespace libscratchcpp { @@ -154,9 +155,6 @@ class LLVMCodeBuilder : public ICodeBuilder void reloadVariables(llvm::Value *targetVariables); void reloadLists(); void updateListDataPtr(const LLVMListPtr &listPtr); - bool isVarOrListTypeSafe(LLVMInstruction *ins, Compiler::StaticType expectedType) const; - bool isVarOrListTypeSafe(LLVMInstruction *ins, Compiler::StaticType expectedType, std::unordered_set &log, int &c) const; - bool isVarOrListWriteResultTypeSafe(LLVMInstruction *ins, Compiler::StaticType expectedType, bool ignoreSavedType, std::unordered_set &log, int &c) const; LLVMRegister *createOp(LLVMInstruction::Type type, Compiler::StaticType retType, Compiler::StaticType argType, const Compiler::Args &args); LLVMRegister *createOp(LLVMInstruction::Type type, Compiler::StaticType retType, const Compiler::ArgTypes &argTypes = {}, const Compiler::Args &args = {}); @@ -169,7 +167,7 @@ class LLVMCodeBuilder : public ICodeBuilder void createValueCopy(llvm::Value *source, llvm::Value *target); void copyStructField(llvm::Value *source, llvm::Value *target, int index, llvm::StructType *structType, llvm::Type *fieldType); llvm::Value *getListItem(const LLVMListPtr &listPtr, llvm::Value *index); - llvm::Value *getListItemIndex(const LLVMListPtr &listPtr, LLVMRegister *item); + llvm::Value *getListItemIndex(const LLVMListPtr &listPtr, Compiler::StaticType listType, LLVMRegister *item); llvm::Value *createValue(LLVMRegister *reg); llvm::Value *createNewValue(LLVMRegister *reg); llvm::Value *createComparison(LLVMRegister *arg1, LLVMRegister *arg2, Comparison type); @@ -219,17 +217,16 @@ class LLVMCodeBuilder : public ICodeBuilder std::unordered_map m_targetVariableMap; std::unordered_map m_variablePtrs; - std::vector> m_scopeVariables; std::unordered_map m_targetListMap; std::unordered_map m_listPtrs; - std::vector> m_scopeLists; LLVMCompilerContext *m_ctx; llvm::LLVMContext &m_llvmCtx; llvm::Module *m_module = nullptr; llvm::IRBuilder<> m_builder; llvm::Function *m_function = nullptr; + LLVMTypeAnalyzer m_typeAnalyzer; llvm::StructType *m_valueDataType = nullptr; llvm::StructType *m_stringPtrType = nullptr; diff --git a/src/engine/internal/llvm/llvmlistptr.h b/src/engine/internal/llvm/llvmlistptr.h index 2dd758696..52e4aff53 100644 --- a/src/engine/internal/llvm/llvmlistptr.h +++ b/src/engine/internal/llvm/llvmlistptr.h @@ -25,7 +25,6 @@ struct LLVMListPtr llvm::Value *sizePtr = nullptr; llvm::Value *allocatedSizePtr = nullptr; llvm::Value *dataPtrDirty = nullptr; - Compiler::StaticType type = Compiler::StaticType::Unknown; // Used in build phase to check the type safety of lists in loops std::unordered_map> loopListWrites; // loop scope, write instructions diff --git a/src/engine/internal/llvm/llvmvariableptr.h b/src/engine/internal/llvm/llvmvariableptr.h index 9907a5aa8..1627da6fb 100644 --- a/src/engine/internal/llvm/llvmvariableptr.h +++ b/src/engine/internal/llvm/llvmvariableptr.h @@ -22,7 +22,6 @@ struct LLVMVariablePtr { llvm::Value *stackPtr = nullptr; llvm::Value *heapPtr = nullptr; - Compiler::StaticType type = Compiler::StaticType::Unknown; bool onStack = false; bool changed = false; diff --git a/test/llvm/llvmcodebuilder_test.cpp b/test/llvm/llvmcodebuilder_test.cpp index f32ad8328..fcbed7b93 100644 --- a/test/llvm/llvmcodebuilder_test.cpp +++ b/test/llvm/llvmcodebuilder_test.cpp @@ -4222,8 +4222,9 @@ TEST_F(LLVMCodeBuilderTest, LoopVariables) ASSERT_EQ(testing::internal::GetCapturedStdout(), expected); } -TEST_F(LLVMCodeBuilderTest, VariableLoopTypeAnalysis1) +TEST_F(LLVMCodeBuilderTest, VariableLoopTypeAnalysis) { + // This just makes sure the type analyzer is used correctly Stage stage; Sprite sprite; sprite.setEngine(&m_engine); @@ -4266,153 +4267,192 @@ TEST_F(LLVMCodeBuilderTest, VariableLoopTypeAnalysis1) ASSERT_EQ(testing::internal::GetCapturedStdout(), expected); } -TEST_F(LLVMCodeBuilderTest, VariableLoopTypeAnalysis2) +TEST_F(LLVMCodeBuilderTest, LoopLists) { Stage stage; Sprite sprite; sprite.setEngine(&m_engine); EXPECT_CALL(m_engine, stage()).WillRepeatedly(Return(&stage)); - auto globalVar = std::make_shared("", ""); - stage.addVariable(globalVar); - - auto localVar = std::make_shared("", ""); - sprite.addVariable(localVar); + auto globalList1 = std::make_shared("", ""); + stage.addList(globalList1); - createBuilder(&sprite, true); + auto globalList2 = std::make_shared("", ""); + stage.addList(globalList2); - CompilerValue *v = m_builder->addConstValue(5.25); - m_builder->createVariableWrite(localVar.get(), v); + auto localList = std::make_shared("", ""); + sprite.addList(localList); - v = m_builder->addConstValue(2); - m_builder->beginRepeatLoop(v); - { - // Type is known here because a number is assigned later - v = m_builder->addVariableValue(localVar.get()); - m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v }); + auto counter1 = std::make_shared("", ""); + auto counter2 = std::make_shared("", ""); + sprite.addVariable(counter1); + sprite.addVariable(counter2); - v = m_builder->addConstValue(12.5); - m_builder->createVariableWrite(localVar.get(), v); - } - m_builder->endLoop(); + createBuilder(&sprite, true); - std::string expected = - "5.25\n" - "12.5\n"; + auto resetLists = [this, globalList1, globalList2, localList]() { + m_builder->createListClear(globalList1.get()); + m_builder->createListClear(globalList2.get()); + m_builder->createListClear(localList.get()); - auto code = m_builder->finalize(); - Script script(&sprite, nullptr, nullptr); - script.setCode(code); - Thread thread(&sprite, nullptr, &script); - auto ctx = code->createExecutionContext(&thread); - testing::internal::CaptureStdout(); - code->run(ctx.get()); - ASSERT_EQ(testing::internal::GetCapturedStdout(), expected); -} + m_builder->createListAppend(globalList1.get(), m_builder->addConstValue(1)); + m_builder->createListAppend(globalList1.get(), m_builder->addConstValue(2)); -TEST_F(LLVMCodeBuilderTest, VariableLoopTypeAnalysis3) -{ - Stage stage; - Sprite sprite; - sprite.setEngine(&m_engine); - EXPECT_CALL(m_engine, stage()).WillRepeatedly(Return(&stage)); + m_builder->createListAppend(globalList2.get(), m_builder->addConstValue("hello")); + m_builder->createListAppend(globalList2.get(), m_builder->addConstValue("world")); - auto globalVar = std::make_shared("", ""); - stage.addVariable(globalVar); + m_builder->createListAppend(localList.get(), m_builder->addConstValue(false)); + m_builder->createListAppend(localList.get(), m_builder->addConstValue(true)); + }; - auto localVar = std::make_shared("", ""); - sprite.addVariable(localVar); + auto checkLists = [this, globalList1, globalList2, localList]() { + CompilerValue *v = m_builder->addListItem(globalList1.get(), m_builder->addConstValue(0)); + m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); - createBuilder(&sprite, true); + v = m_builder->addListItem(globalList2.get(), m_builder->addConstValue(1)); + m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); - CompilerValue *v = m_builder->addConstValue(0); - m_builder->createVariableWrite(globalVar.get(), v); + v = m_builder->addListItem(localList.get(), m_builder->addConstValue(0)); + m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); + }; - v = m_builder->addConstValue(5.25); - m_builder->createVariableWrite(localVar.get(), v); + // repeat (2) + resetLists(); + CompilerValue *v, *v1, *v2; v = m_builder->addConstValue(2); m_builder->beginRepeatLoop(v); { - // Type is unknown here because a variable with unknown type is assigned (the variable has unknown type because a string is assigned later) - v = m_builder->addVariableValue(localVar.get()); - m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v }); + v = m_builder->addConstValue("hello world"); + m_builder->createListAppend(globalList1.get(), v); - v = m_builder->addConstValue(2); - m_builder->beginRepeatLoop(v); - { - v = m_builder->addVariableValue(globalVar.get()); - m_builder->createVariableWrite(localVar.get(), v); + v1 = m_builder->addConstValue(0); + v2 = m_builder->addConstValue(8.5); + m_builder->createListInsert(globalList2.get(), v1, v2); - v = m_builder->addConstValue("test"); - m_builder->createVariableWrite(globalVar.get(), v); - } - m_builder->endLoop(); + v1 = m_builder->addConstValue(1); + v2 = m_builder->addConstValue(-4.25); + m_builder->createListReplace(localList.get(), v1, v2); } m_builder->endLoop(); - std::string expected = - "5.25\n" - "0\n"; + checkLists(); - auto code = m_builder->finalize(); - Script script(&sprite, nullptr, nullptr); - script.setCode(code); - Thread thread(&sprite, nullptr, &script); - auto ctx = code->createExecutionContext(&thread); - testing::internal::CaptureStdout(); - code->run(ctx.get()); - ASSERT_EQ(testing::internal::GetCapturedStdout(), expected); -} + // repeat(0) + resetLists(); -TEST_F(LLVMCodeBuilderTest, VariableLoopTypeAnalysis4) -{ - Stage stage; - Sprite sprite; - sprite.setEngine(&m_engine); - EXPECT_CALL(m_engine, stage()).WillRepeatedly(Return(&stage)); + v = m_builder->addConstValue(0); + m_builder->beginRepeatLoop(v); + { + v = m_builder->addConstValue("hello world"); + m_builder->createListAppend(globalList1.get(), v); - auto globalVar = std::make_shared("", ""); - stage.addVariable(globalVar); + v1 = m_builder->addConstValue(0); + v2 = m_builder->addConstValue(8.5); + m_builder->createListInsert(globalList2.get(), v1, v2); - auto localVar = std::make_shared("", ""); - sprite.addVariable(localVar); + v1 = m_builder->addConstValue(1); + v2 = m_builder->addConstValue(-4.25); + m_builder->createListReplace(localList.get(), v1, v2); + } + m_builder->endLoop(); - createBuilder(&sprite, true); + checkLists(); - CompilerValue *v = m_builder->addConstValue(0); - m_builder->createVariableWrite(globalVar.get(), v); + // while (counter1 < 5) { ... until (counter2 == 3) {... counter2++ }; while (false) { ... }; counter1++ } + resetLists(); - v = m_builder->addConstValue(5.25); - m_builder->createVariableWrite(localVar.get(), v); + v = m_builder->addConstValue(0); + m_builder->createVariableWrite(counter1.get(), v); - v = m_builder->addConstValue(2); - m_builder->beginRepeatLoop(v); + m_builder->beginLoopCondition(); + v1 = m_builder->addVariableValue(counter1.get()); + v2 = m_builder->addConstValue(5); + v = m_builder->createCmpLT(v1, v2); + m_builder->beginWhileLoop(v); { - // Type is known here because a variable is assigned which has a number assigned later - v = m_builder->addVariableValue(localVar.get()); - m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v }); + v = m_builder->addConstValue(0); + m_builder->createVariableWrite(counter2.get(), v); - v = m_builder->addConstValue(2); - m_builder->beginRepeatLoop(v); + m_builder->beginLoopCondition(); + v1 = m_builder->addVariableValue(counter2.get()); + v2 = m_builder->addConstValue(3); + v = m_builder->createCmpEQ(v1, v2); + m_builder->beginRepeatUntilLoop(v); { - v = m_builder->addVariableValue(globalVar.get()); - m_builder->createVariableWrite(localVar.get(), v); + v1 = m_builder->addConstValue(0); + v2 = m_builder->addConstValue(8.5); + m_builder->createListInsert(globalList2.get(), v1, v2); - v = m_builder->addConstValue(12.5); - m_builder->createVariableWrite(globalVar.get(), v); + v1 = m_builder->addConstValue(1); + v2 = m_builder->addConstValue(-4.25); + m_builder->createListReplace(localList.get(), v1, v2); + + v1 = m_builder->addVariableValue(counter2.get()); + v2 = m_builder->addConstValue(1); + v = m_builder->createAdd(v1, v2); + m_builder->createVariableWrite(counter2.get(), v); + } + m_builder->endLoop(); + + m_builder->beginLoopCondition(); + v = m_builder->addConstValue(false); + m_builder->beginWhileLoop(v); + { + v = m_builder->addConstValue("hello world"); + m_builder->createListAppend(globalList1.get(), v); } m_builder->endLoop(); + + v1 = m_builder->addVariableValue(counter1.get()); + v2 = m_builder->addConstValue(1); + v = m_builder->createAdd(v1, v2); + m_builder->createVariableWrite(counter1.get(), v); + } + m_builder->endLoop(); + + checkLists(); + + // until (true) + resetLists(); + + m_builder->beginLoopCondition(); + v = m_builder->addConstValue(true); + m_builder->beginRepeatUntilLoop(v); + { + v = m_builder->addConstValue("hello world"); + m_builder->createListAppend(globalList1.get(), v); + + v1 = m_builder->addConstValue(0); + v2 = m_builder->addConstValue(8.5); + m_builder->createListInsert(globalList2.get(), v1, v2); + + v1 = m_builder->addConstValue(1); + v2 = m_builder->addConstValue(-4.25); + m_builder->createListReplace(localList.get(), v1, v2); } m_builder->endLoop(); + checkLists(); + std::string expected = - "5.25\n" - "12.5\n"; + "1\n" + "8.5\n" + "false\n" + "1\n" + "world\n" + "false\n" + "1\n" + "8.5\n" + "false\n" + "1\n" + "world\n" + "false\n"; auto code = m_builder->finalize(); Script script(&sprite, nullptr, nullptr); script.setCode(code); + ; Thread thread(&sprite, nullptr, &script); auto ctx = code->createExecutionContext(&thread); testing::internal::CaptureStdout(); @@ -4420,1529 +4460,49 @@ TEST_F(LLVMCodeBuilderTest, VariableLoopTypeAnalysis4) ASSERT_EQ(testing::internal::GetCapturedStdout(), expected); } -TEST_F(LLVMCodeBuilderTest, VariableLoopTypeAnalysis5) +TEST_F(LLVMCodeBuilderTest, ListLoopTypeAnalysis) { + // This just makes sure the type analyzer is used correctly Stage stage; Sprite sprite; sprite.setEngine(&m_engine); EXPECT_CALL(m_engine, stage()).WillRepeatedly(Return(&stage)); - auto globalVar = std::make_shared("", ""); - stage.addVariable(globalVar); + auto globalList = std::make_shared("", ""); + stage.addList(globalList); - auto localVar = std::make_shared("", ""); - sprite.addVariable(localVar); + auto localList = std::make_shared("", ""); + sprite.addList(localList); createBuilder(&sprite, true); - CompilerValue *v = m_builder->addConstValue("test"); - m_builder->createVariableWrite(globalVar.get(), v); + m_builder->createListClear(localList.get()); - v = m_builder->addConstValue(5.25); - m_builder->createVariableWrite(localVar.get(), v); + CompilerValue *v = m_builder->addConstValue(5.25); + m_builder->createListAppend(localList.get(), v); - v = m_builder->addConstValue(3); + v = m_builder->addConstValue(2); m_builder->beginRepeatLoop(v); { - // Type is unknown here because a string variable is assigned later which has a number assigned as well - v = m_builder->addVariableValue(localVar.get()); + // Type is unknown here because a string is added later + v = m_builder->createSub(m_builder->addListSize(localList.get()), m_builder->addConstValue(1)); + v = m_builder->addListItem(localList.get(), v); m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v }); - v = m_builder->addVariableValue(globalVar.get()); - m_builder->createVariableWrite(localVar.get(), v); + v = m_builder->addListItemIndex(localList.get(), m_builder->addConstValue(5.25)); + m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v }); - v = m_builder->addConstValue(12.5); - m_builder->createVariableWrite(globalVar.get(), v); + v = m_builder->addListContains(localList.get(), m_builder->addConstValue(5.25)); + m_builder->addFunctionCall("test_print_bool", Compiler::StaticType::Void, { Compiler::StaticType::Bool }, { v }); + + v = m_builder->addConstValue("test"); + m_builder->createListAppend(localList.get(), v); } m_builder->endLoop(); std::string expected = "5.25\n" "0\n" - "12.5\n"; - - auto code = m_builder->finalize(); - Script script(&sprite, nullptr, nullptr); - script.setCode(code); - Thread thread(&sprite, nullptr, &script); - auto ctx = code->createExecutionContext(&thread); - testing::internal::CaptureStdout(); - code->run(ctx.get()); - ASSERT_EQ(testing::internal::GetCapturedStdout(), expected); -} - -TEST_F(LLVMCodeBuilderTest, VariableLoopTypeAnalysis6) -{ - Stage stage; - Sprite sprite; - sprite.setEngine(&m_engine); - EXPECT_CALL(m_engine, stage()).WillRepeatedly(Return(&stage)); - - auto globalVar = std::make_shared("", ""); - stage.addVariable(globalVar); - - auto localVar = std::make_shared("", ""); - sprite.addVariable(localVar); - - createBuilder(&sprite, true); - - CompilerValue *v = m_builder->addConstValue(5.25); - m_builder->createVariableWrite(localVar.get(), v); - - v = m_builder->addConstValue(2); - m_builder->beginRepeatLoop(v); - { - // Type is known here because a variable with known type is assigned later (even though the variable has a string assigned later, there's a number assigned before the read operation) - v = m_builder->addVariableValue(localVar.get()); - m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v }); - - v = m_builder->addConstValue(2); - m_builder->beginRepeatLoop(v); - { - v = m_builder->addConstValue(10); - m_builder->createVariableWrite(globalVar.get(), v); - - v = m_builder->addVariableValue(globalVar.get()); - m_builder->createVariableWrite(localVar.get(), v); - - v = m_builder->addConstValue("test"); - m_builder->createVariableWrite(globalVar.get(), v); - } - m_builder->endLoop(); - } - m_builder->endLoop(); - - std::string expected = - "5.25\n" - "10\n"; - - auto code = m_builder->finalize(); - Script script(&sprite, nullptr, nullptr); - script.setCode(code); - Thread thread(&sprite, nullptr, &script); - auto ctx = code->createExecutionContext(&thread); - testing::internal::CaptureStdout(); - code->run(ctx.get()); - ASSERT_EQ(testing::internal::GetCapturedStdout(), expected); -} - -TEST_F(LLVMCodeBuilderTest, VariableLoopTypeAnalysis7) -{ - Stage stage; - Sprite sprite; - sprite.setEngine(&m_engine); - EXPECT_CALL(m_engine, stage()).WillRepeatedly(Return(&stage)); - - auto globalVar = std::make_shared("", ""); - stage.addVariable(globalVar); - - auto localVar = std::make_shared("", ""); - sprite.addVariable(localVar); - - createBuilder(&sprite, true); - - CompilerValue *v = m_builder->addConstValue(5.25); - m_builder->createVariableWrite(localVar.get(), v); - - v = m_builder->addConstValue(2); - m_builder->beginRepeatLoop(v); - { - // Type is unknown here because a variable with a known, but different type is assigned later - v = m_builder->addVariableValue(localVar.get()); - m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v }); - - v = m_builder->addConstValue(2); - m_builder->beginRepeatLoop(v); - { - v = m_builder->addConstValue("test"); - m_builder->createVariableWrite(globalVar.get(), v); - - v = m_builder->addVariableValue(globalVar.get()); - m_builder->createVariableWrite(localVar.get(), v); - - v = m_builder->addConstValue(10); - m_builder->createVariableWrite(globalVar.get(), v); - } - m_builder->endLoop(); - } - m_builder->endLoop(); - - std::string expected = - "5.25\n" - "0\n"; - - auto code = m_builder->finalize(); - Script script(&sprite, nullptr, nullptr); - script.setCode(code); - Thread thread(&sprite, nullptr, &script); - auto ctx = code->createExecutionContext(&thread); - testing::internal::CaptureStdout(); - code->run(ctx.get()); - ASSERT_EQ(testing::internal::GetCapturedStdout(), expected); -} - -TEST_F(LLVMCodeBuilderTest, VariableLoopTypeAnalysis8) -{ - Stage stage; - Sprite sprite; - sprite.setEngine(&m_engine); - EXPECT_CALL(m_engine, stage()).WillRepeatedly(Return(&stage)); - - auto globalVar = std::make_shared("", ""); - stage.addVariable(globalVar); - - auto localVar = std::make_shared("", ""); - sprite.addVariable(localVar); - - createBuilder(&sprite, true); - - CompilerValue *v = m_builder->addConstValue(5.25); - m_builder->createVariableWrite(localVar.get(), v); - - v = m_builder->addConstValue(2); - m_builder->beginRepeatLoop(v); - { - // Type is unknown here because a variable with a known, but different type is assigned later - v = m_builder->addVariableValue(localVar.get()); - m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v }); - - v = m_builder->addConstValue(2); - m_builder->beginRepeatLoop(v); - { - v = m_builder->addConstValue("test"); - m_builder->createVariableWrite(globalVar.get(), v); - - v = m_builder->addVariableValue(globalVar.get()); - m_builder->createVariableWrite(localVar.get(), v); - } - m_builder->endLoop(); - } - m_builder->endLoop(); - - std::string expected = - "5.25\n" - "0\n"; - - auto code = m_builder->finalize(); - Script script(&sprite, nullptr, nullptr); - script.setCode(code); - Thread thread(&sprite, nullptr, &script); - auto ctx = code->createExecutionContext(&thread); - testing::internal::CaptureStdout(); - code->run(ctx.get()); - ASSERT_EQ(testing::internal::GetCapturedStdout(), expected); -} - -TEST_F(LLVMCodeBuilderTest, VariableLoopTypeAnalysis9) -{ - Stage stage; - Sprite sprite; - sprite.setEngine(&m_engine); - EXPECT_CALL(m_engine, stage()).WillRepeatedly(Return(&stage)); - - auto globalVar = std::make_shared("", "", "123"); - stage.addVariable(globalVar); - - auto localVar = std::make_shared("", ""); - sprite.addVariable(localVar); - - createBuilder(&sprite, true); - - CompilerValue *v = m_builder->addConstValue(5.25); - m_builder->createVariableWrite(localVar.get(), v); - - v = m_builder->addConstValue(2); - m_builder->beginRepeatLoop(v); - { - v = m_builder->addConstValue(2); - m_builder->beginRepeatLoop(v); - { - v = m_builder->addVariableValue(globalVar.get()); - m_builder->createVariableWrite(localVar.get(), v); - - v = m_builder->addConstValue(5); - m_builder->createVariableWrite(globalVar.get(), v); - } - m_builder->endLoop(); - - // Type is unknown here because a variable of unknown type is assigned before the read operation - v = m_builder->addVariableValue(localVar.get()); - m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v }); - - v = m_builder->addConstValue(2); - m_builder->beginRepeatLoop(v); - { - v = m_builder->addConstValue(10); - m_builder->createVariableWrite(globalVar.get(), v); - - v = m_builder->addVariableValue(globalVar.get()); - m_builder->createVariableWrite(localVar.get(), v); - - v = m_builder->addConstValue("test"); - m_builder->createVariableWrite(globalVar.get(), v); - } - m_builder->endLoop(); - } - m_builder->endLoop(); - - std::string expected = - "5\n" - "5\n"; - - auto code = m_builder->finalize(); - Script script(&sprite, nullptr, nullptr); - script.setCode(code); - Thread thread(&sprite, nullptr, &script); - auto ctx = code->createExecutionContext(&thread); - testing::internal::CaptureStdout(); - code->run(ctx.get()); - ASSERT_EQ(testing::internal::GetCapturedStdout(), expected); -} - -TEST_F(LLVMCodeBuilderTest, VariableLoopTypeAnalysis10) -{ - Stage stage; - Sprite sprite; - sprite.setEngine(&m_engine); - EXPECT_CALL(m_engine, stage()).WillRepeatedly(Return(&stage)); - - auto globalVar = std::make_shared("", ""); - stage.addVariable(globalVar); - - auto localVar = std::make_shared("", "", "123"); - sprite.addVariable(localVar); - - createBuilder(&sprite, true); - - CompilerValue *v = m_builder->addConstValue(2); - m_builder->beginRepeatLoop(v); - { - v = m_builder->addConstValue("test"); - m_builder->createVariableWrite(globalVar.get(), v); - - v = m_builder->addConstValue(3); - m_builder->beginRepeatLoop(v); - { - // Type is unknown here because a variable of unknown type is assigned later - v = m_builder->addVariableValue(localVar.get()); - m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v }); - - v = m_builder->addVariableValue(globalVar.get()); - m_builder->createVariableWrite(localVar.get(), v); - - v = m_builder->addConstValue(12.5); - m_builder->createVariableWrite(globalVar.get(), v); - } - m_builder->endLoop(); - } - m_builder->endLoop(); - - std::string expected = - "123\n" - "0\n" - "12.5\n" - "12.5\n" - "0\n" - "12.5\n"; - - auto code = m_builder->finalize(); - Script script(&sprite, nullptr, nullptr); - script.setCode(code); - Thread thread(&sprite, nullptr, &script); - auto ctx = code->createExecutionContext(&thread); - testing::internal::CaptureStdout(); - code->run(ctx.get()); - ASSERT_EQ(testing::internal::GetCapturedStdout(), expected); -} - -TEST_F(LLVMCodeBuilderTest, VariableLoopTypeAnalysis11) -{ - Stage stage; - Sprite sprite; - sprite.setEngine(&m_engine); - EXPECT_CALL(m_engine, stage()).WillRepeatedly(Return(&stage)); - - auto globalVar = std::make_shared("", ""); - stage.addVariable(globalVar); - - auto localVar = std::make_shared("", "", "123"); - sprite.addVariable(localVar); - - createBuilder(&sprite, true); - - CompilerValue *v = m_builder->addConstValue(2); - m_builder->beginRepeatLoop(v); - { - v = m_builder->addConstValue("test"); - m_builder->createVariableWrite(globalVar.get(), v); - - v = m_builder->addConstValue(3); - m_builder->beginRepeatLoop(v); - { - // Type is unknown here because the variable is assigned to itself later - // This case is not checked because the code isn't considered valid - v = m_builder->addVariableValue(localVar.get()); - m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v }); - - v = m_builder->addVariableValue(localVar.get()); - m_builder->createVariableWrite(localVar.get(), v); - - v = m_builder->addConstValue(12.5); - m_builder->createVariableWrite(globalVar.get(), v); - } - m_builder->endLoop(); - } - m_builder->endLoop(); - - std::string expected = - "123\n" - "123\n" - "123\n" - "123\n" - "123\n" - "123\n"; - - auto code = m_builder->finalize(); - Script script(&sprite, nullptr, nullptr); - script.setCode(code); - Thread thread(&sprite, nullptr, &script); - auto ctx = code->createExecutionContext(&thread); - testing::internal::CaptureStdout(); - code->run(ctx.get()); - ASSERT_EQ(testing::internal::GetCapturedStdout(), expected); -} - -TEST_F(LLVMCodeBuilderTest, VariableLoopTypeAnalysis12) -{ - Stage stage; - Sprite sprite; - sprite.setEngine(&m_engine); - EXPECT_CALL(m_engine, stage()).WillRepeatedly(Return(&stage)); - - auto globalVar = std::make_shared("", ""); - stage.addVariable(globalVar); - - auto localVar = std::make_shared("", "", "123"); - sprite.addVariable(localVar); - - createBuilder(&sprite, true); - - CompilerValue *v = m_builder->addConstValue(2); - m_builder->beginRepeatLoop(v); - { - v = m_builder->addConstValue("test"); - m_builder->createVariableWrite(globalVar.get(), v); - - v = m_builder->addConstValue(3); - m_builder->beginRepeatLoop(v); - { - // Type is unknown here because another variable is assigned later, but it has this variable assigned - // This case is not checked because the code isn't considered valid - v = m_builder->addVariableValue(localVar.get()); - m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v }); - - v = m_builder->addVariableValue(globalVar.get()); - m_builder->createVariableWrite(localVar.get(), v); - - v = m_builder->addVariableValue(localVar.get()); - m_builder->createVariableWrite(globalVar.get(), v); - } - m_builder->endLoop(); - } - m_builder->endLoop(); - - std::string expected = - "123\n" - "0\n" - "0\n" - "0\n" - "0\n" - "0\n"; - - auto code = m_builder->finalize(); - Script script(&sprite, nullptr, nullptr); - script.setCode(code); - Thread thread(&sprite, nullptr, &script); - auto ctx = code->createExecutionContext(&thread); - testing::internal::CaptureStdout(); - code->run(ctx.get()); - ASSERT_EQ(testing::internal::GetCapturedStdout(), expected); -} - -TEST_F(LLVMCodeBuilderTest, LoopLists) -{ - Stage stage; - Sprite sprite; - sprite.setEngine(&m_engine); - EXPECT_CALL(m_engine, stage()).WillRepeatedly(Return(&stage)); - - auto globalList1 = std::make_shared("", ""); - stage.addList(globalList1); - - auto globalList2 = std::make_shared("", ""); - stage.addList(globalList2); - - auto localList = std::make_shared("", ""); - sprite.addList(localList); - - auto counter1 = std::make_shared("", ""); - auto counter2 = std::make_shared("", ""); - sprite.addVariable(counter1); - sprite.addVariable(counter2); - - createBuilder(&sprite, true); - - auto resetLists = [this, globalList1, globalList2, localList]() { - m_builder->createListClear(globalList1.get()); - m_builder->createListClear(globalList2.get()); - m_builder->createListClear(localList.get()); - - m_builder->createListAppend(globalList1.get(), m_builder->addConstValue(1)); - m_builder->createListAppend(globalList1.get(), m_builder->addConstValue(2)); - - m_builder->createListAppend(globalList2.get(), m_builder->addConstValue("hello")); - m_builder->createListAppend(globalList2.get(), m_builder->addConstValue("world")); - - m_builder->createListAppend(localList.get(), m_builder->addConstValue(false)); - m_builder->createListAppend(localList.get(), m_builder->addConstValue(true)); - }; - - auto checkLists = [this, globalList1, globalList2, localList]() { - CompilerValue *v = m_builder->addListItem(globalList1.get(), m_builder->addConstValue(0)); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); - - v = m_builder->addListItem(globalList2.get(), m_builder->addConstValue(1)); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); - - v = m_builder->addListItem(localList.get(), m_builder->addConstValue(0)); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); - }; - - // repeat (2) - resetLists(); - - CompilerValue *v, *v1, *v2; - v = m_builder->addConstValue(2); - m_builder->beginRepeatLoop(v); - { - v = m_builder->addConstValue("hello world"); - m_builder->createListAppend(globalList1.get(), v); - - v1 = m_builder->addConstValue(0); - v2 = m_builder->addConstValue(8.5); - m_builder->createListInsert(globalList2.get(), v1, v2); - - v1 = m_builder->addConstValue(1); - v2 = m_builder->addConstValue(-4.25); - m_builder->createListReplace(localList.get(), v1, v2); - } - m_builder->endLoop(); - - checkLists(); - - // repeat(0) - resetLists(); - - v = m_builder->addConstValue(0); - m_builder->beginRepeatLoop(v); - { - v = m_builder->addConstValue("hello world"); - m_builder->createListAppend(globalList1.get(), v); - - v1 = m_builder->addConstValue(0); - v2 = m_builder->addConstValue(8.5); - m_builder->createListInsert(globalList2.get(), v1, v2); - - v1 = m_builder->addConstValue(1); - v2 = m_builder->addConstValue(-4.25); - m_builder->createListReplace(localList.get(), v1, v2); - } - m_builder->endLoop(); - - checkLists(); - - // while (counter1 < 5) { ... until (counter2 == 3) {... counter2++ }; while (false) { ... }; counter1++ } - resetLists(); - - v = m_builder->addConstValue(0); - m_builder->createVariableWrite(counter1.get(), v); - - m_builder->beginLoopCondition(); - v1 = m_builder->addVariableValue(counter1.get()); - v2 = m_builder->addConstValue(5); - v = m_builder->createCmpLT(v1, v2); - m_builder->beginWhileLoop(v); - { - v = m_builder->addConstValue(0); - m_builder->createVariableWrite(counter2.get(), v); - - m_builder->beginLoopCondition(); - v1 = m_builder->addVariableValue(counter2.get()); - v2 = m_builder->addConstValue(3); - v = m_builder->createCmpEQ(v1, v2); - m_builder->beginRepeatUntilLoop(v); - { - v1 = m_builder->addConstValue(0); - v2 = m_builder->addConstValue(8.5); - m_builder->createListInsert(globalList2.get(), v1, v2); - - v1 = m_builder->addConstValue(1); - v2 = m_builder->addConstValue(-4.25); - m_builder->createListReplace(localList.get(), v1, v2); - - v1 = m_builder->addVariableValue(counter2.get()); - v2 = m_builder->addConstValue(1); - v = m_builder->createAdd(v1, v2); - m_builder->createVariableWrite(counter2.get(), v); - } - m_builder->endLoop(); - - m_builder->beginLoopCondition(); - v = m_builder->addConstValue(false); - m_builder->beginWhileLoop(v); - { - v = m_builder->addConstValue("hello world"); - m_builder->createListAppend(globalList1.get(), v); - } - m_builder->endLoop(); - - v1 = m_builder->addVariableValue(counter1.get()); - v2 = m_builder->addConstValue(1); - v = m_builder->createAdd(v1, v2); - m_builder->createVariableWrite(counter1.get(), v); - } - m_builder->endLoop(); - - checkLists(); - - // until (true) - resetLists(); - - m_builder->beginLoopCondition(); - v = m_builder->addConstValue(true); - m_builder->beginRepeatUntilLoop(v); - { - v = m_builder->addConstValue("hello world"); - m_builder->createListAppend(globalList1.get(), v); - - v1 = m_builder->addConstValue(0); - v2 = m_builder->addConstValue(8.5); - m_builder->createListInsert(globalList2.get(), v1, v2); - - v1 = m_builder->addConstValue(1); - v2 = m_builder->addConstValue(-4.25); - m_builder->createListReplace(localList.get(), v1, v2); - } - m_builder->endLoop(); - - checkLists(); - - std::string expected = - "1\n" - "8.5\n" - "false\n" - "1\n" - "world\n" - "false\n" - "1\n" - "8.5\n" - "false\n" - "1\n" - "world\n" - "false\n"; - - auto code = m_builder->finalize(); - Script script(&sprite, nullptr, nullptr); - script.setCode(code); - ; - Thread thread(&sprite, nullptr, &script); - auto ctx = code->createExecutionContext(&thread); - testing::internal::CaptureStdout(); - code->run(ctx.get()); - ASSERT_EQ(testing::internal::GetCapturedStdout(), expected); -} - -TEST_F(LLVMCodeBuilderTest, ListLoopTypeAnalysis1) -{ - Stage stage; - Sprite sprite; - sprite.setEngine(&m_engine); - EXPECT_CALL(m_engine, stage()).WillRepeatedly(Return(&stage)); - - auto globalList = std::make_shared("", ""); - stage.addList(globalList); - - auto localList = std::make_shared("", ""); - sprite.addList(localList); - - createBuilder(&sprite, true); - - m_builder->createListClear(localList.get()); - - CompilerValue *v = m_builder->addConstValue(5.25); - m_builder->createListAppend(localList.get(), v); - - v = m_builder->addConstValue(2); - m_builder->beginRepeatLoop(v); - { - // Type is unknown here because a string is added later - v = m_builder->createSub(m_builder->addListSize(localList.get()), m_builder->addConstValue(1)); - v = m_builder->addListItem(localList.get(), v); - m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v }); - - v = m_builder->addListItemIndex(localList.get(), m_builder->addConstValue(5.25)); - m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v }); - - v = m_builder->addListContains(localList.get(), m_builder->addConstValue(5.25)); - m_builder->addFunctionCall("test_print_bool", Compiler::StaticType::Void, { Compiler::StaticType::Bool }, { v }); - - v = m_builder->addConstValue("test"); - m_builder->createListAppend(localList.get(), v); - } - m_builder->endLoop(); - - std::string expected = - "5.25\n" - "0\n" - "1\n" - "0\n" - "0\n" - "1\n"; - - auto code = m_builder->finalize(); - Script script(&sprite, nullptr, nullptr); - script.setCode(code); - Thread thread(&sprite, nullptr, &script); - auto ctx = code->createExecutionContext(&thread); - testing::internal::CaptureStdout(); - code->run(ctx.get()); - ASSERT_EQ(testing::internal::GetCapturedStdout(), expected); -} - -TEST_F(LLVMCodeBuilderTest, ListLoopTypeAnalysis2) -{ - Stage stage; - Sprite sprite; - sprite.setEngine(&m_engine); - EXPECT_CALL(m_engine, stage()).WillRepeatedly(Return(&stage)); - - auto globalList = std::make_shared("", ""); - stage.addList(globalList); - - auto localList = std::make_shared("", ""); - sprite.addList(localList); - - createBuilder(&sprite, true); - - m_builder->createListClear(localList.get()); - - CompilerValue *v = m_builder->addConstValue(5.25); - m_builder->createListAppend(localList.get(), v); - - v = m_builder->addConstValue(2); - m_builder->beginRepeatLoop(v); - { - // Type is known here because a number is assigned later - v = m_builder->addConstValue(0); - v = m_builder->addListItem(localList.get(), v); - m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v }); - - v = m_builder->addListItemIndex(localList.get(), m_builder->addConstValue(5.25)); - m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v }); - - v = m_builder->addListContains(localList.get(), m_builder->addConstValue(5.25)); - m_builder->addFunctionCall("test_print_bool", Compiler::StaticType::Void, { Compiler::StaticType::Bool }, { v }); - - v = m_builder->addConstValue(12.5); - m_builder->createListReplace(localList.get(), m_builder->addConstValue(0), v); - } - m_builder->endLoop(); - - std::string expected = - "5.25\n" - "0\n" - "1\n" - "12.5\n" - "-1\n" - "0\n"; - - auto code = m_builder->finalize(); - Script script(&sprite, nullptr, nullptr); - script.setCode(code); - Thread thread(&sprite, nullptr, &script); - auto ctx = code->createExecutionContext(&thread); - testing::internal::CaptureStdout(); - code->run(ctx.get()); - ASSERT_EQ(testing::internal::GetCapturedStdout(), expected); -} - -TEST_F(LLVMCodeBuilderTest, ListLoopTypeAnalysis3) -{ - Stage stage; - Sprite sprite; - sprite.setEngine(&m_engine); - EXPECT_CALL(m_engine, stage()).WillRepeatedly(Return(&stage)); - - auto globalList = std::make_shared("", ""); - stage.addList(globalList); - - auto localList = std::make_shared("", ""); - sprite.addList(localList); - - createBuilder(&sprite, true); - - m_builder->createListClear(globalList.get()); - m_builder->createListClear(localList.get()); - - CompilerValue *v = m_builder->addConstValue(0); - m_builder->createListAppend(globalList.get(), v); - - v = m_builder->addConstValue(5.25); - m_builder->createListAppend(localList.get(), v); - - v = m_builder->addConstValue(2); - m_builder->beginRepeatLoop(v); - { - // Type is unknown here because a list item with unknown type is inserted (the item has unknown type because a string is assigned later) - v = m_builder->addConstValue(0); - v = m_builder->addListItem(localList.get(), v); - m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v }); - - v = m_builder->addListItemIndex(localList.get(), m_builder->addConstValue(5.25)); - m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v }); - - v = m_builder->addListContains(localList.get(), m_builder->addConstValue(5.25)); - m_builder->addFunctionCall("test_print_bool", Compiler::StaticType::Void, { Compiler::StaticType::Bool }, { v }); - - v = m_builder->addConstValue(2); - m_builder->beginRepeatLoop(v); - { - v = m_builder->addListItem(globalList.get(), m_builder->addConstValue(0)); - m_builder->createListInsert(localList.get(), m_builder->addConstValue(0), v); - - v = m_builder->addConstValue("test"); - m_builder->createListReplace(globalList.get(), m_builder->addConstValue(0), v); - } - m_builder->endLoop(); - } - m_builder->endLoop(); - - std::string expected = - "5.25\n" - "0\n" - "1\n" - "0\n" - "2\n" - "1\n"; - - auto code = m_builder->finalize(); - Script script(&sprite, nullptr, nullptr); - script.setCode(code); - Thread thread(&sprite, nullptr, &script); - auto ctx = code->createExecutionContext(&thread); - testing::internal::CaptureStdout(); - code->run(ctx.get()); - ASSERT_EQ(testing::internal::GetCapturedStdout(), expected); -} - -TEST_F(LLVMCodeBuilderTest, ListLoopTypeAnalysis4) -{ - Stage stage; - Sprite sprite; - sprite.setEngine(&m_engine); - EXPECT_CALL(m_engine, stage()).WillRepeatedly(Return(&stage)); - - auto globalList = std::make_shared("", ""); - stage.addList(globalList); - - auto localList = std::make_shared("", ""); - sprite.addList(localList); - - createBuilder(&sprite, true); - - m_builder->createListClear(globalList.get()); - m_builder->createListClear(localList.get()); - - CompilerValue *v = m_builder->addConstValue(0); - m_builder->createListAppend(globalList.get(), v); - - v = m_builder->addConstValue(5.25); - m_builder->createListAppend(localList.get(), v); - - v = m_builder->addConstValue(2); - m_builder->beginRepeatLoop(v); - { - // Type is known here because a number list item is added later - v = m_builder->createSub(m_builder->addListSize(localList.get()), m_builder->addConstValue(1)); - v = m_builder->addListItem(localList.get(), v); - m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v }); - - v = m_builder->addListItemIndex(localList.get(), m_builder->addConstValue(5.25)); - m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v }); - - v = m_builder->addListContains(localList.get(), m_builder->addConstValue(5.25)); - m_builder->addFunctionCall("test_print_bool", Compiler::StaticType::Void, { Compiler::StaticType::Bool }, { v }); - - v = m_builder->addConstValue(2); - m_builder->beginRepeatLoop(v); - { - v = m_builder->addListItem(globalList.get(), m_builder->addConstValue(0)); - m_builder->createListAppend(localList.get(), v); - - v = m_builder->addConstValue(12.5); - m_builder->createListInsert(globalList.get(), m_builder->addConstValue(0), v); - } - m_builder->endLoop(); - } - m_builder->endLoop(); - - std::string expected = - "5.25\n" - "0\n" - "1\n" - "12.5\n" - "0\n" - "1\n"; - - auto code = m_builder->finalize(); - Script script(&sprite, nullptr, nullptr); - script.setCode(code); - Thread thread(&sprite, nullptr, &script); - auto ctx = code->createExecutionContext(&thread); - testing::internal::CaptureStdout(); - code->run(ctx.get()); - ASSERT_EQ(testing::internal::GetCapturedStdout(), expected); -} - -TEST_F(LLVMCodeBuilderTest, ListLoopTypeAnalysis5) -{ - Stage stage; - Sprite sprite; - sprite.setEngine(&m_engine); - EXPECT_CALL(m_engine, stage()).WillRepeatedly(Return(&stage)); - - auto globalList = std::make_shared("", ""); - stage.addList(globalList); - - auto localList = std::make_shared("", ""); - sprite.addList(localList); - - createBuilder(&sprite, true); - - m_builder->createListClear(globalList.get()); - m_builder->createListClear(localList.get()); - - CompilerValue *v = m_builder->addConstValue("test"); - m_builder->createListAppend(globalList.get(), v); - - v = m_builder->addConstValue(5.25); - m_builder->createListAppend(localList.get(), v); - - v = m_builder->addConstValue(3); - m_builder->beginRepeatLoop(v); - { - // Type is unknown here because a string list item is assigned later which becomes a number later - v = m_builder->addConstValue(0); - v = m_builder->addListItem(localList.get(), v); - m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v }); - - v = m_builder->addListItemIndex(localList.get(), m_builder->addConstValue(5.25)); - m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v }); - - v = m_builder->addListContains(localList.get(), m_builder->addConstValue(5.25)); - m_builder->addFunctionCall("test_print_bool", Compiler::StaticType::Void, { Compiler::StaticType::Bool }, { v }); - - v = m_builder->addListItem(globalList.get(), m_builder->addConstValue(0)); - m_builder->createListReplace(localList.get(), m_builder->addConstValue(0), v); - - v = m_builder->addConstValue(12.5); - m_builder->createListReplace(globalList.get(), m_builder->addConstValue(0), v); - } - m_builder->endLoop(); - - std::string expected = - "5.25\n" - "0\n" - "1\n" - "0\n" - "-1\n" - "0\n" - "12.5\n" - "-1\n" - "0\n"; - - auto code = m_builder->finalize(); - Script script(&sprite, nullptr, nullptr); - script.setCode(code); - Thread thread(&sprite, nullptr, &script); - auto ctx = code->createExecutionContext(&thread); - testing::internal::CaptureStdout(); - code->run(ctx.get()); - ASSERT_EQ(testing::internal::GetCapturedStdout(), expected); -} - -TEST_F(LLVMCodeBuilderTest, ListLoopTypeAnalysis6) -{ - Stage stage; - Sprite sprite; - sprite.setEngine(&m_engine); - EXPECT_CALL(m_engine, stage()).WillRepeatedly(Return(&stage)); - - auto globalList = std::make_shared("", ""); - stage.addList(globalList); - - auto localList = std::make_shared("", ""); - sprite.addList(localList); - - createBuilder(&sprite, true); - - m_builder->createListClear(globalList.get()); - m_builder->createListClear(localList.get()); - - CompilerValue *v = m_builder->addConstValue(-156.07); - m_builder->createListAppend(globalList.get(), v); - - v = m_builder->addConstValue(5.25); - m_builder->createListAppend(localList.get(), v); - - v = m_builder->addConstValue(2); - m_builder->beginRepeatLoop(v); - { - // Type is unknown here because a list item with unknown type is added later - v = m_builder->createSub(m_builder->addListSize(localList.get()), m_builder->addConstValue(1)); - v = m_builder->addListItem(localList.get(), v); - m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v }); - - v = m_builder->addListItemIndex(localList.get(), m_builder->addConstValue(5.25)); - m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v }); - - v = m_builder->addListContains(localList.get(), m_builder->addConstValue(5.25)); - m_builder->addFunctionCall("test_print_bool", Compiler::StaticType::Void, { Compiler::StaticType::Bool }, { v }); - - v = m_builder->addConstValue(2); - m_builder->beginRepeatLoop(v); - { - v = m_builder->addConstValue(10); - m_builder->createListReplace(globalList.get(), m_builder->addConstValue(0), v); - - v = m_builder->createSub(m_builder->addListSize(globalList.get()), m_builder->addConstValue(1)); - v = m_builder->addListItem(globalList.get(), v); - m_builder->createListAppend(localList.get(), v); - - v = m_builder->addConstValue("test"); - m_builder->createListAppend(globalList.get(), v); - } - m_builder->endLoop(); - } - m_builder->endLoop(); - - std::string expected = - "5.25\n" - "0\n" - "1\n" - "0\n" - "0\n" - "1\n"; - - auto code = m_builder->finalize(); - Script script(&sprite, nullptr, nullptr); - script.setCode(code); - Thread thread(&sprite, nullptr, &script); - auto ctx = code->createExecutionContext(&thread); - testing::internal::CaptureStdout(); - code->run(ctx.get()); - ASSERT_EQ(testing::internal::GetCapturedStdout(), expected); -} - -TEST_F(LLVMCodeBuilderTest, ListLoopTypeAnalysis7) -{ - Stage stage; - Sprite sprite; - sprite.setEngine(&m_engine); - EXPECT_CALL(m_engine, stage()).WillRepeatedly(Return(&stage)); - - auto globalList = std::make_shared("", ""); - stage.addList(globalList); - - auto localList = std::make_shared("", ""); - sprite.addList(localList); - - createBuilder(&sprite, true); - - m_builder->createListClear(localList.get()); - - CompilerValue *v = m_builder->addConstValue(5.25); - m_builder->createListAppend(localList.get(), v); - - v = m_builder->addConstValue(2); - m_builder->beginRepeatLoop(v); - { - // Type is unknown here because a list item with unknown type is assigned later - v = m_builder->addConstValue(0); - v = m_builder->addListItem(localList.get(), v); - m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v }); - - v = m_builder->addListItemIndex(localList.get(), m_builder->addConstValue(5.25)); - m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v }); - - v = m_builder->addListContains(localList.get(), m_builder->addConstValue(5.25)); - m_builder->addFunctionCall("test_print_bool", Compiler::StaticType::Void, { Compiler::StaticType::Bool }, { v }); - - v = m_builder->addConstValue(2); - m_builder->beginRepeatLoop(v); - { - v = m_builder->addConstValue("test"); - m_builder->createListInsert(globalList.get(), m_builder->addConstValue(0), v); - - v = m_builder->addListItem(globalList.get(), m_builder->addConstValue(0)); - m_builder->createListReplace(localList.get(), m_builder->addConstValue(0), v); - - v = m_builder->addConstValue(10); - m_builder->createListReplace(globalList.get(), m_builder->addConstValue(0), v); - } - m_builder->endLoop(); - } - m_builder->endLoop(); - - std::string expected = - "5.25\n" - "0\n" - "1\n" - "0\n" - "-1\n" - "0\n"; - - auto code = m_builder->finalize(); - Script script(&sprite, nullptr, nullptr); - script.setCode(code); - Thread thread(&sprite, nullptr, &script); - auto ctx = code->createExecutionContext(&thread); - testing::internal::CaptureStdout(); - code->run(ctx.get()); - ASSERT_EQ(testing::internal::GetCapturedStdout(), expected); -} - -TEST_F(LLVMCodeBuilderTest, ListLoopTypeAnalysis8) -{ - Stage stage; - Sprite sprite; - sprite.setEngine(&m_engine); - EXPECT_CALL(m_engine, stage()).WillRepeatedly(Return(&stage)); - - auto globalList = std::make_shared("", ""); - stage.addList(globalList); - - auto localList = std::make_shared("", ""); - sprite.addList(localList); - - createBuilder(&sprite, true); - - m_builder->createListClear(localList.get()); - - CompilerValue *v = m_builder->addConstValue(5.25); - m_builder->createListAppend(localList.get(), v); - - v = m_builder->addConstValue(2); - m_builder->beginRepeatLoop(v); - { - // Type is unknown here because a list item with a unknown type is assigned later - v = m_builder->addConstValue(0); - v = m_builder->addListItem(localList.get(), v); - m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v }); - - v = m_builder->addListItemIndex(localList.get(), m_builder->addConstValue(5.25)); - m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v }); - - v = m_builder->addListContains(localList.get(), m_builder->addConstValue(5.25)); - m_builder->addFunctionCall("test_print_bool", Compiler::StaticType::Void, { Compiler::StaticType::Bool }, { v }); - - v = m_builder->addConstValue(2); - m_builder->beginRepeatLoop(v); - { - v = m_builder->addConstValue("test"); - m_builder->createListInsert(globalList.get(), m_builder->addConstValue(0), v); - - v = m_builder->addListItem(globalList.get(), m_builder->addConstValue(0)); - m_builder->createListReplace(localList.get(), m_builder->addConstValue(0), v); - } - m_builder->endLoop(); - } - m_builder->endLoop(); - - std::string expected = - "5.25\n" - "0\n" - "1\n" - "0\n" - "-1\n" - "0\n"; - - auto code = m_builder->finalize(); - Script script(&sprite, nullptr, nullptr); - script.setCode(code); - Thread thread(&sprite, nullptr, &script); - auto ctx = code->createExecutionContext(&thread); - testing::internal::CaptureStdout(); - code->run(ctx.get()); - ASSERT_EQ(testing::internal::GetCapturedStdout(), expected); -} - -TEST_F(LLVMCodeBuilderTest, ListLoopTypeAnalysis9) -{ - Stage stage; - Sprite sprite; - sprite.setEngine(&m_engine); - EXPECT_CALL(m_engine, stage()).WillRepeatedly(Return(&stage)); - - auto globalList = std::make_shared("", ""); - stage.addList(globalList); - - auto localList = std::make_shared("", ""); - sprite.addList(localList); - - createBuilder(&sprite, true); - - m_builder->createListClear(localList.get()); - - CompilerValue *v = m_builder->addConstValue(5.25); - m_builder->createListAppend(localList.get(), v); - - v = m_builder->addConstValue(2); - m_builder->beginRepeatLoop(v); - { - v = m_builder->addConstValue(2); - m_builder->beginRepeatLoop(v); - { - v = m_builder->addListItem(globalList.get(), m_builder->addConstValue(0)); - m_builder->createListReplace(localList.get(), m_builder->addConstValue(0), v); - - v = m_builder->addConstValue(5); - m_builder->createListInsert(globalList.get(), m_builder->addConstValue(0), v); - } - m_builder->endLoop(); - - // Type is unknown here because a list item with unknown type is assigned before the read operation - v = m_builder->addListItem(localList.get(), m_builder->addConstValue(0)); - m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v }); - - v = m_builder->addListItemIndex(localList.get(), m_builder->addConstValue(5)); - m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v }); - - v = m_builder->addListContains(localList.get(), m_builder->addConstValue(5)); - m_builder->addFunctionCall("test_print_bool", Compiler::StaticType::Void, { Compiler::StaticType::Bool }, { v }); - - v = m_builder->addConstValue(2); - m_builder->beginRepeatLoop(v); - { - v = m_builder->addConstValue(10); - m_builder->createListInsert(globalList.get(), m_builder->addConstValue(0), v); - - v = m_builder->addListItem(globalList.get(), m_builder->addConstValue(0)); - m_builder->createListReplace(localList.get(), m_builder->addConstValue(0), v); - - v = m_builder->addConstValue("test"); - m_builder->createListInsert(globalList.get(), m_builder->addConstValue(0), v); - } - m_builder->endLoop(); - } - m_builder->endLoop(); - - std::string expected = - "5\n" - "0\n" - "1\n" - "5\n" - "0\n" - "1\n"; - - auto code = m_builder->finalize(); - Script script(&sprite, nullptr, nullptr); - script.setCode(code); - Thread thread(&sprite, nullptr, &script); - auto ctx = code->createExecutionContext(&thread); - testing::internal::CaptureStdout(); - code->run(ctx.get()); - ASSERT_EQ(testing::internal::GetCapturedStdout(), expected); -} - -TEST_F(LLVMCodeBuilderTest, ListLoopTypeAnalysis10) -{ - Stage stage; - Sprite sprite; - sprite.setEngine(&m_engine); - EXPECT_CALL(m_engine, stage()).WillRepeatedly(Return(&stage)); - - auto globalList = std::make_shared("", ""); - stage.addList(globalList); - - auto localList = std::make_shared("", ""); - sprite.addList(localList); - localList->append(123); - - createBuilder(&sprite, true); - - CompilerValue *v = m_builder->addConstValue(2); - m_builder->beginRepeatLoop(v); - { - v = m_builder->addConstValue("test"); - m_builder->createListAppend(globalList.get(), v); - - v = m_builder->addConstValue(3); - m_builder->beginRepeatLoop(v); - { - // Type is unknown here because a list item with unknown type is assigned later - v = m_builder->addListItem(localList.get(), m_builder->addConstValue(0)); - m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v }); - - v = m_builder->addListItemIndex(localList.get(), m_builder->addConstValue(123)); - m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v }); - - v = m_builder->addListContains(localList.get(), m_builder->addConstValue(123)); - m_builder->addFunctionCall("test_print_bool", Compiler::StaticType::Void, { Compiler::StaticType::Bool }, { v }); - - v = m_builder->addListItem(globalList.get(), m_builder->addConstValue(0)); - m_builder->createListReplace(localList.get(), m_builder->addConstValue(0), v); - - v = m_builder->addConstValue(12.5); - m_builder->createListReplace(globalList.get(), m_builder->addConstValue(0), v); - } - m_builder->endLoop(); - } - m_builder->endLoop(); - - std::string expected = - "123\n" - "0\n" - "1\n" - "0\n" - "-1\n" - "0\n" - "12.5\n" - "-1\n" - "0\n" - "12.5\n" - "-1\n" - "0\n" - "12.5\n" - "-1\n" - "0\n" - "12.5\n" - "-1\n" - "0\n"; - - auto code = m_builder->finalize(); - Script script(&sprite, nullptr, nullptr); - script.setCode(code); - Thread thread(&sprite, nullptr, &script); - auto ctx = code->createExecutionContext(&thread); - testing::internal::CaptureStdout(); - code->run(ctx.get()); - ASSERT_EQ(testing::internal::GetCapturedStdout(), expected); -} - -TEST_F(LLVMCodeBuilderTest, ListLoopTypeAnalysis11) -{ - Stage stage; - Sprite sprite; - sprite.setEngine(&m_engine); - EXPECT_CALL(m_engine, stage()).WillRepeatedly(Return(&stage)); - - auto globalList = std::make_shared("", ""); - stage.addList(globalList); - - auto localList = std::make_shared("", ""); - sprite.addList(localList); - localList->append(123); - localList->append("10"); - - createBuilder(&sprite, true); - - CompilerValue *v = m_builder->addConstValue(2); - m_builder->beginRepeatLoop(v); - { - v = m_builder->addConstValue("test"); - m_builder->createListAppend(globalList.get(), v); - - v = m_builder->addConstValue(3); - m_builder->beginRepeatLoop(v); - { - // Type is unknown here because an item from the same list is assigned later, but the list has unknown type - v = m_builder->addListItem(localList.get(), m_builder->addConstValue(0)); - m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v }); - - v = m_builder->addListItemIndex(localList.get(), m_builder->addConstValue(123)); - m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v }); - - v = m_builder->addListContains(localList.get(), m_builder->addConstValue(123)); - m_builder->addFunctionCall("test_print_bool", Compiler::StaticType::Void, { Compiler::StaticType::Bool }, { v }); - - v = m_builder->addListItem(localList.get(), m_builder->addConstValue(1)); - m_builder->createListReplace(localList.get(), m_builder->addConstValue(0), v); - - v = m_builder->addConstValue(12.5); - m_builder->createListReplace(globalList.get(), m_builder->addConstValue(0), v); - } - m_builder->endLoop(); - } - m_builder->endLoop(); - - std::string expected = - "123\n" - "0\n" - "1\n" - "10\n" - "-1\n" - "0\n" - "10\n" - "-1\n" - "0\n" - "10\n" - "-1\n" - "0\n" - "10\n" - "-1\n" - "0\n" - "10\n" - "-1\n" - "0\n"; - - auto code = m_builder->finalize(); - Script script(&sprite, nullptr, nullptr); - script.setCode(code); - Thread thread(&sprite, nullptr, &script); - auto ctx = code->createExecutionContext(&thread); - testing::internal::CaptureStdout(); - code->run(ctx.get()); - ASSERT_EQ(testing::internal::GetCapturedStdout(), expected); -} - -TEST_F(LLVMCodeBuilderTest, ListLoopTypeAnalysis12) -{ - Stage stage; - Sprite sprite; - sprite.setEngine(&m_engine); - EXPECT_CALL(m_engine, stage()).WillRepeatedly(Return(&stage)); - - auto globalList = std::make_shared("", ""); - stage.addList(globalList); - - auto localList = std::make_shared("", ""); - sprite.addList(localList); - localList->append(123); - - createBuilder(&sprite, true); - - CompilerValue *v = m_builder->addConstValue(2); - m_builder->beginRepeatLoop(v); - { - v = m_builder->addConstValue("test"); - m_builder->createListAppend(globalList.get(), v); - - v = m_builder->addConstValue(3); - m_builder->beginRepeatLoop(v); - { - // Type is unknown here because an item from another list is assigned later, but it has an item from this list assigned - // This case is not checked because the code isn't considered valid - v = m_builder->addListItem(localList.get(), m_builder->addConstValue(0)); - m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v }); - - v = m_builder->addListItemIndex(localList.get(), m_builder->addConstValue(123)); - m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v }); - - v = m_builder->addListContains(localList.get(), m_builder->addConstValue(123)); - m_builder->addFunctionCall("test_print_bool", Compiler::StaticType::Void, { Compiler::StaticType::Bool }, { v }); - - v = m_builder->addListItem(globalList.get(), m_builder->addConstValue(0)); - m_builder->createListReplace(localList.get(), m_builder->addConstValue(0), v); - - v = m_builder->addListItem(localList.get(), m_builder->addConstValue(0)); - m_builder->createListReplace(globalList.get(), m_builder->addConstValue(0), v); - } - m_builder->endLoop(); - } - m_builder->endLoop(); - - std::string expected = - "123\n" - "0\n" - "1\n" - "0\n" - "-1\n" - "0\n" - "0\n" - "-1\n" - "0\n" - "0\n" - "-1\n" - "0\n" - "0\n" - "-1\n" - "0\n" - "0\n" - "-1\n" - "0\n"; - - auto code = m_builder->finalize(); - Script script(&sprite, nullptr, nullptr); - script.setCode(code); - Thread thread(&sprite, nullptr, &script); - auto ctx = code->createExecutionContext(&thread); - testing::internal::CaptureStdout(); - code->run(ctx.get()); - ASSERT_EQ(testing::internal::GetCapturedStdout(), expected); -} - -TEST_F(LLVMCodeBuilderTest, VarAndListLoopTypeAnalysis) -{ - Stage stage; - Sprite sprite; - sprite.setEngine(&m_engine); - EXPECT_CALL(m_engine, stage()).WillRepeatedly(Return(&stage)); - - auto var = std::make_shared("", ""); - sprite.addVariable(var); - - auto list = std::make_shared("", ""); - sprite.addList(list); - - createBuilder(&sprite, true); - - CompilerValue *v = m_builder->addConstValue(-2); - m_builder->createVariableWrite(var.get(), v); - - m_builder->createListClear(list.get()); - - v = m_builder->addConstValue(5.25); - m_builder->createListAppend(list.get(), v); - - v = m_builder->addConstValue(3); - m_builder->beginRepeatLoop(v); - { - // Type is unknown here because a variable value with unknown type is added later - v = m_builder->createSub(m_builder->addListSize(list.get()), m_builder->addConstValue(1)); - v = m_builder->addListItem(list.get(), v); - m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v }); - - v = m_builder->addListItemIndex(list.get(), m_builder->addConstValue(5.25)); - m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v }); - - v = m_builder->addListContains(list.get(), m_builder->addConstValue(5.25)); - m_builder->addFunctionCall("test_print_bool", Compiler::StaticType::Void, { Compiler::StaticType::Bool }, { v }); - - v = m_builder->addVariableValue(var.get()); - m_builder->createListAppend(list.get(), v); - - v = m_builder->addConstValue("test"); - m_builder->createVariableWrite(var.get(), v); - } - m_builder->endLoop(); - - std::string expected = - "5.25\n" - "0\n" - "1\n" - "-2\n" - "0\n" "1\n" "0\n" "0\n" From 846b5f8a0a69754eeb9e6f4e24d0ee5e27e3ece4 Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Fri, 1 Aug 2025 17:23:08 +0200 Subject: [PATCH 49/79] Revert "Comment out stop all test" This reverts commit 8f183a2a364dd39df81f87b6bc1f50fd5c56afe1. --- test/engine/engine_test.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/engine/engine_test.cpp b/test/engine/engine_test.cpp index c14fb6d48..c1dab56d7 100644 --- a/test/engine/engine_test.cpp +++ b/test/engine/engine_test.cpp @@ -1863,7 +1863,7 @@ TEST(EngineTest, BroadcastsProject) ASSERT_EQ(GET_VAR(stage, "test5")->value().toString(), "2 2 0 0"); }*/ -/*TEST(EngineTest, StopAll) +TEST(EngineTest, StopAll) { Project p("stop_all.sb3"); ASSERT_TRUE(p.load()); @@ -1877,7 +1877,7 @@ TEST(EngineTest, BroadcastsProject) ASSERT_VAR(stage, "i"); ASSERT_EQ(GET_VAR(stage, "i")->value().toInt(), 11); ASSERT_FALSE(engine->isRunning()); -}*/ +} TEST(EngineTest, StopAllBypass) { From 83f3aa571e86a1cf3e4c84c681e2ea18e3042618 Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Fri, 1 Aug 2025 17:32:39 +0200 Subject: [PATCH 50/79] Uncomment more engine test cases --- test/engine/engine_test.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/test/engine/engine_test.cpp b/test/engine/engine_test.cpp index c1dab56d7..bb5e963ec 100644 --- a/test/engine/engine_test.cpp +++ b/test/engine/engine_test.cpp @@ -396,7 +396,7 @@ TEST(EngineTest, Fps) ASSERT_EQ(engine.fps(), 250); } -/*TEST(EngineTest, FpsProject) +TEST(EngineTest, FpsProject) { Project p("2_frames.sb3"); ASSERT_TRUE(p.load()); @@ -466,7 +466,7 @@ TEST(EngineTest, Fps) EXPECT_CALL(clock, sleep).Times(0); EXPECT_CALL(redrawMock, redraw()); p.run(); -}*/ +} TEST(EngineTest, TurboModeEnabled) { @@ -480,7 +480,7 @@ TEST(EngineTest, TurboModeEnabled) ASSERT_FALSE(engine.turboModeEnabled()); } -/*TEST(EngineTest, ExecutionOrder) +TEST(EngineTest, ExecutionOrder) { Project p("execution_order.sb3"); ASSERT_TRUE(p.load()); @@ -509,7 +509,7 @@ TEST(EngineTest, TurboModeEnabled) ASSERT_EQ(Value((*list)[10]).toString(), "Sprite1 2 msg"); ASSERT_EQ(Value((*list)[11]).toString(), "Sprite1 3 msg"); ASSERT_EQ(Value((*list)[12]).toString(), "Stage msg"); -}*/ +} TEST(EngineTest, KeyState) { @@ -1745,7 +1745,7 @@ void questionFunction(const std::string &) else ASSERT_EQ(Value((*list)[i]).toString(), "12"); } -} +}*/ TEST(EngineTest, CloneLimit) { @@ -1861,7 +1861,7 @@ TEST(EngineTest, BroadcastsProject) ASSERT_EQ(GET_VAR(stage, "test4")->value().toInt(), 10); ASSERT_VAR(stage, "test5"); ASSERT_EQ(GET_VAR(stage, "test5")->value().toString(), "2 2 0 0"); -}*/ +} TEST(EngineTest, StopAll) { @@ -2064,7 +2064,7 @@ TEST(EngineTest, NoRefreshWhenCallingRunningBroadcast) ASSERT_TRUE(GET_VAR(stage, "passed2")->value().toBool()); } -/*TEST(EngineTest, NoStopWhenCallingRunningBroadcastFromCustomBlock) +TEST(EngineTest, NoStopWhenCallingRunningBroadcastFromCustomBlock) { // Regtest for #257 Project p("regtest_projects/277_custom_block_call_running_broadcast_stop.sb3"); @@ -2081,7 +2081,7 @@ TEST(EngineTest, NoRefreshWhenCallingRunningBroadcast) ASSERT_VAR(stage, "passed2"); ASSERT_TRUE(GET_VAR(stage, "passed2")->value().toBool()); -}*/ +} TEST(EngineTest, ResetRunningHats) { From 096036f9420942d08cb9be476eb053c4e6f69ce3 Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Sat, 2 Aug 2025 18:21:17 +0200 Subject: [PATCH 51/79] LLVMCodeBuilder: Create a global resume function in LLVMCompilerContext The previous logic was incorrect because the resume function was resolved using getOrCreateFunction() and then filled with code, even if it existed. Since it's global and can be used in the entire LLVM module, create it in LLVMCompilerContext. --- src/engine/internal/llvm/llvmcodebuilder.cpp | 28 +------------ src/engine/internal/llvm/llvmcodebuilder.h | 2 - .../internal/llvm/llvmcompilercontext.cpp | 39 +++++++++++++++++-- .../internal/llvm/llvmcompilercontext.h | 10 ++++- src/engine/internal/llvm/llvmcoroutine.cpp | 34 ++++++++-------- src/engine/internal/llvm/llvmcoroutine.h | 2 +- 6 files changed, 64 insertions(+), 51 deletions(-) diff --git a/src/engine/internal/llvm/llvmcodebuilder.cpp b/src/engine/internal/llvm/llvmcodebuilder.cpp index 12043512d..afb0151be 100644 --- a/src/engine/internal/llvm/llvmcodebuilder.cpp +++ b/src/engine/internal/llvm/llvmcodebuilder.cpp @@ -1268,8 +1268,7 @@ std::shared_ptr LLVMCodeBuilder::finalize() m_builder.SetInsertPoint(suspendBranch); createSuspend(coro.get(), warpArg, targetVariables); - name = getResumeFunctionName(step.procedurePrototype); - llvm::Value *done = m_builder.CreateCall(resolveFunction(name, m_resumeFuncType), { handle }); + llvm::Value *done = m_builder.CreateCall(m_ctx->coroutineResumeFunction(), { handle }); m_builder.CreateCondBr(done, nextBranch, suspendBranch); m_builder.SetInsertPoint(nextBranch); @@ -1329,24 +1328,7 @@ std::shared_ptr LLVMCodeBuilder::finalize() verifyFunction(m_function); - // Create resume function - // bool resume(void *) - funcName = getResumeFunctionName(m_procedurePrototype); - llvm::Function *resumeFunc = getOrCreateFunction(funcName, m_resumeFuncType); - resumeFunc->addFnAttr(llvm::Attribute::NoInline); - resumeFunc->addFnAttr(llvm::Attribute::OptimizeNone); - - entry = llvm::BasicBlock::Create(m_llvmCtx, "entry", resumeFunc); - m_builder.SetInsertPoint(entry); - - if (m_warp) - m_builder.CreateRet(m_builder.getInt1(true)); - else - m_builder.CreateRet(coro->createResume(resumeFunc, resumeFunc->getArg(0))); - - verifyFunction(resumeFunc); - - return std::make_shared(m_ctx, m_function->getName().str(), resumeFunc->getName().str(), m_codeType); + return std::make_shared(m_ctx, m_function->getName().str(), m_ctx->coroutineResumeFunction()->getName().str(), m_codeType); } CompilerValue *LLVMCodeBuilder::addFunctionCall(const std::string &functionName, Compiler::StaticType returnType, const Compiler::ArgTypes &argTypes, const Compiler::Args &args) @@ -1890,7 +1872,6 @@ void LLVMCodeBuilder::initTypes() llvm::PointerType *pointerType = llvm::PointerType::get(llvm::Type::getInt8Ty(m_llvmCtx), 0); m_valueDataType = LLVMTypes::createValueDataType(&m_builder); m_stringPtrType = LLVMTypes::createStringPtrType(&m_builder); - m_resumeFuncType = llvm::FunctionType::get(m_builder.getInt1Ty(), pointerType, false); } void LLVMCodeBuilder::createVariableMap() @@ -2015,11 +1996,6 @@ std::string LLVMCodeBuilder::getMainFunctionName(BlockPrototype *procedureProtot return procedurePrototype ? "proc." + procedurePrototype->procCode() : name; } -std::string LLVMCodeBuilder::getResumeFunctionName(BlockPrototype *procedurePrototype) -{ - return procedurePrototype ? "resume.proc." + procedurePrototype->procCode() : "resume.script"; -} - llvm::FunctionType *LLVMCodeBuilder::getMainFunctionType(BlockPrototype *procedurePrototype) { // void *f(ExecutionContext *, Target *, ValueData **, List **, (warp arg), (procedure args...)) diff --git a/src/engine/internal/llvm/llvmcodebuilder.h b/src/engine/internal/llvm/llvmcodebuilder.h index 2ddd8e98f..8fc7a3c5e 100644 --- a/src/engine/internal/llvm/llvmcodebuilder.h +++ b/src/engine/internal/llvm/llvmcodebuilder.h @@ -130,7 +130,6 @@ class LLVMCodeBuilder : public ICodeBuilder void popLoopScope(); std::string getMainFunctionName(BlockPrototype *procedurePrototype); - std::string getResumeFunctionName(BlockPrototype *procedurePrototype); llvm::FunctionType *getMainFunctionType(BlockPrototype *procedurePrototype); llvm::Function *getOrCreateFunction(const std::string &name, llvm::FunctionType *type); void verifyFunction(llvm::Function *func); @@ -230,7 +229,6 @@ class LLVMCodeBuilder : public ICodeBuilder llvm::StructType *m_valueDataType = nullptr; llvm::StructType *m_stringPtrType = nullptr; - llvm::FunctionType *m_resumeFuncType = nullptr; LLVMInstructionList m_instructions; std::vector> m_regs; diff --git a/src/engine/internal/llvm/llvmcompilercontext.cpp b/src/engine/internal/llvm/llvmcompilercontext.cpp index 74199aa1d..78fc85a3c 100644 --- a/src/engine/internal/llvm/llvmcompilercontext.cpp +++ b/src/engine/internal/llvm/llvmcompilercontext.cpp @@ -8,6 +8,7 @@ #include #include "llvmcompilercontext.h" +#include "llvmcoroutine.h" using namespace libscratchcpp; @@ -18,6 +19,7 @@ LLVMCompilerContext::LLVMCompilerContext(IEngine *engine, Target *target) : m_llvmCtxPtr(m_llvmCtx.get()), m_modulePtr(m_module.get()), m_jit((initTarget(), llvm::orc::LLJITBuilder().create())), + m_llvmCoroResumeFunction(createCoroResumeFunction()), m_llvmCoroDestroyFunction(createCoroDestroyFunction()) { if (!m_jit) { @@ -111,6 +113,11 @@ bool LLVMCompilerContext::jitInitialized() const return m_jitInitialized; } +llvm::Function *LLVMCompilerContext::coroutineResumeFunction() const +{ + return m_llvmCoroResumeFunction; +} + void LLVMCompilerContext::destroyCoroutine(void *handle) { if (!m_jitInitialized) { @@ -129,6 +136,26 @@ void LLVMCompilerContext::initTarget() llvm::InitializeNativeTargetAsmParser(); } +llvm::Function *LLVMCompilerContext::createCoroResumeFunction() +{ + llvm::IRBuilder<> builder(*m_llvmCtx); + + // bool coro_resume(void *handle) + llvm::FunctionType *funcType = llvm::FunctionType::get(builder.getInt1Ty(), builder.getVoidTy()->getPointerTo(), false); + llvm::Function *func = llvm::Function::Create(funcType, llvm::Function::ExternalLinkage, "coro_resume", m_module.get()); + func->setComdat(m_module->getOrInsertComdat(func->getName())); + func->setDSOLocal(true); + func->addFnAttr(llvm::Attribute::NoInline); + func->addFnAttr(llvm::Attribute::OptimizeNone); + + llvm::BasicBlock *entry = llvm::BasicBlock::Create(*m_llvmCtx, "entry", func); + builder.SetInsertPoint(entry); + builder.CreateRet(LLVMCoroutine::createResume(m_module.get(), &builder, func, func->getArg(0))); + + verifyFunction(func); + return func; +} + llvm::Function *LLVMCompilerContext::createCoroDestroyFunction() { llvm::IRBuilder<> builder(*m_llvmCtx); @@ -146,10 +173,14 @@ llvm::Function *LLVMCompilerContext::createCoroDestroyFunction() builder.CreateCall(llvm::Intrinsic::getDeclaration(m_module.get(), llvm::Intrinsic::coro_destroy), { func->getArg(0) }); builder.CreateRetVoid(); - if (llvm::verifyFunction(*func, &llvm::errs())) { - llvm::errs() << "error: coro_destroy() function verficiation failed!\n"; + verifyFunction(func); + return func; +} + +void LLVMCompilerContext::verifyFunction(llvm::Function *function) +{ + if (llvm::verifyFunction(*function, &llvm::errs())) { + llvm::errs() << "error: " << function->getName() << "function verficiation failed!\n"; llvm::errs() << "module name: " << m_module->getName() << "\n"; } - - return func; } diff --git a/src/engine/internal/llvm/llvmcompilercontext.h b/src/engine/internal/llvm/llvmcompilercontext.h index 27878ffe4..21ae681ab 100644 --- a/src/engine/internal/llvm/llvmcompilercontext.h +++ b/src/engine/internal/llvm/llvmcompilercontext.h @@ -28,6 +28,7 @@ class LLVMCompilerContext : public CompilerContext void initJit(); bool jitInitialized() const; + llvm::Function *coroutineResumeFunction() const; void destroyCoroutine(void *handle); template @@ -44,19 +45,26 @@ class LLVMCompilerContext : public CompilerContext } private: + using ResumeCoroFuncType = bool (*)(void *); using DestroyCoroFuncType = void (*)(void *); void initTarget(); + llvm::Function *createCoroResumeFunction(); llvm::Function *createCoroDestroyFunction(); + void verifyFunction(llvm::Function *function); + std::unique_ptr m_llvmCtx; std::unique_ptr m_module; llvm::LLVMContext *m_llvmCtxPtr = nullptr; llvm::Module *m_modulePtr = nullptr; llvm::Expected> m_jit; + bool m_jitInitialized = false; + + llvm::Function *m_llvmCoroResumeFunction = nullptr; + llvm::Function *m_llvmCoroDestroyFunction = nullptr; DestroyCoroFuncType m_coroDestroyFunction = nullptr; - bool m_jitInitialized = false; }; } // namespace libscratchcpp diff --git a/src/engine/internal/llvm/llvmcoroutine.cpp b/src/engine/internal/llvm/llvmcoroutine.cpp index 97baff396..f4b268fbe 100644 --- a/src/engine/internal/llvm/llvmcoroutine.cpp +++ b/src/engine/internal/llvm/llvmcoroutine.cpp @@ -105,32 +105,32 @@ void LLVMCoroutine::createSuspend() m_builder->SetInsertPoint(resumeBranch); } -llvm::Value *LLVMCoroutine::createResume(llvm::Function *function, llvm::Value *coroHandle) +llvm::Value *LLVMCoroutine::createResume(llvm::Module *module, llvm::IRBuilder<> *builder, llvm::Function *function, llvm::Value *coroHandle) { - llvm::LLVMContext &ctx = m_builder->getContext(); - llvm::Function *coroDone = llvm::Intrinsic::getDeclaration(m_module, llvm::Intrinsic::coro_done); + llvm::LLVMContext &ctx = builder->getContext(); + llvm::Function *coroDone = llvm::Intrinsic::getDeclaration(module, llvm::Intrinsic::coro_done); - llvm::Value *ret = m_builder->CreateAlloca(m_builder->getInt1Ty()); - llvm::Value *done = m_builder->CreateCall(coroDone, { coroHandle }); - done = m_builder->CreateCall(coroDone, { coroHandle }); + llvm::Value *ret = builder->CreateAlloca(builder->getInt1Ty()); + llvm::Value *done = builder->CreateCall(coroDone, { coroHandle }); + done = builder->CreateCall(coroDone, { coroHandle }); llvm::BasicBlock *destroyBranch = llvm::BasicBlock::Create(ctx, "", function); llvm::BasicBlock *resumeBranch = llvm::BasicBlock::Create(ctx, "", function); llvm::BasicBlock *nextBranch = llvm::BasicBlock::Create(ctx, "", function); - m_builder->CreateCondBr(done, destroyBranch, resumeBranch); + builder->CreateCondBr(done, destroyBranch, resumeBranch); - m_builder->SetInsertPoint(destroyBranch); - m_builder->CreateCall(llvm::Intrinsic::getDeclaration(m_module, llvm::Intrinsic::coro_destroy), { coroHandle }); - m_builder->CreateBr(nextBranch); + builder->SetInsertPoint(destroyBranch); + builder->CreateCall(llvm::Intrinsic::getDeclaration(module, llvm::Intrinsic::coro_destroy), { coroHandle }); + builder->CreateBr(nextBranch); - m_builder->SetInsertPoint(resumeBranch); - m_builder->CreateCall(llvm::Intrinsic::getDeclaration(m_module, llvm::Intrinsic::coro_resume), { coroHandle }); - done = m_builder->CreateCall(coroDone, { coroHandle }); - m_builder->CreateStore(done, ret); - m_builder->CreateCondBr(done, destroyBranch, nextBranch); + builder->SetInsertPoint(resumeBranch); + builder->CreateCall(llvm::Intrinsic::getDeclaration(module, llvm::Intrinsic::coro_resume), { coroHandle }); + done = builder->CreateCall(coroDone, { coroHandle }); + builder->CreateStore(done, ret); + builder->CreateCondBr(done, destroyBranch, nextBranch); - m_builder->SetInsertPoint(nextBranch); - return m_builder->CreateLoad(m_builder->getInt1Ty(), ret); + builder->SetInsertPoint(nextBranch); + return builder->CreateLoad(builder->getInt1Ty(), ret); } void LLVMCoroutine::end() diff --git a/src/engine/internal/llvm/llvmcoroutine.h b/src/engine/internal/llvm/llvmcoroutine.h index 071798d93..fa3d79fd9 100644 --- a/src/engine/internal/llvm/llvmcoroutine.h +++ b/src/engine/internal/llvm/llvmcoroutine.h @@ -22,7 +22,7 @@ class LLVMCoroutine llvm::Value *didSuspendVar() const; void createSuspend(); - llvm::Value *createResume(llvm::Function *function, llvm::Value *coroHandle); + static llvm::Value *createResume(llvm::Module *module, llvm::IRBuilder<> *builder, llvm::Function *function, llvm::Value *coroHandle); void end(); private: From cdba36717f8963c54cca6602a346f84a9dbed9c3 Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Sat, 2 Aug 2025 18:21:48 +0200 Subject: [PATCH 52/79] Uncomment Clones test case --- test/engine/engine_test.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/engine/engine_test.cpp b/test/engine/engine_test.cpp index bb5e963ec..db9f54b79 100644 --- a/test/engine/engine_test.cpp +++ b/test/engine/engine_test.cpp @@ -1702,7 +1702,7 @@ void questionFunction(const std::string &) { } -/*TEST(EngineTest, Clones) +TEST(EngineTest, Clones) { Project p("clones.sb3"); ASSERT_TRUE(p.load()); @@ -1745,7 +1745,7 @@ void questionFunction(const std::string &) else ASSERT_EQ(Value((*list)[i]).toString(), "12"); } -}*/ +} TEST(EngineTest, CloneLimit) { From 8746ca813b3eced0fd50c3e4de87f372777298bc Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Sat, 2 Aug 2025 19:16:51 +0200 Subject: [PATCH 53/79] Engine: Properly handle broadcasts with the same name but different case --- src/engine/internal/engine.cpp | 43 ++++++++++++++++------------------ 1 file changed, 20 insertions(+), 23 deletions(-) diff --git a/src/engine/internal/engine.cpp b/src/engine/internal/engine.cpp index 98612f577..ac446a560 100644 --- a/src/engine/internal/engine.cpp +++ b/src/engine/internal/engine.cpp @@ -528,8 +528,8 @@ void Engine::step() m_frameActivity = !m_threads.empty(); // Resolve stopped broadcast scripts - std::vector resolved; - std::vector resolvedThreads; + std::unordered_map stoppedBroadcasts; // sender thread + std::unordered_map runningStatus; // sender thread for (const auto &[broadcast, senderThread] : m_broadcastSenders) { std::unordered_map> *broadcastMap = nullptr; @@ -544,44 +544,41 @@ void Engine::step() broadcastMap = &m_broadcastMap; } - bool found = false; + bool isRunning = false; if (broadcastMap->find(broadcast) != broadcastMap->cend()) { const auto &scripts = (*broadcastMap)[broadcast]; for (auto script : scripts) { if (std::find_if(m_threads.begin(), m_threads.end(), [script](std::shared_ptr thread) { return thread->script() == script; }) != m_threads.end()) { - found = true; + isRunning = true; break; } } } - if (found) { - // If a broadcast with the same name but different case - // was considered stopped before, restore the promise. - if (std::find(resolvedThreads.begin(), resolvedThreads.end(), senderThread) != resolvedThreads.end()) { - senderThread->promise(); - resolvedThreads.erase(std::remove(resolvedThreads.begin(), resolvedThreads.end(), senderThread), resolvedThreads.end()); - } - } else { - Thread *th = senderThread; + if (runningStatus.find(senderThread) == runningStatus.cend() || isRunning) + runningStatus[senderThread] = isRunning; - if (std::find_if(m_threads.begin(), m_threads.end(), [th](std::shared_ptr thread) { return thread.get() == th; }) != m_threads.end()) { - auto promise = th->promise(); + if (!isRunning) + stoppedBroadcasts[broadcast] = senderThread; + } - if (promise) - promise->resolve(); - } + for (const auto &[broadcast, senderThread] : stoppedBroadcasts) { + m_broadcastSenders.erase(broadcast); - resolved.push_back(broadcast); - resolvedThreads.push_back(th); + // Resolve broadcast promise + Thread *th = senderThread; + + if (std::find_if(m_threads.begin(), m_threads.end(), [th](std::shared_ptr thread) { return thread.get() == th; }) != m_threads.end()) { + auto promise = th->promise().get(); + + // Resolve only if all broadcasts of the same name but different case are stopped + if (promise && !runningStatus[senderThread]) + promise->resolve(); } } - for (Broadcast *broadcast : resolved) - m_broadcastSenders.erase(broadcast); - m_redrawRequested = false; // Step threads From 42bd6a878f9d67cf0994a93663ca4a3450052964 Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Sat, 2 Aug 2025 19:17:08 +0200 Subject: [PATCH 54/79] Uncomment all engine bug tests --- test/engine/engine_test.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/engine/engine_test.cpp b/test/engine/engine_test.cpp index db9f54b79..cf79f5949 100644 --- a/test/engine/engine_test.cpp +++ b/test/engine/engine_test.cpp @@ -2238,7 +2238,7 @@ TEST(EngineTest, DuplicateVariableOrListIDs) ASSERT_TRUE(GET_VAR(stage, "passed")->value().toBool()); } -/*TEST(EngineTest, BroadcastStopsWaitBlocks) +TEST(EngineTest, BroadcastStopsWaitBlocks) { // Regtest for #563 Project p("regtest_projects/563_broadcast_stops_wait_blocks.sb3"); @@ -2272,4 +2272,4 @@ TEST(EngineTest, BroadcastAndWaitCaseInsensitive) ASSERT_VAR(stage, "passed"); ASSERT_TRUE(GET_VAR(stage, "passed")->value().toBool()); -}*/ +} From 9b7ae5a37dc15c79da51a6ff209758aad6e2b3c5 Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Sun, 3 Aug 2025 10:12:56 +0200 Subject: [PATCH 55/79] Store raw data pointer in List --- include/scratchcpp/list.h | 11 ++++++++++- src/scratch/list_functions.cpp | 5 +++++ src/scratch/list_functions.h | 1 + test/scratch_classes/list_functions_test.cpp | 13 +++++++++++++ test/scratch_classes/list_test.cpp | 17 +++++++++++++++++ 5 files changed, 46 insertions(+), 1 deletion(-) diff --git a/include/scratchcpp/list.h b/include/scratchcpp/list.h index 9d5e4b686..47c6782c2 100644 --- a/include/scratchcpp/list.h +++ b/include/scratchcpp/list.h @@ -41,7 +41,13 @@ class LIBSCRATCHCPP_EXPORT List : public Entity void setMonitor(Monitor *monitor); /*! Returns a pointer to the raw list data. */ - inline ValueData *data() const { return m_dataPtr->data(); } + inline ValueData *data() const { return m_rawDataPtr; } + + /*! + * Returns a pointer to pointer to the raw list data. + * \note This is used internally by compiled code for various optimizations. + */ + inline ValueData *const *dataPtr() const { return &m_rawDataPtr; } /*! * Returns a pointer to the list size. @@ -247,6 +253,8 @@ class LIBSCRATCHCPP_EXPORT List : public Entity value_free(&m_dataPtr->back()); m_dataPtr->erase(m_dataPtr->end()); } + + m_rawDataPtr = m_dataPtr->data(); } inline size_t getAllocSize(size_t x) @@ -264,6 +272,7 @@ class LIBSCRATCHCPP_EXPORT List : public Entity spimpl::unique_impl_ptr impl; veque::veque *m_dataPtr = nullptr; // NOTE: accessing through pointer is faster! (from benchmarks) + ValueData *m_rawDataPtr = nullptr; size_t m_size = 0; }; diff --git a/src/scratch/list_functions.cpp b/src/scratch/list_functions.cpp index 948e3e10e..5ef5e681e 100644 --- a/src/scratch/list_functions.cpp +++ b/src/scratch/list_functions.cpp @@ -38,6 +38,11 @@ extern "C" return list->data(); } + ValueData *const *list_data_ptr(List *list) + { + return list->dataPtr(); + } + size_t *list_size_ptr(List *list) { return list->sizePtr(); diff --git a/src/scratch/list_functions.h b/src/scratch/list_functions.h index 7080281c9..f68374194 100644 --- a/src/scratch/list_functions.h +++ b/src/scratch/list_functions.h @@ -21,6 +21,7 @@ extern "C" ValueData *list_get_item(List *list, size_t index); ValueData *list_data(List *list); + ValueData *const *list_data_ptr(List *list); size_t *list_size_ptr(List *list); const size_t *list_alloc_size_ptr(List *list); size_t list_size(List *list); diff --git a/test/scratch_classes/list_functions_test.cpp b/test/scratch_classes/list_functions_test.cpp index 0aeaf48e8..898757b79 100644 --- a/test/scratch_classes/list_functions_test.cpp +++ b/test/scratch_classes/list_functions_test.cpp @@ -100,6 +100,19 @@ TEST(ListFunctionsTest, Data) ASSERT_EQ(data, list.data()); } +TEST(ListFunctionsTest, DataPtr) +{ + List list("", ""); + list.append("Lorem"); + list.append("ipsum"); + list.append("dolor"); + list.append("sit"); + list.append("amet"); + + ValueData *const *dataPtr = list_data_ptr(&list); + ASSERT_EQ(dataPtr, list.dataPtr()); +} + TEST(ListFunctionsTest, SizePtr) { List list("", ""); diff --git a/test/scratch_classes/list_test.cpp b/test/scratch_classes/list_test.cpp index 5aa4d1c23..257b87785 100644 --- a/test/scratch_classes/list_test.cpp +++ b/test/scratch_classes/list_test.cpp @@ -58,6 +58,23 @@ TEST(ListTest, Data) ASSERT_EQ(&data[4], &list[4]); } +TEST(ListTest, DataPtr) +{ + List list("", ""); + list.append("Lorem"); + list.append("ipsum"); + list.append("dolor"); + list.append("sit"); + list.append("amet"); + + ValueData *data = *list.dataPtr(); + ASSERT_EQ(&data[0], &list[0]); + ASSERT_EQ(&data[1], &list[1]); + ASSERT_EQ(&data[2], &list[2]); + ASSERT_EQ(&data[3], &list[3]); + ASSERT_EQ(&data[4], &list[4]); +} + TEST(ListTest, SizePtr) { List list("", "test list"); From fb7ad85dd4dd596c01a8134e7bcd9d5c82082742 Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Sun, 3 Aug 2025 10:24:51 +0200 Subject: [PATCH 56/79] LLVMCodeBuilder: Use pointer to list data pointer Avoid unnecessary function call to list_data(). --- src/engine/internal/llvm/llvmcodebuilder.cpp | 53 ++++---------------- src/engine/internal/llvm/llvmcodebuilder.h | 5 +- src/engine/internal/llvm/llvmlistptr.h | 1 - 3 files changed, 12 insertions(+), 47 deletions(-) diff --git a/src/engine/internal/llvm/llvmcodebuilder.cpp b/src/engine/internal/llvm/llvmcodebuilder.cpp index afb0151be..d6e246dbb 100644 --- a/src/engine/internal/llvm/llvmcodebuilder.cpp +++ b/src/engine/internal/llvm/llvmcodebuilder.cpp @@ -139,14 +139,11 @@ std::shared_ptr LLVMCodeBuilder::finalize() for (auto &[list, listPtr] : m_listPtrs) { listPtr.ptr = getListPtr(targetLists, list); - listPtr.dataPtr = m_builder.CreateAlloca(m_valueDataType->getPointerTo()); - m_builder.CreateStore(m_builder.CreateCall(resolve_list_data(), listPtr.ptr), listPtr.dataPtr); + listPtr.dataPtr = m_builder.CreateAlloca(m_valueDataType->getPointerTo()->getPointerTo()); + m_builder.CreateStore(m_builder.CreateCall(resolve_list_data_ptr(), listPtr.ptr), listPtr.dataPtr); listPtr.sizePtr = m_builder.CreateCall(resolve_list_size_ptr(), listPtr.ptr); listPtr.allocatedSizePtr = m_builder.CreateCall(resolve_list_alloc_size_ptr(), listPtr.ptr); - - listPtr.dataPtrDirty = m_builder.CreateAlloca(m_builder.getInt1Ty()); - m_builder.CreateStore(m_builder.getInt1(false), listPtr.dataPtrDirty); } assert(m_loopScope == -1); @@ -790,13 +787,7 @@ std::shared_ptr LLVMCodeBuilder::finalize() case LLVMInstruction::Type::ClearList: { assert(step.args.size() == 0); LLVMListPtr &listPtr = m_listPtrs[step.workList]; - llvm::Value *oldAllocatedSize = m_builder.CreateLoad(m_builder.getInt64Ty(), listPtr.allocatedSizePtr); m_builder.CreateCall(resolve_list_clear(), listPtr.ptr); - - // Clearing may deallocate, so check if the allocated size changed - llvm::Value *dataPtrDirty = m_builder.CreateLoad(m_builder.getInt1Ty(), listPtr.dataPtrDirty); - llvm::Value *allocatedSize = m_builder.CreateLoad(m_builder.getInt64Ty(), listPtr.allocatedSizePtr); - m_builder.CreateStore(m_builder.CreateOr(dataPtrDirty, m_builder.CreateICmpNE(allocatedSize, oldAllocatedSize)), listPtr.dataPtrDirty); break; } @@ -819,7 +810,6 @@ std::shared_ptr LLVMCodeBuilder::finalize() m_builder.SetInsertPoint(removeBlock); index = m_builder.CreateFPToUI(castValue(arg.second, arg.first), m_builder.getInt64Ty()); m_builder.CreateCall(resolve_list_remove(), { listPtr.ptr, index }); - // NOTE: Removing doesn't deallocate (see List::removeAt()), so there's no need to update the data pointer m_builder.CreateBr(nextBlock); m_builder.SetInsertPoint(nextBlock); @@ -857,7 +847,6 @@ std::shared_ptr LLVMCodeBuilder::finalize() m_builder.SetInsertPoint(elseBlock); itemPtr = m_builder.CreateCall(resolve_list_append_empty(), listPtr.ptr); createReusedValueStore(arg.second, itemPtr, type, listType); - m_builder.CreateStore(m_builder.getInt1(true), listPtr.dataPtrDirty); m_builder.CreateBr(nextBlock); m_builder.SetInsertPoint(nextBlock); @@ -877,8 +866,6 @@ std::shared_ptr LLVMCodeBuilder::finalize() if (m_warp) listType = m_typeAnalyzer.listType(step.workList, &step, Compiler::StaticType::Unknown, false); - llvm::Value *oldAllocatedSize = m_builder.CreateLoad(m_builder.getInt64Ty(), listPtr.allocatedSizePtr); - // Range check llvm::Value *size = m_builder.CreateLoad(m_builder.getInt64Ty(), listPtr.sizePtr); llvm::Value *min = llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(0.0)); @@ -895,11 +882,6 @@ std::shared_ptr LLVMCodeBuilder::finalize() llvm::Value *itemPtr = m_builder.CreateCall(resolve_list_insert_empty(), { listPtr.ptr, index }); createReusedValueStore(valueArg.second, itemPtr, type, listType); - // Check if the allocated size changed - llvm::Value *dataPtrDirty = m_builder.CreateLoad(m_builder.getInt1Ty(), listPtr.dataPtrDirty); - llvm::Value *allocatedSize = m_builder.CreateLoad(m_builder.getInt64Ty(), listPtr.allocatedSizePtr); - m_builder.CreateStore(m_builder.CreateOr(dataPtrDirty, m_builder.CreateICmpNE(allocatedSize, oldAllocatedSize)), listPtr.dataPtrDirty); - m_builder.CreateBr(nextBlock); m_builder.SetInsertPoint(nextBlock); @@ -1275,7 +1257,6 @@ std::shared_ptr LLVMCodeBuilder::finalize() } reloadVariables(targetVariables); - reloadLists(); break; } @@ -2384,6 +2365,11 @@ llvm::Value *LLVMCodeBuilder::getListPtr(llvm::Value *targetLists, List *list) return m_builder.CreateIntToPtr(addr, m_valueDataType->getPointerTo()); } +llvm::Value *LLVMCodeBuilder::getListDataPtr(const LLVMListPtr &listPtr) +{ + return m_builder.CreateLoad(m_valueDataType->getPointerTo(), m_builder.CreateLoad(m_valueDataType->getPointerTo()->getPointerTo(), listPtr.dataPtr)); +} + void LLVMCodeBuilder::syncVariables(llvm::Value *targetVariables) { // Copy stack variables to the actual variables @@ -2404,23 +2390,6 @@ void LLVMCodeBuilder::reloadVariables(llvm::Value *targetVariables) } } -void LLVMCodeBuilder::reloadLists() -{ - // Reset list data dirty - for (auto &[list, listPtr] : m_listPtrs) - m_builder.CreateStore(m_builder.getInt1(true), listPtr.dataPtrDirty); -} - -void LLVMCodeBuilder::updateListDataPtr(const LLVMListPtr &listPtr) -{ - // dataPtr = dirty ? list_data(list) : dataPtr - // dirty = false - llvm::Value *dirty = m_builder.CreateLoad(m_builder.getInt1Ty(), listPtr.dataPtrDirty); - llvm::Value *dataPtr = m_builder.CreateSelect(dirty, m_builder.CreateCall(resolve_list_data(), listPtr.ptr), m_builder.CreateLoad(m_valueDataType->getPointerTo(), listPtr.dataPtr)); - m_builder.CreateStore(dataPtr, listPtr.dataPtr); - m_builder.CreateStore(m_builder.getInt1(false), listPtr.dataPtrDirty); -} - LLVMRegister *LLVMCodeBuilder::createOp(LLVMInstruction::Type type, Compiler::StaticType retType, Compiler::StaticType argType, const Compiler::Args &args) { return createOp({ type, currentLoopScope(), m_loopCondition }, retType, argType, args); @@ -2573,8 +2542,7 @@ void LLVMCodeBuilder::copyStructField(llvm::Value *source, llvm::Value *target, llvm::Value *LLVMCodeBuilder::getListItem(const LLVMListPtr &listPtr, llvm::Value *index) { - updateListDataPtr(listPtr); - return m_builder.CreateGEP(m_valueDataType, m_builder.CreateLoad(m_valueDataType->getPointerTo(), listPtr.dataPtr), index); + return m_builder.CreateGEP(m_valueDataType, getListDataPtr(listPtr), index); } llvm::Value *LLVMCodeBuilder::getListItemIndex(const LLVMListPtr &listPtr, Compiler::StaticType listType, LLVMRegister *item) @@ -2932,7 +2900,6 @@ void LLVMCodeBuilder::createSuspend(LLVMCoroutine *coro, llvm::Value *warpArg, l syncVariables(targetVariables); coro->createSuspend(); reloadVariables(targetVariables); - reloadLists(); if (warpArg) { m_builder.CreateBr(nextBranch); @@ -3090,10 +3057,10 @@ llvm::FunctionCallee LLVMCodeBuilder::resolve_list_insert_empty() return resolveFunction("list_insert_empty", llvm::FunctionType::get(m_valueDataType->getPointerTo(), { listPtr, m_builder.getInt64Ty() }, false)); } -llvm::FunctionCallee LLVMCodeBuilder::resolve_list_data() +llvm::FunctionCallee LLVMCodeBuilder::resolve_list_data_ptr() { llvm::Type *listPtr = llvm::PointerType::get(llvm::Type::getInt8Ty(m_llvmCtx), 0); - llvm::FunctionCallee callee = resolveFunction("list_data", llvm::FunctionType::get(m_valueDataType->getPointerTo(), { listPtr }, false)); + llvm::FunctionCallee callee = resolveFunction("list_data_ptr", llvm::FunctionType::get(m_valueDataType->getPointerTo()->getPointerTo(), { listPtr }, false)); llvm::Function *func = llvm::cast(callee.getCallee()); func->addFnAttr(llvm::Attribute::ReadOnly); return callee; diff --git a/src/engine/internal/llvm/llvmcodebuilder.h b/src/engine/internal/llvm/llvmcodebuilder.h index 8fc7a3c5e..ab641240d 100644 --- a/src/engine/internal/llvm/llvmcodebuilder.h +++ b/src/engine/internal/llvm/llvmcodebuilder.h @@ -150,10 +150,9 @@ class LLVMCodeBuilder : public ICodeBuilder llvm::Value *getVariablePtr(llvm::Value *targetVariables, Variable *variable); llvm::Value *getListPtr(llvm::Value *targetLists, List *list); + llvm::Value *getListDataPtr(const LLVMListPtr &listPtr); void syncVariables(llvm::Value *targetVariables); void reloadVariables(llvm::Value *targetVariables); - void reloadLists(); - void updateListDataPtr(const LLVMListPtr &listPtr); LLVMRegister *createOp(LLVMInstruction::Type type, Compiler::StaticType retType, Compiler::StaticType argType, const Compiler::Args &args); LLVMRegister *createOp(LLVMInstruction::Type type, Compiler::StaticType retType, const Compiler::ArgTypes &argTypes = {}, const Compiler::Args &args = {}); @@ -197,7 +196,7 @@ class LLVMCodeBuilder : public ICodeBuilder llvm::FunctionCallee resolve_list_remove(); llvm::FunctionCallee resolve_list_append_empty(); llvm::FunctionCallee resolve_list_insert_empty(); - llvm::FunctionCallee resolve_list_data(); + llvm::FunctionCallee resolve_list_data_ptr(); llvm::FunctionCallee resolve_list_size_ptr(); llvm::FunctionCallee resolve_list_alloc_size_ptr(); llvm::FunctionCallee resolve_list_to_string(); diff --git a/src/engine/internal/llvm/llvmlistptr.h b/src/engine/internal/llvm/llvmlistptr.h index 52e4aff53..7b13bc394 100644 --- a/src/engine/internal/llvm/llvmlistptr.h +++ b/src/engine/internal/llvm/llvmlistptr.h @@ -24,7 +24,6 @@ struct LLVMListPtr llvm::Value *dataPtr = nullptr; llvm::Value *sizePtr = nullptr; llvm::Value *allocatedSizePtr = nullptr; - llvm::Value *dataPtrDirty = nullptr; // Used in build phase to check the type safety of lists in loops std::unordered_map> loopListWrites; // loop scope, write instructions From 26a5c6318f0c77b3f949fb8ac0c097d1aa3986dd Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Sun, 3 Aug 2025 14:44:58 +0200 Subject: [PATCH 57/79] Add LLVMTestUtils class --- test/llvm/CMakeLists.txt | 2 + test/llvm/llvmtestutils.cpp | 322 ++++++++++++++++++++++++++++++++++++ test/llvm/llvmtestutils.h | 95 +++++++++++ 3 files changed, 419 insertions(+) create mode 100644 test/llvm/llvmtestutils.cpp create mode 100644 test/llvm/llvmtestutils.h diff --git a/test/llvm/CMakeLists.txt b/test/llvm/CMakeLists.txt index e5bd2c391..9db31dd64 100644 --- a/test/llvm/CMakeLists.txt +++ b/test/llvm/CMakeLists.txt @@ -16,6 +16,8 @@ target_link_libraries( add_executable( llvm_test main.cpp + llvmtestutils.cpp + llvmtestutils.h llvmexecutioncontext_test.cpp llvmexecutablecode_test.cpp llvmcodebuilder_test.cpp diff --git a/test/llvm/llvmtestutils.cpp b/test/llvm/llvmtestutils.cpp new file mode 100644 index 000000000..2ace9069e --- /dev/null +++ b/test/llvm/llvmtestutils.cpp @@ -0,0 +1,322 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "llvmtestutils.h" +#include "testfunctions.h" + +using namespace libscratchcpp; + +LLVMTestUtils::LLVMTestUtils() +{ + test_function(nullptr, nullptr, nullptr, nullptr, nullptr); // force dependency +} + +LLVMCodeBuilder *LLVMTestUtils::createBuilder(Target *target, BlockPrototype *procedurePrototype, Compiler::CodeType codeType) +{ + if (m_contexts.find(target) == m_contexts.cend() || !target) + m_contexts[target] = std::make_shared(&m_engine, target); + + m_contextList.push_back(m_contexts[target]); + m_builder = std::make_shared(m_contexts[target].get(), procedurePrototype, codeType); + + return m_builder.get(); +} + +LLVMCodeBuilder *LLVMTestUtils::createBuilder(Target *target, bool warp) +{ + m_procedurePrototype = std::make_shared("test"); + m_procedurePrototype->setWarp(warp); + createBuilder(target, m_procedurePrototype.get()); + + return m_builder.get(); +} + +LLVMCodeBuilder *LLVMTestUtils::createBuilder(bool warp) +{ + return createBuilder(nullptr, warp); +} + +LLVMCodeBuilder *LLVMTestUtils::createReporterBuilder(Target *target) +{ + return createBuilder(target, nullptr, Compiler::CodeType::Reporter); +} + +LLVMCodeBuilder *LLVMTestUtils::createPredicateBuilder(Target *target) +{ + return createBuilder(target, nullptr, Compiler::CodeType::HatPredicate); +} + +CompilerValue *LLVMTestUtils::callConstFuncForType(ValueType type, CompilerValue *arg) +{ + switch (type) { + case ValueType::Number: + return m_builder->addFunctionCall("test_const_number", Compiler::StaticType::Number, { Compiler::StaticType::Number }, { arg }); + + case ValueType::Bool: + return m_builder->addFunctionCall("test_const_bool", Compiler::StaticType::Bool, { Compiler::StaticType::Bool }, { arg }); + + case ValueType::String: + return m_builder->addFunctionCall("test_const_string", Compiler::StaticType::String, { Compiler::StaticType::String }, { arg }); + + default: + EXPECT_TRUE(false); + return nullptr; + } +} + +Value LLVMTestUtils::getOpResult(OpType type, bool rawArg, const Value &v) +{ + createReporterBuilder(nullptr); + + CompilerValue *arg = m_builder->addConstValue(v); + + if (rawArg) + addOp(type, arg); + else { + arg = callConstFuncForType(v.type(), arg); + addOp(type, arg); + } + + auto code = m_builder->finalize(); + Script script(&m_target, nullptr, nullptr); + script.setCode(code); + Thread thread(&m_target, nullptr, &script); + auto ctx = code->createExecutionContext(&thread); + + ValueData data = code->runReporter(ctx.get()); + Value ret(data); + value_free(&data); + + return ret; +} + +Value LLVMTestUtils::getOpResult(OpType type, bool rawArgs, const Value &v1, const Value &v2) +{ + createReporterBuilder(nullptr); + + CompilerValue *arg1 = m_builder->addConstValue(v1); + CompilerValue *arg2 = m_builder->addConstValue(v2); + + if (rawArgs) + addOp(type, arg1, arg2); + else { + arg1 = callConstFuncForType(v1.type(), arg1); + arg2 = callConstFuncForType(v2.type(), arg2); + addOp(type, arg1, arg2); + } + + auto code = m_builder->finalize(); + Script script(&m_target, nullptr, nullptr); + script.setCode(code); + Thread thread(&m_target, nullptr, &script); + auto ctx = code->createExecutionContext(&thread); + ctx->setRng(&m_rng); + + ValueData data = code->runReporter(ctx.get()); + Value ret(data); + value_free(&data); + + return ret; +} + +Value LLVMTestUtils::getExpectedOpResult(OpType type, const Value &v) +{ + switch (type) { + case OpType::Not: + return !v.toBool(); + + case OpType::StringLength: + return v.toUtf16().size(); + + default: + EXPECT_TRUE(false); + return Value(); + } +} + +Value LLVMTestUtils::getExpectedOpResult(OpType type, const Value &v1, const Value &v2) +{ + switch (type) { + case OpType::Add: + return v1 + v2; + + case OpType::Sub: + return v1 - v2; + + case OpType::Mul: + return v1 * v2; + + case OpType::Div: + return v1 / v2; + + case OpType::Random: { + const double sum = v1.toDouble() + v2.toDouble(); + + if (std::isnan(sum) || std::isinf(sum)) + return sum; + + return v1.isInt() && v2.isInt() ? m_rng.randint(v1.toLong(), v2.toLong()) : m_rng.randintDouble(v1.toDouble(), v2.toDouble()); + } + + case OpType::RandomInt: + return m_rng.randint(v1.toLong(), v2.toLong()); + + case OpType::CmpEQ: + return v1 == v2; + + case OpType::CmpGT: + return v1 > v2; + + case OpType::CmpLT: + return v1 < v2; + + case OpType::StrCmpEQCS: + return string_compare_case_sensitive(value_toStringPtr(&v1.data()), value_toStringPtr(&v2.data())) == 0; + + case OpType::StrCmpEQCI: + return string_compare_case_insensitive(value_toStringPtr(&v1.data()), value_toStringPtr(&v2.data())) == 0; + + case OpType::And: + return v1.toBool() && v2.toBool(); + + case OpType::Or: + return v1.toBool() || v2.toBool(); + + case OpType::Mod: + return v1 % v2; + + default: + EXPECT_TRUE(false); + return Value(); + } +} + +const RandomGeneratorMock &LLVMTestUtils::rng() const +{ + return m_rng; +} + +CompilerValue *LLVMTestUtils::addOp(OpType type, CompilerValue *arg) +{ + switch (type) { + case OpType::Not: + return m_builder->createNot(arg); + + case OpType::Round: + return m_builder->createRound(arg); + + case OpType::Abs: + return m_builder->createAbs(arg); + + case OpType::Floor: + return m_builder->createFloor(arg); + + case OpType::Ceil: + return m_builder->createCeil(arg); + + case OpType::Sqrt: + return m_builder->createSqrt(arg); + + case OpType::Sin: + return m_builder->createSin(arg); + + case OpType::Cos: + return m_builder->createCos(arg); + + case OpType::Tan: + return m_builder->createTan(arg); + + case OpType::Asin: + return m_builder->createAsin(arg); + + case OpType::Acos: + return m_builder->createAcos(arg); + + case OpType::Atan: + return m_builder->createAtan(arg); + + case OpType::Ln: + return m_builder->createLn(arg); + + case OpType::Log10: + return m_builder->createLog10(arg); + + case OpType::Exp: + return m_builder->createExp(arg); + + case OpType::Exp10: + return m_builder->createExp10(arg); + + case OpType::StringLength: + return m_builder->addStringLength(arg); + + default: + EXPECT_TRUE(false); + return nullptr; + } +} + +CompilerValue *LLVMTestUtils::addOp(OpType type, CompilerValue *arg1, CompilerValue *arg2) +{ + switch (type) { + case OpType::Add: + return m_builder->createAdd(arg1, arg2); + + case OpType::Sub: + return m_builder->createSub(arg1, arg2); + + case OpType::Mul: + return m_builder->createMul(arg1, arg2); + + case OpType::Div: + return m_builder->createDiv(arg1, arg2); + + case OpType::Random: + return m_builder->createRandom(arg1, arg2); + + case OpType::RandomInt: + return m_builder->createRandomInt(arg1, arg2); + + case OpType::CmpEQ: + return m_builder->createCmpEQ(arg1, arg2); + + case OpType::CmpGT: + return m_builder->createCmpGT(arg1, arg2); + + case OpType::CmpLT: + return m_builder->createCmpLT(arg1, arg2); + + case OpType::StrCmpEQCS: + return m_builder->createStrCmpEQ(arg1, arg2, true); + + case OpType::StrCmpEQCI: + return m_builder->createStrCmpEQ(arg1, arg2, false); + + case OpType::And: + return m_builder->createAnd(arg1, arg2); + + case OpType::Or: + return m_builder->createOr(arg1, arg2); + + case OpType::Mod: + return m_builder->createMod(arg1, arg2); + + case OpType::StringConcat: + return m_builder->createStringConcat(arg1, arg2); + + case OpType::StringChar: + return m_builder->addStringChar(arg1, arg2); + + default: + EXPECT_TRUE(false); + return nullptr; + } +} diff --git a/test/llvm/llvmtestutils.h b/test/llvm/llvmtestutils.h new file mode 100644 index 000000000..8d864fcf4 --- /dev/null +++ b/test/llvm/llvmtestutils.h @@ -0,0 +1,95 @@ +#pragma once + +#include +#include +#include +#include + +#define ASSERT_NUM_OP1(utils, type, rawArg, v) ASSERT_EQ(utils.getOpResult(type, rawArg, v).toDouble(), m_utils.getExpectedOpResult(type, v).toDouble()); +#define ASSERT_NUM_OP2(utils, type, rawArgs, v1, v2) ASSERT_EQ(utils.getOpResult(type, rawArgs, v1, v2).toDouble(), m_utils.getExpectedOpResult(type, v1, v2).toDouble()); + +#define ASSERT_BOOL_OP1(utils, type, rawArg, v) ASSERT_EQ(utils.getOpResult(type, rawArg, v).toBool(), m_utils.getExpectedOpResult(type, v).toBool()); +#define ASSERT_BOOL_OP2(utils, type, rawArgs, v1, v2) ASSERT_EQ(utils.getOpResult(type, rawArgs, v1, v2).toBool(), m_utils.getExpectedOpResult(type, v1, v2).toBool()); + +#define ASSERT_STRING_OP1(utils, type, rawArg, v) ASSERT_EQ(utils.getOpResult(type, rawArg, v).toString(), m_utils.getExpectedOpResult(type, v).toString()); +#define ASSERT_STRING_OP2(utils, type, rawArgs, v1, v2) ASSERT_EQ(utils.getOpResult(type, rawArgs, v1, v2).toString(), m_utils.getExpectedOpResult(type, v1, v2).toString()); + +namespace libscratchcpp +{ + +class LLVMCompilerContext; +class LLVMCodeBuilder; + +class LLVMTestUtils +{ + public: + enum class OpType + { + Add, + Sub, + Mul, + Div, + Random, + RandomInt, + CmpEQ, + CmpGT, + CmpLT, + StrCmpEQCS, + StrCmpEQCI, + And, + Or, + Not, + Mod, + Round, + Abs, + Floor, + Ceil, + Sqrt, + Sin, + Cos, + Tan, + Asin, + Acos, + Atan, + Ln, + Log10, + Exp, + Exp10, + StringConcat, + StringChar, + StringLength + }; + + LLVMTestUtils(); + + LLVMCodeBuilder *createBuilder(Target *target, BlockPrototype *procedurePrototype, Compiler::CodeType codeType = Compiler::CodeType::Script); + LLVMCodeBuilder *createBuilder(Target *target, bool warp); + LLVMCodeBuilder *createBuilder(bool warp); + + LLVMCodeBuilder *createReporterBuilder(Target *target); + LLVMCodeBuilder *createPredicateBuilder(Target *target); + + CompilerValue *callConstFuncForType(ValueType type, CompilerValue *arg); + + Value getOpResult(OpType type, bool rawArg, const Value &v); + Value getOpResult(OpType type, bool rawArgs, const Value &v1, const Value &v2); + + Value getExpectedOpResult(OpType type, const Value &v); + Value getExpectedOpResult(OpType type, const Value &v1, const Value &v2); + + const RandomGeneratorMock &rng() const; + + private: + CompilerValue *addOp(OpType type, CompilerValue *arg); + CompilerValue *addOp(OpType type, CompilerValue *arg1, CompilerValue *arg2); + + std::unordered_map> m_contexts; + std::vector> m_contextList; + std::shared_ptr m_builder; + std::shared_ptr m_procedurePrototype; + EngineMock m_engine; + TargetMock m_target; // NOTE: isStage() is used for call expectations + RandomGeneratorMock m_rng; +}; + +} // namespace libscratchcpp From e70709f9b90893caa93e08bd7e4f9ca8baa990cd Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Sun, 3 Aug 2025 14:59:24 +0200 Subject: [PATCH 58/79] LLVMCodeBuilder: Move operator tests to separate test suites --- test/llvm/CMakeLists.txt | 33 + test/llvm/llvmcodebuilder_test.cpp | 1496 ----------------- test/llvm/operators/equal_comparison_test.cpp | 1205 +++++++++++++ test/llvm/operators/greater_than_test.cpp | 1340 +++++++++++++++ test/llvm/operators/less_than_test.cpp | 1340 +++++++++++++++ test/llvm/operators/logic/and_test.cpp | 890 ++++++++++ test/llvm/operators/logic/not_test.cpp | 260 +++ test/llvm/operators/logic/or_test.cpp | 890 ++++++++++ test/llvm/operators/math/abs_test.cpp | 116 ++ test/llvm/operators/math/acos_test.cpp | 126 ++ test/llvm/operators/math/add_test.cpp | 130 ++ test/llvm/operators/math/asin_test.cpp | 126 ++ test/llvm/operators/math/atan_test.cpp | 86 + test/llvm/operators/math/ceil_test.cpp | 176 ++ test/llvm/operators/math/cos_test.cpp | 136 ++ test/llvm/operators/math/divide_test.cpp | 270 +++ test/llvm/operators/math/exp10_test.cpp | 106 ++ test/llvm/operators/math/exp_test.cpp | 96 ++ test/llvm/operators/math/floor_test.cpp | 166 ++ test/llvm/operators/math/ln_test.cpp | 122 ++ test/llvm/operators/math/log10_test.cpp | 112 ++ test/llvm/operators/math/mod_test.cpp | 280 +++ test/llvm/operators/math/multiply_test.cpp | 180 ++ test/llvm/operators/math/random_int_test.cpp | 134 ++ test/llvm/operators/math/random_test.cpp | 444 +++++ test/llvm/operators/math/round_test.cpp | 146 ++ test/llvm/operators/math/sin_test.cpp | 136 ++ test/llvm/operators/math/sqrt_test.cpp | 96 ++ test/llvm/operators/math/subtract_test.cpp | 130 ++ test/llvm/operators/math/tan_test.cpp | 188 +++ .../operators/string/string_char_test.cpp | 80 + .../operators/string/string_concat_test.cpp | 40 + .../string_equal_case_insensitive_test.cpp | 1210 +++++++++++++ .../string_equal_case_sensitive_test.cpp | 1210 +++++++++++++ .../operators/string/string_length_test.cpp | 50 + 35 files changed, 12050 insertions(+), 1496 deletions(-) create mode 100644 test/llvm/operators/equal_comparison_test.cpp create mode 100644 test/llvm/operators/greater_than_test.cpp create mode 100644 test/llvm/operators/less_than_test.cpp create mode 100644 test/llvm/operators/logic/and_test.cpp create mode 100644 test/llvm/operators/logic/not_test.cpp create mode 100644 test/llvm/operators/logic/or_test.cpp create mode 100644 test/llvm/operators/math/abs_test.cpp create mode 100644 test/llvm/operators/math/acos_test.cpp create mode 100644 test/llvm/operators/math/add_test.cpp create mode 100644 test/llvm/operators/math/asin_test.cpp create mode 100644 test/llvm/operators/math/atan_test.cpp create mode 100644 test/llvm/operators/math/ceil_test.cpp create mode 100644 test/llvm/operators/math/cos_test.cpp create mode 100644 test/llvm/operators/math/divide_test.cpp create mode 100644 test/llvm/operators/math/exp10_test.cpp create mode 100644 test/llvm/operators/math/exp_test.cpp create mode 100644 test/llvm/operators/math/floor_test.cpp create mode 100644 test/llvm/operators/math/ln_test.cpp create mode 100644 test/llvm/operators/math/log10_test.cpp create mode 100644 test/llvm/operators/math/mod_test.cpp create mode 100644 test/llvm/operators/math/multiply_test.cpp create mode 100644 test/llvm/operators/math/random_int_test.cpp create mode 100644 test/llvm/operators/math/random_test.cpp create mode 100644 test/llvm/operators/math/round_test.cpp create mode 100644 test/llvm/operators/math/sin_test.cpp create mode 100644 test/llvm/operators/math/sqrt_test.cpp create mode 100644 test/llvm/operators/math/subtract_test.cpp create mode 100644 test/llvm/operators/math/tan_test.cpp create mode 100644 test/llvm/operators/string/string_char_test.cpp create mode 100644 test/llvm/operators/string/string_concat_test.cpp create mode 100644 test/llvm/operators/string/string_equal_case_insensitive_test.cpp create mode 100644 test/llvm/operators/string/string_equal_case_sensitive_test.cpp create mode 100644 test/llvm/operators/string/string_length_test.cpp diff --git a/test/llvm/CMakeLists.txt b/test/llvm/CMakeLists.txt index 9db31dd64..80ac82f6d 100644 --- a/test/llvm/CMakeLists.txt +++ b/test/llvm/CMakeLists.txt @@ -22,6 +22,39 @@ add_executable( llvmexecutablecode_test.cpp llvmcodebuilder_test.cpp llvminstructionlist_test.cpp + operators/equal_comparison_test.cpp + operators/greater_than_test.cpp + operators/less_than_test.cpp + operators/math/add_test.cpp + operators/math/subtract_test.cpp + operators/math/multiply_test.cpp + operators/math/divide_test.cpp + operators/math/random_test.cpp + operators/math/random_int_test.cpp + operators/math/mod_test.cpp + operators/math/abs_test.cpp + operators/math/round_test.cpp + operators/math/floor_test.cpp + operators/math/ceil_test.cpp + operators/math/sqrt_test.cpp + operators/math/sin_test.cpp + operators/math/cos_test.cpp + operators/math/tan_test.cpp + operators/math/asin_test.cpp + operators/math/acos_test.cpp + operators/math/atan_test.cpp + operators/math/ln_test.cpp + operators/math/log10_test.cpp + operators/math/exp_test.cpp + operators/math/exp10_test.cpp + operators/logic/and_test.cpp + operators/logic/or_test.cpp + operators/logic/not_test.cpp + operators/string/string_equal_case_sensitive_test.cpp + operators/string/string_equal_case_insensitive_test.cpp + operators/string/string_concat_test.cpp + operators/string/string_char_test.cpp + operators/string/string_length_test.cpp type_analyzer/variabletypeafterbranch_test.cpp type_analyzer/variabletype_test.cpp type_analyzer/listtypeafterbranch_test.cpp diff --git a/test/llvm/llvmcodebuilder_test.cpp b/test/llvm/llvmcodebuilder_test.cpp index fcbed7b93..5d18511fd 100644 --- a/test/llvm/llvmcodebuilder_test.cpp +++ b/test/llvm/llvmcodebuilder_test.cpp @@ -26,43 +26,6 @@ using ::testing::Eq; class LLVMCodeBuilderTest : public testing::Test { public: - enum class OpType - { - Add, - Sub, - Mul, - Div, - Random, - RandomInt, - CmpEQ, - CmpGT, - CmpLT, - StrCmpEQCS, - StrCmpEQCI, - And, - Or, - Not, - Mod, - Round, - Abs, - Floor, - Ceil, - Sqrt, - Sin, - Cos, - Tan, - Asin, - Acos, - Atan, - Ln, - Log10, - Exp, - Exp10, - StringConcat, - StringChar, - StringLength - }; - void SetUp() override { test_function(nullptr, nullptr, nullptr, nullptr, nullptr); // force dependency @@ -108,333 +71,6 @@ class LLVMCodeBuilderTest : public testing::Test } } - CompilerValue *addOp(OpType type, CompilerValue *arg1, CompilerValue *arg2) - { - switch (type) { - case OpType::Add: - return m_builder->createAdd(arg1, arg2); - - case OpType::Sub: - return m_builder->createSub(arg1, arg2); - - case OpType::Mul: - return m_builder->createMul(arg1, arg2); - - case OpType::Div: - return m_builder->createDiv(arg1, arg2); - - case OpType::Random: - return m_builder->createRandom(arg1, arg2); - - case OpType::RandomInt: - return m_builder->createRandomInt(arg1, arg2); - - case OpType::CmpEQ: - return m_builder->createCmpEQ(arg1, arg2); - - case OpType::CmpGT: - return m_builder->createCmpGT(arg1, arg2); - - case OpType::CmpLT: - return m_builder->createCmpLT(arg1, arg2); - - case OpType::StrCmpEQCS: - return m_builder->createStrCmpEQ(arg1, arg2, true); - - case OpType::StrCmpEQCI: - return m_builder->createStrCmpEQ(arg1, arg2, false); - - case OpType::And: - return m_builder->createAnd(arg1, arg2); - - case OpType::Or: - return m_builder->createOr(arg1, arg2); - - case OpType::Mod: - return m_builder->createMod(arg1, arg2); - - case OpType::StringConcat: - return m_builder->createStringConcat(arg1, arg2); - - case OpType::StringChar: - return m_builder->addStringChar(arg1, arg2); - - default: - EXPECT_TRUE(false); - return nullptr; - } - } - - CompilerValue *addOp(OpType type, CompilerValue *arg) - { - switch (type) { - case OpType::Not: - return m_builder->createNot(arg); - - case OpType::Round: - return m_builder->createRound(arg); - - case OpType::Abs: - return m_builder->createAbs(arg); - - case OpType::Floor: - return m_builder->createFloor(arg); - - case OpType::Ceil: - return m_builder->createCeil(arg); - - case OpType::Sqrt: - return m_builder->createSqrt(arg); - - case OpType::Sin: - return m_builder->createSin(arg); - - case OpType::Cos: - return m_builder->createCos(arg); - - case OpType::Tan: - return m_builder->createTan(arg); - - case OpType::Asin: - return m_builder->createAsin(arg); - - case OpType::Acos: - return m_builder->createAcos(arg); - - case OpType::Atan: - return m_builder->createAtan(arg); - - case OpType::Ln: - return m_builder->createLn(arg); - - case OpType::Log10: - return m_builder->createLog10(arg); - - case OpType::Exp: - return m_builder->createExp(arg); - - case OpType::Exp10: - return m_builder->createExp10(arg); - - case OpType::StringLength: - return m_builder->addStringLength(arg); - - default: - EXPECT_TRUE(false); - return nullptr; - } - } - - Value doOp(OpType type, const Value &v1, const Value &v2) - { - switch (type) { - case OpType::Add: - return v1 + v2; - - case OpType::Sub: - return v1 - v2; - - case OpType::Mul: - return v1 * v2; - - case OpType::Div: - return v1 / v2; - - case OpType::Random: { - const double sum = v1.toDouble() + v2.toDouble(); - - if (std::isnan(sum) || std::isinf(sum)) - return sum; - - return v1.isInt() && v2.isInt() ? m_rng.randint(v1.toLong(), v2.toLong()) : m_rng.randintDouble(v1.toDouble(), v2.toDouble()); - } - - case OpType::RandomInt: - return m_rng.randint(v1.toLong(), v2.toLong()); - - case OpType::CmpEQ: - return v1 == v2; - - case OpType::CmpGT: - return v1 > v2; - - case OpType::CmpLT: - return v1 < v2; - - case OpType::StrCmpEQCS: - return string_compare_case_sensitive(value_toStringPtr(&v1.data()), value_toStringPtr(&v2.data())) == 0; - - case OpType::StrCmpEQCI: - return string_compare_case_insensitive(value_toStringPtr(&v1.data()), value_toStringPtr(&v2.data())) == 0; - - case OpType::And: - return v1.toBool() && v2.toBool(); - - case OpType::Or: - return v1.toBool() || v2.toBool(); - - case OpType::Mod: - return v1 % v2; - - case OpType::StringConcat: { - const StringPtr *string1 = value_toStringPtr(&v1.data()); - const StringPtr *string2 = value_toStringPtr(&v2.data()); - StringPtr *result = string_pool_new(true); - - result->size = string1->size + string2->size; - string_alloc(result, result->size); - memcpy(result->data, string1->data, string1->size * sizeof(typeof(*string1->data))); - memcpy(result->data + string1->size, string2->data, (string2->size + 1) * sizeof(typeof(*string2->data))); // +1: null-terminate - - Value ret; - value_assign_stringPtr(&ret.data(), result); - return ret; - } - - case OpType::StringChar: { - const StringPtr *string = value_toStringPtr(&v1.data()); - const double index = v2.toDouble(); - const bool inRange = (index >= 0 && index < string->size); - StringPtr *result = string_pool_new(true); - - string_alloc(result, 1); - result->data[0] = inRange ? string->data[static_cast(index)] : u'\0'; - result->data[1] = u'\0'; - result->size = inRange; - - Value ret; - value_assign_stringPtr(&ret.data(), result); - return ret; - } - - default: - EXPECT_TRUE(false); - return Value(); - } - } - - Value doOp(OpType type, const Value &v) - { - switch (type) { - case OpType::Not: - return !v.toBool(); - - case OpType::StringLength: - return v.toUtf16().size(); - - default: - EXPECT_TRUE(false); - return Value(); - } - } - - void runOpTestCommon(OpType type, const Value &v1, const Value &v2) - { - createBuilder(true); - - CompilerValue *arg1 = m_builder->addConstValue(v1); - CompilerValue *arg2 = m_builder->addConstValue(v2); - CompilerValue *ret = addOp(type, arg1, arg2); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { ret }); - - arg1 = m_builder->addConstValue(v1); - arg1 = callConstFuncForType(v1.type(), arg1); - arg2 = m_builder->addConstValue(v2); - arg2 = callConstFuncForType(v2.type(), arg2); - ret = addOp(type, arg1, arg2); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { ret }); - - auto code = m_builder->finalize(); - Script script(&m_target, nullptr, nullptr); - script.setCode(code); - Thread thread(&m_target, nullptr, &script); - auto ctx = code->createExecutionContext(&thread); - ctx->setRng(&m_rng); - - testing::internal::CaptureStdout(); - code->run(ctx.get()); - } - - void checkOpTest(const Value &v1, const Value &v2, const std::string &expected) - { - const std::string quotes1 = v1.isString() ? "\"" : ""; - const std::string quotes2 = v2.isString() ? "\"" : ""; - ASSERT_THAT(testing::internal::GetCapturedStdout(), Eq(expected)) << quotes1 << v1.toString() << quotes1 << " " << quotes2 << v2.toString() << quotes2; - } - - void runOpTest(OpType type, const Value &v1, const Value &v2, const Value &expected) - { - std::string str = expected.toString(); - runOpTestCommon(type, v1, v2); - checkOpTest(v1, v2, str + '\n' + str + '\n'); - }; - - void runOpTest(OpType type, const Value &v1, const Value &v2) - { - runOpTestCommon(type, v1, v2); - std::string str = doOp(type, v1, v2).toString() + '\n'; - std::string expected = str + str; - checkOpTest(v1, v2, expected); - }; - - void runOpTest(OpType type, const Value &v) - { - createBuilder(true); - - CompilerValue *arg = m_builder->addConstValue(v); - CompilerValue *ret = addOp(type, arg); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { ret }); - - arg = m_builder->addConstValue(v); - arg = callConstFuncForType(v.type(), arg); - ret = addOp(type, arg); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { ret }); - - std::string str = doOp(type, v).toString() + '\n'; - std::string expected = str + str; - - auto code = m_builder->finalize(); - Script script(&m_target, nullptr, nullptr); - script.setCode(code); - Thread thread(&m_target, nullptr, &script); - auto ctx = code->createExecutionContext(&thread); - - testing::internal::CaptureStdout(); - code->run(ctx.get()); - const std::string quotes = v.isString() ? "\"" : ""; - ASSERT_THAT(testing::internal::GetCapturedStdout(), Eq(expected)) << "NOT: " << quotes << v.toString() << quotes; - }; - - void runUnaryNumOpTest(OpType type, const Value &v, double expectedResult) - { - createBuilder(true); - - CompilerValue *arg = m_builder->addConstValue(v); - CompilerValue *ret = addOp(type, arg); - m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { ret }); - - arg = m_builder->addConstValue(v); - arg = callConstFuncForType(v.type(), arg); - ret = addOp(type, arg); - m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { ret }); - - std::stringstream stream; - stream << expectedResult; - std::string str = stream.str() + '\n'; - std::string expected = str + str; - - auto code = m_builder->finalize(); - Script script(&m_target, nullptr, nullptr); - script.setCode(code); - Thread thread(&m_target, nullptr, &script); - auto ctx = code->createExecutionContext(&thread); - - testing::internal::CaptureStdout(); - code->run(ctx.get()); - const std::string quotes = v.isString() ? "\"" : ""; - ASSERT_THAT(testing::internal::GetCapturedStdout(), Eq(expected)) << quotes << v.toString() << quotes; - }; - std::unordered_map> m_contexts; std::vector> m_contextList; std::unique_ptr m_builder; @@ -708,1138 +344,6 @@ TEST_F(LLVMCodeBuilderTest, RawValueCasting) ASSERT_EQ(testing::internal::GetCapturedStdout(), expected); } -TEST_F(LLVMCodeBuilderTest, Add) -{ - runOpTest(OpType::Add, 50, 25); - runOpTest(OpType::Add, -500, 25); - runOpTest(OpType::Add, -500, -25); - runOpTest(OpType::Add, "2.54", "6.28"); - runOpTest(OpType::Add, 2.54, "-6.28"); - runOpTest(OpType::Add, true, true); - runOpTest(OpType::Add, "Infinity", "Infinity"); - runOpTest(OpType::Add, "Infinity", "-Infinity"); - runOpTest(OpType::Add, "-Infinity", "Infinity"); - runOpTest(OpType::Add, "-Infinity", "-Infinity"); - runOpTest(OpType::Add, 1, "NaN"); - runOpTest(OpType::Add, "NaN", 1); -} - -TEST_F(LLVMCodeBuilderTest, Subtract) -{ - runOpTest(OpType::Sub, 50, 25); - runOpTest(OpType::Sub, -500, 25); - runOpTest(OpType::Sub, -500, -25); - runOpTest(OpType::Sub, "2.54", "6.28"); - runOpTest(OpType::Sub, 2.54, "-6.28"); - runOpTest(OpType::Sub, true, true); - runOpTest(OpType::Sub, "Infinity", "Infinity"); - runOpTest(OpType::Sub, "Infinity", "-Infinity"); - runOpTest(OpType::Sub, "-Infinity", "Infinity"); - runOpTest(OpType::Sub, "-Infinity", "-Infinity"); - runOpTest(OpType::Sub, 1, "NaN"); - runOpTest(OpType::Sub, "NaN", 1); -} - -TEST_F(LLVMCodeBuilderTest, Multiply) -{ - runOpTest(OpType::Mul, 50, 2); - runOpTest(OpType::Mul, -500, 25); - runOpTest(OpType::Mul, "-500", -25); - runOpTest(OpType::Mul, "2.54", "6.28"); - runOpTest(OpType::Mul, true, true); - runOpTest(OpType::Mul, "Infinity", "Infinity"); - runOpTest(OpType::Mul, "Infinity", 0); - runOpTest(OpType::Mul, "Infinity", 2); - runOpTest(OpType::Mul, "Infinity", -2); - runOpTest(OpType::Mul, "Infinity", "-Infinity"); - runOpTest(OpType::Mul, "-Infinity", "Infinity"); - runOpTest(OpType::Mul, "-Infinity", 0); - runOpTest(OpType::Mul, "-Infinity", 2); - runOpTest(OpType::Mul, "-Infinity", -2); - runOpTest(OpType::Mul, "-Infinity", "-Infinity"); - runOpTest(OpType::Mul, 1, "NaN"); - runOpTest(OpType::Mul, "NaN", 1); -} - -TEST_F(LLVMCodeBuilderTest, Divide) -{ - runOpTest(OpType::Div, 50, 2); - runOpTest(OpType::Div, -500, 25); - runOpTest(OpType::Div, "-500", -25); - runOpTest(OpType::Div, "3.5", "2.5"); - runOpTest(OpType::Div, true, true); - runOpTest(OpType::Div, "Infinity", "Infinity"); - runOpTest(OpType::Div, "Infinity", 0); - runOpTest(OpType::Div, "Infinity", 2); - runOpTest(OpType::Div, "Infinity", -2); - runOpTest(OpType::Div, "Infinity", "-Infinity"); - runOpTest(OpType::Div, "-Infinity", "Infinity"); - runOpTest(OpType::Div, "-Infinity", 0); - runOpTest(OpType::Div, "-Infinity", 2); - runOpTest(OpType::Div, "-Infinity", -2); - runOpTest(OpType::Div, "-Infinity", "-Infinity"); - runOpTest(OpType::Div, 0, "Infinity"); - runOpTest(OpType::Div, 2, "Infinity"); - runOpTest(OpType::Div, -2, "Infinity"); - runOpTest(OpType::Div, 0, "-Infinity"); - runOpTest(OpType::Div, 2, "-Infinity"); - runOpTest(OpType::Div, -2, "-Infinity"); - runOpTest(OpType::Div, 1, "NaN"); - runOpTest(OpType::Div, "NaN", 1); - runOpTest(OpType::Div, 5, 0); - runOpTest(OpType::Div, -5, 0); - runOpTest(OpType::Div, 0, 0); -} - -TEST_F(LLVMCodeBuilderTest, Random) -{ - EXPECT_CALL(m_rng, randint(-45, 12)).Times(3).WillRepeatedly(Return(-18)); - runOpTest(OpType::Random, -45, 12); - - EXPECT_CALL(m_rng, randint(-45, 12)).Times(3).WillRepeatedly(Return(5)); - runOpTest(OpType::Random, -45.0, 12.0); - - EXPECT_CALL(m_rng, randintDouble(12, 6.05)).Times(3).WillRepeatedly(Return(3.486789)); - runOpTest(OpType::Random, 12, 6.05); - - EXPECT_CALL(m_rng, randintDouble(-78.686, -45)).Times(3).WillRepeatedly(Return(-59.468873)); - runOpTest(OpType::Random, -78.686, -45); - - EXPECT_CALL(m_rng, randintDouble(6.05, -78.686)).Times(3).WillRepeatedly(Return(-28.648764)); - runOpTest(OpType::Random, 6.05, -78.686); - - EXPECT_CALL(m_rng, randint(-45, 12)).Times(3).WillRepeatedly(Return(0)); - runOpTest(OpType::Random, "-45", "12"); - - EXPECT_CALL(m_rng, randintDouble(-45, 12)).Times(3).WillRepeatedly(Return(5.2)); - runOpTest(OpType::Random, "-45.0", "12"); - - EXPECT_CALL(m_rng, randintDouble(-45, 12)).Times(3).WillRepeatedly(Return(-15.5787)); - runOpTest(OpType::Random, "-45", "12.0"); - - EXPECT_CALL(m_rng, randintDouble(-45, 12)).Times(3).WillRepeatedly(Return(2.587964)); - runOpTest(OpType::Random, "-45.0", "12.0"); - - EXPECT_CALL(m_rng, randintDouble(6.05, -78.686)).Times(3).WillRepeatedly(Return(5.648764)); - runOpTest(OpType::Random, "6.05", "-78.686"); - - EXPECT_CALL(m_rng, randint(-45, 12)).Times(3).WillRepeatedly(Return(0)); - runOpTest(OpType::Random, "-45", 12); - - EXPECT_CALL(m_rng, randint(-45, 12)).Times(3).WillRepeatedly(Return(0)); - runOpTest(OpType::Random, -45, "12"); - - EXPECT_CALL(m_rng, randintDouble(-45, 12)).Times(3).WillRepeatedly(Return(5.2)); - runOpTest(OpType::Random, "-45.0", 12); - - EXPECT_CALL(m_rng, randintDouble(-45, 12)).Times(3).WillRepeatedly(Return(-15.5787)); - runOpTest(OpType::Random, -45, "12.0"); - - EXPECT_CALL(m_rng, randintDouble(6.05, -78.686)).Times(3).WillRepeatedly(Return(5.648764)); - runOpTest(OpType::Random, 6.05, "-78.686"); - - EXPECT_CALL(m_rng, randintDouble(6.05, -78.686)).Times(3).WillRepeatedly(Return(5.648764)); - runOpTest(OpType::Random, "6.05", -78.686); - - EXPECT_CALL(m_rng, randint(0, 1)).Times(3).WillRepeatedly(Return(1)); - runOpTest(OpType::Random, false, true); - - EXPECT_CALL(m_rng, randint(1, 5)).Times(3).WillRepeatedly(Return(1)); - runOpTest(OpType::Random, true, 5); - - EXPECT_CALL(m_rng, randint(8, 0)).Times(3).WillRepeatedly(Return(1)); - runOpTest(OpType::Random, 8, false); - - const double inf = std::numeric_limits::infinity(); - const double nan = std::numeric_limits::quiet_NaN(); - - EXPECT_CALL(m_rng, randint(0, 5)).Times(3).WillRepeatedly(Return(5)); - runOpTest(OpType::Random, nan, 5); - - EXPECT_CALL(m_rng, randint(5, 0)).Times(3).WillRepeatedly(Return(3)); - runOpTest(OpType::Random, 5, nan); - - EXPECT_CALL(m_rng, randint(0, 0)).Times(3).WillRepeatedly(Return(0)); - runOpTest(OpType::Random, nan, nan); - - EXPECT_CALL(m_rng, randint).WillRepeatedly(Return(0)); - EXPECT_CALL(m_rng, randintDouble).WillRepeatedly(Return(0)); - - runOpTest(OpType::Random, inf, 2, inf); - runOpTest(OpType::Random, -8, inf, inf); - runOpTest(OpType::Random, -inf, -2, -inf); - runOpTest(OpType::Random, 8, -inf, -inf); - - runOpTest(OpType::Random, inf, 2.5, inf); - runOpTest(OpType::Random, -8.09, inf, inf); - runOpTest(OpType::Random, -inf, -2.5, -inf); - runOpTest(OpType::Random, 8.09, -inf, -inf); - - runOpTest(OpType::Random, inf, inf, inf); - runOpTest(OpType::Random, -inf, -inf, -inf); - runOpTest(OpType::Random, inf, -inf, nan); - runOpTest(OpType::Random, -inf, inf, nan); -} - -TEST_F(LLVMCodeBuilderTest, RandomInt) -{ - EXPECT_CALL(m_rng, randint(-45, 12)).Times(3).WillRepeatedly(Return(-18)); - runOpTest(OpType::RandomInt, -45, 12); - - EXPECT_CALL(m_rng, randint(-45, 12)).Times(3).WillRepeatedly(Return(5)); - runOpTest(OpType::RandomInt, -45.0, 12.0); - - EXPECT_CALL(m_rng, randint(12, 6)).Times(3).WillRepeatedly(Return(3)); - runOpTest(OpType::RandomInt, 12, 6.05); - - EXPECT_CALL(m_rng, randint(-78, -45)).Times(3).WillRepeatedly(Return(-59)); - runOpTest(OpType::RandomInt, -78.686, -45); - - EXPECT_CALL(m_rng, randint(-45, 12)).Times(3).WillRepeatedly(Return(0)); - runOpTest(OpType::RandomInt, "-45", "12"); - - EXPECT_CALL(m_rng, randint(-45, 12)).Times(3).WillRepeatedly(Return(5)); - runOpTest(OpType::RandomInt, "-45.0", "12"); - - EXPECT_CALL(m_rng, randint(-45, 12)).Times(3).WillRepeatedly(Return(-15)); - runOpTest(OpType::RandomInt, "-45", "12.0"); - - EXPECT_CALL(m_rng, randint(0, 1)).Times(3).WillRepeatedly(Return(1)); - runOpTest(OpType::RandomInt, false, true); - - EXPECT_CALL(m_rng, randint(1, 5)).Times(3).WillRepeatedly(Return(1)); - runOpTest(OpType::RandomInt, true, 5); - - EXPECT_CALL(m_rng, randint(8, 0)).Times(3).WillRepeatedly(Return(1)); - runOpTest(OpType::RandomInt, 8, false); - - // NOTE: Infinity, -Infinity and NaN behavior is undefined -} - -TEST_F(LLVMCodeBuilderTest, EqualComparison) -{ - runOpTest(OpType::CmpEQ, 10, 10); - runOpTest(OpType::CmpEQ, 10, 8); - runOpTest(OpType::CmpEQ, 8, 10); - - runOpTest(OpType::CmpEQ, -4.25, -4.25); - runOpTest(OpType::CmpEQ, -4.25, 5.312); - runOpTest(OpType::CmpEQ, 5.312, -4.25); - - runOpTest(OpType::CmpEQ, true, true); - runOpTest(OpType::CmpEQ, true, false); - runOpTest(OpType::CmpEQ, false, true); - - runOpTest(OpType::CmpEQ, 1, true); - runOpTest(OpType::CmpEQ, 1, false); - - runOpTest(OpType::CmpEQ, "abC def", "abC def"); - runOpTest(OpType::CmpEQ, "abC def", "abc dEf"); - runOpTest(OpType::CmpEQ, "abC def", "ghi Jkl"); - runOpTest(OpType::CmpEQ, "abC def", "hello world"); - - runOpTest(OpType::CmpEQ, " ", ""); - runOpTest(OpType::CmpEQ, " ", "0"); - runOpTest(OpType::CmpEQ, " ", 0); - runOpTest(OpType::CmpEQ, 0, " "); - runOpTest(OpType::CmpEQ, "", "0"); - runOpTest(OpType::CmpEQ, "", 0); - runOpTest(OpType::CmpEQ, 0, ""); - runOpTest(OpType::CmpEQ, "0", 0); - runOpTest(OpType::CmpEQ, 0, "0"); - - runOpTest(OpType::CmpEQ, 5.25, "5.25"); - runOpTest(OpType::CmpEQ, "5.25", 5.25); - runOpTest(OpType::CmpEQ, 5.25, " 5.25"); - runOpTest(OpType::CmpEQ, " 5.25", 5.25); - runOpTest(OpType::CmpEQ, 5.25, "5.25 "); - runOpTest(OpType::CmpEQ, "5.25 ", 5.25); - runOpTest(OpType::CmpEQ, 5.25, " 5.25 "); - runOpTest(OpType::CmpEQ, " 5.25 ", 5.25); - runOpTest(OpType::CmpEQ, 5.25, "5.26"); - runOpTest(OpType::CmpEQ, "5.26", 5.25); - runOpTest(OpType::CmpEQ, "5.25", "5.26"); - runOpTest(OpType::CmpEQ, 5, "5 "); - runOpTest(OpType::CmpEQ, "5 ", 5); - runOpTest(OpType::CmpEQ, 0, "1"); - runOpTest(OpType::CmpEQ, "1", 0); - runOpTest(OpType::CmpEQ, 0, "test"); - runOpTest(OpType::CmpEQ, "test", 0); - - static const double inf = std::numeric_limits::infinity(); - static const double nan = std::numeric_limits::quiet_NaN(); - - runOpTest(OpType::CmpEQ, inf, inf); - runOpTest(OpType::CmpEQ, -inf, -inf); - runOpTest(OpType::CmpEQ, nan, nan); - runOpTest(OpType::CmpEQ, inf, -inf); - runOpTest(OpType::CmpEQ, -inf, inf); - runOpTest(OpType::CmpEQ, inf, nan); - runOpTest(OpType::CmpEQ, nan, inf); - runOpTest(OpType::CmpEQ, -inf, nan); - runOpTest(OpType::CmpEQ, nan, -inf); - - runOpTest(OpType::CmpEQ, 5, inf); - runOpTest(OpType::CmpEQ, 5, -inf); - runOpTest(OpType::CmpEQ, 5, nan); - runOpTest(OpType::CmpEQ, 0, nan); - - runOpTest(OpType::CmpEQ, true, "true"); - runOpTest(OpType::CmpEQ, "true", true); - runOpTest(OpType::CmpEQ, false, "false"); - runOpTest(OpType::CmpEQ, "false", false); - runOpTest(OpType::CmpEQ, false, "true"); - runOpTest(OpType::CmpEQ, "true", false); - runOpTest(OpType::CmpEQ, true, "false"); - runOpTest(OpType::CmpEQ, "false", true); - runOpTest(OpType::CmpEQ, true, "TRUE"); - runOpTest(OpType::CmpEQ, "TRUE", true); - runOpTest(OpType::CmpEQ, false, "FALSE"); - runOpTest(OpType::CmpEQ, "FALSE", false); - - runOpTest(OpType::CmpEQ, true, "00001"); - runOpTest(OpType::CmpEQ, "00001", true); - runOpTest(OpType::CmpEQ, true, "00000"); - runOpTest(OpType::CmpEQ, "00000", true); - runOpTest(OpType::CmpEQ, false, "00000"); - runOpTest(OpType::CmpEQ, "00000", false); - - runOpTest(OpType::CmpEQ, "true", 1); - runOpTest(OpType::CmpEQ, 1, "true"); - runOpTest(OpType::CmpEQ, "true", 0); - runOpTest(OpType::CmpEQ, 0, "true"); - runOpTest(OpType::CmpEQ, "false", 0); - runOpTest(OpType::CmpEQ, 0, "false"); - runOpTest(OpType::CmpEQ, "false", 1); - runOpTest(OpType::CmpEQ, 1, "false"); - - runOpTest(OpType::CmpEQ, "true", "TRUE"); - runOpTest(OpType::CmpEQ, "true", "FALSE"); - runOpTest(OpType::CmpEQ, "false", "FALSE"); - runOpTest(OpType::CmpEQ, "false", "TRUE"); - - runOpTest(OpType::CmpEQ, true, inf); - runOpTest(OpType::CmpEQ, true, -inf); - runOpTest(OpType::CmpEQ, true, nan); - runOpTest(OpType::CmpEQ, false, inf); - runOpTest(OpType::CmpEQ, false, -inf); - runOpTest(OpType::CmpEQ, false, nan); - - runOpTest(OpType::CmpEQ, "Infinity", inf); - runOpTest(OpType::CmpEQ, "Infinity", -inf); - runOpTest(OpType::CmpEQ, "Infinity", nan); - runOpTest(OpType::CmpEQ, "infinity", inf); - runOpTest(OpType::CmpEQ, "infinity", -inf); - runOpTest(OpType::CmpEQ, "infinity", nan); - runOpTest(OpType::CmpEQ, "-Infinity", inf); - runOpTest(OpType::CmpEQ, "-Infinity", -inf); - runOpTest(OpType::CmpEQ, "-Infinity", nan); - runOpTest(OpType::CmpEQ, "-infinity", inf); - runOpTest(OpType::CmpEQ, "-infinity", -inf); - runOpTest(OpType::CmpEQ, "-infinity", nan); - runOpTest(OpType::CmpEQ, "NaN", inf); - runOpTest(OpType::CmpEQ, "NaN", -inf); - runOpTest(OpType::CmpEQ, "NaN", nan); - runOpTest(OpType::CmpEQ, "nan", inf); - runOpTest(OpType::CmpEQ, "nan", -inf); - runOpTest(OpType::CmpEQ, "nan", nan); - - runOpTest(OpType::CmpEQ, inf, "abc"); - runOpTest(OpType::CmpEQ, inf, " "); - runOpTest(OpType::CmpEQ, inf, ""); - runOpTest(OpType::CmpEQ, inf, "0"); - runOpTest(OpType::CmpEQ, -inf, "abc"); - runOpTest(OpType::CmpEQ, -inf, " "); - runOpTest(OpType::CmpEQ, -inf, ""); - runOpTest(OpType::CmpEQ, -inf, "0"); - runOpTest(OpType::CmpEQ, nan, "abc"); - runOpTest(OpType::CmpEQ, nan, " "); - runOpTest(OpType::CmpEQ, nan, ""); - runOpTest(OpType::CmpEQ, nan, "0"); -} - -TEST_F(LLVMCodeBuilderTest, GreaterAndLowerThanComparison) -{ - std::vector opTypes = { OpType::CmpGT, OpType::CmpLT }; - - for (OpType type : opTypes) { - runOpTest(type, 10, 10); - runOpTest(type, 10, 8); - runOpTest(type, 8, 10); - - runOpTest(type, -4.25, -4.25); - runOpTest(type, -4.25, 5.312); - runOpTest(type, 5.312, -4.25); - - runOpTest(type, true, true); - runOpTest(type, true, false); - runOpTest(type, false, true); - - runOpTest(type, 1, true); - runOpTest(type, 1, false); - - runOpTest(type, "abC def", "abC def"); - runOpTest(type, "abC def", "abc dEf"); - runOpTest(type, "abC def", "ghi Jkl"); - runOpTest(type, "ghi Jkl", "abC def"); - runOpTest(type, "abC def", "hello world"); - - runOpTest(type, " ", ""); - runOpTest(type, " ", "0"); - runOpTest(type, " ", 0); - runOpTest(type, 0, " "); - runOpTest(type, "", "0"); - runOpTest(type, "", 0); - runOpTest(type, 0, ""); - runOpTest(type, "0", 0); - runOpTest(type, 0, "0"); - - runOpTest(type, 5.25, "5.25"); - runOpTest(type, "5.25", 5.25); - runOpTest(type, 5.25, " 5.25"); - runOpTest(type, " 5.25", 5.25); - runOpTest(type, 5.25, "5.25 "); - runOpTest(type, "5.25 ", 5.25); - runOpTest(type, 5.25, " 5.25 "); - runOpTest(type, " 5.25 ", 5.25); - runOpTest(type, 5.25, "5.26"); - runOpTest(type, "5.26", 5.25); - runOpTest(type, "5.25", "5.26"); - runOpTest(type, 5, "5 "); - runOpTest(type, "5 ", 5); - runOpTest(type, 0, "1"); - runOpTest(type, "1", 0); - runOpTest(type, 0, "test"); - runOpTest(type, "test", 0); - runOpTest(type, 55, "abc"); - runOpTest(type, "abc", 55); - - static const double inf = std::numeric_limits::infinity(); - static const double nan = std::numeric_limits::quiet_NaN(); - - runOpTest(type, inf, inf); - runOpTest(type, -inf, -inf); - runOpTest(type, nan, nan); - runOpTest(type, inf, -inf); - runOpTest(type, -inf, inf); - runOpTest(type, inf, nan); - runOpTest(type, nan, inf); - runOpTest(type, -inf, nan); - runOpTest(type, nan, -inf); - - runOpTest(type, 5, inf); - runOpTest(type, inf, 5); - runOpTest(type, 5, -inf); - runOpTest(type, -inf, 5); - runOpTest(type, 5, nan); - runOpTest(type, nan, 5); - runOpTest(type, 0, nan); - runOpTest(type, nan, 0); - - runOpTest(type, true, "true"); - runOpTest(type, "true", true); - runOpTest(type, false, "false"); - runOpTest(type, "false", false); - runOpTest(type, false, "true"); - runOpTest(type, "true", false); - runOpTest(type, true, "false"); - runOpTest(type, "false", true); - runOpTest(type, true, "TRUE"); - runOpTest(type, "TRUE", true); - runOpTest(type, false, "FALSE"); - runOpTest(type, "FALSE", false); - - runOpTest(type, true, "00001"); - runOpTest(type, "00001", true); - runOpTest(type, true, "00000"); - runOpTest(type, "00000", true); - runOpTest(type, false, "00000"); - runOpTest(type, "00000", false); - - runOpTest(type, "true", 1); - runOpTest(type, 1, "true"); - runOpTest(type, "true", 0); - runOpTest(type, 0, "true"); - runOpTest(type, "false", 0); - runOpTest(type, 0, "false"); - runOpTest(type, "false", 1); - runOpTest(type, 1, "false"); - - runOpTest(type, "true", "TRUE"); - runOpTest(type, "true", "FALSE"); - runOpTest(type, "false", "FALSE"); - runOpTest(type, "false", "TRUE"); - - runOpTest(type, true, inf); - runOpTest(type, inf, true); - runOpTest(type, true, -inf); - runOpTest(type, -inf, true); - runOpTest(type, true, nan); - runOpTest(type, nan, true); - runOpTest(type, false, inf); - runOpTest(type, inf, false); - runOpTest(type, false, -inf); - runOpTest(type, -inf, false); - runOpTest(type, false, nan); - runOpTest(type, nan, false); - - runOpTest(type, "Infinity", inf); - runOpTest(type, "Infinity", -inf); - runOpTest(type, "Infinity", nan); - runOpTest(type, "infinity", inf); - runOpTest(type, "infinity", -inf); - runOpTest(type, "infinity", nan); - runOpTest(type, "-Infinity", inf); - runOpTest(type, "-Infinity", -inf); - runOpTest(type, "-Infinity", nan); - runOpTest(type, "-infinity", inf); - runOpTest(type, "-infinity", -inf); - runOpTest(type, "-infinity", nan); - runOpTest(type, "NaN", inf); - runOpTest(type, "NaN", -inf); - runOpTest(type, "NaN", nan); - runOpTest(type, "nan", inf); - runOpTest(type, "nan", -inf); - runOpTest(type, "nan", nan); - - runOpTest(type, inf, "abc"); - runOpTest(type, inf, " "); - runOpTest(type, inf, ""); - runOpTest(type, inf, "0"); - runOpTest(type, -inf, "abc"); - runOpTest(type, -inf, " "); - runOpTest(type, -inf, ""); - runOpTest(type, -inf, "0"); - runOpTest(type, nan, "abc"); - runOpTest(type, nan, " "); - runOpTest(type, nan, ""); - runOpTest(type, nan, "0"); - } -} - -TEST_F(LLVMCodeBuilderTest, StringEqualComparison) -{ - std::vector types = { OpType::StrCmpEQCS, OpType::StrCmpEQCI }; - - for (OpType type : types) { - runOpTest(type, 10, 10); - runOpTest(type, 10, 8); - runOpTest(type, 8, 10); - - runOpTest(type, -4.25, -4.25); - runOpTest(type, -4.25, 5.312); - runOpTest(type, 5.312, -4.25); - - runOpTest(type, true, true); - runOpTest(type, true, false); - runOpTest(type, false, true); - - runOpTest(type, 1, true); - runOpTest(type, 1, false); - - runOpTest(type, "abC def", "abC def"); - runOpTest(type, "abC def", "abc dEf"); - runOpTest(type, "abC def", "ghi Jkl"); - runOpTest(type, "abC def", "hello world"); - - runOpTest(type, " ", ""); - runOpTest(type, " ", "0"); - runOpTest(type, " ", 0); - runOpTest(type, 0, " "); - runOpTest(type, "", "0"); - runOpTest(type, "", 0); - runOpTest(type, 0, ""); - runOpTest(type, "0", 0); - runOpTest(type, 0, "0"); - - runOpTest(type, 5.25, "5.25"); - runOpTest(type, "5.25", 5.25); - runOpTest(type, 5.25, " 5.25"); - runOpTest(type, " 5.25", 5.25); - runOpTest(type, 5.25, "5.25 "); - runOpTest(type, "5.25 ", 5.25); - runOpTest(type, 5.25, " 5.25 "); - runOpTest(type, " 5.25 ", 5.25); - runOpTest(type, 5.25, "5.26"); - runOpTest(type, "5.26", 5.25); - runOpTest(type, "5.25", "5.26"); - runOpTest(type, 5, "5 "); - runOpTest(type, "5 ", 5); - runOpTest(type, 0, "1"); - runOpTest(type, "1", 0); - runOpTest(type, 0, "test"); - runOpTest(type, "test", 0); - - static const double inf = std::numeric_limits::infinity(); - static const double nan = std::numeric_limits::quiet_NaN(); - - runOpTest(type, inf, inf); - runOpTest(type, -inf, -inf); - runOpTest(type, nan, nan); - runOpTest(type, inf, -inf); - runOpTest(type, -inf, inf); - runOpTest(type, inf, nan); - runOpTest(type, nan, inf); - runOpTest(type, -inf, nan); - runOpTest(type, nan, -inf); - - runOpTest(type, 5, inf); - runOpTest(type, 5, -inf); - runOpTest(type, 5, nan); - runOpTest(type, 0, nan); - - runOpTest(type, true, "true"); - runOpTest(type, "true", true); - runOpTest(type, false, "false"); - runOpTest(type, "false", false); - runOpTest(type, false, "true"); - runOpTest(type, "true", false); - runOpTest(type, true, "false"); - runOpTest(type, "false", true); - runOpTest(type, true, "TRUE"); - runOpTest(type, "TRUE", true); - runOpTest(type, false, "FALSE"); - runOpTest(type, "FALSE", false); - - runOpTest(type, true, "00001"); - runOpTest(type, "00001", true); - runOpTest(type, true, "00000"); - runOpTest(type, "00000", true); - runOpTest(type, false, "00000"); - runOpTest(type, "00000", false); - - runOpTest(type, "true", 1); - runOpTest(type, 1, "true"); - runOpTest(type, "true", 0); - runOpTest(type, 0, "true"); - runOpTest(type, "false", 0); - runOpTest(type, 0, "false"); - runOpTest(type, "false", 1); - runOpTest(type, 1, "false"); - - runOpTest(type, "true", "TRUE"); - runOpTest(type, "true", "FALSE"); - runOpTest(type, "false", "FALSE"); - runOpTest(type, "false", "TRUE"); - - runOpTest(type, true, inf); - runOpTest(type, true, -inf); - runOpTest(type, true, nan); - runOpTest(type, false, inf); - runOpTest(type, false, -inf); - runOpTest(type, false, nan); - - runOpTest(type, "Infinity", inf); - runOpTest(type, "Infinity", -inf); - runOpTest(type, "Infinity", nan); - runOpTest(type, "infinity", inf); - runOpTest(type, "infinity", -inf); - runOpTest(type, "infinity", nan); - runOpTest(type, "-Infinity", inf); - runOpTest(type, "-Infinity", -inf); - runOpTest(type, "-Infinity", nan); - runOpTest(type, "-infinity", inf); - runOpTest(type, "-infinity", -inf); - runOpTest(type, "-infinity", nan); - runOpTest(type, "NaN", inf); - runOpTest(type, "NaN", -inf); - runOpTest(type, "NaN", nan); - runOpTest(type, "nan", inf); - runOpTest(type, "nan", -inf); - runOpTest(type, "nan", nan); - - runOpTest(type, inf, "abc"); - runOpTest(type, inf, " "); - runOpTest(type, inf, ""); - runOpTest(type, inf, "0"); - runOpTest(type, -inf, "abc"); - runOpTest(type, -inf, " "); - runOpTest(type, -inf, ""); - runOpTest(type, -inf, "0"); - runOpTest(type, nan, "abc"); - runOpTest(type, nan, " "); - runOpTest(type, nan, ""); - runOpTest(type, nan, "0"); - } -} - -TEST_F(LLVMCodeBuilderTest, AndOr) -{ - std::vector opTypes = { OpType::And, OpType::Or }; - - for (OpType type : opTypes) { - runOpTest(type, 10, 8); - runOpTest(type, -4.25, -4.25); - runOpTest(type, -4.25, 5.312); - - runOpTest(type, true, true); - runOpTest(type, true, false); - runOpTest(type, false, true); - - runOpTest(type, 1, true); - runOpTest(type, 1, false); - - runOpTest(type, "abc", "def"); - runOpTest(type, "true", "true"); - runOpTest(type, "true", "false"); - runOpTest(type, "false", "true"); - runOpTest(type, "false", "false"); - - runOpTest(type, 5.25, "5.25"); - runOpTest(type, "5.25", 5.25); - runOpTest(type, 0, "1"); - runOpTest(type, "1", 0); - runOpTest(type, 0, "test"); - runOpTest(type, "test", 0); - - static const double inf = std::numeric_limits::infinity(); - static const double nan = std::numeric_limits::quiet_NaN(); - - runOpTest(type, inf, inf); - runOpTest(type, -inf, -inf); - runOpTest(type, nan, nan); - runOpTest(type, inf, -inf); - runOpTest(type, -inf, inf); - runOpTest(type, inf, nan); - runOpTest(type, nan, inf); - runOpTest(type, -inf, nan); - runOpTest(type, nan, -inf); - - runOpTest(type, true, "true"); - runOpTest(type, "true", true); - runOpTest(type, false, "false"); - runOpTest(type, "false", false); - runOpTest(type, false, "true"); - runOpTest(type, "true", false); - runOpTest(type, true, "false"); - runOpTest(type, "false", true); - runOpTest(type, true, "TRUE"); - runOpTest(type, "TRUE", true); - runOpTest(type, false, "FALSE"); - runOpTest(type, "FALSE", false); - - runOpTest(type, true, "00001"); - runOpTest(type, "00001", true); - runOpTest(type, true, "00000"); - runOpTest(type, "00000", true); - runOpTest(type, false, "00000"); - runOpTest(type, "00000", false); - - runOpTest(type, "true", 1); - runOpTest(type, 1, "true"); - runOpTest(type, "true", 0); - runOpTest(type, 0, "true"); - runOpTest(type, "false", 0); - runOpTest(type, 0, "false"); - runOpTest(type, "false", 1); - runOpTest(type, 1, "false"); - - runOpTest(type, "true", "TRUE"); - runOpTest(type, "true", "FALSE"); - runOpTest(type, "false", "FALSE"); - runOpTest(type, "false", "TRUE"); - - runOpTest(type, true, inf); - runOpTest(type, inf, true); - runOpTest(type, true, -inf); - runOpTest(type, -inf, true); - runOpTest(type, true, nan); - runOpTest(type, nan, true); - runOpTest(type, false, inf); - runOpTest(type, inf, false); - runOpTest(type, false, -inf); - runOpTest(type, -inf, false); - runOpTest(type, false, nan); - runOpTest(type, nan, false); - - runOpTest(type, "Infinity", inf); - runOpTest(type, "Infinity", -inf); - runOpTest(type, "Infinity", nan); - runOpTest(type, "infinity", inf); - runOpTest(type, "infinity", -inf); - runOpTest(type, "infinity", nan); - runOpTest(type, "-Infinity", inf); - runOpTest(type, "-Infinity", -inf); - runOpTest(type, "-Infinity", nan); - runOpTest(type, "-infinity", inf); - runOpTest(type, "-infinity", -inf); - runOpTest(type, "-infinity", nan); - runOpTest(type, "NaN", inf); - runOpTest(type, "NaN", -inf); - runOpTest(type, "NaN", nan); - runOpTest(type, "nan", inf); - runOpTest(type, "nan", -inf); - runOpTest(type, "nan", nan); - } -} - -TEST_F(LLVMCodeBuilderTest, Not) -{ - runOpTest(OpType::Not, 10); - runOpTest(OpType::Not, -4.25); - runOpTest(OpType::Not, 5.312); - runOpTest(OpType::Not, 1); - runOpTest(OpType::Not, 0); - - runOpTest(OpType::Not, true); - runOpTest(OpType::Not, false); - - runOpTest(OpType::Not, "abc"); - runOpTest(OpType::Not, "5.25"); - runOpTest(OpType::Not, "0"); - - static const double inf = std::numeric_limits::infinity(); - static const double nan = std::numeric_limits::quiet_NaN(); - - runOpTest(OpType::Not, inf); - runOpTest(OpType::Not, -inf); - runOpTest(OpType::Not, nan); - - runOpTest(OpType::Not, "true"); - runOpTest(OpType::Not, "false"); - runOpTest(OpType::Not, "TRUE"); - runOpTest(OpType::Not, "FALSE"); - - runOpTest(OpType::Not, "00001"); - runOpTest(OpType::Not, "00000"); - - runOpTest(OpType::Not, "Infinity"); - runOpTest(OpType::Not, "infinity"); - runOpTest(OpType::Not, "-Infinity"); - runOpTest(OpType::Not, "-infinity"); - runOpTest(OpType::Not, "NaN"); - runOpTest(OpType::Not, "nan"); -} - -TEST_F(LLVMCodeBuilderTest, Mod) -{ - runOpTest(OpType::Mod, 4, 3); - runOpTest(OpType::Mod, 3, 3); - runOpTest(OpType::Mod, 2, 3); - runOpTest(OpType::Mod, 1, 3); - runOpTest(OpType::Mod, 0, 3); - runOpTest(OpType::Mod, -1, 3); - runOpTest(OpType::Mod, -2, 3); - runOpTest(OpType::Mod, -3, 3); - runOpTest(OpType::Mod, -4, 3); - runOpTest(OpType::Mod, 4.75, 2); - runOpTest(OpType::Mod, -4.75, 2); - runOpTest(OpType::Mod, -4.75, -2); - runOpTest(OpType::Mod, 4.75, -2); - runOpTest(OpType::Mod, 5, 0); - runOpTest(OpType::Mod, -5, 0); - runOpTest(OpType::Mod, -2.5, "Infinity"); - runOpTest(OpType::Mod, -1.2, "-Infinity"); - runOpTest(OpType::Mod, 2.5, "Infinity"); - runOpTest(OpType::Mod, 1.2, "-Infinity"); - runOpTest(OpType::Mod, "Infinity", 2); - runOpTest(OpType::Mod, "-Infinity", 2); - runOpTest(OpType::Mod, "Infinity", -2); - runOpTest(OpType::Mod, "-Infinity", -2); - runOpTest(OpType::Mod, 3, "NaN"); - runOpTest(OpType::Mod, -3, "NaN"); - runOpTest(OpType::Mod, "NaN", 5); - runOpTest(OpType::Mod, "NaN", -5); -} - -TEST_F(LLVMCodeBuilderTest, Round) -{ - static const double inf = std::numeric_limits::infinity(); - static const double nan = std::numeric_limits::quiet_NaN(); - - runUnaryNumOpTest(OpType::Round, 4.0, 4.0); - runUnaryNumOpTest(OpType::Round, 3.2, 3.0); - runUnaryNumOpTest(OpType::Round, 3.5, 4.0); - runUnaryNumOpTest(OpType::Round, 3.6, 4.0); - runUnaryNumOpTest(OpType::Round, -2.4, -2.0); - runUnaryNumOpTest(OpType::Round, -2.5, -2.0); - runUnaryNumOpTest(OpType::Round, -2.6, -3.0); - runUnaryNumOpTest(OpType::Round, -0.4, -0.0); - runUnaryNumOpTest(OpType::Round, -0.5, -0.0); - runUnaryNumOpTest(OpType::Round, -0.51, -1.0); - runUnaryNumOpTest(OpType::Round, inf, inf); - runUnaryNumOpTest(OpType::Round, -inf, -inf); - runUnaryNumOpTest(OpType::Round, nan, 0); -} - -TEST_F(LLVMCodeBuilderTest, Abs) -{ - static const double inf = std::numeric_limits::infinity(); - static const double nan = std::numeric_limits::quiet_NaN(); - - runUnaryNumOpTest(OpType::Abs, 4.0, 4.0); - runUnaryNumOpTest(OpType::Abs, 3.2, 3.2); - runUnaryNumOpTest(OpType::Abs, -2.0, 2.0); - runUnaryNumOpTest(OpType::Abs, -2.5, 2.5); - runUnaryNumOpTest(OpType::Abs, -2.6, 2.6); - runUnaryNumOpTest(OpType::Abs, 0.0, 0.0); - runUnaryNumOpTest(OpType::Abs, -0.0, 0.0); - runUnaryNumOpTest(OpType::Abs, inf, inf); - runUnaryNumOpTest(OpType::Abs, -inf, inf); - runUnaryNumOpTest(OpType::Abs, nan, 0); -} - -TEST_F(LLVMCodeBuilderTest, Floor) -{ - static const double inf = std::numeric_limits::infinity(); - static const double nan = std::numeric_limits::quiet_NaN(); - - runUnaryNumOpTest(OpType::Floor, 4.0, 4.0); - runUnaryNumOpTest(OpType::Floor, 3.2, 3.0); - runUnaryNumOpTest(OpType::Floor, 3.5, 3.0); - runUnaryNumOpTest(OpType::Floor, 3.6, 3.0); - runUnaryNumOpTest(OpType::Floor, 0.0, 0.0); - runUnaryNumOpTest(OpType::Floor, -0.0, -0.0); - runUnaryNumOpTest(OpType::Floor, -2.4, -3.0); - runUnaryNumOpTest(OpType::Floor, -2.5, -3.0); - runUnaryNumOpTest(OpType::Floor, -2.6, -3.0); - runUnaryNumOpTest(OpType::Floor, -0.4, -1.0); - runUnaryNumOpTest(OpType::Floor, -0.5, -1.0); - runUnaryNumOpTest(OpType::Floor, -0.51, -1.0); - runUnaryNumOpTest(OpType::Floor, inf, inf); - runUnaryNumOpTest(OpType::Floor, -inf, -inf); - runUnaryNumOpTest(OpType::Floor, nan, 0); -} - -TEST_F(LLVMCodeBuilderTest, Ceil) -{ - static const double inf = std::numeric_limits::infinity(); - static const double nan = std::numeric_limits::quiet_NaN(); - - runUnaryNumOpTest(OpType::Ceil, 8.0, 8.0); - runUnaryNumOpTest(OpType::Ceil, 3.2, 4.0); - runUnaryNumOpTest(OpType::Ceil, 3.5, 4.0); - runUnaryNumOpTest(OpType::Ceil, 3.6, 4.0); - runUnaryNumOpTest(OpType::Ceil, 0.4, 1.0); - runUnaryNumOpTest(OpType::Ceil, 0.0, 0.0); - runUnaryNumOpTest(OpType::Ceil, -0.0, -0.0); - runUnaryNumOpTest(OpType::Ceil, -2.4, -2.0); - runUnaryNumOpTest(OpType::Ceil, -2.5, -2.0); - runUnaryNumOpTest(OpType::Ceil, -2.6, -2.0); - runUnaryNumOpTest(OpType::Ceil, -0.4, -0.0); - runUnaryNumOpTest(OpType::Ceil, -0.5, -0.0); - runUnaryNumOpTest(OpType::Ceil, -0.51, -0.0); - runUnaryNumOpTest(OpType::Ceil, inf, inf); - runUnaryNumOpTest(OpType::Ceil, -inf, -inf); - runUnaryNumOpTest(OpType::Ceil, nan, 0); -} - -TEST_F(LLVMCodeBuilderTest, Sqrt) -{ - static const double inf = std::numeric_limits::infinity(); - static const double nan = std::numeric_limits::quiet_NaN(); - - runUnaryNumOpTest(OpType::Sqrt, 16.0, 4.0); - runUnaryNumOpTest(OpType::Sqrt, 0.04, 0.2); - runUnaryNumOpTest(OpType::Sqrt, 0.0, 0.0); - runUnaryNumOpTest(OpType::Sqrt, -0.0, 0.0); - runUnaryNumOpTest(OpType::Sqrt, -4.0, -nan); // negative NaN shouldn't be a problem - runUnaryNumOpTest(OpType::Sqrt, inf, inf); - runUnaryNumOpTest(OpType::Sqrt, -inf, -nan); - runUnaryNumOpTest(OpType::Sqrt, nan, 0); -} - -TEST_F(LLVMCodeBuilderTest, Sin) -{ - static const double inf = std::numeric_limits::infinity(); - static const double nan = std::numeric_limits::quiet_NaN(); - - runUnaryNumOpTest(OpType::Sin, 30.0, 0.5); - runUnaryNumOpTest(OpType::Sin, 90.0, 1.0); - runUnaryNumOpTest(OpType::Sin, 2.8e-9, 0.0); - runUnaryNumOpTest(OpType::Sin, 2.9e-9, 1e-10); - runUnaryNumOpTest(OpType::Sin, 570.0, -0.5); - runUnaryNumOpTest(OpType::Sin, -30.0, -0.5); - runUnaryNumOpTest(OpType::Sin, -90.0, -1.0); - runUnaryNumOpTest(OpType::Sin, 0.0, 0.0); - runUnaryNumOpTest(OpType::Sin, -0.0, 0.0); - runUnaryNumOpTest(OpType::Sin, inf, -nan); // negative NaN shouldn't be a problem - runUnaryNumOpTest(OpType::Sin, -inf, -nan); - runUnaryNumOpTest(OpType::Sin, nan, 0); -} - -TEST_F(LLVMCodeBuilderTest, Cos) -{ - static const double inf = std::numeric_limits::infinity(); - static const double nan = std::numeric_limits::quiet_NaN(); - - runUnaryNumOpTest(OpType::Cos, 60.0, 0.5); - runUnaryNumOpTest(OpType::Cos, 90.0, 0.0); - runUnaryNumOpTest(OpType::Cos, 600.0, -0.5); - runUnaryNumOpTest(OpType::Cos, 89.9999999971352, 1e-10); - runUnaryNumOpTest(OpType::Cos, 89.999999999, 0.0); - runUnaryNumOpTest(OpType::Cos, -60.0, 0.5); - runUnaryNumOpTest(OpType::Cos, -90.0, 0.0); - runUnaryNumOpTest(OpType::Cos, 0.0, 1.0); - runUnaryNumOpTest(OpType::Cos, -0.0, 1.0); - runUnaryNumOpTest(OpType::Cos, inf, -nan); // negative NaN shouldn't be a problem - runUnaryNumOpTest(OpType::Cos, -inf, -nan); - runUnaryNumOpTest(OpType::Cos, nan, 1.0); -} - -TEST_F(LLVMCodeBuilderTest, Tan) -{ - static const double inf = std::numeric_limits::infinity(); - static const double nan = std::numeric_limits::quiet_NaN(); - - runUnaryNumOpTest(OpType::Tan, 45.0, 1.0); - runUnaryNumOpTest(OpType::Tan, 90.0, inf); - runUnaryNumOpTest(OpType::Tan, 270.0, -inf); - runUnaryNumOpTest(OpType::Tan, 450.0, inf); - runUnaryNumOpTest(OpType::Tan, -90.0, -inf); - runUnaryNumOpTest(OpType::Tan, -270.0, inf); - runUnaryNumOpTest(OpType::Tan, -450.0, -inf); - runUnaryNumOpTest(OpType::Tan, 180.0, 0.0); - runUnaryNumOpTest(OpType::Tan, -180.0, 0.0); - runUnaryNumOpTest(OpType::Tan, 2.87e-9, 1e-10); - runUnaryNumOpTest(OpType::Tan, 2.8647e-9, 0.0); - runUnaryNumOpTest(OpType::Tan, 0.0, 0.0); - runUnaryNumOpTest(OpType::Tan, -0.0, 0.0); - runUnaryNumOpTest(OpType::Tan, inf, -nan); // negative NaN shouldn't be a problem - runUnaryNumOpTest(OpType::Tan, -inf, -nan); - runUnaryNumOpTest(OpType::Tan, nan, 0.0); -} - -TEST_F(LLVMCodeBuilderTest, Asin) -{ - static const double inf = std::numeric_limits::infinity(); - static const double nan = std::numeric_limits::quiet_NaN(); - - runUnaryNumOpTest(OpType::Asin, 1.0, 90.0); - runUnaryNumOpTest(OpType::Asin, 0.5, 30.0); - runUnaryNumOpTest(OpType::Asin, 0.0, 0.0); - runUnaryNumOpTest(OpType::Asin, -0.0, 0.0); - runUnaryNumOpTest(OpType::Asin, -0.5, -30.0); - runUnaryNumOpTest(OpType::Asin, -1.0, -90.0); - runUnaryNumOpTest(OpType::Asin, 1.1, nan); - runUnaryNumOpTest(OpType::Asin, -1.2, nan); - runUnaryNumOpTest(OpType::Asin, inf, nan); - runUnaryNumOpTest(OpType::Asin, -inf, nan); - runUnaryNumOpTest(OpType::Asin, nan, 0.0); -} - -TEST_F(LLVMCodeBuilderTest, Acos) -{ - static const double inf = std::numeric_limits::infinity(); - static const double nan = std::numeric_limits::quiet_NaN(); - - runUnaryNumOpTest(OpType::Acos, 1.0, 0.0); - runUnaryNumOpTest(OpType::Acos, 0.5, 60.0); - runUnaryNumOpTest(OpType::Acos, 0.0, 90.0); - runUnaryNumOpTest(OpType::Acos, -0.0, 90.0); - runUnaryNumOpTest(OpType::Acos, -0.5, 120.0); - runUnaryNumOpTest(OpType::Acos, -1.0, 180.0); - runUnaryNumOpTest(OpType::Acos, 1.1, nan); - runUnaryNumOpTest(OpType::Acos, -1.2, nan); - runUnaryNumOpTest(OpType::Acos, inf, nan); - runUnaryNumOpTest(OpType::Acos, -inf, nan); - runUnaryNumOpTest(OpType::Acos, nan, 90.0); -} - -TEST_F(LLVMCodeBuilderTest, Atan) -{ - static const double inf = std::numeric_limits::infinity(); - static const double nan = std::numeric_limits::quiet_NaN(); - - runUnaryNumOpTest(OpType::Atan, 1.0, 45.0); - runUnaryNumOpTest(OpType::Atan, 0.0, 0.0); - runUnaryNumOpTest(OpType::Atan, -0.0, -0.0); - runUnaryNumOpTest(OpType::Atan, -1.0, -45.0); - runUnaryNumOpTest(OpType::Atan, inf, 90.0); - runUnaryNumOpTest(OpType::Atan, -inf, -90.0); - runUnaryNumOpTest(OpType::Atan, nan, 0.0); -} - -TEST_F(LLVMCodeBuilderTest, Ln) -{ - static const double inf = std::numeric_limits::infinity(); - static const double nan = std::numeric_limits::quiet_NaN(); - - runUnaryNumOpTest(OpType::Ln, std::exp(1.0), 1.0); - runUnaryNumOpTest(OpType::Ln, std::exp(2.0), 2.0); - runUnaryNumOpTest(OpType::Ln, std::exp(0.3), 0.3); - runUnaryNumOpTest(OpType::Ln, 1.0, 0.0); - runUnaryNumOpTest(OpType::Ln, 0.0, -inf); - runUnaryNumOpTest(OpType::Ln, -0.0, -inf); - runUnaryNumOpTest(OpType::Ln, -0.7, -nan); // negative NaN shouldn't be a problem - runUnaryNumOpTest(OpType::Ln, inf, inf); - runUnaryNumOpTest(OpType::Ln, -inf, -nan); - runUnaryNumOpTest(OpType::Ln, nan, -inf); -} - -TEST_F(LLVMCodeBuilderTest, Log10) -{ - static const double inf = std::numeric_limits::infinity(); - static const double nan = std::numeric_limits::quiet_NaN(); - - runUnaryNumOpTest(OpType::Log10, 10.0, 1.0); - runUnaryNumOpTest(OpType::Log10, 1000.0, 3.0); - runUnaryNumOpTest(OpType::Log10, 0.01, -2.0); - runUnaryNumOpTest(OpType::Log10, 0.0, -inf); - runUnaryNumOpTest(OpType::Log10, -0.0, -inf); - runUnaryNumOpTest(OpType::Log10, -0.7, nan); - runUnaryNumOpTest(OpType::Log10, inf, inf); - runUnaryNumOpTest(OpType::Log10, -inf, nan); - runUnaryNumOpTest(OpType::Log10, nan, -inf); -} - -TEST_F(LLVMCodeBuilderTest, Exp) -{ - static const double inf = std::numeric_limits::infinity(); - static const double nan = std::numeric_limits::quiet_NaN(); - - runUnaryNumOpTest(OpType::Exp, 1.0, std::exp(1.0)); - runUnaryNumOpTest(OpType::Exp, 0.5, std::exp(0.5)); - runUnaryNumOpTest(OpType::Exp, 0.0, 1.0); - runUnaryNumOpTest(OpType::Exp, -0.0, 1.0); - runUnaryNumOpTest(OpType::Exp, -0.7, std::exp(-0.7)); - runUnaryNumOpTest(OpType::Exp, inf, inf); - runUnaryNumOpTest(OpType::Exp, -inf, 0.0); - runUnaryNumOpTest(OpType::Exp, nan, 1.0); -} - -TEST_F(LLVMCodeBuilderTest, Exp10) -{ - static const double inf = std::numeric_limits::infinity(); - static const double nan = std::numeric_limits::quiet_NaN(); - - runUnaryNumOpTest(OpType::Exp10, 1.0, 10.0); - runUnaryNumOpTest(OpType::Exp10, 3.0, 1000.0); - runUnaryNumOpTest(OpType::Exp10, 0.0, 1.0); - runUnaryNumOpTest(OpType::Exp10, -0.0, 1.0); - runUnaryNumOpTest(OpType::Exp10, -1.0, 0.1); - runUnaryNumOpTest(OpType::Exp10, -5.0, 0.00001); - runUnaryNumOpTest(OpType::Exp10, inf, inf); - runUnaryNumOpTest(OpType::Exp10, -inf, 0.0); - runUnaryNumOpTest(OpType::Exp10, nan, 1.0); -} - -TEST_F(LLVMCodeBuilderTest, StringConcat) -{ - runOpTest(OpType::StringConcat, "Hello ", "world"); - runOpTest(OpType::StringConcat, "abc", "def"); - runOpTest(OpType::StringConcat, "ábč", "ďéfgh"); -} - -TEST_F(LLVMCodeBuilderTest, StringChar) -{ - runOpTest(OpType::StringChar, "Hello world", 1); - runOpTest(OpType::StringChar, "Hello world", 0); - runOpTest(OpType::StringChar, "Hello world", 11); - runOpTest(OpType::StringChar, "abc", 2); - runOpTest(OpType::StringChar, "abc", -1); - runOpTest(OpType::StringChar, "abc", 3); - runOpTest(OpType::StringChar, "ábč", 0); -} - -TEST_F(LLVMCodeBuilderTest, StringLength) -{ - runUnaryNumOpTest(OpType::StringLength, "Hello world", 11); - runUnaryNumOpTest(OpType::StringLength, "abc", 3); - runUnaryNumOpTest(OpType::StringLength, "abcdef", 6); - runUnaryNumOpTest(OpType::StringLength, "ábč", 3); -} - TEST_F(LLVMCodeBuilderTest, LocalVariables) { Stage stage; diff --git a/test/llvm/operators/equal_comparison_test.cpp b/test/llvm/operators/equal_comparison_test.cpp new file mode 100644 index 000000000..0e2c09a99 --- /dev/null +++ b/test/llvm/operators/equal_comparison_test.cpp @@ -0,0 +1,1205 @@ +#include +#include + +#include "llvmtestutils.h" + +class LLVMEqualComparisonTest : public testing::Test +{ + public: + LLVMTestUtils m_utils; +}; + +TEST_F(LLVMEqualComparisonTest, SameIntegers) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, 10, 10); +} + +TEST_F(LLVMEqualComparisonTest, SameIntegers_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, 10, 10); +} + +TEST_F(LLVMEqualComparisonTest, DifferentIntegers) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, 10, 8); +} + +TEST_F(LLVMEqualComparisonTest, DifferentIntegers_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, 10, 8); +} + +TEST_F(LLVMEqualComparisonTest, DifferentIntegersReversed) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, 8, 10); +} + +TEST_F(LLVMEqualComparisonTest, DifferentIntegersReversed_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, 8, 10); +} + +TEST_F(LLVMEqualComparisonTest, SameDecimals) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, -4.25, -4.25); +} + +TEST_F(LLVMEqualComparisonTest, SameDecimals_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, -4.25, -4.25); +} + +TEST_F(LLVMEqualComparisonTest, DifferentDecimals) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, -4.25, 5.312); +} + +TEST_F(LLVMEqualComparisonTest, DifferentDecimals_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, -4.25, 5.312); +} + +TEST_F(LLVMEqualComparisonTest, DifferentDecimalsReversed) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, 5.312, -4.25); +} + +TEST_F(LLVMEqualComparisonTest, DifferentDecimalsReversed_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, 5.312, -4.25); +} + +TEST_F(LLVMEqualComparisonTest, SameBooleans) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, true, true); +} + +TEST_F(LLVMEqualComparisonTest, SameBooleans_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, true, true); +} + +TEST_F(LLVMEqualComparisonTest, DifferentBooleans) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, true, false); +} + +TEST_F(LLVMEqualComparisonTest, DifferentBooleans_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, true, false); +} + +TEST_F(LLVMEqualComparisonTest, DifferentBooleansReversed) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, false, true); +} + +TEST_F(LLVMEqualComparisonTest, DifferentBooleansReversed_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, false, true); +} + +TEST_F(LLVMEqualComparisonTest, NumberWithTrueBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, 1, true); +} + +TEST_F(LLVMEqualComparisonTest, NumberWithTrueBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, 1, true); +} + +TEST_F(LLVMEqualComparisonTest, NumberWithFalseBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, 1, false); +} + +TEST_F(LLVMEqualComparisonTest, NumberWithFalseBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, 1, false); +} + +TEST_F(LLVMEqualComparisonTest, SameStrings) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "abC def", "abC def"); +} + +TEST_F(LLVMEqualComparisonTest, SameStrings_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "abC def", "abC def"); +} + +TEST_F(LLVMEqualComparisonTest, StringsCaseDifferent) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "abC def", "abc dEf"); +} + +TEST_F(LLVMEqualComparisonTest, StringsCaseDifferent_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "abC def", "abc dEf"); +} + +TEST_F(LLVMEqualComparisonTest, DifferentStrings) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "abC def", "ghi Jkl"); +} + +TEST_F(LLVMEqualComparisonTest, DifferentStrings_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "abC def", "ghi Jkl"); +} + +TEST_F(LLVMEqualComparisonTest, DifferentStringsLonger) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "abC def", "hello world"); +} + +TEST_F(LLVMEqualComparisonTest, DifferentStringsLonger_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "abC def", "hello world"); +} + +TEST_F(LLVMEqualComparisonTest, SpaceVsEmpty) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, " ", ""); +} + +TEST_F(LLVMEqualComparisonTest, SpaceVsEmpty_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, " ", ""); +} + +TEST_F(LLVMEqualComparisonTest, SpaceVsZeroString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, " ", "0"); +} + +TEST_F(LLVMEqualComparisonTest, SpaceVsZeroString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, " ", "0"); +} + +TEST_F(LLVMEqualComparisonTest, SpaceVsZeroNumber) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, " ", 0); +} + +TEST_F(LLVMEqualComparisonTest, SpaceVsZeroNumber_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, " ", 0); +} + +TEST_F(LLVMEqualComparisonTest, ZeroNumberVsSpace) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, 0, " "); +} + +TEST_F(LLVMEqualComparisonTest, ZeroNumberVsSpace_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, 0, " "); +} + +TEST_F(LLVMEqualComparisonTest, EmptyVsZeroString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "", "0"); +} + +TEST_F(LLVMEqualComparisonTest, EmptyVsZeroString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "", "0"); +} + +TEST_F(LLVMEqualComparisonTest, EmptyVsZeroNumber) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "", 0); +} + +TEST_F(LLVMEqualComparisonTest, EmptyVsZeroNumber_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "", 0); +} + +TEST_F(LLVMEqualComparisonTest, ZeroNumberVsEmpty) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, 0, ""); +} + +TEST_F(LLVMEqualComparisonTest, ZeroNumberVsEmpty_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, 0, ""); +} + +TEST_F(LLVMEqualComparisonTest, ZeroStringVsZeroNumber) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "0", 0); +} + +TEST_F(LLVMEqualComparisonTest, ZeroStringVsZeroNumber_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "0", 0); +} + +TEST_F(LLVMEqualComparisonTest, ZeroNumberVsZeroString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, 0, "0"); +} + +TEST_F(LLVMEqualComparisonTest, ZeroNumberVsZeroString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, 0, "0"); +} + +TEST_F(LLVMEqualComparisonTest, NumberVsExactString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, 5.25, "5.25"); +} + +TEST_F(LLVMEqualComparisonTest, NumberVsExactString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, 5.25, "5.25"); +} + +TEST_F(LLVMEqualComparisonTest, ExactStringVsNumber) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "5.25", 5.25); +} + +TEST_F(LLVMEqualComparisonTest, ExactStringVsNumber_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "5.25", 5.25); +} + +TEST_F(LLVMEqualComparisonTest, NumberVsStringWithLeadingSpace) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, 5.25, " 5.25"); +} + +TEST_F(LLVMEqualComparisonTest, NumberVsStringWithLeadingSpace_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, 5.25, " 5.25"); +} + +TEST_F(LLVMEqualComparisonTest, StringWithLeadingSpaceVsNumber) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, " 5.25", 5.25); +} + +TEST_F(LLVMEqualComparisonTest, StringWithLeadingSpaceVsNumber_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, " 5.25", 5.25); +} + +TEST_F(LLVMEqualComparisonTest, NumberVsStringWithTrailingSpace) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, 5.25, "5.25 "); +} + +TEST_F(LLVMEqualComparisonTest, NumberVsStringWithTrailingSpace_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, 5.25, "5.25 "); +} + +TEST_F(LLVMEqualComparisonTest, StringWithTrailingSpaceVsNumber) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "5.25 ", 5.25); +} + +TEST_F(LLVMEqualComparisonTest, StringWithTrailingSpaceVsNumber_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "5.25 ", 5.25); +} + +TEST_F(LLVMEqualComparisonTest, NumberVsStringWithSurroundingSpaces) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, 5.25, " 5.25 "); +} + +TEST_F(LLVMEqualComparisonTest, NumberVsStringWithSurroundingSpaces_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, 5.25, " 5.25 "); +} + +TEST_F(LLVMEqualComparisonTest, StringWithSurroundingSpacesVsNumber) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, " 5.25 ", 5.25); +} + +TEST_F(LLVMEqualComparisonTest, StringWithSurroundingSpacesVsNumber_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, " 5.25 ", 5.25); +} + +TEST_F(LLVMEqualComparisonTest, NumberVsDifferentString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, 5.25, "5.26"); +} + +TEST_F(LLVMEqualComparisonTest, NumberVsDifferentString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, 5.25, "5.26"); +} + +TEST_F(LLVMEqualComparisonTest, DifferentStringVsNumber) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "5.26", 5.25); +} + +TEST_F(LLVMEqualComparisonTest, DifferentStringVsNumber_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "5.26", 5.25); +} + +TEST_F(LLVMEqualComparisonTest, DifferentStringNumbers) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "5.25", "5.26"); +} + +TEST_F(LLVMEqualComparisonTest, DifferentStringNumbers_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "5.25", "5.26"); +} + +TEST_F(LLVMEqualComparisonTest, NumberVsStringWithTrailingSpaces) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, 5, "5 "); +} + +TEST_F(LLVMEqualComparisonTest, NumberVsStringWithTrailingSpaces_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, 5, "5 "); +} + +TEST_F(LLVMEqualComparisonTest, StringWithTrailingSpacesVsNumber) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "5 ", 5); +} + +TEST_F(LLVMEqualComparisonTest, StringWithTrailingSpacesVsNumber_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "5 ", 5); +} + +TEST_F(LLVMEqualComparisonTest, ZeroVsOneString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, 0, "1"); +} + +TEST_F(LLVMEqualComparisonTest, ZeroVsOneString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, 0, "1"); +} + +TEST_F(LLVMEqualComparisonTest, OneStringVsZero) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "1", 0); +} + +TEST_F(LLVMEqualComparisonTest, OneStringVsZero_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "1", 0); +} + +TEST_F(LLVMEqualComparisonTest, ZeroVsTestString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, 0, "test"); +} + +TEST_F(LLVMEqualComparisonTest, ZeroVsTestString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, 0, "test"); +} + +TEST_F(LLVMEqualComparisonTest, TestStringVsZero) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "test", 0); +} + +TEST_F(LLVMEqualComparisonTest, TestStringVsZero_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "test", 0); +} + +TEST_F(LLVMEqualComparisonTest, InfinityWithInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "Infinity", "Infinity"); +} + +TEST_F(LLVMEqualComparisonTest, InfinityWithInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "Infinity", "Infinity"); +} + +TEST_F(LLVMEqualComparisonTest, NegativeInfinityWithNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "-Infinity", "-Infinity"); +} + +TEST_F(LLVMEqualComparisonTest, NegativeInfinityWithNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "-Infinity", "-Infinity"); +} + +TEST_F(LLVMEqualComparisonTest, NaNWithNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "NaN", "NaN"); +} + +TEST_F(LLVMEqualComparisonTest, NaNWithNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "NaN", "NaN"); +} + +TEST_F(LLVMEqualComparisonTest, InfinityWithNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "Infinity", "-Infinity"); +} + +TEST_F(LLVMEqualComparisonTest, InfinityWithNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "Infinity", "-Infinity"); +} + +TEST_F(LLVMEqualComparisonTest, NegativeInfinityWithInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "-Infinity", "Infinity"); +} + +TEST_F(LLVMEqualComparisonTest, NegativeInfinityWithInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "-Infinity", "Infinity"); +} + +TEST_F(LLVMEqualComparisonTest, InfinityWithNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "Infinity", "NaN"); +} + +TEST_F(LLVMEqualComparisonTest, InfinityWithNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "Infinity", "NaN"); +} + +TEST_F(LLVMEqualComparisonTest, NaNWithInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "NaN", "Infinity"); +} + +TEST_F(LLVMEqualComparisonTest, NaNWithInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "NaN", "Infinity"); +} + +TEST_F(LLVMEqualComparisonTest, NegativeInfinityWithNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "-Infinity", "NaN"); +} + +TEST_F(LLVMEqualComparisonTest, NegativeInfinityWithNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "-Infinity", "NaN"); +} + +TEST_F(LLVMEqualComparisonTest, NaNWithNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "NaN", "-Infinity"); +} + +TEST_F(LLVMEqualComparisonTest, NaNWithNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "NaN", "-Infinity"); +} + +TEST_F(LLVMEqualComparisonTest, NumberWithInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, 5, "Infinity"); +} + +TEST_F(LLVMEqualComparisonTest, NumberWithInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, 5, "Infinity"); +} + +TEST_F(LLVMEqualComparisonTest, NumberWithNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, 5, "-Infinity"); +} + +TEST_F(LLVMEqualComparisonTest, NumberWithNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, 5, "-Infinity"); +} + +TEST_F(LLVMEqualComparisonTest, NumberWithNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, 5, "NaN"); +} + +TEST_F(LLVMEqualComparisonTest, NumberWithNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, 5, "NaN"); +} + +TEST_F(LLVMEqualComparisonTest, ZeroWithNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, 0, "NaN"); +} + +TEST_F(LLVMEqualComparisonTest, ZeroWithNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, 0, "NaN"); +} + +TEST_F(LLVMEqualComparisonTest, TrueBooleanWithTrueString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, true, "true"); +} + +TEST_F(LLVMEqualComparisonTest, TrueBooleanWithTrueString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, true, "true"); +} + +TEST_F(LLVMEqualComparisonTest, TrueStringWithTrueBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "true", true); +} + +TEST_F(LLVMEqualComparisonTest, FalseBooleanWithFalseString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, false, "false"); +} + +TEST_F(LLVMEqualComparisonTest, FalseBooleanWithFalseString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, false, "false"); +} + +TEST_F(LLVMEqualComparisonTest, FalseStringWithFalseBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "false", false); +} + +TEST_F(LLVMEqualComparisonTest, FalseStringWithFalseBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "false", false); +} + +TEST_F(LLVMEqualComparisonTest, FalseBooleanWithTrueString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, false, "true"); +} + +TEST_F(LLVMEqualComparisonTest, FalseBooleanWithTrueString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, false, "true"); +} + +TEST_F(LLVMEqualComparisonTest, TrueStringWithFalseBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "true", false); +} + +TEST_F(LLVMEqualComparisonTest, TrueStringWithFalseBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "true", false); +} + +TEST_F(LLVMEqualComparisonTest, TrueBooleanWithFalseString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, true, "false"); +} + +TEST_F(LLVMEqualComparisonTest, TrueBooleanWithFalseString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, true, "false"); +} + +TEST_F(LLVMEqualComparisonTest, FalseStringWithTrueBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "false", true); +} + +TEST_F(LLVMEqualComparisonTest, FalseStringWithTrueBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "false", true); +} + +TEST_F(LLVMEqualComparisonTest, TrueBooleanWithUppercaseTrueString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, true, "TRUE"); +} + +TEST_F(LLVMEqualComparisonTest, TrueBooleanWithUppercaseTrueString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, true, "TRUE"); +} + +TEST_F(LLVMEqualComparisonTest, UppercaseTrueStringWithTrueBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "TRUE", true); +} + +TEST_F(LLVMEqualComparisonTest, UppercaseTrueStringWithTrueBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "TRUE", true); +} + +TEST_F(LLVMEqualComparisonTest, FalseBooleanWithUppercaseFalseString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, false, "FALSE"); +} + +TEST_F(LLVMEqualComparisonTest, FalseBooleanWithUppercaseFalseString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, false, "FALSE"); +} + +TEST_F(LLVMEqualComparisonTest, UppercaseFalseStringWithFalseBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "FALSE", false); +} + +TEST_F(LLVMEqualComparisonTest, UppercaseFalseStringWithFalseBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "FALSE", false); +} + +TEST_F(LLVMEqualComparisonTest, TrueBooleanWithZeroPaddedOne) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, true, "00001"); +} + +TEST_F(LLVMEqualComparisonTest, TrueBooleanWithZeroPaddedOne_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, true, "00001"); +} + +TEST_F(LLVMEqualComparisonTest, ZeroPaddedOneWithTrueBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "00001", true); +} + +TEST_F(LLVMEqualComparisonTest, ZeroPaddedOneWithTrueBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "00001", true); +} + +TEST_F(LLVMEqualComparisonTest, TrueBooleanWithZeroPaddedZero) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, true, "00000"); +} + +TEST_F(LLVMEqualComparisonTest, TrueBooleanWithZeroPaddedZero_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, true, "00000"); +} + +TEST_F(LLVMEqualComparisonTest, ZeroPaddedZeroWithTrueBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "00000", true); +} + +TEST_F(LLVMEqualComparisonTest, ZeroPaddedZeroWithTrueBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "00000", true); +} + +TEST_F(LLVMEqualComparisonTest, FalseBooleanWithZeroPaddedZero) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, false, "00000"); +} + +TEST_F(LLVMEqualComparisonTest, FalseBooleanWithZeroPaddedZero_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, false, "00000"); +} + +TEST_F(LLVMEqualComparisonTest, ZeroPaddedZeroWithFalseBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "00000", false); +} + +TEST_F(LLVMEqualComparisonTest, ZeroPaddedZeroWithFalseBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "00000", false); +} + +TEST_F(LLVMEqualComparisonTest, TrueStringWithOne) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "true", 1); +} + +TEST_F(LLVMEqualComparisonTest, TrueStringWithOne_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "true", 1); +} + +TEST_F(LLVMEqualComparisonTest, OneWithTrueString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, 1, "true"); +} + +TEST_F(LLVMEqualComparisonTest, OneWithTrueString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, 1, "true"); +} + +TEST_F(LLVMEqualComparisonTest, TrueStringWithZero) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "true", 0); +} + +TEST_F(LLVMEqualComparisonTest, TrueStringWithZero_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "true", 0); +} + +TEST_F(LLVMEqualComparisonTest, ZeroWithTrueString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, 0, "true"); +} + +TEST_F(LLVMEqualComparisonTest, ZeroWithTrueString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, 0, "true"); +} + +TEST_F(LLVMEqualComparisonTest, FalseStringWithZero) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "false", 0); +} + +TEST_F(LLVMEqualComparisonTest, FalseStringWithZero_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "false", 0); +} + +TEST_F(LLVMEqualComparisonTest, ZeroWithFalseString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, 0, "false"); +} + +TEST_F(LLVMEqualComparisonTest, ZeroWithFalseString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, 0, "false"); +} + +TEST_F(LLVMEqualComparisonTest, FalseStringWithOne) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "false", 1); +} + +TEST_F(LLVMEqualComparisonTest, FalseStringWithOne_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "false", 1); +} + +TEST_F(LLVMEqualComparisonTest, OneWithFalseString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, 1, "false"); +} + +TEST_F(LLVMEqualComparisonTest, OneWithFalseString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, 1, "false"); +} + +TEST_F(LLVMEqualComparisonTest, TrueStringWithUppercaseTrueString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "true", "TRUE"); +} + +TEST_F(LLVMEqualComparisonTest, TrueStringWithUppercaseTrueString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "true", "TRUE"); +} + +TEST_F(LLVMEqualComparisonTest, TrueStringWithUppercaseFalseString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "true", "FALSE"); +} + +TEST_F(LLVMEqualComparisonTest, TrueStringWithUppercaseFalseString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "true", "FALSE"); +} + +TEST_F(LLVMEqualComparisonTest, FalseStringWithUppercaseFalseString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "false", "FALSE"); +} + +TEST_F(LLVMEqualComparisonTest, FalseStringWithUppercaseFalseString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "false", "FALSE"); +} + +TEST_F(LLVMEqualComparisonTest, FalseStringWithUppercaseTrueString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "false", "TRUE"); +} + +TEST_F(LLVMEqualComparisonTest, FalseStringWithUppercaseTrueString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "false", "TRUE"); +} + +TEST_F(LLVMEqualComparisonTest, TrueBooleanWithInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, true, "Infinity"); +} + +TEST_F(LLVMEqualComparisonTest, TrueBooleanWithInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, true, "Infinity"); +} + +TEST_F(LLVMEqualComparisonTest, TrueBooleanWithNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, true, "-Infinity"); +} + +TEST_F(LLVMEqualComparisonTest, TrueBooleanWithNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, true, "-Infinity"); +} + +TEST_F(LLVMEqualComparisonTest, TrueBooleanWithNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, true, "NaN"); +} + +TEST_F(LLVMEqualComparisonTest, TrueBooleanWithNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, true, "NaN"); +} + +TEST_F(LLVMEqualComparisonTest, FalseBooleanWithInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, false, "Infinity"); +} + +TEST_F(LLVMEqualComparisonTest, FalseBooleanWithInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, false, "Infinity"); +} + +TEST_F(LLVMEqualComparisonTest, FalseBooleanWithNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, false, "-Infinity"); +} + +TEST_F(LLVMEqualComparisonTest, FalseBooleanWithNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, false, "-Infinity"); +} + +TEST_F(LLVMEqualComparisonTest, FalseBooleanWithNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, false, "NaN"); +} + +TEST_F(LLVMEqualComparisonTest, FalseBooleanWithNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, false, "NaN"); +} + +TEST_F(LLVMEqualComparisonTest, InfinityStringWithInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "Infinity", "Infinity"); +} + +TEST_F(LLVMEqualComparisonTest, InfinityStringWithInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "Infinity", "Infinity"); +} + +TEST_F(LLVMEqualComparisonTest, InfinityStringWithNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "Infinity", "-Infinity"); +} + +TEST_F(LLVMEqualComparisonTest, InfinityStringWithNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "Infinity", "-Infinity"); +} + +TEST_F(LLVMEqualComparisonTest, InfinityStringWithNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "Infinity", "NaN"); +} + +TEST_F(LLVMEqualComparisonTest, InfinityStringWithNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "Infinity", "NaN"); +} + +TEST_F(LLVMEqualComparisonTest, LowercaseInfinityStringWithInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "infinity", "Infinity"); +} + +TEST_F(LLVMEqualComparisonTest, LowercaseInfinityStringWithInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "infinity", "Infinity"); +} + +TEST_F(LLVMEqualComparisonTest, LowercaseInfinityStringWithNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "infinity", "-Infinity"); +} + +TEST_F(LLVMEqualComparisonTest, LowercaseInfinityStringWithNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "infinity", "-Infinity"); +} + +TEST_F(LLVMEqualComparisonTest, LowercaseInfinityStringWithNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "infinity", "NaN"); +} + +TEST_F(LLVMEqualComparisonTest, LowercaseInfinityStringWithNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "infinity", "NaN"); +} + +TEST_F(LLVMEqualComparisonTest, NegativeInfinityStringWithInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "-Infinity", "Infinity"); +} + +TEST_F(LLVMEqualComparisonTest, NegativeInfinityStringWithInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "-Infinity", "Infinity"); +} + +TEST_F(LLVMEqualComparisonTest, NegativeInfinityStringWithNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "-Infinity", "-Infinity"); +} + +TEST_F(LLVMEqualComparisonTest, NegativeInfinityStringWithNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "-Infinity", "-Infinity"); +} + +TEST_F(LLVMEqualComparisonTest, NegativeInfinityStringWithNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "-Infinity", "NaN"); +} + +TEST_F(LLVMEqualComparisonTest, NegativeInfinityStringWithNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "-Infinity", "NaN"); +} + +TEST_F(LLVMEqualComparisonTest, LowercaseNegativeInfinityStringWithInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "-infinity", "Infinity"); +} + +TEST_F(LLVMEqualComparisonTest, LowercaseNegativeInfinityStringWithInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "-infinity", "Infinity"); +} + +TEST_F(LLVMEqualComparisonTest, LowercaseNegativeInfinityStringWithNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "-infinity", "-Infinity"); +} + +TEST_F(LLVMEqualComparisonTest, LowercaseNegativeInfinityStringWithNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "-infinity", "-Infinity"); +} + +TEST_F(LLVMEqualComparisonTest, LowercaseNegativeInfinityStringWithNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "-infinity", "NaN"); +} + +TEST_F(LLVMEqualComparisonTest, LowercaseNegativeInfinityStringWithNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "-infinity", "NaN"); +} + +TEST_F(LLVMEqualComparisonTest, NaNStringWithInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "NaN", "Infinity"); +} + +TEST_F(LLVMEqualComparisonTest, NaNStringWithInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "NaN", "Infinity"); +} + +TEST_F(LLVMEqualComparisonTest, NaNStringWithNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "NaN", "-Infinity"); +} + +TEST_F(LLVMEqualComparisonTest, NaNStringWithNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "NaN", "-Infinity"); +} + +TEST_F(LLVMEqualComparisonTest, NaNStringWithNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "NaN", "NaN"); +} + +TEST_F(LLVMEqualComparisonTest, NaNStringWithNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "NaN", "NaN"); +} + +TEST_F(LLVMEqualComparisonTest, LowercaseNaNStringWithInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "nan", "Infinity"); +} + +TEST_F(LLVMEqualComparisonTest, LowercaseNaNStringWithInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "nan", "Infinity"); +} + +TEST_F(LLVMEqualComparisonTest, LowercaseNaNStringWithNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "nan", "-Infinity"); +} + +TEST_F(LLVMEqualComparisonTest, LowercaseNaNStringWithNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "nan", "-Infinity"); +} + +TEST_F(LLVMEqualComparisonTest, LowercaseNaNStringWithNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "nan", "NaN"); +} + +TEST_F(LLVMEqualComparisonTest, LowercaseNaNStringWithNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "nan", "NaN"); +} + +TEST_F(LLVMEqualComparisonTest, InfinityWithStringAbc) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "Infinity", "abc"); +} + +TEST_F(LLVMEqualComparisonTest, InfinityWithStringAbc_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "Infinity", "abc"); +} + +TEST_F(LLVMEqualComparisonTest, InfinityWithStringSpace) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "Infinity", " "); +} + +TEST_F(LLVMEqualComparisonTest, InfinityWithStringSpace_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "Infinity", " "); +} + +TEST_F(LLVMEqualComparisonTest, InfinityWithEmptyString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "Infinity", ""); +} + +TEST_F(LLVMEqualComparisonTest, InfinityWithEmptyString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "Infinity", ""); +} + +TEST_F(LLVMEqualComparisonTest, InfinityWithZeroString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "Infinity", "0"); +} + +TEST_F(LLVMEqualComparisonTest, InfinityWithZeroString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "Infinity", "0"); +} + +TEST_F(LLVMEqualComparisonTest, NegativeInfinityWithStringAbc) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "-Infinity", "abc"); +} + +TEST_F(LLVMEqualComparisonTest, NegativeInfinityWithStringAbc_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "-Infinity", "abc"); +} + +TEST_F(LLVMEqualComparisonTest, NegativeInfinityWithStringSpace) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "-Infinity", " "); +} + +TEST_F(LLVMEqualComparisonTest, NegativeInfinityWithStringSpace_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "-Infinity", " "); +} + +TEST_F(LLVMEqualComparisonTest, NegativeInfinityWithEmptyString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "-Infinity", ""); +} + +TEST_F(LLVMEqualComparisonTest, NegativeInfinityWithEmptyString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "-Infinity", ""); +} + +TEST_F(LLVMEqualComparisonTest, NegativeInfinityWithZeroString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "-Infinity", "0"); +} + +TEST_F(LLVMEqualComparisonTest, NegativeInfinityWithZeroString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "-Infinity", "0"); +} + +TEST_F(LLVMEqualComparisonTest, NaNWithStringAbc) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "NaN", "abc"); +} + +TEST_F(LLVMEqualComparisonTest, NaNWithStringAbc_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "NaN", "abc"); +} + +TEST_F(LLVMEqualComparisonTest, NaNWithStringSpace) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "NaN", " "); +} + +TEST_F(LLVMEqualComparisonTest, NaNWithStringSpace_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "NaN", " "); +} + +TEST_F(LLVMEqualComparisonTest, NaNWithEmptyString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "NaN", ""); +} + +TEST_F(LLVMEqualComparisonTest, NaNWithEmptyString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "NaN", ""); +} + +TEST_F(LLVMEqualComparisonTest, NaNWithZeroString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "NaN", "0"); +} + +TEST_F(LLVMEqualComparisonTest, NaNWithZeroString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "NaN", "0"); +} diff --git a/test/llvm/operators/greater_than_test.cpp b/test/llvm/operators/greater_than_test.cpp new file mode 100644 index 000000000..9256def56 --- /dev/null +++ b/test/llvm/operators/greater_than_test.cpp @@ -0,0 +1,1340 @@ +#include +#include + +#include "llvmtestutils.h" + +class LLVMGreaterThanTest : public testing::Test +{ + public: + LLVMTestUtils m_utils; +}; + +TEST_F(LLVMGreaterThanTest, SameIntegers) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, 10, 10); +} + +TEST_F(LLVMGreaterThanTest, SameIntegers_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, 10, 10); +} + +TEST_F(LLVMGreaterThanTest, FirstGreaterInteger) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, 10, 8); +} + +TEST_F(LLVMGreaterThanTest, FirstGreaterInteger_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, 10, 8); +} + +TEST_F(LLVMGreaterThanTest, SecondGreaterInteger) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, 8, 10); +} + +TEST_F(LLVMGreaterThanTest, SecondGreaterInteger_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, 8, 10); +} + +TEST_F(LLVMGreaterThanTest, SameDecimals) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, -4.25, -4.25); +} + +TEST_F(LLVMGreaterThanTest, SameDecimals_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, -4.25, -4.25); +} + +TEST_F(LLVMGreaterThanTest, FirstGreaterDecimal) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, -4.25, 5.312); +} + +TEST_F(LLVMGreaterThanTest, FirstGreaterDecimal_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, -4.25, 5.312); +} + +TEST_F(LLVMGreaterThanTest, SecondGreaterDecimal) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, 5.312, -4.25); +} + +TEST_F(LLVMGreaterThanTest, SecondGreaterDecimal_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, 5.312, -4.25); +} + +TEST_F(LLVMGreaterThanTest, SameBooleans) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, true, true); +} + +TEST_F(LLVMGreaterThanTest, SameBooleans_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, true, true); +} + +TEST_F(LLVMGreaterThanTest, TrueGreaterThanFalse) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, true, false); +} + +TEST_F(LLVMGreaterThanTest, TrueGreaterThanFalse_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, true, false); +} + +TEST_F(LLVMGreaterThanTest, FalseGreaterThanTrue) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, false, true); +} + +TEST_F(LLVMGreaterThanTest, FalseGreaterThanTrue_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, false, true); +} + +TEST_F(LLVMGreaterThanTest, NumberGreaterThanTrueBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, 1, true); +} + +TEST_F(LLVMGreaterThanTest, NumberGreaterThanTrueBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, 1, true); +} + +TEST_F(LLVMGreaterThanTest, NumberGreaterThanFalseBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, 1, false); +} + +TEST_F(LLVMGreaterThanTest, NumberGreaterThanFalseBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, 1, false); +} + +TEST_F(LLVMGreaterThanTest, SameStrings) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "abC def", "abC def"); +} + +TEST_F(LLVMGreaterThanTest, SameStrings_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "abC def", "abC def"); +} + +TEST_F(LLVMGreaterThanTest, StringsCaseDifferent) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "abC def", "abc dEf"); +} + +TEST_F(LLVMGreaterThanTest, StringsCaseDifferent_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "abC def", "abc dEf"); +} + +TEST_F(LLVMGreaterThanTest, FirstStringGreater) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "abC def", "ghi Jkl"); +} + +TEST_F(LLVMGreaterThanTest, FirstStringGreater_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "abC def", "ghi Jkl"); +} + +TEST_F(LLVMGreaterThanTest, SecondStringGreater) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "ghi Jkl", "abC def"); +} + +TEST_F(LLVMGreaterThanTest, SecondStringGreater_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "ghi Jkl", "abC def"); +} + +TEST_F(LLVMGreaterThanTest, StringsLengthComparison) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "abC def", "hello world"); +} + +TEST_F(LLVMGreaterThanTest, StringsLengthComparison_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "abC def", "hello world"); +} + +TEST_F(LLVMGreaterThanTest, SpaceGreaterThanEmpty) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, " ", ""); +} + +TEST_F(LLVMGreaterThanTest, SpaceGreaterThanEmpty_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, " ", ""); +} + +TEST_F(LLVMGreaterThanTest, SpaceGreaterThanZeroString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, " ", "0"); +} + +TEST_F(LLVMGreaterThanTest, SpaceGreaterThanZeroString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, " ", "0"); +} + +TEST_F(LLVMGreaterThanTest, SpaceGreaterThanZeroNumber) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, " ", 0); +} + +TEST_F(LLVMGreaterThanTest, SpaceGreaterThanZeroNumber_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, " ", 0); +} + +TEST_F(LLVMGreaterThanTest, ZeroNumberGreaterThanSpace) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, 0, " "); +} + +TEST_F(LLVMGreaterThanTest, ZeroNumberGreaterThanSpace_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, 0, " "); +} + +TEST_F(LLVMGreaterThanTest, EmptyGreaterThanZeroString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "", "0"); +} + +TEST_F(LLVMGreaterThanTest, EmptyGreaterThanZeroString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "", "0"); +} + +TEST_F(LLVMGreaterThanTest, EmptyGreaterThanZeroNumber) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "", 0); +} + +TEST_F(LLVMGreaterThanTest, EmptyGreaterThanZeroNumber_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "", 0); +} + +TEST_F(LLVMGreaterThanTest, ZeroNumberGreaterThanEmpty) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, 0, ""); +} + +TEST_F(LLVMGreaterThanTest, ZeroNumberGreaterThanEmpty_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, 0, ""); +} + +TEST_F(LLVMGreaterThanTest, ZeroStringGreaterThanZeroNumber) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "0", 0); +} + +TEST_F(LLVMGreaterThanTest, ZeroStringGreaterThanZeroNumber_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "0", 0); +} + +TEST_F(LLVMGreaterThanTest, ZeroNumberGreaterThanZeroString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, 0, "0"); +} + +TEST_F(LLVMGreaterThanTest, ZeroNumberGreaterThanZeroString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, 0, "0"); +} + +TEST_F(LLVMGreaterThanTest, NumberGreaterThanExactString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, 5.25, "5.25"); +} + +TEST_F(LLVMGreaterThanTest, NumberGreaterThanExactString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, 5.25, "5.25"); +} + +TEST_F(LLVMGreaterThanTest, ExactStringGreaterThanNumber) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "5.25", 5.25); +} + +TEST_F(LLVMGreaterThanTest, ExactStringGreaterThanNumber_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "5.25", 5.25); +} + +TEST_F(LLVMGreaterThanTest, NumberGreaterThanStringWithLeadingSpace) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, 5.25, " 5.25"); +} + +TEST_F(LLVMGreaterThanTest, NumberGreaterThanStringWithLeadingSpace_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, 5.25, " 5.25"); +} + +TEST_F(LLVMGreaterThanTest, StringWithLeadingSpaceGreaterThanNumber) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, " 5.25", 5.25); +} + +TEST_F(LLVMGreaterThanTest, StringWithLeadingSpaceGreaterThanNumber_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, " 5.25", 5.25); +} + +TEST_F(LLVMGreaterThanTest, NumberGreaterThanStringWithTrailingSpace) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, 5.25, "5.25 "); +} + +TEST_F(LLVMGreaterThanTest, NumberGreaterThanStringWithTrailingSpace_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, 5.25, "5.25 "); +} + +TEST_F(LLVMGreaterThanTest, StringWithTrailingSpaceGreaterThanNumber) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "5.25 ", 5.25); +} + +TEST_F(LLVMGreaterThanTest, StringWithTrailingSpaceGreaterThanNumber_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "5.25 ", 5.25); +} + +TEST_F(LLVMGreaterThanTest, NumberGreaterThanStringWithSurroundingSpaces) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, 5.25, " 5.25 "); +} + +TEST_F(LLVMGreaterThanTest, NumberGreaterThanStringWithSurroundingSpaces_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, 5.25, " 5.25 "); +} + +TEST_F(LLVMGreaterThanTest, StringWithSurroundingSpacesGreaterThanNumber) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, " 5.25 ", 5.25); +} + +TEST_F(LLVMGreaterThanTest, StringWithSurroundingSpacesGreaterThanNumber_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, " 5.25 ", 5.25); +} + +TEST_F(LLVMGreaterThanTest, NumberGreaterThanDifferentString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, 5.25, "5.26"); +} + +TEST_F(LLVMGreaterThanTest, NumberGreaterThanDifferentString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, 5.25, "5.26"); +} + +TEST_F(LLVMGreaterThanTest, DifferentStringGreaterThanNumber) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "5.26", 5.25); +} + +TEST_F(LLVMGreaterThanTest, DifferentStringGreaterThanNumber_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "5.26", 5.25); +} + +TEST_F(LLVMGreaterThanTest, DifferentStringNumbers) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "5.25", "5.26"); +} + +TEST_F(LLVMGreaterThanTest, DifferentStringNumbers_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "5.25", "5.26"); +} + +TEST_F(LLVMGreaterThanTest, NumberGreaterThanStringWithTrailingSpaces) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, 5, "5 "); +} + +TEST_F(LLVMGreaterThanTest, NumberGreaterThanStringWithTrailingSpaces_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, 5, "5 "); +} + +TEST_F(LLVMGreaterThanTest, StringWithTrailingSpacesGreaterThanNumber) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "5 ", 5); +} + +TEST_F(LLVMGreaterThanTest, StringWithTrailingSpacesGreaterThanNumber_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "5 ", 5); +} + +TEST_F(LLVMGreaterThanTest, ZeroGreaterThanOneString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, 0, "1"); +} + +TEST_F(LLVMGreaterThanTest, ZeroGreaterThanOneString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, 0, "1"); +} + +TEST_F(LLVMGreaterThanTest, OneStringGreaterThanZero) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "1", 0); +} + +TEST_F(LLVMGreaterThanTest, OneStringGreaterThanZero_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "1", 0); +} + +TEST_F(LLVMGreaterThanTest, ZeroGreaterThanTestString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, 0, "test"); +} + +TEST_F(LLVMGreaterThanTest, ZeroGreaterThanTestString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, 0, "test"); +} + +TEST_F(LLVMGreaterThanTest, TestStringGreaterThanZero) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "test", 0); +} + +TEST_F(LLVMGreaterThanTest, TestStringGreaterThanZero_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "test", 0); +} + +TEST_F(LLVMGreaterThanTest, NumberGreaterThanAbcString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, 55, "abc"); +} + +TEST_F(LLVMGreaterThanTest, NumberGreaterThanAbcString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, 55, "abc"); +} + +TEST_F(LLVMGreaterThanTest, AbcStringGreaterThanNumber) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "abc", 55); +} + +TEST_F(LLVMGreaterThanTest, AbcStringGreaterThanNumber_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "abc", 55); +} + +TEST_F(LLVMGreaterThanTest, InfinityGreaterThanInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "Infinity", "Infinity"); +} + +TEST_F(LLVMGreaterThanTest, InfinityGreaterThanInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "Infinity", "Infinity"); +} + +TEST_F(LLVMGreaterThanTest, NegativeInfinityGreaterThanNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "-Infinity", "-Infinity"); +} + +TEST_F(LLVMGreaterThanTest, NegativeInfinityGreaterThanNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "-Infinity", "-Infinity"); +} + +TEST_F(LLVMGreaterThanTest, NaNGreaterThanNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "NaN", "NaN"); +} + +TEST_F(LLVMGreaterThanTest, NaNGreaterThanNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "NaN", "NaN"); +} + +TEST_F(LLVMGreaterThanTest, InfinityGreaterThanNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "Infinity", "-Infinity"); +} + +TEST_F(LLVMGreaterThanTest, InfinityGreaterThanNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "Infinity", "-Infinity"); +} + +TEST_F(LLVMGreaterThanTest, NegativeInfinityGreaterThanInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "-Infinity", "Infinity"); +} + +TEST_F(LLVMGreaterThanTest, NegativeInfinityGreaterThanInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "-Infinity", "Infinity"); +} + +TEST_F(LLVMGreaterThanTest, InfinityGreaterThanNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "Infinity", "NaN"); +} + +TEST_F(LLVMGreaterThanTest, InfinityGreaterThanNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "Infinity", "NaN"); +} + +TEST_F(LLVMGreaterThanTest, NaNGreaterThanInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "NaN", "Infinity"); +} + +TEST_F(LLVMGreaterThanTest, NaNGreaterThanInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "NaN", "Infinity"); +} + +TEST_F(LLVMGreaterThanTest, NegativeInfinityGreaterThanNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "-Infinity", "NaN"); +} + +TEST_F(LLVMGreaterThanTest, NegativeInfinityGreaterThanNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "-Infinity", "NaN"); +} + +TEST_F(LLVMGreaterThanTest, NaNGreaterThanNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "NaN", "-Infinity"); +} + +TEST_F(LLVMGreaterThanTest, NaNGreaterThanNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "NaN", "-Infinity"); +} + +TEST_F(LLVMGreaterThanTest, NumberGreaterThanInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, 5, "Infinity"); +} + +TEST_F(LLVMGreaterThanTest, NumberGreaterThanInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, 5, "Infinity"); +} + +TEST_F(LLVMGreaterThanTest, InfinityGreaterThanNumber) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "Infinity", 5); +} + +TEST_F(LLVMGreaterThanTest, InfinityGreaterThanNumber_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "Infinity", 5); +} + +TEST_F(LLVMGreaterThanTest, NumberGreaterThanNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, 5, "-Infinity"); +} + +TEST_F(LLVMGreaterThanTest, NumberGreaterThanNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, 5, "-Infinity"); +} + +TEST_F(LLVMGreaterThanTest, NegativeInfinityGreaterThanNumber) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "-Infinity", 5); +} + +TEST_F(LLVMGreaterThanTest, NegativeInfinityGreaterThanNumber_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "-Infinity", 5); +} + +TEST_F(LLVMGreaterThanTest, NumberGreaterThanNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, 5, "NaN"); +} + +TEST_F(LLVMGreaterThanTest, NumberGreaterThanNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, 5, "NaN"); +} + +TEST_F(LLVMGreaterThanTest, NaNGreaterThanNumber) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "NaN", 5); +} + +TEST_F(LLVMGreaterThanTest, NaNGreaterThanNumber_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "NaN", 5); +} + +TEST_F(LLVMGreaterThanTest, ZeroGreaterThanNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, 0, "NaN"); +} + +TEST_F(LLVMGreaterThanTest, ZeroGreaterThanNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, 0, "NaN"); +} + +TEST_F(LLVMGreaterThanTest, NaNGreaterThanZero) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "NaN", 0); +} + +TEST_F(LLVMGreaterThanTest, NaNGreaterThanZero_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "NaN", 0); +} + +TEST_F(LLVMGreaterThanTest, TrueBooleanWithTrueString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, true, "true"); +} + +TEST_F(LLVMGreaterThanTest, TrueBooleanWithTrueString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, true, "true"); +} + +TEST_F(LLVMGreaterThanTest, TrueStringWithTrueBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "true", true); +} + +TEST_F(LLVMGreaterThanTest, TrueStringWithTrueBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "true", true); +} + +TEST_F(LLVMGreaterThanTest, FalseBooleanWithFalseString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, false, "false"); +} + +TEST_F(LLVMGreaterThanTest, FalseBooleanWithFalseString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, false, "false"); +} + +TEST_F(LLVMGreaterThanTest, FalseStringWithFalseBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "false", false); +} + +TEST_F(LLVMGreaterThanTest, FalseStringWithFalseBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "false", false); +} + +TEST_F(LLVMGreaterThanTest, FalseBooleanWithTrueString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, false, "true"); +} + +TEST_F(LLVMGreaterThanTest, FalseBooleanWithTrueString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, false, "true"); +} + +TEST_F(LLVMGreaterThanTest, TrueStringWithFalseBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "true", false); +} + +TEST_F(LLVMGreaterThanTest, TrueStringWithFalseBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "true", false); +} + +TEST_F(LLVMGreaterThanTest, TrueBooleanWithFalseString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, true, "false"); +} + +TEST_F(LLVMGreaterThanTest, TrueBooleanWithFalseString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, true, "false"); +} + +TEST_F(LLVMGreaterThanTest, FalseStringWithTrueBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "false", true); +} + +TEST_F(LLVMGreaterThanTest, FalseStringWithTrueBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "false", true); +} + +TEST_F(LLVMGreaterThanTest, TrueBooleanWithUppercaseTrueString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, true, "TRUE"); +} + +TEST_F(LLVMGreaterThanTest, TrueBooleanWithUppercaseTrueString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, true, "TRUE"); +} + +TEST_F(LLVMGreaterThanTest, UppercaseTrueStringWithTrueBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "TRUE", true); +} + +TEST_F(LLVMGreaterThanTest, UppercaseTrueStringWithTrueBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "TRUE", true); +} + +TEST_F(LLVMGreaterThanTest, FalseBooleanWithUppercaseFalseString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, false, "FALSE"); +} + +TEST_F(LLVMGreaterThanTest, FalseBooleanWithUppercaseFalseString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, false, "FALSE"); +} + +TEST_F(LLVMGreaterThanTest, UppercaseFalseStringWithFalseBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "FALSE", false); +} + +TEST_F(LLVMGreaterThanTest, UppercaseFalseStringWithFalseBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "FALSE", false); +} + +TEST_F(LLVMGreaterThanTest, TrueBooleanWithZeroPaddedOne) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, true, "00001"); +} + +TEST_F(LLVMGreaterThanTest, TrueBooleanWithZeroPaddedOne_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, true, "00001"); +} + +TEST_F(LLVMGreaterThanTest, ZeroPaddedOneWithTrueBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "00001", true); +} + +TEST_F(LLVMGreaterThanTest, ZeroPaddedOneWithTrueBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "00001", true); +} + +TEST_F(LLVMGreaterThanTest, TrueBooleanWithZeroPaddedZero) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, true, "00000"); +} + +TEST_F(LLVMGreaterThanTest, TrueBooleanWithZeroPaddedZero_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, true, "00000"); +} + +TEST_F(LLVMGreaterThanTest, ZeroPaddedZeroWithTrueBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "00000", true); +} + +TEST_F(LLVMGreaterThanTest, ZeroPaddedZeroWithTrueBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "00000", true); +} + +TEST_F(LLVMGreaterThanTest, FalseBooleanWithZeroPaddedZero) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, false, "00000"); +} + +TEST_F(LLVMGreaterThanTest, FalseBooleanWithZeroPaddedZero_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, false, "00000"); +} + +TEST_F(LLVMGreaterThanTest, ZeroPaddedZeroWithFalseBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "00000", false); +} + +TEST_F(LLVMGreaterThanTest, ZeroPaddedZeroWithFalseBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "00000", false); +} + +TEST_F(LLVMGreaterThanTest, TrueStringWithOne) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "true", 1); +} + +TEST_F(LLVMGreaterThanTest, TrueStringWithOne_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "true", 1); +} + +TEST_F(LLVMGreaterThanTest, OneWithTrueString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, 1, "true"); +} + +TEST_F(LLVMGreaterThanTest, OneWithTrueString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, 1, "true"); +} + +TEST_F(LLVMGreaterThanTest, TrueStringWithZero) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "true", 0); +} + +TEST_F(LLVMGreaterThanTest, TrueStringWithZero_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "true", 0); +} + +TEST_F(LLVMGreaterThanTest, ZeroWithTrueString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, 0, "true"); +} + +TEST_F(LLVMGreaterThanTest, ZeroWithTrueString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, 0, "true"); +} + +TEST_F(LLVMGreaterThanTest, FalseStringWithZero) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "false", 0); +} + +TEST_F(LLVMGreaterThanTest, FalseStringWithZero_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "false", 0); +} + +TEST_F(LLVMGreaterThanTest, ZeroWithFalseString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, 0, "false"); +} + +TEST_F(LLVMGreaterThanTest, ZeroWithFalseString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, 0, "false"); +} + +TEST_F(LLVMGreaterThanTest, FalseStringWithOne) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "false", 1); +} + +TEST_F(LLVMGreaterThanTest, FalseStringWithOne_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "false", 1); +} + +TEST_F(LLVMGreaterThanTest, OneWithFalseString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, 1, "false"); +} + +TEST_F(LLVMGreaterThanTest, OneWithFalseString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, 1, "false"); +} + +TEST_F(LLVMGreaterThanTest, TrueStringWithUppercaseTrueString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "true", "TRUE"); +} + +TEST_F(LLVMGreaterThanTest, TrueStringWithUppercaseTrueString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "true", "TRUE"); +} + +TEST_F(LLVMGreaterThanTest, TrueStringWithUppercaseFalseString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "true", "FALSE"); +} + +TEST_F(LLVMGreaterThanTest, TrueStringWithUppercaseFalseString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "true", "FALSE"); +} + +TEST_F(LLVMGreaterThanTest, FalseStringWithUppercaseFalseString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "false", "FALSE"); +} + +TEST_F(LLVMGreaterThanTest, FalseStringWithUppercaseFalseString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "false", "FALSE"); +} + +TEST_F(LLVMGreaterThanTest, FalseStringWithUppercaseTrueString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "false", "TRUE"); +} + +TEST_F(LLVMGreaterThanTest, FalseStringWithUppercaseTrueString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "false", "TRUE"); +} + +TEST_F(LLVMGreaterThanTest, TrueBooleanWithInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, true, "Infinity"); +} + +TEST_F(LLVMGreaterThanTest, TrueBooleanWithInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, true, "Infinity"); +} + +TEST_F(LLVMGreaterThanTest, InfinityWithTrueBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "Infinity", true); +} + +TEST_F(LLVMGreaterThanTest, InfinityWithTrueBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "Infinity", true); +} + +TEST_F(LLVMGreaterThanTest, TrueBooleanWithNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, true, "-Infinity"); +} + +TEST_F(LLVMGreaterThanTest, TrueBooleanWithNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, true, "-Infinity"); +} + +TEST_F(LLVMGreaterThanTest, NegativeInfinityWithTrueBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "-Infinity", true); +} + +TEST_F(LLVMGreaterThanTest, NegativeInfinityWithTrueBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "-Infinity", true); +} + +TEST_F(LLVMGreaterThanTest, TrueBooleanWithNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, true, "NaN"); +} + +TEST_F(LLVMGreaterThanTest, TrueBooleanWithNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, true, "NaN"); +} + +TEST_F(LLVMGreaterThanTest, NaNWithTrueBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "NaN", true); +} + +TEST_F(LLVMGreaterThanTest, NaNWithTrueBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "NaN", true); +} + +TEST_F(LLVMGreaterThanTest, FalseBooleanWithInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, false, "Infinity"); +} + +TEST_F(LLVMGreaterThanTest, FalseBooleanWithInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, false, "Infinity"); +} + +TEST_F(LLVMGreaterThanTest, InfinityWithFalseBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "Infinity", false); +} + +TEST_F(LLVMGreaterThanTest, InfinityWithFalseBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "Infinity", false); +} + +TEST_F(LLVMGreaterThanTest, FalseBooleanWithNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, false, "-Infinity"); +} + +TEST_F(LLVMGreaterThanTest, FalseBooleanWithNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, false, "-Infinity"); +} + +TEST_F(LLVMGreaterThanTest, NegativeInfinityWithFalseBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "-Infinity", false); +} + +TEST_F(LLVMGreaterThanTest, NegativeInfinityWithFalseBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "-Infinity", false); +} + +TEST_F(LLVMGreaterThanTest, FalseBooleanWithNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, false, "NaN"); +} + +TEST_F(LLVMGreaterThanTest, FalseBooleanWithNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, false, "NaN"); +} + +TEST_F(LLVMGreaterThanTest, NaNWithFalseBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "NaN", false); +} + +TEST_F(LLVMGreaterThanTest, NaNWithFalseBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "NaN", false); +} + +TEST_F(LLVMGreaterThanTest, InfinityStringWithInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "Infinity", "Infinity"); +} + +TEST_F(LLVMGreaterThanTest, InfinityStringWithInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "Infinity", "Infinity"); +} + +TEST_F(LLVMGreaterThanTest, InfinityStringWithNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "Infinity", "-Infinity"); +} + +TEST_F(LLVMGreaterThanTest, InfinityStringWithNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "Infinity", "-Infinity"); +} + +TEST_F(LLVMGreaterThanTest, InfinityStringWithNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "Infinity", "NaN"); +} + +TEST_F(LLVMGreaterThanTest, InfinityStringWithNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "Infinity", "NaN"); +} + +TEST_F(LLVMGreaterThanTest, LowercaseInfinityStringWithInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "infinity", "Infinity"); +} + +TEST_F(LLVMGreaterThanTest, LowercaseInfinityStringWithInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "infinity", "Infinity"); +} + +TEST_F(LLVMGreaterThanTest, LowercaseInfinityStringWithNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "infinity", "-Infinity"); +} + +TEST_F(LLVMGreaterThanTest, LowercaseInfinityStringWithNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "infinity", "-Infinity"); +} + +TEST_F(LLVMGreaterThanTest, LowercaseInfinityStringWithNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "infinity", "NaN"); +} + +TEST_F(LLVMGreaterThanTest, LowercaseInfinityStringWithNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "infinity", "NaN"); +} + +TEST_F(LLVMGreaterThanTest, NegativeInfinityStringWithInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "-Infinity", "Infinity"); +} + +TEST_F(LLVMGreaterThanTest, NegativeInfinityStringWithInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "-Infinity", "Infinity"); +} + +TEST_F(LLVMGreaterThanTest, NegativeInfinityStringWithNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "-Infinity", "-Infinity"); +} + +TEST_F(LLVMGreaterThanTest, NegativeInfinityStringWithNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "-Infinity", "-Infinity"); +} + +TEST_F(LLVMGreaterThanTest, NegativeInfinityStringWithNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "-Infinity", "NaN"); +} + +TEST_F(LLVMGreaterThanTest, NegativeInfinityStringWithNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "-Infinity", "NaN"); +} + +TEST_F(LLVMGreaterThanTest, LowercaseNegativeInfinityStringWithInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "-infinity", "Infinity"); +} + +TEST_F(LLVMGreaterThanTest, LowercaseNegativeInfinityStringWithInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "-infinity", "Infinity"); +} + +TEST_F(LLVMGreaterThanTest, LowercaseNegativeInfinityStringWithNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "-infinity", "-Infinity"); +} + +TEST_F(LLVMGreaterThanTest, LowercaseNegativeInfinityStringWithNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "-infinity", "-Infinity"); +} + +TEST_F(LLVMGreaterThanTest, LowercaseNegativeInfinityStringWithNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "-infinity", "NaN"); +} + +TEST_F(LLVMGreaterThanTest, LowercaseNegativeInfinityStringWithNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "-infinity", "NaN"); +} + +TEST_F(LLVMGreaterThanTest, NaNStringWithInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "NaN", "Infinity"); +} + +TEST_F(LLVMGreaterThanTest, NaNStringWithInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "NaN", "Infinity"); +} + +TEST_F(LLVMGreaterThanTest, NaNStringWithNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "NaN", "-Infinity"); +} + +TEST_F(LLVMGreaterThanTest, NaNStringWithNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "NaN", "-Infinity"); +} + +TEST_F(LLVMGreaterThanTest, NaNStringWithNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "NaN", "NaN"); +} + +TEST_F(LLVMGreaterThanTest, NaNStringWithNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "NaN", "NaN"); +} + +TEST_F(LLVMGreaterThanTest, LowercaseNaNStringWithInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "nan", "Infinity"); +} + +TEST_F(LLVMGreaterThanTest, LowercaseNaNStringWithInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "nan", "Infinity"); +} + +TEST_F(LLVMGreaterThanTest, LowercaseNaNStringWithNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "nan", "-Infinity"); +} + +TEST_F(LLVMGreaterThanTest, LowercaseNaNStringWithNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "nan", "-Infinity"); +} + +TEST_F(LLVMGreaterThanTest, LowercaseNaNStringWithNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "nan", "NaN"); +} + +TEST_F(LLVMGreaterThanTest, LowercaseNaNStringWithNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "nan", "NaN"); +} + +TEST_F(LLVMGreaterThanTest, InfinityWithStringAbc) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "Infinity", "abc"); +} + +TEST_F(LLVMGreaterThanTest, InfinityWithStringAbc_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "Infinity", "abc"); +} + +TEST_F(LLVMGreaterThanTest, InfinityWithStringSpace) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "Infinity", " "); +} + +TEST_F(LLVMGreaterThanTest, InfinityWithStringSpace_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "Infinity", " "); +} + +TEST_F(LLVMGreaterThanTest, InfinityWithEmptyString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "Infinity", ""); +} + +TEST_F(LLVMGreaterThanTest, InfinityWithEmptyString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "Infinity", ""); +} + +TEST_F(LLVMGreaterThanTest, InfinityWithZeroString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "Infinity", "0"); +} + +TEST_F(LLVMGreaterThanTest, InfinityWithZeroString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "Infinity", "0"); +} + +TEST_F(LLVMGreaterThanTest, NegativeInfinityWithStringAbc) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "-Infinity", "abc"); +} + +TEST_F(LLVMGreaterThanTest, NegativeInfinityWithStringAbc_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "-Infinity", "abc"); +} + +TEST_F(LLVMGreaterThanTest, NegativeInfinityWithStringSpace) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "-Infinity", " "); +} + +TEST_F(LLVMGreaterThanTest, NegativeInfinityWithStringSpace_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "-Infinity", " "); +} + +TEST_F(LLVMGreaterThanTest, NegativeInfinityWithEmptyString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "-Infinity", ""); +} + +TEST_F(LLVMGreaterThanTest, NegativeInfinityWithEmptyString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "-Infinity", ""); +} + +TEST_F(LLVMGreaterThanTest, NegativeInfinityWithZeroString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "-Infinity", "0"); +} + +TEST_F(LLVMGreaterThanTest, NegativeInfinityWithZeroString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "-Infinity", "0"); +} + +TEST_F(LLVMGreaterThanTest, NaNWithStringAbc) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "NaN", "abc"); +} + +TEST_F(LLVMGreaterThanTest, NaNWithStringAbc_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "NaN", "abc"); +} + +TEST_F(LLVMGreaterThanTest, NaNWithStringSpace) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "NaN", " "); +} + +TEST_F(LLVMGreaterThanTest, NaNWithStringSpace_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "NaN", " "); +} + +TEST_F(LLVMGreaterThanTest, NaNWithEmptyString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "NaN", ""); +} + +TEST_F(LLVMGreaterThanTest, NaNWithEmptyString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "NaN", ""); +} + +TEST_F(LLVMGreaterThanTest, NaNWithZeroString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "NaN", "0"); +} + +TEST_F(LLVMGreaterThanTest, NaNWithZeroString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "NaN", "0"); +} diff --git a/test/llvm/operators/less_than_test.cpp b/test/llvm/operators/less_than_test.cpp new file mode 100644 index 000000000..fcfcadc29 --- /dev/null +++ b/test/llvm/operators/less_than_test.cpp @@ -0,0 +1,1340 @@ +#include +#include + +#include "llvmtestutils.h" + +class LLVMLessThanTest : public testing::Test +{ + public: + LLVMTestUtils m_utils; +}; + +TEST_F(LLVMLessThanTest, SameIntegers) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, 10, 10); +} + +TEST_F(LLVMLessThanTest, SameIntegers_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, 10, 10); +} + +TEST_F(LLVMLessThanTest, FirstGreaterInteger) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, 10, 8); +} + +TEST_F(LLVMLessThanTest, FirstGreaterInteger_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, 10, 8); +} + +TEST_F(LLVMLessThanTest, SecondGreaterInteger) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, 8, 10); +} + +TEST_F(LLVMLessThanTest, SecondGreaterInteger_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, 8, 10); +} + +TEST_F(LLVMLessThanTest, SameDecimals) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, -4.25, -4.25); +} + +TEST_F(LLVMLessThanTest, SameDecimals_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, -4.25, -4.25); +} + +TEST_F(LLVMLessThanTest, FirstGreaterDecimal) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, -4.25, 5.312); +} + +TEST_F(LLVMLessThanTest, FirstGreaterDecimal_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, -4.25, 5.312); +} + +TEST_F(LLVMLessThanTest, SecondGreaterDecimal) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, 5.312, -4.25); +} + +TEST_F(LLVMLessThanTest, SecondGreaterDecimal_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, 5.312, -4.25); +} + +TEST_F(LLVMLessThanTest, SameBooleans) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, true, true); +} + +TEST_F(LLVMLessThanTest, SameBooleans_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, true, true); +} + +TEST_F(LLVMLessThanTest, TrueGreaterThanFalse) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, true, false); +} + +TEST_F(LLVMLessThanTest, TrueGreaterThanFalse_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, true, false); +} + +TEST_F(LLVMLessThanTest, FalseGreaterThanTrue) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, false, true); +} + +TEST_F(LLVMLessThanTest, FalseGreaterThanTrue_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, false, true); +} + +TEST_F(LLVMLessThanTest, NumberGreaterThanTrueBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, 1, true); +} + +TEST_F(LLVMLessThanTest, NumberGreaterThanTrueBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, 1, true); +} + +TEST_F(LLVMLessThanTest, NumberGreaterThanFalseBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, 1, false); +} + +TEST_F(LLVMLessThanTest, NumberGreaterThanFalseBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, 1, false); +} + +TEST_F(LLVMLessThanTest, SameStrings) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "abC def", "abC def"); +} + +TEST_F(LLVMLessThanTest, SameStrings_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "abC def", "abC def"); +} + +TEST_F(LLVMLessThanTest, StringsCaseDifferent) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "abC def", "abc dEf"); +} + +TEST_F(LLVMLessThanTest, StringsCaseDifferent_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "abC def", "abc dEf"); +} + +TEST_F(LLVMLessThanTest, FirstStringGreater) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "abC def", "ghi Jkl"); +} + +TEST_F(LLVMLessThanTest, FirstStringGreater_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "abC def", "ghi Jkl"); +} + +TEST_F(LLVMLessThanTest, SecondStringGreater) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "ghi Jkl", "abC def"); +} + +TEST_F(LLVMLessThanTest, SecondStringGreater_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "ghi Jkl", "abC def"); +} + +TEST_F(LLVMLessThanTest, StringsLengthComparison) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "abC def", "hello world"); +} + +TEST_F(LLVMLessThanTest, StringsLengthComparison_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "abC def", "hello world"); +} + +TEST_F(LLVMLessThanTest, SpaceGreaterThanEmpty) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, " ", ""); +} + +TEST_F(LLVMLessThanTest, SpaceGreaterThanEmpty_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, " ", ""); +} + +TEST_F(LLVMLessThanTest, SpaceGreaterThanZeroString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, " ", "0"); +} + +TEST_F(LLVMLessThanTest, SpaceGreaterThanZeroString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, " ", "0"); +} + +TEST_F(LLVMLessThanTest, SpaceGreaterThanZeroNumber) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, " ", 0); +} + +TEST_F(LLVMLessThanTest, SpaceGreaterThanZeroNumber_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, " ", 0); +} + +TEST_F(LLVMLessThanTest, ZeroNumberGreaterThanSpace) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, 0, " "); +} + +TEST_F(LLVMLessThanTest, ZeroNumberGreaterThanSpace_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, 0, " "); +} + +TEST_F(LLVMLessThanTest, EmptyGreaterThanZeroString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "", "0"); +} + +TEST_F(LLVMLessThanTest, EmptyGreaterThanZeroString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "", "0"); +} + +TEST_F(LLVMLessThanTest, EmptyGreaterThanZeroNumber) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "", 0); +} + +TEST_F(LLVMLessThanTest, EmptyGreaterThanZeroNumber_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "", 0); +} + +TEST_F(LLVMLessThanTest, ZeroNumberGreaterThanEmpty) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, 0, ""); +} + +TEST_F(LLVMLessThanTest, ZeroNumberGreaterThanEmpty_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, 0, ""); +} + +TEST_F(LLVMLessThanTest, ZeroStringGreaterThanZeroNumber) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "0", 0); +} + +TEST_F(LLVMLessThanTest, ZeroStringGreaterThanZeroNumber_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "0", 0); +} + +TEST_F(LLVMLessThanTest, ZeroNumberGreaterThanZeroString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, 0, "0"); +} + +TEST_F(LLVMLessThanTest, ZeroNumberGreaterThanZeroString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, 0, "0"); +} + +TEST_F(LLVMLessThanTest, NumberGreaterThanExactString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, 5.25, "5.25"); +} + +TEST_F(LLVMLessThanTest, NumberGreaterThanExactString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, 5.25, "5.25"); +} + +TEST_F(LLVMLessThanTest, ExactStringGreaterThanNumber) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "5.25", 5.25); +} + +TEST_F(LLVMLessThanTest, ExactStringGreaterThanNumber_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "5.25", 5.25); +} + +TEST_F(LLVMLessThanTest, NumberGreaterThanStringWithLeadingSpace) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, 5.25, " 5.25"); +} + +TEST_F(LLVMLessThanTest, NumberGreaterThanStringWithLeadingSpace_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, 5.25, " 5.25"); +} + +TEST_F(LLVMLessThanTest, StringWithLeadingSpaceGreaterThanNumber) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, " 5.25", 5.25); +} + +TEST_F(LLVMLessThanTest, StringWithLeadingSpaceGreaterThanNumber_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, " 5.25", 5.25); +} + +TEST_F(LLVMLessThanTest, NumberGreaterThanStringWithTrailingSpace) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, 5.25, "5.25 "); +} + +TEST_F(LLVMLessThanTest, NumberGreaterThanStringWithTrailingSpace_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, 5.25, "5.25 "); +} + +TEST_F(LLVMLessThanTest, StringWithTrailingSpaceGreaterThanNumber) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "5.25 ", 5.25); +} + +TEST_F(LLVMLessThanTest, StringWithTrailingSpaceGreaterThanNumber_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "5.25 ", 5.25); +} + +TEST_F(LLVMLessThanTest, NumberGreaterThanStringWithSurroundingSpaces) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, 5.25, " 5.25 "); +} + +TEST_F(LLVMLessThanTest, NumberGreaterThanStringWithSurroundingSpaces_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, 5.25, " 5.25 "); +} + +TEST_F(LLVMLessThanTest, StringWithSurroundingSpacesGreaterThanNumber) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, " 5.25 ", 5.25); +} + +TEST_F(LLVMLessThanTest, StringWithSurroundingSpacesGreaterThanNumber_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, " 5.25 ", 5.25); +} + +TEST_F(LLVMLessThanTest, NumberGreaterThanDifferentString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, 5.25, "5.26"); +} + +TEST_F(LLVMLessThanTest, NumberGreaterThanDifferentString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, 5.25, "5.26"); +} + +TEST_F(LLVMLessThanTest, DifferentStringGreaterThanNumber) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "5.26", 5.25); +} + +TEST_F(LLVMLessThanTest, DifferentStringGreaterThanNumber_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "5.26", 5.25); +} + +TEST_F(LLVMLessThanTest, DifferentStringNumbers) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "5.25", "5.26"); +} + +TEST_F(LLVMLessThanTest, DifferentStringNumbers_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "5.25", "5.26"); +} + +TEST_F(LLVMLessThanTest, NumberGreaterThanStringWithTrailingSpaces) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, 5, "5 "); +} + +TEST_F(LLVMLessThanTest, NumberGreaterThanStringWithTrailingSpaces_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, 5, "5 "); +} + +TEST_F(LLVMLessThanTest, StringWithTrailingSpacesGreaterThanNumber) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "5 ", 5); +} + +TEST_F(LLVMLessThanTest, StringWithTrailingSpacesGreaterThanNumber_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "5 ", 5); +} + +TEST_F(LLVMLessThanTest, ZeroGreaterThanOneString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, 0, "1"); +} + +TEST_F(LLVMLessThanTest, ZeroGreaterThanOneString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, 0, "1"); +} + +TEST_F(LLVMLessThanTest, OneStringGreaterThanZero) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "1", 0); +} + +TEST_F(LLVMLessThanTest, OneStringGreaterThanZero_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "1", 0); +} + +TEST_F(LLVMLessThanTest, ZeroGreaterThanTestString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, 0, "test"); +} + +TEST_F(LLVMLessThanTest, ZeroGreaterThanTestString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, 0, "test"); +} + +TEST_F(LLVMLessThanTest, TestStringGreaterThanZero) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "test", 0); +} + +TEST_F(LLVMLessThanTest, TestStringGreaterThanZero_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "test", 0); +} + +TEST_F(LLVMLessThanTest, NumberGreaterThanAbcString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, 55, "abc"); +} + +TEST_F(LLVMLessThanTest, NumberGreaterThanAbcString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, 55, "abc"); +} + +TEST_F(LLVMLessThanTest, AbcStringGreaterThanNumber) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "abc", 55); +} + +TEST_F(LLVMLessThanTest, AbcStringGreaterThanNumber_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "abc", 55); +} + +TEST_F(LLVMLessThanTest, InfinityGreaterThanInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "Infinity", "Infinity"); +} + +TEST_F(LLVMLessThanTest, InfinityGreaterThanInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "Infinity", "Infinity"); +} + +TEST_F(LLVMLessThanTest, NegativeInfinityGreaterThanNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "-Infinity", "-Infinity"); +} + +TEST_F(LLVMLessThanTest, NegativeInfinityGreaterThanNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "-Infinity", "-Infinity"); +} + +TEST_F(LLVMLessThanTest, NaNGreaterThanNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "NaN", "NaN"); +} + +TEST_F(LLVMLessThanTest, NaNGreaterThanNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "NaN", "NaN"); +} + +TEST_F(LLVMLessThanTest, InfinityGreaterThanNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "Infinity", "-Infinity"); +} + +TEST_F(LLVMLessThanTest, InfinityGreaterThanNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "Infinity", "-Infinity"); +} + +TEST_F(LLVMLessThanTest, NegativeInfinityGreaterThanInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "-Infinity", "Infinity"); +} + +TEST_F(LLVMLessThanTest, NegativeInfinityGreaterThanInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "-Infinity", "Infinity"); +} + +TEST_F(LLVMLessThanTest, InfinityGreaterThanNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "Infinity", "NaN"); +} + +TEST_F(LLVMLessThanTest, InfinityGreaterThanNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "Infinity", "NaN"); +} + +TEST_F(LLVMLessThanTest, NaNGreaterThanInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "NaN", "Infinity"); +} + +TEST_F(LLVMLessThanTest, NaNGreaterThanInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "NaN", "Infinity"); +} + +TEST_F(LLVMLessThanTest, NegativeInfinityGreaterThanNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "-Infinity", "NaN"); +} + +TEST_F(LLVMLessThanTest, NegativeInfinityGreaterThanNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "-Infinity", "NaN"); +} + +TEST_F(LLVMLessThanTest, NaNGreaterThanNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "NaN", "-Infinity"); +} + +TEST_F(LLVMLessThanTest, NaNGreaterThanNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "NaN", "-Infinity"); +} + +TEST_F(LLVMLessThanTest, NumberGreaterThanInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, 5, "Infinity"); +} + +TEST_F(LLVMLessThanTest, NumberGreaterThanInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, 5, "Infinity"); +} + +TEST_F(LLVMLessThanTest, InfinityGreaterThanNumber) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "Infinity", 5); +} + +TEST_F(LLVMLessThanTest, InfinityGreaterThanNumber_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "Infinity", 5); +} + +TEST_F(LLVMLessThanTest, NumberGreaterThanNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, 5, "-Infinity"); +} + +TEST_F(LLVMLessThanTest, NumberGreaterThanNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, 5, "-Infinity"); +} + +TEST_F(LLVMLessThanTest, NegativeInfinityGreaterThanNumber) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "-Infinity", 5); +} + +TEST_F(LLVMLessThanTest, NegativeInfinityGreaterThanNumber_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "-Infinity", 5); +} + +TEST_F(LLVMLessThanTest, NumberGreaterThanNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, 5, "NaN"); +} + +TEST_F(LLVMLessThanTest, NumberGreaterThanNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, 5, "NaN"); +} + +TEST_F(LLVMLessThanTest, NaNGreaterThanNumber) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "NaN", 5); +} + +TEST_F(LLVMLessThanTest, NaNGreaterThanNumber_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "NaN", 5); +} + +TEST_F(LLVMLessThanTest, ZeroGreaterThanNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, 0, "NaN"); +} + +TEST_F(LLVMLessThanTest, ZeroGreaterThanNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, 0, "NaN"); +} + +TEST_F(LLVMLessThanTest, NaNGreaterThanZero) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "NaN", 0); +} + +TEST_F(LLVMLessThanTest, NaNGreaterThanZero_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "NaN", 0); +} + +TEST_F(LLVMLessThanTest, TrueBooleanWithTrueString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, true, "true"); +} + +TEST_F(LLVMLessThanTest, TrueBooleanWithTrueString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, true, "true"); +} + +TEST_F(LLVMLessThanTest, TrueStringWithTrueBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "true", true); +} + +TEST_F(LLVMLessThanTest, TrueStringWithTrueBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "true", true); +} + +TEST_F(LLVMLessThanTest, FalseBooleanWithFalseString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, false, "false"); +} + +TEST_F(LLVMLessThanTest, FalseBooleanWithFalseString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, false, "false"); +} + +TEST_F(LLVMLessThanTest, FalseStringWithFalseBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "false", false); +} + +TEST_F(LLVMLessThanTest, FalseStringWithFalseBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "false", false); +} + +TEST_F(LLVMLessThanTest, FalseBooleanWithTrueString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, false, "true"); +} + +TEST_F(LLVMLessThanTest, FalseBooleanWithTrueString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, false, "true"); +} + +TEST_F(LLVMLessThanTest, TrueStringWithFalseBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "true", false); +} + +TEST_F(LLVMLessThanTest, TrueStringWithFalseBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "true", false); +} + +TEST_F(LLVMLessThanTest, TrueBooleanWithFalseString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, true, "false"); +} + +TEST_F(LLVMLessThanTest, TrueBooleanWithFalseString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, true, "false"); +} + +TEST_F(LLVMLessThanTest, FalseStringWithTrueBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "false", true); +} + +TEST_F(LLVMLessThanTest, FalseStringWithTrueBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "false", true); +} + +TEST_F(LLVMLessThanTest, TrueBooleanWithUppercaseTrueString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, true, "TRUE"); +} + +TEST_F(LLVMLessThanTest, TrueBooleanWithUppercaseTrueString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, true, "TRUE"); +} + +TEST_F(LLVMLessThanTest, UppercaseTrueStringWithTrueBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "TRUE", true); +} + +TEST_F(LLVMLessThanTest, UppercaseTrueStringWithTrueBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "TRUE", true); +} + +TEST_F(LLVMLessThanTest, FalseBooleanWithUppercaseFalseString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, false, "FALSE"); +} + +TEST_F(LLVMLessThanTest, FalseBooleanWithUppercaseFalseString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, false, "FALSE"); +} + +TEST_F(LLVMLessThanTest, UppercaseFalseStringWithFalseBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "FALSE", false); +} + +TEST_F(LLVMLessThanTest, UppercaseFalseStringWithFalseBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "FALSE", false); +} + +TEST_F(LLVMLessThanTest, TrueBooleanWithZeroPaddedOne) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, true, "00001"); +} + +TEST_F(LLVMLessThanTest, TrueBooleanWithZeroPaddedOne_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, true, "00001"); +} + +TEST_F(LLVMLessThanTest, ZeroPaddedOneWithTrueBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "00001", true); +} + +TEST_F(LLVMLessThanTest, ZeroPaddedOneWithTrueBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "00001", true); +} + +TEST_F(LLVMLessThanTest, TrueBooleanWithZeroPaddedZero) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, true, "00000"); +} + +TEST_F(LLVMLessThanTest, TrueBooleanWithZeroPaddedZero_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, true, "00000"); +} + +TEST_F(LLVMLessThanTest, ZeroPaddedZeroWithTrueBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "00000", true); +} + +TEST_F(LLVMLessThanTest, ZeroPaddedZeroWithTrueBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "00000", true); +} + +TEST_F(LLVMLessThanTest, FalseBooleanWithZeroPaddedZero) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, false, "00000"); +} + +TEST_F(LLVMLessThanTest, FalseBooleanWithZeroPaddedZero_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, false, "00000"); +} + +TEST_F(LLVMLessThanTest, ZeroPaddedZeroWithFalseBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "00000", false); +} + +TEST_F(LLVMLessThanTest, ZeroPaddedZeroWithFalseBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "00000", false); +} + +TEST_F(LLVMLessThanTest, TrueStringWithOne) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "true", 1); +} + +TEST_F(LLVMLessThanTest, TrueStringWithOne_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "true", 1); +} + +TEST_F(LLVMLessThanTest, OneWithTrueString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, 1, "true"); +} + +TEST_F(LLVMLessThanTest, OneWithTrueString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, 1, "true"); +} + +TEST_F(LLVMLessThanTest, TrueStringWithZero) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "true", 0); +} + +TEST_F(LLVMLessThanTest, TrueStringWithZero_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "true", 0); +} + +TEST_F(LLVMLessThanTest, ZeroWithTrueString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, 0, "true"); +} + +TEST_F(LLVMLessThanTest, ZeroWithTrueString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, 0, "true"); +} + +TEST_F(LLVMLessThanTest, FalseStringWithZero) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "false", 0); +} + +TEST_F(LLVMLessThanTest, FalseStringWithZero_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "false", 0); +} + +TEST_F(LLVMLessThanTest, ZeroWithFalseString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, 0, "false"); +} + +TEST_F(LLVMLessThanTest, ZeroWithFalseString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, 0, "false"); +} + +TEST_F(LLVMLessThanTest, FalseStringWithOne) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "false", 1); +} + +TEST_F(LLVMLessThanTest, FalseStringWithOne_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "false", 1); +} + +TEST_F(LLVMLessThanTest, OneWithFalseString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, 1, "false"); +} + +TEST_F(LLVMLessThanTest, OneWithFalseString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, 1, "false"); +} + +TEST_F(LLVMLessThanTest, TrueStringWithUppercaseTrueString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "true", "TRUE"); +} + +TEST_F(LLVMLessThanTest, TrueStringWithUppercaseTrueString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "true", "TRUE"); +} + +TEST_F(LLVMLessThanTest, TrueStringWithUppercaseFalseString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "true", "FALSE"); +} + +TEST_F(LLVMLessThanTest, TrueStringWithUppercaseFalseString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "true", "FALSE"); +} + +TEST_F(LLVMLessThanTest, FalseStringWithUppercaseFalseString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "false", "FALSE"); +} + +TEST_F(LLVMLessThanTest, FalseStringWithUppercaseFalseString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "false", "FALSE"); +} + +TEST_F(LLVMLessThanTest, FalseStringWithUppercaseTrueString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "false", "TRUE"); +} + +TEST_F(LLVMLessThanTest, FalseStringWithUppercaseTrueString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "false", "TRUE"); +} + +TEST_F(LLVMLessThanTest, TrueBooleanWithInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, true, "Infinity"); +} + +TEST_F(LLVMLessThanTest, TrueBooleanWithInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, true, "Infinity"); +} + +TEST_F(LLVMLessThanTest, InfinityWithTrueBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "Infinity", true); +} + +TEST_F(LLVMLessThanTest, InfinityWithTrueBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "Infinity", true); +} + +TEST_F(LLVMLessThanTest, TrueBooleanWithNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, true, "-Infinity"); +} + +TEST_F(LLVMLessThanTest, TrueBooleanWithNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, true, "-Infinity"); +} + +TEST_F(LLVMLessThanTest, NegativeInfinityWithTrueBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "-Infinity", true); +} + +TEST_F(LLVMLessThanTest, NegativeInfinityWithTrueBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "-Infinity", true); +} + +TEST_F(LLVMLessThanTest, TrueBooleanWithNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, true, "NaN"); +} + +TEST_F(LLVMLessThanTest, TrueBooleanWithNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, true, "NaN"); +} + +TEST_F(LLVMLessThanTest, NaNWithTrueBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "NaN", true); +} + +TEST_F(LLVMLessThanTest, NaNWithTrueBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "NaN", true); +} + +TEST_F(LLVMLessThanTest, FalseBooleanWithInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, false, "Infinity"); +} + +TEST_F(LLVMLessThanTest, FalseBooleanWithInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, false, "Infinity"); +} + +TEST_F(LLVMLessThanTest, InfinityWithFalseBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "Infinity", false); +} + +TEST_F(LLVMLessThanTest, InfinityWithFalseBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "Infinity", false); +} + +TEST_F(LLVMLessThanTest, FalseBooleanWithNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, false, "-Infinity"); +} + +TEST_F(LLVMLessThanTest, FalseBooleanWithNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, false, "-Infinity"); +} + +TEST_F(LLVMLessThanTest, NegativeInfinityWithFalseBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "-Infinity", false); +} + +TEST_F(LLVMLessThanTest, NegativeInfinityWithFalseBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "-Infinity", false); +} + +TEST_F(LLVMLessThanTest, FalseBooleanWithNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, false, "NaN"); +} + +TEST_F(LLVMLessThanTest, FalseBooleanWithNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, false, "NaN"); +} + +TEST_F(LLVMLessThanTest, NaNWithFalseBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "NaN", false); +} + +TEST_F(LLVMLessThanTest, NaNWithFalseBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "NaN", false); +} + +TEST_F(LLVMLessThanTest, InfinityStringWithInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "Infinity", "Infinity"); +} + +TEST_F(LLVMLessThanTest, InfinityStringWithInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "Infinity", "Infinity"); +} + +TEST_F(LLVMLessThanTest, InfinityStringWithNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "Infinity", "-Infinity"); +} + +TEST_F(LLVMLessThanTest, InfinityStringWithNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "Infinity", "-Infinity"); +} + +TEST_F(LLVMLessThanTest, InfinityStringWithNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "Infinity", "NaN"); +} + +TEST_F(LLVMLessThanTest, InfinityStringWithNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "Infinity", "NaN"); +} + +TEST_F(LLVMLessThanTest, LowercaseInfinityStringWithInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "infinity", "Infinity"); +} + +TEST_F(LLVMLessThanTest, LowercaseInfinityStringWithInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "infinity", "Infinity"); +} + +TEST_F(LLVMLessThanTest, LowercaseInfinityStringWithNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "infinity", "-Infinity"); +} + +TEST_F(LLVMLessThanTest, LowercaseInfinityStringWithNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "infinity", "-Infinity"); +} + +TEST_F(LLVMLessThanTest, LowercaseInfinityStringWithNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "infinity", "NaN"); +} + +TEST_F(LLVMLessThanTest, LowercaseInfinityStringWithNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "infinity", "NaN"); +} + +TEST_F(LLVMLessThanTest, NegativeInfinityStringWithInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "-Infinity", "Infinity"); +} + +TEST_F(LLVMLessThanTest, NegativeInfinityStringWithInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "-Infinity", "Infinity"); +} + +TEST_F(LLVMLessThanTest, NegativeInfinityStringWithNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "-Infinity", "-Infinity"); +} + +TEST_F(LLVMLessThanTest, NegativeInfinityStringWithNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "-Infinity", "-Infinity"); +} + +TEST_F(LLVMLessThanTest, NegativeInfinityStringWithNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "-Infinity", "NaN"); +} + +TEST_F(LLVMLessThanTest, NegativeInfinityStringWithNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "-Infinity", "NaN"); +} + +TEST_F(LLVMLessThanTest, LowercaseNegativeInfinityStringWithInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "-infinity", "Infinity"); +} + +TEST_F(LLVMLessThanTest, LowercaseNegativeInfinityStringWithInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "-infinity", "Infinity"); +} + +TEST_F(LLVMLessThanTest, LowercaseNegativeInfinityStringWithNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "-infinity", "-Infinity"); +} + +TEST_F(LLVMLessThanTest, LowercaseNegativeInfinityStringWithNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "-infinity", "-Infinity"); +} + +TEST_F(LLVMLessThanTest, LowercaseNegativeInfinityStringWithNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "-infinity", "NaN"); +} + +TEST_F(LLVMLessThanTest, LowercaseNegativeInfinityStringWithNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "-infinity", "NaN"); +} + +TEST_F(LLVMLessThanTest, NaNStringWithInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "NaN", "Infinity"); +} + +TEST_F(LLVMLessThanTest, NaNStringWithInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "NaN", "Infinity"); +} + +TEST_F(LLVMLessThanTest, NaNStringWithNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "NaN", "-Infinity"); +} + +TEST_F(LLVMLessThanTest, NaNStringWithNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "NaN", "-Infinity"); +} + +TEST_F(LLVMLessThanTest, NaNStringWithNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "NaN", "NaN"); +} + +TEST_F(LLVMLessThanTest, NaNStringWithNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "NaN", "NaN"); +} + +TEST_F(LLVMLessThanTest, LowercaseNaNStringWithInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "nan", "Infinity"); +} + +TEST_F(LLVMLessThanTest, LowercaseNaNStringWithInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "nan", "Infinity"); +} + +TEST_F(LLVMLessThanTest, LowercaseNaNStringWithNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "nan", "-Infinity"); +} + +TEST_F(LLVMLessThanTest, LowercaseNaNStringWithNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "nan", "-Infinity"); +} + +TEST_F(LLVMLessThanTest, LowercaseNaNStringWithNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "nan", "NaN"); +} + +TEST_F(LLVMLessThanTest, LowercaseNaNStringWithNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "nan", "NaN"); +} + +TEST_F(LLVMLessThanTest, InfinityWithStringAbc) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "Infinity", "abc"); +} + +TEST_F(LLVMLessThanTest, InfinityWithStringAbc_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "Infinity", "abc"); +} + +TEST_F(LLVMLessThanTest, InfinityWithStringSpace) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "Infinity", " "); +} + +TEST_F(LLVMLessThanTest, InfinityWithStringSpace_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "Infinity", " "); +} + +TEST_F(LLVMLessThanTest, InfinityWithEmptyString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "Infinity", ""); +} + +TEST_F(LLVMLessThanTest, InfinityWithEmptyString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "Infinity", ""); +} + +TEST_F(LLVMLessThanTest, InfinityWithZeroString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "Infinity", "0"); +} + +TEST_F(LLVMLessThanTest, InfinityWithZeroString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "Infinity", "0"); +} + +TEST_F(LLVMLessThanTest, NegativeInfinityWithStringAbc) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "-Infinity", "abc"); +} + +TEST_F(LLVMLessThanTest, NegativeInfinityWithStringAbc_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "-Infinity", "abc"); +} + +TEST_F(LLVMLessThanTest, NegativeInfinityWithStringSpace) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "-Infinity", " "); +} + +TEST_F(LLVMLessThanTest, NegativeInfinityWithStringSpace_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "-Infinity", " "); +} + +TEST_F(LLVMLessThanTest, NegativeInfinityWithEmptyString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "-Infinity", ""); +} + +TEST_F(LLVMLessThanTest, NegativeInfinityWithEmptyString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "-Infinity", ""); +} + +TEST_F(LLVMLessThanTest, NegativeInfinityWithZeroString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "-Infinity", "0"); +} + +TEST_F(LLVMLessThanTest, NegativeInfinityWithZeroString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "-Infinity", "0"); +} + +TEST_F(LLVMLessThanTest, NaNWithStringAbc) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "NaN", "abc"); +} + +TEST_F(LLVMLessThanTest, NaNWithStringAbc_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "NaN", "abc"); +} + +TEST_F(LLVMLessThanTest, NaNWithStringSpace) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "NaN", " "); +} + +TEST_F(LLVMLessThanTest, NaNWithStringSpace_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "NaN", " "); +} + +TEST_F(LLVMLessThanTest, NaNWithEmptyString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "NaN", ""); +} + +TEST_F(LLVMLessThanTest, NaNWithEmptyString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "NaN", ""); +} + +TEST_F(LLVMLessThanTest, NaNWithZeroString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "NaN", "0"); +} + +TEST_F(LLVMLessThanTest, NaNWithZeroString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "NaN", "0"); +} diff --git a/test/llvm/operators/logic/and_test.cpp b/test/llvm/operators/logic/and_test.cpp new file mode 100644 index 000000000..8129b2e82 --- /dev/null +++ b/test/llvm/operators/logic/and_test.cpp @@ -0,0 +1,890 @@ +#include +#include + +#include "llvmtestutils.h" + +class LLVMAndTest : public testing::Test +{ + public: + LLVMTestUtils m_utils; +}; + +TEST_F(LLVMAndTest, NumberWithNumber) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, 10, 8); +} + +TEST_F(LLVMAndTest, NumberWithNumber_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, 10, 8); +} + +TEST_F(LLVMAndTest, SameNegativeDecimals) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, -4.25, -4.25); +} + +TEST_F(LLVMAndTest, SameNegativeDecimals_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, -4.25, -4.25); +} + +TEST_F(LLVMAndTest, DifferentDecimals) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, -4.25, 5.312); +} + +TEST_F(LLVMAndTest, DifferentDecimals_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, -4.25, 5.312); +} + +TEST_F(LLVMAndTest, TrueAndTrue) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, true, true); +} + +TEST_F(LLVMAndTest, TrueAndTrue_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, true, true); +} + +TEST_F(LLVMAndTest, TrueAndFalse) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, true, false); +} + +TEST_F(LLVMAndTest, TrueAndFalse_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, true, false); +} + +TEST_F(LLVMAndTest, FalseAndTrue) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, false, true); +} + +TEST_F(LLVMAndTest, FalseAndTrue_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, false, true); +} + +TEST_F(LLVMAndTest, NumberAndTrueBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, 1, true); +} + +TEST_F(LLVMAndTest, NumberAndTrueBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, 1, true); +} + +TEST_F(LLVMAndTest, NumberAndFalseBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, 1, false); +} + +TEST_F(LLVMAndTest, NumberAndFalseBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, 1, false); +} + +TEST_F(LLVMAndTest, StringAndString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "abc", "def"); +} + +TEST_F(LLVMAndTest, StringAndString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "abc", "def"); +} + +TEST_F(LLVMAndTest, TrueStringAndTrueString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "true", "true"); +} + +TEST_F(LLVMAndTest, TrueStringAndTrueString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "true", "true"); +} + +TEST_F(LLVMAndTest, TrueStringAndFalseString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "true", "false"); +} + +TEST_F(LLVMAndTest, TrueStringAndFalseString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "true", "false"); +} + +TEST_F(LLVMAndTest, FalseStringAndTrueString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "false", "true"); +} + +TEST_F(LLVMAndTest, FalseStringAndTrueString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "false", "true"); +} + +TEST_F(LLVMAndTest, FalseStringAndFalseString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "false", "false"); +} + +TEST_F(LLVMAndTest, FalseStringAndFalseString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "false", "false"); +} + +TEST_F(LLVMAndTest, NumberAndExactString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, 5.25, "5.25"); +} + +TEST_F(LLVMAndTest, NumberAndExactString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, 5.25, "5.25"); +} + +TEST_F(LLVMAndTest, ExactStringAndNumber) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "5.25", 5.25); +} + +TEST_F(LLVMAndTest, ExactStringAndNumber_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "5.25", 5.25); +} + +TEST_F(LLVMAndTest, ZeroAndOneString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, 0, "1"); +} + +TEST_F(LLVMAndTest, ZeroAndOneString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, 0, "1"); +} + +TEST_F(LLVMAndTest, OneStringAndZero) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "1", 0); +} + +TEST_F(LLVMAndTest, OneStringAndZero_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "1", 0); +} + +TEST_F(LLVMAndTest, ZeroAndTestString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, 0, "test"); +} + +TEST_F(LLVMAndTest, ZeroAndTestString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, 0, "test"); +} + +TEST_F(LLVMAndTest, TestStringAndZero) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "test", 0); +} + +TEST_F(LLVMAndTest, TestStringAndZero_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "test", 0); +} + +TEST_F(LLVMAndTest, InfinityAndInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "Infinity", "Infinity"); +} + +TEST_F(LLVMAndTest, InfinityAndInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "Infinity", "Infinity"); +} + +TEST_F(LLVMAndTest, NegativeInfinityAndNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "-Infinity", "-Infinity"); +} + +TEST_F(LLVMAndTest, NegativeInfinityAndNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "-Infinity", "-Infinity"); +} + +TEST_F(LLVMAndTest, NaNAndNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "NaN", "NaN"); +} + +TEST_F(LLVMAndTest, NaNAndNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "NaN", "NaN"); +} + +TEST_F(LLVMAndTest, InfinityAndNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "Infinity", "-Infinity"); +} + +TEST_F(LLVMAndTest, InfinityAndNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "Infinity", "-Infinity"); +} + +TEST_F(LLVMAndTest, NegativeInfinityAndInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "-Infinity", "Infinity"); +} + +TEST_F(LLVMAndTest, NegativeInfinityAndInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "-Infinity", "Infinity"); +} + +TEST_F(LLVMAndTest, InfinityAndNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "Infinity", "NaN"); +} + +TEST_F(LLVMAndTest, InfinityAndNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "Infinity", "NaN"); +} + +TEST_F(LLVMAndTest, NaNAndInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "NaN", "Infinity"); +} + +TEST_F(LLVMAndTest, NaNAndInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "NaN", "Infinity"); +} + +TEST_F(LLVMAndTest, NegativeInfinityAndNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "-Infinity", "NaN"); +} + +TEST_F(LLVMAndTest, NegativeInfinityAndNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "-Infinity", "NaN"); +} + +TEST_F(LLVMAndTest, NaNAndNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "NaN", "-Infinity"); +} + +TEST_F(LLVMAndTest, NaNAndNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "NaN", "-Infinity"); +} + +TEST_F(LLVMAndTest, TrueBooleanWithTrueString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, true, "true"); +} + +TEST_F(LLVMAndTest, TrueBooleanWithTrueString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, true, "true"); +} + +TEST_F(LLVMAndTest, TrueStringWithTrueBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "true", true); +} + +TEST_F(LLVMAndTest, TrueStringWithTrueBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "true", true); +} + +TEST_F(LLVMAndTest, FalseBooleanWithFalseString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, false, "false"); +} + +TEST_F(LLVMAndTest, FalseBooleanWithFalseString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, false, "false"); +} + +TEST_F(LLVMAndTest, FalseStringWithFalseBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "false", false); +} + +TEST_F(LLVMAndTest, FalseStringWithFalseBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "false", false); +} + +TEST_F(LLVMAndTest, FalseBooleanWithTrueString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, false, "true"); +} + +TEST_F(LLVMAndTest, FalseBooleanWithTrueString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, false, "true"); +} + +TEST_F(LLVMAndTest, TrueStringWithFalseBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "true", false); +} + +TEST_F(LLVMAndTest, TrueStringWithFalseBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "true", false); +} + +TEST_F(LLVMAndTest, TrueBooleanWithFalseString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, true, "false"); +} + +TEST_F(LLVMAndTest, TrueBooleanWithFalseString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, true, "false"); +} + +TEST_F(LLVMAndTest, FalseStringWithTrueBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "false", true); +} + +TEST_F(LLVMAndTest, FalseStringWithTrueBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "false", true); +} + +TEST_F(LLVMAndTest, TrueBooleanWithUppercaseTrueString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, true, "TRUE"); +} + +TEST_F(LLVMAndTest, TrueBooleanWithUppercaseTrueString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, true, "TRUE"); +} + +TEST_F(LLVMAndTest, UppercaseTrueStringWithTrueBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "TRUE", true); +} + +TEST_F(LLVMAndTest, UppercaseTrueStringWithTrueBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "TRUE", true); +} + +TEST_F(LLVMAndTest, FalseBooleanWithUppercaseFalseString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, false, "FALSE"); +} + +TEST_F(LLVMAndTest, FalseBooleanWithUppercaseFalseString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, false, "FALSE"); +} + +TEST_F(LLVMAndTest, UppercaseFalseStringWithFalseBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "FALSE", false); +} + +TEST_F(LLVMAndTest, UppercaseFalseStringWithFalseBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "FALSE", false); +} + +TEST_F(LLVMAndTest, TrueBooleanWithZeroPaddedOne) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, true, "00001"); +} + +TEST_F(LLVMAndTest, TrueBooleanWithZeroPaddedOne_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, true, "00001"); +} + +TEST_F(LLVMAndTest, ZeroPaddedOneWithTrueBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "00001", true); +} + +TEST_F(LLVMAndTest, ZeroPaddedOneWithTrueBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "00001", true); +} + +TEST_F(LLVMAndTest, TrueBooleanWithZeroPaddedZero) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, true, "00000"); +} + +TEST_F(LLVMAndTest, TrueBooleanWithZeroPaddedZero_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, true, "00000"); +} + +TEST_F(LLVMAndTest, ZeroPaddedZeroWithTrueBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "00000", true); +} + +TEST_F(LLVMAndTest, ZeroPaddedZeroWithTrueBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "00000", true); +} + +TEST_F(LLVMAndTest, FalseBooleanWithZeroPaddedZero) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, false, "00000"); +} + +TEST_F(LLVMAndTest, FalseBooleanWithZeroPaddedZero_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, false, "00000"); +} + +TEST_F(LLVMAndTest, ZeroPaddedZeroWithFalseBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "00000", false); +} + +TEST_F(LLVMAndTest, ZeroPaddedZeroWithFalseBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "00000", false); +} + +TEST_F(LLVMAndTest, TrueStringWithOne) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "true", 1); +} + +TEST_F(LLVMAndTest, TrueStringWithOne_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "true", 1); +} + +TEST_F(LLVMAndTest, OneWithTrueString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, 1, "true"); +} + +TEST_F(LLVMAndTest, OneWithTrueString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, 1, "true"); +} + +TEST_F(LLVMAndTest, TrueStringWithZero) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "true", 0); +} + +TEST_F(LLVMAndTest, TrueStringWithZero_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "true", 0); +} + +TEST_F(LLVMAndTest, ZeroWithTrueString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, 0, "true"); +} + +TEST_F(LLVMAndTest, ZeroWithTrueString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, 0, "true"); +} + +TEST_F(LLVMAndTest, FalseStringWithZero) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "false", 0); +} + +TEST_F(LLVMAndTest, FalseStringWithZero_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "false", 0); +} + +TEST_F(LLVMAndTest, ZeroWithFalseString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, 0, "false"); +} + +TEST_F(LLVMAndTest, ZeroWithFalseString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, 0, "false"); +} + +TEST_F(LLVMAndTest, FalseStringWithOne) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "false", 1); +} + +TEST_F(LLVMAndTest, FalseStringWithOne_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "false", 1); +} + +TEST_F(LLVMAndTest, OneWithFalseString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, 1, "false"); +} + +TEST_F(LLVMAndTest, OneWithFalseString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, 1, "false"); +} + +TEST_F(LLVMAndTest, TrueStringWithUppercaseTrueString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "true", "TRUE"); +} + +TEST_F(LLVMAndTest, TrueStringWithUppercaseTrueString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "true", "TRUE"); +} + +TEST_F(LLVMAndTest, TrueStringWithUppercaseFalseString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "true", "FALSE"); +} + +TEST_F(LLVMAndTest, TrueStringWithUppercaseFalseString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "true", "FALSE"); +} + +TEST_F(LLVMAndTest, FalseStringWithUppercaseFalseString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "false", "FALSE"); +} + +TEST_F(LLVMAndTest, FalseStringWithUppercaseFalseString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "false", "FALSE"); +} + +TEST_F(LLVMAndTest, FalseStringWithUppercaseTrueString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "false", "TRUE"); +} + +TEST_F(LLVMAndTest, FalseStringWithUppercaseTrueString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "false", "TRUE"); +} + +TEST_F(LLVMAndTest, TrueBooleanWithInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, true, "Infinity"); +} + +TEST_F(LLVMAndTest, TrueBooleanWithInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, true, "Infinity"); +} + +TEST_F(LLVMAndTest, InfinityWithTrueBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "Infinity", true); +} + +TEST_F(LLVMAndTest, InfinityWithTrueBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "Infinity", true); +} + +TEST_F(LLVMAndTest, TrueBooleanWithNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, true, "-Infinity"); +} + +TEST_F(LLVMAndTest, TrueBooleanWithNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, true, "-Infinity"); +} + +TEST_F(LLVMAndTest, NegativeInfinityWithTrueBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "-Infinity", true); +} + +TEST_F(LLVMAndTest, NegativeInfinityWithTrueBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "-Infinity", true); +} + +TEST_F(LLVMAndTest, TrueBooleanWithNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, true, "NaN"); +} + +TEST_F(LLVMAndTest, TrueBooleanWithNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, true, "NaN"); +} + +TEST_F(LLVMAndTest, NaNWithTrueBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "NaN", true); +} + +TEST_F(LLVMAndTest, NaNWithTrueBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "NaN", true); +} + +TEST_F(LLVMAndTest, FalseBooleanWithInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, false, "Infinity"); +} + +TEST_F(LLVMAndTest, FalseBooleanWithInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, false, "Infinity"); +} + +TEST_F(LLVMAndTest, InfinityWithFalseBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "Infinity", false); +} + +TEST_F(LLVMAndTest, InfinityWithFalseBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "Infinity", false); +} + +TEST_F(LLVMAndTest, FalseBooleanWithNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, false, "-Infinity"); +} + +TEST_F(LLVMAndTest, FalseBooleanWithNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, false, "-Infinity"); +} + +TEST_F(LLVMAndTest, NegativeInfinityWithFalseBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "-Infinity", false); +} + +TEST_F(LLVMAndTest, NegativeInfinityWithFalseBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "-Infinity", false); +} + +TEST_F(LLVMAndTest, FalseBooleanWithNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, false, "NaN"); +} + +TEST_F(LLVMAndTest, FalseBooleanWithNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, false, "NaN"); +} + +TEST_F(LLVMAndTest, NaNWithFalseBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "NaN", false); +} + +TEST_F(LLVMAndTest, NaNWithFalseBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "NaN", false); +} + +TEST_F(LLVMAndTest, InfinityStringWithInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "Infinity", "Infinity"); +} + +TEST_F(LLVMAndTest, InfinityStringWithInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "Infinity", "Infinity"); +} + +TEST_F(LLVMAndTest, InfinityStringWithNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "Infinity", "-Infinity"); +} + +TEST_F(LLVMAndTest, InfinityStringWithNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "Infinity", "-Infinity"); +} + +TEST_F(LLVMAndTest, InfinityStringWithNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "Infinity", "NaN"); +} + +TEST_F(LLVMAndTest, InfinityStringWithNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "Infinity", "NaN"); +} + +TEST_F(LLVMAndTest, LowercaseInfinityStringWithInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "infinity", "Infinity"); +} + +TEST_F(LLVMAndTest, LowercaseInfinityStringWithInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "infinity", "Infinity"); +} + +TEST_F(LLVMAndTest, LowercaseInfinityStringWithNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "infinity", "-Infinity"); +} + +TEST_F(LLVMAndTest, LowercaseInfinityStringWithNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "infinity", "-Infinity"); +} + +TEST_F(LLVMAndTest, LowercaseInfinityStringWithNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "infinity", "NaN"); +} + +TEST_F(LLVMAndTest, LowercaseInfinityStringWithNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "infinity", "NaN"); +} + +TEST_F(LLVMAndTest, NegativeInfinityStringWithInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "-Infinity", "Infinity"); +} + +TEST_F(LLVMAndTest, NegativeInfinityStringWithInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "-Infinity", "Infinity"); +} + +TEST_F(LLVMAndTest, NegativeInfinityStringWithNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "-Infinity", "-Infinity"); +} + +TEST_F(LLVMAndTest, NegativeInfinityStringWithNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "-Infinity", "-Infinity"); +} + +TEST_F(LLVMAndTest, NegativeInfinityStringWithNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "-Infinity", "NaN"); +} + +TEST_F(LLVMAndTest, NegativeInfinityStringWithNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "-Infinity", "NaN"); +} + +TEST_F(LLVMAndTest, LowercaseNegativeInfinityStringWithInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "-infinity", "Infinity"); +} + +TEST_F(LLVMAndTest, LowercaseNegativeInfinityStringWithInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "-infinity", "Infinity"); +} + +TEST_F(LLVMAndTest, LowercaseNegativeInfinityStringWithNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "-infinity", "-Infinity"); +} + +TEST_F(LLVMAndTest, LowercaseNegativeInfinityStringWithNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "-infinity", "-Infinity"); +} + +TEST_F(LLVMAndTest, LowercaseNegativeInfinityStringWithNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "-infinity", "NaN"); +} + +TEST_F(LLVMAndTest, LowercaseNegativeInfinityStringWithNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "-infinity", "NaN"); +} + +TEST_F(LLVMAndTest, NaNStringWithInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "NaN", "Infinity"); +} + +TEST_F(LLVMAndTest, NaNStringWithInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "NaN", "Infinity"); +} + +TEST_F(LLVMAndTest, NaNStringWithNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "NaN", "-Infinity"); +} + +TEST_F(LLVMAndTest, NaNStringWithNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "NaN", "-Infinity"); +} + +TEST_F(LLVMAndTest, NaNStringWithNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "NaN", "NaN"); +} + +TEST_F(LLVMAndTest, NaNStringWithNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "NaN", "NaN"); +} + +TEST_F(LLVMAndTest, LowercaseNaNStringWithInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "nan", "Infinity"); +} + +TEST_F(LLVMAndTest, LowercaseNaNStringWithInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "nan", "Infinity"); +} + +TEST_F(LLVMAndTest, LowercaseNaNStringWithNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "nan", "-Infinity"); +} + +TEST_F(LLVMAndTest, LowercaseNaNStringWithNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "nan", "-Infinity"); +} + +TEST_F(LLVMAndTest, LowercaseNaNStringWithNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "nan", "NaN"); +} + +TEST_F(LLVMAndTest, LowercaseNaNStringWithNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "nan", "NaN"); +} diff --git a/test/llvm/operators/logic/not_test.cpp b/test/llvm/operators/logic/not_test.cpp new file mode 100644 index 000000000..7c28e577c --- /dev/null +++ b/test/llvm/operators/logic/not_test.cpp @@ -0,0 +1,260 @@ +#include +#include + +#include "llvmtestutils.h" + +class LLVMNotTest : public testing::Test +{ + public: + LLVMTestUtils m_utils; +}; + +TEST_F(LLVMNotTest, PositiveNumber) +{ + ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, false, 10); +} + +TEST_F(LLVMNotTest, PositiveNumber_Const) +{ + ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, true, 10); +} + +TEST_F(LLVMNotTest, NegativeDecimal) +{ + ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, false, -4.25); +} + +TEST_F(LLVMNotTest, NegativeDecimal_Const) +{ + ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, true, -4.25); +} + +TEST_F(LLVMNotTest, PositiveDecimal) +{ + ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, false, 5.312); +} + +TEST_F(LLVMNotTest, PositiveDecimal_Const) +{ + ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, true, 5.312); +} + +TEST_F(LLVMNotTest, One) +{ + ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, false, 1); +} + +TEST_F(LLVMNotTest, One_Const) +{ + ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, true, 1); +} + +TEST_F(LLVMNotTest, Zero) +{ + ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, false, 0); +} + +TEST_F(LLVMNotTest, Zero_Const) +{ + ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, true, 0); +} + +TEST_F(LLVMNotTest, TrueBoolean) +{ + ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, false, true); +} + +TEST_F(LLVMNotTest, TrueBoolean_Const) +{ + ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, true, true); +} + +TEST_F(LLVMNotTest, FalseBoolean) +{ + ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, false, false); +} + +TEST_F(LLVMNotTest, FalseBoolean_Const) +{ + ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, true, false); +} + +TEST_F(LLVMNotTest, AbcString) +{ + ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, false, "abc"); +} + +TEST_F(LLVMNotTest, AbcString_Const) +{ + ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, true, "abc"); +} + +TEST_F(LLVMNotTest, NumericString) +{ + ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, false, "5.25"); +} + +TEST_F(LLVMNotTest, NumericString_Const) +{ + ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, true, "5.25"); +} + +TEST_F(LLVMNotTest, ZeroString) +{ + ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, false, "0"); +} + +TEST_F(LLVMNotTest, ZeroString_Const) +{ + ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, true, "0"); +} + +TEST_F(LLVMNotTest, Infinity) +{ + ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, false, "Infinity"); +} + +TEST_F(LLVMNotTest, Infinity_Const) +{ + ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, true, "Infinity"); +} + +TEST_F(LLVMNotTest, NegativeInfinity) +{ + ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, false, "-Infinity"); +} + +TEST_F(LLVMNotTest, NegativeInfinity_Const) +{ + ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, true, "-Infinity"); +} + +TEST_F(LLVMNotTest, NaN) +{ + ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, false, "NaN"); +} + +TEST_F(LLVMNotTest, NaN_Const) +{ + ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, true, "NaN"); +} + +TEST_F(LLVMNotTest, TrueString) +{ + ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, false, "true"); +} + +TEST_F(LLVMNotTest, TrueString_Const) +{ + ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, true, "true"); +} + +TEST_F(LLVMNotTest, FalseString) +{ + ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, false, "false"); +} + +TEST_F(LLVMNotTest, FalseString_Const) +{ + ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, true, "false"); +} + +TEST_F(LLVMNotTest, UppercaseTrueString) +{ + ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, false, "TRUE"); +} + +TEST_F(LLVMNotTest, UppercaseTrueString_Const) +{ + ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, true, "TRUE"); +} + +TEST_F(LLVMNotTest, UppercaseFalseString) +{ + ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, false, "FALSE"); +} + +TEST_F(LLVMNotTest, UppercaseFalseString_Const) +{ + ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, true, "FALSE"); +} + +TEST_F(LLVMNotTest, ZeroPaddedOne) +{ + ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, false, "00001"); +} + +TEST_F(LLVMNotTest, ZeroPaddedOne_Const) +{ + ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, true, "00001"); +} + +TEST_F(LLVMNotTest, ZeroPaddedZero) +{ + ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, false, "00000"); +} + +TEST_F(LLVMNotTest, ZeroPaddedZero_Const) +{ + ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, true, "00000"); +} + +TEST_F(LLVMNotTest, InfinityString) +{ + ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, false, "Infinity"); +} + +TEST_F(LLVMNotTest, InfinityString_Const) +{ + ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, true, "Infinity"); +} + +TEST_F(LLVMNotTest, LowercaseInfinityString) +{ + ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, false, "infinity"); +} + +TEST_F(LLVMNotTest, LowercaseInfinityString_Const) +{ + ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, true, "infinity"); +} + +TEST_F(LLVMNotTest, NegativeInfinityString) +{ + ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, false, "-Infinity"); +} + +TEST_F(LLVMNotTest, NegativeInfinityString_Const) +{ + ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, true, "-Infinity"); +} + +TEST_F(LLVMNotTest, LowercaseNegativeInfinityString) +{ + ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, false, "-infinity"); +} + +TEST_F(LLVMNotTest, LowercaseNegativeInfinityString_Const) +{ + ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, true, "-infinity"); +} + +TEST_F(LLVMNotTest, NaNString) +{ + ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, false, "NaN"); +} + +TEST_F(LLVMNotTest, NaNString_Const) +{ + ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, true, "NaN"); +} + +TEST_F(LLVMNotTest, LowercaseNaNString) +{ + ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, false, "nan"); +} + +TEST_F(LLVMNotTest, LowercaseNaNString_Const) +{ + ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, true, "nan"); +} diff --git a/test/llvm/operators/logic/or_test.cpp b/test/llvm/operators/logic/or_test.cpp new file mode 100644 index 000000000..f16510c54 --- /dev/null +++ b/test/llvm/operators/logic/or_test.cpp @@ -0,0 +1,890 @@ +#include +#include + +#include "llvmtestutils.h" + +class LLVMOrTest : public testing::Test +{ + public: + LLVMTestUtils m_utils; +}; + +TEST_F(LLVMOrTest, NumberWithNumber) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, 10, 8); +} + +TEST_F(LLVMOrTest, NumberWithNumber_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, 10, 8); +} + +TEST_F(LLVMOrTest, SameNegativeDecimals) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, -4.25, -4.25); +} + +TEST_F(LLVMOrTest, SameNegativeDecimals_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, -4.25, -4.25); +} + +TEST_F(LLVMOrTest, DifferentDecimals) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, -4.25, 5.312); +} + +TEST_F(LLVMOrTest, DifferentDecimals_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, -4.25, 5.312); +} + +TEST_F(LLVMOrTest, TrueAndTrue) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, true, true); +} + +TEST_F(LLVMOrTest, TrueAndTrue_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, true, true); +} + +TEST_F(LLVMOrTest, TrueAndFalse) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, true, false); +} + +TEST_F(LLVMOrTest, TrueAndFalse_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, true, false); +} + +TEST_F(LLVMOrTest, FalseAndTrue) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, false, true); +} + +TEST_F(LLVMOrTest, FalseAndTrue_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, false, true); +} + +TEST_F(LLVMOrTest, NumberAndTrueBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, 1, true); +} + +TEST_F(LLVMOrTest, NumberAndTrueBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, 1, true); +} + +TEST_F(LLVMOrTest, NumberAndFalseBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, 1, false); +} + +TEST_F(LLVMOrTest, NumberAndFalseBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, 1, false); +} + +TEST_F(LLVMOrTest, StringAndString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "abc", "def"); +} + +TEST_F(LLVMOrTest, StringAndString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "abc", "def"); +} + +TEST_F(LLVMOrTest, TrueStringAndTrueString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "true", "true"); +} + +TEST_F(LLVMOrTest, TrueStringAndTrueString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "true", "true"); +} + +TEST_F(LLVMOrTest, TrueStringAndFalseString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "true", "false"); +} + +TEST_F(LLVMOrTest, TrueStringAndFalseString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "true", "false"); +} + +TEST_F(LLVMOrTest, FalseStringAndTrueString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "false", "true"); +} + +TEST_F(LLVMOrTest, FalseStringAndTrueString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "false", "true"); +} + +TEST_F(LLVMOrTest, FalseStringAndFalseString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "false", "false"); +} + +TEST_F(LLVMOrTest, FalseStringAndFalseString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "false", "false"); +} + +TEST_F(LLVMOrTest, NumberAndExactString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, 5.25, "5.25"); +} + +TEST_F(LLVMOrTest, NumberAndExactString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, 5.25, "5.25"); +} + +TEST_F(LLVMOrTest, ExactStringAndNumber) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "5.25", 5.25); +} + +TEST_F(LLVMOrTest, ExactStringAndNumber_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "5.25", 5.25); +} + +TEST_F(LLVMOrTest, ZeroAndOneString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, 0, "1"); +} + +TEST_F(LLVMOrTest, ZeroAndOneString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, 0, "1"); +} + +TEST_F(LLVMOrTest, OneStringAndZero) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "1", 0); +} + +TEST_F(LLVMOrTest, OneStringAndZero_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "1", 0); +} + +TEST_F(LLVMOrTest, ZeroAndTestString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, 0, "test"); +} + +TEST_F(LLVMOrTest, ZeroAndTestString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, 0, "test"); +} + +TEST_F(LLVMOrTest, TestStringAndZero) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "test", 0); +} + +TEST_F(LLVMOrTest, TestStringAndZero_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "test", 0); +} + +TEST_F(LLVMOrTest, InfinityAndInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "Infinity", "Infinity"); +} + +TEST_F(LLVMOrTest, InfinityAndInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "Infinity", "Infinity"); +} + +TEST_F(LLVMOrTest, NegativeInfinityAndNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "-Infinity", "-Infinity"); +} + +TEST_F(LLVMOrTest, NegativeInfinityAndNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "-Infinity", "-Infinity"); +} + +TEST_F(LLVMOrTest, NaNAndNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "NaN", "NaN"); +} + +TEST_F(LLVMOrTest, NaNAndNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "NaN", "NaN"); +} + +TEST_F(LLVMOrTest, InfinityAndNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "Infinity", "-Infinity"); +} + +TEST_F(LLVMOrTest, InfinityAndNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "Infinity", "-Infinity"); +} + +TEST_F(LLVMOrTest, NegativeInfinityAndInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "-Infinity", "Infinity"); +} + +TEST_F(LLVMOrTest, NegativeInfinityAndInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "-Infinity", "Infinity"); +} + +TEST_F(LLVMOrTest, InfinityAndNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "Infinity", "NaN"); +} + +TEST_F(LLVMOrTest, InfinityAndNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "Infinity", "NaN"); +} + +TEST_F(LLVMOrTest, NaNAndInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "NaN", "Infinity"); +} + +TEST_F(LLVMOrTest, NaNAndInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "NaN", "Infinity"); +} + +TEST_F(LLVMOrTest, NegativeInfinityAndNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "-Infinity", "NaN"); +} + +TEST_F(LLVMOrTest, NegativeInfinityAndNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "-Infinity", "NaN"); +} + +TEST_F(LLVMOrTest, NaNAndNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "NaN", "-Infinity"); +} + +TEST_F(LLVMOrTest, NaNAndNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "NaN", "-Infinity"); +} + +TEST_F(LLVMOrTest, TrueBooleanWithTrueString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, true, "true"); +} + +TEST_F(LLVMOrTest, TrueBooleanWithTrueString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, true, "true"); +} + +TEST_F(LLVMOrTest, TrueStringWithTrueBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "true", true); +} + +TEST_F(LLVMOrTest, TrueStringWithTrueBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "true", true); +} + +TEST_F(LLVMOrTest, FalseBooleanWithFalseString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, false, "false"); +} + +TEST_F(LLVMOrTest, FalseBooleanWithFalseString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, false, "false"); +} + +TEST_F(LLVMOrTest, FalseStringWithFalseBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "false", false); +} + +TEST_F(LLVMOrTest, FalseStringWithFalseBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "false", false); +} + +TEST_F(LLVMOrTest, FalseBooleanWithTrueString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, false, "true"); +} + +TEST_F(LLVMOrTest, FalseBooleanWithTrueString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, false, "true"); +} + +TEST_F(LLVMOrTest, TrueStringWithFalseBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "true", false); +} + +TEST_F(LLVMOrTest, TrueStringWithFalseBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "true", false); +} + +TEST_F(LLVMOrTest, TrueBooleanWithFalseString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, true, "false"); +} + +TEST_F(LLVMOrTest, TrueBooleanWithFalseString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, true, "false"); +} + +TEST_F(LLVMOrTest, FalseStringWithTrueBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "false", true); +} + +TEST_F(LLVMOrTest, FalseStringWithTrueBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "false", true); +} + +TEST_F(LLVMOrTest, TrueBooleanWithUppercaseTrueString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, true, "TRUE"); +} + +TEST_F(LLVMOrTest, TrueBooleanWithUppercaseTrueString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, true, "TRUE"); +} + +TEST_F(LLVMOrTest, UppercaseTrueStringWithTrueBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "TRUE", true); +} + +TEST_F(LLVMOrTest, UppercaseTrueStringWithTrueBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "TRUE", true); +} + +TEST_F(LLVMOrTest, FalseBooleanWithUppercaseFalseString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, false, "FALSE"); +} + +TEST_F(LLVMOrTest, FalseBooleanWithUppercaseFalseString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, false, "FALSE"); +} + +TEST_F(LLVMOrTest, UppercaseFalseStringWithFalseBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "FALSE", false); +} + +TEST_F(LLVMOrTest, UppercaseFalseStringWithFalseBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "FALSE", false); +} + +TEST_F(LLVMOrTest, TrueBooleanWithZeroPaddedOne) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, true, "00001"); +} + +TEST_F(LLVMOrTest, TrueBooleanWithZeroPaddedOne_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, true, "00001"); +} + +TEST_F(LLVMOrTest, ZeroPaddedOneWithTrueBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "00001", true); +} + +TEST_F(LLVMOrTest, ZeroPaddedOneWithTrueBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "00001", true); +} + +TEST_F(LLVMOrTest, TrueBooleanWithZeroPaddedZero) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, true, "00000"); +} + +TEST_F(LLVMOrTest, TrueBooleanWithZeroPaddedZero_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, true, "00000"); +} + +TEST_F(LLVMOrTest, ZeroPaddedZeroWithTrueBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "00000", true); +} + +TEST_F(LLVMOrTest, ZeroPaddedZeroWithTrueBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "00000", true); +} + +TEST_F(LLVMOrTest, FalseBooleanWithZeroPaddedZero) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, false, "00000"); +} + +TEST_F(LLVMOrTest, FalseBooleanWithZeroPaddedZero_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, false, "00000"); +} + +TEST_F(LLVMOrTest, ZeroPaddedZeroWithFalseBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "00000", false); +} + +TEST_F(LLVMOrTest, ZeroPaddedZeroWithFalseBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "00000", false); +} + +TEST_F(LLVMOrTest, TrueStringWithOne) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "true", 1); +} + +TEST_F(LLVMOrTest, TrueStringWithOne_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "true", 1); +} + +TEST_F(LLVMOrTest, OneWithTrueString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, 1, "true"); +} + +TEST_F(LLVMOrTest, OneWithTrueString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, 1, "true"); +} + +TEST_F(LLVMOrTest, TrueStringWithZero) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "true", 0); +} + +TEST_F(LLVMOrTest, TrueStringWithZero_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "true", 0); +} + +TEST_F(LLVMOrTest, ZeroWithTrueString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, 0, "true"); +} + +TEST_F(LLVMOrTest, ZeroWithTrueString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, 0, "true"); +} + +TEST_F(LLVMOrTest, FalseStringWithZero) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "false", 0); +} + +TEST_F(LLVMOrTest, FalseStringWithZero_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "false", 0); +} + +TEST_F(LLVMOrTest, ZeroWithFalseString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, 0, "false"); +} + +TEST_F(LLVMOrTest, ZeroWithFalseString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, 0, "false"); +} + +TEST_F(LLVMOrTest, FalseStringWithOne) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "false", 1); +} + +TEST_F(LLVMOrTest, FalseStringWithOne_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "false", 1); +} + +TEST_F(LLVMOrTest, OneWithFalseString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, 1, "false"); +} + +TEST_F(LLVMOrTest, OneWithFalseString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, 1, "false"); +} + +TEST_F(LLVMOrTest, TrueStringWithUppercaseTrueString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "true", "TRUE"); +} + +TEST_F(LLVMOrTest, TrueStringWithUppercaseTrueString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "true", "TRUE"); +} + +TEST_F(LLVMOrTest, TrueStringWithUppercaseFalseString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "true", "FALSE"); +} + +TEST_F(LLVMOrTest, TrueStringWithUppercaseFalseString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "true", "FALSE"); +} + +TEST_F(LLVMOrTest, FalseStringWithUppercaseFalseString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "false", "FALSE"); +} + +TEST_F(LLVMOrTest, FalseStringWithUppercaseFalseString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "false", "FALSE"); +} + +TEST_F(LLVMOrTest, FalseStringWithUppercaseTrueString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "false", "TRUE"); +} + +TEST_F(LLVMOrTest, FalseStringWithUppercaseTrueString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "false", "TRUE"); +} + +TEST_F(LLVMOrTest, TrueBooleanWithInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, true, "Infinity"); +} + +TEST_F(LLVMOrTest, TrueBooleanWithInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, true, "Infinity"); +} + +TEST_F(LLVMOrTest, InfinityWithTrueBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "Infinity", true); +} + +TEST_F(LLVMOrTest, InfinityWithTrueBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "Infinity", true); +} + +TEST_F(LLVMOrTest, TrueBooleanWithNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, true, "-Infinity"); +} + +TEST_F(LLVMOrTest, TrueBooleanWithNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, true, "-Infinity"); +} + +TEST_F(LLVMOrTest, NegativeInfinityWithTrueBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "-Infinity", true); +} + +TEST_F(LLVMOrTest, NegativeInfinityWithTrueBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "-Infinity", true); +} + +TEST_F(LLVMOrTest, TrueBooleanWithNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, true, "NaN"); +} + +TEST_F(LLVMOrTest, TrueBooleanWithNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, true, "NaN"); +} + +TEST_F(LLVMOrTest, NaNWithTrueBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "NaN", true); +} + +TEST_F(LLVMOrTest, NaNWithTrueBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "NaN", true); +} + +TEST_F(LLVMOrTest, FalseBooleanWithInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, false, "Infinity"); +} + +TEST_F(LLVMOrTest, FalseBooleanWithInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, false, "Infinity"); +} + +TEST_F(LLVMOrTest, InfinityWithFalseBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "Infinity", false); +} + +TEST_F(LLVMOrTest, InfinityWithFalseBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "Infinity", false); +} + +TEST_F(LLVMOrTest, FalseBooleanWithNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, false, "-Infinity"); +} + +TEST_F(LLVMOrTest, FalseBooleanWithNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, false, "-Infinity"); +} + +TEST_F(LLVMOrTest, NegativeInfinityWithFalseBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "-Infinity", false); +} + +TEST_F(LLVMOrTest, NegativeInfinityWithFalseBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "-Infinity", false); +} + +TEST_F(LLVMOrTest, FalseBooleanWithNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, false, "NaN"); +} + +TEST_F(LLVMOrTest, FalseBooleanWithNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, false, "NaN"); +} + +TEST_F(LLVMOrTest, NaNWithFalseBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "NaN", false); +} + +TEST_F(LLVMOrTest, NaNWithFalseBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "NaN", false); +} + +TEST_F(LLVMOrTest, InfinityStringWithInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "Infinity", "Infinity"); +} + +TEST_F(LLVMOrTest, InfinityStringWithInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "Infinity", "Infinity"); +} + +TEST_F(LLVMOrTest, InfinityStringWithNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "Infinity", "-Infinity"); +} + +TEST_F(LLVMOrTest, InfinityStringWithNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "Infinity", "-Infinity"); +} + +TEST_F(LLVMOrTest, InfinityStringWithNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "Infinity", "NaN"); +} + +TEST_F(LLVMOrTest, InfinityStringWithNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "Infinity", "NaN"); +} + +TEST_F(LLVMOrTest, LowercaseInfinityStringWithInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "infinity", "Infinity"); +} + +TEST_F(LLVMOrTest, LowercaseInfinityStringWithInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "infinity", "Infinity"); +} + +TEST_F(LLVMOrTest, LowercaseInfinityStringWithNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "infinity", "-Infinity"); +} + +TEST_F(LLVMOrTest, LowercaseInfinityStringWithNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "infinity", "-Infinity"); +} + +TEST_F(LLVMOrTest, LowercaseInfinityStringWithNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "infinity", "NaN"); +} + +TEST_F(LLVMOrTest, LowercaseInfinityStringWithNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "infinity", "NaN"); +} + +TEST_F(LLVMOrTest, NegativeInfinityStringWithInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "-Infinity", "Infinity"); +} + +TEST_F(LLVMOrTest, NegativeInfinityStringWithInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "-Infinity", "Infinity"); +} + +TEST_F(LLVMOrTest, NegativeInfinityStringWithNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "-Infinity", "-Infinity"); +} + +TEST_F(LLVMOrTest, NegativeInfinityStringWithNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "-Infinity", "-Infinity"); +} + +TEST_F(LLVMOrTest, NegativeInfinityStringWithNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "-Infinity", "NaN"); +} + +TEST_F(LLVMOrTest, NegativeInfinityStringWithNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "-Infinity", "NaN"); +} + +TEST_F(LLVMOrTest, LowercaseNegativeInfinityStringWithInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "-infinity", "Infinity"); +} + +TEST_F(LLVMOrTest, LowercaseNegativeInfinityStringWithInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "-infinity", "Infinity"); +} + +TEST_F(LLVMOrTest, LowercaseNegativeInfinityStringWithNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "-infinity", "-Infinity"); +} + +TEST_F(LLVMOrTest, LowercaseNegativeInfinityStringWithNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "-infinity", "-Infinity"); +} + +TEST_F(LLVMOrTest, LowercaseNegativeInfinityStringWithNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "-infinity", "NaN"); +} + +TEST_F(LLVMOrTest, LowercaseNegativeInfinityStringWithNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "-infinity", "NaN"); +} + +TEST_F(LLVMOrTest, NaNStringWithInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "NaN", "Infinity"); +} + +TEST_F(LLVMOrTest, NaNStringWithInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "NaN", "Infinity"); +} + +TEST_F(LLVMOrTest, NaNStringWithNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "NaN", "-Infinity"); +} + +TEST_F(LLVMOrTest, NaNStringWithNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "NaN", "-Infinity"); +} + +TEST_F(LLVMOrTest, NaNStringWithNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "NaN", "NaN"); +} + +TEST_F(LLVMOrTest, NaNStringWithNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "NaN", "NaN"); +} + +TEST_F(LLVMOrTest, LowercaseNaNStringWithInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "nan", "Infinity"); +} + +TEST_F(LLVMOrTest, LowercaseNaNStringWithInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "nan", "Infinity"); +} + +TEST_F(LLVMOrTest, LowercaseNaNStringWithNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "nan", "-Infinity"); +} + +TEST_F(LLVMOrTest, LowercaseNaNStringWithNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "nan", "-Infinity"); +} + +TEST_F(LLVMOrTest, LowercaseNaNStringWithNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "nan", "NaN"); +} + +TEST_F(LLVMOrTest, LowercaseNaNStringWithNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "nan", "NaN"); +} diff --git a/test/llvm/operators/math/abs_test.cpp b/test/llvm/operators/math/abs_test.cpp new file mode 100644 index 000000000..1c49ace13 --- /dev/null +++ b/test/llvm/operators/math/abs_test.cpp @@ -0,0 +1,116 @@ +#include +#include + +#include "llvmtestutils.h" + +class LLVMAbsTest : public testing::Test +{ + public: + LLVMTestUtils m_utils; +}; + +TEST_F(LLVMAbsTest, PositiveFour) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Abs, false, 4.0).toDouble(), 4.0); +} + +TEST_F(LLVMAbsTest, PositiveFour_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Abs, true, 4.0).toDouble(), 4.0); +} + +TEST_F(LLVMAbsTest, PositiveDecimal) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Abs, false, 3.2).toDouble(), 3.2); +} + +TEST_F(LLVMAbsTest, PositiveDecimal_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Abs, true, 3.2).toDouble(), 3.2); +} + +TEST_F(LLVMAbsTest, NegativeTwo) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Abs, false, -2.0).toDouble(), 2.0); +} + +TEST_F(LLVMAbsTest, NegativeTwo_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Abs, true, -2.0).toDouble(), 2.0); +} + +TEST_F(LLVMAbsTest, NegativeDecimalTwoPointFive) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Abs, false, -2.5).toDouble(), 2.5); +} + +TEST_F(LLVMAbsTest, NegativeDecimalTwoPointFive_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Abs, true, -2.5).toDouble(), 2.5); +} + +TEST_F(LLVMAbsTest, NegativeDecimalTwoPointSix) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Abs, false, -2.6).toDouble(), 2.6); +} + +TEST_F(LLVMAbsTest, NegativeDecimalTwoPointSix_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Abs, true, -2.6).toDouble(), 2.6); +} + +TEST_F(LLVMAbsTest, PositiveZero) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Abs, false, 0.0).toDouble(), 0.0); +} + +TEST_F(LLVMAbsTest, PositiveZero_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Abs, true, 0.0).toDouble(), 0.0); +} + +TEST_F(LLVMAbsTest, NegativeZero) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Abs, false, -0.0).toDouble(), 0.0); +} + +TEST_F(LLVMAbsTest, NegativeZero_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Abs, true, -0.0).toDouble(), 0.0); +} + +TEST_F(LLVMAbsTest, PositiveInfinity) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Abs, false, inf).toDouble(), inf); +} + +TEST_F(LLVMAbsTest, PositiveInfinity_Const) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Abs, true, inf).toDouble(), inf); +} + +TEST_F(LLVMAbsTest, NegativeInfinity) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Abs, false, -inf).toDouble(), inf); +} + +TEST_F(LLVMAbsTest, NegativeInfinity_Const) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Abs, true, -inf).toDouble(), inf); +} + +TEST_F(LLVMAbsTest, NaN) +{ + static const double nan = std::numeric_limits::quiet_NaN(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Abs, false, nan).toDouble(), 0); +} + +TEST_F(LLVMAbsTest, NaN_Const) +{ + static const double nan = std::numeric_limits::quiet_NaN(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Abs, true, nan).toDouble(), 0); +} diff --git a/test/llvm/operators/math/acos_test.cpp b/test/llvm/operators/math/acos_test.cpp new file mode 100644 index 000000000..dec02caf6 --- /dev/null +++ b/test/llvm/operators/math/acos_test.cpp @@ -0,0 +1,126 @@ +#include +#include + +#include "llvmtestutils.h" + +class LLVMAcosTest : public testing::Test +{ + public: + LLVMTestUtils m_utils; +}; + +TEST_F(LLVMAcosTest, One) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Acos, false, 1.0).toDouble(), 0.0); +} + +TEST_F(LLVMAcosTest, One_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Acos, true, 1.0).toDouble(), 0.0); +} + +TEST_F(LLVMAcosTest, OneHalf) +{ + ASSERT_EQ(std::round(m_utils.getOpResult(LLVMTestUtils::OpType::Acos, false, 0.5).toDouble() * 100) / 100, 60.0); +} + +TEST_F(LLVMAcosTest, OneHalf_Const) +{ + ASSERT_EQ(std::round(m_utils.getOpResult(LLVMTestUtils::OpType::Acos, true, 0.5).toDouble() * 100) / 100, 60.0); +} + +TEST_F(LLVMAcosTest, PositiveZero) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Acos, false, 0.0).toDouble(), 90.0); +} + +TEST_F(LLVMAcosTest, PositiveZero_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Acos, true, 0.0).toDouble(), 90.0); +} + +TEST_F(LLVMAcosTest, NegativeZero) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Acos, false, -0.0).toDouble(), 90.0); +} + +TEST_F(LLVMAcosTest, NegativeZero_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Acos, true, -0.0).toDouble(), 90.0); +} + +TEST_F(LLVMAcosTest, NegativeOneHalf) +{ + ASSERT_EQ(std::round(m_utils.getOpResult(LLVMTestUtils::OpType::Acos, false, -0.5).toDouble() * 100) / 100, 120.0); +} + +TEST_F(LLVMAcosTest, NegativeOneHalf_Const) +{ + ASSERT_EQ(std::round(m_utils.getOpResult(LLVMTestUtils::OpType::Acos, true, -0.5).toDouble() * 100) / 100, 120.0); +} + +TEST_F(LLVMAcosTest, NegativeOne) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Acos, false, -1.0).toDouble(), 180.0); +} + +TEST_F(LLVMAcosTest, NegativeOne_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Acos, true, -1.0).toDouble(), 180.0); +} + +TEST_F(LLVMAcosTest, OutOfRangePositive) +{ + ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Acos, false, 1.1).isNaN()); +} + +TEST_F(LLVMAcosTest, OutOfRangePositive_Const) +{ + ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Acos, true, 1.1).isNaN()); +} + +TEST_F(LLVMAcosTest, OutOfRangeNegative) +{ + ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Acos, false, -1.2).isNaN()); +} + +TEST_F(LLVMAcosTest, OutOfRangeNegative_Const) +{ + ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Acos, true, -1.2).isNaN()); +} + +TEST_F(LLVMAcosTest, PositiveInfinity) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Acos, false, inf).isNaN()); +} + +TEST_F(LLVMAcosTest, PositiveInfinity_Const) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Acos, true, inf).isNaN()); +} + +TEST_F(LLVMAcosTest, NegativeInfinity) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Acos, false, -inf).isNaN()); +} + +TEST_F(LLVMAcosTest, NegativeInfinity_Const) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Acos, true, -inf).isNaN()); +} + +TEST_F(LLVMAcosTest, NaN) +{ + static const double nan = std::numeric_limits::quiet_NaN(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Acos, false, nan).toDouble(), 90.0); +} + +TEST_F(LLVMAcosTest, NaN_Const) +{ + static const double nan = std::numeric_limits::quiet_NaN(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Acos, true, nan).toDouble(), 90.0); +} diff --git a/test/llvm/operators/math/add_test.cpp b/test/llvm/operators/math/add_test.cpp new file mode 100644 index 000000000..5fb706fe5 --- /dev/null +++ b/test/llvm/operators/math/add_test.cpp @@ -0,0 +1,130 @@ +#include +#include + +#include "llvmtestutils.h" + +class LLVMAddTest : public testing::Test +{ + public: + LLVMTestUtils m_utils; +}; + +TEST_F(LLVMAddTest, PositiveIntegers) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Add, false, 50, 25); +} + +TEST_F(LLVMAddTest, PositiveIntegers_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Add, true, 50, 25); +} + +TEST_F(LLVMAddTest, NegativeWithPositive) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Add, false, -500, 25); +} + +TEST_F(LLVMAddTest, NegativeWithPositive_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Add, true, -500, 25); +} + +TEST_F(LLVMAddTest, NegativeIntegers) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Add, false, -500, -25); +} + +TEST_F(LLVMAddTest, NegativeIntegers_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Add, true, -500, -25); +} + +TEST_F(LLVMAddTest, StringDecimals) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Add, false, "2.54", "6.28"); +} + +TEST_F(LLVMAddTest, StringDecimals_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Add, true, "2.54", "6.28"); +} + +TEST_F(LLVMAddTest, MixedDecimalAndString) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Add, false, 2.54, "-6.28"); +} + +TEST_F(LLVMAddTest, MixedDecimalAndString_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Add, true, 2.54, "-6.28"); +} + +TEST_F(LLVMAddTest, BooleanValues) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Add, false, true, true); +} + +TEST_F(LLVMAddTest, BooleanValues_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Add, true, true, true); +} + +TEST_F(LLVMAddTest, InfinityPlusInfinity) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Add, false, "Infinity", "Infinity"); +} + +TEST_F(LLVMAddTest, InfinityPlusInfinity_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Add, true, "Infinity", "Infinity"); +} + +TEST_F(LLVMAddTest, InfinityPlusNegativeInfinity) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Add, false, "Infinity", "-Infinity"); +} + +TEST_F(LLVMAddTest, InfinityPlusNegativeInfinity_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Add, true, "Infinity", "-Infinity"); +} + +TEST_F(LLVMAddTest, NegativeInfinityPlusInfinity) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Add, false, "-Infinity", "Infinity"); +} + +TEST_F(LLVMAddTest, NegativeInfinityPlusInfinity_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Add, true, "-Infinity", "Infinity"); +} + +TEST_F(LLVMAddTest, NegativeInfinityPlusNegativeInfinity) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Add, false, "-Infinity", "-Infinity"); +} + +TEST_F(LLVMAddTest, NegativeInfinityPlusNegativeInfinity_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Add, true, "-Infinity", "-Infinity"); +} + +TEST_F(LLVMAddTest, NumberPlusNaN) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Add, false, 1, "NaN"); +} + +TEST_F(LLVMAddTest, NumberPlusNaN_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Add, true, 1, "NaN"); +} + +TEST_F(LLVMAddTest, NaNPlusNumber) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Add, false, "NaN", 1); +} + +TEST_F(LLVMAddTest, NaNPlusNumber_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Add, true, "NaN", 1); +} diff --git a/test/llvm/operators/math/asin_test.cpp b/test/llvm/operators/math/asin_test.cpp new file mode 100644 index 000000000..7ecf9daf3 --- /dev/null +++ b/test/llvm/operators/math/asin_test.cpp @@ -0,0 +1,126 @@ +#include +#include + +#include "llvmtestutils.h" + +class LLVMAsinTest : public testing::Test +{ + public: + LLVMTestUtils m_utils; +}; + +TEST_F(LLVMAsinTest, One) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Asin, false, 1.0).toDouble(), 90.0); +} + +TEST_F(LLVMAsinTest, One_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Asin, true, 1.0).toDouble(), 90.0); +} + +TEST_F(LLVMAsinTest, OneHalf) +{ + ASSERT_EQ(std::round(m_utils.getOpResult(LLVMTestUtils::OpType::Asin, false, 0.5).toDouble() * 100) / 100, 30.0); +} + +TEST_F(LLVMAsinTest, OneHalf_Const) +{ + ASSERT_EQ(std::round(m_utils.getOpResult(LLVMTestUtils::OpType::Asin, true, 0.5).toDouble() * 100) / 100, 30.0); +} + +TEST_F(LLVMAsinTest, PositiveZero) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Asin, false, 0.0).toDouble(), 0.0); +} + +TEST_F(LLVMAsinTest, PositiveZero_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Asin, true, 0.0).toDouble(), 0.0); +} + +TEST_F(LLVMAsinTest, NegativeZero) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Asin, false, -0.0).toDouble(), 0.0); +} + +TEST_F(LLVMAsinTest, NegativeZero_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Asin, true, -0.0).toDouble(), 0.0); +} + +TEST_F(LLVMAsinTest, NegativeOneHalf) +{ + ASSERT_EQ(std::round(m_utils.getOpResult(LLVMTestUtils::OpType::Asin, false, -0.5).toDouble() * 100) / 100, -30.0); +} + +TEST_F(LLVMAsinTest, NegativeOneHalf_Const) +{ + ASSERT_EQ(std::round(m_utils.getOpResult(LLVMTestUtils::OpType::Asin, true, -0.5).toDouble() * 100) / 100, -30.0); +} + +TEST_F(LLVMAsinTest, NegativeOne) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Asin, false, -1.0).toDouble(), -90.0); +} + +TEST_F(LLVMAsinTest, NegativeOne_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Asin, true, -1.0).toDouble(), -90.0); +} + +TEST_F(LLVMAsinTest, OutOfRangePositive) +{ + ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Asin, false, 1.1).isNaN()); +} + +TEST_F(LLVMAsinTest, OutOfRangePositive_Const) +{ + ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Asin, true, 1.1).isNaN()); +} + +TEST_F(LLVMAsinTest, OutOfRangeNegative) +{ + ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Asin, false, -1.2).isNaN()); +} + +TEST_F(LLVMAsinTest, OutOfRangeNegative_Const) +{ + ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Asin, true, -1.2).isNaN()); +} + +TEST_F(LLVMAsinTest, PositiveInfinity) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Asin, false, inf).isNaN()); +} + +TEST_F(LLVMAsinTest, PositiveInfinity_Const) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Asin, true, inf).isNaN()); +} + +TEST_F(LLVMAsinTest, NegativeInfinity) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Asin, false, -inf).isNaN()); +} + +TEST_F(LLVMAsinTest, NegativeInfinity_Const) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Asin, true, -inf).isNaN()); +} + +TEST_F(LLVMAsinTest, NaN) +{ + static const double nan = std::numeric_limits::quiet_NaN(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Asin, false, nan).toDouble(), 0.0); +} + +TEST_F(LLVMAsinTest, NaN_Const) +{ + static const double nan = std::numeric_limits::quiet_NaN(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Asin, true, nan).toDouble(), 0.0); +} diff --git a/test/llvm/operators/math/atan_test.cpp b/test/llvm/operators/math/atan_test.cpp new file mode 100644 index 000000000..e6b983777 --- /dev/null +++ b/test/llvm/operators/math/atan_test.cpp @@ -0,0 +1,86 @@ +#include +#include + +#include "llvmtestutils.h" + +class LLVMAtanTest : public testing::Test +{ + public: + LLVMTestUtils m_utils; +}; + +TEST_F(LLVMAtanTest, One) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Atan, false, 1.0).toDouble(), 45.0); +} + +TEST_F(LLVMAtanTest, One_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Atan, true, 1.0).toDouble(), 45.0); +} + +TEST_F(LLVMAtanTest, PositiveZero) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Atan, false, 0.0).toDouble(), 0.0); +} + +TEST_F(LLVMAtanTest, PositiveZero_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Atan, true, 0.0).toDouble(), 0.0); +} + +TEST_F(LLVMAtanTest, NegativeZero) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Atan, false, -0.0).toDouble(), -0.0); +} + +TEST_F(LLVMAtanTest, NegativeZero_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Atan, true, -0.0).toDouble(), -0.0); +} + +TEST_F(LLVMAtanTest, NegativeOne) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Atan, false, -1.0).toDouble(), -45.0); +} + +TEST_F(LLVMAtanTest, NegativeOne_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Atan, true, -1.0).toDouble(), -45.0); +} + +TEST_F(LLVMAtanTest, PositiveInfinity) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Atan, false, inf).toDouble(), 90.0); +} + +TEST_F(LLVMAtanTest, PositiveInfinity_Const) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Atan, true, inf).toDouble(), 90.0); +} + +TEST_F(LLVMAtanTest, NegativeInfinity) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Atan, false, -inf).toDouble(), -90.0); +} + +TEST_F(LLVMAtanTest, NegativeInfinity_Const) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Atan, true, -inf).toDouble(), -90.0); +} + +TEST_F(LLVMAtanTest, NaN) +{ + static const double nan = std::numeric_limits::quiet_NaN(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Atan, false, nan).toDouble(), 0.0); +} + +TEST_F(LLVMAtanTest, NaN_Const) +{ + static const double nan = std::numeric_limits::quiet_NaN(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Atan, true, nan).toDouble(), 0.0); +} diff --git a/test/llvm/operators/math/ceil_test.cpp b/test/llvm/operators/math/ceil_test.cpp new file mode 100644 index 000000000..4537c76f1 --- /dev/null +++ b/test/llvm/operators/math/ceil_test.cpp @@ -0,0 +1,176 @@ +#include +#include + +#include "llvmtestutils.h" + +class LLVMCeilTest : public testing::Test +{ + public: + LLVMTestUtils m_utils; +}; + +TEST_F(LLVMCeilTest, EightPointZero) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ceil, false, 8.0).toDouble(), 8.0); +} + +TEST_F(LLVMCeilTest, EightPointZero_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ceil, true, 8.0).toDouble(), 8.0); +} + +TEST_F(LLVMCeilTest, ThreePointTwo) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ceil, false, 3.2).toDouble(), 4.0); +} + +TEST_F(LLVMCeilTest, ThreePointTwo_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ceil, true, 3.2).toDouble(), 4.0); +} + +TEST_F(LLVMCeilTest, ThreePointFive) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ceil, false, 3.5).toDouble(), 4.0); +} + +TEST_F(LLVMCeilTest, ThreePointFive_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ceil, true, 3.5).toDouble(), 4.0); +} + +TEST_F(LLVMCeilTest, ThreePointSix) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ceil, false, 3.6).toDouble(), 4.0); +} + +TEST_F(LLVMCeilTest, ThreePointSix_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ceil, true, 3.6).toDouble(), 4.0); +} + +TEST_F(LLVMCeilTest, ZeroPointFour) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ceil, false, 0.4).toDouble(), 1.0); +} + +TEST_F(LLVMCeilTest, ZeroPointFour_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ceil, true, 0.4).toDouble(), 1.0); +} + +TEST_F(LLVMCeilTest, PositiveZero) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ceil, false, 0.0).toDouble(), 0.0); +} + +TEST_F(LLVMCeilTest, PositiveZero_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ceil, true, 0.0).toDouble(), 0.0); +} + +TEST_F(LLVMCeilTest, NegativeZero) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ceil, false, -0.0).toDouble(), -0.0); +} + +TEST_F(LLVMCeilTest, NegativeZero_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ceil, true, -0.0).toDouble(), -0.0); +} + +TEST_F(LLVMCeilTest, NegativeTwoPointFour) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ceil, false, -2.4).toDouble(), -2.0); +} + +TEST_F(LLVMCeilTest, NegativeTwoPointFour_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ceil, true, -2.4).toDouble(), -2.0); +} + +TEST_F(LLVMCeilTest, NegativeTwoPointFive) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ceil, false, -2.5).toDouble(), -2.0); +} + +TEST_F(LLVMCeilTest, NegativeTwoPointFive_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ceil, true, -2.5).toDouble(), -2.0); +} + +TEST_F(LLVMCeilTest, NegativeTwoPointSix) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ceil, false, -2.6).toDouble(), -2.0); +} + +TEST_F(LLVMCeilTest, NegativeTwoPointSix_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ceil, true, -2.6).toDouble(), -2.0); +} + +TEST_F(LLVMCeilTest, NegativeZeroPointFour) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ceil, false, -0.4).toDouble(), -0.0); +} + +TEST_F(LLVMCeilTest, NegativeZeroPointFour_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ceil, true, -0.4).toDouble(), -0.0); +} + +TEST_F(LLVMCeilTest, NegativeZeroPointFive) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ceil, false, -0.5).toDouble(), -0.0); +} + +TEST_F(LLVMCeilTest, NegativeZeroPointFive_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ceil, true, -0.5).toDouble(), -0.0); +} + +TEST_F(LLVMCeilTest, NegativeZeroPointFiftyOne) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ceil, false, -0.51).toDouble(), -0.0); +} + +TEST_F(LLVMCeilTest, NegativeZeroPointFiftyOne_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ceil, true, -0.51).toDouble(), -0.0); +} + +TEST_F(LLVMCeilTest, PositiveInfinity) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ceil, false, inf).toDouble(), inf); +} + +TEST_F(LLVMCeilTest, PositiveInfinity_Const) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ceil, true, inf).toDouble(), inf); +} + +TEST_F(LLVMCeilTest, NegativeInfinity) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ceil, false, -inf).toDouble(), -inf); +} + +TEST_F(LLVMCeilTest, NegativeInfinity_Const) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ceil, true, -inf).toDouble(), -inf); +} + +TEST_F(LLVMCeilTest, NaN) +{ + static const double nan = std::numeric_limits::quiet_NaN(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ceil, false, nan).toDouble(), 0); +} + +TEST_F(LLVMCeilTest, NaN_Const) +{ + static const double nan = std::numeric_limits::quiet_NaN(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ceil, true, nan).toDouble(), 0); +} diff --git a/test/llvm/operators/math/cos_test.cpp b/test/llvm/operators/math/cos_test.cpp new file mode 100644 index 000000000..0b5daf305 --- /dev/null +++ b/test/llvm/operators/math/cos_test.cpp @@ -0,0 +1,136 @@ +#include +#include + +#include "llvmtestutils.h" + +class LLVMCosTest : public testing::Test +{ + public: + LLVMTestUtils m_utils; +}; + +TEST_F(LLVMCosTest, SixtyDegrees) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Cos, false, 60.0).toDouble(), 0.5); +} + +TEST_F(LLVMCosTest, SixtyDegrees_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Cos, true, 60.0).toDouble(), 0.5); +} + +TEST_F(LLVMCosTest, NinetyDegrees) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Cos, false, 90.0).toDouble(), 0.0); +} + +TEST_F(LLVMCosTest, NinetyDegrees_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Cos, true, 90.0).toDouble(), 0.0); +} + +TEST_F(LLVMCosTest, SixHundredDegrees) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Cos, false, 600.0).toDouble(), -0.5); +} + +TEST_F(LLVMCosTest, SixHundredDegrees_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Cos, true, 600.0).toDouble(), -0.5); +} + +TEST_F(LLVMCosTest, AlmostNinetyDegrees) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Cos, false, 89.9999999971352).toDouble(), 1e-10); +} + +TEST_F(LLVMCosTest, AlmostNinetyDegrees_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Cos, true, 89.9999999971352).toDouble(), 1e-10); +} + +TEST_F(LLVMCosTest, VeryCloseToNinetyDegrees) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Cos, false, 89.999999999).toDouble(), 0.0); +} + +TEST_F(LLVMCosTest, VeryCloseToNinetyDegrees_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Cos, true, 89.999999999).toDouble(), 0.0); +} + +TEST_F(LLVMCosTest, NegativeSixtyDegrees) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Cos, false, -60.0).toDouble(), 0.5); +} + +TEST_F(LLVMCosTest, NegativeSixtyDegrees_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Cos, true, -60.0).toDouble(), 0.5); +} + +TEST_F(LLVMCosTest, NegativeNinetyDegrees) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Cos, false, -90.0).toDouble(), 0.0); +} + +TEST_F(LLVMCosTest, NegativeNinetyDegrees_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Cos, true, -90.0).toDouble(), 0.0); +} + +TEST_F(LLVMCosTest, PositiveZero) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Cos, false, 0.0).toDouble(), 1.0); +} + +TEST_F(LLVMCosTest, PositiveZero_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Cos, true, 0.0).toDouble(), 1.0); +} + +TEST_F(LLVMCosTest, NegativeZero) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Cos, false, -0.0).toDouble(), 1.0); +} + +TEST_F(LLVMCosTest, NegativeZero_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Cos, true, -0.0).toDouble(), 1.0); +} + +TEST_F(LLVMCosTest, PositiveInfinity) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Cos, false, inf).isNaN()); +} + +TEST_F(LLVMCosTest, PositiveInfinity_Const) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Cos, true, inf).isNaN()); +} + +TEST_F(LLVMCosTest, NegativeInfinity) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Cos, false, -inf).isNaN()); +} + +TEST_F(LLVMCosTest, NegativeInfinity_Const) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Cos, true, -inf).isNaN()); +} + +TEST_F(LLVMCosTest, NaN) +{ + static const double nan = std::numeric_limits::quiet_NaN(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Cos, false, nan).toDouble(), 1.0); +} + +TEST_F(LLVMCosTest, NaN_Const) +{ + static const double nan = std::numeric_limits::quiet_NaN(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Cos, true, nan).toDouble(), 1.0); +} diff --git a/test/llvm/operators/math/divide_test.cpp b/test/llvm/operators/math/divide_test.cpp new file mode 100644 index 000000000..91e327d45 --- /dev/null +++ b/test/llvm/operators/math/divide_test.cpp @@ -0,0 +1,270 @@ +#include +#include + +#include "llvmtestutils.h" + +class LLVMDivideTest : public testing::Test +{ + public: + LLVMTestUtils m_utils; +}; + +TEST_F(LLVMDivideTest, PositiveIntegers) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, false, 50, 2); +} + +TEST_F(LLVMDivideTest, PositiveIntegers_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, true, 50, 2); +} + +TEST_F(LLVMDivideTest, NegativeWithPositive) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, false, -500, 25); +} + +TEST_F(LLVMDivideTest, NegativeWithPositive_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, true, -500, 25); +} + +TEST_F(LLVMDivideTest, StringNegativeWithNegative) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, false, "-500", -25); +} + +TEST_F(LLVMDivideTest, StringNegativeWithNegative_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, true, "-500", -25); +} + +TEST_F(LLVMDivideTest, StringDecimals) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, false, "3.5", "2.5"); +} + +TEST_F(LLVMDivideTest, StringDecimals_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, true, "3.5", "2.5"); +} + +TEST_F(LLVMDivideTest, BooleanValues) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, false, true, true); +} + +TEST_F(LLVMDivideTest, BooleanValues_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, true, true, true); +} + +TEST_F(LLVMDivideTest, InfinityDividedByInfinity) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, false, "Infinity", "Infinity"); +} + +TEST_F(LLVMDivideTest, InfinityDividedByInfinity_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, true, "Infinity", "Infinity"); +} + +TEST_F(LLVMDivideTest, InfinityDividedByZero) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, false, "Infinity", 0); +} + +TEST_F(LLVMDivideTest, InfinityDividedByZero_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, true, "Infinity", 0); +} + +TEST_F(LLVMDivideTest, InfinityDividedByPositive) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, false, "Infinity", 2); +} + +TEST_F(LLVMDivideTest, InfinityDividedByPositive_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, true, "Infinity", 2); +} + +TEST_F(LLVMDivideTest, InfinityDividedByNegative) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, false, "Infinity", -2); +} + +TEST_F(LLVMDivideTest, InfinityDividedByNegative_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, true, "Infinity", -2); +} + +TEST_F(LLVMDivideTest, InfinityDividedByNegativeInfinity) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, false, "Infinity", "-Infinity"); +} + +TEST_F(LLVMDivideTest, InfinityDividedByNegativeInfinity_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, true, "Infinity", "-Infinity"); +} + +TEST_F(LLVMDivideTest, NegativeInfinityDividedByInfinity) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, false, "-Infinity", "Infinity"); +} + +TEST_F(LLVMDivideTest, NegativeInfinityDividedByInfinity_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, true, "-Infinity", "Infinity"); +} + +TEST_F(LLVMDivideTest, NegativeInfinityDividedByZero) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, false, "-Infinity", 0); +} + +TEST_F(LLVMDivideTest, NegativeInfinityDividedByZero_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, true, "-Infinity", 0); +} + +TEST_F(LLVMDivideTest, NegativeInfinityDividedByPositive) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, false, "-Infinity", 2); +} + +TEST_F(LLVMDivideTest, NegativeInfinityDividedByPositive_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, true, "-Infinity", 2); +} + +TEST_F(LLVMDivideTest, NegativeInfinityDividedByNegative) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, false, "-Infinity", -2); +} + +TEST_F(LLVMDivideTest, NegativeInfinityDividedByNegative_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, true, "-Infinity", -2); +} + +TEST_F(LLVMDivideTest, NegativeInfinityDividedByNegativeInfinity) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, false, "-Infinity", "-Infinity"); +} + +TEST_F(LLVMDivideTest, NegativeInfinityDividedByNegativeInfinity_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, true, "-Infinity", "-Infinity"); +} + +TEST_F(LLVMDivideTest, ZeroDividedByInfinity) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, false, 0, "Infinity"); +} + +TEST_F(LLVMDivideTest, ZeroDividedByInfinity_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, true, 0, "Infinity"); +} + +TEST_F(LLVMDivideTest, PositiveDividedByInfinity) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, false, 2, "Infinity"); +} + +TEST_F(LLVMDivideTest, PositiveDividedByInfinity_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, true, 2, "Infinity"); +} + +TEST_F(LLVMDivideTest, NegativeDividedByInfinity) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, false, -2, "Infinity"); +} + +TEST_F(LLVMDivideTest, NegativeDividedByInfinity_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, true, -2, "Infinity"); +} + +TEST_F(LLVMDivideTest, ZeroDividedByNegativeInfinity) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, false, 0, "-Infinity"); +} + +TEST_F(LLVMDivideTest, ZeroDividedByNegativeInfinity_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, true, 0, "-Infinity"); +} + +TEST_F(LLVMDivideTest, PositiveDividedByNegativeInfinity) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, false, 2, "-Infinity"); +} + +TEST_F(LLVMDivideTest, PositiveDividedByNegativeInfinity_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, true, 2, "-Infinity"); +} + +TEST_F(LLVMDivideTest, NegativeDividedByNegativeInfinity) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, false, -2, "-Infinity"); +} + +TEST_F(LLVMDivideTest, NegativeDividedByNegativeInfinity_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, true, -2, "-Infinity"); +} + +TEST_F(LLVMDivideTest, NumberDividedByNaN) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, false, 1, "NaN"); +} + +TEST_F(LLVMDivideTest, NumberDividedByNaN_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, true, 1, "NaN"); +} + +TEST_F(LLVMDivideTest, NaNDividedByNumber) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, false, "NaN", 1); +} + +TEST_F(LLVMDivideTest, NaNDividedByNumber_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, true, "NaN", 1); +} + +TEST_F(LLVMDivideTest, PositiveDividedByZero) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, false, 5, 0); +} + +TEST_F(LLVMDivideTest, PositiveDividedByZero_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, true, 5, 0); +} + +TEST_F(LLVMDivideTest, NegativeDividedByZero) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, false, -5, 0); +} + +TEST_F(LLVMDivideTest, NegativeDividedByZero_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, true, -5, 0); +} + +TEST_F(LLVMDivideTest, ZeroDividedByZero) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, false, 0, 0); +} + +TEST_F(LLVMDivideTest, ZeroDividedByZero_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, true, 0, 0); +} diff --git a/test/llvm/operators/math/exp10_test.cpp b/test/llvm/operators/math/exp10_test.cpp new file mode 100644 index 000000000..b7ff6a255 --- /dev/null +++ b/test/llvm/operators/math/exp10_test.cpp @@ -0,0 +1,106 @@ +#include +#include + +#include "llvmtestutils.h" + +class LLVMExp10Test : public testing::Test +{ + public: + LLVMTestUtils m_utils; +}; + +TEST_F(LLVMExp10Test, One) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Exp10, false, 1.0).toDouble(), 10.0); +} + +TEST_F(LLVMExp10Test, One_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Exp10, true, 1.0).toDouble(), 10.0); +} + +TEST_F(LLVMExp10Test, Three) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Exp10, false, 3.0).toDouble(), 1000.0); +} + +TEST_F(LLVMExp10Test, Three_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Exp10, true, 3.0).toDouble(), 1000.0); +} + +TEST_F(LLVMExp10Test, PositiveZero) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Exp10, false, 0.0).toDouble(), 1.0); +} + +TEST_F(LLVMExp10Test, PositiveZero_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Exp10, true, 0.0).toDouble(), 1.0); +} + +TEST_F(LLVMExp10Test, NegativeZero) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Exp10, false, -0.0).toDouble(), 1.0); +} + +TEST_F(LLVMExp10Test, NegativeZero_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Exp10, true, -0.0).toDouble(), 1.0); +} + +TEST_F(LLVMExp10Test, NegativeOne) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Exp10, false, -1.0).toDouble(), 0.1); +} + +TEST_F(LLVMExp10Test, NegativeOne_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Exp10, true, -1.0).toDouble(), 0.1); +} + +TEST_F(LLVMExp10Test, NegativeFive) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Exp10, false, -5.0).toDouble(), 0.00001); +} + +TEST_F(LLVMExp10Test, NegativeFive_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Exp10, true, -5.0).toDouble(), 0.00001); +} + +TEST_F(LLVMExp10Test, PositiveInfinity) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Exp10, false, inf).toDouble(), inf); +} + +TEST_F(LLVMExp10Test, PositiveInfinity_Const) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Exp10, true, inf).toDouble(), inf); +} + +TEST_F(LLVMExp10Test, NegativeInfinity) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Exp10, false, -inf).toDouble(), 0.0); +} + +TEST_F(LLVMExp10Test, NegativeInfinity_Const) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Exp10, true, -inf).toDouble(), 0.0); +} + +TEST_F(LLVMExp10Test, NaN) +{ + static const double nan = std::numeric_limits::quiet_NaN(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Exp10, false, nan).toDouble(), 1.0); +} + +TEST_F(LLVMExp10Test, NaN_Const) +{ + static const double nan = std::numeric_limits::quiet_NaN(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Exp10, true, nan).toDouble(), 1.0); +} diff --git a/test/llvm/operators/math/exp_test.cpp b/test/llvm/operators/math/exp_test.cpp new file mode 100644 index 000000000..52fc6ecff --- /dev/null +++ b/test/llvm/operators/math/exp_test.cpp @@ -0,0 +1,96 @@ +#include +#include + +#include "llvmtestutils.h" + +class LLVMExpTest : public testing::Test +{ + public: + LLVMTestUtils m_utils; +}; + +TEST_F(LLVMExpTest, One) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Exp, false, 1.0).toDouble(), std::exp(1.0)); +} + +TEST_F(LLVMExpTest, One_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Exp, true, 1.0).toDouble(), std::exp(1.0)); +} + +TEST_F(LLVMExpTest, ZeroPointFive) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Exp, false, 0.5).toDouble(), std::exp(0.5)); +} + +TEST_F(LLVMExpTest, ZeroPointFive_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Exp, true, 0.5).toDouble(), std::exp(0.5)); +} + +TEST_F(LLVMExpTest, PositiveZero) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Exp, false, 0.0).toDouble(), 1.0); +} + +TEST_F(LLVMExpTest, PositiveZero_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Exp, true, 0.0).toDouble(), 1.0); +} + +TEST_F(LLVMExpTest, NegativeZero) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Exp, false, -0.0).toDouble(), 1.0); +} + +TEST_F(LLVMExpTest, NegativeZero_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Exp, true, -0.0).toDouble(), 1.0); +} + +TEST_F(LLVMExpTest, NegativeZeroPointSeven) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Exp, false, -0.7).toDouble(), std::exp(-0.7)); +} + +TEST_F(LLVMExpTest, NegativeZeroPointSeven_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Exp, true, -0.7).toDouble(), std::exp(-0.7)); +} + +TEST_F(LLVMExpTest, PositiveInfinity) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Exp, false, inf).toDouble(), inf); +} + +TEST_F(LLVMExpTest, PositiveInfinity_Const) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Exp, true, inf).toDouble(), inf); +} + +TEST_F(LLVMExpTest, NegativeInfinity) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Exp, false, -inf).toDouble(), 0.0); +} + +TEST_F(LLVMExpTest, NegativeInfinity_Const) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Exp, true, -inf).toDouble(), 0.0); +} + +TEST_F(LLVMExpTest, NaN) +{ + static const double nan = std::numeric_limits::quiet_NaN(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Exp, false, nan).toDouble(), 1.0); +} + +TEST_F(LLVMExpTest, NaN_Const) +{ + static const double nan = std::numeric_limits::quiet_NaN(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Exp, true, nan).toDouble(), 1.0); +} diff --git a/test/llvm/operators/math/floor_test.cpp b/test/llvm/operators/math/floor_test.cpp new file mode 100644 index 000000000..8329bd02b --- /dev/null +++ b/test/llvm/operators/math/floor_test.cpp @@ -0,0 +1,166 @@ +#include +#include + +#include "llvmtestutils.h" + +class LLVMFloorTest : public testing::Test +{ + public: + LLVMTestUtils m_utils; +}; + +TEST_F(LLVMFloorTest, FourPointZero) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Floor, false, 4.0).toDouble(), 4.0); +} + +TEST_F(LLVMFloorTest, FourPointZero_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Floor, true, 4.0).toDouble(), 4.0); +} + +TEST_F(LLVMFloorTest, ThreePointTwo) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Floor, false, 3.2).toDouble(), 3.0); +} + +TEST_F(LLVMFloorTest, ThreePointTwo_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Floor, true, 3.2).toDouble(), 3.0); +} + +TEST_F(LLVMFloorTest, ThreePointFive) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Floor, false, 3.5).toDouble(), 3.0); +} + +TEST_F(LLVMFloorTest, ThreePointFive_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Floor, true, 3.5).toDouble(), 3.0); +} + +TEST_F(LLVMFloorTest, ThreePointSix) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Floor, false, 3.6).toDouble(), 3.0); +} + +TEST_F(LLVMFloorTest, ThreePointSix_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Floor, true, 3.6).toDouble(), 3.0); +} + +TEST_F(LLVMFloorTest, PositiveZero) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Floor, false, 0.0).toDouble(), 0.0); +} + +TEST_F(LLVMFloorTest, PositiveZero_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Floor, true, 0.0).toDouble(), 0.0); +} + +TEST_F(LLVMFloorTest, NegativeZero) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Floor, false, -0.0).toDouble(), -0.0); +} + +TEST_F(LLVMFloorTest, NegativeZero_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Floor, true, -0.0).toDouble(), -0.0); +} + +TEST_F(LLVMFloorTest, NegativeTwoPointFour) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Floor, false, -2.4).toDouble(), -3.0); +} + +TEST_F(LLVMFloorTest, NegativeTwoPointFour_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Floor, true, -2.4).toDouble(), -3.0); +} + +TEST_F(LLVMFloorTest, NegativeTwoPointFive) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Floor, false, -2.5).toDouble(), -3.0); +} + +TEST_F(LLVMFloorTest, NegativeTwoPointFive_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Floor, true, -2.5).toDouble(), -3.0); +} + +TEST_F(LLVMFloorTest, NegativeTwoPointSix) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Floor, false, -2.6).toDouble(), -3.0); +} + +TEST_F(LLVMFloorTest, NegativeTwoPointSix_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Floor, true, -2.6).toDouble(), -3.0); +} + +TEST_F(LLVMFloorTest, NegativeZeroPointFour) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Floor, false, -0.4).toDouble(), -1.0); +} + +TEST_F(LLVMFloorTest, NegativeZeroPointFour_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Floor, true, -0.4).toDouble(), -1.0); +} + +TEST_F(LLVMFloorTest, NegativeZeroPointFive) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Floor, false, -0.5).toDouble(), -1.0); +} + +TEST_F(LLVMFloorTest, NegativeZeroPointFive_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Floor, true, -0.5).toDouble(), -1.0); +} + +TEST_F(LLVMFloorTest, NegativeZeroPointFiftyOne) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Floor, false, -0.51).toDouble(), -1.0); +} + +TEST_F(LLVMFloorTest, NegativeZeroPointFiftyOne_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Floor, true, -0.51).toDouble(), -1.0); +} + +TEST_F(LLVMFloorTest, PositiveInfinity) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Floor, false, inf).toDouble(), inf); +} + +TEST_F(LLVMFloorTest, PositiveInfinity_Const) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Floor, true, inf).toDouble(), inf); +} + +TEST_F(LLVMFloorTest, NegativeInfinity) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Floor, false, -inf).toDouble(), -inf); +} + +TEST_F(LLVMFloorTest, NegativeInfinity_Const) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Floor, true, -inf).toDouble(), -inf); +} + +TEST_F(LLVMFloorTest, NaN) +{ + static const double nan = std::numeric_limits::quiet_NaN(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Floor, false, nan).toDouble(), 0); +} + +TEST_F(LLVMFloorTest, NaN_Const) +{ + static const double nan = std::numeric_limits::quiet_NaN(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Floor, true, nan).toDouble(), 0); +} diff --git a/test/llvm/operators/math/ln_test.cpp b/test/llvm/operators/math/ln_test.cpp new file mode 100644 index 000000000..1a6763fa0 --- /dev/null +++ b/test/llvm/operators/math/ln_test.cpp @@ -0,0 +1,122 @@ +#include +#include + +#include "llvmtestutils.h" + +class LLVMLnTest : public testing::Test +{ + public: + LLVMTestUtils m_utils; +}; + +TEST_F(LLVMLnTest, ExpOfOne) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ln, false, std::exp(1.0)).toDouble(), 1.0); +} + +TEST_F(LLVMLnTest, ExpOfOne_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ln, true, std::exp(1.0)).toDouble(), 1.0); +} + +TEST_F(LLVMLnTest, ExpOfTwo) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ln, false, std::exp(2.0)).toDouble(), 2.0); +} + +TEST_F(LLVMLnTest, ExpOfTwo_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ln, true, std::exp(2.0)).toDouble(), 2.0); +} + +TEST_F(LLVMLnTest, ExpOfZeroPointThree) +{ + ASSERT_EQ(std::round(m_utils.getOpResult(LLVMTestUtils::OpType::Ln, false, std::exp(0.3)).toDouble() * 100) / 100, 0.3); +} + +TEST_F(LLVMLnTest, ExpOfZeroPointThree_Const) +{ + ASSERT_EQ(std::round(m_utils.getOpResult(LLVMTestUtils::OpType::Ln, true, std::exp(0.3)).toDouble() * 100) / 100, 0.3); +} + +TEST_F(LLVMLnTest, One) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ln, false, 1.0).toDouble(), 0.0); +} + +TEST_F(LLVMLnTest, One_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ln, true, 1.0).toDouble(), 0.0); +} + +TEST_F(LLVMLnTest, PositiveZero) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ln, false, 0.0).toDouble(), -inf); +} + +TEST_F(LLVMLnTest, PositiveZero_Const) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ln, true, 0.0).toDouble(), -inf); +} + +TEST_F(LLVMLnTest, NegativeZero) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ln, false, -0.0).toDouble(), -inf); +} + +TEST_F(LLVMLnTest, NegativeZero_Const) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ln, true, -0.0).toDouble(), -inf); +} + +TEST_F(LLVMLnTest, NegativeNumber) +{ + ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Ln, false, -0.7).isNaN()); +} + +TEST_F(LLVMLnTest, NegativeNumber_Const) +{ + ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Ln, true, -0.7).isNaN()); +} + +TEST_F(LLVMLnTest, PositiveInfinity) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ln, false, inf).toDouble(), inf); +} + +TEST_F(LLVMLnTest, PositiveInfinity_Const) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ln, true, inf).toDouble(), inf); +} + +TEST_F(LLVMLnTest, NegativeInfinity) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Ln, false, -inf).isNaN()); +} + +TEST_F(LLVMLnTest, NegativeInfinity_Const) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Ln, true, -inf).isNaN()); +} + +TEST_F(LLVMLnTest, NaN) +{ + static const double inf = std::numeric_limits::infinity(); + static const double nan = std::numeric_limits::quiet_NaN(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ln, false, nan).toDouble(), -inf); +} + +TEST_F(LLVMLnTest, NaN_Const) +{ + static const double inf = std::numeric_limits::infinity(); + static const double nan = std::numeric_limits::quiet_NaN(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ln, true, nan).toDouble(), -inf); +} diff --git a/test/llvm/operators/math/log10_test.cpp b/test/llvm/operators/math/log10_test.cpp new file mode 100644 index 000000000..3b021f13e --- /dev/null +++ b/test/llvm/operators/math/log10_test.cpp @@ -0,0 +1,112 @@ +#include +#include + +#include "llvmtestutils.h" + +class LLVMLog10Test : public testing::Test +{ + public: + LLVMTestUtils m_utils; +}; + +TEST_F(LLVMLog10Test, Ten) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Log10, false, 10.0).toDouble(), 1.0); +} + +TEST_F(LLVMLog10Test, Ten_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Log10, true, 10.0).toDouble(), 1.0); +} + +TEST_F(LLVMLog10Test, OneThousand) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Log10, false, 1000.0).toDouble(), 3.0); +} + +TEST_F(LLVMLog10Test, OneThousand_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Log10, true, 1000.0).toDouble(), 3.0); +} + +TEST_F(LLVMLog10Test, ZeroPointZeroOne) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Log10, false, 0.01).toDouble(), -2.0); +} + +TEST_F(LLVMLog10Test, ZeroPointZeroOne_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Log10, true, 0.01).toDouble(), -2.0); +} + +TEST_F(LLVMLog10Test, PositiveZero) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Log10, false, 0.0).toDouble(), -inf); +} + +TEST_F(LLVMLog10Test, PositiveZero_Const) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Log10, true, 0.0).toDouble(), -inf); +} + +TEST_F(LLVMLog10Test, NegativeZero) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Log10, false, -0.0).toDouble(), -inf); +} + +TEST_F(LLVMLog10Test, NegativeZero_Const) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Log10, true, -0.0).toDouble(), -inf); +} + +TEST_F(LLVMLog10Test, NegativeNumber) +{ + ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Log10, false, -0.7).isNaN()); +} + +TEST_F(LLVMLog10Test, NegativeNumber_Const) +{ + ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Log10, true, -0.7).isNaN()); +} + +TEST_F(LLVMLog10Test, PositiveInfinity) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Log10, false, inf).toDouble(), inf); +} + +TEST_F(LLVMLog10Test, PositiveInfinity_Const) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Log10, true, inf).toDouble(), inf); +} + +TEST_F(LLVMLog10Test, NegativeInfinity) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Log10, false, -inf).isNaN()); +} + +TEST_F(LLVMLog10Test, NegativeInfinity_Const) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Log10, true, -inf).isNaN()); +} + +TEST_F(LLVMLog10Test, NaN) +{ + static const double inf = std::numeric_limits::infinity(); + static const double nan = std::numeric_limits::quiet_NaN(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Log10, false, nan).toDouble(), -inf); +} + +TEST_F(LLVMLog10Test, NaN_Const) +{ + static const double inf = std::numeric_limits::infinity(); + static const double nan = std::numeric_limits::quiet_NaN(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Log10, true, nan).toDouble(), -inf); +} diff --git a/test/llvm/operators/math/mod_test.cpp b/test/llvm/operators/math/mod_test.cpp new file mode 100644 index 000000000..93190c863 --- /dev/null +++ b/test/llvm/operators/math/mod_test.cpp @@ -0,0 +1,280 @@ +#include +#include + +#include "llvmtestutils.h" + +class LLVMModTest : public testing::Test +{ + public: + LLVMTestUtils m_utils; +}; + +TEST_F(LLVMModTest, FourModThree) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, false, 4, 3); +} + +TEST_F(LLVMModTest, FourModThree_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, true, 4, 3); +} + +TEST_F(LLVMModTest, ThreeModThree) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, false, 3, 3); +} + +TEST_F(LLVMModTest, ThreeModThree_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, true, 3, 3); +} + +TEST_F(LLVMModTest, TwoModThree) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, false, 2, 3); +} + +TEST_F(LLVMModTest, TwoModThree_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, true, 2, 3); +} + +TEST_F(LLVMModTest, OneModThree) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, false, 1, 3); +} + +TEST_F(LLVMModTest, OneModThree_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, true, 1, 3); +} + +TEST_F(LLVMModTest, ZeroModThree) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, false, 0, 3); +} + +TEST_F(LLVMModTest, ZeroModThree_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, true, 0, 3); +} + +TEST_F(LLVMModTest, NegativeOneModThree) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, false, -1, 3); +} + +TEST_F(LLVMModTest, NegativeOneModThree_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, true, -1, 3); +} + +TEST_F(LLVMModTest, NegativeTwoModThree) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, false, -2, 3); +} + +TEST_F(LLVMModTest, NegativeTwoModThree_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, true, -2, 3); +} + +TEST_F(LLVMModTest, NegativeThreeModThree) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, false, -3, 3); +} + +TEST_F(LLVMModTest, NegativeThreeModThree_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, true, -3, 3); +} + +TEST_F(LLVMModTest, NegativeFourModThree) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, false, -4, 3); +} + +TEST_F(LLVMModTest, NegativeFourModThree_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, true, -4, 3); +} + +TEST_F(LLVMModTest, DecimalModTwo) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, false, 4.75, 2); +} + +TEST_F(LLVMModTest, DecimalModTwo_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, true, 4.75, 2); +} + +TEST_F(LLVMModTest, NegativeDecimalModTwo) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, false, -4.75, 2); +} + +TEST_F(LLVMModTest, NegativeDecimalModTwo_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, true, -4.75, 2); +} + +TEST_F(LLVMModTest, NegativeDecimalModNegativeTwo) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, false, -4.75, -2); +} + +TEST_F(LLVMModTest, NegativeDecimalModNegativeTwo_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, true, -4.75, -2); +} + +TEST_F(LLVMModTest, DecimalModNegativeTwo) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, false, 4.75, -2); +} + +TEST_F(LLVMModTest, DecimalModNegativeTwo_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, true, 4.75, -2); +} + +TEST_F(LLVMModTest, FiveModZero) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, false, 5, 0); +} + +TEST_F(LLVMModTest, FiveModZero_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, true, 5, 0); +} + +TEST_F(LLVMModTest, NegativeFiveModZero) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, false, -5, 0); +} + +TEST_F(LLVMModTest, NegativeFiveModZero_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, true, -5, 0); +} + +TEST_F(LLVMModTest, NegativeDecimalModInfinity) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, false, -2.5, "Infinity"); +} + +TEST_F(LLVMModTest, NegativeDecimalModInfinity_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, true, -2.5, "Infinity"); +} + +TEST_F(LLVMModTest, NegativeDecimalModNegativeInfinity) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, false, -1.2, "-Infinity"); +} + +TEST_F(LLVMModTest, NegativeDecimalModNegativeInfinity_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, true, -1.2, "-Infinity"); +} + +TEST_F(LLVMModTest, PositiveDecimalModInfinity) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, false, 2.5, "Infinity"); +} + +TEST_F(LLVMModTest, PositiveDecimalModInfinity_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, true, 2.5, "Infinity"); +} + +TEST_F(LLVMModTest, PositiveDecimalModNegativeInfinity) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, false, 1.2, "-Infinity"); +} + +TEST_F(LLVMModTest, PositiveDecimalModNegativeInfinity_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, true, 1.2, "-Infinity"); +} + +TEST_F(LLVMModTest, InfinityModTwo) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, false, "Infinity", 2); +} + +TEST_F(LLVMModTest, InfinityModTwo_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, true, "Infinity", 2); +} + +TEST_F(LLVMModTest, NegativeInfinityModTwo) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, false, "-Infinity", 2); +} + +TEST_F(LLVMModTest, NegativeInfinityModTwo_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, true, "-Infinity", 2); +} + +TEST_F(LLVMModTest, InfinityModNegativeTwo) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, false, "Infinity", -2); +} + +TEST_F(LLVMModTest, InfinityModNegativeTwo_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, true, "Infinity", -2); +} + +TEST_F(LLVMModTest, NegativeInfinityModNegativeTwo) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, false, "-Infinity", -2); +} + +TEST_F(LLVMModTest, NegativeInfinityModNegativeTwo_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, true, "-Infinity", -2); +} + +TEST_F(LLVMModTest, ThreeModNaN) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, false, 3, "NaN"); +} + +TEST_F(LLVMModTest, ThreeModNaN_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, true, 3, "NaN"); +} + +TEST_F(LLVMModTest, NegativeThreeModNaN) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, false, -3, "NaN"); +} + +TEST_F(LLVMModTest, NegativeThreeModNaN_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, true, -3, "NaN"); +} + +TEST_F(LLVMModTest, NaNModFive) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, false, "NaN", 5); +} + +TEST_F(LLVMModTest, NaNModFive_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, true, "NaN", 5); +} + +TEST_F(LLVMModTest, NaNModNegativeFive) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, false, "NaN", -5); +} + +TEST_F(LLVMModTest, NaNModNegativeFive_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, true, "NaN", -5); +} diff --git a/test/llvm/operators/math/multiply_test.cpp b/test/llvm/operators/math/multiply_test.cpp new file mode 100644 index 000000000..acc368802 --- /dev/null +++ b/test/llvm/operators/math/multiply_test.cpp @@ -0,0 +1,180 @@ +#include +#include + +#include "llvmtestutils.h" + +class LLVMMultiplyTest : public testing::Test +{ + public: + LLVMTestUtils m_utils; +}; + +TEST_F(LLVMMultiplyTest, PositiveIntegers) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mul, false, 50, 2); +} + +TEST_F(LLVMMultiplyTest, PositiveIntegers_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mul, true, 50, 2); +} + +TEST_F(LLVMMultiplyTest, NegativeWithPositive) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mul, false, -500, 25); +} + +TEST_F(LLVMMultiplyTest, NegativeWithPositive_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mul, true, -500, 25); +} + +TEST_F(LLVMMultiplyTest, StringNegativeWithNegative) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mul, false, "-500", -25); +} + +TEST_F(LLVMMultiplyTest, StringNegativeWithNegative_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mul, true, "-500", -25); +} + +TEST_F(LLVMMultiplyTest, StringDecimals) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mul, false, "2.54", "6.28"); +} + +TEST_F(LLVMMultiplyTest, StringDecimals_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mul, true, "2.54", "6.28"); +} + +TEST_F(LLVMMultiplyTest, BooleanValues) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mul, false, true, true); +} + +TEST_F(LLVMMultiplyTest, BooleanValues_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mul, true, true, true); +} + +TEST_F(LLVMMultiplyTest, InfinityTimesInfinity) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mul, false, "Infinity", "Infinity"); +} + +TEST_F(LLVMMultiplyTest, InfinityTimesInfinity_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mul, true, "Infinity", "Infinity"); +} + +TEST_F(LLVMMultiplyTest, InfinityTimesZero) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mul, false, "Infinity", 0); +} + +TEST_F(LLVMMultiplyTest, InfinityTimesZero_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mul, true, "Infinity", 0); +} + +TEST_F(LLVMMultiplyTest, InfinityTimesPositive) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mul, false, "Infinity", 2); +} + +TEST_F(LLVMMultiplyTest, InfinityTimesPositive_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mul, true, "Infinity", 2); +} + +TEST_F(LLVMMultiplyTest, InfinityTimesNegative) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mul, false, "Infinity", -2); +} + +TEST_F(LLVMMultiplyTest, InfinityTimesNegative_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mul, true, "Infinity", -2); +} + +TEST_F(LLVMMultiplyTest, InfinityTimesNegativeInfinity) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mul, false, "Infinity", "-Infinity"); +} + +TEST_F(LLVMMultiplyTest, InfinityTimesNegativeInfinity_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mul, true, "Infinity", "-Infinity"); +} + +TEST_F(LLVMMultiplyTest, NegativeInfinityTimesInfinity) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mul, false, "-Infinity", "Infinity"); +} + +TEST_F(LLVMMultiplyTest, NegativeInfinityTimesInfinity_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mul, true, "-Infinity", "Infinity"); +} + +TEST_F(LLVMMultiplyTest, NegativeInfinityTimesZero) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mul, false, "-Infinity", 0); +} + +TEST_F(LLVMMultiplyTest, NegativeInfinityTimesZero_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mul, true, "-Infinity", 0); +} + +TEST_F(LLVMMultiplyTest, NegativeInfinityTimesPositive) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mul, false, "-Infinity", 2); +} + +TEST_F(LLVMMultiplyTest, NegativeInfinityTimesPositive_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mul, true, "-Infinity", 2); +} + +TEST_F(LLVMMultiplyTest, NegativeInfinityTimesNegative) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mul, false, "-Infinity", -2); +} + +TEST_F(LLVMMultiplyTest, NegativeInfinityTimesNegative_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mul, true, "-Infinity", -2); +} + +TEST_F(LLVMMultiplyTest, NegativeInfinityTimesNegativeInfinity) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mul, false, "-Infinity", "-Infinity"); +} + +TEST_F(LLVMMultiplyTest, NegativeInfinityTimesNegativeInfinity_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mul, true, "-Infinity", "-Infinity"); +} + +TEST_F(LLVMMultiplyTest, NumberTimesNaN) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mul, false, 1, "NaN"); +} + +TEST_F(LLVMMultiplyTest, NumberTimesNaN_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mul, true, 1, "NaN"); +} + +TEST_F(LLVMMultiplyTest, NaNTimesNumber) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mul, false, "NaN", 1); +} + +TEST_F(LLVMMultiplyTest, NaNTimesNumber_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mul, true, "NaN", 1); +} diff --git a/test/llvm/operators/math/random_int_test.cpp b/test/llvm/operators/math/random_int_test.cpp new file mode 100644 index 000000000..d224a4dac --- /dev/null +++ b/test/llvm/operators/math/random_int_test.cpp @@ -0,0 +1,134 @@ +#include +#include + +#include "llvmtestutils.h" + +using ::testing::Return; + +class LLVMRandomIntTest : public testing::Test +{ + public: + LLVMTestUtils m_utils; +}; + +TEST_F(LLVMRandomIntTest, IntegerRange) +{ + EXPECT_CALL(m_utils.rng(), randint(-45, 12)).Times(2).WillRepeatedly(Return(-18)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::RandomInt, false, -45, 12); +} + +TEST_F(LLVMRandomIntTest, IntegerRange_Const) +{ + EXPECT_CALL(m_utils.rng(), randint(-45, 12)).Times(2).WillRepeatedly(Return(-18)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::RandomInt, true, -45, 12); +} + +TEST_F(LLVMRandomIntTest, DoubleAsInteger) +{ + EXPECT_CALL(m_utils.rng(), randint(-45, 12)).Times(2).WillRepeatedly(Return(5)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::RandomInt, false, -45.0, 12.0); +} + +TEST_F(LLVMRandomIntTest, DoubleAsInteger_Const) +{ + EXPECT_CALL(m_utils.rng(), randint(-45, 12)).Times(2).WillRepeatedly(Return(5)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::RandomInt, true, -45.0, 12.0); +} + +TEST_F(LLVMRandomIntTest, TruncatedDoubleRange) +{ + EXPECT_CALL(m_utils.rng(), randint(12, 6)).Times(2).WillRepeatedly(Return(3)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::RandomInt, false, 12, 6.05); +} + +TEST_F(LLVMRandomIntTest, TruncatedDoubleRange_Const) +{ + EXPECT_CALL(m_utils.rng(), randint(12, 6)).Times(2).WillRepeatedly(Return(3)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::RandomInt, true, 12, 6.05); +} + +TEST_F(LLVMRandomIntTest, NegativeDoubleRange) +{ + EXPECT_CALL(m_utils.rng(), randint(-78, -45)).Times(2).WillRepeatedly(Return(-59)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::RandomInt, false, -78.686, -45); +} + +TEST_F(LLVMRandomIntTest, NegativeDoubleRange_Const) +{ + EXPECT_CALL(m_utils.rng(), randint(-78, -45)).Times(2).WillRepeatedly(Return(-59)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::RandomInt, true, -78.686, -45); +} + +TEST_F(LLVMRandomIntTest, StringIntegerRange) +{ + EXPECT_CALL(m_utils.rng(), randint(-45, 12)).Times(2).WillRepeatedly(Return(0)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::RandomInt, false, "-45", "12"); +} + +TEST_F(LLVMRandomIntTest, StringIntegerRange_Const) +{ + EXPECT_CALL(m_utils.rng(), randint(-45, 12)).Times(2).WillRepeatedly(Return(0)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::RandomInt, true, "-45", "12"); +} + +TEST_F(LLVMRandomIntTest, StringDoubleToInteger) +{ + EXPECT_CALL(m_utils.rng(), randint(-45, 12)).Times(2).WillRepeatedly(Return(5)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::RandomInt, false, "-45.0", "12"); +} + +TEST_F(LLVMRandomIntTest, StringDoubleToInteger_Const) +{ + EXPECT_CALL(m_utils.rng(), randint(-45, 12)).Times(2).WillRepeatedly(Return(5)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::RandomInt, true, "-45.0", "12"); +} + +TEST_F(LLVMRandomIntTest, StringIntegerToDouble) +{ + EXPECT_CALL(m_utils.rng(), randint(-45, 12)).Times(2).WillRepeatedly(Return(-15)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::RandomInt, false, "-45", "12.0"); +} + +TEST_F(LLVMRandomIntTest, StringIntegerToDouble_Const) +{ + EXPECT_CALL(m_utils.rng(), randint(-45, 12)).Times(2).WillRepeatedly(Return(-15)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::RandomInt, true, "-45", "12.0"); +} + +TEST_F(LLVMRandomIntTest, BooleanRange) +{ + EXPECT_CALL(m_utils.rng(), randint(0, 1)).Times(2).WillRepeatedly(Return(1)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::RandomInt, false, false, true); +} + +TEST_F(LLVMRandomIntTest, BooleanRange_Const) +{ + EXPECT_CALL(m_utils.rng(), randint(0, 1)).Times(2).WillRepeatedly(Return(1)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::RandomInt, true, false, true); +} + +TEST_F(LLVMRandomIntTest, BooleanWithNumber) +{ + EXPECT_CALL(m_utils.rng(), randint(1, 5)).Times(2).WillRepeatedly(Return(1)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::RandomInt, false, true, 5); +} + +TEST_F(LLVMRandomIntTest, BooleanWithNumber_Const) +{ + EXPECT_CALL(m_utils.rng(), randint(1, 5)).Times(2).WillRepeatedly(Return(1)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::RandomInt, true, true, 5); +} + +TEST_F(LLVMRandomIntTest, NumberWithBoolean) +{ + EXPECT_CALL(m_utils.rng(), randint(8, 0)).Times(2).WillRepeatedly(Return(1)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::RandomInt, false, 8, false); +} + +TEST_F(LLVMRandomIntTest, NumberWithBoolean_Const) +{ + EXPECT_CALL(m_utils.rng(), randint(8, 0)).Times(2).WillRepeatedly(Return(1)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::RandomInt, true, 8, false); +} + +// NOTE: Infinity, -Infinity and NaN behavior is undefined diff --git a/test/llvm/operators/math/random_test.cpp b/test/llvm/operators/math/random_test.cpp new file mode 100644 index 000000000..fb66a65f9 --- /dev/null +++ b/test/llvm/operators/math/random_test.cpp @@ -0,0 +1,444 @@ +#include +#include + +#include "llvmtestutils.h" + +using ::testing::Return; + +class LLVMRandomTest : public testing::Test +{ + public: + LLVMTestUtils m_utils; +}; + +TEST_F(LLVMRandomTest, IntegerRange) +{ + EXPECT_CALL(m_utils.rng(), randint(-45, 12)).WillRepeatedly(Return(-18)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, false, -45, 12); +} + +TEST_F(LLVMRandomTest, IntegerRange_Const) +{ + EXPECT_CALL(m_utils.rng(), randint(-45, 12)).WillRepeatedly(Return(-18)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, true, -45, 12); +} + +TEST_F(LLVMRandomTest, DoubleAsInteger) +{ + EXPECT_CALL(m_utils.rng(), randint(-45, 12)).WillRepeatedly(Return(5)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, false, -45.0, 12.0); +} + +TEST_F(LLVMRandomTest, DoubleAsInteger_Const) +{ + EXPECT_CALL(m_utils.rng(), randint(-45, 12)).WillRepeatedly(Return(5)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, true, -45.0, 12.0); +} + +TEST_F(LLVMRandomTest, DoubleRange) +{ + EXPECT_CALL(m_utils.rng(), randintDouble(12, 6.05)).WillRepeatedly(Return(3.486789)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, false, 12, 6.05); +} + +TEST_F(LLVMRandomTest, DoubleRange_Const) +{ + EXPECT_CALL(m_utils.rng(), randintDouble(12, 6.05)).WillRepeatedly(Return(3.486789)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, true, 12, 6.05); +} + +TEST_F(LLVMRandomTest, NegativeDoubleRange) +{ + EXPECT_CALL(m_utils.rng(), randintDouble(-78.686, -45)).WillRepeatedly(Return(-59.468873)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, false, -78.686, -45); +} + +TEST_F(LLVMRandomTest, NegativeDoubleRange_Const) +{ + EXPECT_CALL(m_utils.rng(), randintDouble(-78.686, -45)).WillRepeatedly(Return(-59.468873)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, true, -78.686, -45); +} + +TEST_F(LLVMRandomTest, ReversedDoubleRange) +{ + EXPECT_CALL(m_utils.rng(), randintDouble(6.05, -78.686)).WillRepeatedly(Return(-28.648764)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, false, 6.05, -78.686); +} + +TEST_F(LLVMRandomTest, ReversedDoubleRange_Const) +{ + EXPECT_CALL(m_utils.rng(), randintDouble(6.05, -78.686)).WillRepeatedly(Return(-28.648764)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, true, 6.05, -78.686); +} + +TEST_F(LLVMRandomTest, StringIntegerRange) +{ + EXPECT_CALL(m_utils.rng(), randint(-45, 12)).WillRepeatedly(Return(0)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, false, "-45", "12"); +} + +TEST_F(LLVMRandomTest, StringIntegerRange_Const) +{ + EXPECT_CALL(m_utils.rng(), randint(-45, 12)).WillRepeatedly(Return(0)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, true, "-45", "12"); +} + +TEST_F(LLVMRandomTest, StringDoubleToInteger) +{ + EXPECT_CALL(m_utils.rng(), randintDouble(-45, 12)).WillRepeatedly(Return(5.2)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, false, "-45.0", "12"); +} + +TEST_F(LLVMRandomTest, StringDoubleToInteger_Const) +{ + EXPECT_CALL(m_utils.rng(), randintDouble(-45, 12)).WillRepeatedly(Return(5.2)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, true, "-45.0", "12"); +} + +TEST_F(LLVMRandomTest, StringIntegerToDouble) +{ + EXPECT_CALL(m_utils.rng(), randintDouble(-45, 12)).WillRepeatedly(Return(-15.5787)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, false, "-45", "12.0"); +} + +TEST_F(LLVMRandomTest, StringIntegerToDouble_Const) +{ + EXPECT_CALL(m_utils.rng(), randintDouble(-45, 12)).WillRepeatedly(Return(-15.5787)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, true, "-45", "12.0"); +} + +TEST_F(LLVMRandomTest, StringDoubleRange) +{ + EXPECT_CALL(m_utils.rng(), randintDouble(-45, 12)).WillRepeatedly(Return(2.587964)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, false, "-45.0", "12.0"); +} + +TEST_F(LLVMRandomTest, StringDoubleRange_Const) +{ + EXPECT_CALL(m_utils.rng(), randintDouble(-45, 12)).WillRepeatedly(Return(2.587964)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, true, "-45.0", "12.0"); +} + +TEST_F(LLVMRandomTest, StringReversedDoubleRange) +{ + EXPECT_CALL(m_utils.rng(), randintDouble(6.05, -78.686)).WillRepeatedly(Return(5.648764)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, false, "6.05", "-78.686"); +} + +TEST_F(LLVMRandomTest, StringReversedDoubleRange_Const) +{ + EXPECT_CALL(m_utils.rng(), randintDouble(6.05, -78.686)).WillRepeatedly(Return(5.648764)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, true, "6.05", "-78.686"); +} + +TEST_F(LLVMRandomTest, MixedStringIntegerWithNumber) +{ + EXPECT_CALL(m_utils.rng(), randint(-45, 12)).WillRepeatedly(Return(0)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, false, "-45", 12); +} + +TEST_F(LLVMRandomTest, MixedStringIntegerWithNumber_Const) +{ + EXPECT_CALL(m_utils.rng(), randint(-45, 12)).WillRepeatedly(Return(0)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, true, "-45", 12); +} + +TEST_F(LLVMRandomTest, MixedNumberWithStringInteger) +{ + EXPECT_CALL(m_utils.rng(), randint(-45, 12)).WillRepeatedly(Return(0)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, false, -45, "12"); +} + +TEST_F(LLVMRandomTest, MixedNumberWithStringInteger_Const) +{ + EXPECT_CALL(m_utils.rng(), randint(-45, 12)).WillRepeatedly(Return(0)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, true, -45, "12"); +} + +TEST_F(LLVMRandomTest, MixedStringDoubleWithNumber) +{ + EXPECT_CALL(m_utils.rng(), randintDouble(-45, 12)).WillRepeatedly(Return(5.2)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, false, "-45.0", 12); +} + +TEST_F(LLVMRandomTest, MixedStringDoubleWithNumber_Const) +{ + EXPECT_CALL(m_utils.rng(), randintDouble(-45, 12)).WillRepeatedly(Return(5.2)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, true, "-45.0", 12); +} + +TEST_F(LLVMRandomTest, MixedNumberWithStringDouble) +{ + EXPECT_CALL(m_utils.rng(), randintDouble(-45, 12)).WillRepeatedly(Return(-15.5787)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, false, -45, "12.0"); +} + +TEST_F(LLVMRandomTest, MixedNumberWithStringDouble_Const) +{ + EXPECT_CALL(m_utils.rng(), randintDouble(-45, 12)).WillRepeatedly(Return(-15.5787)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, true, -45, "12.0"); +} + +TEST_F(LLVMRandomTest, MixedDoubleWithStringDouble) +{ + EXPECT_CALL(m_utils.rng(), randintDouble(6.05, -78.686)).WillRepeatedly(Return(5.648764)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, false, 6.05, "-78.686"); +} + +TEST_F(LLVMRandomTest, MixedDoubleWithStringDouble_Const) +{ + EXPECT_CALL(m_utils.rng(), randintDouble(6.05, -78.686)).WillRepeatedly(Return(5.648764)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, true, 6.05, "-78.686"); +} + +TEST_F(LLVMRandomTest, MixedStringDoubleWithDouble) +{ + EXPECT_CALL(m_utils.rng(), randintDouble(6.05, -78.686)).WillRepeatedly(Return(5.648764)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, false, "6.05", -78.686); +} + +TEST_F(LLVMRandomTest, MixedStringDoubleWithDouble_Const) +{ + EXPECT_CALL(m_utils.rng(), randintDouble(6.05, -78.686)).WillRepeatedly(Return(5.648764)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, true, "6.05", -78.686); +} + +TEST_F(LLVMRandomTest, BooleanRange) +{ + EXPECT_CALL(m_utils.rng(), randint(0, 1)).WillRepeatedly(Return(1)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, false, false, true); +} + +TEST_F(LLVMRandomTest, BooleanRange_Const) +{ + EXPECT_CALL(m_utils.rng(), randint(0, 1)).WillRepeatedly(Return(1)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, true, false, true); +} + +TEST_F(LLVMRandomTest, BooleanWithNumber) +{ + EXPECT_CALL(m_utils.rng(), randint(1, 5)).WillRepeatedly(Return(1)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, false, true, 5); +} + +TEST_F(LLVMRandomTest, BooleanWithNumber_Const) +{ + EXPECT_CALL(m_utils.rng(), randint(1, 5)).WillRepeatedly(Return(1)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, true, true, 5); +} + +TEST_F(LLVMRandomTest, NumberWithBoolean) +{ + EXPECT_CALL(m_utils.rng(), randint(8, 0)).WillRepeatedly(Return(1)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, false, 8, false); +} + +TEST_F(LLVMRandomTest, NumberWithBoolean_Const) +{ + EXPECT_CALL(m_utils.rng(), randint(8, 0)).WillRepeatedly(Return(1)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, true, 8, false); +} + +TEST_F(LLVMRandomTest, NaNWithNumber) +{ + EXPECT_CALL(m_utils.rng(), randint(0, 5)).WillRepeatedly(Return(5)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, false, "NaN", 5); +} + +TEST_F(LLVMRandomTest, NaNWithNumber_Const) +{ + EXPECT_CALL(m_utils.rng(), randint(0, 5)).WillRepeatedly(Return(5)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, true, "NaN", 5); +} + +TEST_F(LLVMRandomTest, NumberWithNaN) +{ + EXPECT_CALL(m_utils.rng(), randint(5, 0)).WillRepeatedly(Return(3)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, false, 5, "NaN"); +} + +TEST_F(LLVMRandomTest, NumberWithNaN_Const) +{ + EXPECT_CALL(m_utils.rng(), randint(5, 0)).WillRepeatedly(Return(3)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, true, 5, "NaN"); +} + +TEST_F(LLVMRandomTest, NaNWithNaN) +{ + EXPECT_CALL(m_utils.rng(), randint(0, 0)).WillRepeatedly(Return(0)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, false, "NaN", "NaN"); +} + +TEST_F(LLVMRandomTest, NaNWithNaN_Const) +{ + EXPECT_CALL(m_utils.rng(), randint(0, 0)).WillRepeatedly(Return(0)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, true, "NaN", "NaN"); +} + +TEST_F(LLVMRandomTest, InfinityWithNumber) +{ + EXPECT_CALL(m_utils.rng(), randint).WillRepeatedly(Return(0)); + EXPECT_CALL(m_utils.rng(), randintDouble).WillRepeatedly(Return(0)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, false, "Infinity", 2); +} + +TEST_F(LLVMRandomTest, InfinityWithNumber_Const) +{ + EXPECT_CALL(m_utils.rng(), randint).WillRepeatedly(Return(0)); + EXPECT_CALL(m_utils.rng(), randintDouble).WillRepeatedly(Return(0)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, true, "Infinity", 2); +} + +TEST_F(LLVMRandomTest, NumberWithInfinity) +{ + EXPECT_CALL(m_utils.rng(), randint).WillRepeatedly(Return(0)); + EXPECT_CALL(m_utils.rng(), randintDouble).WillRepeatedly(Return(0)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, false, -8, "Infinity"); +} + +TEST_F(LLVMRandomTest, NumberWithInfinity_Const) +{ + EXPECT_CALL(m_utils.rng(), randint).WillRepeatedly(Return(0)); + EXPECT_CALL(m_utils.rng(), randintDouble).WillRepeatedly(Return(0)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, true, -8, "Infinity"); +} + +TEST_F(LLVMRandomTest, NegativeInfinityWithNumber) +{ + EXPECT_CALL(m_utils.rng(), randint).WillRepeatedly(Return(0)); + EXPECT_CALL(m_utils.rng(), randintDouble).WillRepeatedly(Return(0)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, false, "-Infinity", -2); +} + +TEST_F(LLVMRandomTest, NegativeInfinityWithNumber_Const) +{ + EXPECT_CALL(m_utils.rng(), randint).WillRepeatedly(Return(0)); + EXPECT_CALL(m_utils.rng(), randintDouble).WillRepeatedly(Return(0)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, true, "-Infinity", -2); +} + +TEST_F(LLVMRandomTest, NumberWithNegativeInfinity) +{ + EXPECT_CALL(m_utils.rng(), randint).WillRepeatedly(Return(0)); + EXPECT_CALL(m_utils.rng(), randintDouble).WillRepeatedly(Return(0)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, false, 8, "-Infinity"); +} + +TEST_F(LLVMRandomTest, NumberWithNegativeInfinity_Const) +{ + EXPECT_CALL(m_utils.rng(), randint).WillRepeatedly(Return(0)); + EXPECT_CALL(m_utils.rng(), randintDouble).WillRepeatedly(Return(0)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, true, 8, "-Infinity"); +} + +TEST_F(LLVMRandomTest, InfinityWithDouble) +{ + EXPECT_CALL(m_utils.rng(), randint).WillRepeatedly(Return(0)); + EXPECT_CALL(m_utils.rng(), randintDouble).WillRepeatedly(Return(0)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, false, "Infinity", 2.5); +} + +TEST_F(LLVMRandomTest, InfinityWithDouble_Const) +{ + EXPECT_CALL(m_utils.rng(), randint).WillRepeatedly(Return(0)); + EXPECT_CALL(m_utils.rng(), randintDouble).WillRepeatedly(Return(0)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, true, "Infinity", 2.5); +} + +TEST_F(LLVMRandomTest, DoubleWithInfinity) +{ + EXPECT_CALL(m_utils.rng(), randint).WillRepeatedly(Return(0)); + EXPECT_CALL(m_utils.rng(), randintDouble).WillRepeatedly(Return(0)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, false, -8.09, "Infinity"); +} + +TEST_F(LLVMRandomTest, DoubleWithInfinity_Const) +{ + EXPECT_CALL(m_utils.rng(), randint).WillRepeatedly(Return(0)); + EXPECT_CALL(m_utils.rng(), randintDouble).WillRepeatedly(Return(0)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, true, -8.09, "Infinity"); +} + +TEST_F(LLVMRandomTest, NegativeInfinityWithDouble) +{ + EXPECT_CALL(m_utils.rng(), randint).WillRepeatedly(Return(0)); + EXPECT_CALL(m_utils.rng(), randintDouble).WillRepeatedly(Return(0)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, false, "-Infinity", -2.5); +} + +TEST_F(LLVMRandomTest, NegativeInfinityWithDouble_Const) +{ + EXPECT_CALL(m_utils.rng(), randint).WillRepeatedly(Return(0)); + EXPECT_CALL(m_utils.rng(), randintDouble).WillRepeatedly(Return(0)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, true, "-Infinity", -2.5); +} + +TEST_F(LLVMRandomTest, DoubleWithNegativeInfinity) +{ + EXPECT_CALL(m_utils.rng(), randint).WillRepeatedly(Return(0)); + EXPECT_CALL(m_utils.rng(), randintDouble).WillRepeatedly(Return(0)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, false, 8.09, "-Infinity"); +} + +TEST_F(LLVMRandomTest, DoubleWithNegativeInfinity_Const) +{ + EXPECT_CALL(m_utils.rng(), randint).WillRepeatedly(Return(0)); + EXPECT_CALL(m_utils.rng(), randintDouble).WillRepeatedly(Return(0)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, true, 8.09, "-Infinity"); +} + +TEST_F(LLVMRandomTest, InfinityWithInfinity) +{ + EXPECT_CALL(m_utils.rng(), randint).WillRepeatedly(Return(0)); + EXPECT_CALL(m_utils.rng(), randintDouble).WillRepeatedly(Return(0)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, false, "Infinity", "Infinity"); +} + +TEST_F(LLVMRandomTest, InfinityWithInfinity_Const) +{ + EXPECT_CALL(m_utils.rng(), randint).WillRepeatedly(Return(0)); + EXPECT_CALL(m_utils.rng(), randintDouble).WillRepeatedly(Return(0)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, true, "Infinity", "Infinity"); +} + +TEST_F(LLVMRandomTest, NegativeInfinityWithNegativeInfinity) +{ + EXPECT_CALL(m_utils.rng(), randint).WillRepeatedly(Return(0)); + EXPECT_CALL(m_utils.rng(), randintDouble).WillRepeatedly(Return(0)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, false, "-Infinity", "-Infinity"); +} + +TEST_F(LLVMRandomTest, NegativeInfinityWithNegativeInfinity_Const) +{ + EXPECT_CALL(m_utils.rng(), randint).WillRepeatedly(Return(0)); + EXPECT_CALL(m_utils.rng(), randintDouble).WillRepeatedly(Return(0)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, true, "-Infinity", "-Infinity"); +} + +TEST_F(LLVMRandomTest, InfinityWithNegativeInfinity) +{ + EXPECT_CALL(m_utils.rng(), randint).WillRepeatedly(Return(0)); + EXPECT_CALL(m_utils.rng(), randintDouble).WillRepeatedly(Return(0)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, false, "Infinity", "-Infinity"); +} + +TEST_F(LLVMRandomTest, InfinityWithNegativeInfinity_Const) +{ + EXPECT_CALL(m_utils.rng(), randint).WillRepeatedly(Return(0)); + EXPECT_CALL(m_utils.rng(), randintDouble).WillRepeatedly(Return(0)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, true, "Infinity", "-Infinity"); +} + +TEST_F(LLVMRandomTest, NegativeInfinityWithInfinity) +{ + EXPECT_CALL(m_utils.rng(), randint).WillRepeatedly(Return(0)); + EXPECT_CALL(m_utils.rng(), randintDouble).WillRepeatedly(Return(0)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, false, "-Infinity", "Infinity"); +} + +TEST_F(LLVMRandomTest, NegativeInfinityWithInfinity_Const) +{ + EXPECT_CALL(m_utils.rng(), randint).WillRepeatedly(Return(0)); + EXPECT_CALL(m_utils.rng(), randintDouble).WillRepeatedly(Return(0)); + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, true, "-Infinity", "Infinity"); +} diff --git a/test/llvm/operators/math/round_test.cpp b/test/llvm/operators/math/round_test.cpp new file mode 100644 index 000000000..e5bb7b450 --- /dev/null +++ b/test/llvm/operators/math/round_test.cpp @@ -0,0 +1,146 @@ +#include +#include + +#include "llvmtestutils.h" + +class LLVMRoundTest : public testing::Test +{ + public: + LLVMTestUtils m_utils; +}; + +TEST_F(LLVMRoundTest, FourPointZero) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Round, false, 4.0).toDouble(), 4.0); +} + +TEST_F(LLVMRoundTest, FourPointZero_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Round, true, 4.0).toDouble(), 4.0); +} + +TEST_F(LLVMRoundTest, ThreePointTwo) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Round, false, 3.2).toDouble(), 3.0); +} + +TEST_F(LLVMRoundTest, ThreePointTwo_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Round, true, 3.2).toDouble(), 3.0); +} + +TEST_F(LLVMRoundTest, ThreePointFive) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Round, false, 3.5).toDouble(), 4.0); +} + +TEST_F(LLVMRoundTest, ThreePointFive_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Round, true, 3.5).toDouble(), 4.0); +} + +TEST_F(LLVMRoundTest, ThreePointSix) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Round, false, 3.6).toDouble(), 4.0); +} + +TEST_F(LLVMRoundTest, ThreePointSix_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Round, true, 3.6).toDouble(), 4.0); +} + +TEST_F(LLVMRoundTest, NegativeTwoPointFour) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Round, false, -2.4).toDouble(), -2.0); +} + +TEST_F(LLVMRoundTest, NegativeTwoPointFour_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Round, true, -2.4).toDouble(), -2.0); +} + +TEST_F(LLVMRoundTest, NegativeTwoPointFive) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Round, false, -2.5).toDouble(), -2.0); +} + +TEST_F(LLVMRoundTest, NegativeTwoPointFive_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Round, true, -2.5).toDouble(), -2.0); +} + +TEST_F(LLVMRoundTest, NegativeTwoPointSix) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Round, false, -2.6).toDouble(), -3.0); +} + +TEST_F(LLVMRoundTest, NegativeTwoPointSix_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Round, true, -2.6).toDouble(), -3.0); +} + +TEST_F(LLVMRoundTest, NegativeZeroPointFour) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Round, false, -0.4).toDouble(), -0.0); +} + +TEST_F(LLVMRoundTest, NegativeZeroPointFour_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Round, true, -0.4).toDouble(), -0.0); +} + +TEST_F(LLVMRoundTest, NegativeZeroPointFive) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Round, false, -0.5).toDouble(), -0.0); +} + +TEST_F(LLVMRoundTest, NegativeZeroPointFive_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Round, true, -0.5).toDouble(), -0.0); +} + +TEST_F(LLVMRoundTest, NegativeZeroPointFiftyOne) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Round, false, -0.51).toDouble(), -1.0); +} + +TEST_F(LLVMRoundTest, NegativeZeroPointFiftyOne_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Round, true, -0.51).toDouble(), -1.0); +} + +TEST_F(LLVMRoundTest, Infinity) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Round, false, inf).toDouble(), inf); +} + +TEST_F(LLVMRoundTest, Infinity_Const) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Round, true, inf).toDouble(), inf); +} + +TEST_F(LLVMRoundTest, NegativeInfinity) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Round, false, -inf).toDouble(), -inf); +} + +TEST_F(LLVMRoundTest, NegativeInfinity_Const) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Round, true, -inf).toDouble(), -inf); +} + +TEST_F(LLVMRoundTest, NaN) +{ + static const double nan = std::numeric_limits::quiet_NaN(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Round, false, nan).toDouble(), 0); +} + +TEST_F(LLVMRoundTest, NaN_Const) +{ + static const double nan = std::numeric_limits::quiet_NaN(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Round, true, nan).toDouble(), 0); +} diff --git a/test/llvm/operators/math/sin_test.cpp b/test/llvm/operators/math/sin_test.cpp new file mode 100644 index 000000000..caaa0ea0a --- /dev/null +++ b/test/llvm/operators/math/sin_test.cpp @@ -0,0 +1,136 @@ +#include +#include + +#include "llvmtestutils.h" + +class LLVMSinTest : public testing::Test +{ + public: + LLVMTestUtils m_utils; +}; + +TEST_F(LLVMSinTest, ThirtyDegrees) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Sin, false, 30.0).toDouble(), 0.5); +} + +TEST_F(LLVMSinTest, ThirtyDegrees_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Sin, true, 30.0).toDouble(), 0.5); +} + +TEST_F(LLVMSinTest, NinetyDegrees) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Sin, false, 90.0).toDouble(), 1.0); +} + +TEST_F(LLVMSinTest, NinetyDegrees_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Sin, true, 90.0).toDouble(), 1.0); +} + +TEST_F(LLVMSinTest, VerySmallAngle) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Sin, false, 2.8e-9).toDouble(), 0.0); +} + +TEST_F(LLVMSinTest, VerySmallAngle_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Sin, true, 2.8e-9).toDouble(), 0.0); +} + +TEST_F(LLVMSinTest, SlightlyLargerSmallAngle) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Sin, false, 2.9e-9).toDouble(), 1e-10); +} + +TEST_F(LLVMSinTest, SlightlyLargerSmallAngle_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Sin, true, 2.9e-9).toDouble(), 1e-10); +} + +TEST_F(LLVMSinTest, FiveSeventyDegrees) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Sin, false, 570.0).toDouble(), -0.5); +} + +TEST_F(LLVMSinTest, FiveSeventyDegrees_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Sin, true, 570.0).toDouble(), -0.5); +} + +TEST_F(LLVMSinTest, NegativeThirtyDegrees) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Sin, false, -30.0).toDouble(), -0.5); +} + +TEST_F(LLVMSinTest, NegativeThirtyDegrees_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Sin, true, -30.0).toDouble(), -0.5); +} + +TEST_F(LLVMSinTest, NegativeNinetyDegrees) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Sin, false, -90.0).toDouble(), -1.0); +} + +TEST_F(LLVMSinTest, NegativeNinetyDegrees_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Sin, true, -90.0).toDouble(), -1.0); +} + +TEST_F(LLVMSinTest, PositiveZero) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Sin, false, 0.0).toDouble(), 0.0); +} + +TEST_F(LLVMSinTest, PositiveZero_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Sin, true, 0.0).toDouble(), 0.0); +} + +TEST_F(LLVMSinTest, NegativeZero) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Sin, false, -0.0).toDouble(), 0.0); +} + +TEST_F(LLVMSinTest, NegativeZero_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Sin, true, -0.0).toDouble(), 0.0); +} + +TEST_F(LLVMSinTest, PositiveInfinity) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Sin, false, inf).isNaN()); +} + +TEST_F(LLVMSinTest, PositiveInfinity_Const) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Sin, true, inf).isNaN()); +} + +TEST_F(LLVMSinTest, NegativeInfinity) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Sin, false, -inf).isNaN()); +} + +TEST_F(LLVMSinTest, NegativeInfinity_Const) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Sin, true, -inf).isNaN()); +} + +TEST_F(LLVMSinTest, NaN) +{ + static const double nan = std::numeric_limits::quiet_NaN(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Sin, false, nan).toDouble(), 0); +} + +TEST_F(LLVMSinTest, NaN_Const) +{ + static const double nan = std::numeric_limits::quiet_NaN(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Sin, true, nan).toDouble(), 0); +} diff --git a/test/llvm/operators/math/sqrt_test.cpp b/test/llvm/operators/math/sqrt_test.cpp new file mode 100644 index 000000000..faab7f42d --- /dev/null +++ b/test/llvm/operators/math/sqrt_test.cpp @@ -0,0 +1,96 @@ +#include +#include + +#include "llvmtestutils.h" + +class LLVMSqrtTest : public testing::Test +{ + public: + LLVMTestUtils m_utils; +}; + +TEST_F(LLVMSqrtTest, SixteenPointZero) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Sqrt, false, 16.0).toDouble(), 4.0); +} + +TEST_F(LLVMSqrtTest, SixteenPointZero_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Sqrt, true, 16.0).toDouble(), 4.0); +} + +TEST_F(LLVMSqrtTest, ZeroPointZeroFour) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Sqrt, false, 0.04).toDouble(), 0.2); +} + +TEST_F(LLVMSqrtTest, ZeroPointZeroFour_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Sqrt, true, 0.04).toDouble(), 0.2); +} + +TEST_F(LLVMSqrtTest, PositiveZero) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Sqrt, false, 0.0).toDouble(), 0.0); +} + +TEST_F(LLVMSqrtTest, PositiveZero_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Sqrt, true, 0.0).toDouble(), 0.0); +} + +TEST_F(LLVMSqrtTest, NegativeZero) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Sqrt, false, -0.0).toDouble(), 0.0); +} + +TEST_F(LLVMSqrtTest, NegativeZero_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Sqrt, true, -0.0).toDouble(), 0.0); +} + +TEST_F(LLVMSqrtTest, NegativeFour) +{ + ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Sqrt, false, -4.0).isNaN()); +} + +TEST_F(LLVMSqrtTest, NegativeFour_Const) +{ + ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Sqrt, true, -4.0).isNaN()); +} + +TEST_F(LLVMSqrtTest, PositiveInfinity) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Sqrt, false, inf).toDouble(), inf); +} + +TEST_F(LLVMSqrtTest, PositiveInfinity_Const) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Sqrt, true, inf).toDouble(), inf); +} + +TEST_F(LLVMSqrtTest, NegativeInfinity) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Sqrt, false, -inf).isNaN()); +} + +TEST_F(LLVMSqrtTest, NegativeInfinity_Const) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Sqrt, true, -inf).isNaN()); +} + +TEST_F(LLVMSqrtTest, NaN) +{ + static const double nan = std::numeric_limits::quiet_NaN(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Sqrt, false, nan).toDouble(), 0); +} + +TEST_F(LLVMSqrtTest, NaN_Const) +{ + static const double nan = std::numeric_limits::quiet_NaN(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Sqrt, true, nan).toDouble(), 0); +} diff --git a/test/llvm/operators/math/subtract_test.cpp b/test/llvm/operators/math/subtract_test.cpp new file mode 100644 index 000000000..aa24dd022 --- /dev/null +++ b/test/llvm/operators/math/subtract_test.cpp @@ -0,0 +1,130 @@ +#include +#include + +#include "llvmtestutils.h" + +class LLVMSubtractTest : public testing::Test +{ + public: + LLVMTestUtils m_utils; +}; + +TEST_F(LLVMSubtractTest, PositiveIntegers) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Sub, false, 50, 25); +} + +TEST_F(LLVMSubtractTest, PositiveIntegers_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Sub, true, 50, 25); +} + +TEST_F(LLVMSubtractTest, NegativeWithPositive) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Sub, false, -500, 25); +} + +TEST_F(LLVMSubtractTest, NegativeWithPositive_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Sub, true, -500, 25); +} + +TEST_F(LLVMSubtractTest, NegativeIntegers) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Sub, false, -500, -25); +} + +TEST_F(LLVMSubtractTest, NegativeIntegers_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Sub, true, -500, -25); +} + +TEST_F(LLVMSubtractTest, StringDecimals) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Sub, false, "2.54", "6.28"); +} + +TEST_F(LLVMSubtractTest, StringDecimals_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Sub, true, "2.54", "6.28"); +} + +TEST_F(LLVMSubtractTest, MixedDecimalAndString) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Sub, false, 2.54, "-6.28"); +} + +TEST_F(LLVMSubtractTest, MixedDecimalAndString_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Sub, true, 2.54, "-6.28"); +} + +TEST_F(LLVMSubtractTest, BooleanValues) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Sub, false, true, true); +} + +TEST_F(LLVMSubtractTest, BooleanValues_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Sub, true, true, true); +} + +TEST_F(LLVMSubtractTest, InfinityMinusInfinity) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Sub, false, "Infinity", "Infinity"); +} + +TEST_F(LLVMSubtractTest, InfinityMinusInfinity_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Sub, true, "Infinity", "Infinity"); +} + +TEST_F(LLVMSubtractTest, InfinityMinusNegativeInfinity) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Sub, false, "Infinity", "-Infinity"); +} + +TEST_F(LLVMSubtractTest, InfinityMinusNegativeInfinity_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Sub, true, "Infinity", "-Infinity"); +} + +TEST_F(LLVMSubtractTest, NegativeInfinityMinusInfinity) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Sub, false, "-Infinity", "Infinity"); +} + +TEST_F(LLVMSubtractTest, NegativeInfinityMinusInfinity_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Sub, true, "-Infinity", "Infinity"); +} + +TEST_F(LLVMSubtractTest, NegativeInfinityMinusNegativeInfinity) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Sub, false, "-Infinity", "-Infinity"); +} + +TEST_F(LLVMSubtractTest, NegativeInfinityMinusNegativeInfinity_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Sub, true, "-Infinity", "-Infinity"); +} + +TEST_F(LLVMSubtractTest, NumberMinusNaN) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Sub, false, 1, "NaN"); +} + +TEST_F(LLVMSubtractTest, NumberMinusNaN_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Sub, true, 1, "NaN"); +} + +TEST_F(LLVMSubtractTest, NaNMinusNumber) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Sub, false, "NaN", 1); +} + +TEST_F(LLVMSubtractTest, NaNMinusNumber_Const) +{ + ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Sub, true, "NaN", 1); +} diff --git a/test/llvm/operators/math/tan_test.cpp b/test/llvm/operators/math/tan_test.cpp new file mode 100644 index 000000000..c0f7f59f5 --- /dev/null +++ b/test/llvm/operators/math/tan_test.cpp @@ -0,0 +1,188 @@ +#include +#include + +#include "llvmtestutils.h" + +class LLVMTanTest : public testing::Test +{ + public: + LLVMTestUtils m_utils; +}; + +TEST_F(LLVMTanTest, FortyFiveDegrees) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Tan, false, 45.0).toDouble(), 1.0); +} + +TEST_F(LLVMTanTest, FortyFiveDegrees_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Tan, true, 45.0).toDouble(), 1.0); +} + +TEST_F(LLVMTanTest, NinetyDegrees) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Tan, false, 90.0).toDouble(), inf); +} + +TEST_F(LLVMTanTest, NinetyDegrees_Const) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Tan, true, 90.0).toDouble(), inf); +} + +TEST_F(LLVMTanTest, TwoSeventyDegrees) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Tan, false, 270.0).toDouble(), -inf); +} + +TEST_F(LLVMTanTest, TwoSeventyDegrees_Const) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Tan, true, 270.0).toDouble(), -inf); +} + +TEST_F(LLVMTanTest, FourFiftyDegrees) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Tan, false, 450.0).toDouble(), inf); +} + +TEST_F(LLVMTanTest, FourFiftyDegrees_Const) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Tan, true, 450.0).toDouble(), inf); +} + +TEST_F(LLVMTanTest, NegativeNinetyDegrees) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Tan, false, -90.0).toDouble(), -inf); +} + +TEST_F(LLVMTanTest, NegativeNinetyDegrees_Const) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Tan, true, -90.0).toDouble(), -inf); +} + +TEST_F(LLVMTanTest, NegativeTwoSeventyDegrees) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Tan, false, -270.0).toDouble(), inf); +} + +TEST_F(LLVMTanTest, NegativeTwoSeventyDegrees_Const) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Tan, true, -270.0).toDouble(), inf); +} + +TEST_F(LLVMTanTest, NegativeFourFiftyDegrees) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Tan, false, -450.0).toDouble(), -inf); +} + +TEST_F(LLVMTanTest, NegativeFourFiftyDegrees_Const) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Tan, true, -450.0).toDouble(), -inf); +} + +TEST_F(LLVMTanTest, OneEightyDegrees) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Tan, false, 180.0).toDouble(), 0.0); +} + +TEST_F(LLVMTanTest, OneEightyDegrees_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Tan, true, 180.0).toDouble(), 0.0); +} + +TEST_F(LLVMTanTest, NegativeOneEightyDegrees) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Tan, false, -180.0).toDouble(), 0.0); +} + +TEST_F(LLVMTanTest, NegativeOneEightyDegrees_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Tan, true, -180.0).toDouble(), 0.0); +} + +TEST_F(LLVMTanTest, VerySmallAngle) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Tan, false, 2.87e-9).toDouble(), 1e-10); +} + +TEST_F(LLVMTanTest, VerySmallAngle_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Tan, true, 2.87e-9).toDouble(), 1e-10); +} + +TEST_F(LLVMTanTest, EvenSmallerAngle) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Tan, false, 2.8647e-9).toDouble(), 0.0); +} + +TEST_F(LLVMTanTest, EvenSmallerAngle_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Tan, true, 2.8647e-9).toDouble(), 0.0); +} + +TEST_F(LLVMTanTest, PositiveZero) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Tan, false, 0.0).toDouble(), 0.0); +} + +TEST_F(LLVMTanTest, PositiveZero_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Tan, true, 0.0).toDouble(), 0.0); +} + +TEST_F(LLVMTanTest, NegativeZero) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Tan, false, -0.0).toDouble(), 0.0); +} + +TEST_F(LLVMTanTest, NegativeZero_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Tan, true, -0.0).toDouble(), 0.0); +} + +TEST_F(LLVMTanTest, PositiveInfinity) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Tan, false, inf).isNaN()); +} + +TEST_F(LLVMTanTest, PositiveInfinity_Const) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Tan, true, inf).isNaN()); +} + +TEST_F(LLVMTanTest, NegativeInfinity) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Tan, false, -inf).isNaN()); +} + +TEST_F(LLVMTanTest, NegativeInfinity_Const) +{ + static const double inf = std::numeric_limits::infinity(); + ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Tan, true, -inf).isNaN()); +} + +TEST_F(LLVMTanTest, NaN) +{ + static const double nan = std::numeric_limits::quiet_NaN(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Tan, false, nan).toDouble(), 0.0); +} + +TEST_F(LLVMTanTest, NaN_Const) +{ + static const double nan = std::numeric_limits::quiet_NaN(); + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Tan, true, nan).toDouble(), 0.0); +} diff --git a/test/llvm/operators/string/string_char_test.cpp b/test/llvm/operators/string/string_char_test.cpp new file mode 100644 index 000000000..c8755a67c --- /dev/null +++ b/test/llvm/operators/string/string_char_test.cpp @@ -0,0 +1,80 @@ +#include +#include + +#include "llvmtestutils.h" + +class LLVMStringCharTest : public testing::Test +{ + public: + LLVMTestUtils m_utils; +}; + +TEST_F(LLVMStringCharTest, HelloWorldSecondChar) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::StringChar, false, "Hello world", 1).toString(), "e"); +} + +TEST_F(LLVMStringCharTest, HelloWorldSecondChar_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::StringChar, true, "Hello world", 1).toString(), "e"); +} + +TEST_F(LLVMStringCharTest, HelloWorldZeroIndex) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::StringChar, false, "Hello world", 0).toString(), "H"); +} + +TEST_F(LLVMStringCharTest, HelloWorldZeroIndex_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::StringChar, true, "Hello world", 0).toString(), "H"); +} + +TEST_F(LLVMStringCharTest, HelloWorldOutOfRange) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::StringChar, false, "Hello world", 11).toString(), ""); +} + +TEST_F(LLVMStringCharTest, HelloWorldOutOfRange_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::StringChar, true, "Hello world", 11).toString(), ""); +} + +TEST_F(LLVMStringCharTest, AbcThirdChar) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::StringChar, false, "abc", 2).toString(), "c"); +} + +TEST_F(LLVMStringCharTest, AbcThirdChar_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::StringChar, true, "abc", 2).toString(), "c"); +} + +TEST_F(LLVMStringCharTest, AbcNegativeIndex) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::StringChar, false, "abc", -1).toString(), ""); +} + +TEST_F(LLVMStringCharTest, AbcNegativeIndex_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::StringChar, true, "abc", -1).toString(), ""); +} + +TEST_F(LLVMStringCharTest, AbcOutOfRange) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::StringChar, false, "abc", 3).toString(), ""); +} + +TEST_F(LLVMStringCharTest, AbcOutOfRange_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::StringChar, true, "abc", 3).toString(), ""); +} + +TEST_F(LLVMStringCharTest, UnicodeString) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::StringChar, false, "ábč", 0).toString(), "á"); +} + +TEST_F(LLVMStringCharTest, UnicodeString_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::StringChar, true, "ábč", 0).toString(), "á"); +} diff --git a/test/llvm/operators/string/string_concat_test.cpp b/test/llvm/operators/string/string_concat_test.cpp new file mode 100644 index 000000000..9492b1919 --- /dev/null +++ b/test/llvm/operators/string/string_concat_test.cpp @@ -0,0 +1,40 @@ +#include +#include + +#include "llvmtestutils.h" + +class LLVMStringConcatTest : public testing::Test +{ + public: + LLVMTestUtils m_utils; +}; + +TEST_F(LLVMStringConcatTest, HelloWorld) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::StringConcat, false, "Hello ", "world").toString(), "Hello world"); +} + +TEST_F(LLVMStringConcatTest, HelloWorld_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::StringConcat, true, "Hello ", "world").toString(), "Hello world"); +} + +TEST_F(LLVMStringConcatTest, AbcDef) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::StringConcat, false, "abc", "def").toString(), "abcdef"); +} + +TEST_F(LLVMStringConcatTest, AbcDef_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::StringConcat, true, "abc", "def").toString(), "abcdef"); +} + +TEST_F(LLVMStringConcatTest, UnicodeStrings) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::StringConcat, false, "ábč", "ďéfgh").toString(), "ábčďéfgh"); +} + +TEST_F(LLVMStringConcatTest, UnicodeStrings_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::StringConcat, true, "ábč", "ďéfgh").toString(), "ábčďéfgh"); +} diff --git a/test/llvm/operators/string/string_equal_case_insensitive_test.cpp b/test/llvm/operators/string/string_equal_case_insensitive_test.cpp new file mode 100644 index 000000000..3ef1b33a7 --- /dev/null +++ b/test/llvm/operators/string/string_equal_case_insensitive_test.cpp @@ -0,0 +1,1210 @@ +#include +#include + +#include "llvmtestutils.h" + +class LLVMStringEqualCaseInsensitiveTest : public testing::Test +{ + public: + LLVMTestUtils m_utils; +}; + +TEST_F(LLVMStringEqualCaseInsensitiveTest, SameIntegers) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, 10, 10); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, SameIntegers_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, 10, 10); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, DifferentIntegers) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, 10, 8); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, DifferentIntegers_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, 10, 8); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, DifferentIntegersReversed) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, 8, 10); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, DifferentIntegersReversed_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, 8, 10); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, SameDecimals) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, -4.25, -4.25); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, SameDecimals_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, -4.25, -4.25); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, DifferentDecimals) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, -4.25, 5.312); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, DifferentDecimals_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, -4.25, 5.312); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, DifferentDecimalsReversed) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, 5.312, -4.25); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, DifferentDecimalsReversed_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, 5.312, -4.25); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, SameBooleans) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, true, true); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, SameBooleans_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, true, true); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, DifferentBooleans) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, true, false); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, DifferentBooleans_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, true, false); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, DifferentBooleansReversed) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, false, true); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, DifferentBooleansReversed_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, false, true); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, NumberWithTrueBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, 1, true); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, NumberWithTrueBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, 1, true); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, NumberWithFalseBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, 1, false); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, NumberWithFalseBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, 1, false); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, SameStrings) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "abC def", "abC def"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, SameStrings_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "abC def", "abC def"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, StringsCaseDifferent) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "abC def", "abc dEf"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, StringsCaseDifferent_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "abC def", "abc dEf"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, DifferentStrings) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "abC def", "ghi Jkl"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, DifferentStrings_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "abC def", "ghi Jkl"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, DifferentStringsLonger) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "abC def", "hello world"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, DifferentStringsLonger_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "abC def", "hello world"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, SpaceVsEmpty) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, " ", ""); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, SpaceVsEmpty_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, " ", ""); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, SpaceVsZeroString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, " ", "0"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, SpaceVsZeroString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, " ", "0"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, SpaceVsZeroNumber) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, " ", 0); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, SpaceVsZeroNumber_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, " ", 0); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, ZeroNumberVsSpace) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, 0, " "); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, ZeroNumberVsSpace_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, 0, " "); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, EmptyVsZeroString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "", "0"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, EmptyVsZeroString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "", "0"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, EmptyVsZeroNumber) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "", 0); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, EmptyVsZeroNumber_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "", 0); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, ZeroNumberVsEmpty) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, 0, ""); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, ZeroNumberVsEmpty_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, 0, ""); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, ZeroStringVsZeroNumber) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "0", 0); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, ZeroStringVsZeroNumber_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "0", 0); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, ZeroNumberVsZeroString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, 0, "0"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, ZeroNumberVsZeroString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, 0, "0"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, NumberVsExactString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, 5.25, "5.25"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, NumberVsExactString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, 5.25, "5.25"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, ExactStringVsNumber) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "5.25", 5.25); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, ExactStringVsNumber_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "5.25", 5.25); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, NumberVsStringWithLeadingSpace) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, 5.25, " 5.25"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, NumberVsStringWithLeadingSpace_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, 5.25, " 5.25"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, StringWithLeadingSpaceVsNumber) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, " 5.25", 5.25); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, StringWithLeadingSpaceVsNumber_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, " 5.25", 5.25); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, NumberVsStringWithTrailingSpace) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, 5.25, "5.25 "); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, NumberVsStringWithTrailingSpace_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, 5.25, "5.25 "); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, StringWithTrailingSpaceVsNumber) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "5.25 ", 5.25); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, StringWithTrailingSpaceVsNumber_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "5.25 ", 5.25); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, NumberVsStringWithSurroundingSpaces) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, 5.25, " 5.25 "); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, NumberVsStringWithSurroundingSpaces_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, 5.25, " 5.25 "); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, StringWithSurroundingSpacesVsNumber) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, " 5.25 ", 5.25); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, StringWithSurroundingSpacesVsNumber_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, " 5.25 ", 5.25); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, NumberVsDifferentString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, 5.25, "5.26"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, NumberVsDifferentString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, 5.25, "5.26"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, DifferentStringVsNumber) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "5.26", 5.25); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, DifferentStringVsNumber_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "5.26", 5.25); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, DifferentStringNumbers) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "5.25", "5.26"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, DifferentStringNumbers_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "5.25", "5.26"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, NumberVsStringWithTrailingSpaces) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, 5, "5 "); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, NumberVsStringWithTrailingSpaces_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, 5, "5 "); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, StringWithTrailingSpacesVsNumber) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "5 ", 5); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, StringWithTrailingSpacesVsNumber_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "5 ", 5); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, ZeroVsOneString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, 0, "1"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, ZeroVsOneString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, 0, "1"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, OneStringVsZero) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "1", 0); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, OneStringVsZero_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "1", 0); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, ZeroVsTestString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, 0, "test"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, ZeroVsTestString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, 0, "test"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, TestStringVsZero) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "test", 0); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, TestStringVsZero_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "test", 0); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, InfinityWithInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "Infinity", "Infinity"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, InfinityWithInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "Infinity", "Infinity"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, NegativeInfinityWithNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "-Infinity", "-Infinity"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, NegativeInfinityWithNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "-Infinity", "-Infinity"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, NaNWithNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "NaN", "NaN"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, NaNWithNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "NaN", "NaN"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, InfinityWithNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "Infinity", "-Infinity"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, InfinityWithNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "Infinity", "-Infinity"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, NegativeInfinityWithInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "-Infinity", "Infinity"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, NegativeInfinityWithInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "-Infinity", "Infinity"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, InfinityWithNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "Infinity", "NaN"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, InfinityWithNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "Infinity", "NaN"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, NaNWithInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "NaN", "Infinity"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, NaNWithInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "NaN", "Infinity"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, NegativeInfinityWithNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "-Infinity", "NaN"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, NegativeInfinityWithNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "-Infinity", "NaN"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, NaNWithNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "NaN", "-Infinity"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, NaNWithNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "NaN", "-Infinity"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, NumberWithInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, 5, "Infinity"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, NumberWithInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, 5, "Infinity"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, NumberWithNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, 5, "-Infinity"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, NumberWithNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, 5, "-Infinity"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, NumberWithNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, 5, "NaN"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, NumberWithNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, 5, "NaN"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, ZeroWithNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, 0, "NaN"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, ZeroWithNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, 0, "NaN"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, TrueBooleanWithTrueString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, true, "true"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, TrueBooleanWithTrueString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, true, "true"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, TrueStringWithTrueBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "true", true); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, TrueStringWithTrueBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "true", true); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, FalseBooleanWithFalseString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, false, "false"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, FalseBooleanWithFalseString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, false, "false"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, FalseStringWithFalseBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "false", false); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, FalseStringWithFalseBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "false", false); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, FalseBooleanWithTrueString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, false, "true"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, FalseBooleanWithTrueString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, false, "true"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, TrueStringWithFalseBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "true", false); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, TrueStringWithFalseBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "true", false); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, TrueBooleanWithFalseString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, true, "false"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, TrueBooleanWithFalseString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, true, "false"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, FalseStringWithTrueBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "false", true); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, FalseStringWithTrueBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "false", true); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, TrueBooleanWithUppercaseTrueString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, true, "TRUE"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, TrueBooleanWithUppercaseTrueString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, true, "TRUE"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, UppercaseTrueStringWithTrueBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "TRUE", true); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, UppercaseTrueStringWithTrueBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "TRUE", true); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, FalseBooleanWithUppercaseFalseString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, false, "FALSE"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, FalseBooleanWithUppercaseFalseString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, false, "FALSE"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, UppercaseFalseStringWithFalseBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "FALSE", false); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, UppercaseFalseStringWithFalseBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "FALSE", false); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, TrueBooleanWithZeroPaddedOne) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, true, "00001"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, TrueBooleanWithZeroPaddedOne_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, true, "00001"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, ZeroPaddedOneWithTrueBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "00001", true); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, ZeroPaddedOneWithTrueBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "00001", true); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, TrueBooleanWithZeroPaddedZero) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, true, "00000"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, TrueBooleanWithZeroPaddedZero_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, true, "00000"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, ZeroPaddedZeroWithTrueBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "00000", true); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, ZeroPaddedZeroWithTrueBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "00000", true); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, FalseBooleanWithZeroPaddedZero) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, false, "00000"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, FalseBooleanWithZeroPaddedZero_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, false, "00000"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, ZeroPaddedZeroWithFalseBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "00000", false); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, ZeroPaddedZeroWithFalseBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "00000", false); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, TrueStringWithOne) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "true", 1); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, TrueStringWithOne_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "true", 1); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, OneWithTrueString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, 1, "true"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, OneWithTrueString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, 1, "true"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, TrueStringWithZero) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "true", 0); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, TrueStringWithZero_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "true", 0); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, ZeroWithTrueString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, 0, "true"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, ZeroWithTrueString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, 0, "true"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, FalseStringWithZero) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "false", 0); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, FalseStringWithZero_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "false", 0); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, ZeroWithFalseString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, 0, "false"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, ZeroWithFalseString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, 0, "false"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, FalseStringWithOne) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "false", 1); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, FalseStringWithOne_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "false", 1); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, OneWithFalseString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, 1, "false"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, OneWithFalseString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, 1, "false"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, TrueStringWithUppercaseTrueString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "true", "TRUE"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, TrueStringWithUppercaseTrueString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "true", "TRUE"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, TrueStringWithUppercaseFalseString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "true", "FALSE"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, TrueStringWithUppercaseFalseString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "true", "FALSE"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, FalseStringWithUppercaseFalseString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "false", "FALSE"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, FalseStringWithUppercaseFalseString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "false", "FALSE"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, FalseStringWithUppercaseTrueString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "false", "TRUE"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, FalseStringWithUppercaseTrueString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "false", "TRUE"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, TrueBooleanWithInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, true, "Infinity"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, TrueBooleanWithInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, true, "Infinity"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, TrueBooleanWithNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, true, "-Infinity"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, TrueBooleanWithNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, true, "-Infinity"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, TrueBooleanWithNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, true, "NaN"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, TrueBooleanWithNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, true, "NaN"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, FalseBooleanWithInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, false, "Infinity"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, FalseBooleanWithInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, false, "Infinity"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, FalseBooleanWithNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, false, "-Infinity"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, FalseBooleanWithNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, false, "-Infinity"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, FalseBooleanWithNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, false, "NaN"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, FalseBooleanWithNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, false, "NaN"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, InfinityStringWithInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "Infinity", "Infinity"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, InfinityStringWithInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "Infinity", "Infinity"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, InfinityStringWithNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "Infinity", "-Infinity"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, InfinityStringWithNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "Infinity", "-Infinity"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, InfinityStringWithNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "Infinity", "NaN"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, InfinityStringWithNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "Infinity", "NaN"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, LowercaseInfinityStringWithInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "infinity", "Infinity"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, LowercaseInfinityStringWithInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "infinity", "Infinity"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, LowercaseInfinityStringWithNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "infinity", "-Infinity"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, LowercaseInfinityStringWithNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "infinity", "-Infinity"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, LowercaseInfinityStringWithNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "infinity", "NaN"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, LowercaseInfinityStringWithNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "infinity", "NaN"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, NegativeInfinityStringWithInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "-Infinity", "Infinity"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, NegativeInfinityStringWithInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "-Infinity", "Infinity"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, NegativeInfinityStringWithNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "-Infinity", "-Infinity"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, NegativeInfinityStringWithNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "-Infinity", "-Infinity"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, NegativeInfinityStringWithNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "-Infinity", "NaN"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, NegativeInfinityStringWithNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "-Infinity", "NaN"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, LowercaseNegativeInfinityStringWithInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "-infinity", "Infinity"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, LowercaseNegativeInfinityStringWithInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "-infinity", "Infinity"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, LowercaseNegativeInfinityStringWithNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "-infinity", "-Infinity"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, LowercaseNegativeInfinityStringWithNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "-infinity", "-Infinity"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, LowercaseNegativeInfinityStringWithNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "-infinity", "NaN"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, LowercaseNegativeInfinityStringWithNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "-infinity", "NaN"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, NaNStringWithInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "NaN", "Infinity"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, NaNStringWithInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "NaN", "Infinity"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, NaNStringWithNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "NaN", "-Infinity"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, NaNStringWithNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "NaN", "-Infinity"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, NaNStringWithNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "NaN", "NaN"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, NaNStringWithNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "NaN", "NaN"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, LowercaseNaNStringWithInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "nan", "Infinity"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, LowercaseNaNStringWithInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "nan", "Infinity"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, LowercaseNaNStringWithNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "nan", "-Infinity"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, LowercaseNaNStringWithNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "nan", "-Infinity"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, LowercaseNaNStringWithNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "nan", "NaN"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, LowercaseNaNStringWithNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "nan", "NaN"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, InfinityWithStringAbc) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "Infinity", "abc"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, InfinityWithStringAbc_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "Infinity", "abc"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, InfinityWithStringSpace) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "Infinity", " "); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, InfinityWithStringSpace_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "Infinity", " "); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, InfinityWithEmptyString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "Infinity", ""); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, InfinityWithEmptyString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "Infinity", ""); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, InfinityWithZeroString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "Infinity", "0"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, InfinityWithZeroString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "Infinity", "0"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, NegativeInfinityWithStringAbc) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "-Infinity", "abc"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, NegativeInfinityWithStringAbc_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "-Infinity", "abc"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, NegativeInfinityWithStringSpace) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "-Infinity", " "); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, NegativeInfinityWithStringSpace_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "-Infinity", " "); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, NegativeInfinityWithEmptyString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "-Infinity", ""); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, NegativeInfinityWithEmptyString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "-Infinity", ""); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, NegativeInfinityWithZeroString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "-Infinity", "0"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, NegativeInfinityWithZeroString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "-Infinity", "0"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, NaNWithStringAbc) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "NaN", "abc"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, NaNWithStringAbc_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "NaN", "abc"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, NaNWithStringSpace) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "NaN", " "); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, NaNWithStringSpace_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "NaN", " "); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, NaNWithEmptyString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "NaN", ""); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, NaNWithEmptyString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "NaN", ""); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, NaNWithZeroString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "NaN", "0"); +} + +TEST_F(LLVMStringEqualCaseInsensitiveTest, NaNWithZeroString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "NaN", "0"); +} diff --git a/test/llvm/operators/string/string_equal_case_sensitive_test.cpp b/test/llvm/operators/string/string_equal_case_sensitive_test.cpp new file mode 100644 index 000000000..fc8ae7db4 --- /dev/null +++ b/test/llvm/operators/string/string_equal_case_sensitive_test.cpp @@ -0,0 +1,1210 @@ +#include +#include + +#include "llvmtestutils.h" + +class LLVMStringEqualCaseSensitiveTest : public testing::Test +{ + public: + LLVMTestUtils m_utils; +}; + +TEST_F(LLVMStringEqualCaseSensitiveTest, SameIntegers) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, 10, 10); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, SameIntegers_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, 10, 10); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, DifferentIntegers) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, 10, 8); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, DifferentIntegers_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, 10, 8); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, DifferentIntegersReversed) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, 8, 10); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, DifferentIntegersReversed_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, 8, 10); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, SameDecimals) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, -4.25, -4.25); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, SameDecimals_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, -4.25, -4.25); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, DifferentDecimals) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, -4.25, 5.312); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, DifferentDecimals_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, -4.25, 5.312); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, DifferentDecimalsReversed) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, 5.312, -4.25); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, DifferentDecimalsReversed_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, 5.312, -4.25); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, SameBooleans) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, true, true); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, SameBooleans_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, true, true); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, DifferentBooleans) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, true, false); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, DifferentBooleans_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, true, false); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, DifferentBooleansReversed) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, false, true); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, DifferentBooleansReversed_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, false, true); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, NumberWithTrueBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, 1, true); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, NumberWithTrueBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, 1, true); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, NumberWithFalseBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, 1, false); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, NumberWithFalseBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, 1, false); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, SameStrings) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "abC def", "abC def"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, SameStrings_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "abC def", "abC def"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, StringsCaseDifferent) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "abC def", "abc dEf"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, StringsCaseDifferent_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "abC def", "abc dEf"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, DifferentStrings) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "abC def", "ghi Jkl"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, DifferentStrings_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "abC def", "ghi Jkl"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, DifferentStringsLonger) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "abC def", "hello world"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, DifferentStringsLonger_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "abC def", "hello world"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, SpaceVsEmpty) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, " ", ""); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, SpaceVsEmpty_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, " ", ""); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, SpaceVsZeroString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, " ", "0"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, SpaceVsZeroString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, " ", "0"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, SpaceVsZeroNumber) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, " ", 0); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, SpaceVsZeroNumber_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, " ", 0); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, ZeroNumberVsSpace) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, 0, " "); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, ZeroNumberVsSpace_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, 0, " "); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, EmptyVsZeroString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "", "0"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, EmptyVsZeroString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "", "0"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, EmptyVsZeroNumber) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "", 0); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, EmptyVsZeroNumber_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "", 0); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, ZeroNumberVsEmpty) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, 0, ""); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, ZeroNumberVsEmpty_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, 0, ""); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, ZeroStringVsZeroNumber) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "0", 0); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, ZeroStringVsZeroNumber_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "0", 0); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, ZeroNumberVsZeroString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, 0, "0"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, ZeroNumberVsZeroString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, 0, "0"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, NumberVsExactString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, 5.25, "5.25"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, NumberVsExactString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, 5.25, "5.25"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, ExactStringVsNumber) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "5.25", 5.25); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, ExactStringVsNumber_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "5.25", 5.25); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, NumberVsStringWithLeadingSpace) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, 5.25, " 5.25"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, NumberVsStringWithLeadingSpace_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, 5.25, " 5.25"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, StringWithLeadingSpaceVsNumber) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, " 5.25", 5.25); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, StringWithLeadingSpaceVsNumber_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, " 5.25", 5.25); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, NumberVsStringWithTrailingSpace) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, 5.25, "5.25 "); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, NumberVsStringWithTrailingSpace_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, 5.25, "5.25 "); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, StringWithTrailingSpaceVsNumber) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "5.25 ", 5.25); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, StringWithTrailingSpaceVsNumber_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "5.25 ", 5.25); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, NumberVsStringWithSurroundingSpaces) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, 5.25, " 5.25 "); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, NumberVsStringWithSurroundingSpaces_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, 5.25, " 5.25 "); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, StringWithSurroundingSpacesVsNumber) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, " 5.25 ", 5.25); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, StringWithSurroundingSpacesVsNumber_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, " 5.25 ", 5.25); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, NumberVsDifferentString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, 5.25, "5.26"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, NumberVsDifferentString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, 5.25, "5.26"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, DifferentStringVsNumber) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "5.26", 5.25); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, DifferentStringVsNumber_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "5.26", 5.25); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, DifferentStringNumbers) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "5.25", "5.26"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, DifferentStringNumbers_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "5.25", "5.26"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, NumberVsStringWithTrailingSpaces) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, 5, "5 "); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, NumberVsStringWithTrailingSpaces_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, 5, "5 "); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, StringWithTrailingSpacesVsNumber) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "5 ", 5); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, StringWithTrailingSpacesVsNumber_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "5 ", 5); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, ZeroVsOneString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, 0, "1"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, ZeroVsOneString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, 0, "1"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, OneStringVsZero) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "1", 0); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, OneStringVsZero_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "1", 0); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, ZeroVsTestString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, 0, "test"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, ZeroVsTestString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, 0, "test"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, TestStringVsZero) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "test", 0); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, TestStringVsZero_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "test", 0); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, InfinityWithInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "Infinity", "Infinity"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, InfinityWithInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "Infinity", "Infinity"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, NegativeInfinityWithNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "-Infinity", "-Infinity"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, NegativeInfinityWithNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "-Infinity", "-Infinity"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, NaNWithNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "NaN", "NaN"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, NaNWithNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "NaN", "NaN"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, InfinityWithNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "Infinity", "-Infinity"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, InfinityWithNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "Infinity", "-Infinity"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, NegativeInfinityWithInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "-Infinity", "Infinity"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, NegativeInfinityWithInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "-Infinity", "Infinity"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, InfinityWithNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "Infinity", "NaN"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, InfinityWithNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "Infinity", "NaN"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, NaNWithInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "NaN", "Infinity"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, NaNWithInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "NaN", "Infinity"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, NegativeInfinityWithNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "-Infinity", "NaN"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, NegativeInfinityWithNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "-Infinity", "NaN"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, NaNWithNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "NaN", "-Infinity"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, NaNWithNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "NaN", "-Infinity"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, NumberWithInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, 5, "Infinity"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, NumberWithInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, 5, "Infinity"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, NumberWithNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, 5, "-Infinity"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, NumberWithNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, 5, "-Infinity"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, NumberWithNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, 5, "NaN"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, NumberWithNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, 5, "NaN"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, ZeroWithNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, 0, "NaN"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, ZeroWithNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, 0, "NaN"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, TrueBooleanWithTrueString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, true, "true"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, TrueBooleanWithTrueString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, true, "true"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, TrueStringWithTrueBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "true", true); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, TrueStringWithTrueBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "true", true); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, FalseBooleanWithFalseString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, false, "false"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, FalseBooleanWithFalseString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, false, "false"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, FalseStringWithFalseBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "false", false); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, FalseStringWithFalseBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "false", false); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, FalseBooleanWithTrueString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, false, "true"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, FalseBooleanWithTrueString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, false, "true"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, TrueStringWithFalseBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "true", false); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, TrueStringWithFalseBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "true", false); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, TrueBooleanWithFalseString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, true, "false"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, TrueBooleanWithFalseString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, true, "false"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, FalseStringWithTrueBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "false", true); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, FalseStringWithTrueBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "false", true); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, TrueBooleanWithUppercaseTrueString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, true, "TRUE"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, TrueBooleanWithUppercaseTrueString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, true, "TRUE"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, UppercaseTrueStringWithTrueBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "TRUE", true); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, UppercaseTrueStringWithTrueBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "TRUE", true); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, FalseBooleanWithUppercaseFalseString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, false, "FALSE"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, FalseBooleanWithUppercaseFalseString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, false, "FALSE"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, UppercaseFalseStringWithFalseBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "FALSE", false); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, UppercaseFalseStringWithFalseBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "FALSE", false); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, TrueBooleanWithZeroPaddedOne) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, true, "00001"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, TrueBooleanWithZeroPaddedOne_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, true, "00001"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, ZeroPaddedOneWithTrueBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "00001", true); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, ZeroPaddedOneWithTrueBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "00001", true); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, TrueBooleanWithZeroPaddedZero) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, true, "00000"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, TrueBooleanWithZeroPaddedZero_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, true, "00000"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, ZeroPaddedZeroWithTrueBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "00000", true); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, ZeroPaddedZeroWithTrueBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "00000", true); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, FalseBooleanWithZeroPaddedZero) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, false, "00000"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, FalseBooleanWithZeroPaddedZero_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, false, "00000"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, ZeroPaddedZeroWithFalseBoolean) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "00000", false); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, ZeroPaddedZeroWithFalseBoolean_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "00000", false); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, TrueStringWithOne) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "true", 1); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, TrueStringWithOne_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "true", 1); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, OneWithTrueString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, 1, "true"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, OneWithTrueString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, 1, "true"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, TrueStringWithZero) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "true", 0); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, TrueStringWithZero_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "true", 0); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, ZeroWithTrueString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, 0, "true"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, ZeroWithTrueString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, 0, "true"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, FalseStringWithZero) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "false", 0); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, FalseStringWithZero_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "false", 0); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, ZeroWithFalseString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, 0, "false"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, ZeroWithFalseString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, 0, "false"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, FalseStringWithOne) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "false", 1); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, FalseStringWithOne_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "false", 1); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, OneWithFalseString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, 1, "false"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, OneWithFalseString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, 1, "false"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, TrueStringWithUppercaseTrueString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "true", "TRUE"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, TrueStringWithUppercaseTrueString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "true", "TRUE"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, TrueStringWithUppercaseFalseString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "true", "FALSE"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, TrueStringWithUppercaseFalseString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "true", "FALSE"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, FalseStringWithUppercaseFalseString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "false", "FALSE"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, FalseStringWithUppercaseFalseString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "false", "FALSE"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, FalseStringWithUppercaseTrueString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "false", "TRUE"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, FalseStringWithUppercaseTrueString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "false", "TRUE"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, TrueBooleanWithInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, true, "Infinity"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, TrueBooleanWithInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, true, "Infinity"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, TrueBooleanWithNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, true, "-Infinity"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, TrueBooleanWithNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, true, "-Infinity"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, TrueBooleanWithNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, true, "NaN"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, TrueBooleanWithNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, true, "NaN"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, FalseBooleanWithInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, false, "Infinity"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, FalseBooleanWithInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, false, "Infinity"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, FalseBooleanWithNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, false, "-Infinity"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, FalseBooleanWithNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, false, "-Infinity"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, FalseBooleanWithNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, false, "NaN"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, FalseBooleanWithNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, false, "NaN"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, InfinityStringWithInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "Infinity", "Infinity"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, InfinityStringWithInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "Infinity", "Infinity"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, InfinityStringWithNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "Infinity", "-Infinity"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, InfinityStringWithNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "Infinity", "-Infinity"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, InfinityStringWithNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "Infinity", "NaN"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, InfinityStringWithNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "Infinity", "NaN"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, LowercaseInfinityStringWithInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "infinity", "Infinity"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, LowercaseInfinityStringWithInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "infinity", "Infinity"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, LowercaseInfinityStringWithNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "infinity", "-Infinity"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, LowercaseInfinityStringWithNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "infinity", "-Infinity"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, LowercaseInfinityStringWithNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "infinity", "NaN"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, LowercaseInfinityStringWithNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "infinity", "NaN"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, NegativeInfinityStringWithInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "-Infinity", "Infinity"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, NegativeInfinityStringWithInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "-Infinity", "Infinity"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, NegativeInfinityStringWithNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "-Infinity", "-Infinity"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, NegativeInfinityStringWithNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "-Infinity", "-Infinity"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, NegativeInfinityStringWithNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "-Infinity", "NaN"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, NegativeInfinityStringWithNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "-Infinity", "NaN"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, LowercaseNegativeInfinityStringWithInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "-infinity", "Infinity"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, LowercaseNegativeInfinityStringWithInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "-infinity", "Infinity"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, LowercaseNegativeInfinityStringWithNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "-infinity", "-Infinity"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, LowercaseNegativeInfinityStringWithNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "-infinity", "-Infinity"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, LowercaseNegativeInfinityStringWithNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "-infinity", "NaN"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, LowercaseNegativeInfinityStringWithNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "-infinity", "NaN"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, NaNStringWithInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "NaN", "Infinity"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, NaNStringWithInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "NaN", "Infinity"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, NaNStringWithNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "NaN", "-Infinity"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, NaNStringWithNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "NaN", "-Infinity"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, NaNStringWithNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "NaN", "NaN"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, NaNStringWithNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "NaN", "NaN"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, LowercaseNaNStringWithInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "nan", "Infinity"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, LowercaseNaNStringWithInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "nan", "Infinity"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, LowercaseNaNStringWithNegativeInfinity) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "nan", "-Infinity"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, LowercaseNaNStringWithNegativeInfinity_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "nan", "-Infinity"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, LowercaseNaNStringWithNaN) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "nan", "NaN"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, LowercaseNaNStringWithNaN_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "nan", "NaN"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, InfinityWithStringAbc) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "Infinity", "abc"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, InfinityWithStringAbc_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "Infinity", "abc"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, InfinityWithStringSpace) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "Infinity", " "); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, InfinityWithStringSpace_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "Infinity", " "); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, InfinityWithEmptyString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "Infinity", ""); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, InfinityWithEmptyString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "Infinity", ""); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, InfinityWithZeroString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "Infinity", "0"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, InfinityWithZeroString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "Infinity", "0"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, NegativeInfinityWithStringAbc) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "-Infinity", "abc"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, NegativeInfinityWithStringAbc_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "-Infinity", "abc"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, NegativeInfinityWithStringSpace) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "-Infinity", " "); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, NegativeInfinityWithStringSpace_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "-Infinity", " "); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, NegativeInfinityWithEmptyString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "-Infinity", ""); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, NegativeInfinityWithEmptyString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "-Infinity", ""); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, NegativeInfinityWithZeroString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "-Infinity", "0"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, NegativeInfinityWithZeroString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "-Infinity", "0"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, NaNWithStringAbc) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "NaN", "abc"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, NaNWithStringAbc_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "NaN", "abc"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, NaNWithStringSpace) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "NaN", " "); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, NaNWithStringSpace_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "NaN", " "); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, NaNWithEmptyString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "NaN", ""); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, NaNWithEmptyString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "NaN", ""); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, NaNWithZeroString) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "NaN", "0"); +} + +TEST_F(LLVMStringEqualCaseSensitiveTest, NaNWithZeroString_Const) +{ + ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "NaN", "0"); +} diff --git a/test/llvm/operators/string/string_length_test.cpp b/test/llvm/operators/string/string_length_test.cpp new file mode 100644 index 000000000..f0ce51d53 --- /dev/null +++ b/test/llvm/operators/string/string_length_test.cpp @@ -0,0 +1,50 @@ +#include +#include + +#include "llvmtestutils.h" + +class LLVMStringLengthTest : public testing::Test +{ + public: + LLVMTestUtils m_utils; +}; + +TEST_F(LLVMStringLengthTest, HelloWorld) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::StringLength, false, "Hello world").toDouble(), 11); +} + +TEST_F(LLVMStringLengthTest, HelloWorld_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::StringLength, true, "Hello world").toDouble(), 11); +} + +TEST_F(LLVMStringLengthTest, Abc) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::StringLength, false, "abc").toDouble(), 3); +} + +TEST_F(LLVMStringLengthTest, Abc_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::StringLength, true, "abc").toDouble(), 3); +} + +TEST_F(LLVMStringLengthTest, Abcdef) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::StringLength, false, "abcdef").toDouble(), 6); +} + +TEST_F(LLVMStringLengthTest, Abcdef_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::StringLength, true, "abcdef").toDouble(), 6); +} + +TEST_F(LLVMStringLengthTest, UnicodeString) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::StringLength, false, "ábč").toDouble(), 3); +} + +TEST_F(LLVMStringLengthTest, UnicodeString_Const) +{ + ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::StringLength, true, "ábč").toDouble(), 3); +} From 65e2ed8d9c3a3a9ea846b23fe58954e4023901d2 Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Sun, 3 Aug 2025 17:29:53 +0200 Subject: [PATCH 59/79] LLVMTestUtils: Properly test NaN values --- test/llvm/llvmtestutils.h | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/test/llvm/llvmtestutils.h b/test/llvm/llvmtestutils.h index 8d864fcf4..0f677ed3c 100644 --- a/test/llvm/llvmtestutils.h +++ b/test/llvm/llvmtestutils.h @@ -5,8 +5,17 @@ #include #include -#define ASSERT_NUM_OP1(utils, type, rawArg, v) ASSERT_EQ(utils.getOpResult(type, rawArg, v).toDouble(), m_utils.getExpectedOpResult(type, v).toDouble()); -#define ASSERT_NUM_OP2(utils, type, rawArgs, v1, v2) ASSERT_EQ(utils.getOpResult(type, rawArgs, v1, v2).toDouble(), m_utils.getExpectedOpResult(type, v1, v2).toDouble()); +#define ASSERT_NUM_OP1(utils, type, rawArg, v) \ + Value result = utils.getOpResult(type, rawArg, v); \ + Value expected = utils.getExpectedOpResult(type, v); \ + ASSERT_EQ(result.isNaN(), expected.isNaN()); \ + ASSERT_EQ(result.toDouble(), expected.toDouble()); + +#define ASSERT_NUM_OP2(utils, type, rawArgs, v1, v2) \ + Value result = utils.getOpResult(type, rawArgs, v1, v2); \ + Value expected = utils.getExpectedOpResult(type, v1, v2); \ + ASSERT_EQ(result.isNaN(), expected.isNaN()); \ + ASSERT_EQ(result.toDouble(), expected.toDouble()); #define ASSERT_BOOL_OP1(utils, type, rawArg, v) ASSERT_EQ(utils.getOpResult(type, rawArg, v).toBool(), m_utils.getExpectedOpResult(type, v).toBool()); #define ASSERT_BOOL_OP2(utils, type, rawArgs, v1, v2) ASSERT_EQ(utils.getOpResult(type, rawArgs, v1, v2).toBool(), m_utils.getExpectedOpResult(type, v1, v2).toBool()); From ee32ec43353542774465824587dbd6669fda9712 Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Sun, 3 Aug 2025 20:30:15 +0200 Subject: [PATCH 60/79] Do not pass IRBuilder to LLVMTypes --- src/engine/internal/llvm/llvmcodebuilder.cpp | 4 ++-- src/engine/internal/llvm/llvmtypes.cpp | 10 +++------- src/engine/internal/llvm/llvmtypes.h | 4 ++-- test/llvm/llvmexecutablecode_test.cpp | 2 +- 4 files changed, 8 insertions(+), 12 deletions(-) diff --git a/src/engine/internal/llvm/llvmcodebuilder.cpp b/src/engine/internal/llvm/llvmcodebuilder.cpp index d6e246dbb..739d58068 100644 --- a/src/engine/internal/llvm/llvmcodebuilder.cpp +++ b/src/engine/internal/llvm/llvmcodebuilder.cpp @@ -1851,8 +1851,8 @@ void LLVMCodeBuilder::createProcedureCall(BlockPrototype *prototype, const Compi void LLVMCodeBuilder::initTypes() { llvm::PointerType *pointerType = llvm::PointerType::get(llvm::Type::getInt8Ty(m_llvmCtx), 0); - m_valueDataType = LLVMTypes::createValueDataType(&m_builder); - m_stringPtrType = LLVMTypes::createStringPtrType(&m_builder); + m_valueDataType = LLVMTypes::createValueDataType(m_llvmCtx); + m_stringPtrType = LLVMTypes::createStringPtrType(m_llvmCtx); } void LLVMCodeBuilder::createVariableMap() diff --git a/src/engine/internal/llvm/llvmtypes.cpp b/src/engine/internal/llvm/llvmtypes.cpp index 8c4e1e660..8d46440a1 100644 --- a/src/engine/internal/llvm/llvmtypes.cpp +++ b/src/engine/internal/llvm/llvmtypes.cpp @@ -6,12 +6,10 @@ using namespace libscratchcpp; -llvm::StructType *LLVMTypes::createValueDataType(llvm::IRBuilder<> *builder) +llvm::StructType *LLVMTypes::createValueDataType(llvm::LLVMContext &ctx) { - llvm::LLVMContext &ctx = builder->getContext(); - // Create the ValueData struct - llvm::Type *unionType = builder->getInt64Ty(); // 64 bits is the largest size + llvm::Type *unionType = llvm::Type::getInt64Ty(ctx); // 64 bits is the largest size llvm::Type *valueType = llvm::Type::getInt32Ty(ctx); // Assuming ValueType is a 32-bit enum llvm::Type *padding = llvm::Type::getInt32Ty(ctx); // Padding for alignment @@ -22,10 +20,8 @@ llvm::StructType *LLVMTypes::createValueDataType(llvm::IRBuilder<> *builder) return ret; } -llvm::StructType *LLVMTypes::createStringPtrType(llvm::IRBuilder<> *builder) +llvm::StructType *LLVMTypes::createStringPtrType(llvm::LLVMContext &ctx) { - llvm::LLVMContext &ctx = builder->getContext(); - // Create the StringPtr struct llvm::PointerType *pointerType = llvm::PointerType::get(llvm::Type::getInt8Ty(ctx), 0); llvm::Type *sizeType = llvm::Type::getInt64Ty(ctx); diff --git a/src/engine/internal/llvm/llvmtypes.h b/src/engine/internal/llvm/llvmtypes.h index 61c5f401f..cbfefa601 100644 --- a/src/engine/internal/llvm/llvmtypes.h +++ b/src/engine/internal/llvm/llvmtypes.h @@ -17,8 +17,8 @@ namespace libscratchcpp class LLVMTypes { public: - static llvm::StructType *createValueDataType(llvm::IRBuilder<> *builder); - static llvm::StructType *createStringPtrType(llvm::IRBuilder<> *builder); + static llvm::StructType *createValueDataType(llvm::LLVMContext &ctx); + static llvm::StructType *createStringPtrType(llvm::LLVMContext &ctx); }; } // namespace libscratchcpp diff --git a/test/llvm/llvmexecutablecode_test.cpp b/test/llvm/llvmexecutablecode_test.cpp index d792cfdea..6dbc6d520 100644 --- a/test/llvm/llvmexecutablecode_test.cpp +++ b/test/llvm/llvmexecutablecode_test.cpp @@ -30,7 +30,7 @@ class LLVMExecutableCodeTest : public testing::Test m_module = m_ctx->module(); m_llvmCtx = m_ctx->llvmCtx(); m_builder = std::make_unique>(*m_llvmCtx); - m_valueDataType = LLVMTypes::createValueDataType(m_builder.get()); + m_valueDataType = LLVMTypes::createValueDataType(*m_llvmCtx); test_function(nullptr, nullptr, nullptr, nullptr, nullptr); // force dependency m_script = std::make_unique