From 4b1a7d8a1d315090fb808ba4695bbacdc91e1aff Mon Sep 17 00:00:00 2001 From: johannst Date: Fri, 24 Sep 2021 22:49:57 +0000 Subject: deploy: 6eb6ad9f574c783d471f6a863299af25b6f5a8c7 --- src/llvm_kaleidoscope_rs/codegen.rs.html | 82 +- src/llvm_kaleidoscope_rs/lexer.rs.html | 8 +- src/llvm_kaleidoscope_rs/lib.rs.html | 8 +- src/llvm_kaleidoscope_rs/llvm.rs.html | 1073 -------------------- src/llvm_kaleidoscope_rs/llvm/builder.rs.html | 383 +++++++ src/llvm_kaleidoscope_rs/llvm/lljit.rs.html | 307 ++++++ src/llvm_kaleidoscope_rs/llvm/mod.rs.html | 161 +++ src/llvm_kaleidoscope_rs/llvm/module.rs.html | 397 ++++++++ src/llvm_kaleidoscope_rs/llvm/pass_manager.rs.html | 155 +++ src/llvm_kaleidoscope_rs/llvm/type_.rs.html | 121 +++ src/llvm_kaleidoscope_rs/llvm/value.rs.html | 341 +++++++ src/llvm_kaleidoscope_rs/parser.rs.html | 12 +- 12 files changed, 1947 insertions(+), 1101 deletions(-) delete mode 100644 src/llvm_kaleidoscope_rs/llvm.rs.html create mode 100644 src/llvm_kaleidoscope_rs/llvm/builder.rs.html create mode 100644 src/llvm_kaleidoscope_rs/llvm/lljit.rs.html create mode 100644 src/llvm_kaleidoscope_rs/llvm/mod.rs.html create mode 100644 src/llvm_kaleidoscope_rs/llvm/module.rs.html create mode 100644 src/llvm_kaleidoscope_rs/llvm/pass_manager.rs.html create mode 100644 src/llvm_kaleidoscope_rs/llvm/type_.rs.html create mode 100644 src/llvm_kaleidoscope_rs/llvm/value.rs.html (limited to 'src') diff --git a/src/llvm_kaleidoscope_rs/codegen.rs.html b/src/llvm_kaleidoscope_rs/codegen.rs.html index bcaa770..e94ac8d 100644 --- a/src/llvm_kaleidoscope_rs/codegen.rs.html +++ b/src/llvm_kaleidoscope_rs/codegen.rs.html @@ -1,6 +1,4 @@ -codegen.rs - source - -
  1
+codegen.rs - source
  1
   2
   3
   4
@@ -135,10 +133,37 @@
 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
 
 use std::collections::HashMap;
 
-use crate::llvm::{Builder, FnValue, Module, Value};
+use crate::llvm::{FnValue, FunctionPassManager, IRBuilder, Module, Value};
 use crate::parser::{ExprAST, FunctionAST, PrototypeAST};
 use crate::Either;
 
@@ -147,18 +172,23 @@
 /// Code generator from kaleidoscope AST to LLVM IR.
 pub struct Codegen<'llvm, 'a> {
     module: &'llvm Module,
-    builder: &'a Builder<'llvm>,
+    builder: &'a IRBuilder<'llvm>,
+    fpm: &'a FunctionPassManager<'llvm>,
+    fn_protos: &'a mut HashMap<String, PrototypeAST>,
 }
 
 impl<'llvm, 'a> Codegen<'llvm, 'a> {
     /// Compile either a [`PrototypeAST`] or a [`FunctionAST`] into the LLVM `module`.
     pub fn compile(
         module: &'llvm Module,
+        fn_protos: &mut HashMap<String, PrototypeAST>,
         compilee: Either<&PrototypeAST, &FunctionAST>,
     ) -> CodegenResult<FnValue<'llvm>> {
-        let cg = Codegen {
+        let mut cg = Codegen {
             module,
-            builder: &Builder::with_ctx(module),
+            builder: &IRBuilder::with_ctx(module),
+            fpm: &FunctionPassManager::with_ctx(module),
+            fn_protos,
         };
         let mut variables = HashMap::new();
 
@@ -195,7 +225,7 @@
                     _ => Err("invalid binary operator".into()),
                 }
             }
-            ExprAST::Call(callee, args) => match self.module.get_fn(callee) {
+            ExprAST::Call(callee, args) => match self.get_function(callee) {
                 Some(callee) => {
                     if callee.args() != args.len() {
                         return Err("Incorrect # arguments passed".into());
@@ -235,14 +265,16 @@
     }
 
     fn codegen_function(
-        &self,
+        &mut self,
         FunctionAST(proto, body): &FunctionAST,
         named_values: &mut HashMap<&'llvm str, Value<'llvm>>,
     ) -> CodegenResult<FnValue<'llvm>> {
-        let the_function = match self.module.get_fn(&proto.0) {
-            Some(f) => f,
-            None => self.codegen_prototype(proto),
-        };
+        // Insert the function prototype into the `fn_protos` map to keep track for re-generating
+        // declarations in other modules.
+        self.fn_protos.insert(proto.0.clone(), proto.clone());
+
+        let the_function = self.get_function(&proto.0)
+            .expect("If proto not already generated, get_function will do for us since we updated fn_protos before-hand!");
 
         if the_function.basic_blocks() > 0 {
             return Err("Function cannot be redefined.".into());
@@ -265,11 +297,33 @@
         if let Ok(ret) = self.codegen_expr(body, named_values) {
             self.builder.ret(ret);
             assert!(the_function.verify());
+
+            // Run the optimization passes on the function.
+            self.fpm.run(the_function);
+
             Ok(the_function)
         } else {
             todo!("Failed to codegen function body, erase from module!");
         }
     }
+
+    /// Lookup function with `name` in the LLVM module and return the corresponding value reference.
+    /// If the function is not available in the module, check if the prototype is known and codegen
+    /// it.
+    /// Return [`None`] if the prototype is not known.
+    fn get_function(&self, name: &str) -> Option<FnValue<'llvm>> {
+        let callee = match self.module.get_fn(name) {
+            Some(callee) => callee,
+            None => {
+                let proto = self.fn_protos.get(name)?;
+                self.codegen_prototype(proto)
+            }
+        };
+
+        Some(callee)
+    }
 }
 
-
\ No newline at end of file +
+ + \ No newline at end of file diff --git a/src/llvm_kaleidoscope_rs/lexer.rs.html b/src/llvm_kaleidoscope_rs/lexer.rs.html index 3524648..4b13fd9 100644 --- a/src/llvm_kaleidoscope_rs/lexer.rs.html +++ b/src/llvm_kaleidoscope_rs/lexer.rs.html @@ -1,6 +1,4 @@ -lexer.rs - source - -
  1
+lexer.rs - source
  1
   2
   3
   4
@@ -364,4 +362,6 @@
     }
 }
 
-
\ No newline at end of file +
+ + \ No newline at end of file diff --git a/src/llvm_kaleidoscope_rs/lib.rs.html b/src/llvm_kaleidoscope_rs/lib.rs.html index a752947..955f3c8 100644 --- a/src/llvm_kaleidoscope_rs/lib.rs.html +++ b/src/llvm_kaleidoscope_rs/lib.rs.html @@ -1,6 +1,4 @@ -lib.rs - source - -
  1
+lib.rs - source
  1
   2
   3
   4
@@ -224,4 +222,6 @@
     }
 }
 
-
\ No newline at end of file +
+ + \ No newline at end of file diff --git a/src/llvm_kaleidoscope_rs/llvm.rs.html b/src/llvm_kaleidoscope_rs/llvm.rs.html deleted file mode 100644 index 2da418a..0000000 --- a/src/llvm_kaleidoscope_rs/llvm.rs.html +++ /dev/null @@ -1,1073 +0,0 @@ -llvm.rs - source - -
  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
-214
-215
-216
-217
-218
-219
-220
-221
-222
-223
-224
-225
-226
-227
-228
-229
-230
-231
-232
-233
-234
-235
-236
-237
-238
-239
-240
-241
-242
-243
-244
-245
-246
-247
-248
-249
-250
-251
-252
-253
-254
-255
-256
-257
-258
-259
-260
-261
-262
-263
-264
-265
-266
-267
-268
-269
-270
-271
-272
-273
-274
-275
-276
-277
-278
-279
-280
-281
-282
-283
-284
-285
-286
-287
-288
-289
-290
-291
-292
-293
-294
-295
-296
-297
-298
-299
-300
-301
-302
-303
-304
-305
-306
-307
-308
-309
-310
-311
-312
-313
-314
-315
-316
-317
-318
-319
-320
-321
-322
-323
-324
-325
-326
-327
-328
-329
-330
-331
-332
-333
-334
-335
-336
-337
-338
-339
-340
-341
-342
-343
-344
-345
-346
-347
-348
-349
-350
-351
-352
-353
-354
-355
-356
-357
-358
-359
-360
-361
-362
-363
-364
-365
-366
-367
-368
-369
-370
-371
-372
-373
-374
-375
-376
-377
-378
-379
-380
-381
-382
-383
-384
-385
-386
-387
-388
-389
-390
-391
-392
-393
-394
-395
-396
-397
-398
-399
-400
-401
-402
-403
-404
-405
-406
-407
-408
-409
-410
-411
-412
-413
-414
-415
-416
-417
-418
-419
-420
-421
-422
-423
-424
-425
-426
-427
-428
-429
-430
-431
-432
-433
-434
-435
-436
-437
-438
-439
-440
-441
-442
-443
-444
-445
-446
-447
-448
-449
-450
-451
-452
-453
-454
-455
-456
-457
-458
-459
-460
-461
-462
-463
-464
-465
-466
-467
-468
-469
-470
-471
-472
-473
-474
-475
-476
-477
-478
-479
-480
-481
-482
-483
-484
-485
-486
-487
-488
-489
-490
-491
-492
-493
-494
-495
-496
-497
-498
-499
-500
-501
-502
-503
-504
-505
-506
-507
-508
-509
-510
-511
-512
-513
-514
-515
-516
-517
-518
-519
-520
-521
-522
-523
-524
-525
-526
-527
-528
-529
-530
-531
-532
-533
-534
-
-//! Safe wrapper around the LLVM C API.
-//!
-//! References returned from the LLVM API are tied to the `'llvm` lifetime which is bound to the
-//! context where the objects are created in.
-//! We do not offer wrappers to remove or delete any objects in the context and therefore all the
-//! references will be valid for the liftime of the context.
-
-use llvm_sys::analysis::{LLVMVerifierFailureAction, LLVMVerifyFunction};
-use llvm_sys::core::{
-    LLVMAddFunction, LLVMAppendBasicBlockInContext, LLVMBuildFAdd, LLVMBuildFCmp, LLVMBuildFMul,
-    LLVMBuildFSub, LLVMBuildRet, LLVMBuildUIToFP, LLVMConstReal, LLVMContextCreate,
-    LLVMContextDispose, LLVMCountBasicBlocks, LLVMCountParams, LLVMCreateBuilderInContext,
-    LLVMDisposeBuilder, LLVMDisposeModule, LLVMDoubleTypeInContext, LLVMDumpModule, LLVMDumpType,
-    LLVMDumpValue, LLVMGetNamedFunction, LLVMGetParam, LLVMGetReturnType, LLVMGetTypeKind,
-    LLVMGetValueKind, LLVMGetValueName2, LLVMModuleCreateWithNameInContext,
-    LLVMPositionBuilderAtEnd, LLVMSetValueName2, LLVMTypeOf,
-};
-use llvm_sys::prelude::{
-    LLVMBasicBlockRef, LLVMBool, LLVMBuilderRef, LLVMContextRef, LLVMModuleRef, LLVMTypeRef,
-    LLVMValueRef,
-};
-use llvm_sys::{LLVMRealPredicate, LLVMTypeKind, LLVMValueKind};
-
-use std::convert::TryFrom;
-use std::ffi::CStr;
-use std::marker::PhantomData;
-use std::ops::Deref;
-
-use crate::SmallCStr;
-
-// Definition of LLVM C API functions using our `repr(transparent)` types.
-extern "C" {
-    fn LLVMFunctionType(
-        ReturnType: Type<'_>,
-        ParamTypes: *mut Type<'_>,
-        ParamCount: ::libc::c_uint,
-        IsVarArg: LLVMBool,
-    ) -> LLVMTypeRef;
-    fn LLVMBuildCall2(
-        arg1: LLVMBuilderRef,
-        arg2: Type<'_>,
-        Fn: FnValue<'_>,
-        Args: *mut Value<'_>,
-        NumArgs: ::libc::c_uint,
-        Name: *const ::libc::c_char,
-    ) -> LLVMValueRef;
-}
-
-// ====================
-//   Module / Context
-// ====================
-
-/// Wrapper for a LLVM Module with its own LLVM Context.
-pub struct Module {
-    ctx: LLVMContextRef,
-    module: LLVMModuleRef,
-}
-
-impl<'llvm> Module {
-    /// Create a new Module instance.
-    ///
-    /// # Panics
-    ///
-    /// Panics if creating the context or the module fails.
-    pub fn new() -> Self {
-        let (ctx, module) = unsafe {
-            let c = LLVMContextCreate();
-            let m = LLVMModuleCreateWithNameInContext(b"module\0".as_ptr().cast(), c);
-            assert!(!c.is_null() && !m.is_null());
-            (c, m)
-        };
-
-        Module { ctx, module }
-    }
-
-    /// Dump LLVM IR emitted into the Module to stdout.
-    pub fn dump(&self) {
-        unsafe { LLVMDumpModule(self.module) };
-    }
-
-    /// Get a type reference representing a `f64` float.
-    ///
-    /// # Panics
-    ///
-    /// Panics if LLVM API returns a `null` pointer.
-    pub fn type_f64(&self) -> Type<'llvm> {
-        let type_ref = unsafe { LLVMDoubleTypeInContext(self.ctx) };
-        Type::new(type_ref)
-    }
-
-    /// Get a type reference representing a `fn(args) -> ret` function.
-    ///
-    /// # Panics
-    ///
-    /// Panics if LLVM API returns a `null` pointer.
-    pub fn type_fn(&'llvm self, args: &mut [Type<'llvm>], ret: Type<'llvm>) -> Type<'llvm> {
-        let type_ref = unsafe {
-            LLVMFunctionType(
-                ret,
-                args.as_mut_ptr(),
-                args.len() as libc::c_uint,
-                0, /* IsVarArg */
-            )
-        };
-        Type::new(type_ref)
-    }
-
-    /// Add a function with the given `name` and `fn_type` to the module and return a value
-    /// reference representing the function.
-    ///
-    /// # Panics
-    ///
-    /// Panics if LLVM API returns a `null` pointer or `name` could not be converted to a
-    /// [`SmallCStr`].
-    pub fn add_fn(&'llvm self, name: &str, fn_type: Type<'llvm>) -> FnValue<'llvm> {
-        debug_assert_eq!(
-            fn_type.kind(),
-            LLVMTypeKind::LLVMFunctionTypeKind,
-            "Expected a function type when adding a function!"
-        );
-
-        let name = SmallCStr::try_from(name)
-            .expect("Failed to convert 'name' argument to small C string!");
-
-        let value_ref = unsafe { LLVMAddFunction(self.module, name.as_ptr(), fn_type.0) };
-        FnValue::new(value_ref)
-    }
-
-    /// Get a function value reference to the function with the given `name` if it was previously
-    /// added to the module with [`add_fn`][Module::add_fn].
-    ///
-    /// # Panics
-    ///
-    /// Panics if `name` could not be converted to a [`SmallCStr`].
-    pub fn get_fn(&'llvm self, name: &str) -> Option<FnValue<'llvm>> {
-        let name = SmallCStr::try_from(name)
-            .expect("Failed to convert 'name' argument to small C string!");
-
-        let value_ref = unsafe { LLVMGetNamedFunction(self.module, name.as_ptr()) };
-
-        (!value_ref.is_null()).then(|| FnValue::new(value_ref))
-    }
-
-    /// Append a Basic Block to the end of the function referenced by the value reference
-    /// `fn_value`.
-    ///
-    /// # Panics
-    ///
-    /// Panics if LLVM API returns a `null` pointer.
-    pub fn append_basic_block(&'llvm self, fn_value: FnValue<'llvm>) -> BasicBlock<'llvm> {
-        let block = unsafe {
-            LLVMAppendBasicBlockInContext(
-                self.ctx,
-                fn_value.value_ref(),
-                b"block\0".as_ptr().cast(),
-            )
-        };
-        assert!(!block.is_null());
-
-        BasicBlock(block, PhantomData)
-    }
-}
-
-impl Drop for Module {
-    fn drop(&mut self) {
-        unsafe {
-            LLVMDisposeModule(self.module);
-            LLVMContextDispose(self.ctx);
-        }
-    }
-}
-
-// ===========
-//   Builder
-// ===========
-
-/// Wrapper for a LLVM IR Builder.
-pub struct Builder<'llvm> {
-    builder: LLVMBuilderRef,
-    _ctx: PhantomData<&'llvm ()>,
-}
-
-impl<'llvm> Builder<'llvm> {
-    /// Create a new LLVM IR Builder with the `module`s context.
-    ///
-    /// # Panics
-    ///
-    /// Panics if creating the IR Builder fails.
-    pub fn with_ctx(module: &'llvm Module) -> Builder<'llvm> {
-        let builder = unsafe { LLVMCreateBuilderInContext(module.ctx) };
-        assert!(!builder.is_null());
-
-        Builder {
-            builder,
-            _ctx: PhantomData,
-        }
-    }
-
-    /// Position the IR Builder at the end of the given Basic Block.
-    pub fn pos_at_end(&self, bb: BasicBlock<'llvm>) {
-        unsafe {
-            LLVMPositionBuilderAtEnd(self.builder, bb.0);
-        }
-    }
-
-    /// Emit a [fadd](https://llvm.org/docs/LangRef.html#fadd-instruction) instruction.
-    ///
-    /// # Panics
-    ///
-    /// Panics if LLVM API returns a `null` pointer.
-    pub fn fadd(&self, lhs: Value<'llvm>, rhs: Value<'llvm>) -> Value<'llvm> {
-        debug_assert!(lhs.is_f64(), "fadd: Expected f64 as lhs operand!");
-        debug_assert!(rhs.is_f64(), "fadd: Expected f64 as rhs operand!");
-
-        let value_ref = unsafe {
-            LLVMBuildFAdd(
-                self.builder,
-                lhs.value_ref(),
-                rhs.value_ref(),
-                b"fadd\0".as_ptr().cast(),
-            )
-        };
-        Value::new(value_ref)
-    }
-
-    /// Emit a [fsub](https://llvm.org/docs/LangRef.html#fsub-instruction) instruction.
-    ///
-    /// # Panics
-    ///
-    /// Panics if LLVM API returns a `null` pointer.
-    pub fn fsub(&self, lhs: Value<'llvm>, rhs: Value<'llvm>) -> Value<'llvm> {
-        debug_assert!(lhs.is_f64(), "fsub: Expected f64 as lhs operand!");
-        debug_assert!(rhs.is_f64(), "fsub: Expected f64 as rhs operand!");
-
-        let value_ref = unsafe {
-            LLVMBuildFSub(
-                self.builder,
-                lhs.value_ref(),
-                rhs.value_ref(),
-                b"fsub\0".as_ptr().cast(),
-            )
-        };
-        Value::new(value_ref)
-    }
-
-    /// Emit a [fmul](https://llvm.org/docs/LangRef.html#fmul-instruction) instruction.
-    ///
-    /// # Panics
-    ///
-    /// Panics if LLVM API returns a `null` pointer.
-    pub fn fmul(&self, lhs: Value<'llvm>, rhs: Value<'llvm>) -> Value<'llvm> {
-        debug_assert!(lhs.is_f64(), "fmul: Expected f64 as lhs operand!");
-        debug_assert!(rhs.is_f64(), "fmul: Expected f64 as rhs operand!");
-
-        let value_ref = unsafe {
-            LLVMBuildFMul(
-                self.builder,
-                lhs.value_ref(),
-                rhs.value_ref(),
-                b"fmul\0".as_ptr().cast(),
-            )
-        };
-        Value::new(value_ref)
-    }
-
-    /// Emit a [fcmult](https://llvm.org/docs/LangRef.html#fcmp-instruction) instruction.
-    ///
-    /// # Panics
-    ///
-    /// Panics if LLVM API returns a `null` pointer.
-    pub fn fcmpult(&self, lhs: Value<'llvm>, rhs: Value<'llvm>) -> Value<'llvm> {
-        debug_assert!(lhs.is_f64(), "fcmplt: Expected f64 as lhs operand!");
-        debug_assert!(rhs.is_f64(), "fcmplt: Expected f64 as rhs operand!");
-
-        let value_ref = unsafe {
-            LLVMBuildFCmp(
-                self.builder,
-                LLVMRealPredicate::LLVMRealULT,
-                lhs.value_ref(),
-                rhs.value_ref(),
-                b"fcmplt\0".as_ptr().cast(),
-            )
-        };
-        Value::new(value_ref)
-    }
-
-    /// Emit a [uitofp](https://llvm.org/docs/LangRef.html#uitofp-to-instruction) instruction.
-    ///
-    /// # Panics
-    ///
-    /// Panics if LLVM API returns a `null` pointer.
-    pub fn uitofp(&self, val: Value<'llvm>, dest_type: Type<'llvm>) -> Value<'llvm> {
-        debug_assert!(val.is_int(), "uitofp: Expected integer operand!");
-
-        let value_ref = unsafe {
-            LLVMBuildUIToFP(
-                self.builder,
-                val.value_ref(),
-                dest_type.0,
-                b"uitofp\0".as_ptr().cast(),
-            )
-        };
-        Value::new(value_ref)
-    }
-
-    /// Emit a [call](https://llvm.org/docs/LangRef.html#call-instruction) instruction.
-    ///
-    /// # Panics
-    ///
-    /// Panics if LLVM API returns a `null` pointer.
-    pub fn call(&self, fn_value: FnValue<'llvm>, args: &mut [Value<'llvm>]) -> Value<'llvm> {
-        let value_ref = unsafe {
-            LLVMBuildCall2(
-                self.builder,
-                fn_value.ret_type(),
-                fn_value,
-                args.as_mut_ptr(),
-                args.len() as libc::c_uint,
-                b"call\0".as_ptr().cast(),
-            )
-        };
-        Value::new(value_ref)
-    }
-
-    /// Emit a [ret](https://llvm.org/docs/LangRef.html#ret-instruction) instruction.
-    ///
-    /// # Panics
-    ///
-    /// Panics if LLVM API returns a `null` pointer.
-    pub fn ret(&self, ret: Value<'llvm>) {
-        let ret = unsafe { LLVMBuildRet(self.builder, ret.value_ref()) };
-        assert!(!ret.is_null());
-    }
-}
-
-impl Drop for Builder<'_> {
-    fn drop(&mut self) {
-        unsafe { LLVMDisposeBuilder(self.builder) }
-    }
-}
-
-// ==============
-//   BasicBlock
-// ==============
-
-/// Wrapper for a LLVM Basic Block.
-#[derive(Copy, Clone)]
-pub struct BasicBlock<'llvm>(LLVMBasicBlockRef, PhantomData<&'llvm ()>);
-
-// ========
-//   Type
-// ========
-
-/// Wrapper for a LLVM Type Reference.
-#[derive(Copy, Clone)]
-#[repr(transparent)]
-pub struct Type<'llvm>(LLVMTypeRef, PhantomData<&'llvm ()>);
-
-impl<'llvm> Type<'llvm> {
-    fn new(type_ref: LLVMTypeRef) -> Self {
-        assert!(!type_ref.is_null());
-        Type(type_ref, PhantomData)
-    }
-
-    fn kind(&self) -> LLVMTypeKind {
-        unsafe { LLVMGetTypeKind(self.0) }
-    }
-
-    /// Dump the LLVM Type to stdout.
-    pub fn dump(&self) {
-        unsafe { LLVMDumpType(self.0) };
-    }
-
-    /// Get a value reference representing the const `f64` value.
-    ///
-    /// # Panics
-    ///
-    /// Panics if LLVM API returns a `null` pointer.
-    pub fn const_f64(self, n: f64) -> Value<'llvm> {
-        debug_assert_eq!(
-            self.kind(),
-            LLVMTypeKind::LLVMDoubleTypeKind,
-            "Expected a double type when creating const f64 value!"
-        );
-
-        let value_ref = unsafe { LLVMConstReal(self.0, n) };
-        Value::new(value_ref)
-    }
-}
-
-// =========
-//   Value
-// =========
-
-/// Wrapper for a LLVM Value Reference.
-#[derive(Copy, Clone)]
-#[repr(transparent)]
-pub struct Value<'llvm>(LLVMValueRef, PhantomData<&'llvm ()>);
-
-impl<'llvm> Value<'llvm> {
-    fn new(value_ref: LLVMValueRef) -> Self {
-        assert!(!value_ref.is_null());
-        Value(value_ref, PhantomData)
-    }
-
-    #[inline]
-    fn value_ref(&self) -> LLVMValueRef {
-        self.0
-    }
-
-    fn kind(&self) -> LLVMValueKind {
-        unsafe { LLVMGetValueKind(self.value_ref()) }
-    }
-
-    /// Dump the LLVM Value to stdout.
-    pub fn dump(&self) {
-        unsafe { LLVMDumpValue(self.value_ref()) };
-    }
-
-    /// Get a type reference representing for the given value reference.
-    ///
-    /// # Panics
-    ///
-    /// Panics if LLVM API returns a `null` pointer.
-    pub fn type_of(&self) -> Type<'llvm> {
-        let type_ref = unsafe { LLVMTypeOf(self.value_ref()) };
-        Type::new(type_ref)
-    }
-
-    /// Set the name for the given value reference.
-    ///
-    /// # Panics
-    ///
-    /// Panics if LLVM API returns a `null` pointer.
-    pub fn set_name(&self, name: &str) {
-        unsafe { LLVMSetValueName2(self.value_ref(), name.as_ptr().cast(), name.len()) };
-    }
-
-    /// Get the name for the given value reference.
-    ///
-    /// # Panics
-    ///
-    /// Panics if LLVM API returns a `null` pointer.
-    pub fn get_name(&self) -> &'llvm str {
-        let name = unsafe {
-            let mut len: libc::size_t = 0;
-            let name = LLVMGetValueName2(self.0, &mut len as _);
-            assert!(!name.is_null());
-
-            CStr::from_ptr(name)
-        };
-
-        // TODO: Does this string live for the time of the LLVM context?!
-        name.to_str()
-            .expect("Expected valid UTF8 string from LLVM API")
-    }
-
-    /// Check if value is of `f64` type.
-    pub fn is_f64(&self) -> bool {
-        self.type_of().kind() == LLVMTypeKind::LLVMDoubleTypeKind
-    }
-
-    /// Check if value is of integer type.
-    pub fn is_int(&self) -> bool {
-        self.type_of().kind() == LLVMTypeKind::LLVMIntegerTypeKind
-    }
-}
-
-/// Wrapper for a LLVM Value Reference specialized for contexts where function values are needed.
-#[derive(Copy, Clone)]
-#[repr(transparent)]
-pub struct FnValue<'llvm>(Value<'llvm>);
-
-impl<'llvm> Deref for FnValue<'llvm> {
-    type Target = Value<'llvm>;
-    fn deref(&self) -> &Self::Target {
-        &self.0
-    }
-}
-
-impl<'llvm> FnValue<'llvm> {
-    fn new(value_ref: LLVMValueRef) -> Self {
-        let value = Value::new(value_ref);
-        debug_assert_eq!(
-            value.kind(),
-            LLVMValueKind::LLVMFunctionValueKind,
-            "Expected a fn value when constructing FnValue!"
-        );
-
-        FnValue(value)
-    }
-
-    /// Get a type reference representing the return value of the given function value.
-    ///
-    /// # Panics
-    ///
-    /// Panics if LLVM API returns a `null` pointer.
-    pub fn ret_type(&self) -> Type<'llvm> {
-        let type_ref = unsafe { LLVMGetReturnType(LLVMTypeOf(self.value_ref())) };
-        Type::new(type_ref)
-    }
-
-    /// Get the number of function arguments for the given function value.
-    pub fn args(&self) -> usize {
-        unsafe { LLVMCountParams(self.value_ref()) as usize }
-    }
-
-    /// Get a value reference for the function argument at index `idx`.
-    ///
-    /// # Panics
-    ///
-    /// Panics if LLVM API returns a `null` pointer or indexed out of bounds.
-    pub fn arg(&self, idx: usize) -> Value<'llvm> {
-        assert!(idx < self.args());
-
-        let value_ref = unsafe { LLVMGetParam(self.value_ref(), idx as libc::c_uint) };
-        Value::new(value_ref)
-    }
-
-    /// Get the number of Basic Blocks for the given function value.
-    pub fn basic_blocks(&self) -> usize {
-        unsafe { LLVMCountBasicBlocks(self.value_ref()) as usize }
-    }
-
-    /// Verify that the given function is valid.
-    pub fn verify(&self) -> bool {
-        unsafe {
-            LLVMVerifyFunction(
-                self.value_ref(),
-                LLVMVerifierFailureAction::LLVMPrintMessageAction,
-            ) == 0
-        }
-    }
-}
-
-
\ No newline at end of file diff --git a/src/llvm_kaleidoscope_rs/llvm/builder.rs.html b/src/llvm_kaleidoscope_rs/llvm/builder.rs.html new file mode 100644 index 0000000..9ac539b --- /dev/null +++ b/src/llvm_kaleidoscope_rs/llvm/builder.rs.html @@ -0,0 +1,383 @@ +builder.rs - source
  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
