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) static void print_expr(char k, const struct ir* ir)
{ {
tracef(k, "%s", ir_data[ir->opcode].name); 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, "%d", ir->size);
tracef(k, "("); tracef(k, "(");

View file

@ -8,6 +8,7 @@ struct ir
int id; int id;
enum ir_opcode opcode; enum ir_opcode opcode;
int size; int size;
char type;
struct ir* left; struct ir* left;
struct ir* right; struct ir* right;
struct ir* root; 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_eliminate_trivial_blocks(void);
extern void pass_find_phi_congruence_groups(void); extern void pass_find_phi_congruence_groups(void);
extern void pass_group_irs(void); extern void pass_group_irs(void);
extern void pass_infer_types(void);
extern void pass_insert_moves(void); extern void pass_insert_moves(void);
extern void pass_instruction_selector(void); extern void pass_instruction_selector(void);
extern void pass_live_vreg_analysis(void); extern void pass_live_vreg_analysis(void);
extern void pass_add_prologue_epilogue(void); extern void pass_add_prologue_epilogue(void);
extern void pass_promote_float_ops(void);
extern void pass_register_allocator(void); extern void pass_register_allocator(void);
extern void pass_remove_dead_blocks(void); extern void pass_remove_dead_blocks(void);
extern void pass_remove_dead_phis(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(); pass_convert_locals_to_ssa();
print_blocks('5'); print_blocks('5');
pass_remove_dead_phis(); pass_remove_dead_phis();
pass_promote_float_ops(); pass_infer_types();
print_blocks('6'); print_blocks('6');
pass_instruction_selector(); pass_instruction_selector();

View file

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

View file

@ -10,6 +10,9 @@ struct ir_data
{ {
const char* name; const char* name;
int flags; int flags;
char returntype;
char lefttype;
char righttype;
}; };
extern const struct ir_data ir_data[]; 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 { END {
@ -30,9 +30,18 @@ awk -f - $in >$source << "EOF"
return "0" 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("\t{ \"%s\", ", $3)
printf("%s", char_to_flags(substr($1, 1, 1))) 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") printf(" },\n")
} }