Skip to content

Commit

Permalink
Implement string concatenation, add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
dpoerio committed Mar 18, 2021
1 parent 58f1948 commit 1243474
Show file tree
Hide file tree
Showing 9 changed files with 178 additions and 0 deletions.
42 changes: 42 additions & 0 deletions src/lfortran/codegen/asr_to_llvm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,35 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor<ASRToLLVMVisitor>
return builder->CreateLoad(presult);
}


llvm::Value* lfortran_strop(llvm::Value* left_arg, llvm::Value* right_arg,
std::string runtime_func_name)
{
llvm::Function *fn = module->getFunction(runtime_func_name);
if (!fn) {
llvm::FunctionType *function_type = llvm::FunctionType::get(
llvm::Type::getVoidTy(context), {
character_type->getPointerTo(),
character_type->getPointerTo(),
character_type->getPointerTo()
}, false);
fn = llvm::Function::Create(function_type,
llvm::Function::ExternalLinkage, runtime_func_name, *module);
}
llvm::AllocaInst *pleft_arg = builder->CreateAlloca(character_type,
nullptr);
builder->CreateStore(left_arg, pleft_arg);
llvm::AllocaInst *pright_arg = builder->CreateAlloca(character_type,
nullptr);
builder->CreateStore(right_arg, pright_arg);
llvm::AllocaInst *presult = builder->CreateAlloca(character_type,
nullptr);
std::vector<llvm::Value*> args = {pleft_arg, pright_arg, presult};
builder->CreateCall(fn, args);
return builder->CreateLoad(presult);
}


// This function is called as:
// float complex_re(complex a)
// And it extracts the real part of the complex number
Expand Down Expand Up @@ -792,6 +821,19 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor<ASRToLLVMVisitor>
}
}

void visit_StrOp(const ASR::StrOp_t &x) {
this->visit_expr(*x.m_left);
llvm::Value *left_val = tmp;
this->visit_expr(*x.m_right);
llvm::Value *right_val = tmp;
switch (x.m_op) {
case ASR::stropType::Concat: {
tmp = lfortran_strop(left_val, right_val, "_lfortran_strcat");
break;
};
}
}

