arch, x86: add support for arrays as memory operands
authorSteve Reinhardt <steve.reinhardt@amd.com>
Sun, 7 Feb 2016 01:21:20 +0000 (17:21 -0800)
committerSteve Reinhardt <steve.reinhardt@amd.com>
Sun, 7 Feb 2016 01:21:20 +0000 (17:21 -0800)
Although the cache models support wider accesses, the ISA descriptions
assume that (for the most part) memory operands are integer types,
which makes it difficult to define instructions that do memory accesses
larger than 64 bits.

This patch adds some generic support for memory operands that are arrays
of uint64_t, and specifically a 'u2qw' operand type for x86 that is an
array of 2 uint64_ts (128 bits).  This support is unused at this point,
but will be needed shortly for cmpxchg16b.  Ideally the 128-bit SSE
memory accesses will also be rewritten to use this support.

Support for 128-bit accesses could also have been added using the gcc
__int128_t extension, which would have been less disruptive.  However,
although clang also supports __int128_t, it's still non-standard.
Also, more importantly, this approach creates a path to defining
256- and 512-byte operands as well, which will be useful for eventual
AVX support.

src/arch/isa_parser.py
src/arch/x86/isa/includes.isa
src/arch/x86/isa/microops/ldstop.isa
src/arch/x86/isa/operands.isa
src/arch/x86/memhelpers.hh

index cbc8651d15d90bf1a2de5ea6509ca629545c5eab..749eaf88de8ef8dff7c0317debec020f7e3d2d26 100755 (executable)
@@ -1053,9 +1053,14 @@ stringRE = re.compile(r'"([^"\\]|\\.)*"')
 commentRE = re.compile(r'(^)?[^\S\n]*/(?:\*(.*?)\*/[^\S\n]*|/[^\n]*)($)?',
         re.DOTALL | re.MULTILINE)
 
-# Regular expression object to match assignment statements
-# (used in findOperands())
-assignRE = re.compile(r'\s*=(?!=)', re.MULTILINE)
+# Regular expression object to match assignment statements (used in
+# findOperands()).  If the code immediately following the first
+# appearance of the operand matches this regex, then the operand
+# appears to be on the LHS of an assignment, and is thus a
+# destination.  basically we're looking for an '=' that's not '=='.
+# The heinous tangle before that handles the case where the operand
+# has an array subscript.
+assignRE = re.compile(r'(\[[^\]]+\])?\s*=(?!=)', re.MULTILINE)
 
 def makeFlagConstructor(flag_list):
     if len(flag_list) == 0:
