Skip to content

Commit 52c4d02

Browse files
committed
LLVMCodeBuilder: Add string concat instruction
1 parent a0e773b commit 52c4d02

File tree

6 files changed

+88
-1
lines changed

6 files changed

+88
-1
lines changed

src/engine/internal/icodebuilder.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ class ICodeBuilder
6969
virtual CompilerValue *createExp(CompilerValue *num) = 0;
7070
virtual CompilerValue *createExp10(CompilerValue *num) = 0;
7171

72+
virtual CompilerValue *createStringConcat(CompilerValue *string1, CompilerValue *string2) = 0;
73+
7274
virtual CompilerValue *createSelect(CompilerValue *cond, CompilerValue *trueValue, CompilerValue *falseValue, Compiler::StaticType valueType) = 0;
7375

7476
virtual CompilerLocalVariable *createLocalVariable(Compiler::StaticType type) = 0;

src/engine/internal/llvm/llvmcodebuilder.cpp

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -547,6 +547,49 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
547547
break;
548548
}
549549

550+
case LLVMInstruction::Type::StringConcat: {
551+
assert(step.args.size() == 2);
552+
const auto &arg1 = step.args[0];
553+
const auto &arg2 = step.args[1];
554+
llvm::Value *str1 = castValue(arg1.second, arg1.first);
555+
llvm::Value *str2 = castValue(arg2.second, arg2.first);
556+
llvm::PointerType *charPointerType = m_builder.getInt16Ty()->getPointerTo();
557+
llvm::Function *memcpyFunc = llvm::Intrinsic::getDeclaration(m_module, llvm::Intrinsic::memcpy_inline, { charPointerType, charPointerType, m_builder.getInt64Ty() });
558+
559+
// StringPtr *result = string_pool_new(true)
560+
llvm::Value *result = m_builder.CreateCall(resolve_string_pool_new(), m_builder.getInt1(true));
561+
freeStringLater(result);
562+
563+
// result->size = string1->size + string2->size
564+
llvm::Value *sizeField1 = m_builder.CreateStructGEP(m_stringPtrType, str1, 1);
565+
llvm::Value *sizeField2 = m_builder.CreateStructGEP(m_stringPtrType, str2, 1);
566+
llvm::Value *size1 = m_builder.CreateLoad(m_builder.getInt64Ty(), sizeField1);
567+
llvm::Value *size2 = m_builder.CreateLoad(m_builder.getInt64Ty(), sizeField2);
568+
llvm::Value *resultSize = m_builder.CreateAdd(size1, size2);
569+
llvm::Value *resultSizeField = m_builder.CreateStructGEP(m_stringPtrType, result, 1);
570+
m_builder.CreateStore(resultSize, resultSizeField);
571+
572+
// string_alloc(result, result->size)
573+
m_builder.CreateCall(resolve_string_alloc(), { result, resultSize });
574+
575+
// memcpy(result->data, string1->data, string1->size * sizeof(char16_t))
576+
llvm::Value *dataField1 = m_builder.CreateStructGEP(m_stringPtrType, str1, 0);
577+
llvm::Value *data1 = m_builder.CreateLoad(charPointerType, dataField1);
578+
llvm::Value *resultDataField = m_builder.CreateStructGEP(m_stringPtrType, result, 0);
579+
llvm::Value *writePtr = m_builder.CreateLoad(charPointerType, resultDataField);
580+
m_builder.CreateCall(memcpyFunc, { writePtr, data1, m_builder.CreateMul(size1, m_builder.getInt64(2)), m_builder.getInt1(false) });
581+
582+
// memcpy(result->data + string1->size, string2->data, (string2->size + 1) * sizeof(char16_t))
583+
// +1: null-terminate
584+
llvm::Value *dataField2 = m_builder.CreateStructGEP(m_stringPtrType, str2, 0);
585+
llvm::Value *data2 = m_builder.CreateLoad(charPointerType, dataField2);
586+
writePtr = m_builder.CreateGEP(m_builder.getInt16Ty(), writePtr, size1);
587+
m_builder.CreateCall(memcpyFunc, { writePtr, data2, m_builder.CreateMul(m_builder.CreateAdd(size2, m_builder.getInt64(1)), m_builder.getInt64(2)), m_builder.getInt1(false) });
588+
589+
step.functionReturnReg->value = result;
590+
break;
591+
}
592+
550593
case LLVMInstruction::Type::Select: {
551594
assert(step.args.size() == 3);
552595
const auto &arg1 = step.args[0];
@@ -1556,6 +1599,11 @@ CompilerValue *LLVMCodeBuilder::createExp10(CompilerValue *num)
15561599
return createOp(LLVMInstruction::Type::Exp10, Compiler::StaticType::Number, Compiler::StaticType::Number, { num });
15571600
}
15581601

1602+
CompilerValue *LLVMCodeBuilder::createStringConcat(CompilerValue *string1, CompilerValue *string2)
1603+
{
1604+
return createOp(LLVMInstruction::Type::StringConcat, Compiler::StaticType::String, Compiler::StaticType::String, { string1, string2 });
1605+
}
1606+
15591607
CompilerValue *LLVMCodeBuilder::createSelect(CompilerValue *cond, CompilerValue *trueValue, CompilerValue *falseValue, Compiler::StaticType valueType)
15601608
{
15611609
LLVMRegister *ret = createOp(LLVMInstruction::Type::Select, valueType, { Compiler::StaticType::Bool, valueType, valueType }, { cond, trueValue, falseValue });
@@ -3217,6 +3265,11 @@ llvm::FunctionCallee LLVMCodeBuilder::resolve_string_pool_free()
32173265
return resolveFunction("string_pool_free", llvm::FunctionType::get(m_builder.getVoidTy(), { m_stringPtrType->getPointerTo() }, false));
32183266
}
32193267

