Fix some serious floating-point bugs (fixes test cases such as Oscar,
authorBrian Gaeke <gaeke@uiuc.edu>
Fri, 11 Jul 2003 18:18:35 +0000 (18:18 +0000)
committerBrian Gaeke <gaeke@uiuc.edu>
Fri, 11 Jul 2003 18:18:35 +0000 (18:18 +0000)
Fhourstones, McCat-vor, and many others...)

Printer.cpp: Print implicit uses for AddRegFrm instructions.  Break gas
bug workarounds up into separate stanzas of code for each bug.  Add new
workarounds for fild and fistp.

X86InstrInfo.def: Add O_ST0 implicit uses for more FP instrs where they
obviously apply. Also add PrintImplUses flags for FP instrs where they
are necessary for gas to understand the output.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@7165 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Target/X86/Printer.cpp
lib/Target/X86/X86AsmPrinter.cpp
lib/Target/X86/X86InstrInfo.def

index 74820c8690ddc2437af891874fc4e379374f3ceb..164ff0d08b874126d8ea3024b87ef4d0698a6433 100644 (file)
@@ -665,6 +665,11 @@ void Printer::printMachineInstruction(const MachineInstr *MI, std::ostream &O,
       O << ", ";
       printOp(O, MI->getOperand(1), RI);
     }
+    if (Desc.TSFlags & X86II::PrintImplUses) {
+      for (const unsigned *p = Desc.ImplicitUses; *p; ++p) {
+       O << ", " << RI.get(*p).Name;
+      }
+    }
     O << "\n";
     return;
   }
@@ -819,7 +824,10 @@ void Printer::printMachineInstruction(const MachineInstr *MI, std::ostream &O,
            isMem(MI, 0) && "Bad MRMSxM format!");
     assert((MI->getNumOperands() != 5 || MI->getOperand(4).isImmediate()) &&
            "Bad MRMSxM format!");
-    // Work around GNU assembler bugs in FSTP and FLD.
+    // Bug: The 80-bit FP store-pop instruction "fstp XWORD PTR [...]"
+    // is misassembled by gas in intel_syntax mode as its 32-bit
+    // equivalent "fstp DWORD PTR [...]". Workaround: Output the raw
+    // opcode bytes instead of the instruction.
     if (MI->getOpCode() == X86::FSTPr80) {
       if ((MI->getOperand(0).getReg() == X86::ESP)
          && (MI->getOperand(1).getImmedValue() == 1)) {
@@ -834,7 +842,12 @@ void Printer::printMachineInstruction(const MachineInstr *MI, std::ostream &O,
             << std::dec << "\t# ";
        }
       }
-    } else if (MI->getOpCode() == X86::FLDr80) {
+    }
+    // Bug: The 80-bit FP load instruction "fld XWORD PTR [...]" is
+    // misassembled by gas in intel_syntax mode as its 32-bit
+    // equivalent "fld DWORD PTR [...]". Workaround: Output the raw
+    // opcode bytes instead of the instruction.
+    if (MI->getOpCode() == X86::FLDr80) {
       if ((MI->getOperand(0).getReg() == X86::ESP)
           && (MI->getOperand(1).getImmedValue() == 1)) {
        int DispVal = MI->getOperand(3).getImmedValue();
@@ -849,6 +862,42 @@ void Printer::printMachineInstruction(const MachineInstr *MI, std::ostream &O,
        }
       }
     }
