Skip to content

const_to_int of const_gep results in broken getelementptr call, const_gep segfaults with i64 indexes #213

Description

@djozis

Describe the Bug
I'm not sure if these are related or not. If not, I apologize for the two-for-one.
const_gep followed by const_to_int results in the gep getting butchered (wrong type and an index goes missing in this example). Also const_gep with i64 values segfaults.

To Reproduce
Run this. See comments in code for details.

use inkwell::context::Context;
use inkwell::AddressSpace;

fn main() {
    let context = Context::create();
    let module = context.create_module("my_module");
    let i32_type = context.i32_type();
    let i32_ptr_type = context.i32_type().ptr_type(AddressSpace::Generic);

    let struct_type = context.struct_type(&[i32_type.into(), i32_type.into()], false);

    unsafe { // just being lazy with gep calls.
        let init = struct_type.ptr_type(AddressSpace::Generic).const_zero().const_gep(&[
            i32_type.const_int(0, false).into(),
            i32_type.const_int(1, false).into()
        ]);

        let a = module.add_global(i32_ptr_type, Some(AddressSpace::Generic), "a");
        a.set_constant(true);
        a.set_initializer(&init);
        // Good, normal:
        // @a = constant i32* getelementptr ({ i32, i32 }, { i32, i32 }* null, i32 0, i32 1)

        let b = module.add_global(i32_type, Some(AddressSpace::Generic), "b");
        b.set_constant(true);
        b.set_initializer(&init.const_to_int(i32_type));
        // Why is GEP only passed one index? Where did my 0 go? -----------V
        // @b = constant i32 ptrtoint (i32* getelementptr (i32, i32* null, i32 1) to i32)
        // Types are wrong?^             ^

        let c = module.add_global(i32_ptr_type, Some(AddressSpace::Generic), "c");
        c.set_constant(true);
        c.set_initializer(&init);
        // Same as a - just showing the initializer isn't mutated or unusable or anything.
        // @c = constant i32* getelementptr ({ i32, i32 }, { i32, i32 }* null, i32 0, i32 1)
    }

    println!("{}", module.print_to_string().to_string());
    // This is where I got the above samples. Here's the whole output:
    // ; ModuleID = 'my_module'
    // source_filename = "my_module"
    //
    // @a = constant i32* getelementptr ({ i32, i32 }, { i32, i32 }* null, i32 0, i32 1)
    // @b = constant i32 ptrtoint (i32* getelementptr (i32, i32* null, i32 1) to i32)
    // @c = constant i32* getelementptr ({ i32, i32 }, { i32, i32 }* null, i32 0, i32 1)

    module.verify().unwrap();
    // No errors.

    // This instantly segfaults. Seems using i64s is not valid for the indexing.
    unsafe {
        struct_type.ptr_type(AddressSpace::Generic).const_zero().const_gep(&[
            context.i64_type().const_int(0, false).into(),
            context.i64_type().const_int(1, false).into(),
        ]);
    }
}

Expected Behavior
The gep on variable b should be the same as a, just with the pointer operation as well.
Less important (to me): The program should not segfault, unless gep with i64 indexes is just invalid or something - might be my mistake. If so, maybe it should take a u32 slice reference instead for the indexes?

LLVM Version (please complete the following information):

  • LLVM version 10.0.1
  • Inkwell Branch Used: Cargo dependency configured as inkwell = { git = "https://github.com/TheDan64/inkwell", branch = "master", features = ["llvm10-0"] }

Desktop (please complete the following information):

  • OS: Windows 10

Additional Context
LLVM built from source.

In LLVM clone dir:

>git show HEAD
commit ef32c611aa214dea855364efd7ba451ec5ec3f74 (HEAD -> release/10.x, tag: llvmorg-10.0.1-rc4, tag: llvmorg-10.0.1, origin/release/10.x)

In the clone of inkwell that cargo pulled:

>git show HEAD
commit 67981a09816b705a7304aaa995e29848cb832426 (HEAD -> master, origin/master)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions