Skip to content

Commit

Permalink
Merge pull request #484 from certik/list
Browse files Browse the repository at this point in the history
LLVM: initial list[i32] implementation
  • Loading branch information
namannimmo10 authored May 11, 2022
2 parents c45e1c5 + cf241d0 commit e5af88a
Show file tree
Hide file tree
Showing 4 changed files with 163 additions and 4 deletions.
1 change: 1 addition & 0 deletions integration_tests/run_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"test_types_01.py",
"test_str_01.py",
"test_str_02.py",
"test_list_01.py",
"modules_01.py",
#"modules_02.py",
"test_math.py",
Expand Down
12 changes: 12 additions & 0 deletions integration_tests/test_list_01.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from ltypes import i32

def test_list_i32():
a: list[i32] = [1]
a.append(2)
a.append(3)
a.append(4)
a.append(5)
print(a[1])
assert a[1] == 2 or a[1] == 3

test_list_i32()
114 changes: 110 additions & 4 deletions src/libasr/codegen/asr_to_llvm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor<ASRToLLVMVisitor>
llvm::StructType *complex_type_4, *complex_type_8;
llvm::StructType *complex_type_4_ptr, *complex_type_8_ptr;
llvm::PointerType *character_type;
llvm::PointerType *list_type;

std::unordered_map<std::uint32_t, std::unordered_map<std::string, llvm::Type*>> arr_arg_type_cache;

Expand Down Expand Up @@ -795,6 +796,49 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor<ASRToLLVMVisitor>
return builder->CreateCall(fn, {str, idx1, idx2});
}

llvm::Value* lcompilers_list_init_i32()
{
std::string runtime_func_name = "_lcompilers_list_init_i32";
llvm::Function *fn = module->getFunction(runtime_func_name);
if (!fn) {
llvm::FunctionType *function_type = llvm::FunctionType::get(
list_type, { }, false);
fn = llvm::Function::Create(function_type,
llvm::Function::ExternalLinkage, runtime_func_name, *module);
}
return builder->CreateCall(fn, {});
}

void lcompilers_list_append_i32(llvm::Value* plist, llvm::Value *item)
{
std::string runtime_func_name = "_lcompilers_list_append_i32";
llvm::Function *fn = module->getFunction(runtime_func_name);
if (!fn) {
llvm::FunctionType *function_type = llvm::FunctionType::get(
llvm::Type::getVoidTy(context), {
list_type, llvm::Type::getInt32Ty(context)
}, false);
fn = llvm::Function::Create(function_type,
llvm::Function::ExternalLinkage, runtime_func_name, *module);
}
builder->CreateCall(fn, {plist, item});
}

llvm::Value* lcompilers_list_item_i32(llvm::Value* plist, llvm::Value *pos)
{
std::string runtime_func_name = "_lcompilers_list_item_i32";
llvm::Function *fn = module->getFunction(runtime_func_name);
if (!fn) {
llvm::FunctionType *function_type = llvm::FunctionType::get(
llvm::Type::getInt32Ty(context), {
list_type, llvm::Type::getInt32Ty(context)
}, false);
fn = llvm::Function::Create(function_type,
llvm::Function::ExternalLinkage, runtime_func_name, *module);
}
return builder->CreateCall(fn, {plist, pos});
}

// This function is called as:
// float complex_re(complex a)
// And it extracts the real part of the complex number
Expand Down Expand Up @@ -903,6 +947,7 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor<ASRToLLVMVisitor>
complex_type_4_ptr = llvm::StructType::create(context, els_4_ptr, "complex_4_ptr");
complex_type_8_ptr = llvm::StructType::create(context, els_8_ptr, "complex_8_ptr");
character_type = llvm::Type::getInt8PtrTy(context);
list_type = llvm::Type::getInt8PtrTy(context);

llvm::Type* bound_arg = static_cast<llvm::Type*>(arr_descr->get_dimension_descriptor_type(true));
fname2arg_type["lbound"] = std::make_pair(bound_arg, bound_arg->getPointerTo());
Expand Down Expand Up @@ -1058,6 +1103,56 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor<ASRToLLVMVisitor>
_Deallocate<ASR::ExplicitDeallocate_t>(x);
}

void visit_ListAppend(const ASR::ListAppend_t& x) {
ASR::Variable_t *l = ASR::down_cast<ASR::Variable_t>(x.m_a);
uint32_t v_h = get_hash((ASR::asr_t*)l);
LFORTRAN_ASSERT(llvm_symtab.find(v_h) != llvm_symtab.end());
llvm::Value *plist = llvm_symtab[v_h];

this->visit_expr_wrapper(x.m_ele, true);
llvm::Value *ele = tmp;

ASR::ttype_t *el_type = ASR::down_cast<ASR::List_t>(l->m_type)->m_type;
if (is_a<ASR::Integer_t>(*el_type)) {
int kind = ASR::down_cast<ASR::Integer_t>(el_type)->m_kind;
if (kind == 4) {
llvm::Value *plist2 = CreateLoad(plist);
lcompilers_list_append_i32(plist2, ele);
} else {
throw CodeGenError("Integer kind not supported yet in ListAppend", x.base.base.loc);
}

} else {
throw CodeGenError("List type not supported yet in ListAppend", x.base.base.loc);
}

}

