[llvm] r319128 - [WebAssembly] Fix trapping behavior in fptosi/fptoui.

Dan Gohman via llvm-commits llvm-commits at lists.llvm.org
Mon Nov 27 17:13:40 PST 2017


Author: djg
Date: Mon Nov 27 17:13:40 2017
New Revision: 319128

URL: http://llvm.org/viewvc/llvm-project?rev=319128&view=rev
Log:
[WebAssembly] Fix trapping behavior in fptosi/fptoui.

This adds code to protect WebAssembly's `trunc_s` family of opcodes
from values outside their domain. Even though such conversions have
full undefined behavior in C/C++, LLVM IR's `fptosi` and `fptoui` do
not, and only return undef.

This also implements the proposed non-trapping float-to-int conversion
feature and uses that instead when available.

Added:
    llvm/trunk/test/CodeGen/WebAssembly/conv-trap.ll
Modified:
    llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp
    llvm/trunk/lib/Target/WebAssembly/WebAssembly.td
    llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
    llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelLowering.h
    llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrConv.td
    llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrInfo.td
    llvm/trunk/lib/Target/WebAssembly/WebAssemblySubtarget.cpp
    llvm/trunk/lib/Target/WebAssembly/WebAssemblySubtarget.h
    llvm/trunk/test/CodeGen/WebAssembly/conv.ll

Modified: llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp?rev=319128&r1=319127&r2=319128&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp (original)
+++ llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp Mon Nov 27 17:13:40 2017
@@ -61,8 +61,13 @@ void WebAssemblyMCCodeEmitter::encodeIns
   uint64_t Start = OS.tell();
 
   uint64_t Binary = getBinaryCodeForInstr(MI, Fixups, STI);
-  assert(Binary < UINT8_MAX && "Multi-byte opcodes not supported yet");
-  OS << uint8_t(Binary);
+  if (Binary <= UINT8_MAX) {
+    OS << uint8_t(Binary);
+  } else {
+    assert(Binary <= UINT16_MAX && "Several-byte opcodes not supported yet");
+    OS << uint8_t(Binary >> 8)
+       << uint8_t(Binary);
+  }
 
   // For br_table instructions, encode the size of the table. In the MCInst,
   // there's an index operand, one operand for each table entry, and the

Modified: llvm/trunk/lib/Target/WebAssembly/WebAssembly.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssembly.td?rev=319128&r1=319127&r2=319128&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssembly.td (original)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssembly.td Mon Nov 27 17:13:40 2017
@@ -27,6 +27,10 @@ def FeatureSIMD128 : SubtargetFeature<"s
                                       "Enable 128-bit SIMD">;
 def FeatureAtomics : SubtargetFeature<"atomics", "HasAtomics", "true",
                                       "Enable Atomics">;
+def FeatureNontrappingFPToInt :
+      SubtargetFeature<"nontrapping-fptoint",
+                       "HasNontrappingFPToInt", "true",
+                       "Enable non-trapping float-to-int conversion operators">;
 
 //===----------------------------------------------------------------------===//
 // Architectures.

Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp?rev=319128&r1=319127&r2=319128&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp (original)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp Mon Nov 27 17:13:40 2017
@@ -19,6 +19,7 @@
 #include "WebAssemblyTargetMachine.h"
 #include "llvm/CodeGen/Analysis.h"
 #include "llvm/CodeGen/CallingConvLower.h"
+#include "llvm/CodeGen/MachineInstrBuilder.h"
 #include "llvm/CodeGen/MachineJumpTableInfo.h"
 #include "llvm/CodeGen/MachineRegisterInfo.h"
 #include "llvm/CodeGen/SelectionDAG.h"
@@ -184,6 +185,134 @@ MVT WebAssemblyTargetLowering::getScalar
   return Result;
 }
 
