diff --git a/src/compiler/llvm_codegen_expr.c b/src/compiler/llvm_codegen_expr.c index e58da4a76..92272ae1c 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -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); diff --git a/src/compiler/llvm_codegen_function.c b/src/compiler/llvm_codegen_function.c index 675f0b6a8..b64f52281 100644 --- a/src/compiler/llvm_codegen_function.c +++ b/src/compiler/llvm_codegen_function.c @@ -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; diff --git a/src/compiler/llvm_codegen_internal_impl.h b/src/compiler/llvm_codegen_internal_impl.h index b812d691e..d42612151 100644 --- a/src/compiler/llvm_codegen_internal_impl.h +++ b/src/compiler/llvm_codegen_internal_impl.h @@ -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; diff --git a/src/compiler/llvm_codegen_module.c b/src/compiler/llvm_codegen_module.c index 7c219e8fd..fcb0dde69 100644 --- a/src/compiler/llvm_codegen_module.c +++ b/src/compiler/llvm_codegen_module.c @@ -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)); diff --git a/src/compiler/llvm_codegen_stmt.c b/src/compiler/llvm_codegen_stmt.c index 63ebbdec2..85dcfa9ec 100644 --- a/src/compiler/llvm_codegen_stmt.c +++ b/src/compiler/llvm_codegen_stmt.c @@ -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); } diff --git a/src/compiler/target.c b/src/compiler/target.c index 207906aa1..8ebca3c7d 100644 --- a/src/compiler/target.c +++ b/src/compiler/target.c @@ -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 { \ diff --git a/src/compiler/target.h b/src/compiler/target.h index 35fff3c4d..5a8485cd7 100644 --- a/src/compiler/target.h +++ b/src/compiler/target.h @@ -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;