Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 0 additions & 63 deletions .github/workflows/perf.yml

This file was deleted.

2 changes: 1 addition & 1 deletion shell.nix
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ pkgs.mkShell {
pkgs.gcc
pkgs.mimalloc
pkgs.clang-tools
(pkgs.python3.withPackages (ps: [ ps.matplotlib ]))
pkgs.python3
];
}
2 changes: 2 additions & 0 deletions src/backend/ir/text_parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -542,6 +542,8 @@ namespace rat {
switch(op) {
case Opcode::If:
return fn->create<IfNode>(pn.ty, in[0], in[1]);
case Opcode::Switch:
return fn->create<SwitchNode>(pn.ty, in[0], in[1]);
case Opcode::Proj:
if(in[0] == fn->getStart() && pn.projIndex == StartNode::controlProjIndex() && startCtrl)
return startCtrl;
Expand Down
10 changes: 9 additions & 1 deletion src/backend/pass/emit/x86/x86_encode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,14 @@ namespace rat {
a->patchRel32(skip, a->here());
}

U32 X86EncodePass::blockIdBound(const MachineFunc& f) {
I32 maxId = -1;
for(const MachineBlock& blk : f.blocks)
if(blk.id > maxId)
maxId = blk.id;
return (U32)(maxId + 1);
}

void X86EncodePass::encodeFunction() {
// frame slots in [rbp-frameSize, rbp); saves pushed below, total 16-aligned
U32 saveBytes = 8u * (U32)calleeSaved.size();
Expand Down Expand Up @@ -485,7 +493,7 @@ namespace rat {
}
omitFrame = !framey && !hasCall;

blockOffset.assign(fn->blocks.size(), 0);
blockOffset.assign(blockIdBound(*fn), 0);
prologue();
for(U32 bi = 0; bi < fn->blocks.size(); ++bi) {
const MachineBlock& blk = fn->blocks[bi];
Expand Down
1 change: 1 addition & 0 deletions src/backend/pass/emit/x86/x86_encode.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ namespace rat {
void emitGlobal(ObjectFile& obj, const Global* g, U32 ptrBytes);

void reset(const MachineFunc& f, const X86FrameLayout& layout, Asm& asm_, List<PhysReg> callee);
static U32 blockIdBound(const MachineFunc& f);
void encodeFunction();

static Reg toGp(PhysReg p);
Expand Down
104 changes: 82 additions & 22 deletions src/backend/pass/verify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,21 @@ namespace rat {
err(u, "projection index out of range for an If (must be 0 or 1)");
break;
}
case Opcode::Switch: {
auto* sw = cast<SwitchNode>(n);
if(!isCtrl(sw->getControl()))
err(n, "Switch input 0 (control) is not control-typed");
if(!sw->getSelector()->getType()->isInt())
err(n, "Switch selector must be an integer");
if(!t->isTuple() || t->getTupleElementCount() == 0) {
err(n, "Switch type must be a non-empty tuple of control");
break;
}
for(U32 i = 0, e = t->getTupleElementCount(); i < e; ++i)
if(!t->getTupleElement(i)->isControl())
err(n, "Switch tuple element " + std::to_string(i) + " must be control");
break;
}
case Opcode::Proj: {
auto* p = cast<ProjNode>(n);
Node* prod = p->getProducer();
Expand Down Expand Up @@ -233,8 +248,8 @@ namespace rat {
break;
}
case Opcode::Constant:
if(!t->isInt())
err(n, "Constant type must be an integer");
if(!(t->isInt() || t->isFloat()))
err(n, "Constant type must be an integer or a float");
break;

case Opcode::Global: {
Expand Down Expand Up @@ -425,14 +440,9 @@ namespace rat {
}
break;
}
case OpClass::Unary: {
auto* u = cast<UnaryNode>(n);
if(!t->isInt())
err(n, "unary operates on a non-integer type");
if(u->getOperand()->getType() != t)
err(n, "unary result type differs from its operand");
case OpClass::Unary:
checkUnary(n);
break;
}
case OpClass::Compare: {
auto* c = cast<CompareNode>(n);
if(!(t->isInt() && t->getIntWidth() == 1))
Expand All @@ -441,27 +451,77 @@ namespace rat {
err(n, "comparison operands have different types");
break;
}
case OpClass::Convert: {
auto* c = cast<ConvertNode>(n);
const Type* src = c->getOperand()->getType();
if(!(src->isInt() && t->isInt())) {
err(n, "conversion requires integer source and destination");
break;
}
U32 sw = src->getIntWidth(), dw = t->getIntWidth();
if(op == Opcode::Trunc && dw > sw)
err(n, "trunc widens its operand");
if((op == Opcode::SExt || op == Opcode::ZExt) && dw < sw)
err(n, "extension narrows its operand");
case OpClass::Convert:
checkConvert(n);
break;
}
case OpClass::None:
break;
}
break;
}
}

void VerifyPass::FunctionVerifier::checkUnary(Node* n) {
auto* u = cast<UnaryNode>(n);
const Type* t = n->getType();
if(n->getOpcode() == Opcode::FNeg) {
if(!t->isFloat())
err(n, "fneg operates on a non-float type");
} else if(!t->isInt()) {
err(n, "unary operates on a non-integer type");
}
if(u->getOperand()->getType() != t)
err(n, "unary result type differs from its operand");
}

void VerifyPass::FunctionVerifier::checkConvert(Node* n) {
auto* c = cast<ConvertNode>(n);
Opcode op = n->getOpcode();
const Type* t = n->getType();
const Type* src = c->getOperand()->getType();
switch(op) {
case Opcode::Trunc:
case Opcode::SExt:
case Opcode::ZExt: {
if(!(src->isInt() && t->isInt())) {
err(n, "conversion requires integer source and destination");
break;
}
U32 sw = src->getIntWidth(), dw = t->getIntWidth();
if(op == Opcode::Trunc && dw > sw)
err(n, "trunc widens its operand");
if((op == Opcode::SExt || op == Opcode::ZExt) && dw < sw)
err(n, "extension narrows its operand");
break;
}
case Opcode::SIToFP:
case Opcode::UIToFP:
if(!(src->isInt() && t->isFloat()))
err(n, "conversion requires an integer source and a float destination");
break;
case Opcode::FPToSI:
case Opcode::FPToUI:
if(!(src->isFloat() && t->isInt()))
err(n, "conversion requires a float source and an integer destination");
break;
case Opcode::FPExt:
case Opcode::FPTrunc: {
if(!(src->isFloat() && t->isFloat())) {
err(n, "conversion requires float source and destination");
break;
}
U32 sw = src->getFloatWidth(), dw = t->getFloatWidth();
if(op == Opcode::FPTrunc && dw > sw)
err(n, "fptrunc widens its operand");
if(op == Opcode::FPExt && dw < sw)
err(n, "fpext narrows its operand");
break;
}
default:
break;
}
}

void VerifyPass::FunctionVerifier::checkStopReturns() {
Node* stop = fn.getStop();
if(!stop)
Expand Down
2 changes: 2 additions & 0 deletions src/backend/pass/verify.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ namespace rat {
B32 checkArity(const Node* n);
void checkEdges(Node* n);
void checkNode(Node* n);
void checkUnary(Node* n);
void checkConvert(Node* n);
void checkStopReturns();
};
private:
Expand Down
40 changes: 40 additions & 0 deletions src/backend/test/roundtrip_switch.rat
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
@name parser round-trip: a switch and its case projections survive parse+emit
@passes verify

@input
func sw(i64) -> i32 {
v0 = start : (ctrl, mem, i64)
v1 = stop : ctrl v10, v12, v14
v2 = proj : ctrl #0 "ctrl" of v0
v3 = proj : mem #1 "mem" of v0
v4 = proj : i64 #2 "arg0" of v0
v5 = switch : (ctrl, ctrl, ctrl) v2, v4
v6 = proj : ctrl #0 "case" of v5
v7 = proj : ctrl #1 "case" of v5
v8 = proj : ctrl #2 "case" of v5
v9 = const : i32 10
v10 = return : ctrl v6, v3, v9
v11 = const : i32 11
v12 = return : ctrl v7, v3, v11
v13 = const : i32 12
v14 = return : ctrl v8, v3, v13
}

@expect
func sw(i64) -> i32 {
v0 = start : (ctrl, mem, i64)
v1 = stop : ctrl v10, v12, v14
v2 = proj : ctrl #0 "ctrl" of v0
v3 = proj : mem #1 "mem" of v0
v4 = proj : i64 #2 "arg0" of v0
v5 = switch : (ctrl, ctrl, ctrl) v2, v4
v6 = proj : ctrl #0 "case" of v5
v7 = proj : ctrl #1 "case" of v5
v8 = proj : ctrl #2 "case" of v5
v9 = const : i32 10
v10 = return : ctrl v6, v3, v9
v11 = const : i32 11
v12 = return : ctrl v7, v3, v11
v13 = const : i32 12
v14 = return : ctrl v8, v3, v13
}
5 changes: 5 additions & 0 deletions src/backend/test/runner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,11 @@ namespace detail {
});
if(!ok)
return false;
String diags = trim(sink.str());
if(!diags.empty()) {
err = "pass diagnostics\n " + diags;
return false;
}

String actualCanon, expectCanon, cerr;
if(!canonicalIR(emitToString(mod), actualCanon, cerr)) {
Expand Down
52 changes: 52 additions & 0 deletions src/backend/test/verify_float.rat
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
@name verify: float const, fneg and the six FP conversions are valid IR
@passes verify

@input
func fverify(f64, i32) -> f64 {
v0 = start : (ctrl, mem, f64, i32)
v1 = stop : ctrl v20
v2 = proj : ctrl #0 "ctrl" of v0
v3 = proj : mem #1 "mem" of v0
v4 = proj : f64 #2 "arg0" of v0
v5 = proj : i32 #3 "arg1" of v0
v6 = fneg : f64 v4
v7 = sitofp : f64 v5
v8 = uitofp : f64 v5
v9 = fadd : f64 v6, v7
v10 = fadd : f64 v9, v8
v11 = fptrunc : f32 v10
v12 = fpext : f64 v11
v13 = fptosi : i32 v12
v14 = fptoui : i64 v12
v15 = sitofp : f64 v13
v16 = uitofp : f64 v14
v17 = const : f64 4609434218613702656
v18 = fadd : f64 v15, v16
v19 = fadd : f64 v18, v17
v20 = return : ctrl v2, v3, v19
}

@expect
func fverify(f64, i32) -> f64 {
v0 = start : (ctrl, mem, f64, i32)
v1 = stop : ctrl v20
v2 = proj : ctrl #0 "ctrl" of v0
v3 = proj : mem #1 "mem" of v0
v4 = proj : f64 #2 "arg0" of v0
v5 = proj : i32 #3 "arg1" of v0
v6 = fneg : f64 v4
v7 = sitofp : f64 v5
v8 = uitofp : f64 v5
v9 = fadd : f64 v6, v7
v10 = fadd : f64 v9, v8
v11 = fptrunc : f32 v10
v12 = fpext : f64 v11
v13 = fptosi : i32 v12
v14 = fptoui : i64 v12
v15 = sitofp : f64 v13
v16 = uitofp : f64 v14
v17 = const : f64 4609434218613702656
v18 = fadd : f64 v15, v16
v19 = fadd : f64 v18, v17
v20 = return : ctrl v2, v3, v19
}
6 changes: 5 additions & 1 deletion src/compiler/emit/emit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,11 @@ namespace rat::cc {
if(isPointer(to) && !isPointer(from) && !isFloating(from)) {
if(n->getOpcode() == Opcode::Constant)
return fn.constInt(mod.getPtr(), cast<ConstantNode>(n)->getValue());
return fn.convert(Opcode::SExt, n, mod.getPtr());
U32 fromBits = from.bits == 0 ? 32 : from.bits;
Opcode ext = Opcode::SExt;
if(fromBits < lay.ptrBytes * 8 && from.isUnsigned())
ext = Opcode::ZExt;
return fn.convert(ext, n, mod.getPtr());
}
if(isPointer(from) || isPointer(to))
return n;
Expand Down
2 changes: 2 additions & 0 deletions src/compiler/emit/emit.h
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,8 @@ namespace rat::cc {
const Designator& des,
U32& i,
U32& cur);
B32 initListIsFlat(const Expr* init);
U32 initArrayCount(CType elem, const Expr* init);
U32 arrayInitOuterExtent(CType elem, const Expr* init);
B32 resolveArrayIndices(const List<Expr*>& els,
const List<Designator>& des,
Expand Down
Loading
Loading