Set up crosstest to run simple loop in Om1 on ARM.

We can't run O2 yet because some of the advanced Phi lowering
hooks aren't implemented for O2 yet.

BUG= https://code.google.com/p/nativeclient/issues/detail?id=4076
R=stichnot@chromium.org

Review URL: https://codereview.chromium.org/1160873006.
diff --git a/Makefile.standalone b/Makefile.standalone
index 708c91f..5f2686b 100644
--- a/Makefile.standalone
+++ b/Makefile.standalone
@@ -22,10 +22,13 @@
 NACL_ROOT ?= $(shell python -c "import sys; sys.path.insert(0, 'pydir'); \
 	import utils; print utils.FindBaseNaCl()")
 
+# TOOLCHAIN_ROOT is the location of NaCl/PNaCl toolchains and other
+# tools like qemu.
+TOOLCHAIN_ROOT ?= $(shell readlink -e $(NACL_ROOT)/toolchain/linux_x86)
+
 # PNACL_TOOLCHAIN_ROOT is the location of the PNaCl toolchain.
 # This is used as the default root for finding binutils, libcxx, etc.
-PNACL_TOOLCHAIN_ROOT ?= $(shell readlink -e \
-	$(NACL_ROOT)/toolchain/linux_x86/pnacl_newlib_raw)
+PNACL_TOOLCHAIN_ROOT ?= $(shell readlink -e $(TOOLCHAIN_ROOT)/pnacl_newlib_raw)
 
 # The location of PNaCl tools (e.g., binutils objdump, pnacl-clang++, etc.).
 PNACL_BIN_PATH ?= $(shell readlink -e $(PNACL_TOOLCHAIN_ROOT)/bin)
@@ -105,6 +108,7 @@
 $(info Using LLVM_SRC_PATH = $(LLVM_SRC_PATH))
 $(info Using SB_LLVM_PATH = $(SB_LLVM_PATH))
 $(info Using NACL_ROOT = $(NACL_ROOT))
+$(info Using TOOLCHAIN_ROOT = $(TOOLCHAIN_ROOT))
 $(info Using PNACL_TOOLCHAIN_ROOT = $(PNACL_TOOLCHAIN_ROOT))
 $(info Using PNACL_BIN_PATH = $(PNACL_BIN_PATH))
 $(info Using CLANG_PATH = $(CLANG_PATH))
@@ -303,8 +307,10 @@
        # Do all native/sse2 tests, but only test_vector_ops for native/sse4.1.
        # For (slow) sandboxed tests, limit to Om1/sse4.1.
 	./pydir/crosstest_generator.py -v --lit \
-	  -i native,sse2 -i native,sse4.1,test_vector_ops \
-	  -i sandbox,sse4.1,Om1
+	  --toolchain-root $(TOOLCHAIN_ROOT) \
+	  -i x8632,native,sse2 -i x8632,native,sse4.1,test_vector_ops \
+	  -i x8632,sandbox,sse4.1,Om1 \
+	  -i arm32,native,neon,Om1,simple_loop
 	PNACL_BIN_PATH=$(PNACL_BIN_PATH) \
 	$(LLVM_SRC_PATH)/utils/lit/lit.py -sv crosstest/Output
 endif
diff --git a/pydir/build-runtime.py b/pydir/build-runtime.py
index cc1054f..4010b51 100755
--- a/pydir/build-runtime.py
+++ b/pydir/build-runtime.py
@@ -1,13 +1,15 @@
 #!/usr/bin/env python2
 
 import argparse
-from collections import namedtuple
 import os
 import shutil
 import tempfile
+
+import targets
 from utils import shellcmd
 from utils import FindBaseNaCl
 
