x86 nativeGen: Fix test with mask in range [128,255] (#13425)
authorReid Barton <rwbarton@gmail.com>
Fri, 24 Mar 2017 01:02:29 +0000 (21:02 -0400)
committerBen Gamari <ben@smart-cactus.org>
Fri, 24 Mar 2017 14:14:26 +0000 (10:14 -0400)
My commit bdb0c43c7 optimized the encoding of instructions to test
tag bits, but it did not always set exactly the same condition codes
since the testb instruction does a single-byte comparison, rather
than a full-word comparison.

It would be correct to optimize the expression `x .&. 128 > 0` to
the sequence

    testb $128, %al
    seta %al         ; note: 'a' for unsigned comparison,
                     ; not 'g' for signed comparison

but the pretty-printer is not the right place to make this kind of
context-sensitive optimization.

Test Plan: harbormaster

Reviewers: trofi, austin, bgamari, dfeuer

Reviewed By: trofi, dfeuer

Subscribers: thomie

Differential Revision: https://phabricator.haskell.org/D3359

compiler/nativeGen/X86/Ppr.hs
testsuite/tests/codeGen/should_run/T13425.hs [new file with mode: 0644]
testsuite/tests/codeGen/should_run/T13425.stdout [new file with mode: 0644]
testsuite/tests/codeGen/should_run/all.T

index 7d19e99..5044c83 100644 (file)
@@ -671,8 +671,12 @@ pprInstr (TEST format src dst) = sdocWithPlatform $ \platform ->
         -- (We could handle masks larger than a single byte too,
         -- but it would complicate the code considerably
         -- and tag checks are by far the most common case.)
+        -- The mask must have the high bit clear for this smaller encoding
+        -- to be completely equivalent to the original; in particular so
+        -- that the signed comparison condition bits are the same as they
+        -- would be if doing a full word comparison. See Trac #13425.
         (OpImm (ImmInteger mask), OpReg dstReg)
-          | 0 <= mask && mask < 256 -> minSizeOfReg platform dstReg
+          | 0 <= mask && mask < 128 -> minSizeOfReg platform dstReg
         _ -> format
   in pprFormatOpOp (sLit "test") format' src dst
   where
diff --git a/testsuite/tests/codeGen/should_run/T13425.hs b/testsuite/tests/codeGen/should_run/T13425.hs
new file mode 100644 (file)
index 0000000..49d0721
--- /dev/null
@@ -0,0 +1,10 @@
+import Data.Bits ((.&.))
+
+flags :: Int -> Int
+flags x
+  | x .&. 128 > 0 = 12
+  | otherwise = 13
+{-# NOINLINE flags #-}
+
+main :: IO ()
+main = print (flags 255)
diff --git a/testsuite/tests/codeGen/should_run/T13425.stdout b/testsuite/tests/codeGen/should_run/T13425.stdout
new file mode 100644 (file)
index 0000000..48082f7
--- /dev/null
@@ -0,0 +1 @@
+12
index b952c10..ffe4b64 100644 (file)
@@ -155,3 +155,4 @@ test('T9577', [ unless(arch('x86_64') or arch('i386'),skip),
                 when(opsys('darwin'), expect_broken(12937)),
                 when(opsys('mingw32'), expect_broken(12965)),
                 only_ways(['normal']) ], compile_and_run, [''])
+test('T13425', normal, compile_and_run, ['-O'])