diff --git a/src/codegen/generators/expression_generator.rs b/src/codegen/generators/expression_generator.rs index 404526afd6..782d6838b1 100644 --- a/src/codegen/generators/expression_generator.rs +++ b/src/codegen/generators/expression_generator.rs @@ -282,6 +282,42 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { self.generate_expression_value(const_expression) } + /// Generate an access to the appropriate GOT entry to achieve an access to the given base + /// lvalue. + pub fn generate_got_access( + &self, + context: &AstNode, + llvm_type: &BasicTypeEnum<'ink>, + ) -> Result>, Diagnostic> { + match self.annotations.get(context) { + Some(StatementAnnotation::Variable { qualified_name, .. }) => { + // We will generate a GEP, which has as its base address the magic constant which + // will eventually be replaced by the location of the GOT. + let base = self + .llvm + .context + .i64_type() + .const_int(0xdeadbeef00000000, false) + .const_to_pointer(llvm_type + .ptr_type(AddressSpace::default()) + .ptr_type(AddressSpace::default())); + + self.llvm_index + .find_got_index(qualified_name) + .map(|idx| { + let ptr = self.llvm.load_array_element( + base, + &[self.llvm.context.i32_type().const_int(idx, false)], + "", + )?; + Ok(self.llvm.load_pointer(&ptr, "").into_pointer_value()) + }) + .transpose() + } + _ => Ok(None), + } + } + /// generates a binary expression (e.g. a + b, x AND y, etc.) and returns the resulting `BasicValueEnum` /// - `left` the AstStatement left of the operator /// - `right` the AstStatement right of the operator @@ -1218,13 +1254,17 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { } } + let ctx_type = + self.annotations.get_type_or_void(context, self.index).get_type_information(); + // no context ... so just something like 'x' match self.annotations.get(context) { Some(StatementAnnotation::Variable { qualified_name, .. }) - | Some(StatementAnnotation::Program { qualified_name, .. }) => self - .llvm_index - .find_loaded_associated_variable_value(qualified_name) - .ok_or_else(|| Diagnostic::unresolved_reference(name, offset.clone())), + | Some(StatementAnnotation::Program { qualified_name, .. }) => + self.generate_got_access(context, &self.llvm_index.get_associated_type(ctx_type.get_name())?)?.map_or(self + .llvm_index + .find_loaded_associated_variable_value(qualified_name) + .ok_or_else(|| Diagnostic::unresolved_reference(name, offset.clone())), Ok), _ => Err(Diagnostic::unresolved_reference(name, offset.clone())), } } diff --git a/src/codegen/generators/variable_generator.rs b/src/codegen/generators/variable_generator.rs index 9bd3928c7a..760cb41f8f 100644 --- a/src/codegen/generators/variable_generator.rs +++ b/src/codegen/generators/variable_generator.rs @@ -149,6 +149,7 @@ impl<'ctx, 'b> VariableGenerator<'ctx, 'b> { for (name, _) in &globals { if let Some(idx) = got_entries.get(&name.to_string()) { new_got_entries.insert(name.to_string(), *idx); + index.associate_got_index(name, *idx); new_got.insert(*idx, name.to_string()); } else { new_globals.push(name.to_string()); @@ -162,6 +163,7 @@ impl<'ctx, 'b> VariableGenerator<'ctx, 'b> { idx += 1; } new_got_entries.insert(name.to_string(), idx); + index.associate_got_index(name, idx); new_got.insert(idx, name.to_string()); } diff --git a/src/codegen/llvm_index.rs b/src/codegen/llvm_index.rs index b30d428c23..86604411a0 100644 --- a/src/codegen/llvm_index.rs +++ b/src/codegen/llvm_index.rs @@ -14,6 +14,7 @@ pub struct LlvmTypedIndex<'ink> { type_associations: FxHashMap>, pou_type_associations: FxHashMap>, global_values: FxHashMap>, + got_indices: FxHashMap, initial_value_associations: FxHashMap>, loaded_variable_associations: FxHashMap>, implementations: FxHashMap>, @@ -29,6 +30,7 @@ impl<'ink> LlvmTypedIndex<'ink> { type_associations: FxHashMap::default(), pou_type_associations: FxHashMap::default(), global_values: FxHashMap::default(), + got_indices: FxHashMap::default(), initial_value_associations: FxHashMap::default(), loaded_variable_associations: FxHashMap::default(), implementations: FxHashMap::default(), @@ -51,6 +53,9 @@ impl<'ink> LlvmTypedIndex<'ink> { for (name, value) in other.global_values.drain() { self.global_values.insert(name, value); } + for (name, index) in other.got_indices.drain() { + self.got_indices.insert(name, index); + } for (name, assocication) in other.initial_value_associations.drain() { self.initial_value_associations.insert(name, assocication); } @@ -110,6 +115,13 @@ impl<'ink> LlvmTypedIndex<'ink> { .or_else(|| self.parent_index.and_then(|it| it.find_global_value(name))) } + pub fn find_got_index(&self, name: &str) -> Option { + self.got_indices + .get(&name.to_lowercase()) + .copied() + .or_else(|| self.parent_index.and_then(|it| it.find_got_index(name))) + } + pub fn find_associated_type(&self, type_name: &str) -> Option> { self.type_associations .get(&type_name.to_lowercase()) @@ -153,6 +165,15 @@ impl<'ink> LlvmTypedIndex<'ink> { Ok(()) } + pub fn associate_got_index( + &mut self, + variable_name: &str, + index: u64, + ) -> Result<(), Diagnostic> { + self.got_indices.insert(variable_name.to_lowercase(), index); + Ok(()) + } + pub fn associate_implementation( &mut self, callable_name: &str,