280 likes | 303 Views
This talk explores low-level data representation in Xanadu and DTAL, focusing on dependent datatypes' transformations. It covers state type annotations, type representation, tag functions, and recursive sum types. The process of compiling code fragments from Xanadu to DTAL is demonstrated. An intriguing question is posed regarding the usefulness of forming dependent types without tag functions. Potential benefits of introducing a low-level language with structured features are discussed.
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