void visit_ListItem(const ASR::ListItem_t& x) {
ASR::Variable_t *l = ASR::down_cast<ASR::Variable_t>(x.m_a);
uint32_t v_h = get_hash((ASR::asr_t*)l);
LFORTRAN_ASSERT(llvm_symtab.find(v_h) != llvm_symtab.end());
llvm::Value *plist = llvm_symtab[v_h];

this->visit_expr_wrapper(x.m_pos, true);
llvm::Value *pos = tmp;

ASR::ttype_t *el_type = ASR::down_cast<ASR::List_t>(l->m_type)->m_type;
if (is_a<ASR::Integer_t>(*el_type)) {
int kind = ASR::down_cast<ASR::Integer_t>(el_type)->m_kind;
if (kind == 4) {
llvm::Value *plist2 = CreateLoad(plist);
tmp = lcompilers_list_item_i32(plist2, pos);
} else {
throw CodeGenError("Integer kind not supported yet in ListAppend", x.base.base.loc);
}

} else {
throw CodeGenError("List type not supported yet in ListAppend", x.base.base.loc);
}

}

void visit_ArrayRef(const ASR::ArrayRef_t& x) {
if (x.m_value) {
this->visit_expr_wrapper(x.m_value, true);
Expand Down Expand Up @@ -1250,7 +1345,7 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor<ASRToLLVMVisitor>
}
llvm_symtab[h] = ptr;
} else {
throw CodeGenError("Variable type not supported");
throw CodeGenError("Variable type not supported", x.base.base.loc);
}
}

Expand Down Expand Up @@ -1516,19 +1611,25 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor<ASRToLLVMVisitor>
break;
}
case (ASR::ttypeType::Derived) : {
throw CodeGenError("Pointers for Derived type not implemented yet in conversion");
throw CodeGenError("Pointers for Derived type not implemented yet in conversion", v->base.base.loc);
}
case (ASR::ttypeType::Logical) : {
type = llvm::Type::getInt1Ty(context);
break;
}
default :
throw CodeGenError("Type not implemented");
throw CodeGenError("Type not implemented", v->base.base.loc);
}
break;
}
case (ASR::ttypeType::List) : {
//ASR::List_t* v_type = down_cast<ASR::List_t>(v->m_type);
//ASR::ttype_t *el_type = v_type->m_type;
type = list_type;
break;
}
default :
throw CodeGenError("Type not implemented");
throw CodeGenError("Type not implemented", v->base.base.loc);
}
/*
* The following if block is used for converting any
Expand Down Expand Up @@ -1626,6 +1727,11 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor<ASRToLLVMVisitor>
} else {
throw CodeGenError("Unsupported len value in ASR");
}
} else if (is_a<ASR::List_t>(*v->m_type)) {
// TODO: do a different initialization based on element type
llvm::Value *init_value = lcompilers_list_init_i32();
target_var = ptr;
builder->CreateStore(init_value, target_var);
}
}
}
Expand Down
40 changes: 40 additions & 0 deletions src/runtime/impure/lfortran_intrinsics.c
Original file line number Diff line number Diff line change
Expand Up @@ -675,6 +675,46 @@ LFORTRAN_API void _lfortran_string_init(int size_plus_one, char *s) {
s[size] = '\0';
}

// List -----------------------------------------------------------------------

struct _lcompilers_list_i32 {
uint64_t n;
uint64_t capacity;
int32_t *p;
};

LFORTRAN_API int8_t* _lcompilers_list_init_i32() {
struct _lcompilers_list_i32 *l;
l = (struct _lcompilers_list_i32*)malloc(
sizeof(struct _lcompilers_list_i32));
l->n = 0;
// TODO:
l->capacity = 1024;
l->p = (int32_t*)malloc(1024*sizeof(int32_t));
return (int8_t*)l;
}

LFORTRAN_API void _lcompilers_list_append_i32(int8_t* s, int32_t item) {
struct _lcompilers_list_i32 *l = (struct _lcompilers_list_i32 *)s;
if (l->n < l->capacity) {
l->p[l->n] = item;
l->n++;
} else {
printf("Must reallocate\n");
}
}

// pos is the index = 1..n
LFORTRAN_API int32_t _lcompilers_list_item_i32(int8_t* s, int32_t pos) {
struct _lcompilers_list_i32 *l = (struct _lcompilers_list_i32 *)s;
if (pos >= 1 && pos <= l->n) {
return l->p[pos-1];
} else {
printf("Out of bounds\n");
return 0;
}
}

// bit ------------------------------------------------------------------------

LFORTRAN_API int32_t _lfortran_iand32(int32_t x, int32_t y) {
Expand Down

0 comments on commit e5af88a

Please sign in to comment.