OLD | NEW |
(Empty) | |
| 1 #!/usr/bin/python |
| 2 # Copyright (c) 2012 The Native Client Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. |
| 5 |
| 6 """Tests of the pnacl driver. |
| 7 |
| 8 This tests that pnacl-translate options pass through to LLC correctly, |
| 9 and are overridden correctly. |
| 10 """ |
| 11 |
| 12 from driver_env import env |
| 13 import driver_log |
| 14 import driver_test_utils |
| 15 import driver_tools |
| 16 |
| 17 import cStringIO |
| 18 import os |
| 19 import re |
| 20 import sys |
| 21 import tempfile |
| 22 import unittest |
| 23 |
| 24 class DriverExitException(Exception): |
| 25 pass |
| 26 |
| 27 def FakeExit(i): |
| 28 raise DriverExitException('Stubbed out DriverExit!') |
| 29 |
| 30 def MakeFakeStdStream(): |
| 31 fake_out = cStringIO.StringIO() |
| 32 fake_err = cStringIO.StringIO() |
| 33 backup_stdout = sys.stdout |
| 34 backup_stderr = sys.stderr |
| 35 sys.stdout = fake_out |
| 36 sys.stderr = fake_err |
| 37 return (fake_out, fake_err, backup_stdout, backup_stderr) |
| 38 |
| 39 def RestoreStdStream(fake_out, fake_err, |
| 40 backup_stdout, backup_stderr): |
| 41 sys.stdout = backup_stdout |
| 42 sys.stderr = backup_stderr |
| 43 # For some reason, cStringIO.StringIO() returns the same object |
| 44 # for fake_out, on each iteration. So, if we close() it we could |
| 45 # end up getting a closed object and write to closed object |
| 46 # in the next iteration. |
| 47 fake_out.reset() |
| 48 fake_out.truncate() |
| 49 fake_err.reset() |
| 50 fake_err.truncate() |
| 51 |
| 52 def GetPlatformToTest(): |
| 53 for arg in sys.argv: |
| 54 if arg.startswith('--platform='): |
| 55 return arg.split('=')[1] |
| 56 raise Exception('Unknown platform') |
| 57 |
| 58 class TestLLCOptions(unittest.TestCase): |
| 59 |
| 60 def setUp(self): |
| 61 driver_test_utils.ApplyTestEnvOverrides(env) |
| 62 self.platform = GetPlatformToTest() |
| 63 self.tempfiles = [] |
| 64 |
| 65 def getTemp(self, **kwargs): |
| 66 # Set delete=False, so that we can close the files and |
| 67 # re-open them. Windows sometimes does not allow you to |
| 68 # re-open an already opened temp file. |
| 69 t = tempfile.NamedTemporaryFile(delete=False, **kwargs) |
| 70 self.tempfiles.append(t) |
| 71 return t |
| 72 |
| 73 def tearDown(self): |
| 74 for t in self.tempfiles: |
| 75 if not t.closed: |
| 76 t.close() |
| 77 os.remove(t.name) |
| 78 # Wipe other temp files that are normally wiped by DriverExit. |
| 79 # We don't want anything to exit, so we do not call DriverExit manually. |
| 80 driver_log.TempFiles.wipe() |
| 81 |
| 82 def getFakePexe(self): |
| 83 # Even --dry-run requires a file to exist, so make a fake pexe. |
| 84 # It even cares that the file is really bitcode. |
| 85 with self.getTemp(suffix='.ll') as t: |
| 86 with self.getTemp(suffix='.pexe') as p: |
| 87 t.write(''' |
| 88 define i32 @main() { |
| 89 ret i32 0 |
| 90 } |
| 91 ''') |
| 92 t.close() |
| 93 p.close() |
| 94 driver_tools.RunDriver('as', [t.name, '-o', p.name]) |
| 95 return p |
| 96 |
| 97 |
| 98 def checkLLCTranslateFlags(self, pexe, arch, flags, |
| 99 expected_flags): |
| 100 ''' Given a |pexe| the |arch| for translation and additional pnacl-translate |
| 101 |flags|, check that the commandline for LLC really contains the |
| 102 |expected_flags|. This ensures that the pnacl-translate script |
| 103 does not drop certain flags accidentally. ''' |
| 104 temp_output = self.getTemp() |
| 105 temp_output.close() |
| 106 # Major hack to capture the output. |
| 107 # RunDriver() prints a bunch of things to stdout, which we need to capture. |
| 108 # Another major hack is to prevent DriverExit() from aborting the test.' |
| 109 # The test will surely DriverLog.Fatal() because dry-run currently |
| 110 # does not handle anything that involves invoking a subprocess and |
| 111 # grepping the stdout/stderr since it never actually invokes |
| 112 # the subprocess. Unfortunately, pnacl-translate does grep the output of |
| 113 # the sandboxed LLC run, so we can only go that far with --dry-run. |
| 114 (fake_out, fake_err, backup_stdout, backup_stderr) = MakeFakeStdStream() |
| 115 backup_exit = sys.exit |
| 116 sys.exit = FakeExit |
| 117 try: |
| 118 self.assertRaises(DriverExitException, |
| 119 driver_tools.RunDriver, |
| 120 'translate', |
| 121 ['--pnacl-driver-verbose', |
| 122 '--dry-run', |
| 123 '-arch', arch, |
| 124 pexe.name, |
| 125 '-o', temp_output.name] + flags) |
| 126 finally: |
| 127 out = sys.stdout.getvalue() |
| 128 err = sys.stderr.getvalue() |
| 129 RestoreStdStream(fake_out, fake_err, |
| 130 backup_stdout, backup_stderr) |
| 131 sys.exit = backup_exit |
| 132 for f in expected_flags: |
| 133 self.assertTrue(re.search(f, err), |
| 134 msg='Searching for regex %s in %s' % (f, err)) |
| 135 return |
| 136 |
| 137 |
| 138 #### Individual tests. |
| 139 |
| 140 def test_no_overrides(self): |
| 141 if driver_test_utils.CanRunHost(): |
| 142 pexe = self.getFakePexe() |
| 143 if self.platform == 'arm': |
| 144 expected_triple_cpu = ['-mtriple=arm.*', '-mcpu=cortex.*'] |
| 145 elif self.platform == 'x86-32': |
| 146 expected_triple_cpu = ['-mtriple=i686.*', '-mcpu=pentium.*'] |
| 147 elif self.platform == 'x86-64': |
| 148 expected_triple_cpu = ['-mtriple=x86_64.*', '-mcpu=core.*'] |
| 149 else: |
| 150 raise Exception('Unknown platform') |
| 151 # Test that certain defaults are set, when no flags are given. |
| 152 self.checkLLCTranslateFlags( |
| 153 pexe, |
| 154 self.platform, |
| 155 [], |
| 156 expected_triple_cpu) |
| 157 # Test that the default StreamInit is used, when no flags are given. |
| 158 self.checkLLCTranslateFlags( |
| 159 pexe, |
| 160 self.platform, |
| 161 ['--pnacl-sb'], |
| 162 ['StreamInit h']) |
| 163 |
| 164 def test_overrideO0(self): |
| 165 if driver_test_utils.CanRunHost(): |
| 166 pexe = self.getFakePexe() |
| 167 # Test that you get O0 when you ask for O0. |
| 168 # You also get no frame pointer elimination. |
| 169 self.checkLLCTranslateFlags( |
| 170 pexe, |
| 171 self.platform, |
| 172 ['-O0'], |
| 173 ['-O0 ', '-disable-fp-elim ']) |
| 174 self.checkLLCTranslateFlags( |
| 175 pexe, |
| 176 self.platform, |
| 177 ['-O0', '--pnacl-sb'], |
| 178 ['StreamInitWithOverrides.*-O0.*-disable-fp-elim.*-mcpu=.*']) |
| 179 |
| 180 def test_overrideTranslateFast(self): |
| 181 if driver_test_utils.CanRunHost(): |
| 182 pexe = self.getFakePexe() |
| 183 # Test that you get O0 when you ask for -translate-fast. |
| 184 # In this case... you don't get no frame pointer elimination. |
| 185 self.checkLLCTranslateFlags( |
| 186 pexe, |
| 187 self.platform, |
| 188 ['-translate-fast'], |
| 189 ['-O0']) |
| 190 self.checkLLCTranslateFlags( |
| 191 pexe, |
| 192 self.platform, |
| 193 ['-translate-fast', '--pnacl-sb'], |
| 194 ['StreamInitWithOverrides.*-O0.*-mcpu=.*']) |
| 195 |
| 196 def test_overrideTLSUseCall(self): |
| 197 if driver_test_utils.CanRunHost(): |
| 198 pexe = self.getFakePexe() |
| 199 # Test that you -mtls-use-call, etc. when you ask for it. |
| 200 self.checkLLCTranslateFlags( |
| 201 pexe, |
| 202 self.platform, |
| 203 ['-mtls-use-call', '-fdata-sections', '-ffunction-sections'], |
| 204 ['-mtls-use-call', '-fdata-sections', '-ffunction-sections']) |
| 205 self.checkLLCTranslateFlags( |
| 206 pexe, |
| 207 self.platform, |
| 208 ['-mtls-use-call', '-fdata-sections', '-ffunction-sections', |
| 209 '--pnacl-sb'], |
| 210 ['StreamInitWithOverrides.*-mtls-use-call' + |
| 211 '.*-fdata-sections.*-ffunction-sections']) |
| 212 |
| 213 def test_overrideMCPU(self): |
| 214 if driver_test_utils.CanRunHost(): |
| 215 pexe = self.getFakePexe() |
| 216 if self.platform == 'arm': |
| 217 mcpu_pattern = '-mcpu=cortex-a15' |
| 218 elif self.platform == 'x86-32': |
| 219 mcpu_pattern = '-mcpu=atom' |
| 220 elif self.platform == 'x86-64': |
| 221 mcpu_pattern = '-mcpu=corei7' |
| 222 else: |
| 223 raise Exception('Unknown platform') |
| 224 # Test that you get the -mcpu that you ask for. |
| 225 self.checkLLCTranslateFlags( |
| 226 pexe, |
| 227 self.platform, |
| 228 [mcpu_pattern], |
| 229 [mcpu_pattern]) |
| 230 self.checkLLCTranslateFlags( |
| 231 pexe, |
| 232 self.platform, |
| 233 [mcpu_pattern, '--pnacl-sb'], |
| 234 ['StreamInitWithOverrides.*' + mcpu_pattern]) |
| 235 |
| 236 def test_overrideMAttr(self): |
| 237 if driver_test_utils.CanRunHost(): |
| 238 pexe = self.getFakePexe() |
| 239 if self.platform == 'arm': |
| 240 mattr_flags, mattr_pat = '-mattr=+hwdiv', r'-mattr=\+hwdiv' |
| 241 elif self.platform == 'x86-32' or self.platform == 'x86-64': |
| 242 mattr_flags, mattr_pat = '-mattr=+avx2,+sse41', r'-mattr=\+avx2,\+sse41' |
| 243 else: |
| 244 raise Exception('Unknown platform') |
| 245 # Test that you get the -mattr=.* that you ask for. |
| 246 self.checkLLCTranslateFlags( |
| 247 pexe, |
| 248 self.platform, |
| 249 [mattr_flags], |
| 250 [mattr_pat]) |
| 251 self.checkLLCTranslateFlags( |
| 252 pexe, |
| 253 self.platform, |
| 254 [mattr_flags, '--pnacl-sb'], |
| 255 ['StreamInitWithOverrides.*' + mattr_pat + '.*-mcpu=.*']) |
| 256 |
| 257 |
| 258 if __name__ == '__main__': |
| 259 unittest.main() |
OLD | NEW |