+
+use llvm_sys::{
+    core::{
+        LLVMBuildFAdd, LLVMBuildFCmp, LLVMBuildFMul, LLVMBuildFSub, LLVMBuildRet, LLVMBuildUIToFP,
+        LLVMCreateBuilderInContext, LLVMDisposeBuilder, LLVMPositionBuilderAtEnd,
+    },
+    prelude::{LLVMBuilderRef, LLVMValueRef},
+    LLVMRealPredicate,
+};
+
+use std::marker::PhantomData;
+
+use super::{BasicBlock, FnValue, Module, Type, Value};
+
+// Definition of LLVM C API functions using our `repr(transparent)` types.
+extern "C" {
+    fn LLVMBuildCall2(
+        arg1: LLVMBuilderRef,
+        arg2: Type<'_>,
+        Fn: FnValue<'_>,
+        Args: *mut Value<'_>,
+        NumArgs: ::libc::c_uint,
+        Name: *const ::libc::c_char,
+    ) -> LLVMValueRef;
+}
+
+/// Wrapper for a LLVM IR Builder.
+pub struct IRBuilder<'llvm> {
+    builder: LLVMBuilderRef,
+    _ctx: PhantomData<&'llvm ()>,
+}
+
+impl<'llvm> IRBuilder<'llvm> {
+    /// Create a new LLVM IR Builder with the `module`s context.
+    ///
+    /// # Panics
+    ///
+    /// Panics if creating the IR Builder fails.
+    pub fn with_ctx(module: &'llvm Module) -> IRBuilder<'llvm> {
+        let builder = unsafe { LLVMCreateBuilderInContext(module.ctx()) };
+        assert!(!builder.is_null());
+
+        IRBuilder {
+            builder,
+            _ctx: PhantomData,
+        }
+    }
+
+    /// Position the IR Builder at the end of the given Basic Block.
+    pub fn pos_at_end(&self, bb: BasicBlock<'llvm>) {
+        unsafe {
+            LLVMPositionBuilderAtEnd(self.builder, bb.0);
+        }
+    }
+
+    /// Emit a [fadd](https://llvm.org/docs/LangRef.html#fadd-instruction) instruction.
+    ///
+    /// # Panics
+    ///
+    /// Panics if LLVM API returns a `null` pointer.
+    pub fn fadd(&self, lhs: Value<'llvm>, rhs: Value<'llvm>) -> Value<'llvm> {
+        debug_assert!(lhs.is_f64(), "fadd: Expected f64 as lhs operand!");
+        debug_assert!(rhs.is_f64(), "fadd: Expected f64 as rhs operand!");
+
+        let value_ref = unsafe {
+            LLVMBuildFAdd(
+                self.builder,
+                lhs.value_ref(),
+                rhs.value_ref(),
+                b"fadd\0".as_ptr().cast(),
+            )
+        };
+        Value::new(value_ref)
+    }
+
+    /// Emit a [fsub](https://llvm.org/docs/LangRef.html#fsub-instruction) instruction.
+    ///
+    /// # Panics
+    ///
+    /// Panics if LLVM API returns a `null` pointer.
+    pub fn fsub(&self, lhs: Value<'llvm>, rhs: Value<'llvm>) -> Value<'llvm> {
+        debug_assert!(lhs.is_f64(), "fsub: Expected f64 as lhs operand!");
+        debug_assert!(rhs.is_f64(), "fsub: Expected f64 as rhs operand!");
+
+        let value_ref = unsafe {
+            LLVMBuildFSub(
+                self.builder,
+                lhs.value_ref(),
+                rhs.value_ref(),
+                b"fsub\0".as_ptr().cast(),
+            )
+        };
+        Value::new(value_ref)
+    }
+
+    /// Emit a [fmul](https://llvm.org/docs/LangRef.html#fmul-instruction) instruction.
+    ///
+    /// # Panics
+    ///
+    /// Panics if LLVM API returns a `null` pointer.
+    pub fn fmul(&self, lhs: Value<'llvm>, rhs: Value<'llvm>) -> Value<'llvm> {
+        debug_assert!(lhs.is_f64(), "fmul: Expected f64 as lhs operand!");
+        debug_assert!(rhs.is_f64(), "fmul: Expected f64 as rhs operand!");
+
+        let value_ref = unsafe {
+            LLVMBuildFMul(
+                self.builder,
+                lhs.value_ref(),
+                rhs.value_ref(),
+                b"fmul\0".as_ptr().cast(),
+            )
+        };
+        Value::new(value_ref)
+    }
+
+    /// Emit a [fcmult](https://llvm.org/docs/LangRef.html#fcmp-instruction) instruction.
+    ///
+    /// # Panics
+    ///
+    /// Panics if LLVM API returns a `null` pointer.
+    pub fn fcmpult(&self, lhs: Value<'llvm>, rhs: Value<'llvm>) -> Value<'llvm> {
+        debug_assert!(lhs.is_f64(), "fcmplt: Expected f64 as lhs operand!");
+        debug_assert!(rhs.is_f64(), "fcmplt: Expected f64 as rhs operand!");
+
+        let value_ref = unsafe {
+            LLVMBuildFCmp(
+                self.builder,
+                LLVMRealPredicate::LLVMRealULT,
+                lhs.value_ref(),
+                rhs.value_ref(),
+                b"fcmplt\0".as_ptr().cast(),
+            )
+        };
+        Value::new(value_ref)
+    }
+
+    /// Emit a [uitofp](https://llvm.org/docs/LangRef.html#uitofp-to-instruction) instruction.
+    ///
+    /// # Panics
+    ///
+    /// Panics if LLVM API returns a `null` pointer.
+    pub fn uitofp(&self, val: Value<'llvm>, dest_type: Type<'llvm>) -> Value<'llvm> {
+        debug_assert!(val.is_int(), "uitofp: Expected integer operand!");
+
+        let value_ref = unsafe {
+            LLVMBuildUIToFP(
+                self.builder,
+                val.value_ref(),
+                dest_type.type_ref(),
+                b"uitofp\0".as_ptr().cast(),
+            )
+        };
+        Value::new(value_ref)
+    }
+
+    /// Emit a [call](https://llvm.org/docs/LangRef.html#call-instruction) instruction.
+    ///
+    /// # Panics
+    ///
+    /// Panics if LLVM API returns a `null` pointer.
+    pub fn call(&self, fn_value: FnValue<'llvm>, args: &mut [Value<'llvm>]) -> Value<'llvm> {
+        let value_ref = unsafe {
+            LLVMBuildCall2(
+                self.builder,
+                fn_value.ret_type(),
+                fn_value,
+                args.as_mut_ptr(),
+                args.len() as libc::c_uint,
+                b"call\0".as_ptr().cast(),
+            )
+        };
+        Value::new(value_ref)
+    }
+
+    /// Emit a [ret](https://llvm.org/docs/LangRef.html#ret-instruction) instruction.
+    ///
+    /// # Panics
+    ///
+    /// Panics if LLVM API returns a `null` pointer.
+    pub fn ret(&self, ret: Value<'llvm>) {
+        let ret = unsafe { LLVMBuildRet(self.builder, ret.value_ref()) };
+        assert!(!ret.is_null());
+    }
+}
+
+impl Drop for IRBuilder<'_> {
+    fn drop(&mut self) {
+        unsafe { LLVMDisposeBuilder(self.builder) }
+    }
+}
+
+
+ + \ No newline at end of file diff --git a/src/llvm_kaleidoscope_rs/llvm/lljit.rs.html b/src/llvm_kaleidoscope_rs/llvm/lljit.rs.html new file mode 100644 index 0000000..20420f8 --- /dev/null +++ b/src/llvm_kaleidoscope_rs/llvm/lljit.rs.html @@ -0,0 +1,307 @@ +lljit.rs - source
  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
