use llvm_native_core::types::{Type, TypeId, TypeKind};
use llvm_native_core::value::{valref, SubclassKind, Value, ValueRef};
use std::collections::HashMap;
pub struct ValueMapper {
pub value_map: HashMap<usize, ValueRef>,
pub type_map: HashMap<TypeId, TypeId>,
pub local_map: HashMap<usize, usize>,
}
impl ValueMapper {
pub fn new() -> Self {
Self {
value_map: HashMap::new(),
type_map: HashMap::new(),
local_map: HashMap::new(),
}
}
pub fn map_value(&self, val: &ValueRef) -> ValueRef {
let vid = val.borrow().vid as usize;
self.value_map
.get(&vid)
.cloned()
.unwrap_or_else(|| val.clone())
}
pub fn map_instruction(&self, inst: &ValueRef) -> ValueRef {
self.map_value(inst)
}
pub fn remap_operands(&self, inst: &mut ValueRef) {
let mut i = inst.borrow_mut();
let mut new_operands = Vec::with_capacity(i.operands.len());
for operand in &i.operands {
let mapped = self.map_value(operand);
new_operands.push(mapped);
}
i.operands = new_operands;
i.num_operands = i.operands.len();
}
pub fn register_value(&mut self, src: &ValueRef, dest: ValueRef) {
let src_vid = src.borrow().vid as usize;
self.value_map.insert(src_vid, dest);
}
pub fn map_type(&self, ty: &Type) -> Type {
if let Some(&mapped_id) = self.type_map.get(&ty.id) {
Type {
id: mapped_id,
kind: ty.kind.clone(),
}
} else {
ty.clone()
}
}
pub fn register_type(&mut self, src_id: TypeId, dest_id: TypeId) {
self.type_map.insert(src_id, dest_id);
}
pub fn clone_into(&self, src: &ValueRef, dest: &ValueRef) {
let src_val = src.borrow();
let mut dest_val = dest.borrow_mut();
dest_val.ty = self.map_type(&src_val.ty);
dest_val.subclass = src_val.subclass;
dest_val.opcode = src_val.opcode;
dest_val.num_operands = src_val.num_operands;
dest_val.operands = src_val.operands.clone();
dest_val.parent = src_val.parent.clone();
dest_val.metadata = src_val.metadata.clone();
dest_val.is_used_by_md = src_val.is_used_by_md;
dest_val.subclass_data = src_val.subclass_data;
}
pub fn clone_basic_block(&self, src_bb: &ValueRef, dest_func: &ValueRef) -> ValueRef {
let src = src_bb.borrow();
let mut dest_bb = Value::new(Type::label())
.with_subclass(SubclassKind::BasicBlock)
.named(&src.name);
dest_bb.parent = Some(dest_func.clone());
for inst in &src.operands {
let src_inst = inst.borrow();
if !src_inst.is_instruction() {
continue;
}
let mut dest_inst = Value::new(self.map_type(&src_inst.ty))
.with_subclass(src_inst.subclass)
.named(&src_inst.name);
dest_inst.opcode = src_inst.opcode;
dest_inst.operands = src_inst.operands.clone();
dest_inst.num_operands = src_inst.operands.len();
dest_inst.parent = Some(dest_func.clone());
dest_inst.metadata = src_inst.metadata.clone();
dest_inst.is_used_by_md = src_inst.is_used_by_md;
dest_inst.subclass_data = src_inst.subclass_data;
let dest_inst_ref = valref(dest_inst);
dest_bb.operands.push(dest_inst_ref);
}
valref(dest_bb)
}
pub fn clone_function(&self, src: &ValueRef, name: &str) -> ValueRef {
let src_func = src.borrow();
let mut dest_func = Value::new(src_func.ty.clone())
.with_subclass(SubclassKind::Function)
.named(name);
dest_func.return_type = src_func.return_type.clone();
let dest_func_ref = valref(dest_func);
for operand in &src_func.operands {
if operand.borrow().is_basic_block() {
let cloned_bb = self.clone_basic_block(operand, &dest_func_ref);
dest_func_ref.borrow_mut().operands.push(cloned_bb);
} else if operand.borrow().subclass == SubclassKind::Argument {
let src_arg = operand.borrow();
let mut arg = Value::new(self.map_type(&src_arg.ty))
.with_subclass(SubclassKind::Argument)
.named(&src_arg.name);
arg.parent = Some(dest_func_ref.clone());
dest_func_ref.borrow_mut().operands.push(valref(arg));
}
}
let num_ops = dest_func_ref.borrow().operands.len();
dest_func_ref.borrow_mut().num_operands = num_ops;
dest_func_ref
}
}
impl Default for ValueMapper {
fn default() -> Self {
Self::new()
}
}
pub fn clone_module(src: &llvm_native_core::module::Module, name: &str) -> llvm_native_core::module::Module {
let mut dest = llvm_native_core::module::Module::new(name);
let mut mapper = ValueMapper::new();
dest.source_filename = src.source_filename.clone();
dest.target_triple = src.target_triple.clone();
dest.data_layout = src.data_layout.clone();
for ty in &src.types {
let cloned_ty = ty.clone(); dest.types.push(cloned_ty);
}
dest.named_types = src.named_types.clone();
for global in &src.globals {
let g = global.borrow();
let mut cloned = Value::new(g.ty.clone())
.with_subclass(SubclassKind::GlobalVariable)
.named(&g.name);
cloned.subclass_data = g.subclass_data;
let cloned_ref = valref(cloned);
mapper.register_value(global, cloned_ref.clone());
dest.globals.push(cloned_ref);
}
for func in &src.functions {
let f = func.borrow();
let cloned = mapper.clone_function(func, &f.name);
dest.functions.push(cloned);
}
for alias in &src.aliases {
let a = alias.borrow();
let mut cloned = Value::new(a.ty.clone())
.with_subclass(SubclassKind::GlobalAlias)
.named(&a.name);
let cloned_ref = valref(cloned);
mapper.register_value(alias, cloned_ref.clone());
dest.aliases.push(cloned_ref);
}
for ifunc in &src.ifuncs {
let i = ifunc.borrow();
let mut cloned = Value::new(i.ty.clone())
.with_subclass(SubclassKind::GlobalIFunc)
.named(&i.name);
let cloned_ref = valref(cloned);
mapper.register_value(ifunc, cloned_ref.clone());
dest.ifuncs.push(cloned_ref);
}
dest.comdats = src.comdats.clone();
dest.named_metadata = src.named_metadata.clone();
dest.attr_groups.clone_from(&src.attr_groups);
dest.flags.clone_from(&src.flags);
dest.imported_functions = src.imported_functions.clone();
dest
}
pub fn clone_function_into(
src: &ValueRef,
dest_module: &mut llvm_native_core::module::Module,
name: &str,
) -> ValueRef {
let mapper = ValueMapper::new();
let cloned = mapper.clone_function(src, name);
for operand in &cloned.borrow().operands.clone() {
let mut op = operand.borrow_mut();
op.ty = mapper.map_type(&op.ty);
if op.parent.is_some() {
}
}
dest_module.functions.push(cloned.clone());
cloned
}
#[cfg(test)]
mod tests {
use super::*;
fn make_value(ty: Type) -> ValueRef {
valref(Value::new(ty).named("test"))
}
#[test]
fn test_value_mapper_new() {
let mapper = ValueMapper::new();
assert!(mapper.value_map.is_empty());
assert!(mapper.type_map.is_empty());
assert!(mapper.local_map.is_empty());
}
#[test]
fn test_default() {
let mapper = ValueMapper::default();
assert!(mapper.value_map.is_empty());
}
#[test]
fn test_register_and_map_value() {
let mut mapper = ValueMapper::new();
let src = make_value(Type::i32());
let dest = make_value(Type::i32());
mapper.register_value(&src, dest.clone());
let mapped = mapper.map_value(&src);
assert!(Rc::ptr_eq(&mapped, &dest));
}
#[test]
fn test_map_unregistered_value() {
let mapper = ValueMapper::new();
let val = make_value(Type::i32());
let mapped = mapper.map_value(&val);
assert!(Rc::ptr_eq(&mapped, &val));
}
#[test]
fn test_map_instruction() {
let mut mapper = ValueMapper::new();
let src = make_value(Type::new(TypeKind::Integer { bits: 32 }));
src.borrow_mut().subclass = SubclassKind::Instruction;
let dest = make_value(Type::new(TypeKind::Integer { bits: 32 }));
dest.borrow_mut().subclass = SubclassKind::Instruction;
mapper.register_value(&src, dest.clone());
assert!(Rc::ptr_eq(&mapper.map_instruction(&src), &dest));
}
#[test]
fn test_map_type_registered() {
let mut mapper = ValueMapper::new();
let ty1 = Type::i32();
let ty2 = Type::i64();
mapper.register_type(ty1.id, ty2.id);
let mapped = mapper.map_type(&ty1);
assert_eq!(mapped.id, ty2.id);
}
#[test]
fn test_map_type_unregistered() {
let mapper = ValueMapper::new();
let ty = Type::i32();
let mapped = mapper.map_type(&ty);
assert_eq!(mapped.id, ty.id);
assert_eq!(mapped.kind, ty.kind);
}
#[test]
fn test_remap_operands() {
let mut mapper = ValueMapper::new();
let op1 = make_value(Type::i32());
let op1_mapped = make_value(Type::i32());
mapper.register_value(&op1, op1_mapped.clone());
let inst = make_value(Type::i32());
inst.borrow_mut().operands.push(op1.clone());
inst.borrow_mut().num_operands = 1;
let mut inst_ref = inst.clone();
mapper.remap_operands(&mut inst_ref);
let mapped_inst = inst_ref.borrow();
assert_eq!(mapped_inst.operands.len(), 1);
assert!(Rc::ptr_eq(&mapped_inst.operands[0], &op1_mapped));
}
#[test]
fn test_clone_basic_block() {
let mapper = ValueMapper::new();
let src_bb = valref(
Value::new(Type::label())
.with_subclass(SubclassKind::BasicBlock)
.named("src_bb"),
);
let inst = valref(
Value::new(Type::i32())
.with_subclass(SubclassKind::Instruction)
.named("add"),
);
inst.borrow_mut().opcode = Some(llvm_native_core::opcode::Opcode::Add);
src_bb.borrow_mut().operands.push(inst);
let dest_func = valref(
Value::new(Type::void())
.with_subclass(SubclassKind::Function)
.named("dest_func"),
);
let cloned = mapper.clone_basic_block(&src_bb, &dest_func);
let c = cloned.borrow();
assert_eq!(c.name, "src_bb");
assert!(c.is_basic_block());
assert_eq!(c.operands.len(), 1); }
#[test]
fn test_clone_function() {
let mapper = ValueMapper::new();
let src_func = valref(
Value::new(Type::void())
.with_subclass(SubclassKind::Function)
.named("src_func"),
);
let bb = valref(
Value::new(Type::label())
.with_subclass(SubclassKind::BasicBlock)
.named("entry"),
);
src_func.borrow_mut().operands.push(bb);
let cloned = mapper.clone_function(&src_func, "cloned_func");
let c = cloned.borrow();
assert_eq!(c.name, "cloned_func");
assert!(c.subclass == SubclassKind::Function);
assert_eq!(c.operands.len(), 1); }
#[test]
fn test_clone_module_empty() {
let src = llvm_native_core::module::Module::new("src_module");
let dest = clone_module(&src, "dest_module");
assert_eq!(dest.name, "dest_module");
assert!(dest.functions.is_empty());
assert!(dest.globals.is_empty());
}
#[test]
fn test_clone_module_with_function() {
let mut src = llvm_native_core::module::Module::new("src_module");
let func = valref(
Value::new(Type::void())
.with_subclass(SubclassKind::Function)
.named("my_func"),
);
src.functions.push(func);
let dest = clone_module(&src, "dest_module");
assert_eq!(dest.name, "dest_module");
assert_eq!(dest.functions.len(), 1);
assert_eq!(dest.functions[0].borrow().name, "my_func");
}
#[test]
fn test_clone_module_with_globals() {
let mut src = llvm_native_core::module::Module::new("src_module");
let global = valref(
Value::new(Type::i32())
.with_subclass(SubclassKind::GlobalVariable)
.named("@g"),
);
src.globals.push(global);
let dest = clone_module(&src, "dest_module");
assert_eq!(dest.globals.len(), 1);
assert_eq!(dest.globals[0].borrow().name, "@g");
}
#[test]
fn test_clone_function_into_module() {
let mut src_module = llvm_native_core::module::Module::new("src");
let src_func = valref(
Value::new(Type::void())
.with_subclass(SubclassKind::Function)
.named("original"),
);
let bb = valref(
Value::new(Type::label())
.with_subclass(SubclassKind::BasicBlock)
.named("entry"),
);
src_func.borrow_mut().operands.push(bb);
src_module.functions.push(src_func);
let mut dest_module = llvm_native_core::module::Module::new("dest");
let cloned = clone_function_into(&src_module.functions[0], &mut dest_module, "renamed");
assert_eq!(cloned.borrow().name, "renamed");
assert_eq!(dest_module.functions.len(), 1);
}
#[test]
fn test_clone_module_preserves_metadata() {
let mut src = llvm_native_core::module::Module::new("src");
src.set_source_filename("test.c");
src.set_target_triple("x86_64-unknown-linux-gnu");
src.set_data_layout(
"e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128",
);
let dest = clone_module(&src, "dest");
assert_eq!(dest.source_filename, "test.c");
assert_eq!(dest.target_triple.unwrap(), "x86_64-unknown-linux-gnu");
assert!(dest.data_layout.is_some());
}
#[test]
fn test_register_type_multiple() {
let mut mapper = ValueMapper::new();
let t1 = Type::i32();
let t2 = Type::i32();
let t3 = Type::i64();
mapper.register_type(t1.id, t3.id);
mapper.register_type(t2.id, t3.id);
assert_eq!(mapper.map_type(&t1).id, t3.id);
assert_eq!(mapper.map_type(&t2).id, t3.id);
}
}
use std::rc::Rc;