1
1
//! A `Builder` enables you to build instructions.
2
2
3
- use llvm_sys:: core:: { LLVMBuildAdd , LLVMBuildAlloca , LLVMBuildAnd , LLVMBuildArrayAlloca , LLVMBuildArrayMalloc , LLVMBuildAtomicRMW , LLVMBuildBr , LLVMBuildCall , LLVMBuildCast , LLVMBuildCondBr , LLVMBuildExtractValue , LLVMBuildFAdd , LLVMBuildFCmp , LLVMBuildFDiv , LLVMBuildFence , LLVMBuildFMul , LLVMBuildFNeg , LLVMBuildFree , LLVMBuildFSub , LLVMBuildGEP , LLVMBuildICmp , LLVMBuildInsertValue , LLVMBuildIsNotNull , LLVMBuildIsNull , LLVMBuildLoad , LLVMBuildMalloc , LLVMBuildMul , LLVMBuildNeg , LLVMBuildNot , LLVMBuildOr , LLVMBuildPhi , LLVMBuildPointerCast , LLVMBuildRet , LLVMBuildRetVoid , LLVMBuildStore , LLVMBuildSub , LLVMBuildUDiv , LLVMBuildUnreachable , LLVMBuildXor , LLVMDisposeBuilder , LLVMGetInsertBlock , LLVMInsertIntoBuilder , LLVMPositionBuilderAtEnd , LLVMBuildExtractElement , LLVMBuildInsertElement , LLVMBuildIntToPtr , LLVMBuildPtrToInt , LLVMInsertIntoBuilderWithName , LLVMClearInsertionPosition , LLVMPositionBuilder , LLVMPositionBuilderBefore , LLVMBuildAggregateRet , LLVMBuildStructGEP , LLVMBuildInBoundsGEP , LLVMBuildPtrDiff , LLVMBuildNSWAdd , LLVMBuildNUWAdd , LLVMBuildNSWSub , LLVMBuildNUWSub , LLVMBuildNSWMul , LLVMBuildNUWMul , LLVMBuildSDiv , LLVMBuildSRem , LLVMBuildURem , LLVMBuildFRem , LLVMBuildNSWNeg , LLVMBuildNUWNeg , LLVMBuildFPToUI , LLVMBuildFPToSI , LLVMBuildSIToFP , LLVMBuildUIToFP , LLVMBuildFPTrunc , LLVMBuildFPExt , LLVMBuildIntCast , LLVMBuildFPCast , LLVMBuildSExtOrBitCast , LLVMBuildZExtOrBitCast , LLVMBuildTruncOrBitCast , LLVMBuildSwitch , LLVMAddCase , LLVMBuildShl , LLVMBuildAShr , LLVMBuildLShr , LLVMBuildGlobalString , LLVMBuildGlobalStringPtr , LLVMBuildExactSDiv , LLVMBuildTrunc , LLVMBuildSExt , LLVMBuildZExt , LLVMBuildSelect , LLVMBuildAddrSpaceCast , LLVMBuildBitCast , LLVMBuildShuffleVector , LLVMBuildVAArg , LLVMBuildIndirectBr , LLVMAddDestination } ;
3
+ use llvm_sys:: core:: { LLVMBuildAdd , LLVMBuildAlloca , LLVMBuildAnd , LLVMBuildArrayAlloca , LLVMBuildArrayMalloc , LLVMBuildAtomicRMW , LLVMBuildBr , LLVMBuildCall , LLVMBuildCast , LLVMBuildCondBr , LLVMBuildExtractValue , LLVMBuildFAdd , LLVMBuildFCmp , LLVMBuildFDiv , LLVMBuildFence , LLVMBuildFMul , LLVMBuildFNeg , LLVMBuildFree , LLVMBuildFSub , LLVMBuildGEP , LLVMBuildICmp , LLVMBuildInsertValue , LLVMBuildIsNotNull , LLVMBuildIsNull , LLVMBuildLoad , LLVMBuildMalloc , LLVMBuildMul , LLVMBuildNeg , LLVMBuildNot , LLVMBuildOr , LLVMBuildPhi , LLVMBuildPointerCast , LLVMBuildRet , LLVMBuildRetVoid , LLVMBuildStore , LLVMBuildSub , LLVMBuildUDiv , LLVMBuildUnreachable , LLVMBuildXor , LLVMDisposeBuilder , LLVMGetInsertBlock , LLVMInsertIntoBuilder , LLVMPositionBuilderAtEnd , LLVMBuildExtractElement , LLVMBuildInsertElement , LLVMBuildIntToPtr , LLVMBuildPtrToInt , LLVMInsertIntoBuilderWithName , LLVMClearInsertionPosition , LLVMPositionBuilder , LLVMPositionBuilderBefore , LLVMBuildAggregateRet , LLVMBuildStructGEP , LLVMBuildInBoundsGEP , LLVMBuildPtrDiff , LLVMBuildNSWAdd , LLVMBuildNUWAdd , LLVMBuildNSWSub , LLVMBuildNUWSub , LLVMBuildNSWMul , LLVMBuildNUWMul , LLVMBuildSDiv , LLVMBuildSRem , LLVMBuildURem , LLVMBuildFRem , LLVMBuildNSWNeg , LLVMBuildNUWNeg , LLVMBuildFPToUI , LLVMBuildFPToSI , LLVMBuildSIToFP , LLVMBuildUIToFP , LLVMBuildFPTrunc , LLVMBuildFPExt , LLVMBuildIntCast , LLVMBuildFPCast , LLVMBuildSExtOrBitCast , LLVMBuildZExtOrBitCast , LLVMBuildTruncOrBitCast , LLVMBuildSwitch , LLVMAddCase , LLVMBuildShl , LLVMBuildAShr , LLVMBuildLShr , LLVMBuildGlobalString , LLVMBuildGlobalStringPtr , LLVMBuildExactSDiv , LLVMBuildTrunc , LLVMBuildSExt , LLVMBuildZExt , LLVMBuildSelect , LLVMBuildAddrSpaceCast , LLVMBuildBitCast , LLVMBuildShuffleVector , LLVMBuildVAArg , LLVMBuildIndirectBr , LLVMAddDestination , LLVMBuildInvoke , LLVMBuildResume , LLVMBuildLandingPad , LLVMSetCleanup , LLVMAddClause } ;
4
4
#[ llvm_versions( 3.9 ..=latest) ]
5
5
use llvm_sys:: core:: LLVMBuildAtomicCmpXchg ;
6
6
#[ llvm_versions( 8.0 ..=latest) ]
@@ -10,7 +10,7 @@ use llvm_sys::prelude::{LLVMBuilderRef, LLVMValueRef};
10
10
use crate :: { AtomicOrdering , AtomicRMWBinOp , IntPredicate , FloatPredicate } ;
11
11
use crate :: basic_block:: BasicBlock ;
12
12
use crate :: support:: to_c_str;
13
- use crate :: values:: { AggregateValue , AggregateValueEnum , AsValueRef , BasicValue , BasicValueEnum , PhiValue , IntValue , PointerValue , VectorValue , InstructionValue , GlobalValue , IntMathValue , FloatMathValue , PointerMathValue , InstructionOpcode , CallSiteValue } ;
13
+ use crate :: values:: { AggregateValue , AggregateValueEnum , AsValueRef , FunctionValue , BasicValue , BasicValueEnum , PhiValue , IntValue , PointerValue , VectorValue , InstructionValue , GlobalValue , IntMathValue , FloatMathValue , PointerMathValue , InstructionOpcode , CallSiteValue } ;
14
14
#[ llvm_versions( 7.0 ..=latest) ]
15
15
use crate :: debug_info:: DILocation ;
16
16
#[ llvm_versions( 3.9 ..=latest) ]
@@ -163,6 +163,377 @@ impl<'ctx> Builder<'ctx> {
163
163
}
164
164
}
165
165
166
+ /// An invoke is similar to a normal function call, but used to
167
+ /// call functions that may throw an exception, and then respond to the exception.
168
+ ///
169
+ /// When the called function returns normally, the `then` block is evaluated next. If instead
170
+ /// the function threw an exception, the `catch` block is entered. The first non-phi
171
+ /// instruction of the catch block must be a `landingpad` instruction. See also
172
+ /// [`Builder::build_landing_pad`].
173
+ ///
174
+ /// The [`add_prune_eh_pass`] turns an invoke into a call when the called function is
175
+ /// guaranteed to never throw an exception.
176
+ ///
177
+ /// [`add_prune_eh_pass`]: crate::passes::PassManager::add_prune_eh_pass
178
+ ///
179
+ /// This example catches C++ exceptions of type `int`, and returns `0` if an exceptions is thrown.
180
+ /// For usage of a cleanup landing pad and the `resume` instruction, see [`Builder::build_resume`]
181
+ /// ```no_run
182
+ /// use inkwell::context::Context;
183
+ /// use inkwell::AddressSpace;
184
+ ///
185
+ /// let context = Context::create();
186
+ /// let module = context.create_module("sum");
187
+ /// let builder = context.create_builder();
188
+ ///
189
+ /// let f32_type = context.f32_type();
190
+ /// let fn_type = f32_type.fn_type(&[], false);
191
+ ///
192
+ /// // we will pretend this function can throw an exception
193
+ /// let function = module.add_function("bomb", fn_type, None);
194
+ /// let basic_block = context.append_basic_block(function, "entry");
195
+ ///
196
+ /// builder.position_at_end(basic_block);
197
+ ///
198
+ /// let pi = f32_type.const_float(::std::f64::consts::PI);
199
+ ///
200
+ /// builder.build_return(Some(&pi));
201
+ ///
202
+ /// let function2 = module.add_function("wrapper", fn_type, None);
203
+ /// let basic_block2 = context.append_basic_block(function2, "entry");
204
+ ///
205
+ /// builder.position_at_end(basic_block2);
206
+ ///
207
+ /// let then_block = context.append_basic_block(function2, "then_block");
208
+ /// let catch_block = context.append_basic_block(function2, "catch_block");
209
+ ///
210
+ /// let call_site = builder.build_invoke(function, &[], then_block, catch_block, "get_pi");
211
+ ///
212
+ /// {
213
+ /// builder.position_at_end(then_block);
214
+ ///
215
+ /// // in the then_block, the `call_site` value is defined and can be used
216
+ /// let result = call_site.try_as_basic_value().left().unwrap();
217
+ ///
218
+ /// builder.build_return(Some(&result));
219
+ /// }
220
+ ///
221
+ /// {
222
+ /// builder.position_at_end(catch_block);
223
+ ///
224
+ /// // the personality function used by C++
225
+ /// let personality_function = {
226
+ /// let name = "__gxx_personality_v0";
227
+ /// let linkage = Some(Linkage::External);
228
+ ///
229
+ /// module.add_function(name, context.i64_type().fn_type(&[], false), linkage)
230
+ /// };
231
+ ///
232
+ /// // type of an exception in C++
233
+ /// let i8_ptr_type = context.i32_type().ptr_type(AddressSpace::Generic);
234
+ /// let i32_type = context.i32_type();
235
+ /// let exception_type = context.struct_type(&[i8_ptr_type.into(), i32_type.into()], false);
236
+ ///
237
+ /// let null = i8_ptr_type.const_zero();
238
+ /// let res = builder.build_landing_pad(exception_type, personality_function, &[null], false, "res");
239
+ ///
240
+ /// // we handle the exception by returning a default value
241
+ /// builder.build_return(Some(&f32_type.const_zero()));
242
+ /// }
243
+ /// ```
244
+ pub fn build_invoke < F > (
245
+ & self ,
246
+ function : F ,
247
+ args : & [ BasicValueEnum < ' ctx > ] ,
248
+ then_block : BasicBlock < ' ctx > ,
249
+ catch_block : BasicBlock < ' ctx > ,
250
+ name : & str ,
251
+ ) -> CallSiteValue < ' ctx >
252
+ where
253
+ F : Into < CallableValue < ' ctx > > ,
254
+ {
255
+ let callable_value = function. into ( ) ;
256
+ let fn_val_ref = callable_value. as_value_ref ( ) ;
257
+
258
+ // LLVM gets upset when void return calls are named because they don't return anything
259
+ let name = if callable_value. returns_void ( ) {
260
+ ""
261
+ } else {
262
+ name
263
+ } ;
264
+
265
+ let c_string = to_c_str ( name) ;
266
+ let mut args: Vec < LLVMValueRef > = args. iter ( ) . map ( |val| val. as_value_ref ( ) ) . collect ( ) ;
267
+ let value = unsafe {
268
+ LLVMBuildInvoke (
269
+ self . builder ,
270
+ fn_val_ref,
271
+ args. as_mut_ptr ( ) ,
272
+ args. len ( ) as u32 ,
273
+ then_block. basic_block ,
274
+ catch_block. basic_block ,
275
+ c_string. as_ptr ( ) ,
276
+ )
277
+ } ;
278
+
279
+ unsafe {
280
+ CallSiteValue :: new ( value)
281
+ }
282
+ }
283
+
284
+ /// Landing pads are places where control flow jumps to if a [`Builder::build_invoke`] triggered an exception.
285
+ /// The landing pad will match the exception against its *clauses*. Depending on the clause
286
+ /// that is matched, the exception can then be handled, or resumed after some optional cleanup,
287
+ /// causing the exception to bubble up.
288
+ ///
289
+ /// Exceptions in LLVM are designed based on the needs of a C++ compiler, but can be used more generally.
290
+ /// Here are some specific examples of landing pads. For a full example of handling an exception, see [`Builder::build_invoke`].
291
+ ///
292
+ /// * **cleanup**: a cleanup landing pad is always visited when unwinding the stack.
293
+ /// A cleanup is extra code that needs to be run when unwinding a scope. C++ destructors are a typical example.
294
+ /// In a language with reference counting, the cleanup block can decrement the refcount of values in scope.
295
+ /// The [`Builder::build_resume`] function has a full example using a cleanup lading pad.
296
+ ///
297
+ /// ```no_run
298
+ /// use inkwell::context::Context;
299
+ /// use inkwell::AddressSpace;
300
+ ///
301
+ /// let context = Context::create();
302
+ /// let module = context.create_module("sum");
303
+ /// let builder = context.create_builder();
304
+ ///
305
+ /// // type of an exception in C++
306
+ /// let i8_ptr_type = context.i8_type().ptr_type(AddressSpace::Generic);
307
+ /// let i32_type = context.i32_type();
308
+ /// let exception_type = context.struct_type(&[i8_ptr_type.into(), i32_type.into()], false);
309
+ ///
310
+ /// // the personality function used by C++
311
+ /// let personality_function = {
312
+ /// let name = "__gxx_personality_v0";
313
+ /// let linkage = Some(Linkage::External);
314
+ ///
315
+ /// module.add_function(name, context.i64_type().fn_type(&[], false), linkage)
316
+ /// };
317
+ ///
318
+ /// // make the cleanup landing pad
319
+ /// let res = builder.build_landing_pad( exception_type, personality_function, &[], true, "res");
320
+ /// ```
321
+ ///
322
+ /// * **catch all**: An implementation of the C++ `catch(...)`, which catches all exceptions.
323
+ /// A catch clause with a NULL pointer value will match anything.
324
+ ///
325
+ /// ```no_run
326
+ /// use inkwell::context::Context;
327
+ /// use inkwell::AddressSpace;
328
+ ///
329
+ /// let context = Context::create();
330
+ /// let module = context.create_module("sum");
331
+ /// let builder = context.create_builder();
332
+ ///
333
+ /// // type of an exception in C++
334
+ /// let i8_ptr_type = context.i8_type().ptr_type(AddressSpace::Generic);
335
+ /// let i32_type = context.i32_type();
336
+ /// let exception_type = context.struct_type(&[i8_ptr_type.into(), i32_type.into()], false);
337
+ ///
338
+ /// // the personality function used by C++
339
+ /// let personality_function = {
340
+ /// let name = "__gxx_personality_v0";
341
+ /// let linkage = Some(Linkage::External);
342
+ ///
343
+ /// module.add_function(name, context.i64_type().fn_type(&[], false), linkage)
344
+ /// };
345
+ ///
346
+ /// // make a null pointer of type i8
347
+ /// let null = i8_ptr_type.const_zero();
348
+ ///
349
+ /// // make the catch all landing pad
350
+ /// let res = builder.build_landing_pad(exception_type, personality_function, &[null], false, "res");
351
+ /// ```
352
+ ///
353
+ /// * **catch a type of exception**: Catch a specific type of exception. The example uses C++'s type info.
354
+ ///
355
+ /// ```no_run
356
+ /// use inkwell::context::Context;
357
+ /// use inkwell::module::Linkage;
358
+ /// use inkwell::AddressSpace;
359
+ ///
360
+ /// let context = Context::create();
361
+ /// let module = context.create_module("sum");
362
+ /// let builder = context.create_builder();
363
+ ///
364
+ /// // type of an exception in C++
365
+ /// let i8_ptr_type = context.i8_type().ptr_type(AddressSpace::Generic);
366
+ /// let i32_type = context.i32_type();
367
+ /// let exception_type = context.struct_type(&[i8_ptr_type.into(), i32_type.into()], false);
368
+ ///
369
+ /// // the personality function used by C++
370
+ /// let personality_function = {
371
+ /// let name = "__gxx_personality_v0";
372
+ /// let linkage = Some(Linkage::External);
373
+ ///
374
+ /// module.add_function(name, context.i64_type().fn_type(&[], false), linkage)
375
+ /// };
376
+ ///
377
+ /// // link in the C++ type info for the `int` type
378
+ /// let type_info_int = module.add_global(i8_ptr_type, Some(AddressSpace::Generic), "_ZTIi");
379
+ /// type_info_int.set_linkage(Linkage::External);
380
+ ///
381
+ /// // make the catch landing pad
382
+ /// let res = builder.build_landing_pad(exception_type, personality_function, &[type_info_int], false, "res");
383
+ /// ```
384
+ ///
385
+ /// * **filter**: A filter clause encodes that only some types of exceptions are valid at this
386
+ /// point. A filter clause is made by constructing a clause from a constant array.
387
+ ///
388
+ /// ```no_run
389
+ /// use inkwell::context::Context;
390
+ /// use inkwell::module::Linkage;
391
+ /// use inkwell::values::AnyValue;
392
+ /// use inkwell::AddressSpace;
393
+ ///
394
+ /// let context = Context::create();
395
+ /// let module = context.create_module("sum");
396
+ /// let builder = context.create_builder();
397
+ ///
398
+ /// // type of an exception in C++
399
+ /// let i8_ptr_type = context.i8_type().ptr_type(AddressSpace::Generic);
400
+ /// let i32_type = context.i32_type();
401
+ /// let exception_type = context.struct_type(&[i8_ptr_type.into(), i32_type.into()], false);
402
+ ///
403
+ /// // the personality function used by C++
404
+ /// let personality_function = {
405
+ /// let name = "__gxx_personality_v0";
406
+ /// let linkage = Some(Linkage::External);
407
+ ///
408
+ /// module.add_function(name, context.i64_type().fn_type(&[], false), linkage)
409
+ /// };
410
+ ///
411
+ /// // link in the C++ type info for the `int` type
412
+ /// let type_info_int = module.add_global(i8_ptr_type, Some(AddressSpace::Generic), "_ZTIi");
413
+ /// type_info_int.set_linkage(Linkage::External);
414
+ ///
415
+ /// // make the filter landing pad
416
+ /// let filter_pattern = i8_ptr_type.const_array(&[type_info_int.as_any_value_enum().into_pointer_value()]);
417
+ /// let res = builder.build_landing_pad(exception_type, personality_function, &[filter_pattern], false, "res");
418
+ /// ```
419
+ pub fn build_landing_pad < T > (
420
+ & self ,
421
+ exception_type : T ,
422
+ personality_function : FunctionValue < ' ctx > ,
423
+ clauses : & [ BasicValueEnum < ' ctx > ] ,
424
+ is_cleanup : bool ,
425
+ name : & str
426
+ ) -> BasicValueEnum < ' ctx >
427
+ where
428
+ T : BasicType < ' ctx > ,
429
+ {
430
+ let c_string = to_c_str ( name) ;
431
+ let num_clauses = clauses. len ( ) as u32 ;
432
+
433
+ let value = unsafe {
434
+ LLVMBuildLandingPad (
435
+ self . builder ,
436
+ exception_type. as_type_ref ( ) ,
437
+ personality_function. as_value_ref ( ) ,
438
+ num_clauses,
439
+ c_string. as_ptr ( ) ,
440
+ )
441
+ } ;
442
+
443
+
444
+ for clause in clauses {
445
+ unsafe {
446
+ LLVMAddClause ( value, clause. as_value_ref ( ) ) ;
447
+ }
448
+ }
449
+
450
+ unsafe {
451
+ LLVMSetCleanup ( value, is_cleanup as _ ) ;
452
+ } ;
453
+
454
+ unsafe {
455
+ BasicValueEnum :: new ( value)
456
+ }
457
+ }
458
+
459
+ /// Resume propagation of an existing (in-flight) exception whose unwinding was interrupted with a landingpad instruction.
460
+ ///
461
+ /// This example uses a cleanup landing pad. A cleanup is extra code that needs to be run when
462
+ /// unwinding a scope. C++ destructors are a typical example. In a language with reference counting,
463
+ /// the cleanup block can decrement the refcount of values in scope.
464
+ ///
465
+ /// ```no_run
466
+ /// use inkwell::context::Context;
467
+ /// use inkwell::AddressSpace;
468
+ ///
469
+ /// let context = Context::create();
470
+ /// let module = context.create_module("sum");
471
+ /// let builder = context.create_builder();
472
+ ///
473
+ /// let f32_type = context.f32_type();
474
+ /// let fn_type = f32_type.fn_type(&[], false);
475
+ ///
476
+ /// // we will pretend this function can throw an exception
477
+ /// let function = module.add_function("bomb", fn_type, None);
478
+ /// let basic_block = context.append_basic_block(function, "entry");
479
+ ///
480
+ /// builder.position_at_end(basic_block);
481
+ ///
482
+ /// let pi = f32_type.const_float(::std::f64::consts::PI);
483
+ ///
484
+ /// builder.build_return(Some(&pi));
485
+ ///
486
+ /// let function2 = module.add_function("wrapper", fn_type, None);
487
+ /// let basic_block2 = context.append_basic_block(function2, "entry");
488
+ ///
489
+ /// builder.position_at_end(basic_block2);
490
+ ///
491
+ /// let then_block = context.append_basic_block(function2, "then_block");
492
+ /// let catch_block = context.append_basic_block(function2, "catch_block");
493
+ ///
494
+ /// let call_site = builder.build_invoke(function, &[], then_block, catch_block, "get_pi");
495
+ ///
496
+ /// {
497
+ /// builder.position_at_end(then_block);
498
+ ///
499
+ /// // in the then_block, the `call_site` value is defined and can be used
500
+ /// let result = call_site.try_as_basic_value().left().unwrap();
501
+ ///
502
+ /// builder.build_return(Some(&result));
503
+ /// }
504
+ ///
505
+ /// {
506
+ /// builder.position_at_end(catch_block);
507
+ ///
508
+ /// // the personality function used by C++
509
+ /// let personality_function = {
510
+ /// let name = "__gxx_personality_v0";
511
+ /// let linkage = Some(Linkage::External);
512
+ ///
513
+ /// module.add_function(name, context.i64_type().fn_type(&[], false), linkage)
514
+ /// };
515
+ ///
516
+ /// // type of an exception in C++
517
+ /// let i8_ptr_type = context.i32_type().ptr_type(AddressSpace::Generic);
518
+ /// let i32_type = context.i32_type();
519
+ /// let exception_type = context.struct_type(&[i8_ptr_type.into(), i32_type.into()], false);
520
+ ///
521
+ /// // make the landing pad; must give a concrete type to the slice
522
+ /// let res = builder.build_landing_pad( exception_type, personality_function, &[], true, "res");
523
+ ///
524
+ /// // do cleanup ...
525
+ ///
526
+ /// builder.build_resume(res);
527
+ /// }
528
+ /// ```
529
+ pub fn build_resume < V : BasicValue < ' ctx > > ( & self , value : V ) -> InstructionValue < ' ctx > {
530
+ let val = unsafe { LLVMBuildResume ( self . builder , value. as_value_ref ( ) ) } ;
531
+
532
+ unsafe {
533
+ InstructionValue :: new ( val)
534
+ }
535
+ }
536
+
166
537
// REVIEW: Doesn't GEP work on array too?
167
538
/// GEP is very likely to segfault if indexes are used incorrectly, and is therefore an unsafe function. Maybe we can change this in the future.
168
539
pub unsafe fn build_gep ( & self , ptr : PointerValue < ' ctx > , ordered_indexes : & [ IntValue < ' ctx > ] , name : & str ) -> PointerValue < ' ctx > {
0 commit comments