mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-30 07:14:46 +00:00
use unimplemented! and internal_error! instead of result in dev backend
This commit is contained in:
parent
dd1245dee6
commit
a63dd1eb61
9 changed files with 381 additions and 578 deletions
|
@ -5,6 +5,7 @@ use packed_struct::prelude::*;
|
|||
use roc_collections::all::MutMap;
|
||||
use roc_module::symbol::Symbol;
|
||||
use roc_mono::layout::Layout;
|
||||
use roc_reporting::internal_error;
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
|
||||
#[allow(dead_code)]
|
||||
|
@ -151,13 +152,15 @@ impl CallConv<AArch64GeneralReg, AArch64FloatReg> for AArch64Call {
|
|||
saved_regs: &[AArch64GeneralReg],
|
||||
requested_stack_size: i32,
|
||||
fn_call_stack_size: i32,
|
||||
) -> Result<i32, String> {
|
||||
) -> i32 {
|
||||
// Full size is upcast to i64 to make sure we don't overflow here.
|
||||
let full_stack_size = requested_stack_size
|
||||
let full_stack_size = match requested_stack_size
|
||||
.checked_add(8 * saved_regs.len() as i32 + 8) // The extra 8 is space to store the frame pointer.
|
||||
.ok_or("Ran out of stack space")?
|
||||
.checked_add(fn_call_stack_size)
|
||||
.ok_or("Ran out of stack space")?;
|
||||
.and_then(|size| size.checked_add(fn_call_stack_size))
|
||||
{
|
||||
Some(size) => size,
|
||||
_ => internal_error!("Ran out of stack space"),
|
||||
};
|
||||
let alignment = if full_stack_size <= 0 {
|
||||
0
|
||||
} else {
|
||||
|
@ -194,12 +197,12 @@ impl CallConv<AArch64GeneralReg, AArch64FloatReg> for AArch64Call {
|
|||
offset -= 8;
|
||||
AArch64Assembler::mov_base32_reg64(buf, offset, *reg);
|
||||
}
|
||||
Ok(aligned_stack_size)
|
||||
aligned_stack_size
|
||||
} else {
|
||||
Ok(0)
|
||||
0
|
||||
}
|
||||
} else {
|
||||
Err("Ran out of stack space".to_string())
|
||||
internal_error!("Ran out of stack space");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -209,7 +212,7 @@ impl CallConv<AArch64GeneralReg, AArch64FloatReg> for AArch64Call {
|
|||
saved_regs: &[AArch64GeneralReg],
|
||||
aligned_stack_size: i32,
|
||||
fn_call_stack_size: i32,
|
||||
) -> Result<(), String> {
|
||||
) {
|
||||
if aligned_stack_size > 0 {
|
||||
// All the following stores could be optimized by using `STP` to store pairs.
|
||||
let mut offset = aligned_stack_size;
|
||||
|
@ -230,7 +233,6 @@ impl CallConv<AArch64GeneralReg, AArch64FloatReg> for AArch64Call {
|
|||
aligned_stack_size,
|
||||
);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
|
@ -239,8 +241,8 @@ impl CallConv<AArch64GeneralReg, AArch64FloatReg> for AArch64Call {
|
|||
_symbol_map: &mut MutMap<Symbol, SymbolStorage<AArch64GeneralReg, AArch64FloatReg>>,
|
||||
_args: &'a [(Layout<'a>, Symbol)],
|
||||
_ret_layout: &Layout<'a>,
|
||||
) -> Result<(), String> {
|
||||
Err("Loading args not yet implemented for AArch64".to_string())
|
||||
) {
|
||||
unimplemented!("Loading args not yet implemented for AArch64");
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
|
@ -250,8 +252,8 @@ impl CallConv<AArch64GeneralReg, AArch64FloatReg> for AArch64Call {
|
|||
_args: &'a [Symbol],
|
||||
_arg_layouts: &[Layout<'a>],
|
||||
_ret_layout: &Layout<'a>,
|
||||
) -> Result<u32, String> {
|
||||
Err("Storing args not yet implemented for AArch64".to_string())
|
||||
) -> u32 {
|
||||
unimplemented!("Storing args not yet implemented for AArch64");
|
||||
}
|
||||
|
||||
fn return_struct<'a>(
|
||||
|
@ -260,12 +262,12 @@ impl CallConv<AArch64GeneralReg, AArch64FloatReg> for AArch64Call {
|
|||
_struct_size: u32,
|
||||
_field_layouts: &[Layout<'a>],
|
||||
_ret_reg: Option<AArch64GeneralReg>,
|
||||
) -> Result<(), String> {
|
||||
Err("Returning structs not yet implemented for AArch64".to_string())
|
||||
) {
|
||||
unimplemented!("Returning structs not yet implemented for AArch64");
|
||||
}
|
||||
|
||||
fn returns_via_arg_pointer(_ret_layout: &Layout) -> Result<bool, String> {
|
||||
Err("Returning via arg pointer not yet implemented for AArch64".to_string())
|
||||
fn returns_via_arg_pointer(_ret_layout: &Layout) -> bool {
|
||||
unimplemented!("Returning via arg pointer not yet implemented for AArch64");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -7,6 +7,7 @@ use roc_builtins::bitcode::{FloatWidth, IntWidth};
|
|||
use roc_collections::all::MutMap;
|
||||
use roc_module::symbol::Symbol;
|
||||
use roc_mono::layout::{Builtin, Layout};
|
||||
use roc_reporting::internal_error;
|
||||
|
||||
// Not sure exactly how I want to represent registers.
|
||||
// If we want max speed, we would likely make them structs that impl the same trait to avoid ifs.
|
||||
|
@ -152,7 +153,7 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg> for X86_64SystemV {
|
|||
general_saved_regs: &[X86_64GeneralReg],
|
||||
requested_stack_size: i32,
|
||||
fn_call_stack_size: i32,
|
||||
) -> Result<i32, String> {
|
||||
) -> i32 {
|
||||
x86_64_generic_setup_stack(
|
||||
buf,
|
||||
general_saved_regs,
|
||||
|
@ -167,7 +168,7 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg> for X86_64SystemV {
|
|||
general_saved_regs: &[X86_64GeneralReg],
|
||||
aligned_stack_size: i32,
|
||||
fn_call_stack_size: i32,
|
||||
) -> Result<(), String> {
|
||||
) {
|
||||
x86_64_generic_cleanup_stack(
|
||||
buf,
|
||||
general_saved_regs,
|
||||
|
@ -182,11 +183,11 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg> for X86_64SystemV {
|
|||
symbol_map: &mut MutMap<Symbol, SymbolStorage<X86_64GeneralReg, X86_64FloatReg>>,
|
||||
args: &'a [(Layout<'a>, Symbol)],
|
||||
ret_layout: &Layout<'a>,
|
||||
) -> Result<(), String> {
|
||||
) {
|
||||
let mut base_offset = Self::SHADOW_SPACE_SIZE as i32 + 8; // 8 is the size of the pushed base pointer.
|
||||
let mut general_i = 0;
|
||||
let mut float_i = 0;
|
||||
if X86_64SystemV::returns_via_arg_pointer(ret_layout)? {
|
||||
if X86_64SystemV::returns_via_arg_pointer(ret_layout) {
|
||||
symbol_map.insert(
|
||||
Symbol::RET_POINTER,
|
||||
SymbolStorage::GeneralReg(Self::GENERAL_PARAM_REGS[general_i]),
|
||||
|
@ -251,21 +252,15 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg> for X86_64SystemV {
|
|||
);
|
||||
general_i += 2;
|
||||
} else {
|
||||
return Err(
|
||||
"loading strings args on the stack is not yet implemented".to_string()
|
||||
);
|
||||
unimplemented!("loading strings args on the stack is not yet implemented");
|
||||
}
|
||||
}
|
||||
Layout::Struct(&[]) => {}
|
||||
x => {
|
||||
return Err(format!(
|
||||
"Loading args with layout {:?} not yet implemented",
|
||||
x
|
||||
));
|
||||
unimplemented!("Loading args with layout {:?} not yet implemented", x);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
|
@ -275,7 +270,7 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg> for X86_64SystemV {
|
|||
args: &'a [Symbol],
|
||||
arg_layouts: &[Layout<'a>],
|
||||
ret_layout: &Layout<'a>,
|
||||
) -> Result<u32, String> {
|
||||
) -> u32 {
|
||||
let mut stack_offset = Self::SHADOW_SPACE_SIZE as i32;
|
||||
let mut general_i = 0;
|
||||
let mut float_i = 0;
|
||||
|
@ -284,22 +279,22 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg> for X86_64SystemV {
|
|||
match ret_layout {
|
||||
Layout::Builtin(single_register_builtins!() | Builtin::Str) => {}
|
||||
x => {
|
||||
return Err(format!(
|
||||
"receiving return type, {:?}, is not yet implemented",
|
||||
x
|
||||
));
|
||||
unimplemented!("receiving return type, {:?}, is not yet implemented", x);
|
||||
}
|
||||
}
|
||||
for (i, layout) in arg_layouts.iter().enumerate() {
|
||||
match layout {
|
||||
Layout::Builtin(single_register_integers!()) => {
|
||||
let storage = match symbol_map.get(&args[i]) {
|
||||
Some(storage) => storage,
|
||||
None => {
|
||||
internal_error!("function argument does not reference any symbol")
|
||||
}
|
||||
};
|
||||
if general_i < Self::GENERAL_PARAM_REGS.len() {
|
||||
// Load the value to the param reg.
|
||||
let dst = Self::GENERAL_PARAM_REGS[general_i];
|
||||
match symbol_map
|
||||
.get(&args[i])
|
||||
.ok_or("function argument does not reference any symbol")?
|
||||
{
|
||||
match storage {
|
||||
SymbolStorage::GeneralReg(reg)
|
||||
| SymbolStorage::BaseAndGeneralReg { reg, .. } => {
|
||||
X86_64Assembler::mov_reg64_reg64(buf, dst, *reg);
|
||||
|
@ -308,18 +303,13 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg> for X86_64SystemV {
|
|||
X86_64Assembler::mov_reg64_base32(buf, dst, *offset);
|
||||
}
|
||||
SymbolStorage::FloatReg(_) | SymbolStorage::BaseAndFloatReg { .. } => {
|
||||
return Err(
|
||||
"Cannot load floating point symbol into GeneralReg".to_string()
|
||||
)
|
||||
internal_error!("Cannot load floating point symbol into GeneralReg")
|
||||
}
|
||||
}
|
||||
general_i += 1;
|
||||
} else {
|
||||
// Load the value to the stack.
|
||||
match symbol_map
|
||||
.get(&args[i])
|
||||
.ok_or("function argument does not reference any symbol")?
|
||||
{
|
||||
match storage {
|
||||
SymbolStorage::GeneralReg(reg)
|
||||
| SymbolStorage::BaseAndGeneralReg { reg, .. } => {
|
||||
X86_64Assembler::mov_stack32_reg64(buf, stack_offset, *reg);
|
||||
|
@ -338,22 +328,23 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg> for X86_64SystemV {
|
|||
);
|
||||
}
|
||||
SymbolStorage::FloatReg(_) | SymbolStorage::BaseAndFloatReg { .. } => {
|
||||
return Err(
|
||||
"Cannot load floating point symbol into GeneralReg".to_string()
|
||||
)
|
||||
internal_error!("Cannot load floating point symbol into GeneralReg")
|
||||
}
|
||||
}
|
||||
stack_offset += 8;
|
||||
}
|
||||
}
|
||||
Layout::Builtin(single_register_floats!()) => {
|
||||
let storage = match symbol_map.get(&args[i]) {
|
||||
Some(storage) => storage,
|
||||
None => {
|
||||
internal_error!("function argument does not reference any symbol")
|
||||
}
|
||||
};
|
||||
if float_i < Self::FLOAT_PARAM_REGS.len() {
|
||||
// Load the value to the param reg.
|
||||
let dst = Self::FLOAT_PARAM_REGS[float_i];
|
||||
match symbol_map
|
||||
.get(&args[i])
|
||||
.ok_or("function argument does not reference any symbol")?
|
||||
{
|
||||
match storage {
|
||||
SymbolStorage::FloatReg(reg)
|
||||
| SymbolStorage::BaseAndFloatReg { reg, .. } => {
|
||||
X86_64Assembler::mov_freg64_freg64(buf, dst, *reg);
|
||||
|
@ -363,16 +354,13 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg> for X86_64SystemV {
|
|||
}
|
||||
SymbolStorage::GeneralReg(_)
|
||||
| SymbolStorage::BaseAndGeneralReg { .. } => {
|
||||
return Err("Cannot load general symbol into FloatReg".to_string())
|
||||
internal_error!("Cannot load general symbol into FloatReg")
|
||||
}
|
||||
}
|
||||
float_i += 1;
|
||||
} else {
|
||||
// Load the value to the stack.
|
||||
match symbol_map
|
||||
.get(&args[i])
|
||||
.ok_or("function argument does not reference any symbol")?
|
||||
{
|
||||
match storage {
|
||||
SymbolStorage::FloatReg(reg)
|
||||
| SymbolStorage::BaseAndFloatReg { reg, .. } => {
|
||||
X86_64Assembler::mov_stack32_freg64(buf, stack_offset, *reg);
|
||||
|
@ -392,48 +380,48 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg> for X86_64SystemV {
|
|||
}
|
||||
SymbolStorage::GeneralReg(_)
|
||||
| SymbolStorage::BaseAndGeneralReg { .. } => {
|
||||
return Err("Cannot load general symbol into FloatReg".to_string())
|
||||
internal_error!("Cannot load general symbol into FloatReg")
|
||||
}
|
||||
}
|
||||
stack_offset += 8;
|
||||
}
|
||||
}
|
||||
Layout::Builtin(Builtin::Str) => {
|
||||
let storage = match symbol_map.get(&args[i]) {
|
||||
Some(storage) => storage,
|
||||
None => {
|
||||
internal_error!("function argument does not reference any symbol")
|
||||
}
|
||||
};
|
||||
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")?
|
||||
{
|
||||
match storage {
|
||||
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());
|
||||
internal_error!(
|
||||
"Strings only support being loaded from base offsets"
|
||||
);
|
||||
}
|
||||
}
|
||||
general_i += 2;
|
||||
} else {
|
||||
return Err(
|
||||
unimplemented!(
|
||||
"calling functions with strings on the stack is not yet implemented"
|
||||
.to_string(),
|
||||
);
|
||||
}
|
||||
}
|
||||
Layout::Struct(&[]) => {}
|
||||
x => {
|
||||
return Err(format!(
|
||||
"calling with arg type, {:?}, is not yet implemented",
|
||||
x
|
||||
));
|
||||
unimplemented!("calling with arg type, {:?}, is not yet implemented", x);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(stack_offset as u32)
|
||||
stack_offset as u32
|
||||
}
|
||||
|
||||
fn return_struct<'a>(
|
||||
|
@ -442,14 +430,14 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg> for X86_64SystemV {
|
|||
_struct_size: u32,
|
||||
_field_layouts: &[Layout<'a>],
|
||||
_ret_reg: Option<X86_64GeneralReg>,
|
||||
) -> Result<(), String> {
|
||||
Err("Returning structs not yet implemented for X86_64".to_string())
|
||||
) {
|
||||
unimplemented!("Returning structs not yet implemented for X86_64");
|
||||
}
|
||||
|
||||
fn returns_via_arg_pointer(ret_layout: &Layout) -> Result<bool, String> {
|
||||
fn returns_via_arg_pointer(ret_layout: &Layout) -> bool {
|
||||
// TODO: This may need to be more complex/extended to fully support the calling convention.
|
||||
// details here: https://github.com/hjl-tools/x86-psABI/wiki/x86-64-psABI-1.0.pdf
|
||||
Ok(ret_layout.stack_size(PTR_SIZE) > 16)
|
||||
ret_layout.stack_size(PTR_SIZE) > 16
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -551,7 +539,7 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg> for X86_64WindowsFastcall {
|
|||
saved_regs: &[X86_64GeneralReg],
|
||||
requested_stack_size: i32,
|
||||
fn_call_stack_size: i32,
|
||||
) -> Result<i32, String> {
|
||||
) -> i32 {
|
||||
x86_64_generic_setup_stack(buf, saved_regs, requested_stack_size, fn_call_stack_size)
|
||||
}
|
||||
|
||||
|
@ -561,7 +549,7 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg> for X86_64WindowsFastcall {
|
|||
saved_regs: &[X86_64GeneralReg],
|
||||
aligned_stack_size: i32,
|
||||
fn_call_stack_size: i32,
|
||||
) -> Result<(), String> {
|
||||
) {
|
||||
x86_64_generic_cleanup_stack(buf, saved_regs, aligned_stack_size, fn_call_stack_size)
|
||||
}
|
||||
|
||||
|
@ -571,10 +559,10 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg> for X86_64WindowsFastcall {
|
|||
symbol_map: &mut MutMap<Symbol, SymbolStorage<X86_64GeneralReg, X86_64FloatReg>>,
|
||||
args: &'a [(Layout<'a>, Symbol)],
|
||||
ret_layout: &Layout<'a>,
|
||||
) -> Result<(), String> {
|
||||
) {
|
||||
let mut base_offset = Self::SHADOW_SPACE_SIZE as i32 + 8; // 8 is the size of the pushed base pointer.
|
||||
let mut i = 0;
|
||||
if X86_64WindowsFastcall::returns_via_arg_pointer(ret_layout)? {
|
||||
if X86_64WindowsFastcall::returns_via_arg_pointer(ret_layout) {
|
||||
symbol_map.insert(
|
||||
Symbol::RET_POINTER,
|
||||
SymbolStorage::GeneralReg(Self::GENERAL_PARAM_REGS[i]),
|
||||
|
@ -595,27 +583,20 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg> for X86_64WindowsFastcall {
|
|||
}
|
||||
Layout::Builtin(Builtin::Str) => {
|
||||
// I think this just needs to be passed on the stack, so not a huge deal.
|
||||
return Err(
|
||||
unimplemented!(
|
||||
"Passing str args with Windows fast call not yet implemented."
|
||||
.to_string(),
|
||||
);
|
||||
}
|
||||
Layout::Struct(&[]) => {}
|
||||
x => {
|
||||
return Err(format!(
|
||||
"Loading args with layout {:?} not yet implemented",
|
||||
x
|
||||
));
|
||||
unimplemented!("Loading args with layout {:?} not yet implemented", x);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
base_offset += match layout {
|
||||
Layout::Builtin(single_register_builtins!()) => 8,
|
||||
x => {
|
||||
return Err(format!(
|
||||
"Loading args with layout {:?} not yet implemented",
|
||||
x
|
||||
));
|
||||
unimplemented!("Loading args with layout {:?} not yet implemented", x);
|
||||
}
|
||||
};
|
||||
symbol_map.insert(
|
||||
|
@ -628,7 +609,6 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg> for X86_64WindowsFastcall {
|
|||
);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
|
@ -638,29 +618,29 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg> for X86_64WindowsFastcall {
|
|||
args: &'a [Symbol],
|
||||
arg_layouts: &[Layout<'a>],
|
||||
ret_layout: &Layout<'a>,
|
||||
) -> Result<u32, String> {
|
||||
) -> u32 {
|
||||
let mut stack_offset = Self::SHADOW_SPACE_SIZE as i32;
|
||||
// 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!()) => {}
|
||||
x => {
|
||||
return Err(format!(
|
||||
"receiving return type, {:?}, is not yet implemented",
|
||||
x
|
||||
));
|
||||
unimplemented!("receiving return type, {:?}, is not yet implemented", x);
|
||||
}
|
||||
}
|
||||
for (i, layout) in arg_layouts.iter().enumerate() {
|
||||
match layout {
|
||||
Layout::Builtin(single_register_integers!()) => {
|
||||
let storage = match symbol_map.get(&args[i]) {
|
||||
Some(storage) => storage,
|
||||
None => {
|
||||
internal_error!("function argument does not reference any symbol")
|
||||
}
|
||||
};
|
||||
if i < Self::GENERAL_PARAM_REGS.len() {
|
||||
// Load the value to the param reg.
|
||||
let dst = Self::GENERAL_PARAM_REGS[i];
|
||||
match symbol_map
|
||||
.get(&args[i])
|
||||
.ok_or("function argument does not reference any symbol")?
|
||||
{
|
||||
match storage {
|
||||
SymbolStorage::GeneralReg(reg)
|
||||
| SymbolStorage::BaseAndGeneralReg { reg, .. } => {
|
||||
X86_64Assembler::mov_reg64_reg64(buf, dst, *reg);
|
||||
|
@ -669,17 +649,12 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg> for X86_64WindowsFastcall {
|
|||
X86_64Assembler::mov_reg64_base32(buf, dst, *offset);
|
||||
}
|
||||
SymbolStorage::FloatReg(_) | SymbolStorage::BaseAndFloatReg { .. } => {
|
||||
return Err(
|
||||
"Cannot load floating point symbol into GeneralReg".to_string()
|
||||
)
|
||||
internal_error!("Cannot load floating point symbol into GeneralReg")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Load the value to the stack.
|
||||
match symbol_map
|
||||
.get(&args[i])
|
||||
.ok_or("function argument does not reference any symbol")?
|
||||
{
|
||||
match storage {
|
||||
SymbolStorage::GeneralReg(reg)
|
||||
| SymbolStorage::BaseAndGeneralReg { reg, .. } => {
|
||||
X86_64Assembler::mov_stack32_reg64(buf, stack_offset, *reg);
|
||||
|
@ -698,22 +673,23 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg> for X86_64WindowsFastcall {
|
|||
);
|
||||
}
|
||||
SymbolStorage::FloatReg(_) | SymbolStorage::BaseAndFloatReg { .. } => {
|
||||
return Err(
|
||||
"Cannot load floating point symbol into GeneralReg".to_string()
|
||||
)
|
||||
internal_error!("Cannot load floating point symbol into GeneralReg")
|
||||
}
|
||||
}
|
||||
stack_offset += 8;
|
||||
}
|
||||
}
|
||||
Layout::Builtin(single_register_floats!()) => {
|
||||
let storage = match symbol_map.get(&args[i]) {
|
||||
Some(storage) => storage,
|
||||
None => {
|
||||
internal_error!("function argument does not reference any symbol")
|
||||
}
|
||||
};
|
||||
if i < Self::FLOAT_PARAM_REGS.len() {
|
||||
// Load the value to the param reg.
|
||||
let dst = Self::FLOAT_PARAM_REGS[i];
|
||||
match symbol_map
|
||||
.get(&args[i])
|
||||
.ok_or("function argument does not reference any symbol")?
|
||||
{
|
||||
match storage {
|
||||
SymbolStorage::FloatReg(reg)
|
||||
| SymbolStorage::BaseAndFloatReg { reg, .. } => {
|
||||
X86_64Assembler::mov_freg64_freg64(buf, dst, *reg);
|
||||
|
@ -723,15 +699,12 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg> for X86_64WindowsFastcall {
|
|||
}
|
||||
SymbolStorage::GeneralReg(_)
|
||||
| SymbolStorage::BaseAndGeneralReg { .. } => {
|
||||
return Err("Cannot load general symbol into FloatReg".to_string())
|
||||
unimplemented!("Cannot load general symbol into FloatReg")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Load the value to the stack.
|
||||
match symbol_map
|
||||
.get(&args[i])
|
||||
.ok_or("function argument does not reference any symbol")?
|
||||
{
|
||||
match storage {
|
||||
SymbolStorage::FloatReg(reg)
|
||||
| SymbolStorage::BaseAndFloatReg { reg, .. } => {
|
||||
X86_64Assembler::mov_stack32_freg64(buf, stack_offset, *reg);
|
||||
|
@ -751,7 +724,7 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg> for X86_64WindowsFastcall {
|
|||
}
|
||||
SymbolStorage::GeneralReg(_)
|
||||
| SymbolStorage::BaseAndGeneralReg { .. } => {
|
||||
return Err("Cannot load general symbol into FloatReg".to_string())
|
||||
unimplemented!("Cannot load general symbol into FloatReg")
|
||||
}
|
||||
}
|
||||
stack_offset += 8;
|
||||
|
@ -759,20 +732,15 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg> for X86_64WindowsFastcall {
|
|||
}
|
||||
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(),
|
||||
);
|
||||
unimplemented!("Passing str args with Windows fast call not yet implemented.");
|
||||
}
|
||||
Layout::Struct(&[]) => {}
|
||||
x => {
|
||||
return Err(format!(
|
||||
"calling with arg type, {:?}, is not yet implemented",
|
||||
x
|
||||
));
|
||||
unimplemented!("calling with arg type, {:?}, is not yet implemented", x);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(stack_offset as u32)
|
||||
stack_offset as u32
|
||||
}
|
||||
|
||||
fn return_struct<'a>(
|
||||
|
@ -781,14 +749,14 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg> for X86_64WindowsFastcall {
|
|||
_struct_size: u32,
|
||||
_field_layouts: &[Layout<'a>],
|
||||
_ret_reg: Option<X86_64GeneralReg>,
|
||||
) -> Result<(), String> {
|
||||
Err("Returning structs not yet implemented for X86_64WindowsFastCall".to_string())
|
||||
) {
|
||||
unimplemented!("Returning structs not yet implemented for X86_64WindowsFastCall");
|
||||
}
|
||||
|
||||
fn returns_via_arg_pointer(ret_layout: &Layout) -> Result<bool, String> {
|
||||
fn returns_via_arg_pointer(ret_layout: &Layout) -> bool {
|
||||
// TODO: This is not fully correct there are some exceptions for "vector" types.
|
||||
// details here: https://docs.microsoft.com/en-us/cpp/build/x64-calling-convention?view=msvc-160#return-values
|
||||
Ok(ret_layout.stack_size(PTR_SIZE) > 8)
|
||||
ret_layout.stack_size(PTR_SIZE) > 8
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -798,15 +766,17 @@ fn x86_64_generic_setup_stack<'a>(
|
|||
saved_regs: &[X86_64GeneralReg],
|
||||
requested_stack_size: i32,
|
||||
fn_call_stack_size: i32,
|
||||
) -> Result<i32, String> {
|
||||
) -> i32 {
|
||||
X86_64Assembler::push_reg64(buf, X86_64GeneralReg::RBP);
|
||||
X86_64Assembler::mov_reg64_reg64(buf, X86_64GeneralReg::RBP, X86_64GeneralReg::RSP);
|
||||
|
||||
let full_stack_size = requested_stack_size
|
||||
let full_stack_size = match requested_stack_size
|
||||
.checked_add(8 * saved_regs.len() as i32)
|
||||
.ok_or("Ran out of stack space")?
|
||||
.checked_add(fn_call_stack_size)
|
||||
.ok_or("Ran out of stack space")?;
|
||||
.and_then(|size| size.checked_add(fn_call_stack_size))
|
||||
{
|
||||
Some(size) => size,
|
||||
_ => internal_error!("Ran out of stack space"),
|
||||
};
|
||||
let alignment = if full_stack_size <= 0 {
|
||||
0
|
||||
} else {
|
||||
|
@ -832,12 +802,12 @@ fn x86_64_generic_setup_stack<'a>(
|
|||
X86_64Assembler::mov_base32_reg64(buf, -offset, *reg);
|
||||
offset -= 8;
|
||||
}
|
||||
Ok(aligned_stack_size)
|
||||
aligned_stack_size
|
||||
} else {
|
||||
Ok(0)
|
||||
0
|
||||
}
|
||||
} else {
|
||||
Err("Ran out of stack space".to_string())
|
||||
internal_error!("Ran out of stack space");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -848,7 +818,7 @@ fn x86_64_generic_cleanup_stack<'a>(
|
|||
saved_regs: &[X86_64GeneralReg],
|
||||
aligned_stack_size: i32,
|
||||
fn_call_stack_size: i32,
|
||||
) -> Result<(), String> {
|
||||
) {
|
||||
if aligned_stack_size > 0 {
|
||||
let mut offset = aligned_stack_size - fn_call_stack_size;
|
||||
for reg in saved_regs {
|
||||
|
@ -864,7 +834,6 @@ fn x86_64_generic_cleanup_stack<'a>(
|
|||
}
|
||||
//X86_64Assembler::mov_reg64_reg64(buf, X86_64GeneralReg::RSP, X86_64GeneralReg::RBP);
|
||||
X86_64Assembler::pop_reg64(buf, X86_64GeneralReg::RBP);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
impl Assembler<X86_64GeneralReg, X86_64FloatReg> for X86_64Assembler {
|
||||
|
|
|
@ -13,6 +13,7 @@ use roc_mono::ir::{
|
|||
SelfRecursive, Stmt,
|
||||
};
|
||||
use roc_mono::layout::{Builtin, Layout, LayoutIds};
|
||||
use roc_reporting::internal_error;
|
||||
|
||||
mod generic64;
|
||||
mod object_builder;
|
||||
|
@ -58,7 +59,7 @@ where
|
|||
Self: Sized,
|
||||
{
|
||||
/// new creates a new backend that will output to the specific Object.
|
||||
fn new(env: &'a Env) -> Result<Self, String>;
|
||||
fn new(env: &'a Env) -> Self;
|
||||
|
||||
fn env(&self) -> &'a Env<'a>;
|
||||
|
||||
|
@ -70,55 +71,48 @@ where
|
|||
/// finalize does setup because things like stack size and jump locations are not know until the function is written.
|
||||
/// For example, this can store the frame pointer and setup stack space.
|
||||
/// finalize is run at the end of build_proc when all internal code is finalized.
|
||||
fn finalize(&mut self) -> Result<(&'a [u8], &[Relocation]), String>;
|
||||
fn finalize(&mut self) -> (&'a [u8], &[Relocation]);
|
||||
|
||||
// load_args is used to let the backend know what the args are.
|
||||
// The backend should track these args so it can use them as needed.
|
||||
fn load_args(
|
||||
&mut self,
|
||||
args: &'a [(Layout<'a>, Symbol)],
|
||||
ret_layout: &Layout<'a>,
|
||||
) -> Result<(), String>;
|
||||
fn load_args(&mut self, args: &'a [(Layout<'a>, Symbol)], ret_layout: &Layout<'a>);
|
||||
|
||||
/// Used for generating wrappers for malloc/realloc/free
|
||||
fn build_wrapped_jmp(&mut self) -> Result<(&'a [u8], u64), String>;
|
||||
fn build_wrapped_jmp(&mut self) -> (&'a [u8], u64);
|
||||
|
||||
/// build_proc creates a procedure and outputs it to the wrapped object writer.
|
||||
fn build_proc(&mut self, proc: Proc<'a>) -> Result<(&'a [u8], &[Relocation]), String> {
|
||||
fn build_proc(&mut self, proc: Proc<'a>) -> (&'a [u8], &[Relocation]) {
|
||||
let proc_name = LayoutIds::default()
|
||||
.get(proc.name, &proc.ret_layout)
|
||||
.to_symbol_string(proc.name, &self.env().interns);
|
||||
self.reset(proc_name, proc.is_self_recursive);
|
||||
self.load_args(proc.args, &proc.ret_layout)?;
|
||||
self.load_args(proc.args, &proc.ret_layout);
|
||||
for (layout, sym) in proc.args {
|
||||
self.set_layout_map(*sym, layout)?;
|
||||
self.set_layout_map(*sym, layout);
|
||||
}
|
||||
self.scan_ast(&proc.body);
|
||||
self.create_free_map();
|
||||
self.build_stmt(&proc.body, &proc.ret_layout)?;
|
||||
self.build_stmt(&proc.body, &proc.ret_layout);
|
||||
self.finalize()
|
||||
}
|
||||
|
||||
/// build_stmt builds a statement and outputs at the end of the buffer.
|
||||
fn build_stmt(&mut self, stmt: &Stmt<'a>, ret_layout: &Layout<'a>) -> Result<(), String> {
|
||||
fn build_stmt(&mut self, stmt: &Stmt<'a>, ret_layout: &Layout<'a>) {
|
||||
match stmt {
|
||||
Stmt::Let(sym, expr, layout, following) => {
|
||||
self.build_expr(sym, expr, layout)?;
|
||||
self.set_layout_map(*sym, layout)?;
|
||||
self.free_symbols(stmt)?;
|
||||
self.build_stmt(following, ret_layout)?;
|
||||
Ok(())
|
||||
self.build_expr(sym, expr, layout);
|
||||
self.set_layout_map(*sym, layout);
|
||||
self.free_symbols(stmt);
|
||||
self.build_stmt(following, ret_layout);
|
||||
}
|
||||
Stmt::Ret(sym) => {
|
||||
self.load_literal_symbols(&[*sym])?;
|
||||
self.return_symbol(sym, ret_layout)?;
|
||||
self.free_symbols(stmt)?;
|
||||
Ok(())
|
||||
self.load_literal_symbols(&[*sym]);
|
||||
self.return_symbol(sym, ret_layout);
|
||||
self.free_symbols(stmt);
|
||||
}
|
||||
Stmt::Refcounting(_modify, following) => {
|
||||
// TODO: actually deal with refcounting. For hello world, we just skipped it.
|
||||
self.build_stmt(following, ret_layout)?;
|
||||
Ok(())
|
||||
self.build_stmt(following, ret_layout);
|
||||
}
|
||||
Stmt::Switch {
|
||||
cond_symbol,
|
||||
|
@ -127,16 +121,15 @@ where
|
|||
default_branch,
|
||||
ret_layout,
|
||||
} => {
|
||||
self.load_literal_symbols(&[*cond_symbol])?;
|
||||
self.load_literal_symbols(&[*cond_symbol]);
|
||||
self.build_switch(
|
||||
cond_symbol,
|
||||
cond_layout,
|
||||
branches,
|
||||
default_branch,
|
||||
ret_layout,
|
||||
)?;
|
||||
self.free_symbols(stmt)?;
|
||||
Ok(())
|
||||
);
|
||||
self.free_symbols(stmt);
|
||||
}
|
||||
Stmt::Join {
|
||||
id,
|
||||
|
@ -145,11 +138,10 @@ where
|
|||
remainder,
|
||||
} => {
|
||||
for param in parameters.iter() {
|
||||
self.set_layout_map(param.symbol, ¶m.layout)?;
|
||||
self.set_layout_map(param.symbol, ¶m.layout);
|
||||
}
|
||||
self.build_join(id, parameters, body, remainder, ret_layout)?;
|
||||
self.free_symbols(stmt)?;
|
||||
Ok(())
|
||||
self.build_join(id, parameters, body, remainder, ret_layout);
|
||||
self.free_symbols(stmt);
|
||||
}
|
||||
Stmt::Jump(id, args) => {
|
||||
let mut arg_layouts: bumpalo::collections::Vec<Layout<'a>> =
|
||||
|
@ -160,14 +152,13 @@ where
|
|||
if let Some(layout) = layout_map.get(arg) {
|
||||
arg_layouts.push(*layout);
|
||||
} else {
|
||||
return Err(format!("the argument, {:?}, has no know layout", arg));
|
||||
internal_error!("the argument, {:?}, has no know layout", arg);
|
||||
}
|
||||
}
|
||||
self.build_jump(id, args, arg_layouts.into_bump_slice(), ret_layout)?;
|
||||
self.free_symbols(stmt)?;
|
||||
Ok(())
|
||||
self.build_jump(id, args, arg_layouts.into_bump_slice(), ret_layout);
|
||||
self.free_symbols(stmt);
|
||||
}
|
||||
x => Err(format!("the statement, {:?}, is not yet implemented", x)),
|
||||
x => unimplemented!("the statement, {:?}, is not yet implemented", x),
|
||||
}
|
||||
}
|
||||
// build_switch generates a instructions for a switch statement.
|
||||
|
@ -178,7 +169,7 @@ where
|
|||
branches: &'a [(u64, BranchInfo<'a>, Stmt<'a>)],
|
||||
default_branch: &(BranchInfo<'a>, &'a Stmt<'a>),
|
||||
ret_layout: &Layout<'a>,
|
||||
) -> Result<(), String>;
|
||||
);
|
||||
|
||||
// build_join generates a instructions for a join statement.
|
||||
fn build_join(
|
||||
|
@ -188,7 +179,7 @@ where
|
|||
body: &'a Stmt<'a>,
|
||||
remainder: &'a Stmt<'a>,
|
||||
ret_layout: &Layout<'a>,
|
||||
) -> Result<(), String>;
|
||||
);
|
||||
|
||||
// build_jump generates a instructions for a jump statement.
|
||||
fn build_jump(
|
||||
|
@ -197,24 +188,18 @@ where
|
|||
args: &'a [Symbol],
|
||||
arg_layouts: &[Layout<'a>],
|
||||
ret_layout: &Layout<'a>,
|
||||
) -> Result<(), String>;
|
||||
);
|
||||
|
||||
/// build_expr builds the expressions for the specified symbol.
|
||||
/// The builder must keep track of the symbol because it may be referred to later.
|
||||
fn build_expr(
|
||||
&mut self,
|
||||
sym: &Symbol,
|
||||
expr: &Expr<'a>,
|
||||
layout: &Layout<'a>,
|
||||
) -> Result<(), String> {
|
||||
fn build_expr(&mut self, sym: &Symbol, expr: &Expr<'a>, layout: &Layout<'a>) {
|
||||
match expr {
|
||||
Expr::Literal(lit) => {
|
||||
if self.env().lazy_literals {
|
||||
self.literal_map().insert(*sym, *lit);
|
||||
} else {
|
||||
self.load_literal(sym, lit)?;
|
||||
self.load_literal(sym, lit);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
Expr::Call(roc_mono::ir::Call {
|
||||
call_type,
|
||||
|
@ -244,13 +229,10 @@ where
|
|||
.get(*func_sym, layout)
|
||||
.to_symbol_string(*func_sym, &self.env().interns);
|
||||
// Now that the arguments are needed, load them if they are literals.
|
||||
self.load_literal_symbols(arguments)?;
|
||||
self.load_literal_symbols(arguments);
|
||||
self.build_fn_call(sym, fn_name, arguments, arg_layouts, ret_layout)
|
||||
} else {
|
||||
Err(format!(
|
||||
"the function, {:?}, is not yet implemented",
|
||||
func_sym
|
||||
))
|
||||
unimplemented!("the function, {:?}, is not yet implemented", func_sym)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -263,7 +245,7 @@ where
|
|||
if let Some(layout) = layout_map.get(arg) {
|
||||
arg_layouts.push(*layout);
|
||||
} else {
|
||||
return Err(format!("the argument, {:?}, has no know layout", arg));
|
||||
internal_error!("the argument, {:?}, has no know layout", arg);
|
||||
}
|
||||
}
|
||||
self.build_run_low_level(
|
||||
|
@ -274,19 +256,21 @@ where
|
|||
layout,
|
||||
)
|
||||
}
|
||||
x => Err(format!("the call type, {:?}, is not yet implemented", x)),
|
||||
x => unimplemented!("the call type, {:?}, is not yet implemented", x),
|
||||
}
|
||||
}
|
||||
Expr::Struct(fields) => {
|
||||
self.load_literal_symbols(fields)?;
|
||||
self.create_struct(sym, layout, fields)
|
||||
self.load_literal_symbols(fields);
|
||||
self.create_struct(sym, layout, fields);
|
||||
}
|
||||
Expr::StructAtIndex {
|
||||
index,
|
||||
field_layouts,
|
||||
structure,
|
||||
} => self.load_struct_at_index(sym, structure, *index, field_layouts),
|
||||
x => Err(format!("the expression, {:?}, is not yet implemented", x)),
|
||||
} => {
|
||||
self.load_struct_at_index(sym, structure, *index, field_layouts);
|
||||
}
|
||||
x => unimplemented!("the expression, {:?}, is not yet implemented", x),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -299,9 +283,9 @@ where
|
|||
args: &'a [Symbol],
|
||||
arg_layouts: &[Layout<'a>],
|
||||
ret_layout: &Layout<'a>,
|
||||
) -> Result<(), String> {
|
||||
) {
|
||||
// Now that the arguments are needed, load them if they are literals.
|
||||
self.load_literal_symbols(args)?;
|
||||
self.load_literal_symbols(args);
|
||||
match lowlevel {
|
||||
LowLevel::NumAbs => {
|
||||
debug_assert_eq!(
|
||||
|
@ -464,7 +448,7 @@ where
|
|||
arg_layouts,
|
||||
ret_layout,
|
||||
),
|
||||
x => Err(format!("low level, {:?}. is not yet implemented", x)),
|
||||
x => unimplemented!("low level, {:?}. is not yet implemented", x),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -477,99 +461,47 @@ where
|
|||
args: &'a [Symbol],
|
||||
arg_layouts: &[Layout<'a>],
|
||||
ret_layout: &Layout<'a>,
|
||||
) -> Result<(), String>;
|
||||
);
|
||||
|
||||
/// build_num_abs stores the absolute value of src into dst.
|
||||
fn build_num_abs(
|
||||
&mut self,
|
||||
dst: &Symbol,
|
||||
src: &Symbol,
|
||||
layout: &Layout<'a>,
|
||||
) -> Result<(), String>;
|
||||
fn build_num_abs(&mut self, dst: &Symbol, src: &Symbol, layout: &Layout<'a>);
|
||||
|
||||
/// build_num_add stores the sum of src1 and src2 into dst.
|
||||
fn build_num_add(
|
||||
&mut self,
|
||||
dst: &Symbol,
|
||||
src1: &Symbol,
|
||||
src2: &Symbol,
|
||||
layout: &Layout<'a>,
|
||||
) -> Result<(), String>;
|
||||
fn build_num_add(&mut self, dst: &Symbol, src1: &Symbol, src2: &Symbol, layout: &Layout<'a>);
|
||||
|
||||
/// build_num_mul stores `src1 * src2` into dst.
|
||||
fn build_num_mul(
|
||||
&mut self,
|
||||
dst: &Symbol,
|
||||
src1: &Symbol,
|
||||
src2: &Symbol,
|
||||
layout: &Layout<'a>,
|
||||
) -> Result<(), String>;
|
||||
fn build_num_mul(&mut self, dst: &Symbol, src1: &Symbol, src2: &Symbol, layout: &Layout<'a>);
|
||||
|
||||
/// build_num_neg stores the negated value of src into dst.
|
||||
fn build_num_neg(
|
||||
&mut self,
|
||||
dst: &Symbol,
|
||||
src: &Symbol,
|
||||
layout: &Layout<'a>,
|
||||
) -> Result<(), String>;
|
||||
fn build_num_neg(&mut self, dst: &Symbol, src: &Symbol, layout: &Layout<'a>);
|
||||
|
||||
/// build_num_sub stores the `src1 - src2` difference into dst.
|
||||
fn build_num_sub(
|
||||
&mut self,
|
||||
dst: &Symbol,
|
||||
src1: &Symbol,
|
||||
src2: &Symbol,
|
||||
layout: &Layout<'a>,
|
||||
) -> Result<(), String>;
|
||||
fn build_num_sub(&mut self, dst: &Symbol, src1: &Symbol, src2: &Symbol, layout: &Layout<'a>);
|
||||
|
||||
/// build_eq stores the result of `src1 == src2` into dst.
|
||||
fn build_eq(
|
||||
&mut self,
|
||||
dst: &Symbol,
|
||||
src1: &Symbol,
|
||||
src2: &Symbol,
|
||||
arg_layout: &Layout<'a>,
|
||||
) -> Result<(), String>;
|
||||
fn build_eq(&mut self, dst: &Symbol, src1: &Symbol, src2: &Symbol, arg_layout: &Layout<'a>);
|
||||
|
||||
/// build_neq stores the result of `src1 != src2` into dst.
|
||||
fn build_neq(
|
||||
&mut self,
|
||||
dst: &Symbol,
|
||||
src1: &Symbol,
|
||||
src2: &Symbol,
|
||||
arg_layout: &Layout<'a>,
|
||||
) -> Result<(), String>;
|
||||
fn build_neq(&mut self, dst: &Symbol, src1: &Symbol, src2: &Symbol, arg_layout: &Layout<'a>);
|
||||
|
||||
/// build_num_lt stores the result of `src1 < src2` into dst.
|
||||
fn build_num_lt(
|
||||
&mut self,
|
||||
dst: &Symbol,
|
||||
src1: &Symbol,
|
||||
src2: &Symbol,
|
||||
arg_layout: &Layout<'a>,
|
||||
) -> Result<(), String>;
|
||||
fn build_num_lt(&mut self, dst: &Symbol, src1: &Symbol, src2: &Symbol, arg_layout: &Layout<'a>);
|
||||
|
||||
/// literal_map gets the map from symbol to literal, used for lazy loading and literal folding.
|
||||
fn literal_map(&mut self) -> &mut MutMap<Symbol, Literal<'a>>;
|
||||
|
||||
fn load_literal_symbols(&mut self, syms: &[Symbol]) -> Result<(), String> {
|
||||
fn load_literal_symbols(&mut self, syms: &[Symbol]) {
|
||||
if self.env().lazy_literals {
|
||||
for sym in syms {
|
||||
if let Some(lit) = self.literal_map().remove(sym) {
|
||||
self.load_literal(sym, &lit)?;
|
||||
self.load_literal(sym, &lit);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// create_struct creates a struct with the elements specified loaded into it as data.
|
||||
fn create_struct(
|
||||
&mut self,
|
||||
sym: &Symbol,
|
||||
layout: &Layout<'a>,
|
||||
fields: &'a [Symbol],
|
||||
) -> Result<(), String>;
|
||||
fn create_struct(&mut self, sym: &Symbol, layout: &Layout<'a>, fields: &'a [Symbol]);
|
||||
|
||||
/// load_struct_at_index loads into `sym` the value at `index` in `structure`.
|
||||
fn load_struct_at_index(
|
||||
|
@ -578,27 +510,26 @@ where
|
|||
structure: &Symbol,
|
||||
index: u64,
|
||||
field_layouts: &'a [Layout<'a>],
|
||||
) -> Result<(), String>;
|
||||
);
|
||||
|
||||
/// load_literal sets a symbol to be equal to a literal.
|
||||
fn load_literal(&mut self, sym: &Symbol, lit: &Literal<'a>) -> Result<(), String>;
|
||||
fn load_literal(&mut self, sym: &Symbol, lit: &Literal<'a>);
|
||||
|
||||
/// return_symbol moves a symbol to the correct return location for the backend and adds a jump to the end of the function.
|
||||
fn return_symbol(&mut self, sym: &Symbol, layout: &Layout<'a>) -> Result<(), String>;
|
||||
fn return_symbol(&mut self, sym: &Symbol, layout: &Layout<'a>);
|
||||
|
||||
/// free_symbols will free all symbols for the given statement.
|
||||
fn free_symbols(&mut self, stmt: &Stmt<'a>) -> Result<(), String> {
|
||||
fn free_symbols(&mut self, stmt: &Stmt<'a>) {
|
||||
if let Some(syms) = self.free_map().remove(&(stmt as *const Stmt<'a>)) {
|
||||
for sym in syms {
|
||||
// println!("Freeing symbol: {:?}", sym);
|
||||
self.free_symbol(&sym)?;
|
||||
self.free_symbol(&sym);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// free_symbol frees any registers or stack space used to hold a symbol.
|
||||
fn free_symbol(&mut self, sym: &Symbol) -> Result<(), String>;
|
||||
fn free_symbol(&mut self, sym: &Symbol);
|
||||
|
||||
/// set_last_seen sets the statement a symbol was last seen in.
|
||||
fn set_last_seen(
|
||||
|
@ -617,20 +548,18 @@ where
|
|||
fn last_seen_map(&mut self) -> &mut MutMap<Symbol, *const Stmt<'a>>;
|
||||
|
||||
/// set_layout_map sets the layout for a specific symbol.
|
||||
fn set_layout_map(&mut self, sym: Symbol, layout: &Layout<'a>) -> Result<(), String> {
|
||||
fn set_layout_map(&mut self, sym: Symbol, layout: &Layout<'a>) {
|
||||
if let Some(old_layout) = self.layout_map().insert(sym, *layout) {
|
||||
// Layout map already contains the symbol. We should never need to overwrite.
|
||||
// If the layout is not the same, that is a bug.
|
||||
if &old_layout != layout {
|
||||
Err(format!(
|
||||
"Overwriting layout for symbol, {:?}. This should never happen. got {:?}, want {:?}",
|
||||
sym, layout, old_layout
|
||||
))
|
||||
} else {
|
||||
Ok(())
|
||||
internal_error!(
|
||||
"Overwriting layout for symbol, {:?}: got {:?}, want {:?}",
|
||||
sym,
|
||||
layout,
|
||||
old_layout
|
||||
)
|
||||
}
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ use object::{
|
|||
use roc_collections::all::MutMap;
|
||||
use roc_module::symbol;
|
||||
use roc_mono::ir::{Proc, ProcLayout};
|
||||
use roc_reporting::internal_error;
|
||||
use target_lexicon::{Architecture as TargetArch, BinaryFormat as TargetBF, Triple};
|
||||
|
||||
// This is used by some code below which is currently commented out.
|
||||
|
@ -22,7 +23,7 @@ pub fn build_module<'a>(
|
|||
env: &'a Env,
|
||||
target: &Triple,
|
||||
procedures: MutMap<(symbol::Symbol, ProcLayout<'a>), Proc<'a>>,
|
||||
) -> Result<Object, String> {
|
||||
) -> Object {
|
||||
match target {
|
||||
Triple {
|
||||
architecture: TargetArch::X86_64,
|
||||
|
@ -34,7 +35,7 @@ pub fn build_module<'a>(
|
|||
x86_64::X86_64FloatReg,
|
||||
x86_64::X86_64Assembler,
|
||||
x86_64::X86_64SystemV,
|
||||
> = Backend::new(env)?;
|
||||
> = Backend::new(env);
|
||||
build_object(
|
||||
env,
|
||||
procedures,
|
||||
|
@ -52,7 +53,7 @@ pub fn build_module<'a>(
|
|||
x86_64::X86_64FloatReg,
|
||||
x86_64::X86_64Assembler,
|
||||
x86_64::X86_64SystemV,
|
||||
> = Backend::new(env)?;
|
||||
> = Backend::new(env);
|
||||
build_object(
|
||||
env,
|
||||
procedures,
|
||||
|
@ -74,7 +75,7 @@ pub fn build_module<'a>(
|
|||
aarch64::AArch64FloatReg,
|
||||
aarch64::AArch64Assembler,
|
||||
aarch64::AArch64Call,
|
||||
> = Backend::new(env)?;
|
||||
> = Backend::new(env);
|
||||
build_object(
|
||||
env,
|
||||
procedures,
|
||||
|
@ -92,7 +93,7 @@ pub fn build_module<'a>(
|
|||
aarch64::AArch64FloatReg,
|
||||
aarch64::AArch64Assembler,
|
||||
aarch64::AArch64Call,
|
||||
> = Backend::new(env)?;
|
||||
> = Backend::new(env);
|
||||
build_object(
|
||||
env,
|
||||
procedures,
|
||||
|
@ -104,9 +105,7 @@ pub fn build_module<'a>(
|
|||
),
|
||||
)
|
||||
}
|
||||
x => Err(format! {
|
||||
"the target, {:?}, is not yet implemented",
|
||||
x}),
|
||||
x => unimplemented!("the target, {:?}, is not yet implemented", x),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -115,7 +114,7 @@ fn generate_wrapper<'a, B: Backend<'a>>(
|
|||
output: &mut Object,
|
||||
wrapper_name: String,
|
||||
wraps: String,
|
||||
) -> Result<(), String> {
|
||||
) {
|
||||
let text_section = output.section_id(StandardSection::Text);
|
||||
let proc_symbol = Symbol {
|
||||
name: wrapper_name.as_bytes().to_vec(),
|
||||
|
@ -128,7 +127,7 @@ fn generate_wrapper<'a, B: Backend<'a>>(
|
|||
flags: SymbolFlags::None,
|
||||
};
|
||||
let proc_id = output.add_symbol(proc_symbol);
|
||||
let (proc_data, offset) = backend.build_wrapped_jmp()?;
|
||||
let (proc_data, offset) = backend.build_wrapped_jmp();
|
||||
let proc_offset = output.add_symbol_data(proc_id, text_section, proc_data, 16);
|
||||
|
||||
let name = wraps.as_str().as_bytes();
|
||||
|
@ -154,13 +153,12 @@ fn generate_wrapper<'a, B: Backend<'a>>(
|
|||
addend: -4,
|
||||
};
|
||||
|
||||
output
|
||||
.add_relocation(text_section, reloc)
|
||||
.map_err(|e| format!("{:?}", e))?;
|
||||
|
||||
Ok(())
|
||||
match output.add_relocation(text_section, reloc) {
|
||||
Ok(obj) => obj,
|
||||
Err(e) => internal_error!("{:?}", e),
|
||||
}
|
||||
} else {
|
||||
Err(format!("failed to find fn symbol for {:?}", wraps))
|
||||
unimplemented!("failed to find fn symbol for {:?}", wraps);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -169,7 +167,7 @@ fn build_object<'a, B: Backend<'a>>(
|
|||
procedures: MutMap<(symbol::Symbol, ProcLayout<'a>), Proc<'a>>,
|
||||
mut backend: B,
|
||||
mut output: Object,
|
||||
) -> Result<Object, String> {
|
||||
) -> Object {
|
||||
let data_section = output.section_id(StandardSection::Data);
|
||||
|
||||
/*
|
||||
|
@ -188,25 +186,25 @@ fn build_object<'a, B: Backend<'a>>(
|
|||
&mut output,
|
||||
"roc_alloc".into(),
|
||||
"malloc".into(),
|
||||
)?;
|
||||
);
|
||||
generate_wrapper(
|
||||
&mut backend,
|
||||
&mut output,
|
||||
"roc_realloc".into(),
|
||||
"realloc".into(),
|
||||
)?;
|
||||
);
|
||||
generate_wrapper(
|
||||
&mut backend,
|
||||
&mut output,
|
||||
"roc_dealloc".into(),
|
||||
"free".into(),
|
||||
)?;
|
||||
);
|
||||
generate_wrapper(
|
||||
&mut backend,
|
||||
&mut output,
|
||||
"roc_panic".into(),
|
||||
"roc_builtins.utils.test_panic".into(),
|
||||
)?;
|
||||
);
|
||||
}
|
||||
|
||||
// Setup layout_ids for procedure calls.
|
||||
|
@ -253,7 +251,7 @@ fn build_object<'a, B: Backend<'a>>(
|
|||
let mut relocations = bumpalo::vec![in env.arena];
|
||||
for (fn_name, section_id, proc_id, proc) in procs {
|
||||
let mut local_data_index = 0;
|
||||
let (proc_data, relocs) = backend.build_proc(proc)?;
|
||||
let (proc_data, relocs) = backend.build_proc(proc);
|
||||
let proc_offset = output.add_symbol_data(proc_id, section_id, proc_data, 16);
|
||||
for reloc in relocs {
|
||||
let elfreloc = match reloc {
|
||||
|
@ -293,7 +291,7 @@ fn build_object<'a, B: Backend<'a>>(
|
|||
addend: -4,
|
||||
}
|
||||
} else {
|
||||
return Err(format!("failed to find data symbol for {:?}", name));
|
||||
internal_error!("failed to find data symbol for {:?}", name);
|
||||
}
|
||||
}
|
||||
Relocation::LinkedFunction { offset, name } => {
|
||||
|
@ -323,7 +321,7 @@ fn build_object<'a, B: Backend<'a>>(
|
|||
addend: -4,
|
||||
}
|
||||
} else {
|
||||
return Err(format!("failed to find fn symbol for {:?}", name));
|
||||
internal_error!("failed to find fn symbol for {:?}", name);
|
||||
}
|
||||
}
|
||||
Relocation::JmpToReturn { .. } => unreachable!(),
|
||||
|
@ -332,9 +330,10 @@ fn build_object<'a, B: Backend<'a>>(
|
|||
}
|
||||
}
|
||||
for (section_id, reloc) in relocations {
|
||||
output
|
||||
.add_relocation(section_id, reloc)
|
||||
.map_err(|e| format!("{:?}", e))?;
|
||||
match output.add_relocation(section_id, reloc) {
|
||||
Ok(obj) => obj,
|
||||
Err(e) => internal_error!("{:?}", e),
|
||||
}
|
||||
}
|
||||
Ok(output)
|
||||
output
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue