lh-l4v/tools/autocorres/tests/examples/type_strengthen.c

249 lines
3.9 KiB
C

/*
* Copyright 2020, Data61, CSIRO (ABN 41 687 119 230)
*
* SPDX-License-Identifier: BSD-2-Clause
*/
/*
* Type strengthen test cases.
*/
struct ure {
int x;
struct ure *n;
};
/*********************
* Pure functions.
*********************/
void pure_f(void)
{
}
void pure_f2(void)
{
pure_f();
}
struct ure *pure_g(struct ure *p)
{
return p;
}
int pure_h(struct ure *p)
{
return !!p;
}
int pure_i(int x)
{
return x;
}
int pure_j(struct ure s)
{
return s.x;
}
int pure_k(struct ure s)
{
return pure_i(s.x) && pure_j(s);
}
/* NB: L2Opt removes the division guard, so this lifts successfully. */
unsigned pure_div_roundup(unsigned x, unsigned n)
{
/* Quiz: is this function correct? */
if (n == 0) {
return 0;
}
return (x + (n - 1)) / n;
}
/*********************
* Read-only state monad.
*********************/
unsigned gets_x;
unsigned gets_y[4];
/*
Force the globals to be translated as variables.
Otherwise, c-parser turns them into constants because nothing
writes to them.
We could turn on globals_all_addressed in c-parser,
but that causes the globals to become generic pointers,
and autocorres loses the knowledge that those pointers
always point to valid objects.
Basically, the read-only monad is kind of flimsy and of
dubious usefulness. But see type_strengthen_tricks.thy.
*/
void hax(void)
{
gets_x = 42;
gets_y[0] = 42;
}
unsigned gets_f(void)
{
return gets_x;
}
unsigned gets_g(void)
{
unsigned y[4] = {0};
y[0] = gets_y[0];
y[1] = gets_y[1];
y[2] = gets_y[2];
y[3] = gets_y[3];
if (y[0] && y[1] && y[2] && y[3]) {
if (y[0]) {
y[0] += y[1];
}
if (y[1]) {
y[1] += y[2];
}
if (y[2]) {
y[2] += y[3];
}
if (y[3]) {
y[3] += y[0];
}
} else {
y[0] = 1;
y[1] += y[0];
y[2] += y[1];
y[3] += y[2];
}
return y[0] * y[1] * y[2] * y[3];
}
/*********************
* Option monad (Read with failure).
*********************/
unsigned opt_f(unsigned *p)
{
return *p;
}
int opt_g(int n)
{
return n + 1;
}
unsigned opt_h(struct ure *s)
{
if (!s) {
return 0;
}
return 1 + opt_h(s->n);
}
int opt_none(void);
int opt_i(void)
{
return opt_none();
}
int opt_j(struct ure *p, struct ure *l)
{
return p->x <= l->x;
}
/* This doesn't read state at all, but AutoCorres assumes loops may fail (to terminate). */
unsigned opt_l(unsigned n)
{
unsigned p = 0;
while (n > 1) {
p++;
n /= 10;
}
return p;
}
/* Ditto for recursion. */
unsigned opt_a(unsigned m, unsigned n)
{
if (m == 0) {
return n + 1;
}
if (n == 0) {
return opt_a(m - 1, 1);
}
return opt_a(m - 1, opt_a(m, n - 1));
}
/* Test for measure_call */
unsigned opt_a2(unsigned n)
{
return opt_a(n, n);
}
/*********************
* State monad (with failure).
* TODO: state monad is no longer used, rename these examples.
*********************/
void st_f(struct ure *p, struct ure *s)
{
p->n = s;
}
unsigned st_g(unsigned *p)
{
*p = 42;
return *p;
}
unsigned st_h(unsigned p)
{
return st_g((unsigned *)p);
}
struct ure *st_i(struct ure *p, struct ure *l)
{
if (opt_j(p, l) || !l) {
if (l) {
p->n = l->n;
}
return p;
} else {
l->n = st_i(p, l->n);
return l;
}
}
/*********************
* Exception monad, the most general monad.
*********************/
int exc_f(char *s, int *n)
{
int x = 0;
int sg = 1;
if (*s == '-') {
sg = -1;
s++;
} else if (*s == '+') {
s++;
}
for (; *s; s++) {
if (*s >= '0' && *s <= '9') {
x = 10 * x + sg * (*s - '0');
} else {
return -1;
}
}
if (*s) {
return -1;
} else {
*n = x;
return 0;
}
}