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
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
extern crate pcb_core as core;

pub struct Ctxt(core::pcb::Ctxt);

impl std::fmt::Display for Ctxt {
  fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
    (self.0).fmt(f)
  }
}


impl Ctxt {
  pub fn new() -> Ctxt {
    Ctxt(core::pcb::Ctxt::new(false))
  }

  pub fn build_and_write<B, W>(self, output_file: &mut W,
      print_extra_info: bool)
      where B: core::backend::Backend, W: std::io::Write {
    B::build_and_write(self.0, output_file, print_extra_info)
  }
}

#[derive(Copy, Clone)]
pub struct Function<'c>(&'c core::function::Function<'c>);

impl<'c> Function<'c> {
  pub fn new(ctxt: &'c Ctxt, name: &str, ty: ty::Function<'c>) -> Self {
    Function(ctxt.0.add_function(name, ty.inner()))
  }

  pub fn get_argument(&self, number: u32) -> Value<'c> {
    assert!(number < self.0.ty.inputs.len() as u32, "pcb_assert: attempted to \
        get nonexistent argument");
    Value(self.0.values.get(number as usize).unwrap())
  }
}

#[derive(Copy, Clone)]
pub struct Block<'c>(&'c core::function::Block<'c>);

macro_rules! chk_term {
  ($this:expr) => (
    assert!($this.0.terminator.get().is_none(), "pcb_assert: \
      attempt to build instruction after a terminator");
  )
}

macro_rules! chk_op_types {
  ($lhs:expr, $rhs:expr) => (
    assert!($lhs.0.ty() == $rhs.0.ty(), "pcb_assert: lhs and rhs are not of \
      the same type");
    /*if let core::ty::Type::Integer(_) = *lhs.0.ty() {
    } else {
      panic!("pcb_assert: `add` must take values of integer type");
    }*/
  )
}

impl<'c> Block<'c> {
  pub fn append(func: Function<'c>) -> Self {
    Block(func.0.add_block())
  }

