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)
{
tracef(k, "%s", ir_names[ir->opcode]);
tracef(k, "%s", ir_data[ir->opcode].name);
if (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, "(");
switch (ir->opcode)

View file

@ -3,27 +3,12 @@
#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
{
int id;
enum ir_opcode opcode;
int size;
enum ir_type type;
struct ir* left;
struct ir* right;
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_eliminate_trivial_blocks(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);

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_remove_dead_blocks(proc);
pass_convert_stack_ops(proc);
pass_type_inference(proc);
print_blocks('2', proc);

View file

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

View file

@ -176,9 +176,9 @@ char* stringf(char* fmt, ...)
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);
term(s, esn);
@ -190,15 +190,15 @@ static void registerterminals(void)
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_names[i], i, 2);
registerterminal(ir_names[i], i, 4);
registerterminal(ir_names[i], i, 8);
registerterminal(&ir_data[i], i, 1);
registerterminal(&ir_data[i], i, 2);
registerterminal(&ir_data[i], i, 4);
registerterminal(&ir_data[i], i, 8);
}
else
registerterminal(ir_names[i], i, 0);
registerterminal(&ir_data[i], i, 0);
}
}

View file

@ -1,76 +1,92 @@
# Flags:
# S: has size (use in CONST1, CONST2, CONST4, CONST8 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
S CONST
S REG
S LABEL
S BLOCK
V PAIR
S ANY
S LOCAL
S PHI
SA.. CONST
SF.. CONSTF
SA.. REG
SF.. REGF
SI.. LABEL
SI.. BLOCK
V... PAIR
SA.. ANY
SF.. ANYF
S... LOCAL
S... PHI
# Magic stack operations
S PUSH
S POP
S.A. PUSH
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
S ADD
S SUB
S MUL
S DIV
S MOD
S NEG
S ADDF
S SUBF
S MULF
S DIVF
S NEGF
S AND
S OR
S EOR
S NOT
SIII ADD
SIII SUB
SIII MUL
SIII DIV
SIII MOD
SIII NEG
SFFF ADDF
SFFF SUBF
SFFF MULF
SFFF DIVF
SFFF NEGF
SIII AND
SIII OR
SIII EOR
SIII NOT
# Conversions
S CII1
S CII2
S CII4
S CII8
S CIU1
S CIU2
S CIU4
S CIU8
SIII CII1
SIII CII2
SIII CII4
SIII CII8
SIII CIU1
SIII CIU2
SIII CIU4
SIII CIU8
# Tristate comparisons
S COMPARES
S COMPAREU
SIII COMPARES
SIII COMPAREU
# Boolean comparisons
S IFEQ
S IFLT
S IFLE
SIII IFEQ
SIII IFLT
SIII IFLE
# Procedures
V CALL
VI.. CALL
# Flow control --- these never return
V JUMP
V CJUMPEQ
V CJUMPLT
V CJUMPLE
V RET
V.I. JUMP
VIII CJUMPEQ
VIII CJUMPLT
VIII CJUMPLE
V... RET
# Special
S STACKADJUST
S GETRET
S SETRET
SI.. STACKADJUST
SA.. GETRET
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 {
print "\tIR__COUNT"
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
awk -f - $in >$source << "EOF"
BEGIN {
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)
}
END {
print "};"
}
EOF
awk -f - $in >>$source << "EOF"
BEGIN {
print ""
print "const char ir_flags[IR__COUNT] = {"
}
/^ *[^# ]+/ {
if ($1 == "S")
print("\tIRF_SIZED,")
else
print("\t0,")
printf("\t{ \"%s\", ", $2)
printf("%s, ", char_to_flags(substr($1, 1, 1)))
printf("%s, ", char_to_type(substr($1, 2, 1)))
printf("%s, ", char_to_type(substr($1, 3, 1)))
printf("%s", char_to_type(substr($1, 4, 1)))
printf(" },\n")
}
END {