77import sys
88import textwrap
99
10+ msg_prefix = "\n > NFC-Mode:"
11+
1012def get_relevant_bolt_changes (dir : str ) -> str :
1113 # Return a list of bolt source changes that are relevant to testing.
1214 all_changes = subprocess .run (
@@ -42,14 +44,32 @@ def get_git_ref_or_rev(dir: str) -> str:
4244 cmd_rev = "git rev-parse --short HEAD"
4345 return subprocess .check_output (shlex .split (cmd_rev ), cwd = dir , text = True ).strip ()
4446
47+ def switch_back (
48+ switch_back : bool , stash : bool , source_dir : str , old_ref : str , new_ref : str
49+ ):
50+ # Switch back to the current revision if needed and inform the user of where
51+ # the HEAD is. Must be called after checking out the previous commit on all
52+ # exit paths.
53+ if switch_back :
54+ print (f"{ msg_prefix } Switching back to current revision.." )
55+ if stash :
56+ subprocess .run (shlex .split ("git stash pop" ), cwd = source_dir )
57+ subprocess .run (shlex .split (f"git checkout { old_ref } " ), cwd = source_dir )
58+ else :
59+ print (
60+ f"The repository { source_dir } has been switched from { old_ref } "
61+ f"to { new_ref } . Local changes were stashed. Switch back using\n \t "
62+ f"git checkout { old_ref } \n "
63+ )
4564
4665def main ():
4766 parser = argparse .ArgumentParser (
4867 description = textwrap .dedent (
4968 """
50- This script builds two versions of BOLT (with the current and
51- previous revision) and sets up symlink for llvm-bolt-wrapper.
52- Passes the options through to llvm-bolt-wrapper.
69+ This script builds two versions of BOLT:
70+ llvm-bolt.new, using the current revision, and llvm-bolt.old using
71+ the previous revision. These can be used to check whether the
72+ current revision changes BOLT's functional behavior.
5373 """
5474 )
5575 )
@@ -59,6 +79,12 @@ def main():
5979 default = os .getcwd (),
6080 help = "Path to BOLT build directory, default is current " "directory" ,
6181 )
82+ parser .add_argument (
83+ "--create-wrapper" ,
84+ default = False ,
85+ action = "store_true" ,
86+ help = "Sets up llvm-bolt as a symlink to llvm-bolt-wrapper. Passes the options through to llvm-bolt-wrapper." ,
87+ )
6288 parser .add_argument (
6389 "--check-bolt-sources" ,
6490 default = False ,
@@ -76,28 +102,42 @@ def main():
76102 default = "HEAD^" ,
77103 help = "Revision to checkout to compare vs HEAD" ,
78104 )
105+
106+ # When creating a wrapper, pass any unknown arguments to it. Otherwise, die.
79107 args , wrapper_args = parser .parse_known_args ()
80- bolt_path = f"{ args .build_dir } /bin/llvm-bolt"
108+ if not args .create_wrapper and len (wrapper_args ) > 0 :
109+ parser .parse_args ()
81110
111+ # Find the repo directory.
82112 source_dir = None
83- # find the repo directory
84- with open (f"{ args .build_dir } /CMakeCache.txt" ) as f :
85- for line in f :
86- m = re .match (r"LLVM_SOURCE_DIR:STATIC=(.*)" , line )
87- if m :
88- source_dir = m .groups ()[0 ]
89- if not source_dir :
90- sys .exit ("Source directory is not found" )
91-
92- script_dir = os .path .dirname (os .path .abspath (__file__ ))
93- wrapper_path = f"{ script_dir } /llvm-bolt-wrapper.py"
94- # build the current commit
113+ try :
114+ CMCacheFilename = f"{ args .build_dir } /CMakeCache.txt"
115+ with open (CMCacheFilename ) as f :
116+ for line in f :
117+ m = re .match (r"LLVM_SOURCE_DIR:STATIC=(.*)" , line )
118+ if m :
119+ source_dir = m .groups ()[0 ]
120+ if not source_dir :
121+ raise Exception (f"Source directory not found: '{ CMCacheFilename } '" )
122+ except Exception as e :
123+ sys .exit (e )
124+
125+ # Clean the previous llvm-bolt if it exists.
126+ bolt_path = f"{ args .build_dir } /bin/llvm-bolt"
127+ if os .path .exists (bolt_path ):
128+ os .remove (bolt_path )
129+
130+ # Build the current commit.
131+ print (f"{ msg_prefix } Building current revision.." )
95132 subprocess .run (
96133 shlex .split ("cmake --build . --target llvm-bolt" ), cwd = args .build_dir
97134 )
98- # rename llvm-bolt
135+
136+ if not os .path .exists (bolt_path ):
137+ sys .exit (f"Failed to build the current revision: '{ bolt_path } '" )
138+
139+ # Rename llvm-bolt and memorize the old hash for logging.
99140 os .replace (bolt_path , f"{ bolt_path } .new" )
100- # memorize the old hash for logging
101141 old_ref = get_git_ref_or_rev (source_dir )
102142
103143 if args .check_bolt_sources :
@@ -110,7 +150,7 @@ def main():
110150 print (f"BOLT source changes were found:\n { file_changes } " )
111151 open (marker , "a" ).close ()
112152
113- # determine whether a stash is needed
153+ # Determine whether a stash is needed.
114154 stash = subprocess .run (
115155 shlex .split ("git status --porcelain" ),
116156 cwd = source_dir ,
@@ -119,42 +159,59 @@ def main():
119159 text = True ,
120160 ).stdout
121161 if stash :
122- # save local changes before checkout
162+ # Save local changes before checkout.
123163 subprocess .run (shlex .split ("git stash push -u" ), cwd = source_dir )
124- # check out the previous/cmp commit
164+
165+ # Check out the previous/cmp commit and get its commit hash for logging.
125166 subprocess .run (shlex .split (f"git checkout -f { args .cmp_rev } " ), cwd = source_dir )
126- # get the parent commit hash for logging
127167 new_ref = get_git_ref_or_rev (source_dir )
128- # build the previous commit
168+
169+ # Build the previous commit.
170+ print (f"{ msg_prefix } Building previous revision.." )
129171 subprocess .run (
130172 shlex .split ("cmake --build . --target llvm-bolt" ), cwd = args .build_dir
131173 )
132- # rename llvm-bolt
174+
175+ # Rename llvm-bolt.
176+ if not os .path .exists (bolt_path ):
177+ print (f"Failed to build the previous revision: '{ bolt_path } '" )
178+ switch_back (args .switch_back , stash , source_dir , old_ref , new_ref )
179+ sys .exit (1 )
133180 os .replace (bolt_path , f"{ bolt_path } .old" )
134- # set up llvm-bolt-wrapper.ini
135- ini = subprocess .check_output (
136- shlex .split (f"{ wrapper_path } { bolt_path } .old { bolt_path } .new" ) + wrapper_args ,
137- text = True ,
181+
182+ # Symlink llvm-bolt-wrapper
183+ if args .create_wrapper :
184+ print (f"{ msg_prefix } Creating llvm-bolt wrapper.." )
185+ script_dir = os .path .dirname (os .path .abspath (__file__ ))
186+ wrapper_path = f"{ script_dir } /llvm-bolt-wrapper.py"
187+ try :
188+ # Set up llvm-bolt-wrapper.ini
189+ ini = subprocess .check_output (
190+ shlex .split (f"{ wrapper_path } { bolt_path } .old { bolt_path } .new" )
191+ + wrapper_args ,
192+ text = True ,
193+ )
194+ with open (f"{ args .build_dir } /bin/llvm-bolt-wrapper.ini" , "w" ) as f :
195+ f .write (ini )
196+ os .symlink (wrapper_path , bolt_path )
197+ except Exception as e :
198+ print ("Failed to create a wrapper:\n " + str (e ))
199+ switch_back (args .switch_back , stash , source_dir , old_ref , new_ref )
200+ sys .exit (1 )
201+
202+ switch_back (args .switch_back , stash , source_dir , old_ref , new_ref )
203+
204+ print (
205+ f"{ msg_prefix } Completed!\n Build directory { args .build_dir } is ready for"
206+ " NFC-Mode comparison between the two revisions."
138207 )
139- with open (f"{ args .build_dir } /bin/llvm-bolt-wrapper.ini" , "w" ) as f :
140- f .write (ini )
141- # symlink llvm-bolt-wrapper
142- os .symlink (wrapper_path , bolt_path )
143- if args .switch_back :
144- if stash :
145- subprocess .run (shlex .split ("git stash pop" ), cwd = source_dir )
146- subprocess .run (shlex .split (f"git checkout { old_ref } " ), cwd = source_dir )
147- else :
208+
209+ if args .create_wrapper :
148210 print (
149- f"The repository { source_dir } has been switched from { old_ref } "
150- f"to { new_ref } . Local changes were stashed. Switch back using \n \t "
151- f"git checkout { old_ref } \n "
211+ "Can run BOLT tests using: \n "
212+ " \t bin/llvm-lit -sv tools/bolt/test \n or \n "
213+ " \t bin/llvm-lit -sv tools/bolttests "
152214 )
153- print (
154- f"Build directory { args .build_dir } is ready to run BOLT tests, e.g.\n "
155- "\t bin/llvm-lit -sv tools/bolt/test\n or\n "
156- "\t bin/llvm-lit -sv tools/bolttests"
157- )
158215
159216
160217if __name__ == "__main__" :
0 commit comments