Skip to content

Commit a7bf600

Browse files
committed
LLVMCodeBuilder: Add string char instruction
1 parent 52c4d02 commit a7bf600

File tree

6 files changed

+80
-1
lines changed

6 files changed

+80
-1
lines changed

src/engine/internal/icodebuilder.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ class ICodeBuilder
2424
virtual CompilerValue *addTargetFunctionCall(const std::string &functionName, Compiler::StaticType returnType, const Compiler::ArgTypes &argTypes, const Compiler::Args &args) = 0;
2525
virtual CompilerValue *addFunctionCallWithCtx(const std::string &functionName, Compiler::StaticType returnType, const Compiler::ArgTypes &argTypes, const Compiler::Args &args) = 0;
2626
virtual CompilerConstant *addConstValue(const Value &value) = 0;
27+
virtual CompilerValue *addStringChar(CompilerValue *string, CompilerValue *index) = 0;
2728
virtual CompilerValue *addLoopIndex() = 0;
2829
virtual CompilerValue *addLocalVariableValue(CompilerLocalVariable *variable) = 0;
2930
virtual CompilerValue *addVariableValue(Variable *variable) = 0;

src/engine/internal/llvm/llvmcodebuilder.cpp

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -590,6 +590,45 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
590590
break;
591591
}
592592

593+
case LLVMInstruction::Type::StringChar: {
594+
assert(step.args.size() == 2);
595+
const auto &arg1 = step.args[0];
596+
const auto &arg2 = step.args[1];
597+
llvm::Value *str = castValue(arg1.second, arg1.first);
598+
llvm::Value *index = m_builder.CreateFPToSI(castValue(arg2.second, arg2.first), m_builder.getInt64Ty());
599+
llvm::PointerType *charPointerType = m_builder.getInt16Ty()->getPointerTo();
600+
601+
// Get data ptr and size
602+
llvm::Value *dataField = m_builder.CreateStructGEP(m_stringPtrType, str, 0);
603+
llvm::Value *data = m_builder.CreateLoad(charPointerType, dataField);
604+
llvm::Value *sizeField = m_builder.CreateStructGEP(m_stringPtrType, str, 1);
605+
llvm::Value *size = m_builder.CreateLoad(m_builder.getInt64Ty(), sizeField);
606+
607+
// Check range, get character ptr
608+
llvm::Value *inRange = m_builder.CreateAnd(m_builder.CreateICmpSGE(index, m_builder.getInt64(0)), m_builder.CreateICmpSLT(index, size));
609+
llvm::Value *charPtr = m_builder.CreateGEP(m_builder.getInt16Ty(), data, index);
610+
611+
// Allocate string
612+
llvm::Value *result = m_builder.CreateCall(resolve_string_pool_new(), m_builder.getInt1(true));
613+
freeStringLater(result);
614+
m_builder.CreateCall(resolve_string_alloc(), { result, m_builder.getInt64(1) }); // size 1 to avoid branching
615+
616+
// Get result data ptr
617+
dataField = m_builder.CreateStructGEP(m_stringPtrType, result, 0);
618+
data = m_builder.CreateLoad(charPointerType, dataField);
619+
620+
// Write result
621+
llvm::Value *char1 = m_builder.CreateGEP(m_builder.getInt16Ty(), data, m_builder.getInt64(0));
622+
llvm::Value *char2 = m_builder.CreateGEP(m_builder.getInt16Ty(), data, m_builder.getInt64(1));
623+
sizeField = m_builder.CreateStructGEP(m_stringPtrType, result, 1);
624+
m_builder.CreateStore(m_builder.CreateSelect(inRange, m_builder.CreateLoad(m_builder.getInt16Ty(), charPtr), m_builder.getInt16(0)), char1);
625+
m_builder.CreateStore(m_builder.getInt16(0), char2);
626+
m_builder.CreateStore(m_builder.CreateSelect(inRange, m_builder.getInt64(1), m_builder.getInt64(0)), sizeField);
627+
628+
step.functionReturnReg->value = result;
629+
break;
630+
}
631+
593632
case LLVMInstruction::Type::Select: {
594633
assert(step.args.size() == 3);
595634
const auto &arg1 = step.args[0];
@@ -1335,6 +1374,11 @@ CompilerConstant *LLVMCodeBuilder::addConstValue(const Value &value)
13351374
return static_cast<CompilerConstant *>(static_cast<CompilerValue *>(addReg(reg, nullptr)));
13361375
}
13371376

