@@ -85,6 +85,7 @@ pub struct CodeGenOptions {
85
85
pub backend : CodeGenBackend ,
86
86
pub opt_level : OptLevel ,
87
87
pub emit_debug_info : bool ,
88
+ pub emit_llvm_ir : bool ,
88
89
}
89
90
90
91
type GenFromMono < ' a > = ( CodeObject , CodeGenTiming , ExpectMetadata < ' a > ) ;
@@ -101,6 +102,7 @@ pub fn gen_from_mono_module<'a>(
101
102
) -> GenFromMono < ' a > {
102
103
let path = roc_file_path;
103
104
let debug = code_gen_options. emit_debug_info ;
105
+ let emit_llvm_ir = code_gen_options. emit_llvm_ir ;
104
106
let opt = code_gen_options. opt_level ;
105
107
106
108
match code_gen_options. backend {
@@ -120,15 +122,23 @@ pub fn gen_from_mono_module<'a>(
120
122
wasm_dev_stack_bytes,
121
123
backend_mode,
122
124
) ,
123
- CodeGenBackend :: Llvm ( backend_mode) => {
124
- gen_from_mono_module_llvm ( arena, loaded, path, target, opt, backend_mode, debug)
125
- }
125
+ CodeGenBackend :: Llvm ( backend_mode) => gen_from_mono_module_llvm (
126
+ arena,
127
+ loaded,
128
+ path,
129
+ target,
130
+ opt,
131
+ backend_mode,
132
+ debug,
133
+ emit_llvm_ir,
134
+ ) ,
126
135
}
127
136
}
128
137
129
138
// TODO how should imported modules factor into this? What if those use builtins too?
130
139
// TODO this should probably use more helper functions
131
140
// TODO make this polymorphic in the llvm functions so it can be reused for another backend.
141
+ #[ allow( clippy:: too_many_arguments) ]
132
142
fn gen_from_mono_module_llvm < ' a > (
133
143
arena : & ' a bumpalo:: Bump ,
134
144
loaded : MonomorphizedModule < ' a > ,
@@ -137,6 +147,7 @@ fn gen_from_mono_module_llvm<'a>(
137
147
opt_level : OptLevel ,
138
148
backend_mode : LlvmBackendMode ,
139
149
emit_debug_info : bool ,
150
+ emit_llvm_ir : bool ,
140
151
) -> GenFromMono < ' a > {
141
152
use crate :: target:: { self , convert_opt_level} ;
142
153
use inkwell:: attributes:: { Attribute , AttributeLoc } ;
@@ -151,9 +162,6 @@ fn gen_from_mono_module_llvm<'a>(
151
162
let context = Context :: create ( ) ;
152
163
let module = arena. alloc ( module_from_builtins ( target, & context, "app" ) ) ;
153
164
154
- // strip Zig debug stuff
155
- // module.strip_debug_info();
156
-
157
165
// mark our zig-defined builtins as internal
158
166
let app_ll_file = {
159
167
let mut temp = PathBuf :: from ( roc_file_path) ;
@@ -245,8 +253,9 @@ fn gen_from_mono_module_llvm<'a>(
245
253
246
254
env. dibuilder . finalize ( ) ;
247
255
248
- // we don't use the debug info, and it causes weird errors.
249
- module. strip_debug_info ( ) ;
256
+ if !emit_debug_info {
257
+ module. strip_debug_info ( ) ;
258
+ }
250
259
251
260
// Uncomment this to see the module's optimized LLVM instruction output:
252
261
// env.module.print_to_stderr();
@@ -265,6 +274,11 @@ fn gen_from_mono_module_llvm<'a>(
265
274
) ;
266
275
}
267
276
277
+ if emit_llvm_ir {
278
+ eprintln ! ( "Emitting LLVM IR to {}" , & app_ll_file. display( ) ) ;
279
+ module. print_to_file ( & app_ll_file) . unwrap ( ) ;
280
+ }
281
+
268
282
// Uncomment this to see the module's optimized LLVM instruction output:
269
283
// env.module.print_to_stderr();
270
284
@@ -359,65 +373,6 @@ fn gen_from_mono_module_llvm<'a>(
359
373
360
374
assert ! ( bc_to_object. status. success( ) , "{bc_to_object:#?}" ) ;
361
375
362
- MemoryBuffer :: create_from_file ( & app_o_file) . expect ( "memory buffer creation works" )
363
- } else if emit_debug_info {
364
- module. strip_debug_info ( ) ;
365
-
366
- let mut app_ll_dbg_file = PathBuf :: from ( roc_file_path) ;
367
- app_ll_dbg_file. set_extension ( "dbg.ll" ) ;
368
-
369
- let mut app_o_file = PathBuf :: from ( roc_file_path) ;
370
- app_o_file. set_extension ( "o" ) ;
371
-
372
- use std:: process:: Command ;
373
-
374
- // write the ll code to a file, so we can modify it
375
- module. print_to_file ( & app_ll_file) . unwrap ( ) ;
376
-
377
- // run the debugir https://github.com/vaivaswatha/debugir tool
378
- match Command :: new ( "debugir" )
379
- . args ( [ "-instnamer" , app_ll_file. to_str ( ) . unwrap ( ) ] )
380
- . output ( )
381
- {
382
- Ok ( _) => { }
383
- Err ( error) => {
384
- use std:: io:: ErrorKind ;
385
- match error. kind ( ) {
386
- ErrorKind :: NotFound => internal_error ! (
387
- r"I could not find the `debugir` tool on the PATH, install it from https://github.com/vaivaswatha/debugir"
388
- ) ,
389
- _ => internal_error ! ( "{:?}" , error) ,
390
- }
391
- }
392
- }
393
-
394
- use target_lexicon:: Architecture ;
395
- match target. architecture {
396
- Architecture :: X86_64
397
- | Architecture :: X86_32 ( _)
398
- | Architecture :: Aarch64 ( _)
399
- | Architecture :: Wasm32 => {
400
- // write the .o file. Note that this builds the .o for the local machine,
401
- // and ignores the `target_machine` entirely.
402
- //
403
- // different systems name this executable differently, so we shotgun for
404
- // the most common ones and then give up.
405
- let ll_to_object = Command :: new ( "llc" )
406
- . args ( [
407
- "-relocation-model=pic" ,
408
- "-filetype=obj" ,
409
- app_ll_dbg_file. to_str ( ) . unwrap ( ) ,
410
- "-o" ,
411
- app_o_file. to_str ( ) . unwrap ( ) ,
412
- ] )
413
- . output ( )
414
- . unwrap ( ) ;
415
-
416
- assert ! ( ll_to_object. stderr. is_empty( ) , "{ll_to_object:#?}" ) ;
417
- }
418
- _ => unreachable ! ( ) ,
419
- }
420
-
421
376
MemoryBuffer :: create_from_file ( & app_o_file) . expect ( "memory buffer creation works" )
422
377
} else {
423
378
// Emit the .o file
@@ -1326,6 +1281,7 @@ pub fn build_str_test<'a>(
1326
1281
backend : CodeGenBackend :: Llvm ( LlvmBackendMode :: Binary ) ,
1327
1282
opt_level : OptLevel :: Normal ,
1328
1283
emit_debug_info : false ,
1284
+ emit_llvm_ir : false ,
1329
1285
} ;
1330
1286
1331
1287
let emit_timings = false ;
0 commit comments