+// Lower an fp-to-int conversion operator from the LLVM opcode, which has an
+// undefined result on invalid/overflow, to the WebAssembly opcode, which
+// traps on invalid/overflow.
+static MachineBasicBlock *
+LowerFPToInt(
+    MachineInstr &MI,
+    DebugLoc DL,
+    MachineBasicBlock *BB,
+    const TargetInstrInfo &TII,
+    bool IsUnsigned,
+    bool Int64,
+    bool Float64,
+    unsigned LoweredOpcode
+) {
+  MachineRegisterInfo &MRI = BB->getParent()->getRegInfo();
+
+  unsigned OutReg = MI.getOperand(0).getReg();
+  unsigned InReg = MI.getOperand(1).getReg();
+
+  unsigned Abs = Float64 ? WebAssembly::ABS_F64 : WebAssembly::ABS_F32;
+  unsigned FConst = Float64 ? WebAssembly::CONST_F64 : WebAssembly::CONST_F32;
+  unsigned LT = Float64 ? WebAssembly::LT_F64 : WebAssembly::LT_F32;
+  unsigned IConst = Int64 ? WebAssembly::CONST_I64 : WebAssembly::CONST_I32;
+  int64_t Limit = Int64 ? INT64_MIN : INT32_MIN;
+  int64_t Substitute = IsUnsigned ? 0 : Limit;
+  double CmpVal = IsUnsigned ? -(double)Limit * 2.0 : -(double)Limit;
+  auto &Context = BB->getParent()->getFunction()->getContext();
+  Type *Ty = Float64 ? Type::getDoubleTy(Context) : Type::getFloatTy(Context);
+
+  const BasicBlock *LLVM_BB = BB->getBasicBlock();
+  MachineFunction *F = BB->getParent();
+  MachineBasicBlock *TrueMBB = F->CreateMachineBasicBlock(LLVM_BB);
+  MachineBasicBlock *FalseMBB = F->CreateMachineBasicBlock(LLVM_BB);
+  MachineBasicBlock *DoneMBB = F->CreateMachineBasicBlock(LLVM_BB);
+
+  MachineFunction::iterator It = ++BB->getIterator();
+  F->insert(It, FalseMBB);
+  F->insert(It, TrueMBB);
+  F->insert(It, DoneMBB);
+
+  // Transfer the remainder of BB and its successor edges to DoneMBB.
+  DoneMBB->splice(DoneMBB->begin(), BB,
+                  std::next(MachineBasicBlock::iterator(MI)),
+                  BB->end());
+  DoneMBB->transferSuccessorsAndUpdatePHIs(BB);
+
+  BB->addSuccessor(TrueMBB);
+  BB->addSuccessor(FalseMBB);
+  TrueMBB->addSuccessor(DoneMBB);
+  FalseMBB->addSuccessor(DoneMBB);
+
+  unsigned Tmp0, Tmp1, Tmp2, Tmp3, Tmp4;
+  Tmp0 = MRI.createVirtualRegister(MRI.getRegClass(InReg));
+  Tmp1 = MRI.createVirtualRegister(MRI.getRegClass(InReg));
+  Tmp2 = MRI.createVirtualRegister(&WebAssembly::I32RegClass);
+  Tmp3 = MRI.createVirtualRegister(MRI.getRegClass(OutReg));
+  Tmp4 = MRI.createVirtualRegister(MRI.getRegClass(OutReg));
+
+  MI.eraseFromParent();
+  if (IsUnsigned) {
+    Tmp0 = InReg;
+  } else {
+    BuildMI(BB, DL, TII.get(Abs), Tmp0)
+        .addReg(InReg);
+  }
+  BuildMI(BB, DL, TII.get(FConst), Tmp1)
+      .addFPImm(cast<ConstantFP>(ConstantFP::get(Ty, CmpVal)));
+  BuildMI(BB, DL, TII.get(LT), Tmp2)
+      .addReg(Tmp0)
+      .addReg(Tmp1);
+  BuildMI(BB, DL, TII.get(WebAssembly::BR_IF))
+      .addMBB(TrueMBB)
+      .addReg(Tmp2);
+
+  BuildMI(FalseMBB, DL, TII.get(IConst), Tmp3)
+      .addImm(Substitute);
+  BuildMI(FalseMBB, DL, TII.get(WebAssembly::BR))
+      .addMBB(DoneMBB);
+  BuildMI(TrueMBB, DL, TII.get(LoweredOpcode), Tmp4)
+      .addReg(InReg);
+
+  BuildMI(*DoneMBB, DoneMBB->begin(), DL, TII.get(TargetOpcode::PHI), OutReg)
+      .addReg(Tmp3)
+      .addMBB(FalseMBB)
+      .addReg(Tmp4)
+      .addMBB(TrueMBB);
+
+  return DoneMBB;
+}
+
+MachineBasicBlock *
+WebAssemblyTargetLowering::EmitInstrWithCustomInserter(
+    MachineInstr &MI,
+    MachineBasicBlock *BB
+) const {
+  const TargetInstrInfo &TII = *Subtarget->getInstrInfo();
+  DebugLoc DL = MI.getDebugLoc();
+
+  switch (MI.getOpcode()) {
+  default: llvm_unreachable("Unexpected instr type to insert");
+  case WebAssembly::FP_TO_SINT_I32_F32:
+    return LowerFPToInt(MI, DL, BB, TII, false, false, false,
+                        WebAssembly::I32_TRUNC_S_F32);
+  case WebAssembly::FP_TO_UINT_I32_F32:
+    return LowerFPToInt(MI, DL, BB, TII, true, false, false,
+                        WebAssembly::I32_TRUNC_U_F32);
+  case WebAssembly::FP_TO_SINT_I64_F32:
+    return LowerFPToInt(MI, DL, BB, TII, false, true, false,
+                        WebAssembly::I64_TRUNC_S_F32);
+  case WebAssembly::FP_TO_UINT_I64_F32:
+    return LowerFPToInt(MI, DL, BB, TII, true, true, false,
+                        WebAssembly::I64_TRUNC_U_F32);
+  case WebAssembly::FP_TO_SINT_I32_F64:
+    return LowerFPToInt(MI, DL, BB, TII, false, false, true,
+                        WebAssembly::I32_TRUNC_S_F64);
+  case WebAssembly::FP_TO_UINT_I32_F64:
+    return LowerFPToInt(MI, DL, BB, TII, true, false, true,
+                        WebAssembly::I32_TRUNC_U_F64);
+  case WebAssembly::FP_TO_SINT_I64_F64:
+    return LowerFPToInt(MI, DL, BB, TII, false, true, true,
+                        WebAssembly::I64_TRUNC_S_F64);
+  case WebAssembly::FP_TO_UINT_I64_F64:
+    return LowerFPToInt(MI, DL, BB, TII, true, true, true,
+                        WebAssembly::I64_TRUNC_U_F64);
+  llvm_unreachable("Unexpected instruction to emit with custom inserter");
+  }
+}
+
 const char *WebAssemblyTargetLowering::getTargetNodeName(
     unsigned Opcode) const {
   switch (static_cast<WebAssemblyISD::NodeType>(Opcode)) {

Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelLowering.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelLowering.h?rev=319128&r1=319127&r2=319128&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelLowering.h (original)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelLowering.h Mon Nov 27 17:13:40 2017
@@ -48,6 +48,9 @@ class WebAssemblyTargetLowering final :
                            const TargetLibraryInfo *LibInfo) const override;
   bool isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const override;
   MVT getScalarShiftAmountTy(const DataLayout &DL, EVT) const override;
+  MachineBasicBlock *
+  EmitInstrWithCustomInserter(MachineInstr &MI,
+                              MachineBasicBlock *MBB) const override;
   const char *getTargetNodeName(unsigned Opcode) const override;
   std::pair<unsigned, const TargetRegisterClass *> getRegForInlineAsmConstraint(
       const TargetRegisterInfo *TRI, StringRef Constraint,

Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrConv.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrConv.td?rev=319128&r1=319127&r2=319128&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrConv.td (original)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrConv.td Mon Nov 27 17:13:40 2017
@@ -53,32 +53,88 @@ def : Pat<(i64 (anyext I32:$src)), (I64_
 
 let Defs = [ARGUMENTS] in {
 
+// Conversion from floating point to integer instructions which don't trap on
+// overflow or invalid.
+def I32_TRUNC_S_SAT_F32 : I<(outs I32:$dst), (ins F32:$src),
+                            [(set I32:$dst, (fp_to_sint F32:$src))],
+                            "i32.trunc_s:sat/f32\t$dst, $src", 0xfc00>,
+                            Requires<[HasNontrappingFPToInt]>;
+def I32_TRUNC_U_SAT_F32 : I<(outs I32:$dst), (ins F32:$src),
+                            [(set I32:$dst, (fp_to_uint F32:$src))],
+                            "i32.trunc_u:sat/f32\t$dst, $src", 0xfc01>,
+                            Requires<[HasNontrappingFPToInt]>;
+def I64_TRUNC_S_SAT_F32 : I<(outs I64:$dst), (ins F32:$src),
+                            [(set I64:$dst, (fp_to_sint F32:$src))],
+                            "i64.trunc_s:sat/f32\t$dst, $src", 0xfc04>,
+                            Requires<[HasNontrappingFPToInt]>;
+def I64_TRUNC_U_SAT_F32 : I<(outs I64:$dst), (ins F32:$src),
+                            [(set I64:$dst, (fp_to_uint F32:$src))],
+                            "i64.trunc_u:sat/f32\t$dst, $src", 0xfc05>,
+                            Requires<[HasNontrappingFPToInt]>;
+def I32_TRUNC_S_SAT_F64 : I<(outs I32:$dst), (ins F64:$src),
+                            [(set I32:$dst, (fp_to_sint F64:$src))],
+                            "i32.trunc_s:sat/f64\t$dst, $src", 0xfc02>,
+                            Requires<[HasNontrappingFPToInt]>;
+def I32_TRUNC_U_SAT_F64 : I<(outs I32:$dst), (ins F64:$src),
+                            [(set I32:$dst, (fp_to_uint F64:$src))],
+                            "i32.trunc_u:sat/f64\t$dst, $src", 0xfc03>,
+                            Requires<[HasNontrappingFPToInt]>;
+def I64_TRUNC_S_SAT_F64 : I<(outs I64:$dst), (ins F64:$src),
+                            [(set I64:$dst, (fp_to_sint F64:$src))],
+                            "i64.trunc_s:sat/f64\t$dst, $src", 0xfc06>,
+                            Requires<[HasNontrappingFPToInt]>;
+def I64_TRUNC_U_SAT_F64 : I<(outs I64:$dst), (ins F64:$src),
+                            [(set I64:$dst, (fp_to_uint F64:$src))],
+                            "i64.trunc_u:sat/f64\t$dst, $src", 0xfc07>,
+                            Requires<[HasNontrappingFPToInt]>;
+
+// Conversion from floating point to integer pseudo-instructions which don't
+// trap on overflow or invalid.
+let usesCustomInserter = 1, isCodeGenOnly = 1 in {
+def FP_TO_SINT_I32_F32 : I<(outs I32:$dst), (ins F32:$src),
+                        [(set I32:$dst, (fp_to_sint F32:$src))], "", 0>,
+                        Requires<[NotHasNontrappingFPToInt]>;
+def FP_TO_UINT_I32_F32 : I<(outs I32:$dst), (ins F32:$src),
+                        [(set I32:$dst, (fp_to_uint F32:$src))], "", 0>,
+                        Requires<[NotHasNontrappingFPToInt]>;
+def FP_TO_SINT_I64_F32 : I<(outs I64:$dst), (ins F32:$src),
+                        [(set I64:$dst, (fp_to_sint F32:$src))], "", 0>,
+                        Requires<[NotHasNontrappingFPToInt]>;
+def FP_TO_UINT_I64_F32 : I<(outs I64:$dst), (ins F32:$src),
+                        [(set I64:$dst, (fp_to_uint F32:$src))], "", 0>,
+                        Requires<[NotHasNontrappingFPToInt]>;
+def FP_TO_SINT_I32_F64 : I<(outs I32:$dst), (ins F64:$src),
+                        [(set I32:$dst, (fp_to_sint F64:$src))], "", 0>,
+                        Requires<[NotHasNontrappingFPToInt]>;
+def FP_TO_UINT_I32_F64 : I<(outs I32:$dst), (ins F64:$src),
+                        [(set I32:$dst, (fp_to_uint F64:$src))], "", 0>,
+                        Requires<[NotHasNontrappingFPToInt]>;
+def FP_TO_SINT_I64_F64 : I<(outs I64:$dst), (ins F64:$src),
+                        [(set I64:$dst, (fp_to_sint F64:$src))], "", 0>,
+                        Requires<[NotHasNontrappingFPToInt]>;
+def FP_TO_UINT_I64_F64 : I<(outs I64:$dst), (ins F64:$src),
+                        [(set I64:$dst, (fp_to_uint F64:$src))], "", 0>,
+                        Requires<[NotHasNontrappingFPToInt]>;
+} // usesCustomInserter, isCodeGenOnly = 1
+
 // Conversion from floating point to integer traps on overflow and invalid.
 let hasSideEffects = 1 in {
 def I32_TRUNC_S_F32 : I<(outs I32:$dst), (ins F32:$src),
-                        [(set I32:$dst, (fp_to_sint F32:$src))],
-                        "i32.trunc_s/f32\t$dst, $src", 0xa8>;
+                        [], "i32.trunc_s/f32\t$dst, $src", 0xa8>;
 def I32_TRUNC_U_F32 : I<(outs I32:$dst), (ins F32:$src),
-                        [(set I32:$dst, (fp_to_uint F32:$src))],
-                        "i32.trunc_u/f32\t$dst, $src", 0xa9>;
+                        [], "i32.trunc_u/f32\t$dst, $src", 0xa9>;
 def I64_TRUNC_S_F32 : I<(outs I64:$dst), (ins F32:$src),
-                        [(set I64:$dst, (fp_to_sint F32:$src))],
-                        "i64.trunc_s/f32\t$dst, $src", 0xae>;
+                        [], "i64.trunc_s/f32\t$dst, $src", 0xae>;
 def I64_TRUNC_U_F32 : I<(outs I64:$dst), (ins F32:$src),
-                        [(set I64:$dst, (fp_to_uint F32:$src))],
-                        "i64.trunc_u/f32\t$dst, $src", 0xaf>;
+                        [], "i64.trunc_u/f32\t$dst, $src", 0xaf>;
 def I32_TRUNC_S_F64 : I<(outs I32:$dst), (ins F64:$src),
-                        [(set I32:$dst, (fp_to_sint F64:$src))],
-                        "i32.trunc_s/f64\t$dst, $src", 0xaa>;
+                        [], "i32.trunc_s/f64\t$dst, $src", 0xaa>;
 def I32_TRUNC_U_F64 : I<(outs I32:$dst), (ins F64:$src),
-                        [(set I32:$dst, (fp_to_uint F64:$src))],
-                        "i32.trunc_u/f64\t$dst, $src", 0xab>;
+                        [], "i32.trunc_u/f64\t$dst, $src", 0xab>;
 def I64_TRUNC_S_F64 : I<(outs I64:$dst), (ins F64:$src),
-                        [(set I64:$dst, (fp_to_sint F64:$src))],
-                        "i64.trunc_s/f64\t$dst, $src", 0xb0>;
+                        [], "i64.trunc_s/f64\t$dst, $src", 0xb0>;
 def I64_TRUNC_U_F64 : I<(outs I64:$dst), (ins F64:$src),
-                        [(set I64:$dst, (fp_to_uint F64:$src))],
-                        "i64.trunc_u/f64\t$dst, $src", 0xb1>;
+                        [], "i64.trunc_u/f64\t$dst, $src", 0xb1>;
 } // hasSideEffects = 1
 
 def F32_CONVERT_S_I32 : I<(outs F32:$dst), (ins I32:$src),

Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrInfo.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrInfo.td?rev=319128&r1=319127&r2=319128&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrInfo.td (original)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrInfo.td Mon Nov 27 17:13:40 2017
@@ -22,6 +22,14 @@ def HasSIMD128 : Predicate<"Subtarget->h
                            AssemblerPredicate<"FeatureSIMD128", "simd128">;
 def HasAtomics : Predicate<"Subtarget->hasAtomics()">,
                            AssemblerPredicate<"FeatureAtomics", "atomics">;
+def HasNontrappingFPToInt :
+    Predicate<"Subtarget->hasNontrappingFPToInt()">,
+              AssemblerPredicate<"FeatureNontrappingFPToInt",
+                                 "nontrapping-fptoint">;
+def NotHasNontrappingFPToInt :
+    Predicate<"!Subtarget->hasNontrappingFPToInt()">,
+              AssemblerPredicate<"!FeatureNontrappingFPToInt",
+                                 "nontrapping-fptoint">;
 
 //===----------------------------------------------------------------------===//
 // WebAssembly-specific DAG Node Types.

Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblySubtarget.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblySubtarget.cpp?rev=319128&r1=319127&r2=319128&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssemblySubtarget.cpp (original)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssemblySubtarget.cpp Mon Nov 27 17:13:40 2017
@@ -41,7 +41,8 @@ WebAssemblySubtarget::WebAssemblySubtarg
                                            const std::string &FS,
                                            const TargetMachine &TM)
     : WebAssemblyGenSubtargetInfo(TT, CPU, FS), HasSIMD128(false),
-      HasAtomics(false), CPUString(CPU), TargetTriple(TT), FrameLowering(),
+      HasAtomics(false), HasNontrappingFPToInt(false), CPUString(CPU),
+      TargetTriple(TT), FrameLowering(),
       InstrInfo(initializeSubtargetDependencies(FS)), TSInfo(),
       TLInfo(TM, *this) {}
 

Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblySubtarget.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblySubtarget.h?rev=319128&r1=319127&r2=319128&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssemblySubtarget.h (original)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssemblySubtarget.h Mon Nov 27 17:13:40 2017
@@ -31,6 +31,7 @@ namespace llvm {
 class WebAssemblySubtarget final : public WebAssemblyGenSubtargetInfo {
   bool HasSIMD128;
   bool HasAtomics;
+  bool HasNontrappingFPToInt;
 
   /// String name of used CPU.
   std::string CPUString;
@@ -76,6 +77,7 @@ public:
   bool hasAddr64() const { return TargetTriple.isArch64Bit(); }
   bool hasSIMD128() const { return HasSIMD128; }
   bool hasAtomics() const { return HasAtomics; }
+  bool hasNontrappingFPToInt() const { return HasNontrappingFPToInt; }
 
   /// Parses features string setting specified subtarget options. Definition of
   /// function is auto generated by tblgen.

Added: llvm/trunk/test/CodeGen/WebAssembly/conv-trap.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/WebAssembly/conv-trap.ll?rev=319128&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/WebAssembly/conv-trap.ll (added)
+++ llvm/trunk/test/CodeGen/WebAssembly/conv-trap.ll Mon Nov 27 17:13:40 2017
@@ -0,0 +1,163 @@
+; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-wasm-explicit-locals -mattr=-nontrapping-fptoint | FileCheck %s
+
+; Test that basic conversion operations assemble as expected using
+; the trapping opcodes and explicit code to suppress the trapping.
+
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown-wasm"
+
+; CHECK-LABEL: i32_trunc_s_f32:
+; CHECK-NEXT: .param f32{{$}}
+; CHECK-NEXT: .result i32{{$}}
+; CHECK-NEXT: block
+; CHECK-NEXT: f32.abs $push[[ABS:[0-9]+]]=, $0{{$}}
+; CHECK-NEXT: f32.const $push[[LIMIT:[0-9]+]]=, 0x1p31{{$}}
+; CHECK-NEXT: f32.lt $push[[LT:[0-9]+]]=, $pop[[ABS]], $pop[[LIMIT]]{{$}}
+; CHECK-NEXT: i32.eqz $push[[EQZ:[0-9]+]]=, $pop[[LT]]{{$}}
+; CHECK-NEXT: br_if 0, $pop[[EQZ]]{{$}}
+; CHECK-NEXT: i32.trunc_s/f32 $push[[NUM:[0-9]+]]=, $0{{$}}
+; CHECK-NEXT: return $pop[[NUM]]{{$}}
+; CHECK-NEXT: BB
+; CHECK-NEXT: end_block
+; CHECK-NEXT: i32.const $push[[ALT:[0-9]+]]=, -2147483648{{$}}
+; CHECK-NEXT: return $pop[[ALT]]{{$}}
+define i32 @i32_trunc_s_f32(float %x) {
+  %a = fptosi float %x to i32
+  ret i32 %a
+}
+
+; CHECK-LABEL: i32_trunc_u_f32:
+; CHECK-NEXT: .param f32{{$}}
+; CHECK-NEXT: .result i32{{$}}
+; CHECK-NEXT: block
+; CHECK-NEXT: f32.const $push[[LIMIT:[0-9]+]]=, 0x1p32{{$}}
+; CHECK-NEXT: f32.lt $push[[LT:[0-9]+]]=, $0, $pop[[LIMIT]]{{$}}
+; CHECK-NEXT: i32.eqz $push[[EQZ:[0-9]+]]=, $pop[[LT]]{{$}}
+; CHECK-NEXT: br_if 0, $pop[[EQZ]]{{$}}
+; CHECK-NEXT: i32.trunc_u/f32 $push[[NUM:[0-9]+]]=, $0{{$}}
+; CHECK-NEXT: return $pop[[NUM]]{{$}}
+; CHECK-NEXT: BB
+; CHECK-NEXT: end_block
+; CHECK-NEXT: i32.const $push[[ALT:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: return $pop[[ALT]]{{$}}
+define i32 @i32_trunc_u_f32(float %x) {
+  %a = fptoui float %x to i32
+  ret i32 %a
+}
+
+; CHECK-LABEL: i32_trunc_s_f64:
+; CHECK-NEXT: .param f64{{$}}
+; CHECK-NEXT: .result i32{{$}}
+; CHECK-NEXT: block
+; CHECK-NEXT: f64.abs $push[[ABS:[0-9]+]]=, $0{{$}}
+; CHECK-NEXT: f64.const $push[[LIMIT:[0-9]+]]=, 0x1p31{{$}}
+; CHECK-NEXT: f64.lt $push[[LT:[0-9]+]]=, $pop[[ABS]], $pop[[LIMIT]]{{$}}
+; CHECK-NEXT: i32.eqz $push[[EQZ:[0-9]+]]=, $pop[[LT]]{{$}}
+; CHECK-NEXT: br_if 0, $pop[[EQZ]]{{$}}
+; CHECK-NEXT: i32.trunc_s/f64 $push[[NUM:[0-9]+]]=, $0{{$}}
+; CHECK-NEXT: return $pop[[NUM]]{{$}}
+; CHECK-NEXT: BB
+; CHECK-NEXT: end_block
+; CHECK-NEXT: i32.const $push[[ALT:[0-9]+]]=, -2147483648{{$}}
+; CHECK-NEXT: return $pop[[ALT]]{{$}}
+define i32 @i32_trunc_s_f64(double %x) {
+  %a = fptosi double %x to i32
+  ret i32 %a
+}
+
+; CHECK-LABEL: i32_trunc_u_f64:
+; CHECK-NEXT: .param f64{{$}}
+; CHECK-NEXT: .result i32{{$}}
+; CHECK-NEXT: block
+; CHECK-NEXT: f64.const $push[[LIMIT:[0-9]+]]=, 0x1p32{{$}}
+; CHECK-NEXT: f64.lt $push[[LT:[0-9]+]]=, $0, $pop[[LIMIT]]{{$}}
+; CHECK-NEXT: i32.eqz $push[[EQZ:[0-9]+]]=, $pop[[LT]]{{$}}
+; CHECK-NEXT: br_if 0, $pop[[EQZ]]{{$}}
+; CHECK-NEXT: i32.trunc_u/f64 $push[[NUM:[0-9]+]]=, $0{{$}}
+; CHECK-NEXT: return $pop[[NUM]]{{$}}
+; CHECK-NEXT: BB
+; CHECK-NEXT: end_block
+; CHECK-NEXT: i32.const $push[[ALT:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: return $pop[[ALT]]{{$}}
+define i32 @i32_trunc_u_f64(double %x) {
+  %a = fptoui double %x to i32
+  ret i32 %a
+}
+
+; CHECK-LABEL: i64_trunc_s_f32:
+; CHECK-NEXT: .param f32{{$}}
+; CHECK-NEXT: .result i64{{$}}
+; CHECK-NEXT: block
+; CHECK-NEXT: f32.abs $push[[ABS:[0-9]+]]=, $0{{$}}
+; CHECK-NEXT: f32.const $push[[LIMIT:[0-9]+]]=, 0x1p63{{$}}
+; CHECK-NEXT: f32.lt $push[[LT:[0-9]+]]=, $pop[[ABS]], $pop[[LIMIT]]{{$}}
+; CHECK-NEXT: i32.eqz $push[[EQZ:[0-9]+]]=, $pop[[LT]]{{$}}
+; CHECK-NEXT: br_if 0, $pop[[EQZ]]{{$}}
+; CHECK-NEXT: i64.trunc_s/f32 $push[[NUM:[0-9]+]]=, $0{{$}}
+; CHECK-NEXT: return $pop[[NUM]]{{$}}
+; CHECK-NEXT: BB
+; CHECK-NEXT: end_block
+; CHECK-NEXT: i64.const $push[[ALT:[0-9]+]]=, -9223372036854775808{{$}}
+; CHECK-NEXT: return $pop[[ALT]]{{$}}
+define i64 @i64_trunc_s_f32(float %x) {
+  %a = fptosi float %x to i64
+  ret i64 %a
+}
+
+; CHECK-LABEL: i64_trunc_u_f32:
+; CHECK-NEXT: .param f32{{$}}
+; CHECK-NEXT: .result i64{{$}}
+; CHECK-NEXT: block
+; CHECK-NEXT: f32.const $push[[LIMIT:[0-9]+]]=, 0x1p64{{$}}
+; CHECK-NEXT: f32.lt $push[[LT:[0-9]+]]=, $0, $pop[[LIMIT]]{{$}}
+; CHECK-NEXT: i32.eqz $push[[EQZ:[0-9]+]]=, $pop[[LT]]{{$}}
+; CHECK-NEXT: br_if 0, $pop[[EQZ]]{{$}}
+; CHECK-NEXT: i64.trunc_u/f32 $push[[NUM:[0-9]+]]=, $0{{$}}
+; CHECK-NEXT: return $pop[[NUM]]{{$}}
+; CHECK-NEXT: BB
+; CHECK-NEXT: end_block
+; CHECK-NEXT: i64.const $push[[ALT:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: return $pop[[ALT]]{{$}}
+define i64 @i64_trunc_u_f32(float %x) {
+  %a = fptoui float %x to i64
+  ret i64 %a
+}
+
+; CHECK-LABEL: i64_trunc_s_f64:
+; CHECK-NEXT: .param f64{{$}}
+; CHECK-NEXT: .result i64{{$}}
+; CHECK-NEXT: block
+; CHECK-NEXT: f64.abs $push[[ABS:[0-9]+]]=, $0{{$}}
+; CHECK-NEXT: f64.const $push[[LIMIT:[0-9]+]]=, 0x1p63{{$}}
+; CHECK-NEXT: f64.lt $push[[LT:[0-9]+]]=, $pop[[ABS]], $pop[[LIMIT]]{{$}}
+; CHECK-NEXT: i32.eqz $push[[EQZ:[0-9]+]]=, $pop[[LT]]{{$}}
+; CHECK-NEXT: br_if 0, $pop[[EQZ]]{{$}}
+; CHECK-NEXT: i64.trunc_s/f64 $push[[NUM:[0-9]+]]=, $0{{$}}
+; CHECK-NEXT: return $pop[[NUM]]{{$}}
+; CHECK-NEXT: BB
+; CHECK-NEXT: end_block
+; CHECK-NEXT: i64.const $push[[ALT:[0-9]+]]=, -9223372036854775808{{$}}
+; CHECK-NEXT: return $pop[[ALT]]{{$}}
+define i64 @i64_trunc_s_f64(double %x) {
+  %a = fptosi double %x to i64
+  ret i64 %a
+}
+
+; CHECK-LABEL: i64_trunc_u_f64:
+; CHECK-NEXT: .param f64{{$}}
+; CHECK-NEXT: .result i64{{$}}
+; CHECK-NEXT: block
+; CHECK-NEXT: f64.const $push[[LIMIT:[0-9]+]]=, 0x1p64{{$}}
+; CHECK-NEXT: f64.lt $push[[LT:[0-9]+]]=, $0, $pop[[LIMIT]]{{$}}
+; CHECK-NEXT: i32.eqz $push[[EQZ:[0-9]+]]=, $pop[[LT]]{{$}}
+; CHECK-NEXT: br_if 0, $pop[[EQZ]]{{$}}
+; CHECK-NEXT: i64.trunc_u/f64 $push[[NUM:[0-9]+]]=, $0{{$}}
+; CHECK-NEXT: return $pop[[NUM]]{{$}}
+; CHECK-NEXT: BB
+; CHECK-NEXT: end_block
+; CHECK-NEXT: i64.const $push[[ALT:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: return $pop[[ALT]]{{$}}
+define i64 @i64_trunc_u_f64(double %x) {
+  %a = fptoui double %x to i64
+  ret i64 %a
+}

Modified: llvm/trunk/test/CodeGen/WebAssembly/conv.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/WebAssembly/conv.ll?rev=319128&r1=319127&r2=319128&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/WebAssembly/conv.ll (original)
+++ llvm/trunk/test/CodeGen/WebAssembly/conv.ll Mon Nov 27 17:13:40 2017
@@ -1,4 +1,4 @@
-; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-wasm-explicit-locals | FileCheck %s
+; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-wasm-explicit-locals -mattr=+nontrapping-fptoint | FileCheck %s
 
 ; Test that basic conversion operations assemble as expected.
 
@@ -38,7 +38,7 @@ define i64 @i64_extend_u_i32(i32 %x) {
 ; CHECK-LABEL: i32_trunc_s_f32:
 ; CHECK-NEXT: .param f32{{$}}
 ; CHECK-NEXT: .result i32{{$}}
-; CHECK-NEXT: i32.trunc_s/f32 $push[[NUM:[0-9]+]]=, $0{{$}}
+; CHECK-NEXT: i32.trunc_s:sat/f32 $push[[NUM:[0-9]+]]=, $0{{$}}
 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
 define i32 @i32_trunc_s_f32(float %x) {
   %a = fptosi float %x to i32
@@ -48,7 +48,7 @@ define i32 @i32_trunc_s_f32(float %x) {
 ; CHECK-LABEL: i32_trunc_u_f32:
 ; CHECK-NEXT: .param f32{{$}}
 ; CHECK-NEXT: .result i32{{$}}
-; CHECK-NEXT: i32.trunc_u/f32 $push[[NUM:[0-9]+]]=, $0{{$}}
+; CHECK-NEXT: i32.trunc_u:sat/f32 $push[[NUM:[0-9]+]]=, $0{{$}}
 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
 define i32 @i32_trunc_u_f32(float %x) {
   %a = fptoui float %x to i32
@@ -58,7 +58,7 @@ define i32 @i32_trunc_u_f32(float %x) {
 ; CHECK-LABEL: i32_trunc_s_f64:
 ; CHECK-NEXT: .param f64{{$}}
 ; CHECK-NEXT: .result i32{{$}}
-; CHECK-NEXT: i32.trunc_s/f64 $push[[NUM:[0-9]+]]=, $0{{$}}
+; CHECK-NEXT: i32.trunc_s:sat/f64 $push[[NUM:[0-9]+]]=, $0{{$}}
 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
 define i32 @i32_trunc_s_f64(double %x) {
   %a = fptosi double %x to i32
@@ -68,7 +68,7 @@ define i32 @i32_trunc_s_f64(double %x) {
 ; CHECK-LABEL: i32_trunc_u_f64:
 ; CHECK-NEXT: .param f64{{$}}
 ; CHECK-NEXT: .result i32{{$}}
-; CHECK-NEXT: i32.trunc_u/f64 $push[[NUM:[0-9]+]]=, $0{{$}}
+; CHECK-NEXT: i32.trunc_u:sat/f64 $push[[NUM:[0-9]+]]=, $0{{$}}
 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
 define i32 @i32_trunc_u_f64(double %x) {
   %a = fptoui double %x to i32
@@ -78,7 +78,7 @@ define i32 @i32_trunc_u_f64(double %x) {
 ; CHECK-LABEL: i64_trunc_s_f32:
 ; CHECK-NEXT: .param f32{{$}}
 ; CHECK-NEXT: .result i64{{$}}
-; CHECK-NEXT: i64.trunc_s/f32 $push[[NUM:[0-9]+]]=, $0{{$}}
+; CHECK-NEXT: i64.trunc_s:sat/f32 $push[[NUM:[0-9]+]]=, $0{{$}}
 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
 define i64 @i64_trunc_s_f32(float %x) {
   %a = fptosi float %x to i64
@@ -88,7 +88,7 @@ define i64 @i64_trunc_s_f32(float %x) {
 ; CHECK-LABEL: i64_trunc_u_f32:
 ; CHECK-NEXT: .param f32{{$}}
 ; CHECK-NEXT: .result i64{{$}}
-; CHECK-NEXT: i64.trunc_u/f32 $push[[NUM:[0-9]+]]=, $0{{$}}
+; CHECK-NEXT: i64.trunc_u:sat/f32 $push[[NUM:[0-9]+]]=, $0{{$}}
 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
 define i64 @i64_trunc_u_f32(float %x) {
   %a = fptoui float %x to i64
@@ -98,7 +98,7 @@ define i64 @i64_trunc_u_f32(float %x) {
 ; CHECK-LABEL: i64_trunc_s_f64:
 ; CHECK-NEXT: .param f64{{$}}
 ; CHECK-NEXT: .result i64{{$}}
-; CHECK-NEXT: i64.trunc_s/f64 $push[[NUM:[0-9]+]]=, $0{{$}}
+; CHECK-NEXT: i64.trunc_s:sat/f64 $push[[NUM:[0-9]+]]=, $0{{$}}
 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
 define i64 @i64_trunc_s_f64(double %x) {
   %a = fptosi double %x to i64
@@ -108,7 +108,7 @@ define i64 @i64_trunc_s_f64(double %x) {
 ; CHECK-LABEL: i64_trunc_u_f64:
 ; CHECK-NEXT: .param f64{{$}}
 ; CHECK-NEXT: .result i64{{$}}
-; CHECK-NEXT: i64.trunc_u/f64 $push[[NUM:[0-9]+]]=, $0{{$}}
+; CHECK-NEXT: i64.trunc_u:sat/f64 $push[[NUM:[0-9]+]]=, $0{{$}}
 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
 define i64 @i64_trunc_u_f64(double %x) {
   %a = fptoui double %x to i64




More information about the llvm-commits mailing list