예제 #1
0
파일: gen.c 프로젝트: irori/8cc
static void emit_expr(Node *node) {
    SAVE;
    switch (node->type) {
    case AST_LITERAL: emit_literal(node); return;
    case AST_STRING:  emit_literal_string(node); return;
    case AST_LVAR:    emit_lvar(node); return;
    case AST_GVAR:    emit_gvar(node); return;
    case AST_FUNCALL:
    case AST_FUNCPTR_CALL:
        emit_func_call(node);
        return;
    case AST_DECL:    emit_decl(node); return;
    case AST_CONV:    emit_conv(node); return;
    case AST_ADDR:    emit_addr(node->operand); return;
    case AST_DEREF:   emit_deref(node); return;
    case AST_IF:
    case AST_TERNARY:
        emit_ternary(node);
        return;
    case AST_FOR:     emit_for(node); return;
    case AST_WHILE:   emit_while(node); return;
    case AST_DO:      emit_do(node); return;
    case AST_SWITCH:  emit_switch(node); return;
    case AST_CASE:    emit_case(node); return;
    case AST_DEFAULT: emit_default(node); return;
    case AST_GOTO:    emit_goto(node); return;
    case AST_LABEL:
        if (node->newlabel)
            emit_label(node->newlabel);
        return;
    case AST_RETURN:  emit_return(node); return;
    case AST_BREAK:   emit_break(node); return;
    case AST_CONTINUE: emit_continue(node); return;
    case AST_COMPOUND_STMT: emit_compound_stmt(node); return;
    case AST_STRUCT_REF:
        emit_load_struct_ref(node->struc, node->ctype, 0);
        return;
    case AST_VA_START: emit_va_start(node); return;
    case AST_VA_ARG:   emit_va_arg(node); return;
    case OP_UMINUS:    emit_uminus(node); return;
    case OP_PRE_INC:   emit_pre_inc_dec(node, "add"); return;
    case OP_PRE_DEC:   emit_pre_inc_dec(node, "sub"); return;
    case OP_POST_INC:  emit_post_inc_dec(node, "add"); return;
    case OP_POST_DEC:  emit_post_inc_dec(node, "sub"); return;
    case '!': emit_lognot(node); return;
    case '&': emit_bitand(node); return;
    case '|': emit_bitor(node); return;
    case '~': emit_bitnot(node); return;
    case OP_LOGAND: emit_logand(node); return;
    case OP_LOGOR:  emit_logor(node); return;
    case OP_CAST:   emit_cast(node); return;
    case ',': emit_comma(node); return;
    case '=': emit_assign(node); return;
    case OP_LABEL_ADDR: emit_label_addr(node); return;
    case AST_COMPUTED_GOTO: emit_computed_goto(node); return;
    default:
        emit_binop(node);
    }
}
예제 #2
0
파일: gen.c 프로젝트: 4ker/8cc
static void emit_expr(Node *node) {
    SAVE;
    maybe_print_source_loc(node);
    switch (node->kind) {
    case AST_LITERAL: emit_literal(node); return;
    case AST_LVAR:    emit_lvar(node); return;
    case AST_GVAR:    emit_gvar(node); return;
    case AST_FUNCDESG: return;
    case AST_FUNCALL:
        if (maybe_emit_builtin(node))
            return;
        // fall through
    case AST_FUNCPTR_CALL:
        emit_func_call(node);
        return;
    case AST_DECL:    emit_decl(node); return;
    case AST_CONV:    emit_conv(node); return;
    case AST_ADDR:    emit_addr(node->operand); return;
    case AST_DEREF:   emit_deref(node); return;
    case AST_IF:
    case AST_TERNARY:
        emit_ternary(node);
        return;
    case AST_GOTO:    emit_goto(node); return;
    case AST_LABEL:
        if (node->newlabel)
            emit_label(node->newlabel);
        return;
    case AST_RETURN:  emit_return(node); return;
    case AST_COMPOUND_STMT: emit_compound_stmt(node); return;
    case AST_STRUCT_REF:
        emit_load_struct_ref(node->struc, node->ty, 0);
        return;
    case OP_PRE_INC:   emit_pre_inc_dec(node, "add"); return;
    case OP_PRE_DEC:   emit_pre_inc_dec(node, "sub"); return;
    case OP_POST_INC:  emit_post_inc_dec(node, "add"); return;
    case OP_POST_DEC:  emit_post_inc_dec(node, "sub"); return;
    case '!': emit_lognot(node); return;
    case '&': emit_bitand(node); return;
    case '|': emit_bitor(node); return;
    case '~': emit_bitnot(node); return;
    case OP_LOGAND: emit_logand(node); return;
    case OP_LOGOR:  emit_logor(node); return;
    case OP_CAST:   emit_cast(node); return;
    case ',': emit_comma(node); return;
    case '=': emit_assign(node); return;
    case OP_LABEL_ADDR: emit_label_addr(node); return;
    case AST_COMPUTED_GOTO: emit_computed_goto(node); return;
    default:
        emit_binop(node);
    }
}
예제 #3
0
파일: gen.c 프로젝트: irori/8cc
static void emit_copy_struct(Node *left, Node *right) {
    push("rcx");
    push("r11");
    emit_addr(right);
    emit("mov %%rax, %%rcx");
    emit_addr(left);
    int i = 0;
    for (; i < left->ctype->size; i += 8) {
        emit("movq %d(%%rcx), %%r11", i);
        emit("movq %%r11, %d(%%rax)", i);
    }
    for (; i < left->ctype->size; i += 4) {
        emit("movl %d(%%rcx), %%r11", i);
        emit("movl %%r11, %d(%%rax)", i);
    }
    for (; i < left->ctype->size; i++) {
        emit("movb %d(%%rcx), %%r11", i);
        emit("movb %%r11, %d(%%rax)", i);
    }
    pop("r11");
    pop("rcx");
}
예제 #4
0
파일: gen.c 프로젝트: 4ker/8cc
static void emit_copy_struct(Node *left, Node *right) {
    push("rcx");
    push("r11");
    emit_addr(right);
    emit("mov #rax, #rcx");
    emit_addr(left);
    int i = 0;
    for (; i < left->ty->size; i += 8) {
        emit("movq %d(#rcx), #r11", i);
        emit("movq #r11, %d(#rax)", i);
    }
    for (; i < left->ty->size; i += 4) {
        emit("movl %d(#rcx), #r11", i);
        emit("movl #r11, %d(#rax)", i);
    }
    for (; i < left->ty->size; i++) {
        emit("movb %d(#rcx), #r11", i);
        emit("movb #r11, %d(#rax)", i);
    }
    pop("r11");
    pop("rcx");
}
예제 #5
0
파일: gen.c 프로젝트: irori/8cc
static void emit_addr(Node *node) {
    switch (node->type) {
    case AST_LVAR:
        ensure_lvar_init(node);
        emit("lea %d(%%rbp), %%rax", node->loff);
        break;
    case AST_GVAR:
        emit("lea %s(%%rip), %%rax", node->glabel);
        break;
    case AST_DEREF:
        emit_expr(node->operand);
        break;
    case AST_STRUCT_REF:
        emit_addr(node->struc);
        emit("add $%d, %%rax", node->ctype->offset);
        break;
    default:
        error("internal error: %s", a2s(node));
    }
}
예제 #6
0
파일: gen.c 프로젝트: 4ker/8cc
static int emit_args(Vector *vals) {
    SAVE;
    int r = 0;
    for (int i = 0; i < vec_len(vals); i++) {
        Node *v = vec_get(vals, i);
        if (v->ty->kind == KIND_STRUCT) {
            emit_addr(v);
            r += push_struct(v->ty->size);
        } else if (is_flotype(v->ty)) {
            emit_expr(v);
            push_xmm(0);
            r += 8;
        } else {
            emit_expr(v);
            push("rax");
            r += 8;
        }
    }
    return r;
}
예제 #7
0
파일: gen.c 프로젝트: 4ker/8cc
static void emit_addr(Node *node) {
    switch (node->kind) {
    case AST_LVAR:
        ensure_lvar_init(node);
        emit("lea %d(#rbp), #rax", node->loff);
        break;
    case AST_GVAR:
        emit("lea %s(#rip), #rax", node->glabel);
        break;
    case AST_DEREF:
        emit_expr(node->operand);
        break;
    case AST_STRUCT_REF:
        emit_addr(node->struc);
        emit("add $%d, #rax", node->ty->offset);
        break;
    case AST_FUNCDESG:
        emit("lea %s(#rip), #rax", node->fname);
        break;
    default:
        error("internal error: %s", node2s(node));
    }
}
예제 #8
0
파일: emit_code.c 프로젝트: shabiel/YottaDB
void emit_trip(generic_op op, oprtype *opr, bool val_output, unsigned char use_reg)
{
	unsigned char		base_reg, temp_reg;
	int4			offset, literal;
	triple			*ct;

	if (opr->oprclass == TRIP_REF)
	{
		ct = opr->oprval.tref;
		if (ct->destination.oprclass)
		{
			opr = &ct->destination;
		}
		/* else lit or error */
	}

	switch (cg_phase)
	{
	case CGP_ADDR_OPT:
	case CGP_APPROX_ADDR:
		switch (opr->oprclass)
		{
		case TRIP_REF:
			assert(ct->destination.oprclass == 0);
			assert(val_output);
			switch (ct->opcode)
			{
			case OC_LIT:
				if (run_time)
				{
					int4	pc_value_idx;

					switch (op)
					{
					case LOAD_ADDRESS:
						temp_reg = use_reg;
						break;
					case PUSH:
					case PUSH_ADDRESS:
						temp_reg = I386_REG_ECX;
						break;
					default:
						rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_UNIMPLOP);
						break;
					}
					pc_value_idx = code_idx + 5;
					code_idx += 1 + SIZEOF(int4) + 1;
					emit_addr(0, (int4)ct->operand[0].oprval.mlit->rt_addr, &offset);
					offset -= pc_value_idx;
					force_32 = 1;
					emit_op_base_offset(op, temp_reg, offset, temp_reg);
					force_32 = 0;
				}
				else
				{
					emit_op_alit(op, use_reg);
					code_idx += SIZEOF(int4);
				}
				if (cg_phase == CGP_APPROX_ADDR)
					txtrel_cnt++;
				break;
			case OC_CDLIT:
				if (cg_phase == CGP_APPROX_ADDR)
					define_symbol(GTM_LITERALS, ct->operand[0].oprval.cdlt, 0);
				emit_op_alit(op, use_reg);
				code_idx += SIZEOF(int4);
				break;
			case OC_ILIT:
				literal = ct->operand[0].oprval.ilit;
				switch(op)
				{
				case COMPARE: /* 1byte(opcode) + 1byte(ModR/M) + 4byte(literal) */
					code_idx += 2 + SIZEOF(int4);
					break;
				case LOAD:
					code_idx += 1 + SIZEOF(int4);
					break;
				case PUSH:
					if (literal >= -128  &&  literal <= 127)
						code_idx += 2;
					else
						code_idx += 1 + SIZEOF(int4);
					break;
				default:
					rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_UNIMPLOP);
					break;
				}
				break;
			default:
				assertpro(FALSE && ct->opcode);
				break;
			}
			break;
		case TINT_REF:
		case TVAL_REF:
			assert(val_output);
			offset = sa_temps_offset[opr->oprclass];
			offset -= (sa_temps[opr->oprclass] - opr->oprval.temp) * sa_class_sizes[opr->oprclass];
			assertpro((0 <= offset) && (65535 >= offset));
			emit_op_base_offset(op, I386_REG_EDI, offset, use_reg);
			break;
		case TCAD_REF:
		case TVAD_REF:
		case TVAR_REF:
			offset = sa_temps_offset[opr->oprclass];
			offset -= (sa_temps[opr->oprclass] - opr->oprval.temp) * sa_class_sizes[opr->oprclass];
			assertpro((0 <= offset) && (65535 >= offset));
			if (opr->oprclass == TVAR_REF)
				base_reg = I386_REG_ESI;
			else
				base_reg = I386_REG_EDI;
			switch (op)
			{
			case JUMP:
				if (val_output)
				{
					code_idx++;
					emit_base_offset(I386_REG_EAX, base_reg, offset);
				}
				code_idx++;
				if (val_output)
					emit_base_offset(I386_INS_JMP_Ev, I386_REG_EAX, 0);
				else
					emit_base_offset(I386_INS_JMP_Ev, base_reg, offset);
				break;
			case LOAD_ADDRESS:
				code_idx++;
				emit_base_offset(use_reg, base_reg, offset);
				if (opr->oprclass == TVAR_REF)
				{
					code_idx++;
					emit_base_offset(use_reg, use_reg, offsetof(ht_ent_mname, value));
				}
				break;
			case PUSH:
				if (!val_output)
				{
					code_idx++;
					emit_base_offset(I386_INS_PUSH_Ev, base_reg, offset);
				}
				else
				{
					code_idx++;
					emit_base_offset(I386_REG_ECX, base_reg, offset);

					code_idx++;
					emit_base_offset(I386_INS_PUSH_Ev, I386_REG_ECX, 0);
				}
				break;
			case PUSH_ADDRESS:
				if (val_output)
				{
					if (opr->oprclass == TVAR_REF)
					{
						code_idx++;
						emit_base_offset(use_reg, base_reg, offset);
						code_idx++;
						emit_base_offset(I386_INS_PUSH_Ev, use_reg, offsetof(ht_ent_mname, value));
					}
					else
					{
						code_idx++;
						emit_base_offset(I386_INS_PUSH_Ev, base_reg, offset);
					}
				}
				else
				{
					code_idx++;
					emit_base_offset(I386_REG_ECX, base_reg, offset);
					code_idx++;
				}
				break;
			case STORE:
				if (val_output)
				{
					if (use_reg == I386_REG_EAX)
						temp_reg = I386_REG_EDX;
					else
						temp_reg = I386_REG_EAX;
					code_idx++;
					emit_base_offset(temp_reg, base_reg, offset);
				}
				code_idx++;
				if (val_output)
					emit_base_offset(use_reg, temp_reg, 0);
				else
					emit_base_offset(use_reg, base_reg, offset);
				break;
			default:
				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_UNIMPLOP);
				break;
			}
			break;
		}
		break;
	case CGP_MACHINE:
		switch (opr->oprclass)
		{
		case TRIP_REF:
			assert(ct->destination.oprclass == 0);
			assert(val_output);
			switch (ct->opcode)
			{
			case OC_LIT:
				assert(ct->operand[0].oprclass == MLIT_REF);
				if (run_time)
				{
					int4	pc_value_idx;

					switch(op)
					{
					case LOAD_ADDRESS:
						temp_reg = use_reg;
						break;
					case PUSH:
					case PUSH_ADDRESS:
						temp_reg = I386_REG_ECX;
						break;
					default:
						rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_UNIMPLOP);
						break;
					}
					code_buf[code_idx++] = I386_INS_CALL_Jv;
					*((int4 *)&code_buf[code_idx]) = 0;
					code_idx += SIZEOF(int4);

					pc_value_idx = code_idx;
					code_buf[code_idx++] = I386_INS_POP_eAX + temp_reg;

					emit_addr(0, (int4)ct->operand[0].oprval.mlit->rt_addr, &offset);
					offset -= pc_value_idx;
					force_32 = 1;
					emit_op_base_offset(op, temp_reg, offset, temp_reg);
					force_32 = 0;
				}
				else
				{
					emit_op_alit(op, use_reg);
					emit_addr(code_reference + (code_idx * SIZEOF(unsigned char)),
						(int4)ct->operand[0].oprval.mlit->rt_addr, (int4 *)&code_buf[code_idx]);
					code_idx += SIZEOF(int4);
				}
				break;
			case OC_CDLIT:
				emit_op_alit(op, use_reg);
				emit_reference(code_reference + (code_idx * SIZEOF(unsigned char)),
					ct->operand[0].oprval.cdlt, (uint4 *)&code_buf[code_idx]);
				code_idx += SIZEOF(int4);
				break;
			case OC_ILIT:
				literal = ct->operand[0].oprval.ilit;
				switch (op)
				{
				case COMPARE: /* cmpl $literal,use_reg - 1byte(opcode) + 1byte(ModR/M) + 4byte(literal) */
					code_buf[code_idx++] = I386_INS_Grp1_Ev_Iv_Prefix;
					modrm_byte.modrm.reg_opcode = I386_INS_CMP__;
					modrm_byte.modrm.mod = I386_MOD32_REGISTER;
					modrm_byte.modrm.r_m = use_reg;
					code_buf[code_idx++] = modrm_byte.byte;
					*((int4 *)&code_buf[code_idx]) = literal;
					code_idx += SIZEOF(int4);
					break;
				case LOAD:
					code_buf[code_idx++] = I386_INS_MOV_eAX + use_reg;
					*((int4 *)&code_buf[code_idx]) = literal;
					code_idx += SIZEOF(int4);
					break;
				case PUSH:
					if (literal >= -128  &&  literal <= 127)
					{
						code_buf[code_idx++] = I386_INS_PUSH_Ib;
						code_buf[code_idx++] = literal & 0xff;
					}
					else
					{
						code_buf[code_idx++] = I386_INS_PUSH_Iv;
						*((int4 *)&code_buf[code_idx]) = literal;
						code_idx += SIZEOF(int4);
					}
					break;
				default:
					rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_UNIMPLOP);
					break;
				}
				break;
			default:
				assertpro(FALSE && ct->opcode);
				break;
			}
			break;
		case TINT_REF:
		case TVAL_REF:
			assert(val_output);
			offset = sa_temps_offset[opr->oprclass];
			offset -= (sa_temps[opr->oprclass] - opr->oprval.temp) * sa_class_sizes[opr->oprclass];
			assertpro((0 <= offset) && (65535 >= offset));
			emit_op_base_offset(op, I386_REG_EDI, offset, use_reg);
			break;
		case TCAD_REF:
		case TVAD_REF:
		case TVAR_REF:
			offset = sa_temps_offset[opr->oprclass];
			offset -= (sa_temps[opr->oprclass] - opr->oprval.temp) * sa_class_sizes[opr->oprclass];
			assertpro((0 <= offset) && (65535 >= offset));
			if (opr->oprclass == TVAR_REF)
				base_reg = I386_REG_ESI;
			else
				base_reg = I386_REG_EDI;

			switch (op)
			{
			case JUMP:
				assert(use_reg == 0);
				if (val_output)
				{
					code_buf[code_idx++] = I386_INS_MOV_Gv_Ev;
					emit_base_offset(I386_REG_EAX, base_reg, offset);
				}
				code_buf[code_idx++] = I386_INS_Grp5_Prefix;
				if (val_output)
					emit_base_offset(I386_INS_JMP_Ev, I386_REG_EAX, 0);
				else
					emit_base_offset(I386_INS_JMP_Ev, base_reg, offset);
				break;
			case LOAD_ADDRESS:
				if (val_output)
					code_buf[code_idx++] = I386_INS_MOV_Gv_Ev;
				else
					code_buf[code_idx++] = I386_INS_LEA_Gv_M;
				emit_base_offset(use_reg, base_reg, offset);
				if (opr->oprclass == TVAR_REF)
				{
					code_buf[code_idx++] = I386_INS_MOV_Gv_Ev;
					emit_base_offset(use_reg, use_reg, offsetof(ht_ent_mname, value));
				}
				break;
			case PUSH:
				if (val_output)
				{
					code_buf[code_idx++] = I386_INS_MOV_Gv_Ev;
					emit_base_offset(I386_REG_ECX, base_reg, offset);

					code_buf[code_idx++] = I386_INS_Grp5_Prefix;
					emit_base_offset(I386_INS_PUSH_Ev, I386_REG_ECX, 0);
				}
				else
				{
					code_buf[code_idx++] = I386_INS_Grp5_Prefix;
					emit_base_offset(I386_INS_PUSH_Ev, base_reg, offset);
				}
				break;
			case PUSH_ADDRESS:
				if (val_output)
				{
					if (opr->oprclass == TVAR_REF)
					{
						code_buf[code_idx++] = I386_INS_MOV_Gv_Ev;
						emit_base_offset(use_reg, base_reg, offset);
						code_buf[code_idx++] = I386_INS_Grp5_Prefix;
						emit_base_offset(I386_INS_PUSH_Ev, use_reg, offsetof(ht_ent_mname, value));
					}
					else
					{
						code_buf[code_idx++] = I386_INS_Grp5_Prefix;
						emit_base_offset(I386_INS_PUSH_Ev, base_reg, offset);
					}
				}
				else
				{
					code_buf[code_idx++] = I386_INS_LEA_Gv_M;
					emit_base_offset(I386_REG_ECX, base_reg, offset);

					code_buf[code_idx++] = I386_INS_PUSH_eCX;
				}
				break;
			case STORE:
				if (val_output)
				{
					if (use_reg == I386_REG_EAX)
						temp_reg = I386_REG_EDX;
					else
						temp_reg = I386_REG_EAX;
					assert(temp_reg != use_reg);
					code_buf[code_idx++] = I386_INS_MOV_Gv_Ev;
					emit_base_offset(temp_reg, base_reg, offset);
				}
				code_buf[code_idx++] = I386_INS_MOV_Ev_Gv;
				if (val_output)
					emit_base_offset(use_reg, temp_reg, 0);
				else
					emit_base_offset(use_reg, base_reg, offset);
				break;
			default:
				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_UNIMPLOP);
				break;
			}
			break;
		default:
			assertpro(FALSE && opr->oprclass);
			break;
		}
		break;
	default:
		assertpro(FALSE && cg_phase);
		break;
	}
}