index 43565fda51671f855f7c07aa8051dd813dc63278..0d0c0de3e88cf069b16390a439455d5781884908 100644 (file)
@@ -49,6 +49,7 @@ let {{
 }};
 
 output header {{
+#include <array>
 #include <cstring>
 #include <iostream>
 #include <sstream>
index fa8bc6f2b29252265436e61c665a45905e877a1b..b35954439a949fa2f693fe7295620694c5ab69ba 100644 (file)
@@ -143,7 +143,7 @@ def template MicroLoadCompleteAcc {{
         %(op_decl)s;
         %(op_rd)s;
 
-        Mem = getMem(pkt, dataSize, traceData);
+        getMem(pkt, Mem, dataSize, traceData);
 
         %(code)s;
 
index 59adada13079e25e3d5b5da478b583182715a1be..baa8552e059eda89e3d910e9d85d360553db426e 100644 (file)
@@ -1,4 +1,5 @@
 // Copyright (c) 2007-2008 The Hewlett-Packard Development Company
+// Copyright (c) 2015 Advanced Micro Devices, Inc.
 // All rights reserved.
 //
 // The license below extends only to copyright in the software and shall
@@ -49,6 +50,7 @@ def operand_types {{
     'udw' : 'uint32_t',
     'sqw' : 'int64_t',
     'uqw' : 'uint64_t',
+    'u2qw' : 'std::array<uint64_t, 2>',
     'sf' : 'float',
     'df' : 'double',
 }};
index 705457d675fe48b1c51024218f439d8b4b68db21..b13207ec47ae514b21e6d6b8a96f947a17308758 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2011 Google
+ * Copyright (c) 2015 Advanced Micro Devices, Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,6 +32,8 @@
 #ifndef __ARCH_X86_MEMHELPERS_HH__
 #define __ARCH_X86_MEMHELPERS_HH__
 
+#include <array>
+
 #include "base/types.hh"
 #include "sim/byteswap.hh"
 #include "sim/insttracer.hh"
@@ -47,10 +50,10 @@ initiateMemRead(XC *xc, Trace::InstRecord *traceData, Addr addr,
     return xc->initiateMemRead(addr, dataSize, flags);
 }
 
-static inline uint64_t
-getMem(PacketPtr pkt, unsigned dataSize, Trace::InstRecord *traceData)
+static void
+getMem(PacketPtr pkt, uint64_t &mem, unsigned dataSize,
+       Trace::InstRecord *traceData)
 {
-    uint64_t mem;
     switch (dataSize) {
       case 1:
         mem = pkt->get<uint8_t>();
@@ -69,9 +72,31 @@ getMem(PacketPtr pkt, unsigned dataSize, Trace::InstRecord *traceData)
     }
     if (traceData)
         traceData->setData(mem);
-    return mem;
 }
 
+
+template <size_t N>
+void
+getMem(PacketPtr pkt, std::array<uint64_t, N> &mem, unsigned dataSize,
+       Trace::InstRecord *traceData)
+{
+    assert(dataSize >= 8);
+    assert((dataSize % 8) == 0);
+
+    int num_words = dataSize / 8;
+    assert(num_words <= N);
+
+    auto pkt_data = pkt->getConstPtr<const uint64_t>();
+    for (int i = 0; i < num_words; ++i)
+        mem[i] = gtoh(pkt_data[i]);
+
+    // traceData record only has space for 64 bits, so we just record
+    // the first qword
+    if (traceData)
+        traceData->setData(mem[0]);
+}
+
+
 template <class XC>
 Fault
 readMemAtomic(XC *xc, Trace::InstRecord *traceData, Addr addr, uint64_t &mem,
@@ -90,6 +115,30 @@ readMemAtomic(XC *xc, Trace::InstRecord *traceData, Addr addr, uint64_t &mem,
     return fault;
 }
 
+template <class XC, size_t N>
+Fault
+readMemAtomic(XC *xc, Trace::InstRecord *traceData, Addr addr,
+              std::array<uint64_t, N> &mem, unsigned dataSize,
+              unsigned flags)
+{
+    assert(dataSize >= 8);
+    assert((dataSize % 8) == 0);
+
+    Fault fault = xc->readMem(addr, (uint8_t *)&mem, dataSize, flags);
+
+    if (fault == NoFault) {
+        int num_words = dataSize / 8;
+        assert(num_words <= N);
+
+        for (int i = 0; i < num_words; ++i)
+            mem[i] = gtoh(mem[i]);
+
+        if (traceData)
+            traceData->setData(mem[0]);
+    }
+    return fault;
+}
+
 template <class XC>
 Fault
 writeMemTiming(XC *xc, Trace::InstRecord *traceData, uint64_t mem,
@@ -102,6 +151,28 @@ writeMemTiming(XC *xc, Trace::InstRecord *traceData, uint64_t mem,
     return xc->writeMem((uint8_t *)&mem, dataSize, addr, flags, res);
 }
 
+template <class XC, size_t N>
+Fault
+writeMemTiming(XC *xc, Trace::InstRecord *traceData,
+               std::array<uint64_t, N> &mem, unsigned dataSize,
+               Addr addr, unsigned flags, uint64_t *res)
+{
+    assert(dataSize >= 8);
+    assert((dataSize % 8) == 0);
+
+    if (traceData) {
+        traceData->setData(mem[0]);
+    }
+
+    int num_words = dataSize / 8;
+    assert(num_words <= N);
+
+    for (int i = 0; i < num_words; ++i)
+        mem[i] = htog(mem[i]);
+
+    return xc->writeMem((uint8_t *)&mem, dataSize, addr, flags, res);
+}
+
 template <class XC>
 Fault
 writeMemAtomic(XC *xc, Trace::InstRecord *traceData, uint64_t mem,
@@ -119,6 +190,31 @@ writeMemAtomic(XC *xc, Trace::InstRecord *traceData, uint64_t mem,
     return fault;
 }
 
+template <class XC, size_t N>
+Fault
+writeMemAtomic(XC *xc, Trace::InstRecord *traceData,
+               std::array<uint64_t, N> &mem, unsigned dataSize,
+               Addr addr, unsigned flags, uint64_t *res)
+{
+    if (traceData) {
+        traceData->setData(mem[0]);
+    }
+
+    int num_words = dataSize / 8;
+    assert(num_words <= N);
+
+    for (int i = 0; i < num_words; ++i)
+        mem[i] = htog(mem[i]);
+
+    Fault fault = xc->writeMem((uint8_t *)&mem, dataSize, addr, flags, res);
+
+    if (fault == NoFault && res != NULL) {
+        *res = gtoh(*res);
+    }
+
+    return fault;
+}
+
 }
 
 #endif