Skip to content

Modeling CPU-specific behavior #766

Description

@mrexodia

Certain behaviors are CPU model-specific. One example is floating point rounding/approximation functions: https://www.felixcloutier.com/x86/rsqrtss

The semantics are vagueposted:

DEST[31:0] := APPROXIMATE(1/SQRT(SRC2[31:0]))
DEST[MAXVL-1:32] (Unmodified)

Currently it's implemented like this:

template <typename D, typename S1, typename S2>
DEF_SEM(RSQRTSS, D dst, S1 src1, S2 src2) {

  // Extract a "single-precision" (32-bit) float from [31:0] of src2 vector:
  auto src_float = FExtractV32(FReadV32(src2), 0);

  // Initialize dest vector, while also copying src1[127:32] -> dst[127:32].
  auto temp_vec = FReadV32(src1);

  // Store the square root result in dest[31:0]:
  auto square_root = SquareRoot32(memory, state, src_float);
  temp_vec = FInsertV32(temp_vec, 0, FDiv(1.0f, square_root));

  // Write out the result and return memory state:
  FWriteV32(dst, temp_vec);  // SSE: Writes to XMM, AVX: Zero-extends XMM.
  return memory;
}

But this isn't strictly correct and doesn't match on the bit-level. Ghidra implements this as a pcodeop:

define pcodeop rsqrtss;
:RSQRTSS         XmmReg, m32      is vexMode=0 &  $(PRE_F3) & byte=0x0F; byte=0x52; XmmReg ... & m32 { XmmReg = rsqrtss(XmmReg, m32); }
:RSQRTSS         XmmReg1, XmmReg2 is vexMode=0 &  $(PRE_F3) & byte=0x0F; byte=0x52; xmmmod = 3 & XmmReg1 & XmmReg2 { XmmReg1 = rsqrtss(XmmReg1, XmmReg2); }

Should we do the same and use an intrinsic for things like this? There is a similar issue with undefined flags, which you might want to implement in different ways depending on the CPU the software runs on which would require a 'similar' intrinsic. Just opening this for discussion.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions