Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,8 @@ default-members = [".", "compiler/plc_driver", "compiler/plc_xml"]

[workspace.dependencies]
insta = { version = "1.31.0", features = ["filters"] }
inkwell = { version = "0.6", features = ["llvm14-0"] }
# inkwell = { version = "0.6", features = ["llvm14-0"] }
inkwell = { git = "https://github.com/abroooo/inkwell", branch = "abroooo/enumeration_type" , features = ["llvm14-0"] }
encoding_rs = "0.8"
encoding_rs_io = "0.1"
log = "0.4"
Expand All @@ -96,3 +97,6 @@ serde = { version = "1.0", features = ["derive"] }
serde_json = "1"
toml = "0.5"
rustc-hash = "1.1.0"

[patch.crates-io]
inkwell = { git = "https://github.com/abroooo/inkwell", branch = "abroooo/enumeration_type" }
81 changes: 77 additions & 4 deletions src/codegen/debug.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use inkwell::{
basic_block::BasicBlock,
context::Context,
debug_info::{
AsDIScope, DIBasicType, DICompileUnit, DICompositeType, DIDerivedType, DIFile, DIFlags,
AsDIScope, DIBasicType, DICompileUnit, DICompositeType, DIDerivedType, DIEnumerator, DIFile, DIFlags,
DIFlagsConstants, DILocalVariable, DIScope, DISubprogram, DISubroutineType, DIType,
DWARFEmissionKind, DebugInfoBuilder,
},
Expand Down Expand Up @@ -141,6 +141,7 @@ enum DebugType<'ink> {
Struct(DICompositeType<'ink>),
Derived(DIDerivedType<'ink>),
Composite(DICompositeType<'ink>),
Enumeration(DICompositeType<'ink>),
}

impl<'ink> From<DebugType<'ink>> for DIType<'ink> {
Expand All @@ -150,6 +151,7 @@ impl<'ink> From<DebugType<'ink>> for DIType<'ink> {
DebugType::Struct(t) => t.as_type(),
DebugType::Derived(t) => t.as_type(),
DebugType::Composite(t) => t.as_type(),
DebugType::Enumeration(t) => t.as_type(),
}
}
}
Expand Down Expand Up @@ -287,11 +289,72 @@ impl<'ink> DebugBuilder<'ink> {
let res = self
.debug_info
.create_basic_type(name, size, encoding as u32, DIFlagsConstants::PUBLIC)
.map_err(|err| Diagnostic::codegen_error(err, location))?;
.map_err(|err| Diagnostic::codegen_error(format!("{}", err), location))?;
self.register_concrete_type(name, DebugType::Basic(res));
Ok(())
}

fn create_enum_type(
&mut self,
name: &str,
variants: Vec<VariableIndexEntry>,
referenced_type: &str,
location: &SourceLocation,
index: &Index,
types_index: &LlvmTypedIndex,
) -> Result<(), Diagnostic> {
if location.is_internal() {
return Ok(());
}

let inner_dt = index.get_effective_type_by_name(referenced_type)?;
let inner_type = self.get_or_create_debug_type(inner_dt, index, types_index)?;
let file = location
.get_file_name()
.map(|it| self.get_or_create_debug_file(it))
.unwrap_or_else(|| self.compile_unit.get_file());

let llvm_type = types_index.get_associated_type(name)?;
let size_bits = self.target_data.get_bit_size(&llvm_type);
let align_bits = self.target_data.get_preferred_alignment(&llvm_type) * 8;

let enum_elements: Vec<DIEnumerator> = variants
.iter()
.enumerate()
.map(|(idx, variant)| {
// Access the initial_value field and convert to integer
let value = variant
.initial_value
.as_ref()
.and_then(|const_id| {
index
.get_const_expressions()
.get_constant_int_statement_value(const_id)
.ok()
.map(|v| v as i64)
})
.unwrap_or(idx as i64);

let is_unsigned = inner_dt.get_type_information().is_unsigned_int();
self.debug_info.create_enumerator(variant.get_name(), value, is_unsigned)
})
.collect();

let enum_type = self.debug_info.create_enumeration_type(
file.as_debug_info_scope(),
name,
file,
location.get_line_plus_one() as u32,
size_bits,
align_bits,
&enum_elements,
inner_type.into(),
);

self.register_concrete_type(name, DebugType::Enumeration(enum_type));
Ok(())
}

fn create_struct_type(
&mut self,
name: &str,
Expand Down Expand Up @@ -429,7 +492,10 @@ impl<'ink> DebugBuilder<'ink> {
DebugEncoding::DW_ATE_unsigned as u32,
DIFlagsConstants::PUBLIC,
)
.map_err(|err| Diagnostic::codegen_error(err, SourceLocation::undefined()))?,
// .map_err(|err| Diagnostic::codegen_error(err, SourceLocation::undefined()))?,
.map_err(|err| {
Diagnostic::codegen_error(format!("{:?}", err), SourceLocation::undefined())
})?,
)
} else {
self.get_or_create_debug_type(inner_type, index, types_index)?
Expand Down Expand Up @@ -764,6 +830,14 @@ impl<'ink> Debug<'ink> for DebugBuilder<'ink> {
let location = &datatype.location;
log::trace!("Creating debug info for type {name} with size {size} and info {type_info:?}");
match type_info {
DataTypeInformation::Enum { name, variants, referenced_type, .. } => self.create_enum_type(
name,
variants.to_vec(),
referenced_type,
location,
index,
types_index,
),
DataTypeInformation::Struct { members, .. } => {
self.create_struct_type(name, members.as_slice(), location, index, types_index)
}
Expand Down Expand Up @@ -796,7 +870,6 @@ impl<'ink> Debug<'ink> for DebugBuilder<'ink> {
self.create_string_type(name, length, *encoding, size, index, types_index)
}
DataTypeInformation::Alias { name, referenced_type }
| DataTypeInformation::Enum { name, referenced_type, .. }
| DataTypeInformation::SubRange { name, referenced_type, .. } => {
self.create_typedef_type(name, referenced_type, location, index, types_index)
}
Expand Down
49 changes: 22 additions & 27 deletions src/codegen/generators/expression_generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ use inkwell::{
},
AddressSpace, FloatPredicate, IntPredicate,
};
use itertools::Either;
use rustc_hash::FxHashSet;

