Exemple #1
0
int
_jit_classify_param(jit_param_passing_t *passing,
					_jit_param_t *param, jit_type_t param_type)
{
	if(is_struct_or_union(param_type))
	{
		return _jit_classify_struct(passing, param, param_type);
	}
	else
	{
		int arg_class;

		arg_class = _jit_classify_arg(param_type, 0);

		switch(arg_class)
		{
			case X86_64_ARG_INTEGER:
			{
				if(passing->word_index < passing->max_word_regs)
				{
					/* Set the arg class to the number of registers used */
					param->arg_class = 1;

					/* Set the first register to the register used */
					param->un.reg_info[0].reg = passing->word_regs[passing->word_index];
					param->un.reg_info[0].value = param->value;
					++(passing->word_index);
				}
				else
				{
					/* Set the arg class to stack */
					param->arg_class = JIT_ARG_CLASS_STACK;

					/* Allocate the slot in the arg passing frame */
					_jit_alloc_param_slot(passing, param, param_type);
				}
			}
			break;

			case X86_64_ARG_SSE:
			{
				if(passing->float_index < passing->max_float_regs)
				{
					/* Set the arg class to the number of registers used */
					param->arg_class = 1;

					/* Set the first register to the register used */
					param->un.reg_info[0].reg =	passing->float_regs[passing->float_index];
					param->un.reg_info[0].value = param->value;
					++(passing->float_index);
				}
				else
				{
					/* Set the arg class to stack */
					param->arg_class = JIT_ARG_CLASS_STACK;

					/* Allocate the slot in the arg passing frame */
					_jit_alloc_param_slot(passing, param, param_type);
				}
			}
			break;

			case X86_64_ARG_MEMORY:
			{
				/* Set the arg class to stack */
				param->arg_class = JIT_ARG_CLASS_STACK;

				/* Allocate the slot in the arg passing frame */
				_jit_alloc_param_slot(passing, param, param_type);
			}
			break;
		}
	}
	return 1;
}
Exemple #2
0
static struct block *postfix_expression(struct block *block)
{
    struct var root;

    block = primary_expression(block);
    root = block->expr;

    while (1) {
        const struct member *field;
        const struct typetree *type;
        struct var expr, copy, *arg;
        struct token tok;
        int i, j;

        switch ((tok = peek()).token) {
        case '[':
            do {
                /* Evaluate a[b] = *(a + b). The semantics of pointer arithmetic
                 * takes care of multiplying b with the correct width. */
                consume('[');
                block = expression(block);
                root = eval_expr(block, IR_OP_ADD, root, block->expr);
                root = eval_deref(block, root);
                consume(']');
            } while (peek().token == '[');
            break;
        case '(':
            type = root.type;
            if (is_pointer(root.type) && is_function(root.type->next))
                type = type_deref(root.type);
            else if (!is_function(root.type)) {
                error("Expression must have type pointer to function, was %t.",
                    root.type);
                exit(1);
            }
            consume('(');
            arg = calloc(nmembers(type), sizeof(*arg));
            for (i = 0; i < nmembers(type); ++i) {
                if (peek().token == ')') {
                    error("Too few arguments, expected %d but got %d.",
                        nmembers(type), i);
                    exit(1);
                }
                block = assignment_expression(block);
                arg[i] = block->expr;
                /* todo: type check here. */
                if (i < nmembers(type) - 1) {
                    consume(',');
                }
            }
            while (is_vararg(type) && peek().token != ')') {
                consume(',');
                arg = realloc(arg, (i + 1) * sizeof(*arg));
                block = assignment_expression(block);
                arg[i] = block->expr;
                i++;
            }
            consume(')');
            for (j = 0; j < i; ++j)
                param(block, arg[j]);
            free(arg);
            root = eval_call(block, root);
            break;
        case '.':
            consume('.');
            tok = consume(IDENTIFIER);
            field = find_type_member(root.type, tok.strval);
            if (!field) {
                error("Invalid field access, no member named '%s'.",
                    tok.strval);
                exit(1);
            }
            root.type = field->type;
            root.offset += field->offset;
            break;
        case ARROW:
            consume(ARROW);
            tok = consume(IDENTIFIER);
            if (is_pointer(root.type) && is_struct_or_union(root.type->next)) {
                field = find_type_member(type_deref(root.type), tok.strval);
                if (!field) {
                    error("Invalid field access, no member named '%s'.",
                        tok.strval);
                    exit(1);
                }

                /* Make it look like a pointer to the field type, then perform
                 * normal dereferencing. */
                root.type = type_init(T_POINTER, field->type);
                root = eval_deref(block, root);
                root.offset = field->offset;
            } else {
                error("Invalid field access.");
                exit(1);
            }
            break;
        case INCREMENT:
            consume(INCREMENT);
            copy = create_var(root.type);
            eval_assign(block, copy, root);
            expr = eval_expr(block, IR_OP_ADD, root, var_int(1));
            eval_assign(block, root, expr);
            root = copy;
            break;
        case DECREMENT:
            consume(DECREMENT);
            copy = create_var(root.type);
            eval_assign(block, copy, root);
            expr = eval_expr(block, IR_OP_SUB, root, var_int(1));
            eval_assign(block, root, expr);
            root = copy;
            break;
        default:
            block->expr = root;
            return block;
        }
    }
}
Exemple #3
0
/*
 * On X86_64 the alignment of native types matches their size.
 * This leads to the result that all types except nfloats and aggregates
 * (structs and unions) must start and end in an eightbyte (or the part
 * we are looking at).
 */
