Keep more data around about ir instructions. Implement a half-baked type

inference routine to propagate information about floats up the tree, so we know
whether to put floats into special registers as early as possible.
This commit is contained in:
David Given 2016-09-26 22:12:46 +02:00
parent 416b13fd76
commit cc176e5183
10 changed files with 215 additions and 113 deletions

View file

@ -103,9 +103,15 @@ 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_names[ir->opcode]); tracef(k, "%s", ir_data[ir->opcode].name);
if (ir->size) if (ir->size)
tracef(k, "%d", ir->size); tracef(k, "%d", ir->size);
if (ir->type)
tracef(k, ".%s",
((ir->type == IRT_INT) ? "I" :
(ir->type == IRT_FLOAT) ? "F" :
(ir->type == IRT_ANY) ? "*" :
"?"));
tracef(k, "("); tracef(k, "(");
switch (ir->opcode) switch (ir->opcode)

View file

@ -3,27 +3,12 @@
#include "ircodes.h" #include "ircodes.h"
enum
{
IRR_LB = -1,
IRR_AB = -2,
IRR_SP = -3,
IRR_RR = -4,
};
enum
{
IRS_1,
IRS_2,
IRS_4,
IRS_8
};
struct ir struct ir
{ {
int id; int id;
enum ir_opcode opcode; enum ir_opcode opcode;
int size; int size;
enum ir_type type;
struct ir* left; struct ir* left;
struct ir* right; struct ir* right;
union union

View file

@ -123,6 +123,7 @@ extern void pass_convert_stack_ops(struct procedure* proc);
extern void pass_remove_dead_blocks(struct procedure* proc); extern void pass_remove_dead_blocks(struct procedure* proc);
extern void pass_eliminate_trivial_blocks(struct procedure* proc); extern void pass_eliminate_trivial_blocks(struct procedure* proc);
extern void pass_instruction_selector(struct procedure* proc); extern void pass_instruction_selector(struct procedure* proc);
extern void pass_type_inference(struct procedure* proc);
extern void procedure_compile(struct procedure* proc); extern void procedure_compile(struct procedure* proc);

View file

@ -0,0 +1,63 @@
#include "mcg.h"
static enum ir_type search_for_type(struct ir* ir, enum ir_type desired)
{
const struct ir_data* data;
if (ir->type != IRT_UNSET)
return ir->type;
data = &ir_data[ir->opcode];
if (ir->left)
ir->left->type = search_for_type(ir->left, data->lefttype);
if (ir->right)
ir->right->type = search_for_type(ir->right, data->righttype);
switch (data->returntype)
{
case IRT_ANY:
if (desired == IRT_FLOAT)
ir->opcode++;
return desired;
case IRT_UNSET:
assert(!((data->lefttype == IRT_ANY) && (data->righttype == IRT_ANY)));
if (((data->lefttype == IRT_ANY) && (ir->left->type == IRT_FLOAT)) ||
((data->righttype == IRT_ANY) && (ir->right->type == IRT_FLOAT)))
{
ir->opcode++;
return IRT_FLOAT;
}
if ((data->lefttype == IRT_ANY) && (ir->left->type == IRT_ANY))
ir->left->type = IRT_INT;
if ((data->righttype == IRT_ANY) && (ir->right->type == IRT_ANY))
ir->right->type = IRT_INT;
return IRT_INT;
default:
return data->returntype;
}
}
static void push_types_up(struct basicblock* bb)
{
int i;
for (i=0; i<bb->irs_count; i++)
{
struct ir* ir = bb->irs[i];
ir->type = search_for_type(ir, ir->type);
}
}
void pass_type_inference(struct procedure* proc)
{
int i;
for (i=0; i<proc->blocks_count; i++)
push_types_up(proc->blocks[i]);
}
/* vim: set sw=4 ts=4 expandtab : */

View file

@ -29,6 +29,7 @@ void procedure_compile(struct procedure* proc)
pass_eliminate_trivial_blocks(proc); pass_eliminate_trivial_blocks(proc);
pass_remove_dead_blocks(proc); pass_remove_dead_blocks(proc);
pass_convert_stack_ops(proc); pass_convert_stack_ops(proc);
pass_type_inference(proc);
print_blocks('2', proc); print_blocks('2', proc);

View file

@ -12,7 +12,7 @@ yacc {
normalrule { normalrule {
name = "ircodes", name = "ircodes",
outleaves = { "ircodes.h", "ircodes.c" }, outleaves = { "ircodes-dyn.h", "ircodes.c" },
ins = { ins = {
"./ircodes.sh", "./ircodes.sh",
"./ir.dat" "./ir.dat"
@ -25,10 +25,15 @@ normalrule {
clibrary { clibrary {
name = "lib", name = "lib",
srcs = { srcs = {
matching(filenamesof("+ircodes"), "%.c$") matching(filenamesof("+ircodes"), "%.c$"),
},
deps = {
"+ircodes",
"./ircodes.h"
}, },
hdrs = { hdrs = {
matching(filenamesof("+ircodes"), "%.h$"), matching(filenamesof("+ircodes"), "%.h$"),
"./ircodes.h",
"./mcgg.h" "./mcgg.h"
} }
} }

View file

@ -176,9 +176,9 @@ char* stringf(char* fmt, ...)
return p; return p;
} }
static void registerterminal(const char* name, int iropcode, int size) static void registerterminal(const struct ir_data* data, int iropcode, int size)
{ {
const char* s = (size == 0) ? name : stringf("%s%d", name, size); const char* s = (size == 0) ? data->name : stringf("%s%d", data->name, size);
int esn = ir_to_esn(iropcode, size); int esn = ir_to_esn(iropcode, size);
term(s, esn); term(s, esn);
@ -190,15 +190,15 @@ static void registerterminals(void)
for (i=0; i<IR__COUNT; i++) for (i=0; i<IR__COUNT; i++)
{ {
if (ir_flags[i] & IRF_SIZED) if (ir_data[i].flags & IRF_SIZED)
{ {
registerterminal(ir_names[i], i, 1); registerterminal(&ir_data[i], i, 1);
registerterminal(ir_names[i], i, 2); registerterminal(&ir_data[i], i, 2);
registerterminal(ir_names[i], i, 4); registerterminal(&ir_data[i], i, 4);
registerterminal(ir_names[i], i, 8); registerterminal(&ir_data[i], i, 8);
} }
else else
registerterminal(ir_names[i], i, 0); registerterminal(&ir_data[i], i, 0);
} }
} }

View file

@ -1,76 +1,92 @@
# 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: integer, float
# A: any (will be coerced to I or F during IR postprocessing)
#
# Any instruction with an A type must be followed by the corresponding F
# version.
# Simple terminals # Simple terminals
S CONST SA.. CONST
S REG SF.. CONSTF
S LABEL SA.. REG
S BLOCK SF.. REGF
V PAIR SI.. LABEL
S ANY SI.. BLOCK
S LOCAL V... PAIR
S PHI SA.. ANY
SF.. ANYF
S... LOCAL
S... PHI
# Magic stack operations # Magic stack operations
S PUSH S.A. PUSH
S POP S.F. PUSHF
SA.. POP
SF.. POPF
#... Memory operations
SAI. LOAD
SFI. LOADF
S.IA STORE
S.IF STOREF
# Memory operations
S LOAD
S STORE
# Arithemetic operations # Arithemetic operations
S ADD SIII ADD
S SUB SIII SUB
S MUL SIII MUL
S DIV SIII DIV
S MOD SIII MOD
S NEG SIII NEG
S ADDF SFFF ADDF
S SUBF SFFF SUBF
S MULF SFFF MULF
S DIVF SFFF DIVF
S NEGF SFFF NEGF
S AND SIII AND
S OR SIII OR
S EOR SIII EOR
S NOT SIII NOT
# Conversions # Conversions
S CII1 SIII CII1
S CII2 SIII CII2
S CII4 SIII CII4
S CII8 SIII CII8
S CIU1 SIII CIU1
S CIU2 SIII CIU2
S CIU4 SIII CIU4
S CIU8 SIII CIU8
# Tristate comparisons # Tristate comparisons
S COMPARES SIII COMPARES
S COMPAREU SIII COMPAREU
# Boolean comparisons # Boolean comparisons
S IFEQ SIII IFEQ
S IFLT SIII IFLT
S IFLE SIII IFLE
# Procedures # Procedures
V CALL VI.. CALL
# Flow control --- these never return # Flow control --- these never return
V JUMP V.I. JUMP
V CJUMPEQ VIII CJUMPEQ
V CJUMPLT VIII CJUMPLT
V CJUMPLE VIII CJUMPLE
V RET V... RET
# Special # Special
S STACKADJUST SI.. STACKADJUST
S GETRET SA.. GETRET
S SETRET SF.. GETRETF
S.A. SETRET
S.F. SETRETF

33
util/mcgg/ircodes.h Normal file
View file

@ -0,0 +1,33 @@
#ifndef IRCODES_H
#define IRCODES_H
enum
{
IRF_SIZED = 1,
};
enum ir_type
{
IRT_UNSET = 0,
IRT_INT,
IRT_FLOAT,
IRT_ANY
};
struct ir_data
{
const char* name;
int flags;
enum ir_type returntype;
enum ir_type lefttype;
enum ir_type righttype;
};
extern const struct ir_data ir_data[];
#include "ircodes-dyn.h"
#endif
/* vim: set sw=4 ts=4 expandtab : */

View file

@ -16,42 +16,34 @@ awk -f - $in >$header << "EOF"
END { END {
print "\tIR__COUNT" print "\tIR__COUNT"
print "};" print "};"
print ""
print "enum {"
print "\tIRF_SIZED = 1"
print "};"
print ""
print "extern const char* ir_names[IR__COUNT];"
print "extern const char ir_flags[IR__COUNT];"
} }
EOF EOF
awk -f - $in >$source << "EOF" awk -f - $in >$source << "EOF"
BEGIN { BEGIN {
print "#include \"ircodes.h\"" print "#include \"ircodes.h\""
print "const char* ir_names[IR__COUNT] = {" print "const struct ir_data ir_data[IR__COUNT] = {"
}
function char_to_type(c) {
if (c == "I") return "IRT_INT"
if (c == "F") return "IRT_FLOAT"
if (c == "A") return "IRT_ANY"
return "IRT_UNSET"
}
function char_to_flags(c) {
if (c == "S") return "IRF_SIZED"
return "0"
} }
/^ *[^# ]+/ { /^ *[^# ]+/ {
printf("\t\"%s\",\n", $2) printf("\t{ \"%s\", ", $2)
} printf("%s, ", char_to_flags(substr($1, 1, 1)))
printf("%s, ", char_to_type(substr($1, 2, 1)))
END { printf("%s, ", char_to_type(substr($1, 3, 1)))
print "};" printf("%s", char_to_type(substr($1, 4, 1)))
} printf(" },\n")
EOF
awk -f - $in >>$source << "EOF"
BEGIN {
print ""
print "const char ir_flags[IR__COUNT] = {"
}
/^ *[^# ]+/ {
if ($1 == "S")
print("\tIRF_SIZED,")
else
print("\t0,")
} }
END { END {