1
1
// Copyright (c) 2020 Ghaith Hachem and Mathias Rieder
2
2
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 } ;
4
5
use crate :: resolver:: { AstAnnotations , Dependency } ;
5
6
use crate :: typesystem:: { self , DataTypeInformation , Dimension , StringEncoding , StructSource } ;
6
7
use crate :: {
@@ -12,6 +13,7 @@ use crate::{
12
13
typesystem:: DataType ,
13
14
} ;
14
15
16
+ use inkwell:: types:: { AnyType , AnyTypeEnum , FunctionType } ;
15
17
use inkwell:: {
16
18
types:: { BasicType , BasicTypeEnum } ,
17
19
values:: { BasicValue , BasicValueEnum } ,
@@ -200,15 +202,22 @@ impl<'ink> DataTypeGenerator<'ink, '_> {
200
202
/// Creates an llvm type to be associated with the given data type.
201
203
/// Generates only an opaque type for structs.
202
204
/// 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 > {
204
206
let information = data_type. get_type_information ( ) ;
205
207
match information {
206
208
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 ( ) )
210
- }
211
- StructSource :: Internal ( _) => self . types_index . get_associated_type ( data_type. get_name ( ) ) ,
209
+ StructSource :: Pou ( ..) => self
210
+ . types_index
211
+ . get_associated_pou_type ( data_type. get_name ( ) )
212
+ . map ( |res| res. as_any_type_enum ( ) ) ,
213
+ StructSource :: OriginalDeclaration => self
214
+ . types_index
215
+ . get_associated_type ( data_type. get_name ( ) )
216
+ . map ( |res| res. as_any_type_enum ( ) ) ,
217
+ StructSource :: Internal ( _) => self
218
+ . types_index
219
+ . get_associated_type ( data_type. get_name ( ) )
220
+ . map ( |res| res. as_any_type_enum ( ) ) ,
212
221
} ,
213
222
214
223
// We distinguish between two types of arrays, normal and variable length ones.
@@ -222,7 +231,7 @@ impl<'ink> DataTypeGenerator<'ink, '_> {
222
231
. get_effective_type_by_name ( inner_type_name)
223
232
. and_then ( |inner_type| self . create_type ( inner_type_name, inner_type) )
224
233
. and_then ( |inner_type| self . create_nested_array_type ( inner_type, dimensions) )
225
- . map ( |it| it. as_basic_type_enum ( ) )
234
+ . map ( |it| it. as_any_type_enum ( ) )
226
235
}
227
236
}
228
237
DataTypeInformation :: Integer { size, .. } => {
@@ -263,15 +272,80 @@ impl<'ink> DataTypeGenerator<'ink, '_> {
263
272
. and_then ( |data_type| self . create_type ( name, data_type) ) ,
264
273
DataTypeInformation :: Void => Ok ( get_llvm_int_type ( self . llvm . context , 32 , "Void" ) . into ( ) ) ,
265
274
DataTypeInformation :: Pointer { inner_type_name, .. } => {
266
- 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 ( ) )
275
+ let inner_type = if information. is_function_pointer ( ) {
276
+ self . create_function_type ( inner_type_name) ?. as_any_type_enum ( )
277
+ } else {
278
+ self . create_type ( inner_type_name, self . index . get_type ( inner_type_name) ?) ?
279
+ } ;
280
+
281
+ Ok ( inner_type. create_ptr_type ( AddressSpace :: from ( ADDRESS_SPACE_GENERIC ) ) . into ( ) )
268
282
}
269
283
DataTypeInformation :: Generic { .. } => {
270
284
unreachable ! ( "Generic types should not be generated" )
271
285
}
272
286
}
273
287
}
274
288
289
+ fn create_function_type ( & mut self , method_name : & str ) -> Result < FunctionType < ' ink > , Diagnostic > {
290
+ let return_type = self
291
+ . types_index
292
+ . find_associated_type ( self . index . get_return_type_or_void ( method_name) . get_name ( ) )
293
+ . map ( |opt| opt. as_any_type_enum ( ) )
294
+ . unwrap_or ( self . llvm . context . void_type ( ) . as_any_type_enum ( ) ) ;
295
+
296
+ let mut parameter_types = Vec :: new ( ) ;
297
+
298
+ match self . index . find_pou ( method_name) {
299
+ Some ( PouIndexEntry :: Method { parent_name, .. } ) => {
300
+ let ty = self . types_index . get_associated_type ( parent_name) . expect ( "must exist" ) ;
301
+ let ty_ptr = ty. ptr_type ( AddressSpace :: from ( ADDRESS_SPACE_GENERIC ) ) . into ( ) ;
302
+
303
+ // Methods are defined as functions in the LLVM IR, but carry the underlying POU type as their
304
+ // first parameter to operate on them, hence push the POU type to the very first position.
305
+ parameter_types. push ( ty_ptr) ;
306
+
307
+ for parameter in self . index . get_declared_parameters ( method_name) {
308
+ // Instead of relying on the LLVM index, we create data-types on the fly here because some
309
+ // types have not yet been visited and as a result may not be in the index. For example at
310
+ // the time of writing this the index was not able to find a input parameter of type
311
+ // `__auto_pointer_to_DINT`, consequently panicking
312
+ let ty = self . create_type (
313
+ parameter. get_name ( ) ,
314
+ self . index . get_type ( & parameter. data_type_name ) . expect ( "must exist" ) ,
315
+ ) ?;
316
+
317
+ parameter_types. push ( ty. try_into ( ) . unwrap ( ) ) ;
318
+ }
319
+ }
320
+
321
+ Some ( PouIndexEntry :: FunctionBlock { name, .. } ) => {
322
+ let ty = self . types_index . get_associated_type ( name) . expect ( "must exist" ) ;
323
+ let ty_ptr = ty. ptr_type ( AddressSpace :: from ( ADDRESS_SPACE_GENERIC ) ) . into ( ) ;
324
+
325
+ // Function blocks are a bit "weird" in that they only expect an instance argument even if
326
+ // they define input, output and/or inout parameters. Effectively, while being methods per-se,
327
+ // their calling convention differs from regular methods.
328
+ parameter_types. push ( ty_ptr) ;
329
+ }
330
+
331
+ _ => unreachable ! ( "internal error, invalid method call" ) ,
332
+ }
333
+
334
+ let fn_type = match return_type {
335
+ AnyTypeEnum :: ArrayType ( value) => value. fn_type ( parameter_types. as_slice ( ) , false ) ,
336
+ AnyTypeEnum :: FloatType ( value) => value. fn_type ( parameter_types. as_slice ( ) , false ) ,
337
+ AnyTypeEnum :: IntType ( value) => value. fn_type ( parameter_types. as_slice ( ) , false ) ,
338
+ AnyTypeEnum :: PointerType ( value) => value. fn_type ( parameter_types. as_slice ( ) , false ) ,
339
+ AnyTypeEnum :: StructType ( value) => value. fn_type ( parameter_types. as_slice ( ) , false ) ,
340
+ AnyTypeEnum :: VectorType ( value) => value. fn_type ( parameter_types. as_slice ( ) , false ) ,
341
+ AnyTypeEnum :: VoidType ( value) => value. fn_type ( parameter_types. as_slice ( ) , false ) ,
342
+
343
+ AnyTypeEnum :: FunctionType ( _) => unreachable ! ( ) ,
344
+ } ;
345
+
346
+ Ok ( fn_type)
347
+ }
348
+
275
349
fn generate_initial_value (
276
350
& mut self ,
277
351
data_type : & DataType ,
@@ -435,9 +509,9 @@ impl<'ink> DataTypeGenerator<'ink, '_> {
435
509
/// `arr: ARRAY[0..3] OF INT`.
436
510
fn create_nested_array_type (
437
511
& self ,
438
- inner_type : BasicTypeEnum < ' ink > ,
512
+ inner_type : AnyTypeEnum < ' ink > ,
439
513
dimensions : & [ Dimension ] ,
440
- ) -> Result < BasicTypeEnum < ' ink > , Diagnostic > {
514
+ ) -> Result < AnyTypeEnum < ' ink > , Diagnostic > {
441
515
let len = dimensions
442
516
. iter ( )
443
517
. map ( |dimension| {
@@ -453,14 +527,17 @@ impl<'ink> DataTypeGenerator<'ink, '_> {
453
527
} ) ?;
454
528
455
529
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) ,
530
+ AnyTypeEnum :: IntType ( ty) => ty. array_type ( len) ,
531
+ AnyTypeEnum :: FloatType ( ty) => ty. array_type ( len) ,
532
+ AnyTypeEnum :: StructType ( ty) => ty. array_type ( len) ,
533
+ AnyTypeEnum :: ArrayType ( ty) => ty. array_type ( len) ,
534
+ AnyTypeEnum :: PointerType ( ty) => ty. array_type ( len) ,
535
+ AnyTypeEnum :: VectorType ( ty) => ty. array_type ( len) ,
536
+
537
+ AnyTypeEnum :: FunctionType ( _) => unimplemented ! ( "function types are not supported in arrays" ) ,
538
+ AnyTypeEnum :: VoidType ( _) => unimplemented ! ( "void types not supported in arrays" ) ,
462
539
}
463
- . as_basic_type_enum ( ) ;
540
+ . as_any_type_enum ( ) ;
464
541
465
542
Ok ( result)
466
543
}
0 commit comments