+    // Bug: gas intel_syntax mode treats "fild QWORD PTR [...]" as an
+    // invalid opcode, saying "64 bit operations are only supported in
+    // 64 bit modes." libopcodes disassembles it as "fild DWORD PTR
+    // [...]", which is wrong. Workaround: Output the raw opcode bytes
+    // instead of the instruction.
+    if (MI->getOpCode() == X86::FILDr64) {
+      if ((MI->getOperand(0).getReg() == X86::ESP)
+          && (MI->getOperand(1).getImmedValue() == 1)) {
+       int DispVal = MI->getOperand(3).getImmedValue();
+       if ((DispVal < -128) || (DispVal > 127)) { // 4 byte disp.
+          unsigned int val = (unsigned int) DispVal;
+          O << ".byte 0xdf, 0xac, 0x24\n\t";
+          O << ".long 0x" << std::hex << (unsigned) val << std::dec << "\t# ";
+       } else { // 1 byte disp.
+          unsigned char val = (unsigned char) DispVal;
+          O << ".byte 0xdf, 0x6c, 0x24, 0x" << std::hex << (unsigned) val
+            << std::dec << "\t# ";
+       }
+      }
+    }
+    // Bug: gas intel_syntax mode treats "fistp QWORD PTR [...]" as
+    // an invalid opcode, saying "64 bit operations are only
+    // supported in 64 bit modes." libopcodes disassembles it as
+    // "fistpll DWORD PTR [...]", which is wrong. Workaround: Output
+    // "fistpll DWORD PTR " instead, which is what libopcodes is
+    // expecting to see.
+    if (MI->getOpCode() == X86::FISTPr64) {
+      O << "fistpll DWORD PTR ";
+      printMemReference(O, MI, 0, RI);
+      if (MI->getNumOperands() == 5) {
+       O << ", ";
+       printOp(O, MI->getOperand(4), RI);
+      }
+      O << "\t# ";
+    }
+    
     O << TII.getName(MI->getOpCode()) << " ";
     O << sizePtr(Desc) << " ";
     printMemReference(O, MI, 0, RI);
index 74820c8690ddc2437af891874fc4e379374f3ceb..164ff0d08b874126d8ea3024b87ef4d0698a6433 100644 (file)
@@ -665,6 +665,11 @@ void Printer::printMachineInstruction(const MachineInstr *MI, std::ostream &O,
       O << ", ";
       printOp(O, MI->getOperand(1), RI);
     }
+    if (Desc.TSFlags & X86II::PrintImplUses) {
+      for (const unsigned *p = Desc.ImplicitUses; *p; ++p) {
+       O << ", " << RI.get(*p).Name;
+      }
+    }
     O << "\n";
     return;
   }
@@ -819,7 +824,10 @@ void Printer::printMachineInstruction(const MachineInstr *MI, std::ostream &O,
            isMem(MI, 0) && "Bad MRMSxM format!");
     assert((MI->getNumOperands() != 5 || MI->getOperand(4).isImmediate()) &&
            "Bad MRMSxM format!");
-    // Work around GNU assembler bugs in FSTP and FLD.
+    // Bug: The 80-bit FP store-pop instruction "fstp XWORD PTR [...]"
+    // is misassembled by gas in intel_syntax mode as its 32-bit
+    // equivalent "fstp DWORD PTR [...]". Workaround: Output the raw
+    // opcode bytes instead of the instruction.
     if (MI->getOpCode() == X86::FSTPr80) {
       if ((MI->getOperand(0).getReg() == X86::ESP)
          && (MI->getOperand(1).getImmedValue() == 1)) {
@@ -834,7 +842,12 @@ void Printer::printMachineInstruction(const MachineInstr *MI, std::ostream &O,
             << std::dec << "\t# ";
        }
       }
-    } else if (MI->getOpCode() == X86::FLDr80) {
+    }
+    // Bug: The 80-bit FP load instruction "fld XWORD PTR [...]" is
+    // misassembled by gas in intel_syntax mode as its 32-bit
+    // equivalent "fld DWORD PTR [...]". Workaround: Output the raw
+    // opcode bytes instead of the instruction.
+    if (MI->getOpCode() == X86::FLDr80) {
       if ((MI->getOperand(0).getReg() == X86::ESP)
           && (MI->getOperand(1).getImmedValue() == 1)) {
        int DispVal = MI->getOperand(3).getImmedValue();
@@ -849,6 +862,42 @@ void Printer::printMachineInstruction(const MachineInstr *MI, std::ostream &O,
        }
       }
     }
