Deprecated: The each() function is deprecated. This message will be suppressed on further calls in /home/zhenxiangba/zhenxiangba.com/public_html/phproxy-improved-master/index.php on line 456
Exercise 5: structured-code interpreter using structs The goal of this exercise is to implement and specialize a recursive structured-code interpreter written using structs. But to cover a few basics needed for next time, you're first going to specialize the power program using function pointers. (0) Power with function pointers Implement a power function which takes a binary operator represented as a function pointer as an argument, as well as the exponent, neutral, and base value. Make it specialize into something that directly applies the operator. Hints: provide alias information for the function pointer, so that Tempo can eliminate it, and use post inlining. Pitfalls: - Tempo apparently does not handle function pointers as argument to the entry point very well. Solution: wrap the pointer (and perhaps also the neutral value?) in a struct, and pass this struct as an argument (which is kind of nice anyway). Monovariant structures, which are explained below in (1) are fine here. - There are in some cases some issues with function pointers which cannot be found when Tempo tries to link the program for speicalization. A solution is to put the magic AT2SPEC_struct.all_functions_present_externally:=true; in config.sml, and then provide definitions of the functions in your sctx.c file, for example: int add(int a, int b) { return *((int*)0); } int mul(int a, int b) { return *((int*)0); } (Tempo should never call them, it just uses their address, which is why I defined them to generate an error if called.) - The generated code might not look so nice, even after inlining in FLAT mode. Here are my favorite flags for making the code nicer: post_porky := true; post_porky_flags := "-copy-prop -const-prop -dead-code -unused-syms -iterate"; (if postprocessing breaks, turn them off again :-) - The functions must be in the main C file for Tempo to be able to be able to inline them (otherwise they will not be processed by Tempo). Putting them in the actx.c file is not correct, since what goes there is not always real C code (it might just simulate the effects of the real code). To be able to refer to them in the actx.c file, declare them as 'extern'. (1) Interpreter with monovariant structures Implement datastructures for representing an arithmetic expression with operators, constants, and variables, for example: struct Exp; #define TAG_ADD 1 struct Add { struct Exp *left; struct Exp *right; }; #define TAG_VAR 2 struct Variable { int identifier; /* resolved identifier, index into array which represents the environment */ }; union UExp { struct Add *add; struct Variable *variable; }; struct Exp { char tag; /* holds TAG_x */ union UExp exp; /* holds expression */ }; Add more expressions types, and write a recursive interpreter that given an expression and an environment (as an array of ints) computes the value of the expression. Test that it works. Then specialize the interpreter using Tempo. Ideally, you should end with something quite close to the equivalent C expression (post_inlining will be useful here). Pitfalls: - Tempo does not understand union, it transforms it into a struct (using an evil #define in some cases, so be careful!) - By default, Tempo uses monovariant structures, which means that all structures of a given type are given the same binding time (flow sensitively - they can start out being static and then become dynamic). To make the contents of a struct be static, list the structure in static_locations, e.g. static_locations := ["Add.left", "Add.right", ...] it is not necessary to even initialize the parameters in the actx.c file. - "ABSYN.field_type_spec: no declaration found for field" means that you mistyped a field name in static_locations - The field Exp.exp is a struct, so it is not given a binding time (its binding time is that of the struct), so listing it in static_locations gives an error - Don't use casts between structs, the binding-time analysis does not understand them (and effectively ignores the effects) (2) Interpreter with polyvariant structures Create a new datastructure which makes use of the fact that structures have compatible memory-layout, so that you no longer need the union, e.g.: struct Exp { int tag; } struct Add { int tag; struct Exp *left; struct Exp *right; } IMPORTANT: due to a bug in Tempo, the datastructure must be defined a bit differently, see below; the example above illustrates the principle. IMPORTANT: Tempo does not know anything about memory layout, it uses the names of the fields to trace what's going on. So the fields of the structs that you are going to cast between must have the same names if the memory layout is compatible and different names if it is not. You can then for example use struct Exp *e = ...; if(e->tag==TAG_ADD) { struct Add *add = (struct Add*)e; ... } However, this does not work correctly when using monovariant structures - you could probably make the program specialize, but Tempo has no idea what's going on. If, for example, you were to modify the tag field to become dynamic through a pointer qualified by 'Exp', it would have no effect on the binding-time of the field 'tag' if it was an 'Add' struct you were pointing to. To turn on structure polyvariance, use: struct_version := MONOPOLY; poly_structs := POLY_STRUCTS["Exp","Add",...]; Note that the polyvariant binding time analysis is experimental, and has even more quirks than Tempo normally does. Pitfalls: - If no aliases are defined for a location, the binding-time analysis has a tendency to sometimes believe that dereferencing the location gives a static value - to specialize correctly, you must define a context. - A bug in Tempo prevents you from using the 'tag' field as above. The tag field must be a struct, as follows: struct Tag { int t; }; struct Exp { struct Tag tag; }; #define TAG_ADD 1 struct Add { struct Tag tag; struct Exp *left; struct Exp *right; }; (which should also be listed in POLY_STRUCTS). - A correct alias context is one which reflects that there are multiple 'Add' locations and that each field can point to multiple things. I build the context as follows: struct Add add_loc[1]; extern int staticvalue(); void set_analysis_context(struct Exp **e, int **env) { if(staticvalue()) add_loc[0].left = (struct Exp*)add_loc; else add_loc[0].left = (struct Exp*)var_loc; ...similarly for right and everything else... if(staticvalue()) *e = (struct Exp*)add_loc; else ... } - An error like the following: structure Add must be monovariant structure Add must be monovariant ... structure Tag must be monovariant ERROR (TOP_FUNC 1): incorrect static_locations The first couple of lines are not errors - only the last line is an error, and it indicates that your polyvariant structs have been listed by type in static_locations, which does not make sense. Get rid of the static_locations declaration, you don't need it for the poly structs.