Skip to content

Commit 7d2d504

Browse files
committed
codegen: Index function types
`POINTER TO <function>` are now indexed in the codegen
1 parent 3f7551c commit 7d2d504

File tree

5 files changed

+139
-24
lines changed

5 files changed

+139
-24
lines changed

src/codegen/generators/data_type_generator.rs

Lines changed: 83 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Copyright (c) 2020 Ghaith Hachem and Mathias Rieder
22
use crate::codegen::debug::Debug;
3-
use crate::index::{FxIndexSet, Index, VariableIndexEntry, VariableType};
3+
use crate::codegen::llvm_index::TypeHelper;
4+
use crate::index::{FxIndexSet, Index, PouIndexEntry, VariableIndexEntry, VariableType};
45
use crate::resolver::{AstAnnotations, Dependency};
56
use crate::typesystem::{self, DataTypeInformation, Dimension, StringEncoding, StructSource};
67
use crate::{
@@ -12,12 +13,13 @@ use crate::{
1213
typesystem::DataType,
1314
};
1415

16+
use inkwell::types::{AnyType, AnyTypeEnum, FunctionType};
1517
use inkwell::{
1618
types::{BasicType, BasicTypeEnum},
1719
values::{BasicValue, BasicValueEnum},
1820
AddressSpace,
1921
};
20-
use plc_ast::ast::{AstNode, AstStatement};
22+
use plc_ast::ast::{AstNode, AstStatement, PouType};
2123
use plc_ast::literals::AstLiteral;
2224
use plc_diagnostics::diagnostics::Diagnostic;
2325
use plc_source::source_location::SourceLocation;
@@ -200,15 +202,26 @@ impl<'ink> DataTypeGenerator<'ink, '_> {
200202
/// Creates an llvm type to be associated with the given data type.
201203
/// Generates only an opaque type for structs.
202204
/// Eagerly generates but does not associate nested array and referenced aliased types
203-
fn create_type(&mut self, name: &str, data_type: &DataType) -> Result<BasicTypeEnum<'ink>, Diagnostic> {
205+
fn create_type(&mut self, name: &str, data_type: &DataType) -> Result<AnyTypeEnum<'ink>, Diagnostic> {
204206
let information = data_type.get_type_information();
205207
match information {
206208
DataTypeInformation::Struct { source, .. } => match source {
207-
StructSource::Pou(..) => self.types_index.get_associated_pou_type(data_type.get_name()),
208-
StructSource::OriginalDeclaration => {
209-
self.types_index.get_associated_type(data_type.get_name())
209+
StructSource::Pou(PouType::Method { .. }) => {
210+
Ok(self.create_function_type(name)?.as_any_type_enum())
210211
}
211-
StructSource::Internal(_) => self.types_index.get_associated_type(data_type.get_name()),
212+
213+
StructSource::Pou(..) => self
214+
.types_index
215+
.get_associated_pou_type(data_type.get_name())
216+
.map(|res| res.as_any_type_enum()),
217+
StructSource::OriginalDeclaration => self
218+
.types_index
219+
.get_associated_type(data_type.get_name())
220+
.map(|res| res.as_any_type_enum()),
221+
StructSource::Internal(_) => self
222+
.types_index
223+
.get_associated_type(data_type.get_name())
224+
.map(|res| res.as_any_type_enum()),
212225
},
213226

214227
// We distinguish between two types of arrays, normal and variable length ones.
@@ -222,7 +235,7 @@ impl<'ink> DataTypeGenerator<'ink, '_> {
222235
.get_effective_type_by_name(inner_type_name)
223236
.and_then(|inner_type| self.create_type(inner_type_name, inner_type))
224237
.and_then(|inner_type| self.create_nested_array_type(inner_type, dimensions))
225-
.map(|it| it.as_basic_type_enum())
238+
.map(|it| it.as_any_type_enum())
226239
}
227240
}
228241
DataTypeInformation::Integer { size, .. } => {
@@ -264,14 +277,63 @@ impl<'ink> DataTypeGenerator<'ink, '_> {
264277
DataTypeInformation::Void => Ok(get_llvm_int_type(self.llvm.context, 32, "Void").into()),
265278
DataTypeInformation::Pointer { inner_type_name, .. } => {
266279
let inner_type = self.create_type(inner_type_name, self.index.get_type(inner_type_name)?)?;
267-
Ok(inner_type.ptr_type(AddressSpace::from(ADDRESS_SPACE_GENERIC)).into())
280+
Ok(inner_type.create_ptr_type(AddressSpace::from(ADDRESS_SPACE_GENERIC)).into())
268281
}
269282
DataTypeInformation::Generic { .. } => {
270283
unreachable!("Generic types should not be generated")
271284
}
272285
}
273286
}
274287

