WebAssembly: print immediates
authorJF Bastien <jfb@google.com>
Mon, 10 Aug 2015 22:36:48 +0000 (22:36 +0000)
committerJF Bastien <jfb@google.com>
Mon, 10 Aug 2015 22:36:48 +0000 (22:36 +0000)
Summary:
For now output using C99's hexadecimal floating-point representation.

This patch also cleans up how machine operands are printed: instead of special-casing per type of machine instruction, the code now handles operands generically.

Reviewers: sunfish

Subscribers: llvm-commits, jfb

Differential Revision: http://reviews.llvm.org/D11914

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

lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
lib/Target/WebAssembly/WebAssemblyInstrInfo.td
test/CodeGen/WebAssembly/immediates.ll [new file with mode: 0644]

index 99b23c7..35a4be3 100644 (file)
@@ -99,28 +99,36 @@ void WebAssemblyAsmPrinter::EmitInstruction(const MachineInstr *MI) {
     OS << "(setlocal @" << TargetRegisterInfo::virtReg2Index(Reg) << ' ';
   }
 
-  OS << '(';
-
-  bool PrintOperands = true;
-  switch (MI->getOpcode()) {
-  case WebAssembly::ARGUMENT_Int32:
-  case WebAssembly::ARGUMENT_Int64:
-  case WebAssembly::ARGUMENT_Float32:
-  case WebAssembly::ARGUMENT_Float64:
-    OS << Name(TII, MI) << ' ' << MI->getOperand(1).getImm();
-    PrintOperands = false;
-    break;
-  default:
-    OS << Name(TII, MI);
-    break;
-  }
-
-  if (PrintOperands)
-    for (const MachineOperand &MO : MI->uses()) {
-      if (MO.isReg() && MO.isImplicit())
+  OS << '(' << Name(TII, MI);
+  for (const MachineOperand &MO : MI->uses())
+    switch (MO.getType()) {
+    default:
+      llvm_unreachable("unexpected machine operand type");
+    case MachineOperand::MO_Register: {
+      if (MO.isImplicit())
         continue;
       unsigned Reg = MO.getReg();
       OS << " @" << TargetRegisterInfo::virtReg2Index(Reg);
+    } break;
+    case MachineOperand::MO_Immediate: {
+      OS << ' ' << MO.getImm();
+    } break;
+    case MachineOperand::MO_FPImmediate: {
+      static const size_t BufBytes = 128;
+      char buf[BufBytes];
+      APFloat FP = MO.getFPImm()->getValueAPF();
+      const APFloat CanonicalNaN = APFloat::getQNaN(FP.getSemantics());
+      if (FP.isNaN() && !FP.bitwiseIsEqual(CanonicalNaN))
+        // WebAssembly only has NaNs that are positive, quiet, without payload.
+        FP = CanonicalNaN;
+      // Use C99's hexadecimal floating-point representation.
+      auto Written =
+          FP.convertToHexString(buf, /*hexDigits=*/0, /*upperCase=*/false,
+                                APFloat::rmNearestTiesToEven);
+      assert(Written != 0);
+      assert(Written < BufBytes);
+      OS << ' ' << buf;
+    } break;
     }
   OS << ')';
 
index 4360116..ee155fd 100644 (file)
@@ -108,7 +108,11 @@ WebAssemblyTargetLowering::WebAssemblyTargetLowering(
   // Compute derived properties from the register classes.
   computeRegisterProperties(Subtarget->getRegisterInfo());
 
-  // FIXME: setOperationAction...
+  // FIXME: many setOperationAction are missing...
+
+  // Don't expand the following types to constant pools.
+  setOperationAction(ISD::ConstantFP, MVT::f32, Legal);
+  setOperationAction(ISD::ConstantFP, MVT::f64, Legal);
 }
 
 MVT WebAssemblyTargetLowering::getScalarShiftAmountTy(const DataLayout &DL,
index e88a93a..c633572 100644 (file)
@@ -64,6 +64,16 @@ defm : ARGUMENT<Int64>;
 defm : ARGUMENT<Float32>;
 defm : ARGUMENT<Float64>;
 
+
+def Immediate_I32 : I<(outs Int32:$res), (ins i32imm:$imm),
+                      [(set Int32:$res, imm:$imm)]>;
+def Immediate_I64 : I<(outs Int64:$res), (ins i64imm:$imm),
+                      [(set Int64:$res, imm:$imm)]>;
+def Immediate_F32 : I<(outs Float32:$res), (ins f32imm:$imm),
+                      [(set Float32:$res, fpimm:$imm)]>;
+def Immediate_F64 : I<(outs Float64:$res), (ins f64imm:$imm),
+                      [(set Float64:$res, fpimm:$imm)]>;
+
 //===----------------------------------------------------------------------===//
 // Additional sets of instructions.
 //===----------------------------------------------------------------------===//
diff --git a/test/CodeGen/WebAssembly/immediates.ll b/test/CodeGen/WebAssembly/immediates.ll
new file mode 100644 (file)
index 0000000..f22e294
--- /dev/null
@@ -0,0 +1,174 @@
+; RUN: llc < %s -asm-verbose=false | FileCheck %s
+
+; Test that basic immediates assemble as expected.
+
+target datalayout = "e-p:32:32-i64:64-v128:8:128-n32:64-S128"
+target triple = "wasm32-unknown-unknown"
+
+; CHECK-LABEL: zero_i32:
+; CHECK-NEXT: (setlocal @0 (immediate 0))
+; CHECK-NEXT: (return @0)
+define i32 @zero_i32() {
+  ret i32 0
+}
+
+; CHECK-LABEL: one_i32:
+; CHECK-NEXT: (setlocal @0 (immediate 1))
+; CHECK-NEXT: (return @0)
+define i32 @one_i32() {
+  ret i32 1
+}
+
+; CHECK-LABEL: max_i32:
+; CHECK-NEXT: (setlocal @0 (immediate 2147483647))
+; CHECK-NEXT: (return @0)
+define i32 @max_i32() {
+  ret i32 2147483647
+}
+
+; CHECK-LABEL: min_i32:
+; CHECK-NEXT: (setlocal @0 (immediate -2147483648))
+; CHECK-NEXT: (return @0)
+define i32 @min_i32() {
+  ret i32 -2147483648
+}
+
+; CHECK-LABEL: zero_i64:
+; CHECK-NEXT: (setlocal @0 (immediate 0))
+; CHECK-NEXT: (return @0)
+define i64 @zero_i64() {
+  ret i64 0
+}
+
+; CHECK-LABEL: one_i64:
+; CHECK-NEXT: (setlocal @0 (immediate 1))
+; CHECK-NEXT: (return @0)
+define i64 @one_i64() {
+  ret i64 1
+}
+
+; CHECK-LABEL: max_i64:
+; CHECK-NEXT: (setlocal @0 (immediate 9223372036854775807))
+; CHECK-NEXT: (return @0)
+define i64 @max_i64() {
+  ret i64 9223372036854775807
+}
+
+; CHECK-LABEL: min_i64:
+; CHECK-NEXT: (setlocal @0 (immediate -9223372036854775808))
+; CHECK-NEXT: (return @0)
+define i64 @min_i64() {
+  ret i64 -9223372036854775808
+}
+
+; CHECK-LABEL: negzero_f32:
+; CHECK-NEXT: (setlocal @0 (immediate -0x0p0))
+; CHECK-NEXT: (return @0)
+define float @negzero_f32() {
+  ret float -0.0
+}
+
+; CHECK-LABEL: zero_f32:
+; CHECK-NEXT: (setlocal @0 (immediate 0x0p0))
+; CHECK-NEXT: (return @0)
+define float @zero_f32() {
+  ret float 0.0
+}
+
+; CHECK-LABEL: one_f32:
+; CHECK-NEXT: (setlocal @0 (immediate 0x1p0))
+; CHECK-NEXT: (return @0)
+define float @one_f32() {
+  ret float 1.0
+}
+
+; CHECK-LABEL: two_f32:
+; CHECK-NEXT: (setlocal @0 (immediate 0x1p1))
+; CHECK-NEXT: (return @0)
+define float @two_f32() {
+  ret float 2.0
+}
+
+; CHECK-LABEL: nan_f32:
+; CHECK-NEXT: (setlocal @0 (immediate nan))
+; CHECK-NEXT: (return @0)
+define float @nan_f32() {
+  ret float 0x7FF8000000000000
+}
+
+; CHECK-LABEL: negnan_f32:
+; CHECK-NEXT: (setlocal @0 (immediate nan))
+; CHECK-NEXT: (return @0)
+define float @negnan_f32() {
+  ret float 0xFFF8000000000000
+}
+
+; CHECK-LABEL: inf_f32:
+; CHECK-NEXT: (setlocal @0 (immediate infinity))
+; CHECK-NEXT: (return @0)
+define float @inf_f32() {
+  ret float 0x7FF0000000000000
+}
+
+; CHECK-LABEL: neginf_f32:
+; CHECK-NEXT: (setlocal @0 (immediate -infinity))
+; CHECK-NEXT: (return @0)
+define float @neginf_f32() {
+  ret float 0xFFF0000000000000
+}
+
+; CHECK-LABEL: negzero_f64:
+; CHECK-NEXT: (setlocal @0 (immediate -0x0p0))
+; CHECK-NEXT: (return @0)
+define double @negzero_f64() {
+  ret double -0.0
+}
+
+; CHECK-LABEL: zero_f64:
+; CHECK-NEXT: (setlocal @0 (immediate 0x0p0))
+; CHECK-NEXT: (return @0)
+define double @zero_f64() {
+  ret double 0.0
+}
+
+; CHECK-LABEL: one_f64:
+; CHECK-NEXT: (setlocal @0 (immediate 0x1p0))
+; CHECK-NEXT: (return @0)
+define double @one_f64() {
+  ret double 1.0
+}
+
+; CHECK-LABEL: two_f64:
+; CHECK-NEXT: (setlocal @0 (immediate 0x1p1))
+; CHECK-NEXT: (return @0)
+define double @two_f64() {
+  ret double 2.0
+}
+
+; CHECK-LABEL: nan_f64:
+; CHECK-NEXT: (setlocal @0 (immediate nan))
+; CHECK-NEXT: (return @0)
+define double @nan_f64() {
+  ret double 0x7FF8000000000000
+}
+
+; CHECK-LABEL: negnan_f64:
+; CHECK-NEXT: (setlocal @0 (immediate nan))
+; CHECK-NEXT: (return @0)
+define double @negnan_f64() {
+  ret double 0xFFF8000000000000
+}
+
+; CHECK-LABEL: inf_f64:
+; CHECK-NEXT: (setlocal @0 (immediate infinity))
+; CHECK-NEXT: (return @0)
+define double @inf_f64() {
+  ret double 0x7FF0000000000000
+}
+
+; CHECK-LABEL: neginf_f64:
+; CHECK-NEXT: (setlocal @0 (immediate -infinity))
+; CHECK-NEXT: (return @0)
+define double @neginf_f64() {
+  ret double 0xFFF0000000000000
+}