mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Add macro arguments &foo $foo #foo.
C ABI compatibility aarch64, win64, x86, x64 Added debug info
This commit is contained in:
committed by
Christoffer Lerno
parent
4222f2731e
commit
3c15e495dd
198
src/compiler/llvm_codegen_c_abi_win64.c
Normal file
198
src/compiler/llvm_codegen_c_abi_win64.c
Normal file
@@ -0,0 +1,198 @@
|
||||
// Copyright (c) 2020 Christoffer Lerno. All rights reserved.
|
||||
// Use of this source code is governed by a LGPLv3.0
|
||||
// a copy of which can be found in the LICENSE file.
|
||||
|
||||
#include "llvm_codegen_c_abi_internal.h"
|
||||
|
||||
ABIArgInfo *win64_classify(GenContext *context, Type *type, bool is_return, bool is_vector, bool is_reg)
|
||||
{
|
||||
if (type->type_kind == TYPE_VOID) return abi_arg_new(ABI_ARG_IGNORE);
|
||||
|
||||
// Lower enums etc.
|
||||
type = type_lowering(type);
|
||||
|
||||
Type *base = NULL;
|
||||
unsigned elements = 0;
|
||||
if ((is_vector || is_reg) && type_is_homogenous_aggregate(type, &base, &elements))
|
||||
{
|
||||
if (is_reg)
|
||||
{
|
||||
// Enough registers? Then use direct/expand
|
||||
if (context->abi.sse_registers >= elements)
|
||||
{
|
||||
context->abi.sse_registers -= elements;
|
||||
// Direct if return / builtin / vector
|
||||
if (is_return || type_is_builtin(type->type_kind) || type->type_kind == TYPE_VECTOR)
|
||||
{
|
||||
return abi_arg_new(ABI_ARG_DIRECT_COERCE);
|
||||
}
|
||||
return abi_arg_new(ABI_ARG_EXPAND);
|
||||
}
|
||||
// Otherwise use indirect
|
||||
return abi_arg_new_indirect_not_by_val();
|
||||
}
|
||||
if (is_vector)
|
||||
{
|
||||
// Enough registers AND return / builtin / vector
|
||||
if (context->abi.sse_registers >= elements &&
|
||||
(is_return || type_is_builtin(type->type_kind) || type->type_kind == TYPE_VECTOR))
|
||||
{
|
||||
context->abi.sse_registers -= elements;
|
||||
return abi_arg_new(ABI_ARG_DIRECT_COERCE);
|
||||
}
|
||||
if (is_return)
|
||||
{
|
||||
return abi_arg_new(ABI_ARG_INDIRECT);
|
||||
}
|
||||
// HVAs are handled later.
|
||||
if (!type_is_builtin(type->type_kind) && type->type_kind != TYPE_VECTOR)
|
||||
{
|
||||
return abi_arg_new_indirect_not_by_val();
|
||||
}
|
||||
// => to main handling.
|
||||
}
|
||||
}
|
||||
size_t size = type_size(type);
|
||||
if (type_is_abi_aggregate(type))
|
||||
{
|
||||
// Not 1, 2, 4, 8? Pass indirect.
|
||||
if (size > 8 || !is_power_of_two(size))
|
||||
{
|
||||
return abi_arg_new_indirect_not_by_val();
|
||||
}
|
||||
// Coerce to integer.
|
||||
return abi_arg_new_direct_coerce(abi_type_new_int_bits(size * 8));
|
||||
}
|
||||
if (type_is_builtin(type->type_kind))
|
||||
{
|
||||
switch (type->type_kind)
|
||||
{
|
||||
case TYPE_BOOL:
|
||||
return abi_arg_new_direct_int_ext(type_bool);
|
||||
case TYPE_U128:
|
||||
case TYPE_I128:
|
||||
// Pass by val since greater than 8 bytes.
|
||||
if (!is_return) return abi_arg_new_indirect_not_by_val();
|
||||
// Make i128 return in XMM0
|
||||
return abi_arg_new_direct_coerce(abi_type_new_plain(type_get_vector(type_long, 2)));
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (size > 8)
|
||||
{
|
||||
return abi_arg_new_indirect_not_by_val();
|
||||
}
|
||||
return abi_arg_new(ABI_ARG_DIRECT_COERCE);
|
||||
}
|
||||
|
||||
ABIArgInfo *win64_reclassify_hva_arg(GenContext *context, Type *type, ABIArgInfo *info)
|
||||
{
|
||||
// Assumes vectorCall calling convention.
|
||||
Type *base = NULL;
|
||||
unsigned elements = 0;
|
||||
type = type_lowering(type);
|
||||
if (!type_is_builtin(type->type_kind) && type->type_kind != TYPE_VECTOR && type_is_homogenous_aggregate(type, &base, &elements))
|
||||
{
|
||||
if (context->abi.sse_registers >= elements)
|
||||
{
|
||||
context->abi.sse_registers -= elements;
|
||||
ABIArgInfo *new_info = abi_arg_new(ABI_ARG_DIRECT_COERCE);
|
||||
new_info->attributes.by_reg = true;
|
||||
return new_info;
|
||||
}
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
void win64_vector_call_args(GenContext *context, FunctionSignature *signature, bool is_vector, bool is_reg)
|
||||
{
|
||||
static const unsigned MaxParamVectorCallsAsReg = 6;
|
||||
unsigned count = 0;
|
||||
Decl **params = signature->params;
|
||||
VECEACH(params, i)
|
||||
{
|
||||
Decl *param = params[i];
|
||||
if (count < MaxParamVectorCallsAsReg)
|
||||
{
|
||||
param->var.abi_info = win64_classify(context, param->type, false, is_vector, is_reg);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Cannot be passed in registers pretend no registers.
|
||||
unsigned regs = context->abi.sse_registers;
|
||||
context->abi.sse_registers = 0;
|
||||
param->var.abi_info = win64_classify(context, param->type, false, is_vector, is_reg);
|
||||
context->abi.sse_registers = regs;
|
||||
}
|
||||
count++;
|
||||
}
|
||||
VECEACH(params, i)
|
||||
{
|
||||
Decl *param = params[i];
|
||||
param->var.abi_info = win64_reclassify_hva_arg(context, param->type, param->var.abi_info);
|
||||
}
|
||||
|
||||
}
|
||||
void c_abi_func_create_win64(GenContext *context, FunctionSignature *signature)
|
||||
{
|
||||
// allow calling sysv?
|
||||
|
||||
// Set up return registers.
|
||||
context->abi.int_registers = 0;
|
||||
bool is_reg_call = false;
|
||||
bool is_vector_call = false;
|
||||
switch (context->abi.call_convention)
|
||||
{
|
||||
case CALL_CONVENTION_VECTOR:
|
||||
context->abi.sse_registers = 4;
|
||||
is_vector_call = true;
|
||||
break;
|
||||
case CALL_CONVENTION_REGCALL:
|
||||
context->abi.sse_registers = 16;
|
||||
is_reg_call = true;
|
||||
break;
|
||||
default:
|
||||
context->abi.sse_registers = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (signature->failable)
|
||||
{
|
||||
signature->failable_abi_info = win64_classify(context, type_error, true, is_vector_call, is_reg_call);
|
||||
if (signature->rtype->type->type_kind != TYPE_VOID)
|
||||
{
|
||||
signature->ret_abi_info = win64_classify(context, type_get_ptr(type_lowering(signature->rtype->type)), false, is_vector_call, is_reg_call);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
signature->ret_abi_info = win64_classify(context, signature->rtype->type, true, is_vector_call, is_reg_call);
|
||||
}
|
||||
|
||||
// Set up parameter registers.
|
||||
switch (context->abi.call_convention)
|
||||
{
|
||||
case CALL_CONVENTION_VECTOR:
|
||||
context->abi.sse_registers = 6;
|
||||
is_vector_call = true;
|
||||
break;
|
||||
case CALL_CONVENTION_REGCALL:
|
||||
context->abi.sse_registers = 16;
|
||||
is_reg_call = true;
|
||||
break;
|
||||
default:
|
||||
context->abi.sse_registers = 0;
|
||||
break;
|
||||
}
|
||||
if (is_vector_call)
|
||||
{
|
||||
win64_vector_call_args(context, signature, is_vector_call, is_reg_call);
|
||||
return;
|
||||
}
|
||||
Decl **params = signature->params;
|
||||
VECEACH(params, i)
|
||||
{
|
||||
params[i]->var.abi_info = win64_classify(context, params[i]->type, false, is_vector_call, is_reg_call);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user