/
type.cr
213 lines (178 loc) · 5.39 KB
/
type.cr
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
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 : LLVM::Type
{% if LibLLVM::IS_LT_150 %}
Type.new LibLLVM.pointer_type(self, 0)
{% else %}
Type.new LibLLVM.pointer_type_in_context(LibLLVM.get_type_context(self), 0)
{% 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 inline_asm(asm_string, constraints, has_side_effects = false, is_align_stack = false, can_throw = false)
value =
{% if LibLLVM::IS_LT_130 %}
LibLLVM.get_inline_asm(
self,
asm_string,
asm_string.size,
constraints,
constraints.size,
(has_side_effects ? 1 : 0),
(is_align_stack ? 1 : 0),
LibLLVM::InlineAsmDialect::ATT
)
{% else %}
LibLLVM.get_inline_asm(
self,
asm_string,
asm_string.size,
constraints,
constraints.size,
(has_side_effects ? 1 : 0),
(is_align_stack ? 1 : 0),
LibLLVM::InlineAsmDialect::ATT,
(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