[sw] Move our memory operation functions into lib/base.

This change also introduces read_32() and write_32(), for doing
direct word manipulation without violating strict alising. These
functions will be useful for DIF implementations.

Signed-off-by: Miguel Young de la Sota <mcyoung@google.com>
diff --git a/sw/device/lib/abort.c b/sw/device/lib/abort.c
deleted file mode 100644
index 2185f8b..0000000
--- a/sw/device/lib/abort.c
+++ /dev/null
@@ -1,11 +0,0 @@
-// Copyright lowRISC contributors.
-// Licensed under the Apache License, Version 2.0, see LICENSE for details.
-// SPDX-License-Identifier: Apache-2.0
-
-#include "sw/device/lib/common.h"
-
-_Noreturn void abort(void) {
-  while (true) {
-    asm volatile("wfi;");
-  }
-}
diff --git a/sw/device/lib/base/memory.c b/sw/device/lib/base/memory.c
new file mode 100644
index 0000000..d403989
--- /dev/null
+++ b/sw/device/lib/base/memory.c
@@ -0,0 +1,32 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+#include "sw/device/lib/base/memory.h"
+
+extern uint32_t read_32(void *);
+extern void write_32(uint32_t, void *);
+
+void *memcpy(void *restrict dest, const void *restrict src, size_t len) {
+  uint8_t *dest8 = (uint8_t *)dest;
+  uint8_t *src8 = (uint8_t *)src;
+  for (size_t i = 0; i < len; ++i) {
+    dest8[i] = src8[i];
+  }
+  return dest;
+}
+
+void *memset(void *dest, int value, size_t len) {
+  uint8_t *dest8 = (uint8_t *)dest;
+  uint8_t value8 = (uint8_t)value;
+  for (size_t i = 0; i < len; ++i) {
+    dest8[i] = value8;
+  }
+  return dest;
+}
+
+noreturn void abort(void) {
+  while (true) {
+    asm volatile("wfi");
+  }
+}
diff --git a/sw/device/lib/base/memory.h b/sw/device/lib/base/memory.h
new file mode 100644
index 0000000..bf1d280
--- /dev/null
+++ b/sw/device/lib/base/memory.h
@@ -0,0 +1,107 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+#ifndef SW_DEVICE_LIB_BASE_MEMORY_H_
+#define SW_DEVICE_LIB_BASE_MEMORY_H_
+
+#include <stdalign.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdnoreturn.h>
+
+#include "sw/device/lib/base/stdasm.h"
+
+/**
+ * Load a word from memory directly, bypassing aliasing rules.
+ *
+ * ISO C forbids, in general, casting a pointer to non-character types and
+ * reading them, though it is frequently necessary to read exactly one word out
+ * of a |void *|. This function performs that action in a manner which is
+ * well-defined.
+ *
+ * Of course, |ptr| must point to word-aligned memory that is at least one word
+ * wide. To do otherwise is Undefined Behavior. It goes eithout saying that the
+ * memory this function intents to read must be initialized.
+ *
+ * This function has reordering properties as weak as a normal, non-atomic,
+ * non-volatile load.
+ *
+ * @param ptr a word-aligned pointer pointed to at least four bytes of memory.
+ * @return the word |ptr| points to.
+ */
+inline uint32_t read_32(void *ptr) {
+  // Both GCC and Clang optimize the code below into a single word-load on most
+  // platforms. It is necessary and sufficient to indicate to the compiler that
+  // the pointer points to four bytes of four-byte-aligned memory.
+  //
+  // Failing to get that particular codegen in either GCC or Clang with -O2 or
+  // -Os set shall be considred a bug in this function. The same applies to
+  // |write32()|.
+  ptr = __builtin_assume_aligned(ptr, alignof(uint32_t));
+  uint32_t val;
+  __builtin_memcpy(&val, ptr, sizeof(uint32_t));
+  return val;
+}
+
+/**
+ * Store a word to memory directly, bypassing aliasing rules.
+ *
+ * ISO C forbids, in general, casting a pointer to non-character types and
+ * reading them, though it is frequently necessary to write exactly one word to
+ * a |void *|. This function performs that action in a manner which is
+ * well-defined.
+ *
+ * Of course, |ptr| must point to word-aligned memory that is at least one word
+ * wide. To do otherwise is Undefined Behavior.
+ *
+ * This function has reordering properties as weak as a normal, non-atomic,
+ * non-volatile load.
+ *
+ * @param value the value to store.
+ * @param ptr a word-aligned pointer pointed to at least four bytes of memory.
+ */
+inline void write_32(uint32_t value, void *ptr) {
+  // Both GCC and Clang optimize the code below into a single word-store on most
+  // platforms. See the comment in |read_32()| for more implementation-private
+  // information.
+  ptr = __builtin_assume_aligned(ptr, alignof(uint32_t));
+  __builtin_memcpy(ptr, &value, sizeof(uint32_t));
+}
+
+/**
+ * Copy memory between non-overlapping regions.
+ *
+ * This function conforms to the semantics defined in ISO C11 S7.23.2.1.
+ *
+ * @param dest the region to copy to.
+ * @param src the region to copy from.
+ * @param len the number of bytes to copy.
+ * @return the value of |dest|.
+ */
+void *memcpy(void *restrict dest, const void *restrict src, size_t len);
+
+/**
+ * Set a region of memory to a particular byte value.
+ *
+ * This function conforms to the semantics defined in ISO C11 S7.23.6.1.
+ *
+ * @param dest the region to write to.
+ * @param value the value, converted to a byte, to write to each byte cell.
+ * @param len the number of bytes to write.
+ * #return the value of |dest|.
+ */
+void *memset(void *dest, int value, size_t len);
+
+// TODO: Find a better header for this function to live. See #1207.
+/**
+ * Immediately halt program execution.
+ *
+ * This function conforms to the semantics defined in ISO C11 S7.22.4.1, except
+ * that it cannot be pre-empted by signal handlers (which do not exist in this
+ * environment).
+ */
+noreturn void abort(void);
+
+#endif  // SW_DEVICE_LIB_BASE_MEMORY_H_
diff --git a/sw/device/lib/base/meson.build b/sw/device/lib/base/meson.build
new file mode 100644
index 0000000..0beab29
--- /dev/null
+++ b/sw/device/lib/base/meson.build
@@ -0,0 +1,13 @@
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+
+# Memory Operations library (sw_lib_mem)
+sw_lib_mem = declare_dependency(
+  link_with: static_library(
+    'mem_ot',
+    sources: ['memory.c'],
+    c_args: ['-fno-builtin'],
+  )
+)
+
diff --git a/sw/device/lib/common.h b/sw/device/lib/common.h
index 1aa2b30..8ef1c51 100644
--- a/sw/device/lib/common.h
+++ b/sw/device/lib/common.h
@@ -11,6 +11,7 @@
 #include <stdnoreturn.h>
 
 #include "sw/device/lib/base/stdasm.h"