void visit_BinOp(const ASR::BinOp_t &x) {
this->visit_expr(*x.m_left);
llvm::Value *left_val = tmp;
Expand Down
23 changes: 23 additions & 0 deletions src/runtime/lfort_intrinsics.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <stdlib.h>
#include <math.h>
#include <complex.h>
#include <string.h>

struct _lfortran_complex {
float re, im;
Expand Down Expand Up @@ -537,3 +538,25 @@ double_complex_t _lfortran_zatanh(double_complex_t x)
return atanh(x);
#endif
}


// strcat --------------------------------------------------------------------
void _lfortran_strcat(char** s1, char** s2, char** dest)
{
int cntr = 0;
char trmn = '\0';
int s1_len = strlen(*s1);
int s2_len = strlen(*s2);
int trmn_size = strlen(&trmn);
char* dest_char = (char*)malloc(s1_len+s2_len+trmn_size);
for (int i = 0; i < s1_len; i++) {
dest_char[cntr] = (*s1)[i];
cntr++;
}
for (int i = 0; i < s2_len; i++) {
dest_char[cntr] = (*s2)[i];
cntr++;
}
dest_char[cntr] = trmn;
*dest = &(dest_char[0]);
}
13 changes: 13 additions & 0 deletions tests/reference/asr-string3-aa1dc1c.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"basename": "asr-string3-aa1dc1c",
"cmd": "lfortran --show-asr --no-color {infile} -o {outfile}",
"infile": "tests/../integration_tests/string3.f90",
"infile_hash": "90188a84217deb8d16424b3aaf49f0b2a999cad8494cdf536c6d27e1",
"outfile": null,
"outfile_hash": null,
"stdout": "asr-string3-aa1dc1c.stdout",
"stdout_hash": "ebfbc4cf253158ab88857d927cd83c32a284910515f5d521f27ffa23",
"stderr": null,
"stderr_hash": null,
"returncode": 0
}
1 change: 1 addition & 0 deletions tests/reference/asr-string3-aa1dc1c.stdout
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
(TranslationUnit (SymbolTable 1 {dr_fortran: (Program (SymbolTable 2 {combined: (Variable 2 combined Local () Default (Character 4 []) Source Public), intro: (Variable 2 intro Local () Default (Character 4 []) Source Public), last_name: (Variable 2 last_name Local () Default (Character 4 []) Source Public), posit: (Variable 2 posit Local () Default (Character 4 []) Source Public), title: (Variable 2 title Local () Default (Character 4 []) Source Public), verb: (Variable 2 verb Local () Default (Character 4 []) Source Public)}) dr_fortran [(= (Var 2 intro) (Str "I've " (Character 8 []))) (= (Var 2 verb) (Str "learned " (Character 8 []))) (= (Var 2 posit) (Str "from " (Character 8 []))) (= (Var 2 title) (Str "Dr. " (Character 8 []))) (= (Var 2 last_name) (Str "Fortran" (Character 8 []))) (= (Var 2 combined) (StrOp (StrOp (StrOp (StrOp (Var 2 intro) Concat (Var 2 verb) (Character 4 [])) Concat (Var 2 posit) (Character 4 [])) Concat (Var 2 title) (Character 4 [])) Concat (Var 2 last_name) (Character 4 []))) (Print () [(Var 2 combined)])])}) [])
13 changes: 13 additions & 0 deletions tests/reference/ast-string3-24139f8.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"basename": "ast-string3-24139f8",
"cmd": "lfortran --show-ast --no-color {infile} -o {outfile}",
"infile": "tests/../integration_tests/string3.f90",
"infile_hash": "90188a84217deb8d16424b3aaf49f0b2a999cad8494cdf536c6d27e1",
"outfile": null,
"outfile_hash": null,
"stdout": "ast-string3-24139f8.stdout",
"stdout_hash": "347d4112b125f40efa196d5dd603d29d7051eb7ddc0af2becad263ea",
"stderr": null,
"stderr_hash": null,
"returncode": 0
}
1 change: 1 addition & 0 deletions tests/reference/ast-string3-24139f8.stdout
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
(TranslationUnit [(Program dr_fortran [] [(Declaration [(intro "character" () [(len 5 Value)] [] [] ())]) (Declaration [(verb "character" () [(len 8 Value)] [] [] ())]) (Declaration [(posit "character" () [(len 5 Value)] [] [] ())]) (Declaration [(title "character" () [(len 4 Value)] [] [] ())]) (Declaration [(last_name "character" () [(len 7 Value)] [] [] ())]) (Declaration [(combined "character" () [(len 29 Value)] [] [] ())])] [(= intro (Str "I've ")) (= verb (Str "learned ")) (= posit (Str "from ")) (= title (Str "Dr. ")) (= last_name (Str "Fortran")) (= combined (StrOp (StrOp (StrOp (StrOp intro Concat verb) Concat posit) Concat title) Concat last_name)) (Print () [combined])] [])])
13 changes: 13 additions & 0 deletions tests/reference/llvm-string3-9528793.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"basename": "llvm-string3-9528793",
"cmd": "lfortran --show-llvm {infile} -o {outfile}",
"infile": "tests/../integration_tests/string3.f90",
"infile_hash": "90188a84217deb8d16424b3aaf49f0b2a999cad8494cdf536c6d27e1",
"outfile": null,
"outfile_hash": null,
"stdout": "llvm-string3-9528793.stdout",
"stdout_hash": "5f9a0a51f4e97acfe4ecddfe4379401430df5052a9df1544f4283a21",
"stderr": null,
"stderr_hash": null,
"returncode": 0
}
66 changes: 66 additions & 0 deletions tests/reference/llvm-string3-9528793.stdout
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
; ModuleID = 'LFortran'
source_filename = "LFortran"

