struct LLVM::Type getter unwrap : LibLLVM::TypeRef def initialize(@unwrap : LibLLVM::TypeRef) end def to_unsafe @unwrap end def self.function(arg_types : Array(LLVM::Type), return_type, varargs = false) : self new LibLLVM.function_type(return_type, (arg_types.to_unsafe.as(LibLLVM::TypeRef*)), arg_types.size, varargs ? 1 : 0) end def size # Asking the size of void crashes the program, we definitely don't want that if void? context.int64.const_int(1) else Value.new LibLLVM.size_of(self) end end def alignment # Asking the alignment of void crashes the program, we definitely don't want that if void? context.int64.const_int(1) else Value.new LibLLVM.align_of(self) end end def kind : LLVM::Type::Kind LibLLVM.get_type_kind(self) end def void? kind == Kind::Void end def null Value.new LibLLVM.const_null(self) end def null_pointer Value.new LibLLVM.const_pointer_null(self) end def undef Value.new LibLLVM.get_undef(self) end def pointer(address_space = 0) : LLVM::Type {% if LibLLVM::IS_LT_150 %} Type.new LibLLVM.pointer_type(self, address_space) {% else %} Type.new LibLLVM.pointer_type_in_context(LibLLVM.get_type_context(self), address_space) {% end %} end def array(count) : LLVM::Type Type.new LibLLVM.array_type(self, count) end def vector(count) : self Type.new LibLLVM.vector_type(self, count) end def int_width : Int32 raise "Not an Integer" unless kind == Kind::Integer LibLLVM.get_int_type_width(self).to_i32 end def packed_struct? : Bool raise "Not a Struct" unless kind == Kind::Struct LibLLVM.is_packed_struct(self) != 0 end # Assuming this type is a struct, returns its name. # The name can be `nil` if the struct is anonymous. # Raises if this type is not a struct. def struct_name : String? raise "Not a Struct" unless kind == Kind::Struct name = LibLLVM.get_struct_name(self) name ? String.new(name) : nil end def struct_element_types : Array(LLVM::Type) raise "Not a Struct" unless kind == Kind::Struct count = LibLLVM.count_struct_element_types(self) Array(LLVM::Type).build(count) do |buffer| LibLLVM.get_struct_element_types(self, buffer.as(LibLLVM::TypeRef*)) count end end def element_type : LLVM::Type case kind when Kind::Array, Kind::Vector Type.new LibLLVM.get_element_type(self) when Kind::Pointer {% if LibLLVM::IS_LT_150 %} Type.new LibLLVM.get_element_type(self) {% else %} raise "Typed pointers are unavailable on LLVM 15.0 or above" {% end %} else raise "Not a sequential type" end end def array_size : Int32 raise "Not an Array" unless kind == Kind::Array LibLLVM.get_array_length(self).to_i32 end def vector_size raise "Not a Vector" unless kind == Kind::Vector LibLLVM.get_vector_size(self).to_i32 end def return_type raise "Not a Function" unless kind == Kind::Function Type.new LibLLVM.get_return_type(self) end def params_types params_size = self.params_size Array(LLVM::Type).build(params_size) do |buffer| LibLLVM.get_param_types(self, buffer.as(LibLLVM::TypeRef*)) params_size end end def params_size raise "Not a Function" unless kind == Kind::Function LibLLVM.count_param_types(self).to_i end def varargs? raise "Not a Function" unless kind == Kind::Function LibLLVM.is_function_var_arg(self) != 0 end def const_int(value) : Value if !value.is_a?(Int128) && !value.is_a?(UInt128) && int_width != 128 Value.new LibLLVM.const_int(self, value, 0) else encoded_value = UInt64[value & UInt64::MAX, (value >> 64) & UInt64::MAX] Value.new LibLLVM.const_int_of_arbitrary_precision(self, encoded_value.size, encoded_value) end end def const_float(value : Float32) : Value Value.new LibLLVM.const_real(self, value) end def const_float(value : String) : Value Value.new LibLLVM.const_real_of_string_and_size(self, value, value.bytesize) end def const_double(value : Float64) : Value Value.new LibLLVM.const_real(self, value) end def const_double(string : String) : Value Value.new LibLLVM.const_real_of_string_and_size(self, string, string.bytesize) end def const_array(values : Array(LLVM::Value)) : Value Value.new LibLLVM.const_array(self, (values.to_unsafe.as(LibLLVM::ValueRef*)), values.size) end def const_data_array(buffer : Bytes) : Value {% if LibLLVM::IS_LT_210 %} raise NotImplementedError.new("LLVM::Type#const_data_array") {% else %} Value.new LibLLVM.const_data_array(self, buffer, buffer.bytesize) {% end %} end def inline_asm(asm_string, constraints, has_side_effects = false, is_align_stack = false, can_throw = false, dialect : InlineAsmDialect = InlineAsmDialect::ATT) value = {% if LibLLVM::IS_LT_130 %} LibLLVM.get_inline_asm( self, asm_string, asm_string.bytesize, constraints, constraints.bytesize, (has_side_effects ? 1 : 0), (is_align_stack ? 1 : 0), dialect, ) {% else %} LibLLVM.get_inline_asm( self, asm_string, asm_string.bytesize, constraints, constraints.bytesize, (has_side_effects ? 1 : 0), (is_align_stack ? 1 : 0), dialect, (can_throw ? 1 : 0) ) {% end %} Value.new value end def context : Context Context.new(LibLLVM.get_type_context(self), dispose_on_finalize: false) end def inspect(io : IO) : Nil LLVM.to_io(LibLLVM.print_type_to_string(self), io) self end end