Skip to content

Commit

Permalink
cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
volsa committed May 29, 2024
1 parent e3a1686 commit efb36a9
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 34 deletions.
57 changes: 24 additions & 33 deletions src/codegen/generators/expression_generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -647,84 +647,77 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> {

fn generate_output_assignment_with_direct_access(
&self,
left_statement: &AstNode,
left_pointer: PointerValue,
lvalue_rhs: PointerValue,
statement_lhs: &AstNode,
type_rhs: &DataType,
right_pointer: PointerValue,
right_type: &DataType,
) -> Result<(), Diagnostic> {
let left_value = self.llvm.builder.build_load(left_pointer, "").into_int_value();

//Generate an expression for the right size
let right = self.llvm.builder.build_load(lvalue_rhs, "");
let right = self.llvm.builder.build_load(right_pointer, "");
self.generate_assignment_with_direct_access(
statement_lhs,
left_statement,
left_value,
left_pointer,
type_rhs,
right_type,
right,
)?;

Ok(())
}

fn generate_output_assignment(&self, context: &CallParameterAssignment) -> Result<(), Diagnostic> {
let &CallParameterAssignment { assignment, function_name, index, parameter_struct } = context;
let &CallParameterAssignment { assignment: expr, function_name, index, parameter_struct } = context;
let builder = &self.llvm.builder;

let Some(parameter) = self.index.get_declared_parameter(function_name, index) else {
panic!("or return?");
};
assert!(parameter.get_variable_type().is_output());

// Don't generate code if right-hand side of an assignment is an empty statement (e.g. `foo(out => )`)
if assignment.is_empty_statement() {
// We don't want to generate any code if the right side of an assignment is empty, e.g. `foo(out =>)`
if expr.is_empty_statement() {
return Ok(());
}

// FOO(x => y)
// FOO(x => y.0)
match assignment.get_stmt() {
AstStatement::ReferenceExpr(_) if assignment.has_direct_access() => {
let parameter = self.index.get_declared_parameter(function_name, index).expect("must exist");

match expr.get_stmt() {
AstStatement::ReferenceExpr(_) if expr.has_direct_access() => {
// TODO: Can we this be simplified?
let dt = {
let rhs_type = {
let pou = self.index.find_pou(function_name).unwrap();
let pou_struct = &pou.find_instance_struct_type(self.index).unwrap().information;
let DataTypeInformation::Struct { members, .. } = pou_struct else { panic!() };
let param = &members[index as usize]; // TODO: Create a test for this; this fucks up if populating the members is not in order

self.index.find_effective_type_by_name(&param.data_type_name).unwrap()
self.index.find_effective_type_by_name(&members[index as usize].data_type_name).unwrap()
};

let AstStatement::ReferenceExpr(ReferenceExpr {
access: ReferenceAccess::Member(member),
base,
}) = &assignment.get_stmt()
}) = &expr.get_stmt()
else {
unreachable!("must be a bitaccess, will return early for all other cases")
};

if let AstStatement::DirectAccess(_) = member.as_ref().get_stmt() {
// Given `foo.bar.baz.%W1.%B1.%X3`, we want to grab the base i.e. `foo.bar.baz`
let (Some(base), _) = (base, ..) else { panic!() };
// Given `foo.bar.baz.%W1.%B1.%X3`, we want to grab the lvalue of `foo.bar.baz`
let (base, _) = collect_base_and_direct_access_for_assignment(base).unwrap();

let lhs = self.generate_expression_value(base)?.get_basic_value_enum();
let rhs = self.llvm.builder.build_struct_gep(parameter_struct, index, "").unwrap(); // TODO(volsa): Is a `impl From<...>` possible for inkwell results?
let rhs = self.llvm.builder.build_struct_gep(parameter_struct, index, "").unwrap();

self.generate_output_assignment_with_direct_access(
expr,
lhs.into_pointer_value(),
rhs,
assignment,
dt,
rhs_type,
)?;
};
}

_ => {
let assigned_output = self.generate_lvalue(assignment)?;

let assigned_output = self.generate_lvalue(expr)?;
let assigned_output_type =
self.annotations.get_type_or_void(assignment, self.index).get_type_information();
self.annotations.get_type_or_void(expr, self.index).get_type_information();

let output = builder.build_struct_gep(parameter_struct, index, "").map_err(|_| {
Diagnostic::codegen_error(
Expand All @@ -735,15 +728,15 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> {

let output_value_type = self.index.get_type_information_or_void(parameter.get_type_name());

//Special string handling
// Special string handling
if (assigned_output_type.is_string() && output_value_type.is_string())
|| (assigned_output_type.is_struct() && output_value_type.is_struct())
|| (assigned_output_type.is_array() && output_value_type.is_array())
{
self.generate_string_store(
assigned_output,
assigned_output_type,
assignment.get_location(),
expr.get_location(),
output,
output_value_type,
parameter.source_location.clone(),
Expand All @@ -758,8 +751,6 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> {
Ok(())
}

/// Given an output assignment such as `foo => bar`, the right-hand side of the assignment (i.e. `bar`)
/// will be extracted and fed into [`generate_output_assignment`] in a subsequent call.
fn generate_explicit_output_assignment(
&self,
parameter_struct: PointerValue<'ink>,
Expand Down
4 changes: 3 additions & 1 deletion tests/correctness/bitaccess.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Copyright (c) 2020 Ghaith Hachem and Mathias Rieder

// TODO: Update tests, variable initialization into program body
// TODO: Some of these tests are incorrect, because a `default()` call will override the values defined in the
// VAR block. Thus any tests relying on data initialized in the VAR block needs to be updated such that
// the initialization happens in the POU body. However, this won't be any issue once we convert to LIT.

use crate::*;
use pretty_assertions::assert_eq;
Expand Down

0 comments on commit efb36a9

Please sign in to comment.