+
+use llvm_sys::orc2::{
+    lljit::{
+        LLVMOrcCreateLLJIT, LLVMOrcLLJITAddLLVMIRModuleWithRT, LLVMOrcLLJITGetGlobalPrefix,
+        LLVMOrcLLJITGetMainJITDylib, LLVMOrcLLJITLookup, LLVMOrcLLJITRef,
+    },
+    LLVMOrcCreateDynamicLibrarySearchGeneratorForProcess, LLVMOrcDefinitionGeneratorRef,
+    LLVMOrcJITDylibAddGenerator, LLVMOrcJITDylibCreateResourceTracker, LLVMOrcJITDylibRef,
+    LLVMOrcReleaseResourceTracker, LLVMOrcResourceTrackerRef, LLVMOrcResourceTrackerRemove,
+};
+
+use std::convert::TryFrom;
+use std::marker::PhantomData;
+
+use super::{Error, Module};
+use crate::SmallCStr;
+
+/// Marker trait to constrain function signatures that can be looked up in the JIT.
+pub trait JitFn {}
+
+impl JitFn for unsafe extern "C" fn() -> f64 {}
+
+pub struct LLJit {
+    jit: LLVMOrcLLJITRef,
+    dylib: LLVMOrcJITDylibRef,
+}
+
+impl LLJit {
+    /// Create a new LLJit instance.
+    ///
+    /// # Panics
+    ///
+    /// Panics if LLVM API returns a `null` pointer or an error.
+    pub fn new() -> LLJit {
+        let (jit, dylib) = unsafe {
+            let mut jit = std::ptr::null_mut();
+            let err = LLVMOrcCreateLLJIT(
+                &mut jit as _,
+                std::ptr::null_mut(), /* builder: nullptr -> default */
+            );
+
+            if let Some(err) = Error::from(err) {
+                panic!("Error: {}", err.as_str());
+            }
+
+            let dylib = LLVMOrcLLJITGetMainJITDylib(jit);
+            assert!(!dylib.is_null());
+
+            (jit, dylib)
+        };
+
+        LLJit { jit, dylib }
+    }
+
+    /// Add an LLVM IR module to the JIT. Return a [`ResourceTracker`], which when dropped, will
+    /// remove the code of the LLVM IR module from the JIT.
+    ///
+    /// # Panics
+    ///
+    /// Panics if LLVM API returns a `null` pointer or an error.
+    pub fn add_module(&self, module: Module) -> ResourceTracker<'_> {
+        let tsmod = module.into_raw_thread_safe_module();
+
+        let rt = unsafe {
+            let rt = LLVMOrcJITDylibCreateResourceTracker(self.dylib);
+            let err = LLVMOrcLLJITAddLLVMIRModuleWithRT(self.jit, rt, tsmod);
+
+            if let Some(err) = Error::from(err) {
+                panic!("Error: {}", err.as_str());
+            }
+
+            rt
+        };
+
+        ResourceTracker::new(rt)
+    }
+
+    /// Find the symbol with the name `sym` in the JIT.
+    ///
+    /// # Panics
+    ///
+    /// Panics if the symbol is not found in the JIT.
+    pub fn find_symbol<F: JitFn>(&self, sym: &str) -> F {
+        let sym =
+            SmallCStr::try_from(sym).expect("Failed to convert 'sym' argument to small C string!");
+
+        unsafe {
+            let mut addr = 0u64;
+            let err = LLVMOrcLLJITLookup(self.jit, &mut addr as _, sym.as_ptr());
+
+            if let Some(err) = Error::from(err) {
+                panic!("Error: {}", err.as_str());
+            }
+
+            debug_assert_eq!(core::mem::size_of_val(&addr), core::mem::size_of::<F>());
+            std::mem::transmute_copy(&addr)
+        }
+    }
+
+    /// Enable lookup of dynamic symbols available in the current process from the JIT.
+    ///
+    /// # Panics
+    ///
+    /// Panics if LLVM API returns an error.
+    pub fn enable_process_symbols(&self) {
+        unsafe {
+            let mut proc_syms_gen: LLVMOrcDefinitionGeneratorRef = std::ptr::null_mut();
+            let err = LLVMOrcCreateDynamicLibrarySearchGeneratorForProcess(
+                &mut proc_syms_gen as _,
+                self.global_prefix(),
+                None,                 /* filter */
+                std::ptr::null_mut(), /* filter ctx */
+            );
+
+            if let Some(err) = Error::from(err) {
+                panic!("Error: {}", err.as_str());
+            }
+
+            LLVMOrcJITDylibAddGenerator(self.dylib, proc_syms_gen);
+        }
+    }
+
+    /// Return the global prefix character according to the LLJITs data layout.
+    fn global_prefix(&self) -> libc::c_char {
+        unsafe { LLVMOrcLLJITGetGlobalPrefix(self.jit) }
+    }
+}
+
+/// A resource handle to code added to an [`LLJit`] instance. When a `ResourceTracker` handle is
+/// dropped, the code corresponding to the handle will be removed from the JIT.
+pub struct ResourceTracker<'jit>(LLVMOrcResourceTrackerRef, PhantomData<&'jit ()>);
+
+impl<'jit> ResourceTracker<'jit> {
+    fn new(rt: LLVMOrcResourceTrackerRef) -> ResourceTracker<'jit> {
+        assert!(!rt.is_null());
+        ResourceTracker(rt, PhantomData)
+    }
+}
+
+impl Drop for ResourceTracker<'_> {
+    fn drop(&mut self) {
+        unsafe {
+            let err = LLVMOrcResourceTrackerRemove(self.0);
+
+            if let Some(err) = Error::from(err) {
+                panic!("Error: {}", err.as_str());
+            }
+
+            LLVMOrcReleaseResourceTracker(self.0);
+        };
+    }
+}
+
+
+ + \ No newline at end of file diff --git a/src/llvm_kaleidoscope_rs/llvm/mod.rs.html b/src/llvm_kaleidoscope_rs/llvm/mod.rs.html new file mode 100644 index 0000000..d6eb8b2 --- /dev/null +++ b/src/llvm_kaleidoscope_rs/llvm/mod.rs.html @@ -0,0 +1,161 @@ +mod.rs - source
 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