  pub fn build_const_int(self, ty: ty::Type<'c>, value: u64) -> Value<'c> {
    chk_term!(self);
    Value(self.0.add_value(
        core::function::ValueKind::ConstInt { ty: ty.inner(), value: value }))
  }
  pub fn build_call(self, func: Function<'c>, args: &[Value<'c>])
      -> Value<'c> {
    chk_term!(self);
    assert!(args.len() == func.0.ty.inputs.len(), "pcb_assert: attempt to call \
      a function with the incorrect number of arguments");
    for (arg, param_ty) in args.iter().zip(func.0.ty.inputs.iter()) {
      assert!(arg.0.ty() == *param_ty, "pcb_assert: attempt to call a function \
        with incorrect argument types");
    }
    // TODO(ubsan): check calls against type of func
    let mut inner_params = vec![];
    for param in args {
      inner_params.push(param.0)
    }
    Value(self.0.add_value(
      core::function::ValueKind::Call { function: func.0,
        parameters: inner_params.into_boxed_slice() }))
  }

  // -- binops --
  pub fn build_mul(self, lhs: Value<'c>, rhs: Value<'c>) -> Value<'c> {
    chk_term!(self);
    chk_op_types!(lhs, rhs);
    Value(self.0.add_value(core::function::ValueKind::Mul(lhs.0, rhs.0)))
  }
  pub fn build_udiv(self, lhs: Value<'c>, rhs: Value<'c>) -> Value<'c> {
    chk_term!(self);
    chk_op_types!(lhs, rhs);
    Value(self.0.add_value(core::function::ValueKind::UDiv(lhs.0, rhs.0)))
  }
  pub fn build_sdiv(self, lhs: Value<'c>, rhs: Value<'c>) -> Value<'c> {
    chk_term!(self);
    chk_op_types!(lhs, rhs);
    Value(self.0.add_value(core::function::ValueKind::SDiv(lhs.0, rhs.0)))
  }
  pub fn build_urem(self, lhs: Value<'c>, rhs: Value<'c>) -> Value<'c> {
    chk_term!(self);
    chk_op_types!(lhs, rhs);
    Value(self.0.add_value(core::function::ValueKind::URem(lhs.0, rhs.0)))
  }
  pub fn build_srem(self, lhs: Value<'c>, rhs: Value<'c>) -> Value<'c> {
    chk_term!(self);
    chk_op_types!(lhs, rhs);
    Value(self.0.add_value(core::function::ValueKind::SRem(lhs.0, rhs.0)))
  }

  pub fn build_add(self, lhs: Value<'c>, rhs: Value<'c>) -> Value<'c> {
    chk_term!(self);
    chk_op_types!(lhs, rhs);
    Value(self.0.add_value(core::function::ValueKind::Add(lhs.0, rhs.0)))
  }
  pub fn build_sub(self, lhs: Value<'c>, rhs: Value<'c>) -> Value<'c> {
    chk_term!(self);
    chk_op_types!(lhs, rhs);
    Value(self.0.add_value(core::function::ValueKind::Sub(lhs.0, rhs.0)))
  }

  pub fn build_shl(self, lhs: Value<'c>, rhs: Value<'c>) -> Value<'c> {
    chk_term!(self);
    chk_op_types!(lhs, rhs);
    Value(self.0.add_value(core::function::ValueKind::Shl(lhs.0, rhs.0)))
  }
  pub fn build_zshr(self, lhs: Value<'c>, rhs: Value<'c>) -> Value<'c> {
    chk_term!(self);
    chk_op_types!(lhs, rhs);
    Value(self.0.add_value(core::function::ValueKind::ZShr(lhs.0, rhs.0)))
  }
  pub fn build_sshr(self, lhs: Value<'c>, rhs: Value<'c>) -> Value<'c> {
    chk_term!(self);
    chk_op_types!(lhs, rhs);
    Value(self.0.add_value(core::function::ValueKind::SShr(lhs.0, rhs.0)))
  }

  pub fn build_and(self, lhs: Value<'c>, rhs: Value<'c>) -> Value<'c> {
    chk_term!(self);
    chk_op_types!(lhs, rhs);
    Value(self.0.add_value(core::function::ValueKind::And(lhs.0, rhs.0)))
  }
  pub fn build_xor(self, lhs: Value<'c>, rhs: Value<'c>) -> Value<'c> {
    chk_term!(self);
    chk_op_types!(lhs, rhs);
    Value(self.0.add_value(core::function::ValueKind::Xor(lhs.0, rhs.0)))
  }
  pub fn build_or(self, lhs: Value<'c>, rhs: Value<'c>) -> Value<'c> {
    chk_term!(self);
    chk_op_types!(lhs, rhs);
    Value(self.0.add_value(core::function::ValueKind::Or(lhs.0, rhs.0)))
  }

  pub fn build_return(self, value: Value<'c>) {
    chk_term!(self);
    self.0.terminator.set(core::function::Terminator::Return(value.0))
  }
  pub fn build_branch(self, blk: Block<'c>) {
    chk_term!(self);
    self.0.terminator.set(core::function::Terminator::Branch(blk.0))
  }
}

#[derive(Copy, Clone)]
pub struct Value<'c>(&'c core::function::Value<'c>);

trait TyExt {
  type Output;
  fn inner(self) -> Self::Output;
  fn inner_ref(&self) -> &Self::Output;
}

pub mod ty {
  use core::ty;
  use super::Ctxt;
  #[derive(Copy, Clone, PartialEq, Eq, Hash)]
  pub struct Type<'c>(&'c ty::Type);

  impl<'c> Type<'c> {
    pub fn int(ctxt: &Ctxt, size: u32) -> Type {
      Type(ctxt.0.get_type(ty::Type::Integer(size)))
    }
  }

  #[derive(Clone)]
  pub struct Function<'c>(ty::Function<'c>);

  impl<'c> Function<'c> {
    pub fn new(inputs: Vec<Type<'c>>, output: Type<'c>) -> Function<'c> {
      let mut input_inner = vec![];
      for input in inputs {
        input_inner.push(input.0);
      }
      Function(ty::Function {
        inputs: input_inner.into_boxed_slice(),
        output: output.0,
      })
    }

    #[inline(always)]
    pub fn output(&self) -> Type<'c> {
      Type(self.0.output)
    }
  }

  impl<'c> super::TyExt for Type<'c> {
    type Output = &'c ty::Type;
    fn inner(self) -> &'c ty::Type { self.0 }
    fn inner_ref(&self) -> &&'c ty::Type { &self.0 }
  }
  impl<'c> super::TyExt for Function<'c> {
    type Output = ty::Function<'c>;
    fn inner(self) -> ty::Function<'c> { self.0 }
    fn inner_ref(&self) -> &ty::Function<'c> { &self.0 }
  }
}