Files
c3c/src/compiler/llvm_codegen_internal_impl.h

379 lines
11 KiB
C

INLINE LLVMValueRef llvm_emit_insert_value(GenContext *c, LLVMValueRef agg, LLVMValueRef new_value, ArraySize index) // NOLINT
{
if (LLVMGetTypeKind(LLVMTypeOf(agg)) == LLVMVectorTypeKind)
{
LLVMValueRef index_val = llvm_const_int(c, type_usz, index);
return LLVMBuildInsertElement(c->builder, agg, new_value, index_val, "");
}
return LLVMBuildInsertValue(c->builder, agg, new_value, index, "");
}
INLINE bool llvm_is_int_or_vector_int(LLVMTypeRef type)
{
if (LLVMGetTypeKind(type) == LLVMIntegerTypeKind) return true;
return LLVMGetTypeKind(type) == LLVMVectorTypeKind
&& LLVMGetTypeKind(LLVMGetElementType(type)) == LLVMIntegerTypeKind;
}
INLINE LLVMValueRef llvm_zext_trunc(GenContext *c, LLVMValueRef data, LLVMTypeRef type)
{
LLVMTypeRef current_type = LLVMTypeOf(data);
if (current_type == type) return data;
ASSERT(llvm_is_int_or_vector_int(type));
ASSERT(llvm_is_int_or_vector_int(current_type));
if (llvm_bitsize(c, current_type) < llvm_bitsize(c, type))
{
return LLVMBuildZExt(c->builder, data, type, "zext");
}
ASSERT(llvm_bitsize(c, current_type) > llvm_bitsize(c, type));
return LLVMBuildTrunc(c->builder, data, type, "trunc");
}
INLINE LLVMValueRef llvm_sext_trunc(GenContext *c, LLVMValueRef data, LLVMTypeRef type)
{
LLVMTypeRef current_type = LLVMTypeOf(data);
if (current_type == type) return data;
ASSERT(llvm_is_int_or_vector_int(type));
ASSERT(llvm_is_int_or_vector_int(current_type));
if (llvm_bitsize(c, current_type) < llvm_bitsize(c, type))
{
return LLVMBuildSExt(c->builder, data, type, "sext");
}
ASSERT(llvm_bitsize(c, current_type) > llvm_bitsize(c, type));
return LLVMBuildTrunc(c->builder, data, type, "trunc");
}
INLINE bool type_is_intlike(Type *type)
{
type = type_flatten(type);
if (type_is_integer_or_bool_kind(type)) return true;
if (!type_kind_is_real_vector(type->type_kind)) return false;
type = type->array.base;
return type_is_integer_or_bool_kind(type);
}
INLINE void llvm_value_ext_trunc(GenContext *c, BEValue *value, Type *type)
{
type = type_flatten(type);
Type *from_type = value->type;
ByteSize size = type_size(from_type);
ByteSize to_size = type_size(type);
ASSERT(type_is_intlike(type) && type_is_intlike(from_type));
if (size == to_size) return;
llvm_value_rvalue(c, value);
LLVMTypeRef current_type = llvm_get_type(c, type);
if (size < to_size)
{
if (type_is_signed(from_type))
{
value->value = LLVMBuildSExt(c->builder, value->value, current_type, "sext");
value->type = type;
return;
}
value->value = LLVMBuildZExt(c->builder, value->value, current_type, "zext");
value->type = type;
return;
}
value->value = LLVMBuildTrunc(c->builder, value->value, current_type, "trunc");
value->type = type;
}
INLINE LLVMValueRef llvm_store_decl(GenContext *c, Decl *decl, BEValue *value)
{
BEValue ref;
llvm_value_set_decl(c, &ref, decl);
ASSERT(llvm_value_is_addr(&ref));
return llvm_store(c, &ref, value);
}
INLINE LLVMValueRef llvm_store_raw(GenContext *c, BEValue *destination, LLVMValueRef raw_value)
{
ASSERT(llvm_value_is_addr(destination));
return llvm_store_to_ptr_raw_aligned(c, destination->value, raw_value, destination->alignment);
}
INLINE LLVMValueRef llvm_store_decl_raw(GenContext *context, Decl *decl, LLVMValueRef value)
{
ASSERT(!decl->is_value);
return llvm_store_to_ptr_raw_aligned(context, decl->backend_ref, value, decl->alignment);
}
INLINE AlignSize llvm_type_or_alloca_align(LLVMValueRef dest, Type *type)
{
if (LLVMIsAAllocaInst(dest) || LLVMIsAGlobalVariable(dest))
{
return LLVMGetAlignment(dest);
}
return type_alloca_alignment(type);
}
INLINE LLVMValueRef llvm_store_to_ptr(GenContext *c, LLVMValueRef destination, BEValue *value)
{
return llvm_store_to_ptr_aligned(c, destination, value, llvm_type_or_alloca_align(destination, value->type));
}
INLINE LLVMValueRef llvm_store_to_ptr_raw(GenContext *c, LLVMValueRef pointer, LLVMValueRef value, Type *type)
{
return llvm_store_to_ptr_raw_aligned(c, pointer, value, llvm_type_or_alloca_align(pointer, type));
}
INLINE void llvm_value_bitcast(GenContext *c UNUSED, BEValue *value, Type *type)
{
ASSERT(llvm_value_is_addr(value));
value->type = type_lowering(type);
}
INLINE LLVMValueRef llvm_emit_shl(GenContext *c, LLVMValueRef value, LLVMValueRef shift)
{
return LLVMBuildShl(c->builder, value, shift, "shl");
}
INLINE LLVMValueRef llvm_emit_ashr(GenContext *c, LLVMValueRef value, LLVMValueRef shift)
{
return LLVMBuildAShr(c->builder, value, shift, "ashr");
}
INLINE LLVMValueRef llvm_emit_lshr(GenContext *c, LLVMValueRef value, LLVMValueRef shift)
{
return LLVMBuildLShr(c->builder, value, shift, "lshrl");
}
INLINE LLVMValueRef llvm_emit_trunc_bool(GenContext *c, LLVMValueRef value)
{
LLVMTypeRef type = LLVMTypeOf(value);
if (LLVMGetTypeKind(type) == LLVMVectorTypeKind)
{
return LLVMBuildTrunc(c->builder, value, LLVMVectorType(c->bool_type, LLVMGetVectorSize(type)), "");
}
return LLVMBuildTrunc(c->builder, value, c->bool_type, "");
}
INLINE LLVMValueRef llvm_emit_extract_value(GenContext *c, LLVMValueRef agg, unsigned index)
{
if (LLVMGetTypeKind(LLVMTypeOf(agg)) == LLVMVectorTypeKind )
{
return LLVMBuildExtractElement(c->builder, agg, llvm_const_int(c, type_usz, index), "");
}
return LLVMBuildExtractValue(c->builder, agg, index, "");
}
INLINE bool llvm_use_accurate_debug_info(GenContext *context)
{
return context->debug.builder && compiler.build.optlevel <= OPTIMIZATION_NONE;
}
INLINE bool llvm_use_debug(GenContext *context) { return context->debug.builder != NULL; }
INLINE bool llvm_basic_block_is_unused(LLVMBasicBlockRef block)
{
return !LLVMGetFirstInstruction(block) && !LLVMGetFirstUse(LLVMBasicBlockAsValue(block));
}
static inline bool llvm_delete_current_if_unused(GenContext *c)
{
LLVMBasicBlockRef current = c->current_block;
if (!current || !llvm_basic_block_is_unused(current)) return false;
LLVMBasicBlockRef prev_block = LLVMGetPreviousBasicBlock(current);
LLVMDeleteBasicBlock(current);
c->current_block = prev_block;
LLVMPositionBuilderAtEnd(c->builder, prev_block);
return true;
}
static inline LLVMBasicBlockRef llvm_get_current_block_if_in_use(GenContext *c)
{
LLVMBasicBlockRef block = c->current_block;
if (block && llvm_basic_block_is_unused(block))
{
LLVMDeleteBasicBlock(block);
return c->current_block = NULL;
}
return block;
}
static inline LLVMCallConv llvm_call_convention_from_call(CallABI abi)
{
switch (abi)
{
case CALL_C:
return LLVMCCallConv;
case CALL_X64_VECTOR:
return LLVMX86VectorCallCallConv;
case CALL_AAPCS:
return LLVMARMAAPCSCallConv;
case CALL_AAPCS_VFP:
return LLVMARMAAPCSVFPCallConv;
default:
return LLVMCCallConv;
}
}
INLINE bool llvm_is_global_eval(GenContext *c)
{
return c->builder == c->global_builder;
}
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;
if (llvm_is_const_null(rhs)) return rhs;
return LLVMBuildAnd(c->builder, lhs, rhs, "");
}
INLINE LLVMValueRef llvm_emit_or_raw(GenContext *c, LLVMValueRef lhs, LLVMValueRef rhs)
{
if (llvm_is_const_null(lhs)) return rhs;
if (llvm_is_const_null(rhs)) return lhs;
return LLVMBuildOr(c->builder, lhs, rhs, "");
}
INLINE LLVMValueRef llvm_emit_and(GenContext *c, BEValue *lhs, BEValue *rhs)
{
return llvm_emit_and_raw(c, lhs->value, rhs->value);
}
INLINE LLVMValueRef llvm_get_zero(GenContext *c, Type *type)
{
return LLVMConstNull(llvm_get_type(c, type));
}
INLINE LLVMValueRef llvm_get_zero_raw(LLVMTypeRef type)
{
return LLVMConstNull(type);
}
INLINE LLVMValueRef llvm_get_undef(GenContext *c, Type *type)
{
return LLVMGetUndef(llvm_get_type(c, type));
}
INLINE LLVMValueRef llvm_get_undef_raw(LLVMTypeRef type)
{
return LLVMGetUndef(type);
}
INLINE LLVMValueRef llvm_get_ones_raw(LLVMTypeRef type)
{
return LLVMConstAllOnes(type);
}
INLINE bool llvm_is_const_null(LLVMValueRef value)
{
return LLVMIsNull(value);
}
INLINE bool llvm_is_const(LLVMValueRef value)
{
return LLVMIsConstant(value);
}
INLINE LLVMValueRef llvm_get_zstring(GenContext *c, const char *str, size_t len)
{
ASSERT(len == (unsigned)len);
return LLVMConstStringInContext(c->context, str, (unsigned)len, 0);
}
INLINE LLVMValueRef llvm_get_bytes(GenContext *c, const char *str, size_t len)
{
ASSERT(len == (unsigned)len);
return LLVMConstStringInContext(c->context, str, (unsigned)len, 1);
}
INLINE LLVMValueRef llvm_get_struct(GenContext *c, LLVMValueRef *vals, size_t len)
{
ASSERT(len == (unsigned)len);
return LLVMConstStructInContext(c->context, vals, (unsigned)len, false);
}
INLINE LLVMValueRef llvm_get_packed_struct(GenContext *c, LLVMValueRef *vals, size_t len)
{
ASSERT(len == (unsigned)len);
return LLVMConstStructInContext(c->context, vals, (unsigned)len, true);
}
INLINE LLVMValueRef llvm_get_unnamed_struct(GenContext *c, LLVMValueRef *vals, bool is_packed)
{
return LLVMConstStructInContext(c->context, vals, vec_size(vals), is_packed);
}
INLINE LLVMValueRef llvm_get_array(LLVMTypeRef type, LLVMValueRef *vals, unsigned count)
{
return LLVMConstArray(type, vals, count);
}
INLINE LLVMValueRef llvm_get_struct_named(LLVMTypeRef type, LLVMValueRef *vals, unsigned count)
{
return LLVMConstNamedStruct(type, vals, count);
}
INLINE LLVMValueRef llvm_get_struct_of_type(GenContext *c, Type *type, LLVMValueRef *vals, unsigned count)
{
return LLVMConstNamedStruct(llvm_get_type(c, type), vals, count);
}
INLINE LLVMValueRef llvm_const_integer(GenContext *c, Int128 i, Type *type)
{
switch (type_lowering(type)->type_kind)
{
case TYPE_I128:
case TYPE_U128:
{
uint64_t words[2] = { i.low, i.high };
return LLVMConstIntOfArbitraryPrecision(llvm_get_type(c, type), 2, words);
}
default:
return llvm_const_int(c, type, i.low);
}
}
INLINE LLVMValueRef llvm_const_int(GenContext *c, Type *type, uint64_t val)
{
type = type_lowering(type);
ASSERT(type_is_integer(type) || type->type_kind == TYPE_BOOL);
return LLVMConstInt(llvm_get_type(c, type), val, type_is_integer_signed(type));
}
INLINE LLVMValueRef llvm_add_global(GenContext *c, const char *name, Type *type, AlignSize alignment)
{
return llvm_add_global_raw(c, name, llvm_get_type(c, type_lowering(type_no_optional(type))), alignment);
}
INLINE LLVMValueRef llvm_add_global_raw(GenContext *c, const char *name, LLVMTypeRef type, AlignSize alignment)
{
LLVMValueRef ref = LLVMAddGlobal(c->module, type, name);
LLVMSetAlignment(ref, (unsigned)alignment ? alignment : LLVMPreferredAlignmentOfGlobal(c->target_data, ref));
return ref;
}
INLINE void llvm_emit_exprid(GenContext *c, BEValue *value, ExprId expr)
{
ASSERT(expr);
llvm_emit_expr(c, value, exprptr(expr));
}
INLINE void llvm_set_alignment(LLVMValueRef alloca, AlignSize alignment)
{
ASSERT(alignment > 0);
LLVMSetAlignment(alloca, (unsigned)alignment);
}
INLINE void llvm_emit_statement_chain(GenContext *c, AstId current)
{
while (current)
{
llvm_emit_stmt(c, ast_next(&current));
}
}