Skip to content

Commit

Permalink
Improved name mangling
Browse files Browse the repository at this point in the history
Improved file and module handling
Added ability to specify modules in function names and resolve them via that method
Moved postlex stuff into a separate Postlexer.py
Added outer main method supplied by RIAL
Added support for nested directories
Improved global Compilation Manager
Added functions list to structs to collect and keep track of their functions
  • Loading branch information
L3tum committed Apr 13, 2020
1 parent 140f754 commit 25574ae
Show file tree
Hide file tree
Showing 18 changed files with 316 additions and 173 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -127,3 +127,4 @@ dmypy.json
/.benchmarks/

.idea
/.idea/workspace.xml
40 changes: 31 additions & 9 deletions .idea/workspace.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 15 additions & 4 deletions rial/FunctionDeclarationTransformer.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
from typing import List, Tuple

import os
from llvmlite import ir
from llvmlite.ir import FunctionAttributes

from rial.LLVMFunction import LLVMFunction
from rial.SingleParserState import SingleParserState
from rial.concept.metadata_token import MetadataToken
Expand Down Expand Up @@ -90,15 +87,21 @@ def function_decl(self, nodes):
llvm_args.insert(0, ir.PointerType(self.sps.llvmgen.current_struct.struct))
args.insert(0, (self.sps.llvmgen.current_struct.name, "this"))

# Check if main method
if full_function_name.endswith("main:main") and full_function_name.count(':') == 2:
main_function = True

# Check that main method returns either Int32 or void
if return_type != "Int32" and return_type != "void":
log_fail(f"Main method must return an integer status code or void, {return_type} given!")

# If it's external we need to use the actual defined name instead of the compiler-internal one
if external:
full_function_name = name
else:
full_function_name = mangle_function_name(full_function_name, [str(arg) for arg in llvm_args])

# Search for function in the archives
llvm_func = self.sps.ps.search_function(full_function_name)

# Function has been previously declared
Expand All @@ -116,22 +119,30 @@ def function_decl(self, nodes):
log_fail(f"Function {full_function_name} already declared elsewhere")
raise Discard()
else:
# Hasn't been declared previously, redeclare the function type here
llvm_return_type = self.sps.map_type_to_llvm(return_type)

func_type = self.sps.llvmgen.create_function_type(llvm_return_type, llvm_args, var_args)
llvm_func = LLVMFunction(full_function_name, func_type, access_modifier, self.sps.llvmgen.module.name,
return_type)
self.sps.ps.functions[full_function_name] = llvm_func
self.sps.ps.main_function = llvm_func

# Create the actual function in IR
func = self.sps.llvmgen.create_function_with_type(full_function_name, llvm_func.function_type, linkage,
calling_convention,
list(map(lambda arg: arg[1], args)),
has_body, access_modifier,
llvm_func.rial_return_type)

# Always inline the main function into the compiler supplied one
if main_function:
func.attributes.add('alwaysinline')

# If it's in a struct or class we add it to that struct archives
if self.sps.llvmgen.current_struct is not None:
self.sps.llvmgen.current_struct.functions.append(func)

# If it has no body we do not need to go through it later as it's already declared with this method.
if not has_body:
raise Discard()

Expand Down
6 changes: 5 additions & 1 deletion rial/LLVMStruct.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Optional, Dict, Tuple
from typing import Optional, Dict, Tuple, List

from llvmlite.ir import BaseStructType, Function

Expand All @@ -13,6 +13,8 @@ class LLVMStruct:
properties: Dict[str, Tuple[int, RIALVariable]]
constructor: Optional[Function]
destructor: Optional[Function]
base_structs: List
functions: List[Function]