3268+
llvm::FunctionCallee LLVMCodeBuilder::resolve_string_alloc()
3269+
{
3270+
return resolveFunction("string_alloc", llvm::FunctionType::get(m_builder.getVoidTy(), { m_stringPtrType->getPointerTo(), m_builder.getInt64Ty() }, false));
3271+
}
3272+
32203273
llvm::FunctionCallee LLVMCodeBuilder::resolve_string_compare_case_sensitive()
32213274
{
32223275
llvm::Type *stringPtr = m_stringPtrType->getPointerTo();

src/engine/internal/llvm/llvmcodebuilder.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,8 @@ class LLVMCodeBuilder : public ICodeBuilder
7878
CompilerValue *createExp(CompilerValue *num) override;
7979
CompilerValue *createExp10(CompilerValue *num) override;
8080

81+
CompilerValue *createStringConcat(CompilerValue *string1, CompilerValue *string2) override;
82+
8183
CompilerValue *createSelect(CompilerValue *cond, CompilerValue *trueValue, CompilerValue *falseValue, Compiler::StaticType valueType) override;
8284

8385
CompilerLocalVariable *createLocalVariable(Compiler::StaticType type) override;
@@ -204,6 +206,7 @@ class LLVMCodeBuilder : public ICodeBuilder
204206
llvm::FunctionCallee resolve_llvm_random_bool();
205207
llvm::FunctionCallee resolve_string_pool_new();
206208
llvm::FunctionCallee resolve_string_pool_free();
209+
llvm::FunctionCallee resolve_string_alloc();
207210
llvm::FunctionCallee resolve_string_compare_case_sensitive();
208211
llvm::FunctionCallee resolve_string_compare_case_insensitive();
209212

src/engine/internal/llvm/llvminstruction.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ struct LLVMInstruction
4747
Log10,
4848
Exp,
4949
Exp10,
50+
StringConcat,
5051
Select,
5152
CreateLocalVariable,
5253
WriteLocalVariable,

test/llvm/llvmcodebuilder_test.cpp

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ class LLVMCodeBuilderTest : public testing::Test
5656
Ln,
5757
Log10,
5858
Exp,
59-
Exp10
59+
Exp10,
60+
StringConcat
6061
};
6162

6263
void SetUp() override
@@ -144,6 +145,9 @@ class LLVMCodeBuilderTest : public testing::Test
144145
case OpType::Mod:
145146
return m_builder->createMod(arg1, arg2);
146147

148+
case OpType::StringConcat:
149+
return m_builder->createStringConcat(arg1, arg2);
150+
147151
default:
148152
EXPECT_TRUE(false);
149153
return nullptr;
@@ -258,6 +262,21 @@ class LLVMCodeBuilderTest : public testing::Test
258262
case OpType::Mod:
259263
return v1 % v2;
260264

265+
case OpType::StringConcat: {
266+
const StringPtr *string1 = value_toStringPtr(&v1.data());
267+
const StringPtr *string2 = value_toStringPtr(&v2.data());
268+
StringPtr *result = string_pool_new(true);
269+
270+
result->size = string1->size + string2->size;
271+
string_alloc(result, result->size);
272+
memcpy(result->data, string1->data, string1->size * sizeof(typeof(*string1->data)));
273+
memcpy(result->data + string1->size, string2->data, (string2->size + 1) * sizeof(typeof(*string2->data))); // +1: null-terminate
274+
275+
ValueData data;
276+
value_assign_stringPtr(&data, result);
277+
return Value(data);
278+
}
279+
261280
default:
262281
EXPECT_TRUE(false);
263282
return Value();
@@ -1700,6 +1719,13 @@ TEST_F(LLVMCodeBuilderTest, Exp10)
17001719
runUnaryNumOpTest(OpType::Exp10, nan, 1.0);
17011720
}
17021721

1722+
TEST_F(LLVMCodeBuilderTest, StringConcat)
1723+
{
1724+
runOpTest(OpType::StringConcat, "Hello ", "world");
1725+
runOpTest(OpType::StringConcat, "abc", "def");
1726+
runOpTest(OpType::StringConcat, "ábč", "ďéfgh");
1727+
}
1728+
17031729
TEST_F(LLVMCodeBuilderTest, LocalVariables)
17041730
{
17051731
Stage stage;

test/mocks/codebuildermock.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ class CodeBuilderMock : public ICodeBuilder
5858
MOCK_METHOD(CompilerValue *, createExp, (CompilerValue *), (override));
5959
MOCK_METHOD(CompilerValue *, createExp10, (CompilerValue *), (override));
6060

61+
MOCK_METHOD(CompilerValue *, createStringConcat, (CompilerValue *, CompilerValue *), (override));
62+
6163
MOCK_METHOD(CompilerValue *, createSelect, (CompilerValue *, CompilerValue *, CompilerValue *, Compiler::StaticType), (override));
6264

6365
MOCK_METHOD(CompilerLocalVariable *, createLocalVariable, (Compiler::StaticType), (override));

0 commit comments

Comments
 (0)