static void push_index(ClmExpNode *node) { char index_str[64]; ClmSymbol *var = clm_scope_find(data.scope, node->indExp.id); switch (var->type) { case CLM_TYPE_INT: load_var_location(var, index_str, 4, NULL); asm_push(index_str); asm_push_const_i((int)var->type); break; case CLM_TYPE_FLOAT: load_var_location(var, index_str, 4, NULL); asm_push_f(index_str); asm_push_const_i((int)var->type); break; case CLM_TYPE_MATRIX: push_matrix(node); break; case CLM_TYPE_STRING: // uhh break; default: // shouldn't get here... break; } }
static void gen_statement(ClmStmtNode *node) { switch (node->type) { case STMT_TYPE_ASSIGN: push_expression(node->assignStmt.rhs); pop_into_lhs(node->assignStmt.lhs); break; case STMT_TYPE_CALL: push_expression(node->callExpr); break; case STMT_TYPE_CONDITIONAL: gen_conditional(node); break; case STMT_TYPE_FUNC_DEC: gen_func_dec(node); break; case STMT_TYPE_FOR_LOOP: gen_for_loop(node); break; case STMT_TYPE_WHILE_LOOP: gen_while_loop(node); break; case STMT_TYPE_PRINT: push_expression(node->printStmt.expression); gen_print_type(clm_type_of_exp(node->printStmt.expression, data.scope), node->printStmt.appendNewline); break; case STMT_TYPE_RET: // reset the stack pointer, // save the frame pointer & the stack address // push the return expression onto the stack so the stack looks like this // on return: // // return val // return type // <- esp // note: T_EAX and T_EBX are globals defined in clm_asm.h asm_mov(ESP, EBP); // reset stack pointer to above the function asm_pop("[" T_EBX "]"); // pop the old frame pointer into t_ebx asm_pop("[" T_EAX "]"); // pop the stack address of the next instruction to // execute after call finishes push_expression(node->returnExpr); asm_mov(EBP, "[" T_EBX "]"); // move the old frame pointer into ebp asm_push("[" T_EAX "]"); // push the stack address of the next instruction to // execute after call finishes asm_ret(); // return break; } }
// pushes a matrix identified by the node onto the stack static void push_whole_matrix(ClmExpNode *node) { // TODO case where matrix on stack is actually a pointer char index_str[64]; ClmSymbol *var = clm_scope_find(data.scope, node->indExp.id); char cmp_label[LABEL_SIZE]; char end_label[LABEL_SIZE]; next_label(cmp_label); next_label(end_label); LOAD_COLS(var, index_str); asm_mov(EDX, index_str); // edx = cols LOAD_ROWS(var, index_str); asm_mov(EBX, index_str); // ebx = rows asm_mov(ECX, EBX); asm_imul(ECX, EDX); asm_dec(ECX); // ecx = rows * cols - 1 asm_label(cmp_label); asm_cmp(ECX, "0"); asm_jmp_l(end_label); asm_mov(EAX, ECX); asm_imul(EAX, "4"); load_var_location(var, index_str, 12, EAX); asm_push(index_str); asm_dec(ECX); asm_jmp(cmp_label); asm_label(end_label); // push type info asm_push(EDX); // cols asm_push(EBX); // rows asm_push_const_i((int)CLM_TYPE_MATRIX); }
int asm_move_regimm(uint8_t *stub, register_t reg, uintptr_t value) { uint8_t *base = stub; stub += asm_push(stub, value); if(reg >= R_R8) { *stub++ = 0x41; *stub++ = 0x58 + (reg - R_R8); } else { *stub++ = 0x58 + reg; *stub++ = 0x90; } return stub - base; }
static void push_matrix(ClmExpNode *node) { if (node->indExp.rowIndex == NULL && node->indExp.colIndex == NULL) { push_whole_matrix(node); } else if (node->indExp.rowIndex == NULL || node->indExp.colIndex == NULL) { push_row_or_col(node); } else { char index_str[64]; ClmSymbol *var = clm_scope_find(data.scope, node->indExp.id); // A[x * nc + y] gen_index_into(EAX, node->indExp.rowIndex); gen_index_into(EBX, node->indExp.colIndex); LOAD_COLS(var, index_str); asm_imul(EAX, index_str); // EAX = rowIndex * nc asm_add(EAX, EBX); // EAX = rowIndex * nc + colIndex asm_imul(EAX, "4"); // EAX = 4 * rowIndex * nc + colIndex load_var_location(var, index_str, 12, EAX); asm_push(index_str); asm_push_const_i((int)CLM_TYPE_INT); } }
static binary_op(stream, node, need_lval) { auto op = node[0], sz = type_size( node[2] ); expr_code( stream, node[3], is_assop(op) ); asm_push( stream ); expr_code( stream, node[4], 0 ); if ( op == '[]' ) subscript(stream, node, need_lval); else if ( op == '*' ) pop_mult(stream, 0, node[2][5]); else if ( op == '/' ) pop_div(stream, 0, node[2][5]); else if ( op == '%' ) pop_mod(stream, 0, node[2][5]); else if ( op == '+' ) add_op(stream, node, 0, sz); else if ( op == '-' ) add_op(stream, node, 0, sz); else if ( op == '<<' ) pop_lshift(stream, 0); else if ( op == '>>' ) pop_rshift(stream, 0); else if ( op == '&' ) pop_bitand(stream, 0, sz); else if ( op == '|' ) pop_bitor(stream, 0, sz); else if ( op == '^' ) pop_bitxor(stream, 0, sz); else if ( op == '=' ) pop_assign(stream, sz); else if ( op == '*=' ) pop_mult(stream, 1); else if ( op == '/=' ) pop_div(stream, 1); else if ( op == '%=' ) pop_mod(stream, 1); else if ( op == '+=' ) add_op(stream, node, 1, sz); else if ( op == '-=' ) add_op(stream, node, 1, sz); else if ( op == '<<=' ) pop_lshift(stream, 1); else if ( op == '>>=' ) pop_rshift(stream, 1); else if ( op == '&=' ) pop_bitand(stream, 1, sz); else if ( op == '|=' ) pop_bitor(stream, 1, sz); else if ( op == '^=' ) pop_bitxor(stream, 1, sz); else int_error("Unknown operator: '%Mc'", op); /* The assignment operators are implemented to return lvalues, but * the C standard says they're not lvalues. (The C++ standard has * them as lvalues.) */ if ( is_assop(op) ) dereference(stream, type_size(node[2]), 0); }
static do_call(stream, node, need_lval) { auto args = node[1] - 1, i = args; while ( i ) { expr_code( stream, node[ 3 + i-- ], 0 ); asm_push( stream ); } /* If we're calling an identifier that's not local and isn't an lval, * it must either be an extern function or an extern array. The latter * would be a syntax error but for the present lack of a type system * So we assume it's a function and do a direct call if possible. */ if ( node[3][0] == 'id' ) { auto off, is_lval = lookup_sym( &node[3][3], &off ); if (!off && !is_lval) return asm_call( stream, &node[3][3], args*4 ); } /* And fall back to an indirect call with CALL *%eax. */ expr_code( stream, node[3], 0 ); call_ptr( stream, args*4 ); }
static cmp_op(stream, node) { auto op = node[0]; auto type; /* By this point the types must be compatible */ if ( node[3][2][0] == '*' ) type = node[3][2]; else type = usual_conv( node[3][2], node[4][2] ); auto is_unsgn = type[5]; auto sz = type_size(type); expr_code( stream, node[3], 0 ); promote( stream, is_unsgn, type_size( node[3][2] ), sz ); asm_push( stream ); expr_code( stream, node[4], 0 ); promote( stream, is_unsgn, type_size( node[4][2] ), sz ); if ( op == '<' ) pop_lt(stream, sz, is_unsgn); else if ( op == '>' ) pop_gt(stream, sz, is_unsgn); else if ( op == '<=' ) pop_le(stream, sz, is_unsgn); else if ( op == '>=' ) pop_ge(stream, sz, is_unsgn); else if ( op == '==' ) pop_eq(stream, sz); else if ( op == '!=' ) pop_ne(stream, sz); }
static void gen_func_dec(ClmStmtNode *node) { int i; char func_label[LABEL_SIZE]; sprintf(func_label, "_%s", node->funcDecStmt.name); ClmScope *funcScope = clm_scope_find_child(data.scope, node); asm_label(func_label); asm_push(EBP); asm_mov(EBP, ESP); int local_var_size = 2 * 4 * (funcScope->symbols->length - node->funcDecStmt.parameters->length); char local_var_size_str[32]; sprintf(local_var_size_str, "%d", local_var_size); asm_sub(ESP, local_var_size_str); // each local var has 2 slots on the stack, their type and the value // for matrices, the value is a pointer to the location on the stack // these are all declared below the local variables ClmSymbol *sym; ClmExpNode *dec; char cmp_label[LABEL_SIZE]; char end_label[LABEL_SIZE]; char index_str[32]; for (i = 0; i < funcScope->symbols->length; i++) { sym = funcScope->symbols->data[i]; dec = sym->declaration; if (sym->location == LOCATION_PARAMETER) continue; // setting the type of the local var load_var_location(sym, index_str, 0, NULL); asm_mov_i(index_str, (int)sym->type); // setting the value of the local var load_var_location(sym, index_str, 4, NULL); asm_mov_i(index_str, 0); if (sym->type == CLM_TYPE_MATRIX) { // TODO what does this do? does it work? next_label(cmp_label); next_label(end_label); gen_exp_size(dec); asm_pop(EAX); // eax contains num of rows asm_pop(EBX); // ebx contains num of cols asm_mov(ECX, EAX); asm_imul(ECX, EBX); asm_label(cmp_label); asm_dec(ECX); asm_cmp(ECX, "0"); asm_jmp_eq(end_label); asm_push_const_i(0); asm_jmp(cmp_label); asm_label(end_label); asm_push(EBX); // cols // setting the pointer to point at the rows // note: push changes the value at esp and THEN // decrements it load_var_location(sym, index_str, 4, NULL); asm_mov(index_str, ESP); asm_push(EAX); // rows } } // TODO figure out strings though! data.inFunction = 1; data.scope = funcScope; gen_statements(node->funcDecStmt.body); data.scope = funcScope->parent; data.inFunction = 0; if (node->funcDecStmt.returnSize.rows == -1) { // no return value! asm_mov(ESP, EBP); asm_pop(EBP); } asm_ret(); }
// stack should look like this: // val // type static void push_expression(ClmExpNode *node) { if (node == NULL) return; ClmType expression_type = clm_type_of_exp(node, data.scope); switch (node->type) { case EXP_TYPE_INT: asm_push_const_i(node->ival); asm_push_const_i((int)expression_type); break; case EXP_TYPE_FLOAT: asm_push_const_f(node->fval); asm_push_const_i((int)expression_type); break; case EXP_TYPE_STRING: // TODO push a string onto the stack break; case EXP_TYPE_ARITH: { ClmType right_type = clm_type_of_exp(node->arithExp.right, data.scope); ClmType left_type = clm_type_of_exp(node->arithExp.left, data.scope); if (left_type == CLM_TYPE_MATRIX && clm_type_is_number(right_type)) { // here the only ops are mul & div... we are scaling matrix // gen left and then right here... if we don't then we have // int val // int type // matrix // cols // rows // matrix type // and we have to pop the int after we generate the value... which is hard // and since we are multiplying the matrix in place, it would be easiest // to // gen the matrix first and then the int, so we just have to pop two // values // in total push_expression(node->arithExp.left); asm_mov(EDX, ESP); push_expression(node->arithExp.right); gen_arith(node); } else { push_expression(node->arithExp.right); asm_mov(EDX, ESP); push_expression(node->arithExp.left); gen_arith(node); } break; } case EXP_TYPE_BOOL: push_expression(node->boolExp.right); asm_mov(EDX, ESP); push_expression(node->boolExp.left); gen_bool(node); break; case EXP_TYPE_CALL: { // first push everything thats not a matrix... and for matrices push a pointer int tempStartID = data.temporaryID; int i; ClmExpNode *param; char temporary[256]; // first for any matrices that are parameters that will be pushed through // the stack, push them on the stack and save their location into a temporary // global for (i = node->callExp.params->length - 1; i >= 0; i--) { param = node->callExp.params->data[i]; if(param->type == CLM_TYPE_MATRIX){ ClmLocation location = clm_location_of_exp(param, data.scope); switch(location){ case LOCATION_STACK: push_expression(param); next_temporary(temporary); asm_mov(temporary, ESP); break; default: break; } } } // then push every expression.. when we get to a matrix, push the pointer // to its location int tempOffset = 1; char index_str[256]; for (i = node->callExp.params->length - 1; i >= 0; i--) { param = node->callExp.params->data[i]; if(param->type == CLM_TYPE_MATRIX){ ClmLocation location = clm_location_of_exp(param, data.scope); switch(location){ case LOCATION_STACK: sprintf(temporary, "dword [temporary%d]", tempStartID + tempOffset); asm_push(temporary); tempOffset++; break; default: { // the only way its a matrix and not on the stack is if its an // ind exp with no indices ClmSymbol *symbol = clm_scope_find(data.scope, param->indExp.id); load_var_location(symbol, index_str, 0, NULL); asm_push(index_str); break; } } asm_push_const_i((int) CLM_TYPE_MATRIX); }else{ push_expression(param); } } asm_call(node->callExp.name); // TODO pop off arguments from the stack break; } case EXP_TYPE_INDEX: push_index(node); break; case EXP_TYPE_MAT_DEC: { int i; if (node->matDecExp.arr != NULL) { for (i = node->matDecExp.length - 1; i >= 0; i--) { // TODO... push f or push i? asm_push_const_i((int)node->matDecExp.arr[i]); } asm_push_const_i(node->matDecExp.size.cols); asm_push_const_i(node->matDecExp.size.rows); asm_push_const_i((int)CLM_TYPE_MATRIX); } else { // push a matrix onto the stack with all 0s char cmp_label[LABEL_SIZE]; char end_label[LABEL_SIZE]; next_label(cmp_label); next_label(end_label); gen_exp_size(node); asm_pop(EAX); // # rows asm_pop(EBX); // # cols asm_mov(ECX, EAX); asm_imul(ECX, EBX); asm_dec(ECX); asm_label(cmp_label); asm_cmp(ECX, "0"); asm_jmp_l(end_label); asm_push_const_i(0); asm_dec(ECX); asm_jmp(cmp_label); asm_label(end_label); asm_push(EBX); asm_push(EAX); asm_push_const_i((int)CLM_TYPE_MATRIX); } break; } case EXP_TYPE_PARAM: break; case EXP_TYPE_UNARY: push_expression(node->unaryExp.node); gen_unary(node); break; } }
// pushes a row or col of the matrix identified by node onto the stack static void push_row_or_col(ClmExpNode *node) { // TODO case where matrix on stack is actually a pointer char index_str[64]; ClmSymbol *var = clm_scope_find(data.scope, node->indExp.id); char cmp_label[LABEL_SIZE]; char end_label[LABEL_SIZE]; next_label(cmp_label); next_label(end_label); // put index value into EDX if(node->indExp.rowIndex != NULL){ gen_index_into(EDX, node->indExp.rowIndex); }else{ gen_index_into(EDX, node->indExp.colIndex); } if (node->indExp.rowIndex != NULL) { /* push A[x,] for i in A.cols,-1..1 do push A[x * A.cols + i] end */ LOAD_COLS(var, index_str); asm_mov(ECX, index_str); asm_imul(EDX, ECX); asm_dec(ECX); asm_label(cmp_label); asm_cmp(ECX, "0"); asm_jmp_l(end_label); asm_mov(EAX, EDX); asm_add(EAX, ECX); // eax = rowIndex * A.cols + i asm_imul(EAX, "4"); load_var_location(var, index_str, 12, EAX); asm_push(index_str); } else { /* push A[,y] for i in A.rows,-1..1 do push A[i * A.cols + y] end */ LOAD_ROWS(var, index_str); asm_mov(ECX, index_str); asm_dec(ECX); asm_label(cmp_label); asm_cmp(ECX, "0"); asm_jmp_l(end_label); asm_mov(EAX, ECX); asm_imul(EAX, index_str); asm_add(EAX, EDX); // eax = i * A.cols + y asm_imul(EAX, "4"); load_var_location(var, index_str, 12, EAX); asm_push(index_str); } asm_inc(ECX); asm_jmp(cmp_label); asm_label(end_label); }
/* pushes the number of column and then the number of rows */ static void gen_exp_size(ClmExpNode *node) { char index_str[32]; switch (node->type) { case EXP_TYPE_INT: // falthrough case EXP_TYPE_FLOAT: // fallthrough case EXP_TYPE_BOOL: asm_push_const_i(1); asm_push_const_i(1); break; case EXP_TYPE_STRING: // TODO break; case EXP_TYPE_ARITH: // TODO break; case EXP_TYPE_INDEX: // TODO break; case EXP_TYPE_CALL: // fallthrough case EXP_TYPE_MAT_DEC: // fallthrough case EXP_TYPE_PARAM: { MatrixSize size; if (node->type == EXP_TYPE_MAT_DEC) { size = node->matDecExp.size; } else if (node->type == EXP_TYPE_PARAM) { size = node->paramExp.size; } else if (node->type == EXP_TYPE_CALL) { ClmSymbol *sym = clm_scope_find(data.scope, node->callExp.name); ClmStmtNode *decl = sym->declaration; size = decl->funcDecStmt.returnSize; } if (size.colVar != NULL) { // push dword [ebp+offset] ClmSymbol *sym = clm_scope_find(data.scope, size.colVar); load_var_location(sym, index_str, 8, NULL); asm_push(index_str); } else { // push $colInd asm_push_const_i(size.cols); } if (size.rowVar != NULL) { // push dword [ebp+offset] ClmSymbol *sym = clm_scope_find(data.scope, size.rowVar); load_var_location(sym, index_str, 4, NULL); asm_push(index_str); } else { // push $rowInd asm_push_const_i(size.rows); } break; } case EXP_TYPE_UNARY: gen_exp_size(node->unaryExp.node); break; default: break; } }