mirror of
https://github.com/danog/ir.git
synced 2024-12-03 10:08:29 +01:00
Add support for some LLVM intrinsic
This commit is contained in:
parent
3f14ac4252
commit
a8e514266f
13
ir.h
13
ir.h
@ -136,6 +136,18 @@ typedef enum _ir_type {
|
||||
IR_LAST_TYPE
|
||||
} ir_type;
|
||||
|
||||
#ifdef IR_64
|
||||
# define IR_SIZE_T IR_U64
|
||||
# define IR_SSIZE_T IR_I64
|
||||
# define IR_UINTPTR_T IR_U64
|
||||
# define IR_INTPTR_T IR_I64
|
||||
#else
|
||||
# define IR_SIZE_T IR_U32
|
||||
# define IR_SSIZE_T IR_I32
|
||||
# define IR_UINTPTR_T IR_U32
|
||||
# define IR_INTPTR_T IR_I32
|
||||
#endif
|
||||
|
||||
/* List of IR opcodes
|
||||
* ==================
|
||||
*
|
||||
@ -399,6 +411,7 @@ typedef union _ir_val {
|
||||
#define IR_CONST_EMIT (1<<0)
|
||||
#define IR_CONST_FASTCALL_FUNC (1<<1)
|
||||
#define IR_CONST_VARARG_FUNC (1<<2)
|
||||
#define IR_CONST_BUILTIN_FUNC (1<<3)
|
||||
|
||||
/* IR Instruction */
|
||||
typedef struct _ir_insn {
|
||||
|
102
ir_emit_llvm.c
102
ir_emit_llvm.c
@ -422,9 +422,93 @@ static void ir_emit_switch(ir_ctx *ctx, FILE *f, uint32_t b, ir_ref def, ir_insn
|
||||
fprintf(f, "\t]\n");
|
||||
}
|
||||
|
||||
static const char *ir_builtin_func_name(const char *name, ir_ref *last_arg)
|
||||
{
|
||||
if (strcmp(name, "memset")) {
|
||||
*last_arg = IR_FALSE;
|
||||
return (IR_SIZE_T == IR_I32) ? "llvm.memset.p0.i32" : "llvm.memset.p0.i64";
|
||||
} else if (strcmp(name, "memcpy")) {
|
||||
*last_arg = IR_FALSE;
|
||||
return (IR_SIZE_T == IR_I32) ? "llvm.memcpy.p0.p0.i32" : "llvm.memcpy.p0.p0.i64";
|
||||
} else if (strcmp(name, "memmove")) {
|
||||
*last_arg = IR_FALSE;
|
||||
return (IR_SIZE_T == IR_I32) ? "llvm.memmove.p0.p0.i32" : "llvm.memmve.p0.p0.i64";
|
||||
} else if (strcmp(name, "sqrt")) {
|
||||
return "llvm.sqrt.f64";
|
||||
} else if (strcmp(name, "sqrtf")) {
|
||||
return "llvm.sqrt.f32";
|
||||
} else if (strcmp(name, "sin")) {
|
||||
return "llvm.sin.f64";
|
||||
} else if (strcmp(name, "sinf")) {
|
||||
return "llvm.sin.f32";
|
||||
} else if (strcmp(name, "cos")) {
|
||||
return "llvm.cos.f64";
|
||||
} else if (strcmp(name, "cosf")) {
|
||||
return "llvm.cos.f32";
|
||||
} else if (strcmp(name, "pow")) {
|
||||
return "llvm.pow.f64";
|
||||
} else if (strcmp(name, "powf")) {
|
||||
return "llvm.pow.f32";
|
||||
} else if (strcmp(name, "exp")) {
|
||||
return "llvm.exp.f64";
|
||||
} else if (strcmp(name, "expf")) {
|
||||
return "llvm.exp.f32";
|
||||
} else if (strcmp(name, "exp2")) {
|
||||
return "llvm.exp2.f64";
|
||||
} else if (strcmp(name, "exp2f")) {
|
||||
return "llvm.exp2.f32";
|
||||
} else if (strcmp(name, "exp10")) {
|
||||
return "llvm.exp10.f64";
|
||||
} else if (strcmp(name, "exp10f")) {
|
||||
return "llvm.exp10.f32";
|
||||
} else if (strcmp(name, "ldexp")) {
|
||||
return "llvm.ldexp.f64.i32";
|
||||
} else if (strcmp(name, "ldexpf")) {
|
||||
return "llvm.ldexp.f32.i32";
|
||||
} else if (strcmp(name, "frexp")) {
|
||||
return "llvm.frexp.f64.i32";
|
||||
} else if (strcmp(name, "frexpf")) {
|
||||
return "llvm.frexp.f32.i32";
|
||||
} else if (strcmp(name, "log")) {
|
||||
return "llvm.log.f64";
|
||||
} else if (strcmp(name, "logf")) {
|
||||
return "llvm.log.f32";
|
||||
} else if (strcmp(name, "log2")) {
|
||||
return "llvm.log2.f64";
|
||||
} else if (strcmp(name, "log2f")) {
|
||||
return "llvm.log2.f32";
|
||||
} else if (strcmp(name, "log10")) {
|
||||
return "llvm.log10.f64";
|
||||
} else if (strcmp(name, "log10f")) {
|
||||
return "llvm.log10.f32";
|
||||
} else if (strcmp(name, "copysign")) {
|
||||
return "llvm.copysign.f64";
|
||||
} else if (strcmp(name, "copysignf")) {
|
||||
return "llvm.copysign.f32";
|
||||
} else if (strcmp(name, "floor")) {
|
||||
return "llvm.floor.f64";
|
||||
} else if (strcmp(name, "floorf")) {
|
||||
return "llvm.floor.f32";
|
||||
} else if (strcmp(name, "ceil")) {
|
||||
return "llvm.ceil.f64";
|
||||
} else if (strcmp(name, "ceilf")) {
|
||||
return "llvm.ceil.f32";
|
||||
} else if (strcmp(name, "trunc")) {
|
||||
return "llvm.trunc.f64";
|
||||
} else if (strcmp(name, "truncf")) {
|
||||
return "llvm.trunc.f32";
|
||||
} else if (strcmp(name, "round")) {
|
||||
return "llvm.round.f64";
|
||||
} else if (strcmp(name, "roundf")) {
|
||||
return "llvm.round.f32";
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
static void ir_emit_call(ir_ctx *ctx, FILE *f, ir_ref def, ir_insn *insn)
|
||||
{
|
||||
int j, k, n;
|
||||
ir_ref last_arg = IR_UNUSED;
|
||||
|
||||
if (insn->type != IR_VOID) {
|
||||
ir_emit_def_ref(ctx, f, def);
|
||||
@ -446,7 +530,11 @@ static void ir_emit_call(ir_ctx *ctx, FILE *f, ir_ref def, ir_insn *insn)
|
||||
// TODO: function prototype ???
|
||||
|
||||
if (IR_IS_CONST_REF(insn->op2)) {
|
||||
fprintf(f, "@%s", ir_get_str(ctx, ctx->ir_base[insn->op2].val.i32));
|
||||
const char *name = ir_get_str(ctx, ctx->ir_base[insn->op2].val.i32);
|
||||
if (ctx->ir_base[insn->op2].const_flags & IR_CONST_BUILTIN_FUNC) {
|
||||
name = ir_builtin_func_name(name, &last_arg);
|
||||
}
|
||||
fprintf(f, "@%s", name);
|
||||
} else {
|
||||
ir_emit_ref(ctx, f, insn->op2);
|
||||
}
|
||||
@ -460,6 +548,11 @@ static void ir_emit_call(ir_ctx *ctx, FILE *f, ir_ref def, ir_insn *insn)
|
||||
fprintf(f, "%s ", ir_type_llvm_name[ctx->ir_base[k].type]);
|
||||
ir_emit_ref(ctx, f, k);
|
||||
}
|
||||
if (last_arg) {
|
||||
fprintf(f, ", ");
|
||||
fprintf(f, "%s ", ir_type_llvm_name[ctx->ir_base[last_arg].type]);
|
||||
ir_emit_ref(ctx, f, last_arg);
|
||||
}
|
||||
fprintf(f, ")\n");
|
||||
if (insn->op == IR_TAILCALL) {
|
||||
if (insn->type != IR_VOID) {
|
||||
@ -833,8 +926,13 @@ static int ir_emit_func(ir_ctx *ctx, const char *name, FILE *f)
|
||||
|
||||
for (i = IR_UNUSED + 1, insn = ctx->ir_base - i; i < ctx->consts_count; i++, insn--) {
|
||||
if (insn->op == IR_FUNC) {
|
||||
const char *name = ir_get_str(ctx, insn->val.i32);
|
||||
if (insn->const_flags & IR_CONST_BUILTIN_FUNC) {
|
||||
ir_ref dummy;
|
||||
name = ir_builtin_func_name(name, &dummy);
|
||||
}
|
||||
// TODO: function prototype ???
|
||||
fprintf(f, "declare void @%s()\n", ir_get_str(ctx, insn->val.i32));
|
||||
fprintf(f, "declare void @%s()\n", name);
|
||||
} else if (insn->op == IR_SYM) {
|
||||
// TODO: symbol "global" or "constant" ???
|
||||
// TODO: symbol type ???
|
||||
|
180
ir_load_llvm.c
180
ir_load_llvm.c
@ -16,6 +16,12 @@
|
||||
|
||||
#define IR_BAD_TYPE IR_LAST_TYPE
|
||||
|
||||
#define BUILTIN_FUNC(name) \
|
||||
ir_const_func(ctx, ir_strl(ctx, name, strlen(name)), IR_CONST_BUILTIN_FUNC)
|
||||
|
||||
#define BUILTIN_FP_FUNC(type, dname, fname) \
|
||||
((type == IR_DOUBLE) ? BUILTIN_FUNC(dname) : BUILTIN_FUNC(fname))
|
||||
|
||||
static ir_ref llvm2ir_const_expr(ir_ctx *ctx, LLVMValueRef expr);
|
||||
static ir_ref llvm2ir_auto_cast(ir_ctx *ctx, ir_ref ref, ir_type src_type, ir_type type);
|
||||
|
||||
@ -303,6 +309,26 @@ static ir_ref llvm2ir_icmp_op(ir_ctx *ctx, LLVMValueRef expr)
|
||||
return ref;
|
||||
}
|
||||
|
||||
static ir_ref llvm2ir_fcmp_op_isnan(ir_ctx *ctx, LLVMValueRef expr, ir_type type,
|
||||
LLVMRealPredicate predicate, LLVMValueRef op0, LLVMValueRef op1)
|
||||
{
|
||||
ir_ref func, ref;
|
||||
|
||||
func = BUILTIN_FP_FUNC(type, "isnan", "isnanf");
|
||||
if (LLVMGetValueKind(op1) == LLVMConstantIntValueKind) {
|
||||
ref = ir_CALL_1(IR_BOOL, func, llvm2ir_op(ctx, op0, type));
|
||||
} else {
|
||||
ref = ir_OR_B(
|
||||
ir_CALL_1(IR_BOOL, func, llvm2ir_op(ctx, op0, type)),
|
||||
ir_CALL_1(IR_BOOL, func, llvm2ir_op(ctx, op1, type)));
|
||||
}
|
||||
if (predicate == LLVMRealORD) {
|
||||
ref = ir_NOT_B(ref);
|
||||
}
|
||||
ir_addrtab_add(ctx->binding, (uintptr_t)expr, ref);
|
||||
return ref;
|
||||
}
|
||||
|
||||
static ir_ref llvm2ir_fcmp_op(ir_ctx *ctx, LLVMValueRef expr)
|
||||
{
|
||||
LLVMValueRef op0 = LLVMGetOperand(expr, 0);
|
||||
@ -310,8 +336,9 @@ static ir_ref llvm2ir_fcmp_op(ir_ctx *ctx, LLVMValueRef expr)
|
||||
ir_type type = llvm2ir_type(LLVMTypeOf(op0));
|
||||
ir_ref ref;
|
||||
ir_op op;
|
||||
LLVMRealPredicate predicate = LLVMGetFCmpPredicate(expr);
|
||||
|
||||
switch (LLVMGetFCmpPredicate(expr)) {
|
||||
switch (predicate) {
|
||||
case LLVMRealOEQ:
|
||||
case LLVMRealUEQ: op = IR_EQ; break;
|
||||
case LLVMRealONE:
|
||||
@ -324,8 +351,9 @@ static ir_ref llvm2ir_fcmp_op(ir_ctx *ctx, LLVMValueRef expr)
|
||||
case LLVMRealOGE: op = IR_GE; break;
|
||||
case LLVMRealOLT: op = IR_LT; break;
|
||||
case LLVMRealOLE: op = IR_LE; break;
|
||||
case LLVMRealUNO: op = IR_NE; break; // TODO: isnan() upport. IR_NE is invalid ???
|
||||
case LLVMRealORD: op = IR_NE; break; // TODO: isnan() upport. IR_NE is invalid ???
|
||||
case LLVMRealUNO:
|
||||
case LLVMRealORD:
|
||||
return llvm2ir_fcmp_op_isnan(ctx, expr, type, predicate, op0, op1);
|
||||
default: IR_ASSERT(0); return 0;
|
||||
}
|
||||
ref = ir_fold2(ctx, IR_OPT(op, IR_BOOL), llvm2ir_op(ctx, op0, type), llvm2ir_op(ctx, op1, type));
|
||||
@ -449,6 +477,7 @@ static ir_type llvm2ir_overflow_type(LLVMTypeRef stype)
|
||||
static ir_ref llvm2ir_intrinsic(ir_ctx *ctx, LLVMValueRef insn, LLVMTypeRef ftype, uint32_t count, const char *name, size_t name_len)
|
||||
{
|
||||
ir_type type;
|
||||
ir_ref func;
|
||||
|
||||
if (STR_START(name, name_len, "llvm.lifetime.")) {
|
||||
/* skip */
|
||||
@ -636,56 +665,147 @@ static ir_ref llvm2ir_intrinsic(ir_ctx *ctx, LLVMValueRef insn, LLVMTypeRef ftyp
|
||||
} else if (STR_START(name, name_len, "llvm.cttz.")) {
|
||||
// TODO:
|
||||
} else if (STR_START(name, name_len, "llvm.memset.")) {
|
||||
// TODO:
|
||||
IR_ASSERT(count == 3 || count == 4);
|
||||
func = BUILTIN_FUNC("memset");
|
||||
return ir_CALL_3(IR_VOID, func,
|
||||
llvm2ir_op(ctx, LLVMGetOperand(insn, 0), IR_ADDR),
|
||||
llvm2ir_op(ctx, LLVMGetOperand(insn, 1), IR_I8),
|
||||
llvm2ir_op(ctx, LLVMGetOperand(insn, 2), IR_SIZE_T));
|
||||
} else if (STR_START(name, name_len, "llvm.memcpy.")) {
|
||||
// TODO:
|
||||
IR_ASSERT(count == 3 || count == 4);
|
||||
func = BUILTIN_FUNC("memcpy");
|
||||
return ir_CALL_3(IR_VOID, func,
|
||||
llvm2ir_op(ctx, LLVMGetOperand(insn, 0), IR_ADDR),
|
||||
llvm2ir_op(ctx, LLVMGetOperand(insn, 1), IR_ADDR),
|
||||
llvm2ir_op(ctx, LLVMGetOperand(insn, 2), IR_SIZE_T));
|
||||
} else if (STR_START(name, name_len, "llvm.memmove.")) {
|
||||
// TODO:
|
||||
IR_ASSERT(count == 3 || count == 4);
|
||||
func = BUILTIN_FUNC("memmove");
|
||||
return ir_CALL_3(IR_VOID, func,
|
||||
llvm2ir_op(ctx, LLVMGetOperand(insn, 0), IR_ADDR),
|
||||
llvm2ir_op(ctx, LLVMGetOperand(insn, 1), IR_ADDR),
|
||||
llvm2ir_op(ctx, LLVMGetOperand(insn, 2), IR_SIZE_T));
|
||||
} else if (STR_START(name, name_len, "llvm.frameaddress.")) {
|
||||
// TODO:
|
||||
} else if (STR_EQUAL(name, name_len, "llvm.debugtrap")) {
|
||||
ir_TRAP();
|
||||
return ctx->control;
|
||||
} else if (STR_START(name, name_len, "llvm.sqrt.")) {
|
||||
// TODO:
|
||||
} else if (STR_START(name, name_len, "llvm.powi.")) {
|
||||
// TODO:
|
||||
IR_ASSERT(count == 1);
|
||||
type = llvm2ir_type(LLVMGetReturnType(ftype));
|
||||
IR_ASSERT(IR_IS_TYPE_FP(type));
|
||||
func = BUILTIN_FP_FUNC(type, "sqrt", "sqrtf");
|
||||
return ir_CALL_1(type, func, llvm2ir_op(ctx, LLVMGetOperand(insn, 0), type));
|
||||
} else if (STR_START(name, name_len, "llvm.sin.")) {
|
||||
// TODO:
|
||||
IR_ASSERT(count == 1);
|
||||
type = llvm2ir_type(LLVMGetReturnType(ftype));
|
||||
IR_ASSERT(IR_IS_TYPE_FP(type));
|
||||
func = BUILTIN_FP_FUNC(type, "sin", "sinf");
|
||||
return ir_CALL_1(type, func, llvm2ir_op(ctx, LLVMGetOperand(insn, 0), type));
|
||||
} else if (STR_START(name, name_len, "llvm.cos.")) {
|
||||
// TODO:
|
||||
IR_ASSERT(count == 1);
|
||||
type = llvm2ir_type(LLVMGetReturnType(ftype));
|
||||
IR_ASSERT(IR_IS_TYPE_FP(type));
|
||||
func = BUILTIN_FP_FUNC(type, "cos", "cosf");
|
||||
return ir_CALL_1(type, func, llvm2ir_op(ctx, LLVMGetOperand(insn, 0), type));
|
||||
} else if (STR_START(name, name_len, "llvm.pow.")) {
|
||||
// TODO:
|
||||
IR_ASSERT(count == 2);
|
||||
type = llvm2ir_type(LLVMGetReturnType(ftype));
|
||||
IR_ASSERT(IR_IS_TYPE_FP(type));
|
||||
func = BUILTIN_FP_FUNC(type, "pow", "powf");
|
||||
return ir_CALL_2(type, func, llvm2ir_op(ctx, LLVMGetOperand(insn, 0), type),
|
||||
llvm2ir_op(ctx, LLVMGetOperand(insn, 1), type));
|
||||
} else if (STR_START(name, name_len, "llvm.exp.")) {
|
||||
// TODO:
|
||||
IR_ASSERT(count == 1);
|
||||
type = llvm2ir_type(LLVMGetReturnType(ftype));
|
||||
IR_ASSERT(IR_IS_TYPE_FP(type));
|
||||
func = BUILTIN_FP_FUNC(type, "exp", "expf");
|
||||
return ir_CALL_1(type, func, llvm2ir_op(ctx, LLVMGetOperand(insn, 0), type));
|
||||
} else if (STR_START(name, name_len, "llvm.exp2.")) {
|
||||
// TODO:
|
||||
IR_ASSERT(count == 1);
|
||||
type = llvm2ir_type(LLVMGetReturnType(ftype));
|
||||
IR_ASSERT(IR_IS_TYPE_FP(type));
|
||||
func = BUILTIN_FP_FUNC(type, "exp2", "exp2f");
|
||||
return ir_CALL_1(type, func, llvm2ir_op(ctx, LLVMGetOperand(insn, 0), type));
|
||||
} else if (STR_START(name, name_len, "llvm.exp10.")) {
|
||||
// TODO:
|
||||
IR_ASSERT(count == 1);
|
||||
type = llvm2ir_type(LLVMGetReturnType(ftype));
|
||||
IR_ASSERT(IR_IS_TYPE_FP(type));
|
||||
func = BUILTIN_FP_FUNC(type, "exp10", "exp10f");
|
||||
return ir_CALL_1(type, func, llvm2ir_op(ctx, LLVMGetOperand(insn, 0), type));
|
||||
} else if (STR_START(name, name_len, "llvm.ldexp.")) {
|
||||
// TODO:
|
||||
IR_ASSERT(count == 2);
|
||||
type = llvm2ir_type(LLVMGetReturnType(ftype));
|
||||
IR_ASSERT(IR_IS_TYPE_FP(type));
|
||||
func = BUILTIN_FP_FUNC(type, "ldexp", "ldexpf");
|
||||
return ir_CALL_2(type, func, llvm2ir_op(ctx, LLVMGetOperand(insn, 0), type),
|
||||
llvm2ir_op(ctx, LLVMGetOperand(insn, 1), IR_I32));
|
||||
} else if (STR_START(name, name_len, "llvm.frexp.")) {
|
||||
// TODO:
|
||||
IR_ASSERT(count == 2);
|
||||
type = llvm2ir_type(LLVMGetReturnType(ftype));
|
||||
IR_ASSERT(IR_IS_TYPE_FP(type));
|
||||
func = BUILTIN_FP_FUNC(type, "frexp", "frexpf");
|
||||
return ir_CALL_2(type, func, llvm2ir_op(ctx, LLVMGetOperand(insn, 0), type),
|
||||
llvm2ir_op(ctx, LLVMGetOperand(insn, 1), IR_ADDR));
|
||||
} else if (STR_START(name, name_len, "llvm.log.")) {
|
||||
// TODO:
|
||||
} else if (STR_START(name, name_len, "llvm.log10.")) {
|
||||
// TODO:
|
||||
IR_ASSERT(count == 1);
|
||||
type = llvm2ir_type(LLVMGetReturnType(ftype));
|
||||
IR_ASSERT(IR_IS_TYPE_FP(type));
|
||||
func = BUILTIN_FP_FUNC(type, "log", "logf");
|
||||
return ir_CALL_1(type, func, llvm2ir_op(ctx, LLVMGetOperand(insn, 0), type));
|
||||
} else if (STR_START(name, name_len, "llvm.log2.")) {
|
||||
// TODO:
|
||||
} else if (STR_START(name, name_len, "llvm.frexp.")) {
|
||||
// TODO:
|
||||
IR_ASSERT(count == 1);
|
||||
type = llvm2ir_type(LLVMGetReturnType(ftype));
|
||||
IR_ASSERT(IR_IS_TYPE_FP(type));
|
||||
func = BUILTIN_FP_FUNC(type, "log2", "log2f");
|
||||
return ir_CALL_1(type, func, llvm2ir_op(ctx, LLVMGetOperand(insn, 0), type));
|
||||
} else if (STR_START(name, name_len, "llvm.log10.")) {
|
||||
IR_ASSERT(count == 1);
|
||||
type = llvm2ir_type(LLVMGetReturnType(ftype));
|
||||
IR_ASSERT(IR_IS_TYPE_FP(type));
|
||||
func = BUILTIN_FP_FUNC(type, "log10", "log10f");
|
||||
return ir_CALL_1(type, func, llvm2ir_op(ctx, LLVMGetOperand(insn, 0), type));
|
||||
} else if (STR_START(name, name_len, "llvm.copysign.")) {
|
||||
// TODO:
|
||||
IR_ASSERT(count == 2);
|
||||
type = llvm2ir_type(LLVMGetReturnType(ftype));
|
||||
IR_ASSERT(IR_IS_TYPE_FP(type));
|
||||
func = BUILTIN_FP_FUNC(type, "copysign", "copysignf");
|
||||
return ir_CALL_2(type, func, llvm2ir_op(ctx, LLVMGetOperand(insn, 0), type),
|
||||
llvm2ir_op(ctx, LLVMGetOperand(insn, 1), type));
|
||||
} else if (STR_START(name, name_len, "llvm.floor.")) {
|
||||
// TODO:
|
||||
IR_ASSERT(count == 1);
|
||||
type = llvm2ir_type(LLVMGetReturnType(ftype));
|
||||
IR_ASSERT(IR_IS_TYPE_FP(type));
|
||||
func = BUILTIN_FP_FUNC(type, "floor", "floorf");
|
||||
return ir_CALL_1(type, func, llvm2ir_op(ctx, LLVMGetOperand(insn, 0), type));
|
||||
} else if (STR_START(name, name_len, "llvm.ceil.")) {
|
||||
// TODO:
|
||||
IR_ASSERT(count == 1);
|
||||
type = llvm2ir_type(LLVMGetReturnType(ftype));
|
||||
IR_ASSERT(IR_IS_TYPE_FP(type));
|
||||
func = BUILTIN_FP_FUNC(type, "ceil", "ceilf");
|
||||
return ir_CALL_1(type, func, llvm2ir_op(ctx, LLVMGetOperand(insn, 0), type));
|
||||
} else if (STR_START(name, name_len, "llvm.trunc.")) {
|
||||
// TODO:
|
||||
IR_ASSERT(count == 1);
|
||||
type = llvm2ir_type(LLVMGetReturnType(ftype));
|
||||
IR_ASSERT(IR_IS_TYPE_FP(type));
|
||||
func = BUILTIN_FP_FUNC(type, "trunc", "truncf");
|
||||
return ir_CALL_1(type, func, llvm2ir_op(ctx, LLVMGetOperand(insn, 0), type));
|
||||
} else if (STR_START(name, name_len, "llvm.round.")) {
|
||||
// TODO:
|
||||
} else if (STR_START(name, name_len, "llvm.fmuladd.")) {
|
||||
// TODO:
|
||||
IR_ASSERT(count == 1);
|
||||
type = llvm2ir_type(LLVMGetReturnType(ftype));
|
||||
IR_ASSERT(IR_IS_TYPE_FP(type));
|
||||
func = BUILTIN_FP_FUNC(type, "round", "roundf");
|
||||
return ir_CALL_1(type, func, llvm2ir_op(ctx, LLVMGetOperand(insn, 0), type));
|
||||
} else if (STR_START(name, name_len, "llvm.fmuladd.")
|
||||
|| STR_START(name, name_len, "llvm.fma.")) {
|
||||
IR_ASSERT(count == 3);
|
||||
type = llvm2ir_type(LLVMGetReturnType(ftype));
|
||||
IR_ASSERT(IR_IS_TYPE_FP(type));
|
||||
return ir_fold2(ctx, IR_OPT(IR_ADD, type),
|
||||
ir_fold2(ctx, IR_OPT(IR_MUL, type),
|
||||
llvm2ir_op(ctx, LLVMGetOperand(insn, 0), type),
|
||||
llvm2ir_op(ctx, LLVMGetOperand(insn, 1), type)),
|
||||
llvm2ir_op(ctx, LLVMGetOperand(insn, 2), type));
|
||||
} else {
|
||||
fprintf(stderr, "Unsupported LLVM intrinsic: %s\n", name);
|
||||
IR_ASSERT(0);
|
||||
|
Loading…
Reference in New Issue
Block a user