about summary refs log tree commit diff
diff options
context:
space:
mode:
authorPaul Menage <menage@gmail.com>2023-10-09 02:22:14 -0700
committerPaul Menage <menage@gmail.com>2023-11-11 19:48:47 -0800
commit2e6b57541dc28cdd954b1ce2300b88ccc5c29d5c (patch)
tree8055acc6e3dfb970acd642a19c9b7dea5c583c7a
parent2c1b65ee1431f8d3fe2142e821eb13c623bbf8a0 (diff)
downloadrust-2e6b57541dc28cdd954b1ce2300b88ccc5c29d5c.tar.gz
rust-2e6b57541dc28cdd954b1ce2300b88ccc5c29d5c.zip
Add -Z llvm_module_flag
Allow adding values to the `!llvm.module.flags` metadata for a generated
module.  The syntax is

`-Z llvm_module_flag=<name>:<type>:<value>:<behavior>`

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.viors.

This flag is expected to be perma-unstable.
-rw-r--r--compiler/rustc_codegen_llvm/src/context.rs18
-rw-r--r--compiler/rustc_interface/src/tests.rs1
-rw-r--r--compiler/rustc_session/src/options.rs30
-rw-r--r--src/doc/unstable-book/src/compiler-flags/llvm-module-flag.md12
-rw-r--r--tests/codegen/llvm_module_flags.rs7
5 files changed, 68 insertions, 0 deletions
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 d3081695523..8be23f8e4f3 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -771,6 +771,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 76d69646f1d..2840c783aa8 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 = "<key>:<type>:<value>:<behavior>. 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::<Vec<_>>();
+        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::<u32>() 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! {
@@ -1631,6 +1659,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<String> = (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=<name>:<type>:<value>:<behavior>`
+
+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}