class Savi::Compiler::CodeGen

Overview

The purpose of the CodeGen pass is to generate LLVM code (IR) which can be used along with LLVM tooling to create an executable program.

This pass does not mutate the Program topology. This pass does not mutate the AST. This pass does not raise any compilation errors. This pass keeps state at the program level. This pass produces output state at the program level.

Defined in:

savi/compiler/code_gen.cr
savi/compiler/code_gen/continuation_info.cr
savi/compiler/code_gen/debug_info.cr
savi/compiler/code_gen/gen_func.cr
savi/compiler/code_gen/gen_type.cr

Constructors

Class Method Summary

Instance Method Summary

Constructor Detail

def self.new(runtime : PonyRT.class | VeronaRT.class, options : Compiler::Options) #

[View source]

Class Method Detail

def self.recursively_contains_direct_struct_type?(check_type : LLVM::Type, look_for_type : LLVM::Type) : Bool #

[View source]

Instance Method Detail

def abi_size_of(llvm_type : LLVM::Type) #

[View source]
def alloc_ctx #

[View source]
def bit_width_of(gtype : GenType) #

[View source]
def bit_width_of(llvm_type : LLVM::Type) #

[View source]
def bitwidth : UInt32 #

[View source]
def builder : LLVM::Builder #

[View source]
def ctx : Context #

[View source]
def ctx? : Context | Nil #

[View source]
def current_error_thread_local : LLVM::Value #

[View source]

[View source]
def finish_block #

[View source]
def finish_block_and_move_to(new_block) #

[View source]
def frame #

[View source]
def frame_count #

[View source]
def func_frame #

[View source]
def gen_address_of(term_expr) #

[View source]
def gen_alloc(gtype : GenType, from_expr : AST::Node, name : String) #

This generates the code that allocates an object of the given type. This is the first step before actually calling the constructor of it.


[View source]
def gen_alloc_alloca(gtype : GenType, name : String) #

This generates the code that stack-allocates an object of the given type. This is used before calling the constructor of value types.


[View source]
def gen_alloc_struct(llvm_type : LLVM::Type, name : String) #

This generates more generic code for allocating a given LLVM struct type, without the assumption of it being initialized as a proper runtime object.


[View source]
def gen_alloca(llvm_type : LLVM::Type, name : String) #

Create an alloca at the entry block then return us back to whence we came.


[View source]
def gen_array(array_gtype, values : Array(LLVM::Value)) : LLVM::Value #

[View source]
def gen_as_cond(value : LLVM::Value) #

[View source]
def gen_assign_cast(value : LLVM::Value, to_type : Reach::Ref, to_llvm_type : LLVM::Type | Nil, from_expr : AST::Node, from_frame : Frame | Nil = nil, from_type : Reach::Ref | Nil = nil) #

[View source]
def gen_at_entry(&) #

[View source]
def gen_block(name) #

[View source]
def gen_bool(bool) #

[View source]
def gen_boxed_fields(fields_value, gtype, from_expr) #

[View source]
def gen_boxed_value(value, gtype, from_expr) #

[View source]
def gen_break_loop(value : LLVM::Value, from_expr : AST::Node) #

[View source]
def gen_bstring(value : String) #

[View source]
def gen_call(signature : Reach::Signature, signature_gfunc : GenFunc, func : LLVM::Function | LLVM::Value, args : Array(LLVM::Value), arg_exprs : Array(AST::Node | Nil), arg_frames : Array(Frame | Nil), is_ffi_gfunc : GenFunc | Nil, is_virtual_call : Bool, use_receiver : Bool, use_cont : Bool) #

[View source]
def gen_call_gfunc(gfunc : GenFunc, args : Array(LLVM::Value), value_name : String = "") : LLVM::Value #

[View source]
def gen_call_named(func_name : String, args : Array(LLVM::Value), value_name : String = "") : LLVM::Value #

[View source]
def gen_check_identity_equal(relate : AST::Relate, positive_check : Bool) #

[View source]
def gen_check_identity_equal_inner(lhs : LLVM::Value, rhs : LLVM::Value, lhs_type : Reach::Ref, rhs_type : Reach::Ref, pos : Source::Pos, positive_check : Bool) #

[View source]
def gen_check_subtype(relate : AST::Relate, positive_check : Bool) #

[View source]
def gen_check_subtype_at_runtime(lhs : LLVM::Value, rhs_type : Reach::Ref, positive_check : Bool) #

[View source]
def gen_choice(expr : AST::Choice) #

TODO Use infer resolution for static True/False finding where possible.


[View source]
def gen_const_for_gtype(gtype : GenType, values : Hash(String, LLVM::Value)) #

[View source]
def gen_continue_error_from_call(from_call : AST::Call, error_type : Reach::Ref) #

[View source]
def gen_cstring(value : String) : LLVM::Value #

[View source]
def gen_desc(gtype) #

