aboutsummaryrefslogtreecommitdiff
path: root/patio-to-cranelift
diff options
context:
space:
mode:
authorMichael Williamson <mike@zwobble.org>2026-04-05 21:57:10 +0100
committerMichael Williamson <mike@zwobble.org>2026-04-05 21:57:19 +0100
commitcb298210348c0a1c160ea208eb5f597765de0d31 (patch)
tree631c99e48ef5fe5060c6c4d4f174bdcd1fcc07d6 /patio-to-cranelift
parente937b17b276ca98950c5c2e09e646ccd9338278c (diff)
Create separate codegen module
Diffstat (limited to 'patio-to-cranelift')
-rw-r--r--patio-to-cranelift/src/codegen/context.rs (renamed from patio-to-cranelift/src/context.rs)0
-rw-r--r--patio-to-cranelift/src/codegen/mod.rs1080
-rw-r--r--patio-to-cranelift/src/lib.rs1076
3 files changed, 1085 insertions, 1071 deletions
diff --git a/patio-to-cranelift/src/context.rs b/patio-to-cranelift/src/codegen/context.rs
index 09b08173..09b08173 100644
--- a/patio-to-cranelift/src/context.rs
+++ b/patio-to-cranelift/src/codegen/context.rs
diff --git a/patio-to-cranelift/src/codegen/mod.rs b/patio-to-cranelift/src/codegen/mod.rs
new file mode 100644
index 00000000..aee8e9d8
--- /dev/null
+++ b/patio-to-cranelift/src/codegen/mod.rs
@@ -0,0 +1,1080 @@
+use std::{io::Write, path::Path};
+
+use cranelift::prelude::InstBuilder;
+
+use crate::{
+ codegen::context::{CompilerContext, CompilerFunctionContext, Mutability},
+ errors::CompileError,
+ patio::{
+ compilation_unit::{
+ PatioCompilationUnit, PatioCompilationUnitElement, PatioDataElementImmutableDefinition,
+ PatioDataElementMutableDefinition, PatioFunctionDeclaration, PatioFunctionDefinition,
+ PatioLocal, PatioLocalType, PatioVisibility,
+ },
+ instructions::{
+ PatioBlock, PatioBoolToInt, PatioCall, PatioIf, PatioInstruction, PatioIntAdd,
+ PatioIntEquals, PatioIntNotEqual, PatioIntSub, PatioIntToBool, PatioLocalStore,
+ PatioMemoryLoad, PatioMemoryStore, PatioResume, PatioReturn, PatioReturnVoid,
+ PatioVarLoad, PatioVarStore,
+ },
+ operands::{PatioLocalRef, PatioOperand},
+ types::{PatioDataLayout, PatioType},
+ values::{PatioDataPtrValue, PatioDataValue, PatioIntValue},
+ },
+};
+
+mod context;
+
+pub(crate) fn compile_compilation_unit(
+ compilation_unit: PatioCompilationUnit,
+ source_path: &Path,
+ target_triple: target_lexicon::Triple,
+) -> Result<Vec<u8>, CompileError> {
+ let mut context = CompilerContext::for_object(source_path, target_triple)?;
+
+ for element in &compilation_unit.elements {
+ declare_compilation_unit_element(&element, &mut context);
+ }
+
+ for element in &compilation_unit.elements {
+ define_compilation_unit_element(&element, &mut context);
+ }
+
+ let object = context.into_object();
+ object.emit().map_err(CompileError::ObjectEmitFailed)
+}
+
+fn declare_compilation_unit_element(
+ element: &PatioCompilationUnitElement,
+ context: &mut CompilerContext,
+) {
+ match element {
+ PatioCompilationUnitElement::DataElementImmutableDefinition(
+ data_element_immutable_definition,
+ ) => {
+ declare_data_element_immutable_definition(data_element_immutable_definition, context);
+ }
+
+ PatioCompilationUnitElement::DataElementMutableDefinition(
+ data_element_mutable_definition,
+ ) => {
+ declare_data_element_mutable_definition(data_element_mutable_definition, context);
+ }
+
+ PatioCompilationUnitElement::FunctionDeclaration(function_declaration) => {
+ declare_function_declaration(function_declaration, context);
+ }
+
+ PatioCompilationUnitElement::FunctionDefinition(function_definition) => {
+ declare_function_definition(function_definition, context);
+ }
+ }
+}
+
+fn define_compilation_unit_element(
+ element: &PatioCompilationUnitElement,
+ context: &mut CompilerContext,
+) {
+ match element {
+ PatioCompilationUnitElement::DataElementImmutableDefinition(
+ data_element_immutable_definition,
+ ) => {
+ define_data_element_immutable_definition(data_element_immutable_definition, context);
+ }
+
+ PatioCompilationUnitElement::DataElementMutableDefinition(
+ data_element_mutable_definition,
+ ) => {
+ define_data_element_mutable_definition(data_element_mutable_definition, context);
+ }
+
+ PatioCompilationUnitElement::FunctionDeclaration(_) => {}
+
+ PatioCompilationUnitElement::FunctionDefinition(function_definition) => {
+ define_function_definition(&function_definition, context);
+ }
+ }
+}
+
+fn declare_data_element_immutable_definition(
+ data_element_immutable_definition: &PatioDataElementImmutableDefinition,
+ context: &mut CompilerContext,
+) {
+ context.declare_data(
+ &data_element_immutable_definition.name,
+ patio_visibility_to_cranelift_linkage(data_element_immutable_definition.visibility),
+ Mutability::Immutable,
+ );
+}
+
+fn define_data_element_immutable_definition(
+ data_element_immutable_definition: &PatioDataElementImmutableDefinition,
+ context: &mut CompilerContext,
+) {
+ let bytes = data_value_to_bytes(
+ &data_element_immutable_definition.value,
+ &context.target_triple,
+ );
+ context.define_data(&data_element_immutable_definition.name, bytes);
+}
+
+fn declare_data_element_mutable_definition(
+ data_element_mutable_definition: &PatioDataElementMutableDefinition,
+ context: &mut CompilerContext,
+) {
+ context.declare_data(
+ &data_element_mutable_definition.name,
+ patio_visibility_to_cranelift_linkage(data_element_mutable_definition.visibility),
+ Mutability::Mutable,
+ );
+}
+
+fn define_data_element_mutable_definition(
+ data_element_mutable_definition: &PatioDataElementMutableDefinition,
+ context: &mut CompilerContext,
+) {
+ let bytes = data_value_to_bytes(
+ &data_element_mutable_definition.initial_value,
+ &context.target_triple,
+ );
+ context.define_data(&data_element_mutable_definition.name, bytes);
+}
+
+fn declare_function_declaration(
+ function_declaration: &PatioFunctionDeclaration,
+ context: &mut CompilerContext,
+) {
+ let cranelift_signature = cranelift_signature(
+ function_declaration.params.iter(),
+ function_declaration.return_type,
+ &context.target_triple,
+ );
+
+ context.declare_function(
+ &function_declaration.name,
+ cranelift_module::Linkage::Import,
+ &cranelift_signature,
+ );
+}
+
+fn declare_function_definition(
+ function_definition: &PatioFunctionDefinition,
+ context: &mut CompilerContext,
+) {
+ let cranelift_signature = cranelift_signature(
+ function_definition.locals.iter().map(Into::into),
+ function_definition.return_type,
+ &context.target_triple,
+ );
+
+ let cranelift_linkage = patio_visibility_to_cranelift_linkage(function_definition.visibility);
+
+ context.declare_function(
+ &function_definition.name,
+ cranelift_linkage,
+ &cranelift_signature,
+ );
+}
+
+fn define_function_definition(
+ function_definition: &PatioFunctionDefinition,
+ context: &mut CompilerContext,
+) {
+ let cranelift_signature = cranelift_signature(
+ function_definition.locals.iter().map(Into::into),
+ function_definition.return_type,
+ &context.target_triple,
+ );
+
+ context.enter_function(
+ &function_definition.name,
+ cranelift_signature,
+ |function_context| {
+ for local in &function_definition.locals {
+ match local.local_type {
+ PatioLocalType::Param => {}
+
+ PatioLocalType::Val => {
+ let cranelift_type = patio_type_to_cranelift_type(
+ local.type_,
+ &function_context.target_triple,
+ );
+ function_context.declare_var(&local.name, cranelift_type);
+ }
+
+ PatioLocalType::Var => {
+ let cranelift_type = patio_type_to_cranelift_type(
+ local.type_,
+ &function_context.target_triple,
+ );
+ function_context.create_stack_slot(&local.name, cranelift_type);
+ }
+ }
+ }
+
+ for instruction in &function_definition.body {
+ compile_instruction(instruction, function_context)
+ }
+ },
+ );
+}
+
+fn compile_instruction(instruction: &PatioInstruction, context: &mut CompilerFunctionContext<'_>) {
+ match instruction {
+ PatioInstruction::Block(block) => {
+ compile_block(block, context);
+ }
+
+ PatioInstruction::BoolToInt(bool_to_int) => {
+ compile_bool_to_int(bool_to_int, context);
+ }
+
+ PatioInstruction::Call(call) => {
+ compile_call(call, context);
+ }
+
+ PatioInstruction::If(if_) => {
+ compile_if(if_, context);
+ }
+
+ PatioInstruction::IntAdd(int_add) => {
+ compile_int_add(int_add, context);
+ }
+
+ PatioInstruction::IntEquals(int_equals) => {
+ compile_int_equals(int_equals, context);
+ }
+
+ PatioInstruction::IntNotEqual(int_not_equal) => {
+ compile_int_not_equal(int_not_equal, context);
+ }
+
+ PatioInstruction::IntSub(int_sub) => {
+ compile_int_sub(int_sub, context);
+ }
+
+ PatioInstruction::IntToBool(int_to_bool) => {
+ compile_int_to_bool(int_to_bool, context);
+ }
+
+ PatioInstruction::LocalStore(local_store) => {
+ compile_local_store(local_store, context);
+ }
+
+ PatioInstruction::MemoryLoad(memory_load) => {
+ compile_memory_load(memory_load, context);
+ }
+
+ PatioInstruction::MemoryStore(memory_store) => {
+ compile_memory_store(memory_store, context);
+ }
+
+ PatioInstruction::Resume(resume) => {
+ compile_resume(resume, context);
+ }
+
+ PatioInstruction::Return(return_) => {
+ compile_return(return_, context);
+ }
+
+ PatioInstruction::ReturnVoid(return_void) => {
+ compile_return_void(return_void, context);
+ }
+
+ PatioInstruction::VarLoad(var_load) => {
+ compile_var_load(var_load, context);
+ }
+
+ PatioInstruction::VarStore(var_store) => {
+ compile_var_store(var_store, context);
+ }
+ }
+}
+
+fn compile_block(
+ block: &PatioBlock,
+ context: &mut CompilerFunctionContext<'_>,
+) -> Vec<cranelift_codegen::ir::Value> {
+ for instruction in &block.body {
+ compile_instruction(instruction, context);
+ }
+
+ block
+ .results
+ .iter()
+ .map(|result| compile_operand(&result, context))
+ .collect()
+}
+
+fn compile_bool_to_int(bool_to_int: &PatioBoolToInt, context: &mut CompilerFunctionContext<'_>) {
+ let cranelift_value = compile_operand(&bool_to_int.value, context);
+
+ let cranelift_result = context
+ .function_builder
+ .ins()
+ .uextend(cranelift_int_type(&context.target_triple), cranelift_value);
+
+ def_destination(&bool_to_int.destination, cranelift_result, context)
+}
+
+fn compile_call(call: &PatioCall, context: &mut CompilerFunctionContext<'_>) {
+ let cranelift_args = compile_operands(call.args.iter(), context);
+
+ let func_ref = context.func_id(&call.function_name);
+ context
+ .function_builder
+ .ins()
+ .call(func_ref, &cranelift_args);
+}
+
+fn compile_if(if_: &PatioIf, context: &mut CompilerFunctionContext<'_>) {
+ let cranelift_condition = compile_operand(&if_.condition, context);
+ let cranelift_then_block = context.function_builder.create_block();
+ let cranelift_else_block = context.function_builder.create_block();
+ let cranelift_end_block = context.function_builder.create_block();
+ let cranelift_end_params: Vec<_> = if_
+ .destinations
+ .iter()
+ .map(|destination| {
+ let cranelift_type = context.var_type(&destination.name);
+ context
+ .function_builder
+ .append_block_param(cranelift_end_block, cranelift_type)
+ })
+ .collect();
+
+ context.function_builder.ins().brif(
+ cranelift_condition,
+ cranelift_then_block,
+ &[],
+ cranelift_else_block,
+ &[],
+ );
+ context
+ .function_builder
+ .seal_block(context.function_builder.current_block().unwrap());
+
+ context
+ .function_builder
+ .switch_to_block(cranelift_then_block);
+ let cranelift_then_results = compile_block(&if_.true_body, context);
+ context.function_builder.ins().jump(
+ cranelift_end_block,
+ cranelift_block_args(cranelift_then_results).iter(),
+ );
+ context.function_builder.seal_block(cranelift_then_block);
+
+ context
+ .function_builder
+ .switch_to_block(cranelift_else_block);
+ let cranelift_else_results = compile_block(&if_.false_body, context);
+ context.function_builder.ins().jump(
+ cranelift_end_block,
+ cranelift_block_args(cranelift_else_results).iter(),
+ );
+ context.function_builder.seal_block(cranelift_else_block);
+
+ context
+ .function_builder
+ .switch_to_block(cranelift_end_block);
+
+ for (destination, cranelift_end_param) in if_.destinations.iter().zip(cranelift_end_params) {
+ def_destination(destination, cranelift_end_param, context);
+ }
+}
+
+fn compile_int_add(int_add: &PatioIntAdd, context: &mut CompilerFunctionContext<'_>) {
+ let cranelift_left = compile_operand(&int_add.left, context);
+ let cranelift_right = compile_operand(&int_add.right, context);
+ let cranelift_result = context
+ .function_builder
+ .ins()
+ .iadd(cranelift_left, cranelift_right);
+
+ def_destination(&int_add.destination, cranelift_result, context);
+}
+
+fn compile_int_equals(int_equals: &PatioIntEquals, context: &mut CompilerFunctionContext<'_>) {
+ let cranelift_left = compile_operand(&int_equals.left, context);
+ let cranelift_right = compile_operand(&int_equals.right, context);
+ let cranelift_result = context.function_builder.ins().icmp(
+ cranelift_codegen::ir::condcodes::IntCC::Equal,
+ cranelift_left,
+ cranelift_right,
+ );
+
+ def_destination(&int_equals.destination, cranelift_result, context);
+}
+
+fn compile_int_not_equal(
+ int_not_equal: &PatioIntNotEqual,
+ context: &mut CompilerFunctionContext<'_>,
+) {
+ let cranelift_left = compile_operand(&int_not_equal.left, context);
+ let cranelift_right = compile_operand(&int_not_equal.right, context);
+ let cranelift_result = context.function_builder.ins().icmp(
+ cranelift_codegen::ir::condcodes::IntCC::NotEqual,
+ cranelift_left,
+ cranelift_right,
+ );
+
+ def_destination(&int_not_equal.destination, cranelift_result, context);
+}
+
+fn compile_int_sub(int_sub: &PatioIntSub, context: &mut CompilerFunctionContext<'_>) {
+ let cranelift_left = compile_operand(&int_sub.left, context);
+ let cranelift_right = compile_operand(&int_sub.right, context);
+ let cranelift_result = context
+ .function_builder
+ .ins()
+ .isub(cranelift_left, cranelift_right);
+
+ def_destination(&int_sub.destination, cranelift_result, context);
+}
+
+fn compile_int_to_bool(int_to_bool: &PatioIntToBool, context: &mut CompilerFunctionContext<'_>) {
+ let cranelift_value = compile_operand(&int_to_bool.value, context);
+
+ let cranelift_result = context
+ .function_builder
+ .ins()
+ .ireduce(CRANELIFT_BOOL_TYPE, cranelift_value);
+
+ def_destination(&int_to_bool.destination, cranelift_result, context);
+}
+
+fn compile_local_store(local_store: &PatioLocalStore, context: &mut CompilerFunctionContext<'_>) {
+ let cranelift_value = compile_operand(&local_store.value, context);
+ def_destination(&local_store.destination, cranelift_value, context);
+}
+
+fn compile_memory_load(memory_load: &PatioMemoryLoad, context: &mut CompilerFunctionContext<'_>) {
+ let value_layout = data_layout_element_at(&memory_load.layout, &memory_load.element_offsets);
+ let value_type = data_layout_to_type(value_layout);
+ let cranelift_type = patio_type_to_cranelift_type(value_type, &context.target_triple);
+
+ let cranelift_pointer = compile_operand(&memory_load.pointer, context);
+ let cranelift_flags = cranelift_codegen::ir::MemFlags::new();
+ let byte_offset = data_layout_byte_offset(
+ &memory_load.layout,
+ &memory_load.element_offsets,
+ &context.target_triple,
+ );
+ let cranelift_offset =
+ cranelift_codegen::ir::immediates::Offset32::new(byte_offset.try_into().unwrap());
+ let cranelift_value = context.function_builder.ins().load(
+ cranelift_type,
+ cranelift_flags,
+ cranelift_pointer,
+ cranelift_offset,
+ );
+
+ def_destination(&memory_load.destination, cranelift_value, context);
+}
+
+fn compile_memory_store(
+ memory_store: &PatioMemoryStore,
+ context: &mut CompilerFunctionContext<'_>,
+) {
+ let cranelift_value = compile_operand(&memory_store.value, context);
+ let cranelift_pointer = compile_operand(&memory_store.pointer, context);
+ let cranelift_flags = cranelift_codegen::ir::MemFlags::new();
+ let byte_offset = data_layout_byte_offset(
+ &memory_store.layout,
+ &memory_store.element_offsets,
+ &context.target_triple,
+ );
+ let cranelift_offset =
+ cranelift_codegen::ir::immediates::Offset32::new(byte_offset.try_into().unwrap());
+
+ context.function_builder.ins().store(
+ cranelift_flags,
+ cranelift_value,
+ cranelift_pointer,
+ cranelift_offset,
+ );
+}
+
+fn compile_resume(resume: &PatioResume, context: &mut CompilerFunctionContext<'_>) {
+ let cranelift_value = compile_operand(&resume.value, context);
+
+ context.function_builder.ins().return_(&[cranelift_value]);
+}
+
+fn compile_return(return_: &PatioReturn, context: &mut CompilerFunctionContext<'_>) {
+ let cranelift_value = compile_operand(&return_.value, context);
+
+ context.function_builder.ins().return_(&[cranelift_value]);
+}
+
+fn compile_return_void(_return_void: &PatioReturnVoid, context: &mut CompilerFunctionContext<'_>) {
+ context.function_builder.ins().return_(&[]);
+}
+
+fn compile_var_load(var_load: &PatioVarLoad, context: &mut CompilerFunctionContext<'_>) {
+ let stack_slot = context.stack_slot(&var_load.var.name);
+ let type_ = context.stack_slot_type(&var_load.var.name);
+ let value = context.function_builder.ins().stack_load(
+ type_,
+ stack_slot,
+ cranelift_codegen::ir::immediates::Offset32::new(0),
+ );
+ def_destination(&var_load.destination, value, context);
+}
+
+fn compile_var_store(var_store: &PatioVarStore, context: &mut CompilerFunctionContext<'_>) {
+ let stack_slot = context.stack_slot(&var_store.var.name);
+ let value = compile_operand(&var_store.value, context);
+ context.function_builder.ins().stack_store(
+ value,
+ stack_slot,
+ cranelift_codegen::ir::immediates::Offset32::new(0),
+ );
+}
+
+fn compile_operands<'a>(
+ operands: impl Iterator<Item = &'a PatioOperand>,
+ context: &mut CompilerFunctionContext<'_>,
+) -> Vec<cranelift::prelude::Value> {
+ operands
+ .map(|operand| compile_operand(operand, context))
+ .collect()
+}
+
+fn compile_operand(
+ operand: &PatioOperand,
+ context: &mut CompilerFunctionContext<'_>,
+) -> cranelift::prelude::Value {
+ match operand {
+ PatioOperand::BoolConst(value) => {
+ let integer_value = if *value { 1 } else { 0 };
+
+ context
+ .function_builder
+ .ins()
+ .iconst(CRANELIFT_BOOL_TYPE, integer_value)
+ }
+
+ PatioOperand::DataPtrConst(value) => compile_data_ptr_value(&value, context),
+
+ PatioOperand::IntConst(value) => {
+ let cranelift_int_type = cranelift_int_type(&context.target_triple);
+ compile_int_value(&value, cranelift_int_type, context)
+ }
+
+ PatioOperand::Int32Const(value) => {
+ compile_int_value(&value, CRANELIFT_INT_32_TYPE, context)
+ }
+
+ PatioOperand::LocalRef(local_ref) => {
+ let cranelift_variable = context.var(&local_ref.name);
+ context.function_builder.use_var(cranelift_variable)
+ }
+
+ _ => {
+ todo!("Unhandled operand: {operand:?}",)
+ }
+ }
+}
+
+fn compile_data_ptr_value(
+ data_ptr_value: &PatioDataPtrValue,
+ context: &mut CompilerFunctionContext<'_>,
+) -> cranelift_codegen::ir::Value {
+ let data_ptr_type = context.pointer_type();
+
+ match data_ptr_value {
+ PatioDataPtrValue::DataElement { name } => {
+ let global_value = context.data_ptr(name);
+ context
+ .function_builder
+ .ins()
+ .global_value(data_ptr_type, global_value)
+ }
+
+ PatioDataPtrValue::Null => context.function_builder.ins().iconst(data_ptr_type, 0),
+ }
+}
+
+fn compile_int_value(
+ int_value: &PatioIntValue,
+ cranelift_type: cranelift::prelude::Type,
+ context: &mut CompilerFunctionContext<'_>,
+) -> cranelift::prelude::Value {
+ let value = eval_int_value(int_value, &context.target_triple);
+
+ context
+ .function_builder
+ .ins()
+ .iconst(cranelift_type, i64::from(value))
+}
+
+fn cranelift_block_args(
+ values: impl IntoIterator<Item = cranelift_codegen::ir::Value>,
+) -> Vec<cranelift_codegen::ir::BlockArg> {
+ values
+ .into_iter()
+ .map(|cranelift_result| cranelift_codegen::ir::BlockArg::Value(cranelift_result))
+ .collect()
+}
+
+fn def_destination(
+ destination: &PatioLocalRef,
+ value: cranelift_codegen::ir::Value,
+ context: &mut CompilerFunctionContext<'_>,
+) {
+ let cranelift_destination = context.var(&destination.name);
+ context
+ .function_builder
+ .def_var(cranelift_destination, value);
+}
+
+fn cranelift_signature<'a>(
+ locals: impl Iterator<Item = &'a PatioLocal>,
+ return_type: PatioType,
+ target_triple: &target_lexicon::Triple,
+) -> cranelift::prelude::Signature {
+ let mut signature =
+ cranelift::prelude::Signature::new(cranelift_codegen::isa::CallConv::SystemV);
+
+ for local in locals {
+ if local.local_type == PatioLocalType::Param {
+ let param_type = patio_type_to_cranelift_type(local.type_, &target_triple);
+ let param = cranelift::prelude::AbiParam::new(param_type);
+ signature.params.push(param);
+ }
+ }
+
+ if return_type != PatioType::Void {
+ let cranelift_return_type = patio_type_to_cranelift_type(return_type, &target_triple);
+ let returns = cranelift::prelude::AbiParam::new(cranelift_return_type);
+ signature.returns.push(returns);
+ }
+
+ signature
+}
+
+fn patio_visibility_to_cranelift_linkage(visibility: PatioVisibility) -> cranelift_module::Linkage {
+ match visibility {
+ PatioVisibility::Private => cranelift_module::Linkage::Local,
+ PatioVisibility::Public => cranelift_module::Linkage::Export,
+ }
+}
+
+fn patio_type_to_cranelift_type(
+ patio_type: PatioType,
+ target_triple: &target_lexicon::Triple,
+) -> cranelift::prelude::Type {
+ match patio_type {
+ PatioType::Bool => CRANELIFT_BOOL_TYPE,
+
+ PatioType::Byte => CRANELIFT_BYTE_TYPE,
+
+ PatioType::DataPtr => cranelift::prelude::Type::triple_pointer_type(&target_triple),
+
+ PatioType::FunctionPtr => cranelift::prelude::Type::triple_pointer_type(&target_triple),
+
+ PatioType::Int => cranelift_int_type(target_triple),
+
+ PatioType::Int32 => CRANELIFT_INT_32_TYPE,
+
+ PatioType::Void => todo!(),
+ }
+}
+
+const CRANELIFT_BOOL_TYPE: cranelift_codegen::ir::Type = cranelift_codegen::ir::types::I8;
+const CRANELIFT_BYTE_TYPE: cranelift_codegen::ir::Type = cranelift_codegen::ir::types::I8;
+
+fn cranelift_int_type(target_triple: &target_lexicon::Triple) -> cranelift_codegen::ir::Type {
+ // TODO: this assumes that pointers are at least as wide as i32s:
+ // probably safe, but we should check.
+ // TODO: this relies on cranelift pointer types just being integers.
+ cranelift::prelude::Type::triple_pointer_type(&target_triple)
+}
+
+const CRANELIFT_INT_32_TYPE: cranelift_codegen::ir::Type = cranelift_codegen::ir::types::I32;
+
+fn data_layout_byte_size(layout: &PatioDataLayout, target_triple: &target_lexicon::Triple) -> u32 {
+ match layout {
+ PatioDataLayout::Array { element, size } => {
+ data_layout_byte_size(element, target_triple) * size
+ }
+
+ PatioDataLayout::Bool => CRANELIFT_BOOL_TYPE.bytes(),
+
+ PatioDataLayout::Byte => CRANELIFT_BYTE_TYPE.bytes(),
+
+ PatioDataLayout::DataPtr => {
+ cranelift::prelude::Type::triple_pointer_type(&target_triple).bytes()
+ }
+
+ PatioDataLayout::FunctionPtr => {
+ cranelift::prelude::Type::triple_pointer_type(&target_triple).bytes()
+ }
+
+ PatioDataLayout::Int => cranelift_int_type(target_triple).bytes(),
+
+ PatioDataLayout::Int32 => CRANELIFT_INT_32_TYPE.bytes(),
+
+ PatioDataLayout::Struct { elements } => elements
+ .iter()
+ .map(|element| data_layout_byte_size(element, target_triple))
+ .sum(),
+ }
+}
+
+#[cfg(test)]
+mod data_layout_byte_size_test {
+ use std::str::FromStr;
+
+ use crate::patio::types::PatioDataLayout;
+
+ fn data_layout_byte_size(layout: &PatioDataLayout) -> u32 {
+ super::data_layout_byte_size(
+ layout,
+ &target_lexicon::Triple::from_str("x86_64-unknown-linux-gnu").unwrap(),
+ )
+ }
+
+ #[test]
+ fn bool_is_one_byte() {
+ assert_eq!(data_layout_byte_size(&PatioDataLayout::Bool), 1);
+ }
+
+ #[test]
+ fn byte_is_one_byte() {
+ assert_eq!(data_layout_byte_size(&PatioDataLayout::Byte), 1);
+ }
+
+ #[test]
+ fn data_ptr_is_width_of_pointer() {
+ assert_eq!(data_layout_byte_size(&PatioDataLayout::DataPtr), 8);
+ }
+
+ #[test]
+ fn function_ptr_is_width_of_pointer() {
+ assert_eq!(data_layout_byte_size(&PatioDataLayout::FunctionPtr), 8);
+ }
+
+ #[test]
+ fn int_is_width_of_pointer_and_at_least_32_bits() {
+ assert_eq!(data_layout_byte_size(&PatioDataLayout::Int), 8);
+ }
+
+ #[test]
+ fn int32_is_four_bytes() {
+ assert_eq!(data_layout_byte_size(&PatioDataLayout::Int32), 4);
+ }
+
+ #[test]
+ fn array_size_is_size_of_each_element_multiplied_by_number_of_elements() {
+ assert_eq!(
+ data_layout_byte_size(&PatioDataLayout::array(PatioDataLayout::Int32, 7)),
+ 28
+ );
+ }
+
+ #[test]
+ fn struct_size_is_sum_of_element_sizes() {
+ assert_eq!(
+ data_layout_byte_size(&PatioDataLayout::struct_(vec![
+ PatioDataLayout::Int32,
+ PatioDataLayout::Byte
+ ])),
+ 5
+ );
+ }
+}
+
+fn data_layout_byte_offset(
+ layout: &PatioDataLayout,
+ element_offsets: &[u32],
+ target_triple: &target_lexicon::Triple,
+) -> u32 {
+ let mut byte_offset = 0;
+ let mut current_element = layout;
+
+ for element_offset in element_offsets {
+ match current_element {
+ PatioDataLayout::Array { element, size: _ } => {
+ byte_offset += data_layout_byte_size(element, target_triple) * element_offset;
+ current_element = element;
+ }
+
+ PatioDataLayout::Bool => panic!("offset not allowed for bool"),
+ PatioDataLayout::Byte => panic!("offset not allowed for byte"),
+ PatioDataLayout::DataPtr => panic!("offset not allowed for data ptr"),
+ PatioDataLayout::FunctionPtr => panic!("offset not allowed for function ptr"),
+ PatioDataLayout::Int => panic!("offset not allowed for int"),
+ PatioDataLayout::Int32 => panic!("offset not allowed for int32"),
+
+ PatioDataLayout::Struct { elements } => {
+ for element in elements.iter().take((*element_offset).try_into().unwrap()) {
+ byte_offset += data_layout_byte_size(element, target_triple);
+ }
+
+ current_element = &elements[usize::try_from(*element_offset).unwrap()];
+ }
+ }
+ }
+
+ byte_offset
+}
+
+#[cfg(test)]
+mod data_layout_byte_offset_test {
+ use std::str::FromStr;
+
+ use crate::patio::types::PatioDataLayout;
+
+ fn data_layout_byte_offset(layout: &PatioDataLayout, element_offsets: Vec<u32>) -> u32 {
+ super::data_layout_byte_offset(
+ layout,
+ &element_offsets,
+ &target_lexicon::Triple::from_str("x86_64-unknown-linux-gnu").unwrap(),
+ )
+ }
+
+ #[test]
+ fn byte_offset_of_first_element_of_array_is_zero() {
+ let layout = PatioDataLayout::array(PatioDataLayout::Int32, 2);
+
+ let byte_offset = data_layout_byte_offset(&layout, vec![0]);
+
+ assert_eq!(byte_offset, 0);
+ }
+
+ #[test]
+ fn byte_offset_of_element_of_array_is_size_of_skipped_elements() {
+ let layout = PatioDataLayout::array(PatioDataLayout::Int32, 5);
+
+ let byte_offset = data_layout_byte_offset(&layout, vec![2]);
+
+ assert_eq!(byte_offset, 8);
+ }
+
+ #[test]
+ fn byte_offset_of_element_of_element_of_array_is_size_of_skipped_elements() {
+ let layout = PatioDataLayout::array(PatioDataLayout::array(PatioDataLayout::Byte, 7), 5);
+
+ let byte_offset = data_layout_byte_offset(&layout, vec![2, 3]);
+
+ assert_eq!(byte_offset, 17);
+ }
+
+ #[test]
+ fn byte_offset_of_first_element_of_struct_is_zero() {
+ let layout = PatioDataLayout::struct_(vec![
+ PatioDataLayout::Int32,
+ PatioDataLayout::Byte,
+ PatioDataLayout::DataPtr,
+ ]);
+
+ let byte_offset = data_layout_byte_offset(&layout, vec![0]);
+
+ assert_eq!(byte_offset, 0);
+ }
+
+ #[test]
+ fn byte_offset_of_element_of_struct_is_size_of_skipped_elements() {
+ let layout = PatioDataLayout::struct_(vec![
+ PatioDataLayout::Int32,
+ PatioDataLayout::Byte,
+ PatioDataLayout::DataPtr,
+ ]);
+
+ let byte_offset = data_layout_byte_offset(&layout, vec![2]);
+
+ assert_eq!(byte_offset, 5);
+ }
+
+ #[test]
+ fn byte_offset_of_element_of_element_of_struct_is_size_of_skipped_elements() {
+ let layout = PatioDataLayout::struct_(vec![
+ PatioDataLayout::Int32,
+ PatioDataLayout::struct_(vec![
+ PatioDataLayout::Byte,
+ PatioDataLayout::DataPtr,
+ PatioDataLayout::Byte,
+ ]),
+ PatioDataLayout::Int32,
+ ]);
+
+ let byte_offset = data_layout_byte_offset(&layout, vec![1, 2]);
+
+ assert_eq!(byte_offset, 13);
+ }
+}
+
+fn data_layout_element_at<'a>(
+ layout: &'a PatioDataLayout,
+ element_offsets: &[u32],
+) -> &'a PatioDataLayout {
+ let mut current_element = layout;
+
+ for element_offset in element_offsets {
+ match current_element {
+ PatioDataLayout::Array { element, size: _ } => {
+ current_element = element;
+ }
+
+ PatioDataLayout::Bool => panic!("offset not allowed for bool"),
+ PatioDataLayout::Byte => panic!("offset not allowed for byte"),
+ PatioDataLayout::DataPtr => panic!("offset not allowed for data ptr"),
+ PatioDataLayout::FunctionPtr => panic!("offset not allowed for function ptr"),
+ PatioDataLayout::Int => panic!("offset not allowed for int"),
+ PatioDataLayout::Int32 => panic!("offset not allowed for int32"),
+
+ PatioDataLayout::Struct { elements } => {
+ current_element = &elements[usize::try_from(*element_offset).unwrap()];
+ }
+ }
+ }
+
+ current_element
+}
+
+#[cfg(test)]
+mod data_layout_element_at_test {
+ use crate::patio::types::PatioDataLayout;
+
+ fn data_layout_element_at(
+ layout: &PatioDataLayout,
+ element_offsets: Vec<u32>,
+ ) -> &PatioDataLayout {
+ super::data_layout_element_at(layout, &element_offsets)
+ }
+
+ #[test]
+ fn element_of_array_is_element_layout() {
+ let layout = PatioDataLayout::array(PatioDataLayout::Int32, 2);
+
+ let element = data_layout_element_at(&layout, vec![0]);
+
+ assert_eq!(element, &PatioDataLayout::Int32);
+ }
+
+ #[test]
+ fn element_of_element_of_array() {
+ let layout = PatioDataLayout::array(PatioDataLayout::array(PatioDataLayout::Byte, 7), 5);
+
+ let element = data_layout_element_at(&layout, vec![2, 3]);
+
+ assert_eq!(element, &PatioDataLayout::Byte);
+ }
+
+ #[test]
+ fn first_element_of_struct() {
+ let layout = PatioDataLayout::struct_(vec![
+ PatioDataLayout::Int32,
+ PatioDataLayout::Byte,
+ PatioDataLayout::DataPtr,
+ ]);
+
+ let element = data_layout_element_at(&layout, vec![0]);
+
+ assert_eq!(element, &PatioDataLayout::Int32);
+ }
+
+ #[test]
+ fn non_first_element_of_struct() {
+ let layout = PatioDataLayout::struct_(vec![
+ PatioDataLayout::Int32,
+ PatioDataLayout::Byte,
+ PatioDataLayout::DataPtr,
+ ]);
+
+ let element = data_layout_element_at(&layout, vec![2]);
+
+ assert_eq!(element, &PatioDataLayout::DataPtr);
+ }
+
+ #[test]
+ fn element_of_element_of_struct() {
+ let layout = PatioDataLayout::struct_(vec![
+ PatioDataLayout::Int32,
+ PatioDataLayout::struct_(vec![
+ PatioDataLayout::Byte,
+ PatioDataLayout::DataPtr,
+ PatioDataLayout::Byte,
+ ]),
+ PatioDataLayout::Int32,
+ ]);
+
+ let element = data_layout_element_at(&layout, vec![1, 2]);
+
+ assert_eq!(element, &PatioDataLayout::Byte);
+ }
+}
+
+fn data_layout_to_type(layout: &PatioDataLayout) -> PatioType {
+ match layout {
+ PatioDataLayout::Array { .. } => panic!("array cannot be represented as type"),
+ PatioDataLayout::Bool => PatioType::Bool,
+ PatioDataLayout::Byte => PatioType::Byte,
+ PatioDataLayout::DataPtr => PatioType::DataPtr,
+ PatioDataLayout::FunctionPtr => PatioType::FunctionPtr,
+ PatioDataLayout::Int => PatioType::Int,
+ PatioDataLayout::Int32 => PatioType::Int32,
+ PatioDataLayout::Struct { .. } => panic!("struct cannot be represented as type"),
+ }
+}
+
+fn data_value_to_bytes(
+ value: &PatioDataValue,
+ target_triple: &target_lexicon::Triple,
+) -> Box<[u8]> {
+ let mut bytes = Vec::with_capacity(
+ data_layout_byte_size(&value.layout(), target_triple)
+ .try_into()
+ .unwrap(),
+ );
+
+ write_data_value(value, &mut bytes, target_triple);
+
+ bytes.into_boxed_slice()
+}
+
+fn write_data_value(
+ value: &PatioDataValue,
+ bytes: &mut Vec<u8>,
+ target_triple: &target_lexicon::Triple,
+) {
+ match value {
+ PatioDataValue::Array {
+ element_layout: _,
+ elements: _,
+ } => todo!(),
+ PatioDataValue::Bool(_) => todo!(),
+ PatioDataValue::Byte(_) => todo!(),
+ PatioDataValue::DataPtr(_) => todo!(),
+ PatioDataValue::Int(int_value) => {
+ // TODO: handle 32-bit int
+ let value: i64 = eval_int_value(int_value, target_triple).into();
+ bytes.write_all(&value.to_le_bytes()).unwrap();
+ }
+ PatioDataValue::Int32(_) => todo!(),
+ PatioDataValue::Struct { elements } => {
+ for element in elements {
+ write_data_value(element, bytes, target_triple);
+ }
+ }
+ }
+}
+
+fn eval_int_value(value: &PatioIntValue, target_triple: &target_lexicon::Triple) -> i32 {
+ match value {
+ PatioIntValue::ByteOffsetOf {
+ layout,
+ element_offsets,
+ } => data_layout_byte_offset(layout, element_offsets, target_triple)
+ .try_into()
+ .unwrap(),
+
+ PatioIntValue::ByteSizeOf { layout } => data_layout_byte_size(layout, target_triple)
+ .try_into()
+ .unwrap(),
+
+ PatioIntValue::Literal { value } => *value,
+ }
+}
diff --git a/patio-to-cranelift/src/lib.rs b/patio-to-cranelift/src/lib.rs
index a93e4a32..22afabba 100644
--- a/patio-to-cranelift/src/lib.rs
+++ b/patio-to-cranelift/src/lib.rs
@@ -1,27 +1,6 @@
-use std::{io::Write, path::Path, str::FromStr};
+use std::{path::Path, str::FromStr};
-use cranelift::prelude::InstBuilder;
-
-use crate::{
- context::{CompilerContext, CompilerFunctionContext, Mutability},
- errors::CompileError,
- patio::{
- compilation_unit::{
- PatioCompilationUnit, PatioCompilationUnitElement, PatioDataElementImmutableDefinition,
- PatioDataElementMutableDefinition, PatioFunctionDeclaration, PatioFunctionDefinition,
- PatioLocal, PatioLocalType, PatioVisibility,
- },
- instructions::{
- PatioBlock, PatioBoolToInt, PatioCall, PatioIf, PatioInstruction, PatioIntAdd,
- PatioIntEquals, PatioIntNotEqual, PatioIntSub, PatioIntToBool, PatioLocalStore,
- PatioMemoryLoad, PatioMemoryStore, PatioResume, PatioReturn, PatioReturnVoid,
- PatioVarLoad, PatioVarStore,
- },
- operands::{PatioLocalRef, PatioOperand},
- types::{PatioDataLayout, PatioType},
- values::{PatioDataPtrValue, PatioDataValue, PatioIntValue},
- },
-};
+use crate::{errors::CompileError, patio::compilation_unit::PatioCompilationUnit};
#[allow(dead_code, unused_imports)]
#[path = "./gen/patio_generated.rs"]
@@ -31,7 +10,7 @@ mod patio_generated;
#[path = "./gen/sources_generated.rs"]
mod sources_generated;
-mod context;
+mod codegen;
mod errors;
mod patio;
@@ -46,1056 +25,11 @@ pub fn compile(source_path: &Path, target_str: &str) -> Result<(), CompileError>
let target_triple =
target_lexicon::Triple::from_str(target_str).map_err(CompileError::ParseTargetTriple)?;
- let mut context = CompilerContext::for_object(source_path, target_triple)?;
-
- for element in &compilation_unit.elements {
- declare_compilation_unit_element(&element, &mut context);
- }
-
- for element in &compilation_unit.elements {
- define_compilation_unit_element(&element, &mut context);
- }
-
- let object = context.into_object();
- let object_bytes = object.emit().map_err(CompileError::ObjectEmitFailed)?;
+ let object_bytes =
+ codegen::compile_compilation_unit(compilation_unit, source_path, target_triple)?;
let destination_path = source_path.with_extension("o");
std::fs::write(destination_path, object_bytes).map_err(CompileError::WriteObjectFile)?;
Ok(())
}
-
-fn declare_compilation_unit_element(
- element: &PatioCompilationUnitElement,
- context: &mut CompilerContext,
-) {
- match element {
- PatioCompilationUnitElement::DataElementImmutableDefinition(
- data_element_immutable_definition,
- ) => {
- declare_data_element_immutable_definition(data_element_immutable_definition, context);
- }
-
- PatioCompilationUnitElement::DataElementMutableDefinition(
- data_element_mutable_definition,
- ) => {
- declare_data_element_mutable_definition(data_element_mutable_definition, context);
- }
-
- PatioCompilationUnitElement::FunctionDeclaration(function_declaration) => {
- declare_function_declaration(function_declaration, context);
- }
-
- PatioCompilationUnitElement::FunctionDefinition(function_definition) => {
- declare_function_definition(function_definition, context);
- }
- }
-}
-
-fn define_compilation_unit_element(
- element: &PatioCompilationUnitElement,
- context: &mut CompilerContext,
-) {
- match element {
- PatioCompilationUnitElement::DataElementImmutableDefinition(
- data_element_immutable_definition,
- ) => {
- define_data_element_immutable_definition(data_element_immutable_definition, context);
- }
-
- PatioCompilationUnitElement::DataElementMutableDefinition(
- data_element_mutable_definition,
- ) => {
- define_data_element_mutable_definition(data_element_mutable_definition, context);
- }
-
- PatioCompilationUnitElement::FunctionDeclaration(_) => {}
-
- PatioCompilationUnitElement::FunctionDefinition(function_definition) => {
- define_function_definition(&function_definition, context);
- }
- }
-}
-
-fn declare_data_element_immutable_definition(
- data_element_immutable_definition: &PatioDataElementImmutableDefinition,
- context: &mut CompilerContext,
-) {
- context.declare_data(
- &data_element_immutable_definition.name,
- patio_visibility_to_cranelift_linkage(data_element_immutable_definition.visibility),
- Mutability::Immutable,
- );
-}
-
-fn define_data_element_immutable_definition(
- data_element_immutable_definition: &PatioDataElementImmutableDefinition,
- context: &mut CompilerContext,
-) {
- let bytes = data_value_to_bytes(
- &data_element_immutable_definition.value,
- &context.target_triple,
- );
- context.define_data(&data_element_immutable_definition.name, bytes);
-}
-
-fn declare_data_element_mutable_definition(
- data_element_mutable_definition: &PatioDataElementMutableDefinition,
- context: &mut CompilerContext,
-) {
- context.declare_data(
- &data_element_mutable_definition.name,
- patio_visibility_to_cranelift_linkage(data_element_mutable_definition.visibility),
- Mutability::Mutable,
- );
-}
-
-fn define_data_element_mutable_definition(
- data_element_mutable_definition: &PatioDataElementMutableDefinition,
- context: &mut CompilerContext,
-) {
- let bytes = data_value_to_bytes(
- &data_element_mutable_definition.initial_value,
- &context.target_triple,
- );
- context.define_data(&data_element_mutable_definition.name, bytes);
-}
-
-fn declare_function_declaration(
- function_declaration: &PatioFunctionDeclaration,
- context: &mut CompilerContext,
-) {
- let cranelift_signature = cranelift_signature(
- function_declaration.params.iter(),
- function_declaration.return_type,
- &context.target_triple,
- );
-
- context.declare_function(
- &function_declaration.name,
- cranelift_module::Linkage::Import,
- &cranelift_signature,
- );
-}
-
-fn declare_function_definition(
- function_definition: &PatioFunctionDefinition,
- context: &mut CompilerContext,
-) {
- let cranelift_signature = cranelift_signature(
- function_definition.locals.iter().map(Into::into),
- function_definition.return_type,
- &context.target_triple,
- );
-
- let cranelift_linkage = patio_visibility_to_cranelift_linkage(function_definition.visibility);
-
- context.declare_function(
- &function_definition.name,
- cranelift_linkage,
- &cranelift_signature,
- );
-}
-
-fn define_function_definition(
- function_definition: &PatioFunctionDefinition,
- context: &mut CompilerContext,
-) {
- let cranelift_signature = cranelift_signature(
- function_definition.locals.iter().map(Into::into),
- function_definition.return_type,
- &context.target_triple,
- );
-
- context.enter_function(
- &function_definition.name,
- cranelift_signature,
- |function_context| {
- for local in &function_definition.locals {
- match local.local_type {
- PatioLocalType::Param => {}
-
- PatioLocalType::Val => {
- let cranelift_type = patio_type_to_cranelift_type(
- local.type_,
- &function_context.target_triple,
- );
- function_context.declare_var(&local.name, cranelift_type);
- }
-
- PatioLocalType::Var => {
- let cranelift_type = patio_type_to_cranelift_type(
- local.type_,
- &function_context.target_triple,
- );
- function_context.create_stack_slot(&local.name, cranelift_type);
- }
- }
- }
-
- for instruction in &function_definition.body {
- compile_instruction(instruction, function_context)
- }
- },
- );
-}
-
-fn compile_instruction(instruction: &PatioInstruction, context: &mut CompilerFunctionContext<'_>) {
- match instruction {
- PatioInstruction::Block(block) => {
- compile_block(block, context);
- }
-
- PatioInstruction::BoolToInt(bool_to_int) => {
- compile_bool_to_int(bool_to_int, context);
- }
-
- PatioInstruction::Call(call) => {
- compile_call(call, context);
- }
-
- PatioInstruction::If(if_) => {
- compile_if(if_, context);
- }
-
- PatioInstruction::IntAdd(int_add) => {
- compile_int_add(int_add, context);
- }
-
- PatioInstruction::IntEquals(int_equals) => {
- compile_int_equals(int_equals, context);
- }
-
- PatioInstruction::IntNotEqual(int_not_equal) => {
- compile_int_not_equal(int_not_equal, context);
- }
-
- PatioInstruction::IntSub(int_sub) => {
- compile_int_sub(int_sub, context);
- }
-
- PatioInstruction::IntToBool(int_to_bool) => {
- compile_int_to_bool(int_to_bool, context);
- }
-
- PatioInstruction::LocalStore(local_store) => {
- compile_local_store(local_store, context);
- }
-
- PatioInstruction::MemoryLoad(memory_load) => {
- compile_memory_load(memory_load, context);
- }
-
- PatioInstruction::MemoryStore(memory_store) => {
- compile_memory_store(memory_store, context);
- }
-
- PatioInstruction::Resume(resume) => {
- compile_resume(resume, context);
- }
-
- PatioInstruction::Return(return_) => {
- compile_return(return_, context);
- }
-
- PatioInstruction::ReturnVoid(return_void) => {
- compile_return_void(return_void, context);
- }
-
- PatioInstruction::VarLoad(var_load) => {
- compile_var_load(var_load, context);
- }
-
- PatioInstruction::VarStore(var_store) => {
- compile_var_store(var_store, context);
- }
- }
-}
-
-fn compile_block(
- block: &PatioBlock,
- context: &mut CompilerFunctionContext<'_>,
-) -> Vec<cranelift_codegen::ir::Value> {
- for instruction in &block.body {
- compile_instruction(instruction, context);
- }
-
- block
- .results
- .iter()
- .map(|result| compile_operand(&result, context))
- .collect()
-}
-
-fn compile_bool_to_int(bool_to_int: &PatioBoolToInt, context: &mut CompilerFunctionContext<'_>) {
- let cranelift_value = compile_operand(&bool_to_int.value, context);
-
- let cranelift_result = context
- .function_builder
- .ins()
- .uextend(cranelift_int_type(&context.target_triple), cranelift_value);
-
- def_destination(&bool_to_int.destination, cranelift_result, context)
-}
-
-fn compile_call(call: &PatioCall, context: &mut CompilerFunctionContext<'_>) {
- let cranelift_args = compile_operands(call.args.iter(), context);
-
- let func_ref = context.func_id(&call.function_name);
- context
- .function_builder
- .ins()
- .call(func_ref, &cranelift_args);
-}
-
-fn compile_if(if_: &PatioIf, context: &mut CompilerFunctionContext<'_>) {
- let cranelift_condition = compile_operand(&if_.condition, context);
- let cranelift_then_block = context.function_builder.create_block();
- let cranelift_else_block = context.function_builder.create_block();
- let cranelift_end_block = context.function_builder.create_block();
- let cranelift_end_params: Vec<_> = if_
- .destinations
- .iter()
- .map(|destination| {
- let cranelift_type = context.var_type(&destination.name);
- context
- .function_builder
- .append_block_param(cranelift_end_block, cranelift_type)
- })
- .collect();
-
- context.function_builder.ins().brif(
- cranelift_condition,
- cranelift_then_block,
- &[],
- cranelift_else_block,
- &[],
- );
- context
- .function_builder
- .seal_block(context.function_builder.current_block().unwrap());
-
- context
- .function_builder
- .switch_to_block(cranelift_then_block);
- let cranelift_then_results = compile_block(&if_.true_body, context);
- context.function_builder.ins().jump(
- cranelift_end_block,
- cranelift_block_args(cranelift_then_results).iter(),
- );
- context.function_builder.seal_block(cranelift_then_block);
-
- context
- .function_builder
- .switch_to_block(cranelift_else_block);
- let cranelift_else_results = compile_block(&if_.false_body, context);
- context.function_builder.ins().jump(
- cranelift_end_block,
- cranelift_block_args(cranelift_else_results).iter(),
- );
- context.function_builder.seal_block(cranelift_else_block);
-
- context
- .function_builder
- .switch_to_block(cranelift_end_block);
-
- for (destination, cranelift_end_param) in if_.destinations.iter().zip(cranelift_end_params) {
- def_destination(destination, cranelift_end_param, context);
- }
-}
-
-fn compile_int_add(int_add: &PatioIntAdd, context: &mut CompilerFunctionContext<'_>) {
- let cranelift_left = compile_operand(&int_add.left, context);
- let cranelift_right = compile_operand(&int_add.right, context);
- let cranelift_result = context
- .function_builder
- .ins()
- .iadd(cranelift_left, cranelift_right);
-
- def_destination(&int_add.destination, cranelift_result, context);
-}
-
-fn compile_int_equals(int_equals: &PatioIntEquals, context: &mut CompilerFunctionContext<'_>) {
- let cranelift_left = compile_operand(&int_equals.left, context);
- let cranelift_right = compile_operand(&int_equals.right, context);
- let cranelift_result = context.function_builder.ins().icmp(
- cranelift_codegen::ir::condcodes::IntCC::Equal,
- cranelift_left,
- cranelift_right,
- );
-
- def_destination(&int_equals.destination, cranelift_result, context);
-}
-
-fn compile_int_not_equal(
- int_not_equal: &PatioIntNotEqual,
- context: &mut CompilerFunctionContext<'_>,
-) {
- let cranelift_left = compile_operand(&int_not_equal.left, context);
- let cranelift_right = compile_operand(&int_not_equal.right, context);
- let cranelift_result = context.function_builder.ins().icmp(
- cranelift_codegen::ir::condcodes::IntCC::NotEqual,
- cranelift_left,
- cranelift_right,
- );
-
- def_destination(&int_not_equal.destination, cranelift_result, context);
-}
-
-fn compile_int_sub(int_sub: &PatioIntSub, context: &mut CompilerFunctionContext<'_>) {
- let cranelift_left = compile_operand(&int_sub.left, context);
- let cranelift_right = compile_operand(&int_sub.right, context);
- let cranelift_result = context
- .function_builder
- .ins()
- .isub(cranelift_left, cranelift_right);
-
- def_destination(&int_sub.destination, cranelift_result, context);
-}
-
-fn compile_int_to_bool(int_to_bool: &PatioIntToBool, context: &mut CompilerFunctionContext<'_>) {
- let cranelift_value = compile_operand(&int_to_bool.value, context);
-
- let cranelift_result = context
- .function_builder
- .ins()
- .ireduce(CRANELIFT_BOOL_TYPE, cranelift_value);
-
- def_destination(&int_to_bool.destination, cranelift_result, context);
-}
-
-fn compile_local_store(local_store: &PatioLocalStore, context: &mut CompilerFunctionContext<'_>) {
- let cranelift_value = compile_operand(&local_store.value, context);
- def_destination(&local_store.destination, cranelift_value, context);
-}
-
-fn compile_memory_load(memory_load: &PatioMemoryLoad, context: &mut CompilerFunctionContext<'_>) {
- let value_layout = data_layout_element_at(&memory_load.layout, &memory_load.element_offsets);
- let value_type = data_layout_to_type(value_layout);
- let cranelift_type = patio_type_to_cranelift_type(value_type, &context.target_triple);
-
- let cranelift_pointer = compile_operand(&memory_load.pointer, context);
- let cranelift_flags = cranelift_codegen::ir::MemFlags::new();
- let byte_offset = data_layout_byte_offset(
- &memory_load.layout,
- &memory_load.element_offsets,
- &context.target_triple,
- );
- let cranelift_offset =
- cranelift_codegen::ir::immediates::Offset32::new(byte_offset.try_into().unwrap());
- let cranelift_value = context.function_builder.ins().load(
- cranelift_type,
- cranelift_flags,
- cranelift_pointer,
- cranelift_offset,
- );
-
- def_destination(&memory_load.destination, cranelift_value, context);
-}
-
-fn compile_memory_store(
- memory_store: &PatioMemoryStore,
- context: &mut CompilerFunctionContext<'_>,
-) {
- let cranelift_value = compile_operand(&memory_store.value, context);
- let cranelift_pointer = compile_operand(&memory_store.pointer, context);
- let cranelift_flags = cranelift_codegen::ir::MemFlags::new();
- let byte_offset = data_layout_byte_offset(
- &memory_store.layout,
- &memory_store.element_offsets,
- &context.target_triple,
- );
- let cranelift_offset =
- cranelift_codegen::ir::immediates::Offset32::new(byte_offset.try_into().unwrap());
-
- context.function_builder.ins().store(
- cranelift_flags,
- cranelift_value,
- cranelift_pointer,
- cranelift_offset,
- );
-}
-
-fn compile_resume(resume: &PatioResume, context: &mut CompilerFunctionContext<'_>) {
- let cranelift_value = compile_operand(&resume.value, context);
-
- context.function_builder.ins().return_(&[cranelift_value]);
-}
-
-fn compile_return(return_: &PatioReturn, context: &mut CompilerFunctionContext<'_>) {
- let cranelift_value = compile_operand(&return_.value, context);
-
- context.function_builder.ins().return_(&[cranelift_value]);
-}
-
-fn compile_return_void(_return_void: &PatioReturnVoid, context: &mut CompilerFunctionContext<'_>) {
- context.function_builder.ins().return_(&[]);
-}
-
-fn compile_var_load(var_load: &PatioVarLoad, context: &mut CompilerFunctionContext<'_>) {
- let stack_slot = context.stack_slot(&var_load.var.name);
- let type_ = context.stack_slot_type(&var_load.var.name);
- let value = context.function_builder.ins().stack_load(
- type_,
- stack_slot,
- cranelift_codegen::ir::immediates::Offset32::new(0),
- );
- def_destination(&var_load.destination, value, context);
-}
-
-fn compile_var_store(var_store: &PatioVarStore, context: &mut CompilerFunctionContext<'_>) {
- let stack_slot = context.stack_slot(&var_store.var.name);
- let value = compile_operand(&var_store.value, context);
- context.function_builder.ins().stack_store(
- value,
- stack_slot,
- cranelift_codegen::ir::immediates::Offset32::new(0),
- );
-}
-
-fn compile_operands<'a>(
- operands: impl Iterator<Item = &'a PatioOperand>,
- context: &mut CompilerFunctionContext<'_>,
-) -> Vec<cranelift::prelude::Value> {
- operands
- .map(|operand| compile_operand(operand, context))
- .collect()
-}
-
-fn compile_operand(
- operand: &PatioOperand,
- context: &mut CompilerFunctionContext<'_>,
-) -> cranelift::prelude::Value {
- match operand {
- PatioOperand::BoolConst(value) => {
- let integer_value = if *value { 1 } else { 0 };
-
- context
- .function_builder
- .ins()
- .iconst(CRANELIFT_BOOL_TYPE, integer_value)
- }
-
- PatioOperand::DataPtrConst(value) => compile_data_ptr_value(&value, context),
-
- PatioOperand::IntConst(value) => {
- let cranelift_int_type = cranelift_int_type(&context.target_triple);
- compile_int_value(&value, cranelift_int_type, context)
- }
-
- PatioOperand::Int32Const(value) => {
- compile_int_value(&value, CRANELIFT_INT_32_TYPE, context)
- }
-
- PatioOperand::LocalRef(local_ref) => {
- let cranelift_variable = context.var(&local_ref.name);
- context.function_builder.use_var(cranelift_variable)
- }
-
- _ => {
- todo!("Unhandled operand: {operand:?}",)
- }
- }
-}
-
-fn compile_data_ptr_value(
- data_ptr_value: &PatioDataPtrValue,
- context: &mut CompilerFunctionContext<'_>,
-) -> cranelift_codegen::ir::Value {
- let data_ptr_type = context.pointer_type();
-
- match data_ptr_value {
- PatioDataPtrValue::DataElement { name } => {
- let global_value = context.data_ptr(name);
- context
- .function_builder
- .ins()
- .global_value(data_ptr_type, global_value)
- }
-
- PatioDataPtrValue::Null => context.function_builder.ins().iconst(data_ptr_type, 0),
- }
-}
-
-fn compile_int_value(
- int_value: &PatioIntValue,
- cranelift_type: cranelift::prelude::Type,
- context: &mut CompilerFunctionContext<'_>,
-) -> cranelift::prelude::Value {
- let value = eval_int_value(int_value, &context.target_triple);
-
- context
- .function_builder
- .ins()
- .iconst(cranelift_type, i64::from(value))
-}
-
-fn cranelift_block_args(
- values: impl IntoIterator<Item = cranelift_codegen::ir::Value>,
-) -> Vec<cranelift_codegen::ir::BlockArg> {
- values
- .into_iter()
- .map(|cranelift_result| cranelift_codegen::ir::BlockArg::Value(cranelift_result))
- .collect()
-}
-
-fn def_destination(
- destination: &PatioLocalRef,
- value: cranelift_codegen::ir::Value,
- context: &mut CompilerFunctionContext<'_>,
-) {
- let cranelift_destination = context.var(&destination.name);
- context
- .function_builder
- .def_var(cranelift_destination, value);
-}
-
-fn cranelift_signature<'a>(
- locals: impl Iterator<Item = &'a PatioLocal>,
- return_type: PatioType,
- target_triple: &target_lexicon::Triple,
-) -> cranelift::prelude::Signature {
- let mut signature =
- cranelift::prelude::Signature::new(cranelift_codegen::isa::CallConv::SystemV);
-
- for local in locals {
- if local.local_type == PatioLocalType::Param {
- let param_type = patio_type_to_cranelift_type(local.type_, &target_triple);
- let param = cranelift::prelude::AbiParam::new(param_type);
- signature.params.push(param);
- }
- }
-
- if return_type != PatioType::Void {
- let cranelift_return_type = patio_type_to_cranelift_type(return_type, &target_triple);
- let returns = cranelift::prelude::AbiParam::new(cranelift_return_type);
- signature.returns.push(returns);
- }
-
- signature
-}
-
-fn patio_visibility_to_cranelift_linkage(visibility: PatioVisibility) -> cranelift_module::Linkage {
- match visibility {
- PatioVisibility::Private => cranelift_module::Linkage::Local,
- PatioVisibility::Public => cranelift_module::Linkage::Export,
- }
-}
-
-fn patio_type_to_cranelift_type(
- patio_type: PatioType,
- target_triple: &target_lexicon::Triple,
-) -> cranelift::prelude::Type {
- match patio_type {
- PatioType::Bool => CRANELIFT_BOOL_TYPE,
-
- PatioType::Byte => CRANELIFT_BYTE_TYPE,
-
- PatioType::DataPtr => cranelift::prelude::Type::triple_pointer_type(&target_triple),
-
- PatioType::FunctionPtr => cranelift::prelude::Type::triple_pointer_type(&target_triple),
-
- PatioType::Int => cranelift_int_type(target_triple),
-
- PatioType::Int32 => CRANELIFT_INT_32_TYPE,
-
- PatioType::Void => todo!(),
- }
-}
-
-const CRANELIFT_BOOL_TYPE: cranelift_codegen::ir::Type = cranelift_codegen::ir::types::I8;
-const CRANELIFT_BYTE_TYPE: cranelift_codegen::ir::Type = cranelift_codegen::ir::types::I8;
-
-fn cranelift_int_type(target_triple: &target_lexicon::Triple) -> cranelift_codegen::ir::Type {
- // TODO: this assumes that pointers are at least as wide as i32s:
- // probably safe, but we should check.
- // TODO: this relies on cranelift pointer types just being integers.
- cranelift::prelude::Type::triple_pointer_type(&target_triple)
-}
-
-const CRANELIFT_INT_32_TYPE: cranelift_codegen::ir::Type = cranelift_codegen::ir::types::I32;
-
-fn data_layout_byte_size(layout: &PatioDataLayout, target_triple: &target_lexicon::Triple) -> u32 {
- match layout {
- PatioDataLayout::Array { element, size } => {
- data_layout_byte_size(element, target_triple) * size
- }
-
- PatioDataLayout::Bool => CRANELIFT_BOOL_TYPE.bytes(),
-
- PatioDataLayout::Byte => CRANELIFT_BYTE_TYPE.bytes(),
-
- PatioDataLayout::DataPtr => {
- cranelift::prelude::Type::triple_pointer_type(&target_triple).bytes()
- }
-
- PatioDataLayout::FunctionPtr => {
- cranelift::prelude::Type::triple_pointer_type(&target_triple).bytes()
- }
-
- PatioDataLayout::Int => cranelift_int_type(target_triple).bytes(),
-
- PatioDataLayout::Int32 => CRANELIFT_INT_32_TYPE.bytes(),
-
- PatioDataLayout::Struct { elements } => elements
- .iter()
- .map(|element| data_layout_byte_size(element, target_triple))
- .sum(),
- }
-}
-
-#[cfg(test)]
-mod data_layout_byte_size_test {
- use std::str::FromStr;
-
- use crate::patio::types::PatioDataLayout;
-
- fn data_layout_byte_size(layout: &PatioDataLayout) -> u32 {
- super::data_layout_byte_size(
- layout,
- &target_lexicon::Triple::from_str("x86_64-unknown-linux-gnu").unwrap(),
- )
- }
-
- #[test]
- fn bool_is_one_byte() {
- assert_eq!(data_layout_byte_size(&PatioDataLayout::Bool), 1);
- }
-
- #[test]
- fn byte_is_one_byte() {
- assert_eq!(data_layout_byte_size(&PatioDataLayout::Byte), 1);
- }
-
- #[test]
- fn data_ptr_is_width_of_pointer() {
- assert_eq!(data_layout_byte_size(&PatioDataLayout::DataPtr), 8);
- }
-
- #[test]
- fn function_ptr_is_width_of_pointer() {
- assert_eq!(data_layout_byte_size(&PatioDataLayout::FunctionPtr), 8);
- }
-
- #[test]
- fn int_is_width_of_pointer_and_at_least_32_bits() {
- assert_eq!(data_layout_byte_size(&PatioDataLayout::Int), 8);
- }
-
- #[test]
- fn int32_is_four_bytes() {
- assert_eq!(data_layout_byte_size(&PatioDataLayout::Int32), 4);
- }
-
- #[test]
- fn array_size_is_size_of_each_element_multiplied_by_number_of_elements() {
- assert_eq!(
- data_layout_byte_size(&PatioDataLayout::array(PatioDataLayout::Int32, 7)),
- 28
- );
- }
-
- #[test]
- fn struct_size_is_sum_of_element_sizes() {
- assert_eq!(
- data_layout_byte_size(&PatioDataLayout::struct_(vec![
- PatioDataLayout::Int32,
- PatioDataLayout::Byte
- ])),
- 5
- );
- }
-}
-
-fn data_layout_byte_offset(
- layout: &PatioDataLayout,
- element_offsets: &[u32],
- target_triple: &target_lexicon::Triple,
-) -> u32 {
- let mut byte_offset = 0;
- let mut current_element = layout;
-
- for element_offset in element_offsets {
- match current_element {
- PatioDataLayout::Array { element, size: _ } => {
- byte_offset += data_layout_byte_size(element, target_triple) * element_offset;
- current_element = element;
- }
-
- PatioDataLayout::Bool => panic!("offset not allowed for bool"),
- PatioDataLayout::Byte => panic!("offset not allowed for byte"),
- PatioDataLayout::DataPtr => panic!("offset not allowed for data ptr"),
- PatioDataLayout::FunctionPtr => panic!("offset not allowed for function ptr"),
- PatioDataLayout::Int => panic!("offset not allowed for int"),
- PatioDataLayout::Int32 => panic!("offset not allowed for int32"),
-
- PatioDataLayout::Struct { elements } => {
- for element in elements.iter().take((*element_offset).try_into().unwrap()) {
- byte_offset += data_layout_byte_size(element, target_triple);
- }
-
- current_element = &elements[usize::try_from(*element_offset).unwrap()];
- }
- }
- }
-
- byte_offset
-}
-
-#[cfg(test)]
-mod data_layout_byte_offset_test {
- use std::str::FromStr;
-
- use crate::patio::types::PatioDataLayout;
-
- fn data_layout_byte_offset(layout: &PatioDataLayout, element_offsets: Vec<u32>) -> u32 {
- super::data_layout_byte_offset(
- layout,
- &element_offsets,
- &target_lexicon::Triple::from_str("x86_64-unknown-linux-gnu").unwrap(),
- )
- }
-
- #[test]
- fn byte_offset_of_first_element_of_array_is_zero() {
- let layout = PatioDataLayout::array(PatioDataLayout::Int32, 2);
-
- let byte_offset = data_layout_byte_offset(&layout, vec![0]);
-
- assert_eq!(byte_offset, 0);
- }
-
- #[test]
- fn byte_offset_of_element_of_array_is_size_of_skipped_elements() {
- let layout = PatioDataLayout::array(PatioDataLayout::Int32, 5);
-
- let byte_offset = data_layout_byte_offset(&layout, vec![2]);
-
- assert_eq!(byte_offset, 8);
- }
-
- #[test]
- fn byte_offset_of_element_of_element_of_array_is_size_of_skipped_elements() {
- let layout = PatioDataLayout::array(PatioDataLayout::array(PatioDataLayout::Byte, 7), 5);
-
- let byte_offset = data_layout_byte_offset(&layout, vec![2, 3]);
-
- assert_eq!(byte_offset, 17);
- }
-
- #[test]
- fn byte_offset_of_first_element_of_struct_is_zero() {
- let layout = PatioDataLayout::struct_(vec![
- PatioDataLayout::Int32,
- PatioDataLayout::Byte,
- PatioDataLayout::DataPtr,
- ]);
-
- let byte_offset = data_layout_byte_offset(&layout, vec![0]);
-
- assert_eq!(byte_offset, 0);
- }
-
- #[test]
- fn byte_offset_of_element_of_struct_is_size_of_skipped_elements() {
- let layout = PatioDataLayout::struct_(vec![
- PatioDataLayout::Int32,
- PatioDataLayout::Byte,
- PatioDataLayout::DataPtr,
- ]);
-
- let byte_offset = data_layout_byte_offset(&layout, vec![2]);
-
- assert_eq!(byte_offset, 5);
- }
-
- #[test]
- fn byte_offset_of_element_of_element_of_struct_is_size_of_skipped_elements() {
- let layout = PatioDataLayout::struct_(vec![
- PatioDataLayout::Int32,
- PatioDataLayout::struct_(vec![
- PatioDataLayout::Byte,
- PatioDataLayout::DataPtr,
- PatioDataLayout::Byte,
- ]),
- PatioDataLayout::Int32,
- ]);
-
- let byte_offset = data_layout_byte_offset(&layout, vec![1, 2]);
-
- assert_eq!(byte_offset, 13);
- }
-}
-
-fn data_layout_element_at<'a>(
- layout: &'a PatioDataLayout,
- element_offsets: &[u32],
-) -> &'a PatioDataLayout {
- let mut current_element = layout;
-
- for element_offset in element_offsets {
- match current_element {
- PatioDataLayout::Array { element, size: _ } => {
- current_element = element;
- }
-
- PatioDataLayout::Bool => panic!("offset not allowed for bool"),
- PatioDataLayout::Byte => panic!("offset not allowed for byte"),
- PatioDataLayout::DataPtr => panic!("offset not allowed for data ptr"),
- PatioDataLayout::FunctionPtr => panic!("offset not allowed for function ptr"),
- PatioDataLayout::Int => panic!("offset not allowed for int"),
- PatioDataLayout::Int32 => panic!("offset not allowed for int32"),
-
- PatioDataLayout::Struct { elements } => {
- current_element = &elements[usize::try_from(*element_offset).unwrap()];
- }
- }
- }
-
- current_element
-}
-
-#[cfg(test)]
-mod data_layout_element_at_test {
- use crate::patio::types::PatioDataLayout;
-
- fn data_layout_element_at(
- layout: &PatioDataLayout,
- element_offsets: Vec<u32>,
- ) -> &PatioDataLayout {
- super::data_layout_element_at(layout, &element_offsets)
- }
-
- #[test]
- fn element_of_array_is_element_layout() {
- let layout = PatioDataLayout::array(PatioDataLayout::Int32, 2);
-
- let element = data_layout_element_at(&layout, vec![0]);
-
- assert_eq!(element, &PatioDataLayout::Int32);
- }
-
- #[test]
- fn element_of_element_of_array() {
- let layout = PatioDataLayout::array(PatioDataLayout::array(PatioDataLayout::Byte, 7), 5);
-
- let element = data_layout_element_at(&layout, vec![2, 3]);
-
- assert_eq!(element, &PatioDataLayout::Byte);
- }
-
- #[test]
- fn first_element_of_struct() {
- let layout = PatioDataLayout::struct_(vec![
- PatioDataLayout::Int32,
- PatioDataLayout::Byte,
- PatioDataLayout::DataPtr,
- ]);
-
- let element = data_layout_element_at(&layout, vec![0]);
-
- assert_eq!(element, &PatioDataLayout::Int32);
- }
-
- #[test]
- fn non_first_element_of_struct() {
- let layout = PatioDataLayout::struct_(vec![
- PatioDataLayout::Int32,
- PatioDataLayout::Byte,
- PatioDataLayout::DataPtr,
- ]);
-
- let element = data_layout_element_at(&layout, vec![2]);
-
- assert_eq!(element, &PatioDataLayout::DataPtr);
- }
-
- #[test]
- fn element_of_element_of_struct() {
- let layout = PatioDataLayout::struct_(vec![
- PatioDataLayout::Int32,
- PatioDataLayout::struct_(vec![
- PatioDataLayout::Byte,
- PatioDataLayout::DataPtr,
- PatioDataLayout::Byte,
- ]),
- PatioDataLayout::Int32,
- ]);
-
- let element = data_layout_element_at(&layout, vec![1, 2]);
-
- assert_eq!(element, &PatioDataLayout::Byte);
- }
-}
-
-fn data_layout_to_type(layout: &PatioDataLayout) -> PatioType {
- match layout {
- PatioDataLayout::Array { .. } => panic!("array cannot be represented as type"),
- PatioDataLayout::Bool => PatioType::Bool,
- PatioDataLayout::Byte => PatioType::Byte,
- PatioDataLayout::DataPtr => PatioType::DataPtr,
- PatioDataLayout::FunctionPtr => PatioType::FunctionPtr,
- PatioDataLayout::Int => PatioType::Int,
- PatioDataLayout::Int32 => PatioType::Int32,
- PatioDataLayout::Struct { .. } => panic!("struct cannot be represented as type"),
- }
-}
-
-fn data_value_to_bytes(
- value: &PatioDataValue,
- target_triple: &target_lexicon::Triple,
-) -> Box<[u8]> {
- let mut bytes = Vec::with_capacity(
- data_layout_byte_size(&value.layout(), target_triple)
- .try_into()
- .unwrap(),
- );
-
- write_data_value(value, &mut bytes, target_triple);
-
- bytes.into_boxed_slice()
-}
-
-fn write_data_value(
- value: &PatioDataValue,
- bytes: &mut Vec<u8>,
- target_triple: &target_lexicon::Triple,
-) {
- match value {
- PatioDataValue::Array {
- element_layout: _,
- elements: _,
- } => todo!(),
- PatioDataValue::Bool(_) => todo!(),
- PatioDataValue::Byte(_) => todo!(),
- PatioDataValue::DataPtr(_) => todo!(),
- PatioDataValue::Int(int_value) => {
- // TODO: handle 32-bit int
- let value: i64 = eval_int_value(int_value, target_triple).into();
- bytes.write_all(&value.to_le_bytes()).unwrap();
- }
- PatioDataValue::Int32(_) => todo!(),
- PatioDataValue::Struct { elements } => {
- for element in elements {
- write_data_value(element, bytes, target_triple);
- }
- }
- }
-}
-
-fn eval_int_value(value: &PatioIntValue, target_triple: &target_lexicon::Triple) -> i32 {
- match value {
- PatioIntValue::ByteOffsetOf {
- layout,
- element_offsets,
- } => data_layout_byte_offset(layout, element_offsets, target_triple)
- .try_into()
- .unwrap(),
-
- PatioIntValue::ByteSizeOf { layout } => data_layout_byte_size(layout, target_triple)
- .try_into()
- .unwrap(),
-
- PatioIntValue::Literal { value } => *value,
- }
-}