Comments (12)
Hi, thanks for reporting this issue!
I'm not quite sure why this is happening - it seems like rustc doesn't allow for a name field at all and just passes in a null ptr but trying that didn't help me either. I will have to dig deeper into it.
Also worth noting that Inkwell only supports LLVM 3.7 officially at the moment (I have a PR to get multiple version support going, but it's turning out to be a massive pain), though regardless I am seeing this issue in 3.7 as well.
Sorry that this is blocking you! In the mean time I bet you could create a global i8 pointer to achieve the same effect? A C/LLVM string is just that (and maybe null terminated)
from inkwell.
That would work, though how would I fill the global with my intended value? Glancing at the API docs it seems that there's a barrier between rust types like str, and values created from them, and anything in inkwell that has an impl of BasicValue. So I'm not sure how I would translate between the two
from inkwell.
I think something like this should work:
let context = Context::create();
let module = context.create_module("my_mod");
let my_str = "Hello, World";
let i8_type = context.i8_type();
let i8_array_type = i8_type.array_type(my_str.len() as u32);
let global_string = module.add_global(&i8_array_type, Some(AddressSpace::Generic), "message");
let mut chars = Vec::with_capacity(my_str.len()); // Edit: Not sure if len is unicode chars or bytes, but I'm assuming it's bytes here
for chr in my_str.bytes() {
chars.push(i8_type.const_int(chr as u64, false));
}
let const_str_array = i8_array_type.const_array(chars.as_ref());
global_string.set_initializer(&const_str_array);
Alternatively, you could put it behind an i8_ptr_type
but then you should be sure to to have a null byte at the end so you know when the pointer ends. (This is essentially a C String - the above example is closer to what rust does)
from inkwell.
It seems like I can't use an array because the signature of printf as I have it at the moment expects variadic i8*, and that type doesn't match [i8 x 13]*. I know how I can get a null PointerValue, but how can I fill that with the actual string I'm trying to work with?
from inkwell.
In my edit to my previous comment, I mentioned you could just use almost identical code but with an i8_pointer_type, and as long as you be sure to add a null byte('\0'
) it should work. Might need to do a store or something, though. I'll try and whip up an example tomorrow
from inkwell.
Okay, so, I don't have a full example but I updated the build_cast method after reading some LLVM docs and you should be able to cast an array pointer to an i8 pointer:
let i8_ptr_type = builder.build_cast(InstructionOpcode::BitCast, &const_str_array, &i8_ptr_type);
Though I think const_str_array
is a [n x i8]
and needs to be a [n x i8]*
in which case you might need to go one pointer level higher when creating it
from inkwell.
@Redrield This seems to be an LLVM specific issue. This happens because the global string needs to be created in a function (I don't really get why, since it's global, not local...) but see this SO post which seems to showcase an identical problem: https://stackoverflow.com/questions/8966890/createglobalstringptr-crashes-when-i-dont-create-method-basic-block-for-main
I'm going to spend some more time thinking about whether or not there's anything in inkwell we can do about it... but I might just have to end up closing this issue as it's LLVM specific (Maybe I'll end up collecting a list of LLVM gotchas...). To get the code in your initial post you'd have to move the global string creation to after the main function is generated like so:
fn main() {
Target::initialize_native(&InitializationConfig::default()).unwrap();
let ctx = Context::create();
let module = ctx.create_module("program");
let builder = ctx.create_builder();
let str_type = ctx.i8_type().ptr_type(AddressSpace::Generic);
let i32_type = ctx.i32_type();
let printf_type = i32_type.fn_type(&[&str_type], true);
let printf = module.add_function("printf", &printf_type, Some(&Linkage::ExternalLinkage));
let main_fn_type = i32_type.fn_type(&[&i32_type, &str_type.ptr_type(AddressSpace::Generic)], false);
let main_fn = module.add_function("main", &main_fn_type, None);
let block = ctx.append_basic_block(&main_fn, "entry");
builder.position_at_end(&block);
let global = builder.build_global_string("Hello, World!", "message");
builder.build_call(&printf, &[&global], "", false);
builder.build_return(Some(&i32_type.const_int(0, false)));
println!("{:?}", module.print_to_string());
}
from inkwell.
Maybe Inkwell should require a function value to be passed into the create string global method even if it isn't actually used... Definitely would need to document that
from inkwell.
I ended up just stealing the stuff from librustc_trans which works. Seems there they associate builders with a block directly. The way a builder is constructed makes it linked with the block it is building for, and they make new builders per function. Maybe an architectural change to that would be of use here?
from inkwell.
Dunno, seems odd since you can have multiple blocks per function, but maybe. I'll have to take a look at librustc_trans.
from inkwell.
It looks like librustc_trans also supports creating a builder without a function, hmm: https://github.com/rust-lang/rust/blob/master/src/librustc_codegen_llvm/builder.rs#L61-L84
from inkwell.
@TheDan64 "This seems to be an LLVM specific issue. This happens because the global string needs to be created in a function"
The global needs to be created in a Module, though not a Function. The way the IRBuilder finds the module is by looking at the IRBuilder's current position and walking parents from BasicBlock->Function->Module. When you haven't set the position yet, it will perform undefined behaviour in C++ land as it starts with no basic block.
IMO it's pretty uncommon to use an IRBuilder without setting its position first. If you want to support it, the builder will create detached instructions (see #93) and only some of its methods are safe for that. All the type and constant (non-global) creation are. Some, like, build_malloc and build_global_string won't be. Or you could just mandate that IRBuilders must have a position at all times instead of trying to split the functions by whether they support creating detached IR.
Unfortunately, either way, you can't use the IRBuilder's utility functions like creating a global string until after you've created a basic block somewhere in the module you want to create your string in. (Really, LLVM should split this up and expose the utility for creating a string in a module, and then have IRBuilder use that.)
from inkwell.
Related Issues (20)
- Add llvm-sys linkage flags
- Question: How to use LLVM `type`? HOT 5
- More examples? HOT 6
- Question: Is there a way to get the BasicValueEnum from the name of the instruction. HOT 6
- Question: What does `get_insert_block` returns. HOT 2
- Question: How can I get all defined structures? HOT 2
- Question: How to get the size of a type during LLVM generation? HOT 4
- Add `typos` to CI
- Create new fine-grained enum for `build_cast` HOT 1
- How to link library to jit? HOT 2
- Support llvm 17 HOT 1
- Add support for `global_ctor` HOT 4
- Add support for `global_ctor` HOT 3
- ORC support HOT 1
- Const struct member access HOT 1
- Segfault when using `module.create_jit_execution_engine()` HOT 2
- Named keys on debug struct types HOT 1
- Adding get_allocated_type, is_terminator and is_conditional to InstructionValue HOT 1
- Add a function to add llvm ir directly HOT 1
- after importing LLVM IR, a segmentation fault occurs when calling its internal method HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from inkwell.