Commit 4318a410 by David Sehr

Combine allocas

Partition allocas that occur in the entry block into two categories. The first is those whose size is fixed and alignment are less than or equal to the stack alignment. These are emitted relative to a pointer, either in increasing offset relative to the stack pointer or decreasing offset relative to the frame pointer. (Actually, we are not enabling this optimization for frame pointer frames yet) The second category is allocas whose size is dynamic or alignment is creater than the stack alignment. These are emitted relative to a user variable in increasing offset order. This optimization is only enabled for x86 at O2. BUG= R=stichnot@chromium.org Review URL: https://codereview.chromium.org/1411583007 .
parent 5ff0cfb4
...@@ -201,8 +201,6 @@ void Cfg::translate() { ...@@ -201,8 +201,6 @@ void Cfg::translate() {
if (auto *Var64On32 = llvm::dyn_cast<Variable64On32>(Var)) if (auto *Var64On32 = llvm::dyn_cast<Variable64On32>(Var))
Var64On32->initHiLo(this); Var64On32->initHiLo(this);
processAllocas();
// The set of translation passes and their order are determined by the // The set of translation passes and their order are determined by the
// target. // target.
getTarget()->translate(); getTarget()->translate();
...@@ -451,86 +449,185 @@ void Cfg::doArgLowering() { ...@@ -451,86 +449,185 @@ void Cfg::doArgLowering() {
getTarget()->lowerArguments(); getTarget()->lowerArguments();
} }
void Cfg::sortAllocas(CfgVector<Inst *> &Allocas, InstList &Insts, void Cfg::sortAndCombineAllocas(CfgVector<Inst *> &Allocas,
bool IsKnownFrameOffset) { uint32_t CombinedAlignment, InstList &Insts,
AllocaBaseVariableType BaseVariableType) {
if (Allocas.empty()) if (Allocas.empty())
return; return;
// Sort by decreasing alignment. This does not really matter at the moment, // Sort by decreasing alignment.
// but will allow compacting stack allocation when we fuse to one alloca.
std::sort(Allocas.begin(), Allocas.end(), [](Inst *I1, Inst *I2) { std::sort(Allocas.begin(), Allocas.end(), [](Inst *I1, Inst *I2) {
auto *A1 = llvm::dyn_cast<InstAlloca>(I1); auto *A1 = llvm::dyn_cast<InstAlloca>(I1);
auto *A2 = llvm::dyn_cast<InstAlloca>(I2); auto *A2 = llvm::dyn_cast<InstAlloca>(I2);
return A1->getAlignInBytes() > A2->getAlignInBytes(); return A1->getAlignInBytes() > A2->getAlignInBytes();
}); });
// Process the allocas in order of decreasing stack alignment. This allows
// us to pack less-aligned pieces after more-aligned ones, resulting in less
// stack growth. It also allows there to be at most one stack alignment "and"
// instruction for a whole list of allocas.
uint32_t CurrentOffset = 0;
CfgVector<int32_t> Offsets;
for (Inst *Instr : Allocas) { for (Inst *Instr : Allocas) {
auto *Alloca = llvm::cast<InstAlloca>(Instr); auto *Alloca = llvm::cast<InstAlloca>(Instr);
// Move the alloca to its sorted position. // Adjust the size of the allocation up to the next multiple of the
InstAlloca *NewAlloca = // object's alignment.
InstAlloca::create(this, Alloca->getSizeInBytes(), uint32_t Alignment = std::max(Alloca->getAlignInBytes(), 1u);
Alloca->getAlignInBytes(), Alloca->getDest()); auto *ConstSize =
if (IsKnownFrameOffset) llvm::dyn_cast<ConstantInteger32>(Alloca->getSizeInBytes());
NewAlloca->setKnownFrameOffset(); uint32_t Size = Utils::applyAlignment(ConstSize->getValue(), Alignment);
Insts.push_front(NewAlloca); if (BaseVariableType == BVT_FramePointer) {
// Addressing is relative to the frame pointer. Subtract the offset after
// adding the size of the alloca, because it grows downwards from the
// frame pointer.
Offsets.push_back(-(CurrentOffset + Size));
} else {
// Addressing is relative to the stack pointer or to a user pointer. Add
// the offset before adding the size of the object, because it grows
// upwards from the stack pointer.
Offsets.push_back(CurrentOffset);
}
// Update the running offset of the fused alloca region.
CurrentOffset += Size;
}
// Round the offset up to the alignment granularity to use as the size.
uint32_t TotalSize = Utils::applyAlignment(CurrentOffset, CombinedAlignment);
// Ensure every alloca was assigned an offset.
assert(Allocas.size() == Offsets.size());
Variable *BaseVariable = makeVariable(IceType_i32);
Variable *AllocaDest = BaseVariable;
// Emit one addition for each alloca after the first.
for (size_t i = 0; i < Allocas.size(); ++i) {
auto *Alloca = llvm::cast<InstAlloca>(Allocas[i]);
switch (BaseVariableType) {
case BVT_FramePointer:
case BVT_UserPointer: {
// Emit a new addition operation to replace the alloca.
Operand *AllocaOffset = Ctx->getConstantInt32(Offsets[i]);
InstArithmetic *Add =
InstArithmetic::create(this, InstArithmetic::Add, Alloca->getDest(),
BaseVariable, AllocaOffset);
Insts.push_front(Add);
} break;
case BVT_StackPointer: {
// Emit a fake definition of the rematerializable variable.
Variable *Dest = Alloca->getDest();
InstFakeDef *Def = InstFakeDef::create(this, Dest);
Dest->setRematerializable(getTarget()->getStackReg(), Offsets[i]);
Insts.push_front(Def);
} break;
}
Alloca->setDeleted(); Alloca->setDeleted();
} }
Operand *AllocaSize = Ctx->getConstantInt32(TotalSize);
switch (BaseVariableType) {
case BVT_FramePointer: {
// Adjust the return of the alloca to the top of the returned region.
AllocaDest = makeVariable(IceType_i32);
InstArithmetic *Add = InstArithmetic::create(
this, InstArithmetic::Add, BaseVariable, AllocaDest, AllocaSize);
Insts.push_front(Add);
} break;
case BVT_StackPointer: {
// Emit a fake use to keep the Alloca live.
InstFakeUse *Use = InstFakeUse::create(this, AllocaDest);
Insts.push_front(Use);
} break;
case BVT_UserPointer:
break;
}
// And insert the fused alloca.
InstAlloca *CombinedAlloca =
InstAlloca::create(this, AllocaSize, CombinedAlignment, AllocaDest);
CombinedAlloca->setKnownFrameOffset();
Insts.push_front(CombinedAlloca);
} }
void Cfg::processAllocas() { void Cfg::processAllocas(bool SortAndCombine) {
const uint32_t StackAlignment = getTarget()->getStackAlignment(); const uint32_t StackAlignment = getTarget()->getStackAlignment();
CfgNode *EntryNode = getEntryNode(); CfgNode *EntryNode = getEntryNode();
// Allocas in the entry block that have constant size and alignment less
// than or equal to the function's stack alignment.
CfgVector<Inst *> FixedAllocas;
// Allocas in the entry block that have constant size and alignment greater
// than the function's stack alignment.
CfgVector<Inst *> AlignedAllocas;
// LLVM enforces power of 2 alignment. // LLVM enforces power of 2 alignment.
assert(llvm::isPowerOf2_32(StackAlignment)); assert(llvm::isPowerOf2_32(StackAlignment));
// Collect the Allocas into the two vectors. // Determine if there are large alignment allocations in the entry block or
bool RequiresFramePointer = false; // dynamic allocations (variable size in the entry block).
bool HasLargeAlignment = false;
bool HasDynamicAllocation = false;
for (Inst &Instr : EntryNode->getInsts()) { for (Inst &Instr : EntryNode->getInsts()) {
if (auto *Alloca = llvm::dyn_cast<InstAlloca>(&Instr)) { if (auto *Alloca = llvm::dyn_cast<InstAlloca>(&Instr)) {
if (!llvm::isa<Constant>(Alloca->getSizeInBytes())) {
// Variable-sized allocations require a frame pointer.
RequiresFramePointer = true;
continue;
}
uint32_t AlignmentParam = Alloca->getAlignInBytes(); uint32_t AlignmentParam = Alloca->getAlignInBytes();
// For default align=0, set it to the real value 1, to avoid any if (AlignmentParam > StackAlignment)
// bit-manipulation problems below. HasLargeAlignment = true;
AlignmentParam = std::max(AlignmentParam, 1u); if (llvm::isa<Constant>(Alloca->getSizeInBytes()))
assert(llvm::isPowerOf2_32(AlignmentParam)); Alloca->setKnownFrameOffset();
if (AlignmentParam > StackAlignment) { else {
// Allocations aligned more than the stack require a frame pointer. HasDynamicAllocation = true;
RequiresFramePointer = true; // If Allocas are not sorted, the first dynamic allocation causes
AlignedAllocas.push_back(Alloca); // later Allocas to be at unknown offsets relative to the stack/frame.
} else if (!SortAndCombine)
FixedAllocas.push_back(Alloca); break;
}
} }
} }
// Look for alloca instructions in other blocks // Don't do the heavyweight sorting and layout for low optimization levels.
if (!SortAndCombine)
return;
// Any alloca outside the entry block is a dynamic allocation.
for (CfgNode *Node : Nodes) { for (CfgNode *Node : Nodes) {
if (Node == EntryNode) if (Node == EntryNode)
continue; continue;
for (Inst &Instr : Node->getInsts()) { for (Inst &Instr : Node->getInsts()) {
if (llvm::isa<InstAlloca>(&Instr)) { if (llvm::isa<InstAlloca>(&Instr)) {
// Allocations outside the entry block require a frame pointer. // Allocations outside the entry block require a frame pointer.
RequiresFramePointer = true; HasDynamicAllocation = true;
break; break;
} }
} }
if (RequiresFramePointer) if (HasDynamicAllocation)
break; break;
} }
// Mark the target as requiring a frame pointer. // Mark the target as requiring a frame pointer.
if (RequiresFramePointer) if (HasLargeAlignment || HasDynamicAllocation)
getTarget()->setHasFramePointer(); getTarget()->setHasFramePointer();
// Collect the Allocas into the two vectors.
// Allocas in the entry block that have constant size and alignment less
// than or equal to the function's stack alignment.
CfgVector<Inst *> FixedAllocas;
// Allocas in the entry block that have constant size and alignment greater
// than the function's stack alignment.
CfgVector<Inst *> AlignedAllocas;
// Maximum alignment used for the dynamic/aligned allocas.
uint32_t MaxAlignment = StackAlignment;
for (Inst &Instr : EntryNode->getInsts()) {
if (auto *Alloca = llvm::dyn_cast<InstAlloca>(&Instr)) {
if (!llvm::isa<Constant>(Alloca->getSizeInBytes()))
continue;
uint32_t AlignmentParam = Alloca->getAlignInBytes();
// For default align=0, set it to the real value 1, to avoid any
// bit-manipulation problems below.
AlignmentParam = std::max(AlignmentParam, 1u);
assert(llvm::isPowerOf2_32(AlignmentParam));
if (HasDynamicAllocation && AlignmentParam > StackAlignment) {
// If we have both dynamic allocations and large stack alignments,
// high-alignment allocations are pulled out with their own base.
AlignedAllocas.push_back(Alloca);
} else {
FixedAllocas.push_back(Alloca);
}
MaxAlignment = std::max(AlignmentParam, MaxAlignment);
}
}
// Add instructions to the head of the entry block in reverse order. // Add instructions to the head of the entry block in reverse order.
InstList &Insts = getEntryNode()->getInsts(); InstList &Insts = getEntryNode()->getInsts();
// Fixed, large alignment alloca addresses do not have known offset. if (HasDynamicAllocation && HasLargeAlignment) {
sortAllocas(AlignedAllocas, Insts, false); // We are using a frame pointer, but fixed large-alignment alloca addresses,
// Fixed, small alignment alloca addresses have known offset. // do not have a known offset from either the stack or frame pointer.
sortAllocas(FixedAllocas, Insts, true); // They grow up from a user pointer from an alloca.
sortAndCombineAllocas(AlignedAllocas, MaxAlignment, Insts, BVT_UserPointer);
}
// Otherwise, fixed size allocas are always addressed relative to the stack
// unless there are dynamic allocas.
// TODO(sehr): re-enable frame pointer and decrementing addressing.
AllocaBaseVariableType BasePointerType =
(HasDynamicAllocation ? BVT_UserPointer : BVT_StackPointer);
sortAndCombineAllocas(FixedAllocas, MaxAlignment, Insts, BasePointerType);
} }
void Cfg::doAddressOpt() { void Cfg::doAddressOpt() {
......
...@@ -185,10 +185,19 @@ public: ...@@ -185,10 +185,19 @@ public:
void advancedPhiLowering(); void advancedPhiLowering();
void reorderNodes(); void reorderNodes();
void shuffleNodes(); void shuffleNodes();
void sortAllocas(CfgVector<Inst *> &Allocas, InstList &Insts,
bool IsKnownFrameOffset); enum AllocaBaseVariableType {
/// Merge all the fixed-size allocas in the entry block. BVT_StackPointer,
void processAllocas(); BVT_FramePointer,
BVT_UserPointer
};
void sortAndCombineAllocas(CfgVector<Inst *> &Allocas,
uint32_t CombinedAlignment, InstList &Insts,
AllocaBaseVariableType BaseVariableType);
/// Scan allocas to determine whether we need to use a frame pointer.
/// If SortAndCombine == true, merge all the fixed-size allocas in the
/// entry block and emit stack or frame pointer-relative addressing.
void processAllocas(bool SortAndCombine);
void doAddressOpt(); void doAddressOpt();
void doArgLowering(); void doArgLowering();
void doNopInsertion(); void doNopInsertion();
......
...@@ -101,6 +101,20 @@ MachineTraits<TargetX8632>::X86OperandMem::X86OperandMem( ...@@ -101,6 +101,20 @@ MachineTraits<TargetX8632>::X86OperandMem::X86OperandMem(
void MachineTraits<TargetX8632>::X86OperandMem::emit(const Cfg *Func) const { void MachineTraits<TargetX8632>::X86OperandMem::emit(const Cfg *Func) const {
if (!BuildDefs::dump()) if (!BuildDefs::dump())
return; return;
const ::Ice::TargetLowering *Target = Func->getTarget();
// If the base is rematerializable, we need to replace it with the correct
// physical register (esp or ebp), and update the Offset.
int32_t Disp = 0;
if (getBase() && getBase()->isRematerializable()) {
Disp += getBase()->getStackOffset();
if (!getIgnoreStackAdjust())
Disp += Target->getStackAdjustment();
}
// The index should never be rematerializable. But if we ever allow it, then
// we should make sure the rematerialization offset is shifted by the Shift
// value.
if (getIndex())
assert(!getIndex()->isRematerializable());
Ostream &Str = Func->getContext()->getStrEmit(); Ostream &Str = Func->getContext()->getStrEmit();
if (SegmentReg != DefaultSegment) { if (SegmentReg != DefaultSegment) {
assert(SegmentReg >= 0 && SegmentReg < SegReg_NUM); assert(SegmentReg >= 0 && SegmentReg < SegReg_NUM);
...@@ -108,27 +122,33 @@ void MachineTraits<TargetX8632>::X86OperandMem::emit(const Cfg *Func) const { ...@@ -108,27 +122,33 @@ void MachineTraits<TargetX8632>::X86OperandMem::emit(const Cfg *Func) const {
} }
// Emit as Offset(Base,Index,1<<Shift). Offset is emitted without the leading // Emit as Offset(Base,Index,1<<Shift). Offset is emitted without the leading
// '$'. Omit the (Base,Index,1<<Shift) part if Base==nullptr. // '$'. Omit the (Base,Index,1<<Shift) part if Base==nullptr.
if (!Offset) { if (getOffset() == 0 && Disp == 0) {
// No offset, emit nothing. // No offset, emit nothing.
} else if (const auto *CI = llvm::dyn_cast<ConstantInteger32>(Offset)) { } else if (getOffset() == 0 && Disp != 0) {
if (Base == nullptr || CI->getValue()) Str << Disp;
} else if (const auto *CI = llvm::dyn_cast<ConstantInteger32>(getOffset())) {
if (getBase() == nullptr || CI->getValue() || Disp != 0)
// Emit a non-zero offset without a leading '$'. // Emit a non-zero offset without a leading '$'.
Str << CI->getValue(); Str << CI->getValue() + Disp;
} else if (const auto *CR = llvm::dyn_cast<ConstantRelocatable>(Offset)) { } else if (const auto *CR =
llvm::dyn_cast<ConstantRelocatable>(getOffset())) {
// TODO(sehr): ConstantRelocatable still needs updating for
// rematerializable base/index and Disp.
assert(Disp == 0);
CR->emitWithoutPrefix(Func->getTarget()); CR->emitWithoutPrefix(Func->getTarget());
} else { } else {
llvm_unreachable("Invalid offset type for x86 mem operand"); llvm_unreachable("Invalid offset type for x86 mem operand");
} }
if (Base || Index) { if (getBase() || getIndex()) {
Str << "("; Str << "(";
if (Base) if (getBase())
Base->emit(Func); getBase()->emit(Func);
if (Index) { if (getIndex()) {
Str << ","; Str << ",";
Index->emit(Func); getIndex()->emit(Func);
if (Shift) if (getShift())
Str << "," << (1u << Shift); Str << "," << (1u << getShift());
} }
Str << ")"; Str << ")";
} }
...@@ -144,44 +164,54 @@ void MachineTraits<TargetX8632>::X86OperandMem::dump(const Cfg *Func, ...@@ -144,44 +164,54 @@ void MachineTraits<TargetX8632>::X86OperandMem::dump(const Cfg *Func,
} }
bool Dumped = false; bool Dumped = false;
Str << "["; Str << "[";
if (Base) { int32_t Disp = 0;
if (getBase() && getBase()->isRematerializable()) {
Disp += getBase()->getStackOffset();
if (!getIgnoreStackAdjust())
Disp += Func->getTarget()->getStackAdjustment();
}
if (getBase()) {
if (Func) if (Func)
Base->dump(Func); getBase()->dump(Func);
else else
Base->dump(Str); getBase()->dump(Str);
Dumped = true; Dumped = true;
} }
if (Index) { if (getIndex()) {
if (Base) assert(!getIndex()->isRematerializable());
if (getBase())
Str << "+"; Str << "+";
if (Shift > 0) if (getShift() > 0)
Str << (1u << Shift) << "*"; Str << (1u << getShift()) << "*";
if (Func) if (Func)
Index->dump(Func); getIndex()->dump(Func);
else else
Index->dump(Str); getIndex()->dump(Str);
Dumped = true; Dumped = true;
} }
// Pretty-print the Offset. // Pretty-print the Offset.
bool OffsetIsZero = false; bool OffsetIsZero = false;
bool OffsetIsNegative = false; bool OffsetIsNegative = false;
if (!Offset) { if (getOffset() == 0 && Disp == 0) {
OffsetIsZero = true; OffsetIsZero = true;
} else if (const auto *CI = llvm::dyn_cast<ConstantInteger32>(Offset)) { } else if (getOffset() == 0 && Disp != 0) {
OffsetIsZero = (CI->getValue() == 0); OffsetIsZero = (Disp == 0);
OffsetIsNegative = (static_cast<int32_t>(CI->getValue()) < 0); OffsetIsNegative = (Disp < 0);
} else if (const auto *CI = llvm::dyn_cast<ConstantInteger32>(getOffset())) {
OffsetIsZero = (CI->getValue() + Disp == 0);
OffsetIsNegative = (static_cast<int32_t>(CI->getValue()) + Disp < 0);
} else { } else {
assert(llvm::isa<ConstantRelocatable>(Offset)); assert(llvm::isa<ConstantRelocatable>(getOffset()) && Disp == 0);
} }
if (Dumped) { if (Dumped) {
if (!OffsetIsZero) { // Suppress if Offset is known to be 0 if (!OffsetIsZero) { // Suppress if Offset is known to be 0
if (!OffsetIsNegative) // Suppress if Offset is known to be negative if (!OffsetIsNegative) // Suppress if Offset is known to be negative
Str << "+"; Str << "+";
Offset->dump(Func, Str); getOffset()->dump(Func, Str);
} }
} else { } else {
// There is only the offset. // There is only the offset.
Offset->dump(Func, Str); getOffset()->dump(Func, Str);
} }
Str << "]"; Str << "]";
} }
...@@ -196,16 +226,28 @@ void MachineTraits<TargetX8632>::X86OperandMem::emitSegmentOverride( ...@@ -196,16 +226,28 @@ void MachineTraits<TargetX8632>::X86OperandMem::emitSegmentOverride(
MachineTraits<TargetX8632>::Address MachineTraits<TargetX8632>::Address
MachineTraits<TargetX8632>::X86OperandMem::toAsmAddress( MachineTraits<TargetX8632>::X86OperandMem::toAsmAddress(
MachineTraits<TargetX8632>::Assembler *Asm) const { MachineTraits<TargetX8632>::Assembler *Asm,
const Ice::TargetLowering *Target) const {
int32_t Disp = 0; int32_t Disp = 0;
if (getBase() && getBase()->isRematerializable()) {
Disp += getBase()->getStackOffset();
if (!getIgnoreStackAdjust()) {
Disp += Target->getStackAdjustment();
}
}
// The index should never be rematerializable. But if we ever allow it, then
// we should make sure the rematerialization offset is shifted by the Shift
// value.
if (getIndex())
assert(!getIndex()->isRematerializable());
AssemblerFixup *Fixup = nullptr; AssemblerFixup *Fixup = nullptr;
// Determine the offset (is it relocatable?) // Determine the offset (is it relocatable?)
if (getOffset()) { if (getOffset()) {
if (const auto *CI = llvm::dyn_cast<ConstantInteger32>(getOffset())) { if (const auto *CI = llvm::dyn_cast<ConstantInteger32>(getOffset())) {
Disp = static_cast<int32_t>(CI->getValue()); Disp += static_cast<int32_t>(CI->getValue());
} else if (const auto CR = } else if (const auto CR =
llvm::dyn_cast<ConstantRelocatable>(getOffset())) { llvm::dyn_cast<ConstantRelocatable>(getOffset())) {
Disp = CR->getOffset(); Disp += CR->getOffset();
Fixup = Asm->createFixup(RelFixup, CR); Fixup = Asm->createFixup(RelFixup, CR);
} else { } else {
llvm_unreachable("Unexpected offset type"); llvm_unreachable("Unexpected offset type");
......
...@@ -170,7 +170,14 @@ void MachineTraits<TargetX8664>::X86OperandMem::dump(const Cfg *Func, ...@@ -170,7 +170,14 @@ void MachineTraits<TargetX8664>::X86OperandMem::dump(const Cfg *Func,
MachineTraits<TargetX8664>::Address MachineTraits<TargetX8664>::Address
MachineTraits<TargetX8664>::X86OperandMem::toAsmAddress( MachineTraits<TargetX8664>::X86OperandMem::toAsmAddress(
MachineTraits<TargetX8664>::Assembler *Asm) const { MachineTraits<TargetX8664>::Assembler *Asm,
const Ice::TargetLowering *Target) const {
// TODO(sehr): handle rematerializable base/index.
(void)Target;
if (getBase())
assert(!getBase()->isRematerializable());
if (getIndex())
assert(!getIndex()->isRematerializable());
int32_t Disp = 0; int32_t Disp = 0;
AssemblerFixup *Fixup = nullptr; AssemblerFixup *Fixup = nullptr;
// Determine the offset (is it relocatable?) // Determine the offset (is it relocatable?)
......
...@@ -569,48 +569,51 @@ void InstX86Call<Machine>::emit(const Cfg *Func) const { ...@@ -569,48 +569,51 @@ void InstX86Call<Machine>::emit(const Cfg *Func) const {
Ostream &Str = Func->getContext()->getStrEmit(); Ostream &Str = Func->getContext()->getStrEmit();
assert(this->getSrcSize() == 1); assert(this->getSrcSize() == 1);
Str << "\tcall\t"; Str << "\tcall\t";
if (const auto *CI = llvm::dyn_cast<ConstantInteger32>(getCallTarget())) { Operand *CallTarget = getCallTarget();
TargetLowering *Target = Func->getTarget();
if (const auto *CI = llvm::dyn_cast<ConstantInteger32>(CallTarget)) {
// Emit without a leading '$'. // Emit without a leading '$'.
Str << CI->getValue(); Str << CI->getValue();
} else if (const auto CallTarget = } else if (const auto DirectCallTarget =
llvm::dyn_cast<ConstantRelocatable>(getCallTarget())) { llvm::dyn_cast<ConstantRelocatable>(CallTarget)) {
CallTarget->emitWithoutPrefix(Func->getTarget()); DirectCallTarget->emitWithoutPrefix(Target);
} else { } else {
Str << "*"; Str << "*";
getCallTarget()->emit(Func); CallTarget->emit(Func);
} }
Func->getTarget()->resetStackAdjustment(); Target->resetStackAdjustment();
} }
template <class Machine> template <class Machine>
void InstX86Call<Machine>::emitIAS(const Cfg *Func) const { void InstX86Call<Machine>::emitIAS(const Cfg *Func) const {
typename InstX86Base<Machine>::Traits::Assembler *Asm = typename InstX86Base<Machine>::Traits::Assembler *Asm =
Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
Operand *Target = getCallTarget(); Operand *CallTarget = getCallTarget();
if (const auto *Var = llvm::dyn_cast<Variable>(Target)) { TargetLowering *Target = Func->getTarget();
if (const auto *Var = llvm::dyn_cast<Variable>(CallTarget)) {
if (Var->hasReg()) { if (Var->hasReg()) {
Asm->call(InstX86Base<Machine>::Traits::getEncodedGPR(Var->getRegNum())); Asm->call(InstX86Base<Machine>::Traits::getEncodedGPR(Var->getRegNum()));
} else { } else {
Asm->call( Asm->call(
static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>(
Func->getTarget()) Target)
->stackVarToAsmOperand(Var)); ->stackVarToAsmOperand(Var));
} }
} else if (const auto *Mem = llvm::dyn_cast< } else if (const auto *Mem = llvm::dyn_cast<
typename InstX86Base<Machine>::Traits::X86OperandMem>( typename InstX86Base<Machine>::Traits::X86OperandMem>(
Target)) { CallTarget)) {
assert(Mem->getSegmentRegister() == assert(Mem->getSegmentRegister() ==
InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment); InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment);
Asm->call(Mem->toAsmAddress(Asm)); Asm->call(Mem->toAsmAddress(Asm, Target));
} else if (const auto *CR = llvm::dyn_cast<ConstantRelocatable>(Target)) { } else if (const auto *CR = llvm::dyn_cast<ConstantRelocatable>(CallTarget)) {
assert(CR->getOffset() == 0 && "We only support calling a function"); assert(CR->getOffset() == 0 && "We only support calling a function");
Asm->call(CR); Asm->call(CR);
} else if (const auto *Imm = llvm::dyn_cast<ConstantInteger32>(Target)) { } else if (const auto *Imm = llvm::dyn_cast<ConstantInteger32>(CallTarget)) {
Asm->call(Immediate(Imm->getValue())); Asm->call(Immediate(Imm->getValue()));
} else { } else {
llvm_unreachable("Unexpected operand type"); llvm_unreachable("Unexpected operand type");
} }
Func->getTarget()->resetStackAdjustment(); Target->resetStackAdjustment();
} }
template <class Machine> template <class Machine>
...@@ -651,6 +654,7 @@ template <class Machine> ...@@ -651,6 +654,7 @@ template <class Machine>
void emitIASOpTyGPR(const Cfg *Func, Type Ty, const Operand *Op, void emitIASOpTyGPR(const Cfg *Func, Type Ty, const Operand *Op,
const typename InstX86Base< const typename InstX86Base<
Machine>::Traits::Assembler::GPREmitterOneOp &Emitter) { Machine>::Traits::Assembler::GPREmitterOneOp &Emitter) {
TargetLowering *Target = Func->getTarget();
typename InstX86Base<Machine>::Traits::Assembler *Asm = typename InstX86Base<Machine>::Traits::Assembler *Asm =
Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
if (const auto *Var = llvm::dyn_cast<Variable>(Op)) { if (const auto *Var = llvm::dyn_cast<Variable>(Op)) {
...@@ -662,14 +666,14 @@ void emitIASOpTyGPR(const Cfg *Func, Type Ty, const Operand *Op, ...@@ -662,14 +666,14 @@ void emitIASOpTyGPR(const Cfg *Func, Type Ty, const Operand *Op,
} else { } else {
typename InstX86Base<Machine>::Traits::Address StackAddr( typename InstX86Base<Machine>::Traits::Address StackAddr(
static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>(
Func->getTarget()) Target)
->stackVarToAsmOperand(Var)); ->stackVarToAsmOperand(Var));
(Asm->*(Emitter.Addr))(Ty, StackAddr); (Asm->*(Emitter.Addr))(Ty, StackAddr);
} }
} else if (const auto *Mem = llvm::dyn_cast< } else if (const auto *Mem = llvm::dyn_cast<
typename InstX86Base<Machine>::Traits::X86OperandMem>(Op)) { typename InstX86Base<Machine>::Traits::X86OperandMem>(Op)) {
Mem->emitSegmentOverride(Asm); Mem->emitSegmentOverride(Asm);
(Asm->*(Emitter.Addr))(Ty, Mem->toAsmAddress(Asm)); (Asm->*(Emitter.Addr))(Ty, Mem->toAsmAddress(Asm, Target));
} else { } else {
llvm_unreachable("Unexpected operand type"); llvm_unreachable("Unexpected operand type");
} }
...@@ -680,6 +684,7 @@ void emitIASRegOpTyGPR( ...@@ -680,6 +684,7 @@ void emitIASRegOpTyGPR(
const Cfg *Func, Type Ty, const Variable *Var, const Operand *Src, const Cfg *Func, Type Ty, const Variable *Var, const Operand *Src,
const typename InstX86Base<Machine>::Traits::Assembler::GPREmitterRegOp const typename InstX86Base<Machine>::Traits::Assembler::GPREmitterRegOp
&Emitter) { &Emitter) {
TargetLowering *Target = Func->getTarget();
typename InstX86Base<Machine>::Traits::Assembler *Asm = typename InstX86Base<Machine>::Traits::Assembler *Asm =
Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
assert(Var->hasReg()); assert(Var->hasReg());
...@@ -699,14 +704,14 @@ void emitIASRegOpTyGPR( ...@@ -699,14 +704,14 @@ void emitIASRegOpTyGPR(
} else { } else {
typename InstX86Base<Machine>::Traits::Address SrcStackAddr = typename InstX86Base<Machine>::Traits::Address SrcStackAddr =
static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>(
Func->getTarget()) Target)
->stackVarToAsmOperand(SrcVar); ->stackVarToAsmOperand(SrcVar);
(Asm->*(Emitter.GPRAddr))(Ty, VarReg, SrcStackAddr); (Asm->*(Emitter.GPRAddr))(Ty, VarReg, SrcStackAddr);
} }
} else if (const auto *Mem = llvm::dyn_cast< } else if (const auto *Mem = llvm::dyn_cast<
typename InstX86Base<Machine>::Traits::X86OperandMem>(Src)) { typename InstX86Base<Machine>::Traits::X86OperandMem>(Src)) {
Mem->emitSegmentOverride(Asm); Mem->emitSegmentOverride(Asm);
(Asm->*(Emitter.GPRAddr))(Ty, VarReg, Mem->toAsmAddress(Asm)); (Asm->*(Emitter.GPRAddr))(Ty, VarReg, Mem->toAsmAddress(Asm, Target));
} else if (const auto *Imm = llvm::dyn_cast<ConstantInteger32>(Src)) { } else if (const auto *Imm = llvm::dyn_cast<ConstantInteger32>(Src)) {
(Asm->*(Emitter.GPRImm))(Ty, VarReg, Immediate(Imm->getValue())); (Asm->*(Emitter.GPRImm))(Ty, VarReg, Immediate(Imm->getValue()));
} else if (const auto *Reloc = llvm::dyn_cast<ConstantRelocatable>(Src)) { } else if (const auto *Reloc = llvm::dyn_cast<ConstantRelocatable>(Src)) {
...@@ -752,11 +757,12 @@ void emitIASAsAddrOpTyGPR( ...@@ -752,11 +757,12 @@ void emitIASAsAddrOpTyGPR(
const Cfg *Func, Type Ty, const Operand *Op0, const Operand *Op1, const Cfg *Func, Type Ty, const Operand *Op0, const Operand *Op1,
const typename InstX86Base<Machine>::Traits::Assembler::GPREmitterAddrOp const typename InstX86Base<Machine>::Traits::Assembler::GPREmitterAddrOp
&Emitter) { &Emitter) {
TargetLowering *Target = Func->getTarget();
if (const auto *Op0Var = llvm::dyn_cast<Variable>(Op0)) { if (const auto *Op0Var = llvm::dyn_cast<Variable>(Op0)) {
assert(!Op0Var->hasReg()); assert(!Op0Var->hasReg());
typename InstX86Base<Machine>::Traits::Address StackAddr( typename InstX86Base<Machine>::Traits::Address StackAddr(
static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>(
Func->getTarget()) Target)
->stackVarToAsmOperand(Op0Var)); ->stackVarToAsmOperand(Op0Var));
emitIASAddrOpTyGPR<Machine>(Func, Ty, StackAddr, Op1, Emitter); emitIASAddrOpTyGPR<Machine>(Func, Ty, StackAddr, Op1, Emitter);
} else if (const auto *Op0Mem = llvm::dyn_cast< } else if (const auto *Op0Mem = llvm::dyn_cast<
...@@ -764,8 +770,8 @@ void emitIASAsAddrOpTyGPR( ...@@ -764,8 +770,8 @@ void emitIASAsAddrOpTyGPR(
typename InstX86Base<Machine>::Traits::Assembler *Asm = typename InstX86Base<Machine>::Traits::Assembler *Asm =
Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
Op0Mem->emitSegmentOverride(Asm); Op0Mem->emitSegmentOverride(Asm);
emitIASAddrOpTyGPR<Machine>(Func, Ty, Op0Mem->toAsmAddress(Asm), Op1, emitIASAddrOpTyGPR<Machine>(Func, Ty, Op0Mem->toAsmAddress(Asm, Target),
Emitter); Op1, Emitter);
} else if (const auto *Split = llvm::dyn_cast< } else if (const auto *Split = llvm::dyn_cast<
typename InstX86Base<Machine>::Traits::VariableSplit>(Op0)) { typename InstX86Base<Machine>::Traits::VariableSplit>(Op0)) {
emitIASAddrOpTyGPR<Machine>(Func, Ty, Split->toAsmAddress(Func), Op1, emitIASAddrOpTyGPR<Machine>(Func, Ty, Split->toAsmAddress(Func), Op1,
...@@ -835,6 +841,7 @@ void emitIASXmmShift( ...@@ -835,6 +841,7 @@ void emitIASXmmShift(
const Cfg *Func, Type Ty, const Variable *Var, const Operand *Src, const Cfg *Func, Type Ty, const Variable *Var, const Operand *Src,
const typename InstX86Base<Machine>::Traits::Assembler::XmmEmitterShiftOp const typename InstX86Base<Machine>::Traits::Assembler::XmmEmitterShiftOp
&Emitter) { &Emitter) {
TargetLowering *Target = Func->getTarget();
typename InstX86Base<Machine>::Traits::Assembler *Asm = typename InstX86Base<Machine>::Traits::Assembler *Asm =
Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
assert(Var->hasReg()); assert(Var->hasReg());
...@@ -848,7 +855,7 @@ void emitIASXmmShift( ...@@ -848,7 +855,7 @@ void emitIASXmmShift(
} else { } else {
typename InstX86Base<Machine>::Traits::Address SrcStackAddr = typename InstX86Base<Machine>::Traits::Address SrcStackAddr =
static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>(
Func->getTarget()) Target)
->stackVarToAsmOperand(SrcVar); ->stackVarToAsmOperand(SrcVar);
(Asm->*(Emitter.XmmAddr))(Ty, VarReg, SrcStackAddr); (Asm->*(Emitter.XmmAddr))(Ty, VarReg, SrcStackAddr);
} }
...@@ -856,7 +863,7 @@ void emitIASXmmShift( ...@@ -856,7 +863,7 @@ void emitIASXmmShift(
typename InstX86Base<Machine>::Traits::X86OperandMem>(Src)) { typename InstX86Base<Machine>::Traits::X86OperandMem>(Src)) {
assert(Mem->getSegmentRegister() == assert(Mem->getSegmentRegister() ==
InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment); InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment);
(Asm->*(Emitter.XmmAddr))(Ty, VarReg, Mem->toAsmAddress(Asm)); (Asm->*(Emitter.XmmAddr))(Ty, VarReg, Mem->toAsmAddress(Asm, Target));
} else if (const auto *Imm = llvm::dyn_cast<ConstantInteger32>(Src)) { } else if (const auto *Imm = llvm::dyn_cast<ConstantInteger32>(Src)) {
(Asm->*(Emitter.XmmImm))(Ty, VarReg, Immediate(Imm->getValue())); (Asm->*(Emitter.XmmImm))(Ty, VarReg, Immediate(Imm->getValue()));
} else { } else {
...@@ -869,6 +876,7 @@ void emitIASRegOpTyXMM( ...@@ -869,6 +876,7 @@ void emitIASRegOpTyXMM(
const Cfg *Func, Type Ty, const Variable *Var, const Operand *Src, const Cfg *Func, Type Ty, const Variable *Var, const Operand *Src,
const typename InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp const typename InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp
&Emitter) { &Emitter) {
TargetLowering *Target = Func->getTarget();
typename InstX86Base<Machine>::Traits::Assembler *Asm = typename InstX86Base<Machine>::Traits::Assembler *Asm =
Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
assert(Var->hasReg()); assert(Var->hasReg());
...@@ -882,7 +890,7 @@ void emitIASRegOpTyXMM( ...@@ -882,7 +890,7 @@ void emitIASRegOpTyXMM(
} else { } else {
typename InstX86Base<Machine>::Traits::Address SrcStackAddr = typename InstX86Base<Machine>::Traits::Address SrcStackAddr =
static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>(
Func->getTarget()) Target)
->stackVarToAsmOperand(SrcVar); ->stackVarToAsmOperand(SrcVar);
(Asm->*(Emitter.XmmAddr))(Ty, VarReg, SrcStackAddr); (Asm->*(Emitter.XmmAddr))(Ty, VarReg, SrcStackAddr);
} }
...@@ -890,7 +898,7 @@ void emitIASRegOpTyXMM( ...@@ -890,7 +898,7 @@ void emitIASRegOpTyXMM(
typename InstX86Base<Machine>::Traits::X86OperandMem>(Src)) { typename InstX86Base<Machine>::Traits::X86OperandMem>(Src)) {
assert(Mem->getSegmentRegister() == assert(Mem->getSegmentRegister() ==
InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment); InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment);
(Asm->*(Emitter.XmmAddr))(Ty, VarReg, Mem->toAsmAddress(Asm)); (Asm->*(Emitter.XmmAddr))(Ty, VarReg, Mem->toAsmAddress(Asm, Target));
} else if (const auto *Imm = llvm::dyn_cast<Constant>(Src)) { } else if (const auto *Imm = llvm::dyn_cast<Constant>(Src)) {
(Asm->*(Emitter.XmmAddr))( (Asm->*(Emitter.XmmAddr))(
Ty, VarReg, Ty, VarReg,
...@@ -906,6 +914,7 @@ void emitIASCastRegOp(const Cfg *Func, Type DestTy, const Variable *Dest, ...@@ -906,6 +914,7 @@ void emitIASCastRegOp(const Cfg *Func, Type DestTy, const Variable *Dest,
Type SrcTy, const Operand *Src, Type SrcTy, const Operand *Src,
const typename InstX86Base<Machine>::Traits::Assembler:: const typename InstX86Base<Machine>::Traits::Assembler::
template CastEmitterRegOp<DReg_t, SReg_t> &Emitter) { template CastEmitterRegOp<DReg_t, SReg_t> &Emitter) {
TargetLowering *Target = Func->getTarget();
typename InstX86Base<Machine>::Traits::Assembler *Asm = typename InstX86Base<Machine>::Traits::Assembler *Asm =
Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
assert(Dest->hasReg()); assert(Dest->hasReg());
...@@ -917,14 +926,15 @@ void emitIASCastRegOp(const Cfg *Func, Type DestTy, const Variable *Dest, ...@@ -917,14 +926,15 @@ void emitIASCastRegOp(const Cfg *Func, Type DestTy, const Variable *Dest,
} else { } else {
typename InstX86Base<Machine>::Traits::Address SrcStackAddr = typename InstX86Base<Machine>::Traits::Address SrcStackAddr =
static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>(
Func->getTarget()) Target)
->stackVarToAsmOperand(SrcVar); ->stackVarToAsmOperand(SrcVar);
(Asm->*(Emitter.RegAddr))(DestTy, DestReg, SrcTy, SrcStackAddr); (Asm->*(Emitter.RegAddr))(DestTy, DestReg, SrcTy, SrcStackAddr);
} }
} else if (const auto *Mem = llvm::dyn_cast< } else if (const auto *Mem = llvm::dyn_cast<
typename InstX86Base<Machine>::Traits::X86OperandMem>(Src)) { typename InstX86Base<Machine>::Traits::X86OperandMem>(Src)) {
Mem->emitSegmentOverride(Asm); Mem->emitSegmentOverride(Asm);
(Asm->*(Emitter.RegAddr))(DestTy, DestReg, SrcTy, Mem->toAsmAddress(Asm)); (Asm->*(Emitter.RegAddr))(DestTy, DestReg, SrcTy,
Mem->toAsmAddress(Asm, Target));
} else { } else {
llvm_unreachable("Unexpected operand type"); llvm_unreachable("Unexpected operand type");
} }
...@@ -937,6 +947,7 @@ void emitIASThreeOpImmOps( ...@@ -937,6 +947,7 @@ void emitIASThreeOpImmOps(
const Operand *Src1, const Operand *Src1,
const typename InstX86Base<Machine>::Traits::Assembler:: const typename InstX86Base<Machine>::Traits::Assembler::
template ThreeOpImmEmitter<DReg_t, SReg_t> Emitter) { template ThreeOpImmEmitter<DReg_t, SReg_t> Emitter) {
TargetLowering *Target = Func->getTarget();
typename InstX86Base<Machine>::Traits::Assembler *Asm = typename InstX86Base<Machine>::Traits::Assembler *Asm =
Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
// This only handles Dest being a register, and Src1 being an immediate. // This only handles Dest being a register, and Src1 being an immediate.
...@@ -950,15 +961,15 @@ void emitIASThreeOpImmOps( ...@@ -950,15 +961,15 @@ void emitIASThreeOpImmOps(
} else { } else {
typename InstX86Base<Machine>::Traits::Address SrcStackAddr = typename InstX86Base<Machine>::Traits::Address SrcStackAddr =
static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>(
Func->getTarget()) Target)
->stackVarToAsmOperand(SrcVar); ->stackVarToAsmOperand(SrcVar);
(Asm->*(Emitter.RegAddrImm))(DispatchTy, DestReg, SrcStackAddr, Imm); (Asm->*(Emitter.RegAddrImm))(DispatchTy, DestReg, SrcStackAddr, Imm);
} }
} else if (const auto *Mem = llvm::dyn_cast< } else if (const auto *Mem = llvm::dyn_cast<
typename InstX86Base<Machine>::Traits::X86OperandMem>(Src0)) { typename InstX86Base<Machine>::Traits::X86OperandMem>(Src0)) {
Mem->emitSegmentOverride(Asm); Mem->emitSegmentOverride(Asm);
(Asm->*(Emitter.RegAddrImm))(DispatchTy, DestReg, Mem->toAsmAddress(Asm), (Asm->*(Emitter.RegAddrImm))(DispatchTy, DestReg,
Imm); Mem->toAsmAddress(Asm, Target), Imm);
} else { } else {
llvm_unreachable("Unexpected operand type"); llvm_unreachable("Unexpected operand type");
} }
...@@ -969,6 +980,7 @@ void emitIASMovlikeXMM( ...@@ -969,6 +980,7 @@ void emitIASMovlikeXMM(
const Cfg *Func, const Variable *Dest, const Operand *Src, const Cfg *Func, const Variable *Dest, const Operand *Src,
const typename InstX86Base<Machine>::Traits::Assembler::XmmEmitterMovOps const typename InstX86Base<Machine>::Traits::Assembler::XmmEmitterMovOps
Emitter) { Emitter) {
TargetLowering *Target = Func->getTarget();
typename InstX86Base<Machine>::Traits::Assembler *Asm = typename InstX86Base<Machine>::Traits::Assembler *Asm =
Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
if (Dest->hasReg()) { if (Dest->hasReg()) {
...@@ -981,8 +993,8 @@ void emitIASMovlikeXMM( ...@@ -981,8 +993,8 @@ void emitIASMovlikeXMM(
InstX86Base<Machine>::Traits::getEncodedXmm(SrcVar->getRegNum())); InstX86Base<Machine>::Traits::getEncodedXmm(SrcVar->getRegNum()));
} else { } else {
typename InstX86Base<Machine>::Traits::Address StackAddr( typename InstX86Base<Machine>::Traits::Address StackAddr(
static_cast<typename InstX86Base<Machine>::Traits::TargetLowering static_cast<
*>(Func->getTarget()) typename InstX86Base<Machine>::Traits::TargetLowering *>(Target)
->stackVarToAsmOperand(SrcVar)); ->stackVarToAsmOperand(SrcVar));
(Asm->*(Emitter.XmmAddr))(DestReg, StackAddr); (Asm->*(Emitter.XmmAddr))(DestReg, StackAddr);
} }
...@@ -990,14 +1002,14 @@ void emitIASMovlikeXMM( ...@@ -990,14 +1002,14 @@ void emitIASMovlikeXMM(
typename InstX86Base<Machine>::Traits::X86OperandMem>(Src)) { typename InstX86Base<Machine>::Traits::X86OperandMem>(Src)) {
assert(SrcMem->getSegmentRegister() == assert(SrcMem->getSegmentRegister() ==
InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment); InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment);
(Asm->*(Emitter.XmmAddr))(DestReg, SrcMem->toAsmAddress(Asm)); (Asm->*(Emitter.XmmAddr))(DestReg, SrcMem->toAsmAddress(Asm, Target));
} else { } else {
llvm_unreachable("Unexpected operand type"); llvm_unreachable("Unexpected operand type");
} }
} else { } else {
typename InstX86Base<Machine>::Traits::Address StackAddr( typename InstX86Base<Machine>::Traits::Address StackAddr(
static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>(
Func->getTarget()) Target)
->stackVarToAsmOperand(Dest)); ->stackVarToAsmOperand(Dest));
// Src must be a register in this case. // Src must be a register in this case.
const auto *SrcVar = llvm::cast<Variable>(Src); const auto *SrcVar = llvm::cast<Variable>(Src);
...@@ -1054,10 +1066,11 @@ void InstX86Pmull<Machine>::emit(const Cfg *Func) const { ...@@ -1054,10 +1066,11 @@ void InstX86Pmull<Machine>::emit(const Cfg *Func) const {
char buf[30]; char buf[30];
bool TypesAreValid = this->getDest()->getType() == IceType_v4i32 || bool TypesAreValid = this->getDest()->getType() == IceType_v4i32 ||
this->getDest()->getType() == IceType_v8i16; this->getDest()->getType() == IceType_v8i16;
TargetLowering *Target = Func->getTarget();
bool InstructionSetIsValid = bool InstructionSetIsValid =
this->getDest()->getType() == IceType_v8i16 || this->getDest()->getType() == IceType_v8i16 ||
static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>(
Func->getTarget()) Target)
->getInstructionSet() >= InstX86Base<Machine>::Traits::SSE4_1; ->getInstructionSet() >= InstX86Base<Machine>::Traits::SSE4_1;
(void)TypesAreValid; (void)TypesAreValid;
(void)InstructionSetIsValid; (void)InstructionSetIsValid;
...@@ -1074,10 +1087,11 @@ template <class Machine> ...@@ -1074,10 +1087,11 @@ template <class Machine>
void InstX86Pmull<Machine>::emitIAS(const Cfg *Func) const { void InstX86Pmull<Machine>::emitIAS(const Cfg *Func) const {
Type Ty = this->getDest()->getType(); Type Ty = this->getDest()->getType();
bool TypesAreValid = Ty == IceType_v4i32 || Ty == IceType_v8i16; bool TypesAreValid = Ty == IceType_v4i32 || Ty == IceType_v8i16;
TargetLowering *Target = Func->getTarget();
bool InstructionSetIsValid = bool InstructionSetIsValid =
Ty == IceType_v8i16 || Ty == IceType_v8i16 ||
static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>(
Func->getTarget()) Target)
->getInstructionSet() >= InstX86Base<Machine>::Traits::SSE4_1; ->getInstructionSet() >= InstX86Base<Machine>::Traits::SSE4_1;
(void)TypesAreValid; (void)TypesAreValid;
(void)InstructionSetIsValid; (void)InstructionSetIsValid;
...@@ -1222,16 +1236,18 @@ template <class Machine> ...@@ -1222,16 +1236,18 @@ template <class Machine>
void InstX86Blendvps<Machine>::emit(const Cfg *Func) const { void InstX86Blendvps<Machine>::emit(const Cfg *Func) const {
if (!BuildDefs::dump()) if (!BuildDefs::dump())
return; return;
TargetLowering *Target = Func->getTarget();
assert(static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( assert(static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>(
Func->getTarget()) Target)
->getInstructionSet() >= InstX86Base<Machine>::Traits::SSE4_1); ->getInstructionSet() >= InstX86Base<Machine>::Traits::SSE4_1);
emitVariableBlendInst<Machine>(this->Opcode, this, Func); emitVariableBlendInst<Machine>(this->Opcode, this, Func);
} }
template <class Machine> template <class Machine>
void InstX86Blendvps<Machine>::emitIAS(const Cfg *Func) const { void InstX86Blendvps<Machine>::emitIAS(const Cfg *Func) const {
TargetLowering *Target = Func->getTarget();
assert(static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( assert(static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>(
Func->getTarget()) Target)
->getInstructionSet() >= InstX86Base<Machine>::Traits::SSE4_1); ->getInstructionSet() >= InstX86Base<Machine>::Traits::SSE4_1);
static const typename InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp static const typename InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp
Emitter = {&InstX86Base<Machine>::Traits::Assembler::blendvps, Emitter = {&InstX86Base<Machine>::Traits::Assembler::blendvps,
...@@ -1243,16 +1259,18 @@ template <class Machine> ...@@ -1243,16 +1259,18 @@ template <class Machine>
void InstX86Pblendvb<Machine>::emit(const Cfg *Func) const { void InstX86Pblendvb<Machine>::emit(const Cfg *Func) const {
if (!BuildDefs::dump()) if (!BuildDefs::dump())
return; return;
TargetLowering *Target = Func->getTarget();
assert(static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( assert(static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>(
Func->getTarget()) Target)
->getInstructionSet() >= InstX86Base<Machine>::Traits::SSE4_1); ->getInstructionSet() >= InstX86Base<Machine>::Traits::SSE4_1);
emitVariableBlendInst<Machine>(this->Opcode, this, Func); emitVariableBlendInst<Machine>(this->Opcode, this, Func);
} }
template <class Machine> template <class Machine>
void InstX86Pblendvb<Machine>::emitIAS(const Cfg *Func) const { void InstX86Pblendvb<Machine>::emitIAS(const Cfg *Func) const {
TargetLowering *Target = Func->getTarget();
assert(static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( assert(static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>(
Func->getTarget()) Target)
->getInstructionSet() >= InstX86Base<Machine>::Traits::SSE4_1); ->getInstructionSet() >= InstX86Base<Machine>::Traits::SSE4_1);
static const typename InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp static const typename InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp
Emitter = {&InstX86Base<Machine>::Traits::Assembler::pblendvb, Emitter = {&InstX86Base<Machine>::Traits::Assembler::pblendvb,
...@@ -1357,8 +1375,9 @@ void InstX86ImulImm<Machine>::emitIAS(const Cfg *Func) const { ...@@ -1357,8 +1375,9 @@ void InstX86ImulImm<Machine>::emitIAS(const Cfg *Func) const {
template <class Machine> template <class Machine>
void InstX86Insertps<Machine>::emitIAS(const Cfg *Func) const { void InstX86Insertps<Machine>::emitIAS(const Cfg *Func) const {
assert(this->getSrcSize() == 3); assert(this->getSrcSize() == 3);
TargetLowering *Target = Func->getTarget();
assert(static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( assert(static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>(
Func->getTarget()) Target)
->getInstructionSet() >= InstX86Base<Machine>::Traits::SSE4_1); ->getInstructionSet() >= InstX86Base<Machine>::Traits::SSE4_1);
const Variable *Dest = this->getDest(); const Variable *Dest = this->getDest();
assert(Dest == this->getSrc(0)); assert(Dest == this->getSrc(0));
...@@ -1605,6 +1624,7 @@ void InstX86Cmov<Machine>::emitIAS(const Cfg *Func) const { ...@@ -1605,6 +1624,7 @@ void InstX86Cmov<Machine>::emitIAS(const Cfg *Func) const {
(InstX86Base<Machine>::Traits::Is64Bit)); (InstX86Base<Machine>::Traits::Is64Bit));
typename InstX86Base<Machine>::Traits::Assembler *Asm = typename InstX86Base<Machine>::Traits::Assembler *Asm =
Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
TargetLowering *Target = Func->getTarget();
if (const auto *SrcVar = llvm::dyn_cast<Variable>(Src)) { if (const auto *SrcVar = llvm::dyn_cast<Variable>(Src)) {
if (SrcVar->hasReg()) { if (SrcVar->hasReg()) {
Asm->cmov( Asm->cmov(
...@@ -1616,7 +1636,7 @@ void InstX86Cmov<Machine>::emitIAS(const Cfg *Func) const { ...@@ -1616,7 +1636,7 @@ void InstX86Cmov<Machine>::emitIAS(const Cfg *Func) const {
SrcTy, Condition, InstX86Base<Machine>::Traits::getEncodedGPR( SrcTy, Condition, InstX86Base<Machine>::Traits::getEncodedGPR(
this->getDest()->getRegNum()), this->getDest()->getRegNum()),
static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>(
Func->getTarget()) Target)
->stackVarToAsmOperand(SrcVar)); ->stackVarToAsmOperand(SrcVar));
} }
} else if (const auto *Mem = llvm::dyn_cast< } else if (const auto *Mem = llvm::dyn_cast<
...@@ -1625,7 +1645,7 @@ void InstX86Cmov<Machine>::emitIAS(const Cfg *Func) const { ...@@ -1625,7 +1645,7 @@ void InstX86Cmov<Machine>::emitIAS(const Cfg *Func) const {
InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment); InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment);
Asm->cmov(SrcTy, Condition, InstX86Base<Machine>::Traits::getEncodedGPR( Asm->cmov(SrcTy, Condition, InstX86Base<Machine>::Traits::getEncodedGPR(
this->getDest()->getRegNum()), this->getDest()->getRegNum()),
Mem->toAsmAddress(Asm)); Mem->toAsmAddress(Asm, Target));
} else { } else {
llvm_unreachable("Unexpected operand type"); llvm_unreachable("Unexpected operand type");
} }
...@@ -1671,6 +1691,7 @@ void InstX86Cmpps<Machine>::emitIAS(const Cfg *Func) const { ...@@ -1671,6 +1691,7 @@ void InstX86Cmpps<Machine>::emitIAS(const Cfg *Func) const {
// Assuming there isn't any load folding for cmpps, and vector constants are // Assuming there isn't any load folding for cmpps, and vector constants are
// not allowed in PNaCl. // not allowed in PNaCl.
assert(llvm::isa<Variable>(this->getSrc(1))); assert(llvm::isa<Variable>(this->getSrc(1)));
TargetLowering *Target = Func->getTarget();
const auto *SrcVar = llvm::cast<Variable>(this->getSrc(1)); const auto *SrcVar = llvm::cast<Variable>(this->getSrc(1));
if (SrcVar->hasReg()) { if (SrcVar->hasReg()) {
Asm->cmpps(InstX86Base<Machine>::Traits::getEncodedXmm( Asm->cmpps(InstX86Base<Machine>::Traits::getEncodedXmm(
...@@ -1680,7 +1701,7 @@ void InstX86Cmpps<Machine>::emitIAS(const Cfg *Func) const { ...@@ -1680,7 +1701,7 @@ void InstX86Cmpps<Machine>::emitIAS(const Cfg *Func) const {
} else { } else {
typename InstX86Base<Machine>::Traits::Address SrcStackAddr = typename InstX86Base<Machine>::Traits::Address SrcStackAddr =
static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>(
Func->getTarget()) Target)
->stackVarToAsmOperand(SrcVar); ->stackVarToAsmOperand(SrcVar);
Asm->cmpps(InstX86Base<Machine>::Traits::getEncodedXmm( Asm->cmpps(InstX86Base<Machine>::Traits::getEncodedXmm(
this->getDest()->getRegNum()), this->getDest()->getRegNum()),
...@@ -1724,13 +1745,14 @@ void InstX86Cmpxchg<Machine>::emitIAS(const Cfg *Func) const { ...@@ -1724,13 +1745,14 @@ void InstX86Cmpxchg<Machine>::emitIAS(const Cfg *Func) const {
typename InstX86Base<Machine>::Traits::Assembler *Asm = typename InstX86Base<Machine>::Traits::Assembler *Asm =
Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
Type Ty = this->getSrc(0)->getType(); Type Ty = this->getSrc(0)->getType();
TargetLowering *Target = Func->getTarget();
const auto Mem = const auto Mem =
llvm::cast<typename InstX86Base<Machine>::Traits::X86OperandMem>( llvm::cast<typename InstX86Base<Machine>::Traits::X86OperandMem>(
this->getSrc(0)); this->getSrc(0));
assert(Mem->getSegmentRegister() == assert(Mem->getSegmentRegister() ==
InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment); InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment);
const typename InstX86Base<Machine>::Traits::Address Addr = const typename InstX86Base<Machine>::Traits::Address Addr =
Mem->toAsmAddress(Asm); Mem->toAsmAddress(Asm, Target);
const auto *VarReg = llvm::cast<Variable>(this->getSrc(2)); const auto *VarReg = llvm::cast<Variable>(this->getSrc(2));
assert(VarReg->hasReg()); assert(VarReg->hasReg());
const typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister Reg = const typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister Reg =
...@@ -1773,8 +1795,9 @@ void InstX86Cmpxchg8b<Machine>::emitIAS(const Cfg *Func) const { ...@@ -1773,8 +1795,9 @@ void InstX86Cmpxchg8b<Machine>::emitIAS(const Cfg *Func) const {
this->getSrc(0)); this->getSrc(0));
assert(Mem->getSegmentRegister() == assert(Mem->getSegmentRegister() ==
InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment); InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment);
TargetLowering *Target = Func->getTarget();
const typename InstX86Base<Machine>::Traits::Address Addr = const typename InstX86Base<Machine>::Traits::Address Addr =
Mem->toAsmAddress(Asm); Mem->toAsmAddress(Asm, Target);
Asm->cmpxchg8b(Addr, this->Locked); Asm->cmpxchg8b(Addr, this->Locked);
} }
...@@ -2114,11 +2137,12 @@ void InstX86Store<Machine>::emitIAS(const Cfg *Func) const { ...@@ -2114,11 +2137,12 @@ void InstX86Store<Machine>::emitIAS(const Cfg *Func) const {
InstX86Base<Machine>::Traits::getEncodedXmm(SrcVar->getRegNum()); InstX86Base<Machine>::Traits::getEncodedXmm(SrcVar->getRegNum());
typename InstX86Base<Machine>::Traits::Assembler *Asm = typename InstX86Base<Machine>::Traits::Assembler *Asm =
Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
TargetLowering *Target = Func->getTarget();
if (const auto *DestVar = llvm::dyn_cast<Variable>(Dest)) { if (const auto *DestVar = llvm::dyn_cast<Variable>(Dest)) {
assert(!DestVar->hasReg()); assert(!DestVar->hasReg());
typename InstX86Base<Machine>::Traits::Address StackAddr( typename InstX86Base<Machine>::Traits::Address StackAddr(
static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>(
Func->getTarget()) Target)
->stackVarToAsmOperand(DestVar)); ->stackVarToAsmOperand(DestVar));
Asm->movss(DestTy, StackAddr, SrcReg); Asm->movss(DestTy, StackAddr, SrcReg);
} else { } else {
...@@ -2127,7 +2151,7 @@ void InstX86Store<Machine>::emitIAS(const Cfg *Func) const { ...@@ -2127,7 +2151,7 @@ void InstX86Store<Machine>::emitIAS(const Cfg *Func) const {
Dest); Dest);
assert(DestMem->getSegmentRegister() == assert(DestMem->getSegmentRegister() ==
InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment); InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment);
Asm->movss(DestTy, DestMem->toAsmAddress(Asm), SrcReg); Asm->movss(DestTy, DestMem->toAsmAddress(Asm, Target), SrcReg);
} }
return; return;
} else { } else {
...@@ -2176,7 +2200,8 @@ void InstX86StoreP<Machine>::emitIAS(const Cfg *Func) const { ...@@ -2176,7 +2200,8 @@ void InstX86StoreP<Machine>::emitIAS(const Cfg *Func) const {
assert(DestMem->getSegmentRegister() == assert(DestMem->getSegmentRegister() ==
InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment); InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment);
assert(SrcVar->hasReg()); assert(SrcVar->hasReg());
Asm->movups(DestMem->toAsmAddress(Asm), TargetLowering *Target = Func->getTarget();
Asm->movups(DestMem->toAsmAddress(Asm, Target),
InstX86Base<Machine>::Traits::getEncodedXmm(SrcVar->getRegNum())); InstX86Base<Machine>::Traits::getEncodedXmm(SrcVar->getRegNum()));
} }
...@@ -2218,7 +2243,8 @@ void InstX86StoreQ<Machine>::emitIAS(const Cfg *Func) const { ...@@ -2218,7 +2243,8 @@ void InstX86StoreQ<Machine>::emitIAS(const Cfg *Func) const {
assert(DestMem->getSegmentRegister() == assert(DestMem->getSegmentRegister() ==
InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment); InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment);
assert(SrcVar->hasReg()); assert(SrcVar->hasReg());
Asm->movq(DestMem->toAsmAddress(Asm), TargetLowering *Target = Func->getTarget();
Asm->movq(DestMem->toAsmAddress(Asm, Target),
InstX86Base<Machine>::Traits::getEncodedXmm(SrcVar->getRegNum())); InstX86Base<Machine>::Traits::getEncodedXmm(SrcVar->getRegNum()));
} }
...@@ -2281,8 +2307,9 @@ template <class Machine> void InstX86Mov<Machine>::emit(const Cfg *Func) const { ...@@ -2281,8 +2307,9 @@ template <class Machine> void InstX86Mov<Machine>::emit(const Cfg *Func) const {
// TODO: This assert disallows usages such as copying a floating // TODO: This assert disallows usages such as copying a floating
// point value between a vector and a scalar (which movss is used for). Clean // point value between a vector and a scalar (which movss is used for). Clean
// this up. // this up.
assert(Func->getTarget()->typeWidthInBytesOnStack(DestTy) == TargetLowering *Target = Func->getTarget();
Func->getTarget()->typeWidthInBytesOnStack(SrcTy)); assert(Target->typeWidthInBytesOnStack(DestTy) ==
Target->typeWidthInBytesOnStack(SrcTy));
const Operand *NewSrc = Src; const Operand *NewSrc = Src;
if (auto *SrcVar = llvm::dyn_cast<Variable>(Src)) { if (auto *SrcVar = llvm::dyn_cast<Variable>(Src)) {
int32_t NewRegNum = Variable::NoRegister; int32_t NewRegNum = Variable::NoRegister;
...@@ -2326,9 +2353,9 @@ void InstX86Mov<Machine>::emitIAS(const Cfg *Func) const { ...@@ -2326,9 +2353,9 @@ void InstX86Mov<Machine>::emitIAS(const Cfg *Func) const {
// TODO: This assert disallows usages such as copying a floating // TODO: This assert disallows usages such as copying a floating
// point value between a vector and a scalar (which movss is used for). Clean // point value between a vector and a scalar (which movss is used for). Clean
// this up. // this up.
assert( TargetLowering *Target = Func->getTarget();
Func->getTarget()->typeWidthInBytesOnStack(this->getDest()->getType()) == assert(Target->typeWidthInBytesOnStack(this->getDest()->getType()) ==
Func->getTarget()->typeWidthInBytesOnStack(Src->getType())); Target->typeWidthInBytesOnStack(Src->getType()));
if (Dest->hasReg()) { if (Dest->hasReg()) {
if (isScalarFloatingType(DestTy)) { if (isScalarFloatingType(DestTy)) {
emitIASRegOpTyXMM<Machine>(Func, DestTy, Dest, Src, XmmRegEmitter); emitIASRegOpTyXMM<Machine>(Func, DestTy, Dest, Src, XmmRegEmitter);
...@@ -2362,7 +2389,7 @@ void InstX86Mov<Machine>::emitIAS(const Cfg *Func) const { ...@@ -2362,7 +2389,7 @@ void InstX86Mov<Machine>::emitIAS(const Cfg *Func) const {
// decide on the emitters. // decide on the emitters.
typename InstX86Base<Machine>::Traits::Address StackAddr( typename InstX86Base<Machine>::Traits::Address StackAddr(
static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>(
Func->getTarget()) Target)
->stackVarToAsmOperand(Dest)); ->stackVarToAsmOperand(Dest));
if (isScalarFloatingType(SrcTy)) { if (isScalarFloatingType(SrcTy)) {
// Src must be a register. // Src must be a register.
...@@ -2391,6 +2418,7 @@ void InstX86Movd<Machine>::emitIAS(const Cfg *Func) const { ...@@ -2391,6 +2418,7 @@ void InstX86Movd<Machine>::emitIAS(const Cfg *Func) const {
assert(this->getSrcSize() == 1); assert(this->getSrcSize() == 1);
const Variable *Dest = this->getDest(); const Variable *Dest = this->getDest();
const auto *SrcVar = llvm::cast<Variable>(this->getSrc(0)); const auto *SrcVar = llvm::cast<Variable>(this->getSrc(0));
TargetLowering *Target = Func->getTarget();
// For insert/extract element (one of Src/Dest is an Xmm vector and the other // For insert/extract element (one of Src/Dest is an Xmm vector and the other
// is an int type). // is an int type).
if (SrcVar->getType() == IceType_i32 || if (SrcVar->getType() == IceType_i32 ||
...@@ -2410,7 +2438,7 @@ void InstX86Movd<Machine>::emitIAS(const Cfg *Func) const { ...@@ -2410,7 +2438,7 @@ void InstX86Movd<Machine>::emitIAS(const Cfg *Func) const {
} else { } else {
typename InstX86Base<Machine>::Traits::Address StackAddr( typename InstX86Base<Machine>::Traits::Address StackAddr(
static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>(
Func->getTarget()) Target)
->stackVarToAsmOperand(SrcVar)); ->stackVarToAsmOperand(SrcVar));
Asm->movd(SrcVar->getType(), DestReg, StackAddr); Asm->movd(SrcVar->getType(), DestReg, StackAddr);
} }
...@@ -2432,7 +2460,7 @@ void InstX86Movd<Machine>::emitIAS(const Cfg *Func) const { ...@@ -2432,7 +2460,7 @@ void InstX86Movd<Machine>::emitIAS(const Cfg *Func) const {
} else { } else {
typename InstX86Base<Machine>::Traits::Address StackAddr( typename InstX86Base<Machine>::Traits::Address StackAddr(
static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>(
Func->getTarget()) Target)
->stackVarToAsmOperand(Dest)); ->stackVarToAsmOperand(Dest));
Asm->movd(Dest->getType(), StackAddr, SrcReg); Asm->movd(Dest->getType(), StackAddr, SrcReg);
} }
...@@ -2595,6 +2623,7 @@ void InstX86Fld<Machine>::emitIAS(const Cfg *Func) const { ...@@ -2595,6 +2623,7 @@ void InstX86Fld<Machine>::emitIAS(const Cfg *Func) const {
Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
assert(this->getSrcSize() == 1); assert(this->getSrcSize() == 1);
const Operand *Src = this->getSrc(0); const Operand *Src = this->getSrc(0);
TargetLowering *Target = Func->getTarget();
Type Ty = Src->getType(); Type Ty = Src->getType();
if (const auto *Var = llvm::dyn_cast<Variable>(Src)) { if (const auto *Var = llvm::dyn_cast<Variable>(Src)) {
if (Var->hasReg()) { if (Var->hasReg()) {
...@@ -2617,7 +2646,7 @@ void InstX86Fld<Machine>::emitIAS(const Cfg *Func) const { ...@@ -2617,7 +2646,7 @@ void InstX86Fld<Machine>::emitIAS(const Cfg *Func) const {
} else { } else {
typename InstX86Base<Machine>::Traits::Address StackAddr( typename InstX86Base<Machine>::Traits::Address StackAddr(
static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>(
Func->getTarget()) Target)
->stackVarToAsmOperand(Var)); ->stackVarToAsmOperand(Var));
Asm->fld(Ty, StackAddr); Asm->fld(Ty, StackAddr);
} }
...@@ -2625,7 +2654,7 @@ void InstX86Fld<Machine>::emitIAS(const Cfg *Func) const { ...@@ -2625,7 +2654,7 @@ void InstX86Fld<Machine>::emitIAS(const Cfg *Func) const {
typename InstX86Base<Machine>::Traits::X86OperandMem>(Src)) { typename InstX86Base<Machine>::Traits::X86OperandMem>(Src)) {
assert(Mem->getSegmentRegister() == assert(Mem->getSegmentRegister() ==
InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment); InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment);
Asm->fld(Ty, Mem->toAsmAddress(Asm)); Asm->fld(Ty, Mem->toAsmAddress(Asm, Target));
} else if (const auto *Imm = llvm::dyn_cast<Constant>(Src)) { } else if (const auto *Imm = llvm::dyn_cast<Constant>(Src)) {
Asm->fld(Ty, InstX86Base<Machine>::Traits::Address::ofConstPool(Asm, Imm)); Asm->fld(Ty, InstX86Base<Machine>::Traits::Address::ofConstPool(Asm, Imm));
} else { } else {
...@@ -2688,11 +2717,12 @@ void InstX86Fstp<Machine>::emitIAS(const Cfg *Func) const { ...@@ -2688,11 +2717,12 @@ void InstX86Fstp<Machine>::emitIAS(const Cfg *Func) const {
Asm->fstp(InstX86Base<Machine>::Traits::RegisterSet::getEncodedSTReg(0)); Asm->fstp(InstX86Base<Machine>::Traits::RegisterSet::getEncodedSTReg(0));
return; return;
} }
TargetLowering *Target = Func->getTarget();
Type Ty = Dest->getType(); Type Ty = Dest->getType();
if (!Dest->hasReg()) { if (!Dest->hasReg()) {
typename InstX86Base<Machine>::Traits::Address StackAddr( typename InstX86Base<Machine>::Traits::Address StackAddr(
static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>(
Func->getTarget()) Target)
->stackVarToAsmOperand(Dest)); ->stackVarToAsmOperand(Dest));
Asm->fstp(Ty, StackAddr); Asm->fstp(Ty, StackAddr);
} else { } else {
...@@ -2755,10 +2785,11 @@ void InstX86Pextr<Machine>::emit(const Cfg *Func) const { ...@@ -2755,10 +2785,11 @@ void InstX86Pextr<Machine>::emit(const Cfg *Func) const {
Ostream &Str = Func->getContext()->getStrEmit(); Ostream &Str = Func->getContext()->getStrEmit();
assert(this->getSrcSize() == 2); assert(this->getSrcSize() == 2);
// pextrb and pextrd are SSE4.1 instructions. // pextrb and pextrd are SSE4.1 instructions.
TargetLowering *Target = Func->getTarget();
assert(this->getSrc(0)->getType() == IceType_v8i16 || assert(this->getSrc(0)->getType() == IceType_v8i16 ||
this->getSrc(0)->getType() == IceType_v8i1 || this->getSrc(0)->getType() == IceType_v8i1 ||
static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>(
Func->getTarget()) Target)
->getInstructionSet() >= InstX86Base<Machine>::Traits::SSE4_1); ->getInstructionSet() >= InstX86Base<Machine>::Traits::SSE4_1);
Str << "\t" << this->Opcode Str << "\t" << this->Opcode
<< InstX86Base<Machine>::Traits::TypeAttributes[this->getSrc(0) << InstX86Base<Machine>::Traits::TypeAttributes[this->getSrc(0)
...@@ -2783,9 +2814,10 @@ void InstX86Pextr<Machine>::emitIAS(const Cfg *Func) const { ...@@ -2783,9 +2814,10 @@ void InstX86Pextr<Machine>::emitIAS(const Cfg *Func) const {
const Variable *Dest = this->getDest(); const Variable *Dest = this->getDest();
Type DispatchTy = InstX86Base<Machine>::Traits::getInVectorElementType( Type DispatchTy = InstX86Base<Machine>::Traits::getInVectorElementType(
this->getSrc(0)->getType()); this->getSrc(0)->getType());
TargetLowering *Target = Func->getTarget();
assert(DispatchTy == IceType_i16 || assert(DispatchTy == IceType_i16 ||
static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>(
Func->getTarget()) Target)
->getInstructionSet() >= InstX86Base<Machine>::Traits::SSE4_1); ->getInstructionSet() >= InstX86Base<Machine>::Traits::SSE4_1);
// pextrw must take a register dest. There is an SSE4.1 version that takes a // pextrw must take a register dest. There is an SSE4.1 version that takes a
// memory dest, but we aren't using it. For uniformity, just restrict them // memory dest, but we aren't using it. For uniformity, just restrict them
...@@ -2813,10 +2845,11 @@ void InstX86Pinsr<Machine>::emit(const Cfg *Func) const { ...@@ -2813,10 +2845,11 @@ void InstX86Pinsr<Machine>::emit(const Cfg *Func) const {
Ostream &Str = Func->getContext()->getStrEmit(); Ostream &Str = Func->getContext()->getStrEmit();
assert(this->getSrcSize() == 3); assert(this->getSrcSize() == 3);
// pinsrb and pinsrd are SSE4.1 instructions. // pinsrb and pinsrd are SSE4.1 instructions.
TargetLowering *Target = Func->getTarget();
assert(this->getDest()->getType() == IceType_v8i16 || assert(this->getDest()->getType() == IceType_v8i16 ||
this->getDest()->getType() == IceType_v8i1 || this->getDest()->getType() == IceType_v8i1 ||
static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>(
Func->getTarget()) Target)
->getInstructionSet() >= InstX86Base<Machine>::Traits::SSE4_1); ->getInstructionSet() >= InstX86Base<Machine>::Traits::SSE4_1);
Str << "\t" << this->Opcode Str << "\t" << this->Opcode
<< InstX86Base< << InstX86Base<
...@@ -2849,9 +2882,10 @@ void InstX86Pinsr<Machine>::emitIAS(const Cfg *Func) const { ...@@ -2849,9 +2882,10 @@ void InstX86Pinsr<Machine>::emitIAS(const Cfg *Func) const {
// pinsrb and pinsrd are SSE4.1 instructions. // pinsrb and pinsrd are SSE4.1 instructions.
const Operand *Src0 = this->getSrc(1); const Operand *Src0 = this->getSrc(1);
Type DispatchTy = Src0->getType(); Type DispatchTy = Src0->getType();
TargetLowering *Target = Func->getTarget();
assert(DispatchTy == IceType_i16 || assert(DispatchTy == IceType_i16 ||
static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>(
Func->getTarget()) Target)
->getInstructionSet() >= InstX86Base<Machine>::Traits::SSE4_1); ->getInstructionSet() >= InstX86Base<Machine>::Traits::SSE4_1);
// If src1 is a register, it should always be r32 (this should fall out from // If src1 is a register, it should always be r32 (this should fall out from
// the encodings for ByteRegs overlapping the encodings for r32), but we have // the encodings for ByteRegs overlapping the encodings for r32), but we have
...@@ -2939,9 +2973,10 @@ void InstX86Pop<Machine>::emitIAS(const Cfg *Func) const { ...@@ -2939,9 +2973,10 @@ void InstX86Pop<Machine>::emitIAS(const Cfg *Func) const {
Asm->popl(InstX86Base<Machine>::Traits::getEncodedGPR( Asm->popl(InstX86Base<Machine>::Traits::getEncodedGPR(
this->getDest()->getRegNum())); this->getDest()->getRegNum()));
} else { } else {
TargetLowering *Target = Func->getTarget();
Asm->popl( Asm->popl(
static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>(
Func->getTarget()) Target)
->stackVarToAsmOperand(this->getDest())); ->stackVarToAsmOperand(this->getDest()));
} }
} }
...@@ -2960,7 +2995,8 @@ void InstX86AdjustStack<Machine>::emit(const Cfg *Func) const { ...@@ -2960,7 +2995,8 @@ void InstX86AdjustStack<Machine>::emit(const Cfg *Func) const {
return; return;
Ostream &Str = Func->getContext()->getStrEmit(); Ostream &Str = Func->getContext()->getStrEmit();
Str << "\tsubl\t$" << Amount << ", %esp"; Str << "\tsubl\t$" << Amount << ", %esp";
Func->getTarget()->updateStackAdjustment(Amount); TargetLowering *Target = Func->getTarget();
Target->updateStackAdjustment(Amount);
} }
template <class Machine> template <class Machine>
...@@ -2970,7 +3006,8 @@ void InstX86AdjustStack<Machine>::emitIAS(const Cfg *Func) const { ...@@ -2970,7 +3006,8 @@ void InstX86AdjustStack<Machine>::emitIAS(const Cfg *Func) const {
Asm->sub(IceType_i32, Asm->sub(IceType_i32,
InstX86Base<Machine>::Traits::RegisterSet::Encoded_Reg_esp, InstX86Base<Machine>::Traits::RegisterSet::Encoded_Reg_esp,
Immediate(Amount)); Immediate(Amount));
Func->getTarget()->updateStackAdjustment(Amount); TargetLowering *Target = Func->getTarget();
Target->updateStackAdjustment(Amount);
} }
template <class Machine> template <class Machine>
...@@ -3100,6 +3137,7 @@ void InstX86Setcc<Machine>::emitIAS(const Cfg *Func) const { ...@@ -3100,6 +3137,7 @@ void InstX86Setcc<Machine>::emitIAS(const Cfg *Func) const {
assert(this->getSrcSize() == 0); assert(this->getSrcSize() == 0);
typename InstX86Base<Machine>::Traits::Assembler *Asm = typename InstX86Base<Machine>::Traits::Assembler *Asm =
Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
TargetLowering *Target = Func->getTarget();
if (this->getDest()->hasReg()) if (this->getDest()->hasReg())
Asm->setcc(Condition, InstX86Base<Machine>::Traits::getEncodedByteReg( Asm->setcc(Condition, InstX86Base<Machine>::Traits::getEncodedByteReg(
this->getDest()->getRegNum())); this->getDest()->getRegNum()));
...@@ -3107,7 +3145,7 @@ void InstX86Setcc<Machine>::emitIAS(const Cfg *Func) const { ...@@ -3107,7 +3145,7 @@ void InstX86Setcc<Machine>::emitIAS(const Cfg *Func) const {
Asm->setcc( Asm->setcc(
Condition, Condition,
static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>(
Func->getTarget()) Target)
->stackVarToAsmOperand(this->getDest())); ->stackVarToAsmOperand(this->getDest()));
return; return;
} }
...@@ -3148,8 +3186,9 @@ void InstX86Xadd<Machine>::emitIAS(const Cfg *Func) const { ...@@ -3148,8 +3186,9 @@ void InstX86Xadd<Machine>::emitIAS(const Cfg *Func) const {
this->getSrc(0)); this->getSrc(0));
assert(Mem->getSegmentRegister() == assert(Mem->getSegmentRegister() ==
InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment); InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment);
TargetLowering *Target = Func->getTarget();
const typename InstX86Base<Machine>::Traits::Address Addr = const typename InstX86Base<Machine>::Traits::Address Addr =
Mem->toAsmAddress(Asm); Mem->toAsmAddress(Asm, Target);
const auto *VarReg = llvm::cast<Variable>(this->getSrc(1)); const auto *VarReg = llvm::cast<Variable>(this->getSrc(1));
assert(VarReg->hasReg()); assert(VarReg->hasReg());
const typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister Reg = const typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister Reg =
...@@ -3205,8 +3244,9 @@ void InstX86Xchg<Machine>::emitIAS(const Cfg *Func) const { ...@@ -3205,8 +3244,9 @@ void InstX86Xchg<Machine>::emitIAS(const Cfg *Func) const {
this->getSrc(0)); this->getSrc(0));
assert(Mem->getSegmentRegister() == assert(Mem->getSegmentRegister() ==
InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment); InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment);
TargetLowering *Target = Func->getTarget();
const typename InstX86Base<Machine>::Traits::Address Addr = const typename InstX86Base<Machine>::Traits::Address Addr =
Mem->toAsmAddress(Asm); Mem->toAsmAddress(Asm, Target);
Asm->xchg(Ty, Addr, Reg1); Asm->xchg(Ty, Addr, Reg1);
} }
......
...@@ -509,6 +509,13 @@ public: ...@@ -509,6 +509,13 @@ public:
bool mustNotHaveReg() const { bool mustNotHaveReg() const {
return RegRequirement == RR_MustNotHaveRegister; return RegRequirement == RR_MustNotHaveRegister;
} }
void setRematerializable(int32_t NewRegNum, int32_t NewOffset) {
IsRematerializable = true;
setRegNum(NewRegNum);
setStackOffset(NewOffset);
setMustHaveReg();
}
bool isRematerializable() const { return IsRematerializable; }
void setRegClass(uint8_t RC) { RegisterClass = static_cast<RegClass>(RC); } void setRegClass(uint8_t RC) { RegisterClass = static_cast<RegClass>(RC); }
RegClass getRegClass() const { return RegisterClass; } RegClass getRegClass() const { return RegisterClass; }
...@@ -573,6 +580,9 @@ protected: ...@@ -573,6 +580,9 @@ protected:
/// and validating live ranges. This is usually reserved for the stack /// and validating live ranges. This is usually reserved for the stack
/// pointer and other physical registers specifically referenced by name. /// pointer and other physical registers specifically referenced by name.
bool IgnoreLiveness = false; bool IgnoreLiveness = false;
// If IsRematerializable, RegNum keeps track of which register (stack or frame
// pointer), and StackOffset is the known offset from that register.
bool IsRematerializable = false;
RegRequirement RegRequirement = RR_MayHaveRegister; RegRequirement RegRequirement = RR_MayHaveRegister;
RegClass RegisterClass; RegClass RegisterClass;
/// RegNum is the allocated register, or NoRegister if it isn't /// RegNum is the allocated register, or NoRegister if it isn't
......
...@@ -239,6 +239,11 @@ void TargetARM32::translateO2() { ...@@ -239,6 +239,11 @@ void TargetARM32::translateO2() {
// TODO(stichnot): share passes with X86? // TODO(stichnot): share passes with X86?
// https://code.google.com/p/nativeclient/issues/detail?id=4094 // https://code.google.com/p/nativeclient/issues/detail?id=4094
// Do not merge Alloca instructions, and lay out the stack.
static constexpr bool SortAndCombineAllocas = false;
Func->processAllocas(SortAndCombineAllocas);
Func->dump("After Alloca processing");
if (!Ctx->getFlags().getPhiEdgeSplit()) { if (!Ctx->getFlags().getPhiEdgeSplit()) {
// Lower Phi instructions. // Lower Phi instructions.
Func->placePhiLoads(); Func->placePhiLoads();
...@@ -340,6 +345,11 @@ void TargetARM32::translateOm1() { ...@@ -340,6 +345,11 @@ void TargetARM32::translateOm1() {
// TODO: share passes with X86? // TODO: share passes with X86?
// Do not merge Alloca instructions, and lay out the stack.
static constexpr bool SortAndCombineAllocas = false;
Func->processAllocas(SortAndCombineAllocas);
Func->dump("After Alloca processing");
Func->placePhiLoads(); Func->placePhiLoads();
if (Func->hasError()) if (Func->hasError())
return; return;
......
...@@ -92,6 +92,11 @@ void TargetMIPS32::translateO2() { ...@@ -92,6 +92,11 @@ void TargetMIPS32::translateO2() {
// TODO(stichnot): share passes with X86? // TODO(stichnot): share passes with X86?
// https://code.google.com/p/nativeclient/issues/detail?id=4094 // https://code.google.com/p/nativeclient/issues/detail?id=4094
// Merge Alloca instructions, and lay out the stack.
static constexpr bool SortAndCombineAllocas = true;
Func->processAllocas(SortAndCombineAllocas);
Func->dump("After Alloca processing");
if (!Ctx->getFlags().getPhiEdgeSplit()) { if (!Ctx->getFlags().getPhiEdgeSplit()) {
// Lower Phi instructions. // Lower Phi instructions.
Func->placePhiLoads(); Func->placePhiLoads();
...@@ -187,6 +192,11 @@ void TargetMIPS32::translateOm1() { ...@@ -187,6 +192,11 @@ void TargetMIPS32::translateOm1() {
// TODO: share passes with X86? // TODO: share passes with X86?
// Do not merge Alloca instructions, and lay out the stack.
static constexpr bool SortAndCombineAllocas = false;
Func->processAllocas(SortAndCombineAllocas);
Func->dump("After Alloca processing");
Func->placePhiLoads(); Func->placePhiLoads();
if (Func->hasError()) if (Func->hasError())
return; return;
......
...@@ -151,8 +151,10 @@ void TargetX8632::lowerCall(const InstCall *Instr) { ...@@ -151,8 +151,10 @@ void TargetX8632::lowerCall(const InstCall *Instr) {
Variable *esp = Variable *esp =
Func->getTarget()->getPhysicalRegister(Traits::RegisterSet::Reg_esp); Func->getTarget()->getPhysicalRegister(Traits::RegisterSet::Reg_esp);
Constant *Loc = Ctx->getConstantInt32(ParameterAreaSizeBytes); Constant *Loc = Ctx->getConstantInt32(ParameterAreaSizeBytes);
StackArgLocations.push_back( auto *Mem = Traits::X86OperandMem::create(Func, Ty, esp, Loc);
Traits::X86OperandMem::create(Func, Ty, esp, Loc)); // Stack stores for arguments are fixed to esp.
Mem->setIgnoreStackAdjust(true);
StackArgLocations.push_back(Mem);
ParameterAreaSizeBytes += typeWidthInBytesOnStack(Arg->getType()); ParameterAreaSizeBytes += typeWidthInBytesOnStack(Arg->getType());
} }
} }
......
...@@ -735,7 +735,8 @@ template <> struct MachineTraits<TargetX8632> { ...@@ -735,7 +735,8 @@ template <> struct MachineTraits<TargetX8632> {
uint16_t getShift() const { return Shift; } uint16_t getShift() const { return Shift; }
SegmentRegisters getSegmentRegister() const { return SegmentReg; } SegmentRegisters getSegmentRegister() const { return SegmentReg; }
void emitSegmentOverride(Assembler *Asm) const; void emitSegmentOverride(Assembler *Asm) const;
Address toAsmAddress(Assembler *Asm) const; Address toAsmAddress(Assembler *Asm,
const Ice::TargetLowering *Target) const;
void emit(const Cfg *Func) const override; void emit(const Cfg *Func) const override;
using X86Operand::dump; using X86Operand::dump;
...@@ -749,6 +750,9 @@ template <> struct MachineTraits<TargetX8632> { ...@@ -749,6 +750,9 @@ template <> struct MachineTraits<TargetX8632> {
bool getRandomized() const { return Randomized; } bool getRandomized() const { return Randomized; }
void setIgnoreStackAdjust(bool Ignore) { IgnoreStackAdjust = Ignore; }
bool getIgnoreStackAdjust() const { return IgnoreStackAdjust; }
private: private:
X86OperandMem(Cfg *Func, Type Ty, Variable *Base, Constant *Offset, X86OperandMem(Cfg *Func, Type Ty, Variable *Base, Constant *Offset,
Variable *Index, uint16_t Shift, SegmentRegisters SegmentReg); Variable *Index, uint16_t Shift, SegmentRegisters SegmentReg);
...@@ -762,6 +766,11 @@ template <> struct MachineTraits<TargetX8632> { ...@@ -762,6 +766,11 @@ template <> struct MachineTraits<TargetX8632> {
/// memory operands are generated in /// memory operands are generated in
/// TargetX86Base::randomizeOrPoolImmediate() /// TargetX86Base::randomizeOrPoolImmediate()
bool Randomized; bool Randomized;
/// Memory operations involving the stack pointer need to know when the
/// stack pointer was moved temporarily. Ignore that adjustment in
/// cases that should be pinned to the stack pointer, such as outgoing
/// arguments to calls.
bool IgnoreStackAdjust = false;
}; };
/// VariableSplit is a way to treat an f64 memory location as a pair of i32 /// VariableSplit is a way to treat an f64 memory location as a pair of i32
......
...@@ -717,7 +717,8 @@ template <> struct MachineTraits<TargetX8664> { ...@@ -717,7 +717,8 @@ template <> struct MachineTraits<TargetX8664> {
uint16_t getShift() const { return Shift; } uint16_t getShift() const { return Shift; }
SegmentRegisters getSegmentRegister() const { return DefaultSegment; } SegmentRegisters getSegmentRegister() const { return DefaultSegment; }
void emitSegmentOverride(Assembler *) const {} void emitSegmentOverride(Assembler *) const {}
Address toAsmAddress(Assembler *Asm) const; Address toAsmAddress(Assembler *Asm,
const Ice::TargetLowering *Target) const;
void emit(const Cfg *Func) const override; void emit(const Cfg *Func) const override;
using X86Operand::dump; using X86Operand::dump;
...@@ -731,6 +732,9 @@ template <> struct MachineTraits<TargetX8664> { ...@@ -731,6 +732,9 @@ template <> struct MachineTraits<TargetX8664> {
bool getRandomized() const { return Randomized; } bool getRandomized() const { return Randomized; }
void setIgnoreStackAdjust(bool Ignore) { IgnoreStackAdjust = Ignore; }
bool getIgnoreStackAdjust() const { return IgnoreStackAdjust; }
private: private:
X86OperandMem(Cfg *Func, Type Ty, Variable *Base, Constant *Offset, X86OperandMem(Cfg *Func, Type Ty, Variable *Base, Constant *Offset,
Variable *Index, uint16_t Shift); Variable *Index, uint16_t Shift);
...@@ -743,6 +747,11 @@ template <> struct MachineTraits<TargetX8664> { ...@@ -743,6 +747,11 @@ template <> struct MachineTraits<TargetX8664> {
/// memory operands are generated in /// memory operands are generated in
/// TargetX86Base::randomizeOrPoolImmediate() /// TargetX86Base::randomizeOrPoolImmediate()
bool Randomized = false; bool Randomized = false;
/// Memory operations involving the stack pointer need to know when the
/// stack pointer was moved temporarily. Ignore that adjustment in
/// cases that should be pinned to the stack pointer, such as outgoing
/// arguments to calls.
bool IgnoreStackAdjust = false;
}; };
/// VariableSplit is a way to treat an f64 memory location as a pair of i32 /// VariableSplit is a way to treat an f64 memory location as a pair of i32
......
...@@ -237,7 +237,8 @@ protected: ...@@ -237,7 +237,8 @@ protected:
Legal_Reg = 1 << 0, // physical register, not stack location Legal_Reg = 1 << 0, // physical register, not stack location
Legal_Imm = 1 << 1, Legal_Imm = 1 << 1,
Legal_Mem = 1 << 2, // includes [eax+4*ecx] as well as [esp+12] Legal_Mem = 1 << 2, // includes [eax+4*ecx] as well as [esp+12]
Legal_All = ~Legal_None Legal_Rematerializable = 1 << 3,
Legal_All = ~Legal_Rematerializable
}; };
using LegalMask = uint32_t; using LegalMask = uint32_t;
Operand *legalize(Operand *From, LegalMask Allowed = Legal_All, Operand *legalize(Operand *From, LegalMask Allowed = Legal_All,
......
...@@ -302,6 +302,11 @@ template <class Machine> void TargetX86Base<Machine>::staticInit() { ...@@ -302,6 +302,11 @@ template <class Machine> void TargetX86Base<Machine>::staticInit() {
template <class Machine> void TargetX86Base<Machine>::translateO2() { template <class Machine> void TargetX86Base<Machine>::translateO2() {
TimerMarker T(TimerStack::TT_O2, Func); TimerMarker T(TimerStack::TT_O2, Func);
// Merge Alloca instructions, and lay out the stack.
static constexpr bool SortAndCombineAllocas = true;
Func->processAllocas(SortAndCombineAllocas);
Func->dump("After Alloca processing");
if (!Ctx->getFlags().getPhiEdgeSplit()) { if (!Ctx->getFlags().getPhiEdgeSplit()) {
// Lower Phi instructions. // Lower Phi instructions.
Func->placePhiLoads(); Func->placePhiLoads();
...@@ -420,6 +425,11 @@ template <class Machine> void TargetX86Base<Machine>::translateO2() { ...@@ -420,6 +425,11 @@ template <class Machine> void TargetX86Base<Machine>::translateO2() {
template <class Machine> void TargetX86Base<Machine>::translateOm1() { template <class Machine> void TargetX86Base<Machine>::translateOm1() {
TimerMarker T(TimerStack::TT_Om1, Func); TimerMarker T(TimerStack::TT_Om1, Func);
// Do not merge Alloca instructions, and lay out the stack.
static constexpr bool SortAndCombineAllocas = false;
Func->processAllocas(SortAndCombineAllocas);
Func->dump("After Alloca processing");
Func->placePhiLoads(); Func->placePhiLoads();
if (Func->hasError()) if (Func->hasError())
return; return;
...@@ -945,7 +955,7 @@ TargetX86Base<Machine>::getRegisterSet(RegSetMask Include, ...@@ -945,7 +955,7 @@ TargetX86Base<Machine>::getRegisterSet(RegSetMask Include,
template <class Machine> template <class Machine>
void TargetX86Base<Machine>::lowerAlloca(const InstAlloca *Inst) { void TargetX86Base<Machine>::lowerAlloca(const InstAlloca *Inst) {
if (!Inst->getKnownFrameOffset()) if (!Inst->getKnownFrameOffset())
IsEbpBasedFrame = true; setHasFramePointer();
// Conservatively require the stack to be aligned. Some stack adjustment // Conservatively require the stack to be aligned. Some stack adjustment
// operations implemented below assume that the stack is aligned before the // operations implemented below assume that the stack is aligned before the
// alloca. All the alloca code ensures that the stack alignment is preserved // alloca. All the alloca code ensures that the stack alignment is preserved
...@@ -969,6 +979,7 @@ void TargetX86Base<Machine>::lowerAlloca(const InstAlloca *Inst) { ...@@ -969,6 +979,7 @@ void TargetX86Base<Machine>::lowerAlloca(const InstAlloca *Inst) {
uint32_t Alignment = uint32_t Alignment =
std::max(AlignmentParam, Traits::X86_STACK_ALIGNMENT_BYTES); std::max(AlignmentParam, Traits::X86_STACK_ALIGNMENT_BYTES);
if (Alignment > Traits::X86_STACK_ALIGNMENT_BYTES) { if (Alignment > Traits::X86_STACK_ALIGNMENT_BYTES) {
setHasFramePointer();
_and(esp, Ctx->getConstantInt32(-Alignment)); _and(esp, Ctx->getConstantInt32(-Alignment));
} }
if (const auto *ConstantTotalSize = if (const auto *ConstantTotalSize =
...@@ -5500,10 +5511,12 @@ Operand *TargetX86Base<Machine>::legalize(Operand *From, LegalMask Allowed, ...@@ -5500,10 +5511,12 @@ Operand *TargetX86Base<Machine>::legalize(Operand *From, LegalMask Allowed,
Variable *RegBase = nullptr; Variable *RegBase = nullptr;
Variable *RegIndex = nullptr; Variable *RegIndex = nullptr;
if (Base) { if (Base) {
RegBase = legalizeToReg(Base); RegBase = llvm::cast<Variable>(
legalize(Base, Legal_Reg | Legal_Rematerializable));
} }
if (Index) { if (Index) {
RegIndex = legalizeToReg(Index); RegIndex = llvm::cast<Variable>(
legalize(Index, Legal_Reg | Legal_Rematerializable));
} }
if (Base != RegBase || Index != RegIndex) { if (Base != RegBase || Index != RegIndex) {
Mem = Traits::X86OperandMem::create(Func, Ty, RegBase, Mem->getOffset(), Mem = Traits::X86OperandMem::create(Func, Ty, RegBase, Mem->getOffset(),
...@@ -5575,12 +5588,25 @@ Operand *TargetX86Base<Machine>::legalize(Operand *From, LegalMask Allowed, ...@@ -5575,12 +5588,25 @@ Operand *TargetX86Base<Machine>::legalize(Operand *From, LegalMask Allowed,
// either when the variable is pre-colored or when it is assigned infinite // either when the variable is pre-colored or when it is assigned infinite
// weight. // weight.
bool MustHaveRegister = (Var->hasReg() || Var->mustHaveReg()); bool MustHaveRegister = (Var->hasReg() || Var->mustHaveReg());
bool MustRematerialize =
(Var->isRematerializable() && !(Allowed & Legal_Rematerializable));
// We need a new physical register for the operand if: // We need a new physical register for the operand if:
// Mem is not allowed and Var isn't guaranteed a physical // - Mem is not allowed and Var isn't guaranteed a physical register, or
// register, or // - RegNum is required and Var->getRegNum() doesn't match, or
// RegNum is required and Var->getRegNum() doesn't match. // - Var is a rematerializable variable and rematerializable pass-through is
if ((!(Allowed & Legal_Mem) && !MustHaveRegister) || // not allowed (in which case we need an lea instruction).
(RegNum != Variable::NoRegister && RegNum != Var->getRegNum())) { if (MustRematerialize) {
assert(Ty == IceType_i32);
Variable *NewVar = makeReg(Ty, RegNum);
// Since Var is rematerializable, the offset will be added when the lea is
// emitted.
constexpr Constant *NoOffset = nullptr;
auto *Mem = Traits::X86OperandMem::create(Func, Ty, Var, NoOffset);
_lea(NewVar, Mem);
From = NewVar;
} else if ((!(Allowed & Legal_Mem) && !MustHaveRegister) ||
(RegNum != Variable::NoRegister && RegNum != Var->getRegNum()) ||
MustRematerialize) {
From = copyToReg(From, RegNum); From = copyToReg(From, RegNum);
} }
return From; return From;
......
; This is a basic test of the alloca instruction and a call.
; RUN: %if --need=target_X8632 --command %p2i --filetype=obj --disassemble \
; RUN: --target x8632 -i %s --args -O2 -allow-externally-defined-symbols \
; RUN: | %if --need=target_X8632 --command FileCheck %s
declare void @copy(i32 %arg1, i8* %arr1, i8* %arr2, i8* %arr3, i8* %arr4);
; Test that alloca base addresses get passed correctly to functions.
define internal void @caller1(i32 %arg) {
entry:
%a1 = alloca i8, i32 32, align 4
%p1 = bitcast i8* %a1 to i32*
store i32 %arg, i32* %p1, align 1
call void @copy(i32 %arg, i8* %a1, i8* %a1, i8* %a1, i8* %a1)
ret void
}
; CHECK-LABEL: caller1
; CHECK-NEXT: sub esp,0xc
; CHECK-NEXT: mov eax,DWORD PTR [esp+0x10]
; CHECK-NEXT: sub esp,0x20
; CHECK-NEXT: mov ecx,esp
; CHECK-NEXT: mov DWORD PTR [esp],eax
; CHECK-NEXT: sub esp,0x20
; CHECK-NEXT: mov DWORD PTR [esp],eax
; CHECK-NEXT: lea eax,[esp+0x20]
; CHECK-NEXT: mov DWORD PTR [esp+0x4],eax
; CHECK-NEXT: lea eax,[esp+0x20]
; CHECK-NEXT: mov DWORD PTR [esp+0x8],eax
; CHECK-NEXT: lea eax,[esp+0x20]
; CHECK-NEXT: mov DWORD PTR [esp+0xc],eax
; CHECK-NEXT: lea eax,[esp+0x20]
; CHECK-NEXT: mov DWORD PTR [esp+0x10],eax
; CHECK-NEXT: call
; CHECK-NEXT: add esp,0x20
; CHECK-NEXT: add esp,0x2c
; CHECK-NEXT: ret
; Test that alloca base addresses get passed correctly to functions.
define internal void @caller2(i32 %arg) {
entry:
%a1 = alloca i8, i32 32, align 4
%a2 = alloca i8, i32 32, align 4
%p1 = bitcast i8* %a1 to i32*
%p2 = bitcast i8* %a2 to i32*
store i32 %arg, i32* %p1, align 1
store i32 %arg, i32* %p2, align 1
call void @copy(i32 %arg, i8* %a1, i8* %a2, i8* %a1, i8* %a2)
ret void
}
; CHECK-LABEL: caller2
; CHECK-NEXT: sub esp,0xc
; CHECK-NEXT: mov eax,DWORD PTR [esp+0x10]
; CHECK-NEXT: sub esp,0x40
; CHECK-NEXT: mov ecx,esp
; CHECK-NEXT: mov DWORD PTR [esp],eax
; CHECK-NEXT: mov DWORD PTR [esp+0x20],eax
; CHECK-NEXT: sub esp,0x20
; CHECK-NEXT: mov DWORD PTR [esp],eax
; CHECK-NEXT: lea eax,[esp+0x20]
; CHECK-NEXT: mov DWORD PTR [esp+0x4],eax
; CHECK-NEXT: lea eax,[esp+0x40]
; CHECK-NEXT: mov DWORD PTR [esp+0x8],eax
; CHECK-NEXT: lea eax,[esp+0x20]
; CHECK-NEXT: mov DWORD PTR [esp+0xc],eax
; CHECK-NEXT: lea eax,[esp+0x40]
; CHECK-NEXT: mov DWORD PTR [esp+0x10],eax
; CHECK-NEXT: call
; CHECK-NEXT: add esp,0x20
; CHECK-NEXT: add esp,0x4c
; CHECK-NEXT: ret
; This is a basic test of the alloca instruction.
; RUN: %if --need=target_X8632 --command %p2i --filetype=obj --disassemble \
; RUN: --target x8632 -i %s --args -O2 -allow-externally-defined-symbols \
; RUN: | %if --need=target_X8632 --command FileCheck %s
; Test that a sequence of allocas with less than stack alignment get fused.
define internal void @fused_small_align(i32 %arg) {
entry:
%a1 = alloca i8, i32 8, align 4
%a2 = alloca i8, i32 12, align 4
%a3 = alloca i8, i32 16, align 8
%p1 = bitcast i8* %a1 to i32*
%p2 = bitcast i8* %a2 to i32*
%p3 = bitcast i8* %a3 to i32*
store i32 %arg, i32* %p1, align 1
store i32 %arg, i32* %p2, align 1
store i32 %arg, i32* %p3, align 1
ret void
}
; CHECK-LABEL: fused_small_align
; CHECK-NEXT: sub esp,0xc
; CHECK-NEXT: mov eax,DWORD PTR [esp+0x10]
; CHECK-NEXT: sub esp,0x30
; CHECK-NEXT: mov {{.*}},esp
; CHECK-NEXT: mov DWORD PTR [esp+0x10],eax
; CHECK-NEXT: mov DWORD PTR [esp+0x18],eax
; CHECK-NEXT: mov DWORD PTR [esp],eax
; CHECK-NEXT: add esp,0x3c
; Test that a sequence of allocas with greater than stack alignment get fused.
define internal void @fused_large_align(i32 %arg) {
entry:
%a1 = alloca i8, i32 8, align 32
%a2 = alloca i8, i32 12, align 64
%a3 = alloca i8, i32 16, align 32
%p1 = bitcast i8* %a1 to i32*
%p2 = bitcast i8* %a2 to i32*
%p3 = bitcast i8* %a3 to i32*
store i32 %arg, i32* %p1, align 1
store i32 %arg, i32* %p2, align 1
store i32 %arg, i32* %p3, align 1
ret void
}
; CHECK-LABEL: fused_large_align
; CHECK-NEXT: push ebp
; CHECK-NEXT: mov ebp,esp
; CHECK-NEXT: sub esp,0x8
; CHECK-NEXT: mov eax,DWORD PTR [ebp+0x8]
; CHECK-NEXT: and esp,0xffffffc0
; CHECK-NEXT: sub esp,0x80
; CHECK-NEXT: mov ecx,esp
; CHECK-NEXT: mov DWORD PTR [esp+0x40],eax
; CHECK-NEXT: mov DWORD PTR [esp],eax
; CHECK-NEXT: mov DWORD PTR [esp+0x60],eax
; CHECK-NEXT: mov esp,ebp
; CHECK-NEXT: pop ebp
...@@ -40,7 +40,6 @@ entry: ...@@ -40,7 +40,6 @@ entry:
} }
; CHECK-LABEL: test_fused_load_sub_a ; CHECK-LABEL: test_fused_load_sub_a
; alloca store ; alloca store
; CHECK: mov {{.*}},esp
; CHECK: mov DWORD PTR {{.*}},0x3e7 ; CHECK: mov DWORD PTR {{.*}},0x3e7
; atomic store (w/ its own mfence) ; atomic store (w/ its own mfence)
; The load + sub are optimized into one everywhere. ; The load + sub are optimized into one everywhere.
...@@ -80,7 +79,6 @@ entry: ...@@ -80,7 +79,6 @@ entry:
} }
; CHECK-LABEL: test_fused_load_sub_b ; CHECK-LABEL: test_fused_load_sub_b
; alloca store ; alloca store
; CHECK: mov {{.*}},esp
; CHECK: mov DWORD PTR {{.*}},0x3e7 ; CHECK: mov DWORD PTR {{.*}},0x3e7
; atomic store (w/ its own mfence) ; atomic store (w/ its own mfence)
; CHECK: sub {{.*}},DWORD PTR {{.*}}g32_a ; CHECK: sub {{.*}},DWORD PTR {{.*}}g32_a
...@@ -121,7 +119,6 @@ entry: ...@@ -121,7 +119,6 @@ entry:
} }
; CHECK-LABEL: test_fused_load_sub_c ; CHECK-LABEL: test_fused_load_sub_c
; alloca store ; alloca store
; CHECK: mov {{.*}},esp
; CHECK: mov DWORD PTR {{.*}},0x3e7 ; CHECK: mov DWORD PTR {{.*}},0x3e7
; atomic store (w/ its own mfence) ; atomic store (w/ its own mfence)
; CHECK: sub {{.*}},DWORD PTR {{.*}}g32_a ; CHECK: sub {{.*}},DWORD PTR {{.*}}g32_a
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment