YouCompleteMe/cpp/llvm/utils/llvm-native-gxx

250 lines
6.2 KiB
Plaintext
Raw Normal View History

2012-07-05 20:51:06 -04:00
#!/usr/bin/perl
# Wrapper around LLVM tools to generate a native .o from llvm-gxx using an
# LLVM back-end (CBE by default).
# set up defaults.
$Verbose = 0;
$SaveTemps = 1;
$PreprocessOnly = 0;
$CompileDontLink = 0;
$Backend = 'cbe';
chomp ($ProgramName = `basename $0`);
sub boldprint {
print "", @_, "";
}
# process command-line options.
# most of these are passed on to llvm-gxx.
$GCCOptions = "";
for ($i = 0; $i <= $#ARGV; ++$i) {
if ($ARGV[$i] =~ /-mllvm-backend=([a-z0-9]*)/) {
$Backend = $1;
if ($ProgramName =~ /llvm-native-gxx/) {
splice (@ARGV, $i, 1);
--$i;
}
} elsif ($ARGV[$i] eq "-E") {
$PreprocessOnly = 1;
} elsif ($ARGV[$i] eq "-c") {
$GCCOptions .= " " . $ARGV[$i];
$CompileDontLink = 1;
} elsif ($ARGV[$i] eq "-v") {
$GCCOptions .= " " . $ARGV[$i];
$Verbose = 1;
} elsif ($ARGV[$i] eq "-o") {
$OutputFile = $ARGV[$i + 1];
} elsif ($ARGV[$i] eq "-save-temps") {
$GCCOptions .= " " . $ARGV[$i];
$SaveTemps = 1;
} elsif ($ARGV[$i] =~ /\.bc$/) {
push (@BytecodeFiles, $ARGV[$i]);
} elsif ($ARGV[$i] =~ /^-L/) {
$GCCOptions .= " " . $ARGV[$i];
push (@LibDirs, $ARGV[$i]);
} elsif ($ARGV[$i] =~ /^-l/) {
$GCCOptions .= " " . $ARGV[$i];
push (@Libs, $ARGV[$i]);
} elsif ($ARGV[$i] =~ /\.(c|cpp|cc|i|ii|C)$/) {
$LastCFile = $ARGV[$i];
}
}
sub GetDefaultOutputFileName {
my $DefaultOutputFileBase;
if ($ProgramName =~ /llvm-native-gxx/) {
$DefaultOutputFileBase = $LastCFile;
} elsif ($ProgramName =~ /native-build/) {
$DefaultOutputFileBase = $BytecodeFiles[0];
}
my $def = $DefaultOutputFileBase;
die "Can't figure out name of output file.\n"
unless $DefaultOutputFileBase
&& (($ProgramName !~ /native-build/)
|| $#BytecodeFiles == 0);
print "Warning: defaulting output file name ",
"based on '$DefaultOutputFileBase'\n" if $Verbose;
if ($ProgramName =~ /llvm-native-gxx/) {
$def =~ s/\.(c|cpp|cc|i|ii|C)$/.o/;
} elsif ($ProgramName =~ /native-build/) {
$def =~ s/\.bc$/.$Backend/;
if ($CompileDontLink) {
$def .= ".o";
}
}
return $def;
}
# run a command, optionally echoing, and quitting if it fails:
sub run {
my $command = join(" ", @_);
print "$command\n" if $Verbose;
$command =~ s/\"/\\\"/g;
system $command and die "$0: $command failed";
}
sub LinkBytecodeFilesIntoTemporary {
my $FinalOutputFileName = shift @_;
my @BytecodeFiles = @_;
my $BCFiles = join (" ", @BytecodeFiles);
my $LinkedBCFile;
if ($SaveTemps) {
$LinkedBCFile = "${FinalOutputFileName}.llvm.bc";
} else {
$LinkedBCFile = "/tmp/nativebuild-$$.llvm.bc";
}
run "llvm-link -o $LinkedBCFile $BCFiles";
return $LinkedBCFile;
}
sub CompileBytecodeToNative {
my ($BCFile, $Backend, $OutputFile) = @_;
my $GeneratedCode;
if ($Backend eq 'cbe') {
if ($SaveTemps) {
$GeneratedCode = "${OutputFile}.c";
} else {
$GeneratedCode = "/tmp/nativebuild-$$.c";
}
run "llc -march=c -f -o $GeneratedCode $BCFile";
} elsif ($Backend eq 'llc') {
if ($SaveTemps) {
$GeneratedCode = "${OutputFile}.s";
} else {
$GeneratedCode = "/tmp/nativebuild-$$.s";
}
run "llc -f -o $GeneratedCode $BCFile";
}
my $LibDirs = join (" ", @LibDirs);
my $Libs = join (" ", @Libs);
run "gcc $GCCOptions $GeneratedCode -o $OutputFile $LibDirs $Libs";
run "rm $BCFile $GeneratedCode"
unless $SaveTemps;
}
sub CompileCToNative {
my ($LLVMGCCCommand, $Backend, $OutputFile) = @_;
run $LLVMGCCCommand;
if ($PreprocessOnly) {
return;
}
my $BCFile = "${OutputFile}.llvm.bc";
if ($CompileDontLink) {
run "mv ${OutputFile} $BCFile";
} else { # gccld messes with the output file name
run "mv ${OutputFile}.bc $BCFile";
}
my $GeneratedCode;
if ($Backend eq 'cbe') {
$GeneratedCode = "${OutputFile}.cbe.c";
run "llc -march=c -f -o $GeneratedCode $BCFile";
} elsif ($Backend eq 'llc') {
$GeneratedCode = "${OutputFile}.llc.s";
run "llc -f -o $GeneratedCode $BCFile";
}
my $NativeGCCOptions = "";
if ($CompileDontLink) {
$NativeGCCOptions = "-c";
}
run "gcc $NativeGCCOptions $GeneratedCode -o $OutputFile";
run "rm ${OutputFile}.llvm.bc $GeneratedCode"
unless $SaveTemps;
}
# guess the name of the output file, if -o was not specified.
$OutputFile = GetDefaultOutputFileName () unless $OutputFile;
print "Output file is $OutputFile\n" if $Verbose;
# do all the dirty work:
if ($ProgramName eq /native-build/) {
my $LinkedBCFile = LinkBytecodeFilesIntoTemporary (@BytecodeFiles);
CompileBytecodeToNative ($LinkedBCFile, $Backend, $OutputFile);
} elsif ($ProgramName =~ /llvm-native-gxx/) {
# build the llvm-gxx command line.
$LLVMGCCCommand = join (" ", ("llvm-g++", @ARGV));
CompileCToNative ($LLVMGCCCommand, $Backend, $OutputFile);
}
# we're done.
exit 0;
__END__
=pod
=head1 NAME
llvm-native-gxx
=head1 SYNOPSIS
llvm-native-g++ [OPTIONS...] FILE
native-build [OPTIONS...] FILE
=head1 DESCRIPTION
llvm-native-g++ is a wrapper around the LLVM command-line tools which generates
a native object (.o) file by compiling FILE with llvm-g++, and then running
an LLVM back-end (CBE by default) over the resulting bitcode, and then
compiling the resulting code to a native object file.
If called as "native-build", it compiles bitcode to native code, and takes
different options.
=head1 OPTIONS
llvm-native-g++ takes the same options as llvm-gcc. All options
except -mllvm-backend=... are passed on to llvm-g++.
=over 4
=item -mllvm-backend=BACKEND
Use BACKEND for native code generation.
=item -v
Print command lines that llvm-native-g++ runs.
=item -o FILE
llvm-native-g++ tries to guess the name of the llvm-g++ output file by looking
for this option in the command line. If it can't find it, it finds the last C
or C++ source file named on the command line, and turns its suffix into .o. See
BUGS.
=item -save-temps
Save temporary files used by llvm-native-g++ (and llvm-g++, and g++).
=back
=head1 BUGS
llvm-native-g++ only handles the case where llvm-g++ compiles a single
file per invocation. llvm-native-g++ has weak command-line argument
parsing and is a poor substitute for making g++/g++.c do this stuff.
This manual page does not adequately document native-build mode.
llvm-native-g++ is pretty gross because it represents the blind merging of two
other scripts that predated it. It could use some code clean-up.
=head1 SEE ALSO
g++(1)
=head1 AUTHOR
Brian R. Gaeke
=cut