This is peep.c in view mode; [Download] [Up]
/* * Copyright (C) 1985-1992 New York University * * This file is part of the Ada/Ed-C system. See the Ada/Ed README file for * warranty (none) and distribution info and also the GNU General Public * License for more details. */ #define GEN #include "hdr.h" #include "vars.h" #include "gvars.h" #include "ops.h" #include "genop.h" #include "genprots.h" #include "peepprots.h" static void code_stack_copy(Op, Op); static int code_same_arg(Op, Op); static void flush(int); static int remov(int); extern int peep_option; /* defined in gmain.c */ #define STACK_DEPTH 50 #define MATCH(v) (code_stack[index-1].op_code == v) static Op_s code_stack[STACK_DEPTH + 1]; /* stack of instructions */ static int tos = 0; /* top of stack for peep-hole */ /* * P E E P - H O L E O P T I M I Z E R * * Algorithm: keep a array of instructions to be optimized in the * global array code_stack. The global variable tos is * the index of the last instruction entered in the array. * * The algorithm proceeds in three steps: * * 1/ check if the array is full and take the appropriate action. * Add the new opcode in the array and increment tos. * * 2/ loop over the list of codes, using the local variable index * as a pointer to the current instruction. * * If an optimization is performed, index is set to point to * the last untouched instruction or to the first instruction * in the array (0 is not used). At the end of the loop, it * is incremented. If an optimization is performed, index may * be decremented by 1 or left untouched. It is incremented * by 1 otherwise. The loop stops when index points to the last * instruction entered in the array. Note: it is essential that * index verifies the following relation on entry of the loop: * 2 <= index < tos * As a consequence, index must be at least 1 on exit of the loop. * * If an instruction is garanteed to prevent any further * optimization, all the instructions which preceed are flushed. * This instruction is kept in the array for the shake of the * 'fence post effect'. (I_NOT followed by I_JUMP_IF_FALSE would * not be catched otherwise). * * 3/ if the last instruction added to the array was I_END, flush * the list and reset tos to 0. * */ void peep_hole(Op next) /*;peep_hole*/ { int index; /* index in the array of instructions: 1 < index < tos */ Op temp; /* temporary op_code */ char *smalloc(); if (peep_option == 0) { /* if no optimization assemble immediately */ assemble(next); return; } if (tos == 50) flush(10); ++tos; /* put new instruction in the array */ code_stack_copy(&code_stack[tos], next); for(index = ((tos > 2) ? (tos - 1) : 2); index < tos; index++) { switch(code_stack[index].op_code) { #ifdef TBSL case(I_POP): if(MATCH(I_DEREF)) { temp = &code_stack[index-1]; temp->op_code = I_INDIRECT_POP; index = remov(index); } break; case(I_MOVE): if(MATCH(I_DEREF)) { temp = &code_stack[index-1]; temp->op_code = I_INDIRECT_MOVE; index = remov(index); } break; #endif case(I_ADD_IMMEDIATE): if(MATCH(I_ADD_IMMEDIATE) || MATCH(I_PUSH_IMMEDIATE)) { temp = &code_stack[index-1]; temp->op_arg.arg_int = (temp->op_arg.arg_int + code_stack[index].op_arg.arg_int); index = remov(index); } /* next is test for integer zero */ else if (code_stack[index].op_type == OP_INT && code_stack[index].op_arg.arg_int == 0) { index = remov(index); } break; case(I_DEREF): if(MATCH(I_PUSH_EFFECTIVE_ADDRESS)) { temp = &code_stack[index-1]; temp->op_code = I_PUSH; temp->op_kind = code_stack[index].op_kind; index = remov(index); } break; case(I_DISCARD_ADDR): if(code_stack[index+1].op_code == I_DISCARD_ADDR) { temp = &code_stack[index]; temp->op_kind += code_stack[index+1].op_kind; temp->op_arg.arg_int = temp->op_kind; index = remov(index+1); } else if(code_stack[index].op_kind == 0) { index = remov(index); } else if(MATCH(I_PUSH_EFFECTIVE_ADDRESS)) { temp = &code_stack[index]; temp->op_kind -= 1; temp->op_arg.arg_int -= 1; index = remov(index-1); } else if(MATCH(I_UPDATE)) { temp = &code_stack[index]; temp->op_kind -= 1; temp->op_arg.arg_int -= 1; index -= 1; code_stack[index].op_code = I_UPDATE_AND_DISCARD; } break; case(I_FLOAT_POW): if(MATCH(I_PUSH_IMMEDIATE)) { temp = &code_stack[index-1]; if (temp->op_arg.arg_int == 2) { temp->op_code = I_DUPLICATE; temp->op_kind = code_stack[index].op_kind; code_stack[index].op_code = I_FLOAT_MUL; } } break; case(I_PUSH): if (MATCH(I_PUSH) && (code_same_arg(&code_stack[index], &code_stack[index-1]))) { code_stack[index].op_code = I_DUPLICATE; } else if(MATCH(I_POP) && (code_same_arg(&code_stack[index], &code_stack[index-1]))) { code_stack[index].op_code = I_POP; code_stack[index-1].op_code = I_DUPLICATE; } break; case(I_PUSH_EFFECTIVE_ADDRESS): if(MATCH(I_UPDATE_AND_DISCARD) && (code_same_arg(&code_stack[index], &code_stack[index-1]))) { temp = &code_stack[index-1]; temp->op_code = I_UPDATE; index = remov(index); } break; case(I_POW): if(MATCH(I_PUSH_IMMEDIATE)) { temp = &code_stack[index-1]; if (temp->op_type == OP_INT && temp->op_arg.arg_int == 2) { temp->op_code = I_DUPLICATE; temp->op_kind = code_stack[index].op_kind; code_stack[index].op_code = I_MUL; } } break; case(I_STMT): if (MATCH(I_STMT)) { index = remov(index-1); } break; case(I_NOT): temp = &code_stack[index+1]; if(temp->op_code == I_JUMP_IF_FALSE) { temp->op_code = I_JUMP_IF_TRUE; index = remov(index); } else if(temp->op_code == I_JUMP_IF_TRUE) { temp->op_code = I_JUMP_IF_FALSE; index = remov(index); } else { flush(index); index = 1; } break; /* * Here follow the instructions for which no optimization * can be attempted. Note: those should not appear in any * of the preceeding rules. */ case(I_ABORT): case(I_ABS): case(I_ACTIVATE): case(I_ACTIVATE_NEW): case(I_ADD): case(I_AND): case(I_ALLOCATE): case(I_ALLOCATE_COPY): case(I_ARRAY_AND): case(I_ARRAY_CATENATE): case(I_ARRAY_MOVE): case(I_ARRAY_NOT): case(I_ARRAY_OR): case(I_ARRAY_SLICE): case(I_ARRAY_XOR): case(I_ATTRIBUTE): case(I_CALL): case(I_CALL_PREDEF): case(I_CASE): case(I_CASE_TABLE): case(I_COMPARE): case(I_COMPARE_STRUC): case(I_CONVERT_TO): case(I_CREATE): case(I_CREATE_COPY): case(I_CREATE_COPY_STRUC): case(I_CREATE_TASK): case(I_CURRENT_TASK): case(I_DATA): case(I_DECLARE): case(I_DIV): case(I_END_ACTIVATION): case(I_END_FOR_LOOP): case(I_END_FORREV_LOOP): case(I_END_RENDEZVOUS): case(I_ENTER_BLOCK): case(I_ENTRY_CALL): case(I_FIX_MUL): case(I_FIX_DIV): case(I_FLOAT_ABS): case(I_FLOAT_ADD): case(I_FLOAT_COMPARE): case(I_FLOAT_DIV): case(I_FLOAT_MUL): case(I_FLOAT_NEG): case(I_FLOAT_SUB): case(I_INSTALL_HANDLER): case(I_IS_EQUAL): case(I_IS_GREATER): case(I_IS_GREATER_OR_EQUAL): case(I_IS_LESS): case(I_IS_LESS_OR_EQUAL): case(I_JUMP): case(I_JUMP_IF_GREATER): case(I_JUMP_IF_GREATER_OR_EQUAL): case(I_JUMP_IF_LESS): case(I_JUMP_IF_LESS_OR_EQUAL): case(I_LABEL): case(I_LEAVE_BLOCK): case(I_LINK_TASKS_DECLARED): case(I_LOAD_EXCEPTION_REGISTER): case(I_MEMBERSHIP): case(I_MOD): case(I_MUL): case(I_NEG): case(I_NOP): case(I_OR): case(I_POP_TASKS_DECLARED): case(I_QUAL_DISCR): case(I_QUAL_INDEX): case(I_QUAL_RANGE): case(I_QUAL_SUB): case(I_RAISE_IN_CALLER): case(I_RECORD_MOVE): case(I_REM): case(I_RESTORE_STACK_POINTER): case(I_RETURN): case(I_RETURN_STRUC): case(I_SAVE_STACK_POINTER): case(I_SELECT): case(I_SELECTIVE_WAIT): case(I_SUB): case(I_SUBPROGRAM): case(I_SUBSCRIPT): case(I_TERMINATE): case(I_TEST_EXCEPTION_REGISTER): case(I_TIMED_ENTRY_CALL): case(I_TYPE_GLOBAL): case(I_TYPE_LOCAL): case(I_UNCREATE): case(I_WAIT): case(I_XOR): case(I_CALL_INTERFACE): case(I_COMPARE_ARRAYS): case(I_CHECK_REC_SUBTYPE): flush(index-1); index = 1; break; default: ; } } /* end for */ if(next->op_code == I_END) flush(tos); } static void code_stack_copy(Op opnew, Op opold) /*;code_stack_copy*/ { /* copy operation values */ register int i; register char *newc, *old; old = (char *) opold; newc = (char *) opnew; for (i = sizeof(Op_s); i; i--) *newc++ = *old++; } static int code_same_arg(Op op1, Op op2) /*;code_same_arg*/ { /* see if operations i1 and i2 in code_stack have same argument */ if (op1->op_type != op2->op_type) return FALSE; switch (op1->op_type) { case OP_FIX : return (op1->op_arg.arg_fix == op2->op_arg.arg_fix); case OP_FLT : return (op1->op_arg.arg_flt == op2->op_arg.arg_flt); case OP_INT : return (op1->op_arg.arg_int == op2->op_arg.arg_int); case OP_SYM : return (op1->op_arg.arg_sym == op2->op_arg.arg_sym); } return FALSE; } static void flush(int n) /*;flush*/ { /* Flush n instructions from the array code_stack and move * the remaining instructions n positions to the beginning * of the array. Note: n should be positive. The global * variable tos is set accordingly. If the argument is equal * to tos, all the instructions of the array are passed to * assemble and tos is set to 0 (peep-hole called with I_END). */ int i, j; for (i = 1; i <= n; i++) assemble(&code_stack[i]); for (j = 1, i = n; i++ < tos; j++) code_stack_copy(&code_stack[j], &code_stack[i]); tos -= n; } static int remov(int n) /*;remov*/ { /* * Remove the instruction of rank n from the array. * The instructions with greater values of the index, if * any, are shifted one position toward the lower indices. * This function returns the last untouched index or 1. */ int i; for (i = n; i < tos; i++) code_stack_copy(&code_stack[i], &code_stack[i+1]); tos -= 1; return ((n > 1) ? (n-1) : 1); }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.