mirror of
https://github.com/danog/ir.git
synced 2024-12-04 02:28:32 +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_LAST_TYPE
|
||||||
} ir_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
|
/* List of IR opcodes
|
||||||
* ==================
|
* ==================
|
||||||
*
|
*
|
||||||
@ -399,6 +411,7 @@ typedef union _ir_val {
|
|||||||
#define IR_CONST_EMIT (1<<0)
|
#define IR_CONST_EMIT (1<<0)
|
||||||
#define IR_CONST_FASTCALL_FUNC (1<<1)
|
#define IR_CONST_FASTCALL_FUNC (1<<1)
|
||||||
#define IR_CONST_VARARG_FUNC (1<<2)
|
#define IR_CONST_VARARG_FUNC (1<<2)
|
||||||
|
#define IR_CONST_BUILTIN_FUNC (1<<3)
|
||||||
|
|
||||||
/* IR Instruction */
|
/* IR Instruction */
|
||||||
typedef struct _ir_insn {
|
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");
|
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)
|
static void ir_emit_call(ir_ctx *ctx, FILE *f, ir_ref def, ir_insn *insn)
|
||||||
{
|
{
|
||||||
int j, k, n;
|
int j, k, n;
|
||||||
|
ir_ref last_arg = IR_UNUSED;
|
||||||
|
|
||||||
if (insn->type != IR_VOID) {
|
if (insn->type != IR_VOID) {
|
||||||
ir_emit_def_ref(ctx, f, def);
|
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 ???
|
// TODO: function prototype ???
|
||||||
|
|
||||||
if (IR_IS_CONST_REF(insn->op2)) {
|
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 {
|
} else {
|
||||||
ir_emit_ref(ctx, f, insn->op2);
|
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]);
|
fprintf(f, "%s ", ir_type_llvm_name[ctx->ir_base[k].type]);
|
||||||
ir_emit_ref(ctx, f, k);
|
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");
|
fprintf(f, ")\n");
|
||||||
if (insn->op == IR_TAILCALL) {
|
if (insn->op == IR_TAILCALL) {
|
||||||
if (insn->type != IR_VOID) {
|
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--) {
|
for (i = IR_UNUSED + 1, insn = ctx->ir_base - i; i < ctx->consts_count; i++, insn--) {
|
||||||
if (insn->op == IR_FUNC) {
|
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 ???
|
// 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) {
|
} else if (insn->op == IR_SYM) {
|
||||||
// TODO: symbol "global" or "constant" ???
|
// TODO: symbol "global" or "constant" ???
|
||||||
// TODO: symbol type ???
|
// 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 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_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);
|
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;
|
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)
|
static ir_ref llvm2ir_fcmp_op(ir_ctx *ctx, LLVMValueRef expr)
|
||||||
{
|
{
|
||||||
LLVMValueRef op0 = LLVMGetOperand(expr, 0);
|
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_type type = llvm2ir_type(LLVMTypeOf(op0));
|
||||||
ir_ref ref;
|
ir_ref ref;
|
||||||
ir_op op;
|
ir_op op;
|
||||||
|
LLVMRealPredicate predicate = LLVMGetFCmpPredicate(expr);
|
||||||
|
|
||||||
switch (LLVMGetFCmpPredicate(expr)) {
|
switch (predicate) {
|
||||||
case LLVMRealOEQ:
|
case LLVMRealOEQ:
|
||||||
case LLVMRealUEQ: op = IR_EQ; break;
|
case LLVMRealUEQ: op = IR_EQ; break;
|
||||||
case LLVMRealONE:
|
case LLVMRealONE:
|
||||||
@ -324,8 +351,9 @@ static ir_ref llvm2ir_fcmp_op(ir_ctx *ctx, LLVMValueRef expr)
|
|||||||
case LLVMRealOGE: op = IR_GE; break;
|
case LLVMRealOGE: op = IR_GE; break;
|
||||||
case LLVMRealOLT: op = IR_LT; break;
|
case LLVMRealOLT: op = IR_LT; break;
|
||||||
case LLVMRealOLE: op = IR_LE; break;
|
case LLVMRealOLE: op = IR_LE; break;
|
||||||
case LLVMRealUNO: op = IR_NE; break; // TODO: isnan() upport. IR_NE is invalid ???
|
case LLVMRealUNO:
|
||||||
case LLVMRealORD: op = IR_NE; break; // TODO: isnan() upport. IR_NE is invalid ???
|
case LLVMRealORD:
|
||||||
|
return llvm2ir_fcmp_op_isnan(ctx, expr, type, predicate, op0, op1);
|
||||||
default: IR_ASSERT(0); return 0;
|
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));
|
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)
|
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_type type;
|
||||||
|
ir_ref func;
|
||||||
|
|
||||||
if (STR_START(name, name_len, "llvm.lifetime.")) {
|
if (STR_START(name, name_len, "llvm.lifetime.")) {
|
||||||
/* skip */
|
/* 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.")) {
|
} else if (STR_START(name, name_len, "llvm.cttz.")) {
|
||||||
// TODO:
|
// TODO:
|
||||||
} else if (STR_START(name, name_len, "llvm.memset.")) {
|
} 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.")) {
|
} 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.")) {
|
} 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.")) {
|
} else if (STR_START(name, name_len, "llvm.frameaddress.")) {
|
||||||
// TODO:
|
// TODO:
|
||||||
} else if (STR_EQUAL(name, name_len, "llvm.debugtrap")) {
|
} else if (STR_EQUAL(name, name_len, "llvm.debugtrap")) {
|
||||||
ir_TRAP();
|
ir_TRAP();
|
||||||
return ctx->control;
|
return ctx->control;
|
||||||
} else if (STR_START(name, name_len, "llvm.sqrt.")) {
|
} else if (STR_START(name, name_len, "llvm.sqrt.")) {
|
||||||
// TODO:
|
IR_ASSERT(count == 1);
|
||||||
} else if (STR_START(name, name_len, "llvm.powi.")) {
|
type = llvm2ir_type(LLVMGetReturnType(ftype));
|
||||||
// TODO:
|
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.")) {
|
} 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.")) {
|
} 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.")) {
|
} 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.")) {
|
} 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.")) {
|
} 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.")) {
|
} 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.")) {
|
} 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.")) {
|
} 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.")) {
|
} else if (STR_START(name, name_len, "llvm.log.")) {
|
||||||
// TODO:
|
IR_ASSERT(count == 1);
|
||||||
} else if (STR_START(name, name_len, "llvm.log10.")) {
|
type = llvm2ir_type(LLVMGetReturnType(ftype));
|
||||||
// TODO:
|
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.")) {
|
} else if (STR_START(name, name_len, "llvm.log2.")) {
|
||||||
// TODO:
|
IR_ASSERT(count == 1);
|
||||||
} else if (STR_START(name, name_len, "llvm.frexp.")) {
|
type = llvm2ir_type(LLVMGetReturnType(ftype));
|
||||||
// TODO:
|
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.")) {
|
} 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.")) {
|
} 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.")) {
|
} 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.")) {
|
} 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.")) {
|
} else if (STR_START(name, name_len, "llvm.round.")) {
|
||||||
// TODO:
|
IR_ASSERT(count == 1);
|
||||||
} else if (STR_START(name, name_len, "llvm.fmuladd.")) {
|
type = llvm2ir_type(LLVMGetReturnType(ftype));
|
||||||
// TODO:
|
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 {
|
} else {
|
||||||
fprintf(stderr, "Unsupported LLVM intrinsic: %s\n", name);
|
fprintf(stderr, "Unsupported LLVM intrinsic: %s\n", name);
|
||||||
IR_ASSERT(0);
|
IR_ASSERT(0);
|
||||||
|
Loading…
Reference in New Issue
Block a user