+
 def Translate(ll_files, extra_args, obj, verbose):
     """Translate a set of input bitcode files into a single object file.
 
@@ -29,6 +31,7 @@
               obj
         ], echo=verbose)
 
+
 def PartialLink(obj_files, extra_args, lib, verbose):
     """Partially links a set of obj files into a final obj library."""
     shellcmd(['le32-nacl-ld',
@@ -37,10 +40,6 @@
         ] + extra_args + obj_files, echo=verbose)
 
 
-TargetInfo = namedtuple('TargetInfo',
-                        ['target', 'triple', 'llc_flags', 'ld_emu'])
-
-
 def MakeRuntimesForTarget(target_info, ll_files,
                           srcdir, tempdir, rtdir, verbose):
     def TmpFile(template):
@@ -72,7 +71,7 @@
     # The sandboxed library does not get the profiler helper function as the
     # binaries are linked with -nostdlib.
     Translate(ll_files,
-              ['-mtriple=' + target_info.triple.replace('linux', 'nacl')] +
+              ['-mtriple=' + targets.ConvertTripleToNaCl(target_info.triple)] +
               target_info.llc_flags,
               OutFile('{rtdir}/szrt_sb_{target}.o'),
               verbose)
@@ -123,19 +122,9 @@
         ll_files = ['{dir}/szrt.ll'.format(dir=tempdir),
                     '{srcdir}/szrt_ll.ll'.format(srcdir=srcdir)]
 
-        x8632_target = TargetInfo(target='x8632',
-                                  triple='i686-none-linux',
-                                  llc_flags=['-mcpu=pentium4m'],
-                                  ld_emu='elf_i386_nacl')
-        MakeRuntimesForTarget(x8632_target, ll_files,
+        MakeRuntimesForTarget(targets.X8632Target, ll_files,
                               srcdir, tempdir, rtdir, args.verbose)
-        arm32_target = TargetInfo(target='arm32',
-                                  triple='armv7a-none-linux-gnueabihf',
-                                  llc_flags=['-mcpu=cortex-a9',
-                                             '-float-abi=hard',
-                                             '-mattr=+neon'],
-                                  ld_emu='armelf_nacl')
-        MakeRuntimesForTarget(arm32_target, ll_files,
+        MakeRuntimesForTarget(targets.ARM32Target, ll_files,
                               srcdir, tempdir, rtdir, args.verbose)
 
     finally:
diff --git a/pydir/crosstest.py b/pydir/crosstest.py
index ca7e242..ebc33f8 100755
--- a/pydir/crosstest.py
+++ b/pydir/crosstest.py
@@ -6,6 +6,7 @@
 import sys
 import tempfile
 
+import targets
 from utils import shellcmd
 from utils import FindBaseNaCl
 
@@ -22,8 +23,23 @@
     results.
 
     """
-    # arch_map maps a Subzero target string to an llvm-mc -triple string.
-    arch_map = { 'x8632':'i686', 'x8664':'x86_64', 'arm':'armv7a' }
+    # arch_map maps a Subzero target string to TargetInfo (e.g., triple).
+    arch_map = { 'x8632': targets.X8632Target,
+                 'x8664': targets.X8664Target,
+                 'arm32': targets.ARM32Target }
+    arch_sz_flags = { 'x8632': [],
+                      'x8664': [],
+                      # TODO(jvoung): remove skip-unimplemented when implemented
+                      'arm32': ['--skip-unimplemented']
+    }
+    arch_llc_flags_extra = {
+        # Use sse2 instructions regardless of input -mattr
+        # argument to avoid differences in (undefined) behavior of
+        # converting NaN to int.
+        'x8632': ['-mattr=sse2'],
+        'x8664': ['-mattr=sse2'],
+        'arm32': [],
+    }
     desc = 'Build a cross-test that compares Subzero and llc translation.'
     argparser = argparse.ArgumentParser(description=desc)
     argparser.add_argument('--test', required=True, action='append',
@@ -46,7 +62,8 @@
     argparser.add_argument('--clang-opt', required=False, default=True,
                            dest='clang_opt')
     argparser.add_argument('--mattr',  required=False, default='sse2',
-                           dest='attr', choices=['sse2', 'sse4.1'],
+                           dest='attr', choices=['sse2', 'sse4.1',
+                                                 'neon', 'hwdiv-arm'],
                            metavar='ATTRIBUTE',
                            help='Target attribute. Default %(default)s.')
     argparser.add_argument('--sandbox', required=False, default=0, type=int,
@@ -76,7 +93,11 @@
     nacl_root = FindBaseNaCl()
     bindir = ('{root}/toolchain/linux_x86/pnacl_newlib_raw/bin'
               .format(root=nacl_root))
-    triple = arch_map[args.target] + ('-nacl' if args.sandbox else '')
+    target_info = arch_map[args.target]
+    triple = target_info.triple
+    if args.sandbox:
+        triple = targets.ConvertTripleToNaCl(triple)
+    llc_flags = target_info.llc_flags + arch_llc_flags_extra[args.target]
     mypath = os.path.abspath(os.path.dirname(sys.argv[0]))
 
     objs = []
@@ -116,7 +137,7 @@
                   '-externalize',
                   '-filetype=' + args.filetype,
                   '-o=' + (obj_sz if args.filetype == 'obj' else asm_sz),
-                  bitcode])
+                  bitcode] + arch_sz_flags[args.target])
         if args.filetype != 'obj':
             shellcmd(['{bin}/llvm-mc'.format(bin=bindir),
                       '-triple=' + triple,
@@ -137,14 +158,10 @@
         if args.crosstest_bitcode:
             shellcmd(['{bin}/pnacl-llc'.format(bin=bindir),
                       '-mtriple=' + triple,
-                      # Use sse2 instructions regardless of input -mattr
-                      # argument to avoid differences in (undefined) behavior of
-                      # converting NaN to int.
-                      '-mattr=sse2',
                       '-externalize',
                       '-filetype=obj',
                       '-o=' + obj_llc,
-                      bitcode])
+                      bitcode] + llc_flags)
             objs.append(obj_llc)
         else:
             objs.append(arg)
