Skip to content
4 changes: 4 additions & 0 deletions src/codegen/inter/optimizations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,10 @@ fn has_side_effects(instr: &TacInstr) -> bool {
dst: Operand::Var(_),
..
}
| TacInstr::Copy {
dst: Operand::Global(_),
..
}
)
}

Expand Down
2 changes: 1 addition & 1 deletion src/codegen/last/frame.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ impl SlotKey {
match op {
Operand::Temp(temp) => Some(Self::Temp(temp.0)),
Operand::Var(name) => Some(Self::Var(name.clone())),
Operand::Const(_) => None,
Operand::Global(_) | Operand::Const(_) => None,
Operand::Deref(inner) => Self::from_operand(inner),
}
}
Expand Down
71 changes: 69 additions & 2 deletions src/codegen/last/x86_64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ struct StringPool {
impl StringPool {
fn collect(prog: &TacProgram) -> Self {
let mut pool = Self::default();
for global in &prog.globals {
if let Some(value) = &global.init {
pool.visit_operand(&Operand::Const(value.clone()));
}
}
for func in &prog.functions {
for instr in &func.instrs {
pool.visit_instr(instr);
Expand Down Expand Up @@ -80,8 +85,12 @@ impl StringPool {
}

fn visit_operand(&mut self, op: &Operand) {
if let Operand::Const(ConstValue::String(value)) = op {
self.label_for(value);
match op {
Operand::Const(ConstValue::String(value)) => {
self.label_for(value);
}
Operand::Deref(inner) => self.visit_operand(inner),
_ => {}
}
}

Expand Down Expand Up @@ -147,6 +156,7 @@ pub fn emit_program(prog: &TacProgram) -> EmitResult<String> {
}
em.blank();
}
emit_globals(&mut em, prog, &strings)?;
em.raw(".text");
for func in &prog.functions {
em.blank();
Expand All @@ -160,6 +170,47 @@ pub fn emit_program(prog: &TacProgram) -> EmitResult<String> {
Ok(em.into_string())
}

fn emit_globals(em: &mut Emitter, prog: &TacProgram, strings: &StringPool) -> EmitResult<()> {
let initialized: Vec<_> = prog.globals.iter().filter(|g| g.init.is_some()).collect();
if !initialized.is_empty() {
em.raw(".data");
for global in initialized {
em.raw(".balign 8");
em.raw(&format!(".globl {}", global.name));
em.raw(&format!("{}:", global.name));
match global.init.as_ref().expect("filtrado acima") {
ConstValue::Int(value) => em.raw(&format!(" .quad {value}")),
ConstValue::Char(value) => em.raw(&format!(" .quad {}", *value as i64)),
ConstValue::Double(value) => em.raw(&format!(" .quad {}", value.to_bits())),
ConstValue::String(value) => {
let label = strings
.labels
.get(value)
.expect("string global deve ter sido coletada");
em.raw(&format!(" .quad {label}"));
}
}
if global.size > 8 {
em.raw(&format!(" .zero {}", global.size - 8));
}
}
em.blank();
}

let zeroed: Vec<_> = prog.globals.iter().filter(|g| g.init.is_none()).collect();
if !zeroed.is_empty() {
em.raw(".bss");
for global in zeroed {
em.raw(".balign 8");
em.raw(&format!(".globl {}", global.name));
em.raw(&format!("{}:", global.name));
em.raw(&format!(" .zero {}", global.size));
}
em.blank();
}
Ok(())
}

/// Emite o assembly de uma unica funcao: directiva `.globl`, rotulo,
/// prologue, corpo e epilogue.
fn emit_function(func: &TacFunction, strings: &StringPool) -> EmitResult<String> {
Expand Down Expand Up @@ -449,6 +500,11 @@ fn emit_unop(
// passa por `load_op` (que faria `movq slot(%rbp), %reg`, carregando o
// conteudo em vez do endereco).
if matches!(op, UnOp::AddrOf) {
if let Operand::Global(name) = src {
em.insn(&format!("leaq {name}(%rip), %rax"));
store_op(em, frame, &Operand::Temp(dst), "rax", strings)?;
return Ok(());
}
let key = SlotKey::from_operand(src).ok_or_else(|| {
codegen_error(
"endereco-de (&) requer uma variavel ou temporario com slot",
Expand Down Expand Up @@ -559,6 +615,10 @@ fn load_op(
em.insn(&format!("movq {offset}(%rbp), %{reg}"));
Ok(())
}
Operand::Global(name) => {
em.insn(&format!("movq {name}(%rip), %{reg}"));
Ok(())
}
Operand::Deref(inner) => {
// `%r11` e scratch/caller-saved e nao e usado como `reg` por
// nenhum chamador de `load_op`/`store_op` neste backend, entao e
Expand All @@ -584,13 +644,19 @@ fn store_op(
return Ok(());
}

if let Operand::Global(name) = op {
em.insn(&format!("movq %{reg}, {name}(%rip)"));
return Ok(());
}

let offset = match op {
Operand::Temp(temp) => frame
.offset_of(&SlotKey::Temp(temp.0))
.expect("temp sem slot alocado"),
Operand::Var(name) => frame
.offset_of(&SlotKey::Var(name.clone()))
.expect("var sem slot alocado"),
Operand::Global(_) => unreachable!("tratado antes do match acima"),
Operand::Const(_) => {
return Err(codegen_error(
"nao e possivel armazenar em uma constante",
Expand Down Expand Up @@ -919,6 +985,7 @@ mod tests {
#[test]
fn emit_program_prepends_text_section() {
let prog = TacProgram {
globals: Vec::new(),
functions: vec![asm_simple_return_const()],
};

Expand Down
Loading
Loading