| #!/usr/dcs/software/supported/bin/perl -w | 
 | # LLVM Web Demo script | 
 | # | 
 |  | 
 | use strict; | 
 | use CGI; | 
 | use POSIX; | 
 | use Mail::Send; | 
 |  | 
 | $| = 1; | 
 |  | 
 | my $ROOT = "/tmp/webcompile"; | 
 | #my $ROOT = "/home/vadve/lattner/webcompile"; | 
 |  | 
 | open( STDERR, ">&STDOUT" ) or die "can't redirect stderr to stdout"; | 
 |  | 
 | if ( !-d $ROOT ) { mkdir( $ROOT, 0777 ); } | 
 |  | 
 | my $LOGFILE         = "$ROOT/log.txt"; | 
 | my $FORM_URL        = 'index.cgi'; | 
 | my $MAILADDR        = 'sabre@nondot.org'; | 
 | my $CONTACT_ADDRESS = 'Questions or comments?  Email the <a href="http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev">LLVMdev mailing list</a>.'; | 
 | my $LOGO_IMAGE_URL  = 'cathead.png'; | 
 | my $TIMEOUTAMOUNT   = 20; | 
 | $ENV{'LD_LIBRARY_PATH'} = '/home/vadve/shared/localtools/fc1/lib/'; | 
 |  | 
 | my @PREPENDPATHDIRS = | 
 |   (   | 
 |     '/home/vadve/shared/llvm-gcc4.0-2.1/bin/', | 
 |     '/home/vadve/shared/llvm-2.1/Release/bin'); | 
 |  | 
 | my $defaultsrc = "#include <stdio.h>\n#include <stdlib.h>\n\n" . | 
 |                  "int power(int X) {\n  if (X == 0) return 1;\n" . | 
 |                  "  return X*power(X-1);\n}\n\n" . | 
 |                  "int main(int argc, char **argv) {\n" . | 
 |                  "  printf(\"%d\\n\", power(atoi(argv[0])));\n}\n"; | 
 |  | 
 | sub getname { | 
 |     my ($extension) = @_; | 
 |     for ( my $count = 0 ; ; $count++ ) { | 
 |         my $name = | 
 |           sprintf( "$ROOT/_%d_%d%s", $$, $count, $extension ); | 
 |         if ( !-f $name ) { return $name; } | 
 |     } | 
 | } | 
 |  | 
 | my $c; | 
 |  | 
 | sub barf { | 
 |     print "<b>", @_, "</b>\n"; | 
 |     print $c->end_html; | 
 |     system("rm -f $ROOT/locked"); | 
 |     exit 1; | 
 | } | 
 |  | 
 | sub writeIntoFile { | 
 |     my $extension = shift @_; | 
 |     my $contents  = join "", @_; | 
 |     my $name      = getname($extension); | 
 |     local (*FILE); | 
 |     open( FILE, ">$name" ) or barf("Can't write to $name: $!"); | 
 |     print FILE $contents; | 
 |     close FILE; | 
 |     return $name; | 
 | } | 
 |  | 
 | sub addlog { | 
 |     my ( $source, $pid, $result ) = @_; | 
 |     open( LOG, ">>$LOGFILE" ); | 
 |     my $time       = scalar localtime; | 
 |     my $remotehost = $ENV{'REMOTE_ADDR'}; | 
 |     print LOG "[$time] [$remotehost]: $pid\n"; | 
 |     print LOG "<<<\n$source\n>>>\nResult is: <<<\n$result\n>>>\n"; | 
 |     close LOG; | 
 | } | 
 |  | 
 | sub dumpFile { | 
 |     my ( $header, $file ) = @_; | 
 |     my $result; | 
 |     open( FILE, "$file" ) or barf("Can't read $file: $!"); | 
 |     while (<FILE>) { | 
 |         $result .= $_; | 
 |     } | 
 |     close FILE; | 
 |     my $UnhilightedResult = $result; | 
 |     my $HtmlResult        = | 
 |       "<h3>$header</h3>\n<pre>\n" . $c->escapeHTML($result) . "\n</pre>\n"; | 
 |     if (wantarray) { | 
 |         return ( $UnhilightedResult, $HtmlResult ); | 
 |     } | 
 |     else { | 
 |         return $HtmlResult; | 
 |     } | 
 | } | 
 |  | 
 | sub syntaxHighlightLLVM { | 
 |   my ($input) = @_; | 
 |   $input =~ s@\b(void|i8|i1|i16|i32|i64|float|double|type|label|opaque)\b@<span class="llvm_type">$1</span>@g; | 
 |   $input =~ s@\b(add|sub|mul|div|rem|and|or|xor|setne|seteq|setlt|setgt|setle|setge|phi|tail|call|cast|to|shl|shr|vaarg|vanext|ret|br|switch|invoke|unwind|malloc|alloca|free|load|store|getelementptr|begin|end|true|false|declare|global|constant|const|internal|uninitialized|external|implementation|linkonce|weak|appending|null|to|except|not|target|endian|pointersize|big|little|volatile)\b@<span class="llvm_keyword">$1</span>@g; | 
 |  | 
 |   # Add links to the FAQ. | 
 |   $input =~ s@(_ZNSt8ios_base4Init[DC]1Ev)@<a href="../docs/FAQ.html#iosinit">$1</a>@g; | 
 |   $input =~ s@\bundef\b@<a href="../docs/FAQ.html#undef">undef</a>@g; | 
 |   return $input; | 
 | } | 
 |  | 
 | sub mailto { | 
 |     my ( $recipient, $body ) = @_; | 
 |     my $msg = | 
 |       new Mail::Send( Subject => "LLVM Demo Page Run", To => $recipient ); | 
 |     my $fh = $msg->open(); | 
 |     print $fh $body; | 
 |     $fh->close(); | 
 | } | 
 |  | 
 | $c = new CGI; | 
 | print $c->header; | 
 |  | 
 | print <<EOF; | 
 | <html> | 
 | <head> | 
 |   <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> | 
 |   <title>Try out LLVM in your browser!</title> | 
 |   <style> | 
 |     \@import url("syntax.css"); | 
 |     \@import url("http://llvm.org/llvm.css"); | 
 |   </style> | 
 | </head> | 
 | <body leftmargin="10" marginwidth="10"> | 
 |  | 
 | <div class="www_sectiontitle"> | 
 |   Try out LLVM in your browser! | 
 | </div> | 
 |  | 
 | <table border=0><tr><td> | 
 | <img align=right width=100 height=111 src="$LOGO_IMAGE_URL"> | 
 | </td><td> | 
 | EOF | 
 |  | 
 | if ( -f "$ROOT/locked" ) { | 
 |   my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$locktime) =  | 
 |     stat("$ROOT/locked"); | 
 |   my $currtime = time(); | 
 |   if ($locktime + 60 > $currtime) { | 
 |     print "This page is already in use by someone else at this "; | 
 |     print "time, try reloading in a second or two.  Meow!</td></tr></table>'\n"; | 
 |     exit 0; | 
 |   } | 
 | } | 
 |  | 
 | system("touch $ROOT/locked"); | 
 |  | 
 | print <<END; | 
 | Bitter Melon the cat says, paste a C/C++ program in the text box or upload | 
 | one from your computer, and you can see LLVM compile it, meow!! | 
 | </td></tr></table><p> | 
 | END | 
 |  | 
 | print $c->start_multipart_form( 'POST', $FORM_URL ); | 
 |  | 
 | my $source = $c->param('source'); | 
 |  | 
 |  | 
 | # Start the user out with something valid if no code. | 
 | $source = $defaultsrc if (!defined($source)); | 
 |  | 
 | print '<table border="0"><tr><td>'; | 
 |  | 
 | print "Type your source code in below: (<a href='DemoInfo.html#hints'>hints and  | 
 | advice</a>)<br>\n"; | 
 |  | 
 | print $c->textarea( | 
 |     -name    => "source", | 
 |     -rows    => 16, | 
 |     -columns => 60, | 
 |     -default => $source | 
 | ), "<br>"; | 
 |  | 
 | print "Or upload a file: "; | 
 | print $c->filefield( -name => 'uploaded_file', -default => '' ); | 
 |  | 
 | print "<p />\n"; | 
 |  | 
 |  | 
 | print '<p></td><td valign=top>'; | 
 |  | 
 | print "<center><h3>General Options</h3></center>"; | 
 |  | 
 | print "Source language: ", | 
 |   $c->radio_group( | 
 |     -name    => 'language', | 
 |     -values  => [ 'C', 'C++' ], | 
 |     -default => 'C' | 
 |   ), "<p>"; | 
 |  | 
 | print $c->checkbox( | 
 |     -name  => 'linkopt', | 
 |     -label => 'Run link-time optimizer', | 
 |     -checked => 'checked' | 
 |   ),' <a href="DemoInfo.html#lto">?</a><br>'; | 
 |  | 
 | print $c->checkbox( | 
 |     -name  => 'showstats', | 
 |     -label => 'Show detailed pass statistics' | 
 |   ), ' <a href="DemoInfo.html#stats">?</a><br>'; | 
 |  | 
 | print $c->checkbox( | 
 |     -name  => 'cxxdemangle', | 
 |     -label => 'Demangle C++ names' | 
 |   ),' <a href="DemoInfo.html#demangle">?</a><p>'; | 
 |  | 
 |  | 
 | print "<center><h3>Output Options</h3></center>"; | 
 |  | 
 | print $c->checkbox( | 
 |     -name => 'showbcanalysis', | 
 |     -label => 'Show detailed bytecode analysis' | 
 |   ),' <a href="DemoInfo.html#bcanalyzer">?</a><br>'; | 
 |  | 
 | print $c->checkbox( | 
 |     -name => 'showllvm2cpp', | 
 |     -label => 'Show LLVM C++ API code' | 
 |   ), ' <a href="DemoInfo.html#llvm2cpp">?</a>'; | 
 |  | 
 | print "</td></tr></table>"; | 
 |  | 
 | print "<center>", $c->submit(-value=> 'Compile Source Code'),  | 
 |       "</center>\n", $c->endform; | 
 |  | 
 | print "\n<p>If you have questions about the LLVM code generated by the | 
 | front-end, please check the <a href='/docs/FAQ.html#cfe_code'>FAQ</a> and | 
 | the demo page <a href='DemoInfo.html#hints'>hints section</a>. | 
 | </p>\n"; | 
 |  | 
 | $ENV{'PATH'} = ( join ( ':', @PREPENDPATHDIRS ) ) . ":" . $ENV{'PATH'}; | 
 |  | 
 | sub sanitychecktools { | 
 |     my $sanitycheckfail = ''; | 
 |  | 
 |     # insert tool-specific sanity checks here | 
 |     $sanitycheckfail .= ' llvm-dis' | 
 |       if `llvm-dis --help 2>&1` !~ /ll disassembler/; | 
 |  | 
 |     $sanitycheckfail .= ' llvm-gcc' | 
 |       if ( `llvm-gcc --version 2>&1` !~ /Free Software Foundation/ ); | 
 |  | 
 |     $sanitycheckfail .= ' llvm-ld' | 
 |       if `llvm-ld --help 2>&1` !~ /llvm linker/; | 
 |  | 
 |     $sanitycheckfail .= ' llvm-bcanalyzer' | 
 |       if `llvm-bcanalyzer --help 2>&1` !~ /bcanalyzer/; | 
 |  | 
 |     barf( | 
 | "<br/>The demo page is currently unavailable. [tools: ($sanitycheckfail ) failed sanity check]" | 
 |       ) | 
 |       if $sanitycheckfail; | 
 | } | 
 |  | 
 | sanitychecktools(); | 
 |  | 
 | sub try_run { | 
 |     my ( $program, $commandline, $outputFile ) = @_; | 
 |     my $retcode = 0; | 
 |  | 
 |     eval { | 
 |         local $SIG{ALRM} = sub { die "timeout"; }; | 
 |         alarm $TIMEOUTAMOUNT; | 
 |         $retcode = system($commandline); | 
 |         alarm 0; | 
 |     }; | 
 |     if ( $@ and $@ =~ /timeout/ ) {  | 
 |       barf("Program $program took too long, compile time limited for the web script, sorry!.\n");  | 
 |     } | 
 |     if ( -s $outputFile ) { | 
 |         print scalar dumpFile( "Output from $program", $outputFile ); | 
 |     } | 
 |     #print "<p>Finished dumping command output.</p>\n"; | 
 |     if ( WIFEXITED($retcode) && WEXITSTATUS($retcode) != 0 ) { | 
 |         barf( | 
 | "$program exited with an error. Please correct source and resubmit.<p>\n" . | 
 | "Please note that this form only allows fully formed and correct source" . | 
 | " files.  It will not compile fragments of code.<p>" | 
 |         ); | 
 |     } | 
 |     if ( WIFSIGNALED($retcode) != 0 ) { | 
 |         my $sig = WTERMSIG($retcode); | 
 |         barf( | 
 |             "Ouch, $program caught signal $sig. Sorry, better luck next time!\n" | 
 |         ); | 
 |     } | 
 | } | 
 |  | 
 | my %suffixes = ( | 
 |     'Java'             => '.java', | 
 |     'JO99'             => '.jo9', | 
 |     'C'                => '.c', | 
 |     'C++'              => '.cc', | 
 |     'Stacker'          => '.st', | 
 |     'preprocessed C'   => '.i', | 
 |     'preprocessed C++' => '.ii' | 
 | ); | 
 | my %languages = ( | 
 |     '.jo9'  => 'JO99', | 
 |     '.java' => 'Java', | 
 |     '.c'    => 'C', | 
 |     '.i'    => 'preprocessed C', | 
 |     '.ii'   => 'preprocessed C++', | 
 |     '.cc'   => 'C++', | 
 |     '.cpp'  => 'C++', | 
 |     '.st'   => 'Stacker' | 
 | ); | 
 |  | 
 | my $uploaded_file_name = $c->param('uploaded_file'); | 
 | if ($uploaded_file_name) { | 
 |     if ($source) { | 
 |         barf( | 
 | "You must choose between uploading a file and typing code in. You can't do both at the same time." | 
 |         ); | 
 |     } | 
 |     $uploaded_file_name =~ s/^.*(\.[A-Za-z]+)$/$1/; | 
 |     my $language = $languages{$uploaded_file_name}; | 
 |     $c->param( 'language', $language ); | 
 |  | 
 |     print "<p>Processing uploaded file. It looks like $language.</p>\n"; | 
 |     my $fh = $c->upload('uploaded_file'); | 
 |     if ( !$fh ) { | 
 |         barf( "Error uploading file: " . $c->cgi_error ); | 
 |     } | 
 |     while (<$fh>) { | 
 |         $source .= $_; | 
 |     } | 
 |     close $fh; | 
 | } | 
 |  | 
 | if ($c->param('source')) { | 
 |     print $c->hr; | 
 |     my $extension = $suffixes{ $c->param('language') }; | 
 |     barf "Unknown language; can't compile\n" unless $extension; | 
 |  | 
 |     # Add a newline to the source here to avoid a warning from gcc. | 
 |     $source .= "\n"; | 
 |  | 
 |     # Avoid security hole due to #including bad stuff. | 
 |     $source =~ | 
 | s@(\n)?#include.*[<"](.*\.\..*)[">].*\n@$1#error "invalid #include file $2 detected"\n@g; | 
 |  | 
 |     my $inputFile = writeIntoFile( $extension, $source ); | 
 |     my $pid       = $$; | 
 |  | 
 |     my $bytecodeFile = getname(".bc"); | 
 |     my $outputFile   = getname(".llvm-gcc.out"); | 
 |     my $timerFile    = getname(".llvm-gcc.time"); | 
 |  | 
 |     my $stats = ''; | 
 |     if ( $extension eq ".st" ) { | 
 |       $stats = "-stats -time-passes " | 
 | 	if ( $c->param('showstats') ); | 
 |       try_run( "llvm Stacker front-end (stkrc)", | 
 |         "stkrc $stats -o $bytecodeFile $inputFile > $outputFile 2>&1", | 
 |         $outputFile ); | 
 |     } else { | 
 |       #$stats = "-Wa,--stats,--time-passes,--info-output-file=$timerFile" | 
 |       $stats = "-ftime-report" | 
 | 	if ( $c->param('showstats') ); | 
 |       try_run( "llvm C/C++ front-end (llvm-gcc)", | 
 | 	"llvm-gcc -emit-llvm -W -Wall -O2 $stats -o $bytecodeFile -c $inputFile > $outputFile 2>&1", | 
 |         $outputFile ); | 
 |     } | 
 |  | 
 |     if ( $c->param('showstats') && -s $timerFile ) { | 
 |         my ( $UnhilightedResult, $HtmlResult ) = | 
 |           dumpFile( "Statistics for front-end compilation", $timerFile ); | 
 |         print "$HtmlResult\n"; | 
 |     } | 
 |  | 
 |     if ( $c->param('linkopt') ) { | 
 |         my $stats      = ''; | 
 |         my $outputFile = getname(".gccld.out"); | 
 |         my $timerFile  = getname(".gccld.time"); | 
 |         $stats = "--stats --time-passes --info-output-file=$timerFile" | 
 |           if ( $c->param('showstats') ); | 
 |         my $tmpFile = getname(".bc"); | 
 |         try_run( | 
 |             "optimizing linker (llvm-ld)", | 
 | "llvm-ld $stats -o=$tmpFile $bytecodeFile > $outputFile 2>&1", | 
 |             $outputFile | 
 |         ); | 
 |         system("mv $tmpFile.bc $bytecodeFile"); | 
 |         system("rm $tmpFile"); | 
 |  | 
 |         if ( $c->param('showstats') && -s $timerFile ) { | 
 |             my ( $UnhilightedResult, $HtmlResult ) = | 
 |               dumpFile( "Statistics for optimizing linker", $timerFile ); | 
 |             print "$HtmlResult\n"; | 
 |         } | 
 |     } | 
 |  | 
 |     print " Bytecode size is ", -s $bytecodeFile, " bytes.\n"; | 
 |  | 
 |     my $disassemblyFile = getname(".ll"); | 
 |     try_run( "llvm-dis", | 
 |         "llvm-dis -o=$disassemblyFile $bytecodeFile > $outputFile 2>&1", | 
 |         $outputFile ); | 
 |  | 
 |     if ( $c->param('cxxdemangle') ) { | 
 |         print " Demangling disassembler output.\n"; | 
 |         my $tmpFile = getname(".ll"); | 
 |         system("c++filt < $disassemblyFile > $tmpFile 2>&1"); | 
 |         system("mv $tmpFile $disassemblyFile"); | 
 |     } | 
 |  | 
 |     my ( $UnhilightedResult, $HtmlResult ); | 
 |     if ( -s $disassemblyFile ) { | 
 |         ( $UnhilightedResult, $HtmlResult ) = | 
 |           dumpFile( "Output from LLVM disassembler", $disassemblyFile ); | 
 |         print syntaxHighlightLLVM($HtmlResult); | 
 |     } | 
 |     else { | 
 |         print "<p>Hmm, that's weird, llvm-dis didn't produce any output.</p>\n"; | 
 |     } | 
 |  | 
 |     if ( $c->param('showbcanalysis') ) { | 
 |       my $analFile = getname(".bca"); | 
 |       try_run( "llvm-bcanalyzer", "llvm-bcanalyzer $bytecodeFile > $analFile 2>&1",  | 
 |         $analFile); | 
 |     } | 
 |     if ($c->param('showllvm2cpp') ) { | 
 |       my $l2cppFile = getname(".l2cpp"); | 
 |       try_run("llvm2cpp","llvm2cpp $bytecodeFile -o $l2cppFile 2>&1", | 
 |         $l2cppFile); | 
 |     } | 
 |  | 
 |     # Get the source presented by the user to CGI, convert newline sequences to simple \n. | 
 |     my $actualsrc = $c->param('source'); | 
 |     $actualsrc =~ s/\015\012/\n/go; | 
 |     # Don't log this or mail it if it is the default code. | 
 |     if ($actualsrc ne $defaultsrc) { | 
 |     addlog( $source, $pid, $UnhilightedResult ); | 
 |  | 
 |     my ( $ip, $host, $lg, $lines ); | 
 |     chomp( $lines = `wc -l < $inputFile` ); | 
 |     $lg = $c->param('language'); | 
 |     $ip = $c->remote_addr(); | 
 |     chomp( $host = `host $ip` ) if $ip; | 
 |     mailto( $MAILADDR, | 
 |         "--- Query: ---\nFrom: ($ip) $host\nInput: $lines lines of $lg\n" | 
 |           . "C++ demangle = " | 
 |           . ( $c->param('cxxdemangle') ? 1 : 0 ) | 
 |           . ", Link opt = " | 
 |           . ( $c->param('linkopt') ? 1 : 0 ) . "\n\n" | 
 |           . ", Show stats = " | 
 |           . ( $c->param('showstats') ? 1 : 0 ) . "\n\n" | 
 |           . "--- Source: ---\n$source\n" | 
 |           . "--- Result: ---\n$UnhilightedResult\n" ); | 
 |     } | 
 |     unlink( $inputFile, $bytecodeFile, $outputFile, $disassemblyFile ); | 
 | } | 
 |  | 
 | print $c->hr, "<address>$CONTACT_ADDRESS</address>", $c->end_html; | 
 | system("rm $ROOT/locked"); | 
 | exit 0; |