diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,11 @@
 # kempe
 
+## 0.2.0.1
+
+  * Performance improvements when assembling x86
+  * Fix pattern match exhaustiveness checker
+  * More lenient command-line parser
+
 ## 0.2.0.0
 
   * Add aarch64 backend
diff --git a/bench/Bench.hs b/bench/Bench.hs
--- a/bench/Bench.hs
+++ b/bench/Bench.hs
@@ -5,6 +5,7 @@
 import           Data.Bifunctor            (Bifunctor, bimap)
 import qualified Data.ByteString.Lazy      as BSL
 import qualified Data.Text                 as T
+import qualified Data.Text.Lazy.IO         as TLIO
 import           Kempe.Asm.Liveness
 import qualified Kempe.Asm.X86.ControlFlow as X86
 import qualified Kempe.Asm.X86.Linear      as X86
@@ -21,8 +22,10 @@
 import           Kempe.Pipeline
 import           Kempe.Shuttle
 import           Kempe.TyAssign
-import           Prettyprinter             (Doc, defaultLayoutOptions, layoutPretty)
-import           Prettyprinter.Render.Text (renderStrict)
+import           Prettyprinter             (Doc, defaultLayoutOptions, layoutCompact, layoutPretty)
+import           Prettyprinter.Render.Text (renderLazy, renderStrict)
+import           System.IO                 (hFlush)
+import           System.IO.Temp            (withSystemTempFile)
 
 bivoid :: Bifunctor p => p a b -> p () ()
 bivoid = bimap (const ()) (const ())
@@ -48,6 +51,7 @@
                 , env eitherMod $ \ e ->
                     bgroup "Pattern match exhaustiveness checker"
                         [ bench "lib/either.kmp" $ nf checkModuleExhaustive e
+                        , bench "examples/vierergruppe.kmp" $ nf checkModuleExhaustive e
                         ]
                   , env parsedInteresting $ \ ~(f, n) ->
                       bgroup "Inliner"
@@ -96,9 +100,9 @@
                         , bench "Generate assembly (examples/splitmix.kmp)" $ nfIO (writeAsm "examples/splitmix.kmp")
                         , bench "Generate assembly (lib/numbertheory.kmp)" $ nfIO (writeAsm "lib/numbertheory.kmp")
                         , bench "Generate assembly (lib/gaussian.kmp)" $ nfIO (writeAsm "lib/gaussian.kmp")
+                        , bench "Write assembly to file (lib/gaussian.kmp)" $ nfIO (writeAsmToFile "lib/gaussian.kmp")
                         , bench "Generate arm assembly (examples/factorial.kmp)" $ nfIO (writeArmAsm "examples/factorial.kmp")
                         , bench "Generate arm assembly (lib/gaussian.kmp)" $ nfIO (writeArmAsm "lib/gaussian.kmp")
-                        -- , bench "Generate assembly (lib/rational.kmp)" $ nfIO (writeAsm "lib/rational.kmp")
                         , bench "Object file (examples/factorial.kmp)" $ nfIO (compile "examples/factorial.kmp" "/tmp/factorial.o" False)
                         , bench "Object file (lib/numbertheory.kmp)" $ nfIO (compile "lib/numbertheory.kmp" "/tmp/numbertheory.o" False)
                         , bench "Object file (examples/splitmix.kmp)" $ nfIO (compile "examples/splitmix.kmp" "/tmp/splitmix.o" False)
@@ -144,6 +148,13 @@
           absX86 = (,,) <$> splitmixAbsX86 <*> facAbsX86 <*> numAbsX86
           -- not even gonna justify this
           yrrucnu f (y, x) = f x y
+
+writeAsmToFile :: FilePath
+               -> IO ()
+writeAsmToFile inp = withSystemTempFile "unassembled.kmp" $ \_ h -> do
+    res <- parseProcess inp
+    TLIO.hPutStr h $ renderLazy $ layoutCompact $ uncurry dumpX86 res
+    hFlush h
 
 writeAsm :: FilePath
          -> IO T.Text