+#include "sw/device/lib/base/memory.h"
 
 #ifdef SIMULATION
 #define CLK_FIXED_FREQ_HZ (500 * 1000)
@@ -45,9 +46,4 @@
 #define BITLENGTH(X) \
   ((BITLENGTH_5(BITLENGTH_4(BITLENGTH_3(BITLENGTH_2(BITLENGTH_1(X)))))) & 0x7f)
 
-void *memcpy(void *restrict dest, const void *restrict src, size_t n);
-void *memset(void *dest, int val, size_t n);
-
-void abort(void);
-
 #endif
diff --git a/sw/device/lib/memcpy.c b/sw/device/lib/memcpy.c
deleted file mode 100644
index 8fd7401..0000000
--- a/sw/device/lib/memcpy.c
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright lowRISC contributors.
-// Licensed under the Apache License, Version 2.0, see LICENSE for details.
-// SPDX-License-Identifier: Apache-2.0
-
-#include "sw/device/lib/common.h"
-
-void *memcpy(void *dest, const void *src, size_t n) {
-  char *dest_c = (char *)dest;
-  char *src_c = (char *)src;
-
-  for (; n > 0; n--) {
-    *dest_c++ = *src_c++;
-  }
-
-  return dest;
-}
diff --git a/sw/device/lib/memset.c b/sw/device/lib/memset.c
deleted file mode 100644
index 36150b0..0000000
--- a/sw/device/lib/memset.c
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright lowRISC contributors.
-// Licensed under the Apache License, Version 2.0, see LICENSE for details.
-// SPDX-License-Identifier: Apache-2.0
-
-#include "sw/device/lib/common.h"
-
-void *memset(void *dest, int val, size_t n) {
-  char *dest_c = (char *)dest;
-
-  for (; n > 0; n--) {
-    *dest_c++ = (char)val;
-  }
-
-  return dest;
-}
diff --git a/sw/device/lib/meson.build b/sw/device/lib/meson.build
index 6c29b60..bd88345 100644
--- a/sw/device/lib/meson.build
+++ b/sw/device/lib/meson.build
@@ -2,20 +2,7 @@
 # Licensed under the Apache License, Version 2.0, see LICENSE for details.
 # SPDX-License-Identifier: Apache-2.0
 
-# Memory Operations library (sw_lib_mem)
-sw_lib_mem = declare_dependency(
-  link_with: static_library(
-    'mem_ot',
-    sources: [
-      'memcpy.c',
-      'memset.c',
-      'abort.c',
-    ],
-    c_args: [
-      '-fno-builtin',
-    ],
-  )
-)
+subdir('base')
 
 # UART library (sw_lib_uart)
 sw_lib_uart = declare_dependency(