Skip to content

Commit

Permalink
feat: Access references to globals through a custom GOT
Browse files Browse the repository at this point in the history
  • Loading branch information
lewis-revill committed Jun 12, 2024
1 parent 58b262e commit 23b0133
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 4 deletions.
47 changes: 43 additions & 4 deletions src/codegen/generators/expression_generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,40 @@ 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<Option<PointerValue<'ink>>, 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(0.into()).ptr_type(0.into()));

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
Expand Down Expand Up @@ -1221,13 +1255,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())),
}
}
Expand Down Expand Up @@ -2391,6 +2429,7 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> {
self.generate_direct_access_expression(base, &base_value, member, &data.access, &data.index)
} else {
let member_name = member.get_flat_reference_name().unwrap_or("unknown");
println!("{:?}", self.llvm_index.find_got_index(member_name));
self.create_llvm_pointer_value_for_reference(
base_value.map(|it| it.get_basic_value_enum().into_pointer_value()).as_ref(),
self.get_load_name(member).as_deref().unwrap_or(member_name),
Expand Down
2 changes: 2 additions & 0 deletions src/codegen/generators/variable_generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,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());
Expand All @@ -160,6 +161,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());
}

Expand Down
21 changes: 21 additions & 0 deletions src/codegen/llvm_index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ pub struct LlvmTypedIndex<'ink> {
type_associations: HashMap<String, BasicTypeEnum<'ink>>,
pou_type_associations: HashMap<String, BasicTypeEnum<'ink>>,
global_values: HashMap<String, GlobalValue<'ink>>,
got_indices: HashMap<String, u64>,
initial_value_associations: HashMap<String, BasicValueEnum<'ink>>,
loaded_variable_associations: HashMap<String, PointerValue<'ink>>,
implementations: HashMap<String, FunctionValue<'ink>>,
Expand All @@ -29,6 +30,7 @@ impl<'ink> LlvmTypedIndex<'ink> {
type_associations: HashMap::new(),
pou_type_associations: HashMap::new(),
global_values: HashMap::new(),
got_indices: HashMap::new(),
initial_value_associations: HashMap::new(),
loaded_variable_associations: HashMap::new(),
implementations: HashMap::new(),
Expand All @@ -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);
}
Expand Down Expand Up @@ -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<u64> {
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<BasicTypeEnum<'ink>> {
self.type_associations
.get(&type_name.to_lowercase())
Expand Down Expand Up @@ -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,
Expand Down

0 comments on commit 23b0133

Please sign in to comment.