+    // Bug: gas intel_syntax mode treats "fild QWORD PTR [...]" as an
+    // invalid opcode, saying "64 bit operations are only supported in
+    // 64 bit modes." libopcodes disassembles it as "fild DWORD PTR
+    // [...]", which is wrong. Workaround: Output the raw opcode bytes
+    // instead of the instruction.
+    if (MI->getOpCode() == X86::FILDr64) {
+      if ((MI->getOperand(0).getReg() == X86::ESP)
+          && (MI->getOperand(1).getImmedValue() == 1)) {
+       int DispVal = MI->getOperand(3).getImmedValue();
+       if ((DispVal < -128) || (DispVal > 127)) { // 4 byte disp.
+          unsigned int val = (unsigned int) DispVal;
+          O << ".byte 0xdf, 0xac, 0x24\n\t";
+          O << ".long 0x" << std::hex << (unsigned) val << std::dec << "\t# ";
+       } else { // 1 byte disp.
+          unsigned char val = (unsigned char) DispVal;
+          O << ".byte 0xdf, 0x6c, 0x24, 0x" << std::hex << (unsigned) val
+            << std::dec << "\t# ";
+       }
+      }
+    }
+    // Bug: gas intel_syntax mode treats "fistp QWORD PTR [...]" as
+    // an invalid opcode, saying "64 bit operations are only
+    // supported in 64 bit modes." libopcodes disassembles it as
+    // "fistpll DWORD PTR [...]", which is wrong. Workaround: Output
+    // "fistpll DWORD PTR " instead, which is what libopcodes is
+    // expecting to see.
+    if (MI->getOpCode() == X86::FISTPr64) {
+      O << "fistpll DWORD PTR ";
+      printMemReference(O, MI, 0, RI);
+      if (MI->getNumOperands() == 5) {
+       O << ", ";
+       printOp(O, MI->getOperand(4), RI);
+      }
+      O << "\t# ";
+    }
+    
     O << TII.getName(MI->getOpCode()) << " ";
     O << sizePtr(Desc) << " ";
     printMemReference(O, MI, 0, RI);