+
+//! Safe wrapper around the LLVM C API.
+//!
+//! References returned from the LLVM API are tied to the `'llvm` lifetime which is bound to the
+//! context where the objects are created in.
+//! We do not offer wrappers to remove or delete any objects in the context and therefore all the
+//! references will be valid for the liftime of the context.
+//!
+//! For the scope of this tutorial we mainly use assertions to validate the results from the LLVM
+//! API calls.
+
+use llvm_sys::{
+    core::LLVMShutdown,
+    error::{LLVMDisposeErrorMessage, LLVMErrorRef, LLVMGetErrorMessage},
+    prelude::LLVMBasicBlockRef,
+    target::{
+        LLVM_InitializeNativeAsmParser, LLVM_InitializeNativeAsmPrinter,
+        LLVM_InitializeNativeTarget,
+    },
+};
+
+use std::ffi::CStr;
+use std::marker::PhantomData;
+
+mod builder;
+mod lljit;
+mod module;
+mod pass_manager;
+mod type_;
+mod value;
+
+pub use builder::IRBuilder;
+pub use lljit::{LLJit, ResourceTracker};
+pub use module::Module;
+pub use pass_manager::FunctionPassManager;
+pub use type_::Type;
+pub use value::{FnValue, Value};
+
+/// Wrapper for a LLVM Basic Block.
+#[derive(Copy, Clone)]
+pub struct BasicBlock<'llvm>(LLVMBasicBlockRef, PhantomData<&'llvm ()>);
+
+struct Error<'llvm>(&'llvm mut libc::c_char);
+
+impl<'llvm> Error<'llvm> {
+    fn from(err: LLVMErrorRef) -> Option<Error<'llvm>> {
+        (!err.is_null()).then(|| Error(unsafe { &mut *LLVMGetErrorMessage(err) }))
+    }
+
+    fn as_str(&self) -> &str {
+        unsafe { CStr::from_ptr(self.0) }
+            .to_str()
+            .expect("Expected valid UTF8 string from LLVM API")
+    }
+}
+
+impl Drop for Error<'_> {
+    fn drop(&mut self) {
+        unsafe {
+            LLVMDisposeErrorMessage(self.0 as *mut libc::c_char);
+        }
+    }
+}
+
+/// Initialize native target for corresponding to host (useful for jitting).
+pub fn initialize_native_taget() {
+    unsafe {
+        assert_eq!(LLVM_InitializeNativeTarget(), 0);
+        assert_eq!(LLVM_InitializeNativeAsmParser(), 0);
+        assert_eq!(LLVM_InitializeNativeAsmPrinter(), 0);
+    }
+}
+
+/// Deallocate and destroy all "ManagedStatic" variables.
+pub fn shutdown() {
+    unsafe {
+        LLVMShutdown();
+    };
+}
+
+
+ + \ No newline at end of file diff --git a/src/llvm_kaleidoscope_rs/llvm/module.rs.html b/src/llvm_kaleidoscope_rs/llvm/module.rs.html new file mode 100644 index 0000000..be37a0b --- /dev/null +++ b/src/llvm_kaleidoscope_rs/llvm/module.rs.html @@ -0,0 +1,397 @@ +module.rs - source
  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
