mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Comments and cleanup.
This commit is contained in:
@@ -54,6 +54,12 @@ INLINE void llvm_emit_initialize_reference_bitstruct_array(GenContext *c, BEValu
|
||||
|
||||
#define MAX_AGG 16
|
||||
|
||||
/**
|
||||
* Emit an expression into a value (as opposed to the address)
|
||||
* @param c the current context
|
||||
* @param expr the expression to emit
|
||||
* @return the LLVM value.
|
||||
*/
|
||||
static inline LLVMValueRef llvm_emit_expr_to_rvalue(GenContext *c, Expr *expr)
|
||||
{
|
||||
BEValue value;
|
||||
@@ -206,6 +212,16 @@ static LLVMValueRef llvm_emit_coerce_alignment(GenContext *c, BEValue *be_value,
|
||||
return be_value->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Emit a two value aggregate { value1, value2 }. If the values are constant, emit this
|
||||
* as a constant, otherwise generate two inserts.
|
||||
*
|
||||
* @param c the context
|
||||
* @param type the type of the aggregate
|
||||
* @param value1 the first value
|
||||
* @param value2 the second value
|
||||
* @return the resulting aggregate
|
||||
*/
|
||||
LLVMValueRef llvm_emit_aggregate_two(GenContext *c, Type *type, LLVMValueRef value1, LLVMValueRef value2)
|
||||
{
|
||||
bool is_constant = llvm_is_const(value1) && llvm_is_const(value2);
|
||||
@@ -219,6 +235,15 @@ LLVMValueRef llvm_emit_aggregate_two(GenContext *c, Type *type, LLVMValueRef val
|
||||
return llvm_emit_insert_value(c, result, value2, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a value as an aggregate,
|
||||
* @param c the context
|
||||
* @param value the BEValue to set.
|
||||
* @param type the type of the aggregate
|
||||
* @param value1 the first value
|
||||
* @param value2 the second value
|
||||
* @return the resulting aggregate
|
||||
*/
|
||||
void llvm_value_aggregate_two(GenContext *c, BEValue *value, Type *type, LLVMValueRef value1, LLVMValueRef value2)
|
||||
{
|
||||
llvm_value_set(value, llvm_emit_aggregate_two(c, type, value1, value2), type);
|
||||
@@ -238,7 +263,16 @@ static inline LLVMValueRef llvm_const_high_bitmask(GenContext *c, LLVMTypeRef ty
|
||||
return LLVMBuildNot(c->builder, llvm_emit_lshr_fixed(c, llvm_get_ones_raw(type), high_bits), "");
|
||||
}
|
||||
|
||||
LLVMValueRef llvm_mask_low_bits(GenContext *c, LLVMValueRef value, unsigned low_bits)
|
||||
/**
|
||||
* Given an integer value, return the n lowest bits. This function is
|
||||
* valid even for low_bits == 0.
|
||||
*
|
||||
* @param c the context
|
||||
* @param value the value to mask
|
||||
* @param low_bits the number of bits to retain
|
||||
* @return the resulting masked value.
|
||||
*/
|
||||
static inline LLVMValueRef llvm_mask_low_bits(GenContext *c, LLVMValueRef value, unsigned low_bits)
|
||||
{
|
||||
LLVMTypeRef type = LLVMTypeOf(value);
|
||||
if (low_bits < 1) return llvm_get_zero_raw(type);
|
||||
@@ -248,6 +282,15 @@ LLVMValueRef llvm_mask_low_bits(GenContext *c, LLVMValueRef value, unsigned low_
|
||||
return llvm_emit_and_raw(c, mask, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the desired padding type for n number of bytes, returning an i8 for size = 1
|
||||
* otherwise returning [i8 x size] for
|
||||
* larger padding. The size must be at least 1.
|
||||
*
|
||||
* @param c the context
|
||||
* @param size the size of the padding 1 or higher
|
||||
* @return the resulting padding type
|
||||
*/
|
||||
LLVMTypeRef llvm_const_padding_type(GenContext *c, AlignSize size)
|
||||
{
|
||||
assert(size > 0);
|
||||
@@ -255,6 +298,13 @@ LLVMTypeRef llvm_const_padding_type(GenContext *c, AlignSize size)
|
||||
return LLVMArrayType(c->byte_type, (unsigned)size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an undefined constant with a given padding.
|
||||
*
|
||||
* @param c the context
|
||||
* @param size the size of the padding, must be 1 or more.
|
||||
* @return the resulting padding.
|
||||
*/
|
||||
LLVMValueRef llvm_emit_const_padding(GenContext *c, AlignSize size)
|
||||
{
|
||||
return llvm_get_undef_raw(llvm_const_padding_type(c, size));
|
||||
@@ -285,19 +335,32 @@ static inline LLVMValueRef llvm_emit_add_int(GenContext *c, Type *type, LLVMValu
|
||||
return LLVMBuildAdd(c->builder, left, right, "add");
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively find the largest, non-trivial inner type that is the dest_size or smaller.
|
||||
*
|
||||
* @param c context
|
||||
* @param type the LLVM type to step into
|
||||
* @param dest_size the min size
|
||||
* @return the type containing this inner type.
|
||||
*/
|
||||
static LLVMTypeRef llvm_find_inner_struct_type_for_coerce(GenContext *c, LLVMTypeRef type, ByteSize dest_size)
|
||||
{
|
||||
ByteSize container_size = llvm_store_size(c, type);
|
||||
while (1)
|
||||
{
|
||||
if (LLVMGetTypeKind(type) != LLVMStructTypeKind) break;
|
||||
// This should strictly speaking never happen because we don't have zero size elements.
|
||||
if (!LLVMCountStructElementTypes(type)) break;
|
||||
|
||||
LLVMTypeRef first_element = LLVMStructGetTypeAtIndex(type, 0);
|
||||
ByteSize first_element_size = llvm_store_size(c, first_element);
|
||||
// If the size is smaller than the total size and smaller than the destination size
|
||||
// then we're done.
|
||||
if (first_element_size < dest_size && first_element_size < llvm_store_size(c, type)) break;
|
||||
AlignSize dummy;
|
||||
// If the size is smaller than the desired size, the previous type is what we wanted.
|
||||
// then we're done if this type is actually smaller than our previous.
|
||||
// The reason for the second check is to avoid the case when one isn't stepping into the sub
|
||||
// structs, e.g. struct { struct { int } }. Here, even if dest_size > 4, we want struct { int }.
|
||||
if (first_element_size < dest_size && first_element_size < container_size) break;
|
||||
type = first_element;
|
||||
container_size = first_element_size;
|
||||
}
|
||||
return type;
|
||||
}
|
||||
@@ -1034,6 +1097,7 @@ INLINE LLVMValueRef llvm_emit_bitstruct_value_update(GenContext *c, LLVMValueRef
|
||||
current_val = llvm_emit_or_raw(c, current_val, val);
|
||||
return current_val;
|
||||
}
|
||||
|
||||
static inline void llvm_emit_bitassign_expr(GenContext *c, BEValue *be_value, Expr *expr)
|
||||
{
|
||||
Expr *lhs = exprptr(expr->binary_expr.left);
|
||||
|
||||
@@ -16,9 +16,14 @@ static inline void llvm_emit_body(GenContext *c, LLVMValueRef function, const ch
|
||||
FileId file_id, FunctionPrototype *prototype, Signature *signature, Ast *body);
|
||||
|
||||
|
||||
bool llvm_emit_check_block_branch(GenContext *context)
|
||||
/**
|
||||
* Erases the current block if it is empty.
|
||||
* @param c the context to use.
|
||||
* @return true if the block was erased.
|
||||
*/
|
||||
bool llvm_emit_check_block_branch(GenContext *c)
|
||||
{
|
||||
if (!context->current_block) return false;
|
||||
if (!c->current_block) return false;
|
||||
// If it's not used, we can delete the previous block and skip the branch.
|
||||
// Unless it is the entry block or a label target for jumps
|
||||
// These empty blocks will occur when doing branches.
|
||||
@@ -41,13 +46,13 @@ bool llvm_emit_check_block_branch(GenContext *context)
|
||||
// br label %for.cond
|
||||
//
|
||||
// But this leaves us with blocks that have no parent.
|
||||
// Consequently we will delete those and realize that
|
||||
// Consequently, we will delete those and realize that
|
||||
// we then have no need for emitting a br.
|
||||
if (!context->current_block_is_target
|
||||
&& !LLVMGetFirstUse(LLVMBasicBlockAsValue(context->current_block)))
|
||||
if (!c->current_block_is_target
|
||||
&& !LLVMGetFirstUse(LLVMBasicBlockAsValue(c->current_block)))
|
||||
{
|
||||
LLVMDeleteBasicBlock(context->current_block);
|
||||
context->current_block = NULL;
|
||||
LLVMDeleteBasicBlock(c->current_block);
|
||||
c->current_block = NULL;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -226,7 +226,6 @@ INLINE bool llvm_is_local_eval(GenContext *c)
|
||||
return c->builder != c->global_builder;
|
||||
}
|
||||
|
||||
|
||||
INLINE LLVMValueRef llvm_emit_and_raw(GenContext *c, LLVMValueRef lhs, LLVMValueRef rhs)
|
||||
{
|
||||
if (llvm_is_const_null(lhs)) return lhs;
|
||||
|
||||
@@ -5,7 +5,12 @@
|
||||
#include "llvm_codegen_internal.h"
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Create the introspection type { byte kind, void* dtable, usz sizeof, typeid inner, usz len, [0xtypeid] additional }
|
||||
*
|
||||
* @param c the context
|
||||
* @return the generated introspection type.
|
||||
*/
|
||||
static inline LLVMTypeRef create_introspection_type(GenContext *c)
|
||||
{
|
||||
LLVMTypeRef type = LLVMStructCreateNamed(c->context, ".introspect");
|
||||
@@ -21,6 +26,11 @@ static inline LLVMTypeRef create_introspection_type(GenContext *c)
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the fault type { typeid parent, String[] name, usz ordinal }
|
||||
* @param c the context to use.
|
||||
* @return the resulting LLVM type.
|
||||
*/
|
||||
static inline LLVMTypeRef create_fault_type(GenContext *c)
|
||||
{
|
||||
LLVMTypeRef type = LLVMStructCreateNamed(c->context, ".fault");
|
||||
@@ -29,6 +39,15 @@ static inline LLVMTypeRef create_fault_type(GenContext *c)
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a module flag.
|
||||
*
|
||||
* @param c the context to use
|
||||
* @param flag_behavior how the flag should be merged
|
||||
* @param flag the flag name
|
||||
* @param value the flag value
|
||||
* @param type the type of the flag value
|
||||
*/
|
||||
static void llvm_set_module_flag(GenContext *c, LLVMModuleFlagBehavior flag_behavior, const char *flag, uint64_t value, Type *type)
|
||||
{
|
||||
LLVMMetadataRef val = LLVMValueAsMetadata(LLVMConstInt(LLVMIntTypeInContext(c->context, type_bit_size(type)), value, false));
|
||||
|
||||
@@ -1001,15 +1001,17 @@ static inline void llvm_emit_assert_stmt(GenContext *c, Ast *ast)
|
||||
llvm_emit_cond_br(c, &value, on_ok, on_fail);
|
||||
llvm_emit_block(c, on_fail);
|
||||
SourceSpan loc = assert_expr->span;
|
||||
const char *error = NULL;
|
||||
const char *error = "Assert violation";
|
||||
const char *fmt = NULL;
|
||||
Expr *message_expr = exprptrzero(ast->assert_stmt.message);
|
||||
BEValue *values = NULL;
|
||||
if (message_expr)
|
||||
{
|
||||
error = exprptr(ast->assert_stmt.message)->const_expr.string.chars;
|
||||
const char *err_msg = exprptr(ast->assert_stmt.message)->const_expr.string.chars;
|
||||
Expr **args = ast->assert_stmt.args;
|
||||
if (vec_size(args))
|
||||
{
|
||||
fmt = err_msg;
|
||||
FOREACH_BEGIN(Expr *arg, args)
|
||||
BEValue var;
|
||||
llvm_emit_expr(c, &var, arg);
|
||||
@@ -1017,12 +1019,12 @@ static inline void llvm_emit_assert_stmt(GenContext *c, Ast *ast)
|
||||
vec_add(values, var);
|
||||
FOREACH_END();
|
||||
}
|
||||
else
|
||||
{
|
||||
error = err_msg;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
error = "Assert violation";
|
||||
}
|
||||
llvm_emit_panic(c, values ? NULL : error, loc, values ? error : NULL, values);
|
||||
llvm_emit_panic(c, error, loc, fmt, values);
|
||||
llvm_emit_br(c, on_ok);
|
||||
llvm_emit_block(c, on_ok);
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@ static unsigned os_target_supports_int128(OsType os, ArchType arch);
|
||||
static unsigned os_target_supports_float16(OsType os, ArchType arch);
|
||||
static unsigned os_target_supports_float128(OsType os, ArchType arch);
|
||||
static unsigned os_target_supports_vec(OsType os, ArchType arch, int bits, bool is_int);
|
||||
static bool os_requires_libc(OsType os);
|
||||
static void x86_features_from_host(X86Features *cpu_features);
|
||||
static void x86_features_add_feature(X86Features *cpu_features, X86Feature feature);
|
||||
static const char *x86features_as_string(X86Features *cpu_features);
|
||||
@@ -1460,15 +1459,6 @@ static unsigned os_target_c_type_bits(OsType os, ArchType arch, CType type)
|
||||
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
MACHO_MANGLING,
|
||||
ELF_MANGLING,
|
||||
MIPS_MANGLING,
|
||||
WIN86_MANGLING,
|
||||
WIN_MANGLING,
|
||||
XCOFF_MANGLING
|
||||
} Mangling;
|
||||
|
||||
|
||||
static AlignData os_target_alignment_of_int(OsType os, ArchType arch, uint32_t bits)
|
||||
{
|
||||
@@ -1660,36 +1650,6 @@ static bool arch_os_pic_default_forced(ArchType arch, OsType os)
|
||||
}
|
||||
|
||||
|
||||
static AlignSize os_target_pref_alignment_of_float(OsType os, ArchType arch, uint32_t bits)
|
||||
{
|
||||
switch (arch)
|
||||
{
|
||||
case ARCH_TYPE_UNKNOWN:
|
||||
case ARCH_UNSUPPORTED:
|
||||
UNREACHABLE
|
||||
case ARCH_TYPE_X86:
|
||||
if (os == OS_TYPE_ELFIAMCU && bits >= 32) return 4;
|
||||
return bits / 8;
|
||||
case ARCH_TYPE_AARCH64:
|
||||
case ARCH_TYPE_AARCH64_BE:
|
||||
case ARCH_TYPE_PPC64:
|
||||
case ARCH_TYPE_PPC64LE:
|
||||
case ARCH_TYPE_PPC:
|
||||
case ARCH_TYPE_RISCV32:
|
||||
case ARCH_TYPE_RISCV64:
|
||||
case ARCH_TYPE_WASM32:
|
||||
case ARCH_TYPE_WASM64:
|
||||
case ARCH_TYPE_ARM:
|
||||
case ARCH_TYPE_THUMB:
|
||||
case ARCH_TYPE_THUMBEB:
|
||||
case ARCH_TYPE_ARMB:
|
||||
return bits / 8;
|
||||
case ARCH_TYPE_X86_64:
|
||||
if (bits == 128 && os == OS_TYPE_ELFIAMCU) return 4;
|
||||
return bits / 8;
|
||||
}
|
||||
UNREACHABLE
|
||||
}
|
||||
|
||||
|
||||
#define INITIALIZE_TARGET(X) do { \
|
||||
|
||||
@@ -267,6 +267,7 @@ typedef struct
|
||||
ABI abi;
|
||||
AlignData integers[BITSIZES_LEN];
|
||||
AlignData floats[BITSIZES_LEN];
|
||||
AlignData floats_pref[BITSIZES_LEN];
|
||||
RelocModel reloc_model;
|
||||
bool pic_required : 1;
|
||||
bool signed_c_char : 1;
|
||||
|
||||
Reference in New Issue
Block a user