Clang floating-point alignment on powerpc

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view

Clang floating-point alignment on powerpc

Mark Kettenis
As pointed out by George Koehler, clang may generate floating-point
load and store instructions that are misaligned.  Modern POWER CPUs
support this in hardware, allegedly without making things
significantly slower.  But the traditional PowerPC CPUs that OpenBSD
runs on don't support this and generate an alignment trap.

Later versions of the POWER ISA (I checked version 2.0.7 and 3.0)
contain a "programming note" that states that the alignment exception
handler should emulate unaligned access in this case.  With that in
mind, clang's behaviour makes some sense.  It will generate code that
is optimized for modern CPUs while the code will still run, with the
help of the OS, on older CPUs.

OpenBSD does emulate lfd/stfd instructions (double-precision
load/store), but does not emulate lfs/stfs (single-precision).  We
could of course extend the emulation code, but frankly we don't want
to emulation if it will happen on the vast majority of the systems we
run on.  So I think George's diff is indeed the way to go.

Here is a polished version that checks whether the target is OpenBSD
before refusing the misaligned access.


Index: gnu/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
RCS file: /cvs/src/gnu/llvm/lib/Target/PowerPC/PPCISelLowering.cpp,v
retrieving revision
diff -u -p -r1.1.1.6 PPCISelLowering.cpp
--- gnu/llvm/lib/Target/PowerPC/PPCISelLowering.cpp 27 Jan 2019 16:42:22 -0000
+++ gnu/llvm/lib/Target/PowerPC/PPCISelLowering.cpp 16 Feb 2019 12:11:26 -0000
@@ -13921,6 +13921,14 @@ bool PPCTargetLowering::allowsMisaligned
   if (VT == MVT::ppcf128)
     return false;
+  if (Subtarget.isTargetOpenBSD()) {
+    // Traditional PowerPC does not support unaligned memory access
+    // for floating-point and the OpenBSD kernel does not emulate
+    // all possible floating-point load-store instructions.
+    if (VT == MVT::f32 || VT == MVT::f64)
+      return false;
+  }
   if (Fast)
     *Fast = true;
Index: gnu/llvm/lib/Target/PowerPC/PPCSubtarget.h
RCS file: /cvs/src/gnu/llvm/lib/Target/PowerPC/PPCSubtarget.h,v
retrieving revision
diff -u -p -r1.1.1.6 PPCSubtarget.h
--- gnu/llvm/lib/Target/PowerPC/PPCSubtarget.h 27 Jan 2019 16:42:22 -0000
+++ gnu/llvm/lib/Target/PowerPC/PPCSubtarget.h 16 Feb 2019 12:11:26 -0000
@@ -305,6 +305,7 @@ public:
   bool isTargetELF() const { return TargetTriple.isOSBinFormatELF(); }
   bool isTargetMachO() const { return TargetTriple.isOSBinFormatMachO(); }
   bool isTargetLinux() const { return TargetTriple.isOSLinux(); }
+  bool isTargetOpenBSD() const { return TargetTriple.isOSOpenBSD(); }
   bool isDarwinABI() const { return isTargetMachO() || isDarwin(); }
   bool isSVR4ABI() const { return !isDarwinABI(); }