1377+
CompilerValue *LLVMCodeBuilder::addStringChar(CompilerValue *string, CompilerValue *index)
1378+
{
1379+
return createOp(LLVMInstruction::Type::StringChar, Compiler::StaticType::String, { Compiler::StaticType::String, Compiler::StaticType::Number }, { string, index });
1380+
}
1381+
13381382
CompilerValue *LLVMCodeBuilder::addLoopIndex()
13391383
{
13401384
return createOp(LLVMInstruction::Type::LoopIndex, Compiler::StaticType::Number, {}, {});

src/engine/internal/llvm/llvmcodebuilder.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ class LLVMCodeBuilder : public ICodeBuilder
3333
CompilerValue *addTargetFunctionCall(const std::string &functionName, Compiler::StaticType returnType, const Compiler::ArgTypes &argTypes, const Compiler::Args &args) override;
3434
CompilerValue *addFunctionCallWithCtx(const std::string &functionName, Compiler::StaticType returnType, const Compiler::ArgTypes &argTypes, const Compiler::Args &args) override;
3535
CompilerConstant *addConstValue(const Value &value) override;
36+
CompilerValue *addStringChar(CompilerValue *string, CompilerValue *index) override;
3637
CompilerValue *addLoopIndex() override;
3738
CompilerValue *addLocalVariableValue(CompilerLocalVariable *variable) override;
3839
CompilerValue *addVariableValue(Variable *variable) override;

src/engine/internal/llvm/llvminstruction.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ struct LLVMInstruction
4848
Exp,
4949
Exp10,
5050
StringConcat,
51+
StringChar,
5152
Select,
5253
CreateLocalVariable,
5354
WriteLocalVariable,

test/llvm/llvmcodebuilder_test.cpp

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,8 @@ class LLVMCodeBuilderTest : public testing::Test
5757
Log10,
5858
Exp,
5959
Exp10,
60-
StringConcat
60+
StringConcat,
61+
StringChar
6162
};
6263

6364
void SetUp() override
@@ -148,6 +149,9 @@ class LLVMCodeBuilderTest : public testing::Test
148149
case OpType::StringConcat:
149150
return m_builder->createStringConcat(arg1, arg2);
150151

152+
case OpType::StringChar:
153+
return m_builder->addStringChar(arg1, arg2);
154+
151155
default:
152156
EXPECT_TRUE(false);
153157
return nullptr;
@@ -277,6 +281,22 @@ class LLVMCodeBuilderTest : public testing::Test
277281
return Value(data);
278282
}
279283

284+
case OpType::StringChar: {
285+
const StringPtr *string = value_toStringPtr(&v1.data());
286+
const double index = v2.toDouble();
287+
const bool inRange = (index >= 0 && index < string->size);
288+
StringPtr *result = string_pool_new(true);
289+
290+
string_alloc(result, 1);
291+
result->data[0] = inRange ? string->data[static_cast<size_t>(index)] : u'\0';
292+
result->data[1] = u'\0';
293+
result->size = inRange;
294+
295+
ValueData data;
296+
value_assign_stringPtr(&data, result);
297+
return Value(data);
298+
}
299+
280300
default:
281301
EXPECT_TRUE(false);
282302
return Value();
@@ -1726,6 +1746,17 @@ TEST_F(LLVMCodeBuilderTest, StringConcat)
17261746
runOpTest(OpType::StringConcat, "ábč", "ďéfgh");
17271747
}
17281748

1749+
TEST_F(LLVMCodeBuilderTest, StringChar)
1750+
{
1751+
runOpTest(OpType::StringChar, "Hello world", 1);
1752+
runOpTest(OpType::StringChar, "Hello world", 0);
1753+
runOpTest(OpType::StringChar, "Hello world", 11);
1754+
runOpTest(OpType::StringChar, "abc", 2);
1755+
runOpTest(OpType::StringChar, "abc", -1);
1756+
runOpTest(OpType::StringChar, "abc", 3);
1757+
runOpTest(OpType::StringChar, "ábč", 0);
1758+
}
1759+
17291760
TEST_F(LLVMCodeBuilderTest, LocalVariables)
17301761
{
17311762
Stage stage;

test/mocks/codebuildermock.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ class CodeBuilderMock : public ICodeBuilder
1313
MOCK_METHOD(CompilerValue *, addTargetFunctionCall, (const std::string &, Compiler::StaticType, const Compiler::ArgTypes &, const Compiler::Args &), (override));
1414
MOCK_METHOD(CompilerValue *, addFunctionCallWithCtx, (const std::string &, Compiler::StaticType, const Compiler::ArgTypes &, const Compiler::Args &), (override));
1515
MOCK_METHOD(CompilerConstant *, addConstValue, (const Value &), (override));
16+
MOCK_METHOD(CompilerValue *, addStringChar, (CompilerValue *, CompilerValue *), (override));
1617
MOCK_METHOD(CompilerValue *, addLoopIndex, (), (override));
1718
MOCK_METHOD(CompilerValue *, addLocalVariableValue, (CompilerLocalVariable *), (override));
1819
MOCK_METHOD(CompilerValue *, addVariableValue, (Variable *), (override));

0 commit comments

Comments
 (0)