diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp --- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp +++ b/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())); diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp --- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp +++ b/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(OS, F, support::little); } else { assert(Info.OperandType == WebAssembly::OPERAND_F64IMM); diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp --- a/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp +++ b/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: diff --git a/llvm/test/CodeGen/WebAssembly/immediates.ll b/llvm/test/CodeGen/WebAssembly/immediates.ll --- a/llvm/test/CodeGen/WebAssembly/immediates.ll +++ b/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"