280 likes | 400 Views
Compiling with Dependent Types. Hongwei Xi University of Cincinnati. What do we want to do?. To produce (optimized) self-certified code that can guarantee both type safety and memory safety Self-certification is done through the use of a form of low-level dependent types
E N D
Compiling with Dependent Types Hongwei Xi University of Cincinnati
What do we want to do? • To produce (optimized) self-certified code that can guarantee both type safety and memory safety • Self-certification is done through the use of a form of low-level dependent types • Such low-level dependent types are to be translated from high-level dependent types in source programs
Source Language: Xanadu • Xanadu (Xi, 2000) is a dependently typed imperative programming language with C-like syntax • The type of a variable in Xanadu can change during execution • The programmer may need to provide dependent type annotations for type-checking purpose
A Program in Xanadu {n:nat} float dotprod (len: int(n), a[n]: float, b[n]: float) { var: nat i; float sum;; /* nat is [a: int | a >= 0] int(a) */ sum = 0.0; for (i = 0; i < len; i = i + 1) { sum = sum +. a[i] *. b [i]; } return sum;}
A Datatype in Xanadu • A polymorphic datatype for lists:union <‘a> list with nat = { Nil (0); Cons (n+1) of ‘a * <‘a> list(n)}
Another Program in Xanadu (‘a){n:nat} int(n) length (xs: <‘a>list(n)) { var: int x;;invariant: [i:nat,j:nat | i+j=n] (xs:<‘a> list(i), x:int(j)) while (true) { switch (xs) { case Nil: return x; case Cons (_, xs): x = x+1; } } exit; /* can never be reached */}
Target Language: DTAL • DTAL is a dependently typed assembly language (Xi and Harper, 1999) • DTAL was originally designed to extend TAL (Morrisett et al, 1998) with a form of dependent types adopted from DML (Xi and Pfenning, 1999) for certifying memory safety.
What is in this talk? • This talk is focused on low-level data representation • In particular, we show how dependent datatypes are represented • We also briefly explain how a state type annotation in Xanadu is transformed into a state type in DTAL
Low-Level Types • t = int | float | a | top (s)|T (t1, …, tn) | & (d; t)| d (i; t1, …, tn)| … • t1 + … + tn = Sa:natn. d (a; t1, …, tn)where natn is {a:int | 0<= a < n}
Sizes of Types • |int| = 1, |float| = 2 • |top (s)| = s, |a| = 1 • |& (d; t)| = 1 • |T (t1,…, tn) | = |t1| + … + |tn| • |d (i; t1,…, tn) | = max (|t1|, …, |tn|)(currently, we require |t1| = … = |tn|)
Tuple Type Representation • T(t1, …, tn) is represented flatly as t1 … tn
Pointer Type Representation • &(d; t) is represented as t d
An Example of Boxing • The high-level type Int * float may be translated into the low-level type: &(0,T(int, & (0, float)))
Tag Functions • A tag function for (t1,…, tn) has the following typePa:natn. d (a; t1,…, tn) -> int(a)
An Example of Tag Function • Let t1 = & (1, T (int(0), int))t2 = & (1, T (int(1), float)) • Then the following is a tag function for (t1, t2): tag (x) = { var y; load y, x(-1); ret y; }
An Example of Tagging (I) • The high-level type int + float may be translated into the low-level type:Sa:nat2. d(a; t1, t2)wheret1 = & (1, T (int(0), int))t2 = & (1, T (int(1), float))
An Example of Tagging (II) Sa:nat2. d(a; &(1,T(int(0), int)),&(1,T(int(1), float))) int(0) / int(1) Int / float
An Interesting Question • Would it be still useful to formd(i; t1, …,tn)even if we could not find a tag function for (t1,…,tn) ?
Another Example of Tagging • The high-level type Int + float may also be translated into the low-level type:Sa:nat2. int(a) *d(a; t1, t2)where t1= int and t2 = & (0, float)
Recursive Sum Types (I) • (a)list = unit + a * (a)list • (a)list = Sa:nat2. d (a; &(1; int(0)), &(1; T(int(1), a, (a)list))) • (a)list may be translated into (a)list
Recursive Sum Types (II) • (a)list = unit + a * (a)list • null = &(0; top(0)) /* null pointer */ • (a)list = Sa:nat2.d (a; null, &(0; T(a, (a)list ))) • (a)list may be translated into (a)list
Dependent Datatypes (I) • union <‘a> list with nat = { Nil (0); Cons (n+1) of ‘a * <‘a> list(n)} • Nil: <‘a> list(0) • Cons: {n:nat} ‘a * <‘a> list(n) -> <‘a> list(n+1)
Dependent Datatypes (II) • list =foralla.P n:nat.Sf1. unit + Sf2. a * (a)list(a)wheref1 isn = 0 and f2is a:nat, n = a+1
Dependent Datatypes (III) • list=foralla.P n:nat.Sf1. & (1, int(0)) + Sf2. & (1, T(int(1), a, (a)list(a))) wheref1 isn = 0 and f2is a:nat, n = a+1
A Code Fragment in Xanadu • We now explain how the following code fragment is compiled invariant: [i:nat,j:nat | i+j=n] (xs:<‘a> list(i), x:int(j)) while (true) { switch (xs) { case Nil: return x; case Cons (_, xs): x = x+1; } }
A Code Fragment in DTAL loop: (‘a,’r){i:nat,j:nat | i + j = n} [r1:<’a>list(i), r2:int(j), sp: [sp: int(n) :: ‘r] :: ‘r] unfold r1 /* for type-checking purpose */ load r3, r1(-1) beq r3, finish load r1, r1(1) add r2, r2, 1 jmp loop
Some Questions • Would it be beneficial to introduce a low-level language with some structures instead of handling native code directly? • In particular, would it be beneficial to introduce the notion of macros? How?
Conclusion • Translating (dependent) types from source level to target level presents an effective approach to establishing properties on low-level code, which would often be difficult to prove from scratch • This practice can also be of great help for debugging a compiler