Skip to content

Commit

Permalink
Working bitfield instrs
Browse files Browse the repository at this point in the history
  • Loading branch information
john-h-k committed Dec 13, 2024
1 parent e75841d commit b6b3c9c
Show file tree
Hide file tree
Showing 10 changed files with 292 additions and 115 deletions.
43 changes: 43 additions & 0 deletions aarch64/codegen.c
Original file line number Diff line number Diff line change
Expand Up @@ -564,6 +564,43 @@ static void codegen_store_addr_op(struct codegen_state *state,
}
}

static void codegen_bitfield_insert(struct codegen_state *state, struct ir_op *op) {
struct ir_bitfield bitfield = op->bitfield_insert.bitfield;

struct aarch64_reg value_reg = codegen_reg(op->bitfield_insert.value);
struct aarch64_reg target_reg = codegen_reg(op->bitfield_insert.target);
struct aarch64_reg dest = codegen_reg(op);

struct instr *mov = alloc_instr(state->func);
*mov->aarch64 = MOV_ALIAS(dest, target_reg);

struct instr *instr = alloc_instr(state->func);
instr->aarch64->ty = AARCH64_INSTR_TY_BFM;
instr->aarch64->bfm = (struct aarch64_bitfield){
.dest = dest,
.source = value_reg,
.imms = bitfield.width - 1,
.immr = bitfield.offset,
};
}


static void codegen_bitfield_extract(struct codegen_state *state, struct ir_op *op) {
struct ir_bitfield bitfield = op->bitfield_extract.bitfield;

struct aarch64_reg value_reg = codegen_reg(op->bitfield_extract.value);
struct aarch64_reg dest = codegen_reg(op);

struct instr *instr = alloc_instr(state->func);
instr->aarch64->ty = AARCH64_INSTR_TY_UBFM;
instr->aarch64->ubfm = (struct aarch64_bitfield){
.dest = dest,
.source = value_reg,
.imms = bitfield.width - 1,
.immr = bitfield.offset
};
}

