aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Lattner <sabre@nondot.org>2008-03-11 19:50:13 +0000
committerChris Lattner <sabre@nondot.org>2008-03-11 19:50:13 +0000
commite12ecf272d90c366e15531c15b6681ab5399ba33 (patch)
tree41d938da8b2d0eb3f624bf5463e1cc456c97e258
parent1d38677e34f67961bbff40a5fed96f96ebfea836 (diff)
Implement basic support for the 'f' register class constraint. This basically
works, but probably won't if you mix it with 't' or 'u' yet. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@48243 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/Target/X86/X86FloatingPoint.cpp47
-rw-r--r--test/CodeGen/X86/inline-asm-fpstack.ll14
2 files changed, 59 insertions, 2 deletions
diff --git a/lib/Target/X86/X86FloatingPoint.cpp b/lib/Target/X86/X86FloatingPoint.cpp
index 18e0f909c3..ca965375f2 100644
--- a/lib/Target/X86/X86FloatingPoint.cpp
+++ b/lib/Target/X86/X86FloatingPoint.cpp
@@ -214,7 +214,12 @@ bool FPS::processBasicBlock(MachineFunction &MF, MachineBasicBlock &BB) {
for (MachineBasicBlock::iterator I = BB.begin(); I != BB.end(); ++I) {
MachineInstr *MI = I;
unsigned Flags = MI->getDesc().TSFlags;
- if ((Flags & X86II::FPTypeMask) == X86II::NotFP)
+
+ unsigned FPInstClass = Flags & X86II::FPTypeMask;
+ if (MI->getOpcode() == TargetInstrInfo::INLINEASM)
+ FPInstClass = X86II::SpecialFP;
+
+ if (FPInstClass == X86II::NotFP)
continue; // Efficiently ignore non-fp insts!
MachineInstr *PrevMI = 0;
@@ -233,7 +238,7 @@ bool FPS::processBasicBlock(MachineFunction &MF, MachineBasicBlock &BB) {
DeadRegs.push_back(MO.getReg());
}
- switch (Flags & X86II::FPTypeMask) {
+ switch (FPInstClass) {
case X86II::ZeroArgFP: handleZeroArgFP(I); break;
case X86II::OneArgFP: handleOneArgFP(I); break; // fstp ST(0)
case X86II::OneArgFPRW: handleOneArgFPRW(I); break; // ST(0) = fsqrt(ST(0))
@@ -966,6 +971,44 @@ void FPS::handleSpecialFP(MachineBasicBlock::iterator &I) {
}
}
break;
+ case TargetInstrInfo::INLINEASM: {
+ // The inline asm MachineInstr currently only *uses* FP registers for the
+ // 'f' constraint. These should be turned into the current ST(x) register
+ // in the machine instr. Also, any kills should be explicitly popped after
+ // the inline asm.
+ unsigned Kills[7];
+ unsigned NumKills = 0;
+ for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
+ MachineOperand &Op = MI->getOperand(i);
+ if (!Op.isReg() || Op.getReg() < X86::FP0 || Op.getReg() > X86::FP6)
+ continue;
+ assert(Op.isUse() && "Only handle inline asm uses right now");
+
+ unsigned FPReg = getFPReg(Op);
+ Op.setReg(getSTReg(FPReg));
+
+ // If we kill this operand, make sure to pop it from the stack after the
+ // asm. We just remember it for now, and pop them all off at the end in
+ // a batch.
+ if (Op.isKill())
+ Kills[NumKills++] = FPReg;
+ }
+
+ // If this asm kills any FP registers (is the last use of them) we must
+ // explicitly emit pop instructions for them. Do this now after the asm has
+ // executed so that the ST(x) numbers are not off (which would happen if we
+ // did this inline with operand rewriting).
+ //
+ // Note: this might be a non-optimal pop sequence. We might be able to do
+ // better by trying to pop in stack order or something.
+ MachineBasicBlock::iterator InsertPt = MI;
+ while (NumKills)
+ freeStackSlotAfter(InsertPt, Kills[--NumKills]);
+
+ // Don't delete the inline asm!
+ return;
+ }
+
case X86::RET:
case X86::RETI:
// If RET has an FP register use operand, pass the first one in ST(0) and
diff --git a/test/CodeGen/X86/inline-asm-fpstack.ll b/test/CodeGen/X86/inline-asm-fpstack.ll
index 1e308d9b78..91f2f2fb93 100644
--- a/test/CodeGen/X86/inline-asm-fpstack.ll
+++ b/test/CodeGen/X86/inline-asm-fpstack.ll
@@ -26,4 +26,18 @@ define void @test5(double %X) {
ret void
}
+define void @test6(double %A, double %B, double %C,
+ double %D, double %E) nounwind {
+entry:
+ ; Uses the same value twice, should have one fstp after the asm.
+ tail call void asm sideeffect "foo $0 $1", "f,f,~{dirflag},~{fpsr},~{flags}"( double %A, double %A ) nounwind
+ ; Uses two different values, should be in st(0)/st(1) and both be popped.
+ tail call void asm sideeffect "bar $0 $1", "f,f,~{dirflag},~{fpsr},~{flags}"( double %B, double %C ) nounwind
+ ; Uses two different values, one of which isn't killed in this asm, it
+ ; should not be popped after the asm.
+ tail call void asm sideeffect "baz $0 $1", "f,f,~{dirflag},~{fpsr},~{flags}"( double %D, double %E ) nounwind
+ ; This is the last use of %D, so it should be popped after.
+ tail call void asm sideeffect "baz $0", "f,~{dirflag},~{fpsr},~{flags}"( double %D ) nounwind
+ ret void
+}