mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Added round/ceil/trunc/sqrt intrinsics.
This commit is contained in:
@@ -1188,6 +1188,10 @@ extern const char *kw_len;
|
||||
extern const char *kw_ordinal;
|
||||
extern const char *kw___alloc;
|
||||
extern const char *kw___free;
|
||||
extern const char *kw___round;
|
||||
extern const char *kw___ceil;
|
||||
extern const char *kw___trunc;
|
||||
extern const char *kw___sqrt;
|
||||
|
||||
#define AST_NEW_TOKEN(_kind, _token) new_ast(_kind, source_span_from_token_id(_token.id))
|
||||
#define AST_NEW(_kind, _loc) new_ast(_kind, _loc)
|
||||
|
||||
@@ -203,15 +203,66 @@ static inline unsigned lookup_attribute(const char *name)
|
||||
}
|
||||
|
||||
static bool intrinsics_setup = false;
|
||||
unsigned intrinsic_id_ssub_overflow;
|
||||
unsigned intrinsic_id_usub_overflow;
|
||||
unsigned intrinsic_id_sadd_overflow;
|
||||
unsigned intrinsic_id_uadd_overflow;
|
||||
unsigned intrinsic_id_smul_overflow;
|
||||
unsigned intrinsic_id_umul_overflow;
|
||||
unsigned intrinsic_id_trap;
|
||||
unsigned intrinsic_id_assume;
|
||||
|
||||
unsigned intrinsic_id_ssub_overflow;
|
||||
unsigned intrinsic_id_ssub_sat;
|
||||
unsigned intrinsic_id_usub_overflow;
|
||||
unsigned intrinsic_id_usub_sat;
|
||||
unsigned intrinsic_id_sadd_overflow;
|
||||
unsigned intrinsic_id_sadd_sat;
|
||||
unsigned intrinsic_id_uadd_overflow;
|
||||
unsigned intrinsic_id_uadd_sat;
|
||||
unsigned intrinsic_id_smul_overflow;
|
||||
unsigned intrinsic_id_umul_overflow;
|
||||
unsigned intrinsic_id_sshl_sat;
|
||||
unsigned intrinsic_id_ushl_sat;
|
||||
unsigned intrinsic_id_fmuladd;
|
||||
unsigned intrinsic_id_rint;
|
||||
unsigned intrinsic_id_trunc;
|
||||
unsigned intrinsic_id_ceil;
|
||||
unsigned intrinsic_id_floor;
|
||||
unsigned intrinsic_id_sqrt;
|
||||
unsigned intrinsic_id_nearbyint;
|
||||
unsigned intrinsic_id_roundeven;
|
||||
unsigned intrinsic_in_lround;
|
||||
unsigned intrinsic_in_llround;
|
||||
unsigned intrinsic_in_lrint;
|
||||
unsigned intrinsic_in_llrint;
|
||||
unsigned intrinsic_id_powi;
|
||||
unsigned intrinsic_id_pow;
|
||||
unsigned intrinsic_id_sin;
|
||||
unsigned intrinsic_id_cos;
|
||||
unsigned intrinsic_id_exp;
|
||||
unsigned intrinsic_id_exp2;
|
||||
unsigned intrinsic_id_log;
|
||||
unsigned intrinsic_id_log10;
|
||||
unsigned intrinsic_id_fabs;
|
||||
unsigned intrinsic_id_fma;
|
||||
unsigned intrinsic_id_copysign;
|
||||
unsigned intrinsic_id_minnum;
|
||||
unsigned intrinsic_id_maxnum;
|
||||
unsigned intrinsic_id_minimum;
|
||||
unsigned intrinsic_id_maximum;
|
||||
unsigned intrinsic_id_smax;
|
||||
unsigned intrinsic_id_smin;
|
||||
unsigned intrinsic_id_umax;
|
||||
unsigned intrinsic_id_umin;
|
||||
unsigned intrinsic_id_abs;
|
||||
unsigned intrinsic_id_fshl;
|
||||
unsigned intrinsic_id_fshr;
|
||||
unsigned intrinsic_id_bitreverse;
|
||||
unsigned intrinsic_id_bswap;
|
||||
unsigned intrinsic_id_ctpop;
|
||||
unsigned intrinsic_id_ctlz;
|
||||
unsigned intrinsic_id_cttz;
|
||||
unsigned intrinsic_id_convert_from_fp16;
|
||||
unsigned intrinsic_id_convert_to_fp16;
|
||||
|
||||
|
||||
|
||||
|
||||
unsigned attribute_noinline;
|
||||
unsigned attribute_alwaysinline;
|
||||
unsigned attribute_inlinehint;
|
||||
@@ -231,15 +282,69 @@ unsigned attribute_inreg;
|
||||
void llvm_codegen_setup()
|
||||
{
|
||||
assert(intrinsics_setup == false);
|
||||
intrinsic_id_ssub_overflow = lookup_intrinsic("llvm.ssub.with.overflow");
|
||||
intrinsic_id_usub_overflow = lookup_intrinsic("llvm.usub.with.overflow");
|
||||
intrinsic_id_sadd_overflow = lookup_intrinsic("llvm.sadd.with.overflow");
|
||||
intrinsic_id_uadd_overflow = lookup_intrinsic("llvm.uadd.with.overflow");
|
||||
intrinsic_id_smul_overflow = lookup_intrinsic("llvm.smul.with.overflow");
|
||||
intrinsic_id_umul_overflow = lookup_intrinsic("llvm.umul.with.overflow");
|
||||
intrinsic_id_trap = lookup_intrinsic("llvm.trap");
|
||||
intrinsic_id_assume = lookup_intrinsic("llvm.assume");
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
intrinsic_id_ssub_overflow = lookup_intrinsic("llvm.ssub.with.overflow");
|
||||
intrinsic_id_ssub_sat = lookup_intrinsic("llvm.ssub.sat");
|
||||
intrinsic_id_usub_overflow = lookup_intrinsic("llvm.usub.with.overflow");
|
||||
intrinsic_id_usub_sat = lookup_intrinsic("llvm.usub.sat");
|
||||
intrinsic_id_sadd_overflow = lookup_intrinsic("llvm.sadd.with.overflow");
|
||||
intrinsic_id_sadd_sat = lookup_intrinsic("llvm.sadd.sat");
|
||||
intrinsic_id_uadd_overflow = lookup_intrinsic("llvm.uadd.with.overflow");
|
||||
intrinsic_id_uadd_sat = lookup_intrinsic("llvm.uadd.sat");
|
||||
intrinsic_id_smul_overflow = lookup_intrinsic("llvm.smul.with.overflow");
|
||||
intrinsic_id_umul_overflow = lookup_intrinsic("llvm.umul.with.overflow");
|
||||
//intrinsic_id_sshl_sat = lookup_intrinsic("llvm.sshl.sat");
|
||||
//intrinsic_id_ushl_sat = lookup_intrinsic("llvm.ushl.sat");
|
||||
intrinsic_id_fshl = lookup_intrinsic("llvm.fshl");
|
||||
intrinsic_id_fshr = lookup_intrinsic("llvm.fshr");
|
||||
intrinsic_id_bitreverse = lookup_intrinsic("llvm.bitreverse");
|
||||
intrinsic_id_bswap = lookup_intrinsic("llvm.bswap");
|
||||
intrinsic_id_ctpop = lookup_intrinsic("llvm.ctpop");
|
||||
intrinsic_id_cttz = lookup_intrinsic("llvm.cttz");
|
||||
intrinsic_id_ctlz = lookup_intrinsic("llvm.ctlz");
|
||||
|
||||
intrinsic_id_rint = lookup_intrinsic("llvm.rint");
|
||||
intrinsic_id_trunc = lookup_intrinsic("llvm.trunc");
|
||||
intrinsic_id_ceil = lookup_intrinsic("llvm.ceil");
|
||||
intrinsic_id_floor = lookup_intrinsic("llvm.floor");
|
||||
intrinsic_id_sqrt = lookup_intrinsic("llvm.sqrt");
|
||||
intrinsic_id_powi = lookup_intrinsic("llvm.powi");
|
||||
intrinsic_id_pow = lookup_intrinsic("llvm.pow");
|
||||
intrinsic_id_sin = lookup_intrinsic("llvm.sin");
|
||||
intrinsic_id_cos = lookup_intrinsic("llvm.cos");
|
||||
intrinsic_id_exp = lookup_intrinsic("llvm.exp");
|
||||
intrinsic_id_exp2 = lookup_intrinsic("llvm.exp2");
|
||||
intrinsic_id_log = lookup_intrinsic("llvm.log");
|
||||
intrinsic_id_log10 = lookup_intrinsic("llvm.log10");
|
||||
intrinsic_id_fabs = lookup_intrinsic("llvm.fabs");
|
||||
intrinsic_id_fma = lookup_intrinsic("llvm.fma");
|
||||
intrinsic_id_copysign = lookup_intrinsic("llvm.copysign");
|
||||
intrinsic_id_minnum = lookup_intrinsic("llvm.minnum");
|
||||
intrinsic_id_maxnum = lookup_intrinsic("llvm.maxnum");
|
||||
intrinsic_id_minimum = lookup_intrinsic("llvm.minimum");
|
||||
intrinsic_id_maximum = lookup_intrinsic("llvm.maximum");
|
||||
intrinsic_id_convert_to_fp16 = lookup_intrinsic("llvm.convert.to.fp16");
|
||||
intrinsic_id_convert_from_fp16 = lookup_intrinsic("llvm.convert.from.fp16");
|
||||
intrinsic_id_nearbyint = lookup_intrinsic("llvm.nearbyint");
|
||||
intrinsic_id_roundeven = lookup_intrinsic("llvm.roundeven");
|
||||
intrinsic_in_lround = lookup_intrinsic("llvm.lround");
|
||||
intrinsic_in_llround = lookup_intrinsic("llvm.llround");
|
||||
intrinsic_in_lrint = lookup_intrinsic("llvm.lrint");
|
||||
intrinsic_in_llrint = lookup_intrinsic("llvm.llrint");
|
||||
|
||||
//intrinsic_id_abs = lookup_intrinsic("llvm.abs");
|
||||
intrinsic_id_smax = lookup_intrinsic("llvm.smax");
|
||||
intrinsic_id_smin = lookup_intrinsic("llvm.smin");
|
||||
intrinsic_id_umax = lookup_intrinsic("llvm.umax");
|
||||
intrinsic_id_umin = lookup_intrinsic("llvm.umin");
|
||||
|
||||
attribute_noinline = lookup_attribute("noinline");
|
||||
attribute_alwaysinline = lookup_attribute("alwaysinline");
|
||||
attribute_inlinehint = lookup_attribute("inlinehint");
|
||||
|
||||
@@ -2133,17 +2133,46 @@ void llvm_value_struct_gep(GenContext *c, BEValue *element, BEValue *struct_poin
|
||||
element->alignment = alignment;
|
||||
}
|
||||
|
||||
void gencontext_emit_call_intrinsic_expr(GenContext *context, BEValue *be_value, Expr *expr)
|
||||
static void llvm_emit_fp_intrinsic_expr(GenContext *c, unsigned intrinsic_id, BEValue *be_value, Expr *expr)
|
||||
{
|
||||
unsigned arguments = vec_size(expr->call_expr.arguments);
|
||||
llvm_emit_expr(c, be_value, expr->call_expr.arguments[0]);
|
||||
llvm_value_rvalue(c, be_value);
|
||||
LLVMTypeRef call_type = llvm_get_type(c, be_value->type);
|
||||
LLVMValueRef result = llvm_emit_call_intrinsic(c, intrinsic_id, &call_type, 1, &be_value->value, 1);
|
||||
be_value->value = result;
|
||||
}
|
||||
void gencontext_emit_call_intrinsic_expr(GenContext *c, BEValue *be_value, Expr *expr)
|
||||
{
|
||||
Decl *function_decl = expr->call_expr.function->identifier_expr.decl;
|
||||
if (function_decl->name == kw___round)
|
||||
{
|
||||
llvm_emit_fp_intrinsic_expr(c, intrinsic_id_rint, be_value, expr);
|
||||
return;
|
||||
}
|
||||
if (function_decl->name == kw___sqrt)
|
||||
{
|
||||
llvm_emit_fp_intrinsic_expr(c, intrinsic_id_sqrt, be_value, expr);
|
||||
return;
|
||||
}
|
||||
if (function_decl->name == kw___trunc)
|
||||
{
|
||||
llvm_emit_fp_intrinsic_expr(c, intrinsic_id_trunc, be_value, expr);
|
||||
return;
|
||||
}
|
||||
if (function_decl->name == kw___ceil)
|
||||
{
|
||||
llvm_emit_fp_intrinsic_expr(c, intrinsic_id_ceil, be_value, expr);
|
||||
return;
|
||||
}
|
||||
if (function_decl->name == kw___alloc)
|
||||
{
|
||||
unsigned arguments = vec_size(expr->call_expr.arguments);
|
||||
BEValue size_value;
|
||||
llvm_emit_expr(context, &size_value, expr->call_expr.arguments[0]);
|
||||
llvm_value_rvalue(context, &size_value);
|
||||
LLVMValueRef result = LLVMBuildArrayMalloc(context->builder, llvm_get_type(context, type_byte), llvm_value_rvalue_store(context, &size_value), "");
|
||||
result = LLVMBuildBitCast(context->builder, result, llvm_get_type(context, expr->type), "");
|
||||
llvm_emit_expr(c, &size_value, expr->call_expr.arguments[0]);
|
||||
llvm_value_rvalue(c, &size_value);
|
||||
LLVMValueRef result = LLVMBuildArrayMalloc(c->builder, llvm_get_type(c, type_byte), llvm_value_rvalue_store(c, &size_value), "");
|
||||
result = LLVMBuildBitCast(c->builder, result, llvm_get_type(c, expr->type), "");
|
||||
llvm_value_set(be_value, result, expr->type);
|
||||
return;
|
||||
}
|
||||
@@ -2151,9 +2180,9 @@ void gencontext_emit_call_intrinsic_expr(GenContext *context, BEValue *be_value,
|
||||
{
|
||||
unsigned arguments = vec_size(expr->call_expr.arguments);
|
||||
BEValue size_value;
|
||||
llvm_emit_expr(context, &size_value, expr->call_expr.arguments[0]);
|
||||
llvm_value_rvalue(context, &size_value);
|
||||
LLVMBuildFree(context->builder, llvm_value_rvalue_store(context, &size_value));
|
||||
llvm_emit_expr(c, &size_value, expr->call_expr.arguments[0]);
|
||||
llvm_value_rvalue(c, &size_value);
|
||||
LLVMBuildFree(c->builder, llvm_value_rvalue_store(c, &size_value));
|
||||
return;
|
||||
}
|
||||
UNREACHABLE
|
||||
|
||||
@@ -183,13 +183,61 @@ typedef struct
|
||||
|
||||
// LLVM Intrinsics
|
||||
extern unsigned intrinsic_id_sadd_overflow;
|
||||
extern unsigned intrinsic_id_sadd_sat;
|
||||
extern unsigned intrinsic_id_uadd_overflow;
|
||||
extern unsigned intrinsic_id_uadd_sat;
|
||||
extern unsigned intrinsic_id_ssub_overflow;
|
||||
extern unsigned intrinsic_id_ssub_sat;
|
||||
extern unsigned intrinsic_id_usub_overflow;
|
||||
extern unsigned intrinsic_id_usub_sat;
|
||||
extern unsigned intrinsic_id_sshl_sat;
|
||||
extern unsigned intrinsic_id_ushl_sat;
|
||||
extern unsigned intrinsic_id_smul_overflow;
|
||||
extern unsigned intrinsic_id_umul_overflow;
|
||||
extern unsigned intrinsic_id_trap;
|
||||
extern unsigned intrinsic_id_assume;
|
||||
extern unsigned intrinsic_id_fmuladd;
|
||||
extern unsigned intrinsic_id_rint;
|
||||
extern unsigned intrinsic_id_trunc;
|
||||
extern unsigned intrinsic_id_ceil;
|
||||
extern unsigned intrinsic_id_sqrt;
|
||||
extern unsigned intrinsic_id_nearbyint;
|
||||
extern unsigned intrinsic_id_roundeven;
|
||||
extern unsigned intrinsic_in_lround;
|
||||
extern unsigned intrinsic_in_llround;
|
||||
extern unsigned intrinsic_in_lrint;
|
||||
extern unsigned intrinsic_in_llrint;
|
||||
extern unsigned intrinsic_id_floor;
|
||||
extern unsigned intrinsic_id_powi;
|
||||
extern unsigned intrinsic_id_pow;
|
||||
extern unsigned intrinsic_id_sin;
|
||||
extern unsigned intrinsic_id_cos;
|
||||
extern unsigned intrinsic_id_exp;
|
||||
extern unsigned intrinsic_id_exp2;
|
||||
extern unsigned intrinsic_id_log;
|
||||
extern unsigned intrinsic_id_log10;
|
||||
extern unsigned intrinsic_id_fabs;
|
||||
extern unsigned intrinsic_id_fma;
|
||||
extern unsigned intrinsic_id_copysign;
|
||||
extern unsigned intrinsic_id_minnum;
|
||||
extern unsigned intrinsic_id_maxnum;
|
||||
extern unsigned intrinsic_id_minimum;
|
||||
extern unsigned intrinsic_id_maximum;
|
||||
extern unsigned intrinsic_id_smax;
|
||||
extern unsigned intrinsic_id_smin;
|
||||
extern unsigned intrinsic_id_umax;
|
||||
extern unsigned intrinsic_id_umin;
|
||||
extern unsigned intrinsic_id_abs;
|
||||
extern unsigned intrinsic_id_fshl;
|
||||
extern unsigned intrinsic_id_fshr;
|
||||
extern unsigned intrinsic_id_bitreverse;
|
||||
extern unsigned intrinsic_id_bswap;
|
||||
extern unsigned intrinsic_id_ctpop;
|
||||
extern unsigned intrinsic_id_ctlz;
|
||||
extern unsigned intrinsic_id_cttz;
|
||||
extern unsigned intrinsic_id_convert_from_fp16;
|
||||
extern unsigned intrinsic_id_convert_to_fp16;
|
||||
|
||||
|
||||
// LLVM Attributes
|
||||
extern unsigned attribute_noinline; // No function inlining
|
||||
|
||||
@@ -692,9 +692,43 @@ static inline int find_index_of_named_parameter(Context *context, Decl** func_pa
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline bool sema_expr_analyse_intrinsic_fp_invocation(Context *context, Expr *expr, Decl *decl, Type *to)
|
||||
{
|
||||
unsigned arguments = vec_size(expr->call_expr.arguments);
|
||||
if (arguments != 1)
|
||||
{
|
||||
SEMA_ERROR(expr, "Expected 1 argument to intrinsic %s.", decl->name);
|
||||
return false;
|
||||
}
|
||||
Expr *arg = expr->call_expr.arguments[0];
|
||||
if (!sema_analyse_expr(context, to, arg)) return false;
|
||||
// Convert ints to float comptime float.
|
||||
if (type_is_any_integer(arg->type->canonical))
|
||||
{
|
||||
if (!cast_implicit(context, arg, type_compfloat)) return false;
|
||||
}
|
||||
// If this is not a float argument => error.
|
||||
if (!type_is_float(arg->type->canonical))
|
||||
{
|
||||
SEMA_ERROR(arg, "Expected a floating point argument.", decl->name);
|
||||
return false;
|
||||
}
|
||||
// We lower to a real float in case we got a compfloat.
|
||||
if (!cast_implicitly_to_runtime(context, arg)) return false;
|
||||
|
||||
// The expression type is the argument type.
|
||||
expr->type = arg->type;
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
static inline bool sema_expr_analyse_intrinsic_invocation(Context *context, Expr *expr, Decl *decl, Type *to)
|
||||
{
|
||||
unsigned arguments = vec_size(expr->call_expr.arguments);
|
||||
if (decl->name == kw___ceil || decl->name == kw___trunc || decl->name == kw___round || decl->name == kw___sqrt)
|
||||
{
|
||||
return sema_expr_analyse_intrinsic_fp_invocation(context, expr, decl, to);
|
||||
}
|
||||
if (decl->name == kw___alloc)
|
||||
{
|
||||
if (to && type_is_pointer(to))
|
||||
|
||||
@@ -45,8 +45,12 @@ void sema_analysis_pass_process_imports(Context *context)
|
||||
}
|
||||
}
|
||||
}
|
||||
context_add_intrinsic(context, kw___round);
|
||||
context_add_intrinsic(context, kw___trunc);
|
||||
context_add_intrinsic(context, kw___ceil);
|
||||
context_add_intrinsic(context, kw___alloc);
|
||||
context_add_intrinsic(context, kw___free);
|
||||
context_add_intrinsic(context, kw___sqrt);
|
||||
DEBUG_LOG("Pass finished with %d error(s).", diagnostics.errors);
|
||||
}
|
||||
|
||||
|
||||
@@ -48,6 +48,10 @@ const char *kw_len;
|
||||
const char *kw_ordinal;
|
||||
const char *kw___alloc;
|
||||
const char *kw___free;
|
||||
const char *kw___round;
|
||||
const char *kw___ceil;
|
||||
const char *kw___trunc;
|
||||
const char *kw___sqrt;
|
||||
|
||||
void symtab_init(uint32_t capacity)
|
||||
{
|
||||
@@ -93,6 +97,11 @@ void symtab_init(uint32_t capacity)
|
||||
kw_ordinal = KW_DEF("ordinal");
|
||||
kw___alloc = KW_DEF("__alloc");
|
||||
kw___free = KW_DEF("__free");
|
||||
kw___round = KW_DEF("__round");
|
||||
kw___sqrt = KW_DEF("__sqrt");
|
||||
kw___trunc = KW_DEF("__trunc");
|
||||
kw___ceil = KW_DEF("__ceil");
|
||||
|
||||
attribute_list[ATTRIBUTE_INLINE] = KW_DEF("inline");
|
||||
attribute_list[ATTRIBUTE_NOINLINE] = KW_DEF("noinline");
|
||||
attribute_list[ATTRIBUTE_STDCALL] = KW_DEF("stdcall");
|
||||
|
||||
Reference in New Issue
Block a user