static int
_jit_classify_structpart(jit_type_t struct_type, unsigned int start,
						 unsigned int start_offset, unsigned int end_offset)
{
	int arg_class = X86_64_ARG_NO_CLASS;
	unsigned int num_fields = jit_type_num_fields(struct_type);
	unsigned int current_field;
	
	for(current_field = 0; current_field < num_fields; ++current_field)
	{
		jit_nuint field_offset = jit_type_get_offset(struct_type,
													 current_field);

		if(field_offset <= end_offset)
		{
			/* The field starts at a place that's inerresting for us */
			jit_type_t field_type = jit_type_get_field(struct_type,
													   current_field);
			jit_nuint field_size = jit_type_get_size(field_type); 

			if(field_offset + field_size > start_offset)
			{
				/* The field is at least partially in the part we are */
				/* looking at */
				int arg_class2 = X86_64_ARG_NO_CLASS;

				if(is_struct_or_union(field_type))
				{
					/* We have to check this struct recursively */
					unsigned int current_start;
					unsigned int nested_struct_start;
					unsigned int nested_struct_end;

					current_start = start + start_offset;
					if(field_offset < current_start)
					{
						nested_struct_start = current_start - field_offset;
					}
					else
					{
						nested_struct_start = 0;
					}
					if(field_offset + field_size - 1 > end_offset)
					{
						/* The struct ends beyond the part we are looking at */
						nested_struct_end = field_offset + field_size -
												(nested_struct_start + 1);
					}
					else
					{
						nested_struct_end = field_size - 1;
					}
					arg_class2 = _jit_classify_structpart(field_type,
														  start + field_offset,
														  nested_struct_start,
														  nested_struct_end);
				}
				else
				{
					if((start + start_offset) & (field_size - 1))
					{
						/* The field is misaligned */
						return X86_64_ARG_MEMORY;
					}
					arg_class2 = _jit_classify_arg(field_type, 0);
				}
				if(arg_class == X86_64_ARG_NO_CLASS)
				{
					arg_class = arg_class2;
				}
				else if(arg_class != arg_class2)
				{
					if(arg_class == X86_64_ARG_MEMORY ||
					   arg_class2 == X86_64_ARG_MEMORY)
					{
						arg_class = X86_64_ARG_MEMORY;
					}
					else if(arg_class == X86_64_ARG_INTEGER ||
					   arg_class2 == X86_64_ARG_INTEGER)
					{
						arg_class = X86_64_ARG_INTEGER;
					}
					else if(arg_class == X86_64_ARG_X87 ||
					   arg_class2 == X86_64_ARG_X87)
					{
						arg_class = X86_64_ARG_MEMORY;
					}
					else
					{
						arg_class = X86_64_ARG_SSE;
					}
				}
			}
		}
	}
	return arg_class;
}