mirror of
https://github.com/danog/ir.git
synced 2024-11-30 04:39:43 +01:00
Add bit counting nodes (JIT code generation is not supported yet)
This commit is contained in:
parent
90b6f34db2
commit
ea2de69592
3
ir.h
3
ir.h
@ -264,6 +264,9 @@ typedef enum _ir_type {
|
||||
_(ROL, d2, def, def, ___) /* rotate left */ \
|
||||
_(ROR, d2, def, def, ___) /* rotate right */ \
|
||||
_(BSWAP, d1, def, ___, ___) /* byte swap */ \
|
||||
_(CTPOP, d1, def, ___, ___) /* count population */ \
|
||||
_(CTLZ, d1, def, ___, ___) /* count leading zeros */ \
|
||||
_(CTTZ, d1, def, ___, ___) /* count trailing zeros */ \
|
||||
\
|
||||
/* branch-less conditional ops */ \
|
||||
_(MIN, d2C, def, def, ___) /* min(op1, op2) */ \
|
||||
|
36
ir_builder.h
36
ir_builder.h
@ -389,6 +389,42 @@ extern "C" {
|
||||
#define ir_BSWAP_I32(_op1) ir_UNARY_OP_I32(IR_BSWAP, (_op1))
|
||||
#define ir_BSWAP_I64(_op1) ir_UNARY_OP_I64(IR_BSWAP, (_op1))
|
||||
|
||||
#define ir_CTPOP(_type, _op1) ir_UNARY_OP(IR_CTPOP, (_type), (_op1))
|
||||
#define ir_CTPOP_8(_op1) ir_UNARY_OP_U8(IR_CTPOP, (_op1))
|
||||
#define ir_CTPOP_U16(_op1) ir_UNARY_OP_U16(IR_CTPOP, (_op1))
|
||||
#define ir_CTPOP_U32(_op1) ir_UNARY_OP_U32(IR_CTPOP, (_op1))
|
||||
#define ir_CTPOP_U64(_op1) ir_UNARY_OP_U64(IR_CTPOP, (_op1))
|
||||
#define ir_CTPOP_A(_op1) ir_UNARY_OP_A(IR_CTPOP, (_op1))
|
||||
#define ir_CTPOP_C(_op1) ir_UNARY_OP_C(IR_CTPOP, (_op1))
|
||||
#define ir_CTPOP_I8(_op1) ir_UNARY_OP_I8(IR_CTPOP, (_op1))
|
||||
#define ir_CTPOP_I16(_op1) ir_UNARY_OP_I16(IR_CTPOP, (_op1))
|
||||
#define ir_CTPOP_I32(_op1) ir_UNARY_OP_I32(IR_CTPOP, (_op1))
|
||||
#define ir_CTPOP_I64(_op1) ir_UNARY_OP_I64(IR_CTPOP, (_op1))
|
||||
|
||||
#define ir_CTLZ(_type, _op1) ir_UNARY_OP(IR_CTLZ, (_type), (_op1))
|
||||
#define ir_CTLZ_8(_op1) ir_UNARY_OP_U8(IR_CTLZ, (_op1))
|
||||
#define ir_CTLZ_U16(_op1) ir_UNARY_OP_U16(IR_CTLZ, (_op1))
|
||||
#define ir_CTLZ_U32(_op1) ir_UNARY_OP_U32(IR_CTLZ, (_op1))
|
||||
#define ir_CTLZ_U64(_op1) ir_UNARY_OP_U64(IR_CTLZ, (_op1))
|
||||
#define ir_CTLZ_A(_op1) ir_UNARY_OP_A(IR_CTLZ, (_op1))
|
||||
#define ir_CTLZ_C(_op1) ir_UNARY_OP_C(IR_CTLZ, (_op1))
|
||||
#define ir_CTLZ_I8(_op1) ir_UNARY_OP_I8(IR_CTLZ, (_op1))
|
||||
#define ir_CTLZ_I16(_op1) ir_UNARY_OP_I16(IR_CTLZ, (_op1))
|
||||
#define ir_CTLZ_I32(_op1) ir_UNARY_OP_I32(IR_CTLZ, (_op1))
|
||||
#define ir_CTLZ_I64(_op1) ir_UNARY_OP_I64(IR_CTLZ, (_op1))
|
||||
|
||||
#define ir_CTTZ(_type, _op1) ir_UNARY_OP(IR_CTTZ, (_type), (_op1))
|
||||
#define ir_CTTZ_8(_op1) ir_UNARY_OP_U8(IR_CTTZ, (_op1))
|
||||
#define ir_CTTZ_U16(_op1) ir_UNARY_OP_U16(IR_CTTZ, (_op1))
|
||||
#define ir_CTTZ_U32(_op1) ir_UNARY_OP_U32(IR_CTTZ, (_op1))
|
||||
#define ir_CTTZ_U64(_op1) ir_UNARY_OP_U64(IR_CTTZ, (_op1))
|
||||
#define ir_CTTZ_A(_op1) ir_UNARY_OP_A(IR_CTTZ, (_op1))
|
||||
#define ir_CTTZ_C(_op1) ir_UNARY_OP_C(IR_CTTZ, (_op1))
|
||||
#define ir_CTTZ_I8(_op1) ir_UNARY_OP_I8(IR_CTTZ, (_op1))
|
||||
#define ir_CTTZ_I16(_op1) ir_UNARY_OP_I16(IR_CTTZ, (_op1))
|
||||
#define ir_CTTZ_I32(_op1) ir_UNARY_OP_I32(IR_CTTZ, (_op1))
|
||||
#define ir_CTTZ_I64(_op1) ir_UNARY_OP_I64(IR_CTTZ, (_op1))
|
||||
|
||||
#define ir_MIN(_type, _op1, _op2) ir_BINARY_OP(IR_MIN, (_type), (_op1), (_op2))
|
||||
#define ir_MIN_U8(_op1, _op2) ir_BINARY_OP_U8(IR_MIN, (_op1), (_op2))
|
||||
#define ir_MIN_U16(_op1, _op2) ir_BINARY_OP_U16(IR_MIN, (_op1), (_op2))
|
||||
|
20
ir_emit_c.c
20
ir_emit_c.c
@ -223,6 +223,14 @@ static void ir_emit_bswap(ir_ctx *ctx, FILE *f, int def, ir_insn *insn)
|
||||
fprintf(f, ");\n");
|
||||
}
|
||||
|
||||
static void ir_emit_count(ir_ctx *ctx, FILE *f, int def, ir_insn *insn, const char *name)
|
||||
{
|
||||
ir_emit_def_ref(ctx, f, def);
|
||||
fprintf(f, "__builtin_%s%s(", name, ir_type_size[insn->type] == 8 ? "ll" : "");
|
||||
ir_emit_ref(ctx, f, insn->op1);
|
||||
fprintf(f, ");\n");
|
||||
}
|
||||
|
||||
static void ir_emit_sext(ir_ctx *ctx, FILE *f, int def, ir_insn *insn)
|
||||
{
|
||||
IR_ASSERT(IR_IS_TYPE_INT(insn->type));
|
||||
@ -895,6 +903,15 @@ static int ir_emit_func(ir_ctx *ctx, const char *name, FILE *f)
|
||||
case IR_BSWAP:
|
||||
ir_emit_bswap(ctx, f, i, insn);
|
||||
break;
|
||||
case IR_CTPOP:
|
||||
ir_emit_count(ctx, f, i, insn, "popcount");
|
||||
break;
|
||||
case IR_CTLZ:
|
||||
ir_emit_count(ctx, f, i, insn, "clz");
|
||||
break;
|
||||
case IR_CTTZ:
|
||||
ir_emit_count(ctx, f, i, insn, "ctz");
|
||||
break;
|
||||
case IR_SEXT:
|
||||
ir_emit_sext(ctx, f, i, insn);
|
||||
break;
|
||||
@ -1006,6 +1023,9 @@ static int ir_emit_func(ir_ctx *ctx, const char *name, FILE *f)
|
||||
ir_emit_ref(ctx, f, insn->op2);
|
||||
fprintf(f, ", %s);\n", ir_type_cname[insn->type]);
|
||||
break;
|
||||
case IR_TRAP:
|
||||
fprintf(f, "\t__builtin_debugtrap();\n");
|
||||
break;
|
||||
default:
|
||||
IR_ASSERT(0 && "NIY instruction");
|
||||
ctx->status = IR_ERROR_UNSUPPORTED_CODE_RULE;
|
||||
|
@ -235,14 +235,17 @@ static void ir_emit_rol_ror(ir_ctx *ctx, FILE *f, int def, ir_insn *insn, const
|
||||
fprintf(f, ")\n");
|
||||
}
|
||||
|
||||
static void ir_emit_bswap(ir_ctx *ctx, FILE *f, int def, ir_insn *insn)
|
||||
static void ir_emit_bitop(ir_ctx *ctx, FILE *f, int def, ir_insn *insn, const char *name, bool poison)
|
||||
{
|
||||
ir_type type = insn->type;
|
||||
|
||||
ir_emit_def_ref(ctx, f, def);
|
||||
fprintf(f, "call %s @llvm.bswap.%s(%s ",
|
||||
ir_type_llvm_name[type], ir_type_llvm_name[type], ir_type_llvm_name[type]);
|
||||
fprintf(f, "call %s @llvm.%s.%s(%s ",
|
||||
ir_type_llvm_name[type], name, ir_type_llvm_name[type], ir_type_llvm_name[type]);
|
||||
ir_emit_ref(ctx, f, insn->op1);
|
||||
if (poison) {
|
||||
fprintf(f, ", 0");
|
||||
}
|
||||
fprintf(f, ")\n");
|
||||
}
|
||||
|
||||
@ -795,7 +798,16 @@ static int ir_emit_func(ir_ctx *ctx, const char *name, FILE *f)
|
||||
ir_emit_rol_ror(ctx, f, i, insn, "fshr");
|
||||
break;
|
||||
case IR_BSWAP:
|
||||
ir_emit_bswap(ctx, f, i, insn);
|
||||
ir_emit_bitop(ctx, f, i, insn, "bswap", 0);
|
||||
break;
|
||||
case IR_CTPOP:
|
||||
ir_emit_bitop(ctx, f, i, insn, "ctpop", 0);
|
||||
break;
|
||||
case IR_CTLZ:
|
||||
ir_emit_bitop(ctx, f, i, insn, "ctlz", 1);
|
||||
break;
|
||||
case IR_CTTZ:
|
||||
ir_emit_bitop(ctx, f, i, insn, "cttz", 1);
|
||||
break;
|
||||
case IR_SEXT:
|
||||
IR_ASSERT(IR_IS_TYPE_INT(insn->type));
|
||||
|
@ -772,11 +772,22 @@ static ir_ref llvm2ir_intrinsic(ir_ctx *ctx, LLVMValueRef insn, LLVMTypeRef ftyp
|
||||
llvm2ir_op(ctx, LLVMGetOperand(insn, 1), IR_ADDR));
|
||||
return IR_NULL;
|
||||
} else if (STR_START(name, name_len, "llvm.ctpop.")) {
|
||||
// TODO:
|
||||
LLVMValueRef op0 = LLVMGetOperand(insn, 0);
|
||||
ir_type type = llvm2ir_type(LLVMTypeOf(op0));
|
||||
|
||||
return ir_CTPOP(type, llvm2ir_op(ctx, op0, type));
|
||||
} else if (STR_START(name, name_len, "llvm.ctlz.")) {
|
||||
// TODO:
|
||||
LLVMValueRef op0 = LLVMGetOperand(insn, 0);
|
||||
ir_type type = llvm2ir_type(LLVMTypeOf(op0));
|
||||
|
||||
// TODO: support for the second argument
|
||||
return ir_CTLZ(type, llvm2ir_op(ctx, op0, type));
|
||||
} else if (STR_START(name, name_len, "llvm.cttz.")) {
|
||||
// TODO:
|
||||
LLVMValueRef op0 = LLVMGetOperand(insn, 0);
|
||||
ir_type type = llvm2ir_type(LLVMTypeOf(op0));
|
||||
|
||||
// TODO: support for the second argument
|
||||
return ir_CTTZ(type, llvm2ir_op(ctx, op0, type));
|
||||
} else if (STR_START(name, name_len, "llvm.memset.")) {
|
||||
IR_ASSERT(count == 3 || count == 4);
|
||||
func = BUILTIN_FUNC("memset");
|
||||
|
Loading…
Reference in New Issue
Block a user