///|
pub(all) struct Module {
source_file : String
mut llvm_mod : @IR.Module?
arch_config : ArchConfig
functions : Map[String, Function]
all_llvm_functions : Map[String, @IR.Function] // includes external functions
external_functions : Map[String, @IR.Function]
global_values : Array[GlobalValue]
}
///|
pub fn Module::new(arch_config : ArchConfig, source_file? : String) -> Module {
let source_file = match source_file {
None => "demo"
Some(f) => f
}
Module::{
source_file,
llvm_mod: None,
arch_config,
functions: Map::new(),
all_llvm_functions: Map::new(),
external_functions: Map::new(),
global_values: Array::new(),
}
}
///|
pub(all) enum ArgPattern {
I
F
}
///|
///
/// ```mbt
/// let mod = Module::new(ArchConfig::riscv64())
/// let func = mod.add_function("add", [I, I], false)
/// let entry_bb = func.append_basic_block("entry")
/// let builder = IRBuilder::new(func, entry_bb)
///
/// let a0 = func.get_param(0).unwrap()
/// let a1 = func.get_param(1).unwrap()
/// guard a0 is IRegister(a0)
/// guard a1 is IRegister(a1)
///
/// builder.build_ibinary(Add, 32, dst = AReg(0), src1 = a0, src2 = a1)
/// |> BasicBlock::push(entry_bb, _)
///
/// builder.build_ret()
/// |> BasicBlock::push(entry_bb, _)
///
/// let expected =
/// #|func add(a0, a1) {
/// #|entry:
/// #| a0 = add.i32 a0, a1
/// #| ret
/// #|}
/// #|
/// inspect(func, content=expected)
/// ```
pub fn Module::add_function(
self : Self,
name : String,
arg_patterns : Array[ArgPattern],
is_external : Bool,
is_variadic? : Bool = false,
) -> Function {
let func = Function::new(self, name, is_external, is_variadic~)
self.functions.set(name, func)
if arg_patterns.is_empty() {
return func
}
func.set_params_by_patterns(arg_patterns)
func
}
///|
pub fn Module::get_function(self : Self, name : String) -> Function? {
self.functions.get(name)
}
///|
///
/// ```mbt
/// let mod = Module::new(ArchConfig::riscv64())
/// let content = #|Hello, World!\n
/// let gv = mod.add_global_string(label="msg", content~)
///
/// let expected =
/// #|global msg {
/// #| "Hello, World!\n"
/// #|}
/// #|
/// inspect(gv, content=expected)
/// ```
pub fn Module::add_global_string(
self : Self,
label~ : String,
content~ : String,
) -> GlobalValue {
let content = content
.replace(old="\n", new="\\n")
.replace(old="\t", new="\\t")
.replace(old="\r", new="\\r")
let gv = GlobalValue::{
label,
content: GlobalValueContent::String(content),
mod: self,
llvm_gv: None,
}
self.global_values.push(gv)
gv
}
///|
///
/// ```mbt
/// let mod = Module::new(ArchConfig::riscv64())
/// let gv = mod.add_global_zero_data("buffer", 64)
///
/// let expected =
/// #|global buffer {
/// #| .zero 64
/// #|}
/// #|
/// inspect(gv, content=expected)
/// ```
pub fn Module::add_global_zero_data(
self : Self,
label : String,
size : UInt,
) -> GlobalValue {
let gv = GlobalValue::{
label,
content: GlobalValueContent::Zero(size),
mod: self,
llvm_gv: None,
}
self.global_values.push(gv)
gv
}
///|
///
/// ```mbt
/// let mod = Module::new(ArchConfig::riscv64())
/// let data : Array[GlobalValueData] = [
/// Quad(0x1122334455667788),
/// Word(0x99AABBCC),
/// Half(0xDDEE),
/// Byte(0xFF),
/// ]
/// let gv = mod.add_global_data("data", data)
///
/// let expected =
/// #|global data {
/// #| .quad 1234605616436508552
/// #| .word 2578103244
/// #| .half 56814
/// #| .byte 255
/// #|}
/// #|
/// inspect(gv, content=expected)
/// ```
pub fn Module::add_global_data(
self : Self,
label : String,
data : Array[GlobalValueData],
) -> GlobalValue {
let gv = GlobalValue::{
label,
content: GlobalValueContent::Data(data),
mod: self,
llvm_gv: None,
}
self.global_values.push(gv)
gv
}
///|
pub impl Show for Module with output(self, logger) {
logger.write_string("; Source File: \{self.source_file}\n")
logger.write_string("; Architecture: \{self.arch_config.arch_name}\n\n")
for gv in self.global_values {
logger.write_object(gv)
logger.write_string("\n")
}
for _, func in self.functions {
logger.write_object(func)
logger.write_string("\n")
}
}