Skip to content

Commit

Permalink
Merge pull request #2752 from Vipul-Cariappa/top-lists
Browse files Browse the repository at this point in the history
Support to print lists in REPL
  • Loading branch information
Shaikh-Ubaid authored Jul 9, 2024
2 parents a77c390 + d6f1e15 commit ba07d7b
Show file tree
Hide file tree
Showing 7 changed files with 266 additions and 77 deletions.
10 changes: 10 additions & 0 deletions src/bin/lpython.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1007,6 +1007,16 @@ int interactive_python_repl(
}
break;
}
case (LCompilers::PythonCompiler::EvalResult::struct_type) : {
if (verbose) {
std::cout << "Return type: "
<< LCompilers::ASRUtils::get_type_code(r.structure.ttype)
<< std::endl;
}
if (verbose) section("Result:");
std::cout << fe.aggregate_type_to_string(r) << std::endl;
break;
}
case (LCompilers::PythonCompiler::EvalResult::none) : {
if (verbose) {
std::cout << "Return type: none" << std::endl;
Expand Down
14 changes: 10 additions & 4 deletions src/libasr/codegen/evaluator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,11 @@ std::string LLVMModule::str()
return LLVMEvaluator::module_to_string(*m_m);
}

llvm::Function *LLVMModule::get_function(const std::string &fn_name) {
llvm::Module *m = m_m.get();
return m->getFunction(fn_name);
}

std::string LLVMModule::get_return_type(const std::string &fn_name)
{
llvm::Module *m = m_m.get();
Expand Down Expand Up @@ -121,12 +126,9 @@ std::string LLVMModule::get_return_type(const std::string &fn_name)
return "complex4";
} else if (startswith(std::string(st->getName()), "complex_8")) {
return "complex8";
} else {
throw LCompilersException("LLVMModule::get_return_type(): Struct return type `" + std::string(st->getName()) + "` not supported");
}
} else {
throw LCompilersException("LLVMModule::get_return_type(): Noname struct return type not supported");
}
return "struct";
} else if (type->isVectorTy()) {
// Used for passing complex_4 on some platforms
return "complex4";
Expand Down Expand Up @@ -377,6 +379,10 @@ llvm::LLVMContext &LLVMEvaluator::get_context()
return *context;
}

const llvm::DataLayout &LLVMEvaluator::get_jit_data_layout() {
return jit->getDataLayout();
}

