Skip to content

Commit

Permalink
Remove unused virtual register
Browse files Browse the repository at this point in the history
If a virtual register is set but not read, remove it
(except function parameter).

Now you can use post increment expression (`i++`)
without worry about extra cost.

Also unused return value from a function is eliminated.
  • Loading branch information
tyfkda committed Aug 8, 2023
1 parent c373e30 commit 11a71a7
Show file tree
Hide file tree
Showing 9 changed files with 83 additions and 3 deletions.
6 changes: 6 additions & 0 deletions src/_debug/dump_ir.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ static void dump_ir(FILE *fp, IR *ir) {
static char *kCond[] = {"__", "MP", "EQ", "NE", "LT", "LE", "GE", "GT", "ULT", "ULE", "UGE", "UGT"};

switch (ir->kind) {
case IR_NOOP: fprintf(fp, "\tNOOP\n"); break;
case IR_BOFS: fprintf(fp, "\tBOFS\t"); dump_vreg(fp, ir->dst); fprintf(fp, " = &[rbp %c %d]\n", ir->opr1->offset >= 0 ? '+' : '-', ir->opr1->offset > 0 ? ir->opr1->offset : -ir->opr1->offset); break;
case IR_IOFS: fprintf(fp, "\tIOFS\t"); dump_vreg(fp, ir->dst); fprintf(fp, " = &%.*s\n", ir->iofs.label->bytes, ir->iofs.label->chars); break;
case IR_SOFS: fprintf(fp, "\tSOFS\t"); dump_vreg(fp, ir->dst); fprintf(fp, " = &[rsp %c %" PRId64 "]\n", ir->opr1->fixnum >= 0 ? '+' : '-', ir->opr1->fixnum > 0 ? ir->opr1->fixnum : -ir->opr1->fixnum); break;
Expand Down Expand Up @@ -118,6 +119,11 @@ static void dump_func_ir(Function *func) {
for (int i = 0; i < ra->vregs->len; ++i) {
LiveInterval *li = sorted_intervals[i];
VReg *vreg = ra->vregs->data[li->virt];
if (vreg == NULL) {
fprintf(fp, " V%3d: null\n", li->virt);
continue;
}

switch (li->state) {
case LI_NORMAL:
{
Expand Down
2 changes: 2 additions & 0 deletions src/cc/arch/aarch64/ir_aarch64.c
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,8 @@ static bool is_got(const Name *name) {

static void ir_out(IR *ir) {
switch (ir->kind) {
case IR_NOOP:
break;
case IR_BOFS:
{
const char *dst = kReg64s[ir->dst->phys];
Expand Down
2 changes: 2 additions & 0 deletions src/cc/arch/x64/ir_x64.c
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,8 @@ static bool is_got(const Name *name) {

static void ir_out(IR *ir) {
switch (ir->kind) {
case IR_NOOP:
break;
case IR_BOFS:
if (ir->opr1->flag & VRF_CONST)
LEA(OFFSET_INDIRECT(ir->opr1->fixnum, RBP, NULL, 1), kReg64s[ir->dst->phys]);
Expand Down
6 changes: 5 additions & 1 deletion src/cc/backend/codegen.c
Original file line number Diff line number Diff line change
Expand Up @@ -555,6 +555,8 @@ static void prepare_register_allocation(Function *func) {
static void map_virtual_to_physical_registers(RegAlloc *ra) {
for (int i = 0, vreg_count = ra->vregs->len; i < vreg_count; ++i) {
VReg *vreg = ra->vregs->data[i];
if (vreg == NULL)
continue;
if (!(vreg->flag & VRF_CONST))
vreg->phys = ra->intervals[vreg->virt].phys;
}
Expand Down Expand Up @@ -603,6 +605,8 @@ static void detect_living_registers(RegAlloc *ra, BBContainer *bbcon) {
// Add activated registers.
for (; head < ra->vregs->len; ++head) {
LiveInterval *li = ra->sorted_intervals[head];
if (ra->vregs->data[li->virt] == NULL)
continue;
if (li->state != LI_NORMAL)
continue;
if (li->start > nip)
Expand Down Expand Up @@ -689,7 +693,7 @@ static void gen_defun(Function *func) {
set_curbb(fnbe->ret_bb);
curbb = NULL;

optimize(fnbe->bbcon);
optimize(fnbe->ra, fnbe->bbcon);

prepare_register_allocation(func);
tweak_irs(fnbe);
Expand Down
6 changes: 6 additions & 0 deletions src/cc/backend/ir.c
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,12 @@ void new_ir_asm(const char *asm_, VReg *dst) {
ir->dst = dst;
}

void make_ir_noop(IR *ir) {
ir->kind = IR_NOOP;
ir->dst = ir->opr1 = ir->opr2 = NULL;
ir->value = 0;
}

IR *new_ir_load_spilled(VReg *reg, VReg *src) {
IR *ir = new_ir(IR_LOAD_SPILLED);
ir->dst = reg;
Expand Down
2 changes: 2 additions & 0 deletions src/cc/backend/ir.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ void spill_vreg(VReg *vreg);
// Intermediate Representation

enum IrKind {
IR_NOOP, // No operation (removed)
IR_BOFS, // dst = [rbp + offset]
IR_IOFS, // dst = [rip + label]
IR_SOFS, // dst = [rsp + offset]
Expand Down Expand Up @@ -180,6 +181,7 @@ VReg *new_ir_cast(VReg *vreg, const VRegType *dsttype);
void new_ir_memcpy(VReg *dst, VReg *src, size_t size);
void new_ir_clear(VReg *reg, size_t size);
void new_ir_asm(const char *asm_, VReg *dst);
void make_ir_noop(IR *ir);

IR *new_ir_load_spilled(VReg *reg, VReg *src);
IR *new_ir_store_spilled(VReg *dst, VReg *reg);
Expand Down
54 changes: 53 additions & 1 deletion src/cc/backend/optimize.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
#include "optimize.h"

#include <assert.h>
#include <stdlib.h> // free

#include "ir.h"
#include "regalloc.h"
#include "table.h"
#include "util.h"

Expand Down Expand Up @@ -136,6 +138,56 @@ static void remove_unnecessary_bb(BBContainer *bbcon) {

//

void optimize(BBContainer *bbcon) {
static void remove_unused_vregs(RegAlloc *ra, BBContainer *bbcon) {
int vreg_count = ra->vregs->len;
unsigned char *vreg_read = malloc_or_die(vreg_count);
for (int i = 0; i < vreg_count; ++i) {
VReg *vreg = ra->vregs->data[i];
vreg_read[i] = (vreg->flag & VRF_PARAM) != 0; // Must keep function parameter.
}

// Check VReg usage.
for (int i = 0; i < bbcon->bbs->len; ++i) {
BB *bb = bbcon->bbs->data[i];
for (int j = 0; j < bb->irs->len; ++j) {
IR *ir = bb->irs->data[j];
VReg *operands[] = {ir->opr1, ir->opr2};
for (int k = 0; k < 2; ++k) {
VReg *vreg = operands[k];
if (vreg != NULL)
vreg_read[vreg->virt] = true;
}
}
}

// Make instruction NOOP if the destination is unread.
for (int i = 0; i < bbcon->bbs->len; ++i) {
BB *bb = bbcon->bbs->data[i];
for (int j = 0; j < bb->irs->len; ++j) {
IR *ir = bb->irs->data[j];
if (ir->dst == NULL || vreg_read[ir->dst->virt])
continue;
if (ir->kind == IR_CALL)
ir->dst = NULL;
else
make_ir_noop(ir);
}
}

// Release unused VRegs.
for (int i = 0; i < vreg_count; ++i) {
if (!vreg_read[i]) {
free(ra->vregs->data[i]);
ra->vregs->data[i] = NULL;
}
}

free(vreg_read);
}

//

void optimize(RegAlloc *ra, BBContainer *bbcon) {
remove_unused_vregs(ra, bbcon);
remove_unnecessary_bb(bbcon);
}
3 changes: 2 additions & 1 deletion src/cc/backend/optimize.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#pragma once

typedef struct BBContainer BBContainer;
typedef struct RegAlloc RegAlloc;

void optimize(BBContainer *bbcon);
void optimize(RegAlloc *ra, BBContainer *bbcon);
5 changes: 5 additions & 0 deletions src/cc/backend/regalloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,8 @@ static void linear_scan_register_allocation(RegAlloc *ra, LiveInterval **sorted_

for (int i = 0; i < vreg_count; ++i) {
LiveInterval *li = sorted_intervals[i];
if (ra->vregs->data[li->virt] == NULL)
continue;
if (li->state != LI_NORMAL)
continue;
expire_old_intervals(ireg_info.active, &ireg_info.active_count, &ireg_info.using_bits,
Expand Down Expand Up @@ -277,6 +279,7 @@ static int insert_load_store_spilled_irs(RegAlloc *ra, BBContainer *bbcon) {
flag = 4;
break;

case IR_NOOP:
case IR_LOAD_SPILLED:
case IR_STORE_SPILLED:
continue;
Expand Down Expand Up @@ -321,6 +324,8 @@ void alloc_physical_registers(RegAlloc *ra, BBContainer *bbcon) {
for (int i = 0; i < vreg_count; ++i) {
LiveInterval *li = &intervals[i];
VReg *vreg = ra->vregs->data[i];
if (vreg == NULL)
continue;

if (vreg->flag & VRF_CONST) {
li->state = LI_CONST;
Expand Down

0 comments on commit 11a71a7

Please sign in to comment.