Compare commits
17 Commits
llvmorg-7.
...
llvmorg-1.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
303b238cc3 | ||
|
|
c1d8934838 | ||
|
|
3c96135937 | ||
|
|
3c0d59f546 | ||
|
|
510529f5e1 | ||
|
|
df834c2b61 | ||
|
|
d0118041ec | ||
|
|
87340561e3 | ||
|
|
d118722f63 | ||
|
|
052debc4d8 | ||
|
|
9f115d2063 | ||
|
|
e2fb1d0251 | ||
|
|
3c5f2201c9 | ||
|
|
3f024e982f | ||
|
|
51a4de5f2e | ||
|
|
6babfa929c | ||
|
|
bb8b55b1e4 |
@@ -53,11 +53,6 @@ language.
|
|||||||
list of available analysis passes.
|
list of available analysis passes.
|
||||||
<p>
|
<p>
|
||||||
|
|
||||||
<li> -dsa-track-integers
|
|
||||||
<br>
|
|
||||||
Track integers as potential pointers.
|
|
||||||
<p>
|
|
||||||
|
|
||||||
<li> -profile-info-file <filename>
|
<li> -profile-info-file <filename>
|
||||||
<br>
|
<br>
|
||||||
Specify the name of the file loaded by the -profile-loader option.
|
Specify the name of the file loaded by the -profile-loader option.
|
||||||
|
|||||||
@@ -190,6 +190,16 @@ non-obvious ways. Here are some hints and tips:<p>
|
|||||||
when attempting to reduce test programs. If you're trying to find
|
when attempting to reduce test programs. If you're trying to find
|
||||||
a bug in one of these passes, <tt>bugpoint</tt> may crash.<p>
|
a bug in one of these passes, <tt>bugpoint</tt> may crash.<p>
|
||||||
|
|
||||||
|
<li><tt>-enable-correct-eh-support</tt><br>
|
||||||
|
Make the -lowerinvoke pass insert expensive, but correct, exception
|
||||||
|
handling code.<p>
|
||||||
|
|
||||||
|
<li><tt>-internalize-public-api-file <filename></tt><br>
|
||||||
|
Preserve the symbols listed in the file <tt>filename</tt>.<p>
|
||||||
|
|
||||||
|
<li><tt>-internalize-public-api-list <list></tt><br>
|
||||||
|
Preserve the symbols listed in <tt>list</tt>.<p>
|
||||||
|
|
||||||
<li> <tt>-help</tt><br>
|
<li> <tt>-help</tt><br>
|
||||||
Print a summary of command line options.<p>
|
Print a summary of command line options.<p>
|
||||||
|
|
||||||
@@ -215,6 +225,9 @@ non-obvious ways. Here are some hints and tips:<p>
|
|||||||
<tt>bugpoint</tt> will attempt to generate a reference output by
|
<tt>bugpoint</tt> will attempt to generate a reference output by
|
||||||
compiling the program with the C backend and running it.<p>
|
compiling the program with the C backend and running it.<p>
|
||||||
|
|
||||||
|
<li><tt>-profile-info-file <filename></tt><br>
|
||||||
|
Profile file loaded by -profile-loader.<p>
|
||||||
|
|
||||||
<a name="opt_run-"><li><tt>-run-{int,jit,llc,cbe}</tt><br>
|
<a name="opt_run-"><li><tt>-run-{int,jit,llc,cbe}</tt><br>
|
||||||
Whenever the test program is compiled, <tt>bugpoint</tt> should generate
|
Whenever the test program is compiled, <tt>bugpoint</tt> should generate
|
||||||
code for it using the specified code generator. These options allow
|
code for it using the specified code generator. These options allow
|
||||||
|
|||||||
@@ -53,11 +53,6 @@ writes its output to the standard output.
|
|||||||
Specify the output filename.
|
Specify the output filename.
|
||||||
<p>
|
<p>
|
||||||
|
|
||||||
<li> -dsa-track-integers
|
|
||||||
<br>
|
|
||||||
Track integers as potential pointers.
|
|
||||||
<p>
|
|
||||||
|
|
||||||
<li> -profile-info-file <filename>
|
<li> -profile-info-file <filename>
|
||||||
<br>
|
<br>
|
||||||
Specify the name of the file loaded by the -profile-loader option.
|
Specify the name of the file loaded by the -profile-loader option.
|
||||||
|
|||||||
@@ -49,6 +49,8 @@
|
|||||||
<li>I've built LLVM and am testing it, but the tests freeze.</li>
|
<li>I've built LLVM and am testing it, but the tests freeze.</li>
|
||||||
<li>Why do test results differ when I perform different types of builds?</li>
|
<li>Why do test results differ when I perform different types of builds?</li>
|
||||||
<li>Compiling LLVM with GCC 3.3.2 fails, what should I do?</li>
|
<li>Compiling LLVM with GCC 3.3.2 fails, what should I do?</li>
|
||||||
|
<li>When I use the test suite, all of the C Backend tests fail. What is
|
||||||
|
wrong?</li>
|
||||||
</ol></li>
|
</ol></li>
|
||||||
|
|
||||||
<li><a href="#cfe">Using the GCC Front End</a>
|
<li><a href="#cfe">Using the GCC Front End</a>
|
||||||
@@ -338,6 +340,31 @@ build.</p>
|
|||||||
affects projects other than LLVM. Try upgrading or downgrading your GCC.</p>
|
affects projects other than LLVM. Try upgrading or downgrading your GCC.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="question">
|
||||||
|
<p>
|
||||||
|
When I use the test suite, all of the C Backend tests fail. What is
|
||||||
|
wrong?
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="answer">
|
||||||
|
<p>
|
||||||
|
If you build LLVM and the C Backend tests fail in <tt>llvm/test/Programs</tt>,
|
||||||
|
then chances are good that the directory pointed to by the LLVM_LIB_SEARCH_PATH
|
||||||
|
environment variable does not contain the libcrtend.a library.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
To fix it, verify that LLVM_LIB_SEARCH_PATH points to the correct directory
|
||||||
|
and that libcrtend.a is inside. For pre-built LLVM GCC front ends, this
|
||||||
|
should be the absolute path to
|
||||||
|
<tt>cfrontend/<<i>platform</i>>/llvm-gcc/bytecode-libs</tt>. If you've
|
||||||
|
built your own LLVM GCC front end, then ensure that you've built and installed
|
||||||
|
the libraries in <tt>llvm/runtime</tt> and have LLVM_LIB_SEARCH_PATH pointing
|
||||||
|
to the <tt>LLVMGCCDIR/bytecode-libs</tt> subdirectory.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- *********************************************************************** -->
|
<!-- *********************************************************************** -->
|
||||||
<div class="doc_section">
|
<div class="doc_section">
|
||||||
<a name="cfe">Using the GCC Front End</a>
|
<a name="cfe">Using the GCC Front End</a>
|
||||||
|
|||||||
@@ -182,10 +182,10 @@ software you will need.</p>
|
|||||||
|
|
||||||
<li>Linux on x86 (Pentium and above)
|
<li>Linux on x86 (Pentium and above)
|
||||||
<ul>
|
<ul>
|
||||||
<li>Approximately 918 MB of Free Disk Space
|
<li>Approximately 1.02 GB of Free Disk Space
|
||||||
<ul>
|
<ul>
|
||||||
<li>Source code: 28 MB</li>
|
<li>Source code: 45 MB</li>
|
||||||
<li>Object code: 850 MB</li>
|
<li>Object code: 956 MB</li>
|
||||||
<li>GCC front end: 40 MB</li>
|
<li>GCC front end: 40 MB</li>
|
||||||
</ul></li>
|
</ul></li>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -193,10 +193,10 @@ software you will need.</p>
|
|||||||
|
|
||||||
<li>Solaris on SparcV9 (Ultrasparc)
|
<li>Solaris on SparcV9 (Ultrasparc)
|
||||||
<ul>
|
<ul>
|
||||||
<li>Approximately 1.52 GB of Free Disk Space
|
<li>Approximately 1.75 GB of Free Disk Space
|
||||||
<ul>
|
<ul>
|
||||||
<li>Source code: 28 MB</li>
|
<li>Source code: 45 MB</li>
|
||||||
<li>Object code: 1470 MB</li>
|
<li>Object code: 1705 MB</li>
|
||||||
<li>GCC front end: 50 MB</li>
|
<li>GCC front end: 50 MB</li>
|
||||||
</ul></li>
|
</ul></li>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -204,9 +204,9 @@ software you will need.</p>
|
|||||||
|
|
||||||
<li>FreeBSD on x86 (Pentium and above)
|
<li>FreeBSD on x86 (Pentium and above)
|
||||||
<ul>
|
<ul>
|
||||||
<li>Approximately 918 MB of Free Disk Space
|
<li>Approximately 935 MB of Free Disk Space
|
||||||
<ul>
|
<ul>
|
||||||
<li>Source code: 28 MB</li>
|
<li>Source code: 45 MB</li>
|
||||||
<li>Object code: 850 MB</li>
|
<li>Object code: 850 MB</li>
|
||||||
<li>GCC front end: 40 MB</li>
|
<li>GCC front end: 40 MB</li>
|
||||||
</ul></li>
|
</ul></li>
|
||||||
@@ -216,9 +216,9 @@ software you will need.</p>
|
|||||||
<li>MacOS X on PowerPC
|
<li>MacOS X on PowerPC
|
||||||
<ul>
|
<ul>
|
||||||
<li>No native code generation
|
<li>No native code generation
|
||||||
<li>Approximately 1.20 GB of Free Disk Space
|
<li>Approximately 1.25 GB of Free Disk Space
|
||||||
<ul>
|
<ul>
|
||||||
<li>Source code: 28 MB</li>
|
<li>Source code: 45 MB</li>
|
||||||
<li>Object code: 1160 MB</li>
|
<li>Object code: 1160 MB</li>
|
||||||
<li>GCC front end: 40 MB</li>
|
<li>GCC front end: 40 MB</li>
|
||||||
</ul></li>
|
</ul></li>
|
||||||
@@ -274,10 +274,23 @@ LLVM:</p>
|
|||||||
automake from 1.4p5 on should work; we only use aclocal from that
|
automake from 1.4p5 on should work; we only use aclocal from that
|
||||||
package.</p></li>
|
package.</p></li>
|
||||||
|
|
||||||
<li><A href="http://www.codesourcery.com/qm/qmtest">QMTest</A></li>
|
<li><A href="http://www.codesourcery.com/qm/qmtest">QMTest 2.0.3</A></li>
|
||||||
<li><A href="http://www.python.org">Python</A>
|
<li><A href="http://www.python.org">Python</A>
|
||||||
|
|
||||||
<p>These are needed to use the LLVM test suite.</p></li>
|
<p>
|
||||||
|
These are needed to use the LLVM test suite. Please note that newer
|
||||||
|
versions of QMTest may not work with the LLVM test suite. QMTest 2.0.3
|
||||||
|
can be retrieved from the QMTest CVS repository using the following
|
||||||
|
commands:
|
||||||
|
<ul>
|
||||||
|
<li><tt>cvs -d :pserver:anoncvs@cvs.codesourcery.com:/home/qm/Repository login</tt>
|
||||||
|
</li>
|
||||||
|
<li>When prompted, use <tt>anoncvs</tt> as the password.
|
||||||
|
</li>
|
||||||
|
<li><tt>cvs -d :pserver:anoncvs@cvs.codesourcery.com:/home/qm/Repository co -r release-2-0-3 qm</tt>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</p></li>
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
@@ -858,7 +871,7 @@ different <a href="#tools">tools</a>.</p>
|
|||||||
|
|
||||||
<dt><tt>llvm/lib/Target/</tt><dd> This directory contains files that
|
<dt><tt>llvm/lib/Target/</tt><dd> This directory contains files that
|
||||||
describe various target architectures for code generation. For example,
|
describe various target architectures for code generation. For example,
|
||||||
the llvm/lib/Target/Sparc directory holds the Sparc machine
|
the llvm/lib/Target/SparcV9 directory holds the Sparc machine
|
||||||
description.<br>
|
description.<br>
|
||||||
|
|
||||||
<dt><tt>llvm/lib/CodeGen/</tt><dd> This directory contains the major parts
|
<dt><tt>llvm/lib/CodeGen/</tt><dd> This directory contains the major parts
|
||||||
|
|||||||
@@ -1,180 +0,0 @@
|
|||||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
|
|
||||||
"http://www.w3.org/TR/html4/strict.dtd">
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<link rel="stylesheet" href="llvm.css" type="text/css">
|
|
||||||
<title>LLVM vs. the World - Comparing Compilers to Compilers</title>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
|
|
||||||
<div class="doc_title">
|
|
||||||
LLVM vs. the World - Comparing Compilers to Compilers
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<ol>
|
|
||||||
<li><a href="#introduction">Introduction</a></li>
|
|
||||||
<li><a href="#generalapplicability">General Applicability</a></li>
|
|
||||||
<li><a href="#typesystem">Type System</a></li>
|
|
||||||
<li><a href="#dataflowinformation">Control-flow and Data-flow Information</a></li>
|
|
||||||
<li><a href="#registers">Registers</a></li>
|
|
||||||
<li><a href="#programmerinterface">Programmer Interface</a></li>
|
|
||||||
<li><a href="#codeemission">Machine Code Emission</a></li>
|
|
||||||
</ol>
|
|
||||||
|
|
||||||
<div class="doc_text">
|
|
||||||
<p><b>Written by Brian R. Gaeke</b></p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- *********************************************************************** -->
|
|
||||||
<div class="doc_section">
|
|
||||||
<a name="introduction">Introduction</a>
|
|
||||||
</div>
|
|
||||||
<!-- *********************************************************************** -->
|
|
||||||
|
|
||||||
<div class="doc_text">
|
|
||||||
<p>Whether you are a stranger to LLVM or not, and whether you are considering
|
|
||||||
using it for your projects or not, you may find it useful to understand how we
|
|
||||||
compare ourselves to other well-known compilers. The following list of points
|
|
||||||
should help you understand -- from our point of view -- some of the important
|
|
||||||
ways in which we see LLVM as different from other selected compilers and
|
|
||||||
code generation systems.</p>
|
|
||||||
|
|
||||||
<p>At the moment, we only compare ourselves below to <a
|
|
||||||
href="http://gcc.gnu.org/">GCC</a> and <a
|
|
||||||
href="http://www.gnu.org/software/lightning/">GNU lightning</a>, but we will try
|
|
||||||
to revise and expand it as our knowledge and experience permit. Contributions are
|
|
||||||
welcome.</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- *********************************************************************** -->
|
|
||||||
<div class="doc_section">
|
|
||||||
<a name="generalapplicability">General Applicability</a>
|
|
||||||
</div>
|
|
||||||
<!-- *********************************************************************** -->
|
|
||||||
|
|
||||||
<div class="doc_text">
|
|
||||||
<p>GNU lightning: Only currently usable for dynamic runtime emission of binary
|
|
||||||
machine code to memory. Supports one backend at a time.</p>
|
|
||||||
|
|
||||||
<p>LLVM: Supports compilation of C and C++ (with more languages coming soon),
|
|
||||||
strong SSA-based optimization at compile-time, link-time, run-time, and
|
|
||||||
off-line, and multiple platform backends with Just-in-Time and ahead-of-time
|
|
||||||
compilation frameworks. (See our document on <a
|
|
||||||
href="http://llvm.cs.uiuc.edu/pubs/2004-01-30-CGO-LLVM.html">Lifelong
|
|
||||||
Code Optimization</a> for more.)</p>
|
|
||||||
|
|
||||||
<p>GCC: Many relatively mature platform backends support assembly-language code
|
|
||||||
generation from many source languages. No run-time compilation
|
|
||||||
support.</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- *********************************************************************** -->
|
|
||||||
<div class="doc_section">
|
|
||||||
<a name="typesystem">Type System</a>
|
|
||||||
</div>
|
|
||||||
<!-- *********************************************************************** -->
|
|
||||||
|
|
||||||
<div class="doc_text">
|
|
||||||
<p>GNU lightning: C integer types and "void *" are supported. No type checking
|
|
||||||
is performed. Explicit type casts are not typically necessary unless the
|
|
||||||
underlying machine-specific types are distinct (e.g., sign- or zero-extension is
|
|
||||||
apparently necessary, but casting "int" to "void *" would not be.)
|
|
||||||
Floating-point support may not work on all platforms (it does not appear to be
|
|
||||||
documented in the latest release).</p>
|
|
||||||
|
|
||||||
<p>LLVM: Compositional type system based on C types, supporting structures,
|
|
||||||
opaque types, and C integer and floating point types. Explicit cast instructions
|
|
||||||
are required to transform a value from one type to another.</p>
|
|
||||||
|
|
||||||
<p>GCC: Union of high-level types including those used in Pascal, C, C++, Ada,
|
|
||||||
Java, and FORTRAN.</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- *********************************************************************** -->
|
|
||||||
<div class="doc_section">
|
|
||||||
<a name="dataflowinformation">Control-flow and Data-flow Information</a>
|
|
||||||
</div>
|
|
||||||
<!-- *********************************************************************** -->
|
|
||||||
|
|
||||||
<div class="doc_text">
|
|
||||||
<p>GNU lightning: No data-flow information encoded in the generated program. No
|
|
||||||
support for calculating CFG or def-use chains over generated programs.</p>
|
|
||||||
|
|
||||||
<p>LLVM: Scalar values in Static Single-Assignment form; def-use chains and CFG
|
|
||||||
always implicitly available and automatically kept up to date.</p>
|
|
||||||
|
|
||||||
<p>GCC: Trees and RTL do not directly encode data-flow info; but def-use chains
|
|
||||||
and CFGs can be calculated on the side. They are not automatically kept up to
|
|
||||||
date.</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- *********************************************************************** -->
|
|
||||||
<div class="doc_section">
|
|
||||||
<a name="registers">Registers</a>
|
|
||||||
</div>
|
|
||||||
<!-- *********************************************************************** -->
|
|
||||||
|
|
||||||
<div class="doc_text">
|
|
||||||
<p>GNU lightning: Very small fixed register set -- it takes the least common
|
|
||||||
denominator of supported platforms; basically it inherits its tiny register set
|
|
||||||
from IA-32, unnecessarily crippling targets like PowerPC with a large register
|
|
||||||
set.</p>
|
|
||||||
|
|
||||||
<p>LLVM: An infinite register set, reduced to a particular platform's finite
|
|
||||||
register set by register allocator.</p>
|
|
||||||
|
|
||||||
<p>GCC: Trees and RTL provide an arbitrarily large set of values. Reduced to a
|
|
||||||
particular platform's finite register set by register allocator.</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- *********************************************************************** -->
|
|
||||||
<div class="doc_section">
|
|
||||||
<a name="programmerinterface">Programmer Interface</a>
|
|
||||||
</div>
|
|
||||||
<!-- *********************************************************************** -->
|
|
||||||
|
|
||||||
<div class="doc_text">
|
|
||||||
<p>GNU lightning: Library interface based on C preprocessor macros that emit
|
|
||||||
binary code for a particular instruction to memory. No support for manipulating
|
|
||||||
code before emission.</p>
|
|
||||||
|
|
||||||
<p>LLVM: Library interface based on classes representing platform-independent
|
|
||||||
intermediate code (Instruction) and platform-dependent code (MachineInstr) which
|
|
||||||
can be manipulated arbitrarily and then emitted to memory.</p>
|
|
||||||
|
|
||||||
<p>GCC: Internal header file interface (tree.h) to abstract syntax trees,
|
|
||||||
representing roughly the union of all possible supported source-language
|
|
||||||
constructs; also, an internal header file interface (rtl.h, rtl.def) to a
|
|
||||||
low-level IR called RTL which represents roughly the union of all possible
|
|
||||||
target machine instructions.</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- *********************************************************************** -->
|
|
||||||
<div class="doc_section">
|
|
||||||
<a name="codeemission">Machine Code Emission</a>
|
|
||||||
</div>
|
|
||||||
<!-- *********************************************************************** -->
|
|
||||||
|
|
||||||
<div class="doc_text">
|
|
||||||
<p>GNU lightning: Only supports binary machine code emission to memory.</p>
|
|
||||||
|
|
||||||
<p>LLVM: Supports writing out assembly language to a file, and binary machine
|
|
||||||
code to memory, from the same back-end.</p>
|
|
||||||
|
|
||||||
<p>GCC: Supports writing out assembly language to a file. No support for
|
|
||||||
emitting machine code to memory.</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- *********************************************************************** -->
|
|
||||||
|
|
||||||
<hr>
|
|
||||||
<div class="doc_footer">
|
|
||||||
<address>Brian R. Gaeke</address>
|
|
||||||
<a href="http://llvm.cs.uiuc.edu">The LLVM Compiler Infrastructure</a>
|
|
||||||
<br>
|
|
||||||
Last modified: $Date$
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -121,12 +121,12 @@ href="http://llvm.cs.uiuc.edu/PR203">RPM package generation</a>.</li>
|
|||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
<li><a href="http://llvm.cs.uiuc.edu/PR253">LLVM now no longer depends on the boost library</a>.</li>
|
<li><a href="http://llvm.cs.uiuc.edu/PR253">LLVM now no longer depends on the boost library</a>.</li>
|
||||||
<li>The X86 backend now generates <b>substantially</b> better native code, and is faster.</li>
|
<li>The X86 backend now generates <b>substantially</b> better native code and is faster.</li>
|
||||||
<li>The C backend has been turned moved from the "llvm-dis" tool to the "llc"
|
<li>The C backend has been turned moved from the "llvm-dis" tool to the "llc"
|
||||||
tool. You can activate it with "<tt>llc -march=c foo.bc -o foo.c</tt>".</li>
|
tool. You can activate it with "<tt>llc -march=c foo.bc -o foo.c</tt>".</li>
|
||||||
<li>LLVM includes a new interprocedural optimization that marks global variables
|
<li>LLVM includes a new interprocedural optimization that marks global variables
|
||||||
"constant" when they are provably never written to.</li>
|
"constant" when they are provably never written to.</li>
|
||||||
<li>LLVM now includes a new interprocedural optimization that converts small "by reference" arguments to "by value" arguments, which is often improve the performance of C++ programs substantially.</li>
|
<li>LLVM now includes a new interprocedural optimization that converts small "by reference" arguments to "by value" arguments, which often improves the performance of C++ programs substantially.</li>
|
||||||
<li>Bugpoint can now do a better job reducing miscompilation problems by
|
<li>Bugpoint can now do a better job reducing miscompilation problems by
|
||||||
reducing programs down to a particular loop nest, instead of just the function
|
reducing programs down to a particular loop nest, instead of just the function
|
||||||
being miscompiled.</li>
|
being miscompiled.</li>
|
||||||
@@ -145,7 +145,7 @@ In this release, the following missing features were implemented:
|
|||||||
<ol>
|
<ol>
|
||||||
<li><a href="http://llvm.cs.uiuc.edu/PR16">Exception handling in the X86
|
<li><a href="http://llvm.cs.uiuc.edu/PR16">Exception handling in the X86
|
||||||
& Sparc native code generators</a> is now supported</li>
|
& Sparc native code generators</a> is now supported</li>
|
||||||
<li>The C/C++ front-end now support the GCC <tt>__builtin_return_address</tt> and <tt>__builtin_frame_address</tt> extensions. These are also supported by the X86 backend and by the C backend.</li>
|
<li>The C/C++ front-end now supports the GCC <tt>__builtin_return_address</tt> and <tt>__builtin_frame_address</tt> extensions. These are also supported by the X86 backend and by the C backend.</li>
|
||||||
<li><a href="http://llvm.cs.uiuc.edu/PR249">[X86] Missing cast from ULong -> Double, cast FP -> bool and support for -9223372036854775808</a></li>
|
<li><a href="http://llvm.cs.uiuc.edu/PR249">[X86] Missing cast from ULong -> Double, cast FP -> bool and support for -9223372036854775808</a></li>
|
||||||
<li>The C/C++ front-end <a href="http://llvm.cs.uiuc.edu/PR273">now supports</a>
|
<li>The C/C++ front-end <a href="http://llvm.cs.uiuc.edu/PR273">now supports</a>
|
||||||
the "<a href="http://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html#Labels%20as%20Values">labels as values</a>" GCC extension, often used to build "threaded interpreters".</a></li>
|
the "<a href="http://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html#Labels%20as%20Values">labels as values</a>" GCC extension, often used to build "threaded interpreters".</a></li>
|
||||||
@@ -231,7 +231,7 @@ cause use of invalid pointers!</a></li>
|
|||||||
<li><a href="http://llvm.cs.uiuc.edu/PR274">[JIT] Programs cannot resolve the fstat function</a></li>
|
<li><a href="http://llvm.cs.uiuc.edu/PR274">[JIT] Programs cannot resolve the fstat function</a></li>
|
||||||
<li><a href="http://llvm.cs.uiuc.edu/PR284">[indvars] Induction variable analysis violates LLVM invariants</a></li>
|
<li><a href="http://llvm.cs.uiuc.edu/PR284">[indvars] Induction variable analysis violates LLVM invariants</a></li>
|
||||||
<li><a href="http://llvm.cs.uiuc.edu/PR296">[execution engines] Unhandled cast constant expression</a></li>
|
<li><a href="http://llvm.cs.uiuc.edu/PR296">[execution engines] Unhandled cast constant expression</a></li>
|
||||||
|
<li><a href="http://llvm.cs.uiuc.edu/PR299">[Sparc] Code generator asserts on alloca of zero size type</a></li>
|
||||||
</ol>
|
</ol>
|
||||||
|
|
||||||
|
|
||||||
@@ -602,7 +602,7 @@ href="http://gcc.gnu.org/gcc-3.4/changes.html">GCC 3.4 release notes</a>.</li>
|
|||||||
<div class="doc_text">
|
<div class="doc_text">
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
<li>None so far.
|
<li>There are several programs in the LLVM testsuite that the Sparc code generator is known to miscompile.</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -59,7 +59,10 @@
|
|||||||
<ul>
|
<ul>
|
||||||
<li><a href="#getAnalysisUsage">The <tt>getAnalysisUsage</tt>
|
<li><a href="#getAnalysisUsage">The <tt>getAnalysisUsage</tt>
|
||||||
method</a></li>
|
method</a></li>
|
||||||
<li><a href="#getAnalysis">The <tt>getAnalysis</tt> method</a></li>
|
<li><a href="#AU::addRequired">The <tt>AnalysisUsage::addRequired<></tt> and <tt>AnalysisUsage::addRequiredTransitive<></tt> methods</a></li>
|
||||||
|
<li><a href="#AU::addPreserved">The <tt>AnalysisUsage::addPreserved<></tt> method</a></li>
|
||||||
|
<li><a href="#AU::examples">Example implementations of <tt>getAnalysisUsage</tt></a></li>
|
||||||
|
<li><a href="#getAnalysis">The <tt>getAnalysis<></tt> and <tt>getAnalysisToUpdate<></tt> methods</a></li>
|
||||||
</ul></li>
|
</ul></li>
|
||||||
<li><a href="#analysisgroup">Implementing Analysis Groups</a>
|
<li><a href="#analysisgroup">Implementing Analysis Groups</a>
|
||||||
<ul>
|
<ul>
|
||||||
@@ -171,12 +174,9 @@ include $(LEVEL)/Makefile.common
|
|||||||
<p>This makefile specifies that all of the <tt>.cpp</tt> files in the current
|
<p>This makefile specifies that all of the <tt>.cpp</tt> files in the current
|
||||||
directory are to be compiled and linked together into a
|
directory are to be compiled and linked together into a
|
||||||
<tt>lib/Debug/libhello.so</tt> shared object that can be dynamically loaded by
|
<tt>lib/Debug/libhello.so</tt> shared object that can be dynamically loaded by
|
||||||
the <tt>opt</tt> or <tt>analyze</tt> tools.</p>
|
the <tt>opt</tt> or <tt>analyze</tt> tools. If your operating system uses a
|
||||||
|
suffix other than .so (such as windows of Mac OS/X), the appropriate extension
|
||||||
<p>
|
will be used.</p>
|
||||||
Note that the suffix of the shared library may differ from the example above if
|
|
||||||
your system uses a different suffix by default.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>Now that we have the build scripts set up, we just need to write the code for
|
<p>Now that we have the build scripts set up, we just need to write the code for
|
||||||
the pass itself.</p>
|
the pass itself.</p>
|
||||||
@@ -487,7 +487,7 @@ should return true if they modified the program, or false if they didn't.</p>
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- _______________________________________________________________________ -->
|
<!-- _______________________________________________________________________ -->
|
||||||
<div class="subsubsection">
|
<div class="doc_subsubsection">
|
||||||
<a name="doInitialization_mod">The <tt>doInitialization(Module &)</tt>
|
<a name="doInitialization_mod">The <tt>doInitialization(Module &)</tt>
|
||||||
method</a>
|
method</a>
|
||||||
</div>
|
</div>
|
||||||
@@ -516,7 +516,7 @@ free functions that it needs, adding prototypes to the module if necessary.</p>
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- _______________________________________________________________________ -->
|
<!-- _______________________________________________________________________ -->
|
||||||
<div class="subsubsection">
|
<div class="doc_subsubsection">
|
||||||
<a name="runOnFunction">The <tt>runOnFunction</tt> method</a>
|
<a name="runOnFunction">The <tt>runOnFunction</tt> method</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -533,7 +533,7 @@ be returned if the function is modified.</p>
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- _______________________________________________________________________ -->
|
<!-- _______________________________________________________________________ -->
|
||||||
<div class="subsubsection">
|
<div class="doc_subsubsection">
|
||||||
<a name="doFinalization_mod">The <tt>doFinalization(Module
|
<a name="doFinalization_mod">The <tt>doFinalization(Module
|
||||||
&)</tt> method</a>
|
&)</tt> method</a>
|
||||||
</div>
|
</div>
|
||||||
@@ -581,7 +581,7 @@ href="#FunctionPass"><tt>FunctionPass</tt></a>'s have, but also have the followi
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- _______________________________________________________________________ -->
|
<!-- _______________________________________________________________________ -->
|
||||||
<div class="subsubsection">
|
<div class="doc_subsubsection">
|
||||||
<a name="doInitialization_fn">The <tt>doInitialization(Function
|
<a name="doInitialization_fn">The <tt>doInitialization(Function
|
||||||
&)</tt> method</a>
|
&)</tt> method</a>
|
||||||
</div>
|
</div>
|
||||||
@@ -603,7 +603,7 @@ fast).</p>
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- _______________________________________________________________________ -->
|
<!-- _______________________________________________________________________ -->
|
||||||
<div class="subsubsection">
|
<div class="doc_subsubsection">
|
||||||
<a name="runOnBasicBlock">The <tt>runOnBasicBlock</tt> method</a>
|
<a name="runOnBasicBlock">The <tt>runOnBasicBlock</tt> method</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -621,7 +621,7 @@ if the basic block is modified.</p>
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- _______________________________________________________________________ -->
|
<!-- _______________________________________________________________________ -->
|
||||||
<div class="subsubsection">
|
<div class="doc_subsubsection">
|
||||||
<a name="doFinalization_fn">The <tt>doFinalization(Function &)</tt>
|
<a name="doFinalization_fn">The <tt>doFinalization(Function &)</tt>
|
||||||
method</a>
|
method</a>
|
||||||
</div>
|
</div>
|
||||||
@@ -647,14 +647,12 @@ finalization.</p>
|
|||||||
|
|
||||||
<div class="doc_text">
|
<div class="doc_text">
|
||||||
|
|
||||||
<p>A <tt>MachineFunctionPass</tt> executes on the machine-dependent
|
<p>A <tt>MachineFunctionPass</tt> is a part of the LLVM code generator that
|
||||||
representation of each LLVM function in the program,
|
executes on the machine-dependent representation of each LLVM function in the
|
||||||
independent of all of the other functions in the program.
|
program. A <tt>MachineFunctionPass</tt> is also a <tt>FunctionPass</tt>, so all
|
||||||
A <tt>MachineFunctionPass</tt> is also a <tt>FunctionPass</tt>, so all
|
|
||||||
the restrictions that apply to a <tt>FunctionPass</tt> also apply to it.
|
the restrictions that apply to a <tt>FunctionPass</tt> also apply to it.
|
||||||
<tt>MachineFunctionPass</tt>es also have additional restrictions. In
|
<tt>MachineFunctionPass</tt>es also have additional restrictions. In particular,
|
||||||
particular, <tt>MachineFunctionPass</tt>es are not allowed to do any of
|
<tt>MachineFunctionPass</tt>es are not allowed to do any of the following:</p>
|
||||||
the following:</p>
|
|
||||||
|
|
||||||
<ol>
|
<ol>
|
||||||
<li>Modify any LLVM Instructions, BasicBlocks or Functions.</li>
|
<li>Modify any LLVM Instructions, BasicBlocks or Functions.</li>
|
||||||
@@ -669,7 +667,7 @@ data)</li>
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- _______________________________________________________________________ -->
|
<!-- _______________________________________________________________________ -->
|
||||||
<div class="subsubsection">
|
<div class="doc_subsubsection">
|
||||||
<a name="runOnMachineFunction">The <tt>runOnMachineFunction(MachineFunction
|
<a name="runOnMachineFunction">The <tt>runOnMachineFunction(MachineFunction
|
||||||
&MF)</tt> method</a>
|
&MF)</tt> method</a>
|
||||||
</div>
|
</div>
|
||||||
@@ -718,11 +716,7 @@ registering a pass that logically should be available for use in the
|
|||||||
|
|
||||||
<li><b><tt>RegisterAnalysis</tt></b> - This template should be used when you are
|
<li><b><tt>RegisterAnalysis</tt></b> - This template should be used when you are
|
||||||
registering a pass that logically should be available for use in the
|
registering a pass that logically should be available for use in the
|
||||||
'<tt>analysis</tt>' utility.</li>
|
'<tt>analyze</tt>' utility.</li>
|
||||||
|
|
||||||
<li><b><tt>RegisterLLC</tt></b> - This template should be used when you are
|
|
||||||
registering a pass that logically should be available for use in the
|
|
||||||
'<tt>llc</tt>' utility.</li>
|
|
||||||
|
|
||||||
<li><b><tt>RegisterPass</tt></b> - This is the generic form of the
|
<li><b><tt>RegisterPass</tt></b> - This is the generic form of the
|
||||||
<tt>Register*</tt> templates that should be used if you want your pass listed by
|
<tt>Register*</tt> templates that should be used if you want your pass listed by
|
||||||
@@ -740,14 +734,6 @@ example <tt>opt</tt> or <tt>analyze</tt>). The second argument is the name of
|
|||||||
the pass, which is to be used for the <tt>--help</tt> output of programs, as
|
the pass, which is to be used for the <tt>--help</tt> output of programs, as
|
||||||
well as for debug output generated by the <tt>--debug-pass</tt> option.</p>
|
well as for debug output generated by the <tt>--debug-pass</tt> option.</p>
|
||||||
|
|
||||||
<p>If you pass is constructed by its default constructor, you only ever have to
|
|
||||||
pass these two arguments. If, on the other hand, you require other information
|
|
||||||
(like target specific information), you must pass an additional argument. This
|
|
||||||
argument is a pointer to a function used to create the pass. For an example of
|
|
||||||
how this works, look at the <a
|
|
||||||
href="http://llvm.cs.uiuc.edu/doxygen/LowerAllocations_8cpp-source.html">LowerAllocations.cpp</a>
|
|
||||||
file.</p>
|
|
||||||
|
|
||||||
<p>If a pass is registered to be used by the <tt>analyze</tt> utility, you
|
<p>If a pass is registered to be used by the <tt>analyze</tt> utility, you
|
||||||
should implement the virtual <tt>print</tt> method:</p>
|
should implement the virtual <tt>print</tt> method:</p>
|
||||||
|
|
||||||
@@ -819,34 +805,77 @@ invalidated sets may be specified for your transformation. The implementation
|
|||||||
should fill in the <tt><a
|
should fill in the <tt><a
|
||||||
href="http://llvm.cs.uiuc.edu/doxygen/classllvm_1_1AnalysisUsage.html">AnalysisUsage</a></tt>
|
href="http://llvm.cs.uiuc.edu/doxygen/classllvm_1_1AnalysisUsage.html">AnalysisUsage</a></tt>
|
||||||
object with information about which passes are required and not invalidated. To
|
object with information about which passes are required and not invalidated. To
|
||||||
do this, the following set methods are provided by the <tt><a
|
do this, a pass may call any of the following methods on the AnalysisUsage
|
||||||
href="http://llvm.cs.uiuc.edu/doxygen/classllvm_1_1AnalysisUsage.html">AnalysisUsage</a></tt>
|
object:</p>
|
||||||
class:</p>
|
</div>
|
||||||
|
|
||||||
<pre>
|
<!-- _______________________________________________________________________ -->
|
||||||
<i>// addRequires - Add the specified pass to the required set for your pass.</i>
|
<div class="doc_subsubsection">
|
||||||
<b>template</b><<b>class</b> PassClass>
|
<a name="AU::addRequired">The <tt>AnalysisUsage::addRequired<></tt> and <tt>AnalysisUsage::addRequiredTransitive<></tt> methods</a>
|
||||||
AnalysisUsage &AnalysisUsage::addRequired();
|
</div>
|
||||||
|
|
||||||
<i>// addPreserved - Add the specified pass to the set of analyses preserved by
|
<div class="doc_text">
|
||||||
// this pass</i>
|
<p>
|
||||||
<b>template</b><<b>class</b> PassClass>
|
If you pass requires a previous pass to be executed (an analysis for example),
|
||||||
AnalysisUsage &AnalysisUsage::addPreserved();
|
it can use one of these methods to arrange for it to be run before your pass.
|
||||||
|
LLVM has many different types of analyses and passes that can be required,
|
||||||
|
spaning the range from <tt>DominatorSet</tt> to <tt>BreakCriticalEdges</tt>.
|
||||||
|
requiring <tt>BreakCriticalEdges</tt>, for example, guarantees that there will
|
||||||
|
be no critical edges in the CFG when your pass has been run.
|
||||||
|
</p>
|
||||||
|
|
||||||
<i>// setPreservesAll - Call this if the pass does not modify its input at all</i>
|
<p>
|
||||||
<b>void</b> AnalysisUsage::setPreservesAll();
|
Some analyses chain to other analyses to do their job. For example, an <a
|
||||||
|
href="AliasAnalysis.html">AliasAnalysis</a> implementation is required to <a
|
||||||
|
href="AliasAnalysis.html#chaining">chain</a> to other alias analysis passes. In
|
||||||
|
cases where analyses chain, the <tt>addRequiredTransitive</tt> method should be
|
||||||
|
used instead of the <tt>addRequired</tt> method. This informs the PassManager
|
||||||
|
that the transitively required pass should be alive as long as the requiring
|
||||||
|
pass is.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
<i>// setPreservesCFG - This function should be called by the pass, iff they do not:
|
<!-- _______________________________________________________________________ -->
|
||||||
//
|
<div class="doc_subsubsection">
|
||||||
// 1. Add or remove basic blocks from the function
|
<a name="AU::addPreserved">The <tt>AnalysisUsage::addPreserved<></tt> method</a>
|
||||||
// 2. Modify terminator instructions in any way.
|
</div>
|
||||||
//
|
|
||||||
// This is automatically implied for <a href="#BasicBlockPass">BasicBlockPass</a>'s
|
|
||||||
//</i>
|
|
||||||
<b>void</b> AnalysisUsage::setPreservesCFG();
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>Some examples of how to use these methods are:</p>
|
<div class="doc_text">
|
||||||
|
<p>
|
||||||
|
One of the jobs of the PassManager is to optimize how and when analyses are run.
|
||||||
|
In particular, it attempts to avoid recomputing data unless it needs to. For
|
||||||
|
this reason, passes are allowed to declare that they preserve (i.e., they don't
|
||||||
|
invalidate) an existing analysis if it's available. For example, a simple
|
||||||
|
constant folding pass would not modify the CFG, so it can't possible effect the
|
||||||
|
results of dominator analysis. By default, all passes are assumed to invalidate
|
||||||
|
all others.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The <tt>AnalysisUsage</tt> class provides several methods which are useful in
|
||||||
|
certain circumstances that are related to <tt>addPreserved</tt>. In particular,
|
||||||
|
the <tt>setPreservesAll</tt> method can be called to indicate that the pass does
|
||||||
|
not modify the LLVM program at all (which is true for analyses), and the
|
||||||
|
<tt>setPreservesCFG</tt> method can be used by transformations that change
|
||||||
|
instructions in the program but do not modify the CFG or terminator instructions
|
||||||
|
(note that this property is implicitly set for <a
|
||||||
|
href="#BasicBlockPass">BasicBlockPass</a>'s).
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<tt>addPreserved</tt> is particularly useful for transformations like
|
||||||
|
<tt>BreakCriticalEdges</tt>. This pass knows how to update a small set of loop
|
||||||
|
and dominator related analyses if they exist, so it can preserve them, despite
|
||||||
|
the fact that it hacks on the CFG.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- _______________________________________________________________________ -->
|
||||||
|
<div class="doc_subsubsection">
|
||||||
|
<a name="AU::examples">Example implementations of <tt>getAnalysisUsage</tt></a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="doc_text">
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
<i>// This is an example implementation from an analysis, which does not modify
|
<i>// This is an example implementation from an analysis, which does not modify
|
||||||
@@ -871,20 +900,22 @@ class:</p>
|
|||||||
|
|
||||||
<!-- _______________________________________________________________________ -->
|
<!-- _______________________________________________________________________ -->
|
||||||
<div class="doc_subsubsection">
|
<div class="doc_subsubsection">
|
||||||
<a name="getAnalysis">The <tt>getAnalysis<></tt> method</a>
|
<a name="getAnalysis">The <tt>getAnalysis<></tt> and <tt>getAnalysisToUpdate<></tt> methods</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="doc_text">
|
<div class="doc_text">
|
||||||
|
|
||||||
<p>The <tt>Pass::getAnalysis<></tt> method is inherited by your class,
|
<p>The <tt>Pass::getAnalysis<></tt> method is automatically inherited by
|
||||||
providing you with access to the passes that you declared that you required with
|
your class, providing you with access to the passes that you declared that you
|
||||||
the <a href="#getAnalysisUsage"><tt>getAnalysisUsage</tt></a> method. It takes
|
required with the <a href="#getAnalysisUsage"><tt>getAnalysisUsage</tt></a>
|
||||||
a single template argument that specifies which pass class you want, and returns
|
method. It takes a single template argument that specifies which pass class you
|
||||||
a reference to that pass.</p>
|
want, and returns a reference to that pass. For example:</p>
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
<b>template</b><<b>typename</b> PassClass>
|
bool LICM::runOnFunction(Function &F) {
|
||||||
AnalysisType &getAnalysis();
|
LoopInfo &LI = getAnalysis<LoopInfo>();
|
||||||
|
...
|
||||||
|
}
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
<p>This method call returns a reference to the pass desired. You may get a
|
<p>This method call returns a reference to the pass desired. You may get a
|
||||||
@@ -894,6 +925,20 @@ href="#getAnalysisUsage"><tt>getAnalysisUsage</tt></a> implementation. This
|
|||||||
method can be called by your <tt>run*</tt> method implementation, or by any
|
method can be called by your <tt>run*</tt> method implementation, or by any
|
||||||
other local method invoked by your <tt>run*</tt> method.</p>
|
other local method invoked by your <tt>run*</tt> method.</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
If your pass is capable of updating analyses if they exist (e.g.,
|
||||||
|
<tt>BreakCriticalEdges</tt>, as described above), you can use the
|
||||||
|
<tt>getAnalysisToUpdate</tt> method, which returns a pointer to the analysis if
|
||||||
|
it is active. For example:</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
...
|
||||||
|
if (DominatorSet *DS = getAnalysisToUpdate<DominatorSet>()) {
|
||||||
|
<i>// A DominatorSet is active. This code will update it.</i>
|
||||||
|
}
|
||||||
|
...
|
||||||
|
</pre>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- *********************************************************************** -->
|
<!-- *********************************************************************** -->
|
||||||
@@ -924,7 +969,7 @@ Analysis Groups.</p>
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- _______________________________________________________________________ -->
|
<!-- _______________________________________________________________________ -->
|
||||||
<div class="subsubsection">
|
<div class="doc_subsubsection">
|
||||||
<a name="agconcepts">Analysis Group Concepts</a>
|
<a name="agconcepts">Analysis Group Concepts</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -975,7 +1020,7 @@ hypothetical example) instead.</p>
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- _______________________________________________________________________ -->
|
<!-- _______________________________________________________________________ -->
|
||||||
<div class="subsubsection">
|
<div class="doc_subsubsection">
|
||||||
<a name="registerag">Using <tt>RegisterAnalysisGroup</tt></a>
|
<a name="registerag">Using <tt>RegisterAnalysisGroup</tt></a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -1345,7 +1390,7 @@ where we are going:</p>
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- _______________________________________________________________________ -->
|
<!-- _______________________________________________________________________ -->
|
||||||
<div class="subsubsection">
|
<div class="doc_subsubsection">
|
||||||
<a name="SMP">Multithreaded LLVM</a>
|
<a name="SMP">Multithreaded LLVM</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -1368,7 +1413,7 @@ Despite that, we have kept the LLVM passes SMP ready, and you should too.</p>
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- _______________________________________________________________________ -->
|
<!-- _______________________________________________________________________ -->
|
||||||
<div class="subsubsection">
|
<div class="doc_subsubsection">
|
||||||
<a name="ModuleSource">A new <tt>ModuleSource</tt> interface</a>
|
<a name="ModuleSource">A new <tt>ModuleSource</tt> interface</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -1395,7 +1440,7 @@ capable of this, the loader just needs to be reworked a bit.</p>
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- _______________________________________________________________________ -->
|
<!-- _______________________________________________________________________ -->
|
||||||
<div class="subsubsection">
|
<div class="doc_subsubsection">
|
||||||
<a name="PassFunctionPass"><tt>Pass</tt>es requiring <tt>FunctionPass</tt>es</a>
|
<a name="PassFunctionPass"><tt>Pass</tt>es requiring <tt>FunctionPass</tt>es</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -1,240 +0,0 @@
|
|||||||
/* Title: SparcRegClassInfo.h -*- C++ -*-
|
|
||||||
Author: Ruchira Sasanka
|
|
||||||
Date: Aug 20, 01
|
|
||||||
Purpose: Contains the description of integer register class of Sparc
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef SPARC_INT_REG_CLASS_H
|
|
||||||
#define SPARC_INT_REG_CLASS_H
|
|
||||||
|
|
||||||
#include "llvm/Target/RegInfo.h"
|
|
||||||
#include "llvm/CodeGen/IGNode.h"
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
// Integer Register Class
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
// Int register names in same order as enum in class SparcIntRegOrder
|
|
||||||
|
|
||||||
static string const IntRegNames[] =
|
|
||||||
{ "g1", "g2", "g3", "g4", "g5", "g6", "g7",
|
|
||||||
"o0", "o1", "o2", "o3", "o4", "o5", "o7",
|
|
||||||
"l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7",
|
|
||||||
"i0", "i1", "i2", "i3", "i4", "i5",
|
|
||||||
"g0", "i6", "i7", "o6" };
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class SparcIntRegOrder{
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
enum RegsInPrefOrder // colors possible for a LR (in preferred order)
|
|
||||||
{
|
|
||||||
// --- following colors are volatile across function calls
|
|
||||||
// %g0 can't be used for coloring - always 0
|
|
||||||
|
|
||||||
g1, g2, g3, g4, g5, g6, g7, //%g1-%g7
|
|
||||||
o0, o1, o2, o3, o4, o5, o7, // %o0-%o5,
|
|
||||||
|
|
||||||
// %o6 is sp,
|
|
||||||
// all %0's can get modified by a call
|
|
||||||
|
|
||||||
// --- following colors are NON-volatile across function calls
|
|
||||||
|
|
||||||
l0, l1, l2, l3, l4, l5, l6, l7, // %l0-%l7
|
|
||||||
i0, i1, i2, i3, i4, i5, // %i0-%i5: i's need not be preserved
|
|
||||||
|
|
||||||
// %i6 is the fp - so not allocated
|
|
||||||
// %i7 is the ret address - can be used if saved
|
|
||||||
|
|
||||||
// max # of colors reg coloring can allocate (NumOfAvailRegs)
|
|
||||||
|
|
||||||
// --- following colors are not available for allocation within this phase
|
|
||||||
// --- but can appear for pre-colored ranges
|
|
||||||
|
|
||||||
g0, i6, i7, o6
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
// max # of colors reg coloring can allocate
|
|
||||||
static unsigned int const NumOfAvailRegs = g0;
|
|
||||||
|
|
||||||
static unsigned int const StartOfNonVolatileRegs = l0;
|
|
||||||
static unsigned int const StartOfAllRegs = g1;
|
|
||||||
static unsigned int const NumOfAllRegs = o6 + 1;
|
|
||||||
|
|
||||||
|
|
||||||
static const string getRegName(const unsigned reg) {
|
|
||||||
assert( reg < NumOfAllRegs );
|
|
||||||
return IntRegNames[reg];
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class SparcIntRegClass : public MachineRegClassInfo
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
SparcIntRegClass(unsigned ID)
|
|
||||||
: MachineRegClassInfo(ID,
|
|
||||||
SparcIntRegOrder::NumOfAvailRegs,
|
|
||||||
SparcIntRegOrder::NumOfAllRegs)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
void colorIGNode(IGNode * Node, bool IsColorUsedArr[] ) const;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
// Float Register Class
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
static string const FloatRegNames[] =
|
|
||||||
{
|
|
||||||
"f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9",
|
|
||||||
"f10", "f11", "f12", "f13", "f14", "f15", "f16", "f17", "f18", "f19",
|
|
||||||
"f20", "f21", "f22", "f23", "f24", "f25", "f26", "f27", "f28", "f29",
|
|
||||||
"f30", "f31", "f32", "f33", "f34", "f35", "f36", "f37", "f38", "f39",
|
|
||||||
"f40", "f41", "f42", "f43", "f44", "f45", "f46", "f47", "f48", "f49",
|
|
||||||
"f50", "f51", "f52", "f53", "f54", "f55", "f56", "f57", "f58", "f59",
|
|
||||||
"f60", "f61", "f62", "f63"
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class SparcFloatRegOrder{
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
enum RegsInPrefOrder {
|
|
||||||
|
|
||||||
f0, f1, f2, f3, f4, f5, f6, f7, f8, f9,
|
|
||||||
f10, f11, f12, f13, f14, f15, f16, f17, f18, f19,
|
|
||||||
f20, f21, f22, f23, f24, f25, f26, f27, f28, f29,
|
|
||||||
f30, f31, f32, f33, f34, f35, f36, f37, f38, f39,
|
|
||||||
f40, f41, f42, f43, f44, f45, f46, f47, f48, f49,
|
|
||||||
f50, f51, f52, f53, f54, f55, f56, f57, f58, f59,
|
|
||||||
f60, f61, f62, f63
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
// there are 64 regs alltogether but only 32 regs can be allocated at
|
|
||||||
// a time.
|
|
||||||
|
|
||||||
static unsigned int const NumOfAvailRegs = 32;
|
|
||||||
static unsigned int const NumOfAllRegs = 64;
|
|
||||||
|
|
||||||
static unsigned int const StartOfNonVolatileRegs = f6;
|
|
||||||
static unsigned int const StartOfAllRegs = f0;
|
|
||||||
|
|
||||||
|
|
||||||
static const string getRegName(const unsigned reg) {
|
|
||||||
assert( reg < NumOfAllRegs );
|
|
||||||
return FloatRegNames[reg];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class SparcFloatRegClass : public MachineRegClassInfo
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
|
|
||||||
int findFloatColor(const IGNode *const Node, unsigned Start,
|
|
||||||
unsigned End, bool IsColorUsedArr[] ) const;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
SparcFloatRegClass(unsigned ID)
|
|
||||||
: MachineRegClassInfo(ID,
|
|
||||||
SparcFloatRegOrder::NumOfAvailRegs,
|
|
||||||
SparcFloatRegOrder::NumOfAllRegs)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
void colorIGNode(IGNode * Node, bool IsColorUsedArr[] ) const;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
// Int CC Register Class
|
|
||||||
// Only one integer cc register is available
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
class SparcIntCCRegClass : public MachineRegClassInfo
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
SparcIntCCRegClass(unsigned ID)
|
|
||||||
: MachineRegClassInfo(ID,1, 1) { }
|
|
||||||
|
|
||||||
inline void colorIGNode(IGNode * Node, bool IsColorUsedArr[] ) const {
|
|
||||||
Node->setColor(0); // only one int cc reg is available
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
// Float CC Register Class
|
|
||||||
// Only 4 Float CC registers are available
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
static string const FloatCCRegNames[] =
|
|
||||||
{
|
|
||||||
"fcc0", "fcc1", "fcc2", "fcc3"
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class SparcFloatCCRegOrder{
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
enum RegsInPrefOrder {
|
|
||||||
|
|
||||||
fcc0, fcc1, fcc2, fcc3
|
|
||||||
};
|
|
||||||
|
|
||||||
static const string getRegName(const unsigned reg) {
|
|
||||||
assert( reg < 4 );
|
|
||||||
return FloatCCRegNames[reg];
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class SparcFloatCCRegClass : public MachineRegClassInfo
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
SparcFloatCCRegClass(unsigned ID)
|
|
||||||
: MachineRegClassInfo(ID, 4, 4) { }
|
|
||||||
|
|
||||||
void colorIGNode(IGNode * Node, bool IsColorUsedArr[] ) const {
|
|
||||||
int c;
|
|
||||||
for(c=0; c < 4 && IsColorUsedArr[c] ; ++c) ; // find color
|
|
||||||
assert( (c < 4) && "Can allocate only 4 float cc registers");
|
|
||||||
Node->setColor(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -14,23 +14,26 @@
|
|||||||
#ifndef LLVM_TRANSFORMS_UTILS_FUNCTION_H
|
#ifndef LLVM_TRANSFORMS_UTILS_FUNCTION_H
|
||||||
#define LLVM_TRANSFORMS_UTILS_FUNCTION_H
|
#define LLVM_TRANSFORMS_UTILS_FUNCTION_H
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
|
class BasicBlock;
|
||||||
|
class DominatorSet;
|
||||||
|
class Function;
|
||||||
|
class Loop;
|
||||||
|
|
||||||
|
/// ExtractCodeRegion - rip out a sequence of basic blocks into a new function
|
||||||
|
///
|
||||||
|
Function* ExtractCodeRegion(DominatorSet &DS,
|
||||||
|
const std::vector<BasicBlock*> &code);
|
||||||
|
|
||||||
class Function;
|
/// ExtractLoop - rip out a natural loop into a new function
|
||||||
class Loop;
|
///
|
||||||
|
Function* ExtractLoop(DominatorSet &DS, Loop *L);
|
||||||
/// ExtractCodeRegion - rip out a sequence of basic blocks into a new function
|
|
||||||
///
|
|
||||||
Function* ExtractCodeRegion(const std::vector<BasicBlock*> &code);
|
|
||||||
|
|
||||||
/// ExtractLoop - rip out a natural loop into a new function
|
|
||||||
///
|
|
||||||
Function* ExtractLoop(Loop *L);
|
|
||||||
|
|
||||||
/// ExtractBasicBlock - rip out a basic block into a new function
|
|
||||||
///
|
|
||||||
Function* ExtractBasicBlock(BasicBlock *BB);
|
|
||||||
|
|
||||||
|
/// ExtractBasicBlock - rip out a basic block into a new function
|
||||||
|
///
|
||||||
|
Function* ExtractBasicBlock(BasicBlock *BB);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ void AliasSet::addCallSite(CallSite CS, AliasAnalysis &AA) {
|
|||||||
return;
|
return;
|
||||||
else if (AA.onlyReadsMemory(F)) {
|
else if (AA.onlyReadsMemory(F)) {
|
||||||
AliasTy = MayAlias;
|
AliasTy = MayAlias;
|
||||||
AccessTy = Refs;
|
AccessTy |= Refs;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
#
|
#
|
||||||
##===----------------------------------------------------------------------===##
|
##===----------------------------------------------------------------------===##
|
||||||
LEVEL = ../..
|
LEVEL = ../..
|
||||||
DIRS = CBackend X86 SparcV9 PowerPC
|
DIRS = CBackend X86 SparcV9
|
||||||
LIBRARYNAME = target
|
LIBRARYNAME = target
|
||||||
BUILD_ARCHIVE = 1
|
BUILD_ARCHIVE = 1
|
||||||
|
|
||||||
|
|||||||
@@ -1,42 +0,0 @@
|
|||||||
//===-- PowerPC.h - Top-level interface for PowerPC representation -*- C++ -*-//
|
|
||||||
//
|
|
||||||
// The LLVM Compiler Infrastructure
|
|
||||||
//
|
|
||||||
// This file was developed by the LLVM research group and is distributed under
|
|
||||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
// This file contains the entry points for global functions defined in the LLVM
|
|
||||||
// PowerPC back-end.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#ifndef TARGET_POWERPC_H
|
|
||||||
#define TARGET_POWERPC_H
|
|
||||||
|
|
||||||
#include <iosfwd>
|
|
||||||
|
|
||||||
namespace llvm {
|
|
||||||
|
|
||||||
class FunctionPass;
|
|
||||||
class TargetMachine;
|
|
||||||
|
|
||||||
// Here is where you would define factory methods for powerpc-specific
|
|
||||||
// passes. For example:
|
|
||||||
// FunctionPass *createPowerPCSimpleInstructionSelector (TargetMachine &TM);
|
|
||||||
// FunctionPass *createPowerPCCodePrinterPass(std::ostream &OS,
|
|
||||||
// TargetMachine &TM);
|
|
||||||
|
|
||||||
} // end namespace llvm;
|
|
||||||
|
|
||||||
// Defines symbolic names for PowerPC registers. This defines a mapping from
|
|
||||||
// register name to register number.
|
|
||||||
//
|
|
||||||
#include "PowerPCGenRegisterNames.inc"
|
|
||||||
|
|
||||||
// Defines symbolic names for the PowerPC instructions.
|
|
||||||
//
|
|
||||||
#include "PowerPCGenInstrNames.inc"
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
//===- PowerPCInstrInfo.td - Describe the PowerPC Instruction Set -*- C++ -*-=//
|
|
||||||
//
|
|
||||||
// The LLVM Compiler Infrastructure
|
|
||||||
//
|
|
||||||
// This file was developed by the LLVM research group and is distributed under
|
|
||||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
class Format<bits<4> val> {
|
|
||||||
bits<4> Value = val;
|
|
||||||
}
|
|
||||||
|
|
||||||
// All of the PowerPC instruction formats, plus a pseudo-instruction format:
|
|
||||||
def Pseudo : Format<0>;
|
|
||||||
def IForm : Format<1>;
|
|
||||||
def BForm : Format<2>;
|
|
||||||
def SCForm : Format<3>;
|
|
||||||
def DForm : Format<4>;
|
|
||||||
def XForm : Format<5>;
|
|
||||||
def XLForm : Format<6>;
|
|
||||||
def XFXForm : Format<7>;
|
|
||||||
def XFLForm : Format<8>;
|
|
||||||
def XOForm : Format<9>;
|
|
||||||
def AForm : Format<10>;
|
|
||||||
def MForm : Format<11>;
|
|
||||||
|
|
||||||
class PPCInst<string nm, bits<6> opcd, Format f> : Instruction {
|
|
||||||
let Namespace = "PowerPC";
|
|
||||||
|
|
||||||
let Name = nm;
|
|
||||||
bits<6> Opcode = opcd;
|
|
||||||
Format Form = f;
|
|
||||||
bits<4> FormBits = Form.Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pseudo-instructions:
|
|
||||||
def PHI : PPCInst<"PHI", 0, Pseudo>; // PHI node...
|
|
||||||
def NOP : PPCInst<"NOP", 0, Pseudo>; // No-op
|
|
||||||
def ADJCALLSTACKDOWN : PPCInst<"ADJCALLSTACKDOWN", 0, Pseudo>;
|
|
||||||
def ADJCALLSTACKUP : PPCInst<"ADJCALLSTACKUP", 0, Pseudo>;
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
//===- PowerPCJITInfo.h - PowerPC impl. of the JIT interface ----*- C++ -*-===//
|
|
||||||
//
|
|
||||||
// The LLVM Compiler Infrastructure
|
|
||||||
//
|
|
||||||
// This file was developed by the LLVM research group and is distributed under
|
|
||||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
// This file contains the PowerPC implementation of the TargetJITInfo class.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#ifndef POWERPCJITINFO_H
|
|
||||||
#define POWERPCJITINFO_H
|
|
||||||
|
|
||||||
#include "llvm/Target/TargetJITInfo.h"
|
|
||||||
|
|
||||||
namespace llvm {
|
|
||||||
class TargetMachine;
|
|
||||||
class IntrinsicLowering;
|
|
||||||
|
|
||||||
class PowerPCJITInfo : public TargetJITInfo {
|
|
||||||
TargetMachine &TM;
|
|
||||||
public:
|
|
||||||
PowerPCJITInfo(TargetMachine &tm) : TM(tm) {}
|
|
||||||
|
|
||||||
/// addPassesToJITCompile - Add passes to the specified pass manager to
|
|
||||||
/// implement a fast dynamic compiler for this target. Return true if this
|
|
||||||
/// is not supported for this target.
|
|
||||||
///
|
|
||||||
virtual void addPassesToJITCompile(FunctionPassManager &PM);
|
|
||||||
|
|
||||||
/// replaceMachineCodeForFunction - Make it so that calling the function
|
|
||||||
/// whose machine code is at OLD turns into a call to NEW, perhaps by
|
|
||||||
/// overwriting OLD with a branch to NEW. This is used for self-modifying
|
|
||||||
/// code.
|
|
||||||
///
|
|
||||||
virtual void replaceMachineCodeForFunction(void *Old, void *New);
|
|
||||||
|
|
||||||
/// getJITStubForFunction - Create or return a stub for the specified
|
|
||||||
/// function. This stub acts just like the specified function, except that
|
|
||||||
/// it allows the "address" of the function to be taken without having to
|
|
||||||
/// generate code for it.
|
|
||||||
virtual void *getJITStubForFunction(Function *F, MachineCodeEmitter &MCE);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,82 +0,0 @@
|
|||||||
//===- PowerPCReg.td - Describe the PowerPC Register File -------*- C++ -*-===//
|
|
||||||
//
|
|
||||||
// The LLVM Compiler Infrastructure
|
|
||||||
//
|
|
||||||
// This file was developed by the LLVM research group and is distributed under
|
|
||||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
class PPCReg : Register {
|
|
||||||
let Namespace = "PowerPC";
|
|
||||||
}
|
|
||||||
|
|
||||||
// We identify all our registers with a 5-bit ID, for consistency's sake.
|
|
||||||
|
|
||||||
// GPR - One of the 32 32-bit general-purpose registers
|
|
||||||
class GPR<bits<5> num> : PPCReg {
|
|
||||||
field bits<5> Num = num;
|
|
||||||
}
|
|
||||||
|
|
||||||
// SPR - One of the 32-bit special-purpose registers
|
|
||||||
class SPR<bits<5> num> : PPCReg {
|
|
||||||
field bits<5> Num = num;
|
|
||||||
}
|
|
||||||
|
|
||||||
// FPR - One of the 32 64-bit floating-point registers
|
|
||||||
class FPR<bits<5> num> : PPCReg {
|
|
||||||
field bits<5> Num = num;
|
|
||||||
}
|
|
||||||
|
|
||||||
// CR - One of the 8 4-bit condition registers
|
|
||||||
class CR<bits<5> num> : PPCReg {
|
|
||||||
field bits<5> Num = num;
|
|
||||||
}
|
|
||||||
|
|
||||||
// General-purpose registers
|
|
||||||
def R0 : GPR< 0>; def R1 : GPR< 1>; def R2 : GPR< 2>; def R3 : GPR< 3>;
|
|
||||||
def R4 : GPR< 4>; def R5 : GPR< 5>; def R6 : GPR< 6>; def R7 : GPR< 7>;
|
|
||||||
def R8 : GPR< 8>; def R9 : GPR< 9>; def R10 : GPR<10>; def R11 : GPR<11>;
|
|
||||||
def R12 : GPR<12>; def R13 : GPR<13>; def R14 : GPR<14>; def R15 : GPR<15>;
|
|
||||||
def R16 : GPR<16>; def R17 : GPR<17>; def R18 : GPR<18>; def R19 : GPR<19>;
|
|
||||||
def R20 : GPR<20>; def R21 : GPR<21>; def R22 : GPR<22>; def R23 : GPR<23>;
|
|
||||||
def R24 : GPR<24>; def R25 : GPR<25>; def R26 : GPR<26>; def R27 : GPR<27>;
|
|
||||||
def R28 : GPR<28>; def R29 : GPR<29>; def R30 : GPR<30>; def R31 : GPR<31>;
|
|
||||||
|
|
||||||
// Floating-point registers
|
|
||||||
def F0 : FPR< 0>; def F1 : FPR< 1>; def F2 : FPR< 2>; def F3 : FPR< 3>;
|
|
||||||
def F4 : FPR< 4>; def F5 : FPR< 5>; def F6 : FPR< 6>; def F7 : FPR< 7>;
|
|
||||||
def F8 : FPR< 8>; def F9 : FPR< 9>; def F10 : FPR<10>; def F11 : FPR<11>;
|
|
||||||
def F12 : FPR<12>; def F13 : FPR<13>; def F14 : FPR<14>; def F15 : FPR<15>;
|
|
||||||
def F16 : FPR<16>; def F17 : FPR<17>; def F18 : FPR<18>; def F19 : FPR<19>;
|
|
||||||
def F20 : FPR<20>; def F21 : FPR<21>; def F22 : FPR<22>; def F23 : FPR<23>;
|
|
||||||
def F24 : FPR<24>; def F25 : FPR<25>; def F26 : FPR<26>; def F27 : FPR<27>;
|
|
||||||
def F28 : FPR<28>; def F29 : FPR<29>; def F30 : FPR<30>; def F31 : FPR<31>;
|
|
||||||
|
|
||||||
// Condition registers
|
|
||||||
def CR0 : CR<0>; def CR1 : CR<1>; def CR2 : CR<2>; def CR3 : CR<3>;
|
|
||||||
def CR4 : CR<4>; def CR5 : CR<5>; def CR6 : CR<6>; def CR7 : CR<7>;
|
|
||||||
|
|
||||||
// Floating-point status and control register
|
|
||||||
def FPSCR : SPR<0>;
|
|
||||||
// fiXed-point Exception Register? :-)
|
|
||||||
def XER : SPR<1>;
|
|
||||||
// Link register
|
|
||||||
def LR : SPR<2>;
|
|
||||||
// Count register
|
|
||||||
def CTR : SPR<3>;
|
|
||||||
// These are the "time base" registers which are read-only in user mode.
|
|
||||||
def TBL : SPR<4>;
|
|
||||||
def TBU : SPR<5>;
|
|
||||||
|
|
||||||
/// Register classes: one for floats and another for non-floats.
|
|
||||||
def GPRC : RegisterClass<i32, 4, [R0, R1, R2, R3, R4, R5, R6, R7,
|
|
||||||
R8, R9, R10, R11, R12, R13, R14, R15, R16, R17, R18, R19, R20, R21,
|
|
||||||
R22, R23, R24, R25, R26, R27, R28, R29, R30, R31]>;
|
|
||||||
def FPRC : RegisterClass<f64, 8, [F0, F1, F2, F3, F4, F5, F6, F7,
|
|
||||||
F8, F9, F10, F11, F12, F13, F14, F15, F16, F17, F18, F19, F20, F21,
|
|
||||||
F22, F23, F24, F25, F26, F27, F28, F29, F30, F31]>;
|
|
||||||
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
//===-- PowerPCTargetMachine.cpp - Define TargetMachine for PowerPC -------===//
|
|
||||||
//
|
|
||||||
// The LLVM Compiler Infrastructure
|
|
||||||
//
|
|
||||||
// This file was developed by the LLVM research group and is distributed under
|
|
||||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "PowerPCTargetMachine.h"
|
|
||||||
#include "PowerPC.h"
|
|
||||||
#include "llvm/Module.h"
|
|
||||||
#include "llvm/PassManager.h"
|
|
||||||
#include "llvm/Target/TargetMachineImpls.h"
|
|
||||||
#include "llvm/CodeGen/MachineFunction.h"
|
|
||||||
#include "llvm/CodeGen/Passes.h"
|
|
||||||
using namespace llvm;
|
|
||||||
|
|
||||||
// allocatePowerPCTargetMachine - Allocate and return a subclass of
|
|
||||||
// TargetMachine that implements the PowerPC backend.
|
|
||||||
//
|
|
||||||
TargetMachine *llvm::allocatePowerPCTargetMachine(const Module &M,
|
|
||||||
IntrinsicLowering *IL) {
|
|
||||||
return new PowerPCTargetMachine(M, IL);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// PowerPCTargetMachine ctor - Create an ILP32 architecture model
|
|
||||||
///
|
|
||||||
PowerPCTargetMachine::PowerPCTargetMachine(const Module &M,
|
|
||||||
IntrinsicLowering *IL)
|
|
||||||
: TargetMachine("PowerPC", IL, true, 4, 4, 4, 4, 4),
|
|
||||||
FrameInfo(TargetFrameInfo::StackGrowsDown, 8, 4), JITInfo(*this) {
|
|
||||||
}
|
|
||||||
|
|
||||||
/// addPassesToEmitAssembly - Add passes to the specified pass manager
|
|
||||||
/// to implement a static compiler for this target.
|
|
||||||
///
|
|
||||||
bool PowerPCTargetMachine::addPassesToEmitAssembly(PassManager &PM,
|
|
||||||
std::ostream &Out) {
|
|
||||||
// <insert instruction selector passes here>
|
|
||||||
PM.add(createRegisterAllocator());
|
|
||||||
PM.add(createPrologEpilogCodeInserter());
|
|
||||||
// <insert assembly code output passes here>
|
|
||||||
PM.add(createMachineCodeDeleter());
|
|
||||||
return true; // change to `return false' when this actually works.
|
|
||||||
}
|
|
||||||
|
|
||||||
/// addPassesToJITCompile - Add passes to the specified pass manager to
|
|
||||||
/// implement a fast dynamic compiler for this target.
|
|
||||||
///
|
|
||||||
void PowerPCJITInfo::addPassesToJITCompile(FunctionPassManager &PM) {
|
|
||||||
// <insert instruction selector passes here>
|
|
||||||
PM.add(createRegisterAllocator());
|
|
||||||
PM.add(createPrologEpilogCodeInserter());
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,334 +0,0 @@
|
|||||||
//===-- InstSelectSimple.cpp - A simple instruction selector for SparcV8 --===//
|
|
||||||
//
|
|
||||||
// The LLVM Compiler Infrastructure
|
|
||||||
//
|
|
||||||
// This file was developed by the LLVM research group and is distributed under
|
|
||||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
// This file defines a simple peephole instruction selector for the V8 target
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "SparcV8.h"
|
|
||||||
#include "SparcV8InstrInfo.h"
|
|
||||||
#include "llvm/Instructions.h"
|
|
||||||
#include "llvm/IntrinsicLowering.h"
|
|
||||||
#include "llvm/Pass.h"
|
|
||||||
#include "llvm/Constants.h"
|
|
||||||
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
|
||||||
#include "llvm/CodeGen/MachineFunction.h"
|
|
||||||
#include "llvm/CodeGen/SSARegMap.h"
|
|
||||||
#include "llvm/Target/TargetMachine.h"
|
|
||||||
#include "llvm/Support/GetElementPtrTypeIterator.h"
|
|
||||||
#include "llvm/Support/InstVisitor.h"
|
|
||||||
#include "llvm/Support/CFG.h"
|
|
||||||
using namespace llvm;
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
struct V8ISel : public FunctionPass, public InstVisitor<V8ISel> {
|
|
||||||
TargetMachine &TM;
|
|
||||||
MachineFunction *F; // The function we are compiling into
|
|
||||||
MachineBasicBlock *BB; // The current MBB we are compiling
|
|
||||||
|
|
||||||
std::map<Value*, unsigned> RegMap; // Mapping between Val's and SSA Regs
|
|
||||||
|
|
||||||
// MBBMap - Mapping between LLVM BB -> Machine BB
|
|
||||||
std::map<const BasicBlock*, MachineBasicBlock*> MBBMap;
|
|
||||||
|
|
||||||
V8ISel(TargetMachine &tm) : TM(tm), F(0), BB(0) {}
|
|
||||||
|
|
||||||
/// runOnFunction - Top level implementation of instruction selection for
|
|
||||||
/// the entire function.
|
|
||||||
///
|
|
||||||
bool runOnFunction(Function &Fn);
|
|
||||||
|
|
||||||
virtual const char *getPassName() const {
|
|
||||||
return "SparcV8 Simple Instruction Selection";
|
|
||||||
}
|
|
||||||
|
|
||||||
/// visitBasicBlock - This method is called when we are visiting a new basic
|
|
||||||
/// block. This simply creates a new MachineBasicBlock to emit code into
|
|
||||||
/// and adds it to the current MachineFunction. Subsequent visit* for
|
|
||||||
/// instructions will be invoked for all instructions in the basic block.
|
|
||||||
///
|
|
||||||
void visitBasicBlock(BasicBlock &LLVM_BB) {
|
|
||||||
BB = MBBMap[&LLVM_BB];
|
|
||||||
}
|
|
||||||
|
|
||||||
void visitBinaryOperator(BinaryOperator &I);
|
|
||||||
void visitReturnInst(ReturnInst &RI);
|
|
||||||
|
|
||||||
void visitInstruction(Instruction &I) {
|
|
||||||
std::cerr << "Unhandled instruction: " << I;
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// LowerUnknownIntrinsicFunctionCalls - This performs a prepass over the
|
|
||||||
/// function, lowering any calls to unknown intrinsic functions into the
|
|
||||||
/// equivalent LLVM code.
|
|
||||||
void LowerUnknownIntrinsicFunctionCalls(Function &F);
|
|
||||||
void visitIntrinsicCall(Intrinsic::ID ID, CallInst &CI);
|
|
||||||
|
|
||||||
/// copyConstantToRegister - Output the instructions required to put the
|
|
||||||
/// specified constant into the specified register.
|
|
||||||
///
|
|
||||||
void copyConstantToRegister(MachineBasicBlock *MBB,
|
|
||||||
MachineBasicBlock::iterator IP,
|
|
||||||
Constant *C, unsigned R);
|
|
||||||
|
|
||||||
/// makeAnotherReg - This method returns the next register number we haven't
|
|
||||||
/// yet used.
|
|
||||||
///
|
|
||||||
/// Long values are handled somewhat specially. They are always allocated
|
|
||||||
/// as pairs of 32 bit integer values. The register number returned is the
|
|
||||||
/// lower 32 bits of the long value, and the regNum+1 is the upper 32 bits
|
|
||||||
/// of the long value.
|
|
||||||
///
|
|
||||||
unsigned makeAnotherReg(const Type *Ty) {
|
|
||||||
assert(dynamic_cast<const SparcV8RegisterInfo*>(TM.getRegisterInfo()) &&
|
|
||||||
"Current target doesn't have SparcV8 reg info??");
|
|
||||||
const SparcV8RegisterInfo *MRI =
|
|
||||||
static_cast<const SparcV8RegisterInfo*>(TM.getRegisterInfo());
|
|
||||||
if (Ty == Type::LongTy || Ty == Type::ULongTy) {
|
|
||||||
const TargetRegisterClass *RC = MRI->getRegClassForType(Type::IntTy);
|
|
||||||
// Create the lower part
|
|
||||||
F->getSSARegMap()->createVirtualRegister(RC);
|
|
||||||
// Create the upper part.
|
|
||||||
return F->getSSARegMap()->createVirtualRegister(RC)-1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the mapping of regnumber => reg class to MachineFunction
|
|
||||||
const TargetRegisterClass *RC = MRI->getRegClassForType(Ty);
|
|
||||||
return F->getSSARegMap()->createVirtualRegister(RC);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned getReg(Value &V) { return getReg (&V); } // allow refs.
|
|
||||||
unsigned getReg(Value *V) {
|
|
||||||
// Just append to the end of the current bb.
|
|
||||||
MachineBasicBlock::iterator It = BB->end();
|
|
||||||
return getReg(V, BB, It);
|
|
||||||
}
|
|
||||||
unsigned getReg(Value *V, MachineBasicBlock *MBB,
|
|
||||||
MachineBasicBlock::iterator IPt) {
|
|
||||||
unsigned &Reg = RegMap[V];
|
|
||||||
if (Reg == 0) {
|
|
||||||
Reg = makeAnotherReg(V->getType());
|
|
||||||
RegMap[V] = Reg;
|
|
||||||
}
|
|
||||||
// If this operand is a constant, emit the code to copy the constant into
|
|
||||||
// the register here...
|
|
||||||
//
|
|
||||||
if (Constant *C = dyn_cast<Constant>(V)) {
|
|
||||||
copyConstantToRegister(MBB, IPt, C, Reg);
|
|
||||||
RegMap.erase(V); // Assign a new name to this constant if ref'd again
|
|
||||||
} else if (GlobalValue *GV = dyn_cast<GlobalValue>(V)) {
|
|
||||||
// Move the address of the global into the register
|
|
||||||
unsigned TmpReg = makeAnotherReg(V->getType());
|
|
||||||
BuildMI (*MBB, IPt, V8::SETHIi, 1, TmpReg).addGlobalAddress (GV);
|
|
||||||
BuildMI (*MBB, IPt, V8::ORri, 2, Reg).addReg (TmpReg)
|
|
||||||
.addGlobalAddress (GV);
|
|
||||||
RegMap.erase(V); // Assign a new name to this address if ref'd again
|
|
||||||
}
|
|
||||||
|
|
||||||
return Reg;
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
FunctionPass *llvm::createSparcV8SimpleInstructionSelector(TargetMachine &TM) {
|
|
||||||
return new V8ISel(TM);
|
|
||||||
}
|
|
||||||
|
|
||||||
enum TypeClass {
|
|
||||||
cByte, cShort, cInt, cLong, cFloat, cDouble
|
|
||||||
};
|
|
||||||
|
|
||||||
static TypeClass getClass (const Type *T) {
|
|
||||||
switch (T->getPrimitiveID ()) {
|
|
||||||
case Type::UByteTyID: case Type::SByteTyID: return cByte;
|
|
||||||
case Type::UShortTyID: case Type::ShortTyID: return cShort;
|
|
||||||
case Type::UIntTyID: case Type::IntTyID: return cInt;
|
|
||||||
case Type::ULongTyID: case Type::LongTyID: return cLong;
|
|
||||||
case Type::FloatTyID: return cFloat;
|
|
||||||
case Type::DoubleTyID: return cDouble;
|
|
||||||
default:
|
|
||||||
assert (0 && "Type of unknown class passed to getClass?");
|
|
||||||
return cByte;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// copyConstantToRegister - Output the instructions required to put the
|
|
||||||
/// specified constant into the specified register.
|
|
||||||
///
|
|
||||||
void V8ISel::copyConstantToRegister(MachineBasicBlock *MBB,
|
|
||||||
MachineBasicBlock::iterator IP,
|
|
||||||
Constant *C, unsigned R) {
|
|
||||||
if (ConstantInt *CI = dyn_cast<ConstantInt> (C)) {
|
|
||||||
unsigned Class = getClass(C->getType());
|
|
||||||
switch (Class) {
|
|
||||||
case cByte:
|
|
||||||
BuildMI (*MBB, IP, V8::ORri, 2, R).addReg (V8::G0).addImm ((uint8_t) CI->getRawValue ());
|
|
||||||
return;
|
|
||||||
case cShort: {
|
|
||||||
unsigned TmpReg = makeAnotherReg (C->getType ());
|
|
||||||
BuildMI (*MBB, IP, V8::SETHIi, 1, TmpReg).addImm (((uint16_t) CI->getRawValue ()) >> 10);
|
|
||||||
BuildMI (*MBB, IP, V8::ORri, 2, R).addReg (TmpReg).addImm (((uint16_t) CI->getRawValue ()) & 0x03ff);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case cInt: {
|
|
||||||
unsigned TmpReg = makeAnotherReg (C->getType ());
|
|
||||||
BuildMI (*MBB, IP, V8::SETHIi, 1, TmpReg).addImm (((uint32_t) CI->getRawValue ()) >> 10);
|
|
||||||
BuildMI (*MBB, IP, V8::ORri, 2, R).addReg (TmpReg).addImm (((uint32_t) CI->getRawValue ()) & 0x03ff);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
assert (0 && "Can't copy this kind of constant into register yet");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
assert (0 && "Can't copy this kind of constant into register yet");
|
|
||||||
}
|
|
||||||
|
|
||||||
bool V8ISel::runOnFunction(Function &Fn) {
|
|
||||||
// First pass over the function, lower any unknown intrinsic functions
|
|
||||||
// with the IntrinsicLowering class.
|
|
||||||
LowerUnknownIntrinsicFunctionCalls(Fn);
|
|
||||||
|
|
||||||
F = &MachineFunction::construct(&Fn, TM);
|
|
||||||
|
|
||||||
// Create all of the machine basic blocks for the function...
|
|
||||||
for (Function::iterator I = Fn.begin(), E = Fn.end(); I != E; ++I)
|
|
||||||
F->getBasicBlockList().push_back(MBBMap[I] = new MachineBasicBlock(I));
|
|
||||||
|
|
||||||
BB = &F->front();
|
|
||||||
|
|
||||||
// Set up a frame object for the return address. This is used by the
|
|
||||||
// llvm.returnaddress & llvm.frameaddress intrinisics.
|
|
||||||
//ReturnAddressIndex = F->getFrameInfo()->CreateFixedObject(4, -4);
|
|
||||||
|
|
||||||
// Copy incoming arguments off of the stack and out of fixed registers.
|
|
||||||
//LoadArgumentsToVirtualRegs(Fn);
|
|
||||||
|
|
||||||
// Instruction select everything except PHI nodes
|
|
||||||
visit(Fn);
|
|
||||||
|
|
||||||
// Select the PHI nodes
|
|
||||||
//SelectPHINodes();
|
|
||||||
|
|
||||||
RegMap.clear();
|
|
||||||
MBBMap.clear();
|
|
||||||
F = 0;
|
|
||||||
// We always build a machine code representation for the function
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void V8ISel::visitReturnInst(ReturnInst &I) {
|
|
||||||
if (I.getNumOperands () == 1) {
|
|
||||||
unsigned RetValReg = getReg (I.getOperand (0));
|
|
||||||
switch (getClass (I.getOperand (0)->getType ())) {
|
|
||||||
case cByte:
|
|
||||||
case cShort:
|
|
||||||
case cInt:
|
|
||||||
// Schlep it over into i0 (where it will become o0 after restore).
|
|
||||||
BuildMI (BB, V8::ORrr, 2, V8::I0).addReg(V8::G0).addReg(RetValReg);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
visitInstruction (I);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else if (I.getNumOperands () != 1) {
|
|
||||||
visitInstruction (I);
|
|
||||||
}
|
|
||||||
// Just emit a 'retl' instruction to return.
|
|
||||||
BuildMI(BB, V8::RETL, 0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
void V8ISel::visitBinaryOperator (BinaryOperator &I) {
|
|
||||||
unsigned DestReg = getReg (I);
|
|
||||||
unsigned Op0Reg = getReg (I.getOperand (0));
|
|
||||||
unsigned Op1Reg = getReg (I.getOperand (1));
|
|
||||||
|
|
||||||
unsigned ResultReg = makeAnotherReg (I.getType ());
|
|
||||||
switch (I.getOpcode ()) {
|
|
||||||
case Instruction::Add:
|
|
||||||
BuildMI (BB, V8::ADDrr, 2, ResultReg).addReg (Op0Reg).addReg (Op1Reg);
|
|
||||||
break;
|
|
||||||
case Instruction::Sub:
|
|
||||||
BuildMI (BB, V8::SUBrr, 2, ResultReg).addReg (Op0Reg).addReg (Op1Reg);
|
|
||||||
break;
|
|
||||||
case Instruction::Mul: {
|
|
||||||
unsigned MulOpcode = I.getType ()->isSigned () ? V8::SMULrr : V8::UMULrr;
|
|
||||||
BuildMI (BB, MulOpcode, 2, ResultReg).addReg (Op0Reg).addReg (Op1Reg);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
visitInstruction (I);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (getClass (I.getType ())) {
|
|
||||||
case cByte:
|
|
||||||
if (I.getType ()->isSigned ()) { // add byte
|
|
||||||
BuildMI (BB, V8::ANDri, 2, DestReg).addReg (ResultReg).addZImm (0xff);
|
|
||||||
} else { // add ubyte
|
|
||||||
unsigned TmpReg = makeAnotherReg (I.getType ());
|
|
||||||
BuildMI (BB, V8::SLLri, 2, TmpReg).addReg (ResultReg).addZImm (24);
|
|
||||||
BuildMI (BB, V8::SRAri, 2, DestReg).addReg (TmpReg).addZImm (24);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case cShort:
|
|
||||||
if (I.getType ()->isSigned ()) { // add short
|
|
||||||
unsigned TmpReg = makeAnotherReg (I.getType ());
|
|
||||||
BuildMI (BB, V8::SLLri, 2, TmpReg).addReg (ResultReg).addZImm (16);
|
|
||||||
BuildMI (BB, V8::SRAri, 2, DestReg).addReg (TmpReg).addZImm (16);
|
|
||||||
} else { // add ushort
|
|
||||||
unsigned TmpReg = makeAnotherReg (I.getType ());
|
|
||||||
BuildMI (BB, V8::SLLri, 2, TmpReg).addReg (ResultReg).addZImm (16);
|
|
||||||
BuildMI (BB, V8::SRLri, 2, DestReg).addReg (TmpReg).addZImm (16);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case cInt:
|
|
||||||
BuildMI (BB, V8::ORrr, 2, DestReg).addReg (V8::G0).addReg (ResultReg);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
visitInstruction (I);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// LowerUnknownIntrinsicFunctionCalls - This performs a prepass over the
|
|
||||||
/// function, lowering any calls to unknown intrinsic functions into the
|
|
||||||
/// equivalent LLVM code.
|
|
||||||
void V8ISel::LowerUnknownIntrinsicFunctionCalls(Function &F) {
|
|
||||||
for (Function::iterator BB = F.begin(), E = F.end(); BB != E; ++BB)
|
|
||||||
for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; )
|
|
||||||
if (CallInst *CI = dyn_cast<CallInst>(I++))
|
|
||||||
if (Function *F = CI->getCalledFunction())
|
|
||||||
switch (F->getIntrinsicID()) {
|
|
||||||
case Intrinsic::not_intrinsic: break;
|
|
||||||
default:
|
|
||||||
// All other intrinsic calls we must lower.
|
|
||||||
Instruction *Before = CI->getPrev();
|
|
||||||
TM.getIntrinsicLowering().LowerIntrinsicCall(CI);
|
|
||||||
if (Before) { // Move iterator to instruction after call
|
|
||||||
I = Before; ++I;
|
|
||||||
} else {
|
|
||||||
I = BB->begin();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void V8ISel::visitIntrinsicCall(Intrinsic::ID ID, CallInst &CI) {
|
|
||||||
unsigned TmpReg1, TmpReg2;
|
|
||||||
switch (ID) {
|
|
||||||
default: assert(0 && "Intrinsic not supported!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
##===- lib/Target/SparcV8/Makefile -------------------------*- Makefile -*-===##
|
|
||||||
#
|
|
||||||
# The LLVM Compiler Infrastructure
|
|
||||||
#
|
|
||||||
# This file was developed by the LLVM research group and is distributed under
|
|
||||||
# the University of Illinois Open Source License. See LICENSE.TXT for details.
|
|
||||||
#
|
|
||||||
##===----------------------------------------------------------------------===##
|
|
||||||
LEVEL = ../../..
|
|
||||||
LIBRARYNAME = sparcv8
|
|
||||||
include $(LEVEL)/Makefile.common
|
|
||||||
|
|
||||||
TDFILES := $(wildcard $(SourceDir)/*.td) $(SourceDir)/../Target.td
|
|
||||||
TDFILE := $(SourceDir)/SparcV8.td
|
|
||||||
|
|
||||||
# Make sure that tblgen is run, first thing.
|
|
||||||
$(SourceDepend): SparcV8GenRegisterInfo.h.inc SparcV8GenRegisterNames.inc \
|
|
||||||
SparcV8GenRegisterInfo.inc SparcV8GenInstrNames.inc \
|
|
||||||
SparcV8GenInstrInfo.inc SparcV8GenInstrSelector.inc
|
|
||||||
|
|
||||||
SparcV8GenRegisterNames.inc:: $(TDFILES) $(TBLGEN)
|
|
||||||
@echo "Building SparcV8.td register names with tblgen"
|
|
||||||
$(VERB) $(TBLGEN) -I $(BUILD_SRC_DIR) $(TDFILE) -gen-register-enums -o $@
|
|
||||||
|
|
||||||
SparcV8GenRegisterInfo.h.inc:: $(TDFILES) $(TBLGEN)
|
|
||||||
@echo "Building SparcV8.td register information header with tblgen"
|
|
||||||
$(VERB) $(TBLGEN) -I $(BUILD_SRC_DIR) $(TDFILE) -gen-register-desc-header -o $@
|
|
||||||
|
|
||||||
SparcV8GenRegisterInfo.inc:: $(TDFILES) $(TBLGEN)
|
|
||||||
@echo "Building SparcV8.td register information implementation with tblgen"
|
|
||||||
$(VERB) $(TBLGEN) -I $(BUILD_SRC_DIR) $(TDFILE) -gen-register-desc -o $@
|
|
||||||
|
|
||||||
SparcV8GenInstrNames.inc:: $(TDFILES) $(TBLGEN)
|
|
||||||
@echo "Building SparcV8.td instruction names with tblgen"
|
|
||||||
$(VERB) $(TBLGEN) -I $(BUILD_SRC_DIR) $(TDFILE) -gen-instr-enums -o $@
|
|
||||||
|
|
||||||
SparcV8GenInstrInfo.inc:: $(TDFILES) $(TBLGEN)
|
|
||||||
@echo "Building SparcV8.td instruction information with tblgen"
|
|
||||||
$(VERB) $(TBLGEN) -I $(BUILD_SRC_DIR) $(TDFILE) -gen-instr-desc -o $@
|
|
||||||
|
|
||||||
SparcV8GenInstrSelector.inc:: $(TDFILES) $(TBLGEN)
|
|
||||||
@echo "Building SparcV8.td instruction selector with tblgen"
|
|
||||||
$(VERB) $(TBLGEN) -I $(BUILD_SRC_DIR) $(TDFILE) -gen-instr-selector -o $@
|
|
||||||
|
|
||||||
clean::
|
|
||||||
$(VERB) rm -f *.inc
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
|
|
||||||
SparcV8 backend skeleton
|
|
||||||
------------------------
|
|
||||||
|
|
||||||
This directory will house a 32-bit SPARC V8 backend employing a expander-based
|
|
||||||
instruction selector. Watch this space for more news coming soon!
|
|
||||||
|
|
||||||
$Date$
|
|
||||||
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
//===-- SparcV8.h - Top-level interface for SparcV8 representation -*- C++ -*-//
|
|
||||||
//
|
|
||||||
// The LLVM Compiler Infrastructure
|
|
||||||
//
|
|
||||||
// This file was developed by the LLVM research group and is distributed under
|
|
||||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
// This file contains the entry points for global functions defined in the LLVM
|
|
||||||
// SparcV8 back-end.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#ifndef TARGET_SPARCV8_H
|
|
||||||
#define TARGET_SPARCV8_H
|
|
||||||
|
|
||||||
#include <iosfwd>
|
|
||||||
|
|
||||||
namespace llvm {
|
|
||||||
|
|
||||||
class FunctionPass;
|
|
||||||
class TargetMachine;
|
|
||||||
|
|
||||||
FunctionPass *createSparcV8SimpleInstructionSelector(TargetMachine &TM);
|
|
||||||
FunctionPass *createSparcV8CodePrinterPass(std::ostream &OS,
|
|
||||||
TargetMachine &TM);
|
|
||||||
|
|
||||||
} // end namespace llvm;
|
|
||||||
|
|
||||||
// Defines symbolic names for SparcV8 registers. This defines a mapping from
|
|
||||||
// register name to register number.
|
|
||||||
//
|
|
||||||
#include "SparcV8GenRegisterNames.inc"
|
|
||||||
|
|
||||||
// Defines symbolic names for the SparcV8 instructions.
|
|
||||||
//
|
|
||||||
#include "SparcV8GenInstrNames.inc"
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
//===- SparcV8.td - Describe the SparcV8 Target Machine ---------*- C++ -*-===//
|
|
||||||
//
|
|
||||||
// The LLVM Compiler Infrastructure
|
|
||||||
//
|
|
||||||
// This file was developed by the LLVM research group and is distributed under
|
|
||||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
// Get the target-independent interfaces which we are implementing...
|
|
||||||
//
|
|
||||||
include "../Target.td"
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// Register File Description
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
include "SparcV8RegisterInfo.td"
|
|
||||||
include "SparcV8InstrInfo.td"
|
|
||||||
|
|
||||||
def SparcV8InstrInfo : InstrInfo {
|
|
||||||
let PHIInst = PHI;
|
|
||||||
}
|
|
||||||
|
|
||||||
def SparcV8 : Target {
|
|
||||||
// Pointers are 32-bits in size.
|
|
||||||
let PointerType = i32;
|
|
||||||
|
|
||||||
// According to the Mach-O Runtime ABI, these regs are nonvolatile across
|
|
||||||
// calls:
|
|
||||||
let CalleeSavedRegisters = [];
|
|
||||||
|
|
||||||
// Pull in Instruction Info:
|
|
||||||
let InstructionSet = SparcV8InstrInfo;
|
|
||||||
}
|
|
||||||
@@ -1,529 +0,0 @@
|
|||||||
//===-- SparcV8AsmPrinter.cpp - SparcV8 LLVM assembly writer --------------===//
|
|
||||||
//
|
|
||||||
// The LLVM Compiler Infrastructure
|
|
||||||
//
|
|
||||||
// This file was developed by the LLVM research group and is distributed under
|
|
||||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
// This file contains a printer that converts from our internal representation
|
|
||||||
// of machine-dependent LLVM code to GAS-format Sparc V8 assembly language.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "SparcV8.h"
|
|
||||||
#include "SparcV8InstrInfo.h"
|
|
||||||
#include "llvm/Constants.h"
|
|
||||||
#include "llvm/DerivedTypes.h"
|
|
||||||
#include "llvm/Module.h"
|
|
||||||
#include "llvm/Assembly/Writer.h"
|
|
||||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
|
||||||
#include "llvm/CodeGen/MachineConstantPool.h"
|
|
||||||
#include "llvm/CodeGen/MachineInstr.h"
|
|
||||||
#include "llvm/Target/TargetMachine.h"
|
|
||||||
#include "llvm/Support/Mangler.h"
|
|
||||||
#include "Support/Statistic.h"
|
|
||||||
#include "Support/StringExtras.h"
|
|
||||||
#include "Support/CommandLine.h"
|
|
||||||
#include <cctype>
|
|
||||||
using namespace llvm;
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
Statistic<> EmittedInsts("asm-printer", "Number of machine instrs printed");
|
|
||||||
|
|
||||||
struct V8Printer : public MachineFunctionPass {
|
|
||||||
/// Output stream on which we're printing assembly code.
|
|
||||||
///
|
|
||||||
std::ostream &O;
|
|
||||||
|
|
||||||
/// Target machine description which we query for reg. names, data
|
|
||||||
/// layout, etc.
|
|
||||||
///
|
|
||||||
TargetMachine &TM;
|
|
||||||
|
|
||||||
/// Name-mangler for global names.
|
|
||||||
///
|
|
||||||
Mangler *Mang;
|
|
||||||
|
|
||||||
V8Printer(std::ostream &o, TargetMachine &tm) : O(o), TM(tm) { }
|
|
||||||
|
|
||||||
/// We name each basic block in a Function with a unique number, so
|
|
||||||
/// that we can consistently refer to them later. This is cleared
|
|
||||||
/// at the beginning of each call to runOnMachineFunction().
|
|
||||||
///
|
|
||||||
typedef std::map<const Value *, unsigned> ValueMapTy;
|
|
||||||
ValueMapTy NumberForBB;
|
|
||||||
|
|
||||||
/// Cache of mangled name for current function. This is
|
|
||||||
/// recalculated at the beginning of each call to
|
|
||||||
/// runOnMachineFunction().
|
|
||||||
///
|
|
||||||
std::string CurrentFnName;
|
|
||||||
|
|
||||||
virtual const char *getPassName() const {
|
|
||||||
return "SparcV8 Assembly Printer";
|
|
||||||
}
|
|
||||||
|
|
||||||
void emitConstantValueOnly(const Constant *CV);
|
|
||||||
void emitGlobalConstant(const Constant *CV);
|
|
||||||
void printConstantPool(MachineConstantPool *MCP);
|
|
||||||
void printOperand(const MachineOperand &MI);
|
|
||||||
void printMachineInstruction(const MachineInstr *MI);
|
|
||||||
bool runOnMachineFunction(MachineFunction &F);
|
|
||||||
bool doInitialization(Module &M);
|
|
||||||
bool doFinalization(Module &M);
|
|
||||||
};
|
|
||||||
} // end of anonymous namespace
|
|
||||||
|
|
||||||
/// createSparcV8CodePrinterPass - Returns a pass that prints the SparcV8
|
|
||||||
/// assembly code for a MachineFunction to the given output stream,
|
|
||||||
/// using the given target machine description. This should work
|
|
||||||
/// regardless of whether the function is in SSA form.
|
|
||||||
///
|
|
||||||
FunctionPass *llvm::createSparcV8CodePrinterPass (std::ostream &o,
|
|
||||||
TargetMachine &tm) {
|
|
||||||
return new V8Printer(o, tm);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// toOctal - Convert the low order bits of X into an octal digit.
|
|
||||||
///
|
|
||||||
static inline char toOctal(int X) {
|
|
||||||
return (X&7)+'0';
|
|
||||||
}
|
|
||||||
|
|
||||||
/// getAsCString - Return the specified array as a C compatible
|
|
||||||
/// string, only if the predicate isStringCompatible is true.
|
|
||||||
///
|
|
||||||
static void printAsCString(std::ostream &O, const ConstantArray *CVA) {
|
|
||||||
assert(CVA->isString() && "Array is not string compatible!");
|
|
||||||
|
|
||||||
O << "\"";
|
|
||||||
for (unsigned i = 0; i != CVA->getNumOperands(); ++i) {
|
|
||||||
unsigned char C = cast<ConstantInt>(CVA->getOperand(i))->getRawValue();
|
|
||||||
|
|
||||||
if (C == '"') {
|
|
||||||
O << "\\\"";
|
|
||||||
} else if (C == '\\') {
|
|
||||||
O << "\\\\";
|
|
||||||
} else if (isprint(C)) {
|
|
||||||
O << C;
|
|
||||||
} else {
|
|
||||||
switch(C) {
|
|
||||||
case '\b': O << "\\b"; break;
|
|
||||||
case '\f': O << "\\f"; break;
|
|
||||||
case '\n': O << "\\n"; break;
|
|
||||||
case '\r': O << "\\r"; break;
|
|
||||||
case '\t': O << "\\t"; break;
|
|
||||||
default:
|
|
||||||
O << '\\';
|
|
||||||
O << toOctal(C >> 6);
|
|
||||||
O << toOctal(C >> 3);
|
|
||||||
O << toOctal(C >> 0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
O << "\"";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Print out the specified constant, without a storage class. Only the
|
|
||||||
// constants valid in constant expressions can occur here.
|
|
||||||
void V8Printer::emitConstantValueOnly(const Constant *CV) {
|
|
||||||
if (CV->isNullValue())
|
|
||||||
O << "0";
|
|
||||||
else if (const ConstantBool *CB = dyn_cast<ConstantBool>(CV)) {
|
|
||||||
assert(CB == ConstantBool::True);
|
|
||||||
O << "1";
|
|
||||||
} else if (const ConstantSInt *CI = dyn_cast<ConstantSInt>(CV))
|
|
||||||
if (((CI->getValue() << 32) >> 32) == CI->getValue())
|
|
||||||
O << CI->getValue();
|
|
||||||
else
|
|
||||||
O << (unsigned long long)CI->getValue();
|
|
||||||
else if (const ConstantUInt *CI = dyn_cast<ConstantUInt>(CV))
|
|
||||||
O << CI->getValue();
|
|
||||||
else if (const ConstantPointerRef *CPR = dyn_cast<ConstantPointerRef>(CV))
|
|
||||||
// This is a constant address for a global variable or function. Use the
|
|
||||||
// name of the variable or function as the address value.
|
|
||||||
O << Mang->getValueName(CPR->getValue());
|
|
||||||
else if (const ConstantExpr *CE = dyn_cast<ConstantExpr>(CV)) {
|
|
||||||
const TargetData &TD = TM.getTargetData();
|
|
||||||
switch(CE->getOpcode()) {
|
|
||||||
case Instruction::GetElementPtr: {
|
|
||||||
// generate a symbolic expression for the byte address
|
|
||||||
const Constant *ptrVal = CE->getOperand(0);
|
|
||||||
std::vector<Value*> idxVec(CE->op_begin()+1, CE->op_end());
|
|
||||||
if (unsigned Offset = TD.getIndexedOffset(ptrVal->getType(), idxVec)) {
|
|
||||||
O << "(";
|
|
||||||
emitConstantValueOnly(ptrVal);
|
|
||||||
O << ") + " << Offset;
|
|
||||||
} else {
|
|
||||||
emitConstantValueOnly(ptrVal);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case Instruction::Cast: {
|
|
||||||
// Support only non-converting or widening casts for now, that is, ones
|
|
||||||
// that do not involve a change in value. This assertion is really gross,
|
|
||||||
// and may not even be a complete check.
|
|
||||||
Constant *Op = CE->getOperand(0);
|
|
||||||
const Type *OpTy = Op->getType(), *Ty = CE->getType();
|
|
||||||
|
|
||||||
// Pointers on ILP32 machines can be losslessly converted back and
|
|
||||||
// forth into 32-bit or wider integers, regardless of signedness.
|
|
||||||
assert(((isa<PointerType>(OpTy)
|
|
||||||
&& (Ty == Type::LongTy || Ty == Type::ULongTy
|
|
||||||
|| Ty == Type::IntTy || Ty == Type::UIntTy))
|
|
||||||
|| (isa<PointerType>(Ty)
|
|
||||||
&& (OpTy == Type::LongTy || OpTy == Type::ULongTy
|
|
||||||
|| OpTy == Type::IntTy || OpTy == Type::UIntTy))
|
|
||||||
|| (((TD.getTypeSize(Ty) >= TD.getTypeSize(OpTy))
|
|
||||||
&& OpTy->isLosslesslyConvertibleTo(Ty))))
|
|
||||||
&& "FIXME: Don't yet support this kind of constant cast expr");
|
|
||||||
O << "(";
|
|
||||||
emitConstantValueOnly(Op);
|
|
||||||
O << ")";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case Instruction::Add:
|
|
||||||
O << "(";
|
|
||||||
emitConstantValueOnly(CE->getOperand(0));
|
|
||||||
O << ") + (";
|
|
||||||
emitConstantValueOnly(CE->getOperand(1));
|
|
||||||
O << ")";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
assert(0 && "Unsupported operator!");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
assert(0 && "Unknown constant value!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Print a constant value or values, with the appropriate storage class as a
|
|
||||||
// prefix.
|
|
||||||
void V8Printer::emitGlobalConstant(const Constant *CV) {
|
|
||||||
const TargetData &TD = TM.getTargetData();
|
|
||||||
|
|
||||||
if (CV->isNullValue()) {
|
|
||||||
O << "\t.zero\t " << TD.getTypeSize(CV->getType()) << "\n";
|
|
||||||
return;
|
|
||||||
} else if (const ConstantArray *CVA = dyn_cast<ConstantArray>(CV)) {
|
|
||||||
if (CVA->isString()) {
|
|
||||||
O << "\t.ascii\t";
|
|
||||||
printAsCString(O, CVA);
|
|
||||||
O << "\n";
|
|
||||||
} else { // Not a string. Print the values in successive locations
|
|
||||||
const std::vector<Use> &constValues = CVA->getValues();
|
|
||||||
for (unsigned i=0; i < constValues.size(); i++)
|
|
||||||
emitGlobalConstant(cast<Constant>(constValues[i].get()));
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
} else if (const ConstantStruct *CVS = dyn_cast<ConstantStruct>(CV)) {
|
|
||||||
// Print the fields in successive locations. Pad to align if needed!
|
|
||||||
const StructLayout *cvsLayout = TD.getStructLayout(CVS->getType());
|
|
||||||
const std::vector<Use>& constValues = CVS->getValues();
|
|
||||||
unsigned sizeSoFar = 0;
|
|
||||||
for (unsigned i=0, N = constValues.size(); i < N; i++) {
|
|
||||||
const Constant* field = cast<Constant>(constValues[i].get());
|
|
||||||
|
|
||||||
// Check if padding is needed and insert one or more 0s.
|
|
||||||
unsigned fieldSize = TD.getTypeSize(field->getType());
|
|
||||||
unsigned padSize = ((i == N-1? cvsLayout->StructSize
|
|
||||||
: cvsLayout->MemberOffsets[i+1])
|
|
||||||
- cvsLayout->MemberOffsets[i]) - fieldSize;
|
|
||||||
sizeSoFar += fieldSize + padSize;
|
|
||||||
|
|
||||||
// Now print the actual field value
|
|
||||||
emitGlobalConstant(field);
|
|
||||||
|
|
||||||
// Insert the field padding unless it's zero bytes...
|
|
||||||
if (padSize)
|
|
||||||
O << "\t.zero\t " << padSize << "\n";
|
|
||||||
}
|
|
||||||
assert(sizeSoFar == cvsLayout->StructSize &&
|
|
||||||
"Layout of constant struct may be incorrect!");
|
|
||||||
return;
|
|
||||||
} else if (const ConstantFP *CFP = dyn_cast<ConstantFP>(CV)) {
|
|
||||||
// FP Constants are printed as integer constants to avoid losing
|
|
||||||
// precision...
|
|
||||||
double Val = CFP->getValue();
|
|
||||||
switch (CFP->getType()->getPrimitiveID()) {
|
|
||||||
default: assert(0 && "Unknown floating point type!");
|
|
||||||
case Type::FloatTyID: {
|
|
||||||
union FU { // Abide by C TBAA rules
|
|
||||||
float FVal;
|
|
||||||
unsigned UVal;
|
|
||||||
} U;
|
|
||||||
U.FVal = Val;
|
|
||||||
O << ".long\t" << U.UVal << "\t! float " << Val << "\n";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case Type::DoubleTyID: {
|
|
||||||
union DU { // Abide by C TBAA rules
|
|
||||||
double FVal;
|
|
||||||
uint64_t UVal;
|
|
||||||
} U;
|
|
||||||
U.FVal = Val;
|
|
||||||
O << ".quad\t" << U.UVal << "\t! double " << Val << "\n";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const Type *type = CV->getType();
|
|
||||||
O << "\t";
|
|
||||||
switch (type->getPrimitiveID()) {
|
|
||||||
case Type::BoolTyID: case Type::UByteTyID: case Type::SByteTyID:
|
|
||||||
O << ".byte";
|
|
||||||
break;
|
|
||||||
case Type::UShortTyID: case Type::ShortTyID:
|
|
||||||
O << ".word";
|
|
||||||
break;
|
|
||||||
case Type::FloatTyID: case Type::PointerTyID:
|
|
||||||
case Type::UIntTyID: case Type::IntTyID:
|
|
||||||
O << ".long";
|
|
||||||
break;
|
|
||||||
case Type::DoubleTyID:
|
|
||||||
case Type::ULongTyID: case Type::LongTyID:
|
|
||||||
O << ".quad";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
assert (0 && "Can't handle printing this type of thing");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
O << "\t";
|
|
||||||
emitConstantValueOnly(CV);
|
|
||||||
O << "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
/// printConstantPool - Print to the current output stream assembly
|
|
||||||
/// representations of the constants in the constant pool MCP. This is
|
|
||||||
/// used to print out constants which have been "spilled to memory" by
|
|
||||||
/// the code generator.
|
|
||||||
///
|
|
||||||
void V8Printer::printConstantPool(MachineConstantPool *MCP) {
|
|
||||||
const std::vector<Constant*> &CP = MCP->getConstants();
|
|
||||||
const TargetData &TD = TM.getTargetData();
|
|
||||||
|
|
||||||
if (CP.empty()) return;
|
|
||||||
|
|
||||||
for (unsigned i = 0, e = CP.size(); i != e; ++i) {
|
|
||||||
O << "\t.section .rodata\n";
|
|
||||||
O << "\t.align " << (unsigned)TD.getTypeAlignment(CP[i]->getType())
|
|
||||||
<< "\n";
|
|
||||||
O << ".CPI" << CurrentFnName << "_" << i << ":\t\t\t\t\t!"
|
|
||||||
<< *CP[i] << "\n";
|
|
||||||
emitGlobalConstant(CP[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// runOnMachineFunction - This uses the printMachineInstruction()
|
|
||||||
/// method to print assembly for each instruction.
|
|
||||||
///
|
|
||||||
bool V8Printer::runOnMachineFunction(MachineFunction &MF) {
|
|
||||||
// BBNumber is used here so that a given Printer will never give two
|
|
||||||
// BBs the same name. (If you have a better way, please let me know!)
|
|
||||||
static unsigned BBNumber = 0;
|
|
||||||
|
|
||||||
O << "\n\n";
|
|
||||||
// What's my mangled name?
|
|
||||||
CurrentFnName = Mang->getValueName(MF.getFunction());
|
|
||||||
|
|
||||||
// Print out constants referenced by the function
|
|
||||||
printConstantPool(MF.getConstantPool());
|
|
||||||
|
|
||||||
// Print out labels for the function.
|
|
||||||
O << "\t.text\n";
|
|
||||||
O << "\t.align 16\n";
|
|
||||||
O << "\t.globl\t" << CurrentFnName << "\n";
|
|
||||||
O << "\t.type\t" << CurrentFnName << ", #function\n";
|
|
||||||
O << CurrentFnName << ":\n";
|
|
||||||
|
|
||||||
// Number each basic block so that we can consistently refer to them
|
|
||||||
// in PC-relative references.
|
|
||||||
NumberForBB.clear();
|
|
||||||
for (MachineFunction::const_iterator I = MF.begin(), E = MF.end();
|
|
||||||
I != E; ++I) {
|
|
||||||
NumberForBB[I->getBasicBlock()] = BBNumber++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Print out code for the function.
|
|
||||||
for (MachineFunction::const_iterator I = MF.begin(), E = MF.end();
|
|
||||||
I != E; ++I) {
|
|
||||||
// Print a label for the basic block.
|
|
||||||
O << ".LBB" << NumberForBB[I->getBasicBlock()] << ":\t! "
|
|
||||||
<< I->getBasicBlock()->getName() << "\n";
|
|
||||||
for (MachineBasicBlock::const_iterator II = I->begin(), E = I->end();
|
|
||||||
II != E; ++II) {
|
|
||||||
// Print the assembly for the instruction.
|
|
||||||
O << "\t";
|
|
||||||
printMachineInstruction(II);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// We didn't modify anything.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
std::string LowercaseString (const std::string &S) {
|
|
||||||
std::string result (S);
|
|
||||||
for (unsigned i = 0; i < S.length(); ++i)
|
|
||||||
if (isupper (result[i]))
|
|
||||||
result[i] = tolower(result[i]);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void V8Printer::printOperand(const MachineOperand &MO) {
|
|
||||||
const MRegisterInfo &RI = *TM.getRegisterInfo();
|
|
||||||
switch (MO.getType()) {
|
|
||||||
case MachineOperand::MO_VirtualRegister:
|
|
||||||
if (Value *V = MO.getVRegValueOrNull()) {
|
|
||||||
O << "<" << V->getName() << ">";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// FALLTHROUGH
|
|
||||||
case MachineOperand::MO_MachineRegister:
|
|
||||||
if (MRegisterInfo::isPhysicalRegister(MO.getReg()))
|
|
||||||
O << "%" << LowercaseString (RI.get(MO.getReg()).Name);
|
|
||||||
else
|
|
||||||
O << "%reg" << MO.getReg();
|
|
||||||
return;
|
|
||||||
|
|
||||||
case MachineOperand::MO_SignExtendedImmed:
|
|
||||||
case MachineOperand::MO_UnextendedImmed:
|
|
||||||
O << (int)MO.getImmedValue();
|
|
||||||
return;
|
|
||||||
case MachineOperand::MO_PCRelativeDisp: {
|
|
||||||
ValueMapTy::const_iterator i = NumberForBB.find(MO.getVRegValue());
|
|
||||||
assert (i != NumberForBB.end()
|
|
||||||
&& "Could not find a BB in the NumberForBB map!");
|
|
||||||
O << ".LBB" << i->second << " ! PC rel: " << MO.getVRegValue()->getName();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case MachineOperand::MO_GlobalAddress:
|
|
||||||
O << Mang->getValueName(MO.getGlobal());
|
|
||||||
return;
|
|
||||||
case MachineOperand::MO_ExternalSymbol:
|
|
||||||
O << MO.getSymbolName();
|
|
||||||
return;
|
|
||||||
default:
|
|
||||||
O << "<unknown operand type>"; return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// printMachineInstruction -- Print out a single SparcV8 LLVM instruction
|
|
||||||
/// MI in GAS syntax to the current output stream.
|
|
||||||
///
|
|
||||||
void V8Printer::printMachineInstruction(const MachineInstr *MI) {
|
|
||||||
unsigned Opcode = MI->getOpcode();
|
|
||||||
const TargetInstrInfo &TII = TM.getInstrInfo();
|
|
||||||
const TargetInstrDescriptor &Desc = TII.get(Opcode);
|
|
||||||
O << Desc.Name << " ";
|
|
||||||
|
|
||||||
// print non-immediate, non-register-def operands
|
|
||||||
// then print immediate operands
|
|
||||||
// then print register-def operands.
|
|
||||||
std::vector<MachineOperand> print_order;
|
|
||||||
for (unsigned i = 0; i < MI->getNumOperands (); ++i)
|
|
||||||
if (!(MI->getOperand (i).isImmediate ()
|
|
||||||
|| (MI->getOperand (i).isRegister ()
|
|
||||||
&& MI->getOperand (i).isDef ())))
|
|
||||||
print_order.push_back (MI->getOperand (i));
|
|
||||||
for (unsigned i = 0; i < MI->getNumOperands (); ++i)
|
|
||||||
if (MI->getOperand (i).isImmediate ())
|
|
||||||
print_order.push_back (MI->getOperand (i));
|
|
||||||
for (unsigned i = 0; i < MI->getNumOperands (); ++i)
|
|
||||||
if (MI->getOperand (i).isRegister () && MI->getOperand (i).isDef ())
|
|
||||||
print_order.push_back (MI->getOperand (i));
|
|
||||||
for (unsigned i = 0, e = print_order.size (); i != e; ++i) {
|
|
||||||
printOperand (print_order[i]);
|
|
||||||
if (i != (print_order.size () - 1))
|
|
||||||
O << ", ";
|
|
||||||
}
|
|
||||||
O << "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
bool V8Printer::doInitialization(Module &M) {
|
|
||||||
Mang = new Mangler(M);
|
|
||||||
return false; // success
|
|
||||||
}
|
|
||||||
|
|
||||||
// SwitchSection - Switch to the specified section of the executable if we are
|
|
||||||
// not already in it!
|
|
||||||
//
|
|
||||||
static void SwitchSection(std::ostream &OS, std::string &CurSection,
|
|
||||||
const char *NewSection) {
|
|
||||||
if (CurSection != NewSection) {
|
|
||||||
CurSection = NewSection;
|
|
||||||
if (!CurSection.empty())
|
|
||||||
OS << "\t" << NewSection << "\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool V8Printer::doFinalization(Module &M) {
|
|
||||||
const TargetData &TD = TM.getTargetData();
|
|
||||||
std::string CurSection;
|
|
||||||
|
|
||||||
// Print out module-level global variables here.
|
|
||||||
for (Module::const_giterator I = M.gbegin(), E = M.gend(); I != E; ++I)
|
|
||||||
if (I->hasInitializer()) { // External global require no code
|
|
||||||
O << "\n\n";
|
|
||||||
std::string name = Mang->getValueName(I);
|
|
||||||
Constant *C = I->getInitializer();
|
|
||||||
unsigned Size = TD.getTypeSize(C->getType());
|
|
||||||
unsigned Align = TD.getTypeAlignment(C->getType());
|
|
||||||
|
|
||||||
if (C->isNullValue() &&
|
|
||||||
(I->hasLinkOnceLinkage() || I->hasInternalLinkage() ||
|
|
||||||
I->hasWeakLinkage() /* FIXME: Verify correct */)) {
|
|
||||||
SwitchSection(O, CurSection, ".data");
|
|
||||||
if (I->hasInternalLinkage())
|
|
||||||
O << "\t.local " << name << "\n";
|
|
||||||
|
|
||||||
O << "\t.comm " << name << "," << TD.getTypeSize(C->getType())
|
|
||||||
<< "," << (unsigned)TD.getTypeAlignment(C->getType());
|
|
||||||
O << "\t\t! ";
|
|
||||||
WriteAsOperand(O, I, true, true, &M);
|
|
||||||
O << "\n";
|
|
||||||
} else {
|
|
||||||
switch (I->getLinkage()) {
|
|
||||||
case GlobalValue::LinkOnceLinkage:
|
|
||||||
case GlobalValue::WeakLinkage: // FIXME: Verify correct for weak.
|
|
||||||
// Nonnull linkonce -> weak
|
|
||||||
O << "\t.weak " << name << "\n";
|
|
||||||
SwitchSection(O, CurSection, "");
|
|
||||||
O << "\t.section\t.llvm.linkonce.d." << name << ",\"aw\",@progbits\n";
|
|
||||||
break;
|
|
||||||
|
|
||||||
case GlobalValue::AppendingLinkage:
|
|
||||||
// FIXME: appending linkage variables should go into a section of
|
|
||||||
// their name or something. For now, just emit them as external.
|
|
||||||
case GlobalValue::ExternalLinkage:
|
|
||||||
// If external or appending, declare as a global symbol
|
|
||||||
O << "\t.globl " << name << "\n";
|
|
||||||
// FALL THROUGH
|
|
||||||
case GlobalValue::InternalLinkage:
|
|
||||||
if (C->isNullValue())
|
|
||||||
SwitchSection(O, CurSection, ".bss");
|
|
||||||
else
|
|
||||||
SwitchSection(O, CurSection, ".data");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
O << "\t.align " << Align << "\n";
|
|
||||||
O << "\t.type " << name << ",#object\n";
|
|
||||||
O << "\t.size " << name << "," << Size << "\n";
|
|
||||||
O << name << ":\t\t\t\t! ";
|
|
||||||
WriteAsOperand(O, I, true, true, &M);
|
|
||||||
O << " = ";
|
|
||||||
WriteAsOperand(O, C, false, false, &M);
|
|
||||||
O << "\n";
|
|
||||||
emitGlobalConstant(C);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
delete Mang;
|
|
||||||
return false; // success
|
|
||||||
}
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
//===-- SparcV8CodeEmitter.cpp - JIT Code Emitter for SparcV8 -----*- C++ -*-=//
|
|
||||||
//
|
|
||||||
// The LLVM Compiler Infrastructure
|
|
||||||
//
|
|
||||||
// This file was developed by the LLVM research group and is distributed under
|
|
||||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "SparcV8TargetMachine.h"
|
|
||||||
|
|
||||||
namespace llvm {
|
|
||||||
|
|
||||||
/// addPassesToEmitMachineCode - Add passes to the specified pass manager to get
|
|
||||||
/// machine code emitted. This uses a MachineCodeEmitter object to handle
|
|
||||||
/// actually outputting the machine code and resolving things like the address
|
|
||||||
/// of functions. This method should returns true if machine code emission is
|
|
||||||
/// not supported.
|
|
||||||
///
|
|
||||||
bool SparcV8TargetMachine::addPassesToEmitMachineCode(FunctionPassManager &PM,
|
|
||||||
MachineCodeEmitter &MCE) {
|
|
||||||
return true;
|
|
||||||
// It should go something like this:
|
|
||||||
// PM.add(new Emitter(MCE)); // Machine code emitter pass for SparcV8
|
|
||||||
// Delete machine code for this function after emitting it:
|
|
||||||
// PM.add(createMachineCodeDeleter());
|
|
||||||
}
|
|
||||||
|
|
||||||
void *SparcV8JITInfo::getJITStubForFunction(Function *F,
|
|
||||||
MachineCodeEmitter &MCE) {
|
|
||||||
assert (0 && "SparcV8JITInfo::getJITStubForFunction not implemented");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SparcV8JITInfo::replaceMachineCodeForFunction (void *Old, void *New) {
|
|
||||||
assert (0 && "SparcV8JITInfo::replaceMachineCodeForFunction not implemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
} // end llvm namespace
|
|
||||||
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
//===- SparcV8InstrInfo.cpp - SparcV8 Instruction Information ---*- C++ -*-===//
|
|
||||||
//
|
|
||||||
// The LLVM Compiler Infrastructure
|
|
||||||
//
|
|
||||||
// This file was developed by the LLVM research group and is distributed under
|
|
||||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
// This file contains the SparcV8 implementation of the TargetInstrInfo class.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "SparcV8InstrInfo.h"
|
|
||||||
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
|
||||||
#include "SparcV8GenInstrInfo.inc"
|
|
||||||
using namespace llvm;
|
|
||||||
|
|
||||||
SparcV8InstrInfo::SparcV8InstrInfo()
|
|
||||||
: TargetInstrInfo(SparcV8Insts, sizeof(SparcV8Insts)/sizeof(SparcV8Insts[0])){
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
//===- SparcV8InstrInfo.h - SparcV8 Instruction Information -----*- C++ -*-===//
|
|
||||||
//
|
|
||||||
// The LLVM Compiler Infrastructure
|
|
||||||
//
|
|
||||||
// This file was developed by the LLVM research group and is distributed under
|
|
||||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
// This file contains the SparcV8 implementation of the TargetInstrInfo class.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#ifndef SPARCV8INSTRUCTIONINFO_H
|
|
||||||
#define SPARCV8INSTRUCTIONINFO_H
|
|
||||||
|
|
||||||
#include "llvm/Target/TargetInstrInfo.h"
|
|
||||||
#include "SparcV8RegisterInfo.h"
|
|
||||||
|
|
||||||
namespace llvm {
|
|
||||||
|
|
||||||
class SparcV8InstrInfo : public TargetInstrInfo {
|
|
||||||
const SparcV8RegisterInfo RI;
|
|
||||||
public:
|
|
||||||
SparcV8InstrInfo();
|
|
||||||
|
|
||||||
/// getRegisterInfo - TargetInstrInfo is a superset of MRegister info. As
|
|
||||||
/// such, whenever a client has an instance of instruction info, it should
|
|
||||||
/// always be able to get register info as well (through this method).
|
|
||||||
///
|
|
||||||
virtual const MRegisterInfo &getRegisterInfo() const { return RI; }
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,97 +0,0 @@
|
|||||||
//===- SparcV8Instrs.td - Target Description for SparcV8 Target -----------===//
|
|
||||||
//
|
|
||||||
// The LLVM Compiler Infrastructure
|
|
||||||
//
|
|
||||||
// This file was developed by the LLVM research group and is distributed under
|
|
||||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
// This file describes the SparcV8 instructions in TableGen format.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// Instruction format superclass
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
class InstV8 : Instruction { // SparcV8 instruction baseline
|
|
||||||
field bits<32> Inst;
|
|
||||||
|
|
||||||
let Namespace = "V8";
|
|
||||||
|
|
||||||
bits<2> op;
|
|
||||||
let Inst{31-30} = op; // Top two bits are the 'op' field
|
|
||||||
|
|
||||||
// Bit attributes specific to SparcV8 instructions
|
|
||||||
bit isPasi = 0; // Does this instruction affect an alternate addr space?
|
|
||||||
bit isPrivileged = 0; // Is this a privileged instruction?
|
|
||||||
}
|
|
||||||
|
|
||||||
include "SparcV8InstrInfo_F2.td"
|
|
||||||
include "SparcV8InstrInfo_F3.td"
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// Instructions
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
// Pseudo instructions.
|
|
||||||
def PHI : InstV8 {
|
|
||||||
let Name = "PHI";
|
|
||||||
}
|
|
||||||
def ADJCALLSTACKDOWN : InstV8 {
|
|
||||||
let Name = "ADJCALLSTACKDOWN";
|
|
||||||
}
|
|
||||||
def ADJCALLSTACKUP : InstV8 {
|
|
||||||
let Name = "ADJCALLSTACKUP";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Section A.3 - Synthetic Instructions, p. 85
|
|
||||||
let isReturn = 1, isTerminator = 1, simm13 = 8 in
|
|
||||||
def RET : F3_2<2, 0b111000, "ret">;
|
|
||||||
let isReturn = 1, isTerminator = 1, simm13 = 8 in
|
|
||||||
def RETL : F3_2<2, 0b111000, "retl">;
|
|
||||||
|
|
||||||
// Section B.9 - SETHI Instruction, p. 104
|
|
||||||
def SETHIi: F2_1<0b100, "sethi">;
|
|
||||||
|
|
||||||
// Section B.11 - Logical Instructions, p. 106
|
|
||||||
def ANDri : F3_2<2, 0b000001, "and">;
|
|
||||||
def ORrr : F3_1<2, 0b000010, "or">;
|
|
||||||
def ORri : F3_2<2, 0b000010, "or">;
|
|
||||||
|
|
||||||
// Section B.12 - Shift Instructions, p. 107
|
|
||||||
def SLLri : F3_1<2, 0b100101, "sll">;
|
|
||||||
def SRLri : F3_1<2, 0b100110, "srl">;
|
|
||||||
def SRAri : F3_1<2, 0b100111, "sra">;
|
|
||||||
|
|
||||||
// Section B.13 - Add Instructions, p. 108
|
|
||||||
def ADDrr : F3_1<2, 0b000000, "add">;
|
|
||||||
|
|
||||||
// Section B.15 - Subtract Instructions, p. 110
|
|
||||||
def SUBrr : F3_1<2, 0b000100, "sub">;
|
|
||||||
|
|
||||||
// Section B.18 - Multiply Instructions, p. 113
|
|
||||||
def UMULrr : F3_1<2, 0b001010, "umul">;
|
|
||||||
def SMULrr : F3_1<2, 0b001011, "smul">;
|
|
||||||
|
|
||||||
// Section B.20 - SAVE and RESTORE, p. 117
|
|
||||||
def SAVErr : F3_1<2, 0b111100, "save">; // save r, r, r
|
|
||||||
def SAVEri : F3_2<2, 0b111100, "save">; // save r, i, r
|
|
||||||
def RESTORErr : F3_1<2, 0b111101, "restore">; // restore r, r, r
|
|
||||||
def RESTOREri : F3_2<2, 0b111101, "restore">; // restore r, i, r
|
|
||||||
|
|
||||||
// Section B.24 - Call and Link, p. 125
|
|
||||||
// This is the only Format 1 instruction
|
|
||||||
def CALL : InstV8 {
|
|
||||||
bits<30> disp;
|
|
||||||
let op = 1;
|
|
||||||
let Inst{29-0} = disp;
|
|
||||||
let Name = "call";
|
|
||||||
let isCall = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Section B.25 - Jump and Link, p. 126
|
|
||||||
def JMPLrr : F3_1<2, 0b111000, "jmpl">; // jmpl [rs1+rs2], rd
|
|
||||||
def JMPLri : F3_2<2, 0b111000, "jmpl">; // jmpl [rs1+imm], rd
|
|
||||||
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
//===- SparcV8Instrs_F2.td - Format 2 instructions: SparcV8 Target --------===//
|
|
||||||
//
|
|
||||||
// The LLVM Compiler Infrastructure
|
|
||||||
//
|
|
||||||
// This file was developed by the LLVM research group and is distributed under
|
|
||||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
// Format #2 instruction classes in the SparcV8
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
class F2 : InstV8 { // Format 2 instructions
|
|
||||||
bits<3> op2;
|
|
||||||
bits<22> imm22;
|
|
||||||
let op = 0; // op = 0
|
|
||||||
let Inst{24-22} = op2;
|
|
||||||
let Inst{21-0} = imm22;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Specific F2 classes: SparcV8 manual, page 44
|
|
||||||
//
|
|
||||||
class F2_1<bits<3> op2Val, string name> : F2 {
|
|
||||||
bits<5> rd;
|
|
||||||
bits<22> imm;
|
|
||||||
|
|
||||||
let op2 = op2Val;
|
|
||||||
let Name = name;
|
|
||||||
|
|
||||||
let Inst{29-25} = rd;
|
|
||||||
}
|
|
||||||
|
|
||||||
class F2_2<bits<4> condVal, bits<3> op2Val, string name> : F2 {
|
|
||||||
bits<4> cond;
|
|
||||||
bit annul = 0; // currently unused
|
|
||||||
|
|
||||||
let cond = condVal;
|
|
||||||
let op2 = op2Val;
|
|
||||||
let Name = name;
|
|
||||||
|
|
||||||
let Inst{29} = annul;
|
|
||||||
let Inst{28-25} = cond;
|
|
||||||
}
|
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
//===- SparcV8Instrs_F3.td - Format 3 Instructions: SparcV8 Target --------===//
|
|
||||||
//
|
|
||||||
// The LLVM Compiler Infrastructure
|
|
||||||
//
|
|
||||||
// This file was developed by the LLVM research group and is distributed under
|
|
||||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
// Format #3 instruction classes in the SparcV8
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
class F3 : InstV8 {
|
|
||||||
bits<5> rd;
|
|
||||||
bits<6> op3;
|
|
||||||
bits<5> rs1;
|
|
||||||
let op{1} = 1; // Op = 2 or 3
|
|
||||||
let Inst{29-25} = rd;
|
|
||||||
let Inst{24-19} = op3;
|
|
||||||
let Inst{18-14} = rs1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Specific F3 classes: SparcV8 manual, page 44
|
|
||||||
//
|
|
||||||
class F3_1<bits<2> opVal, bits<6> op3val, string name> : F3 {
|
|
||||||
bits<8> asi;
|
|
||||||
bits<5> rs2;
|
|
||||||
|
|
||||||
let op = opVal;
|
|
||||||
let op3 = op3val;
|
|
||||||
let Name = name;
|
|
||||||
|
|
||||||
let Inst{13} = 0; // i field = 0
|
|
||||||
let Inst{12-5} = asi; // address space identifier
|
|
||||||
let Inst{4-0} = rs2;
|
|
||||||
}
|
|
||||||
|
|
||||||
class F3_2<bits<2> opVal, bits<6> op3val, string name> : F3 {
|
|
||||||
bits<13> simm13;
|
|
||||||
|
|
||||||
let op = opVal;
|
|
||||||
let op3 = op3val;
|
|
||||||
let Name = name;
|
|
||||||
|
|
||||||
let Inst{13} = 1; // i field = 1
|
|
||||||
let Inst{12-0} = simm13;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
class F3_3<bits<2> opVal, bits<6> op3val, bits<9> opfVal, string name>
|
|
||||||
: F3_rs1rs2 {
|
|
||||||
bits<5> rs2;
|
|
||||||
|
|
||||||
let op = opVal;
|
|
||||||
let op3 = op3val;
|
|
||||||
let Name = name;
|
|
||||||
|
|
||||||
let Inst{13-5} = opfVal;
|
|
||||||
let Inst{4-0} = rs2;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
//===- SparcV8JITInfo.h - SparcV8 impl. of the JIT interface ----*- C++ -*-===//
|
|
||||||
//
|
|
||||||
// The LLVM Compiler Infrastructure
|
|
||||||
//
|
|
||||||
// This file was developed by the LLVM research group and is distributed under
|
|
||||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
// This file contains the SparcV8 implementation of the TargetJITInfo class.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#ifndef SPARCV8JITINFO_H
|
|
||||||
#define SPARCV8JITINFO_H
|
|
||||||
|
|
||||||
#include "llvm/Target/TargetJITInfo.h"
|
|
||||||
|
|
||||||
namespace llvm {
|
|
||||||
class TargetMachine;
|
|
||||||
class IntrinsicLowering;
|
|
||||||
|
|
||||||
class SparcV8JITInfo : public TargetJITInfo {
|
|
||||||
TargetMachine &TM;
|
|
||||||
public:
|
|
||||||
SparcV8JITInfo(TargetMachine &tm) : TM(tm) {}
|
|
||||||
|
|
||||||
/// addPassesToJITCompile - Add passes to the specified pass manager to
|
|
||||||
/// implement a fast dynamic compiler for this target. Return true if this
|
|
||||||
/// is not supported for this target.
|
|
||||||
///
|
|
||||||
virtual void addPassesToJITCompile(FunctionPassManager &PM);
|
|
||||||
|
|
||||||
/// replaceMachineCodeForFunction - Make it so that calling the function
|
|
||||||
/// whose machine code is at OLD turns into a call to NEW, perhaps by
|
|
||||||
/// overwriting OLD with a branch to NEW. This is used for self-modifying
|
|
||||||
/// code.
|
|
||||||
///
|
|
||||||
virtual void replaceMachineCodeForFunction(void *Old, void *New);
|
|
||||||
|
|
||||||
/// getJITStubForFunction - Create or return a stub for the specified
|
|
||||||
/// function. This stub acts just like the specified function, except that
|
|
||||||
/// it allows the "address" of the function to be taken without having to
|
|
||||||
/// generate code for it.
|
|
||||||
virtual void *getJITStubForFunction(Function *F, MachineCodeEmitter &MCE);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,106 +0,0 @@
|
|||||||
//===- SparcV8RegisterInfo.cpp - SparcV8 Register Information ---*- C++ -*-===//
|
|
||||||
//
|
|
||||||
// The LLVM Compiler Infrastructure
|
|
||||||
//
|
|
||||||
// This file was developed by the LLVM research group and is distributed under
|
|
||||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
// This file contains the SparcV8 implementation of the MRegisterInfo class.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "SparcV8.h"
|
|
||||||
#include "SparcV8RegisterInfo.h"
|
|
||||||
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
|
||||||
#include "llvm/CodeGen/MachineFunction.h"
|
|
||||||
#include "llvm/Type.h"
|
|
||||||
#include "Support/STLExtras.h"
|
|
||||||
using namespace llvm;
|
|
||||||
|
|
||||||
SparcV8RegisterInfo::SparcV8RegisterInfo()
|
|
||||||
: SparcV8GenRegisterInfo(V8::ADJCALLSTACKDOWN,
|
|
||||||
V8::ADJCALLSTACKUP) {}
|
|
||||||
|
|
||||||
int SparcV8RegisterInfo::storeRegToStackSlot(
|
|
||||||
MachineBasicBlock &MBB,
|
|
||||||
MachineBasicBlock::iterator MBBI,
|
|
||||||
unsigned SrcReg, int FrameIdx,
|
|
||||||
const TargetRegisterClass *RC) const
|
|
||||||
{
|
|
||||||
abort();
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int SparcV8RegisterInfo::loadRegFromStackSlot(
|
|
||||||
MachineBasicBlock &MBB,
|
|
||||||
MachineBasicBlock::iterator MBBI,
|
|
||||||
unsigned DestReg, int FrameIdx,
|
|
||||||
const TargetRegisterClass *RC) const
|
|
||||||
{
|
|
||||||
abort();
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int SparcV8RegisterInfo::copyRegToReg(MachineBasicBlock &MBB,
|
|
||||||
MachineBasicBlock::iterator MBBI,
|
|
||||||
unsigned DestReg, unsigned SrcReg,
|
|
||||||
const TargetRegisterClass *RC) const {
|
|
||||||
abort();
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SparcV8RegisterInfo::
|
|
||||||
eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB,
|
|
||||||
MachineBasicBlock::iterator I) const {
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
SparcV8RegisterInfo::eliminateFrameIndex(MachineFunction &MF,
|
|
||||||
MachineBasicBlock::iterator II) const {
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SparcV8RegisterInfo::
|
|
||||||
processFunctionBeforeFrameFinalized(MachineFunction &MF) const {}
|
|
||||||
|
|
||||||
void SparcV8RegisterInfo::emitPrologue(MachineFunction &MF) const {
|
|
||||||
MachineBasicBlock &MBB = MF.front();
|
|
||||||
|
|
||||||
// Eventually this should emit the correct save instruction based on the
|
|
||||||
// number of bytes in the frame. For now we just hardcode it.
|
|
||||||
BuildMI(MBB, MBB.begin(), V8::SAVEri, 2, V8::SP).addImm(-112).addReg(V8::SP);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SparcV8RegisterInfo::emitEpilogue(MachineFunction &MF,
|
|
||||||
MachineBasicBlock &MBB) const {
|
|
||||||
MachineBasicBlock::iterator MBBI = prior(MBB.end());
|
|
||||||
assert(MBBI->getOpcode() == V8::RETL &&
|
|
||||||
"Can only put epilog before 'retl' instruction!");
|
|
||||||
BuildMI(MBB, MBBI, V8::RESTORErr, 2, V8::G0).addReg(V8::G0).addReg(V8::G0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#include "SparcV8GenRegisterInfo.inc"
|
|
||||||
|
|
||||||
const TargetRegisterClass*
|
|
||||||
SparcV8RegisterInfo::getRegClassForType(const Type* Ty) const {
|
|
||||||
switch (Ty->getPrimitiveID()) {
|
|
||||||
case Type::FloatTyID: return &FPRegsInstance;
|
|
||||||
case Type::DoubleTyID: return &DFPRegsInstance;
|
|
||||||
case Type::LongTyID:
|
|
||||||
case Type::ULongTyID: assert(0 && "Long values can't fit in registers!");
|
|
||||||
default: assert(0 && "Invalid type to getClass!");
|
|
||||||
case Type::BoolTyID:
|
|
||||||
case Type::SByteTyID:
|
|
||||||
case Type::UByteTyID:
|
|
||||||
case Type::ShortTyID:
|
|
||||||
case Type::UShortTyID:
|
|
||||||
case Type::IntTyID:
|
|
||||||
case Type::UIntTyID:
|
|
||||||
case Type::PointerTyID: return &IntRegsInstance;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
//===- SparcV8RegisterInfo.h - SparcV8 Register Information Impl -*- C++ -*-==//
|
|
||||||
//
|
|
||||||
// The LLVM Compiler Infrastructure
|
|
||||||
//
|
|
||||||
// This file was developed by the LLVM research group and is distributed under
|
|
||||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
// This file contains the SparcV8 implementation of the MRegisterInfo class.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#ifndef SPARCV8REGISTERINFO_H
|
|
||||||
#define SPARCV8REGISTERINFO_H
|
|
||||||
|
|
||||||
#include "llvm/Target/MRegisterInfo.h"
|
|
||||||
#include "SparcV8GenRegisterInfo.h.inc"
|
|
||||||
|
|
||||||
namespace llvm {
|
|
||||||
|
|
||||||
class Type;
|
|
||||||
|
|
||||||
struct SparcV8RegisterInfo : public SparcV8GenRegisterInfo {
|
|
||||||
SparcV8RegisterInfo();
|
|
||||||
const TargetRegisterClass* getRegClassForType(const Type* Ty) const;
|
|
||||||
|
|
||||||
/// Code Generation virtual methods...
|
|
||||||
int storeRegToStackSlot(MachineBasicBlock &MBB,
|
|
||||||
MachineBasicBlock::iterator MBBI,
|
|
||||||
unsigned SrcReg, int FrameIndex,
|
|
||||||
const TargetRegisterClass *RC) const;
|
|
||||||
|
|
||||||
int loadRegFromStackSlot(MachineBasicBlock &MBB,
|
|
||||||
MachineBasicBlock::iterator MBBI,
|
|
||||||
unsigned DestReg, int FrameIndex,
|
|
||||||
const TargetRegisterClass *RC) const;
|
|
||||||
|
|
||||||
int copyRegToReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
|
|
||||||
unsigned DestReg, unsigned SrcReg,
|
|
||||||
const TargetRegisterClass *RC) const;
|
|
||||||
|
|
||||||
void eliminateCallFramePseudoInstr(MachineFunction &MF,
|
|
||||||
MachineBasicBlock &MBB,
|
|
||||||
MachineBasicBlock::iterator I) const;
|
|
||||||
|
|
||||||
void eliminateFrameIndex(MachineFunction &MF,
|
|
||||||
MachineBasicBlock::iterator II) const;
|
|
||||||
|
|
||||||
void processFunctionBeforeFrameFinalized(MachineFunction &MF) const;
|
|
||||||
|
|
||||||
void emitPrologue(MachineFunction &MF) const;
|
|
||||||
void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // end namespace llvm
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,101 +0,0 @@
|
|||||||
//===- SparcV8Reg.td - Describe the SparcV8 Register File -------*- C++ -*-===//
|
|
||||||
//
|
|
||||||
// The LLVM Compiler Infrastructure
|
|
||||||
//
|
|
||||||
// This file was developed by the LLVM research group and is distributed under
|
|
||||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
// Declarations that describe the SparcV8 register file
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
// Registers are identified with 5-bit ID numbers.
|
|
||||||
// Ri - 32-bit integer registers
|
|
||||||
class Ri<bits<5> num> : Register {
|
|
||||||
field bits<5> Num = num;
|
|
||||||
}
|
|
||||||
// Rf - 32-bit floating-point registers
|
|
||||||
class Rf<bits<5> num> : Register {
|
|
||||||
field bits<5> Num = num;
|
|
||||||
}
|
|
||||||
// Rd - Slots in the FP register file for 64-bit floating-point values.
|
|
||||||
class Rd<bits<5> num> : Register {
|
|
||||||
field bits<5> Num = num;
|
|
||||||
}
|
|
||||||
|
|
||||||
let Namespace = "V8" in {
|
|
||||||
def G0 : Ri< 0>; def G1 : Ri< 1>; def G2 : Ri< 2>; def G3 : Ri< 3>;
|
|
||||||
def G4 : Ri< 4>; def G5 : Ri< 5>; def G6 : Ri< 6>; def G7 : Ri< 7>;
|
|
||||||
def O0 : Ri< 8>; def O1 : Ri< 9>; def O2 : Ri<10>; def O3 : Ri<11>;
|
|
||||||
def O4 : Ri<12>; def O5 : Ri<13>; def O6 : Ri<14>; def O7 : Ri<15>;
|
|
||||||
def L0 : Ri<16>; def L1 : Ri<17>; def L2 : Ri<18>; def L3 : Ri<19>;
|
|
||||||
def L4 : Ri<20>; def L5 : Ri<21>; def L6 : Ri<22>; def L7 : Ri<23>;
|
|
||||||
def I0 : Ri<24>; def I1 : Ri<25>; def I2 : Ri<26>; def I3 : Ri<27>;
|
|
||||||
def I4 : Ri<28>; def I5 : Ri<29>; def I6 : Ri<30>; def I7 : Ri<31>;
|
|
||||||
|
|
||||||
// Standard register aliases.
|
|
||||||
def SP : Ri<14>; def FP : Ri<30>;
|
|
||||||
|
|
||||||
// Floating-point registers:
|
|
||||||
def F0 : Rf< 0>; def F1 : Rf< 1>; def F2 : Rf< 2>; def F3 : Rf< 3>;
|
|
||||||
def F4 : Rf< 4>; def F5 : Rf< 5>; def F6 : Rf< 6>; def F7 : Rf< 7>;
|
|
||||||
def F8 : Rf< 8>; def F9 : Rf< 9>; def F10 : Rf<10>; def F11 : Rf<11>;
|
|
||||||
def F12 : Rf<12>; def F13 : Rf<13>; def F14 : Rf<14>; def F15 : Rf<15>;
|
|
||||||
def F16 : Rf<16>; def F17 : Rf<17>; def F18 : Rf<18>; def F19 : Rf<19>;
|
|
||||||
def F20 : Rf<20>; def F21 : Rf<21>; def F22 : Rf<22>; def F23 : Rf<23>;
|
|
||||||
def F24 : Rf<24>; def F25 : Rf<25>; def F26 : Rf<26>; def F27 : Rf<27>;
|
|
||||||
def F28 : Rf<28>; def F29 : Rf<29>; def F30 : Rf<30>; def F31 : Rf<31>;
|
|
||||||
|
|
||||||
// Aliases of the F* registers used to hold 64-bit fp values (doubles).
|
|
||||||
def D0 : Rd< 0>; def D1 : Rd< 2>; def D2 : Rd< 4>; def D3 : Rd< 6>;
|
|
||||||
def D4 : Rd< 8>; def D5 : Rd<10>; def D6 : Rd<12>; def D7 : Rd<14>;
|
|
||||||
def D8 : Rd<16>; def D9 : Rd<18>; def D10 : Rd<20>; def D11 : Rd<22>;
|
|
||||||
def D12 : Rd<24>; def D13 : Rd<26>; def D14 : Rd<28>; def D15 : Rd<30>;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Register classes.
|
|
||||||
//
|
|
||||||
// FIXME: the register order should be defined in terms of the preferred
|
|
||||||
// allocation order...
|
|
||||||
//
|
|
||||||
def IntRegs : RegisterClass<i32, 8, [G1, G2, G3, G4, G5, G6, G7,
|
|
||||||
O0, O1, O2, O3, O4, O5, O7,
|
|
||||||
L0, L1, L2, L3, L4, L5, L6, L7,
|
|
||||||
I0, I1, I2, I3, I4, I5,
|
|
||||||
// Non-allocatable regs
|
|
||||||
O6, I6, I7, G0]> {
|
|
||||||
let Methods = [{
|
|
||||||
iterator allocation_order_end(MachineFunction &MF) const {
|
|
||||||
return end()-4; // Don't allocate special registers
|
|
||||||
}
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
|
|
||||||
def FPRegs : RegisterClass<f32, 4, [F0, F1, F2, F3, F4, F5, F6, F7, F8,
|
|
||||||
F9, F10, F11, F12, F13, F14, F15, F16, F17, F18, F19, F20, F21, F22,
|
|
||||||
F23, F24, F25, F26, F27, F28, F29, F30, F31]>;
|
|
||||||
|
|
||||||
def DFPRegs : RegisterClass<f64, 8, [D0, D1, D2, D3, D4, D5, D6, D7,
|
|
||||||
D8, D9, D10, D11, D12, D13, D14, D15]>;
|
|
||||||
|
|
||||||
// Tell the register file generator that the double-fp pseudo-registers
|
|
||||||
// alias the registers used for single-fp values.
|
|
||||||
def : RegisterAliases<D0, [F0, F1]>;
|
|
||||||
def : RegisterAliases<D1, [F2, F3]>;
|
|
||||||
def : RegisterAliases<D2, [F4, F5]>;
|
|
||||||
def : RegisterAliases<D3, [F6, F7]>;
|
|
||||||
def : RegisterAliases<D4, [F8, F9]>;
|
|
||||||
def : RegisterAliases<D5, [F10, F11]>;
|
|
||||||
def : RegisterAliases<D6, [F12, F13]>;
|
|
||||||
def : RegisterAliases<D7, [F14, F15]>;
|
|
||||||
def : RegisterAliases<D8, [F16, F17]>;
|
|
||||||
def : RegisterAliases<D9, [F18, F19]>;
|
|
||||||
def : RegisterAliases<D10, [F20, F21]>;
|
|
||||||
def : RegisterAliases<D11, [F22, F23]>;
|
|
||||||
def : RegisterAliases<D12, [F24, F25]>;
|
|
||||||
def : RegisterAliases<D13, [F26, F27]>;
|
|
||||||
def : RegisterAliases<D14, [F28, F29]>;
|
|
||||||
def : RegisterAliases<D15, [F30, F31]>;
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
//===-- SparcV8TargetMachine.cpp - Define TargetMachine for SparcV8 -------===//
|
|
||||||
//
|
|
||||||
// The LLVM Compiler Infrastructure
|
|
||||||
//
|
|
||||||
// This file was developed by the LLVM research group and is distributed under
|
|
||||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "SparcV8TargetMachine.h"
|
|
||||||
#include "SparcV8.h"
|
|
||||||
#include "llvm/Module.h"
|
|
||||||
#include "llvm/PassManager.h"
|
|
||||||
#include "llvm/Target/TargetMachineImpls.h"
|
|
||||||
#include "llvm/CodeGen/MachineFunction.h"
|
|
||||||
#include "llvm/CodeGen/Passes.h"
|
|
||||||
using namespace llvm;
|
|
||||||
|
|
||||||
// allocateSparcV8TargetMachine - Allocate and return a subclass of
|
|
||||||
// TargetMachine that implements the SparcV8 backend.
|
|
||||||
//
|
|
||||||
TargetMachine *llvm::allocateSparcV8TargetMachine(const Module &M,
|
|
||||||
IntrinsicLowering *IL) {
|
|
||||||
return new SparcV8TargetMachine(M, IL);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// SparcV8TargetMachine ctor - Create an ILP32 architecture model
|
|
||||||
///
|
|
||||||
SparcV8TargetMachine::SparcV8TargetMachine(const Module &M,
|
|
||||||
IntrinsicLowering *IL)
|
|
||||||
: TargetMachine("SparcV8", IL, true, 4, 4, 4, 4, 4),
|
|
||||||
FrameInfo(TargetFrameInfo::StackGrowsDown, 8, 4), JITInfo(*this) {
|
|
||||||
}
|
|
||||||
|
|
||||||
/// addPassesToEmitAssembly - Add passes to the specified pass manager
|
|
||||||
/// to implement a static compiler for this target.
|
|
||||||
///
|
|
||||||
bool SparcV8TargetMachine::addPassesToEmitAssembly(PassManager &PM,
|
|
||||||
std::ostream &Out) {
|
|
||||||
PM.add(createSparcV8SimpleInstructionSelector(*this));
|
|
||||||
|
|
||||||
// Print machine instructions as they were initially generated.
|
|
||||||
if (PrintMachineCode)
|
|
||||||
PM.add(createMachineFunctionPrinterPass(&std::cerr));
|
|
||||||
|
|
||||||
PM.add(createRegisterAllocator());
|
|
||||||
PM.add(createPrologEpilogCodeInserter());
|
|
||||||
|
|
||||||
// Print machine instructions after register allocation and prolog/epilog
|
|
||||||
// insertion.
|
|
||||||
if (PrintMachineCode)
|
|
||||||
PM.add(createMachineFunctionPrinterPass(&std::cerr));
|
|
||||||
|
|
||||||
// Output assembly language.
|
|
||||||
PM.add(createSparcV8CodePrinterPass(Out, *this));
|
|
||||||
|
|
||||||
// Delete the MachineInstrs we generated, since they're no longer needed.
|
|
||||||
PM.add(createMachineCodeDeleter());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// addPassesToJITCompile - Add passes to the specified pass manager to
|
|
||||||
/// implement a fast dynamic compiler for this target.
|
|
||||||
///
|
|
||||||
void SparcV8JITInfo::addPassesToJITCompile(FunctionPassManager &PM) {
|
|
||||||
// <insert instruction selector passes here>
|
|
||||||
PM.add(createRegisterAllocator());
|
|
||||||
PM.add(createPrologEpilogCodeInserter());
|
|
||||||
}
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
//===-- SparcV8TargetMachine.h - Define TargetMachine for SparcV8 -*- C++ -*-=//
|
|
||||||
//
|
|
||||||
// The LLVM Compiler Infrastructure
|
|
||||||
//
|
|
||||||
// This file was developed by the LLVM research group and is distributed under
|
|
||||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
// This file declares the SparcV8 specific subclass of TargetMachine.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#ifndef SPARCV8TARGETMACHINE_H
|
|
||||||
#define SPARCV8TARGETMACHINE_H
|
|
||||||
|
|
||||||
#include "llvm/Target/TargetMachine.h"
|
|
||||||
#include "llvm/Target/TargetFrameInfo.h"
|
|
||||||
#include "llvm/PassManager.h"
|
|
||||||
#include "SparcV8InstrInfo.h"
|
|
||||||
#include "SparcV8JITInfo.h"
|
|
||||||
|
|
||||||
namespace llvm {
|
|
||||||
|
|
||||||
class IntrinsicLowering;
|
|
||||||
|
|
||||||
class SparcV8TargetMachine : public TargetMachine {
|
|
||||||
SparcV8InstrInfo InstrInfo;
|
|
||||||
TargetFrameInfo FrameInfo;
|
|
||||||
SparcV8JITInfo JITInfo;
|
|
||||||
public:
|
|
||||||
SparcV8TargetMachine(const Module &M, IntrinsicLowering *IL);
|
|
||||||
|
|
||||||
virtual const SparcV8InstrInfo &getInstrInfo() const { return InstrInfo; }
|
|
||||||
virtual const TargetFrameInfo &getFrameInfo() const { return FrameInfo; }
|
|
||||||
virtual const MRegisterInfo *getRegisterInfo() const {
|
|
||||||
return &InstrInfo.getRegisterInfo();
|
|
||||||
}
|
|
||||||
virtual TargetJITInfo *getJITInfo() {
|
|
||||||
return &JITInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual const TargetSchedInfo &getSchedInfo() const { abort(); }
|
|
||||||
virtual const TargetRegInfo &getRegInfo() const { abort(); }
|
|
||||||
|
|
||||||
/// addPassesToEmitMachineCode - Add passes to the specified pass manager to
|
|
||||||
/// get machine code emitted. This uses a MachineCodeEmitter object to handle
|
|
||||||
/// actually outputting the machine code and resolving things like the address
|
|
||||||
/// of functions. This method should returns true if machine code emission is
|
|
||||||
/// not supported.
|
|
||||||
///
|
|
||||||
virtual bool addPassesToEmitMachineCode(FunctionPassManager &PM,
|
|
||||||
MachineCodeEmitter &MCE);
|
|
||||||
|
|
||||||
virtual bool addPassesToEmitAssembly(PassManager &PM, std::ostream &Out);
|
|
||||||
};
|
|
||||||
|
|
||||||
} // end namespace llvm
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1156,12 +1156,18 @@ CreateCodeForFixedSizeAlloca(const TargetMachine& target,
|
|||||||
unsigned numElements,
|
unsigned numElements,
|
||||||
std::vector<MachineInstr*>& getMvec)
|
std::vector<MachineInstr*>& getMvec)
|
||||||
{
|
{
|
||||||
assert(tsize > 0 && "Illegal (zero) type size for alloca");
|
|
||||||
assert(result && result->getParent() &&
|
assert(result && result->getParent() &&
|
||||||
"Result value is not part of a function?");
|
"Result value is not part of a function?");
|
||||||
Function *F = result->getParent()->getParent();
|
Function *F = result->getParent()->getParent();
|
||||||
MachineFunction &mcInfo = MachineFunction::get(F);
|
MachineFunction &mcInfo = MachineFunction::get(F);
|
||||||
|
|
||||||
|
// If the alloca is of zero bytes (which is perfectly legal) we bump it up to
|
||||||
|
// one byte. This is unnecessary, but I really don't want to break any
|
||||||
|
// fragile logic in this code. FIXME.
|
||||||
|
if (tsize == 0)
|
||||||
|
tsize = 1;
|
||||||
|
|
||||||
|
|
||||||
// Put the variable in the dynamically sized area of the frame if either:
|
// Put the variable in the dynamically sized area of the frame if either:
|
||||||
// (a) The offset is too large to use as an immediate in load/stores
|
// (a) The offset is too large to use as an immediate in load/stores
|
||||||
// (check LDX because all load/stores have the same-size immed. field).
|
// (check LDX because all load/stores have the same-size immed. field).
|
||||||
|
|||||||
@@ -1422,6 +1422,8 @@ static bool isSafeToFoldLoadIntoInstruction(LoadInst &LI, Instruction &User) {
|
|||||||
// really use alias analysis here, but for now we just do something simple.
|
// really use alias analysis here, but for now we just do something simple.
|
||||||
for (++It; It != BasicBlock::iterator(&User); ++It) {
|
for (++It; It != BasicBlock::iterator(&User); ++It) {
|
||||||
switch (It->getOpcode()) {
|
switch (It->getOpcode()) {
|
||||||
|
case Instruction::Malloc:
|
||||||
|
case Instruction::Free:
|
||||||
case Instruction::Store:
|
case Instruction::Store:
|
||||||
case Instruction::Call:
|
case Instruction::Call:
|
||||||
case Instruction::Invoke:
|
case Instruction::Invoke:
|
||||||
|
|||||||
@@ -18,12 +18,16 @@
|
|||||||
#include "llvm/iTerminators.h"
|
#include "llvm/iTerminators.h"
|
||||||
#include "llvm/Module.h"
|
#include "llvm/Module.h"
|
||||||
#include "llvm/Pass.h"
|
#include "llvm/Pass.h"
|
||||||
|
#include "llvm/Analysis/Dominators.h"
|
||||||
#include "llvm/Analysis/LoopInfo.h"
|
#include "llvm/Analysis/LoopInfo.h"
|
||||||
#include "llvm/Transforms/Scalar.h"
|
#include "llvm/Transforms/Scalar.h"
|
||||||
#include "llvm/Transforms/Utils/FunctionUtils.h"
|
#include "llvm/Transforms/Utils/FunctionUtils.h"
|
||||||
|
#include "Support/Statistic.h"
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
Statistic<> NumExtracted("loop-extract", "Number of loops extracted");
|
||||||
|
|
||||||
// FIXME: This is not a function pass, but the PassManager doesn't allow
|
// FIXME: This is not a function pass, but the PassManager doesn't allow
|
||||||
// Module passes to require FunctionPasses, so we can't get loop info if we're
|
// Module passes to require FunctionPasses, so we can't get loop info if we're
|
||||||
// not a function pass.
|
// not a function pass.
|
||||||
@@ -35,8 +39,10 @@ namespace {
|
|||||||
virtual bool runOnFunction(Function &F);
|
virtual bool runOnFunction(Function &F);
|
||||||
|
|
||||||
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
|
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
|
||||||
AU.addRequired<LoopInfo>();
|
AU.addRequiredID(BreakCriticalEdgesID);
|
||||||
AU.addRequiredID(LoopSimplifyID);
|
AU.addRequiredID(LoopSimplifyID);
|
||||||
|
AU.addRequired<DominatorSet>();
|
||||||
|
AU.addRequired<LoopInfo>();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -59,6 +65,8 @@ bool LoopExtractor::runOnFunction(Function &F) {
|
|||||||
if (LI.begin() == LI.end())
|
if (LI.begin() == LI.end())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
DominatorSet &DS = getAnalysis<DominatorSet>();
|
||||||
|
|
||||||
// If there is more than one top-level loop in this function, extract all of
|
// If there is more than one top-level loop in this function, extract all of
|
||||||
// the loops.
|
// the loops.
|
||||||
bool Changed = false;
|
bool Changed = false;
|
||||||
@@ -66,7 +74,8 @@ bool LoopExtractor::runOnFunction(Function &F) {
|
|||||||
for (LoopInfo::iterator i = LI.begin(), e = LI.end(); i != e; ++i) {
|
for (LoopInfo::iterator i = LI.begin(), e = LI.end(); i != e; ++i) {
|
||||||
if (NumLoops == 0) return Changed;
|
if (NumLoops == 0) return Changed;
|
||||||
--NumLoops;
|
--NumLoops;
|
||||||
Changed |= (ExtractLoop(*i) != 0);
|
Changed |= ExtractLoop(DS, *i) != 0;
|
||||||
|
++NumExtracted;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Otherwise there is exactly one top-level loop. If this function is more
|
// Otherwise there is exactly one top-level loop. If this function is more
|
||||||
@@ -93,7 +102,8 @@ bool LoopExtractor::runOnFunction(Function &F) {
|
|||||||
if (ShouldExtractLoop) {
|
if (ShouldExtractLoop) {
|
||||||
if (NumLoops == 0) return Changed;
|
if (NumLoops == 0) return Changed;
|
||||||
--NumLoops;
|
--NumLoops;
|
||||||
Changed |= (ExtractLoop(TLL) != 0);
|
Changed |= ExtractLoop(DS, TLL) != 0;
|
||||||
|
++NumExtracted;
|
||||||
} else {
|
} else {
|
||||||
// Okay, this function is a minimal container around the specified loop.
|
// Okay, this function is a minimal container around the specified loop.
|
||||||
// If we extract the loop, we will continue to just keep extracting it
|
// If we extract the loop, we will continue to just keep extracting it
|
||||||
@@ -102,7 +112,8 @@ bool LoopExtractor::runOnFunction(Function &F) {
|
|||||||
for (Loop::iterator i = TLL->begin(), e = TLL->end(); i != e; ++i) {
|
for (Loop::iterator i = TLL->begin(), e = TLL->end(); i != e; ++i) {
|
||||||
if (NumLoops == 0) return Changed;
|
if (NumLoops == 0) return Changed;
|
||||||
--NumLoops;
|
--NumLoops;
|
||||||
Changed |= (ExtractLoop(*i) != 0);
|
Changed |= ExtractLoop(DS, *i) != 0;
|
||||||
|
++NumExtracted;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,16 +13,16 @@
|
|||||||
//
|
//
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
#include "llvm/BasicBlock.h"
|
#include "llvm/Transforms/Utils/FunctionUtils.h"
|
||||||
#include "llvm/Constants.h"
|
#include "llvm/Constants.h"
|
||||||
#include "llvm/DerivedTypes.h"
|
#include "llvm/DerivedTypes.h"
|
||||||
#include "llvm/Instructions.h"
|
#include "llvm/Instructions.h"
|
||||||
#include "llvm/Module.h"
|
#include "llvm/Module.h"
|
||||||
#include "llvm/Pass.h"
|
#include "llvm/Pass.h"
|
||||||
|
#include "llvm/Analysis/Dominators.h"
|
||||||
#include "llvm/Analysis/LoopInfo.h"
|
#include "llvm/Analysis/LoopInfo.h"
|
||||||
#include "llvm/Analysis/Verifier.h"
|
#include "llvm/Analysis/Verifier.h"
|
||||||
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
|
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
|
||||||
#include "llvm/Transforms/Utils/FunctionUtils.h"
|
|
||||||
#include "Support/Debug.h"
|
#include "Support/Debug.h"
|
||||||
#include "Support/StringExtras.h"
|
#include "Support/StringExtras.h"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
@@ -30,22 +30,13 @@
|
|||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
class CodeExtractor {
|
||||||
/// getFunctionArg - Return a pointer to F's ARGNOth argument.
|
|
||||||
///
|
|
||||||
Argument *getFunctionArg(Function *F, unsigned argno) {
|
|
||||||
Function::aiterator I = F->abegin();
|
|
||||||
std::advance(I, argno);
|
|
||||||
return I;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct CodeExtractor {
|
|
||||||
typedef std::vector<Value*> Values;
|
typedef std::vector<Value*> Values;
|
||||||
typedef std::vector<std::pair<unsigned, unsigned> > PhiValChangesTy;
|
|
||||||
typedef std::map<PHINode*, PhiValChangesTy> PhiVal2ArgTy;
|
|
||||||
PhiVal2ArgTy PhiVal2Arg;
|
|
||||||
std::set<BasicBlock*> BlocksToExtract;
|
std::set<BasicBlock*> BlocksToExtract;
|
||||||
|
DominatorSet *DS;
|
||||||
public:
|
public:
|
||||||
|
CodeExtractor(DominatorSet *ds = 0) : DS(ds) {}
|
||||||
|
|
||||||
Function *ExtractCodeRegion(const std::vector<BasicBlock*> &code);
|
Function *ExtractCodeRegion(const std::vector<BasicBlock*> &code);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -53,15 +44,9 @@ namespace {
|
|||||||
BasicBlock *newHeader,
|
BasicBlock *newHeader,
|
||||||
BasicBlock *newRootNode);
|
BasicBlock *newRootNode);
|
||||||
|
|
||||||
void processPhiNodeInputs(PHINode *Phi,
|
|
||||||
Values &inputs,
|
|
||||||
BasicBlock *newHeader,
|
|
||||||
BasicBlock *newRootNode);
|
|
||||||
|
|
||||||
void rewritePhiNodes(Function *F, BasicBlock *newFuncRoot);
|
|
||||||
|
|
||||||
Function *constructFunction(const Values &inputs,
|
Function *constructFunction(const Values &inputs,
|
||||||
const Values &outputs,
|
const Values &outputs,
|
||||||
|
BasicBlock *header,
|
||||||
BasicBlock *newRootNode, BasicBlock *newHeader,
|
BasicBlock *newRootNode, BasicBlock *newHeader,
|
||||||
Function *oldFunction, Module *M);
|
Function *oldFunction, Module *M);
|
||||||
|
|
||||||
@@ -75,95 +60,6 @@ namespace {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
void CodeExtractor::processPhiNodeInputs(PHINode *Phi,
|
|
||||||
Values &inputs,
|
|
||||||
BasicBlock *codeReplacer,
|
|
||||||
BasicBlock *newFuncRoot) {
|
|
||||||
// Separate incoming values and BasicBlocks as internal/external. We ignore
|
|
||||||
// the case where both the value and BasicBlock are internal, because we don't
|
|
||||||
// need to do a thing.
|
|
||||||
std::vector<unsigned> EValEBB;
|
|
||||||
std::vector<unsigned> EValIBB;
|
|
||||||
std::vector<unsigned> IValEBB;
|
|
||||||
|
|
||||||
for (unsigned i = 0, e = Phi->getNumIncomingValues(); i != e; ++i) {
|
|
||||||
Value *phiVal = Phi->getIncomingValue(i);
|
|
||||||
if (Instruction *Inst = dyn_cast<Instruction>(phiVal)) {
|
|
||||||
if (BlocksToExtract.count(Inst->getParent())) {
|
|
||||||
if (!BlocksToExtract.count(Phi->getIncomingBlock(i)))
|
|
||||||
IValEBB.push_back(i);
|
|
||||||
} else {
|
|
||||||
if (BlocksToExtract.count(Phi->getIncomingBlock(i)))
|
|
||||||
EValIBB.push_back(i);
|
|
||||||
else
|
|
||||||
EValEBB.push_back(i);
|
|
||||||
}
|
|
||||||
} else if (Argument *Arg = dyn_cast<Argument>(phiVal)) {
|
|
||||||
// arguments are external
|
|
||||||
if (BlocksToExtract.count(Phi->getIncomingBlock(i)))
|
|
||||||
EValIBB.push_back(i);
|
|
||||||
else
|
|
||||||
EValEBB.push_back(i);
|
|
||||||
} else {
|
|
||||||
// Globals/Constants are internal, but considered `external' if they are
|
|
||||||
// coming from an external block.
|
|
||||||
if (!BlocksToExtract.count(Phi->getIncomingBlock(i)))
|
|
||||||
EValEBB.push_back(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Both value and block are external. Need to group all of these, have an
|
|
||||||
// external phi, pass the result as an argument, and have THIS phi use that
|
|
||||||
// result.
|
|
||||||
if (EValEBB.size() > 0) {
|
|
||||||
if (EValEBB.size() == 1) {
|
|
||||||
// Now if it's coming from the newFuncRoot, it's that funky input
|
|
||||||
unsigned phiIdx = EValEBB[0];
|
|
||||||
if (!isa<Constant>(Phi->getIncomingValue(phiIdx))) {
|
|
||||||
PhiVal2Arg[Phi].push_back(std::make_pair(phiIdx, inputs.size()));
|
|
||||||
// We can just pass this value in as argument
|
|
||||||
inputs.push_back(Phi->getIncomingValue(phiIdx));
|
|
||||||
}
|
|
||||||
Phi->setIncomingBlock(phiIdx, newFuncRoot);
|
|
||||||
} else {
|
|
||||||
PHINode *externalPhi = new PHINode(Phi->getType(), "extPhi");
|
|
||||||
codeReplacer->getInstList().insert(codeReplacer->begin(), externalPhi);
|
|
||||||
for (std::vector<unsigned>::iterator i = EValEBB.begin(),
|
|
||||||
e = EValEBB.end(); i != e; ++i) {
|
|
||||||
externalPhi->addIncoming(Phi->getIncomingValue(*i),
|
|
||||||
Phi->getIncomingBlock(*i));
|
|
||||||
|
|
||||||
// We make these values invalid instead of deleting them because that
|
|
||||||
// would shift the indices of other values... The fixPhiNodes should
|
|
||||||
// clean these phi nodes up later.
|
|
||||||
Phi->setIncomingValue(*i, 0);
|
|
||||||
Phi->setIncomingBlock(*i, 0);
|
|
||||||
}
|
|
||||||
PhiVal2Arg[Phi].push_back(std::make_pair(Phi->getNumIncomingValues(),
|
|
||||||
inputs.size()));
|
|
||||||
// We can just pass this value in as argument
|
|
||||||
inputs.push_back(externalPhi);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// When the value is external, but block internal... just pass it in as
|
|
||||||
// argument, no change to phi node
|
|
||||||
for (std::vector<unsigned>::iterator i = EValIBB.begin(),
|
|
||||||
e = EValIBB.end(); i != e; ++i) {
|
|
||||||
// rewrite the phi input node to be an argument
|
|
||||||
PhiVal2Arg[Phi].push_back(std::make_pair(*i, inputs.size()));
|
|
||||||
inputs.push_back(Phi->getIncomingValue(*i));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Value internal, block external this can happen if we are extracting a part
|
|
||||||
// of a loop.
|
|
||||||
for (std::vector<unsigned>::iterator i = IValEBB.begin(),
|
|
||||||
e = IValEBB.end(); i != e; ++i) {
|
|
||||||
assert(0 && "Cannot (YET) handle internal values via external blocks");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void CodeExtractor::findInputsOutputs(Values &inputs, Values &outputs,
|
void CodeExtractor::findInputsOutputs(Values &inputs, Values &outputs,
|
||||||
BasicBlock *newHeader,
|
BasicBlock *newHeader,
|
||||||
BasicBlock *newRootNode) {
|
BasicBlock *newRootNode) {
|
||||||
@@ -173,8 +69,18 @@ void CodeExtractor::findInputsOutputs(Values &inputs, Values &outputs,
|
|||||||
for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ++I) {
|
for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ++I) {
|
||||||
// If a used value is defined outside the region, it's an input. If an
|
// If a used value is defined outside the region, it's an input. If an
|
||||||
// instruction is used outside the region, it's an output.
|
// instruction is used outside the region, it's an output.
|
||||||
if (PHINode *Phi = dyn_cast<PHINode>(I)) {
|
if (PHINode *PN = dyn_cast<PHINode>(I)) {
|
||||||
processPhiNodeInputs(Phi, inputs, newHeader, newRootNode);
|
for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i) {
|
||||||
|
Value *V = PN->getIncomingValue(i);
|
||||||
|
if (!BlocksToExtract.count(PN->getIncomingBlock(i)) &&
|
||||||
|
(isa<Instruction>(V) || isa<Argument>(V)))
|
||||||
|
inputs.push_back(V);
|
||||||
|
else if (Instruction *opI = dyn_cast<Instruction>(V)) {
|
||||||
|
if (!BlocksToExtract.count(opI->getParent()))
|
||||||
|
inputs.push_back(opI);
|
||||||
|
} else if (isa<Argument>(V))
|
||||||
|
inputs.push_back(V);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// All other instructions go through the generic input finder
|
// All other instructions go through the generic input finder
|
||||||
// Loop over the operands of each instruction (inputs)
|
// Loop over the operands of each instruction (inputs)
|
||||||
@@ -192,59 +98,26 @@ void CodeExtractor::findInputsOutputs(Values &inputs, Values &outputs,
|
|||||||
// Consider uses of this instruction (outputs)
|
// Consider uses of this instruction (outputs)
|
||||||
for (Value::use_iterator UI = I->use_begin(), E = I->use_end();
|
for (Value::use_iterator UI = I->use_begin(), E = I->use_end();
|
||||||
UI != E; ++UI)
|
UI != E; ++UI)
|
||||||
if (!BlocksToExtract.count(cast<Instruction>(*UI)->getParent()))
|
if (!BlocksToExtract.count(cast<Instruction>(*UI)->getParent())) {
|
||||||
outputs.push_back(*UI);
|
outputs.push_back(I);
|
||||||
|
break;
|
||||||
|
}
|
||||||
} // for: insts
|
} // for: insts
|
||||||
} // for: basic blocks
|
} // for: basic blocks
|
||||||
}
|
}
|
||||||
|
|
||||||
void CodeExtractor::rewritePhiNodes(Function *F,
|
|
||||||
BasicBlock *newFuncRoot) {
|
|
||||||
// Write any changes that were saved before: use function arguments as inputs
|
|
||||||
for (PhiVal2ArgTy::iterator i = PhiVal2Arg.begin(), e = PhiVal2Arg.end();
|
|
||||||
i != e; ++i) {
|
|
||||||
PHINode *phi = i->first;
|
|
||||||
PhiValChangesTy &values = i->second;
|
|
||||||
for (unsigned cIdx = 0, ce = values.size(); cIdx != ce; ++cIdx)
|
|
||||||
{
|
|
||||||
unsigned phiValueIdx = values[cIdx].first, argNum = values[cIdx].second;
|
|
||||||
if (phiValueIdx < phi->getNumIncomingValues())
|
|
||||||
phi->setIncomingValue(phiValueIdx, getFunctionArg(F, argNum));
|
|
||||||
else
|
|
||||||
phi->addIncoming(getFunctionArg(F, argNum), newFuncRoot);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete any invalid Phi node inputs that were marked as NULL previously
|
|
||||||
for (PhiVal2ArgTy::iterator i = PhiVal2Arg.begin(), e = PhiVal2Arg.end();
|
|
||||||
i != e; ++i) {
|
|
||||||
PHINode *phi = i->first;
|
|
||||||
for (unsigned idx = 0, end = phi->getNumIncomingValues(); idx != end; ++idx)
|
|
||||||
{
|
|
||||||
if (phi->getIncomingValue(idx) == 0 && phi->getIncomingBlock(idx) == 0) {
|
|
||||||
phi->removeIncomingValue(idx);
|
|
||||||
--idx;
|
|
||||||
--end;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// We are done with the saved values
|
|
||||||
PhiVal2Arg.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// constructFunction - make a function based on inputs and outputs, as follows:
|
/// constructFunction - make a function based on inputs and outputs, as follows:
|
||||||
/// f(in0, ..., inN, out0, ..., outN)
|
/// f(in0, ..., inN, out0, ..., outN)
|
||||||
///
|
///
|
||||||
Function *CodeExtractor::constructFunction(const Values &inputs,
|
Function *CodeExtractor::constructFunction(const Values &inputs,
|
||||||
const Values &outputs,
|
const Values &outputs,
|
||||||
|
BasicBlock *header,
|
||||||
BasicBlock *newRootNode,
|
BasicBlock *newRootNode,
|
||||||
BasicBlock *newHeader,
|
BasicBlock *newHeader,
|
||||||
Function *oldFunction, Module *M) {
|
Function *oldFunction,
|
||||||
|
Module *M) {
|
||||||
DEBUG(std::cerr << "inputs: " << inputs.size() << "\n");
|
DEBUG(std::cerr << "inputs: " << inputs.size() << "\n");
|
||||||
DEBUG(std::cerr << "outputs: " << outputs.size() << "\n");
|
DEBUG(std::cerr << "outputs: " << outputs.size() << "\n");
|
||||||
BasicBlock *header = *BlocksToExtract.begin();
|
|
||||||
|
|
||||||
// This function returns unsigned, outputs will go back by reference.
|
// This function returns unsigned, outputs will go back by reference.
|
||||||
Type *retTy = Type::UShortTy;
|
Type *retTy = Type::UShortTy;
|
||||||
@@ -258,18 +131,11 @@ Function *CodeExtractor::constructFunction(const Values &inputs,
|
|||||||
paramTy.push_back(value->getType());
|
paramTy.push_back(value->getType());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the types of the output values to the function's argument list, but
|
// Add the types of the output values to the function's argument list.
|
||||||
// make them pointer types for scalars
|
for (Values::const_iterator I = outputs.begin(), E = outputs.end();
|
||||||
for (Values::const_iterator i = outputs.begin(),
|
I != E; ++I) {
|
||||||
e = outputs.end(); i != e; ++i) {
|
DEBUG(std::cerr << "instr used in func: " << *I << "\n");
|
||||||
const Value *value = *i;
|
paramTy.push_back(PointerType::get((*I)->getType()));
|
||||||
DEBUG(std::cerr << "instr used in func: " << value << "\n");
|
|
||||||
const Type *valueType = value->getType();
|
|
||||||
// Convert scalar types into a pointer of that type
|
|
||||||
if (valueType->isPrimitiveType()) {
|
|
||||||
valueType = PointerType::get(valueType);
|
|
||||||
}
|
|
||||||
paramTy.push_back(valueType);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG(std::cerr << "Function type: " << retTy << " f(");
|
DEBUG(std::cerr << "Function type: " << retTy << " f(");
|
||||||
@@ -286,30 +152,37 @@ Function *CodeExtractor::constructFunction(const Values &inputs,
|
|||||||
oldFunction->getName() + "_code", M);
|
oldFunction->getName() + "_code", M);
|
||||||
newFunction->getBasicBlockList().push_back(newRootNode);
|
newFunction->getBasicBlockList().push_back(newRootNode);
|
||||||
|
|
||||||
for (unsigned i = 0, e = inputs.size(); i != e; ++i) {
|
// Create an iterator to name all of the arguments we inserted.
|
||||||
|
Function::aiterator AI = newFunction->abegin();
|
||||||
|
|
||||||
|
// Rewrite all users of the inputs in the extracted region to use the
|
||||||
|
// arguments instead.
|
||||||
|
for (unsigned i = 0, e = inputs.size(); i != e; ++i, ++AI) {
|
||||||
|
AI->setName(inputs[i]->getName());
|
||||||
std::vector<User*> Users(inputs[i]->use_begin(), inputs[i]->use_end());
|
std::vector<User*> Users(inputs[i]->use_begin(), inputs[i]->use_end());
|
||||||
for (std::vector<User*>::iterator use = Users.begin(), useE = Users.end();
|
for (std::vector<User*>::iterator use = Users.begin(), useE = Users.end();
|
||||||
use != useE; ++use)
|
use != useE; ++use)
|
||||||
if (Instruction* inst = dyn_cast<Instruction>(*use))
|
if (Instruction* inst = dyn_cast<Instruction>(*use))
|
||||||
if (BlocksToExtract.count(inst->getParent()))
|
if (BlocksToExtract.count(inst->getParent()))
|
||||||
inst->replaceUsesOfWith(inputs[i], getFunctionArg(newFunction, i));
|
inst->replaceUsesOfWith(inputs[i], AI);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set names for all of the output arguments.
|
||||||
|
for (unsigned i = 0, e = outputs.size(); i != e; ++i, ++AI)
|
||||||
|
AI->setName(outputs[i]->getName()+".out");
|
||||||
|
|
||||||
|
|
||||||
// Rewrite branches to basic blocks outside of the loop to new dummy blocks
|
// Rewrite branches to basic blocks outside of the loop to new dummy blocks
|
||||||
// within the new function. This must be done before we lose track of which
|
// within the new function. This must be done before we lose track of which
|
||||||
// blocks were originally in the code region.
|
// blocks were originally in the code region.
|
||||||
std::vector<User*> Users(header->use_begin(), header->use_end());
|
std::vector<User*> Users(header->use_begin(), header->use_end());
|
||||||
for (std::vector<User*>::iterator i = Users.begin(), e = Users.end();
|
for (unsigned i = 0, e = Users.size(); i != e; ++i)
|
||||||
i != e; ++i) {
|
// The BasicBlock which contains the branch is not in the region
|
||||||
if (BranchInst *inst = dyn_cast<BranchInst>(*i)) {
|
// modify the branch target to a new block
|
||||||
BasicBlock *BB = inst->getParent();
|
if (TerminatorInst *TI = dyn_cast<TerminatorInst>(Users[i]))
|
||||||
if (!BlocksToExtract.count(BB) && BB->getParent() == oldFunction) {
|
if (!BlocksToExtract.count(TI->getParent()) &&
|
||||||
// The BasicBlock which contains the branch is not in the region
|
TI->getParent()->getParent() == oldFunction)
|
||||||
// modify the branch target to a new block
|
TI->replaceUsesOfWith(header, newHeader);
|
||||||
inst->replaceUsesOfWith(header, newHeader);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return newFunction;
|
return newFunction;
|
||||||
}
|
}
|
||||||
@@ -333,34 +206,30 @@ void
|
|||||||
CodeExtractor::emitCallAndSwitchStatement(Function *newFunction,
|
CodeExtractor::emitCallAndSwitchStatement(Function *newFunction,
|
||||||
BasicBlock *codeReplacer,
|
BasicBlock *codeReplacer,
|
||||||
Values &inputs,
|
Values &inputs,
|
||||||
Values &outputs)
|
Values &outputs) {
|
||||||
{
|
|
||||||
// Emit a call to the new function, passing allocated memory for outputs and
|
// Emit a call to the new function, passing allocated memory for outputs and
|
||||||
// just plain inputs for non-scalars
|
// just plain inputs for non-scalars
|
||||||
std::vector<Value*> params(inputs);
|
std::vector<Value*> params(inputs);
|
||||||
|
|
||||||
for (Values::const_iterator i = outputs.begin(), e = outputs.end(); i != e;
|
// Get an iterator to the first output argument.
|
||||||
++i) {
|
Function::aiterator OutputArgBegin = newFunction->abegin();
|
||||||
Value *Output = *i;
|
std::advance(OutputArgBegin, inputs.size());
|
||||||
// Create allocas for scalar outputs
|
|
||||||
if (Output->getType()->isPrimitiveType()) {
|
|
||||||
AllocaInst *alloca =
|
|
||||||
new AllocaInst((*i)->getType(), 0, Output->getName()+".loc",
|
|
||||||
codeReplacer->getParent()->begin()->begin());
|
|
||||||
params.push_back(alloca);
|
|
||||||
|
|
||||||
LoadInst *load = new LoadInst(alloca, Output->getName()+".reload");
|
for (unsigned i = 0, e = outputs.size(); i != e; ++i) {
|
||||||
codeReplacer->getInstList().push_back(load);
|
Value *Output = outputs[i];
|
||||||
std::vector<User*> Users((*i)->use_begin(), (*i)->use_end());
|
// Create allocas for scalar outputs
|
||||||
for (std::vector<User*>::iterator use = Users.begin(), useE =Users.end();
|
AllocaInst *alloca =
|
||||||
use != useE; ++use) {
|
new AllocaInst(outputs[i]->getType(), 0, Output->getName()+".loc",
|
||||||
if (Instruction* inst = dyn_cast<Instruction>(*use)) {
|
codeReplacer->getParent()->begin()->begin());
|
||||||
if (!BlocksToExtract.count(inst->getParent()))
|
params.push_back(alloca);
|
||||||
inst->replaceUsesOfWith(*i, load);
|
|
||||||
}
|
LoadInst *load = new LoadInst(alloca, Output->getName()+".reload");
|
||||||
}
|
codeReplacer->getInstList().push_back(load);
|
||||||
} else {
|
std::vector<User*> Users(outputs[i]->use_begin(), outputs[i]->use_end());
|
||||||
params.push_back(*i);
|
for (unsigned u = 0, e = Users.size(); u != e; ++u) {
|
||||||
|
Instruction *inst = cast<Instruction>(Users[u]);
|
||||||
|
if (!BlocksToExtract.count(inst->getParent()))
|
||||||
|
inst->replaceUsesOfWith(outputs[i], load);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -400,8 +269,12 @@ CodeExtractor::emitCallAndSwitchStatement(Function *newFunction,
|
|||||||
|
|
||||||
// Restore values just before we exit
|
// Restore values just before we exit
|
||||||
// FIXME: Use a GetElementPtr to bunch the outputs in a struct
|
// FIXME: Use a GetElementPtr to bunch the outputs in a struct
|
||||||
for (unsigned out = 0, e = outputs.size(); out != e; ++out)
|
Function::aiterator OAI = OutputArgBegin;
|
||||||
new StoreInst(outputs[out], getFunctionArg(newFunction, out),NTRet);
|
for (unsigned out = 0, e = outputs.size(); out != e; ++out, ++OAI)
|
||||||
|
if (!DS ||
|
||||||
|
DS->dominates(cast<Instruction>(outputs[out])->getParent(),
|
||||||
|
TI->getParent()))
|
||||||
|
new StoreInst(outputs[out], OAI, NTRet);
|
||||||
}
|
}
|
||||||
|
|
||||||
// rewrite the original branch instruction with this new target
|
// rewrite the original branch instruction with this new target
|
||||||
@@ -486,16 +359,36 @@ Function *CodeExtractor::ExtractCodeRegion(const std::vector<BasicBlock*> &code)
|
|||||||
|
|
||||||
// Step 2: Construct new function based on inputs/outputs,
|
// Step 2: Construct new function based on inputs/outputs,
|
||||||
// Add allocas for all defs
|
// Add allocas for all defs
|
||||||
Function *newFunction = constructFunction(inputs, outputs, newFuncRoot,
|
Function *newFunction = constructFunction(inputs, outputs, code[0],
|
||||||
|
newFuncRoot,
|
||||||
codeReplacer, oldFunction,
|
codeReplacer, oldFunction,
|
||||||
oldFunction->getParent());
|
oldFunction->getParent());
|
||||||
|
|
||||||
rewritePhiNodes(newFunction, newFuncRoot);
|
|
||||||
|
|
||||||
emitCallAndSwitchStatement(newFunction, codeReplacer, inputs, outputs);
|
emitCallAndSwitchStatement(newFunction, codeReplacer, inputs, outputs);
|
||||||
|
|
||||||
moveCodeToFunction(newFunction);
|
moveCodeToFunction(newFunction);
|
||||||
|
|
||||||
|
// Loop over all of the PHI nodes in the entry block (code[0]), and change any
|
||||||
|
// references to the old incoming edge to be the new incoming edge.
|
||||||
|
for (BasicBlock::iterator I = code[0]->begin();
|
||||||
|
PHINode *PN = dyn_cast<PHINode>(I); ++I)
|
||||||
|
for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i)
|
||||||
|
if (!BlocksToExtract.count(PN->getIncomingBlock(i)))
|
||||||
|
PN->setIncomingBlock(i, newFuncRoot);
|
||||||
|
|
||||||
|
// Look at all successors of the codeReplacer block. If any of these blocks
|
||||||
|
// had PHI nodes in them, we need to update the "from" block to be the code
|
||||||
|
// replacer, not the original block in the extracted region.
|
||||||
|
std::vector<BasicBlock*> Succs(succ_begin(codeReplacer),
|
||||||
|
succ_end(codeReplacer));
|
||||||
|
for (unsigned i = 0, e = Succs.size(); i != e; ++i)
|
||||||
|
for (BasicBlock::iterator I = Succs[i]->begin();
|
||||||
|
PHINode *PN = dyn_cast<PHINode>(I); ++I)
|
||||||
|
for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i)
|
||||||
|
if (BlocksToExtract.count(PN->getIncomingBlock(i)))
|
||||||
|
PN->setIncomingBlock(i, codeReplacer);
|
||||||
|
|
||||||
|
|
||||||
DEBUG(if (verifyFunction(*newFunction)) abort());
|
DEBUG(if (verifyFunction(*newFunction)) abort());
|
||||||
return newFunction;
|
return newFunction;
|
||||||
}
|
}
|
||||||
@@ -503,14 +396,15 @@ Function *CodeExtractor::ExtractCodeRegion(const std::vector<BasicBlock*> &code)
|
|||||||
/// ExtractCodeRegion - slurp a sequence of basic blocks into a brand new
|
/// ExtractCodeRegion - slurp a sequence of basic blocks into a brand new
|
||||||
/// function
|
/// function
|
||||||
///
|
///
|
||||||
Function* llvm::ExtractCodeRegion(const std::vector<BasicBlock*> &code) {
|
Function* llvm::ExtractCodeRegion(DominatorSet &DS,
|
||||||
return CodeExtractor().ExtractCodeRegion(code);
|
const std::vector<BasicBlock*> &code) {
|
||||||
|
return CodeExtractor(&DS).ExtractCodeRegion(code);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ExtractBasicBlock - slurp a natural loop into a brand new function
|
/// ExtractBasicBlock - slurp a natural loop into a brand new function
|
||||||
///
|
///
|
||||||
Function* llvm::ExtractLoop(Loop *L) {
|
Function* llvm::ExtractLoop(DominatorSet &DS, Loop *L) {
|
||||||
return CodeExtractor().ExtractCodeRegion(L->getBlocks());
|
return CodeExtractor(&DS).ExtractCodeRegion(L->getBlocks());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ExtractBasicBlock - slurp a basic block into a brand new function
|
/// ExtractBasicBlock - slurp a basic block into a brand new function
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ BYTECODE_LIBRARY=1
|
|||||||
BUILD_ARCHIVE=1
|
BUILD_ARCHIVE=1
|
||||||
DONT_BUILD_RELINKED=1
|
DONT_BUILD_RELINKED=1
|
||||||
LIBRARYNAME=z
|
LIBRARYNAME=z
|
||||||
|
CPPFLAGS += -DNO_DUMMY_DECL=1
|
||||||
|
|
||||||
Source = adler32.c compress.c crc32.c gzio.c uncompr.c deflate.c trees.c \
|
Source = adler32.c compress.c crc32.c gzio.c uncompr.c deflate.c trees.c \
|
||||||
zutil.c inflate.c infback.c inftrees.c inffast.c
|
zutil.c inflate.c infback.c inftrees.c inffast.c
|
||||||
|
|||||||
@@ -34,6 +34,10 @@ ifeq ($(OS),SunOS)
|
|||||||
QMEXPECT:=$(LLVM_SRC_ROOT)/test/QMTest/expectations.sunos.qmr
|
QMEXPECT:=$(LLVM_SRC_ROOT)/test/QMTest/expectations.sunos.qmr
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ($(OS),Darwin)
|
||||||
|
QMEXPECT:=$(LLVM_SRC_ROOT)/test/QMTest/expectations.darwin.qmr
|
||||||
|
endif
|
||||||
|
|
||||||
#
|
#
|
||||||
# This is configuration information used by the test suite. In QM Test, it's
|
# This is configuration information used by the test suite. In QM Test, it's
|
||||||
# called a 'context.'
|
# called a 'context.'
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ TOOLNAME = llc
|
|||||||
USEDLIBS = cwriter \
|
USEDLIBS = cwriter \
|
||||||
sparcv9 \
|
sparcv9 \
|
||||||
x86 \
|
x86 \
|
||||||
powerpc \
|
|
||||||
selectiondag \
|
selectiondag \
|
||||||
sparcv9regalloc \
|
sparcv9regalloc \
|
||||||
sched \
|
sched \
|
||||||
|
|||||||
@@ -39,13 +39,12 @@ OutputFilename("o", cl::desc("Output filename"), cl::value_desc("filename"));
|
|||||||
|
|
||||||
static cl::opt<bool> Force("f", cl::desc("Overwrite output files"));
|
static cl::opt<bool> Force("f", cl::desc("Overwrite output files"));
|
||||||
|
|
||||||
enum ArchName { noarch, X86, SparcV9, PowerPC, CBackend };
|
enum ArchName { noarch, X86, SparcV9, CBackend };
|
||||||
|
|
||||||
static cl::opt<ArchName>
|
static cl::opt<ArchName>
|
||||||
Arch("march", cl::desc("Architecture to generate assembly for:"), cl::Prefix,
|
Arch("march", cl::desc("Architecture to generate assembly for:"), cl::Prefix,
|
||||||
cl::values(clEnumValN(X86, "x86", " IA-32 (Pentium and above)"),
|
cl::values(clEnumValN(X86, "x86", " IA-32 (Pentium and above)"),
|
||||||
clEnumValN(SparcV9, "sparcv9", " SPARC V9"),
|
clEnumValN(SparcV9, "sparcv9", " SPARC V9"),
|
||||||
clEnumValN(PowerPC, "powerpc", " PowerPC (experimental)"),
|
|
||||||
clEnumValN(CBackend, "c", " C backend"),
|
clEnumValN(CBackend, "c", " C backend"),
|
||||||
0),
|
0),
|
||||||
cl::init(noarch));
|
cl::init(noarch));
|
||||||
@@ -95,9 +94,6 @@ int main(int argc, char **argv) {
|
|||||||
case SparcV9:
|
case SparcV9:
|
||||||
TargetMachineAllocator = allocateSparcV9TargetMachine;
|
TargetMachineAllocator = allocateSparcV9TargetMachine;
|
||||||
break;
|
break;
|
||||||
case PowerPC:
|
|
||||||
TargetMachineAllocator = allocatePowerPCTargetMachine;
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
// Decide what the default target machine should be, by looking at
|
// Decide what the default target machine should be, by looking at
|
||||||
// the module. This heuristic (ILP32, LE -> IA32; LP64, BE ->
|
// the module. This heuristic (ILP32, LE -> IA32; LP64, BE ->
|
||||||
@@ -106,9 +102,6 @@ int main(int argc, char **argv) {
|
|||||||
if (mod.getEndianness() == Module::LittleEndian &&
|
if (mod.getEndianness() == Module::LittleEndian &&
|
||||||
mod.getPointerSize() == Module::Pointer32) {
|
mod.getPointerSize() == Module::Pointer32) {
|
||||||
TargetMachineAllocator = allocateX86TargetMachine;
|
TargetMachineAllocator = allocateX86TargetMachine;
|
||||||
} else if (mod.getEndianness() == Module::BigEndian &&
|
|
||||||
mod.getPointerSize() == Module::Pointer32) {
|
|
||||||
TargetMachineAllocator = allocatePowerPCTargetMachine;
|
|
||||||
} else if (mod.getEndianness() == Module::BigEndian &&
|
} else if (mod.getEndianness() == Module::BigEndian &&
|
||||||
mod.getPointerSize() == Module::Pointer64) {
|
mod.getPointerSize() == Module::Pointer64) {
|
||||||
TargetMachineAllocator = allocateSparcV9TargetMachine;
|
TargetMachineAllocator = allocateSparcV9TargetMachine;
|
||||||
@@ -119,8 +112,6 @@ int main(int argc, char **argv) {
|
|||||||
TargetMachineAllocator = allocateX86TargetMachine;
|
TargetMachineAllocator = allocateX86TargetMachine;
|
||||||
#elif defined(sparc) || defined(__sparc__) || defined(__sparcv9)
|
#elif defined(sparc) || defined(__sparc__) || defined(__sparcv9)
|
||||||
TargetMachineAllocator = allocateSparcV9TargetMachine;
|
TargetMachineAllocator = allocateSparcV9TargetMachine;
|
||||||
#elif defined(__POWERPC__) || defined(__ppc__) || defined(__APPLE__)
|
|
||||||
TargetMachineAllocator = allocatePowerPCTargetMachine;
|
|
||||||
#else
|
#else
|
||||||
std::cerr << argv[0] << ": module does not specify a target to use. "
|
std::cerr << argv[0] << ": module does not specify a target to use. "
|
||||||
<< "You must use the -march option. If no native target is "
|
<< "You must use the -march option. If no native target is "
|
||||||
|
|||||||
Reference in New Issue
Block a user