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; }
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; } } }
/* * 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; }