static void codegen_load_op(struct codegen_state *state, struct ir_op *op) {
switch (op->load.ty) {
case IR_OP_LOAD_TY_LCL:
Expand Down Expand Up @@ -2568,6 +2605,12 @@ static void codegen_op(struct codegen_state *state, struct ir_op *op) {
}
break;
}
case IR_OP_TY_BITFIELD_INSERT:
codegen_bitfield_insert(state, op);
break;
case IR_OP_TY_BITFIELD_EXTRACT:
codegen_bitfield_extract(state, op);
break;
case IR_OP_TY_LOAD:
codegen_load_op(state, op);
break;
Expand Down
4 changes: 2 additions & 2 deletions aarch64/isa.h
Original file line number Diff line number Diff line change
Expand Up @@ -309,9 +309,9 @@
#define SBFM_IMM(sf, immr, imms, Rn, Rd) \
BITFIELD_IMM(sf, 0b00, immr, imms, Rn, Rd)
#define BFM_IMM(sf, immr, imms, Rn, Rd) \
BITFIELD_IMM(sf, 0b10, immr, imms, Rn, Rd)
#define UBFM_IMM(sf, immr, imms, Rn, Rd) \
BITFIELD_IMM(sf, 0b01, immr, imms, Rn, Rd)
#define UBFM_IMM(sf, immr, imms, Rn, Rd) \
BITFIELD_IMM(sf, 0b10, immr, imms, Rn, Rd)

/* Addressing (Immediate) */

Expand Down
4 changes: 4 additions & 0 deletions aarch64/lower.c
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,8 @@ void aarch64_lower(struct ir_unit *unit) {
case IR_OP_TY_LOAD:
case IR_OP_TY_STORE_BITFIELD:
case IR_OP_TY_LOAD_BITFIELD:
case IR_OP_TY_BITFIELD_EXTRACT:
case IR_OP_TY_BITFIELD_INSERT:
case IR_OP_TY_ADDR:
case IR_OP_TY_BR_SWITCH:
case IR_OP_TY_BR:
Expand Down Expand Up @@ -507,6 +509,8 @@ void aarch64_lower(struct ir_unit *unit) {
case IR_OP_TY_LOAD:
case IR_OP_TY_STORE_BITFIELD:
case IR_OP_TY_LOAD_BITFIELD:
case IR_OP_TY_BITFIELD_EXTRACT:
case IR_OP_TY_BITFIELD_INSERT:
case IR_OP_TY_ADDR:
case IR_OP_TY_BR:
case IR_OP_TY_BR_COND:
Expand Down
16 changes: 12 additions & 4 deletions ir/build.c
Original file line number Diff line number Diff line change
Expand Up @@ -1621,7 +1621,9 @@ static struct ir_op *build_ir_for_assg(struct ir_func_builder *irb,
store->ty = IR_OP_TY_STORE_BITFIELD;
store->var_ty = IR_VAR_TY_NONE;
store->store_bitfield =
(struct ir_op_store_bitfield){.addr = address, .value = value, .bitfield = bitfield};
(struct ir_op_store_bitfield){
.ty = IR_OP_STORE_TY_ADDR,
.addr = address, .value = value, .bitfield = bitfield};
} else {
struct ir_op *store = alloc_ir_op(irb->func, *stmt);
store->ty = IR_OP_TY_STORE;
Expand Down Expand Up @@ -1676,7 +1678,9 @@ build_ir_for_memberaccess(struct ir_func_builder *irb, struct ir_stmt **stmt,
struct ir_op *op = alloc_ir_op(irb->func, *stmt);
op->ty = IR_OP_TY_LOAD_BITFIELD;
op->var_ty = var_ty;
op->load_bitfield = (struct ir_op_load_bitfield){.addr = address, .bitfield = bitfield};
op->load_bitfield = (struct ir_op_load_bitfield){
.ty = IR_OP_LOAD_TY_ADDR,
.addr = address, .bitfield = bitfield};

return op;
} else {
Expand Down Expand Up @@ -1707,7 +1711,9 @@ build_ir_for_pointeraccess(struct ir_func_builder *irb, struct ir_stmt **stmt,
struct ir_op *op = alloc_ir_op(irb->func, *stmt);
op->ty = IR_OP_TY_LOAD_BITFIELD;
op->var_ty = var_ty;
op->load_bitfield = (struct ir_op_load_bitfield){.addr = address, .bitfield = bitfield};
op->load_bitfield = (struct ir_op_load_bitfield){
.ty = IR_OP_LOAD_TY_ADDR,
.addr = address, .bitfield = bitfield};

return op;
} else {
Expand Down Expand Up @@ -2440,7 +2446,9 @@ static void build_ir_for_init_list(struct ir_func_builder *irb,
store->ty = IR_OP_TY_STORE_BITFIELD;
store->var_ty = IR_VAR_TY_NONE;
store->store_bitfield =
(struct ir_op_store_bitfield){.addr = init_address, .value = value, .bitfield = init->bitfield};
(struct ir_op_store_bitfield){
.ty = IR_OP_STORE_TY_ADDR,
.addr = init_address, .value = value, .bitfield = init->bitfield};
} else {
store->ty = IR_OP_TY_STORE;
store->var_ty = IR_VAR_TY_NONE;
Expand Down
53 changes: 52 additions & 1 deletion ir/ir.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ bool op_has_side_effects(const struct ir_op *op) {
case IR_OP_TY_CAST_OP:
case IR_OP_TY_LOAD:
case IR_OP_TY_LOAD_BITFIELD:
case IR_OP_TY_BITFIELD_EXTRACT:
case IR_OP_TY_BITFIELD_INSERT:
case IR_OP_TY_ADDR:
case IR_OP_TY_BINARY_OP:
case IR_OP_TY_UNARY_OP:
Expand Down Expand Up @@ -101,6 +103,8 @@ bool op_produces_value(const struct ir_op *op) {
case IR_OP_TY_CAST_OP:
case IR_OP_TY_LOAD:
case IR_OP_TY_LOAD_BITFIELD:
case IR_OP_TY_BITFIELD_INSERT:
case IR_OP_TY_BITFIELD_EXTRACT:
case IR_OP_TY_ADDR:
return true;
case IR_OP_TY_CALL:
Expand Down Expand Up @@ -139,6 +143,8 @@ bool op_is_branch(enum ir_op_ty ty) {
case IR_OP_TY_LOAD:
case IR_OP_TY_STORE_BITFIELD:
case IR_OP_TY_LOAD_BITFIELD:
case IR_OP_TY_BITFIELD_EXTRACT:
case IR_OP_TY_BITFIELD_INSERT:
case IR_OP_TY_ADDR:
return false;
case IR_OP_TY_CUSTOM:
Expand Down Expand Up @@ -357,6 +363,13 @@ void walk_op_uses(struct ir_op *op, walk_op_callback *cb, void *cb_metadata) {
cb(&op->ret.value, cb_metadata);
}
break;
case IR_OP_TY_BITFIELD_EXTRACT:
cb(&op->bitfield_extract.value, cb_metadata);
break;
case IR_OP_TY_BITFIELD_INSERT:
cb(&op->bitfield_insert.target, cb_metadata);
cb(&op->bitfield_insert.value, cb_metadata);
break;
}
}

Expand Down Expand Up @@ -409,6 +422,8 @@ void walk_op(struct ir_op *op, walk_op_callback *cb, void *cb_metadata) {
case IR_OP_TY_RET:
walk_ret(&op->ret, cb, cb_metadata);
break;
default:
TODO("");
}
}

Expand Down Expand Up @@ -1141,7 +1156,9 @@ void mk_pointer_constant(struct ir_unit *iru, struct ir_op *op,
}

struct ir_op *build_addr(struct ir_func *irb, struct ir_op *op) {
DEBUG_ASSERT(op->ty == IR_OP_TY_LOAD || op->ty == IR_OP_TY_STORE,
DEBUG_ASSERT(op->ty == IR_OP_TY_LOAD || op->ty == IR_OP_TY_STORE ||
op->ty == IR_OP_TY_LOAD_BITFIELD ||
op->ty == IR_OP_TY_STORE_BITFIELD,
"only makes sense on load/store ops");

struct ir_op_addr addr;
Expand All @@ -1163,6 +1180,40 @@ struct ir_op *build_addr(struct ir_func *irb, struct ir_op *op) {
case IR_OP_LOAD_TY_ADDR:
return op->load.addr;
}
} else if (op->ty == IR_OP_TY_LOAD_BITFIELD) {
switch (op->load_bitfield.ty) {
case IR_OP_LOAD_TY_LCL:
addr = (struct ir_op_addr){
.ty = IR_OP_ADDR_TY_LCL,
.lcl = op->load_bitfield.lcl,
};
goto mk_op;
case IR_OP_LOAD_TY_GLB:
addr = (struct ir_op_addr){
.ty = IR_OP_ADDR_TY_GLB,
.glb = op->load_bitfield.glb,
};
goto mk_op;
case IR_OP_LOAD_TY_ADDR:
return op->load_bitfield.addr;
}
} else if (op->ty == IR_OP_TY_STORE_BITFIELD) {
switch (op->store_bitfield.ty) {
case IR_OP_STORE_TY_LCL:
addr = (struct ir_op_addr){
.ty = IR_OP_ADDR_TY_LCL,
.lcl = op->store_bitfield.lcl,
};
goto mk_op;
case IR_OP_STORE_TY_GLB:
addr = (struct ir_op_addr){
.ty = IR_OP_ADDR_TY_GLB,
.glb = op->store_bitfield.glb,
};
goto mk_op;
case IR_OP_STORE_TY_ADDR:
return op->store_bitfield.addr;
}
} else {
switch (op->store.ty) {
case IR_OP_STORE_TY_LCL:
Expand Down
18 changes: 18 additions & 0 deletions ir/ir.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ enum ir_op_ty {
IR_OP_TY_STORE_BITFIELD,
IR_OP_TY_LOAD_BITFIELD,

IR_OP_TY_BITFIELD_EXTRACT,
IR_OP_TY_BITFIELD_INSERT,

IR_OP_TY_ADDR,

IR_OP_TY_BR,
Expand Down Expand Up @@ -269,6 +272,19 @@ struct ir_bitfield {
size_t width;
};

struct ir_op_bitfield_extract {
struct ir_op *value;

struct ir_bitfield bitfield;
};

struct ir_op_bitfield_insert {
struct ir_op *target;
struct ir_op *value;

struct ir_bitfield bitfield;
};

enum ir_op_store_ty {
IR_OP_STORE_TY_LCL,
IR_OP_STORE_TY_GLB,
Expand Down Expand Up @@ -444,6 +460,8 @@ struct ir_op {
struct ir_op_load load;
struct ir_op_store_bitfield store_bitfield;
struct ir_op_load_bitfield load_bitfield;
struct ir_op_bitfield_extract bitfield_extract;
struct ir_op_bitfield_insert bitfield_insert;
struct ir_op_addr addr;
struct ir_op_br_cond br_cond;
struct ir_op_br_switch br_switch;
Expand Down
97 changes: 82 additions & 15 deletions ir/prettyprint.c
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,7 @@ static void debug_print_op(FILE *file, struct ir_func *irb, struct ir_op *ir,
case IR_OP_TY_STORE:
switch (ir->store.ty) {
case IR_OP_STORE_TY_LCL:
if (ir->lcl) {
if (ir->store.lcl) {
fprintf(file, "store.lcl LCL(%zu), %%%zu", ir->store.lcl->id,
ir->store.value->id);
} else {
Expand All @@ -376,7 +376,7 @@ static void debug_print_op(FILE *file, struct ir_func *irb, struct ir_op *ir,
case IR_OP_TY_LOAD:
switch (ir->load.ty) {
case IR_OP_LOAD_TY_LCL:
if (ir->lcl) {
if (ir->load.lcl) {
fprintf(file, "load.lcl LCL(%zu)", ir->load.lcl->id);
} else {
fprintf(file, "load.lcl LCL(UNASSIGNED)");
Expand All @@ -397,21 +397,74 @@ static void debug_print_op(FILE *file, struct ir_func *irb, struct ir_op *ir,
}

break;
case IR_OP_TY_STORE_BITFIELD:
fprintf(file, "store.bitfield (#%zu, #%zu) [",
ir->store_bitfield.bitfield.offset,
ir->store_bitfield.bitfield.width);
debug_print_op_use(file, irb, ir->store_bitfield.addr);
fprintf(file, "], ");
debug_print_op_use(file, irb, ir->store_bitfield.value);

case IR_OP_TY_STORE_BITFIELD: {
struct ir_bitfield bitfield = ir->store_bitfield.bitfield;

switch (ir->store_bitfield.ty) {
case IR_OP_STORE_TY_LCL:
if (ir->store_bitfield.lcl) {
fprintf(file, "store.bitfield.lcl (#%zu, #%zu) LCL(%zu), %%%zu",
bitfield.offset, bitfield.width, ir->store_bitfield.lcl->id,
ir->store_bitfield.value->id);
} else {
fprintf(file, "store.bitfield.lcl (#%zu, #%zu) LCL(UNASSIGNED), %%%zu",
bitfield.offset, bitfield.width, ir->store_bitfield.value->id);
}
break;
case IR_OP_STORE_TY_GLB:
if (ir->store_bitfield.glb) {
fprintf(file, "store.bitfield.glb (#%zu, #%zu) GLB(%zu), %%%zu",
bitfield.offset, bitfield.width, ir->store_bitfield.glb->id,
ir->store_bitfield.value->id);
} else {
fprintf(file, "store.bitfield.glb (#%zu, #%zu) GLB(UNASSIGNED), %%%zu",
bitfield.offset, bitfield.width, ir->store_bitfield.value->id);
}
break;
case IR_OP_STORE_TY_ADDR:
fprintf(file, "store.bitfield.addr (#%zu, #%zu) [", bitfield.offset,
bitfield.width);
debug_print_op_use(file, irb, ir->store_bitfield.addr);
fprintf(file, "], ");
debug_print_op_use(file, irb, ir->store_bitfield.value);
break;
}

break;
case IR_OP_TY_LOAD_BITFIELD:
fprintf(file, "load.bitfield (#%zu, #%zu) [",
ir->load_bitfield.bitfield.offset,
ir->load_bitfield.bitfield.width);
debug_print_op_use(file, irb, ir->load_bitfield.addr);
fprintf(file, "]");
}
case IR_OP_TY_LOAD_BITFIELD: {
struct ir_bitfield bitfield = ir->load_bitfield.bitfield;

switch (ir->load_bitfield.ty) {
case IR_OP_LOAD_TY_LCL:
if (ir->load_bitfield.glb) {
fprintf(file, "load.bitfield.lcl (#%zu, #%zu) LCL(%zu)", bitfield.offset,
bitfield.width, ir->load_bitfield.lcl->id);
} else {
fprintf(file, "load.bitfield.lcl (#%zu, #%zu) LCL(UNASSIGNED)", bitfield.offset,
bitfield.width);
}
break;
case IR_OP_LOAD_TY_GLB:
if (ir->load_bitfield.glb) {
fprintf(file, "load.bitfield.glb (#%zu, #%zu) GLB(%zu)", bitfield.offset,
bitfield.width, ir->load_bitfield.glb->id);
} else {
fprintf(file, "load.bitfield.glb (#%zu, #%zu) GLB(UNASSIGNED)", bitfield.offset,
bitfield.width);
}
break;
case IR_OP_LOAD_TY_ADDR:
fprintf(file, "load.bitfield.addr (#%zu, #%zu) [", bitfield.offset,
bitfield.width);
debug_print_op_use(file, irb, ir->load_bitfield.addr);
fprintf(file, "]");
break;
}

break;
}
case IR_OP_TY_ADDR:
switch (ir->addr.ty) {
case IR_OP_ADDR_TY_LCL:
Expand Down Expand Up @@ -479,6 +532,20 @@ static void debug_print_op(FILE *file, struct ir_func *irb, struct ir_op *ir,
fprintf(file, "return");
}
break;
case IR_OP_TY_BITFIELD_EXTRACT:
fprintf(file, "bitfield.extract #(%zu, %zu), ",
ir->bitfield_extract.bitfield.offset,
ir->bitfield_extract.bitfield.width);
debug_print_op_use(file, irb, ir->bitfield_extract.value);
break;
case IR_OP_TY_BITFIELD_INSERT:
fprintf(file, "bitfield.insert #(%zu, %zu), ",
ir->bitfield_insert.bitfield.offset,
ir->bitfield_insert.bitfield.width);
debug_print_op_use(file, irb, ir->bitfield_insert.target);
fprintf(file, ", ");
debug_print_op_use(file, irb, ir->bitfield_insert.value);
break;
}
}

Expand Down
Loading

0 comments on commit b6b3c9c

Please sign in to comment.