Skip to content

Commit

Permalink
Use Identifier as key to AttributeDict
Browse files Browse the repository at this point in the history
Also move `ConstantOp` to the LLVM, and test dialects separately.
  • Loading branch information
vaivaswatha committed Jun 21, 2024
1 parent f1f70b0 commit 9c14df9
Show file tree
Hide file tree
Showing 16 changed files with 629 additions and 369 deletions.
1 change: 0 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ downcast-rs = "1.2.1"
rustc-hash.workspace = true
thiserror.workspace = true
apint = "0.2.0"
sorted_vector_map = "0.1.0"
linkme.workspace = true
once_cell = "1.19.0"
paste = "1.0"
Expand Down
4 changes: 2 additions & 2 deletions pliron-llvm/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "pliron-llvm"
description = "Derive macros for pliron"
description = "LLVM dialect for pliron"
version.workspace = true
edition.workspace = true
repository.workspace = true
Expand All @@ -14,7 +14,7 @@ license.workspace = true
[dependencies]
pliron-derive = { path = "../pliron-derive", version = "0" }
pliron = { path = "../", version = "0" }
clap = "4.5"
clap = { version = "4.5", features = ["derive"] }
combine.workspace = true
thiserror.workspace = true
linkme.workspace = true
Expand Down
54 changes: 51 additions & 3 deletions pliron-llvm/src/bin/llvm-opt.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,53 @@
use pliron::result::Result;
use std::{path::PathBuf, process::ExitCode};

pub fn main() -> Result<()> {
todo!()
use inkwell::{context::Context as IWContext, module::Module as IWModule};

use clap::Parser;
use pliron::{arg_error_noloc, context::Context, printable::Printable, result::Result};
use pliron_llvm::from_inkwell;

#[derive(Parser)]
#[command(version, about="LLVM Optimizer", long_about = None)]
struct Cli {
/// Input LLVM file
#[arg(short, value_name = "FILE")]
input: PathBuf,

/// Output LLVM file
#[arg(short, value_name = "FILE")]
output: PathBuf,

/// Emit text LLVM-IR
#[arg(short = 'S', default_value_t = false)]
text_output: bool,
}

fn run(cli: Cli, ctx: &mut Context) -> Result<()> {
let context = IWContext::create();
let module = IWModule::parse_bitcode_from_path(cli.input, &context)
.map_err(|err| arg_error_noloc!("{}", err))?;

let pliron_module = from_inkwell::convert_module(ctx, &module)?;
println!("{}", pliron_module.disp(ctx));

if cli.text_output {
module
.print_to_file(&cli.output)
.map_err(|err| arg_error_noloc!("{}", err.to_string()))?;
} else {
module.write_bitcode_to_path(&cli.output);
}
Ok(())
}

pub fn main() -> ExitCode {
let cli = Cli::parse();
let ctx = &mut Context::default();
match run(cli, ctx) {
Ok(_) => ExitCode::SUCCESS,
Err(e) => {
eprintln!("{}", e.disp(ctx));
ExitCode::FAILURE
}
}
}
58 changes: 35 additions & 23 deletions pliron-llvm/src/from_inkwell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,12 +119,23 @@ pub fn convert_ipredicate(ipred: IntPredicate) -> ICmpPredicateAttr {
}

/// Mapping from inkwell entities to pliron entities.
#[derive(Default)]
struct ConversionMaps<'ctx> {
struct ConversionContext<'ctx> {
// A map from inkwell's Values to pliron's Values.
value_map: FxHashMap<AnyValueEnum<'ctx>, Value>,
// A map from inkwell's basic blocks to plirons'.
block_map: FxHashMap<IWBasicBlock<'ctx>, Ptr<BasicBlock>>,
// Entry block of the function we're processing.
_entry_block: Ptr<BasicBlock>,
}

impl<'ctx> ConversionContext<'ctx> {
fn new(entry_block: Ptr<BasicBlock>) -> Self {
Self {
value_map: FxHashMap::default(),
block_map: FxHashMap::default(),
_entry_block: entry_block,
}
}
}

/// Get the successors of an inkwell block.
Expand Down Expand Up @@ -201,22 +212,23 @@ pub enum ConversionErr {
}

