Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix ASR verify pass error while using Interactive #2706

Merged
merged 13 commits into from
Jun 8, 2024
14 changes: 14 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,20 @@ if (WITH_LCOMPILERS_FAST_ALLOC)
add_definitions("-DLCOMPILERS_FAST_ALLOC=1")
endif()

# copy runtime files
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/src/runtime/lpython/lpython.py" "${CMAKE_CURRENT_BINARY_DIR}/src/runtime/lpython/lpython.py")
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/src/runtime/cmath.py" "${CMAKE_CURRENT_BINARY_DIR}/src/runtime/cmath.py")
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/src/runtime/lpython_builtin.py" "${CMAKE_CURRENT_BINARY_DIR}/src/runtime/lpython_builtin.py")
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/src/runtime/lpython_intrinsic_numpy.py" "${CMAKE_CURRENT_BINARY_DIR}/src/runtime/lpython_intrinsic_numpy.py")
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/src/runtime/lpython_parser.py" "${CMAKE_CURRENT_BINARY_DIR}/src/runtime/lpython_parser.py")
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/src/runtime/math.py" "${CMAKE_CURRENT_BINARY_DIR}/src/runtime/math.py")
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/src/runtime/os.py" "${CMAKE_CURRENT_BINARY_DIR}/src/runtime/os.py")
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/src/runtime/platform.py" "${CMAKE_CURRENT_BINARY_DIR}/src/runtime/platform.py")
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/src/runtime/random.py" "${CMAKE_CURRENT_BINARY_DIR}/src/runtime/random.py")
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/src/runtime/statistics.py" "${CMAKE_CURRENT_BINARY_DIR}/src/runtime/statistics.py")
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/src/runtime/sys.py" "${CMAKE_CURRENT_BINARY_DIR}/src/runtime/sys.py")
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/src/runtime/time.py" "${CMAKE_CURRENT_BINARY_DIR}/src/runtime/time.py")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if its a good idea to copy these. As of now, where does lpython look for these? Can we update lpython to look into the correct location?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copying is the safest thing to do. Right now it uses relative path from the executable's location to figure out the runtime file's path.

The reason I say it is a safe option is because the user building the LPython may set the CMAKE_CURRENT_BINARY_DIR to a completely different folder. For example, in Windows, I may want to store the source files in D drive and the compiled executable in C drive.


# LLVM
set(WITH_LLVM no CACHE BOOL "Build with LLVM support")
set(WITH_TARGET_AARCH64 no CACHE BOOL "Enable target AARCH64")
Expand Down
11 changes: 8 additions & 3 deletions src/libasr/asr_scopes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include <libasr/asr_scopes.h>
#include <libasr/asr_utils.h>
#include <libasr/pass/pass_utils.h>

std::string lcompilers_unique_ID;

