#include #include "ir.h" #include #include #include typedef struct Inst Inst; typedef enum { ARG, /* Copy an argument to a variable */ LABEL, /* Label */ JUMP_NEQ, /* Jump if expressions are not equal */ JUMP_NAND, /* Jump if "and" of expressions is zero */ MOV, /* Copy from b to a */ BEGIN_BINARY, SUB, /* sub d, a, b: Subtract b from a and store in d */ MUL, /* mul d, a, b: Multiply a, b and store in d */ ADD, /* add d, a, b: Add a, b, store in d */ ADDS, /* adds d, a, b: Add a and b saturated, store in d */ XOR, /* xor d, a, b: XOR a, b, and store in d */ END_BINARY, BEGIN_SHIFT, SHRL, /* shrl d, a, pos */ END_SHIFT, SHUFFLE4, } InstType; struct Inst { InstType type; union { struct { int arg_no; IRVar * dest; } arg; struct { const char *name; } label; struct { IRVar * op1; IRVar * op2; char * label; } jump_neq, jump_nand; struct { IRVar * dest; IRVar * src1; IRVar * src2; } binary; struct { IRVar * dest; IRVar * src; IRVar * n_pos; } shift; struct { IRVar * dest; IRVar * src; } mov; struct { IRVar * dest; IRVar * src; int s1; int s2; int s3; int s4; } shuffle4; } u; }; struct IR { GQueue *instructions; }; struct IRVar { int n_fields; IRBasicType type; }; static Inst * inst_new (IR *ir, InstType type) { Inst *inst = g_new0 (Inst, 1); inst->type = type; g_queue_push_tail (ir->instructions, inst); return inst; } IR * ir_new (void) { return g_new0 (IR, 1); } IRVar * ir_var_new (IR *ir, int n_fields, IRBasicType type) { IRVar *var = g_new0 (IRVar, 1); var->n_fields = n_fields; var->type = type; return var; } IRVar * ir_arg (IR *ir, int arg_no, IRBasicType type) { Inst *inst = inst_new (ir, ARG); inst->u.arg.arg_no = arg_no; inst->u.arg.dest = ir_var_new (ir, 1, type); return NULL; } /* Create a new variable with the same type as other */ IRVar * ir_var_new_similar (IR *ir, IRVar *other) { return ir_var_new (ir, other->n_fields, other->type); } /* Create a new variable with half the number of * twice as wide fields. */ IRVar * ir_var_new_wider (IR *ir, IRVar *other) { IRBasicType type; int n_fields; assert (other->n_fields > 1); /* Or it doesn't make sense to widen */ switch (other->type) { case IR_UINT64: assert (FALSE); break; case IR_UINT32: type = IR_UINT64; break; case IR_UINT16: type = IR_UINT32; break; case IR_UINT8: type = IR_UINT16; break; case IR_INT64: assert (FALSE); break; case IR_INT32: type = IR_INT32; break; case IR_INT16: type = IR_INT32; break; case IR_INT8: type = IR_INT16; break; case IR_POINTER: assert (FALSE); break; } n_fields = other->n_fields / 2; return ir_var_new (ir, n_fields, type); } void ir_label (IR *ir, const char *name) { Inst *inst = inst_new (ir, LABEL); inst->u.label.name = g_strdup (name); } void ir_jump_neq (IR *ir, IRVar *op1, IRVar *op2, const char *label) { Inst *inst = inst_new (ir, JUMP_NEQ); inst->u.jump_neq.op1 = op1; inst->u.jump_neq.op2 = op2; inst->u.jump_neq.label = g_strdup (label); } void ir_jump_nand (IR *ir, IRVar *op1, IRVar *op2, const char *label) { Inst *inst = inst_new (ir, JUMP_NAND); inst->u.jump_nand.op1 = op1; inst->u.jump_nand.op2 = op2; inst->u.jump_nand.label = g_strdup (label); } void ir_mov (IR *ir, IRVar *dest, IRVar *src) { Inst *inst = inst_new (ir, MOV); inst->u.mov.dest = dest; inst->u.mov.src = src; } static void add_binary (IR *ir, InstType type, IRVar *dest, IRVar *src1, IRVar *src2) { Inst *inst; assert (type > BEGIN_BINARY); assert (type < END_BINARY); inst = inst_new (ir, type); inst->u.binary.dest = dest; inst->u.binary.src1 = src1; inst->u.binary.src2 = src2; } void ir_sub (IR *ir, IRVar *dest, IRVar *src1, IRVar *src2) { add_binary (ir, SUB, dest, src1, src2); } void ir_mul (IR *ir, IRVar *dest, IRVar *src1, IRVar *src2) { add_binary (ir, MUL, dest, src1, src2); } void ir_add (IR *ir, IRVar *dest, IRVar *src1, IRVar *src2) { add_binary (ir, ADD, dest, src1, src2); } void ir_adds (IR *ir, IRVar *dest, IRVar *src1, IRVar *src2) { add_binary (ir, ADDS, dest, src1, src2); } void ir_xor (IR *ir, IRVar *dest, IRVar *src1, IRVar *src2) { add_binary (ir, XOR, dest, src1, src2); } static void add_shift (IR *ir, InstType type, IRVar *dest, IRVar *src, IRVar *n_pos) { Inst *inst; assert (type > BEGIN_SHIFT); assert (type < END_SHIFT); inst = inst_new (ir, type); inst->u.shift.dest = dest; inst->u.shift.src = src; inst->u.shift.n_pos = n_pos; } void ir_shrl (IR *ir, IRVar *dest, IRVar *src, IRVar *n_pos) { add_shift (ir, SHRL, dest, src, n_pos); } void ir_shuffle4 (IR *ir, IRVar *dest, IRVar *src, int s1, int s2, int s3, int s4) { Inst *inst = inst_new (ir, SHUFFLE4); inst->u.shuffle4.dest = dest; inst->u.shuffle4.src = src; inst->u.shuffle4.s1 = s1; inst->u.shuffle4.s2 = s2; inst->u.shuffle4.s3 = s3; inst->u.shuffle4.s4 = s4; } IRVar * ir_iconst1 (IR *ir, uint32_t value) { return NULL; } void ir_load32 (IR *ir, IRVar *dest, IRVar *src) { } void ir_load8 (IR *ir, IRVar *dest, IRVar *src) { } void ir_store (IR *ir, IRVar *src, IRVar *pointer) { } void ir_jump (IR *ir, const char *label) { } void ir_unpack_low (IR *ir, IRVar *dest, IRVar *src1, IRVar *src2) { } void ir_unpack_high (IR *ir, IRVar *dest, IRVar *src1, IRVar *src2) { } void ir_pack (IR *ir, IRVar *dest, IRVar *low, IRVar *high) { }