1*760c253cSXin Li#!/usr/bin/env python3 2*760c253cSXin Li# Copyright 2022 The ChromiumOS Authors 3*760c253cSXin Li# Use of this source code is governed by a BSD-style license that can be 4*760c253cSXin Li# found in the LICENSE file. 5*760c253cSXin Li 6*760c253cSXin Li"""Unit tests for the patch_utils.py file.""" 7*760c253cSXin Li 8*760c253cSXin Liimport copy 9*760c253cSXin Liimport io 10*760c253cSXin Liimport json 11*760c253cSXin Lifrom pathlib import Path 12*760c253cSXin Liimport shutil 13*760c253cSXin Liimport subprocess 14*760c253cSXin Liimport tempfile 15*760c253cSXin Liimport unittest 16*760c253cSXin Lifrom unittest import mock 17*760c253cSXin Li 18*760c253cSXin Liimport patch_utils as pu 19*760c253cSXin Li 20*760c253cSXin Li 21*760c253cSXin Liclass TestPatchUtils(unittest.TestCase): 22*760c253cSXin Li """Test the patch_utils.""" 23*760c253cSXin Li 24*760c253cSXin Li def make_tempdir(self) -> Path: 25*760c253cSXin Li tmpdir = Path(tempfile.mkdtemp(prefix="patch_utils_unittest")) 26*760c253cSXin Li self.addCleanup(shutil.rmtree, tmpdir) 27*760c253cSXin Li return tmpdir 28*760c253cSXin Li 29*760c253cSXin Li def test_predict_indent(self): 30*760c253cSXin Li test_str1 = """ 31*760c253cSXin Lia 32*760c253cSXin Li a 33*760c253cSXin Li a 34*760c253cSXin Li a 35*760c253cSXin Lia 36*760c253cSXin Li""" 37*760c253cSXin Li self.assertEqual(pu.predict_indent(test_str1.splitlines()), 2) 38*760c253cSXin Li test_str2 = """ 39*760c253cSXin Lia 40*760c253cSXin Li a 41*760c253cSXin Li a 42*760c253cSXin Li a 43*760c253cSXin Lia 44*760c253cSXin Li""" 45*760c253cSXin Li self.assertEqual(pu.predict_indent(test_str2.splitlines()), 4) 46*760c253cSXin Li 47*760c253cSXin Li def test_from_to_dict(self): 48*760c253cSXin Li """Test to and from dict conversion.""" 49*760c253cSXin Li d = TestPatchUtils._default_json_dict() 50*760c253cSXin Li d["metadata"] = { 51*760c253cSXin Li "title": "hello world", 52*760c253cSXin Li "info": [], 53*760c253cSXin Li "other_extra_info": { 54*760c253cSXin Li "extra_flags": [], 55*760c253cSXin Li }, 56*760c253cSXin Li } 57*760c253cSXin Li e = pu.PatchEntry.from_dict(TestPatchUtils._mock_dir(), d) 58*760c253cSXin Li self.assertEqual(d, e.to_dict()) 59*760c253cSXin Li 60*760c253cSXin Li # Test that they aren't serialised the same, as 'd' isn't sorted. 61*760c253cSXin Li self.assertNotEqual( 62*760c253cSXin Li json.dumps(d["metadata"]), json.dumps(e.to_dict()["metadata"]) 63*760c253cSXin Li ) 64*760c253cSXin Li self.assertEqual( 65*760c253cSXin Li ["info", "other_extra_info", "title"], 66*760c253cSXin Li list(e.to_dict()["metadata"].keys()), 67*760c253cSXin Li ) 68*760c253cSXin Li 69*760c253cSXin Li def test_patch_path(self): 70*760c253cSXin Li """Test that we can get the full path from a PatchEntry.""" 71*760c253cSXin Li d = TestPatchUtils._default_json_dict() 72*760c253cSXin Li with mock.patch.object(Path, "is_dir", return_value=True): 73*760c253cSXin Li entry = pu.PatchEntry.from_dict(Path("/home/dir"), d) 74*760c253cSXin Li self.assertEqual( 75*760c253cSXin Li entry.patch_path(), Path("/home/dir") / d["rel_patch_path"] 76*760c253cSXin Li ) 77*760c253cSXin Li 78*760c253cSXin Li def test_can_patch_version(self): 79*760c253cSXin Li """Test that patch application based on version is correct.""" 80*760c253cSXin Li base_dict = TestPatchUtils._default_json_dict() 81*760c253cSXin Li workdir = TestPatchUtils._mock_dir() 82*760c253cSXin Li e1 = pu.PatchEntry.from_dict(workdir, base_dict) 83*760c253cSXin Li self.assertFalse(e1.can_patch_version(3)) 84*760c253cSXin Li self.assertTrue(e1.can_patch_version(4)) 85*760c253cSXin Li self.assertTrue(e1.can_patch_version(5)) 86*760c253cSXin Li self.assertFalse(e1.can_patch_version(9)) 87*760c253cSXin Li base_dict["version_range"] = {"until": 9} 88*760c253cSXin Li e2 = pu.PatchEntry.from_dict(workdir, base_dict) 89*760c253cSXin Li self.assertTrue(e2.can_patch_version(0)) 90*760c253cSXin Li self.assertTrue(e2.can_patch_version(5)) 91*760c253cSXin Li self.assertFalse(e2.can_patch_version(9)) 92*760c253cSXin Li base_dict["version_range"] = {"from": 4} 93*760c253cSXin Li e3 = pu.PatchEntry.from_dict(workdir, base_dict) 94*760c253cSXin Li self.assertFalse(e3.can_patch_version(3)) 95*760c253cSXin Li self.assertTrue(e3.can_patch_version(5)) 96*760c253cSXin Li self.assertTrue(e3.can_patch_version(1 << 31)) 97*760c253cSXin Li base_dict["version_range"] = {"from": 4, "until": None} 98*760c253cSXin Li e4 = pu.PatchEntry.from_dict(workdir, base_dict) 99*760c253cSXin Li self.assertFalse(e4.can_patch_version(3)) 100*760c253cSXin Li self.assertTrue(e4.can_patch_version(5)) 101*760c253cSXin Li self.assertTrue(e4.can_patch_version(1 << 31)) 102*760c253cSXin Li base_dict["version_range"] = {"from": None, "until": 9} 103*760c253cSXin Li e5 = pu.PatchEntry.from_dict(workdir, base_dict) 104*760c253cSXin Li self.assertTrue(e5.can_patch_version(0)) 105*760c253cSXin Li self.assertTrue(e5.can_patch_version(5)) 106*760c253cSXin Li self.assertFalse(e5.can_patch_version(9)) 107*760c253cSXin Li 108*760c253cSXin Li def test_can_parse_from_json(self): 109*760c253cSXin Li """Test that patches be loaded from json.""" 110*760c253cSXin Li patches_json = """ 111*760c253cSXin Li[ 112*760c253cSXin Li { 113*760c253cSXin Li "metadata": {}, 114*760c253cSXin Li "platforms": [], 115*760c253cSXin Li "rel_patch_path": "cherry/nowhere.patch", 116*760c253cSXin Li "version_range": {} 117*760c253cSXin Li }, 118*760c253cSXin Li { 119*760c253cSXin Li "metadata": {}, 120*760c253cSXin Li "rel_patch_path": "cherry/somewhere.patch", 121*760c253cSXin Li "version_range": {} 122*760c253cSXin Li }, 123*760c253cSXin Li { 124*760c253cSXin Li "rel_patch_path": "where.patch", 125*760c253cSXin Li "version_range": null 126*760c253cSXin Li }, 127*760c253cSXin Li { 128*760c253cSXin Li "rel_patch_path": "cherry/anywhere.patch" 129*760c253cSXin Li } 130*760c253cSXin Li] 131*760c253cSXin Li """ 132*760c253cSXin Li result = pu.json_str_to_patch_entries(Path(), patches_json) 133*760c253cSXin Li self.assertEqual(len(result), 4) 134*760c253cSXin Li 135*760c253cSXin Li result = pu.json_to_patch_entries(Path(), io.StringIO(patches_json)) 136*760c253cSXin Li self.assertEqual(len(result), 4) 137*760c253cSXin Li 138*760c253cSXin Li def test_parsed_hunks(self): 139*760c253cSXin Li """Test that we can parse patch file hunks.""" 140*760c253cSXin Li m = mock.mock_open(read_data=_EXAMPLE_PATCH) 141*760c253cSXin Li 142*760c253cSXin Li def mocked_open(self, *args, **kwargs): 143*760c253cSXin Li return m(self, *args, **kwargs) 144*760c253cSXin Li 145*760c253cSXin Li with mock.patch.object(Path, "open", mocked_open): 146*760c253cSXin Li e = pu.PatchEntry.from_dict( 147*760c253cSXin Li TestPatchUtils._mock_dir(), TestPatchUtils._default_json_dict() 148*760c253cSXin Li ) 149*760c253cSXin Li hunk_dict = e.parsed_hunks() 150*760c253cSXin Li 151*760c253cSXin Li m.assert_called() 152*760c253cSXin Li filename1 = "clang/lib/Driver/ToolChains/Clang.cpp" 153*760c253cSXin Li filename2 = "llvm/lib/Passes/PassBuilder.cpp" 154*760c253cSXin Li self.assertEqual(set(hunk_dict.keys()), {filename1, filename2}) 155*760c253cSXin Li hunk_list1 = hunk_dict[filename1] 156*760c253cSXin Li hunk_list2 = hunk_dict[filename2] 157*760c253cSXin Li self.assertEqual(len(hunk_list1), 1) 158*760c253cSXin Li self.assertEqual(len(hunk_list2), 2) 159*760c253cSXin Li 160*760c253cSXin Li def test_apply_when_patch_nonexistent(self): 161*760c253cSXin Li """Test that we error out when we try to apply a non-existent patch.""" 162*760c253cSXin Li src_dir = TestPatchUtils._mock_dir("somewhere/llvm-project") 163*760c253cSXin Li patch_dir = TestPatchUtils._mock_dir() 164*760c253cSXin Li e = pu.PatchEntry.from_dict( 165*760c253cSXin Li patch_dir, TestPatchUtils._default_json_dict() 166*760c253cSXin Li ) 167*760c253cSXin Li with mock.patch("subprocess.run", mock.MagicMock()): 168*760c253cSXin Li self.assertRaises(RuntimeError, lambda: e.apply(src_dir)) 169*760c253cSXin Li 170*760c253cSXin Li def test_apply_success(self): 171*760c253cSXin Li """Test that we can call apply.""" 172*760c253cSXin Li src_dir = TestPatchUtils._mock_dir("somewhere/llvm-project") 173*760c253cSXin Li patch_dir = TestPatchUtils._mock_dir() 174*760c253cSXin Li e = pu.PatchEntry.from_dict( 175*760c253cSXin Li patch_dir, TestPatchUtils._default_json_dict() 176*760c253cSXin Li ) 177*760c253cSXin Li 178*760c253cSXin Li # Make a deepcopy of the case for testing commit patch option. 179*760c253cSXin Li e1 = copy.deepcopy(e) 180*760c253cSXin Li 181*760c253cSXin Li with mock.patch("pathlib.Path.is_file", return_value=True): 182*760c253cSXin Li with mock.patch("subprocess.run", mock.MagicMock()): 183*760c253cSXin Li result = e.apply(src_dir) 184*760c253cSXin Li self.assertTrue(result.succeeded) 185*760c253cSXin Li 186*760c253cSXin Li # Test that commit patch option works. 187*760c253cSXin Li with mock.patch("pathlib.Path.is_file", return_value=True): 188*760c253cSXin Li with mock.patch("subprocess.run", mock.MagicMock()): 189*760c253cSXin Li result1 = e1.apply(src_dir, pu.git_am) 190*760c253cSXin Li self.assertTrue(result1.succeeded) 191*760c253cSXin Li 192*760c253cSXin Li def test_parse_failed_patch_output(self): 193*760c253cSXin Li """Test that we can call parse `patch` output.""" 194*760c253cSXin Li fixture = """ 195*760c253cSXin Lichecking file a/b/c.cpp 196*760c253cSXin LiHunk #1 SUCCEEDED at 96 with fuzz 1. 197*760c253cSXin LiHunk #12 FAILED at 77. 198*760c253cSXin LiHunk #42 FAILED at 1979. 199*760c253cSXin Lichecking file x/y/z.h 200*760c253cSXin LiHunk #4 FAILED at 30. 201*760c253cSXin Lichecking file works.cpp 202*760c253cSXin LiHunk #1 SUCCEEDED at 96 with fuzz 1. 203*760c253cSXin Li""" 204*760c253cSXin Li result = pu.parse_failed_patch_output(fixture) 205*760c253cSXin Li self.assertEqual(result["a/b/c.cpp"], [12, 42]) 206*760c253cSXin Li self.assertEqual(result["x/y/z.h"], [4]) 207*760c253cSXin Li self.assertNotIn("works.cpp", result) 208*760c253cSXin Li 209*760c253cSXin Li def test_is_git_dirty(self): 210*760c253cSXin Li """Test if a git directory has uncommitted changes.""" 211*760c253cSXin Li dirpath = self.make_tempdir() 212*760c253cSXin Li 213*760c253cSXin Li def _run_h(cmd): 214*760c253cSXin Li subprocess.run( 215*760c253cSXin Li cmd, 216*760c253cSXin Li cwd=dirpath, 217*760c253cSXin Li stdout=subprocess.DEVNULL, 218*760c253cSXin Li stderr=subprocess.DEVNULL, 219*760c253cSXin Li check=True, 220*760c253cSXin Li ) 221*760c253cSXin Li 222*760c253cSXin Li _run_h(["git", "init"]) 223*760c253cSXin Li self.assertFalse(pu.is_git_dirty(dirpath)) 224*760c253cSXin Li test_file = dirpath / "test_file" 225*760c253cSXin Li test_file.touch() 226*760c253cSXin Li self.assertTrue(pu.is_git_dirty(dirpath)) 227*760c253cSXin Li _run_h(["git", "add", "."]) 228*760c253cSXin Li _run_h(["git", "commit", "-m", "test"]) 229*760c253cSXin Li self.assertFalse(pu.is_git_dirty(dirpath)) 230*760c253cSXin Li test_file.touch() 231*760c253cSXin Li self.assertFalse(pu.is_git_dirty(dirpath)) 232*760c253cSXin Li with test_file.open("w", encoding="utf-8"): 233*760c253cSXin Li test_file.write_text("abc") 234*760c253cSXin Li self.assertTrue(pu.is_git_dirty(dirpath)) 235*760c253cSXin Li 236*760c253cSXin Li @mock.patch("patch_utils.git_clean_context", mock.MagicMock) 237*760c253cSXin Li def test_update_version_ranges(self): 238*760c253cSXin Li """Test the UpdateVersionRanges function.""" 239*760c253cSXin Li dirpath = self.make_tempdir() 240*760c253cSXin Li patches = [ 241*760c253cSXin Li pu.PatchEntry( 242*760c253cSXin Li workdir=dirpath, 243*760c253cSXin Li rel_patch_path="x.patch", 244*760c253cSXin Li metadata=None, 245*760c253cSXin Li platforms=None, 246*760c253cSXin Li version_range={ 247*760c253cSXin Li "from": 0, 248*760c253cSXin Li "until": 2, 249*760c253cSXin Li }, 250*760c253cSXin Li ), 251*760c253cSXin Li pu.PatchEntry( 252*760c253cSXin Li workdir=dirpath, 253*760c253cSXin Li rel_patch_path="y.patch", 254*760c253cSXin Li metadata=None, 255*760c253cSXin Li platforms=None, 256*760c253cSXin Li version_range={ 257*760c253cSXin Li "from": 0, 258*760c253cSXin Li "until": 2, 259*760c253cSXin Li }, 260*760c253cSXin Li ), 261*760c253cSXin Li pu.PatchEntry( 262*760c253cSXin Li workdir=dirpath, 263*760c253cSXin Li rel_patch_path="z.patch", 264*760c253cSXin Li metadata=None, 265*760c253cSXin Li platforms=None, 266*760c253cSXin Li version_range={ 267*760c253cSXin Li "from": 4, 268*760c253cSXin Li "until": 5, 269*760c253cSXin Li }, 270*760c253cSXin Li ), 271*760c253cSXin Li ] 272*760c253cSXin Li 273*760c253cSXin Li patches[0].apply = mock.MagicMock( 274*760c253cSXin Li return_value=pu.PatchResult( 275*760c253cSXin Li succeeded=False, failed_hunks={"a/b/c": []} 276*760c253cSXin Li ) 277*760c253cSXin Li ) 278*760c253cSXin Li patches[1].apply = mock.MagicMock( 279*760c253cSXin Li return_value=pu.PatchResult(succeeded=True) 280*760c253cSXin Li ) 281*760c253cSXin Li patches[2].apply = mock.MagicMock( 282*760c253cSXin Li return_value=pu.PatchResult(succeeded=False) 283*760c253cSXin Li ) 284*760c253cSXin Li 285*760c253cSXin Li # Make a deepcopy of patches to test commit patch option 286*760c253cSXin Li patches2 = copy.deepcopy(patches) 287*760c253cSXin Li 288*760c253cSXin Li results, _ = pu.update_version_ranges_with_entries( 289*760c253cSXin Li 1, dirpath, patches, pu.gnu_patch 290*760c253cSXin Li ) 291*760c253cSXin Li 292*760c253cSXin Li # We should only have updated the version_range of the first patch, 293*760c253cSXin Li # as that one failed to apply. 294*760c253cSXin Li self.assertEqual(len(results), 1) 295*760c253cSXin Li self.assertEqual(results[0].version_range, {"from": 0, "until": 1}) 296*760c253cSXin Li self.assertEqual(patches[0].version_range, {"from": 0, "until": 1}) 297*760c253cSXin Li self.assertEqual(patches[1].version_range, {"from": 0, "until": 2}) 298*760c253cSXin Li self.assertEqual(patches[2].version_range, {"from": 4, "until": 5}) 299*760c253cSXin Li 300*760c253cSXin Li # Test git am option 301*760c253cSXin Li results2, _ = pu.update_version_ranges_with_entries( 302*760c253cSXin Li 1, dirpath, patches2, pu.git_am 303*760c253cSXin Li ) 304*760c253cSXin Li 305*760c253cSXin Li # We should only have updated the version_range of the first patch 306*760c253cSXin Li # via git am, as that one failed to apply. 307*760c253cSXin Li self.assertEqual(len(results2), 1) 308*760c253cSXin Li self.assertEqual(results2[0].version_range, {"from": 0, "until": 1}) 309*760c253cSXin Li self.assertEqual(patches2[0].version_range, {"from": 0, "until": 1}) 310*760c253cSXin Li self.assertEqual(patches2[1].version_range, {"from": 0, "until": 2}) 311*760c253cSXin Li self.assertEqual(patches2[2].version_range, {"from": 4, "until": 5}) 312*760c253cSXin Li 313*760c253cSXin Li def test_remove_old_patches(self): 314*760c253cSXin Li patches = [ 315*760c253cSXin Li {"rel_patch_path": "foo.patch"}, 316*760c253cSXin Li { 317*760c253cSXin Li "rel_patch_path": "bar.patch", 318*760c253cSXin Li "version_range": { 319*760c253cSXin Li "from": 1, 320*760c253cSXin Li }, 321*760c253cSXin Li }, 322*760c253cSXin Li { 323*760c253cSXin Li "rel_patch_path": "baz.patch", 324*760c253cSXin Li "version_range": { 325*760c253cSXin Li "until": 1, 326*760c253cSXin Li }, 327*760c253cSXin Li }, 328*760c253cSXin Li ] 329*760c253cSXin Li 330*760c253cSXin Li tempdir = self.make_tempdir() 331*760c253cSXin Li patches_json = tempdir / "PATCHES.json" 332*760c253cSXin Li with patches_json.open("w", encoding="utf-8") as f: 333*760c253cSXin Li json.dump(patches, f) 334*760c253cSXin Li 335*760c253cSXin Li removed_paths = pu.remove_old_patches( 336*760c253cSXin Li svn_version=10, patches_json=patches_json 337*760c253cSXin Li ) 338*760c253cSXin Li self.assertEqual(removed_paths, [tempdir / "baz.patch"]) 339*760c253cSXin Li expected_patches = [ 340*760c253cSXin Li x for x in patches if x["rel_patch_path"] != "baz.patch" 341*760c253cSXin Li ] 342*760c253cSXin Li self.assertEqual( 343*760c253cSXin Li json.loads(patches_json.read_text(encoding="utf-8")), 344*760c253cSXin Li expected_patches, 345*760c253cSXin Li ) 346*760c253cSXin Li 347*760c253cSXin Li @staticmethod 348*760c253cSXin Li def _default_json_dict(): 349*760c253cSXin Li return { 350*760c253cSXin Li "metadata": { 351*760c253cSXin Li "title": "hello world", 352*760c253cSXin Li }, 353*760c253cSXin Li "platforms": ["a"], 354*760c253cSXin Li "rel_patch_path": "x/y/z", 355*760c253cSXin Li "version_range": { 356*760c253cSXin Li "from": 4, 357*760c253cSXin Li "until": 9, 358*760c253cSXin Li }, 359*760c253cSXin Li } 360*760c253cSXin Li 361*760c253cSXin Li @staticmethod 362*760c253cSXin Li def _mock_dir(path: str = "a/b/c"): 363*760c253cSXin Li workdir = Path(path) 364*760c253cSXin Li workdir = mock.MagicMock(workdir) 365*760c253cSXin Li workdir.is_dir = lambda: True 366*760c253cSXin Li workdir.joinpath = lambda x: Path(path).joinpath(x) 367*760c253cSXin Li workdir.__truediv__ = lambda self, x: self.joinpath(x) 368*760c253cSXin Li return workdir 369*760c253cSXin Li 370*760c253cSXin Li 371*760c253cSXin Li_EXAMPLE_PATCH = """ 372*760c253cSXin Lidiff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp 373*760c253cSXin Liindex 5620a543438..099eb769ca5 100644 374*760c253cSXin Li--- a/clang/lib/Driver/ToolChains/Clang.cpp 375*760c253cSXin Li+++ b/clang/lib/Driver/ToolChains/Clang.cpp 376*760c253cSXin Li@@ -3995,8 +3995,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, 377*760c253cSXin Li Args.hasArg(options::OPT_dA)) 378*760c253cSXin Li CmdArgs.push_back("-masm-verbose"); 379*760c253cSXin Li 380*760c253cSXin Li- if (!TC.useIntegratedAs()) 381*760c253cSXin Li+ if (!TC.useIntegratedAs()) { 382*760c253cSXin Li CmdArgs.push_back("-no-integrated-as"); 383*760c253cSXin Li+ CmdArgs.push_back("-mllvm"); 384*760c253cSXin Li+ CmdArgs.push_back("-enable-call-graph-profile-sort=false"); 385*760c253cSXin Li+ } 386*760c253cSXin Li 387*760c253cSXin Li if (Args.hasArg(options::OPT_fdebug_pass_structure)) { 388*760c253cSXin Li CmdArgs.push_back("-mdebug-pass"); 389*760c253cSXin Lidiff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp 390*760c253cSXin Liindex c5fd68299eb..4c6e15eeeb9 100644 391*760c253cSXin Li--- a/llvm/lib/Passes/PassBuilder.cpp 392*760c253cSXin Li+++ b/llvm/lib/Passes/PassBuilder.cpp 393*760c253cSXin Li@@ -212,6 +212,10 @@ static cl::opt<bool> 394*760c253cSXin Li EnableCHR("enable-chr-npm", cl::init(true), cl::Hidden, 395*760c253cSXin Li cl::desc("Enable control height reduction optimization (CHR)")); 396*760c253cSXin Li 397*760c253cSXin Li+static cl::opt<bool> EnableCallGraphProfileSort( 398*760c253cSXin Li+ "enable-call-graph-profile-sort", cl::init(true), cl::Hidden, 399*760c253cSXin Li+ cl::desc("Enable call graph profile pass for the new PM (default = on)")); 400*760c253cSXin Li+ 401*760c253cSXin Li extern cl::opt<bool> EnableHotColdSplit; 402*760c253cSXin Li extern cl::opt<bool> EnableOrderFileInstrumentation; 403*760c253cSXin Li 404*760c253cSXin Li@@ -939,7 +943,8 @@ ModulePassManager PassBuilder::buildModuleOptimizationPipeline( 405*760c253cSXin Li // Add the core optimizing pipeline. 406*760c253cSXin Li MPM.addPass(createModuleToFunctionPassAdaptor(std::move(OptimizePM))); 407*760c253cSXin Li 408*760c253cSXin Li- MPM.addPass(CGProfilePass()); 409*760c253cSXin Li+ if (EnableCallGraphProfileSort) 410*760c253cSXin Li+ MPM.addPass(CGProfilePass()); 411*760c253cSXin Li 412*760c253cSXin Li // Now we need to do some global optimization transforms. 413*760c253cSXin Li // FIXME: It would seem like these should come first in the optimization 414*760c253cSXin Li""" 415*760c253cSXin Li 416*760c253cSXin Liif __name__ == "__main__": 417*760c253cSXin Li unittest.main() 418