288+
// TODO(vosa): Is this neccessary? Are the function types indexed and later on used in the expression
289+
// generator? If not this whole commit could be reverted, double-check before merging
290+
fn create_function_type(&mut self, pou_name: &str) -> Result<FunctionType<'ink>, Diagnostic> {
291+
let return_type = self
292+
.types_index
293+
.find_associated_type(self.index.get_return_type_or_void(pou_name).get_name())
294+
.map(|opt| opt.as_any_type_enum())
295+
.unwrap_or(self.llvm.context.void_type().as_any_type_enum());
296+
297+
let mut parameter_types = Vec::new();
298+
299+
// Methods are defined as functions in the LLVM IR, but carry the underlying POU type as their first
300+
// parameter to operate on them, hence push the POU type to the very first position.
301+
if let Some(PouIndexEntry::Method { parent_name, .. }) = self.index.find_pou(pou_name) {
302+
let ty = self.types_index.get_associated_type(parent_name).expect("must exist");
303+
let ty_ptr = ty.ptr_type(AddressSpace::from(ADDRESS_SPACE_GENERIC)).into();
304+
305+
parameter_types.push(ty_ptr);
306+
}
307+
308+
for parameter in self.index.get_declared_parameters(pou_name) {
309+
// Instead of relying on the LLVM index, we create data-types directly in here because some of
310+
// them may not have been registered yet. For example, at the time of writing this comment the
311+
// `__auto_pointer_to_DINT` type was not present in the index for a VAR_IN_OUT parameter which
312+
// resulted in an error
313+
let ty = self.create_type(
314+
parameter.get_name(),
315+
self.index.get_type(&parameter.data_type_name).expect("must exist"),
316+
)?;
317+
318+
parameter_types.push(ty.try_into().unwrap());
319+
}
320+
321+
let fn_type = match return_type {
322+
AnyTypeEnum::ArrayType(value) => value.fn_type(parameter_types.as_slice(), false),
323+
AnyTypeEnum::FloatType(value) => value.fn_type(parameter_types.as_slice(), false),
324+
AnyTypeEnum::IntType(value) => value.fn_type(parameter_types.as_slice(), false),
325+
AnyTypeEnum::PointerType(value) => value.fn_type(parameter_types.as_slice(), false),
326+
AnyTypeEnum::StructType(value) => value.fn_type(parameter_types.as_slice(), false),
327+
AnyTypeEnum::VectorType(value) => value.fn_type(parameter_types.as_slice(), false),
328+
AnyTypeEnum::VoidType(value) => value.fn_type(parameter_types.as_slice(), false),
329+
330+
AnyTypeEnum::FunctionType(_) => unreachable!(),
331+
};
332+
333+
eprintln!("created function type: {}", fn_type.print_to_string());
334+
Ok(fn_type)
335+
}
336+
275337
fn generate_initial_value(
276338
&mut self,
277339
data_type: &DataType,
@@ -435,9 +497,9 @@ impl<'ink> DataTypeGenerator<'ink, '_> {
435497
/// `arr: ARRAY[0..3] OF INT`.
436498
fn create_nested_array_type(
437499
&self,
438-
inner_type: BasicTypeEnum<'ink>,
500+
inner_type: AnyTypeEnum<'ink>,
439501
dimensions: &[Dimension],
440-
) -> Result<BasicTypeEnum<'ink>, Diagnostic> {
502+
) -> Result<AnyTypeEnum<'ink>, Diagnostic> {
441503
let len = dimensions
442504
.iter()
443505
.map(|dimension| {
@@ -453,14 +515,17 @@ impl<'ink> DataTypeGenerator<'ink, '_> {
453515
})?;
454516