+
+use llvm_sys::{
+    core::{
+        LLVMAddFunction, LLVMAppendBasicBlockInContext, LLVMDisposeModule, LLVMDoubleTypeInContext,
+        LLVMDumpModule, LLVMGetNamedFunction, LLVMModuleCreateWithNameInContext,
+    },
+    orc2::{
+        LLVMOrcCreateNewThreadSafeContext, LLVMOrcCreateNewThreadSafeModule,
+        LLVMOrcDisposeThreadSafeContext, LLVMOrcThreadSafeContextGetContext,
+        LLVMOrcThreadSafeContextRef, LLVMOrcThreadSafeModuleRef,
+    },
+    prelude::{LLVMBool, LLVMContextRef, LLVMModuleRef, LLVMTypeRef},
+    LLVMTypeKind,
+};
+
+use std::convert::TryFrom;
+use std::marker::PhantomData;
+
+use super::{BasicBlock, FnValue, Type};
+use crate::SmallCStr;
+
+// Definition of LLVM C API functions using our `repr(transparent)` types.
+extern "C" {
+    fn LLVMFunctionType(
+        ReturnType: Type<'_>,
+        ParamTypes: *mut Type<'_>,
+        ParamCount: ::libc::c_uint,
+        IsVarArg: LLVMBool,
+    ) -> LLVMTypeRef;
+}
+
+/// Wrapper for a LLVM Module with its own LLVM Context.
+pub struct Module {
+    tsctx: LLVMOrcThreadSafeContextRef,
+    ctx: LLVMContextRef,
+    module: LLVMModuleRef,
+}
+
+impl<'llvm> Module {
+    /// Create a new Module instance.
+    ///
+    /// # Panics
+    ///
+    /// Panics if creating the context or the module fails.
+    pub fn new() -> Self {
+        let (tsctx, ctx, module) = unsafe {
+            // We generate a thread safe context because we are going to jit this IR module and
+            // there is no method to create a thread safe context wrapper from an existing context
+            // reference (at the time of writing this).
+            //
+            // ThreadSafeContext has shared ownership (start with ref count 1).
+            // We must explicitly dispose our reference (dec ref count).
+            let tc = LLVMOrcCreateNewThreadSafeContext();
+            assert!(!tc.is_null());
+
+            let c = LLVMOrcThreadSafeContextGetContext(tc);
+            let m = LLVMModuleCreateWithNameInContext(b"module\0".as_ptr().cast(), c);
+            assert!(!c.is_null() && !m.is_null());
+            (tc, c, m)
+        };
+
+        Module { tsctx, ctx, module }
+    }
+
+    /// Get the raw LLVM context reference.
+    #[inline]
+    pub(super) fn ctx(&self) -> LLVMContextRef {
+        self.ctx
+    }
+
+    /// Get the raw LLVM module reference.
+    #[inline]
+    pub(super) fn module(&self) -> LLVMModuleRef {
+        self.module
+    }
+
+    /// Consume the module and turn in into a raw LLVM ThreadSafeModule reference.
+    ///
+    /// If ownership of the raw reference is not transferred (eg to the JIT), memory will be leaked
+    /// in case the reference is disposed explicitly with LLVMOrcDisposeThreadSafeModule.
+    #[inline]
+    pub(super) fn into_raw_thread_safe_module(mut self) -> LLVMOrcThreadSafeModuleRef {
+        let m = std::mem::replace(&mut self.module, std::ptr::null_mut());
+
+        // ThreadSafeModule has unique ownership.
+        // Takes ownership of module and increments ThreadSafeContext ref count.
+        //
+        // We must not reference/dispose `m` after this call, but we need to dispose our `tsctx`
+        // reference.
+        let tm = unsafe { LLVMOrcCreateNewThreadSafeModule(m, self.tsctx) };
+        assert!(!tm.is_null());
+
+        tm
+    }
+
+    /// Dump LLVM IR emitted into the Module to stdout.
+    pub fn dump(&self) {
+        unsafe { LLVMDumpModule(self.module) };
+    }
+
+    /// Get a type reference representing a `f64` float.
+    ///
+    /// # Panics
+    ///
+    /// Panics if LLVM API returns a `null` pointer.
+    pub fn type_f64(&self) -> Type<'llvm> {
+        let type_ref = unsafe { LLVMDoubleTypeInContext(self.ctx) };
+        Type::new(type_ref)
+    }
+
+    /// Get a type reference representing a `fn(args) -> ret` function.
+    ///
+    /// # Panics
+    ///
+    /// Panics if LLVM API returns a `null` pointer.
+    pub fn type_fn(&'llvm self, args: &mut [Type<'llvm>], ret: Type<'llvm>) -> Type<'llvm> {
+        let type_ref = unsafe {
+            LLVMFunctionType(
+                ret,
+                args.as_mut_ptr(),
+                args.len() as libc::c_uint,
+                0, /* IsVarArg */
+            )
+        };
+        Type::new(type_ref)
+    }
+
+    /// Add a function with the given `name` and `fn_type` to the module and return a value
+    /// reference representing the function.
+    ///
+    /// # Panics
+    ///
+    /// Panics if LLVM API returns a `null` pointer or `name` could not be converted to a
+    /// [`SmallCStr`].
+    pub fn add_fn(&'llvm self, name: &str, fn_type: Type<'llvm>) -> FnValue<'llvm> {
+        debug_assert_eq!(
+            fn_type.kind(),
+            LLVMTypeKind::LLVMFunctionTypeKind,
+            "Expected a function type when adding a function!"
+        );
+
+        let name = SmallCStr::try_from(name)
+            .expect("Failed to convert 'name' argument to small C string!");
+
+        let value_ref = unsafe { LLVMAddFunction(self.module, name.as_ptr(), fn_type.type_ref()) };
+        FnValue::new(value_ref)
+    }
+
+    /// Get a function value reference to the function with the given `name` if it was previously
+    /// added to the module with [`add_fn`][Module::add_fn].
+    ///
+    /// # Panics
+    ///
+    /// Panics if `name` could not be converted to a [`SmallCStr`].
+    pub fn get_fn(&'llvm self, name: &str) -> Option<FnValue<'llvm>> {
+        let name = SmallCStr::try_from(name)
+            .expect("Failed to convert 'name' argument to small C string!");
+
+        let value_ref = unsafe { LLVMGetNamedFunction(self.module, name.as_ptr()) };
+
+        (!value_ref.is_null()).then(|| FnValue::new(value_ref))
+    }
+
+    /// Append a Basic Block to the end of the function referenced by the value reference
+    /// `fn_value`.
+    ///
+    /// # Panics
+    ///
+    /// Panics if LLVM API returns a `null` pointer.
+    pub fn append_basic_block(&'llvm self, fn_value: FnValue<'llvm>) -> BasicBlock<'llvm> {
+        let block = unsafe {
+            LLVMAppendBasicBlockInContext(
+                self.ctx,
+                fn_value.value_ref(),
+                b"block\0".as_ptr().cast(),
+            )
+        };
+        assert!(!block.is_null());
+
+        BasicBlock(block, PhantomData)
+    }
+}
+
+impl Drop for Module {
+    fn drop(&mut self) {
+        unsafe {
+            // In case we turned the module into a ThreadSafeModule, we must not dispose the module
+            // reference because ThreadSafeModule took ownership!
+            if !self.module.is_null() {
+                LLVMDisposeModule(self.module);
+            }
+
+            // Dispose ThreadSafeContext reference (dec ref count) in any case.
+            LLVMOrcDisposeThreadSafeContext(self.tsctx);
+        }
+    }
+}
+
+
+ + \ No newline at end of file diff --git a/src/llvm_kaleidoscope_rs/llvm/pass_manager.rs.html b/src/llvm_kaleidoscope_rs/llvm/pass_manager.rs.html new file mode 100644 index 0000000..ab73029 --- /dev/null +++ b/src/llvm_kaleidoscope_rs/llvm/pass_manager.rs.html @@ -0,0 +1,155 @@ +pass_manager.rs - source
 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