@@ -162,7 +179,8 @@
     sb_native_args = (['-O0', '--pnacl-allow-native', '-arch', 'x8632',
                        '-Wn,-defsym=__Sz_AbsoluteZero=0']
                       if args.sandbox else
-                      ['-g', '-m32', '-lm', '-lpthread',
+                      ['-g', '-target=' + triple,
+                       '-lm', '-lpthread',
                        '-Wl,--defsym=__Sz_AbsoluteZero=0'])
     shellcmd([compiler, args.driver] + objs +
              ['-o', os.path.join(args.dir, args.output)] + sb_native_args)
diff --git a/pydir/crosstest_generator.py b/pydir/crosstest_generator.py
index 945ad00..e79657f 100755
--- a/pydir/crosstest_generator.py
+++ b/pydir/crosstest_generator.py
@@ -27,6 +27,22 @@
       return True
   return default_match
 
+
+def RunNativePrefix(toolchain_root, target, run_cmd):
+  """Returns a prefix for running an executable for the target.
+
+  For example, we may be running an ARM or MIPS target executable on an
+  x86 machine and need to use an emulator.
+  """
+  arch_map = { 'x8632' : '',
+               'x8664' : '',
+               'arm32' : os.path.join(toolchain_root, 'arm_trusted',
+                                      'run_under_qemu_arm'),
+             }
+  prefix = arch_map[target]
+  return (prefix + ' ' + run_cmd) if prefix else run_cmd
+
+
 def main():
   """Framework for cross test generation and execution.
 
@@ -39,13 +55,20 @@
   root = FindBaseNaCl()
 
   # The rest of the attribute sets.
-  targets = [ 'x8632' ]
+  targets = [ 'x8632', 'arm32' ]
   sandboxing = [ 'native', 'sandbox' ]
   opt_levels = [ 'Om1', 'O2' ]
-  arch_attrs = [ 'sse2', 'sse4.1' ]
+  arch_attrs = { 'x8632': [ 'sse2', 'sse4.1' ],
+                 'arm32': [ 'neon', 'hwdiv-arm' ] }
+  flat_attrs = []
+  for v in arch_attrs.values():
+    flat_attrs += v
+  arch_flags = { 'x8632': [],
+                 # ARM doesn't have an integrated assembler yet.
+                 'arm32': ['--filetype=asm'] }
   # all_keys is only used in the help text.
   all_keys = '; '.join([' '.join(targets), ' '.join(sandboxing),
-                        ' '.join(opt_levels), ' '.join(arch_attrs)])
+                        ' '.join(opt_levels), ' '.join(flat_attrs)])
 
   argparser = argparse.ArgumentParser(
     description='  ' + main.__doc__ +
@@ -76,6 +99,8 @@
                          help='Output directory')
   argparser.add_argument('--lit', default=False, action='store_true',
                          help='Generate files for lit testing')
+  argparser.add_argument('--toolchain-root', dest='toolchain_root',
+                           help='Path to toolchain binaries.')
   args = argparser.parse_args()
 
   # Run from the crosstest directory to make it easy to grab inputs.
@@ -113,7 +138,7 @@
     for target in targets:
       for sb in sandboxing:
         for opt in opt_levels:
-          for attr in arch_attrs:
+          for attr in arch_attrs[target]:
             desc = [ test, target, sb, opt, attr ]
             if Match(set(desc), includes, excludes, default_match):
               exe = '{test}_{target}_{sb}_{opt}_{attr}'.format(
@@ -122,24 +147,27 @@
               extra = (tests.get(test, 'flags').split(' ')
                        if tests.has_option(test, 'flags') else [])
               # Generate the compile command.
-              cmp_cmd = ['{path}/crosstest.py'.format(path=pypath),
-                         '-{opt}'.format(opt=opt),
-                         '--mattr={attr}'.format(attr=attr),
-                         '--prefix=Subzero_',
-                         '--target={target}'.format(target=target),
-                         '--sandbox={sb}'.format(sb='1' if sb=='sandbox'
-                                                 else '0'),
-                         '--dir={dir}'.format(dir=args.dir),
-                         '--output={exe}'.format(exe=exe),
-                         '--driver={drv}'.format(drv=tests.get(test, 'driver')),
-                        ] + extra + \
-                        [ '--test=' + t
-                          for t in tests.get(test, 'test').split(' ') ]
+              cmp_cmd = (
+                ['{path}/crosstest.py'.format(path=pypath),
+                 '-{opt}'.format(opt=opt),
+                 '--mattr={attr}'.format(attr=attr),
+                 '--prefix=Subzero_',
+                 '--target={target}'.format(target=target),
+                 '--sandbox={sb}'.format(sb='1' if sb=='sandbox' else '0'),
+                 '--dir={dir}'.format(dir=args.dir),
+                 '--output={exe}'.format(exe=exe),
+                 '--driver={drv}'.format(drv=tests.get(test, 'driver'))] +
+                extra +
+                ['--test=' + t
+                 for t in tests.get(test, 'test').split(' ')] +
+                arch_flags[target])
               run_cmd_base = os.path.join(args.dir, exe)
               # Generate the run command.
               run_cmd = run_cmd_base
               if sb == 'sandbox':
                 run_cmd = '{root}/run.py -q '.format(root=root) + run_cmd
+              else:
+                run_cmd = RunNativePrefix(args.toolchain_root, target, run_cmd)
               if args.lit:
                 # Create a file to drive the lit test.
                 with open(run_cmd_base + '.xtest', 'w') as f:
diff --git a/pydir/targets.py b/pydir/targets.py
new file mode 100644
index 0000000..0f6433c
--- /dev/null
+++ b/pydir/targets.py
@@ -0,0 +1,27 @@
+#!/usr/bin/env python2
+
+from collections import namedtuple
+
+TargetInfo = namedtuple('TargetInfo',
+                        ['target', 'triple', 'llc_flags', 'ld_emu'])
+
+X8632Target = TargetInfo(target='x8632',
+                         triple='i686-none-linux',
+                         llc_flags=['-mcpu=pentium4m'],
+                         ld_emu='elf_i386_nacl')
+
+X8664Target = TargetInfo(target='x8664',
+                         triple='x86_64-none-linux',
+                         llc_flags=['-mcpu=x86-64'],
+                         ld_emu='elf_x86_64_nacl')
+
+ARM32Target = TargetInfo(target='arm32',
+                         triple='armv7a-none-linux-gnueabihf',
+                         llc_flags=['-mcpu=cortex-a9',
+                                    '-float-abi=hard',
+                                    '-mattr=+neon'],
+                         ld_emu='armelf_nacl')
+
+
+def ConvertTripleToNaCl(nonsfi_triple):
+  return nonsfi_triple.replace('linux', 'nacl')