Function

A function or a subroutine, with or without a body.

Declaration

Syntax

Function(symbol_table symtab, identifier name,
    ttype function_signature, identifier* dependencies, expr* args,
    stmt* body, expr? return_var, access access, bool deterministic,
    bool side_effect_free, string? module_file, gpu_kernel_layout? gpu,
    location start_name, location end_name)

Arguments

Argument

Description

symtab

the symbol table of the procedure: its dummy arguments, its result variable and its local variables.

name

the name of the procedure.

function_signature

a FunctionType giving the argument types, the result type (nil for a subroutine), the ABI and the attributes (elemental, pure, module, …).

dependencies

the names of the symbols the body refers to.

args

the dummy arguments, as Var expressions pointing into symtab. The order is the calling order.

body

the statements of the procedure. Empty for an interface (deftype=Interface) and for an external procedure.

return_var

the result variable of a function, as a Var; nil for a subroutine.

access

Public or Private, from the module’s access specification.

deterministic

true when the procedure returns the same result for the same arguments. Reserved for optimizations that need to duplicate or eliminate calls.

side_effect_free

true when a call has no effect other than its result. Reserved for the same optimizations.

module_file

the module file the procedure was loaded from, when it was; nil otherwise.

gpu

the finalized GPU kernel layout, or nil. Records buffer and scalar bindings, workspace extents and parameters, and the device call graph.

start_name

the source span of the name in the function or subroutine statement.

end_name

the source span of the name in the matching end statement.

Return values

None.

Description

One constructor represents both Fortran functions and Fortran subroutines. A subroutine is a Function whose return_var is nil and whose function_signature has no return_var_type; it is called by SubroutineCall rather than by FunctionCall.

The dummy arguments appear twice: in symtab, which owns the Variable symbols, and in args, which fixes their order. The result variable of a function is likewise owned by symtab, with intent=ReturnVar, and referenced by return_var.

A nonallocatable, nonpointer character dummy (a scalar, or an explicit-shape or assumed-size array) of a procedure without BIND(C) is passed as a pointer to its data, with the length of the actual (the element length of an array) passed by value in a hidden argument, as gfortran does. The string_length_arguments pass makes this explicit: it gives each such dummy an integer(8), value, intent(in) dummy after all the other dummies, in the order of the character dummies, makes it the len of an assumed-length dummy, and appends the lengths of the actuals to every call. Afterwards ASR verification requires every such dummy to have its hidden dummy and every call to pass it. ASRUtils::is_string_dummy_with_hidden_length() says which dummies these are; a code generator passes them as their data pointer alone.

deterministic and side_effect_free are declarations about the procedure, not consequences of its body. A frontend that cannot prove them must leave them false.

Only a kernel may own gpu metadata. It is produced after shared array and procedure lowering, before host launch expansion. Runtime workspace extents are expressions over the original kernel arguments; the host evaluates each once and passes the result in an additional scalar argument. The device uses that same scalar for its workspace slice. Buffer order and device-procedure identity are explicit rather than inferred from generated names.

ASR verification checks binding identities, ranks, workspace slots, extent dependencies and the ordered device-call closure. Absent optional aggregate metadata is omitted from readable ASR, so ordinary procedures retain their existing text representation.

Examples

An ASR text document that uses it:

(TranslationUnit
  :symtab (SymbolTable
    :id 0
    :symbols {
      "m" (Module
        :symtab (SymbolTable
          :id 1
          :symbols {
            "add" (Function
              :symtab (SymbolTable
                :id 2
                :symbols {
                  "a" (Variable
                    :parent_symtab 2
                    :name "a"
                    :dependencies []
                    :intent :In
                    :symbolic_value nil
                    :value nil
                    :storage :Default
                    :type (Integer
                      :kind 4
                    )
                    :type_declaration nil
                    :abi :Source
                    :access :Public
                    :presence :Required
                    :value_attr false
                    :target_attr false
                    :contiguous_attr false
                    :bindc_name nil
                    :is_volatile false
                    :is_protected false
                    :pass_attr :NotMethod
                    :self_argument nil
                    :codims []
                    :common_block nil
                  )
                  "b" (Variable
                    :parent_symtab 2
                    :name "b"
                    :dependencies []
                    :intent :In
                    :symbolic_value nil
                    :value nil
                    :storage :Default
                    :type (Integer
                      :kind 4
                    )
                    :type_declaration nil
                    :abi :Source
                    :access :Public
                    :presence :Required
                    :value_attr false
                    :target_attr false
                    :contiguous_attr false
                    :bindc_name nil
                    :is_volatile false
                    :is_protected false
                    :pass_attr :NotMethod
                    :self_argument nil
                    :codims []
                    :common_block nil
                  )
                  "c" (Variable
                    :parent_symtab 2
                    :name "c"
                    :dependencies []
                    :intent :ReturnVar
                    :symbolic_value nil
                    :value nil
                    :storage :Default
                    :type (Integer
                      :kind 4
                    )
                    :type_declaration nil
                    :abi :Source
                    :access :Public
                    :presence :Required
                    :value_attr false
                    :target_attr false
                    :contiguous_attr false
                    :bindc_name nil
                    :is_volatile false
                    :is_protected false
                    :pass_attr :NotMethod
                    :self_argument nil
                    :codims []
                    :common_block nil
                  )
                }
              )
              :name "add"
              :function_signature (FunctionType
                :arg_types [
                  (Integer
                    :kind 4
                  )
                  (Integer
                    :kind 4
                  )
                ]
                :return_var_type (Integer
                  :kind 4
                )
                :abi :Source
                :deftype :Implementation
                :bindc_name nil
                :elemental false
                :pure false
                :module false
                :inline false
                :static false
                :restrictions []
                :is_restriction false
                :exec_space :Host
              )
              :dependencies []
              :args [
                (Var
                  :v (SymbolRef 2 "a")
                )
                (Var
                  :v (SymbolRef 2 "b")
                )
              ]
              :body [
                (Assignment
                  :target (Var
                    :v (SymbolRef 2 "c")
                  )
                  :value (IntegerBinOp
                    :left (Var
                      :v (SymbolRef 2 "a")
                    )
                    :op :Add
                    :right (Var
                      :v (SymbolRef 2 "b")
                    )
                    :type (Integer
                      :kind 4
                    )
                    :value nil
                  )
                  :overloaded nil
                  :realloc_lhs false
                  :move_allocation false
                )
              ]
              :return_var (Var
                :v (SymbolRef 2 "c")
              )
              :access :Public
              :deterministic false
              :side_effect_free false
              :module_file nil
            )
          }
        )
        :name "m"
        :parent_module nil
        :dependencies []
        :loaded_from_mod false
        :intrinsic false
        :has_submodules false
        :global_init nil
      )
      "main" (Program
        :symtab (SymbolTable
          :id 3
          :symbols {}
        )
        :name "main"
        :dependencies []
        :body []
        :global_init nil
      )
    }
  )
  :items []
  :global_init nil
)

See Also

Module, Variable, FunctionCall, SubroutineCall, FunctionType