This defines a global constant for the type descriptor of a type, which is held as the first value in an object, used for identifying its type at runtime, as well as a host of other functions related to dealing with objects in the runtime, such as allocating them and tracing them.


[View source]
def gen_desc_fn_impls(gtype : GenType) #

[View source]
def gen_desc_init(gtype, vtable) #

This populates the descriptor for the given type with its initialized data.


[View source]
def gen_desc_type(type_def : Reach::Def, vtable_size : Int32) : LLVM::Type #

This defines a more specific struct type than the above function, tailored to the specific type definition and its virtual table size. The actual type descriptor value for the type is an instance of this.


[View source]
def gen_displacing_eq(relate) #

[View source]
def gen_dot(call : AST::Call) #

[View source]
def gen_dynamic_array(expr : AST::Group) : LLVM::Value #

[View source]
def gen_eq(relate) #

[View source]
def gen_expr(expr : AST::Node, const_only = false) : LLVM::Value #

[View source]
def gen_ffi_call(gfunc, args, cast_to_ret_type) #

[View source]
def gen_ffi_decl(gfunc) #

[View source]
def gen_ffi_global_cpointer_getter_impl(gtype, gfunc, llvm_func) #

[View source]
def gen_ffi_global_decl(gfunc) #

[View source]
def gen_ffi_global_getter_impl(gtype, gfunc, llvm_func) #

[View source]
def gen_ffi_global_setter_impl(gtype, gfunc, llvm_func) #

[View source]
def gen_ffi_impl(gtype, gfunc, llvm_func) #

[View source]
def gen_field_displace(node : AST::FieldDisplace) #

[View source]
def gen_field_eq(node : AST::FieldWrite) #

[View source]
def gen_field_gep(name, gtype = func_frame.gtype.not_nil!) #

[View source]
def gen_field_load(name, gtype = func_frame.gtype.not_nil!) #

[View source]
def gen_field_store(name, value) #

[View source]
def gen_float(expr : AST::LiteralFloat) #

[View source]
def gen_force_cast(value : LLVM::Value, to_type : LLVM::Type) #

[View source]
def gen_frame #

[View source]
def gen_func_decl(gtype, gfunc) #

[View source]
def gen_func_end(gfunc = nil) #

[View source]
def gen_func_impl(gtype, gfunc, llvm_func) #

[View source]
def gen_func_start(llvm_func, gtype : GenType | Nil = nil, gfunc : GenFunc | Nil = nil) #

[View source]
def gen_get_desc(value : LLVM::Value) #

Dereference the type descriptor header of the given LLVM value, loading the type descriptor of the object at runtime. Prefer the above function instead when the type is statically known.


[View source]
def gen_global_const(*args) #

[View source]
def gen_global_for_const(const : LLVM::Value, name : String = "") : LLVM::Value #

[View source]
def gen_identity_digest_of(value, reach_type, pos) #

[View source]
def gen_identity_digest_of(term_expr) #

[View source]
def gen_identity_digest_of_i64(value : LLVM::Value, name : String) #

[View source]
def gen_integer(expr : AST::LiteralInteger | AST::LiteralCharacter) #

[View source]
def gen_intrinsic(gtype, gfunc, llvm_func) #

[View source]
def gen_intrinsic_cpointer(gtype, gfunc, llvm_func) #

[View source]
def gen_intrinsic_inhibit_optimization(gtype, gfunc, llvm_func) #

[View source]
def gen_intrinsic_platform(gtype, gfunc, llvm_func) #

[View source]
def gen_llvm_func(name, param_types, ret_type, &) #

[View source]
def gen_local_alloca(ref, llvm_type) #

[View source]
def gen_loop(expr : AST::Loop) #

[View source]
def gen_next(value : LLVM::Value, from_expr : AST::Node) #

[View source]
def gen_none #

[View source]
def gen_numeric_conv(from_gtype : GenType, to_gtype : GenType, value : LLVM::Value, partial : Bool = false) #

[View source]
def gen_numeric_conv_f32_to_sint(value : LLVM::Value, to_type : LLVM::Type, partial : Bool) #

[View source]
def gen_numeric_conv_f32_to_uint(value : LLVM::Value, to_type : LLVM::Type, partial : Bool) #

[View source]
def gen_numeric_conv_f64_to_f32(value : LLVM::Value, partial : Bool) #

[View source]
def gen_numeric_conv_f64_to_sint(value : LLVM::Value, to_type : LLVM::Type, partial : Bool) #

[View source]
def gen_numeric_conv_f64_to_uint(value : LLVM::Value, to_type : LLVM::Type, partial : Bool) #

[View source]
def gen_numeric_conv_float_handle_nan(value : LLVM::Value, int_type : LLVM::Type, exp : UInt64, mantissa : UInt64) #

[View source]
def gen_numeric_conv_float_handle_overflow_saturate(value : LLVM::Value, from_type : LLVM::Type, to_type : LLVM::Type, to_min : LLVM::Value, to_max : LLVM::Value, is_signed : Bool, partial : Bool) #

