@@ -51,10 +51,11 @@ pub(crate) fn llvm_err<'a>(dcx: DiagCtxtHandle<'_>, err: LlvmError<'a>) -> Fatal
51
51
}
52
52
}
53
53
54
- fn write_output_file < ' ll > (
54
+ // SAFETY: the pass manager must come from the closure argument of `with_codegen`.
55
+ unsafe fn write_output_file < ' ll > (
55
56
dcx : DiagCtxtHandle < ' _ > ,
56
57
target : & ' ll llvm:: TargetMachine ,
57
- pm : & llvm:: PassManager < ' ll > ,
58
+ pm : * mut llvm:: PassManager < ' ll > ,
58
59
m : & ' ll llvm:: Module ,
59
60
output : & Path ,
60
61
dwo_output : Option < & Path > ,
@@ -63,39 +64,39 @@ fn write_output_file<'ll>(
63
64
verify_llvm_ir : bool ,
64
65
) -> Result < ( ) , FatalError > {
65
66
debug ! ( "write_output_file output={:?} dwo_output={:?}" , output, dwo_output) ;
66
- unsafe {
67
- let output_c = path_to_c_string ( output ) ;
68
- let dwo_output_c ;
69
- let dwo_output_ptr = if let Some ( dwo_output) = dwo_output {
70
- dwo_output_c = path_to_c_string ( dwo_output ) ;
71
- dwo_output_c . as_ptr ( )
72
- } else {
73
- std :: ptr :: null ( )
74
- } ;
75
- let result = llvm:: LLVMRustWriteOutputFile (
67
+ let output_c = path_to_c_string ( output ) ;
68
+ let dwo_output_c ;
69
+ let dwo_output_ptr = if let Some ( dwo_output ) = dwo_output {
70
+ dwo_output_c = path_to_c_string ( dwo_output) ;
71
+ dwo_output_c. as_ptr ( )
72
+ } else {
73
+ std :: ptr :: null ( )
74
+ } ;
75
+ let result = unsafe {
76
+ llvm:: LLVMRustWriteOutputFile (
76
77
target,
77
78
pm,
78
79
m,
79
80
output_c. as_ptr ( ) ,
80
81
dwo_output_ptr,
81
82
file_type,
82
83
verify_llvm_ir,
83
- ) ;
84
+ )
85
+ } ;
84
86
85
- // Record artifact sizes for self-profiling
86
- if result == llvm:: LLVMRustResult :: Success {
87
- let artifact_kind = match file_type {
88
- llvm:: FileType :: ObjectFile => "object_file" ,
89
- llvm:: FileType :: AssemblyFile => "assembly_file" ,
90
- } ;
91
- record_artifact_size ( self_profiler_ref, artifact_kind, output) ;
92
- if let Some ( dwo_file) = dwo_output {
93
- record_artifact_size ( self_profiler_ref, "dwo_file" , dwo_file) ;
94
- }
87
+ // Record artifact sizes for self-profiling
88
+ if result == llvm:: LLVMRustResult :: Success {
89
+ let artifact_kind = match file_type {
90
+ llvm:: FileType :: ObjectFile => "object_file" ,
91
+ llvm:: FileType :: AssemblyFile => "assembly_file" ,
92
+ } ;
93
+ record_artifact_size ( self_profiler_ref, artifact_kind, output) ;
94
+ if let Some ( dwo_file) = dwo_output {
95
+ record_artifact_size ( self_profiler_ref, "dwo_file" , dwo_file) ;
95
96
}
96
-
97
- result. into_result ( ) . map_err ( |( ) | llvm_err ( dcx, LlvmError :: WriteOutput { path : output } ) )
98
97
}
98
+
99
+ result. into_result ( ) . map_err ( |( ) | llvm_err ( dcx, LlvmError :: WriteOutput { path : output } ) )
99
100
}
100
101
101
102
pub ( crate ) fn create_informational_target_machine (
@@ -325,13 +326,17 @@ pub(crate) fn save_temp_bitcode(
325
326
if !cgcx. save_temps {
326
327
return ;
327
328
}
329
+ let ext = format ! ( "{name}.bc" ) ;
330
+ let cgu = Some ( & module. name [ ..] ) ;
331
+ let path = cgcx. output_filenames . temp_path_ext ( & ext, cgu) ;
332
+ write_bitcode_to_file ( module, & path)
333
+ }
334
+
335
+ fn write_bitcode_to_file ( module : & ModuleCodegen < ModuleLlvm > , path : & Path ) {
328
336
unsafe {
329
- let ext = format ! ( "{name}.bc" ) ;
330
- let cgu = Some ( & module. name [ ..] ) ;
331
- let path = cgcx. output_filenames . temp_path_ext ( & ext, cgu) ;
332
- let cstr = path_to_c_string ( & path) ;
337
+ let path = path_to_c_string ( & path) ;
333
338
let llmod = module. module_llvm . llmod ( ) ;
334
- llvm:: LLVMWriteBitcodeToFile ( llmod, cstr . as_ptr ( ) ) ;
339
+ llvm:: LLVMWriteBitcodeToFile ( llmod, path . as_ptr ( ) ) ;
335
340
}
336
341
}
337
342
@@ -661,7 +666,6 @@ pub(crate) unsafe fn optimize(
661
666
) -> Result < ( ) , FatalError > {
662
667
let _timer = cgcx. prof . generic_activity_with_arg ( "LLVM_module_optimize" , & * module. name ) ;
663
668
664
- let llmod = module. module_llvm . llmod ( ) ;
665
669
let llcx = & * module. module_llvm . llcx ;
666
670
let _handlers = DiagnosticHandlers :: new ( cgcx, dcx, llcx, module, CodegenDiagnosticsStage :: Opt ) ;
667
671
@@ -670,8 +674,7 @@ pub(crate) unsafe fn optimize(
670
674
671
675
if config. emit_no_opt_bc {
672
676
let out = cgcx. output_filenames . temp_path_ext ( "no-opt.bc" , module_name) ;
673
- let out = path_to_c_string ( & out) ;
674
- unsafe { llvm:: LLVMWriteBitcodeToFile ( llmod, out. as_ptr ( ) ) } ;
677
+ write_bitcode_to_file ( module, & out)
675
678
}
676
679
677
680
// FIXME(ZuseZ4): support SanitizeHWAddress and prevent illegal/unsupported opts
@@ -748,18 +751,18 @@ pub(crate) unsafe fn codegen(
748
751
// files for an LLVM module.
749
752
//
750
753
// Apparently each of these pass managers is a one-shot kind of
751
- // thing, so we create a new one for each type of output. The
752
- // pass manager passed to the closure should be ensured to not
753
- // escape the closure itself, and the manager should only be
754
- // used once.
755
- unsafe fn with_codegen < ' ll , F , R > (
754
+ // thing, so we create a new one for each type of output.
755
+ // The pass manager must be consumed by `LLVMRustWriteOutputFile`,
756
+ // which also takes care of freeing its memory. For details of why it's
757
+ // this way, see the C++ code of `LLVMRustWriteOutputFile`
758
+ fn with_codegen < ' ll , F , R > (
756
759
tm : & ' ll llvm:: TargetMachine ,
757
760
llmod : & ' ll llvm:: Module ,
758
761
no_builtins : bool ,
759
762
f : F ,
760
763
) -> R
761
764
where
762
- F : FnOnce ( & ' ll mut PassManager < ' ll > ) -> R ,
765
+ F : FnOnce ( * mut PassManager < ' ll > ) -> R ,
763
766
{
764
767
unsafe {
765
768
let cpm = llvm:: LLVMCreatePassManager ( ) ;
@@ -890,21 +893,19 @@ pub(crate) unsafe fn codegen(
890
893
} else {
891
894
llmod
892
895
} ;
893
- unsafe {
894
- with_codegen ( tm, llmod, config. no_builtins , |cpm| {
895
- write_output_file (
896
- dcx,
897
- tm,
898
- cpm,
899
- llmod,
900
- & path,
901
- None ,
902
- llvm:: FileType :: AssemblyFile ,
903
- & cgcx. prof ,
904
- config. verify_llvm_ir ,
905
- )
906
- } ) ?;
907
- }
896
+ with_codegen ( tm, llmod, config. no_builtins , |cpm| unsafe {
897
+ write_output_file (
898
+ dcx,
899
+ tm,
900
+ cpm,
901
+ llmod,
902
+ & path,
903
+ None ,
904
+ llvm:: FileType :: AssemblyFile ,
905
+ & cgcx. prof ,
906
+ config. verify_llvm_ir ,
907
+ )
908
+ } ) ?;
908
909
}
909
910
910
911
match config. emit_obj {
@@ -928,21 +929,19 @@ pub(crate) unsafe fn codegen(
928
929
( _, SplitDwarfKind :: Split ) => Some ( dwo_out. as_path ( ) ) ,
929
930
} ;
930
931
931
- unsafe {
932
- with_codegen ( tm, llmod, config. no_builtins , |cpm| {
933
- write_output_file (
934
- dcx,
935
- tm,
936
- cpm,
937
- llmod,
938
- & obj_out,
939
- dwo_out,
940
- llvm:: FileType :: ObjectFile ,
941
- & cgcx. prof ,
942
- config. verify_llvm_ir ,
943
- )
944
- } ) ?;
945
- }
932
+ with_codegen ( tm, llmod, config. no_builtins , |cpm| unsafe {
933
+ write_output_file (
934
+ dcx,
935
+ tm,
936
+ cpm,
937
+ llmod,
938
+ & obj_out,
939
+ dwo_out,
940
+ llvm:: FileType :: ObjectFile ,
941
+ & cgcx. prof ,
942
+ config. verify_llvm_ir ,
943
+ )
944
+ } ) ?;
946
945
}
947
946
948
947
EmitObj :: Bitcode => {
@@ -1069,24 +1068,18 @@ unsafe fn embed_bitcode(
1069
1068
{
1070
1069
// We don't need custom section flags, create LLVM globals.
1071
1070
let llconst = common:: bytes_in_context ( llcx, bitcode) ;
1072
- let llglobal = llvm:: LLVMAddGlobal (
1073
- llmod,
1074
- common:: val_ty ( llconst) ,
1075
- c"rustc.embedded.module" . as_ptr ( ) ,
1076
- ) ;
1077
- llvm:: LLVMSetInitializer ( llglobal, llconst) ;
1071
+ let llglobal =
1072
+ llvm:: add_global ( llmod, common:: val_ty ( llconst) , c"rustc.embedded.module" ) ;
1073
+ llvm:: set_initializer ( llglobal, llconst) ;
1078
1074
1079
1075
llvm:: set_section ( llglobal, bitcode_section_name ( cgcx) ) ;
1080
1076
llvm:: set_linkage ( llglobal, llvm:: Linkage :: PrivateLinkage ) ;
1081
1077
llvm:: LLVMSetGlobalConstant ( llglobal, llvm:: True ) ;
1082
1078
1083
1079
let llconst = common:: bytes_in_context ( llcx, cmdline. as_bytes ( ) ) ;
1084
- let llglobal = llvm:: LLVMAddGlobal (
1085
- llmod,
1086
- common:: val_ty ( llconst) ,
1087
- c"rustc.embedded.cmdline" . as_ptr ( ) ,
1088
- ) ;
1089
- llvm:: LLVMSetInitializer ( llglobal, llconst) ;
1080
+ let llglobal =
1081
+ llvm:: add_global ( llmod, common:: val_ty ( llconst) , c"rustc.embedded.cmdline" ) ;
1082
+ llvm:: set_initializer ( llglobal, llconst) ;
1090
1083
let section = if cgcx. target_is_like_osx {
1091
1084
c"__LLVM,__cmdline"
1092
1085
} else if cgcx. target_is_like_aix {
@@ -1126,31 +1119,29 @@ fn create_msvc_imps(
1126
1119
// underscores added in front).
1127
1120
let prefix = if cgcx. target_arch == "x86" { "\x01 __imp__" } else { "\x01 __imp_" } ;
1128
1121
1129
- unsafe {
1130
- let ptr_ty = Type :: ptr_llcx ( llcx) ;
1131
- let globals = base:: iter_globals ( llmod)
1132
- . filter ( |& val| {
1133
- llvm:: get_linkage ( val) == llvm:: Linkage :: ExternalLinkage
1134
- && llvm:: LLVMIsDeclaration ( val) == 0
1135
- } )
1136
- . filter_map ( |val| {
1137
- // Exclude some symbols that we know are not Rust symbols.
1138
- let name = llvm:: get_value_name ( val) ;
1139
- if ignored ( name) { None } else { Some ( ( val, name) ) }
1140
- } )
1141
- . map ( move |( val, name) | {
1142
- let mut imp_name = prefix. as_bytes ( ) . to_vec ( ) ;
1143
- imp_name. extend ( name) ;
1144
- let imp_name = CString :: new ( imp_name) . unwrap ( ) ;
1145
- ( imp_name, val)
1146
- } )
1147
- . collect :: < Vec < _ > > ( ) ;
1122
+ let ptr_ty = Type :: ptr_llcx ( llcx) ;
1123
+ let globals = base:: iter_globals ( llmod)
1124
+ . filter ( |& val| {
1125
+ llvm:: get_linkage ( val) == llvm:: Linkage :: ExternalLinkage && llvm:: is_declaration ( val)
1126
+ } )
1127
+ . filter_map ( |val| {
1128
+ // Exclude some symbols that we know are not Rust symbols.
1129
+ let name = llvm:: get_value_name ( val) ;
1130
+ if ignored ( name) { None } else { Some ( ( val, name) ) }
1131
+ } )
1132
+ . map ( move |( val, name) | {
1133
+ let mut imp_name = prefix. as_bytes ( ) . to_vec ( ) ;
1134
+ imp_name. extend ( name) ;
1135
+ let imp_name = CString :: new ( imp_name) . unwrap ( ) ;
1136
+ ( imp_name, val)
1137
+ } )
1138
+ . collect :: < Vec < _ > > ( ) ;
1148
1139
1149
- for ( imp_name, val) in globals {
1150
- let imp = llvm:: LLVMAddGlobal ( llmod, ptr_ty, imp_name. as_ptr ( ) ) ;
1151
- llvm :: LLVMSetInitializer ( imp , val ) ;
1152
- llvm:: set_linkage ( imp, llvm :: Linkage :: ExternalLinkage ) ;
1153
- }
1140
+ for ( imp_name, val) in globals {
1141
+ let imp = llvm:: add_global ( llmod, ptr_ty, & imp_name) ;
1142
+
1143
+ llvm:: set_initializer ( imp, val ) ;
1144
+ llvm :: set_linkage ( imp , llvm :: Linkage :: ExternalLinkage ) ;
1154
1145
}
1155
1146
1156
1147
// Use this function to exclude certain symbols from `__imp` generation.
0 commit comments