00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 #include "inst-priv.h"
00021 #include "context-priv.h"
00022 
00025 
00026 
00027 
00028 
00029 enum {
00030     P_TERM_X_REGISTER = 32,
00031     P_TERM_Y_REGISTER
00032 };
00033 
00034 #define P_REG_WORD_SIZE     ((int)(8 * sizeof(unsigned int)))
00035 
00036 P_INLINE void p_inst_set_reg(unsigned int *regs, int reg)
00037 {
00038     regs[reg / P_REG_WORD_SIZE] |=
00039         (((unsigned int)1) << (reg % P_REG_WORD_SIZE));
00040 }
00041 
00042 P_INLINE void p_inst_clear_reg(unsigned int *regs, int reg)
00043 {
00044     regs[reg / P_REG_WORD_SIZE] &=
00045         ~(((unsigned int)1) << (reg % P_REG_WORD_SIZE));
00046 }
00047 
00048 P_INLINE int p_inst_is_reg_set(const unsigned int *regs, int reg)
00049 {
00050     return (regs[reg / P_REG_WORD_SIZE] &
00051                 (((unsigned int)1) << (reg % P_REG_WORD_SIZE))) != 0;
00052 }
00053 
00054 
00055 static int p_inst_allocate_reg(p_code *code)
00056 {
00057     int reg = code->blocked_regs;
00058     for (;;) {
00059         if (reg >= code->max_regs) {
00060             int new_max_regs = code->max_regs * 2;
00061             if (new_max_regs < P_REG_WORD_SIZE)
00062                 new_max_regs = P_REG_WORD_SIZE;
00063             code->used_regs = GC_REALLOC
00064                 (code->used_regs,
00065                  new_max_regs * sizeof(unsigned int) / P_REG_WORD_SIZE);
00066             code->temp_regs = GC_REALLOC
00067                 (code->temp_regs,
00068                  new_max_regs * sizeof(unsigned int) / P_REG_WORD_SIZE);
00069             code->max_regs = new_max_regs;
00070         }
00071         if (reg >= code->num_regs)
00072             break;
00073         if (!p_inst_is_reg_set(code->used_regs, reg))
00074             break;
00075         ++reg;
00076     }
00077     p_inst_set_reg(code->used_regs, reg);
00078     if (reg >= code->num_regs)
00079         code->num_regs = reg + 1;
00080     return reg;
00081 }
00082 
00083 
00084 
00085 static int p_inst_new_reg(p_code *code)
00086 {
00087     int reg = p_inst_allocate_reg(code);
00088     p_inst_clear_reg(code->temp_regs, reg);
00089     return reg;
00090 }
00091 
00092 
00093 
00094 
00095 static int p_inst_new_temp_reg(p_code *code)
00096 {
00097     int reg = p_inst_allocate_reg(code);
00098     p_inst_set_reg(code->temp_regs, reg);
00099     return reg;
00100 }
00101 
00102 
00103 
00104 static void p_inst_reg_used(p_code *code, int reg)
00105 {
00106     if (p_inst_is_reg_set(code->temp_regs, reg)) {
00107         p_inst_clear_reg(code->used_regs, reg);
00108         p_inst_clear_reg(code->temp_regs, reg);
00109     }
00110 }
00111 
00112 
00113 static p_inst *_p_inst_new
00114     (p_code *code, p_opcode opcode, size_t inst_size)
00115 {
00116     p_code_block *block;
00117     p_inst *inst;
00118     if ((code->posn + inst_size + sizeof(struct p_inst_label)) >
00119             P_CODE_BLOCK_SIZE) {
00120         
00121 
00122         block = GC_NEW(p_code_block);
00123         if (code->current_block) {
00124             inst = (p_inst *)
00125                 (((char *)(code->current_block->inst)) + code->posn);
00126             inst->label.opcode = P_OP_JUMP;
00127             inst->label.label = (p_inst *)(block->inst);
00128             if (code->current_block == code->first_block) {
00129                 code->first_block_size =
00130                     code->posn + sizeof(struct p_inst_label);
00131             }
00132             code->current_block = block;
00133         } else {
00134             code->first_block = block;
00135             code->current_block = block;
00136         }
00137         code->posn = 0;
00138     } else {
00139         
00140         block = code->current_block;
00141     }
00142     inst = (p_inst *)(((char *)(block->inst)) + code->posn);
00143     inst->header.opcode = opcode;
00144     code->posn += inst_size;
00145     return inst;
00146 }
00147 #define p_inst_new(code,opcode,type)    \
00148     _p_inst_new((code), (opcode), sizeof(type))
00149 
00150 
00151 P_INLINE void p_inst_new_two_reg
00152     (p_code *code, p_opcode opcode, int reg1, int reg2)
00153 {
00154     p_inst *inst;
00155     if (reg1 <= P_MAX_SMALL_REG && reg2 <= P_MAX_SMALL_REG &&
00156             !code->force_large_regs) {
00157         inst = p_inst_new(code, opcode, struct p_inst_two_reg);
00158         inst->two_reg.reg1 = (unsigned int)reg1;
00159         inst->two_reg.reg2 = (unsigned int)reg2;
00160     } else {
00161         inst = p_inst_new
00162             (code, opcode + 1, struct p_inst_large_two_reg);
00163         inst->large_two_reg.reg1 = (unsigned int)reg1;
00164         inst->large_two_reg.reg2 = (unsigned int)reg2;
00165     }
00166 }
00167 
00168 
00169 P_INLINE void p_inst_new_functor
00170     (p_code *code, p_opcode opcode, int reg1,
00171      unsigned int arity, p_term *name)
00172 {
00173     p_inst *inst;
00174     if (reg1 <= P_MAX_SMALL_REG && arity <= P_MAX_SMALL_REG &&
00175             !code->force_large_regs) {
00176         inst = p_inst_new(code, opcode, struct p_inst_functor);
00177         inst->functor.reg1 = (unsigned int)reg1;
00178         inst->functor.arity = arity;
00179         inst->functor.name = name;
00180     } else {
00181         inst = p_inst_new
00182             (code, opcode + 1, struct p_inst_large_functor);
00183         inst->large_functor.reg1 = (unsigned int)reg1;
00184         inst->large_functor.arity = arity;
00185         inst->large_functor.name = name;
00186     }
00187 }
00188 
00189 
00190 void _p_code_allocate_args(p_code *code, int arity)
00191 {
00192     code->blocked_regs = 0;
00193     code->num_regs = 0;
00194     while (code->num_regs < arity)
00195         p_inst_allocate_reg(code);
00196     code->blocked_regs = arity;
00197 }
00198 
00199 
00200 
00201 
00202 static void p_code_analyze_variables
00203     (p_context *context, p_term *term, unsigned int goal_number)
00204 {
00205     term = p_term_deref(term);
00206     if (!term)
00207         return;
00208     switch (term->header.type) {
00209     case P_TERM_FUNCTOR: {
00210         
00211         unsigned int index;
00212         for (index = 0; index < term->header.size; ++index) {
00213             p_code_analyze_variables
00214                 (context, term->functor.arg[index], goal_number);
00215         }
00216         break; }
00217     case P_TERM_LIST: {
00218         
00219         do {
00220             p_code_analyze_variables
00221                 (context, term->list.head, goal_number);
00222             term = p_term_deref(term->list.tail);
00223             if (!term)
00224                 return;
00225         } while (term->header.type == P_TERM_LIST);
00226         p_code_analyze_variables(context, term, goal_number);
00227         break; }
00228     case P_TERM_ATOM:
00229     case P_TERM_STRING:
00230     case P_TERM_INTEGER:
00231     case P_TERM_REAL:
00232     case P_TERM_OBJECT:
00233     case P_TERM_PREDICATE:
00234     case P_TERM_CLAUSE:
00235     case P_TERM_DATABASE:
00236         
00237         break;
00238     case P_TERM_VARIABLE: {
00239         
00240         struct p_term_register *reg =
00241             p_term_new(context, struct p_term_register);
00242         if (!reg)
00243             return;
00244         reg->header.type = P_TERM_X_REGISTER;
00245         reg->usage_count = 1;
00246         reg->goal_number = goal_number;
00247         _p_context_record_in_trail(context, term);
00248         term->var.value = (p_term *)reg;
00249         break; }
00250     case P_TERM_MEMBER_VARIABLE:
00251         p_code_analyze_variables
00252             (context, term->member_var.object, goal_number);
00253         break;
00254     case P_TERM_X_REGISTER:
00255     case P_TERM_Y_REGISTER:
00256         
00257 
00258         ++(term->reg.usage_count);
00259         if (term->reg.goal_number != goal_number)
00260             term->header.type = P_TERM_Y_REGISTER;
00261         break;
00262     default: break;
00263     }
00264 }
00265 
00266 static void p_code_generate_list_setter
00267     (p_context *context, p_term *term, p_code *code,
00268      int list_reg, int preserve_reg);
00269 static int p_code_generate_builder_inner
00270     (p_context *context, p_term *term, p_code *code, int preferred_reg);
00271 
00272 
00273 
00274 
00275 static int p_code_generate_setter
00276     (p_context *context, p_term *term, p_code *code)
00277 {
00278     int reg;
00279     p_inst *inst;
00280     unsigned int index;
00281     p_term *arg;
00282     switch (term->header.type) {
00283     case P_TERM_FUNCTOR:
00284         
00285         reg = p_inst_new_temp_reg(code);
00286         p_inst_new_functor
00287             (code, P_OP_SET_FUNCTOR, reg, term->header.size,
00288              term->functor.functor_name);
00289 
00290         
00291         if (term->header.size == 2 &&
00292                 term->functor.functor_name == context->comma_atom) {
00293             
00294 
00295             for (;;) {
00296                 arg = p_term_deref(term->functor.arg[0]);
00297                 if (!arg)
00298                     return 0;
00299                 if (p_code_generate_setter(context, arg, code)) {
00300                     p_inst_new_two_reg
00301                         (code, P_OP_RESET_ARGUMENT, reg, 1);
00302                 }
00303                 term = p_term_deref(term->functor.arg[1]);
00304                 if (!term)
00305                     return 0;
00306                 if (term->header.type != P_TERM_FUNCTOR ||
00307                         term->header.size != 2 ||
00308                         term->functor.functor_name !=
00309                                 context->comma_atom)
00310                     break;
00311                 p_inst_new_functor
00312                     (code, P_OP_SET_FUNCTOR, reg, term->header.size,
00313                      term->functor.functor_name);
00314             }
00315             p_code_generate_setter(context, term, code);
00316         } else {
00317             for (index = 0; index < term->header.size; ++index) {
00318                 arg = p_term_deref(term->functor.arg[index]);
00319                 if (!arg)
00320                     return 0;
00321                 if (p_code_generate_setter(context, arg, code) &&
00322                         index < (term->header.size - 1)) {
00323                     p_inst_new_two_reg
00324                         (code, P_OP_RESET_ARGUMENT, reg, index + 1);
00325                 }
00326             }
00327         }
00328         p_inst_reg_used(code, reg);
00329 
00330         
00331         return 1;
00332     case P_TERM_LIST:
00333         
00334         reg = p_inst_new_temp_reg(code);
00335         inst = p_inst_new(code, P_OP_SET_LIST, struct p_inst_one_reg);
00336         inst->one_reg.reg1 = reg;
00337         p_code_generate_list_setter(context, term, code, reg, 0);
00338         return 1;
00339     case P_TERM_ATOM:
00340     case P_TERM_STRING:
00341     case P_TERM_INTEGER:
00342     case P_TERM_REAL:
00343     case P_TERM_OBJECT:
00344     case P_TERM_PREDICATE:
00345     case P_TERM_CLAUSE:
00346     case P_TERM_DATABASE:
00347         
00348         inst = p_inst_new
00349             (code, P_OP_SET_CONSTANT, struct p_inst_constant);
00350         inst->constant.value = term;
00351         break;
00352     case P_TERM_MEMBER_VARIABLE:
00353         
00354         reg = p_code_generate_builder_inner(context, term, code, -1);
00355         inst = p_inst_new
00356             (code, P_OP_SET_X_VALUE, struct p_inst_one_reg);
00357         inst->one_reg.reg1 = reg;
00358         p_inst_reg_used(code, reg);
00359         break;
00360     case P_TERM_X_REGISTER:
00361         
00362         if (term->reg.allocated) {
00363             reg = (int)(term->header.size);
00364             inst = p_inst_new
00365                 (code, P_OP_SET_X_VALUE, struct p_inst_one_reg);
00366             inst->one_reg.reg1 = reg;
00367         } else if (term->reg.usage_count != 1) {
00368             reg = p_inst_new_reg(code);
00369             term->header.size = (unsigned int)reg;
00370             term->reg.allocated = 1;
00371             inst = p_inst_new
00372                 (code, P_OP_SET_X_VARIABLE, struct p_inst_one_reg);
00373             inst->one_reg.reg1 = reg;
00374         } else {
00375             
00376             p_inst_new(code, P_OP_SET_VOID, struct p_inst_header);
00377         }
00378         break;
00379     case P_TERM_Y_REGISTER:
00380         
00381         if (term->reg.allocated) {
00382             reg = (int)(term->header.size);
00383             inst = p_inst_new
00384                 (code, P_OP_SET_Y_VALUE, struct p_inst_one_reg);
00385             inst->one_reg.reg1 = reg;
00386         } else {
00387             reg = (code->num_yregs)++;
00388             term->header.size = (unsigned int)reg;
00389             term->reg.allocated = 1;
00390             inst = p_inst_new
00391                 (code, P_OP_SET_Y_VARIABLE, struct p_inst_one_reg);
00392             inst->one_reg.reg1 = reg;
00393         }
00394         break;
00395     default: break;
00396     }
00397     return 0;
00398 }
00399 
00400 
00401 static void p_code_generate_list_setter
00402     (p_context *context, p_term *term, p_code *code,
00403      int list_reg, int preserve_reg)
00404 {
00405     p_term *arg;
00406     int need_reset;
00407     p_inst *inst;
00408     int start_reg = list_reg;
00409 
00410     
00411     arg = p_term_deref(term->list.head);
00412     if (!arg)
00413         return;
00414     need_reset = p_code_generate_setter(context, arg, code);
00415 
00416     
00417     term = p_term_deref(term->list.tail);
00418     while (term && term->header.type == P_TERM_LIST) {
00419         if (list_reg == start_reg && preserve_reg) {
00420             
00421 
00422             list_reg = p_inst_new_temp_reg(code);
00423             p_inst_new_two_reg
00424                 (code, P_OP_PUT_X_VALUE, start_reg, list_reg);
00425         }
00426         inst = p_inst_new(code, P_OP_SET_LIST_TAIL,
00427                           struct p_inst_one_reg);
00428         inst->one_reg.reg1 = list_reg;
00429         arg = p_term_deref(term->list.head);
00430         if (!arg)
00431             return;
00432         need_reset = p_code_generate_setter(context, arg, code);
00433         term = p_term_deref(term->list.tail);
00434     }
00435 
00436     
00437     if (!term || term == context->nil_atom) {
00438         inst = p_inst_new(code, P_OP_SET_NIL_TAIL,
00439                           struct p_inst_one_reg);
00440         inst->one_reg.reg1 = list_reg;
00441     } else {
00442         if (need_reset) {
00443             inst = p_inst_new(code, P_OP_RESET_TAIL,
00444                               struct p_inst_one_reg);
00445             inst->one_reg.reg1 = list_reg;
00446         }
00447         p_code_generate_setter(context, term, code);
00448     }
00449 
00450     
00451     if (list_reg != start_reg)
00452         p_inst_reg_used(code, list_reg);
00453 }
00454 
00455 static int p_code_generate_builder_inner
00456     (p_context *context, p_term *term, p_code *code, int preferred_reg)
00457 {
00458     int reg, arg_reg;
00459     p_inst *inst;
00460     unsigned int index;
00461     p_term *arg;
00462     term = p_term_deref(term);
00463     if (!term)
00464         return 0;
00465     switch (term->header.type) {
00466     case P_TERM_FUNCTOR:
00467         
00468         if (preferred_reg != -1)
00469             reg = preferred_reg;
00470         else
00471             reg = p_inst_new_temp_reg(code);
00472         p_inst_new_functor
00473             (code, P_OP_PUT_FUNCTOR, reg, term->header.size,
00474              term->functor.functor_name);
00475 
00476         
00477         for (index = 0; index < term->header.size; ++index) {
00478             arg = p_term_deref(term->functor.arg[index]);
00479             if (!arg)
00480                 return 0;
00481             if (p_code_generate_setter(context, arg, code) &&
00482                     index < (term->header.size - 1)) {
00483                 p_inst_new_two_reg
00484                     (code, P_OP_RESET_ARGUMENT, reg, index + 1);
00485             }
00486         }
00487         break;
00488     case P_TERM_LIST:
00489         
00490         if (preferred_reg != -1)
00491             reg = preferred_reg;
00492         else
00493             reg = p_inst_new_temp_reg(code);
00494         inst = p_inst_new(code, P_OP_PUT_LIST, struct p_inst_one_reg);
00495         inst->one_reg.reg1 = reg;
00496 
00497         
00498         p_code_generate_list_setter(context, term, code, reg, 1);
00499         break;
00500     case P_TERM_ATOM:
00501     case P_TERM_STRING:
00502     case P_TERM_INTEGER:
00503     case P_TERM_REAL:
00504     case P_TERM_OBJECT:
00505     case P_TERM_PREDICATE:
00506     case P_TERM_CLAUSE:
00507     case P_TERM_DATABASE:
00508         
00509         if (preferred_reg != -1)
00510             reg = preferred_reg;
00511         else
00512             reg = p_inst_new_temp_reg(code);
00513         inst = p_inst_new
00514             (code, P_OP_PUT_CONSTANT, struct p_inst_constant);
00515         inst->constant.reg1 = reg;
00516         inst->constant.value = term;
00517         break;
00518     case P_TERM_MEMBER_VARIABLE:
00519         
00520         arg_reg = p_code_generate_builder_inner
00521             (context, term->member_var.object, code, -1);
00522         if (preferred_reg != -1)
00523             reg = preferred_reg;
00524         else
00525             reg = p_inst_new_temp_reg(code);
00526         p_inst_new_functor
00527             (code, (term->header.size ?
00528                         P_OP_PUT_MEMBER_VARIABLE_AUTO :
00529                         P_OP_PUT_MEMBER_VARIABLE), arg_reg, reg,
00530              term->member_var.name);
00531         p_inst_reg_used(code, arg_reg);
00532         break;
00533     case P_TERM_X_REGISTER:
00534         
00535         if (term->reg.allocated) {
00536             
00537             reg = (int)(term->header.size);
00538             if (preferred_reg != -1 && preferred_reg != reg) {
00539                 p_inst_new_two_reg
00540                     (code, P_OP_PUT_X_VALUE, reg, preferred_reg);
00541             }
00542             if (preferred_reg != -1)
00543                 reg = preferred_reg;
00544         } else if (term->reg.usage_count != 1 || preferred_reg == -1) {
00545             
00546             reg = p_inst_new_reg(code);
00547             term->header.size = (unsigned int)reg;
00548             term->reg.allocated = 1;
00549             if (preferred_reg != -1) {
00550                 p_inst_new_two_reg
00551                     (code, P_OP_PUT_X_VARIABLE2, reg, preferred_reg);
00552                 reg = preferred_reg;
00553             } else {
00554                 inst = p_inst_new
00555                     (code, P_OP_PUT_X_VARIABLE, struct p_inst_one_reg);
00556                 inst->one_reg.reg1 = reg;
00557             }
00558         } else {
00559             
00560 
00561             inst = p_inst_new
00562                 (code, P_OP_PUT_X_VARIABLE, struct p_inst_one_reg);
00563             inst->one_reg.reg1 = preferred_reg;
00564             reg = preferred_reg;
00565         }
00566         break;
00567     case P_TERM_Y_REGISTER:
00568         
00569 
00570         if (term->reg.allocated) {
00571             
00572             reg = (int)(term->header.size);
00573             if (preferred_reg != -1) {
00574                 p_inst_new_two_reg
00575                     (code, P_OP_PUT_Y_VALUE, reg, preferred_reg);
00576                 reg = preferred_reg;
00577             } else {
00578                 arg_reg = p_inst_new_temp_reg(code);
00579                 p_inst_new_two_reg
00580                     (code, P_OP_PUT_Y_VALUE, reg, arg_reg);
00581                 reg = arg_reg;
00582             }
00583         } else {
00584             
00585             reg = (code->num_yregs)++;
00586             term->header.size = (unsigned int)reg;
00587             term->reg.allocated = 1;
00588             if (preferred_reg != -1) {
00589                 p_inst_new_two_reg
00590                     (code, P_OP_PUT_Y_VARIABLE2, reg, preferred_reg);
00591                 reg = preferred_reg;
00592             } else {
00593                 arg_reg = p_inst_new_temp_reg(code);
00594                 p_inst_new_two_reg
00595                     (code, P_OP_PUT_Y_VARIABLE2, reg, arg_reg);
00596                 reg = arg_reg;
00597             }
00598         }
00599         break;
00600     default: return 0;
00601     }
00602     return reg;
00603 }
00604 
00605 
00606 
00607 
00608 int _p_code_generate_builder
00609     (p_context *context, p_term *term, p_code *code, int preferred_reg)
00610 {
00611     void *marker = p_context_mark_trail(context);
00612     int reg;
00613     p_code_analyze_variables(context, term, 0);
00614     reg = p_code_generate_builder_inner
00615         (context, term, code, preferred_reg);
00616     p_context_backtrack_trail(context, marker);
00617     return reg;
00618 }
00619 
00620 
00621 void _p_code_generate_return(p_code *code, int reg)
00622 {
00623     p_inst *inst;
00624     if (reg >= 0) {
00625         inst = p_inst_new(code, P_OP_RETURN, struct p_inst_one_reg);
00626         inst->one_reg.reg1 = reg;
00627     } else {
00628         p_inst_new(code, P_OP_RETURN_TRUE, struct p_inst_header);
00629     }
00630 }
00631 
00632 static void p_code_generate_list_unifier
00633     (p_context *context, p_term *term, p_code *code,
00634      int list_reg, int input_only);
00635 
00636 
00637 
00638 
00639 
00640 static int p_code_generate_unifier
00641     (p_context *context, p_term *term, p_code *code, int input_only)
00642 {
00643     p_term *arg;
00644     p_inst *inst;
00645     int arg_reg;
00646     unsigned int index;
00647     switch (term->header.type) {
00648     case P_TERM_FUNCTOR:
00649         
00650 
00651         arg_reg = p_inst_new_temp_reg(code);
00652         p_inst_new_functor
00653             (code, input_only ? P_OP_UNIFY_IN_FUNCTOR
00654                               : P_OP_UNIFY_FUNCTOR,
00655              arg_reg, term->header.size, term->functor.functor_name);
00656 
00657         
00658         for (index = 0; index < term->header.size; ++index) {
00659             arg = p_term_deref(term->functor.arg[index]);
00660             if (!arg)
00661                 return 0;
00662             if (p_code_generate_unifier
00663                         (context, arg, code, input_only) &&
00664                     index < (term->header.size - 1)) {
00665                 p_inst_new_two_reg
00666                     (code, P_OP_RESET_ARGUMENT, arg_reg, index + 1);
00667             }
00668         }
00669 
00670         
00671         p_inst_reg_used(code, arg_reg);
00672 
00673         
00674         return 1;
00675     case P_TERM_LIST:
00676         
00677         arg_reg = p_inst_new_temp_reg(code);
00678         inst = p_inst_new
00679             (code, input_only ? P_OP_UNIFY_IN_LIST : P_OP_UNIFY_LIST,
00680              struct p_inst_one_reg);
00681         inst->one_reg.reg1 = arg_reg;
00682         p_code_generate_list_unifier
00683             (context, term, code, arg_reg, input_only);
00684         p_inst_reg_used(code, arg_reg);
00685 
00686         
00687         return 1;
00688     case P_TERM_ATOM:
00689         
00690         inst = p_inst_new
00691             (code, input_only ? P_OP_UNIFY_IN_ATOM
00692                               : P_OP_UNIFY_ATOM,
00693              struct p_inst_constant);
00694         inst->constant.value = term;
00695         break;
00696     case P_TERM_STRING:
00697     case P_TERM_INTEGER:
00698     case P_TERM_REAL:
00699     case P_TERM_OBJECT:
00700     case P_TERM_PREDICATE:
00701     case P_TERM_CLAUSE:
00702     case P_TERM_DATABASE:
00703         
00704         inst = p_inst_new
00705             (code, input_only ? P_OP_UNIFY_IN_CONSTANT
00706                               : P_OP_UNIFY_CONSTANT,
00707              struct p_inst_constant);
00708         inst->constant.value = term;
00709         break;
00710     case P_TERM_MEMBER_VARIABLE:
00711         
00712 
00713         arg_reg = p_code_generate_builder_inner
00714             (context, term, code, -1);
00715         inst = p_inst_new
00716             (code, input_only ? P_OP_UNIFY_IN_X_VALUE
00717                               : P_OP_UNIFY_X_VALUE,
00718              struct p_inst_one_reg);
00719         inst->one_reg.reg1 = arg_reg;
00720         p_inst_reg_used(code, arg_reg);
00721         break;
00722     case P_TERM_X_REGISTER:
00723         
00724         if (term->reg.allocated) {
00725             inst = p_inst_new
00726                 (code, input_only ? P_OP_UNIFY_IN_X_VALUE
00727                                   : P_OP_UNIFY_X_VALUE,
00728                  struct p_inst_one_reg);
00729             inst->one_reg.reg1 = (int)(term->header.size);
00730         } else if (term->reg.usage_count != 1) {
00731             arg_reg = p_inst_new_reg(code);
00732             term->header.size = (unsigned int)arg_reg;
00733             term->reg.allocated = 1;
00734             inst = p_inst_new
00735                 (code, P_OP_UNIFY_X_VARIABLE, struct p_inst_one_reg);
00736             inst->one_reg.reg1 = arg_reg;
00737         } else {
00738             
00739             p_inst_new(code, input_only ? P_OP_UNIFY_IN_VOID
00740                             : P_OP_UNIFY_VOID, struct p_inst_header);
00741         }
00742         break;
00743     case P_TERM_Y_REGISTER:
00744         
00745         if (term->reg.allocated) {
00746             inst = p_inst_new
00747                 (code, input_only ? P_OP_UNIFY_IN_Y_VALUE
00748                                   : P_OP_UNIFY_Y_VALUE,
00749                  struct p_inst_one_reg);
00750             inst->one_reg.reg1 = (int)(term->header.size);
00751         } else {
00752             arg_reg = (code->num_yregs)++;
00753             term->header.size = (unsigned int)arg_reg;
00754             term->reg.allocated = 1;
00755             inst = p_inst_new
00756                 (code, P_OP_UNIFY_Y_VARIABLE, struct p_inst_one_reg);
00757             inst->one_reg.reg1 = arg_reg;
00758         }
00759         break;
00760     default: break;
00761     }
00762     return 0;
00763 }
00764 
00765 
00766 static void p_code_generate_list_unifier
00767     (p_context *context, p_term *term, p_code *code,
00768      int list_reg, int input_only)
00769 {
00770     p_term *arg;
00771     int need_reset;
00772     p_inst *inst;
00773 
00774     
00775     arg = p_term_deref(term->list.head);
00776     if (!arg)
00777         return;
00778     need_reset = p_code_generate_unifier
00779         (context, arg, code, input_only);
00780 
00781     
00782     term = p_term_deref(term->list.tail);
00783     while (term && term->header.type == P_TERM_LIST) {
00784         inst = p_inst_new
00785             (code, input_only ? P_OP_UNIFY_IN_LIST_TAIL
00786                               : P_OP_UNIFY_LIST_TAIL,
00787              struct p_inst_one_reg);
00788         inst->one_reg.reg1 = list_reg;
00789         arg = p_term_deref(term->list.head);
00790         if (!arg)
00791             return;
00792         need_reset = p_code_generate_unifier
00793             (context, arg, code, input_only);
00794         term = p_term_deref(term->list.tail);
00795     }
00796 
00797     
00798     if (!term || term == context->nil_atom) {
00799         if (need_reset) {
00800             inst = p_inst_new
00801                 (code, input_only ? P_OP_UNIFY_IN_NIL_TAIL
00802                                   : P_OP_UNIFY_NIL_TAIL,
00803                  struct p_inst_one_reg);
00804             inst->one_reg.reg1 = list_reg;
00805         } else {
00806             inst = p_inst_new
00807                 (code, input_only ? P_OP_UNIFY_IN_ATOM
00808                                   : P_OP_UNIFY_ATOM,
00809                  struct p_inst_constant);
00810             inst->constant.value = context->nil_atom;
00811         }
00812     } else {
00813         if (need_reset) {
00814             inst = p_inst_new(code, P_OP_RESET_TAIL,
00815                               struct p_inst_one_reg);
00816             inst->one_reg.reg1 = list_reg;
00817         }
00818         p_code_generate_unifier(context, term, code, input_only);
00819     }
00820 }
00821 
00822 
00823 static void p_code_generate_matcher_inner
00824     (p_context *context, p_term *term, p_code *code, int reg,
00825      int input_only)
00826 {
00827     int arg_reg;
00828     p_inst *inst;
00829     p_term *arg;
00830     unsigned int index;
00831     term = p_term_deref(term);
00832     if (!term)
00833         return;
00834     switch (term->header.type) {
00835     case P_TERM_FUNCTOR:
00836         
00837         p_inst_new_functor
00838             (code, input_only ? P_OP_GET_IN_FUNCTOR : P_OP_GET_FUNCTOR,
00839              reg, term->header.size, term->functor.functor_name);
00840 
00841         
00842         for (index = 0; index < term->header.size; ++index) {
00843             arg = p_term_deref(term->functor.arg[index]);
00844             if (!arg)
00845                 return;
00846             if (p_code_generate_unifier(context, arg, code, input_only) &&
00847                     index < (term->header.size - 1)) {
00848                 p_inst_new_two_reg
00849                     (code, P_OP_RESET_ARGUMENT, reg, index + 1);
00850             }
00851         }
00852         break;
00853     case P_TERM_LIST:
00854         
00855         arg_reg = p_inst_new_temp_reg(code);
00856         p_inst_new_two_reg
00857             (code, input_only ? P_OP_GET_IN_LIST : P_OP_GET_LIST,
00858              reg, arg_reg);
00859         p_code_generate_list_unifier
00860             (context, term, code, arg_reg, input_only);
00861         p_inst_reg_used(code, arg_reg);
00862         break;
00863     case P_TERM_ATOM:
00864         
00865         inst = p_inst_new
00866             (code, input_only ? P_OP_GET_IN_ATOM : P_OP_GET_ATOM,
00867              struct p_inst_constant);
00868         inst->constant.reg1 = reg;
00869         inst->constant.value = term;
00870         break;
00871     case P_TERM_STRING:
00872     case P_TERM_INTEGER:
00873     case P_TERM_REAL:
00874     case P_TERM_OBJECT:
00875     case P_TERM_PREDICATE:
00876     case P_TERM_CLAUSE:
00877     case P_TERM_DATABASE:
00878         
00879         inst = p_inst_new
00880             (code, input_only ? P_OP_GET_IN_CONSTANT : P_OP_GET_CONSTANT,
00881              struct p_inst_constant);
00882         inst->constant.reg1 = reg;
00883         inst->constant.value = term;
00884         break;
00885     case P_TERM_MEMBER_VARIABLE:
00886         
00887 
00888         arg_reg = p_code_generate_builder_inner
00889             (context, term, code, -1);
00890         p_inst_new_two_reg
00891             (code, input_only ? P_OP_GET_IN_X_VALUE : P_OP_GET_X_VALUE,
00892              arg_reg, reg);
00893         break;
00894     case P_TERM_X_REGISTER:
00895         
00896         if (term->reg.allocated) {
00897             arg_reg = (int)(term->header.size);
00898             if (reg != arg_reg) {
00899                 p_inst_new_two_reg
00900                     (code, input_only ? P_OP_GET_IN_X_VALUE
00901                                       : P_OP_GET_X_VALUE, arg_reg, reg);
00902             }
00903         } else if (term->reg.usage_count != 1) {
00904             
00905 
00906 
00907 
00908 
00909             arg_reg = p_inst_new_reg(code);
00910             term->header.size = (unsigned int)arg_reg;
00911             term->reg.allocated = 1;
00912             p_inst_new_two_reg(code, P_OP_PUT_X_VALUE, reg, arg_reg);
00913         }
00914         break;
00915     case P_TERM_Y_REGISTER:
00916         
00917         if (term->reg.allocated) {
00918             arg_reg = (int)(term->header.size);
00919             p_inst_new_two_reg
00920                 (code, input_only ? P_OP_GET_IN_Y_VALUE
00921                                   : P_OP_GET_Y_VALUE, arg_reg, reg);
00922         } else {
00923             arg_reg = (code->num_yregs)++;
00924             term->header.size = (unsigned int)arg_reg;
00925             term->reg.allocated = 1;
00926             p_inst_new_two_reg(code, P_OP_GET_Y_VARIABLE, reg, arg_reg);
00927         }
00928         break;
00929     default: break;
00930     }
00931 }
00932 
00933 void _p_code_generate_matcher
00934     (p_context *context, p_term *term, p_code *code, int reg,
00935      int input_only)
00936 {
00937     void *marker = p_context_mark_trail(context);
00938     p_code_analyze_variables(context, term, 0);
00939     p_code_generate_matcher_inner
00940         (context, term, code, reg, input_only);
00941     p_context_backtrack_trail(context, marker);
00942 }
00943 
00944 
00945 
00946 void _p_code_generate_dynamic_clause
00947     (p_context *context, p_term *head, p_term *body, p_code *code)
00948 {
00949     void *marker = p_context_mark_trail(context);
00950     int arity, index, reg;
00951     p_term *arg;
00952 
00953     
00954 
00955 
00956     p_code_analyze_variables(context, head, 0);
00957     p_code_analyze_variables(context, body, 0);
00958 
00959     
00960     arity = p_term_arg_count(head);
00961     _p_code_allocate_args(code, arity);
00962     for (index = 0; index < arity; ++index) {
00963         arg = p_term_deref(p_term_arg(head, index));
00964         if (!arg)
00965             continue;
00966         if (arg->header.type == P_TERM_FUNCTOR &&
00967                 arg->header.size == 1 &&
00968                 arg->functor.functor_name == context->in_atom) {
00969             p_code_generate_matcher_inner
00970                 (context, p_term_arg(arg, 0), code, index, 1);
00971         } else {
00972             p_code_generate_matcher_inner(context, arg, code, index, 0);
00973         }
00974     }
00975 
00976     
00977 
00978     if (body != context->true_atom) {
00979         reg = p_code_generate_builder_inner(context, body, code, -1);
00980         _p_code_generate_return(code, reg);
00981     } else {
00982         _p_code_generate_return(code, -1);
00983     }
00984 
00985     
00986     p_context_backtrack_trail(context, marker);
00987 }
00988 
00989 p_code *_p_code_new(void)
00990 {
00991     p_code *code = GC_NEW(p_code);
00992     code->posn = P_CODE_BLOCK_SIZE;
00993     return code;
00994 }
00995 
00996 void _p_code_finish(p_code *code, p_code_clause *clause)
00997 {
00998     p_code_block *block;
00999     p_inst *inst;
01000 
01001     
01002     block = code->current_block;
01003     if (block) {
01004         inst = (p_inst *)(((char *)(block->inst)) + code->posn);
01005         inst->header.opcode = P_OP_END;
01006     } else {
01007         p_inst_new(code, P_OP_END, struct p_inst_header);
01008     }
01009 
01010     
01011     clause->num_xregs = code->num_regs;
01012     clause->num_yregs = code->num_yregs;
01013     clause->code = code->first_block;
01014 
01015     
01016     if (code->used_regs)
01017         GC_FREE(code->used_regs);
01018     if (code->temp_regs)
01019         GC_FREE(code->temp_regs);
01020     GC_FREE(code);
01021 }
01022