index 242b59d343cae29d41aa867bcab97bf1e4354055..bb24074ded29723aa2628a5abdb27640db08112f 100644 (file)
@@ -318,14 +318,14 @@ I(FSTr64      , "fst",   0xDD,            0,             X86II::Void | X86II::Ar
 I(FSTPr32     , "fstp",  0xD9,            0,             X86II::Void | X86II::ArgF32 | X86II::MRMS3m                   , NoIR, NoIR)   // store float, pop
 I(FSTPr64     , "fstp",  0xDD,            0,             X86II::Void | X86II::ArgF64 | X86II::MRMS3m                   , NoIR, NoIR)   // store double, pop
 I(FSTPr80     , "fstp",  0xDB,            0,             X86II::Void | X86II::ArgF80 | X86II::MRMS7m | X86II::OneArgFP , NoIR, NoIR)   // store extended, pop
-I(FSTrr       , "fst"  ,   0xD0,            0, X86II::DD | X86II::Void | X86II::ArgF80 | X86II::AddRegFrm                , NoIR, NoIR)   // ST(i) = ST(0)
-I(FSTPrr      , "fstp" ,   0xD8,            0, X86II::DD | X86II::Void | X86II::ArgF80 | X86II::AddRegFrm                , NoIR, NoIR)   // ST(i) = ST(0), pop
+I(FSTrr       , "fst"  ,   0xD0,            0, X86II::DD | X86II::Void | X86II::ArgF80 | X86II::AddRegFrm                , O_ST0, NoIR)   // ST(i) = ST(0)
+I(FSTPrr      , "fstp" ,   0xD8,            0, X86II::DD | X86II::Void | X86II::ArgF80 | X86II::AddRegFrm                , O_ST0, NoIR)   // ST(i) = ST(0), pop
 
 I(FISTr16     , "fist",  0xDF,            0,             X86II::Void | X86II::Arg16  | X86II::MRMS2m | X86II::OneArgFP , NoIR, NoIR)   // store signed short
 I(FISTr32     , "fist",  0xDB,            0,             X86II::Void | X86II::Arg32  | X86II::MRMS2m | X86II::OneArgFP , NoIR, NoIR)   // store signed int
 I(FISTPr16    , "fistp", 0xDF,            0,             X86II::Void | X86II::Arg16  | X86II::MRMS3m                   , NoIR, NoIR)   // store short, pop
 I(FISTPr32    , "fistp", 0xDB,            0,             X86II::Void | X86II::Arg32  | X86II::MRMS3m                   , NoIR, NoIR)   // store int, pop
-I(FISTPr64    , "fistp", 0xDF,            0,             X86II::Void | X86II::Arg64  | X86II::MRMS7m | X86II::OneArgFP , NoIR, NoIR)   // store long, pop
+I(FISTPr64    , "fistpll", 0xDF,          0,             X86II::Void | X86II::Arg64  | X86II::MRMS7m | X86II::OneArgFP , NoIR, NoIR)   // store long, pop
 
 
 I(FXCH        , "fxch" , 0xC8,              0, X86II::D9 | X86II::Void | X86II::ArgF80 | X86II::AddRegFrm                , O_ST0, O_ST0) // fxch ST(i), ST(0)
@@ -335,34 +335,34 @@ I(FLD0        , "fldz" , 0xEE,              0, X86II::D9 |               X86II::
 I(FLD1        , "fld1" , 0xE8,              0, X86II::D9 |               X86II::ArgF80 | X86II::RawFrm | X86II::ZeroArgFP, NoIR, NoIR)   // load +1.0
 
 // Binary arithmetic operations...
-I(FADDST0r    , "fadd",   0xC0,           0, X86II::D8 |               X86II::ArgF80 | X86II::AddRegFrm               , NoIR, NoIR)   // ST(0) = ST(0) + ST(i)
-I(FADDrST0    , "fadd",   0xC0,           0, X86II::DC |               X86II::ArgF80 | X86II::AddRegFrm               , NoIR, NoIR)   // ST(i) = ST(i) + ST(0)
-I(FADDPrST0   , "faddp",  0xC0,           0, X86II::DE |               X86II::ArgF80 | X86II::AddRegFrm               , NoIR, NoIR)   // ST(i) = ST(i) + ST(0), pop
+I(FADDST0r    , "fadd",   0xC0,           0, X86II::D8 |               X86II::ArgF80 | X86II::AddRegFrm               , O_ST0, O_ST0)   // ST(0) = ST(0) + ST(i)
+I(FADDrST0    , "fadd",   0xC0,           0, X86II::DC |               X86II::ArgF80 | X86II::AddRegFrm | X86II::PrintImplUses, O_ST0, NoIR)   // ST(i) = ST(i) + ST(0)
+I(FADDPrST0   , "faddp",  0xC0,           0, X86II::DE |               X86II::ArgF80 | X86II::AddRegFrm               , O_ST0, NoIR)    // ST(i) = ST(i) + ST(0), pop
 
-I(FSUBRST0r   , "fsubr" , 0xE8,           0, X86II::D8 |               X86II::ArgF80 | X86II::AddRegFrm               , NoIR, NoIR)   // ST(0) = ST(i) - ST(0)
-I(FSUBrST0    , "fsub"  , 0xE8,           0, X86II::DC |               X86II::ArgF80 | X86II::AddRegFrm               , NoIR, NoIR)   // ST(i) = ST(i) - ST(0)
-I(FSUBPrST0   , "fsubp" , 0xE8,           0, X86II::DE |               X86II::ArgF80 | X86II::AddRegFrm               , NoIR, NoIR)   // ST(i) = ST(i) - ST(0), pop
+I(FSUBRST0r   , "fsubr" , 0xE8,           0, X86II::D8 |               X86II::ArgF80 | X86II::AddRegFrm               , O_ST0, O_ST0)   // ST(0) = ST(i) - ST(0)
+I(FSUBrST0    , "fsub"  , 0xE8,           0, X86II::DC |               X86II::ArgF80 | X86II::AddRegFrm | X86II::PrintImplUses, O_ST0, NoIR)   // ST(i) = ST(i) - ST(0)
+I(FSUBPrST0   , "fsubp" , 0xE8,           0, X86II::DE |               X86II::ArgF80 | X86II::AddRegFrm               , O_ST0, NoIR)    // ST(i) = ST(i) - ST(0), pop
 
-I(FSUBST0r    , "fsub"  , 0xE0,           0, X86II::D8 |               X86II::ArgF80 | X86II::AddRegFrm               , NoIR, NoIR)   // ST(0) = ST(0) - ST(i)
-I(FSUBRrST0   , "fsubr" , 0xE0,           0, X86II::DC |               X86II::ArgF80 | X86II::AddRegFrm               , NoIR, NoIR)   // ST(i) = ST(0) - ST(i)
-I(FSUBRPrST0  , "fsubrp", 0xE0,           0, X86II::DE |               X86II::ArgF80 | X86II::AddRegFrm               , NoIR, NoIR)   // ST(i) = ST(0) - ST(i), pop
+I(FSUBST0r    , "fsub"  , 0xE0,           0, X86II::D8 |               X86II::ArgF80 | X86II::AddRegFrm               , O_ST0, O_ST0)   // ST(0) = ST(0) - ST(i)
+I(FSUBRrST0   , "fsubr" , 0xE0,           0, X86II::DC |               X86II::ArgF80 | X86II::AddRegFrm | X86II::PrintImplUses, O_ST0, NoIR)   // ST(i) = ST(0) - ST(i)
+I(FSUBRPrST0  , "fsubrp", 0xE0,           0, X86II::DE |               X86II::ArgF80 | X86II::AddRegFrm               , O_ST0, NoIR)    // ST(i) = ST(0) - ST(i), pop
 
-I(FMULST0r    , "fmul",   0xC8,           0, X86II::D8 |               X86II::ArgF80 | X86II::AddRegFrm               , NoIR, NoIR)   // ST(0) = ST(0) * ST(i)
-I(FMULrST0    , "fmul",   0xC8,           0, X86II::DC |               X86II::ArgF80 | X86II::AddRegFrm               , NoIR, NoIR)   // ST(i) = ST(i) * ST(0)
-I(FMULPrST0   , "fmulp",  0xC8,           0, X86II::DE |               X86II::ArgF80 | X86II::AddRegFrm               , NoIR, NoIR)   // ST(i) = ST(i) * ST(0), pop
+I(FMULST0r    , "fmul",   0xC8,           0, X86II::D8 |               X86II::ArgF80 | X86II::AddRegFrm               , O_ST0, O_ST0)   // ST(0) = ST(0) * ST(i)
+I(FMULrST0    , "fmul",   0xC8,           0, X86II::DC |               X86II::ArgF80 | X86II::AddRegFrm | X86II::PrintImplUses, O_ST0, NoIR)   // ST(i) = ST(i) * ST(0)
+I(FMULPrST0   , "fmulp",  0xC8,           0, X86II::DE |               X86II::ArgF80 | X86II::AddRegFrm               , O_ST0, NoIR)    // ST(i) = ST(i) * ST(0), pop
 
-I(FDIVRST0r   , "fdivr" , 0xF8,           0, X86II::D8 |               X86II::ArgF80 | X86II::AddRegFrm               , NoIR, NoIR)   // ST(0) = ST(i) / ST(0)
-I(FDIVrST0    , "fdiv"  , 0xF8,           0, X86II::DC |               X86II::ArgF80 | X86II::AddRegFrm               , NoIR, NoIR)   // ST(i) = ST(i) / ST(0)
-I(FDIVPrST0   , "fdivp" , 0xF8,           0, X86II::DE |               X86II::ArgF80 | X86II::AddRegFrm               , NoIR, NoIR)   // ST(i) = ST(i) / ST(0), pop
+I(FDIVRST0r   , "fdivr" , 0xF8,           0, X86II::D8 |               X86II::ArgF80 | X86II::AddRegFrm               , O_ST0, O_ST0)   // ST(0) = ST(i) / ST(0)
+I(FDIVrST0    , "fdiv"  , 0xF8,           0, X86II::DC |               X86II::ArgF80 | X86II::AddRegFrm | X86II::PrintImplUses, O_ST0, NoIR)   // ST(i) = ST(i) / ST(0)
+I(FDIVPrST0   , "fdivp" , 0xF8,           0, X86II::DE |               X86II::ArgF80 | X86II::AddRegFrm               , O_ST0, NoIR)    // ST(i) = ST(i) / ST(0), pop
 
-I(FDIVST0r    , "fdiv"  , 0xF0,           0, X86II::D8 |               X86II::ArgF80 | X86II::AddRegFrm               , NoIR, NoIR)   // ST(0) = ST(0) / ST(i)
-I(FDIVRrST0   , "fdivr" , 0xF0,           0, X86II::DC |               X86II::ArgF80 | X86II::AddRegFrm               , NoIR, NoIR)   // ST(i) = ST(0) / ST(i)
-I(FDIVRPrST0  , "fdivrp", 0xF0,           0, X86II::DE |               X86II::ArgF80 | X86II::AddRegFrm               , NoIR, NoIR)   // ST(i) = ST(0) / ST(i), pop
+I(FDIVST0r    , "fdiv"  , 0xF0,           0, X86II::D8 |               X86II::ArgF80 | X86II::AddRegFrm               , O_ST0, O_ST0)   // ST(0) = ST(0) / ST(i)
+I(FDIVRrST0   , "fdivr" , 0xF0,           0, X86II::DC |               X86II::ArgF80 | X86II::AddRegFrm | X86II::PrintImplUses, O_ST0, NoIR)   // ST(i) = ST(0) / ST(i)
+I(FDIVRPrST0  , "fdivrp", 0xF0,           0, X86II::DE |               X86II::ArgF80 | X86II::AddRegFrm               , O_ST0, NoIR)    // ST(i) = ST(0) / ST(i), pop
 
 // Floating point compares
-I(FUCOMr      , "fucom"   , 0xE0,           0, X86II::DD | X86II::Void | X86II::ArgF80 | X86II::AddRegFrm               , NoIR, NoIR)   // FPSW = compare ST(0) with ST(i)
-I(FUCOMPr     , "fucomp"  , 0xE8,           0, X86II::DD | X86II::Void | X86II::ArgF80 | X86II::AddRegFrm               , NoIR, NoIR)   // compare, pop
-I(FUCOMPPr    , "fucompp" , 0xE9,           0, X86II::DA | X86II::Void                 | X86II::RawFrm                  , NoIR, NoIR)   // compare ST(0) with ST(1), pop, pop
+I(FUCOMr      , "fucom"   , 0xE0,           0, X86II::DD | X86II::Void | X86II::ArgF80 | X86II::AddRegFrm               , O_ST0, NoIR)   // FPSW = compare ST(0) with ST(i)
+I(FUCOMPr     , "fucomp"  , 0xE8,           0, X86II::DD | X86II::Void | X86II::ArgF80 | X86II::AddRegFrm               , O_ST0, NoIR)   // compare, pop
+I(FUCOMPPr    , "fucompp" , 0xE9,           0, X86II::DA | X86II::Void                 | X86II::RawFrm                  , O_ST0, NoIR)   // compare ST(0) with ST(1), pop, pop
 
 // Floating point flag ops
 I(FNSTSWr8    , "fnstsw"  , 0xE0,           0, X86II::DF | X86II::Void                 | X86II::RawFrm                  , NoIR, O_AX)   // AX = fp flags