flx now with stupid inner functions!
posted on September 25, 2009 - 11:20 PM PDT by Erick Tryzelaar
It's been quite some time since I last posted, but I've been pretty busy. I only wasted 2 days this time wandering down the depths of the felix type system and name binding... shudder. A couple nice things this time around. flxc now partially uses the language independent frontend for symbol lowering. None of the optimizations yet though. Also managed to get trivial non-closured inner functions working, as demonstrated here:
type int = "%i32";
typedef bool = 2;
fun add : int*int -> int = "%add";
fun eq : int*int -> bool = "%eq";
fun lnot : bool -> bool = "%lnot";
proc exit : int = "exit";
fun foo (x:int) = {
val y = x + 1;
fun bar (x:int) = {
if x == 1 do
return y;
else
return 3;
done;
}
return bar y;
}
exit $ foo 2;
This now generates this code:
declare void @exit(i32)
define i32 @foo(i32 %x) {
entry:
%foo.y = alloca i32 ; <i32*> [#uses=2]
%foo.x = alloca i32 ; <i32*> [#uses=2]
store i32 %x, i32* %foo.x
%0 = load i32* %foo.x ; <i32> [#uses=1]
%1 = add i32 %0, 1 ; <i32> [#uses=1]
store i32 %1, i32* %foo.y
%2 = load i32* %foo.y ; <i32> [#uses=1]
%3 = call i32 @foo.bar(i32 %2) ; <i32> [#uses=1]
ret i32 %3
}
define i32 @foo.bar(i32 %x) {
entry:
%foo.bar.x = alloca i32 ; <i32*> [#uses=2]
store i32 %x, i32* %foo.bar.x
%0 = load i32* %foo.bar.x ; <i32> [#uses=1]
%1 = icmp eq i32 %0, 1 ; <i1> [#uses=1]
%2 = icmp eq i1 %1, false ; <i1> [#uses=1]
br i1 %2, label %_ifdoend_1, label %else
_ifdoend_1: ; preds = %entry
ret i32 3
else: ; preds = %entry
ret i32 2
}
define void @0() {
entry:
%0 = call i32 @foo(i32 2) ; <i32> [#uses=1]
call void @exit(i32 %0)
ret void
}
And if you optimize it with flxc -O 1 ..., then you'll get:
declare void @exit(i32)
define i32 @foo(i32 %x) {
entry:
%0 = add i32 %x, 1 ; <i32> [#uses=1]
%1 = call i32 @foo.bar(i32 %0) ; <i32> [#uses=1]
ret i32 %1
}
define i32 @foo.bar(i32 %x) {
entry:
%0 = icmp eq i32 %x, 1 ; <i1> [#uses=1]
%retval = select i1 %0, i32 2, i32 3 ; <i32> [#uses=1]
ret i32 %retval
}
define void @0() {
entry:
%0 = call i32 @foo(i32 2) ; <i32> [#uses=1]
call void @exit(i32 %0)
ret void
}
Which looks surprisingly readable. You'll also notice that we're prepending the parent's name in the llvm symbol name, so it should hopefully help with debugging.