[View source]
def gen_numeric_conv_integer_partial(value : LLVM::Value, to_type : LLVM::Type, from_width : Int, to_width : Int, from_signed : Bool, to_signed : Bool) #

[View source]
def gen_put_desc(value, gtype, name = "") #

[View source]
def gen_raise_error(error_value : LLVM::Value, from_expr : AST::Node | Nil) #

[View source]
def gen_reflection_mutator_of_type(mutator_gtype, gtype, gfunc) #

[View source]
def gen_reflection_of_runtime_type_name(expr, term_expr) #

[View source]
def gen_reflection_of_type(expr, term_expr) #

[View source]
def gen_return_value(value : LLVM::Value, from_expr : AST::Node | Nil) #

[View source]
def gen_savi_supplied_ffi_funcs #

[View source]
def gen_send_impl(gtype, gfunc) #

[View source]
def gen_sequence(expr : AST::Group) #

[View source]
def gen_singleton(gtype) #

This defines the global singleton stateless value associated with this type. This value is invoked whenever you reference the type with as a non, acting as a runtime representation of a type itself rather than an instance. For modules, this is the only value you'll ever see.


[View source]
def gen_source_code_pos(pos : Source::Pos) #

[View source]
def gen_stack_address_of_variable(expr, term_expr) #

[View source]
def gen_static_address_of_function(expr : AST::Relate) : LLVM::Value #

[View source]
def gen_string(value : String) #

[View source]
def gen_struct_bit_cast(value : LLVM::Value, to_type : LLVM::Type) #

[View source]
def gen_struct_type(gtype) #

This defines the LLVM struct type for objects of this type.


[View source]
def gen_tidy_up #

Do some basic housekeeping tasks to ensure LLVM doesn't yell at us.


[View source]
def gen_try(expr : AST::Try) #

[View source]
def gen_unboxed_fields(boxed, gtype) #

[View source]
def gen_unboxed_value(boxed, gtype) #

[View source]
def gen_value_not_needed #

[View source]
def gen_vtable_func_get(receiver : LLVM::Value, type_ref : Reach::Ref, vtable_index : Int32, name : String) #

[View source]
def gen_within_foreign_frame(gtype : GenType, gfunc : GenFunc, &) #

[View source]
def gen_within_foreign_frame(frame : Frame, &) #

[View source]
def gen_wrapper #

[View source]
def gen_yield(expr : AST::Yield) #

[View source]
def gen_yielding_call_cont_gep(call, call_gfunc, name) #

[View source]
def gen_yielding_call_receiver_gep(call, name) #

[View source]
def gtype_main #

[View source]
def gtype_of(expr : AST::Node, in_gfunc : GenFunc | Nil = nil) #

[View source]
def gtype_of(reach_ref : Reach::Ref) #

[View source]

[View source]
def gtypes_of(expr : AST::Node, in_gfunc : GenFunc | Nil = nil) #

[View source]
def isize : LLVM::Type #

[View source]
def llvm : LLVM::Context #

[View source]
def llvm_mem_type_of(expr : AST::Node, in_gfunc : GenFunc | Nil = nil) #

[View source]
def llvm_mem_type_of(ref : Reach::Ref) #

[View source]
def llvm_type_of(gtype : GenType) #

[View source]
def llvm_type_of(expr : AST::Node, in_gfunc : GenFunc | Nil = nil) #

[View source]
def llvm_type_of(ref : Reach::Ref) #

[View source]
def meta_type_of(expr : AST::Node, in_gfunc : GenFunc | Nil = nil) #

[View source]
def meta_type_unconstrained?(expr : AST::Node, in_gfunc : GenFunc | Nil = nil) #

[View source]
def mod : LLVM::Module #

[View source]
def ptr : LLVM::Type #

[View source]
def resolve_call(call : AST::Call, in_gfunc : GenFunc | Nil = nil) #

[View source]
def resolve_yielding_call_cont_type(call : AST::Call, call_gfunc : GenFunc, in_gfunc : GenFunc | Nil = nil) : LLVM::Type #

[View source]
def run(ctx : Context) #

[View source]
def target : LLVM::Target #

[View source]
def target_info : Target #

[View source]
def target_machine : LLVM::TargetMachine #

[View source]
def trait_bitmap_size #

Calculate the number of @bitwidth-sized integers (i.e. @isize) would be needed to hold a single bit for each trait in the trait_count. For example, if there are 64 traits, the trait_bitmap_size is 2, but if there is a 65th trait, the trait_bitmap_size increases to 3, because another integer will be added to hold that many bits.


[View source]
def type_of(expr : AST::Node, in_gfunc : GenFunc | Nil = nil) #

[View source]
def type_of_unless_unsatisfiable(expr : AST::Node, in_gfunc : GenFunc | Nil = nil) #

[View source]
def use_external_llvm_func(name, param_types, ret_type, is_variadic = false) #

[View source]