summaryrefslogtreecommitdiffstats
path: root/third_party/rust/cranelift-codegen/src/legalizer/globalvalue.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
commit2aa4a82499d4becd2284cdb482213d541b8804dd (patch)
treeb80bf8bf13c3766139fbacc530efd0dd9d54394c /third_party/rust/cranelift-codegen/src/legalizer/globalvalue.rs
parentInitial commit. (diff)
downloadfirefox-2aa4a82499d4becd2284cdb482213d541b8804dd.tar.xz
firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.zip
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/cranelift-codegen/src/legalizer/globalvalue.rs')
-rw-r--r--third_party/rust/cranelift-codegen/src/legalizer/globalvalue.rs140
1 files changed, 140 insertions, 0 deletions
diff --git a/third_party/rust/cranelift-codegen/src/legalizer/globalvalue.rs b/third_party/rust/cranelift-codegen/src/legalizer/globalvalue.rs
new file mode 100644
index 0000000000..5c7a72b45c
--- /dev/null
+++ b/third_party/rust/cranelift-codegen/src/legalizer/globalvalue.rs
@@ -0,0 +1,140 @@
+//! Legalization of global values.
+//!
+//! This module exports the `expand_global_value` function which transforms a `global_value`
+//! instruction into code that depends on the kind of global value referenced.
+
+use crate::cursor::{Cursor, FuncCursor};
+use crate::flowgraph::ControlFlowGraph;
+use crate::ir::{self, InstBuilder};
+use crate::isa::TargetIsa;
+
+/// Expand a `global_value` instruction according to the definition of the global value.
+pub fn expand_global_value(
+ inst: ir::Inst,
+ func: &mut ir::Function,
+ _cfg: &mut ControlFlowGraph,
+ isa: &dyn TargetIsa,
+) {
+ // Unpack the instruction.
+ let gv = match func.dfg[inst] {
+ ir::InstructionData::UnaryGlobalValue {
+ opcode,
+ global_value,
+ } => {
+ debug_assert_eq!(opcode, ir::Opcode::GlobalValue);
+ global_value
+ }
+ _ => panic!("Wanted global_value: {}", func.dfg.display_inst(inst, None)),
+ };
+
+ match func.global_values[gv] {
+ ir::GlobalValueData::VMContext => vmctx_addr(inst, func),
+ ir::GlobalValueData::IAddImm {
+ base,
+ offset,
+ global_type,
+ } => iadd_imm_addr(inst, func, base, offset.into(), global_type),
+ ir::GlobalValueData::Load {
+ base,
+ offset,
+ global_type,
+ readonly,
+ } => load_addr(inst, func, base, offset, global_type, readonly, isa),
+ ir::GlobalValueData::Symbol { tls, .. } => symbol(inst, func, gv, isa, tls),
+ }
+}
+
+/// Expand a `global_value` instruction for a vmctx global.
+fn vmctx_addr(inst: ir::Inst, func: &mut ir::Function) {
+ // Get the value representing the `vmctx` argument.
+ let vmctx = func
+ .special_param(ir::ArgumentPurpose::VMContext)
+ .expect("Missing vmctx parameter");
+
+ // Replace the `global_value` instruction's value with an alias to the vmctx arg.
+ let result = func.dfg.first_result(inst);
+ func.dfg.clear_results(inst);
+ func.dfg.change_to_alias(result, vmctx);
+ func.layout.remove_inst(inst);
+}
+
+/// Expand a `global_value` instruction for an iadd_imm global.
+fn iadd_imm_addr(
+ inst: ir::Inst,
+ func: &mut ir::Function,
+ base: ir::GlobalValue,
+ offset: i64,
+ global_type: ir::Type,
+) {
+ let mut pos = FuncCursor::new(func).at_inst(inst);
+
+ // Get the value for the lhs. For tidiness, expand VMContext here so that we avoid
+ // `vmctx_addr` which creates an otherwise unneeded value alias.
+ let lhs = if let ir::GlobalValueData::VMContext = pos.func.global_values[base] {
+ pos.func
+ .special_param(ir::ArgumentPurpose::VMContext)
+ .expect("Missing vmctx parameter")
+ } else {
+ pos.ins().global_value(global_type, base)
+ };
+
+ // Simply replace the `global_value` instruction with an `iadd_imm`, reusing the result value.
+ pos.func.dfg.replace(inst).iadd_imm(lhs, offset);
+}
+
+/// Expand a `global_value` instruction for a load global.
+fn load_addr(
+ inst: ir::Inst,
+ func: &mut ir::Function,
+ base: ir::GlobalValue,
+ offset: ir::immediates::Offset32,
+ global_type: ir::Type,
+ readonly: bool,
+ isa: &dyn TargetIsa,
+) {
+ // We need to load a pointer from the `base` global value, so insert a new `global_value`
+ // instruction. This depends on the iterative legalization loop. Note that the IR verifier
+ // detects any cycles in the `load` globals.
+ let ptr_ty = isa.pointer_type();
+ let mut pos = FuncCursor::new(func).at_inst(inst);
+ pos.use_srcloc(inst);
+
+ // Get the value for the base. For tidiness, expand VMContext here so that we avoid
+ // `vmctx_addr` which creates an otherwise unneeded value alias.
+ let base_addr = if let ir::GlobalValueData::VMContext = pos.func.global_values[base] {
+ pos.func
+ .special_param(ir::ArgumentPurpose::VMContext)
+ .expect("Missing vmctx parameter")
+ } else {
+ pos.ins().global_value(ptr_ty, base)
+ };
+
+ // Global-value loads are always notrap and aligned. They may be readonly.
+ let mut mflags = ir::MemFlags::trusted();
+ if readonly {
+ mflags.set_readonly();
+ }
+
+ // Perform the load.
+ pos.func
+ .dfg
+ .replace(inst)
+ .load(global_type, mflags, base_addr, offset);
+}
+
+/// Expand a `global_value` instruction for a symbolic name global.
+fn symbol(
+ inst: ir::Inst,
+ func: &mut ir::Function,
+ gv: ir::GlobalValue,
+ isa: &dyn TargetIsa,
+ tls: bool,
+) {
+ let ptr_ty = isa.pointer_type();
+
+ if tls {
+ func.dfg.replace(inst).tls_value(ptr_ty, gv);
+ } else {
+ func.dfg.replace(inst).symbol_value(ptr_ty, gv);
+ }
+}