fn convert_operands(
cmap: &ConversionMaps,
cctx: &ConversionContext,
inst: InstructionValue,
) -> Result<(Vec<Value>, Vec<Ptr<BasicBlock>>)> {
let mut opds = vec![];
let mut succs = vec![];
for opd in inst.get_operands().flatten() {
if let Some(val) = opd.left() {
let Some(m_val) = cmap.value_map.get(&val.as_any_value_enum()) else {
if let Some(m_val) = cctx.value_map.get(&val.as_any_value_enum()) {
opds.push(*m_val);
} else {
return input_err_noloc!(ConversionErr::UndefinedValue(
val.as_any_value_enum().print_to_string().to_string()
));
};
opds.push(*m_val);
}
} else {
let block = opd.right().unwrap();
let Some(m_block) = cmap.block_map.get(&block) else {
let Some(m_block) = cctx.block_map.get(&block) else {
return input_err_noloc!(ConversionErr::UndefinedBlock(
block.get_name().to_str_res().unwrap().to_string()
));
Expand All @@ -235,7 +247,7 @@ fn get_operand<T: Clone>(opds: &[T], idx: usize) -> Result<T> {

/// Compute the arguments to be passed when branching from `src` to `dest`.
fn convert_branch_args(
cmap: &ConversionMaps,
cctx: &ConversionContext,
src_block: IWBasicBlock,
dst_block: IWBasicBlock,
) -> Result<Vec<Value>> {
Expand All @@ -249,7 +261,7 @@ fn convert_branch_args(
src_block.get_name().to_str_res().unwrap().to_string()
));
};
let Some(m_incoming_val) = cmap.value_map.get(&incoming_val.as_any_value_enum()) else {
let Some(m_incoming_val) = cctx.value_map.get(&incoming_val.as_any_value_enum()) else {
return input_err_noloc!(ConversionErr::UndefinedValue(
incoming_val
.as_any_value_enum()
Expand All @@ -268,10 +280,10 @@ fn convert_branch_args(

fn convert_instruction(
ctx: &mut Context,
cmap: &ConversionMaps,
cctx: &ConversionContext,
inst: InstructionValue,
) -> Result<Ptr<Operation>> {
let (ref opds, ref succs) = convert_operands(cmap, inst)?;
let (ref opds, ref succs) = convert_operands(cctx, inst)?;
match inst.get_opcode() {
InstructionOpcode::Add => {
let (lhs, rhs) = (get_operand(opds, 0)?, get_operand(opds, 1)?);
Expand Down Expand Up @@ -306,12 +318,12 @@ fn convert_instruction(
"Conditional branch must have two successors"
);
let true_dest_opds = convert_branch_args(
cmap,
cctx,
inst.get_parent().unwrap(),
inst.get_operand(1).unwrap().unwrap_right(),
)?;
let false_dest_opds = convert_branch_args(
cmap,
cctx,
inst.get_parent().unwrap(),
inst.get_operand(2).unwrap().unwrap_right(),
)?;
Expand All @@ -326,7 +338,7 @@ fn convert_instruction(
.get_operation())
} else {
let dest_opds = convert_branch_args(
cmap,
cctx,
inst.get_parent().unwrap(),
inst.get_operand(0).unwrap().unwrap_right(),
)?;
Expand Down Expand Up @@ -444,7 +456,7 @@ fn convert_instruction(
// Convert inkwell `block` to pliron's `m_block`.
fn convert_block<'ctx>(
ctx: &mut Context,
cmap: &mut ConversionMaps<'ctx>,
cctx: &mut ConversionContext<'ctx>,
block: IWBasicBlock<'ctx>,
m_block: Ptr<BasicBlock>,
) -> Result<()> {
Expand All @@ -453,14 +465,14 @@ fn convert_block<'ctx>(
if inst_val.is_phi_value() {
let ty = convert_type(ctx, &inst.get_type().as_any_type_enum())?;
let arg_idx = m_block.deref_mut(ctx).add_argument(ty);
cmap.value_map
cctx.value_map
.insert(inst_val, m_block.deref(ctx).get_argument(arg_idx).unwrap());
} else {
let m_inst = convert_instruction(ctx, cmap, inst)?;
let m_inst = convert_instruction(ctx, cctx, inst)?;
m_inst.insert_at_back(m_block, ctx);
// LLVM instructions have at most one result.
if let Some(res) = m_inst.deref(ctx).get_result(0) {
cmap.value_map.insert(inst_val, res);
cctx.value_map.insert(inst_val, res);
}
}
}
Expand All @@ -475,30 +487,30 @@ fn convert_function(ctx: &mut Context, function: FunctionValue) -> Result<FuncOp
let m_func = FuncOp::new(ctx, name, fn_ty);
let m_func_reg = m_func.get_region(ctx);

let cmap = &mut ConversionMaps::default();
let cctx = &mut ConversionContext::new(m_func.get_entry_block(ctx));
let blocks = rpo(function);
// Map entry block
let mut blocks_iter = blocks.iter();
let Some(entry) = blocks_iter.next() else {
return Ok(m_func);
};

cmap.block_map.insert(*entry, m_func.get_entry_block(ctx));
cctx.block_map.insert(*entry, m_func.get_entry_block(ctx));
// Create, place and map rest of the blocks.
for block in blocks_iter {
let label = block.get_name().to_str_res()?.try_into().ok();
let m_block = BasicBlock::new(ctx, label, vec![]);
m_block.insert_at_back(m_func_reg, ctx);
cmap.block_map.insert(*block, m_block);
cctx.block_map.insert(*block, m_block);
}

// Finally, convert all blocks
for block in blocks {
let m_block = *cmap
let m_block = *cctx
.block_map
.get(&block)
.expect("We have an unmapped block !");
convert_block(ctx, cmap, block, m_block)?;
convert_block(ctx, cctx, block, m_block)?;
}

Ok(m_func)
Expand Down
10 changes: 6 additions & 4 deletions pliron-llvm/src/op_interfaces.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use pliron::{
},
context::{Context, Ptr},
decl_op_interface,
identifier::Identifier,
location::Located,
op::{op_cast, Op},
operation::Operation,
Expand Down Expand Up @@ -86,7 +87,8 @@ decl_op_interface! {
}

/// Attribute key for integer overflow flags.
pub const ATTR_KEY_INTEGER_OVERFLOW_FLAGS: &str = "llvm.integer_overflow_flags";
pub static ATTR_KEY_INTEGER_OVERFLOW_FLAGS: pliron::Lazy<Identifier> =
pliron::Lazy::new(|| "llvm_integer_overflow_flags".try_into().unwrap());

#[derive(Error, Debug)]
#[error("IntegerOverflowFlag missing on Op")]
Expand All @@ -103,7 +105,7 @@ decl_op_interface! {
self.get_operation()
.deref(ctx)
.attributes
.get::<IntegerOverflowFlagsAttr>(ATTR_KEY_INTEGER_OVERFLOW_FLAGS)
.get::<IntegerOverflowFlagsAttr>(&ATTR_KEY_INTEGER_OVERFLOW_FLAGS)
.expect("Integer overflow flag missing or is of incorrect type")
.clone()
}
Expand All @@ -116,7 +118,7 @@ decl_op_interface! {
self.get_operation()
.deref_mut(ctx)
.attributes
.set(ATTR_KEY_INTEGER_OVERFLOW_FLAGS, flag);
.set(ATTR_KEY_INTEGER_OVERFLOW_FLAGS.clone(), flag);
}

fn verify(op: &dyn Op, ctx: &Context) -> Result<()>
Expand All @@ -125,7 +127,7 @@ decl_op_interface! {
{
let op = op.get_operation().deref(ctx);
if op.attributes.get::<IntegerOverflowFlagsAttr>
(ATTR_KEY_INTEGER_OVERFLOW_FLAGS).is_none()
(&ATTR_KEY_INTEGER_OVERFLOW_FLAGS).is_none()
{
return verify_err!(op.loc(), IntBinArithOpWithOverflowFlagErr);
}
Expand Down
Loading

0 comments on commit 9c14df9

Please sign in to comment.