void LLVMEvaluator::print_targets()
{
llvm::InitializeNativeTarget();
Expand Down
3 changes: 3 additions & 0 deletions src/libasr/codegen/evaluator.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ namespace llvm {
class Module;
class Function;
class TargetMachine;
class DataLayout;
namespace orc {
class KaleidoscopeJIT;
}
Expand All @@ -35,6 +36,7 @@ class LLVMModule
std::string str();
// Return a function return type as a string (real / integer)
std::string get_return_type(const std::string &fn_name);
llvm::Function *get_function(const std::string &fn_name);
};

class LLVMEvaluator
Expand All @@ -60,6 +62,7 @@ class LLVMEvaluator
static std::string module_to_string(llvm::Module &m);
static void print_version_message();
llvm::LLVMContext &get_context();
const llvm::DataLayout &get_jit_data_layout();
static void print_targets();
static std::string get_default_target_triple();

Expand Down
98 changes: 29 additions & 69 deletions src/libasr/pass/global_stmts.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ void pass_wrap_global_stmts(Allocator &al,
char *fn_name = s.c_str(al);
SymbolTable *fn_scope = al.make_new<SymbolTable>(unit.m_symtab);

ASR::ttype_t *type;
ASR::ttype_t *type = nullptr;
Location loc = unit.base.base.loc;
ASR::asr_t *return_var=nullptr;
ASR::expr_t *return_var_ref=nullptr;
Expand All @@ -45,58 +45,14 @@ void pass_wrap_global_stmts(Allocator &al,
ASR::expr_t *target;
ASR::expr_t *value = EXPR(unit.m_items[i]);
// Create a new variable with the right type
if (ASRUtils::expr_type(value)->type == ASR::ttypeType::Integer) {
s.from_str(al, fn_name_s + std::to_string(idx));
var_name = s.c_str(al);

int a_kind = down_cast<ASR::Integer_t>(ASRUtils::expr_type(value))->m_kind;

type = ASRUtils::TYPE(ASR::make_Integer_t(al, loc, a_kind));
return_var = ASR::make_Variable_t(al, loc,
fn_scope, var_name, nullptr, 0, ASRUtils::intent_local, nullptr, nullptr,
ASR::storage_typeType::Default, type,
nullptr, ASR::abiType::BindC,
ASR::Public, ASR::presenceType::Required, false);
return_var_ref = EXPR(ASR::make_Var_t(al, loc,
down_cast<ASR::symbol_t>(return_var)));
fn_scope->add_symbol(std::string(var_name), down_cast<ASR::symbol_t>(return_var));
target = return_var_ref;
idx++;
} else if (ASRUtils::expr_type(value)->type == ASR::ttypeType::UnsignedInteger) {
s.from_str(al, fn_name_s + std::to_string(idx));
var_name = s.c_str(al);

int a_kind = down_cast<ASR::UnsignedInteger_t>(ASRUtils::expr_type(value))->m_kind;

type = ASRUtils::TYPE(ASR::make_UnsignedInteger_t(al, loc, a_kind));
return_var = ASR::make_Variable_t(al, loc,
fn_scope, var_name, nullptr, 0, ASRUtils::intent_local, nullptr, nullptr,
ASR::storage_typeType::Default, type,
nullptr, ASR::abiType::BindC,
ASR::Public, ASR::presenceType::Required, false);
return_var_ref = EXPR(ASR::make_Var_t(al, loc,
down_cast<ASR::symbol_t>(return_var)));
fn_scope->add_symbol(std::string(var_name), down_cast<ASR::symbol_t>(return_var));
target = return_var_ref;
idx++;
} else if (ASRUtils::expr_type(value)->type == ASR::ttypeType::Logical) {
s.from_str(al, fn_name_s + std::to_string(idx));
var_name = s.c_str(al);

int a_kind = down_cast<ASR::Logical_t>(ASRUtils::expr_type(value))->m_kind;

type = ASRUtils::TYPE(ASR::make_Logical_t(al, loc, a_kind));
return_var = ASR::make_Variable_t(al, loc,
fn_scope, var_name, nullptr, 0, ASRUtils::intent_local, nullptr, nullptr,
ASR::storage_typeType::Default, type,
nullptr, ASR::abiType::BindC,
ASR::Public, ASR::presenceType::Required, false);
return_var_ref = EXPR(ASR::make_Var_t(al, loc,
down_cast<ASR::symbol_t>(return_var)));
fn_scope->add_symbol(std::string(var_name), down_cast<ASR::symbol_t>(return_var));
target = return_var_ref;
idx++;
} else if (ASRUtils::expr_type(value)->type == ASR::ttypeType::Real) {
if ((ASRUtils::expr_type(value)->type == ASR::ttypeType::Integer) ||
(ASRUtils::expr_type(value)->type == ASR::ttypeType::UnsignedInteger) ||
(ASRUtils::expr_type(value)->type == ASR::ttypeType::Logical) ||
(ASRUtils::expr_type(value)->type == ASR::ttypeType::Real) ||
(ASRUtils::expr_type(value)->type == ASR::ttypeType::Complex) ||
(ASRUtils::expr_type(value)->type == ASR::ttypeType::Character) ||
(ASRUtils::expr_type(value)->type == ASR::ttypeType::List) ||
(ASRUtils::expr_type(value)->type == ASR::ttypeType::Tuple)) {
s.from_str(al, fn_name_s + std::to_string(idx));
var_name = s.c_str(al);
type = ASRUtils::expr_type(value);
Expand All @@ -110,22 +66,7 @@ void pass_wrap_global_stmts(Allocator &al,
fn_scope->add_symbol(std::string(var_name), down_cast<ASR::symbol_t>(return_var));
target = return_var_ref;
idx++;
} else if ((ASRUtils::expr_type(value)->type == ASR::ttypeType::Complex) ||
(ASRUtils::expr_type(value)->type == ASR::ttypeType::Character)) {
s.from_str(al, fn_name_s + std::to_string(idx));
var_name = s.c_str(al);
type = ASRUtils::expr_type(value);
return_var = ASR::make_Variable_t(al, loc,
fn_scope, var_name, nullptr, 0, ASRUtils::intent_local, nullptr, nullptr,
ASR::storage_typeType::Default, type,
nullptr, ASR::abiType::BindC,
ASR::Public, ASR::presenceType::Required, false);
return_var_ref = EXPR(ASR::make_Var_t(al, loc,
down_cast<ASR::symbol_t>(return_var)));
fn_scope->add_symbol(std::string(var_name), down_cast<ASR::symbol_t>(return_var));
target = return_var_ref;
idx++;
} else {
} else {
throw LCompilersException("Return type not supported in interactive mode");
}
ASR::stmt_t* asr_stmt = ASRUtils::STMT(ASR::make_Assignment_t(al, loc, target, value, nullptr));
Expand All @@ -141,7 +82,26 @@ void pass_wrap_global_stmts(Allocator &al,

if (return_var) {
// The last defined `return_var` is the actual return value
LCOMPILERS_ASSERT(type)
LCOMPILERS_ASSERT(return_var_ref)

ASR::down_cast2<ASR::Variable_t>(return_var)->m_intent = ASRUtils::intent_return_var;
std::string global_underscore_name = "_" + fn_name_s;
s.from_str(al, global_underscore_name);

ASR::asr_t *global_underscore = ASR::make_Variable_t(al, loc,
unit.m_symtab, s.c_str(al), nullptr, 0, ASRUtils::intent_local, nullptr, nullptr,
ASR::storage_typeType::Default, type,
nullptr, ASR::abiType::Source,
ASR::Public, ASR::presenceType::Required, false);
ASR::expr_t * global_underscore_ref = EXPR(ASR::make_Var_t(al, loc, down_cast<ASR::symbol_t>(global_underscore)));

if (fn_scope->parent->get_symbol(global_underscore_name) != nullptr) {
throw LCompilersException("Global variable already defined");
}
unit.m_symtab->add_symbol(global_underscore_name, down_cast<ASR::symbol_t>(global_underscore));
ASR::stmt_t* asr_stmt = ASRUtils::STMT(ASR::make_Assignment_t(al, loc, global_underscore_ref, return_var_ref, nullptr));
body.push_back(al, asr_stmt);
}

ASR::asr_t *fn = ASRUtils::make_Function_t_util(
Expand Down
163 changes: 159 additions & 4 deletions src/lpython/python_evaluator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
#ifdef HAVE_LFORTRAN_LLVM
#include <libasr/codegen/evaluator.h>
#include <libasr/codegen/asr_to_llvm.h>
#include <llvm/IR/Function.h>
#include <llvm/IR/Type.h>
#include <llvm/IR/DataLayout.h>
#else
namespace LCompilers {
class LLVMEvaluator {};
Expand Down Expand Up @@ -120,10 +123,24 @@ Result<PythonCompiler::EvalResult> PythonCompiler::evaluate(
}

bool call_run_fn = false;
std::string return_type;
if (m->get_return_type(run_fn) != "none") {
call_run_fn = true;
return_type = m->get_return_type(run_fn);
std::string return_type = m->get_return_type(run_fn);
if (return_type != "none") {
call_run_fn = true;
}

ASR::symbol_t *global_underscore_sym = symbol_table->get_symbol("_" + run_fn);
if ((return_type == "struct") && (global_underscore_sym)) {
// we compute the offsets of the struct's attribute here
// we will be using it later in aggregate_type_to_string to print the struct

// we compute the offsets here instead of computing it in aggregate_type_to_string
// because once we call `e->add_module`, internally LLVM may deallocate all the
// type info after compiling the IR into machine code

llvm::Function *fn = m->get_function(run_fn);
llvm::Type *llvm_type = fn->getReturnType();
LCOMPILERS_ASSERT(llvm_type->isStructTy())
compute_offsets(llvm_type, global_underscore_sym, result);
}

e->add_module(std::move(m));
Expand Down Expand Up @@ -213,6 +230,14 @@ Result<PythonCompiler::EvalResult> PythonCompiler::evaluate(
bool r = e->execfn<bool>(run_fn);
result.type = EvalResult::boolean;
result.b = r;
} else if (return_type == "struct") {
e->execfn<void>(run_fn);
if (global_underscore_sym) {
void *r = (void*)e->get_symbol_address("_" + run_fn);
LCOMPILERS_ASSERT(r)
result.structure.structure = r;
result.type = EvalResult::struct_type;
}
} else if (return_type == "void") {
e->execfn<void>(run_fn);
result.type = EvalResult::statement;
Expand Down Expand Up @@ -449,4 +474,134 @@ Result<std::string> PythonCompiler::get_asm(
}


void print_type(ASR::ttype_t *t, void *data, std::string &result);

std::string PythonCompiler::aggregate_type_to_string(const struct EvalResult &r) {
ASR::ttype_t *asr_type = r.structure.ttype;
void *data = r.structure.structure;
size_t *offsets = r.structure.offsets;
size_t element_size = r.structure.element_size;

std::string result;

if (asr_type->type == ASR::ttypeType::List) {
int32_t size = *(int32_t*)(((char*)data)+offsets[0]);
void *array = *(void**)(((char*)data)+offsets[2]);
ASR::ttype_t *element_ttype = ASR::down_cast<ASR::List_t>(asr_type)->m_type;

result += "[";
for (int32_t i = 0; i < size - 1; i++) {
print_type(element_ttype, ((char*)array)+(i*element_size), result);
result += ", ";
}
print_type(element_ttype, ((char*)array)+((size - 1)*element_size), result);
result += "]";

} else {
throw LCompilersException("PythonCompiler::evaluate(): Return type not supported");
}

return result;
}

void PythonCompiler::compute_offsets(llvm::Type *type, ASR::symbol_t *asr_type, EvalResult &result) {
#ifdef HAVE_LFORTRAN_LLVM
LCOMPILERS_ASSERT(type->isStructTy())

const llvm::DataLayout &dl = e->get_jit_data_layout();
size_t elements_count = type->getStructNumElements();
LCompilers::Vec<size_t> offsets;
offsets.reserve(al, elements_count);
for (size_t i = 0; i < elements_count; i++) {
size_t offset = dl.getStructLayout((llvm::StructType*)type)->getElementOffset(i);
offsets.push_back(al, offset);
}
result.structure.offsets = offsets.p;

result.structure.ttype = ASR::down_cast<ASR::Variable_t>(asr_type)->m_type;
if (result.structure.ttype->type == ASR::ttypeType::List) {
type = type->getStructElementType(2);
LCOMPILERS_ASSERT(type->isPointerTy())
result.structure.element_size = e->get_jit_data_layout().getTypeAllocSize(
#if LLVM_VERSION_MAJOR >= 14
type->getNonOpaquePointerElementType()
#else
type->getPointerElementType()
#endif
);
}
#else
throw LCompilersException("LLVM is not enabled");
#endif
}

void print_type(ASR::ttype_t *t, void *data, std::string &result) {
switch (t->type) {
case ASR::ttypeType::Logical:
result += (*(bool*)data ? "True" : "False");
break;
case ASR::ttypeType::Integer: {
int64_t a_kind = ASR::down_cast<ASR::Integer_t>(t)->m_kind;
switch (a_kind) {
case 1:
result += std::to_string(int(*(int8_t*)data));
break;
case 2:
result += std::to_string(*(int16_t*)data);
break;
case 4:
result += std::to_string(*(int32_t*)data);
break;
case 8:
result += std::to_string(*(int64_t*)data);
break;
default:
throw LCompilersException("Unaccepted int size");
}
break;
}
case ASR::ttypeType::UnsignedInteger: {
int64_t a_kind = ASR::down_cast<ASR::UnsignedInteger_t>(t)->m_kind;
switch (a_kind) {
case 1:
result += std::to_string(int(*(uint8_t*)data));
break;
case 2:
result += std::to_string(*(uint16_t*)data);
break;
case 4:
result += std::to_string(*(uint32_t*)data);
break;
case 8:
result += std::to_string(*(uint64_t*)data);
break;
default:
throw LCompilersException("Unaccepted int size");
}
break;
}
case ASR::ttypeType::Real: {
int64_t a_kind = ASR::down_cast<ASR::Real_t>(t)->m_kind;
switch (a_kind) {
case 4:
result += std::to_string(*(float*)data);
break;
case 8:
result += std::to_string(*(double*)data);
break;
default:
throw LCompilersException("Unaccepted real size");
}
break;
}
case ASR::ttypeType::Character:
result += '"';
result += std::string(*(char**)data); // TODO: replace \n with \\n
result += '"';
break;
default:
throw LCompilersException("PythonCompiler::print_type(): type not supported");
}
}

} // namespace LCompilers::LPython
Loading

0 comments on commit ba07d7b

Please sign in to comment.