arch-power: Add doubleword multiply-add instructions

This introduces 128-bit addition helpers and adds the
following instructions.
  * Multiply-Add Low Doubleword (maddld)
  * Multiply-Add High Doubleword (maddhd)
  * Multiply-Add High Doubleword Unsigned (maddhdu)

Change-Id: I04e6ea5fb4978b341a6e648424de2930ad41f449
Signed-off-by: Sandipan Das <sandipan@linux.ibm.com>
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/40905
Reviewed-by: Boris Shingarov <shingarov@labware.com>
Maintainer: Jason Lowe-Power <power.jg@gmail.com>
Tested-by: kokoro <noreply+kokoro@google.com>
This commit is contained in:
Sandipan Das
2021-02-06 17:17:53 +05:30
committed by Boris Shingarov
parent a74a9633f2
commit 52fb5e42ec
4 changed files with 134 additions and 0 deletions

View File

@@ -117,6 +117,7 @@ IntArithOp::generateDisassembly(
{
std::stringstream ss;
bool printSecondSrc = true;
bool printThirdSrc = false;
// Generate the correct mnemonic
std::string myMnemonic(mnemonic);
@@ -128,6 +129,10 @@ IntArithOp::generateDisassembly(
myMnemonic == "subfze" ||
myMnemonic == "neg") {
printSecondSrc = false;
} else if (myMnemonic == "maddhd" ||
myMnemonic == "maddhdu" ||
myMnemonic == "maddld") {
printThirdSrc = true;
}
// Additional characters depending on isa bits being set
@@ -151,6 +156,12 @@ IntArithOp::generateDisassembly(
if (_numSrcRegs > 1 && printSecondSrc) {
ss << ", ";
printReg(ss, srcRegIdx(1));
// Print the third source register
if (_numSrcRegs > 2 && printThirdSrc) {
ss << ", ";
printReg(ss, srcRegIdx(2));
}
}
}

View File

@@ -134,6 +134,52 @@ class IntArithOp : public IntOp
{
}
/* Compute 128-bit sum of 128-bit to 64-bit unsigned integer addition */
inline std::tuple<uint64_t, uint64_t>
add(uint64_t ralo, uint64_t rahi, uint64_t rb) const
{
uint64_t slo, shi;
#if defined(__SIZEOF_INT128__)
__uint128_t ra = ((__uint128_t)rahi << 64) | ralo;
__uint128_t sum = ra + rb;
slo = sum;
shi = sum >> 64;
#else
shi = rahi + ((ralo + rb) < ralo);
slo = ralo + rb;
#endif
return std::make_tuple(slo, shi);
}
/* Compute 128-bit sum of 128-bit to 64-bit signed integer addition */
inline std::tuple<uint64_t, int64_t>
add(uint64_t ralo, int64_t rahi, int64_t rb) const
{
uint64_t slo;
int64_t shi;
#if defined(__SIZEOF_INT128__)
__int128_t ra = ((__int128_t)rahi << 64) | ralo;
__int128_t sum = (__int128_t)ra + rb;
slo = sum;
shi = sum >> 64;
#else
if (rb < 0) {
shi = rahi - 1;
slo = ralo + rb;
if (slo < rb) {
shi++;
}
} else {
shi = rahi;
slo = ralo + rb;
if (slo < rb) {
shi++;
}
}
#endif
return std::make_tuple(slo, shi);
}
/**
* Compute 128-bit product of 64-bit unsigned integer multiplication
* based on https://stackoverflow.com/a/28904636
@@ -177,6 +223,48 @@ class IntArithOp : public IntOp
return std::make_tuple(plo, (int64_t)phi);
}
/**
* Compute 128-bit result of 64-bit unsigned integer multiplication
* followed by addition
*/
inline std::tuple<uint64_t, uint64_t>
multiplyAdd(uint64_t ra, uint64_t rb, uint64_t rc) const
{
uint64_t rlo, rhi;
#if defined(__SIZEOF_INT128__)
__uint128_t res = ((__uint128_t)ra * rb) + rc;
rlo = res;
rhi = res >> 64;
#else
uint64_t plo, phi;
std::tie(plo, phi) = multiply(ra, rb);
std::tie(rlo, rhi) = add(plo, phi, rc);
#endif
return std::make_tuple(rlo, rhi);
}
/**
* Compute 128-bit result of 64-bit signed integer multiplication
* followed by addition
*/
inline std::tuple<uint64_t, int64_t>
multiplyAdd(int64_t ra, int64_t rb, int64_t rc) const
{
uint64_t rlo;
int64_t rhi;
#if defined(__SIZEOF_INT128__)
__int128_t res = (__int128_t)ra * rb + rc;
rlo = res;
rhi = res >> 64;
#else
uint64_t plo;
int64_t phi;
std::tie(plo, phi) = multiply(ra, rb);
std::tie(rlo, rhi) = add(plo, phi, rc);
#endif
return std::make_tuple(rlo, rhi);
}
std::string generateDisassembly(
Addr pc, const Loader::SymbolTable *symtab) const override;
};

View File

@@ -36,6 +36,31 @@
//
decode PO default Unknown::unknown() {
4: decode VA_XO {
// Arithmetic instructions that use source registers Ra, Rb and Rc,
// with destination register Rt.
format IntArithOp {
48: maddhd({{
int64_t res;
std::tie(std::ignore, res) = multiplyAdd(Ra_sd, Rb_sd, Rc_sd);
Rt = res;
}});
49: maddhdu({{
uint64_t res;
std::tie(std::ignore, res) = multiplyAdd(Ra, Rb, Rc);
Rt = res;
}});
51: maddld({{
uint64_t res;
std::tie(res, std::ignore) = multiplyAdd(Ra_sd, Rb_sd, Rc_sd);
Rt = res;
}});
}
}
format IntImmArithOp {
7: mulli({{
int64_t res = Ra_sd * si;

View File

@@ -290,6 +290,16 @@ def format IntSumOp(src1, src2, ca = {{ 0 }}, computeCA = 0,
}};
// Instructions that use source registers Ra and Rb, with the result
// placed into Rt but do not check for carry, overflow or the Rc bit.
def format IntArithOp(code, inst_flags = []) {{
# Generate the class
(header_output, decoder_output, decode_block, exec_output) = \
GenAluOp(name, Name, 'IntArithOp', code, inst_flags, BasicDecode,
BasicConstructor)
}};
// Instructions that use source registers Ra and Rb, with the result
// placed into Rt. Basically multiply and divide instructions. The