diff --git a/docs/manual.pdf b/docs/manual.pdf
Binary files a/docs/manual.pdf and b/docs/manual.pdf differ
diff --git a/examples/vierergruppe.kmp b/examples/vierergruppe.kmp
new file mode 100644
--- /dev/null
+++ b/examples/vierergruppe.kmp
@@ -0,0 +1,14 @@
+type Element { E | A | B | C }
+
+; see: https://mathworld.wolfram.com/Vierergruppe.html
+mult : Element Element -- Element
+     =: [
+        { case
+            | E ->
+            | A -> { case | E -> A | A -> E | B -> C | C -> B }
+            | B -> { case | E -> B | A -> C | B -> E | C -> A }
+            | C -> { case | E -> C | A -> B | B -> A | C -> E }
+        }
+]
+
+%foreign kabi mult
diff --git a/kempe.cabal b/kempe.cabal
--- a/kempe.cabal
+++ b/kempe.cabal
@@ -1,6 +1,6 @@
 cabal-version:   3.0
 name:            kempe
-version:         0.2.0.0
+version:         0.2.0.1
 license:         BSD-3-Clause
 license-file:    LICENSE
 copyright:       Copyright: (c) 2020-2021 Vanessa McHale
@@ -247,7 +247,8 @@
         bytestring,
         criterion,
         prettyprinter,
-        text
+        text,
+        temporary
 
     if impl(ghc >=8.0)
         ghc-options:
diff --git a/lib/these.kmp b/lib/these.kmp
new file mode 100644
--- /dev/null
+++ b/lib/these.kmp
@@ -0,0 +1,1 @@
+type These a b { This a | That b | These a b }
diff --git a/run/Main.hs b/run/Main.hs
--- a/run/Main.hs
+++ b/run/Main.hs
@@ -79,7 +79,11 @@
             (Nothing, "aarch64") -> Aarch64
             (Nothing, "x86_64")  -> X64
             (Just "aarch64", _)  -> Aarch64
+            (Just "arm64", _)    -> Aarch64
             (Just "x64", _)      -> X64
+            (Just "x86_64", _)   -> X64
+            (Just "x86-64", _)   -> X64
+            (Just "amd64", _)    -> X64
             _                    -> error "Failed to parse architecture! Try one of x64, aarch64"
 
 irSwitch :: Parser Bool
diff --git a/src/Kempe/Asm/Arm/Trans.hs b/src/Kempe/Asm/Arm/Trans.hs
--- a/src/Kempe/Asm/Arm/Trans.hs
+++ b/src/Kempe/Asm/Arm/Trans.hs
@@ -81,6 +81,12 @@
     ; eEval <- evalE e r
     ; pure $ eEval ++ [BranchZero () (toAbsReg r) l1, Branch () l0]
     }
+-- handles e.g. (mjump (=b (mem [1] (+ (reg datapointer) (int 0))) (tag 0x0)) kmp2)
+irEmit _ (IR.MJump (IR.EqByte e (IR.ConstTag 0)) l) = do
+    { r <- allocTemp64
+    ; eEval <- evalE e r
+    ; pure $ eEval ++ [BranchZero () (toAbsReg r) l]
+    }
 irEmit _ (IR.MJump e l) = do
     { r <- allocTemp64
     ; eEval <- evalE e r
@@ -103,6 +109,7 @@
           b1 = (w .&. 0xFFFF0000) `shiftR` 16
           b2 = (w .&. 0xFFFF00000000) `shiftR` 32
           b3 = (w .&. 0xFFFF000000000000) `shiftR` 48
+          -- TODO: only MovRK if nonzero
 
 evalE :: IR.Exp -> IR.Temp -> WriteM [Arm AbsReg ()]
 evalE (IR.ConstInt i) r                                                        = pure [MovRC () (toAbsReg r) i]
@@ -123,6 +130,8 @@
 evalE (IR.ExprIntBinOp IR.IntMinusIR (IR.Reg r1) (IR.ConstInt i)) r            = pure [SubRC () (toAbsReg r) (toAbsReg r1) i]
 evalE (IR.Mem 8 (IR.Reg r0)) r                                                 = pure [Load () (toAbsReg r) (Reg $ toAbsReg r0)]
 evalE (IR.Mem 1 (IR.Reg r0)) r                                                 = pure [LoadByte () (toAbsReg r) (Reg $ toAbsReg r0)]
+evalE (IR.Mem 1 (IR.ExprIntBinOp IR.IntPlusIR (IR.Reg r0) (IR.ConstInt i))) r  = pure [LoadByte () (toAbsReg r) (AddRCPlus (toAbsReg r0) i)]
+evalE (IR.Mem 1 (IR.ExprIntBinOp IR.IntMinusIR (IR.Reg r0) (IR.ConstInt i))) r = pure [LoadByte () (toAbsReg r) (AddRCPlus (toAbsReg r0) (negate i))]
 evalE (IR.Mem 8 (IR.ExprIntBinOp IR.IntPlusIR (IR.Reg r0) (IR.ConstInt i))) r  = pure [Load () (toAbsReg r) (AddRCPlus (toAbsReg r0) i)]
 evalE (IR.Mem 8 (IR.ExprIntBinOp IR.IntMinusIR (IR.Reg r0) (IR.ConstInt i))) r = pure [Load () (toAbsReg r) (AddRCPlus (toAbsReg r0) (negate i))]
 evalE (IR.Mem 8 e) r                                                           = do
@@ -136,17 +145,22 @@
     ; pure $ placeE ++ [LoadByte () (toAbsReg r) (Reg $ toAbsReg r')]
     }
 evalE (IR.Reg r) r' = pure [MovRR () (toAbsReg r') (toAbsReg r)]
