|
1 | 1 | use either::Either;
|
2 |
| -use llvm_sys::core::{LLVMBuildAdd, LLVMBuildAlloca, LLVMBuildAnd, LLVMBuildArrayAlloca, LLVMBuildArrayMalloc, 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, LLVMGetElementType, LLVMGetInsertBlock, LLVMGetReturnType, LLVMGetTypeKind, LLVMInsertIntoBuilder, LLVMPositionBuilderAtEnd, LLVMTypeOf, LLVMSetTailCall, LLVMBuildExtractElement, LLVMBuildInsertElement, LLVMBuildIntToPtr, LLVMBuildPtrToInt, LLVMInsertIntoBuilderWithName, LLVMClearInsertionPosition, LLVMCreateBuilder, 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}; |
| 2 | +use llvm_sys::core::{LLVMBuildAdd, LLVMBuildAlloca, LLVMBuildAnd, LLVMBuildArrayAlloca, LLVMBuildArrayMalloc, 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, LLVMGetElementType, LLVMGetInsertBlock, LLVMGetReturnType, LLVMGetTypeKind, LLVMInsertIntoBuilder, LLVMPositionBuilderAtEnd, LLVMTypeOf, LLVMSetTailCall, LLVMBuildExtractElement, LLVMBuildInsertElement, LLVMBuildIntToPtr, LLVMBuildPtrToInt, LLVMInsertIntoBuilderWithName, LLVMClearInsertionPosition, LLVMCreateBuilder, 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}; |
3 | 3 | use llvm_sys::prelude::{LLVMBuilderRef, LLVMValueRef};
|
4 | 4 | use llvm_sys::{LLVMOpcode, LLVMIntPredicate, LLVMTypeKind, LLVMRealPredicate, LLVMAtomicOrdering};
|
5 | 5 |
|
@@ -500,6 +500,132 @@ impl Builder {
|
500 | 500 | IntValue::new(value)
|
501 | 501 | }
|
502 | 502 |
|
| 503 | + /// Builds an `IntValue` containing the result of a logical left shift instruction. |
| 504 | + /// |
| 505 | + /// # Example |
| 506 | + /// A logical left shift is an operation in which an integer value's bits are shifted left by N number of positions. |
| 507 | + /// |
| 508 | + /// ```rust |
| 509 | + /// assert_eq!(0b0000_0001 << 0, 0b0000_0001); |
| 510 | + /// assert_eq!(0b0000_0001 << 1, 0b0000_0010); |
| 511 | + /// assert_eq!(0b0000_0011 << 2, 0b0000_1100); |
| 512 | + /// ``` |
| 513 | + /// |
| 514 | + /// In Rust, a function that could do this for 8bit values looks like: |
| 515 | + /// |
| 516 | + /// ```rust |
| 517 | + /// fn left_shift(value: u8, n: u8) -> u8 { |
| 518 | + /// value << n |
| 519 | + /// } |
| 520 | + /// ``` |
| 521 | + /// |
| 522 | + /// And in Inkwell, the corresponding function would look roughly like: |
| 523 | + /// |
| 524 | + /// ```rust |
| 525 | + /// use inkwell::context::Context; |
| 526 | + /// |
| 527 | + /// // Setup |
| 528 | + /// let context = Context::create(); |
| 529 | + /// let module = context.create_module("my_module"); |
| 530 | + /// let builder = context.create_builder(); |
| 531 | + /// let i8_type = context.i8_type(); |
| 532 | + /// let fn_type = i8_type.fn_type(&[&i8_type, &i8_type], false); |
| 533 | + /// |
| 534 | + /// // Function Definition |
| 535 | + /// let function = module.add_function("left_shift", &fn_type, None); |
| 536 | + /// let value = function.get_first_param().unwrap().into_int_value(); |
| 537 | + /// let n = function.get_nth_param(1).unwrap().into_int_value(); |
| 538 | + /// let entry_block = function.append_basic_block("entry"); |
| 539 | + /// |
| 540 | + /// builder.position_at_end(&entry_block); |
| 541 | + /// |
| 542 | + /// let shift = builder.build_left_shift(&value, &n, "left_shift"); // value << n |
| 543 | + /// |
| 544 | + /// builder.build_return(Some(&shift)); |
| 545 | + /// ``` |
| 546 | + pub fn build_left_shift(&self, lhs: &IntValue, rhs: &IntValue, name: &str) -> IntValue { |
| 547 | + let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly"); |
| 548 | + |
| 549 | + let value = unsafe { |
| 550 | + LLVMBuildShl(self.builder, lhs.as_value_ref(), rhs.as_value_ref(), c_string.as_ptr()) |
| 551 | + }; |
| 552 | + |
| 553 | + IntValue::new(value) |
| 554 | + } |
| 555 | + |
| 556 | + /// Builds an `IntValue` containing the result of a right shift instruction. |
| 557 | + /// |
| 558 | + /// # Example |
| 559 | + /// A right shift is an operation in which an integer value's bits are shifted right by N number of positions. |
| 560 | + /// It may either be logical and have its leftmost N bit(s) filled with zeros or sign extended and filled with ones |
| 561 | + /// if the leftmost bit was one. |
| 562 | + /// |
| 563 | + /// ```rust |
| 564 | + /// // Logical Right Shift |
| 565 | + /// assert_eq!(0b1100_0000 >> 2, 0b0011_0000); |
| 566 | + /// assert_eq!(0b0000_0010 >> 1, 0b0000_0001); |
| 567 | + /// assert_eq!(0b0000_1100 >> 2, 0b0000_0011); |
| 568 | + /// |
| 569 | + /// // Sign Extended Right Shift |
| 570 | + /// assert_eq!(0b0100_0000i8 >> 2, 0b0001_0000); |
| 571 | + /// assert_eq!(0b1110_0000i8 >> 1, 0b1111_0000); |
| 572 | + /// assert_eq!(0b1100_0000i8 >> 2, 0b1111_0000); |
| 573 | + /// ``` |
| 574 | + /// |
| 575 | + /// In Rust, functions that could do this for 8bit values look like: |
| 576 | + /// |
| 577 | + /// ```rust |
| 578 | + /// fn logical_right_shift(value: u8, n: u8) -> u8 { |
| 579 | + /// value >> n |
| 580 | + /// } |
| 581 | + /// |
| 582 | + /// fn sign_extended_right_shift(value: i8, n: u8) -> i8 { |
| 583 | + /// value >> n |
| 584 | + /// } |
| 585 | + /// ``` |
| 586 | + /// Notice that, in Rust (and most other languages), whether or not a value is sign extended depends wholly on whether |
| 587 | + /// or not the type is signed (ie an i8 is a signed 8 bit value). LLVM does not make this distinction for you. |
| 588 | + /// |
| 589 | + /// In Inkwell, the corresponding functions would look roughly like: |
| 590 | + /// |
| 591 | + /// ```rust |
| 592 | + /// use inkwell::context::Context; |
| 593 | + /// |
| 594 | + /// // Setup |
| 595 | + /// let context = Context::create(); |
| 596 | + /// let module = context.create_module("my_module"); |
| 597 | + /// let builder = context.create_builder(); |
| 598 | + /// let i8_type = context.i8_type(); |
| 599 | + /// let fn_type = i8_type.fn_type(&[&i8_type, &i8_type], false); |
| 600 | + /// |
| 601 | + /// // Function Definition |
| 602 | + /// let function = module.add_function("right_shift", &fn_type, None); |
| 603 | + /// let value = function.get_first_param().unwrap().into_int_value(); |
| 604 | + /// let n = function.get_nth_param(1).unwrap().into_int_value(); |
| 605 | + /// let entry_block = function.append_basic_block("entry"); |
| 606 | + /// |
| 607 | + /// builder.position_at_end(&entry_block); |
| 608 | + /// |
| 609 | + /// // Whether or not your right shift is sign extended (true) or logical (false) depends |
| 610 | + /// // on the boolean input parameter: |
| 611 | + /// let shift = builder.build_right_shift(&value, &n, false, "right_shift"); // value >> n |
| 612 | + /// |
| 613 | + /// builder.build_return(Some(&shift)); |
| 614 | + /// ``` |
| 615 | + pub fn build_right_shift(&self, lhs: &IntValue, rhs: &IntValue, sign_extend: bool, name: &str) -> IntValue { |
| 616 | + let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly"); |
| 617 | + |
| 618 | + let value = unsafe { |
| 619 | + if sign_extend { |
| 620 | + LLVMBuildAShr(self.builder, lhs.as_value_ref(), rhs.as_value_ref(), c_string.as_ptr()) |
| 621 | + } else { |
| 622 | + LLVMBuildLShr(self.builder, lhs.as_value_ref(), rhs.as_value_ref(), c_string.as_ptr()) |
| 623 | + } |
| 624 | + }; |
| 625 | + |
| 626 | + IntValue::new(value) |
| 627 | + } |
| 628 | + |
503 | 629 | // SubType: <I>(&self, lhs: &IntValue<I>, rhs: &IntValue<I>, name: &str) -> IntValue<I> {
|
504 | 630 | pub fn build_int_sub(&self, lhs: &IntValue, rhs: &IntValue, name: &str) -> IntValue {
|
505 | 631 | let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
|
|
0 commit comments