forked from OSchip/llvm-project
[WebAssembly] Implement support for custom NaN bit patterns.
llvm-svn: 260968
This commit is contained in:
parent
c70aedab0e
commit
aa7429112e
|
@ -110,7 +110,8 @@ MCDisassembler::DecodeStatus WebAssemblyDisassembler::getInstruction(
|
|||
MI.addOperand(MCOperand::createReg(Reg));
|
||||
break;
|
||||
}
|
||||
case WebAssembly::OPERAND_FPIMM: {
|
||||
case WebAssembly::OPERAND_FP32IMM:
|
||||
case WebAssembly::OPERAND_FP64IMM: {
|
||||
// TODO: MC converts all floating point immediate operands to double.
|
||||
// This is fine for numeric values, but may cause NaNs to change bits.
|
||||
if (Pos + sizeof(uint64_t) > Bytes.size())
|
||||
|
|
|
@ -110,14 +110,22 @@ void WebAssemblyInstPrinter::printInst(const MCInst *MI, raw_ostream &OS,
|
|||
}
|
||||
|
||||
static std::string toString(const APFloat &FP) {
|
||||
// Print NaNs with custom payloads specially.
|
||||
if (FP.isNaN() &&
|
||||
!FP.bitwiseIsEqual(APFloat::getQNaN(FP.getSemantics())) &&
|
||||
!FP.bitwiseIsEqual(APFloat::getQNaN(FP.getSemantics(), /*Negative=*/true))) {
|
||||
APInt AI = FP.bitcastToAPInt();
|
||||
return
|
||||
std::string(AI.isNegative() ? "-" : "") + "nan:0x" +
|
||||
utohexstr(AI.getZExtValue() &
|
||||
(AI.getBitWidth() == 32 ? INT64_C(0x007fffff) :
|
||||
INT64_C(0x000fffffffffffff)),
|
||||
/*LowerCase=*/true);
|
||||
}
|
||||
|
||||
// Use C99's hexadecimal floating-point representation.
|
||||
static const size_t BufBytes = 128;
|
||||
char buf[BufBytes];
|
||||
if (FP.isNaN())
|
||||
assert((FP.bitwiseIsEqual(APFloat::getQNaN(FP.getSemantics())) ||
|
||||
FP.bitwiseIsEqual(
|
||||
APFloat::getQNaN(FP.getSemantics(), /*Negative=*/true))) &&
|
||||
"convertToHexString handles neither SNaN nor NaN payloads");
|
||||
// Use C99's hexadecimal floating-point representation.
|
||||
auto Written = FP.convertToHexString(
|
||||
buf, /*hexDigits=*/0, /*upperCase=*/false, APFloat::rmNearestTiesToEven);
|
||||
(void)Written;
|
||||
|
@ -157,10 +165,20 @@ void WebAssemblyInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
|
|||
// control flow stack, and it may be nice to pretty-print.
|
||||
O << Op.getImm();
|
||||
} else if (Op.isFPImm()) {
|
||||
assert((OpNo < MII.get(MI->getOpcode()).getNumOperands() ||
|
||||
MII.get(MI->getOpcode()).TSFlags == 0) &&
|
||||
const MCInstrDesc &Desc = MII.get(MI->getOpcode());
|
||||
assert(OpNo < Desc.getNumOperands() &&
|
||||
"Unexpected floating-point immediate as a non-fixed operand");
|
||||
assert(Desc.TSFlags == 0 &&
|
||||
"WebAssembly variable_ops floating point ops don't use TSFlags");
|
||||
O << toString(APFloat(Op.getFPImm()));
|
||||
const MCOperandInfo &Info = Desc.OpInfo[OpNo];
|
||||
if (Info.OperandType == WebAssembly::OPERAND_FP32IMM) {
|
||||
// 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())));
|
||||
} else {
|
||||
assert(Info.OperandType == WebAssembly::OPERAND_FP64IMM);
|
||||
O << toString(APFloat(Op.getFPImm()));
|
||||
}
|
||||
} else {
|
||||
assert((OpNo < MII.get(MI->getOpcode()).getNumOperands() ||
|
||||
(MII.get(MI->getOpcode()).TSFlags &
|
||||
|
|
|
@ -44,8 +44,10 @@ namespace WebAssembly {
|
|||
enum OperandType {
|
||||
/// Basic block label in a branch construct.
|
||||
OPERAND_BASIC_BLOCK = MCOI::OPERAND_FIRST_TARGET,
|
||||
/// Floating-point immediate.
|
||||
OPERAND_FPIMM,
|
||||
/// 32-bit floating-point immediates.
|
||||
OPERAND_FP32IMM,
|
||||
/// 64-bit floating-point immediates.
|
||||
OPERAND_FP64IMM,
|
||||
/// p2align immediate for load and store address alignment.
|
||||
OPERAND_P2ALIGN
|
||||
};
|
||||
|
|
|
@ -71,10 +71,11 @@ let OperandNamespace = "WebAssembly" in {
|
|||
let OperandType = "OPERAND_BASIC_BLOCK" in
|
||||
def bb_op : Operand<OtherVT>;
|
||||
|
||||
let OperandType = "OPERAND_FPIMM" in {
|
||||
let OperandType = "OPERAND_FP32IMM" in
|
||||
def f32imm_op : Operand<f32>;
|
||||
|
||||
let OperandType = "OPERAND_FP64IMM" in
|
||||
def f64imm_op : Operand<f64>;
|
||||
} // OperandType = "OPERAND_FPIMM"
|
||||
|
||||
let OperandType = "OPERAND_P2ALIGN" in {
|
||||
def P2Align : Operand<i32> {
|
||||
|
|
|
@ -133,6 +133,25 @@ define float @neginf_f32() {
|
|||
ret float 0xFFF0000000000000
|
||||
}
|
||||
|
||||
; CHECK-LABEL: custom_nan_f32:
|
||||
; CHECK-NEXT: .result f32{{$}}
|
||||
; CHECK-NEXT: f32.const $push[[NUM:[0-9]+]]=, -nan:0x6bcdef{{$}}
|
||||
; CHECK-NEXT: return $pop[[NUM]]{{$}}
|
||||
define float @custom_nan_f32() {
|
||||
ret float 0xFFFD79BDE0000000
|
||||
}
|
||||
|
||||
; TODO: LLVM's MC layer stores f32 operands as host doubles, requiring a
|
||||
; conversion, so the bits of the NaN are not fully preserved.
|
||||
|
||||
; CHECK-LABEL: custom_nans_f32:
|
||||
; CHECK-NEXT: .result f32{{$}}
|
||||
; CHECK-NEXT: f32.const $push[[NUM:[0-9]+]]=, -nan:0x6bcdef{{$}}
|
||||
; CHECK-NEXT: return $pop[[NUM]]{{$}}
|
||||
define float @custom_nans_f32() {
|
||||
ret float 0xFFF579BDE0000000
|
||||
}
|
||||
|
||||
; CHECK-LABEL: negzero_f64:
|
||||
; CHECK-NEXT: .result f64{{$}}
|
||||
; CHECK-NEXT: f64.const $push[[NUM:[0-9]+]]=, -0x0p0{{$}}
|
||||
|
@ -196,3 +215,19 @@ define double @inf_f64() {
|
|||
define double @neginf_f64() {
|
||||
ret double 0xFFF0000000000000
|
||||
}
|
||||
|
||||
; CHECK-LABEL: custom_nan_f64:
|
||||
; CHECK-NEXT: .result f64{{$}}
|
||||
; CHECK-NEXT: f64.const $push[[NUM:[0-9]+]]=, -nan:0xabcdef0123456{{$}}
|
||||
; CHECK-NEXT: return $pop[[NUM]]{{$}}
|
||||
define double @custom_nan_f64() {
|
||||
ret double 0xFFFABCDEF0123456
|
||||
}
|
||||
|
||||
; CHECK-LABEL: custom_nans_f64:
|
||||
; CHECK-NEXT: .result f64{{$}}
|
||||
; CHECK-NEXT: f64.const $push[[NUM:[0-9]+]]=, -nan:0x2bcdef0123456{{$}}
|
||||
; CHECK-NEXT: return $pop[[NUM]]{{$}}
|
||||
define double @custom_nans_f64() {
|
||||
ret double 0xFFF2BCDEF0123456
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue