[llvm] 698c6b0 - [WebAssembly] Support single-floating-point immediate value

Dan Gohman via llvm-commits llvm-commits at lists.llvm.org
Thu Feb 4 18:06:29 PST 2021


Author: Dan Gohman
Date: 2021-02-04T18:05:06-08:00
New Revision: 698c6b0a099b902722d9e89234e0205ac240c13e

URL: https://github.com/llvm/llvm-project/commit/698c6b0a099b902722d9e89234e0205ac240c13e
DIFF: https://github.com/llvm/llvm-project/commit/698c6b0a099b902722d9e89234e0205ac240c13e.diff

LOG: [WebAssembly] Support single-floating-point immediate value

As mentioned in TODO comment, casting double to float causes NaNs to change bits.
To avoid the change, this patch adds support for single-floating-point immediate value on MachineCode.

Patch by Yuta Saito.

Differential Revision: https://reviews.llvm.org/D77384

Added: 
    llvm/test/CodeGen/WebAssembly/snan_literal.ll

Modified: 
    llvm/include/llvm/MC/MCInst.h
    llvm/include/llvm/MC/MCInstBuilder.h
    llvm/lib/MC/MCInst.cpp
    llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp
    llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUInstPrinter.cpp
    llvm/lib/Target/AMDGPU/MCTargetDesc/SIMCCodeEmitter.cpp
    llvm/lib/Target/ARM/ARMMCInstLower.cpp
    llvm/lib/Target/ARM/MCTargetDesc/ARMMCCodeEmitter.cpp
    llvm/lib/Target/AVR/MCTargetDesc/AVRMCCodeEmitter.cpp
    llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp
    llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
    llvm/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp
    llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp
    llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp
    llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td
    llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
    llvm/test/CodeGen/WebAssembly/immediates.ll
    llvm/tools/llvm-exegesis/lib/BenchmarkResult.cpp
    llvm/tools/llvm-exegesis/lib/MCInstrDescView.cpp
    llvm/unittests/tools/llvm-exegesis/X86/BenchmarkResultTest.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/MC/MCInst.h b/llvm/include/llvm/MC/MCInst.h
index 2ce2ee063daa..60d8334db9f5 100644
--- a/llvm/include/llvm/MC/MCInst.h
+++ b/llvm/include/llvm/MC/MCInst.h
@@ -17,6 +17,7 @@
 
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/bit.h"
 #include "llvm/Support/SMLoc.h"
 #include <cassert>
 #include <cstddef>
