[PATCH] D91052: [WebAssembly] Fix NaN handing when converting FP types

Luís Marques via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Mon Nov 9 00:39:41 PST 2020


luismarques created this revision.
luismarques added reviewers: sunfish, jfb, atanasyan, asb, lenary.
Herald added subscribers: llvm-commits, ecnelises, s.egerton, PkmX, simoncook, hiraditya, jgravelle-google, arichardson, sbc100, sdardis, dschuff.
Herald added a project: LLVM.
luismarques requested review of this revision.
Herald added a subscriber: aheejin.

Use APFloat's platform-independent FP conversions, instead of C++'s native floating-point type conversions. This addresses an issue that was noted in comments as TODO. 
This patch allows the test `llvm/test/CodeGen/WebAssembly/immediates.ll` to pass on various platforms where it would fail, like RISC-V and MIPS. On RISC-V (hardfloat), the float <-> double conversion canonicalizes the NaN, so some NaN tests in that file would fail.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D91052

Files:
  llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp
  llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp
  llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
  llvm/test/CodeGen/WebAssembly/immediates.ll


Index: llvm/test/CodeGen/WebAssembly/immediates.ll
===================================================================
--- llvm/test/CodeGen/WebAssembly/immediates.ll
+++ llvm/test/CodeGen/WebAssembly/immediates.ll
@@ -1,10 +1,5 @@
 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-keep-registers | FileCheck %s
 
-; Usually MIPS hosts uses a legacy (non IEEE 754-2008) encoding for NaNs.
-; Tests like `nan_f32` failed in attempt to compare hard-coded IEEE 754-2008
-; NaN value and a legacy NaN value provided by a system.
-; XFAIL: mips-, mipsel-, mips64-, mips64el-
-
 ; Test that basic immediates assemble as expected.
 
 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
Index: llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
===================================================================
--- llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
+++ llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
@@ -277,15 +277,21 @@
       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();
-      if (Imm->getType()->isFloatTy())
-        MCOp = MCOperand::createFPImm(Imm->getValueAPF().convertToFloat());
-      else if (Imm->getType()->isDoubleTy())
-        MCOp = MCOperand::createFPImm(Imm->getValueAPF().convertToDouble());
-      else
-        llvm_unreachable("unknown floating point immediate type");
+      APFloat APFloatImm = Imm->getValueAPF();
+      if (Imm->getType()->isFloatTy()) {
+        // MC floating point immediate operands are always encoded with the type
+        // double, so MCOperand::createFPImm takes an argument of type double.
+        // To avoid changes to NaN values that can occur when converting a C++
+        // float to a double, we convert the immediate to a double using
+        // APFloat's architecture-independent FP value manipulation code.
+        bool Ignored;
+        APFloatImm.convert(APFloat::IEEEdouble(), APFloat::rmNearestTiesToEven,
+                           &Ignored);
+      } else
+        assert(Imm->getType()->isDoubleTy() &&
+               "unknown floating point immediate type");
+      MCOp = MCOperand::createFPImm(APFloatImm.convertToDouble());
       break;
     }
     case MachineOperand::MO_GlobalAddress:
Index: llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp
===================================================================
--- llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp
+++ llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp
@@ -132,9 +132,15 @@
     } 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());
+        // MC floating point immediate operands are always encoded with the type
+        // double. To avoid changes to NaN values that can occur when converting
+        // a C++ double to a float, we convert the immediate to a float using
+        // APFloat's architecture-independent FP value manipulation code.
+        APFloat APFloatImm = APFloat(MO.getFPImm());
+        bool Ignored;
+        APFloatImm.convert(APFloat::IEEEsingle(), APFloat::rmNearestTiesToEven,
+                           &Ignored);
+        float F = APFloatImm.convertToFloat();
         support::endian::write<float>(OS, F, support::little);
       } else {
         assert(Info.OperandType == WebAssembly::OPERAND_F64IMM);
Index: llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp
===================================================================
--- llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp
+++ llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp
@@ -240,9 +240,15 @@
     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())));
+      // MC floating point immediate operands are always encoded with the type
+      // double. To avoid changes to NaN values that can occur when converting
+      // a C++ double to a float, we convert the immediate to a float using
+      // APFloat's architecture-independent FP value manipulation code.
+      APFloat APFloatImm = APFloat(Op.getFPImm());
+      bool Ignored;
+      APFloatImm.convert(APFloat::IEEEsingle(), APFloat::rmNearestTiesToEven,
+                         &Ignored);
+      O << ::toString(APFloatImm);
     } else {
       assert(Info.OperandType == WebAssembly::OPERAND_F64IMM);
       O << ::toString(APFloat(Op.getFPImm()));


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D91052.303765.patch
Type: text/x-patch
Size: 5160 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20201109/ae530bb1/attachment-0001.bin>


More information about the llvm-commits mailing list