Improve LLVM IR SSA names

This commit is contained in:
Sofia 2025-07-20 20:49:26 +03:00
parent 71a01dad69
commit 33d5ee03f0
6 changed files with 139 additions and 74 deletions

View File

@ -18,9 +18,9 @@ fn main() {
FunctionFlags::default(),
);
let arg = m_entry.build(Constant(I32(5))).unwrap();
let arg = m_entry.build("const", Constant(I32(5))).unwrap();
let fibonacci_call = m_entry
.build(FunctionCall(fibonacci.value(), vec![arg]))
.build("const", FunctionCall(fibonacci.value(), vec![arg]))
.unwrap();
m_entry
.terminate(TerminatorKind::Ret(fibonacci_call))
@ -28,10 +28,10 @@ fn main() {
let mut f_entry = fibonacci.block("entry");
let num_3 = f_entry.build(Constant(I32(3))).unwrap();
let param_n = f_entry.build(Param(0)).unwrap();
let num_3 = f_entry.build("const", Constant(I32(3))).unwrap();
let param_n = f_entry.build("param", Param(0)).unwrap();
let cond = f_entry
.build(ICmp(CmpPredicate::LT, param_n, num_3))
.build("cmp", ICmp(CmpPredicate::LT, param_n, num_3))
.unwrap();
let mut then_b = fibonacci.block("then");
@ -41,21 +41,21 @@ fn main() {
.terminate(TerminatorKind::CondBr(cond, then_b.value(), else_b.value()))
.unwrap();
let ret_const = then_b.build(Constant(I32(1))).unwrap();
let ret_const = then_b.build("const", Constant(I32(1))).unwrap();
then_b.terminate(TerminatorKind::Ret(ret_const)).unwrap();
let const_1 = else_b.build(Constant(I32(1))).unwrap();
let const_2 = else_b.build(Constant(I32(2))).unwrap();
let param_1 = else_b.build(Sub(param_n, const_1)).unwrap();
let param_2 = else_b.build(Sub(param_n, const_2)).unwrap();
let const_1 = else_b.build("const", Constant(I32(1))).unwrap();
let const_2 = else_b.build("const", Constant(I32(2))).unwrap();
let param_1 = else_b.build("sub", Sub(param_n, const_1)).unwrap();
let param_2 = else_b.build("sub", Sub(param_n, const_2)).unwrap();
let call_1 = else_b
.build(FunctionCall(fibonacci.value(), vec![param_1]))
.build("fibonacci", FunctionCall(fibonacci.value(), vec![param_1]))
.unwrap();
let call_2 = else_b
.build(FunctionCall(fibonacci.value(), vec![param_2]))
.build("fibonacci", FunctionCall(fibonacci.value(), vec![param_2]))
.unwrap();
let add = else_b.build(Add(call_1, call_2)).unwrap();
let add = else_b.build("add", Add(call_1, call_2)).unwrap();
else_b.terminate(TerminatorKind::Ret(add)).unwrap();

View File

@ -61,6 +61,7 @@ pub struct BlockHolder {
pub struct InstructionHolder {
pub(crate) value: InstructionValue,
pub(crate) data: InstructionData,
pub(crate) name: String,
pub(crate) record: Option<InstructionDebugRecordData>,
}
@ -149,6 +150,7 @@ impl Builder {
&self,
block_val: &BlockValue,
data: InstructionData,
name: String,
) -> Result<InstructionValue, ()> {
unsafe {
let mut modules = self.modules.borrow_mut();
@ -159,6 +161,7 @@ impl Builder {
block.instructions.push(InstructionHolder {
value,
data,
name,
record: None,
});

View File

@ -743,6 +743,7 @@ impl InstructionHolder {
_block: LLVMBasicBlockRef,
) -> LLVMValue {
let _ty = self.value.get_type(module.builder).unwrap();
let name = into_cstring(self.name.clone());
let val = unsafe {
use super::Instr::*;
match &self.data.kind {
@ -751,22 +752,22 @@ impl InstructionHolder {
Add(lhs, rhs) => {
let lhs_val = module.values.get(&lhs).unwrap().value_ref;
let rhs_val = module.values.get(&rhs).unwrap().value_ref;
LLVMBuildAdd(module.builder_ref, lhs_val, rhs_val, c"add".as_ptr())
LLVMBuildAdd(module.builder_ref, lhs_val, rhs_val, name.as_ptr())
}
Sub(lhs, rhs) => {
let lhs_val = module.values.get(&lhs).unwrap().value_ref;
let rhs_val = module.values.get(&rhs).unwrap().value_ref;
LLVMBuildSub(module.builder_ref, lhs_val, rhs_val, c"sub".as_ptr())
LLVMBuildSub(module.builder_ref, lhs_val, rhs_val, name.as_ptr())
}
Mult(lhs, rhs) => {
let lhs_val = module.values.get(&lhs).unwrap().value_ref;
let rhs_val = module.values.get(&rhs).unwrap().value_ref;
LLVMBuildMul(module.builder_ref, lhs_val, rhs_val, c"mul".as_ptr())
LLVMBuildMul(module.builder_ref, lhs_val, rhs_val, name.as_ptr())
}
And(lhs, rhs) => {
let lhs_val = module.values.get(&lhs).unwrap().value_ref;
let rhs_val = module.values.get(&rhs).unwrap().value_ref;
LLVMBuildAnd(module.builder_ref, lhs_val, rhs_val, c"and".as_ptr())
LLVMBuildAnd(module.builder_ref, lhs_val, rhs_val, name.as_ptr())
}
ICmp(pred, lhs, rhs) => {
let lhs = module.values.get(&lhs).unwrap();
@ -777,7 +778,7 @@ impl InstructionHolder {
pred.as_llvm_int(lhs._ty.signed()),
lhs.value_ref,
rhs_val,
c"icmp".as_ptr(),
name.as_ptr(),
)
}
FunctionCall(function_value, instruction_values) => {
@ -797,7 +798,7 @@ impl InstructionHolder {
fun.value_ref,
param_list.as_mut_ptr(),
param_list.len() as u32,
c"call".as_ptr(),
name.as_ptr(),
);
if is_void {
LLVMContextSetDiscardValueNames(module.context_ref, 0);
@ -814,7 +815,7 @@ impl InstructionHolder {
let phi = LLVMBuildPhi(
module.builder_ref,
_ty.as_llvm(module.context_ref, &module.types),
c"phi".as_ptr(),
name.as_ptr(),
);
LLVMAddIncoming(
phi,
@ -827,13 +828,13 @@ impl InstructionHolder {
Alloca(ty) => LLVMBuildAlloca(
module.builder_ref,
ty.as_llvm(module.context_ref, &module.types),
c"alloca".as_ptr(),
name.as_ptr(),
),
Load(ptr, ty) => LLVMBuildLoad2(
module.builder_ref,
ty.as_llvm(module.context_ref, &module.types),
module.values.get(&ptr).unwrap().value_ref,
c"load".as_ptr(),
name.as_ptr(),
),
Store(ptr, val) => {
let store = LLVMBuildStore(
@ -849,7 +850,7 @@ impl InstructionHolder {
module.builder_ref,
ty.as_llvm(module.context_ref, &module.types),
array_len,
c"array_alloca".as_ptr(),
name.as_ptr(),
)
}
GetElemPtr(arr, indices) => {
@ -867,32 +868,26 @@ impl InstructionHolder {
module.values.get(arr).unwrap().value_ref,
llvm_indices.as_mut_ptr(),
llvm_indices.len() as u32,
into_cstring(format!("array_gep")).as_ptr(),
name.as_ptr(),
)
}
GetStructElemPtr(struct_val, idx) => {
let t = struct_val.get_type(module.builder).unwrap();
let Type::Ptr(struct_t) = t else { panic!() };
let type_fmt = if let Type::CustomType(type_val) = *struct_t {
format!("M{}T{}", type_val.0.0, type_val.1)
} else {
format!("{:?}", struct_t)
};
LLVMBuildStructGEP2(
module.builder_ref,
struct_t.as_llvm(module.context_ref, &module.types),
module.values.get(struct_val).unwrap().value_ref,
*idx,
into_cstring(format!("struct.{}.{}.gep", type_fmt, idx)).as_ptr(),
name.as_ptr(),
)
}
ExtractValue(agg_val, idx) => LLVMBuildExtractValue(
module.builder_ref,
module.values.get(agg_val).unwrap().value_ref,
*idx,
c"extract".as_ptr(),
name.as_ptr(),
),
}
};

View File

@ -71,6 +71,7 @@ impl Debug for BlockHolder {
impl Debug for InstructionHolder {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.value.fmt(f)?;
write!(f, " ({})", self.name)?;
f.write_str(" = ")?;
self.data.fmt(f)
}

View File

@ -204,7 +204,11 @@ pub struct Block<'builder> {
}
impl<'builder> Block<'builder> {
pub fn build(&mut self, instruction: Instr) -> Result<InstructionValue, ()> {
pub fn build<T: Into<String>>(
&mut self,
name: T,
instruction: Instr,
) -> Result<InstructionValue, ()> {
unsafe {
self.builder.add_instruction(
&self.value,
@ -213,6 +217,7 @@ impl<'builder> Block<'builder> {
location: None,
meta: None,
},
name.into(),
)
}
}

View File

@ -343,11 +343,19 @@ impl mir::Module {
let mut stack_values = HashMap::new();
for (i, (p_name, p_ty)) in mir_function.parameters.iter().enumerate() {
// Codegen actual parameters
let param = entry.build(Instr::Param(i)).unwrap();
let alloca = entry
.build(Instr::Alloca(p_ty.get_type(&type_values, &types)))
let arg_name = format!("arg.{}", p_name);
let param = entry
.build(format!("{}.get", arg_name), Instr::Param(i))
.unwrap();
let alloca = entry
.build(
&arg_name,
Instr::Alloca(p_ty.get_type(&type_values, &types)),
)
.unwrap();
entry
.build(format!("{}.store", arg_name), Instr::Store(alloca, param))
.unwrap();
entry.build(Instr::Store(alloca, param)).unwrap();
stack_values.insert(
p_name.clone(),
StackValue(
@ -470,15 +478,22 @@ impl mir::Statement {
mir::StmtKind::Let(NamedVariableRef(ty, name, _), mutable, expression) => {
let value = expression.codegen(scope, &state).unwrap();
dbg!(&name);
let alloca = scope
.block
.build(Instr::Alloca(ty.get_type(scope.type_values, scope.types)))
.build(
name,
Instr::Alloca(ty.get_type(scope.type_values, scope.types)),
)
.unwrap()
.maybe_location(&mut scope.block, location);
let store = scope
.block
.build(Instr::Store(alloca, value.instr()))
.build(
format!("{}.store", name),
Instr::Store(alloca, value.instr()),
)
.unwrap()
.maybe_location(&mut scope.block, location);
@ -522,6 +537,12 @@ impl mir::Statement {
let rhs_value = rhs.codegen(scope, state)?;
let backing_var = if let Some(var) = lhs.backing_var() {
&format!("store.{}", var.1)
} else {
"store"
};
match lhs_value.0 {
StackValueKind::Immutable(_) => {
panic!("Tried to assign to immutable!")
@ -529,7 +550,7 @@ impl mir::Statement {
StackValueKind::Mutable(instr) => {
scope
.block
.build(Instr::Store(instr, rhs_value.instr()))
.build(backing_var, Instr::Store(instr, rhs_value.instr()))
.unwrap()
.maybe_location(&mut scope.block, location);
}
@ -572,10 +593,13 @@ impl mir::Expression {
v.0.derive(
scope
.block
.build(Instr::Load(
v.0.instr(),
inner.get_type(scope.type_values, scope.types),
))
.build(
format!("{}", varref.1),
Instr::Load(
v.0.instr(),
inner.get_type(scope.type_values, scope.types),
),
)
.unwrap(),
),
*inner.clone(),
@ -604,20 +628,20 @@ impl mir::Expression {
Some(StackValue(
StackValueKind::Immutable(match binop {
mir::BinaryOperator::Add => {
scope.block.build(Instr::Add(lhs, rhs)).unwrap()
scope.block.build("add", Instr::Add(lhs, rhs)).unwrap()
}
mir::BinaryOperator::Minus => {
scope.block.build(Instr::Sub(lhs, rhs)).unwrap()
scope.block.build("sub", Instr::Sub(lhs, rhs)).unwrap()
}
mir::BinaryOperator::Mult => {
scope.block.build(Instr::Mult(lhs, rhs)).unwrap()
scope.block.build("mul", Instr::Mult(lhs, rhs)).unwrap()
}
mir::BinaryOperator::And => {
scope.block.build(Instr::And(lhs, rhs)).unwrap()
scope.block.build("and", Instr::And(lhs, rhs)).unwrap()
}
mir::BinaryOperator::Cmp(l) => scope
.block
.build(Instr::ICmp(l.int_predicate(), lhs, rhs))
.build("cmp", Instr::ICmp(l.int_predicate(), lhs, rhs))
.unwrap(),
}),
TypeKind::U32,
@ -643,7 +667,10 @@ impl mir::Expression {
StackValueKind::Immutable(
scope
.block
.build(Instr::FunctionCall(callee.ir.value(), params))
.build(
call.name.clone(),
Instr::FunctionCall(callee.ir.value(), params),
)
.unwrap(),
),
ret_type,
@ -673,12 +700,15 @@ impl mir::Expression {
let first = scope
.block
.build(Instr::Constant(ConstValue::U32(0)))
.build("array.zero", Instr::Constant(ConstValue::U32(0)))
.unwrap();
let ptr = scope
.block
.build(Instr::GetElemPtr(kind.instr(), vec![first, idx]))
.build(
format!("array.gep"),
Instr::GetElemPtr(kind.instr(), vec![first, idx]),
)
.unwrap()
.maybe_location(&mut scope.block, location);
@ -694,10 +724,13 @@ impl mir::Expression {
kind.derive(
scope
.block
.build(Instr::Load(
ptr,
val_t.get_type(scope.type_values, scope.types),
))
.build(
"array.load",
Instr::Load(
ptr,
val_t.get_type(scope.type_values, scope.types),
),
)
.unwrap()
.maybe_location(&mut scope.block, location),
),
@ -727,37 +760,45 @@ impl mir::Expression {
Box::new(elem_ty_kind.get_type(scope.type_values, scope.types)),
instr_list.len() as u64,
);
let array_name = format!("{}.{}", elem_ty_kind, instr_list.len());
let load_n = format!("{}.load", array_name);
let array = scope
.block
.build(Instr::Alloca(array_ty.clone()))
.build(&array_name, Instr::Alloca(array_ty.clone()))
.unwrap()
.maybe_location(&mut scope.block, location);
for (index, instr) in instr_list.iter().enumerate() {
let gep_n = format!("{}.{}.gep", array_name, index);
let store_n = format!("{}.{}.store", array_name, index);
let index_expr = scope
.block
.build(Instr::Constant(ConstValue::U32(index as u32)))
.build(
index.to_string(),
Instr::Constant(ConstValue::U32(index as u32)),
)
.unwrap();
let first = scope
.block
.build(Instr::Constant(ConstValue::U32(0)))
.build("zero", Instr::Constant(ConstValue::U32(0)))
.unwrap();
let ptr = scope
.block
.build(Instr::GetElemPtr(array, vec![first, index_expr]))
.build(gep_n, Instr::GetElemPtr(array, vec![first, index_expr]))
.unwrap()
.maybe_location(&mut scope.block, location);
scope
.block
.build(Instr::Store(ptr, *instr))
.build(store_n, Instr::Store(ptr, *instr))
.unwrap()
.maybe_location(&mut scope.block, location);
}
let array_val = scope
.block
.build(Instr::Load(array, array_ty))
.build(load_n, Instr::Load(array, array_ty))
.unwrap()
.maybe_location(&mut scope.block, location);
@ -779,9 +820,15 @@ impl mir::Expression {
scope.get_typedef(&name).unwrap().kind.clone();
let idx = struct_ty.find_index(field).unwrap();
let gep_n = format!("{}.{}.gep", name, field);
let load_n = format!("{}.{}.load", name, field);
let value = scope
.block
.build(Instr::GetStructElemPtr(struct_val.instr(), idx as u32))
.build(
gep_n,
Instr::GetStructElemPtr(struct_val.instr(), idx as u32),
)
.unwrap();
// value.maybe_location(&mut scope.block, location);
@ -791,10 +838,13 @@ impl mir::Expression {
struct_val.0.derive(
scope
.block
.build(Instr::Load(
value,
type_kind.get_type(scope.type_values, scope.types),
))
.build(
load_n,
Instr::Load(
value,
type_kind.get_type(scope.type_values, scope.types),
),
)
.unwrap(),
),
struct_ty.get_field_ty(&field).unwrap().clone(),
@ -808,22 +858,28 @@ impl mir::Expression {
}
mir::ExprKind::Struct(name, items) => {
let struct_ty = Type::CustomType(*scope.type_values.get(name)?);
let load_n = format!("{}.load", name);
let struct_ptr = scope
.block
.build(Instr::Alloca(struct_ty.clone()))
.build(name, Instr::Alloca(struct_ty.clone()))
.unwrap()
.maybe_location(&mut scope.block, location);
for (i, (_, exp)) in items.iter().enumerate() {
for (i, (field_n, exp)) in items.iter().enumerate() {
let gep_n = format!("{}.{}.gep", name, field_n);
let store_n = format!("{}.{}.store", name, field_n);
let elem_ptr = scope
.block
.build(Instr::GetStructElemPtr(struct_ptr, i as u32))
.build(gep_n, Instr::GetStructElemPtr(struct_ptr, i as u32))
.unwrap()
.maybe_location(&mut scope.block, location);
if let Some(val) = exp.codegen(scope, state) {
scope
.block
.build(Instr::Store(elem_ptr, val.instr()))
.build(store_n, Instr::Store(elem_ptr, val.instr()))
.unwrap()
.maybe_location(&mut scope.block, location);
}
@ -831,7 +887,7 @@ impl mir::Expression {
let struct_val = scope
.block
.build(Instr::Load(struct_ptr, struct_ty))
.build(load_n, Instr::Load(struct_ptr, struct_ty))
.unwrap();
Some(StackValue(
@ -919,7 +975,10 @@ impl mir::IfExpression {
incoming.extend(else_res.clone());
let instr = scope
.block
.build(Instr::Phi(incoming.iter().map(|i| i.instr()).collect()))
.build(
"phi",
Instr::Phi(incoming.iter().map(|i| i.instr()).collect()),
)
.unwrap();
use StackValueKind::*;
@ -957,7 +1016,9 @@ impl mir::CmpOperator {
impl mir::Literal {
fn as_const(&self, block: &mut Block) -> InstructionValue {
block.build(self.as_const_kind()).unwrap()
block
.build(format!("{}", self), self.as_const_kind())
.unwrap()
}
fn as_const_kind(&self) -> Instr {