On Tue, Feb 10, 2015 at 11:11 PM, Keean Schupke <[email protected]> wrote:
> Does the compiler do anything with curried arguments? A mistake I gave > made in the past is to link currying with partial evaluation. They are not > the sane thing, currying is simply a transform on the function type so the > type system sees everything as a unary function. Many languages simply > accumulate the arguments in a data structure and only run the function when > complete. How aggressive is BitC's partial evaluation? > One answer is: it depends on the compiler implementation. But I think that's not the best answer. In a systems-oriented language, it's very important that the programmer be able to understand, syntactically, which operations induce heap allocations. So it's a general rule that the compiler must not introduce a heap allocation unless syntactically directed to do so. More precisely: no program transformation can alter a function's "heap allocation" effect type. We can introduce an allocation in a no-heap function if an optimization would then eliminate the allocation 100% of the time, but not if the optimization works 99.44% of the time. Optimizations that introduce or eliminate allocations in procedures that already allocate are fine. We construe the existing allocation[s] as permission to use the heap. The thing is: a systems programming language needs to very strongly prefer no-heap functions. It's both a GC issue and a fragmentation issue. For this reason, the implicit lambda injection that I discussed above doesn't really work. Because of the "don't change effects" rule, it can only be done at non-escaping parameters (where the closure can be stack allocated). We could certainly build a compiler pass that *attempts* to insert the lambdas, but in a no-heap function we would have to signal an error (or at least a warning) in any case where that lambda cannot be stack allocated. Since no-heap is what we want by preference, it's an issue. Incidentally: accumulating arguments in a structure is a horrifically slow way to implement a procedure call. Register-based calling conventions are important. Unless, perhaps, there's further optimization being done there that I'm not considering. I don't know a better solution in the presence of partial applications, but the ability to use register-based calling conventions is one of the reasons we need to preserve knowledge of arity. The other reason being native calls. As much as I'm a fan of closures, most implementations do not favor an efficient calling convention. You typically will end up wanting the closure pointer to be register allocated, but in many calling conventions (notably Apple's), there aren't any available registers for use in conveying the closure pointer to the receiving procedure implementation. The current closure stub implementation in the BitC tree turns out to be wrong. It will be interesting to see what LLVM produces. shap
_______________________________________________ bitc-dev mailing list [email protected] http://www.coyotos.org/mailman/listinfo/bitc-dev