use plc_ast::{
Expand Down Expand Up @@ -571,21 +570,6 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> {
// if the target is a function, declare the struct locally
// assign all parameters into the struct values

// so grab either:
// - the call's return value
// - or a null-ptr
let value = call
.try_as_basic_value()
.either(Ok, |_| {
// we return an uninitialized int pointer for void methods :-/
// dont deref it!!
Ok(get_llvm_int_type(self.llvm.context, INT_SIZE, INT_TYPE)
.ptr_type(AddressSpace::from(ADDRESS_SPACE_CONST))
.const_null()
.as_basic_value_enum())
})
.map(ExpressionValue::RValue);

// after the call we need to copy the values for assigned outputs
// this is only necessary for outputs defined as `rusty::index::ArgumentType::ByVal` (PROGRAM, FUNCTION_BLOCK)
// FUNCTION outputs are defined as `rusty::index::ArgumentType::ByRef` // FIXME(mhasel): for standard-compliance functions also need to support VAR_OUTPUT
Expand All @@ -598,7 +582,20 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> {
self.assign_output_values(parameter_struct, implementation_name, parameters_list)?
}

value
// if the target is a function, declare the struct locally
// assign all parameters into the struct values

// so grab either:
// - the call's return value
// - or a null-ptr
Ok(ExpressionValue::RValue(call.try_as_basic_value().basic().unwrap_or_else(|| {
// we return an uninitialized int pointer for void methods :-/
// dont deref it!!
get_llvm_int_type(self.llvm.context, INT_SIZE, INT_TYPE)
.ptr_type(AddressSpace::from(ADDRESS_SPACE_CONST))
.const_null()
.as_basic_value_enum()
})))
}

fn generate_fnptr_call(
Expand Down Expand Up @@ -668,21 +665,19 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> {
.build_call(callable, &arguments_llvm, "fnptr_call")
.map_err(CodegenError::from)?;

let value = match call.try_as_basic_value() {
Either::Left(value) => value,
Either::Right(_) => get_llvm_int_type(self.llvm.context, INT_SIZE, INT_TYPE)
.ptr_type(AddressSpace::from(ADDRESS_SPACE_CONST))
.const_null()
.as_basic_value_enum(),
};

// Output variables are assigned after the function block call, effectively gep'ing the instance
// struct fetching the output values
if impl_entry.is_function_block() {
self.assign_output_values(instance, qualified_pou_name, arguments_raw)?
}

Ok(ExpressionValue::RValue(value))
Ok(ExpressionValue::RValue(call.try_as_basic_value().basic().unwrap_or_else(|| {
// we return an uninitialized int pointer for void methods :-/
// dont deref it!!
get_llvm_int_type(self.llvm.context, INT_SIZE, INT_TYPE)
.ptr_type(AddressSpace::from(ADDRESS_SPACE_CONST))
.const_null()
.as_basic_value_enum()
})))
}

/// copies the output values to the assigned output variables
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,50 +8,59 @@ target datalayout = "[filtered]"
target triple = "[filtered]"

@en3 = global i64 0, !dbg !0
@en1.a = unnamed_addr constant i32 0, !dbg !5
@en1.b = unnamed_addr constant i32 1, !dbg !10
@en1.c = unnamed_addr constant i32 2, !dbg !12
@en2.d = unnamed_addr constant i8 0, !dbg !14
@en2.e = unnamed_addr constant i8 1, !dbg !19
@en2.f = unnamed_addr constant i8 2, !dbg !21
@__global_en3.a = unnamed_addr constant i64 0, !dbg !23
@__global_en3.b = unnamed_addr constant i64 1, !dbg !26
@__global_en3.c = unnamed_addr constant i64 2, !dbg !28
@en1.a = unnamed_addr constant i32 0, !dbg !9
@en1.b = unnamed_addr constant i32 1, !dbg !14
@en1.c = unnamed_addr constant i32 2, !dbg !16
@en2.d = unnamed_addr constant i8 0, !dbg !18
@en2.e = unnamed_addr constant i8 1, !dbg !27
@en2.f = unnamed_addr constant i8 2, !dbg !29
@__global_en3.a = unnamed_addr constant i64 0, !dbg !31
@__global_en3.b = unnamed_addr constant i64 1, !dbg !34
@__global_en3.c = unnamed_addr constant i64 2, !dbg !36

!llvm.module.flags = !{!30, !31}
!llvm.dbg.cu = !{!32}
!llvm.module.flags = !{!38, !39}
!llvm.dbg.cu = !{!40}

!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
!1 = distinct !DIGlobalVariable(name: "en3", scope: !2, file: !2, line: 5, type: !3, isLocal: false, isDefinition: true)
!2 = !DIFile(filename: "<internal>", directory: "")
!3 = !DIDerivedType(tag: DW_TAG_typedef, name: "__global_en3", scope: !2, file: !2, line: 5, baseType: !4, align: 64)
!3 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "__global_en3", scope: !2, file: !2, line: 5, baseType: !4, size: 64, align: 64, elements: !5)
!4 = !DIBasicType(name: "LINT", size: 64, encoding: DW_ATE_signed, flags: DIFlagPublic)
!5 = !DIGlobalVariableExpression(var: !6, expr: !DIExpression())
!6 = distinct !DIGlobalVariable(name: "en1.a", scope: !2, file: !2, line: 2, type: !7, isLocal: false, isDefinition: true)
!7 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !8)
!8 = !DIDerivedType(tag: DW_TAG_typedef, name: "en1", scope: !2, file: !2, line: 2, baseType: !9, align: 32)
!9 = !DIBasicType(name: "DINT", size: 32, encoding: DW_ATE_signed, flags: DIFlagPublic)
!10 = !DIGlobalVariableExpression(var: !11, expr: !DIExpression())
!11 = distinct !DIGlobalVariable(name: "en1.b", scope: !2, file: !2, line: 2, type: !7, isLocal: false, isDefinition: true)
!12 = !DIGlobalVariableExpression(var: !13, expr: !DIExpression())
!13 = distinct !DIGlobalVariable(name: "en1.c", scope: !2, file: !2, line: 2, type: !7, isLocal: false, isDefinition: true)
!5 = !{!6, !7, !8}
!6 = !DIEnumerator(name: "a", value: 0)
!7 = !DIEnumerator(name: "b", value: 1)
!8 = !DIEnumerator(name: "c", value: 2)
!9 = !DIGlobalVariableExpression(var: !10, expr: !DIExpression())
!10 = distinct !DIGlobalVariable(name: "en1.a", scope: !2, file: !2, line: 2, type: !11, isLocal: false, isDefinition: true)
!11 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !12)
!12 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "en1", scope: !2, file: !2, line: 2, baseType: !13, size: 32, align: 32, elements: !5)
!13 = !DIBasicType(name: "DINT", size: 32, encoding: DW_ATE_signed, flags: DIFlagPublic)
!14 = !DIGlobalVariableExpression(var: !15, expr: !DIExpression())
!15 = distinct !DIGlobalVariable(name: "en2.d", scope: !2, file: !2, line: 3, type: !16, isLocal: false, isDefinition: true)
!16 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !17)
!17 = !DIDerivedType(tag: DW_TAG_typedef, name: "en2", scope: !2, file: !2, line: 3, baseType: !18, align: 8)
!18 = !DIBasicType(name: "BYTE", size: 8, encoding: DW_ATE_unsigned, flags: DIFlagPublic)
!19 = !DIGlobalVariableExpression(var: !20, expr: !DIExpression())
!20 = distinct !DIGlobalVariable(name: "en2.e", scope: !2, file: !2, line: 3, type: !16, isLocal: false, isDefinition: true)
!21 = !DIGlobalVariableExpression(var: !22, expr: !DIExpression())
!22 = distinct !DIGlobalVariable(name: "en2.f", scope: !2, file: !2, line: 3, type: !16, isLocal: false, isDefinition: true)
!23 = !DIGlobalVariableExpression(var: !24, expr: !DIExpression())
!24 = distinct !DIGlobalVariable(name: "__global_en3.a", scope: !2, file: !2, line: 5, type: !25, isLocal: false, isDefinition: true)
!25 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !3)
!26 = !DIGlobalVariableExpression(var: !27, expr: !DIExpression())
!27 = distinct !DIGlobalVariable(name: "__global_en3.b", scope: !2, file: !2, line: 5, type: !25, isLocal: false, isDefinition: true)
!28 = !DIGlobalVariableExpression(var: !29, expr: !DIExpression())
!29 = distinct !DIGlobalVariable(name: "__global_en3.c", scope: !2, file: !2, line: 5, type: !25, isLocal: false, isDefinition: true)
!30 = !{i32 2, !"Dwarf Version", i32 5}
!31 = !{i32 2, !"Debug Info Version", i32 3}
!32 = distinct !DICompileUnit(language: DW_LANG_C, file: !2, producer: "RuSTy Structured text Compiler", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !33, splitDebugInlining: false)
!33 = !{!0, !5, !10, !12, !14, !19, !21, !23, !26, !28}
!15 = distinct !DIGlobalVariable(name: "en1.b", scope: !2, file: !2, line: 2, type: !11, isLocal: false, isDefinition: true)
!16 = !DIGlobalVariableExpression(var: !17, expr: !DIExpression())
!17 = distinct !DIGlobalVariable(name: "en1.c", scope: !2, file: !2, line: 2, type: !11, isLocal: false, isDefinition: true)
!18 = !DIGlobalVariableExpression(var: !19, expr: !DIExpression())
!19 = distinct !DIGlobalVariable(name: "en2.d", scope: !2, file: !2, line: 3, type: !20, isLocal: false, isDefinition: true)
!20 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !21)
!21 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "en2", scope: !2, file: !2, line: 3, baseType: !22, size: 8, align: 8, elements: !23)
!22 = !DIBasicType(name: "BYTE", size: 8, encoding: DW_ATE_unsigned, flags: DIFlagPublic)
!23 = !{!24, !25, !26}
!24 = !DIEnumerator(name: "d", value: 0, isUnsigned: true)
!25 = !DIEnumerator(name: "e", value: 1, isUnsigned: true)
!26 = !DIEnumerator(name: "f", value: 2, isUnsigned: true)
!27 = !DIGlobalVariableExpression(var: !28, expr: !DIExpression())
!28 = distinct !DIGlobalVariable(name: "en2.e", scope: !2, file: !2, line: 3, type: !20, isLocal: false, isDefinition: true)
!29 = !DIGlobalVariableExpression(var: !30, expr: !DIExpression())
!30 = distinct !DIGlobalVariable(name: "en2.f", scope: !2, file: !2, line: 3, type: !20, isLocal: false, isDefinition: true)
!31 = !DIGlobalVariableExpression(var: !32, expr: !DIExpression())
!32 = distinct !DIGlobalVariable(name: "__global_en3.a", scope: !2, file: !2, line: 5, type: !33, isLocal: false, isDefinition: true)
!33 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !3)
!34 = !DIGlobalVariableExpression(var: !35, expr: !DIExpression())
!35 = distinct !DIGlobalVariable(name: "__global_en3.b", scope: !2, file: !2, line: 5, type: !33, isLocal: false, isDefinition: true)
!36 = !DIGlobalVariableExpression(var: !37, expr: !DIExpression())
!37 = distinct !DIGlobalVariable(name: "__global_en3.c", scope: !2, file: !2, line: 5, type: !33, isLocal: false, isDefinition: true)
!38 = !{i32 2, !"Dwarf Version", i32 5}
!39 = !{i32 2, !"Debug Info Version", i32 3}
!40 = distinct !DICompileUnit(language: DW_LANG_C, file: !2, producer: "RuSTy Structured text Compiler", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !41, globals: !42, splitDebugInlining: false)
!41 = !{!3, !12, !21}
!42 = !{!0, !9, !14, !16, !18, !27, !29, !31, !34, !36}