mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-03 11:52:19 +00:00
Merge branch 'main' into clippy-1.74
This commit is contained in:
commit
aaba3f4d82
320 changed files with 11155 additions and 18862 deletions
|
@ -365,6 +365,7 @@ impl CallConv<AArch64GeneralReg, AArch64FloatReg, AArch64Assembler> for AArch64C
|
|||
/// 213568: f90033fd str x29, [sp, #96]
|
||||
const SHADOW_SPACE_SIZE: u8 = 16;
|
||||
|
||||
// These are registers that a called function must save and restore if it wants to use them.
|
||||
#[inline(always)]
|
||||
fn general_callee_saved(reg: &AArch64GeneralReg) -> bool {
|
||||
matches!(
|
||||
|
|
|
@ -82,8 +82,8 @@ pub trait CallConv<GeneralReg: RegTrait, FloatReg: RegTrait, ASM: Assembler<Gene
|
|||
|
||||
fn setup_stack(
|
||||
buf: &mut Vec<'_, u8>,
|
||||
general_saved_regs: &[GeneralReg],
|
||||
float_saved_regs: &[FloatReg],
|
||||
saved_general_regs: &[GeneralReg],
|
||||
saved_float_regs: &[FloatReg],
|
||||
requested_stack_size: i32,
|
||||
fn_call_stack_size: i32,
|
||||
) -> i32;
|
||||
|
@ -900,8 +900,11 @@ impl<
|
|||
let mut out = bumpalo::vec![in self.env.arena];
|
||||
|
||||
// Setup stack.
|
||||
let used_general_regs = self.storage_manager.general_used_callee_saved_regs();
|
||||
let used_float_regs = self.storage_manager.float_used_callee_saved_regs();
|
||||
let (used_general_regs, used_float_regs) = self
|
||||
.storage_manager
|
||||
.used_callee_saved_regs
|
||||
.as_vecs(self.env.arena);
|
||||
|
||||
let aligned_stack_size = CC::setup_stack(
|
||||
&mut out,
|
||||
&used_general_regs,
|
||||
|
@ -1199,6 +1202,12 @@ impl<
|
|||
max_branch_stack_size =
|
||||
std::cmp::max(max_branch_stack_size, self.storage_manager.stack_size());
|
||||
base_storage.update_fn_call_stack_size(self.storage_manager.fn_call_stack_size());
|
||||
|
||||
// make sure that used callee-saved registers get saved/restored even if used in only
|
||||
// one of the branches of the switch
|
||||
base_storage
|
||||
.used_callee_saved_regs
|
||||
.extend(&self.storage_manager.used_callee_saved_regs);
|
||||
}
|
||||
self.storage_manager = base_storage;
|
||||
self.literal_map = base_literal_map;
|
||||
|
|
|
@ -3,7 +3,7 @@ use crate::{
|
|||
pointer_layouts, sign_extended_int_builtins, single_register_floats,
|
||||
single_register_int_builtins, single_register_integers, single_register_layouts, Env,
|
||||
};
|
||||
use bumpalo::collections::Vec;
|
||||
use bumpalo::collections::{CollectIn, Vec};
|
||||
use roc_builtins::bitcode::{FloatWidth, IntWidth};
|
||||
use roc_collections::all::{MutMap, MutSet};
|
||||
use roc_error_macros::{internal_error, todo_lambda_erasure};
|
||||
|
@ -118,10 +118,7 @@ pub struct StorageManager<
|
|||
general_used_regs: Vec<'a, (GeneralReg, Symbol)>,
|
||||
float_used_regs: Vec<'a, (FloatReg, Symbol)>,
|
||||
|
||||
// TODO: it probably would be faster to make these a list that linearly scans rather than hashing.
|
||||
// used callee saved regs must be tracked for pushing and popping at the beginning/end of the function.
|
||||
general_used_callee_saved_regs: MutSet<GeneralReg>,
|
||||
float_used_callee_saved_regs: MutSet<FloatReg>,
|
||||
pub(crate) used_callee_saved_regs: UsedCalleeRegisters<GeneralReg, FloatReg>,
|
||||
|
||||
free_stack_chunks: Vec<'a, (i32, u32)>,
|
||||
stack_size: u32,
|
||||
|
@ -152,16 +149,62 @@ pub fn new_storage_manager<
|
|||
join_param_map: MutMap::default(),
|
||||
general_free_regs: bumpalo::vec![in env.arena],
|
||||
general_used_regs: bumpalo::vec![in env.arena],
|
||||
general_used_callee_saved_regs: MutSet::default(),
|
||||
// must be saved on entering a function, and restored before returning
|
||||
used_callee_saved_regs: UsedCalleeRegisters::default(),
|
||||
float_free_regs: bumpalo::vec![in env.arena],
|
||||
float_used_regs: bumpalo::vec![in env.arena],
|
||||
float_used_callee_saved_regs: MutSet::default(),
|
||||
free_stack_chunks: bumpalo::vec![in env.arena],
|
||||
stack_size: 0,
|
||||
fn_call_stack_size: 0,
|
||||
}
|
||||
}
|
||||
|
||||
// optimization idea: use a bitset
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct UsedCalleeRegisters<GeneralReg, FloatReg> {
|
||||
general: MutSet<GeneralReg>,
|
||||
float: MutSet<FloatReg>,
|
||||
}
|
||||
|
||||
impl<GeneralReg: RegTrait, FloatReg: RegTrait> UsedCalleeRegisters<GeneralReg, FloatReg> {
|
||||
fn clear(&mut self) {
|
||||
self.general.clear();
|
||||
self.float.clear();
|
||||
}
|
||||
|
||||
fn insert_general(&mut self, reg: GeneralReg) -> bool {
|
||||
self.general.insert(reg)
|
||||
}
|
||||
|
||||
fn insert_float(&mut self, reg: FloatReg) -> bool {
|
||||
self.float.insert(reg)
|
||||
}
|
||||
|
||||
pub(crate) fn extend(&mut self, other: &Self) {
|
||||
self.general.extend(other.general.iter().copied());
|
||||
self.float.extend(other.float.iter().copied());
|
||||
}
|
||||
|
||||
pub(crate) fn as_vecs<'a>(
|
||||
&self,
|
||||
arena: &'a bumpalo::Bump,
|
||||
) -> (Vec<'a, GeneralReg>, Vec<'a, FloatReg>) {
|
||||
(
|
||||
self.general.iter().copied().collect_in(arena),
|
||||
self.float.iter().copied().collect_in(arena),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<GeneralReg, FloatReg> Default for UsedCalleeRegisters<GeneralReg, FloatReg> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
general: Default::default(),
|
||||
float: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<
|
||||
'a,
|
||||
'r,
|
||||
|
@ -175,16 +218,16 @@ impl<
|
|||
self.symbol_storage_map.clear();
|
||||
self.allocation_map.clear();
|
||||
self.join_param_map.clear();
|
||||
self.general_used_callee_saved_regs.clear();
|
||||
self.used_callee_saved_regs.clear();
|
||||
self.general_free_regs.clear();
|
||||
self.general_used_regs.clear();
|
||||
self.general_free_regs
|
||||
.extend_from_slice(CC::GENERAL_DEFAULT_FREE_REGS);
|
||||
self.float_used_callee_saved_regs.clear();
|
||||
self.float_free_regs.clear();
|
||||
self.float_used_regs.clear();
|
||||
self.float_free_regs
|
||||
.extend_from_slice(CC::FLOAT_DEFAULT_FREE_REGS);
|
||||
self.used_callee_saved_regs.clear();
|
||||
self.free_stack_chunks.clear();
|
||||
self.stack_size = 0;
|
||||
self.fn_call_stack_size = 0;
|
||||
|
@ -198,18 +241,6 @@ impl<
|
|||
self.fn_call_stack_size
|
||||
}
|
||||
|
||||
pub fn general_used_callee_saved_regs(&self) -> Vec<'a, GeneralReg> {
|
||||
let mut used_regs = bumpalo::vec![in self.env.arena];
|
||||
used_regs.extend(&self.general_used_callee_saved_regs);
|
||||
used_regs
|
||||
}
|
||||
|
||||
pub fn float_used_callee_saved_regs(&self) -> Vec<'a, FloatReg> {
|
||||
let mut used_regs = bumpalo::vec![in self.env.arena];
|
||||
used_regs.extend(&self.float_used_callee_saved_regs);
|
||||
used_regs
|
||||
}
|
||||
|
||||
/// Returns true if the symbol is storing a primitive value.
|
||||
pub fn is_stored_primitive(&self, sym: &Symbol) -> bool {
|
||||
matches!(
|
||||
|
@ -223,7 +254,7 @@ impl<
|
|||
fn get_general_reg(&mut self, buf: &mut Vec<'a, u8>) -> GeneralReg {
|
||||
if let Some(reg) = self.general_free_regs.pop() {
|
||||
if CC::general_callee_saved(®) {
|
||||
self.general_used_callee_saved_regs.insert(reg);
|
||||
self.used_callee_saved_regs.insert_general(reg);
|
||||
}
|
||||
reg
|
||||
} else if !self.general_used_regs.is_empty() {
|
||||
|
@ -240,7 +271,7 @@ impl<
|
|||
fn get_float_reg(&mut self, buf: &mut Vec<'a, u8>) -> FloatReg {
|
||||
if let Some(reg) = self.float_free_regs.pop() {
|
||||
if CC::float_callee_saved(®) {
|
||||
self.float_used_callee_saved_regs.insert(reg);
|
||||
self.used_callee_saved_regs.insert_float(reg);
|
||||
}
|
||||
reg
|
||||
} else if !self.float_used_regs.is_empty() {
|
||||
|
|
|
@ -199,6 +199,7 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg, X86_64Assembler> for X86_64Syste
|
|||
];
|
||||
const SHADOW_SPACE_SIZE: u8 = 0;
|
||||
|
||||
// These are registers that a called function must save and restore if it wants to use them.
|
||||
#[inline(always)]
|
||||
fn general_callee_saved(reg: &X86_64GeneralReg) -> bool {
|
||||
matches!(
|
||||
|
@ -1409,6 +1410,8 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg, X86_64Assembler> for X86_64Windo
|
|||
];
|
||||
const SHADOW_SPACE_SIZE: u8 = 32;
|
||||
|
||||
// These are registers that a called function must save and restore if it wants to use them.
|
||||
//
|
||||
// Refer https://learn.microsoft.com/en-us/cpp/build/x64-calling-convention?view=msvc-170#callercallee-saved-registers
|
||||
// > The x64 ABI considers registers RBX, RBP, RDI, RSI, RSP, R12, R13, R14, R15, and XMM6-XMM15 nonvolatile.
|
||||
// > They must be saved and restored by a function that uses them.
|
||||
|
|
|
@ -57,6 +57,14 @@ impl AssemblyBackendMode {
|
|||
AssemblyBackendMode::Repl => true,
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_roc_dbg(self) -> bool {
|
||||
match self {
|
||||
AssemblyBackendMode::Binary => false,
|
||||
AssemblyBackendMode::Test => true,
|
||||
AssemblyBackendMode::Repl => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Env<'a> {
|
||||
|
@ -182,7 +190,7 @@ impl<'a> LastSeenMap<'a> {
|
|||
Expr::UnionAtIndex { structure, .. } => {
|
||||
self.set_last_seen(*structure, stmt);
|
||||
}
|
||||
Expr::UnionFieldPtrAtIndex { structure, .. } => {
|
||||
Expr::GetElementPointer { structure, .. } => {
|
||||
self.set_last_seen(*structure, stmt);
|
||||
}
|
||||
Expr::Array { elems, .. } => {
|
||||
|
@ -849,13 +857,20 @@ trait Backend<'a> {
|
|||
} => {
|
||||
self.load_union_at_index(sym, structure, *tag_id, *index, union_layout);
|
||||
}
|
||||
Expr::UnionFieldPtrAtIndex {
|
||||
Expr::GetElementPointer {
|
||||
structure,
|
||||
tag_id,
|
||||
union_layout,
|
||||
index,
|
||||
indices,
|
||||
..
|
||||
} => {
|
||||
self.load_union_field_ptr_at_index(sym, structure, *tag_id, *index, union_layout);
|
||||
debug_assert!(indices.len() >= 2);
|
||||
self.load_union_field_ptr_at_index(
|
||||
sym,
|
||||
structure,
|
||||
indices[0] as u16,
|
||||
indices[1],
|
||||
union_layout,
|
||||
);
|
||||
}
|
||||
Expr::GetTagId {
|
||||
structure,
|
||||
|
|
|
@ -296,6 +296,23 @@ fn generate_roc_panic<'a, B: Backend<'a>>(backend: &mut B, output: &mut Object)
|
|||
}
|
||||
}
|
||||
|
||||
fn generate_roc_dbg<'a, B: Backend<'a>>(_backend: &mut B, output: &mut Object) {
|
||||
let text_section = output.section_id(StandardSection::Text);
|
||||
let proc_symbol = Symbol {
|
||||
name: "roc_dbg".as_bytes().to_vec(),
|
||||
value: 0,
|
||||
size: 0,
|
||||
kind: SymbolKind::Text,
|
||||
scope: SymbolScope::Dynamic,
|
||||
weak: false,
|
||||
section: SymbolSection::Section(text_section),
|
||||
flags: SymbolFlags::None,
|
||||
};
|
||||
let _proc_id = output.add_symbol(proc_symbol);
|
||||
// TODO: Actually generate an impl instead of just an empty symbol.
|
||||
// At a minimum, it should just be a ret.
|
||||
}
|
||||
|
||||
fn generate_wrapper<'a, B: Backend<'a>>(
|
||||
backend: &mut B,
|
||||
output: &mut Object,
|
||||
|
@ -412,6 +429,10 @@ fn build_object<'a, B: Backend<'a>>(
|
|||
generate_longjmp(&mut backend, &mut output);
|
||||
}
|
||||
|
||||
if backend.env().mode.generate_roc_dbg() {
|
||||
generate_roc_dbg(&mut backend, &mut output);
|
||||
}
|
||||
|
||||
if backend.env().mode.generate_allocators() {
|
||||
generate_wrapper(
|
||||
&mut backend,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue