From 60b5a25d13eff60ee8ed43c72eeb4926dd51452c Mon Sep 17 00:00:00 2001 From: JF Bastien Date: Mon, 10 Aug 2015 22:36:48 +0000 Subject: [PATCH] WebAssembly: print immediates 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 --- .../WebAssembly/WebAssemblyAsmPrinter.cpp | 46 +++-- .../WebAssembly/WebAssemblyISelLowering.cpp | 6 +- .../WebAssembly/WebAssemblyInstrInfo.td | 10 + test/CodeGen/WebAssembly/immediates.ll | 174 ++++++++++++++++++ 4 files changed, 216 insertions(+), 20 deletions(-) create mode 100644 test/CodeGen/WebAssembly/immediates.ll diff --git a/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp b/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp index 99b23c7433b..35a4be3805d 100644 --- a/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp +++ b/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp @@ -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 << ')'; diff --git a/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp b/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp index 4360116a7f1..ee155fdbb22 100644 --- a/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp +++ b/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp @@ -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, diff --git a/lib/Target/WebAssembly/WebAssemblyInstrInfo.td b/lib/Target/WebAssembly/WebAssemblyInstrInfo.td index e88a93a63ae..c6335723b4c 100644 --- a/lib/Target/WebAssembly/WebAssemblyInstrInfo.td +++ b/lib/Target/WebAssembly/WebAssemblyInstrInfo.td @@ -64,6 +64,16 @@ defm : ARGUMENT; defm : ARGUMENT; defm : ARGUMENT; + +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 index 00000000000..f22e2943466 --- /dev/null +++ b/test/CodeGen/WebAssembly/immediates.ll @@ -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 +} -- 2.34.1