Example #1
0
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;
  }
}
Example #2
0
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;
  }
}
Example #3
0
// 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);
}
Example #4
0
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;
}
Example #5
0
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);
  }
}
Example #6
0
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);
}
Example #7
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 );
}
Example #8
0
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);
}
Example #9
0
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();
}
Example #10
0
// 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;
  }
}
Example #11
0
// 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);
}
Example #12
0
/* 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;
  }
}