+evalE (IR.ExprIntRel IR.IntLeqIR (IR.Reg r1) (IR.Reg r2)) r =
+    pure [CmpRR () (toAbsReg r1) (toAbsReg r2), CSet () (toAbsReg r) Leq]
 evalE (IR.ExprIntRel IR.IntLtIR (IR.Reg r1) (IR.Reg r2)) r =
     pure [CmpRR () (toAbsReg r1) (toAbsReg r2), CSet () (toAbsReg r) Lt]
+evalE (IR.ExprIntRel IR.IntGtIR (IR.Reg r1) (IR.Reg r2)) r =
+    pure [CmpRR () (toAbsReg r1) (toAbsReg r2), CSet () (toAbsReg r) Gt]
 evalE (IR.ExprIntRel IR.IntEqIR (IR.Reg r1) (IR.Reg r2)) r =
     pure [CmpRR () (toAbsReg r1) (toAbsReg r2), CSet () (toAbsReg r) Eq]
-evalE (IR.ExprIntRel IR.IntEqIR e e') r = do
-    { r0 <- allocTemp64
-    ; r1 <- allocTemp64
-    ; eEval <- evalE e r0
-    ; e'Eval <- evalE e' r1
-    ; pure $ eEval ++ e'Eval ++ [CmpRR () (toAbsReg r0) (toAbsReg r1), CSet () (toAbsReg r) Eq]
-    }
+evalE (IR.ExprIntRel IR.IntNeqIR (IR.Reg r1) (IR.Reg r2)) r =
+    pure [CmpRR () (toAbsReg r1) (toAbsReg r2), CSet () (toAbsReg r) Neq]
+evalE (IR.ExprIntRel IR.IntEqIR e e') r = cmpE e e' r Eq
+evalE (IR.ExprIntRel IR.IntNeqIR e e') r = cmpE e e' r Neq
+evalE (IR.ExprIntRel IR.IntLtIR e e') r = cmpE e e' r Lt
+evalE (IR.ExprIntRel IR.IntGtIR e e') r = cmpE e e' r Gt
+evalE (IR.ExprIntRel IR.IntLeqIR e e') r = cmpE e e' r Leq
+evalE (IR.ExprIntRel IR.IntGeqIR e e') r = cmpE e e' r Geq
 evalE (IR.EqByte e (IR.ConstTag b)) r = do
     { r0 <- allocTemp64
     ; eEval <- evalE e r0
@@ -169,7 +183,25 @@
     { rTrash <- allocTemp64
     ; pure [ UnsignedDivRR () (toAbsReg rTrash) (toAbsReg r1) (toAbsReg r2), MulSubRRR () (toAbsReg r) (toAbsReg rTrash) (toAbsReg r2) (toAbsReg r1) ]
     }
+evalE (IR.ExprIntBinOp IR.IntModIR e e') r = do
+    { rTrash <- allocTemp64
+    ; r0 <- allocTemp64
+    ; r1 <- allocTemp64
+    ; eEval <- evalE e r0
+    ; e'Eval <- evalE e' r1
+    ; pure $ eEval ++ e'Eval ++ [ UnsignedDivRR () (toAbsReg rTrash) (toAbsReg r0) (toAbsReg r1), MulSubRRR () (toAbsReg r) (toAbsReg rTrash) (toAbsReg r1) (toAbsReg r0) ]
+    }
 evalE (IR.ConstBool b) r = pure [MovRC () (toAbsReg r) (toInt b)]
+
+-- | Helper for <, >, etc. used by 'evalE'
+cmpE :: IR.Exp -> IR.Exp -> IR.Temp -> Cond -> WriteM [Arm AbsReg ()]
+cmpE e e' r c = do
+    { r0 <- allocTemp64
+    ; r1 <- allocTemp64
+    ; eEval <- evalE e r0
+    ; e'Eval <- evalE e' r1
+    ; pure $ eEval ++ e'Eval ++ [CmpRR () (toAbsReg r0) (toAbsReg r1), CSet () (toAbsReg r) c]
+    }
 
 -- | Just use 64-bit integers here
 toInt :: Bool -> Int64
diff --git a/src/Kempe/Asm/Liveness.hs b/src/Kempe/Asm/Liveness.hs
--- a/src/Kempe/Asm/Liveness.hs
+++ b/src/Kempe/Asm/Liveness.hs
@@ -56,6 +56,7 @@
     where nSt' = {-# SCC "iterNodes" #-} iterNodes is nSt
 
 iterNodes :: [Int] -> LivenessMap -> LivenessMap
+-- this is fickle, thread will seemingly thunk leak (??) if optimizations aren't on
 iterNodes is = thread (fmap stepNode is)
 
 stepNode :: Int -> LivenessMap -> LivenessMap
diff --git a/src/Kempe/Check/Pattern.hs b/src/Kempe/Check/Pattern.hs
--- a/src/Kempe/Check/Pattern.hs
+++ b/src/Kempe/Check/Pattern.hs
@@ -16,6 +16,7 @@
 import qualified Data.IntMap.Strict         as IM
 import qualified Data.IntSet                as IS
 import           Data.List.NonEmpty         (NonEmpty (..))
+import qualified Data.List.NonEmpty         as NE
 import           Kempe.AST
 import           Kempe.Error
 import           Kempe.Name
@@ -25,8 +26,9 @@
 
 checkAtom :: PatternEnv -> Atom c b -> Maybe (Error b)
 checkAtom env (Case l ls) =
-    if isExhaustive env $ fmap fst ls
-        then Nothing
+    let (ps, as) = NE.unzip ls in
+    if isExhaustive env ps
+        then foldMapAlternative (foldMapAlternative (checkAtom env)) as
         else Just (InexhaustiveMatch l)
 checkAtom _ _ = Nothing
 
@@ -90,8 +92,10 @@
 isExhaustive _ (PatternInt{}:|ps)                          = hasWildcard ps
 isExhaustive _ (PatternBool _ True:|PatternBool _ False:_) = True
 isExhaustive _ (PatternBool _ False:|PatternBool _ True:_) = True
+-- doesn't technically work since you could have True True False but like...
+-- don't do that
 isExhaustive _ (PatternBool{}:|ps)                         = hasWildcard ps
-isExhaustive env ps@(PatternCons{}:|_)                     = isCompleteSet env (fmap patternName ps)
+isExhaustive env ps@(PatternCons{}:|_)                     = hasWildcard ps || isCompleteSet env (fmap patternName ps)
 
 isCompleteSet :: PatternEnv -> NonEmpty (TyName a) -> Bool
 isCompleteSet env ns@(n:|_) =
diff --git a/src/Kempe/IR/Type.hs b/src/Kempe/IR/Type.hs
--- a/src/Kempe/IR/Type.hs
+++ b/src/Kempe/IR/Type.hs
@@ -75,14 +75,13 @@
 
 data Stmt = Labeled Label
           | Jump Label
-          -- conditional jump for ifs
-          | CJump Exp Label Label -- ^ If the 'Exp' evaluates to @1@, go to the first label, otherwise go to the second (if-then-else)
+          | CJump Exp Label Label -- ^ If the 'Exp' evaluates to @1@, go to the first label, otherwise go to the second (if-then-else). Used to implement ifs.
           | MJump Exp Label
           | CCall MonoStackType BSL.ByteString
-          | KCall Label -- KCall is a jump to a Kempe procedure
+          | KCall Label -- ^ a 'KCall' is a jump to a Kempe procedure
           | WrapKCall ABI MonoStackType BS.ByteString Label
-          | MovTemp Temp Exp -- put e in temp
-          | MovMem Exp Int64 Exp -- store e2 at address given by e1
+          | MovTemp Temp Exp -- ^ Put @e@ in temp
+          | MovMem Exp Int64 Exp -- ^ Store @e2@ at address given by @e1@, with sizing information
           | Ret
           deriving (Generic, NFData)
 
@@ -92,7 +91,7 @@
          | ConstWord Word
          | ConstBool Bool
          | Reg Temp -- TODO: size?
-         | Mem Int64 Exp -- fetch from address
+         | Mem Int64 Exp -- ^ Fetch from address
          | ExprIntBinOp IntBinOp Exp Exp
          | ExprIntRel RelBinOp Exp Exp
          | BoolBinOp BoolBinOp Exp Exp
@@ -134,7 +133,7 @@
               | IntMinusIR
               | IntModIR -- rem?
               | IntXorIR
-              | WordShiftRIR -- compiles to shr on x86
+              | WordShiftRIR -- ^ compiles to @shr@ on x86
               | WordShiftLIR
               -- int/word mod are different, see: https://stackoverflow.com/questions/8231882/how-to-implement-the-mod-operator-in-assembly
               | WordModIR
diff --git a/src/Kempe/Proc/As.hs b/src/Kempe/Proc/As.hs
--- a/src/Kempe/Proc/As.hs
+++ b/src/Kempe/Proc/As.hs
@@ -2,7 +2,7 @@
                      ) where
 
 import           Data.Functor                (void)
-import           Prettyprinter               (Doc, defaultLayoutOptions, layoutPretty)
+import           Prettyprinter               (Doc, layoutCompact)
 import           Prettyprinter.Render.String (renderString)
 import           System.Info                 (arch)
 import           System.Process              (CreateProcess (..), StdStream (Inherit), proc, readCreateProcess)
@@ -21,6 +21,6 @@
        -> Bool -- ^ Debug symbols?
        -> IO ()
 writeO p fpO dbg = do
-    let inp = renderString (layoutPretty defaultLayoutOptions p)
+    let inp = renderString (layoutCompact p)
         debugFlag = if dbg then ("-g":) else id
     void $ readCreateProcess ((proc assembler (debugFlag ["-o", fpO, "--"])) { std_err = Inherit }) inp
diff --git a/src/Kempe/Proc/Nasm.hs b/src/Kempe/Proc/Nasm.hs
--- a/src/Kempe/Proc/Nasm.hs
+++ b/src/Kempe/Proc/Nasm.hs
@@ -2,8 +2,9 @@
                        ) where
 
 import           Data.Functor              (void)
-import           Prettyprinter             (Doc, defaultLayoutOptions, layoutPretty)
-import           Prettyprinter.Render.Text (renderIO)
+import qualified Data.Text.Lazy.IO         as TLIO
+import           Prettyprinter             (Doc, layoutCompact)
+import           Prettyprinter.Render.Text (renderLazy)
 import           System.IO                 (hFlush)
 import           System.IO.Temp            (withSystemTempFile)
 import           System.Process            (CreateProcess (..), StdStream (Inherit), proc, readCreateProcess)
@@ -14,7 +15,8 @@
        -> Bool -- ^ Debug symbols?
        -> IO ()
 writeO p fpO dbg = withSystemTempFile "kmp.S" $ \fp h -> do
-    renderIO h (layoutPretty defaultLayoutOptions p)
+    let txt = renderLazy $ layoutCompact p
+    TLIO.hPutStr h txt
     hFlush h
     let debugFlag = if dbg then ("-g":) else id
     -- -O1 is signed byte optimization but no multi-passes
diff --git a/test/Golden.hs b/test/Golden.hs
--- a/test/Golden.hs
+++ b/test/Golden.hs
@@ -22,7 +22,7 @@
                 , compileArm "lib/numbertheory.kmp"
                 , compileArm "test/examples/bool.kmp"
                 , compileArm "examples/splitmix.kmp"
-                -- , compileArm "lib/gaussian.kmp"
+                , compileArm "lib/gaussian.kmp"
                 ]
     "aarch64" -> []
     _ -> error "Test suite must be run on x86_64 or aarch64"