@@ -33,30 +34,33 @@ class raw_ostream;
 /// This is a simple discriminated union.
 class MCOperand {
   enum MachineOperandType : unsigned char {
-    kInvalid,     ///< Uninitialized.
-    kRegister,    ///< Register operand.
-    kImmediate,   ///< Immediate operand.
-    kFPImmediate, ///< Floating-point immediate operand.
-    kExpr,        ///< Relocatable immediate operand.
-    kInst         ///< Sub-instruction operand.
+    kInvalid,      ///< Uninitialized.
+    kRegister,     ///< Register operand.
+    kImmediate,    ///< Immediate operand.
+    kSFPImmediate, ///< Single-floating-point immediate operand.
+    kDFPImmediate, ///< Double-Floating-point immediate operand.
+    kExpr,         ///< Relocatable immediate operand.
+    kInst          ///< Sub-instruction operand.
   };
   MachineOperandType Kind = kInvalid;
 
   union {
     unsigned RegVal;
     int64_t ImmVal;
-    double FPImmVal;
+    uint32_t SFPImmVal;
+    uint64_t FPImmVal;
     const MCExpr *ExprVal;
     const MCInst *InstVal;
   };
 
 public:
-  MCOperand() : FPImmVal(0.0) {}
+  MCOperand() : FPImmVal(0) {}
 
   bool isValid() const { return Kind != kInvalid; }
   bool isReg() const { return Kind == kRegister; }
   bool isImm() const { return Kind == kImmediate; }
-  bool isFPImm() const { return Kind == kFPImmediate; }
+  bool isSFPImm() const { return Kind == kSFPImmediate; }
+  bool isDFPImm() const { return Kind == kDFPImmediate; }
   bool isExpr() const { return Kind == kExpr; }
   bool isInst() const { return Kind == kInst; }
 
@@ -82,13 +86,23 @@ class MCOperand {
     ImmVal = Val;
   }
 
-  double getFPImm() const {
-    assert(isFPImm() && "This is not an FP immediate");
+  uint32_t getSFPImm() const {
+    assert(isSFPImm() && "This is not an SFP immediate");
+    return SFPImmVal;
+  }
+
+  void setSFPImm(uint32_t Val) {
+    assert(isSFPImm() && "This is not an SFP immediate");
+    SFPImmVal = Val;
+  }
+
+  uint64_t getDFPImm() const {
+    assert(isDFPImm() && "This is not an FP immediate");
     return FPImmVal;
   }
 
-  void setFPImm(double Val) {
-    assert(isFPImm() && "This is not an FP immediate");
+  void setDFPImm(uint64_t Val) {
+    assert(isDFPImm() && "This is not an FP immediate");
     FPImmVal = Val;
   }
 
@@ -126,9 +140,16 @@ class MCOperand {
     return Op;
   }
 
-  static MCOperand createFPImm(double Val) {
+  static MCOperand createSFPImm(uint32_t Val) {
+    MCOperand Op;
+    Op.Kind = kSFPImmediate;
+    Op.SFPImmVal = Val;
+    return Op;
+  }
+
+  static MCOperand createDFPImm(uint64_t Val) {
     MCOperand Op;
-    Op.Kind = kFPImmediate;
+    Op.Kind = kDFPImmediate;
     Op.FPImmVal = Val;
     return Op;
   }

diff  --git a/llvm/include/llvm/MC/MCInstBuilder.h b/llvm/include/llvm/MC/MCInstBuilder.h
index 0c8e01fdc412..6e5e9dd69018 100644
--- a/llvm/include/llvm/MC/MCInstBuilder.h
+++ b/llvm/include/llvm/MC/MCInstBuilder.h
@@ -39,9 +39,15 @@ class MCInstBuilder {
     return *this;
   }
 
+  /// Add a new single floating point immediate operand.
+  MCInstBuilder &addSFPImm(uint32_t Val) {
+    Inst.addOperand(MCOperand::createSFPImm(Val));
+    return *this;
+  }
+
   /// Add a new floating point immediate operand.
-  MCInstBuilder &addFPImm(double Val) {
-    Inst.addOperand(MCOperand::createFPImm(Val));
+  MCInstBuilder &addDFPImm(uint64_t Val) {
+    Inst.addOperand(MCOperand::createDFPImm(Val));
     return *this;
   }
 

diff  --git a/llvm/lib/MC/MCInst.cpp b/llvm/lib/MC/MCInst.cpp
index f6f6edee5822..be312b9a8d33 100644
--- a/llvm/lib/MC/MCInst.cpp
+++ b/llvm/lib/MC/MCInst.cpp
@@ -25,8 +25,10 @@ void MCOperand::print(raw_ostream &OS) const {
     OS << "Reg:" << getReg();
   else if (isImm())
     OS << "Imm:" << getImm();
-  else if (isFPImm())
-    OS << "FPImm:" << getFPImm();
+  else if (isSFPImm())
+    OS << "SFPImm:" << bit_cast<float>(getSFPImm());
+  else if (isDFPImm())
+    OS << "DFPImm:" << bit_cast<double>(getDFPImm());
   else if (isExpr()) {
     OS << "Expr:(" << *getExpr() << ")";
   } else if (isInst()) {

diff  --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp
index 340120d2b9e8..8204156d98a9 100644
--- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp
+++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp
@@ -1164,8 +1164,8 @@ void AArch64InstPrinter::printFPImmOperand(const MCInst *MI, unsigned OpNum,
                                            const MCSubtargetInfo &STI,
                                            raw_ostream &O) {
   const MCOperand &MO = MI->getOperand(OpNum);
-  float FPImm =
-      MO.isFPImm() ? MO.getFPImm() : AArch64_AM::getFPImmFloat(MO.getImm());
+  float FPImm = MO.isDFPImm() ? bit_cast<double>(MO.getDFPImm())
+                              : AArch64_AM::getFPImmFloat(MO.getImm());
 
   // 8 decimal places are enough to perfectly represent permitted floats.
   O << format("#%.8f", FPImm);

diff  --git a/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUInstPrinter.cpp b/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUInstPrinter.cpp
index fbf7dc2a72db..00bc9b2b65db 100644
--- a/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUInstPrinter.cpp
+++ b/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUInstPrinter.cpp
@@ -656,18 +656,19 @@ void AMDGPUInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
       // custom printer.
       llvm_unreachable("unexpected immediate operand type");
     }
-  } else if (Op.isFPImm()) {
+  } else if (Op.isDFPImm()) {
+    double Value = bit_cast<double>(Op.getDFPImm());
     // We special case 0.0 because otherwise it will be printed as an integer.
-    if (Op.getFPImm() == 0.0)
+    if (Value == 0.0)
       O << "0.0";
     else {
       const MCInstrDesc &Desc = MII.get(MI->getOpcode());
       int RCID = Desc.OpInfo[OpNo].RegClass;
       unsigned RCBits = AMDGPU::getRegBitWidth(MRI.getRegClass(RCID));
       if (RCBits == 32)
-        printImmediate32(FloatToBits(Op.getFPImm()), STI, O);
+        printImmediate32(FloatToBits(Value), STI, O);
       else if (RCBits == 64)
-        printImmediate64(DoubleToBits(Op.getFPImm()), STI, O);
+        printImmediate64(DoubleToBits(Value), STI, O);
       else
         llvm_unreachable("Invalid register class size");
     }
@@ -727,7 +728,7 @@ void AMDGPUInstPrinter::printOperandAndFPInputMods(const MCInst *MI,
     if (OpNo + 1 < MI->getNumOperands() &&
         (InputModifiers & SISrcMods::ABS) == 0) {
       const MCOperand &Op = MI->getOperand(OpNo + 1);
-      NegMnemo = Op.isImm() || Op.isFPImm();
+      NegMnemo = Op.isImm() || Op.isDFPImm();
     }
     if (NegMnemo) {
       O << "neg(";
@@ -1560,12 +1561,12 @@ void R600InstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
     }
   } else if (Op.isImm()) {
       O << Op.getImm();
-  } else if (Op.isFPImm()) {
+  } else if (Op.isDFPImm()) {
     // We special case 0.0 because otherwise it will be printed as an integer.
-    if (Op.getFPImm() == 0.0)
+    if (Op.getDFPImm() == 0.0)
       O << "0.0";
     else {
-      O << Op.getFPImm();
+      O << bit_cast<double>(Op.getDFPImm());
     }
   } else if (Op.isExpr()) {
     const MCExpr *Exp = Op.getExpr();

diff  --git a/llvm/lib/Target/AMDGPU/MCTargetDesc/SIMCCodeEmitter.cpp b/llvm/lib/Target/AMDGPU/MCTargetDesc/SIMCCodeEmitter.cpp
index 1a1ffcda3b4e..1aac821294db 100644
--- a/llvm/lib/Target/AMDGPU/MCTargetDesc/SIMCCodeEmitter.cpp
+++ b/llvm/lib/Target/AMDGPU/MCTargetDesc/SIMCCodeEmitter.cpp
@@ -219,7 +219,7 @@ uint32_t SIMCCodeEmitter::getLitEncoding(const MCOperand &MO,
     Imm = C->getValue();
   } else {
 
-    assert(!MO.isFPImm());
+    assert(!MO.isDFPImm());
 
     if (!MO.isImm())
       return ~0;

diff  --git a/llvm/lib/Target/ARM/ARMMCInstLower.cpp b/llvm/lib/Target/ARM/ARMMCInstLower.cpp
index f893faa4cf97..2c12e188049f 100644
--- a/llvm/lib/Target/ARM/ARMMCInstLower.cpp
+++ b/llvm/lib/Target/ARM/ARMMCInstLower.cpp
@@ -110,7 +110,7 @@ bool ARMAsmPrinter::lowerOperand(const MachineOperand &MO,
     APFloat Val = MO.getFPImm()->getValueAPF();
     bool ignored;
     Val.convert(APFloat::IEEEdouble(), APFloat::rmTowardZero, &ignored);
-    MCOp = MCOperand::createFPImm(Val.convertToDouble());
+    MCOp = MCOperand::createDFPImm(Val.convertToDouble());
     break;
   }
   case MachineOperand::MO_RegisterMask:

diff  --git a/llvm/lib/Target/ARM/MCTargetDesc/ARMMCCodeEmitter.cpp b/llvm/lib/Target/ARM/MCTargetDesc/ARMMCCodeEmitter.cpp
index 6df3af10fdcf..2396412996e1 100644
--- a/llvm/lib/Target/ARM/MCTargetDesc/ARMMCCodeEmitter.cpp
+++ b/llvm/lib/Target/ARM/MCTargetDesc/ARMMCCodeEmitter.cpp
@@ -576,9 +576,11 @@ getMachineOpValue(const MCInst &MI, const MCOperand &MO,
     }
   } else if (MO.isImm()) {
     return static_cast<unsigned>(MO.getImm());
-  } else if (MO.isFPImm()) {
-    return static_cast<unsigned>(APFloat(MO.getFPImm())
-                     .bitcastToAPInt().getHiBits(32).getLimitedValue());
+  } else if (MO.isDFPImm()) {
+    return static_cast<unsigned>(APFloat(bit_cast<double>(MO.getDFPImm()))
+                                     .bitcastToAPInt()
+                                     .getHiBits(32)
+                                     .getLimitedValue());
   }
 
   llvm_unreachable("Unable to encode MCOperand!");

diff  --git a/llvm/lib/Target/AVR/MCTargetDesc/AVRMCCodeEmitter.cpp b/llvm/lib/Target/AVR/MCTargetDesc/AVRMCCodeEmitter.cpp
index db995e247562..50872d6d7a92 100644
--- a/llvm/lib/Target/AVR/MCTargetDesc/AVRMCCodeEmitter.cpp
+++ b/llvm/lib/Target/AVR/MCTargetDesc/AVRMCCodeEmitter.cpp
@@ -254,11 +254,8 @@ unsigned AVRMCCodeEmitter::getMachineOpValue(const MCInst &MI,
   if (MO.isReg()) return Ctx.getRegisterInfo()->getEncodingValue(MO.getReg());
   if (MO.isImm()) return static_cast<unsigned>(MO.getImm());
 
-  if (MO.isFPImm())
-    return static_cast<unsigned>(APFloat(MO.getFPImm())
-                                     .bitcastToAPInt()
-                                     .getHiBits(32)
-                                     .getLimitedValue());
+  if (MO.isDFPImm())
+    return static_cast<unsigned>(bit_cast<double>(MO.getDFPImm()));
 
   // MO must be an Expr.
   assert(MO.isExpr());

diff  --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp
index 9de34cc0e787..b81ebedfb9c7 100644
--- a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp
+++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp
@@ -740,9 +740,8 @@ getMachineOpValue(const MCInst &MI, const MCOperand &MO,
     return RegNo;
   } else if (MO.isImm()) {
     return static_cast<unsigned>(MO.getImm());
-  } else if (MO.isFPImm()) {
-    return static_cast<unsigned>(APFloat(MO.getFPImm())
-        .bitcastToAPInt().getHiBits(32).getLimitedValue());
+  } else if (MO.isDFPImm()) {
+    return static_cast<unsigned>(bit_cast<double>(MO.getDFPImm()));
   }
   // MO must be an Expr.
   assert(MO.isExpr());

diff  --git a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
index 60ac3248b9e7..7748bfa7f80f 100644
--- a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
+++ b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
@@ -125,10 +125,19 @@ struct WebAssemblyOperand : public MCParsedAsmOperand {
       llvm_unreachable("Should be integer immediate or symbol!");
   }
 
-  void addFPImmOperands(MCInst &Inst, unsigned N) const {
+  void addFPImmf32Operands(MCInst &Inst, unsigned N) const {
     assert(N == 1 && "Invalid number of operands!");
     if (Kind == Float)
-      Inst.addOperand(MCOperand::createFPImm(Flt.Val));
+      Inst.addOperand(
+          MCOperand::createSFPImm(bit_cast<uint32_t>(float(Flt.Val))));
+    else
+      llvm_unreachable("Should be float immediate!");
+  }
+
+  void addFPImmf64Operands(MCInst &Inst, unsigned N) const {
+    assert(N == 1 && "Invalid number of operands!");
+    if (Kind == Float)
+      Inst.addOperand(MCOperand::createDFPImm(bit_cast<uint64_t>(Flt.Val)));
     else
       llvm_unreachable("Should be float immediate!");
   }

diff  --git a/llvm/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp b/llvm/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp
index 1b7cc093f7ad..f2522562e535 100644
--- a/llvm/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp
+++ b/llvm/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp
@@ -114,7 +114,7 @@ bool parseImmediate(MCInst &MI, uint64_t &Size, ArrayRef<uint8_t> Bytes) {
       Bytes.data() + Size);
   Size += sizeof(T);
   if (std::is_floating_point<T>::value) {
-    MI.addOperand(MCOperand::createFPImm(static_cast<double>(Val)));
+    MI.addOperand(MCOperand::createDFPImm(static_cast<double>(Val)));
   } else {
     MI.addOperand(MCOperand::createImm(static_cast<int64_t>(Val)));
   }

diff  --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp
index fb8b0c364f30..ee40b6d2adf7 100644
--- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp
+++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp
@@ -235,17 +235,10 @@ void WebAssemblyInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
       O << '=';
   } else if (Op.isImm()) {
     O << Op.getImm();
-  } else if (Op.isFPImm()) {
-    const MCInstrDesc &Desc = MII.get(MI->getOpcode());
-    const MCOperandInfo &Info = Desc.OpInfo[OpNo];
-    if (Info.OperandType == WebAssembly::OPERAND_F32IMM) {
-      // TODO: MC converts all floating point immediate operands to double.
-      // This is fine for numeric values, but may cause NaNs to change bits.
-      O << ::toString(APFloat(float(Op.getFPImm())));
-    } else {
-      assert(Info.OperandType == WebAssembly::OPERAND_F64IMM);
-      O << ::toString(APFloat(Op.getFPImm()));
-    }
+  } else if (Op.isSFPImm()) {
+    O << ::toString(APFloat(bit_cast<float>(Op.getSFPImm())));
+  } else if (Op.isDFPImm()) {
+    O << ::toString(APFloat(bit_cast<double>(Op.getDFPImm())));
   } else {
     assert(Op.isExpr() && "unknown operand kind in printOperand");
     // call_indirect instructions have a TYPEINDEX operand that we print

diff  --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp
index 55bf5d14fdac..e53c20203d35 100644
--- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp
+++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp
@@ -130,19 +130,12 @@ void WebAssemblyMCCodeEmitter::encodeInstruction(
         encodeULEB128(uint64_t(MO.getImm()), OS);
       }
 
-    } else if (MO.isFPImm()) {
-      const MCOperandInfo &Info = Desc.OpInfo[I];
-      if (Info.OperandType == WebAssembly::OPERAND_F32IMM) {
-        // TODO: MC converts all floating point immediate operands to double.
-        // This is fine for numeric values, but may cause NaNs to change bits.
-        auto F = float(MO.getFPImm());
-        support::endian::write<float>(OS, F, support::little);
-      } else {
-        assert(Info.OperandType == WebAssembly::OPERAND_F64IMM);
-        double D = MO.getFPImm();
-        support::endian::write<double>(OS, D, support::little);
-      }
-
+    } else if (MO.isSFPImm()) {
+      uint32_t F = MO.getSFPImm();
+      support::endian::write<uint32_t>(OS, F, support::little);
+    } else if (MO.isDFPImm()) {
+      uint64_t D = MO.getDFPImm();
+      support::endian::write<uint64_t>(OS, D, support::little);
     } else if (MO.isExpr()) {
       const MCOperandInfo &Info = Desc.OpInfo[I];
       llvm::MCFixupKind FixupKind;

diff  --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td
index 2f5a64a87a59..a1173ce11647 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td
@@ -117,13 +117,13 @@ def WebAssemblycatch : SDNode<"WebAssemblyISD::CATCH", SDT_WebAssemblyCatch,
 
 // Default Operand has AsmOperandClass "Imm" which is for integers (and
 // symbols), so specialize one for floats:
-def FPImmAsmOperand : AsmOperandClass {
-  let Name = "FPImm";
+class FPImmAsmOperand<ValueType ty> : AsmOperandClass {
+  let Name = "FPImm" # ty;
   let PredicateMethod = "isFPImm";
 }
 
 class FPOperand<ValueType ty> : Operand<ty> {
-  AsmOperandClass ParserMatchClass = FPImmAsmOperand;
+  AsmOperandClass ParserMatchClass = FPImmAsmOperand<ty>;
 }
 
 let OperandNamespace = "WebAssembly" in {

diff  --git a/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
index 86d59ef807ab..280fbf9d4dbb 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
@@ -285,13 +285,13 @@ void WebAssemblyMCInstLower::lower(const MachineInstr *MI,
       break;
     }
     case MachineOperand::MO_FPImmediate: {
-      // TODO: MC converts all floating point immediate operands to double.
-      // This is fine for numeric values, but may cause NaNs to change bits.
       const ConstantFP *Imm = MO.getFPImm();
+      const uint64_t BitPattern =
+          Imm->getValueAPF().bitcastToAPInt().getZExtValue();
       if (Imm->getType()->isFloatTy())
-        MCOp = MCOperand::createFPImm(Imm->getValueAPF().convertToFloat());
+        MCOp = MCOperand::createSFPImm(static_cast<uint32_t>(BitPattern));
       else if (Imm->getType()->isDoubleTy())
-        MCOp = MCOperand::createFPImm(Imm->getValueAPF().convertToDouble());
+        MCOp = MCOperand::createDFPImm(BitPattern);
       else
         llvm_unreachable("unknown floating point immediate type");
       break;

diff  --git a/llvm/test/CodeGen/WebAssembly/immediates.ll b/llvm/test/CodeGen/WebAssembly/immediates.ll
index b10b32915f23..33d55ab45613 100644
--- a/llvm/test/CodeGen/WebAssembly/immediates.ll
+++ b/llvm/test/CodeGen/WebAssembly/immediates.ll
@@ -146,12 +146,9 @@ define float @custom_nan_f32() {
   ret float 0xFFFD79BDE0000000
 }
 
-; TODO: LLVM's MC layer stores f32 operands as host doubles, requiring a
-; conversion, so the bits of the NaN are not fully preserved.
-
 ; CHECK-LABEL: custom_nans_f32:
 ; CHECK-NEXT: .functype custom_nans_f32 () -> (f32){{$}}
-; CHECK-NEXT: f32.const $push[[NUM:[0-9]+]]=, -nan:0x6bcdef{{$}}
+; CHECK-NEXT: f32.const $push[[NUM:[0-9]+]]=, -nan:0x2bcdef{{$}}
 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
 define float @custom_nans_f32() {
   ret float 0xFFF579BDE0000000

diff  --git a/llvm/test/CodeGen/WebAssembly/snan_literal.ll b/llvm/test/CodeGen/WebAssembly/snan_literal.ll
new file mode 100644
index 000000000000..133f76b7292c
--- /dev/null
+++ b/llvm/test/CodeGen/WebAssembly/snan_literal.ll
@@ -0,0 +1,29 @@
+; RUN: llc < %s --filetype=obj | llvm-objdump -d - | FileCheck %s
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown"
+
+define float @float_sNaN() #0 {
+entry:
+; CHECK: 00 00 a0 7f
+  ret float 0x7ff4000000000000
+}
+
+define float @float_qNaN() #0 {
+entry:
+; CHECK: 00 00 e0 7f
+  ret float 0x7ffc000000000000
+}
+
+
+define double @double_sNaN() #0 {
+entry:
+; CHECK: 00 00 00 00 00 00 f4 7f
+  ret double 0x7ff4000000000000
+}
+
+define double @double_qNaN() #0 {
+entry:
+; CHECK: 00 00 00 00 00 00 fc 7f
+  ret double 0x7ffc000000000000
+}
+

diff  --git a/llvm/tools/llvm-exegesis/lib/BenchmarkResult.cpp b/llvm/tools/llvm-exegesis/lib/BenchmarkResult.cpp
index 5f22e2a998fb..819a062e9b6a 100644
--- a/llvm/tools/llvm-exegesis/lib/BenchmarkResult.cpp
+++ b/llvm/tools/llvm-exegesis/lib/BenchmarkResult.cpp
@@ -134,8 +134,8 @@ struct YamlContext {
       OS << getRegName(MCOperand.getReg());
     } else if (MCOperand.isImm()) {
       serializeIntegerOperand(OS, MCOperand.getImm());
-    } else if (MCOperand.isFPImm()) {
-      serializeFPOperand(OS, MCOperand.getFPImm());
+    } else if (MCOperand.isDFPImm()) {
+      serializeFPOperand(OS, bit_cast<double>(MCOperand.getDFPImm()));
     } else {
       OS << kInvalidOperand;
     }
@@ -148,7 +148,7 @@ struct YamlContext {
     if (tryDeserializeIntegerOperand(String, IntValue))
       return MCOperand::createImm(IntValue);
     if (tryDeserializeFPOperand(String, DoubleValue))
-      return MCOperand::createFPImm(DoubleValue);
+      return MCOperand::createDFPImm(bit_cast<uint64_t>(DoubleValue));
     if (auto RegNo = getRegNo(String))
       return MCOperand::createReg(*RegNo);
     if (String != kInvalidOperand)

diff  --git a/llvm/tools/llvm-exegesis/lib/MCInstrDescView.cpp b/llvm/tools/llvm-exegesis/lib/MCInstrDescView.cpp
index 674db3fe1598..049cc68b4fb9 100644
--- a/llvm/tools/llvm-exegesis/lib/MCInstrDescView.cpp
+++ b/llvm/tools/llvm-exegesis/lib/MCInstrDescView.cpp
@@ -374,8 +374,10 @@ void DumpMCOperand(const MCRegisterInfo &MCRegisterInfo, const MCOperand &Op,
     OS << MCRegisterInfo.getName(Op.getReg());
   else if (Op.isImm())
     OS << Op.getImm();
-  else if (Op.isFPImm())
-    OS << Op.getFPImm();
+  else if (Op.isDFPImm())
+    OS << bit_cast<double>(Op.getDFPImm());
+  else if (Op.isSFPImm())
+    OS << bit_cast<float>(Op.getSFPImm());
   else if (Op.isExpr())
     OS << "Expr";
   else if (Op.isInst())

diff  --git a/llvm/unittests/tools/llvm-exegesis/X86/BenchmarkResultTest.cpp b/llvm/unittests/tools/llvm-exegesis/X86/BenchmarkResultTest.cpp
index 517d3ac5acb0..ac2002bb0eff 100644
--- a/llvm/unittests/tools/llvm-exegesis/X86/BenchmarkResultTest.cpp
+++ b/llvm/unittests/tools/llvm-exegesis/X86/BenchmarkResultTest.cpp
@@ -67,7 +67,7 @@ TEST(BenchmarkResultTest, WriteToAndReadFromDisk) {
                                         .addReg(X86::AL)
                                         .addReg(X86::AH)
                                         .addImm(123)
-                                        .addFPImm(0.5));
+                                        .addDFPImm(bit_cast<uint64_t>(0.5)));
   ToDisk.Key.Config = "config";
   ToDisk.Key.RegisterInitialValues = {
       RegisterValue{X86::AL, APInt(8, "-1", 10)},


        


More information about the llvm-commits mailing list