Added round/ceil/trunc/sqrt intrinsics.

This commit is contained in:
Christoffer Lerno
2020-12-03 15:53:42 +01:00
parent ac89023a2d
commit 0b00fe6988
7 changed files with 253 additions and 20 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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