Skip to content

Commit

Permalink
WebAssembly: print immediates
Browse files Browse the repository at this point in the history
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

llvm-svn: 244520
  • Loading branch information
jfbastien committed Aug 10, 2015
1 parent 6dce129 commit 4a64225
Show file tree
Hide file tree
Showing 4 changed files with 216 additions and 20 deletions.
46 changes: 27 additions & 19 deletions llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
Expand Up @@ -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 << ')';

Expand Down
6 changes: 5 additions & 1 deletion llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
Expand Up @@ -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,
Expand Down
10 changes: 10 additions & 0 deletions llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td
Expand Up @@ -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.
//===----------------------------------------------------------------------===//
Expand Down
174 changes: 174 additions & 0 deletions llvm/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
}

0 comments on commit 4a64225

Please sign in to comment.