def __init__(self, struct: BaseStructType, name: str, access_modifier: RIALAccessModifier):
self.struct = struct
Expand All @@ -21,3 +23,5 @@ def __init__(self, struct: BaseStructType, name: str, access_modifier: RIALAcces
self.properties = dict()
self.constructor = None
self.destructor = None
self.base_structs = list()
self.functions = list()
1 change: 1 addition & 0 deletions rial/ParserState.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ class ParserState(object):
functions: Dict[str, LLVMFunction]
implemented_functions: List[str]
structs: Dict[str, LLVMStruct]
main_function: LLVMFunction

def __init__(self):
self.functions = dict()
Expand Down
48 changes: 30 additions & 18 deletions rial/SingleParserState.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from rial.LLVMGen import LLVMGen
from rial.ParserState import ParserState
from rial.builtin_type_to_llvm_mapper import map_type_to_llvm
from rial.compilation_manager import CompilationManager
from rial.log import log_fail
from rial.rial_types.RIALAccessModifier import RIALAccessModifier

Expand All @@ -27,7 +28,8 @@ def find_function(self, full_function_name: str) -> Optional[Function]:

# Try to find function in current module with module specifier
if func is None:
func = next((func for func in self.llvmgen.module.functions if func.name == f"{self.llvmgen.module.name}:{full_function_name}"), None)
func = next((func for func in self.llvmgen.module.functions if
func.name == f"{self.llvmgen.module.name}:{full_function_name}"), None)

# If func isn't in current module
if func is None:
Expand All @@ -44,30 +46,40 @@ def find_function(self, full_function_name: str) -> Optional[Function]:
continue
functions_found.append((use, llvm_function,))

# Check for number of functions found
if len(functions_found) == 0:
return None

if len(functions_found) > 1:
log_fail(f"Function {full_function_name} has been declared multiple times!")
log_fail(f"Specify the specific function to use by adding the namespace to the function call")
log_fail(f"E.g. {functions_found[0][0]}:{full_function_name}()")
return None

llvm_function = functions_found[0][1]

# Function is either:
# - public or
# - internal and
# - in same TLM
if llvm_function.access_modifier != RIALAccessModifier.PUBLIC and \
(llvm_function.access_modifier != RIALAccessModifier.INTERNAL and llvm_function.module.split(':')[0]
== self.llvmgen.module.name.split(':')[0]):
log_fail(
f"Cannot access method {full_function_name} in module {llvm_function.module}!")
return None
# Check for number of functions found
if len(functions_found) == 1:
llvm_function = functions_found[0][1]

if llvm_function is not None:
# Function is either:
# - public or
# - internal and
# - in same TLM
if llvm_function.access_modifier != RIALAccessModifier.PUBLIC and \
(llvm_function.access_modifier != RIALAccessModifier.INTERNAL and
llvm_function.module.split(':')[0]
== self.llvmgen.module.name.split(':')[0]):
log_fail(
f"Cannot access method {full_function_name} in module {llvm_function.module}!")
return None

func = ir.Function(self.llvmgen.module, llvm_function.function_type, name=llvm_function.name)

# Try request the module that the function might(!) be in
if func is None:
if ":" in full_function_name:
mod_name = ':'.join(full_function_name.split(':')[0:-1])

func = ir.Function(self.llvmgen.module, llvm_function.function_type, name=llvm_function.name)
# Check that the module hasn't been compiled yet
if not CompilationManager.check_module_already_compiled(mod_name):
CompilationManager.request_module(mod_name)
return self.find_function(full_function_name)

return func

Expand Down
3 changes: 3 additions & 0 deletions rial/builtin/start.rial
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
public void main(){
#programMain();
}
2 changes: 0 additions & 2 deletions rial/builtin_type_to_llvm_mapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,6 @@ def map_shortcut_to_type(shortcut: str) -> str:


def map_type_to_llvm(rial_type: str) -> Optional[Type]:
rial_type = map_shortcut_to_type(rial_type)

if rial_type == "Int32":
# 32bit integer
return ir.IntType(32)
Expand Down
9 changes: 9 additions & 0 deletions rial/codegen.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import traceback
from pathlib import Path
from threading import Lock
from typing import Optional

Expand Down Expand Up @@ -107,18 +108,26 @@ def generate_final_module(self, mod: ModuleRef):
self.engine.run_static_constructors()
self.engine.remove_module(mod)

def _check_dirs_exist(self, dest: str):
directory = '/'.join(dest.split("/")[0:-1])
Path(directory).mkdir(parents=True, exist_ok=True)

def save_ir(self, dest: str, module: ModuleRef):
self._check_dirs_exist(dest)
with open(dest, "w") as file:
file.write(str(module))

def save_object(self, dest: str, module: ModuleRef):
self._check_dirs_exist(dest)
with open(dest, "wb") as file:
file.write(self.target_machine.emit_object(module))

def save_assembly(self, dest: str, module: ModuleRef):
self._check_dirs_exist(dest)
with open(dest, "w") as file:
file.write(self.target_machine.emit_assembly(module))

def save_llvm_bitcode(self, dest: str, module: ModuleRef):
self._check_dirs_exist(dest)
with open(dest, "wb") as file:
file.write(module.as_bitcode())
Loading

0 comments on commit 25574ae

Please sign in to comment.