1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
use llvm_sys::prelude::LLVMValueRef;
use llvm_sys::core::{LLVMConstExtractValue, LLVMConstInsertValue};

use std::convert::TryFrom;
use std::fmt::Debug;

use crate::values::{ArrayValue, AggregateValueEnum, BasicValueUse, CallSiteValue, GlobalValue, StructValue, BasicValueEnum, AnyValueEnum, IntValue, FloatValue, PointerValue, PhiValue, VectorValue, FunctionValue, InstructionValue, Value};
use crate::types::{IntMathType, FloatMathType, PointerMathType, IntType, FloatType, PointerType, VectorType};

// This is an ugly privacy hack so that Type can stay private to this module
// and so that super traits using this trait will be not be implementable
// outside this library
pub trait AsValueRef {
    fn as_value_ref(&self) -> LLVMValueRef;
}

macro_rules! trait_value_set {
    ($trait_name:ident: $($args:ident),*) => (
        $(
            impl $trait_name for $args {}
        )*

        // REVIEW: Possible encompassing methods to implement:
        // as_instruction, is_sized, ge/set metadata methods
    );
}

macro_rules! math_trait_value_set {
    ($trait_name:ident: $(($value_type:ident => $base_type:ident)),*) => (
        $(
            impl $trait_name for $value_type {
                type BaseType = $base_type;
                fn new(value: LLVMValueRef) -> Self {
                    $value_type::new(value)
                }
            }
        )*
    )
}

/// Represents an aggregate value, built on top of other values.
pub trait AggregateValue: BasicValue {
    /// Returns an enum containing a typed version of the `AggregateValue`.
    fn as_aggregate_value_enum(&self) -> AggregateValueEnum {
        AggregateValueEnum::new(self.as_value_ref())
    }

    // REVIEW: How does LLVM treat out of bound index? Maybe we should return an Option?
    // or is that only in bounds GEP
    // REVIEW: Should this be AggregatePointerValue?
    fn const_extract_value(&self, indexes: &mut [u32]) -> BasicValueEnum {
        let value = unsafe {
            LLVMConstExtractValue(self.as_value_ref(), indexes.as_mut_ptr(), indexes.len() as u32)
        };

        BasicValueEnum::new(value)
    }

    // SubTypes: value should really be T in self: VectorValue<T> I think
    fn const_insert_value<BV: BasicValue>(&self, value: BV, indexes: &mut [u32]) -> BasicValueEnum {
        let value = unsafe {
            LLVMConstInsertValue(self.as_value_ref(), value.as_value_ref(), indexes.as_mut_ptr(), indexes.len() as u32)
        };

        BasicValueEnum::new(value)
    }
}

/// Represents a basic value, which can be used both by itself, or in an `AggregateValue`.
pub trait BasicValue: AnyValue {
    /// Returns an enum containing a typed version of the `BasicValue`.
    fn as_basic_value_enum(&self) -> BasicValueEnum {
        BasicValueEnum::new(self.as_value_ref())
    }

    /// Most `BasicValue`s are the byproduct of an instruction
    /// and so are convertable into an `InstructionValue`
    fn as_instruction_value(&self) -> Option<InstructionValue> {
        let value = Value::new(self.as_value_ref());

        if !value.is_instruction() {
            return None;
        }

        Some(InstructionValue::new(self.as_value_ref()))
    }

    fn get_first_use(&self) -> Option<BasicValueUse> {
        Value::new(self.as_value_ref()).get_first_use()
    }

    // REVIEW: Possible encompassing methods to implement:
    // is_sized, get/set metadata
}

/// Represents a value which is permitted in integer math operations
pub trait IntMathValue: BasicValue {
    type BaseType: IntMathType;
    fn new(value: LLVMValueRef) -> Self;
}

/// Represents a value which is permitted in floating point math operations
pub trait FloatMathValue: BasicValue {
    type BaseType: FloatMathType;
    fn new(value: LLVMValueRef) -> Self;
}

pub trait PointerMathValue: BasicValue {
    type BaseType: PointerMathType;
    fn new(value: LLVMValueRef) -> Self;
}

// REVIEW: print_to_string might be a good candidate to live here?
/// Defines any struct wrapping an LLVM value.
pub trait AnyValue: AsValueRef + Debug {
    /// Returns an enum containing a typed version of `AnyValue`.
    fn as_any_value_enum(&self) -> AnyValueEnum {
        AnyValueEnum::new(self.as_value_ref())
    }
}

trait_value_set! {AggregateValue: ArrayValue, AggregateValueEnum, StructValue}
trait_value_set! {AnyValue: AnyValueEnum, BasicValueEnum, AggregateValueEnum, ArrayValue, IntValue, FloatValue, GlobalValue, PhiValue, PointerValue, FunctionValue, StructValue, VectorValue, InstructionValue, CallSiteValue}
trait_value_set! {BasicValue: ArrayValue, BasicValueEnum, AggregateValueEnum, IntValue, FloatValue, GlobalValue, StructValue, PointerValue, VectorValue}
math_trait_value_set! {IntMathValue: (IntValue => IntType), (VectorValue => VectorType)}
math_trait_value_set! {FloatMathValue: (FloatValue => FloatType), (VectorValue => VectorType)}
math_trait_value_set! {PointerMathValue: (PointerValue => PointerType), (VectorValue => VectorType)}

macro_rules! impl_try_from_basic_value_enum {
    ($value_name:ident) => (
        impl TryFrom<BasicValueEnum> for $value_name {
            type Error = &'static str;

            fn try_from(value: BasicValueEnum) -> Result<Self, Self::Error> {
                match value {
                    BasicValueEnum::$value_name(value) => Ok(value),
                    _ => Err("bad try from"),
                }
            }
        }
    )
}

impl_try_from_basic_value_enum!(ArrayValue);
impl_try_from_basic_value_enum!(IntValue);
impl_try_from_basic_value_enum!(FloatValue);
impl_try_from_basic_value_enum!(PointerValue);
impl_try_from_basic_value_enum!(StructValue);
impl_try_from_basic_value_enum!(VectorValue);