1use super::{arith::ArithBlockExt, builtin::BuiltinBlockExt};
2use crate::{
3 Context, Error,
4 dialect::{llvm::r#type, ods},
5 ir::{
6 Block, Location, Type, Value, ValueLike,
7 attribute::{
8 DenseI32ArrayAttribute, DenseI64ArrayAttribute, IntegerAttribute, TypeAttribute,
9 },
10 block::BlockLike,
11 r#type::IntegerType,
12 },
13};
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq)]
17pub enum GepIndex<'c, 'a> {
18 Const(i32),
20 Value(Value<'c, 'a>),
22}
23
24pub trait LlvmBlockExt<'c>: BuiltinBlockExt<'c> + ArithBlockExt<'c> {
26 fn extract_value(
28 &self,
29 context: &'c Context,
30 location: Location<'c>,
31 container: Value<'c, '_>,
32 value_type: Type<'c>,
33 index: usize,
34 ) -> Result<Value<'c, '_>, Error>;
35
36 fn insert_value(
38 &self,
39 context: &'c Context,
40 location: Location<'c>,
41 container: Value<'c, '_>,
42 value: Value<'c, '_>,
43 index: usize,
44 ) -> Result<Value<'c, '_>, Error>;
45
46 fn insert_values<'block>(
49 &'block self,
50 context: &'c Context,
51 location: Location<'c>,
52 container: Value<'c, 'block>,
53 values: &[Value<'c, 'block>],
54 ) -> Result<Value<'c, 'block>, Error>;
55
56 fn load(
58 &self,
59 context: &'c Context,
60 location: Location<'c>,
61 addr: Value<'c, '_>,
62 value_type: Type<'c>,
63 ) -> Result<Value<'c, '_>, Error>;
64
65 fn alloca(
67 &self,
68 context: &'c Context,
69 location: Location<'c>,
70 element_type: Type<'c>,
71 element_count: Value<'c, '_>,
72 align: usize,
73 ) -> Result<Value<'c, '_>, Error>;
74
75 fn alloca1(
77 &self,
78 context: &'c Context,
79 location: Location<'c>,
80 r#type: Type<'c>,
81 align: usize,
82 ) -> Result<Value<'c, '_>, Error>;
83
84 fn alloca_int(
87 &self,
88 context: &'c Context,
89 location: Location<'c>,
90 bits: u32,
91 align: usize,
92 ) -> Result<Value<'c, '_>, Error>;
93
94 fn store(
96 &self,
97 context: &'c Context,
98 location: Location<'c>,
99 pointer: Value<'c, '_>,
100 value: Value<'c, '_>,
101 ) -> Result<(), Error>;
102
103 fn memcpy(
105 &self,
106 context: &'c Context,
107 location: Location<'c>,
108 src: Value<'c, '_>,
109 dst: Value<'c, '_>,
110 len_bytes: Value<'c, '_>,
111 );
112
113 fn gep(
118 &self,
119 context: &'c Context,
120 location: Location<'c>,
121 pointer: Value<'c, '_>,
122 indexes: &[GepIndex<'c, '_>],
123 element_type: Type<'c>,
124 ) -> Result<Value<'c, '_>, Error>;
125}
126
127impl<'c> LlvmBlockExt<'c> for Block<'c> {
128 #[inline]
129 fn extract_value(
130 &self,
131 context: &'c Context,
132 location: Location<'c>,
133 container: Value<'c, '_>,
134 value_type: Type<'c>,
135 index: usize,
136 ) -> Result<Value<'c, '_>, Error> {
137 self.append_op_result(
138 ods::llvm::extractvalue(
139 context,
140 value_type,
141 container,
142 DenseI64ArrayAttribute::new(context, &[index as _]).into(),
143 location,
144 )
145 .into(),
146 )
147 }
148
149 #[inline]
150 fn insert_value(
151 &self,
152 context: &'c Context,
153 location: Location<'c>,
154 container: Value<'c, '_>,
155 value: Value<'c, '_>,
156 index: usize,
157 ) -> Result<Value<'c, '_>, Error> {
158 self.append_op_result(
159 ods::llvm::insertvalue(
160 context,
161 container.r#type(),
162 container,
163 value,
164 DenseI64ArrayAttribute::new(context, &[index as _]).into(),
165 location,
166 )
167 .into(),
168 )
169 }
170
171 #[inline]
172 fn insert_values<'block>(
173 &'block self,
174 context: &'c Context,
175 location: Location<'c>,
176 mut container: Value<'c, 'block>,
177 values: &[Value<'c, 'block>],
178 ) -> Result<Value<'c, 'block>, Error> {
179 for (i, value) in values.iter().enumerate() {
180 container = self.insert_value(context, location, container, *value, i)?;
181 }
182 Ok(container)
183 }
184
185 #[inline]
186 fn store(
187 &self,
188 context: &'c Context,
189 location: Location<'c>,
190 addr: Value<'c, '_>,
191 value: Value<'c, '_>,
192 ) -> Result<(), Error> {
193 self.append_operation(ods::llvm::store(context, value, addr, location).into());
194 Ok(())
195 }
196
197 #[inline]
198 fn load(
199 &self,
200 context: &'c Context,
201 location: Location<'c>,
202 addr: Value<'c, '_>,
203 value_type: Type<'c>,
204 ) -> Result<Value<'c, '_>, Error> {
205 self.append_op_result(ods::llvm::load(context, value_type, addr, location).into())
206 }
207
208 #[inline]
209 fn memcpy(
210 &self,
211 context: &'c Context,
212 location: Location<'c>,
213 src: Value<'c, '_>,
214 dst: Value<'c, '_>,
215 len_bytes: Value<'c, '_>,
216 ) {
217 self.append_operation(
218 ods::llvm::intr_memcpy(
219 context,
220 dst,
221 src,
222 len_bytes,
223 IntegerAttribute::new(IntegerType::new(context, 1).into(), 0),
224 location,
225 )
226 .into(),
227 );
228 }
229
230 #[inline]
231 fn alloca(
232 &self,
233 context: &'c Context,
234 location: Location<'c>,
235 element_type: Type<'c>,
236 element_count: Value<'c, '_>,
237 align: usize,
238 ) -> Result<Value<'c, '_>, Error> {
239 let mut operation = ods::llvm::alloca(
240 context,
241 r#type::pointer(context, 0),
242 element_count,
243 TypeAttribute::new(element_type),
244 location,
245 );
246
247 operation.set_elem_type(TypeAttribute::new(element_type));
248 operation.set_alignment(IntegerAttribute::new(
249 IntegerType::new(context, 64).into(),
250 align as _,
251 ));
252
253 self.append_op_result(operation.into())
254 }
255
256 #[inline]
257 fn alloca1(
258 &self,
259 context: &'c Context,
260 location: Location<'c>,
261 r#type: Type<'c>,
262 align: usize,
263 ) -> Result<Value<'c, '_>, Error> {
264 self.alloca(
265 context,
266 location,
267 r#type,
268 self.const_int(context, location, 1, 64)?,
269 align,
270 )
271 }
272
273 #[inline]
274 fn alloca_int(
275 &self,
276 context: &'c Context,
277 location: Location<'c>,
278 bits: u32,
279 align: usize,
280 ) -> Result<Value<'c, '_>, Error> {
281 self.alloca1(
282 context,
283 location,
284 IntegerType::new(context, bits).into(),
285 align,
286 )
287 }
288
289 #[inline]
290 fn gep(
291 &self,
292 context: &'c Context,
293 location: Location<'c>,
294 pointer: Value<'c, '_>,
295 indexes: &[GepIndex<'c, '_>],
296 element_type: Type<'c>,
297 ) -> Result<Value<'c, '_>, Error> {
298 let mut static_indices = Vec::with_capacity(indexes.len());
299 let mut dynamic_indices = Vec::with_capacity(indexes.len());
300
301 for index in indexes {
302 match index {
303 GepIndex::Const(index) => static_indices.push(*index),
304 GepIndex::Value(value) => {
305 static_indices.push(i32::MIN); dynamic_indices.push(*value);
307 }
308 }
309 }
310
311 let operation = ods::llvm::getelementptr(
312 context,
313 r#type::pointer(context, 0),
314 pointer,
315 &dynamic_indices,
316 DenseI32ArrayAttribute::new(context, &static_indices),
317 TypeAttribute::new(element_type),
318 location,
319 );
320
321 self.append_op_result(operation.into())
322 }
323}