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