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
32 changes: 29 additions & 3 deletions src/backend/codegen/schedule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ namespace rat {
placeLoads(work, early);
return;
}
markGuarded(work);
scheduleLate(work, early);
buildBlockLists();
}
Expand Down Expand Up @@ -398,8 +399,33 @@ namespace rat {

B32 Schedule::mayTrap(const Node* n) {
Opcode op = n->getOpcode();
return op == Opcode::Load || op == Opcode::SDiv || op == Opcode::UDiv || op == Opcode::SRem ||
op == Opcode::URem;
if(op == Opcode::Load)
return true;
if(op != Opcode::SDiv && op != Opcode::UDiv && op != Opcode::SRem && op != Opcode::URem)
return false;
const ConstantNode* c = dyn_cast<ConstantNode>(cast<BinaryNode>(n)->getRHS());
if(!c)
return true;
I64 d = signExtend(c->getValue(), n->getType()->getIntWidth());
B32 isSigned = op == Opcode::SDiv || op == Opcode::SRem;
return d == 0 || (isSigned && d == -1); // INT_MIN / -1 traps
}

void Schedule::markGuarded(const List<Node*>& work) {
guarded.assign(fn.idBound(), 0);
List<Node*> stack;
for(Node* n : work)
if(mayTrap(n))
stack.push_back(n);
while(!stack.empty()) {
Node* n = stack.back();
stack.pop_back();
if(guarded[n->getId()] || isa<LoadNode>(n) || !isFloating(n))
continue;
guarded[n->getId()] = 1;
for(Node* u : n->getUsers())
stack.push_back(u);
}
}

I32 Schedule::homeBlock(Node* n) const { return headBlock(headOf(n->getControlInput())); }
Expand All @@ -409,7 +435,7 @@ namespace rat {
return late; // nothing above is shallower, so the walk cannot move it
Opcode op = n->getOpcode();
B32 remat = op == Opcode::Constant || op == Opcode::Global;
B32 trapping = mayTrap(n);
B32 trapping = mayTrap(n) || (n->getId() < guarded.size() && guarded[n->getId()]);
I32 cur = late, pick = late;
while(true) {
if(blocks[cur].loopDepth < blocks[pick].loopDepth) {
Expand Down
2 changes: 2 additions & 0 deletions src/backend/codegen/schedule.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ namespace rat {
I32 predBlockForRegionInput(I32 regionBlock, U32 i) const;
I32 hoistTarget(const Node* n, I32 late, I32 early) const;
I32 homeBlock(Node* n) const;
void markGuarded(const List<Node*>& work);

struct TopoScratch {
List<I32> localOf; // node id -> local index in the current block (-1)
Expand All @@ -125,6 +126,7 @@ namespace rat {
List<I32> rpoOrder;
I32 entryBlock = -1;
mutable List<Node*> headMemo;
List<C8> guarded;
};
} // namespace rat

Expand Down
3 changes: 2 additions & 1 deletion src/backend/ir/function.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -478,7 +478,8 @@ namespace rat {
Set<Node*> dead;
List<Node*> work;
for(Node* n : nodes) {
B32 anchored = isa<LoadNode>(n) || isa<StoreNode>(n) || isa<CallNode>(n) || isa<AsmNode>(n);
B32 anchored = isa<LoadNode>(n) || isa<StoreNode>(n) || isa<CallNode>(n) || isa<AsmNode>(n) ||
isa<PhiNode>(n);
if(anchored && !n->getControlInput()) {
dead.insert(n);
work.push_back(n);
Expand Down
14 changes: 10 additions & 4 deletions src/backend/pass/emit/x86/x86_encode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,13 @@ namespace rat {
a->storeMem(R10, 16, R11, 8);
}

void X86EncodePass::vaFetchOverflow(I32 step) {
a->load64(R11, R10, 8); // R11 = overflow_arg_area
void X86EncodePass::vaFetchOverflow(I32 step, U32 align) {
a->load64(R11, R10, 8); // R11 = overflow_arg_area
if(align > 8) {
// round up to the argument alignment
a->addRegImm32(R11, (I32)align - 1);
a->aluImm(4, R11, -(I32)align); // and
}
a->storeMem(RBP, fl->ldScratch, R11, 8); // stash address
a->addRegImm32(R11, step); // advance
a->storeMem(R10, 8, R11, 8); // write back overflow_arg_area
Expand All @@ -111,7 +116,7 @@ namespace rat {
a->addRegMem(R11, R10, 16); // R11 += reg_save_area base
U32 done = a->jmpRel32();
a->patchRel32(toStack, a->here());
vaFetchOverflow(8);
vaFetchOverflow(8, 8);
a->patchRel32(done, a->here());
}

Expand All @@ -121,7 +126,7 @@ namespace rat {
vaPtrToR10(in);
VaArgKind kind = (VaArgKind)in.imm;
if(kind == VaArgKind::X87)
vaFetchOverflow(16);
vaFetchOverflow(16, 16);
else if(kind == VaArgKind::Sse)
vaFetch(4, conv->regSaveBytes, (I32)conv->sseSlotBytes);
else
Expand Down Expand Up @@ -150,6 +155,7 @@ namespace rat {
const MachineOperand& u = in.uses[i];
if(u.kind == MachineOperand::Kind::FrameSlot) {
if(u.width == 16) { // by-value x87
off = (off + 15) & ~15;
fldSlot(u.slot);
a->fstpT(RSP, off);
off += 16;
Expand Down
2 changes: 1 addition & 1 deletion src/backend/pass/emit/x86/x86_encode.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ namespace rat {
void vaPtrToR10(const MachineInstr& in);
void vaLoadResult(const MachineInstr& in);
void emitVaStart(const MachineInstr& in);
void vaFetchOverflow(I32 step);
void vaFetchOverflow(I32 step, U32 align);
void vaFetch(I32 offDisp, U32 limit, I32 regStep);
void emitVaArg(const MachineInstr& in);
void emitVaStartWin64(const MachineInstr& in);
Expand Down
9 changes: 8 additions & 1 deletion src/backend/pass/emit/x86/x86_lower.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -515,6 +515,8 @@ namespace rat {
const Schedule::Block& tb = sched->block(targetBlock);
List<PhiNode*> live;
List<VReg> tmp;
List<PhiNode*> liveX87;
List<I32> tmpX87;
for(PhiNode* phi : tb.phis) {
Node* v = phi->getValue(predIdx);
if(v == phi)
Expand All @@ -523,7 +525,10 @@ namespace rat {
if(cls == detail::kX87) {
I32 s = x87Value(v);
needScratch();
x87Move(x87SlotOf(phi), s);
I32 t = reserve(16);
x87Move(t, s);
liveX87.push_back(phi);
tmpX87.push_back(t);
continue;
}
VReg t = fresh(cls);
Expand All @@ -536,6 +541,8 @@ namespace rat {
U32 cls = classOf(phi->getType());
phiMove(vregFor(phi), tmp[i], cls, opWidth(phi->getType()));
}
for(U32 i = 0; i < (U32)liveX87.size(); ++i)
x87Move(x87SlotOf(liveX87[i]), tmpX87[i]);
}

void X86LowerPass::emitTerminator(I32 b) {
Expand Down
2 changes: 2 additions & 0 deletions src/backend/pass/emit/x86/x86_lower.h
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,8 @@ namespace rat {
void emitConvert(ConvertNode* n);
void emitU64ToFP(ConvertNode* n, VReg s, U32 w);
void emitFPToU64(ConvertNode* n, Node* src);
void emitUIntToX87(ConvertNode* n, VReg s, U32 bits);
void emitX87ToU64(ConvertNode* n, Node* src);
void emitConvertX87(ConvertNode* n, Node* src, Opcode op);
List<PhysReg> callerSavedClobbers() const;
List<PhysReg> allRegClobbers() const;
Expand Down
76 changes: 70 additions & 6 deletions src/backend/pass/emit/x86/x86_lower_ops.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -133,15 +133,17 @@ namespace rat {
mov(d, lhs);
if(op == X86Op::LShr)
maskBits(d, bits);
I64 iv;
if(immOf(n->getRHS(), iv)) { // constant count: shift-by-imm, no RCX
I64 iv = 0;
B32 immCnt = immOf(n->getRHS(), iv);
if(immCnt) { // constant count: shift-by-imm, no RCX
shift(op, d, imm(iv & 63));
} else {
VReg rhs = gpValue(n->getRHS());
mov(RCX, rhs);
shift(op, d, RCX);
}
if(op == X86Op::Shl)
B32 cntMayBeZero = !immCnt || (iv & 63) == 0;
if(op == X86Op::Shl || (op == X86Op::LShr && cntMayBeZero))
signExtBits(d, bits);
}

Expand Down Expand Up @@ -721,6 +723,57 @@ namespace rat {
gpAcc(X86Op::Xor, d, lo);
}

void X86LowerPass::emitUIntToX87(ConvertNode* n, VReg s, U32 bits) {
if(bits < 64) {
VReg z = fresh(detail::kGp);
mov(z, s);
maskBits(z, bits);
fild(slot(x87SlotOf(n)), z);
return;
}
VReg hi = fresh(detail::kGp);
mov(hi, s);
gpShrImm(hi, 32);
VReg lo = fresh(detail::kGp);
mov(lo, s);
maskBits(lo, 32);

Slot fh = slot(reserve(16));
fild(fh, hi);
Slot flo = slot(reserve(16));
fild(flo, lo);
Slot k = slot(reserve(16));
fldImm(k, 0x41f0000000000000ull); // 2^32
x87Arith(X86Op::X87Mul, fh, fh, k);
x87Arith(X86Op::X87Add, slot(x87SlotOf(n)), fh, flo); // exact in the 64-bit mantissa
}

void X86LowerPass::emitX87ToU64(ConvertNode* n, Node* src) {
I32 x = x87Value(src);
needScratch();
Slot k = slot(reserve(16));
fldImm(k, 0x43e0000000000000ull); // 2^63

VReg lo = fresh(detail::kGp); // while x < 2^63
fistp(lo, slot(x));

Slot biased = slot(reserve(16));
x87Arith(X86Op::X87Sub, biased, slot(x), k);
VReg hi = fresh(detail::kGp);
fistp(hi, biased);
gpAcc(X86Op::Xor, hi, gpConst((I64)0x8000000000000000ull)); // undo the bias

VReg m = fresh(detail::kGp); // -(x >= 2^63)
fucomi(m, slot(x), k, CC_AE, false);
neg(m);

VReg d = vregFor(n); // d = lo ^ ((lo ^ hi) & m)
mov(d, hi);
gpAcc(X86Op::Xor, d, lo);
gpAcc(X86Op::And, d, m);
gpAcc(X86Op::Xor, d, lo);
}

void X86LowerPass::emitConvertX87(ConvertNode* n, Node* src, Opcode op) {
switch(op) {
case Opcode::FPExt: {
Expand All @@ -743,18 +796,29 @@ namespace rat {
fstpSse(vregFor(n), dw, slot(s));
return;
}
case Opcode::SIToFP:
case Opcode::UIToFP: {
case Opcode::SIToFP: {
VReg s = gpValue(src);
needScratch();
fild(slot(x87SlotOf(n)), s);
return;
}
case Opcode::UIToFP: {
VReg s = gpValue(src);
needScratch();
emitUIntToX87(n, s, intBits(src->getType()));
return;
}
case Opcode::FPToSI:
case Opcode::FPToUI: {
if(op == Opcode::FPToUI && intBits(n->getType()) >= 64) {
emitX87ToU64(n, src);
return;
}
I32 s = x87Value(src);
needScratch();
fistp(vregFor(n), slot(s));
VReg d = vregFor(n);
fistp(d, slot(s));
signExtBits(d, intBits(n->getType()));
return;
}
default:
Expand Down
3 changes: 3 additions & 0 deletions src/backend/pass/opt/gvn.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "pass/opt/gvn.h"

#include "codegen/schedule.h"
#include "ir/function.h"
#include "ir/node.h"

Expand Down Expand Up @@ -43,6 +44,8 @@ namespace rat {

B32 GVNPass::isPureValue(Node* n) {
Opcode op = n->getOpcode();
if(Schedule::mayTrap(n))
return false;
return op == Opcode::Constant || op == Opcode::Global || isArithmeticOpcode(op) ||
isVectorUtilOpcode(op);
}
Expand Down
26 changes: 26 additions & 0 deletions src/backend/pass/opt/simplify_cfg.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "pass/opt/simplify_cfg.h"

#include "codegen/schedule.h"
#include "ir/function.h"
#include "ir/node.h"
#include "ir/type.h"
Expand Down Expand Up @@ -84,6 +85,29 @@ namespace rat {
}
}

B32 SimplifyCFGPass::walkCone(Node* root) {
B32 trap = false;
coneWork.clear();
coneWork.push_back(root);
while(!coneWork.empty()) {
Node* n = coneWork.back();
coneWork.pop_back();
if(!coneSeen.insert(n).second || freeValue(n))
continue;
trap |= Schedule::mayTrap(n);
for(U32 i = 0, e = n->getInputCount(); i < e; ++i)
if(Node* in = n->getInput(i))
coneWork.push_back(in);
}
return trap;
}

B32 SimplifyCFGPass::coneMayTrap(Node* v, Node* pred) {
coneSeen.clear();
walkCone(pred);
return walkCone(v);
}

I32 SimplifyCFGPass::speculationCost(Node* v, Node* phi, U32 depth) {
if(freeValue(v))
return 0;
Expand Down Expand Up @@ -141,6 +165,8 @@ namespace rat {
I32 c1 = speculationCost(fv, phi, kSpeculationDepth);
if(!selectableType(phi->getType()) || c0 < 0 || c1 < 0)
return false;
if(coneMayTrap(tv, pred) || coneMayTrap(fv, pred))
return false;
cost += c0 + c1;
}
if(phis.empty() || cost > kSpeculationBudget)
Expand Down
4 changes: 4 additions & 0 deletions src/backend/pass/opt/simplify_cfg.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ namespace rat {
// if-conversion
static B32 freeValue(Node* v);
static B32 cheapOp(Opcode op);
B32 walkCone(Node* root);
B32 coneMayTrap(Node* v, Node* pred);
static I32 speculationCost(Node* v, Node* phi, U32 depth);
static B32 selectableType(Type* t);
U32 ifToSelect(Function& fn);
Expand All @@ -51,6 +53,8 @@ namespace rat {
List<Node*> selectRegions;
List<PhiNode*> phis;
List<PhiNode*> detachPhis;
Set<Node*> coneSeen;
List<Node*> coneWork;
};
} // namespace rat

Expand Down
9 changes: 6 additions & 3 deletions src/backend/pass/opt/slp/slp_driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,16 +115,17 @@ namespace rat {
return provablyDisjoint(aa, a->getPointer(), ka, ka.size, b->getPointer(), kb, kb.size);
}

// skip the maximal run of stores that are disjoint from loadBase purely by object identity
// skip the maximal run of stores that are disjoint from loadBase purely by object identity,
// within the control of s
Node* slp::Slp::skipDisjointRun(StoreNode* s, Node* loadBase) {
Map<const Node*, Node*>& memo = skipMemo[loadBase];
List<const Node*> run;
Node* cur = s;
Node* endpoint = nullptr;
while(true) {
StoreNode* cs = dyn_cast<StoreNode>(cur);
if(!cs) {
endpoint = cur; // reached function entry / a non-store producer
if(!cs || cs->getControl() != s->getControl()) {
endpoint = cur; // function entry, a non-store producer, or another control
break;
}
auto it = memo.find(cur);
Expand Down Expand Up @@ -180,6 +181,8 @@ namespace rat {

Node* m = l->getMemory();
while(StoreNode* s = dyn_cast<StoreNode>(m)) {
if(s->getControl() != l->getControl())
break;
if(fastPath) {
Node* jumped = skipDisjointRun(s, lk.base);
if(jumped != m) {
Expand Down
1 change: 1 addition & 0 deletions src/backend/target/x86/x86_asm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ namespace rat {

X86ArgAssigner::Loc X86ArgAssigner::next(Kind k) {
if(k == Kind::X87) {
stackBytes = (stackBytes + 15u) & ~15u;
Loc l{-1, stackBytes};
stackBytes += 16;
return l;
Expand Down
Loading
Loading