+
+use llvm_sys::{
+    core::{
+        LLVMCreateFunctionPassManagerForModule, LLVMDisposePassManager,
+        LLVMInitializeFunctionPassManager, LLVMRunFunctionPassManager,
+    },
+    prelude::LLVMPassManagerRef,
+    transforms::{
+        instcombine::LLVMAddInstructionCombiningPass,
+        scalar::{LLVMAddCFGSimplificationPass, LLVMAddNewGVNPass, LLVMAddReassociatePass},
+    },
+};
+
+use std::marker::PhantomData;
+
+use super::{FnValue, Module};
+
+/// Wrapper for a LLVM Function PassManager (legacy).
+pub struct FunctionPassManager<'llvm> {
+    fpm: LLVMPassManagerRef,
+    _ctx: PhantomData<&'llvm ()>,
+}
+
+impl<'llvm> FunctionPassManager<'llvm> {
+    /// Create a new Function PassManager with the following optimization passes
+    /// - InstructionCombiningPass
+    /// - ReassociatePass
+    /// - NewGVNPass
+    /// - CFGSimplificationPass
+    ///
+    /// The list of selected optimization passes is taken from the tutorial chapter [LLVM
+    /// Optimization Passes](https://llvm.org/docs/tutorial/MyFirstLanguageFrontend/LangImpl04.html#id3).
+    pub fn with_ctx(module: &'llvm Module) -> FunctionPassManager<'llvm> {
+        let fpm = unsafe {
+            // Borrows module reference.
+            LLVMCreateFunctionPassManagerForModule(module.module())
+        };
+        assert!(!fpm.is_null());
+
+        unsafe {
+            // Do simple "peephole" optimizations and bit-twiddling optzns.
+            LLVMAddInstructionCombiningPass(fpm);
+            // Reassociate expressions.
+            LLVMAddReassociatePass(fpm);
+            // Eliminate Common SubExpressions.
+            LLVMAddNewGVNPass(fpm);
+            // Simplify the control flow graph (deleting unreachable blocks, etc).
+            LLVMAddCFGSimplificationPass(fpm);
+
+            let fail = LLVMInitializeFunctionPassManager(fpm);
+            assert_eq!(fail, 0);
+        }
+
+        FunctionPassManager {
+            fpm,
+            _ctx: PhantomData,
+        }
+    }
+
+    /// Run the optimization passes registered with the Function PassManager on the function
+    /// referenced by `fn_value`.
+    pub fn run(&'llvm self, fn_value: FnValue<'llvm>) {
+        unsafe {
+            // Returns 1 if any of the passes modified the function, false otherwise.
+            LLVMRunFunctionPassManager(self.fpm, fn_value.value_ref());
+        }
+    }
+}
+
+impl Drop for FunctionPassManager<'_> {
+    fn drop(&mut self) {
+        unsafe {
+            LLVMDisposePassManager(self.fpm);
+        }
+    }
+}
+
+
+ + \ No newline at end of file diff --git a/src/llvm_kaleidoscope_rs/llvm/type_.rs.html b/src/llvm_kaleidoscope_rs/llvm/type_.rs.html new file mode 100644 index 0000000..89e332a --- /dev/null +++ b/src/llvm_kaleidoscope_rs/llvm/type_.rs.html @@ -0,0 +1,121 @@ +type_.rs - source
 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
