Comments and cleanup.

This commit is contained in:
Christoffer Lerno
2023-06-30 18:02:34 +02:00
parent 378ea1deea
commit 9102fc6032
7 changed files with 111 additions and 61 deletions

View File

@@ -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);

View File

@@ -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;

View File

@@ -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;

View File

@@ -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));

View File

@@ -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);
}

View File

@@ -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 { \

View File

@@ -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;