diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 4dd6372b5e0..242c6aed906 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -368,6 +368,24 @@ pub unsafe fn create_module<'ll>( llvm::LLVMMDNodeInContext(llcx, &name_metadata, 1), ); + // Add module flags specified via -Z llvm_module_flag + for (key, value, behavior) in &sess.opts.unstable_opts.llvm_module_flag { + let key = format!("{key}\0"); + let behavior = match behavior.as_str() { + "error" => llvm::LLVMModFlagBehavior::Error, + "warning" => llvm::LLVMModFlagBehavior::Warning, + "require" => llvm::LLVMModFlagBehavior::Require, + "override" => llvm::LLVMModFlagBehavior::Override, + "append" => llvm::LLVMModFlagBehavior::Append, + "appendunique" => llvm::LLVMModFlagBehavior::AppendUnique, + "max" => llvm::LLVMModFlagBehavior::Max, + "min" => llvm::LLVMModFlagBehavior::Min, + // We already checked this during option parsing + _ => unreachable!(), + }; + llvm::LLVMRustAddModuleFlag(llmod, behavior, key.as_ptr().cast(), *value) + } + llmod } diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 8a5851bd5cb..e6e132978ed 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -769,6 +769,7 @@ fn test_unstable_options_tracking_hash() { tracked!(instrument_xray, Some(InstrumentXRay::default())); tracked!(link_directives, false); tracked!(link_only, true); + tracked!(llvm_module_flag, vec![("bar".to_string(), 123, "max".to_string())]); tracked!(llvm_plugins, vec![String::from("plugin_name")]); tracked!(location_detail, LocationDetail { file: true, line: false, column: false }); tracked!(maximal_hir_to_mir_coverage, true); diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 07712636445..b824eb51ef7 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -429,6 +429,7 @@ mod desc { pub const parse_remap_path_scope: &str = "comma separated list of scopes: `macro`, `diagnostics`, `unsplit-debuginfo`, `split-debuginfo`, `split-debuginfo-path`, `object`, `all`"; pub const parse_inlining_threshold: &str = "either a boolean (`yes`, `no`, `on`, `off`, etc), or a non-negative number"; + pub const parse_llvm_module_flag: &str = ":::. Type must currently be `u32`. Behavior should be one of (`error`, `warning`, `require`, `override`, `append`, `appendunique`, `max`, `min`)"; } mod parse { @@ -1331,6 +1332,33 @@ mod parse { } true } + + pub(crate) fn parse_llvm_module_flag( + slot: &mut Vec<(String, u32, String)>, + v: Option<&str>, + ) -> bool { + let elements = v.unwrap_or_default().split(':').collect::>(); + let [key, md_type, value, behavior] = elements.as_slice() else { + return false; + }; + if *md_type != "u32" { + // Currently we only support u32 metadata flags, but require the + // type for forward-compatibility. + return false; + } + let Ok(value) = value.parse::() else { + return false; + }; + let behavior = behavior.to_lowercase(); + let all_behaviors = + ["error", "warning", "require", "override", "append", "appendunique", "max", "min"]; + if !all_behaviors.contains(&behavior.as_str()) { + return false; + } + + slot.push((key.to_string(), value, behavior)); + true + } } options! { @@ -1629,6 +1657,8 @@ options! { "link native libraries in the linker invocation (default: yes)"), link_only: bool = (false, parse_bool, [TRACKED], "link the `.rlink` file generated by `-Z no-link` (default: no)"), + llvm_module_flag: Vec<(String, u32, String)> = (Vec::new(), parse_llvm_module_flag, [TRACKED], + "a list of module flags to pass to LLVM (space separated)"), llvm_plugins: Vec = (Vec::new(), parse_list, [TRACKED], "a list LLVM plugins to enable (space separated)"), llvm_time_trace: bool = (false, parse_bool, [UNTRACKED], diff --git a/src/doc/unstable-book/src/compiler-flags/llvm-module-flag.md b/src/doc/unstable-book/src/compiler-flags/llvm-module-flag.md new file mode 100644 index 00000000000..454ad0a9a6d --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/llvm-module-flag.md @@ -0,0 +1,12 @@ +# `llvm-module-flag` + +--------------------- + +This flag allows adding a key/value to the `!llvm.module.flags` metadata in the +LLVM-IR for a compiled Rust module. The syntax is + +`-Z llvm_module_flag=:::` + +Currently only u32 values are supported but the type is required to be specified +for forward compatibility. The `behavior` element must match one of the named +LLVM [metadata behaviors](https://llvm.org/docs/LangRef.html#module-flags-metadata) diff --git a/tests/codegen/llvm_module_flags.rs b/tests/codegen/llvm_module_flags.rs new file mode 100644 index 00000000000..acc035086de --- /dev/null +++ b/tests/codegen/llvm_module_flags.rs @@ -0,0 +1,7 @@ +// Test for -Z llvm_module_flags +// compile-flags: -Z llvm_module_flag=foo:u32:123:error -Z llvm_module_flag=bar:u32:42:max + +fn main() {} + +// CHECK: !{i32 1, !"foo", i32 123} +// CHECK: !{i32 7, !"bar", i32 42}