+
+use llvm_sys::{
+    core::{LLVMConstReal, LLVMDumpType, LLVMGetTypeKind},
+    prelude::LLVMTypeRef,
+    LLVMTypeKind,
+};
+
+use std::marker::PhantomData;
+
+use super::Value;
+
+/// Wrapper for a LLVM Type Reference.
+#[derive(Copy, Clone)]
+#[repr(transparent)]
+pub struct Type<'llvm>(LLVMTypeRef, PhantomData<&'llvm ()>);
+
+impl<'llvm> Type<'llvm> {
+    /// Create a new Type instance.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `type_ref` is a null pointer.
+    pub(super) fn new(type_ref: LLVMTypeRef) -> Self {
+        assert!(!type_ref.is_null());
+        Type(type_ref, PhantomData)
+    }
+
+    /// Get the raw LLVM type reference.
+    #[inline]
+    pub(super) fn type_ref(&self) -> LLVMTypeRef {
+        self.0
+    }
+
+    /// Get the LLVM type kind for the given type reference.
+    pub(super) fn kind(&self) -> LLVMTypeKind {
+        unsafe { LLVMGetTypeKind(self.type_ref()) }
+    }
+
+    /// Dump the LLVM Type to stdout.
+    pub fn dump(&self) {
+        unsafe { LLVMDumpType(self.type_ref()) };
+    }
+
+    /// Get a value reference representing the const `f64` value.
+    ///
+    /// # Panics
+    ///
+    /// Panics if LLVM API returns a `null` pointer.
+    pub fn const_f64(self, n: f64) -> Value<'llvm> {
+        debug_assert_eq!(
+            self.kind(),
+            LLVMTypeKind::LLVMDoubleTypeKind,
+            "Expected a double type when creating const f64 value!"
+        );
+
+        let value_ref = unsafe { LLVMConstReal(self.type_ref(), n) };
+        Value::new(value_ref)
+    }
+}
+
+
+ + \ No newline at end of file diff --git a/src/llvm_kaleidoscope_rs/llvm/value.rs.html b/src/llvm_kaleidoscope_rs/llvm/value.rs.html new file mode 100644 index 0000000..950eae0 --- /dev/null +++ b/src/llvm_kaleidoscope_rs/llvm/value.rs.html @@ -0,0 +1,341 @@ +value.rs - source
  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
+
+use llvm_sys::{
+    analysis::{LLVMVerifierFailureAction, LLVMVerifyFunction},
+    core::{
+        LLVMCountBasicBlocks, LLVMCountParams, LLVMDumpValue, LLVMGetParam, LLVMGetReturnType,
+        LLVMGetValueKind, LLVMGetValueName2, LLVMSetValueName2, LLVMTypeOf,
+    },
+    prelude::LLVMValueRef,
+    LLVMTypeKind, LLVMValueKind,
+};
+
+use std::ffi::CStr;
+use std::marker::PhantomData;
+use std::ops::Deref;
+
+use super::Type;
+
+/// Wrapper for a LLVM Value Reference.
+#[derive(Copy, Clone)]
+#[repr(transparent)]
+pub struct Value<'llvm>(LLVMValueRef, PhantomData<&'llvm ()>);
+
+impl<'llvm> Value<'llvm> {
+    /// Create a new Value instance.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `value_ref` is a null pointer.
+    pub(super) fn new(value_ref: LLVMValueRef) -> Self {
+        assert!(!value_ref.is_null());
+        Value(value_ref, PhantomData)
+    }
+
+    /// Get the raw LLVM value reference.
+    #[inline]
+    pub(super) fn value_ref(&self) -> LLVMValueRef {
+        self.0
+    }
+
+    /// Get the LLVM value kind for the given value reference.
+    pub(super) fn kind(&self) -> LLVMValueKind {
+        unsafe { LLVMGetValueKind(self.value_ref()) }
+    }
+
+    /// Dump the LLVM Value to stdout.
+    pub fn dump(&self) {
+        unsafe { LLVMDumpValue(self.value_ref()) };
+    }
+
+    /// Get a type reference representing for the given value reference.
+    ///
+    /// # Panics
+    ///
+    /// Panics if LLVM API returns a `null` pointer.
+    pub fn type_of(&self) -> Type<'llvm> {
+        let type_ref = unsafe { LLVMTypeOf(self.value_ref()) };
+        Type::new(type_ref)
+    }
+
+    /// Set the name for the given value reference.
+    ///
+    /// # Panics
+    ///
+    /// Panics if LLVM API returns a `null` pointer.
+    pub fn set_name(&self, name: &str) {
+        unsafe { LLVMSetValueName2(self.value_ref(), name.as_ptr().cast(), name.len()) };
+    }
+
+    /// Get the name for the given value reference.
+    ///
+    /// # Panics
+    ///
+    /// Panics if LLVM API returns a `null` pointer.
+    pub fn get_name(&self) -> &'llvm str {
+        let name = unsafe {
+            let mut len: libc::size_t = 0;
+            let name = LLVMGetValueName2(self.0, &mut len as _);
+            assert!(!name.is_null());
+
+            CStr::from_ptr(name)
+        };
+
+        // TODO: Does this string live for the time of the LLVM context?!
+        name.to_str()
+            .expect("Expected valid UTF8 string from LLVM API")
+    }
+
+    /// Check if value is of `f64` type.
+    pub fn is_f64(&self) -> bool {
+        self.type_of().kind() == LLVMTypeKind::LLVMDoubleTypeKind
+    }
+
+    /// Check if value is of integer type.
+    pub fn is_int(&self) -> bool {
+        self.type_of().kind() == LLVMTypeKind::LLVMIntegerTypeKind
+    }
+}
+
+/// Wrapper for a LLVM Value Reference specialized for contexts where function values are needed.
+#[derive(Copy, Clone)]
+#[repr(transparent)]
+pub struct FnValue<'llvm>(Value<'llvm>);
+
+impl<'llvm> Deref for FnValue<'llvm> {
+    type Target = Value<'llvm>;
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
+impl<'llvm> FnValue<'llvm> {
+    /// Create a new FnValue instance.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `value_ref` is a null pointer.
+    pub(super) fn new(value_ref: LLVMValueRef) -> Self {
+        let value = Value::new(value_ref);
+        debug_assert_eq!(
+            value.kind(),
+            LLVMValueKind::LLVMFunctionValueKind,
+            "Expected a fn value when constructing FnValue!"
+        );
+
+        FnValue(value)
+    }
+
+    /// Get a type reference representing the return value of the given function value.
+    ///
+    /// # Panics
+    ///
+    /// Panics if LLVM API returns a `null` pointer.
+    pub fn ret_type(&self) -> Type<'llvm> {
+        let type_ref = unsafe { LLVMGetReturnType(LLVMTypeOf(self.value_ref())) };
+        Type::new(type_ref)
+    }
+
+    /// Get the number of function arguments for the given function value.
+    pub fn args(&self) -> usize {
+        unsafe { LLVMCountParams(self.value_ref()) as usize }
+    }
+
+    /// Get a value reference for the function argument at index `idx`.
+    ///
+    /// # Panics
+    ///
+    /// Panics if LLVM API returns a `null` pointer or indexed out of bounds.
+    pub fn arg(&self, idx: usize) -> Value<'llvm> {
+        assert!(idx < self.args());
+
+        let value_ref = unsafe { LLVMGetParam(self.value_ref(), idx as libc::c_uint) };
+        Value::new(value_ref)
+    }
+
+    /// Get the number of Basic Blocks for the given function value.
+    pub fn basic_blocks(&self) -> usize {
+        unsafe { LLVMCountBasicBlocks(self.value_ref()) as usize }
+    }
+
+    /// Verify that the given function is valid.
+    pub fn verify(&self) -> bool {
+        unsafe {
+            LLVMVerifyFunction(
+                self.value_ref(),
+                LLVMVerifierFailureAction::LLVMPrintMessageAction,
+            ) == 0
+        }
+    }
+}
+
+
+ + \ No newline at end of file diff --git a/src/llvm_kaleidoscope_rs/parser.rs.html b/src/llvm_kaleidoscope_rs/parser.rs.html index 3bd0dc8..9093695 100644 --- a/src/llvm_kaleidoscope_rs/parser.rs.html +++ b/src/llvm_kaleidoscope_rs/parser.rs.html @@ -1,6 +1,4 @@ -parser.rs - source - -
  1
+parser.rs - source
  1
   2
   3
   4
@@ -481,7 +479,7 @@
 /// PrototypeAST - This class represents the "prototype" for a function,
 /// which captures its name, and its argument names (thus implicitly the number
 /// of arguments the function takes).
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Clone)]
 pub struct PrototypeAST(pub String, pub Vec<String>);
 
 /// FunctionAST - This class represents a function definition itself.
@@ -770,7 +768,7 @@
     /// Implement `std::unique_ptr<FunctionAST> ParseTopLevelExpr();` from the tutorial.
     pub fn parse_top_level_expr(&mut self) -> ParseResult<FunctionAST> {
         let e = self.parse_expression()?;
-        let proto = PrototypeAST("".into(), Vec::new());
+        let proto = PrototypeAST("__anon_expr".into(), Vec::new());
         Ok(FunctionAST(proto, e))
     }
 }
@@ -922,4 +920,6 @@
     }
 }
 
-
\ No newline at end of file +
+ + \ No newline at end of file -- cgit v1.2.3