/* l3lib.c
 * Library for the compilation of safe L3
 * Author: Frank Pfenning, Fall 2007
 */
extern void* calloc(unsigned int num_elts, unsigned int size);
extern int raise(int sig);

#define NULL 0L
#define SIGSEGV 11

/*
 * Arithmetic operations that may be incorrectly optimized
 * by gcc with default optimizations enabled
 * For example: x/(-1) ==> -x  or  x/x ==> 1  or  x<<32 ==> 0
 */
int _idiv (int x, int y) {
  return x/y;
}

int _imod (int x, int y) {
  return x%y;
}

int _sal (int x, int y) {
  return x << y;
}

int _sar (int x, int y) {
  return x >> y;
}

/*
 * Replace lv /= e  by _idiv_asn(&lv,e) and
 * similarly for %=, <<=, >>=
 */
void _idiv_asn (int* px, int y) {
  *px /= y;
}

void _imod_asn (int* px, int y) {
  *px %= y;
}

void _sal_asn (int* px, int y) {
  *px <<= y;
}

void _sar_asn (int* px, int y) {
  *px >>= y;
}

/*
 * compile e1[e2] to (tau)_sub(e1, e2, sizeof(tau))
 * where e1 : tau[]
 */
void* _sub (int* A, int i, int elt_size) {
  if (i < 0 || i >= *A) raise(SIGSEGV);
  return (void *)(A+2+i*(elt_size/4));
}

/* compile new(tau) to (tau*)_newptr(sizeof(tau)) */
void* _newptr (int elt_size) {
  int* p = calloc(1, elt_size);
  if (p == NULL) raise(SIGSEGV);
  return (void *)p;
}

/* compile new(tau[e]) to (int*)_newarray(e,sizeof(tau)) */
void* _newarray (int num, int elt_size) {
  if (num < 0 || num > (0x7FFFFFFF-8)/elt_size) raise(SIGSEGV);
  int* p = calloc(num*(elt_size/4)+2, sizeof(int));
  if (p == NULL) raise(SIGSEGV);
  *p = num;			/* initialize number of elements */
  return (void *)p;
}

/* compile statement e; to _eval(0, e); to avoid gcc dead code elimination */
void _eval(int i, ...) {
  return;
}

/* 
 * The remaining inequality and disequality functions are there to avoid
 * gcc optimization of, for example, *p == *p  ==>  1  even if
 * p may be NULL
 */
int _eq_ptr (void* p, void* q) {
  return (p == q);
}

int _eq_int (int i, int j) {
  return (i == j);
}

int _noteq_ptr (void* p, void* q) {
  return (p != q);
}

int _noteq_int (int i, int j) {
  return (i != j);
}