Expand Down Expand Up @@ -39,9 +40,13 @@ void SymbolTable::mark_all_variables_external(Allocator &al) {
case (ASR::symbolType::Function) : {
ASR::Function_t *v = ASR::down_cast<ASR::Function_t>(a.second);
ASR::FunctionType_t* v_func_type = ASR::down_cast<ASR::FunctionType_t>(v->m_function_signature);
v_func_type->m_abi = ASR::abiType::Interactive;
v->m_body = nullptr;
v->n_body = 0;
if (v_func_type->m_abi != ASR::abiType::Interactive) {
v_func_type->m_abi = ASR::abiType::Interactive;
v->m_body = nullptr;
v->n_body = 0;
PassUtils::UpdateDependenciesVisitor ud(al);
ud.visit_Function(*v);
}
break;
}
case (ASR::symbolType::Module) : {
Expand Down
5 changes: 5 additions & 0 deletions src/libasr/asr_verify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,11 @@ class VerifyVisitor : public BaseWalkVisitor<VerifyVisitor>
}

void visit_Function(const Function_t &x) {
ASR::FunctionType_t* x_func_type = ASR::down_cast<ASR::FunctionType_t>(x.m_function_signature);
if (x_func_type->m_abi == abiType::Interactive) {
require(x.n_body == 0,
"The Function::n_body should be 0 if abi set to Interactive");
}
std::vector<std::string> function_dependencies_copy = function_dependencies;
function_dependencies.clear();
function_dependencies.reserve(x.n_dependencies);
Expand Down
77 changes: 40 additions & 37 deletions src/libasr/codegen/KaleidoscopeJIT.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@
#include "llvm/IR/LLVMContext.h"
#include <memory>

#if LLVM_VERSION_MAJOR >= 13
#include "llvm/ExecutionEngine/Orc/ExecutorProcessControl.h"
#endif

#if LLVM_VERSION_MAJOR >= 16
# define RM_OPTIONAL_TYPE std::optional
#else
Expand All @@ -37,77 +41,76 @@ namespace orc {

class KaleidoscopeJIT {
private:
ExecutionSession ES;
std::unique_ptr<ExecutionSession> ES;
RTDyldObjectLinkingLayer ObjectLayer;
IRCompileLayer CompileLayer;

DataLayout DL;
MangleAndInterner Mangle;
ThreadSafeContext Ctx;
JITDylib &JITDL;

TargetMachine *TM;

public:
KaleidoscopeJIT(JITTargetMachineBuilder JTMB, DataLayout DL)
KaleidoscopeJIT(std::unique_ptr<ExecutionSession> ES, JITTargetMachineBuilder JTMB, DataLayout DL)
:
#if LLVM_VERSION_MAJOR >= 13
ES(cantFail(SelfExecutorProcessControl::Create())),
#endif
ObjectLayer(ES,
ES(std::move(ES)),
ObjectLayer(*this->ES,
[]() { return std::make_unique<SectionMemoryManager>(); }),
CompileLayer(ES, ObjectLayer, std::make_unique<ConcurrentIRCompiler>(ConcurrentIRCompiler(std::move(JTMB)))),
DL(std::move(DL)), Mangle(ES, this->DL),
Ctx(std::make_unique<LLVMContext>()),
CompileLayer(*this->ES, ObjectLayer, std::make_unique<ConcurrentIRCompiler>(std::move(JTMB))),
DL(std::move(DL)), Mangle(*this->ES, this->DL),
JITDL(
#if LLVM_VERSION_MAJOR >= 11
cantFail
#endif
(ES.createJITDylib("Main"))) {
(this->ES->createJITDylib("Main"))) {
JITDL.addGenerator(
cantFail(DynamicLibrarySearchGenerator::GetForCurrentProcess(
DL.getGlobalPrefix())));

std::string Error;
auto TargetTriple = sys::getDefaultTargetTriple();
auto Target = TargetRegistry::lookupTarget(TargetTriple, Error);
if (!Target) {
throw std::runtime_error("Failed to lookup the target");
if (JTMB.getTargetTriple().isOSBinFormatCOFF()) {
ObjectLayer.setOverrideObjectFlagsWithResponsibilityFlags(true);
ObjectLayer.setAutoClaimResponsibilityForObjectSymbols(true);
}
auto CPU = "generic";
auto Features = "";
TargetOptions opt;
auto RM = RM_OPTIONAL_TYPE<Reloc::Model>();
TM = Target->createTargetMachine(TargetTriple, CPU, Features, opt, RM);
}

static Expected<std::unique_ptr<KaleidoscopeJIT>> Create() {
auto JTMB = JITTargetMachineBuilder::detectHost();
#if LLVM_VERSION_MAJOR >= 13
auto EPC = SelfExecutorProcessControl::Create();
if (!EPC)
return EPC.takeError();

if (!JTMB)
return JTMB.takeError();
auto ES = std::make_unique<ExecutionSession>(std::move(*EPC));

auto DL = JTMB->getDefaultDataLayoutForTarget();
JITTargetMachineBuilder JTMB(
ES->getExecutorProcessControl().getTargetTriple());
#else
auto ES = std::make_unique<ExecutionSession>();

auto JTMB_P = JITTargetMachineBuilder::detectHost();
if (!JTMB_P)
return JTMB_P.takeError();

auto JTMB = *JTMB_P;
#endif

auto DL = JTMB.getDefaultDataLayoutForTarget();
if (!DL)
return DL.takeError();

return std::make_unique<KaleidoscopeJIT>(std::move(*JTMB), std::move(*DL));
return std::make_unique<KaleidoscopeJIT>(std::move(ES), std::move(JTMB),
std::move(*DL));
}

const DataLayout &getDataLayout() const { return DL; }

LLVMContext &getContext() { return *Ctx.getContext(); }

Error addModule(std::unique_ptr<Module> M) {
return CompileLayer.add(JITDL,
ThreadSafeModule(std::move(M), Ctx));
Error addModule(std::unique_ptr<Module> M, std::unique_ptr<LLVMContext> &Ctx) {
auto res = CompileLayer.add(JITDL,
ThreadSafeModule(std::move(M), std::move(Ctx)));
Ctx = std::make_unique<LLVMContext>();
return res;
}

Expected<JITEvaluatedSymbol> lookup(StringRef Name) {
return ES.lookup({&JITDL}, Mangle(Name.str()));
return ES->lookup({&JITDL}, Mangle(Name.str()));
}

TargetMachine &getTargetMachine() { return *TM; }
};

} // end namespace orc
Expand Down
6 changes: 3 additions & 3 deletions src/libasr/codegen/evaluator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ std::unique_ptr<llvm::Module> LLVMEvaluator::parse_module(const std::string &sou
throw LCompilersException("parse_module(): module failed verification.");
};
module->setTargetTriple(target_triple);
module->setDataLayout(jit->getTargetMachine().createDataLayout());
module->setDataLayout(jit->getDataLayout());
return module;
}

Expand All @@ -234,7 +234,7 @@ void LLVMEvaluator::add_module(std::unique_ptr<llvm::Module> mod) {
// cases when the Module was constructed directly, not via parse_module().
mod->setTargetTriple(target_triple);
mod->setDataLayout(jit->getDataLayout());
llvm::Error err = jit->addModule(std::move(mod));
llvm::Error err = jit->addModule(std::move(mod), context);
if (err) {
llvm::SmallVector<char, 128> buf;
llvm::raw_svector_ostream dest(buf);
Expand Down Expand Up @@ -354,7 +354,7 @@ std::string LLVMEvaluator::get_asm(llvm::Module &m)
llvm::CodeGenFileType ft = llvm::CGFT_AssemblyFile;
llvm::SmallVector<char, 128> buf;
llvm::raw_svector_ostream dest(buf);
if (jit->getTargetMachine().addPassesToEmitFile(pass, dest, nullptr, ft)) {
if (TM->addPassesToEmitFile(pass, dest, nullptr, ft)) {
throw std::runtime_error("TargetMachine can't emit a file of this type");
}
pass.run(m);
Expand Down
2 changes: 1 addition & 1 deletion src/libasr/string_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ std::string read_file(const std::string &filename)
std::vector<char> bytes(filesize);
ifs.read(&bytes[0], filesize);

return std::string(&bytes[0], filesize);
return replace(std::string(&bytes[0], filesize), "\r\n", "\n");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's open an issue that our tokenizer/parser should be updated/fixed to produce the same tokens/parse-tree on windows and unix.

}

std::string parent_path(const std::string &path) {
Expand Down
130 changes: 130 additions & 0 deletions src/lpython/tests/test_llvm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -624,6 +624,25 @@ TEST_CASE("PythonCompiler 1") {
CHECK(r.result.i32 == 1);
}

TEST_CASE("PythonCompiler 2") {
CompilerOptions cu;
cu.po.disable_main = true;
cu.emit_debug_line_column = false;
cu.generate_object_code = false;
cu.interactive = true;
cu.po.runtime_library_dir = LCompilers::LPython::get_runtime_library_dir();
PythonCompiler e(cu);
LCompilers::Result<PythonCompiler::EvalResult>

r = e.evaluate2("i: i32 = 3 % 2");
CHECK(r.ok);
CHECK(r.result.type == PythonCompiler::EvalResult::none);
r = e.evaluate2("i");
CHECK(r.ok);
CHECK(r.result.type == PythonCompiler::EvalResult::integer4);
CHECK(r.result.i32 == 1);
}

TEST_CASE("PythonCompiler i32 expressions") {
CompilerOptions cu;
cu.po.disable_main = true;
Expand Down Expand Up @@ -845,6 +864,7 @@ TEST_CASE("PythonCompiler u32 declaration") {
r = e.evaluate2("i: u32");
CHECK(r.ok);
CHECK(r.result.type == PythonCompiler::EvalResult::none);

r = e.evaluate2("i = u32(5)");
CHECK(r.ok);
CHECK(r.result.type == PythonCompiler::EvalResult::statement);
Expand Down Expand Up @@ -1358,3 +1378,113 @@ def my_concat(x: str, y: str) -> str:
CHECK(r.result.type == PythonCompiler::EvalResult::string);
CHECK(std::strcmp(r.result.str, "Python REPL") == 0);
}

TEST_CASE("PythonCompiler asr verify 1") {
CompilerOptions cu;
cu.po.disable_main = true;
cu.emit_debug_line_column = false;
cu.generate_object_code = false;
cu.interactive = true;
cu.po.runtime_library_dir = LCompilers::LPython::get_runtime_library_dir();
PythonCompiler e(cu);
LCompilers::Result<PythonCompiler::EvalResult>

r = e.evaluate2("i: i32 = 3 % 2");
CHECK(r.ok);
CHECK(r.result.type == PythonCompiler::EvalResult::none);
r = e.evaluate2("i");
CHECK(r.ok);
CHECK(r.result.type == PythonCompiler::EvalResult::integer4);
CHECK(r.result.i32 == 1);
}

TEST_CASE("PythonCompiler asr verify 2") {
CompilerOptions cu;
cu.po.disable_main = true;
cu.emit_debug_line_column = false;
cu.generate_object_code = false;
cu.interactive = true;
cu.po.runtime_library_dir = LCompilers::LPython::get_runtime_library_dir();
PythonCompiler e(cu);
LCompilers::Result<PythonCompiler::EvalResult>
r = e.evaluate2(R"(
def is_even(x: i32) -> i32:
if x % 2 == 0:
return 1
return 0
)");
CHECK(r.ok);
CHECK(r.result.type == PythonCompiler::EvalResult::none);
r = e.evaluate2("is_even(4)");
CHECK(r.ok);
CHECK(r.result.type == PythonCompiler::EvalResult::integer4);
CHECK(r.result.i32 == 1);
r = e.evaluate2("is_even(3)");
CHECK(r.ok);
CHECK(r.result.type == PythonCompiler::EvalResult::integer4);
CHECK(r.result.i32 == 0);
}

TEST_CASE("PythonCompiler asr verify 3") {
CompilerOptions cu;
cu.po.disable_main = true;
cu.emit_debug_line_column = false;
cu.generate_object_code = false;
cu.interactive = true;
cu.po.runtime_library_dir = LCompilers::LPython::get_runtime_library_dir();
PythonCompiler e(cu);
LCompilers::Result<PythonCompiler::EvalResult>

r = e.evaluate2(R"(
def addi(x: i32, y: i32) -> i32:
return x + y
)");
CHECK(r.ok);
CHECK(r.result.type == PythonCompiler::EvalResult::none);
r = e.evaluate2(R"(
def subi(x: i32, y: i32) -> i32:
return addi(x, -y)
)");
CHECK(r.ok);
CHECK(r.result.type == PythonCompiler::EvalResult::none);
r = e.evaluate2("addi(2, 3)");
CHECK(r.ok);
CHECK(r.result.type == PythonCompiler::EvalResult::integer4);
CHECK(r.result.i32 == 5);
r = e.evaluate2("subi(2, 3)");
CHECK(r.ok);
CHECK(r.result.type == PythonCompiler::EvalResult::integer4);
CHECK(r.result.i32 == -1);
}

TEST_CASE("PythonCompiler asr verify 4") {
CompilerOptions cu;
cu.po.disable_main = true;
cu.emit_debug_line_column = false;
cu.generate_object_code = false;
cu.interactive = true;
cu.po.runtime_library_dir = LCompilers::LPython::get_runtime_library_dir();
PythonCompiler e(cu);
LCompilers::Result<PythonCompiler::EvalResult>

r = e.evaluate2(R"(
def addr(x: f64, y: f64) -> f64:
return x + y
)");
CHECK(r.ok);
CHECK(r.result.type == PythonCompiler::EvalResult::none);
r = e.evaluate2(R"(
def subr(x: f64, y: f64) -> f64:
return addr(x, -y)
)");
CHECK(r.ok);
CHECK(r.result.type == PythonCompiler::EvalResult::none);
r = e.evaluate2("addr(2.5, 3.5)");
CHECK(r.ok);
CHECK(r.result.type == PythonCompiler::EvalResult::real8);
CHECK(r.result.f64 == 6);
r = e.evaluate2("subr(2.5, 3.5)");
CHECK(r.ok);
CHECK(r.result.type == PythonCompiler::EvalResult::real8);
CHECK(r.result.f64 == -1);
}
1 change: 0 additions & 1 deletion src/runtime/lpython_builtin.py
Original file line number Diff line number Diff line change
Expand Up @@ -1143,4 +1143,3 @@ def list(s: str) -> list[str]:
for i in range(len(s)):
l.append(s[i])
return l

2 changes: 1 addition & 1 deletion src/runtime/platform.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ def python_implementation() -> str:
return "LPython"

def python_version() -> str:
return __LPYTHON_VERSION__
return __LPYTHON_VERSION__
Loading