@0 = private unnamed_addr constant [6 x i8] c"I've \00", align 1
@1 = private unnamed_addr constant [9 x i8] c"learned \00", align 1
@2 = private unnamed_addr constant [6 x i8] c"from \00", align 1
@3 = private unnamed_addr constant [5 x i8] c"Dr. \00", align 1
@4 = private unnamed_addr constant [8 x i8] c"Fortran\00", align 1
@5 = private unnamed_addr constant [4 x i8] c"%s\0A\00", align 1

define i64 @main() {
.entry:
%combined = alloca i8*, align 8
%intro = alloca i8*, align 8
%last_name = alloca i8*, align 8
%posit = alloca i8*, align 8
%title = alloca i8*, align 8
%verb = alloca i8*, align 8
store i8* getelementptr inbounds ([6 x i8], [6 x i8]* @0, i32 0, i32 0), i8** %intro, align 8
store i8* getelementptr inbounds ([9 x i8], [9 x i8]* @1, i32 0, i32 0), i8** %verb, align 8
store i8* getelementptr inbounds ([6 x i8], [6 x i8]* @2, i32 0, i32 0), i8** %posit, align 8
store i8* getelementptr inbounds ([5 x i8], [5 x i8]* @3, i32 0, i32 0), i8** %title, align 8
store i8* getelementptr inbounds ([8 x i8], [8 x i8]* @4, i32 0, i32 0), i8** %last_name, align 8
%0 = load i8*, i8** %intro, align 8
%1 = load i8*, i8** %verb, align 8
%2 = alloca i8*, align 8
store i8* %0, i8** %2, align 8
%3 = alloca i8*, align 8
store i8* %1, i8** %3, align 8
%4 = alloca i8*, align 8
call void @_lfortran_strcat(i8** %2, i8** %3, i8** %4)
%5 = load i8*, i8** %4, align 8
%6 = load i8*, i8** %posit, align 8
%7 = alloca i8*, align 8
store i8* %5, i8** %7, align 8
%8 = alloca i8*, align 8
store i8* %6, i8** %8, align 8
%9 = alloca i8*, align 8
call void @_lfortran_strcat(i8** %7, i8** %8, i8** %9)
%10 = load i8*, i8** %9, align 8
%11 = load i8*, i8** %title, align 8
%12 = alloca i8*, align 8
store i8* %10, i8** %12, align 8
%13 = alloca i8*, align 8
store i8* %11, i8** %13, align 8
%14 = alloca i8*, align 8
call void @_lfortran_strcat(i8** %12, i8** %13, i8** %14)
%15 = load i8*, i8** %14, align 8
%16 = load i8*, i8** %last_name, align 8
%17 = alloca i8*, align 8
store i8* %15, i8** %17, align 8
%18 = alloca i8*, align 8
store i8* %16, i8** %18, align 8
%19 = alloca i8*, align 8
call void @_lfortran_strcat(i8** %17, i8** %18, i8** %19)
%20 = load i8*, i8** %19, align 8
store i8* %20, i8** %combined, align 8
%21 = load i8*, i8** %combined, align 8
call void (i8*, ...) @_lfortran_printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @5, i32 0, i32 0), i8* %21)
ret i64 0
}

declare void @_lfortran_strcat(i8**, i8**, i8**)

declare void @_lfortran_printf(i8*, ...)

6 changes: 6 additions & 0 deletions tests/tests.toml
Original file line number Diff line number Diff line change
Expand Up @@ -743,3 +743,9 @@ filename = "../integration_tests/string2.f90"
ast = true
asr = true
llvm = true

[[test]]
filename = "../integration_tests/string3.f90"
ast = true
asr = true
llvm = true

0 comments on commit 1243474

Please sign in to comment.