Re-re-add the type inference layer, now I know more about how things work.

Remove that terrible float promotion code.
This commit is contained in:
David Given 2016-10-22 23:04:13 +02:00
parent 11b0bc1055
commit b1a3d76d6f
9 changed files with 405 additions and 220 deletions

View file

@ -105,7 +105,9 @@ struct ir* ir_find(struct ir* ir, int opcode)
static void print_expr(char k, const struct ir* ir)
{
tracef(k, "%s", ir_data[ir->opcode].name);
if (ir->size)
if (ir->type)
tracef(k, ".%c", ir->type);
else if (ir->size)
tracef(k, "%d", ir->size);
tracef(k, "(");

View file

@ -8,6 +8,7 @@ struct ir
int id;
enum ir_opcode opcode;
int size;
char type;
struct ir* left;
struct ir* right;
struct ir* root;

View file

@ -109,11 +109,11 @@ extern void pass_convert_stack_ops(void);
extern void pass_eliminate_trivial_blocks(void);
extern void pass_find_phi_congruence_groups(void);
extern void pass_group_irs(void);
extern void pass_infer_types(void);
extern void pass_insert_moves(void);
extern void pass_instruction_selector(void);
extern void pass_live_vreg_analysis(void);
extern void pass_add_prologue_epilogue(void);
extern void pass_promote_float_ops(void);
extern void pass_register_allocator(void);
extern void pass_remove_dead_blocks(void);
extern void pass_remove_dead_phis(void);

View file

@ -1,122 +0,0 @@
#include "mcg.h"
static ARRAYOF(struct ir) pending;
static ARRAYOF(struct ir) promotable;
static void addall(struct ir* ir)
{
if (array_appendu(&pending, ir))
return;
if (ir->left)
addall(ir->left);
if (ir->right)
addall(ir->right);
}
static void collect_irs(void)
{
int i;
pending.count = 0;
promotable.count = 0;
for (i=0; i<cfg.preorder.count; i++)
{
struct basicblock* bb = cfg.preorder.item[i];
int j;
for (j=0; j<bb->irs.count; j++)
addall(bb->irs.item[j]);
}
}
static void promote(struct ir* ir)
{
switch (ir->opcode)
{
case IR_CONST:
case IR_POP:
case IR_LOAD:
array_appendu(&promotable, ir);
break;
case IR_NOP:
promote(ir->left);
break;
case IR_PHI:
{
int i;
for (i=0; i<ir->u.phivalue.count; i++)
promote(ir->u.phivalue.item[i].right);
break;
}
}
}
static void search_for_promotable_irs(void)
{
int i;
for (i=0; i<pending.count; i++)
{
struct ir* ir = pending.item[i];
switch (ir->opcode)
{
case IR_ADDF:
case IR_SUBF:
case IR_MULF:
case IR_DIVF:
case IR_NEGF:
case IR_COMPAREF1:
case IR_COMPAREF2:
case IR_COMPAREF4:
case IR_COMPAREF8:
case IR_CFF1:
case IR_CFF2:
case IR_CFF4:
case IR_CFF8:
if (ir->left)
promote(ir->left);
if (ir->right)
promote(ir->right);
break;
}
}
}
static void modify_promotable_irs(void)
{
int i;
for (i=0; i<promotable.count; i++)
{
struct ir* ir = promotable.item[i];
switch (ir->opcode)
{
case IR_ADDF:
case IR_SUBF:
case IR_MULF:
case IR_DIVF:
case IR_NEGF:
case IR_PHI:
case IR_NOP:
break;
default:
ir->opcode++;
break;
}
}
}
void pass_promote_float_ops(void)
{
collect_irs();
search_for_promotable_irs();
modify_promotable_irs();
}
/* vim: set sw=4 ts=4 expandtab : */

View file

@ -0,0 +1,277 @@
#include "mcg.h"
static bool changed;
static ARRAYOF(struct ir) irs;
static void addall(struct ir* ir)
{
if (array_appendu(&irs, ir))
return;
if (ir->left)
addall(ir->left);
if (ir->right)
addall(ir->right);
}
static void collect_irs(void)
{
int i;
irs.count = 0;
for (i=0; i<cfg.preorder.count; i++)
{
struct basicblock* bb = cfg.preorder.item[i];
int j;
for (j=0; j<bb->irs.count; j++)
addall(bb->irs.item[j]);
}
}
static char effective_type(struct ir* ir, char type)
{
switch (type)
{
case 'I':
case 'F':
case 'L':
case 'D':
return type;
case 'i':
if (ir->size == EM_wordsize)
return 'I';
else if (ir->size == (EM_wordsize*2))
return 'L';
break;
case 'f':
if (ir->size == EM_wordsize)
return 'F';
else if (ir->size == (EM_wordsize*2))
return 'D';
break;
}
return 0;
}
static void scan_irs(void)
{
int i;
for (i=0; i<irs.count; i++)
{
struct ir* ir = irs.item[i];
if (ir->opcode == IR_PHI)
{
int j;
/* Phis are special. We treat them as ?=? for every import value.
* */
if (ir->type)
{
/* Push this type to all our children. */
for (j=0; j<ir->u.phivalue.count; j++)
{
struct ir* child = ir->u.phivalue.item[j].right;
if (!child->type)
{
child->type = ir->type;
changed = true;
}
}
}
else
{
/* Pull our type from the first child with a set type; we
* ignore the rest, as the next iteration will push our type to
* them. It's possible for our children to have conflicting
* types. There's not much we can do about that so we just have
* to live with it and intelligently insert casts. */
for (j=0; j<ir->u.phivalue.count; j++)
{
struct ir* child = ir->u.phivalue.item[j].right;
if (child->type)
{
/* Found one! */
ir->type = child->type;
changed = true;
break;
}
}
}
}
else
{
const struct ir_data* ird = &ir_data[ir->opcode];
if (!ir->type)
{
char etype = effective_type(ir, ird->returntype);
if (etype)
{
ir->type = etype;
changed = true;
}
}
if (ir->left && !ir->left->type)
{
const struct ir_data* leftird = &ir_data[ir->left->opcode];
if (leftird->returntype == '?')
{
char etype = effective_type(ir, ird->lefttype);
if (etype)
{
ir->left->type = etype;
changed = true;
}
}
}
if (ir->right && !ir->right->type)
{
const struct ir_data* rightird = &ir_data[ir->right->opcode];
if (rightird->returntype == '?')
{
char etype = effective_type(ir, ird->righttype);
if (etype)
{
ir->right->type = etype;
changed = true;
}
}
}
if (!ir->type && (ird->returntype == '?'))
{
if ((ird->lefttype == '?') && ir->left->type)
{
ir->type = ir->left->type;
changed = true;
}
if ((ird->righttype == '?') && ir->right->type)
{
ir->type = ir->right->type;
changed = true;
}
}
if (ir->type && (ird->lefttype == '?') && !ir->left->type)
{
ir->left->type = ir->type;
changed = true;
}
if (ir->type && (ird->righttype == '?') && !ir->right->type)
{
ir->right->type = ir->type;
changed = true;
}
}
}
}
static void propagate_types(void)
{
do
{
changed = false;
scan_irs();
}
while (changed);
}
static void assign_fallback_types(void)
{
int i;
for (i=0; i<irs.count; i++)
{
struct ir* ir = irs.item[i];
const struct ir_data* ird = &ir_data[ir->opcode];
if (!ir->type && (ird->returntype == '?'))
ir->type = effective_type(ir, 'i');
}
}
static struct ir* new_copy(char wanted, char real, struct ir* ir)
{
struct ir* copy;
int opcode;
if ((wanted == 'F') && (real == 'I'))
opcode = IR_COPYI;
else if ((wanted == 'D') && (real == 'L'))
opcode = IR_COPYI;
else if ((wanted == 'I') && (real == 'F'))
opcode = IR_COPYF;
else if ((wanted == 'L') && (real == 'D'))
opcode = IR_COPYF;
else
fatal("type mismatch: parent IR wanted %c, child IR provided %c",
wanted, real);
copy = new_ir1(opcode, ir->size, ir);
copy->type = wanted;
return copy;
}
static void insert_copies(void)
{
int i;
/* Insert copies for normal IR nodes. */
for (i=0; i<irs.count; i++)
{
struct ir* ir = irs.item[i];
const struct ir_data* ird = &ir_data[ir->opcode];
if (ir->left)
{
char wanted = effective_type(ir, ird->lefttype);
char real = ir->left->type;
if (wanted && (wanted != real))
{
struct ir* copy = new_copy(wanted, real, ir->left);
copy->root = ir->root;
ir->left = copy;
}
}
if (ir->right)
{
char wanted = effective_type(ir, ird->righttype);
char real = ir->right->type;
if (wanted && (wanted != real))
{
struct ir* copy = new_copy(wanted, real, ir->right);
copy->root = ir->root;
ir->right = copy;
}
}
}
}
void pass_infer_types(void)
{
collect_irs();
propagate_types();
assign_fallback_types();
insert_copies();
}
/* vim: set sw=4 ts=4 expandtab : */

View file

@ -184,7 +184,7 @@ void procedure_compile(struct procedure* proc)
pass_convert_locals_to_ssa();
print_blocks('5');
pass_remove_dead_phis();
pass_promote_float_ops();
pass_infer_types();
print_blocks('6');
pass_instruction_selector();

View file

@ -1,123 +1,138 @@
# Flags:
# S: has size (use in CONST1, CONST2, CONST4, CONST8 forms)
# V: has no size (use in JUMP, CJUMP, RET forms)
#
# Types:
#
# I, F, L, D: int, float, long, double
# i, F: int, float; promoted to long, double based on size
# .: ignore this parameter
# ?: pull/push types from other ? parameters
# Simple terminals
S CONST # must be followed by float form
S CONSTF
V REG
V NOP
S LABEL
S BLOCK
V PAIR
S ANY
S LOCAL
V PHI
S ?=.. CONST # must be followed by float form
S ?=.. CONSTF
V ?=.. REG
V ?=?. NOP
S I=.. LABEL
S I=.. BLOCK
V ?=.. PAIR
S ?=.. ANY
S ?=.. LOCAL
V ?=.. PHI
# Magic stack operations
S PUSH
S POP # must be followed by float form
S POPF
S ?=?. PUSH
S ?=.. POP
S ?=.. POPF
#... Memory operations
S LOAD # must be followed by float form
S LOADF
S STORE
S STOREF
# Memory operations
S ?=I. LOAD # must be followed by float form
S f=I. LOADF
S ?=I? STORE
S ?=If STOREF
# Arithemetic operations
S ADD
S SUB
S MUL
S DIV
S DIVU
S MOD
S MODU
S NEG
S i=ii ADD
S i=ii SUB
S i=ii MUL
S i=ii DIV
S i=ii DIVU
S i=ii MOD
S i=ii MODU
S i=ii NEG
S ADDF
S SUBF
S MULF
S DIVF
S NEGF
S f=ff ADDF
S f=ff SUBF
S f=ff MULF
S f=ff DIVF
S f=ff NEGF
S AND
S OR
S EOR
S NOT
S ASL
S ASR
S LSL
S LSR
S i=ii AND
S i=ii OR
S i=ii EOR
S i=ii NOT
S i=ii ASL
S i=ii ASR
S i=ii LSL
S i=ii LSR
# Conversions
S CII1
S CII2
S CII4
S CII8
# Bitwise conversions
# (Remember, these don't change the value, merely move it)
S i=f. COPYF
S f=i. COPYI
S CIU1
S CIU2
S CIU4
S CIU8
# Semantic conversions
S F=D. D2F
S D=F. F2D
S CUI1
S CUI2
S CUI4
S CUI8
S I=I. CII1
S I=I. CII2
S I=I. CII4
S L=L. CII8
S CFI1
S CFI2
S CFI4
S CFI8
S I=I. CIU1
S I=I. CIU2
S I=I. CIU4
S L=L. CIU8
S CIF1
S CIF2
S CIF4
S CIF8
S I=I. CUI1
S I=I. CUI2
S I=I. CUI4
S L=L. CUI8
S CFF1
S CFF2
S CFF4
S CFF8
S I=F. CFI1
S I=F. CFI2
S I=F. CFI4
S L=D. CFI8
S I=F. CIF1
S I=F. CIF2
S I=F. CIF4
S L=D. CIF8
S F=F. CFF1
S F=F. CFF2
S F=F. CFF4
S D=D. CFF8
# Tristate comparisons
S COMPARES1
S COMPARES2
S COMPARES4
S COMPARES8
S I=II COMPARES1
S I=II COMPARES2
S I=II COMPARES4
S I=LL COMPARES8
S COMPAREU1
S COMPAREU2
S COMPAREU4
S COMPAREU8
S I=II COMPAREU1
S I=II COMPAREU2
S I=II COMPAREU4
S I=LL COMPAREU8
S COMPAREF1
S COMPAREF2
S COMPAREF4
S COMPAREF8
S I=FF COMPAREF1
S I=FF COMPAREF2
S I=FF COMPAREF4
S I=DD COMPAREF8
# Tristate to boolean conversion
S IFEQ
S IFLT
S IFLE
S I=I. IFEQ
S I=I. IFLT
S I=I. IFLE
# Procedures
S CALL
S i=.. CALL
# Flow control --- these never return
V JUMP
V CJUMPEQ
V CJUMPLT
V CJUMPLE
V RET
V .=i. JUMP
V .=i. CJUMPEQ
V .=i. CJUMPLT
V .=i. CJUMPLE
V .=.. RET
# Special
S STACKADJUST
S SETRET
S GETFP
S GETSP
S SETSP
S CHAINFP
S FPTOARGS
S ?=i. STACKADJUST
S ?=i. SETRET
S i=.. GETFP
S i=.. GETSP
S ?=i. SETSP
S i=i. CHAINFP
S i=i. FPTOARGS

View file

@ -10,6 +10,9 @@ struct ir_data
{
const char* name;
int flags;
char returntype;
char lefttype;
char righttype;
};
extern const struct ir_data ir_data[];

View file

@ -10,7 +10,7 @@ awk -f - $in >$header << "EOF"
}
/^ *[^# ]+/ {
print "\tIR_" $2 ","
print "\tIR_" $3 ","
}
END {
@ -30,9 +30,18 @@ awk -f - $in >$source << "EOF"
return "0"
}
function char_to_type(c) {
if (c ~ /[A-Za-z]/) return "'"c"'"
if (c == "?") return "'?'"
if (c == ".") return "0"
}
/^ *[^# ]+/ {
printf("\t{ \"%s\", ", $2)
printf("%s", char_to_flags(substr($1, 1, 1)))
printf("\t{ \"%s\", ", $3)
printf("%s, ", char_to_flags(substr($1, 1, 1)))
printf("%s, ", char_to_type(substr($2, 1, 1)))
printf("%s, ", char_to_type(substr($2, 3, 1)))
printf("%s, ", char_to_type(substr($2, 4, 1)))
printf(" },\n")
}