455517
let result = match inner_type {
456-
BasicTypeEnum::IntType(ty) => ty.array_type(len),
457-
BasicTypeEnum::FloatType(ty) => ty.array_type(len),
458-
BasicTypeEnum::StructType(ty) => ty.array_type(len),
459-
BasicTypeEnum::ArrayType(ty) => ty.array_type(len),
460-
BasicTypeEnum::PointerType(ty) => ty.array_type(len),
461-
BasicTypeEnum::VectorType(ty) => ty.array_type(len),
518+
AnyTypeEnum::IntType(ty) => ty.array_type(len),
519+
AnyTypeEnum::FloatType(ty) => ty.array_type(len),
520+
AnyTypeEnum::StructType(ty) => ty.array_type(len),
521+
AnyTypeEnum::ArrayType(ty) => ty.array_type(len),
522+
AnyTypeEnum::PointerType(ty) => ty.array_type(len),
523+
AnyTypeEnum::VectorType(ty) => ty.array_type(len),
524+
525+
AnyTypeEnum::FunctionType(_) => unimplemented!("function types are not supported in arrays"),
526+
AnyTypeEnum::VoidType(_) => unimplemented!("void types not supported in arrays"),
462527
}
463-
.as_basic_type_enum();
528+
.as_any_type_enum();
464529

465530
Ok(result)
466531
}

src/codegen/generators/expression_generator.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -490,6 +490,10 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> {
490490
operator: &AstNode,
491491
parameters: Option<&AstNode>,
492492
) -> Result<ExpressionValue<'ink>, Diagnostic> {
493+
if self.annotations.get(operator).is_some_and(StatementAnnotation::is_fnptr) {
494+
unimplemented!();
495+
}
496+
493497
// find the pou we're calling
494498
let pou = self.annotations.get_call_name(operator).zip(self.annotations.get_qualified_name(operator))
495499
.and_then(|(call_name, qualified_name)| self.index.find_pou(call_name)

src/codegen/llvm_index.rs

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Copyright (c) 2020 Ghaith Hachem and Mathias Rieder
2-
use inkwell::types::BasicTypeEnum;
2+
use inkwell::types::{AnyTypeEnum, BasicType, BasicTypeEnum, PointerType};
33
use inkwell::values::{BasicValueEnum, FunctionValue, GlobalValue, PointerValue};
4+
use inkwell::AddressSpace;
45
use plc_diagnostics::diagnostics::Diagnostic;
56
use plc_source::source_location::SourceLocation;
67
use plc_util::convention::qualified_name;
@@ -11,8 +12,8 @@ use rustc_hash::FxHashMap;
1112
#[derive(Debug, Clone, Default)]
1213
pub struct LlvmTypedIndex<'ink> {
1314
parent_index: Option<&'ink LlvmTypedIndex<'ink>>,
14-
type_associations: FxHashMap<String, BasicTypeEnum<'ink>>,
15-
pou_type_associations: FxHashMap<String, BasicTypeEnum<'ink>>,
15+
type_associations: FxHashMap<String, AnyTypeEnum<'ink>>,
16+
pou_type_associations: FxHashMap<String, AnyTypeEnum<'ink>>,
1617
global_values: FxHashMap<String, GlobalValue<'ink>>,
1718
got_indices: FxHashMap<String, u64>,
1819
initial_value_associations: FxHashMap<String, BasicValueEnum<'ink>>,
@@ -23,6 +24,41 @@ pub struct LlvmTypedIndex<'ink> {
2324
utf16_literals: FxHashMap<String, GlobalValue<'ink>>,
2425
}
2526

