1 # 2 # Copyright (C) 2010 The Android Open Source Project 3 # 4 # Licensed under the Apache License, Version 2.0 (the "License"); 5 # you may not use this file except in compliance with the License. 6 # You may obtain a copy of the License at 7 # 8 # http://www.apache.org/licenses/LICENSE-2.0 9 # 10 # Unless required by applicable law or agreed to in writing, software 11 # distributed under the License is distributed on an "AS IS" BASIS, 12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 # See the License for the specific language governing permissions and 14 # limitations under the License. 15 # 16 17 # 18 # Test the bcc compiler 19 20 import unittest 21 import subprocess 22 import os 23 import sys 24 25 gArmInitialized = False 26 gUseArm = True 27 gUseX86 = True 28 gRunOTCCOutput = True 29 30 31 def parseArgv(): 32 global gUseArm 33 global gUseX86 34 global gRunOTCCOutput 35 for arg in sys.argv[1:]: 36 if arg == "--noarm": 37 print "--noarm: not testing ARM" 38 gUseArm = False 39 elif arg == "--nox86": 40 print "--nox86: not testing x86" 41 gUseX86 = False 42 elif arg == "--norunotcc": 43 print "--norunotcc detected, not running OTCC output" 44 gRunOTCCOutput = False 45 else: 46 print "Unknown parameter: ", arg 47 raise "Unknown parameter" 48 sys.argv = sys.argv[0:1] 49 50 def compile(args): 51 proc = subprocess.Popen(["../libbcc_driver"] + args, stderr=subprocess.PIPE, stdout=subprocess.PIPE) 52 result = proc.communicate() 53 return result 54 55 def runCmd(args): 56 proc = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 57 result = proc.communicate() 58 return result[0].strip() 59 60 def uname(): 61 return runCmd(["uname"]) 62 63 def unameM(): 64 return runCmd(["uname", "-m"]) 65 66 def which(item): 67 return runCmd(["which", item]) 68 69 def fileType(item): 70 return runCmd(["file", item]) 71 72 def outputCanRun(): 73 ft = fileType(which("bcc")) 74 return ft.find("ELF 32-bit LSB executable, Intel 80386") >= 0 75 76 def checkEnvironment(): 77 global gRunOTCCOutput 78 gRunOTCCOutput = uname() == "Linux" and unameM() != "x86_64" and outputCanRun() 79 80 def adb(args): 81 return runCmd(["adb"] + args) 82 83 def setupArm(): 84 global gArmInitialized 85 if gArmInitialized: 86 return 87 print "Setting up arm" 88 adb(["remount"]) 89 adb(["shell", "rm", "/system/bin/bcc"]) 90 adb(["shell", "mkdir", "/system/bin/bccdata"]) 91 adb(["shell", "mkdir", "/system/bin/bccdata/data"]) 92 # Clear out old data TODO: handle recursion 93 adb(["shell", "rm", "/system/bin/bccdata/data/*"]) 94 # Copy over data 95 for root, dirs, files in os.walk("data"): 96 for d in dirs: 97 adb(["shell", "mkdir", os.path.join(root, d)]) 98 for f in files: 99 adb(["push", os.path.join(root, f), os.path.join("/system/bin/bccdata", root, f)]) 100 # Copy over compiler 101 adb(["sync"]) 102 gArmInitialized = True 103 104 def compileArm(args): 105 setupArm() 106 proc = subprocess.Popen(["adb", "shell", "/system/bin/bcc"] + args, stdout=subprocess.PIPE) 107 result = proc.communicate() 108 return result[0].replace("\r","") 109 110 def compare(a, b): 111 if a != b: 112 firstDiff = firstDifference(a, b) 113 print "Strings differ at character %d. Common: %s. Difference '%s' != '%s'" % ( 114 firstDiff, a[0:firstDiff], safeAccess(a, firstDiff), safeAccess(b, firstDiff)) 115 116 def safeAccess(s, i): 117 if 0 <= i < len(s): 118 return s[i] 119 else: 120 return '?' 121 122 def firstDifference(a, b): 123 commonLen = min(len(a), len(b)) 124 for i in xrange(0, commonLen): 125 if a[i] != b[i]: 126 return i 127 return commonLen 128 129 # a1 and a2 are the expected stdout and stderr. 130 # b1 and b2 are the actual stdout and stderr. 131 # Compare the two, sets. Allow any individual line 132 # to appear in either stdout or stderr. This is because 133 # the way we obtain output on the ARM combines both 134 # streams into one sequence. 135 136 def compareOuput(a1,a2,b1,b2): 137 while True: 138 totalLen = len(a1) + len(a2) + len(b1) + len(b2) 139 a1, b1 = matchCommon(a1, b1) 140 a1, b2 = matchCommon(a1, b2) 141 a2, b1 = matchCommon(a2, b1) 142 a2, b2 = matchCommon(a2, b2) 143 newTotalLen = len(a1) + len(a2) + len(b1) + len(b2) 144 if newTotalLen == 0: 145 return True 146 if newTotalLen == totalLen: 147 print "Failed at %d %d %d %d" % (len(a1), len(a2), len(b1), len(b2)) 148 print "a1", a1 149 print "a2", a2 150 print "b1", b1 151 print "b2", b2 152 return False 153 154 def matchCommon(a, b): 155 """Remove common items from the beginning of a and b, 156 return just the tails that are different.""" 157 while len(a) > 0 and len(b) > 0 and a[0] == b[0]: 158 a = a[1:] 159 b = b[1:] 160 return a, b 161 162 def rewritePaths(args): 163 return [rewritePath(x) for x in args] 164 165 def rewritePath(p): 166 """Take a path that's correct on the x86 and convert to a path 167 that's correct on ARM.""" 168 if p.startswith("data/"): 169 p = "/system/bin/bccdata/" + p 170 return p 171 172 class TestACC(unittest.TestCase): 173 174 def checkResult(self, out, err, stdErrResult, stdOutResult=""): 175 a1 = out.splitlines() 176 a2 = err.splitlines() 177 b2 = stdErrResult.splitlines() 178 b1 = stdOutResult.splitlines() 179 self.assertEqual(True, compareOuput(a1,a2,b1,b2)) 180 181 def compileCheck(self, args, stdErrResult, stdOutResult="", 182 targets=['arm', 'x86']): 183 global gUseArm 184 global gUseX86 185 targetSet = frozenset(targets) 186 if gUseX86 and 'x86' in targetSet: 187 print args 188 out, err = compile(args) 189 self.checkResult(out, err, stdErrResult, stdOutResult) 190 if gUseArm and 'arm' in targetSet: 191 out = compileArm(rewritePaths(args)) 192 self.checkResult(out, "", stdErrResult, stdOutResult) 193 194 def compileCheckArm(self, args, result): 195 self.assertEqual(compileArm(args), result) 196 197 def testCompileReturnVal(self): 198 self.compileCheck(["data/returnval-ansi.bc"], "") 199 200 def testCompileOTCCANSII(self): 201 self.compileCheck(["data/otcc-ansi.bc"], "", "", ['x86']) 202 203 def testRunReturnVal(self): 204 self.compileCheck(["-R", "data/returnval-ansi.bc"], 205 "Executing compiled code:\nresult: 42\n") 206 207 def testStringLiteralConcatenation(self): 208 self.compileCheck(["-R", "data/testStringConcat.bc"], 209 "Executing compiled code:\nresult: 13\n", "Hello, world\n") 210 211 def testRunOTCCANSI(self): 212 global gRunOTCCOutput 213 if gRunOTCCOutput: 214 self.compileCheck(["-R", "data/otcc-ansi.bc", "data/returnval.c"], 215 "Executing compiled code:\notcc-ansi.c: About to execute compiled code:\natcc-ansi.c: result: 42\nresult: 42\n", "", 216 ['x86']) 217 218 def testRunOTCCANSI2(self): 219 global gRunOTCCOutput 220 if gRunOTCCOutput: 221 self.compileCheck(["-R", "data/otcc-ansi.bc", "data/otcc.c", "data/returnval.c"], 222 "Executing compiled code:\notcc-ansi.c: About to execute compiled code:\notcc.c: about to execute compiled code.\natcc-ansi.c: result: 42\nresult: 42\n", "",['x86']) 223 224 def testRunConstants(self): 225 self.compileCheck(["-R", "data/constants.bc"], 226 "Executing compiled code:\nresult: 0\n", 227 "0 = 0\n010 = 8\n0x10 = 16\n'\\a' = 7\n'\\b' = 8\n'\\f' = 12\n'\\n' = 10\n'\\r' = 13\n'\\t' = 9\n'\\v' = 11\n'\\\\' = 92\n'\\'' = 39\n" + 228 "'\\\"' = 34\n'\\?' = 63\n'\\0' = 0\n'\\1' = 1\n'\\12' = 10\n'\\123' = 83\n'\\x0' = 0\n'\\x1' = 1\n'\\x12' = 18\n'\\x123' = 35\n'\\x1f' = 31\n'\\x1F' = 31\n") 229 230 def testRunFloat(self): 231 self.compileCheck(["-R", "data/float.bc"], 232 "Executing compiled code:\nresult: 0\n", 233 """Constants: 0 0 0 0.01 0.01 0.1 10 10 0.1 234 int: 1 float: 2.2 double: 3.3 235 ftoi(1.4f)=1 236 dtoi(2.4)=2 237 itof(3)=3 238 itod(4)=4 239 globals: 1 2 3 4 240 args: 1 2 3 4 241 locals: 1 2 3 4 242 cast rval: 2 4 243 cast lval: 1.1 2 3.3 4 244 """) 245 246 def testRunFlops(self): 247 self.compileCheck(["-R", "data/flops.bc"], 248 """Executing compiled code: 249 result: 0""", 250 """-1.1 = -1.1 251 !1.2 = 0 252 !0 = 1 253 double op double: 254 1 + 2 = 3 255 1 - 2 = -1 256 1 * 2 = 2 257 1 / 2 = 0.5 258 float op float: 259 1 + 2 = 3 260 1 - 2 = -1 261 1 * 2 = 2 262 1 / 2 = 0.5 263 double op float: 264 1 + 2 = 3 265 1 - 2 = -1 266 1 * 2 = 2 267 1 / 2 = 0.5 268 double op int: 269 1 + 2 = 3 270 1 - 2 = -1 271 1 * 2 = 2 272 1 / 2 = 0.5 273 int op double: 274 1 + 2 = 3 275 1 - 2 = -1 276 1 * 2 = 2 277 1 / 2 = 0.5 278 double op double: 279 1 op 2: < 1 <= 1 == 0 >= 0 > 0 != 1 280 1 op 1: < 0 <= 1 == 1 >= 1 > 0 != 0 281 2 op 1: < 0 <= 0 == 0 >= 1 > 1 != 1 282 double op float: 283 1 op 2: < 1 <= 1 == 0 >= 0 > 0 != 1 284 1 op 1: < 0 <= 1 == 1 >= 1 > 0 != 0 285 2 op 1: < 0 <= 0 == 0 >= 1 > 1 != 1 286 float op float: 287 1 op 2: < 1 <= 1 == 0 >= 0 > 0 != 1 288 1 op 1: < 0 <= 1 == 1 >= 1 > 0 != 0 289 2 op 1: < 0 <= 0 == 0 >= 1 > 1 != 1 290 int op double: 291 1 op 2: < 1 <= 1 == 0 >= 0 > 0 != 1 292 1 op 1: < 0 <= 1 == 1 >= 1 > 0 != 0 293 2 op 1: < 0 <= 0 == 0 >= 1 > 1 != 1 294 double op int: 295 1 op 2: < 1 <= 1 == 0 >= 0 > 0 != 1 296 1 op 1: < 0 <= 1 == 1 >= 1 > 0 != 0 297 2 op 1: < 0 <= 0 == 0 >= 1 > 1 != 1 298 branching: 1 0 1 299 testpassi: 1 2 3 4 5 6 7 8 9 10 11 12 300 testpassf: 1 2 3 4 5 6 7 8 9 10 11 12 301 testpassd: 1 2 3 4 5 6 7 8 9 10 11 12 302 testpassi: 1 2 3 4 5 6 7 8 9 10 11 12 303 testpassf: 1 2 3 4 5 6 7 8 9 10 11 12 304 testpassd: 1 2 3 4 5 6 7 8 9 10 11 12 305 testpassi: 1 2 3 4 5 6 7 8 9 10 11 12 306 testpassf: 1 2 3 4 5 6 7 8 9 10 11 12 307 testpassd: 1 2 3 4 5 6 7 8 9 10 11 12 308 testpassidf: 1 2 3 309 """) 310 def testCasts(self): 311 self.compileCheck(["-R", "data/casts.bc"], 312 """Executing compiled code: 313 result: 0""", """Reading from a pointer: 3 3 314 Writing to a pointer: 4 315 Testing casts: 3 3 4.5 4 316 Testing reading (int*): 4 317 Testing writing (int*): 8 9 318 Testing reading (char*): 0x78 0x56 0x34 0x12 319 Testing writing (char*): 0x87654321 320 f(10) 321 Function pointer result: 70 322 Testing read/write (float*): 8.8 9.9 323 Testing read/write (double*): 8.8 9.9 324 """) 325 326 def testChar(self): 327 self.compileCheck(["-R", "data/char.bc"], """Executing compiled code: 328 result: 0""", """a = 99, b = 41 329 ga = 100, gb = 44""") 330 331 def testPointerArithmetic(self): 332 self.compileCheck(["-R", "data/pointers.bc"], """Executing compiled code: 333 result: 0""", """Pointer difference: 1 4 334 Pointer addition: 2 335 Pointer comparison to zero: 0 0 1 336 Pointer comparison: 1 0 0 0 1 337 """) 338 def testRollo3(self): 339 self.compileCheck(["-R", "data/rollo3.bc"], """Executing compiled code: 340 result: 10""", """""") 341 342 def testFloatDouble(self): 343 self.compileCheck(["-R", "data/floatdouble.bc"], """Executing compiled code: 344 result: 0""", """0.002 0.1 10""") 345 346 def testIncDec(self): 347 self.compileCheck(["-R", "data/inc.bc"], """Executing compiled code: 348 0 349 1 350 2 351 1 352 1 353 2 354 1 355 0 356 result: 0 357 ""","""""") 358 359 def testIops(self): 360 self.compileCheck(["-R", "data/iops.bc"], """Executing compiled code: 361 result: 0""", """Literals: 1 -1 362 ++ 363 0 364 1 365 2 366 3 367 4 368 5 369 6 370 7 371 8 372 9 373 -- 374 10 375 9 376 8 377 7 378 6 379 5 380 4 381 3 382 2 383 1 384 0 385 """) 386 387 def testFilm(self): 388 self.compileCheck(["-R", "data/film.bc"], """Executing compiled code: 389 result: 0""", """testing... 390 Total bad: 0 391 """) 392 393 def testpointers2(self): 394 self.compileCheck(["-R", "data/pointers2.bc"], """Executing compiled code: 395 result: 0""", """a = 0, *pa = 0 396 a = 2, *pa = 2 397 a = 0, *pa = 0 **ppa = 0 398 a = 2, *pa = 2 **ppa = 2 399 a = 0, *pa = 0 **ppa = 0 400 a = 2, *pa = 2 **ppa = 2 401 """) 402 403 def testassignmentop(self): 404 self.compileCheck(["-R", "data/assignmentop.bc"], """Executing compiled code: 405 result: 0""", """2 *= 5 10 406 20 /= 5 4 407 17 %= 5 2 408 17 += 5 22 409 17 -= 5 12 410 17<<= 1 34 411 17>>= 1 8 412 17&= 1 1 413 17^= 1 16 414 16|= 1 17 415 *f() = *f() + 10; 416 f() 417 f() 418 a = 10 419 *f() += 10; 420 f() 421 a = 10 422 """) 423 424 def testcomma(self): 425 self.compileCheck(["-R", "data/comma.bc"], """Executing compiled code: 426 result: 0""", """statement: 10 427 if: a = 0 428 while: b = 11 429 for: b = 22 430 return: 30 431 arg: 12 432 """) 433 434 def testBrackets(self): 435 self.compileCheck(["-R", "data/brackets.bc"], """Executing compiled code: 436 Errors: 0 437 2D Errors: 0 438 result: 0 439 ""","""""") 440 441 def testShort(self): 442 self.compileCheck(["-R", "data/short.bc"], """Executing compiled code: 443 result: -2 444 ""","""""") 445 446 def testAssignment(self): 447 self.compileCheck(["-R", "data/assignment.bc"], """Executing compiled code: 448 result: 7 449 ""","""""") 450 451 def testArray(self): 452 self.compileCheck(["-R", "data/array.bc"], """Executing compiled code: 453 localInt: 3 454 localDouble: 3 3 455 globalChar: 3 456 globalDouble: 3 457 testArgs: 0 2 4 458 testDecay: Hi! 459 test2D: 460 abcdefghijklmnopabcd 461 defghijklmnopabcdefg 462 ghijklmnopabcdefghij 463 jklmnopabcdefghijklm 464 mnopabcdefghijklmnop 465 pabcdefghijklmnopabc 466 cdefghijklmnopabcdef 467 fghijklmnopabcdefghi 468 ijklmnopabcdefghijkl 469 lmnopabcdefghijklmno 470 result: 0 471 ""","""""") 472 473 def testDefines(self): 474 self.compileCheck(["-R", "data/defines.bc"], """Executing compiled code: 475 result: 3 476 ""","""""") 477 478 def testFuncArgs(self): 479 self.compileCheck(["-R", "data/funcargs.bc"], """Executing compiled code: 480 result: 4 481 ""","""""") 482 483 def testB2071670(self): 484 self.compileCheck(["-R", "data/b2071670.bc"], """Executing compiled code: 485 result: 1092616192 486 ""","""""") 487 488 def testStructs(self): 489 self.compileCheck(["-R", "data/structs.bc"], """Executing compiled code: 490 testCopying: 37 == 37 491 testUnion: 1 == 0x3f800000 492 testArgs: (6, 8, 10, 12) 493 result: 6 494 ""","""""") 495 496 def testAddressOf(self): 497 self.compileCheck(["-R", "data/addressOf.bc"], """Executing compiled code: 498 testStruct: 10 10 10 499 testArray: 1 1 1 500 result: 0 501 ""","""""") 502 503 def main(): 504 checkEnvironment() 505 parseArgv() 506 unittest.main() 507 508 if __name__ == '__main__': 509 main() 510 511