Add StrCat support and update hello-zig to support dev backend

This commit is contained in:
Brendan Hansknecht 2021-09-18 15:55:04 -07:00
parent 2f24067267
commit d1021d652d
6 changed files with 186 additions and 94 deletions

View file

@ -226,6 +226,7 @@ impl CallConv<AArch64GeneralReg, AArch64FloatReg> for AArch64Call {
#[inline(always)]
fn load_args<'a>(
_buf: &mut Vec<'a, u8>,
_symbol_map: &mut MutMap<Symbol, SymbolStorage<AArch64GeneralReg, AArch64FloatReg>>,
_args: &'a [(Layout<'a>, Symbol)],
_ret_layout: &Layout<'a>,

View file

@ -48,6 +48,7 @@ pub trait CallConv<GeneralReg: RegTrait, FloatReg: RegTrait> {
// load_args updates the symbol map to know where every arg is stored.
fn load_args<'a>(
buf: &mut Vec<'a, u8>,
symbol_map: &mut MutMap<Symbol, SymbolStorage<GeneralReg, FloatReg>>,
args: &'a [(Layout<'a>, Symbol)],
// ret_layout is needed because if it is a complex type, we pass a pointer as the first arg.
@ -422,7 +423,12 @@ impl<
args: &'a [(Layout<'a>, Symbol)],
ret_layout: &Layout<'a>,
) -> Result<(), String> {
CC::load_args(&mut self.symbol_storage_map, args, ret_layout)?;
CC::load_args(
&mut self.buf,
&mut self.symbol_storage_map,
args,
ret_layout,
)?;
// Update used and free regs.
for (sym, storage) in &self.symbol_storage_map {
match storage {
@ -1063,7 +1069,7 @@ impl<
Layout::Builtin(Builtin::Str) => {
if self.symbol_storage_map.contains_key(&Symbol::RET_POINTER) {
// This will happen on windows, return via pointer here.
Err("Returning strings via pointer not yet implemented".to_string())
return Err("Returning strings via pointer not yet implemented".to_string());
} else {
ASM::mov_reg64_base32(&mut self.buf, CC::GENERAL_RETURN_REGS[0], *offset);
ASM::mov_reg64_base32(
@ -1071,7 +1077,6 @@ impl<
CC::GENERAL_RETURN_REGS[1],
*offset + 8,
);
Ok(())
}
}
Layout::Struct(field_layouts) => {

View file

@ -177,6 +177,7 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg> for X86_64SystemV {
#[inline(always)]
fn load_args<'a>(
buf: &mut Vec<'a, u8>,
symbol_map: &mut MutMap<Symbol, SymbolStorage<X86_64GeneralReg, X86_64FloatReg>>,
args: &'a [(Layout<'a>, Symbol)],
ret_layout: &Layout<'a>,
@ -231,6 +232,29 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg> for X86_64SystemV {
);
}
}
Layout::Builtin(Builtin::Str) => {
if general_i + 1 < Self::GENERAL_PARAM_REGS.len() {
// Load the value to the param reg.
let dst1 = Self::GENERAL_PARAM_REGS[general_i];
let dst2 = Self::GENERAL_PARAM_REGS[general_i + 1];
base_offset += 16;
X86_64Assembler::mov_reg64_base32(buf, dst1, base_offset - 8);
X86_64Assembler::mov_reg64_base32(buf, dst2, base_offset);
symbol_map.insert(
*sym,
SymbolStorage::Base {
offset: base_offset,
size: 16,
owned: true,
},
);
general_i += 2;
} else {
return Err(
"loading strings args on the stack is not yet implemented".to_string()
);
}
}
Layout::Struct(&[]) => {}
x => {
return Err(format!(
@ -257,7 +281,7 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg> for X86_64SystemV {
// For most return layouts we will do nothing.
// In some cases, we need to put the return address as the first arg.
match ret_layout {
Layout::Builtin(single_register_builtins!()) => {}
Layout::Builtin(single_register_builtins!() | Builtin::Str) => {}
x => {
return Err(format!(
"receiving return type, {:?}, is not yet implemented",
@ -373,6 +397,32 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg> for X86_64SystemV {
stack_offset += 8;
}
}
Layout::Builtin(Builtin::Str) => {
if general_i + 1 < Self::GENERAL_PARAM_REGS.len() {
// Load the value to the param reg.
let dst1 = Self::GENERAL_PARAM_REGS[general_i];
let dst2 = Self::GENERAL_PARAM_REGS[general_i + 1];
match symbol_map
.get(&args[i])
.ok_or("function argument does not reference any symbol")?
{
SymbolStorage::Base { offset, .. } => {
X86_64Assembler::mov_reg64_base32(buf, dst1, *offset);
X86_64Assembler::mov_reg64_base32(buf, dst2, *offset + 8);
}
_ => {
return Err("Strings only support being loaded from base offsets"
.to_string());
}
}
general_i += 2;
} else {
return Err(
"calling functions with strings on the stack is not yet implemented"
.to_string(),
);
}
}
Layout::Struct(&[]) => {}
x => {
return Err(format!(
@ -516,6 +566,7 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg> for X86_64WindowsFastcall {
#[inline(always)]
fn load_args<'a>(
_buf: &mut Vec<'a, u8>,
symbol_map: &mut MutMap<Symbol, SymbolStorage<X86_64GeneralReg, X86_64FloatReg>>,
args: &'a [(Layout<'a>, Symbol)],
ret_layout: &Layout<'a>,
@ -535,9 +586,18 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg> for X86_64WindowsFastcall {
Layout::Builtin(single_register_integers!()) => {
symbol_map
.insert(*sym, SymbolStorage::GeneralReg(Self::GENERAL_PARAM_REGS[i]));
i += 1;
}
Layout::Builtin(single_register_floats!()) => {
symbol_map.insert(*sym, SymbolStorage::FloatReg(Self::FLOAT_PARAM_REGS[i]));
i += 1;
}
Layout::Builtin(Builtin::Str) => {
// I think this just needs to be passed on the stack, so not a huge deal.
return Err(
"Passing str args with Windows fast call not yet implemented."
.to_string(),
);
}
Layout::Struct(&[]) => {}
x => {
@ -547,7 +607,6 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg> for X86_64WindowsFastcall {
));
}
}
i += 1;
} else {
base_offset += match layout {
Layout::Builtin(single_register_builtins!()) => 8,
@ -580,7 +639,6 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg> for X86_64WindowsFastcall {
ret_layout: &Layout<'a>,
) -> Result<u32, String> {
let mut stack_offset = Self::SHADOW_SPACE_SIZE as i32;
let mut reg_i = 0;
// For most return layouts we will do nothing.
// In some cases, we need to put the return address as the first arg.
match ret_layout {
@ -597,7 +655,7 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg> for X86_64WindowsFastcall {
Layout::Builtin(single_register_integers!()) => {
if i < Self::GENERAL_PARAM_REGS.len() {
// Load the value to the param reg.
let dst = Self::GENERAL_PARAM_REGS[reg_i];
let dst = Self::GENERAL_PARAM_REGS[i];
match symbol_map
.get(&args[i])
.ok_or("function argument does not reference any symbol")?
@ -615,7 +673,6 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg> for X86_64WindowsFastcall {
)
}
}
reg_i += 1;
} else {
// Load the value to the stack.
match symbol_map
@ -651,7 +708,7 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg> for X86_64WindowsFastcall {
Layout::Builtin(single_register_floats!()) => {
if i < Self::FLOAT_PARAM_REGS.len() {
// Load the value to the param reg.
let dst = Self::FLOAT_PARAM_REGS[reg_i];
let dst = Self::FLOAT_PARAM_REGS[i];
match symbol_map
.get(&args[i])
.ok_or("function argument does not reference any symbol")?
@ -668,7 +725,6 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg> for X86_64WindowsFastcall {
return Err("Cannot load general symbol into FloatReg".to_string())
}
}
reg_i += 1;
} else {
// Load the value to the stack.
match symbol_map
@ -700,6 +756,12 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg> for X86_64WindowsFastcall {
stack_offset += 8;
}
}
Layout::Builtin(Builtin::Str) => {
// I think this just needs to be passed on the stack, so not a huge deal.
return Err(
"Passing str args with Windows fast call not yet implemented.".to_string(),
);
}
Layout::Struct(&[]) => {}
x => {
return Err(format!(

View file

@ -93,12 +93,8 @@ where
for (layout, sym) in proc.args {
self.set_layout_map(*sym, layout)?;
}
// let start = std::time::Instant::now();
self.scan_ast(&proc.body);
self.create_free_map();
// let duration = start.elapsed();
// println!("Time to calculate lifetimes: {:?}", duration);
// println!("{:?}", self.last_seen_map());
self.build_stmt(&proc.body, &proc.ret_layout)?;
self.finalize()
}
@ -119,6 +115,11 @@ where
self.free_symbols(stmt)?;
Ok(())
}
Stmt::Refcounting(_modify, following) => {
// TODO: actually deal with refcounting. For hello world, we just skipped it.
self.build_stmt(following, ret_layout)?;
Ok(())
}
Stmt::Switch {
cond_symbol,
cond_layout,
@ -298,6 +299,13 @@ where
arg_layouts,
ret_layout,
),
Symbol::STR_CONCAT => self.build_run_low_level(
sym,
&LowLevel::StrConcat,
arguments,
arg_layouts,
ret_layout,
),
x if x
.module_string(&self.env().interns)
.starts_with(ModuleName::APP) =>
@ -470,6 +478,13 @@ where
arg_layouts,
ret_layout,
),
LowLevel::StrConcat => self.build_fn_call(
sym,
bitcode::STR_CONCAT.to_string(),
args,
arg_layouts,
ret_layout,
),
x => Err(format!("low level, {:?}. is not yet implemented", x)),
}
}