27+
pub trait TypeHelper<'ink> {
28+
#[allow(clippy::wrong_self_convention)]
29+
fn as_basic_type(self) -> Option<BasicTypeEnum<'ink>>;
30+
31+
fn create_ptr_type(&self, address_space: AddressSpace) -> PointerType<'ink>;
32+
}
33+
34+
impl<'ink> TypeHelper<'ink> for AnyTypeEnum<'ink> {
35+
fn as_basic_type(self) -> Option<BasicTypeEnum<'ink>> {
36+
match self {
37+
AnyTypeEnum::ArrayType(value) => Some(value.as_basic_type_enum()),
38+
AnyTypeEnum::FloatType(value) => Some(value.as_basic_type_enum()),
39+
AnyTypeEnum::IntType(value) => Some(value.as_basic_type_enum()),
40+
AnyTypeEnum::PointerType(value) => Some(value.as_basic_type_enum()),
41+
AnyTypeEnum::StructType(value) => Some(value.as_basic_type_enum()),
42+
AnyTypeEnum::VectorType(value) => Some(value.as_basic_type_enum()),
43+
AnyTypeEnum::VoidType(_) => None,
44+
AnyTypeEnum::FunctionType(_) => None,
45+
}
46+
}
47+
48+
fn create_ptr_type(&self, address_space: AddressSpace) -> PointerType<'ink> {
49+
match self {
50+
AnyTypeEnum::ArrayType(value) => value.ptr_type(address_space),
51+
AnyTypeEnum::FloatType(value) => value.ptr_type(address_space),
52+
AnyTypeEnum::IntType(value) => value.ptr_type(address_space),
53+
AnyTypeEnum::PointerType(value) => value.ptr_type(address_space),
54+
AnyTypeEnum::StructType(value) => value.ptr_type(address_space),
55+
AnyTypeEnum::VectorType(value) => value.ptr_type(address_space),
56+
AnyTypeEnum::FunctionType(value) => value.ptr_type(address_space),
57+
AnyTypeEnum::VoidType(_) => unreachable!("Void type cannot be converted to pointer"),
58+
}
59+
}
60+
}
61+
2662
impl<'ink> LlvmTypedIndex<'ink> {
2763
pub fn create_child(parent: &'ink LlvmTypedIndex<'ink>) -> LlvmTypedIndex<'ink> {
2864
LlvmTypedIndex {
@@ -73,7 +109,7 @@ impl<'ink> LlvmTypedIndex<'ink> {
73109
pub fn associate_type(
74110
&mut self,
75111
type_name: &str,
76-
target_type: BasicTypeEnum<'ink>,
112+
target_type: AnyTypeEnum<'ink>,
77113
) -> Result<(), Diagnostic> {
78114
self.type_associations.insert(type_name.to_lowercase(), target_type);
79115
Ok(())
@@ -82,7 +118,7 @@ impl<'ink> LlvmTypedIndex<'ink> {
82118
pub fn associate_pou_type(
83119
&mut self,
84120
type_name: &str,
85-
target_type: BasicTypeEnum<'ink>,
121+
target_type: AnyTypeEnum<'ink>,
86122
) -> Result<(), Diagnostic> {
87123
self.pou_type_associations.insert(type_name.to_lowercase(), target_type);
88124
Ok(())
@@ -126,6 +162,7 @@ impl<'ink> LlvmTypedIndex<'ink> {
126162
self.type_associations
127163
.get(&type_name.to_lowercase())
128164
.copied()
165+
.and_then(TypeHelper::as_basic_type)
129166
.or_else(|| self.parent_index.and_then(|it| it.find_associated_type(type_name)))
130167
.or_else(|| self.find_associated_pou_type(type_name))
131168
}
@@ -134,6 +171,7 @@ impl<'ink> LlvmTypedIndex<'ink> {
134171
self.pou_type_associations
135172
.get(&type_name.to_lowercase())
136173
.copied()
174+
.and_then(TypeHelper::as_basic_type)
137175
.or_else(|| self.parent_index.and_then(|it| it.find_associated_pou_type(type_name)))
138176
}
139177

src/index.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1792,6 +1792,10 @@ impl Index {
17921792
variable.and_then(|it| self.get_type(it.get_type_name()).ok())
17931793
}
17941794

1795+
pub fn get_return_type_or_void(&self, pou_name: &str) -> &DataType {
1796+
self.find_return_type(pou_name).unwrap_or(self.get_void_type())
1797+
}
1798+
17951799
pub fn get_type_information_or_void(&self, type_name: &str) -> &DataTypeInformation {
17961800
self.find_effective_type_by_name(type_name)
17971801
.map(|it| it.get_type_information())

src/resolver.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -777,6 +777,10 @@ impl StatementAnnotation {
777777
_ => None,
778778
}
779779
}
780+
781+
pub fn is_fnptr(&self) -> bool {
782+
matches!(self, StatementAnnotation::FunctionPointer { .. })
783+
}
780784
}
781785

782786
impl From<&PouIndexEntry> for StatementAnnotation {
@@ -877,7 +881,7 @@ pub trait AnnotationMap {
877881
StatementAnnotation::Program { qualified_name }
878882
| StatementAnnotation::Super { name: qualified_name, .. }
879883
| StatementAnnotation::Function { qualified_name, .. }
880-
| StatementAnnotation::FunctionPointer { qualified_name, .. } => Some(&qualified_name),
884+
| StatementAnnotation::FunctionPointer { qualified_name, .. } => Some(qualified_name),
881885
StatementAnnotation::Label { .. }
882886
| StatementAnnotation::Override { .. }
883887
| StatementAnnotation::MethodDeclarations { .. }

0 commit comments

Comments
 (0)