
Translating Prolog to C: a WAM-based approach M.R. Levy and R.N. Horsp o ol Department of Computer Science, University of Victoria P.O. Box 3055, Victoria, BC, Canada V8W 3P6 E-mail: [email protected], [email protected] 1 Intro duction A translator from Prolog to C or C++ can b e used as a very e ective to ol for p erforming multi- paradigm programming. In [4], we have argued in favour of translation-based multi-paradigm programming. We illustrated how C++ and Prolog could be used advantageously together to build a demonstration compiler. We are now directing our e orts to improving the quality of the translation. Many Prolog systems do allow the use of \foreign" co de. For example, SICSTUS Prolog allows C mo dules to be dynamically loaded and then executed. However the translator based approach o ers certain advantages, including p ortability plus a greater degree of control of the overall system. The question wewanted to address was this: Is C an appropriate target for Prolog compilation? By appropriate, we mean that the resultant co de is comp etitive in sp eed and space with the b est-known Prolog compilation strategies. Furthermore, b ecause the ob jectiveistouse the translated co de in larger systems, we certainly require the ability to create separate mo dules, each containing the C co de equivalent of one or more Prolog predicates. Although C is sometimes regarded as a high-level assembler language, its implicit run-time structure is not compatible with ecient implementation of Prolog's backtracking. In this pap er, we rep ort on exp eriments we have conducted on translating Prolog to C using a WAM-based approach[5, 1]. There are a few advantages to using WAM, the main one b eing that we can b ene t from a fairly extensive amount of research that has b een done on WAM-based Prolog optimizations, b oth for storage and execution sp eed. We will show that it is p ossible to pro duce C co de whose execution time lies somewhere between byte-co de compiled Prolog and native-co de compiled Prolog. Byte-co de is something of a misnomer: it refers to the approach that enco des the WAM version of a program in a data array, and then interpretively executes the contents of the array. A native-co de compiler translates predicates into the machine instructions of a target computer. 2 Implementing the WAM in C Warren's abstract machine the WAM, was rst describ ed in [5]. That rep ort was not designed to be tutorial, and several exp ository articles have subsequently app eared. We used A t-Kaci's excellent tutorial [1]. One pleasing asp ect of this b o ok is that it presents the implementation of each of the WAM op erations in the form of a Pascal-like pro cedure. For example, put-variable is de ned as follows: HEAP[H] <- <REF,H>; Xn <- HEAP[H]; Ai <- HEAP[H]; H <- H+1; P <- P + instruction_sizeP; 1 At rst glance this would suggest that a Prolog predicate could b e translated by compiling it to WAM, and then representing eachWAM op eration as a call to the corresp onding C function. Consider, for example, the Prolog predicate pX,Y :- qX,rY. The predicate compiles to the following WAM co de assuming that this is the only clause: p/2: get_variable A2,X3 call q/1 put_value X3,A1 execute r/1 The obvious optimization has b een done to eliminate a redundant get/put sequence for A1. It would b e tempting to translate this to the following C co de: void p_2void{ get_variableA2,X3; q_1; put_valueX3,A1; r_1; } The problem is, what if either of the calls to q 1orr1 fails? In WAM, detection of failure invokes a call to the backtrack op eration, which selects the next control p oint from a stack of choice p oints. If q 1 fails, return will not necessarily b e to p 2's caller, so it is not sucient, for example, to insert a test for failure after the call to q 1 in the C co de. In A t-Kaci's b o ok, detection of failure results in a call to a pro cedure called backtrack. The co de for backtrack mo di es the program counter P.However the only suitable mechanism that C provides takes the form of the setjmp/long jmp library functions { but these are to o inecient for use in the Prolog system. One p ossible strategy is to use continuations [2, 6]. That is, each function takes as its last argument the p ointer to a continuation that must be called as the last action of the function. Although this can b e used as the basis for translation, it leads to unacceptable stack growth. The growth is esp ecially severe when recursive calls are executed, mainly b ecause last-call optimization is imp ossible to implement as C statements if more than one predicate is involved. Furthermore, the C programming language unlike Scheme, for example provides no ecient mechanism for creating continuations. We have used an approach that is an extension of the incorrect approach that translates WAM op erations to calls to C functions. We use a dispatching lo op to monitor the call sequence, and wehave mo di ed the WAM design as presented in A t-Kaci as follows: Firstly, P and CP are de ned as p ointers to C functions. Secondly,wehave added two registers whichwehave called W and CW. P and CP are used to select C functions, whereas W and CW are used within C functions that is, to select co de within a function. The complete details will app ear in a full version of this pap er. Our translator is built on top of a traditional WAM compiler. A Prolog program translates Prolog to WAM, p erforms various optimizations such as the register optimization given ab ove, and generates a WAM program in a list. This is then translated by another Prolog predicate into C co de. Our translator can pro duce fast or compact co de. Fast co de is pro duced by generating macro calls wheras compact co de generates function calls for the WAM op erations. The fast co de is larger than the compact co de b ecause each call is expanded to p ossibly several C statements. The WAM data structures Heap, Stack and Trail are implemented using C arrays. Toachieve acceptable p erformance in the fast co de, very careful attention must b e paid to the design of the macros. For example, wehave exploited a technique that we gleaned by studying SICSTUS Prolog that eliminates multiple tests of WAM's read/write ag in co de sequences for building or matching structures on the heap. Wehave also b een careful to eliminate unnecessary p ointer dereferencing. 2 Table 1: Benchmark results Machine/system nrev queens Sun SPARC: SICSTUS byte co de: 2.92secs177Klips 1.44secs SICSTUS native co de: 0.75sec687Klips 0.44secs Translated to C compact: 2.77secs187Klips 0.77secs Translated to C fast: 1.87secs277Klips 0.69secs Macintosh I Ici: BNR Prolog interpreted: 96.8secs 5.3Klips 63.5secs Op en Prolog: 101secs 5Klips 40.0secs Translated to C compact: 33secs 15.6Klips 13.7secs Translated to C fast: 18.4secs 28Klips 10.2secs The size of the compact co de can be further reduced without much e ect on its sp eed by replacing rep eated sequences of op erations with calls to sp ecially created new functions. This is obviously a form of data compression. Wehave implemented certain sp eci c compressions, and are currently exp erimenting with a general strategy based on \tupling" [3]. 3 Benchmark results Wehave compared our system with SICSTUS Prolog. We used SICSTUS Prolog b ecause it can compile either byte-co de or native co de, it is WAM-based and the source co de is available. We have also run the identical C co de on a Macintosh. Wewere unable to nd a compiled Prolog on the Mac, so we used BNR Prolog and Op en Prolog for comparison. As far as we can tell, b oth are interpreters, although the Op en Prolog do cumentation claims that it do es p erform last-call optimization and indexing. There are manywell-known pitfalls to b enchmarking. One problem is comparing like with like. For example, it is reputed and not denied that a certain well-known Prolog system detects the de nition of app end or any predicate de ned equivalently! and \compiles" sp ecially written, hand optimized co de for it. Such a strategy will drastically improve the p erformance of one of the standard b enchmarks used for comparing Prolog systems, namely the naive-reverse b enchmark. TABLE 1 shows the results of our b enchmarks on a Sun 4/390 SPARC server, and on a vanilla Apple Macintosh I Ici. Note that we are not able to run SICSTUS co de on a Mac, whereas our translated co de is written in ANSI C, and hence is p ortable to any system that provides an ANSI- C compiler. On the Mac we used SYMANTEC's THINK C, v 5.0. We ran na ve reverse 100 times using a list of length 100. As can be seen in the table, our compact co de slightly outp erforms SICSTUS byte co de compiled programs on the SPARC architecture.
Details
-
File Typepdf
-
Upload Time-
-
Content LanguagesEnglish
-
Upload UserAnonymous/Not logged-in
-
File Pages4 Page
-
File Size-