diff options
author | rdivacky <rdivacky@FreeBSD.org> | 2009-10-23 14:19:52 +0000 |
---|---|---|
committer | rdivacky <rdivacky@FreeBSD.org> | 2009-10-23 14:19:52 +0000 |
commit | 9643cca39fb9fb3b49a8912926de98acf882283c (patch) | |
tree | 22cc59e4b240d84c3a5a60531119c4eca914a256 | |
parent | 1adacceba9c9ee0f16e54388e56c9a249b296f75 (diff) | |
download | FreeBSD-src-9643cca39fb9fb3b49a8912926de98acf882283c.zip FreeBSD-src-9643cca39fb9fb3b49a8912926de98acf882283c.tar.gz |
Update LLVM to r84949.
383 files changed, 20097 insertions, 5689 deletions
@@ -19,6 +19,12 @@ LEVEL := . # # When cross-compiling, there are some things (tablegen) that need to # be build for the build system first. + +# If "RC_ProjectName" exists in the environment, and its value is +# "llvmCore", then this is an "Apple-style" build; search for +# "Apple-style" in the comments for more info. Anything else is a +# normal build. +ifneq ($(RC_ProjectName),llvmCore) # Normal build (not "Apple-style"). ifeq ($(BUILD_DIRS_ONLY),1) DIRS := lib/System lib/Support utils OPTIONAL_DIRS := @@ -211,3 +217,9 @@ happiness: update all check unittests .NOTPARALLEL: +else # Building "Apple-style." +# In an Apple-style build, once configuration is done, lines marked +# "Apple-style" are removed with sed! Please don't remove these! +# Look for the string "Apple-style" in utils/buildit/build_llvm. +include $(shell find . -name GNUmakefile) # Building "Apple-style." +endif # Building "Apple-style." diff --git a/Makefile.rules b/Makefile.rules index e3f388d5..4e0bd5c 100644 --- a/Makefile.rules +++ b/Makefile.rules @@ -1540,8 +1540,8 @@ $(ObjDir)/%GenCallingConv.inc.tmp : %.td $(ObjDir)/.dir $(Verb) $(TableGen) -gen-callingconv -o $(call SYSPATH, $@) $< $(TARGET:%=$(ObjDir)/%GenIntrinsics.inc.tmp): \ -$(ObjDir)/%GenIntrinsics.inc.tmp : Intrinsics%.td $(ObjDir)/.dir - $(Echo) "Building $(<F) calling convention information with tblgen" +$(ObjDir)/%GenIntrinsics.inc.tmp : %.td $(ObjDir)/.dir + $(Echo) "Building $(<F) intrinsics information with tblgen" $(Verb) $(TableGen) -gen-tgt-intrinsic -o $(call SYSPATH, $@) $< clean-local:: diff --git a/cmake/modules/LLVMLibDeps.cmake b/cmake/modules/LLVMLibDeps.cmake index fba999e..1a4aa34 100644 --- a/cmake/modules/LLVMLibDeps.cmake +++ b/cmake/modules/LLVMLibDeps.cmake @@ -34,7 +34,7 @@ set(MSVC_LIB_DEPS_LLVMMC LLVMSupport LLVMSystem) set(MSVC_LIB_DEPS_LLVMMSIL LLVMAnalysis LLVMCodeGen LLVMCore LLVMMSILInfo LLVMScalarOpts LLVMSupport LLVMSystem LLVMTarget LLVMTransformUtils LLVMipa) set(MSVC_LIB_DEPS_LLVMMSILInfo LLVMSupport) set(MSVC_LIB_DEPS_LLVMMSP430AsmPrinter LLVMAsmPrinter LLVMCodeGen LLVMCore LLVMMC LLVMMSP430Info LLVMSupport LLVMSystem LLVMTarget) -set(MSVC_LIB_DEPS_LLVMMSP430CodeGen LLVMCodeGen LLVMCore LLVMMC LLVMMSP430Info LLVMSelectionDAG LLVMSupport LLVMTarget) +set(MSVC_LIB_DEPS_LLVMMSP430CodeGen LLVMCodeGen LLVMCore LLVMMC LLVMMSP430Info LLVMSelectionDAG LLVMSupport LLVMSystem LLVMTarget) set(MSVC_LIB_DEPS_LLVMMSP430Info LLVMSupport) set(MSVC_LIB_DEPS_LLVMMipsAsmPrinter LLVMAsmPrinter LLVMCodeGen LLVMCore LLVMMC LLVMMipsCodeGen LLVMMipsInfo LLVMSupport LLVMSystem LLVMTarget) set(MSVC_LIB_DEPS_LLVMMipsCodeGen LLVMCodeGen LLVMCore LLVMMC LLVMMipsInfo LLVMSelectionDAG LLVMSupport LLVMSystem LLVMTarget) diff --git a/docs/CMake.html b/docs/CMake.html index 25f4710..d83e3ad 100644 --- a/docs/CMake.html +++ b/docs/CMake.html @@ -209,7 +209,7 @@ <dt><b>CMAKE_BUILD_TYPE</b>:STRING</dt> <dd>Sets the build type for <i>make</i> based generators. Possible - values are Release, Debug, RelWithDebInfo and MiniSizeRel. On + values are Release, Debug, RelWithDebInfo and MinSizeRel. On systems like Visual Studio the user sets the build type with the IDE settings.</dd> @@ -260,7 +260,7 @@ <dd>Build with threads support, if available. Defaults to ON.</dd> <dt><b>LLVM_ENABLE_ASSERTIONS</b>:BOOL</dt> - <dd>Enables code assertions. Defaults to ON if and only if + <dd>Enables code assertions. Defaults to OFF if and only if CMAKE_BUILD_TYPE is <i>Release</i>.</dd> <dt><b>LLVM_ENABLE_PIC</b>:BOOL</dt> diff --git a/docs/CommandGuide/FileCheck.pod b/docs/CommandGuide/FileCheck.pod index 539f66f..d3f640d 100644 --- a/docs/CommandGuide/FileCheck.pod +++ b/docs/CommandGuide/FileCheck.pod @@ -21,9 +21,6 @@ for matching multiple different inputs in one file in a specific order. The I<match-filename> file specifies the file that contains the patterns to match. The file to verify is always read from standard input. -The input and output of B<FileCheck> is beyond the scope of this short -introduction. Please see the I<TestingGuide> page in the LLVM documentation. - =head1 OPTIONS =over @@ -58,6 +55,189 @@ If B<FileCheck> verifies that the file matches the expected contents, it exits with 0. Otherwise, if not, or if an error occurs, it will exit with a non-zero value. +=head1 TUTORIAL + +FileCheck is typically used from LLVM regression tests, being invoked on the RUN +line of the test. A simple example of using FileCheck from a RUN line looks +like this: + + ; RUN: llvm-as < %s | llc -march=x86-64 | FileCheck %s + +This syntax says to pipe the current file ("%s") into llvm-as, pipe that into +llc, then pipe the output of llc into FileCheck. This means that FileCheck will +be verifying its standard input (the llc output) against the filename argument +specified (the original .ll file specified by "%s"). To see how this works, +lets look at the rest of the .ll file (after the RUN line): + + define void @sub1(i32* %p, i32 %v) { + entry: + ; <b>CHECK: sub1:</b> + ; <b>CHECK: subl</b> + %0 = tail call i32 @llvm.atomic.load.sub.i32.p0i32(i32* %p, i32 %v) + ret void + } + + define void @inc4(i64* %p) { + entry: + ; <b>CHECK: inc4:</b> + ; <b>CHECK: incq</b> + %0 = tail call i64 @llvm.atomic.load.add.i64.p0i64(i64* %p, i64 1) + ret void + } + +Here you can see some "CHECK:" lines specified in comments. Now you can see +how the file is piped into llvm-as, then llc, and the machine code output is +what we are verifying. FileCheck checks the machine code output to verify that +it matches what the "CHECK:" lines specify. + +The syntax of the CHECK: lines is very simple: they are fixed strings that +must occur in order. FileCheck defaults to ignoring horizontal whitespace +differences (e.g. a space is allowed to match a tab) but otherwise, the contents +of the CHECK: line is required to match some thing in the test file exactly. + +One nice thing about FileCheck (compared to grep) is that it allows merging +test cases together into logical groups. For example, because the test above +is checking for the "sub1:" and "inc4:" labels, it will not match unless there +is a "subl" in between those labels. If it existed somewhere else in the file, +that would not count: "grep subl" matches if subl exists anywhere in the +file. + + + +=head2 The FileCheck -check-prefix option + +The FileCheck -check-prefix option allows multiple test configurations to be +driven from one .ll file. This is useful in many circumstances, for example, +testing different architectural variants with llc. Here's a simple example: + + ; RUN: llvm-as < %s | llc -mtriple=i686-apple-darwin9 -mattr=sse41 \ + ; RUN: | <b>FileCheck %s -check-prefix=X32</b> + ; RUN: llvm-as < %s | llc -mtriple=x86_64-apple-darwin9 -mattr=sse41 \ + ; RUN: | <b>FileCheck %s -check-prefix=X64</b> + + define <4 x i32> @pinsrd_1(i32 %s, <4 x i32> %tmp) nounwind { + %tmp1 = insertelement <4 x i32>; %tmp, i32 %s, i32 1 + ret <4 x i32> %tmp1 + ; <b>X32:</b> pinsrd_1: + ; <b>X32:</b> pinsrd $1, 4(%esp), %xmm0 + + ; <b>X64:</b> pinsrd_1: + ; <b>X64:</b> pinsrd $1, %edi, %xmm0 + } + +In this case, we're testing that we get the expected code generation with +both 32-bit and 64-bit code generation. + + + +=head2 The "CHECK-NEXT:" directive + +Sometimes you want to match lines and would like to verify that matches +happen on exactly consequtive lines with no other lines in between them. In +this case, you can use CHECK: and CHECK-NEXT: directives to specify this. If +you specified a custom check prefix, just use "<PREFIX>-NEXT:". For +example, something like this works as you'd expect: + + define void @t2(<2 x double>* %r, <2 x double>* %A, double %B) { + %tmp3 = load <2 x double>* %A, align 16 + %tmp7 = insertelement <2 x double> undef, double %B, i32 0 + %tmp9 = shufflevector <2 x double> %tmp3, + <2 x double> %tmp7, + <2 x i32> < i32 0, i32 2 > + store <2 x double> %tmp9, <2 x double>* %r, align 16 + ret void + + ; <b>CHECK:</b> t2: + ; <b>CHECK:</b> movl 8(%esp), %eax + ; <b>CHECK-NEXT:</b> movapd (%eax), %xmm0 + ; <b>CHECK-NEXT:</b> movhpd 12(%esp), %xmm0 + ; <b>CHECK-NEXT:</b> movl 4(%esp), %eax + ; <b>CHECK-NEXT:</b> movapd %xmm0, (%eax) + ; <b>CHECK-NEXT:</b> ret + } + +CHECK-NEXT: directives reject the input unless there is exactly one newline +between it an the previous directive. A CHECK-NEXT cannot be the first +directive in a file. + + + +=head2 The "CHECK-NOT:" directive + +The CHECK-NOT: directive is used to verify that a string doesn't occur +between two matches (or the first match and the beginning of the file). For +example, to verify that a load is removed by a transformation, a test like this +can be used: + + define i8 @coerce_offset0(i32 %V, i32* %P) { + store i32 %V, i32* %P + + %P2 = bitcast i32* %P to i8* + %P3 = getelementptr i8* %P2, i32 2 + + %A = load i8* %P3 + ret i8 %A + ; <b>CHECK:</b> @coerce_offset0 + ; <b>CHECK-NOT:</b> load + ; <b>CHECK:</b> ret i8 + } + + + +=head2 FileCheck Pattern Matching Syntax + +The CHECK: and CHECK-NOT: directives both take a pattern to match. For most +uses of FileCheck, fixed string matching is perfectly sufficient. For some +things, a more flexible form of matching is desired. To support this, FileCheck +allows you to specify regular expressions in matching strings, surrounded by +double braces: B<{{yourregex}}>. Because we want to use fixed string +matching for a majority of what we do, FileCheck has been designed to support +mixing and matching fixed string matching with regular expressions. This allows +you to write things like this: + + ; CHECK: movhpd <b>{{[0-9]+}}</b>(%esp), <b>{{%xmm[0-7]}}</b> + +In this case, any offset from the ESP register will be allowed, and any xmm +register will be allowed. + +Because regular expressions are enclosed with double braces, they are +visually distinct, and you don't need to use escape characters within the double +braces like you would in C. In the rare case that you want to match double +braces explicitly from the input, you can use something ugly like +B<{{[{][{]}}> as your pattern. + + + +=head2 FileCheck Variables + +It is often useful to match a pattern and then verify that it occurs again +later in the file. For codegen tests, this can be useful to allow any register, +but verify that that register is used consistently later. To do this, FileCheck +allows named variables to be defined and substituted into patterns. Here is a +simple example: + + ; CHECK: test5: + ; CHECK: notw <b>[[REGISTER:%[a-z]+]]</b> + ; CHECK: andw {{.*}}<b>[[REGISTER]]</b> + +The first check line matches a regex (<tt>%[a-z]+</tt>) and captures it into +the variables "REGISTER". The second line verifies that whatever is in REGISTER +occurs later in the file after an "andw". FileCheck variable references are +always contained in <tt>[[ ]]</tt> pairs, are named, and their names can be +formed with the regex "<tt>[a-zA-Z][a-zA-Z0-9]*</tt>". If a colon follows the +name, then it is a definition of the variable, if not, it is a use. + +FileCheck variables can be defined multiple times, and uses always get the +latest value. Note that variables are all read at the start of a "CHECK" line +and are all defined at the end. This means that if you have something like +"<tt>CHECK: [[XYZ:.*]]x[[XYZ]]<tt>" that the check line will read the previous +value of the XYZ variable and define a new one after the match is performed. If +you need to do something like this you can probably take advantage of the fact +that FileCheck is not actually line-oriented when it matches, this allows you to +define two separate CHECK lines that match on the same line. + + + =head1 AUTHORS Maintained by The LLVM Team (L<http://llvm.org>). diff --git a/docs/CommandGuide/index.html b/docs/CommandGuide/index.html index f1046fa..14635dd 100644 --- a/docs/CommandGuide/index.html +++ b/docs/CommandGuide/index.html @@ -132,6 +132,8 @@ options) arguments to the tool you are interested in.</p> Flexible file verifier used extensively by the testing harness</li> <li><a href="/cmds/tblgen.html"><b>tblgen</b></a> - target description reader and generator</li> +<li><a href="/cmds/lit.html"><b>lit</b></a> - + LLVM Integrated Tester, for running tests</li> </ul> </div> @@ -146,7 +148,7 @@ options) arguments to the tool you are interested in.</p> src="http://www.w3.org/Icons/valid-html401-blue" alt="Valid HTML 4.01"></a> <a href="http://llvm.org">LLVM Compiler Infrastructure</a><br> - Last modified: $Date: 2009-08-15 17:38:11 +0200 (Sat, 15 Aug 2009) $ + Last modified: $Date: 2009-10-19 05:54:13 +0200 (Mon, 19 Oct 2009) $ </address> </body> diff --git a/docs/GettingStarted.html b/docs/GettingStarted.html index 8a8bce3..e3ceec6 100644 --- a/docs/GettingStarted.html +++ b/docs/GettingStarted.html @@ -724,6 +724,7 @@ revision), you can checkout it from the '<tt>tags</tt>' directory (instead of subdirectories of the '<tt>tags</tt>' directory:</p> <ul> +<li>Release 2.6: <b>RELEASE_26</b></li> <li>Release 2.5: <b>RELEASE_25</b></li> <li>Release 2.4: <b>RELEASE_24</b></li> <li>Release 2.3: <b>RELEASE_23</b></li> @@ -1635,7 +1636,7 @@ out:</p> <a href="mailto:sabre@nondot.org">Chris Lattner</a><br> <a href="http://llvm.x10sys.com/rspencer/">Reid Spencer</a><br> <a href="http://llvm.org">The LLVM Compiler Infrastructure</a><br> - Last modified: $Date: 2009-09-27 06:56:27 +0200 (Sun, 27 Sep 2009) $ + Last modified: $Date: 2009-10-23 08:20:06 +0200 (Fri, 23 Oct 2009) $ </address> </body> </html> diff --git a/docs/LangRef.html b/docs/LangRef.html index 21e41d5..9741fdb 100644 --- a/docs/LangRef.html +++ b/docs/LangRef.html @@ -2339,9 +2339,9 @@ has undefined behavior.</p> a special value. This value represents the inline assembler as a string (containing the instructions to emit), a list of operand constraints (stored as a string), a flag that indicates whether or not the inline asm - expression has side effects, and a flag indicating whether the asm came - originally from an asm block. An example inline assembler - expression is:</p> + expression has side effects, and a flag indicating whether the function + containing the asm needs to align its stack conservatively. An example + inline assembler expression is:</p> <div class="doc_code"> <pre> @@ -2369,12 +2369,16 @@ call void asm sideeffect "eieio", ""() </pre> </div> -<p>Inline asms derived from asm blocks are similarly marked with the - '<tt>msasm</tt>' keyword:</p> +<p>In some cases inline asms will contain code that will not work unless the + stack is aligned in some way, such as calls or SSE instructions on x86, + yet will not contain code that does that alignment within the asm. + The compiler should make conservative assumptions about what the asm might + contain and should generate its usual stack alignment code in the prologue + if the '<tt>alignstack</tt>' keyword is present:</p> <div class="doc_code"> <pre> -call void asm msasm "eieio", ""() +call void asm alignstack "eieio", ""() </pre> </div> @@ -7274,7 +7278,7 @@ LLVM</a>.</p> <a href="mailto:sabre@nondot.org">Chris Lattner</a><br> <a href="http://llvm.org">The LLVM Compiler Infrastructure</a><br> - Last modified: $Date: 2009-10-13 23:56:55 +0200 (Tue, 13 Oct 2009) $ + Last modified: $Date: 2009-10-22 01:28:00 +0200 (Thu, 22 Oct 2009) $ </address> </body> diff --git a/docs/ProgrammersManual.html b/docs/ProgrammersManual.html index 3234554..c5451b6 100644 --- a/docs/ProgrammersManual.html +++ b/docs/ProgrammersManual.html @@ -83,6 +83,7 @@ option</a></li> <li><a href="#dss_stringmap">"llvm/ADT/StringMap.h"</a></li> <li><a href="#dss_indexedmap">"llvm/ADT/IndexedMap.h"</a></li> <li><a href="#dss_densemap">"llvm/ADT/DenseMap.h"</a></li> + <li><a href="#dss_valuemap">"llvm/ADT/ValueMap.h"</a></li> <li><a href="#dss_map"><map></a></li> <li><a href="#dss_othermap">Other Map-Like Container Options</a></li> </ul></li> @@ -1492,6 +1493,23 @@ inserted into the map) that it needs internally.</p> <!-- _______________________________________________________________________ --> <div class="doc_subsubsection"> + <a name="dss_valuemap">"llvm/ADT/ValueMap.h"</a> +</div> + +<div class="doc_text"> + +<p> +ValueMap is a wrapper around a <a href="#dss_densemap">DenseMap</a> mapping +Value*s (or subclasses) to another type. When a Value is deleted or RAUW'ed, +ValueMap will update itself so the new version of the key is mapped to the same +value, just as if the key were a WeakVH. You can configure exactly how this +happens, and what else happens on these two events, by passing +a <code>Config</code> parameter to the ValueMap template.</p> + +</div> + +<!-- _______________________________________________________________________ --> +<div class="doc_subsubsection"> <a name="dss_map"><map></a> </div> @@ -3854,7 +3872,7 @@ arguments. An argument has a pointer to the parent Function.</p> <a href="mailto:dhurjati@cs.uiuc.edu">Dinakar Dhurjati</a> and <a href="mailto:sabre@nondot.org">Chris Lattner</a><br> <a href="http://llvm.org">The LLVM Compiler Infrastructure</a><br> - Last modified: $Date: 2009-10-12 16:46:08 +0200 (Mon, 12 Oct 2009) $ + Last modified: $Date: 2009-10-23 00:11:22 +0200 (Fri, 23 Oct 2009) $ </address> </body> diff --git a/docs/ReleaseNotes.html b/docs/ReleaseNotes.html index 8707052..2b93b1f 100644 --- a/docs/ReleaseNotes.html +++ b/docs/ReleaseNotes.html @@ -246,7 +246,7 @@ KLEE.</p> <p> The goal of <a href="http://dragonegg.llvm.org/">DragonEgg</a> is to make gcc-4.5 act like llvm-gcc without requiring any gcc modifications whatsoever. -<a href="http://dragonegg.llvm.org/">DragonEgg</a> is a shared library (llvm.so) +<a href="http://dragonegg.llvm.org/">DragonEgg</a> is a shared library (dragonegg.so) that is loaded by gcc at runtime. It uses the new gcc plugin architecture to disable the GCC optimizers and code generators, and schedule the LLVM optimizers and code generators (or direct output of LLVM IR) instead. Currently only Linux @@ -1025,7 +1025,7 @@ guide. For clients, the notable API changes are: <li>Intel and AMD machines running on Win32 using MinGW libraries (native).</li> <li>Intel and AMD machines running on Win32 with the Cygwin libraries (limited support is available for native builds with Visual C++).</li> -<li>Sun UltraSPARC workstations running Solaris 10.</li> +<li>Sun x86 and AMD64 machines running Solaris 10, OpenSolaris 0906.</li> <li>Alpha-based machines running Debian GNU/Linux.</li> </ul> @@ -1348,7 +1348,7 @@ lists</a>.</p> src="http://www.w3.org/Icons/valid-html401-blue" alt="Valid HTML 4.01"></a> <a href="http://llvm.org/">LLVM Compiler Infrastructure</a><br> - Last modified: $Date: 2009-10-13 19:48:04 +0200 (Tue, 13 Oct 2009) $ + Last modified: $Date: 2009-10-16 18:30:58 +0200 (Fri, 16 Oct 2009) $ </address> </body> diff --git a/examples/BrainF/BrainF.cpp b/examples/BrainF/BrainF.cpp index 5cf2b88..c64b87f 100644 --- a/examples/BrainF/BrainF.cpp +++ b/examples/BrainF/BrainF.cpp @@ -25,6 +25,7 @@ #include "BrainF.h" #include "llvm/Constants.h" +#include "llvm/Instructions.h" #include "llvm/Intrinsics.h" #include "llvm/ADT/STLExtras.h" #include <iostream> @@ -78,7 +79,11 @@ void BrainF::header(LLVMContext& C) { //%arr = malloc i8, i32 %d ConstantInt *val_mem = ConstantInt::get(C, APInt(32, memtotal)); - ptr_arr = builder->CreateMalloc(IntegerType::getInt8Ty(C), val_mem, "arr"); + BasicBlock* BB = builder->GetInsertBlock(); + const Type* IntPtrTy = IntegerType::getInt32Ty(C); + ptr_arr = CallInst::CreateMalloc(BB, IntPtrTy, IntegerType::getInt8Ty(C), + val_mem, NULL, "arr"); + BB->getInstList().push_back(cast<Instruction>(ptr_arr)); //call void @llvm.memset.i32(i8 *%arr, i8 0, i32 %d, i32 1) { diff --git a/include/llvm-c/Core.h b/include/llvm-c/Core.h index 74c1709..353cab2 100644 --- a/include/llvm-c/Core.h +++ b/include/llvm-c/Core.h @@ -457,7 +457,6 @@ void LLVMDisposeTypeHandle(LLVMTypeHandleRef TypeHandle); macro(UnaryInstruction) \ macro(AllocationInst) \ macro(AllocaInst) \ - macro(MallocInst) \ macro(CastInst) \ macro(BitCastInst) \ macro(FPExtInst) \ diff --git a/include/llvm/ADT/APFloat.h b/include/llvm/ADT/APFloat.h index 4d7e7ae..30d998f 100644 --- a/include/llvm/ADT/APFloat.h +++ b/include/llvm/ADT/APFloat.h @@ -125,6 +125,7 @@ namespace llvm { public: /* We support the following floating point semantics. */ + static const fltSemantics IEEEhalf; static const fltSemantics IEEEsingle; static const fltSemantics IEEEdouble; static const fltSemantics IEEEquad; @@ -321,12 +322,14 @@ namespace llvm { opStatus roundSignificandWithExponent(const integerPart *, unsigned int, int, roundingMode); + APInt convertHalfAPFloatToAPInt() const; APInt convertFloatAPFloatToAPInt() const; APInt convertDoubleAPFloatToAPInt() const; APInt convertQuadrupleAPFloatToAPInt() const; APInt convertF80LongDoubleAPFloatToAPInt() const; APInt convertPPCDoubleDoubleAPFloatToAPInt() const; void initFromAPInt(const APInt& api, bool isIEEE = false); + void initFromHalfAPInt(const APInt& api); void initFromFloatAPInt(const APInt& api); void initFromDoubleAPInt(const APInt& api); void initFromQuadrupleAPInt(const APInt &api); diff --git a/include/llvm/ADT/DenseMapInfo.h b/include/llvm/ADT/DenseMapInfo.h index 52ac5f9..2f241c5 100644 --- a/include/llvm/ADT/DenseMapInfo.h +++ b/include/llvm/ADT/DenseMapInfo.h @@ -76,7 +76,7 @@ template<> struct DenseMapInfo<unsigned long> { static inline unsigned long getEmptyKey() { return ~0UL; } static inline unsigned long getTombstoneKey() { return ~0UL - 1L; } static unsigned getHashValue(const unsigned long& Val) { - return Val * 37UL; + return (unsigned)(Val * 37UL); } static bool isPod() { return true; } static bool isEqual(const unsigned long& LHS, const unsigned long& RHS) { @@ -89,7 +89,7 @@ template<> struct DenseMapInfo<unsigned long long> { static inline unsigned long long getEmptyKey() { return ~0ULL; } static inline unsigned long long getTombstoneKey() { return ~0ULL - 1ULL; } static unsigned getHashValue(const unsigned long long& Val) { - return (unsigned)Val * 37ULL; + return (unsigned)(Val * 37ULL); } static bool isPod() { return true; } static bool isEqual(const unsigned long long& LHS, diff --git a/include/llvm/ADT/FoldingSet.h b/include/llvm/ADT/FoldingSet.h index c62c47d..26090ce 100644 --- a/include/llvm/ADT/FoldingSet.h +++ b/include/llvm/ADT/FoldingSet.h @@ -19,7 +19,6 @@ #include "llvm/Support/DataTypes.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" -#include <iterator> namespace llvm { class APFloat; diff --git a/include/llvm/ADT/StringExtras.h b/include/llvm/ADT/StringExtras.h index 3d1993c..899823d 100644 --- a/include/llvm/ADT/StringExtras.h +++ b/include/llvm/ADT/StringExtras.h @@ -16,6 +16,7 @@ #include "llvm/Support/DataTypes.h" #include "llvm/ADT/APFloat.h" +#include "llvm/ADT/StringRef.h" #include <cctype> #include <cstdio> #include <string> @@ -216,14 +217,18 @@ void SplitString(const std::string &Source, std::vector<std::string> &OutFragments, const char *Delimiters = " \t\n\v\f\r"); -/// UnescapeString - Modify the argument string, turning two character sequences -/// like '\\' 'n' into '\n'. This handles: \e \a \b \f \n \r \t \v \' \\ and -/// \num (where num is a 1-3 byte octal value). -void UnescapeString(std::string &Str); - -/// EscapeString - Modify the argument string, turning '\\' and anything that -/// doesn't satisfy std::isprint into an escape sequence. -void EscapeString(std::string &Str); +/// HashString - Hash funtion for strings. +/// +/// This is the Bernstein hash function. +// +// FIXME: Investigate whether a modified bernstein hash function performs +// better: http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx +// X*33+c -> X*33^c +static inline unsigned HashString(StringRef Str, unsigned Result = 0) { + for (unsigned i = 0, e = Str.size(); i != e; ++i) + Result = Result * 33 + Str[i]; + return Result; +} } // End llvm namespace diff --git a/include/llvm/ADT/StringRef.h b/include/llvm/ADT/StringRef.h index aa7d577..2fa5c66 100644 --- a/include/llvm/ADT/StringRef.h +++ b/include/llvm/ADT/StringRef.h @@ -29,7 +29,7 @@ namespace llvm { typedef const char *iterator; static const size_t npos = ~size_t(0); typedef size_t size_type; - + private: /// The start of the string, in an external buffer. const char *Data; @@ -45,15 +45,15 @@ namespace llvm { /*implicit*/ StringRef() : Data(0), Length(0) {} /// Construct a string ref from a cstring. - /*implicit*/ StringRef(const char *Str) + /*implicit*/ StringRef(const char *Str) : Data(Str) { if (Str) Length = ::strlen(Str); else Length = 0; } - + /// Construct a string ref from a pointer and length. - /*implicit*/ StringRef(const char *data, unsigned length) + /*implicit*/ StringRef(const char *data, size_t length) : Data(data), Length(length) {} /// Construct a string ref from an std::string. - /*implicit*/ StringRef(const std::string &Str) + /*implicit*/ StringRef(const std::string &Str) : Data(Str.c_str()), Length(Str.length()) {} /// @} @@ -83,7 +83,7 @@ namespace llvm { assert(!empty()); return Data[0]; } - + /// back - Get the last character in the string. char back() const { assert(!empty()); @@ -93,7 +93,7 @@ namespace llvm { /// equals - Check for string equality, this is more efficient than /// compare() when the relative ordering of inequal strings isn't needed. bool equals(const StringRef &RHS) const { - return (Length == RHS.Length && + return (Length == RHS.Length && memcmp(Data, RHS.Data, RHS.Length) == 0); } @@ -117,9 +117,9 @@ namespace llvm { /// @name Operator Overloads /// @{ - char operator[](size_t Index) const { + char operator[](size_t Index) const { assert(Index < Length && "Invalid index!"); - return Data[Index]; + return Data[Index]; } /// @} @@ -135,7 +135,7 @@ namespace llvm { /// @{ /// startswith - Check if this string starts with the given \arg Prefix. - bool startswith(const StringRef &Prefix) const { + bool startswith(const StringRef &Prefix) const { return substr(0, Prefix.Length).equals(Prefix); } @@ -164,7 +164,7 @@ namespace llvm { /// \return - The index of the first occurence of \arg Str, or npos if not /// found. size_t find(const StringRef &Str) const; - + /// rfind - Search for the last character \arg C in the string. /// /// \return - The index of the last occurence of \arg C, or npos if not @@ -179,29 +179,29 @@ namespace llvm { } return npos; } - + /// rfind - Search for the last string \arg Str in the string. /// /// \return - The index of the last occurence of \arg Str, or npos if not /// found. size_t rfind(const StringRef &Str) const; - + /// find_first_of - Find the first instance of the specified character or /// return npos if not in string. Same as find. size_type find_first_of(char C) const { return find(C); } - + /// find_first_of - Find the first character from the string 'Chars' in the /// current string or return npos if not in string. size_type find_first_of(StringRef Chars) const; - + /// find_first_not_of - Find the first character in the string that is not /// in the string 'Chars' or return npos if all are in string. Same as find. size_type find_first_not_of(StringRef Chars) const; - + /// @} /// @name Helpful Algorithms /// @{ - + /// count - Return the number of occurrences of \arg C in the string. size_t count(char C) const { size_t Count = 0; @@ -210,11 +210,11 @@ namespace llvm { ++Count; return Count; } - + /// count - Return the number of non-overlapped occurrences of \arg Str in /// the string. size_t count(const StringRef &Str) const; - + /// getAsInteger - Parse the current string as an integer of the specified /// radix. If Radix is specified as zero, this does radix autosensing using /// extended C rules: 0 is octal, 0x is hex, 0b is binary. @@ -229,7 +229,7 @@ namespace llvm { bool getAsInteger(unsigned Radix, unsigned &Result) const; // TODO: Provide overloads for int/unsigned that check for overflow. - + /// @} /// @name Substring Operations /// @{ @@ -308,24 +308,24 @@ namespace llvm { return LHS.equals(RHS); } - inline bool operator!=(const StringRef &LHS, const StringRef &RHS) { + inline bool operator!=(const StringRef &LHS, const StringRef &RHS) { return !(LHS == RHS); } - + inline bool operator<(const StringRef &LHS, const StringRef &RHS) { - return LHS.compare(RHS) == -1; + return LHS.compare(RHS) == -1; } inline bool operator<=(const StringRef &LHS, const StringRef &RHS) { - return LHS.compare(RHS) != 1; + return LHS.compare(RHS) != 1; } inline bool operator>(const StringRef &LHS, const StringRef &RHS) { - return LHS.compare(RHS) == 1; + return LHS.compare(RHS) == 1; } inline bool operator>=(const StringRef &LHS, const StringRef &RHS) { - return LHS.compare(RHS) != -1; + return LHS.compare(RHS) != -1; } /// @} diff --git a/include/llvm/ADT/Triple.h b/include/llvm/ADT/Triple.h index 89736bc..7fb0014 100644 --- a/include/llvm/ADT/Triple.h +++ b/include/llvm/ADT/Triple.h @@ -95,7 +95,8 @@ public: NetBSD, OpenBSD, Solaris, - Win32 + Win32, + Haiku }; private: diff --git a/include/llvm/ADT/ValueMap.h b/include/llvm/ADT/ValueMap.h new file mode 100644 index 0000000..14f2100 --- /dev/null +++ b/include/llvm/ADT/ValueMap.h @@ -0,0 +1,365 @@ +//===- llvm/ADT/ValueMap.h - Safe map from Values to data -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the ValueMap class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_VALUEMAP_H +#define LLVM_ADT_VALUEMAP_H + +#include "llvm/ADT/DenseMap.h" +#include "llvm/Support/ValueHandle.h" +#include "llvm/Support/type_traits.h" +#include "llvm/System/Mutex.h" + +#include <iterator> + +namespace llvm { + +template<typename KeyT, typename ValueT, typename Config, typename ValueInfoT> +class ValueMapCallbackVH; + +template<typename DenseMapT, typename KeyT> +class ValueMapIterator; +template<typename DenseMapT, typename KeyT> +class ValueMapConstIterator; + +template<typename KeyT> +struct ValueMapConfig { + /// If FollowRAUW is true, the ValueMap will update mappings on RAUW. If it's + /// false, the ValueMap will leave the original mapping in place. + enum { FollowRAUW = true }; + + // All methods will be called with a first argument of type ExtraData. The + // default implementations in this class take a templated first argument so + // that users' subclasses can use any type they want without having to + // override all the defaults. + struct ExtraData {}; + + template<typename ExtraDataT> + static void onRAUW(const ExtraDataT &Data, KeyT Old, KeyT New) {} + template<typename ExtraDataT> + static void onDeleted(const ExtraDataT &Data, KeyT Old) {} + + /// Returns a mutex that should be acquired around any changes to the map. + /// This is only acquired from the CallbackVH (and held around calls to onRAUW + /// and onDeleted) and not inside other ValueMap methods. NULL means that no + /// mutex is necessary. + template<typename ExtraDataT> + static sys::Mutex *getMutex(const ExtraDataT &Data) { return NULL; } +}; + +/// ValueMap maps Value* or any subclass to an arbitrary other +/// type. It provides the DenseMap interface. When the key values are +/// deleted or RAUWed, ValueMap relies on the Config to decide what to +/// do. Config parameters should inherit from ValueMapConfig<KeyT> to +/// get default implementations of all the methods ValueMap uses. +/// +/// By default, when a key is RAUWed from V1 to V2, the old mapping +/// V1->target is removed, and a new mapping V2->target is added. If +/// V2 already existed, its old target is overwritten. When a key is +/// deleted, its mapping is removed. You can override Config to get +/// called back on each event. +template<typename KeyT, typename ValueT, typename Config = ValueMapConfig<KeyT>, + typename ValueInfoT = DenseMapInfo<ValueT> > +class ValueMap { + friend class ValueMapCallbackVH<KeyT, ValueT, Config, ValueInfoT>; + typedef ValueMapCallbackVH<KeyT, ValueT, Config, ValueInfoT> ValueMapCVH; + typedef DenseMap<ValueMapCVH, ValueT, DenseMapInfo<ValueMapCVH>, + ValueInfoT> MapT; + typedef typename Config::ExtraData ExtraData; + MapT Map; + ExtraData Data; +public: + typedef KeyT key_type; + typedef ValueT mapped_type; + typedef std::pair<KeyT, ValueT> value_type; + + ValueMap(const ValueMap& Other) : Map(Other.Map), Data(Other.Data) {} + + explicit ValueMap(unsigned NumInitBuckets = 64) + : Map(NumInitBuckets), Data() {} + explicit ValueMap(const ExtraData &Data, unsigned NumInitBuckets = 64) + : Map(NumInitBuckets), Data(Data) {} + + ~ValueMap() {} + + typedef ValueMapIterator<MapT, KeyT> iterator; + typedef ValueMapConstIterator<MapT, KeyT> const_iterator; + inline iterator begin() { return iterator(Map.begin()); } + inline iterator end() { return iterator(Map.end()); } + inline const_iterator begin() const { return const_iterator(Map.begin()); } + inline const_iterator end() const { return const_iterator(Map.end()); } + + bool empty() const { return Map.empty(); } + unsigned size() const { return Map.size(); } + + /// Grow the map so that it has at least Size buckets. Does not shrink + void resize(size_t Size) { Map.resize(Size); } + + void clear() { Map.clear(); } + + /// count - Return true if the specified key is in the map. + bool count(const KeyT &Val) const { + return Map.count(Wrap(Val)); + } + + iterator find(const KeyT &Val) { + return iterator(Map.find(Wrap(Val))); + } + const_iterator find(const KeyT &Val) const { + return const_iterator(Map.find(Wrap(Val))); + } + + /// lookup - Return the entry for the specified key, or a default + /// constructed value if no such entry exists. + ValueT lookup(const KeyT &Val) const { + return Map.lookup(Wrap(Val)); + } + + // Inserts key,value pair into the map if the key isn't already in the map. + // If the key is already in the map, it returns false and doesn't update the + // value. + std::pair<iterator, bool> insert(const std::pair<KeyT, ValueT> &KV) { + std::pair<typename MapT::iterator, bool> map_result= + Map.insert(std::make_pair(Wrap(KV.first), KV.second)); + return std::make_pair(iterator(map_result.first), map_result.second); + } + + /// insert - Range insertion of pairs. + template<typename InputIt> + void insert(InputIt I, InputIt E) { + for (; I != E; ++I) + insert(*I); + } + + + bool erase(const KeyT &Val) { + return Map.erase(Wrap(Val)); + } + bool erase(iterator I) { + return Map.erase(I.base()); + } + + value_type& FindAndConstruct(const KeyT &Key) { + return Map.FindAndConstruct(Wrap(Key)); + } + + ValueT &operator[](const KeyT &Key) { + return Map[Wrap(Key)]; + } + + ValueMap& operator=(const ValueMap& Other) { + Map = Other.Map; + Data = Other.Data; + return *this; + } + + /// isPointerIntoBucketsArray - Return true if the specified pointer points + /// somewhere into the ValueMap's array of buckets (i.e. either to a key or + /// value in the ValueMap). + bool isPointerIntoBucketsArray(const void *Ptr) const { + return Map.isPointerIntoBucketsArray(Ptr); + } + + /// getPointerIntoBucketsArray() - Return an opaque pointer into the buckets + /// array. In conjunction with the previous method, this can be used to + /// determine whether an insertion caused the ValueMap to reallocate. + const void *getPointerIntoBucketsArray() const { + return Map.getPointerIntoBucketsArray(); + } + +private: + ValueMapCVH Wrap(KeyT key) const { + // The only way the resulting CallbackVH could try to modify *this (making + // the const_cast incorrect) is if it gets inserted into the map. But then + // this function must have been called from a non-const method, making the + // const_cast ok. + return ValueMapCVH(key, const_cast<ValueMap*>(this)); + } +}; + +template<typename KeyT, typename ValueT, typename Config, typename ValueInfoT> +class ValueMapCallbackVH : public CallbackVH { + friend class ValueMap<KeyT, ValueT, Config, ValueInfoT>; + friend class DenseMapInfo<ValueMapCallbackVH>; + typedef ValueMap<KeyT, ValueT, Config, ValueInfoT> ValueMapT; + typedef typename llvm::remove_pointer<KeyT>::type KeySansPointerT; + + ValueMapT *Map; + + ValueMapCallbackVH(KeyT Key, ValueMapT *Map) + : CallbackVH(const_cast<Value*>(static_cast<const Value*>(Key))), + Map(Map) {} + +public: + KeyT Unwrap() const { return cast_or_null<KeySansPointerT>(getValPtr()); } + + virtual void deleted() { + // Make a copy that won't get changed even when *this is destroyed. + ValueMapCallbackVH Copy(*this); + sys::Mutex *M = Config::getMutex(Copy.Map->Data); + if (M) + M->acquire(); + Config::onDeleted(Copy.Map->Data, Copy.Unwrap()); // May destroy *this. + Copy.Map->Map.erase(Copy); // Definitely destroys *this. + if (M) + M->release(); + } + virtual void allUsesReplacedWith(Value *new_key) { + assert(isa<KeySansPointerT>(new_key) && + "Invalid RAUW on key of ValueMap<>"); + // Make a copy that won't get changed even when *this is destroyed. + ValueMapCallbackVH Copy(*this); + sys::Mutex *M = Config::getMutex(Copy.Map->Data); + if (M) + M->acquire(); + + KeyT typed_new_key = cast<KeySansPointerT>(new_key); + // Can destroy *this: + Config::onRAUW(Copy.Map->Data, Copy.Unwrap(), typed_new_key); + if (Config::FollowRAUW) { + typename ValueMapT::MapT::iterator I = Copy.Map->Map.find(Copy); + // I could == Copy.Map->Map.end() if the onRAUW callback already + // removed the old mapping. + if (I != Copy.Map->Map.end()) { + ValueT Target(I->second); + Copy.Map->Map.erase(I); // Definitely destroys *this. + Copy.Map->insert(std::make_pair(typed_new_key, Target)); + } + } + if (M) + M->release(); + } +}; + +template<typename KeyT, typename ValueT, typename Config, typename ValueInfoT> +struct DenseMapInfo<ValueMapCallbackVH<KeyT, ValueT, Config, ValueInfoT> > { + typedef ValueMapCallbackVH<KeyT, ValueT, Config, ValueInfoT> VH; + typedef DenseMapInfo<KeyT> PointerInfo; + + static inline VH getEmptyKey() { + return VH(PointerInfo::getEmptyKey(), NULL); + } + static inline VH getTombstoneKey() { + return VH(PointerInfo::getTombstoneKey(), NULL); + } + static unsigned getHashValue(const VH &Val) { + return PointerInfo::getHashValue(Val.Unwrap()); + } + static bool isEqual(const VH &LHS, const VH &RHS) { + return LHS == RHS; + } + static bool isPod() { return false; } +}; + + +template<typename DenseMapT, typename KeyT> +class ValueMapIterator : + public std::iterator<std::forward_iterator_tag, + std::pair<KeyT, typename DenseMapT::mapped_type>, + ptrdiff_t> { + typedef typename DenseMapT::iterator BaseT; + typedef typename DenseMapT::mapped_type ValueT; + BaseT I; +public: + ValueMapIterator() : I() {} + + ValueMapIterator(BaseT I) : I(I) {} + + BaseT base() const { return I; } + + struct ValueTypeProxy { + const KeyT first; + ValueT& second; + ValueTypeProxy *operator->() { return this; } + operator std::pair<KeyT, ValueT>() const { + return std::make_pair(first, second); + } + }; + + ValueTypeProxy operator*() const { + ValueTypeProxy Result = {I->first.Unwrap(), I->second}; + return Result; + } + + ValueTypeProxy operator->() const { + return operator*(); + } + + bool operator==(const ValueMapIterator &RHS) const { + return I == RHS.I; + } + bool operator!=(const ValueMapIterator &RHS) const { + return I != RHS.I; + } + + inline ValueMapIterator& operator++() { // Preincrement + ++I; + return *this; + } + ValueMapIterator operator++(int) { // Postincrement + ValueMapIterator tmp = *this; ++*this; return tmp; + } +}; + +template<typename DenseMapT, typename KeyT> +class ValueMapConstIterator : + public std::iterator<std::forward_iterator_tag, + std::pair<KeyT, typename DenseMapT::mapped_type>, + ptrdiff_t> { + typedef typename DenseMapT::const_iterator BaseT; + typedef typename DenseMapT::mapped_type ValueT; + BaseT I; +public: + ValueMapConstIterator() : I() {} + ValueMapConstIterator(BaseT I) : I(I) {} + ValueMapConstIterator(ValueMapIterator<DenseMapT, KeyT> Other) + : I(Other.base()) {} + + BaseT base() const { return I; } + + struct ValueTypeProxy { + const KeyT first; + const ValueT& second; + ValueTypeProxy *operator->() { return this; } + operator std::pair<KeyT, ValueT>() const { + return std::make_pair(first, second); + } + }; + + ValueTypeProxy operator*() const { + ValueTypeProxy Result = {I->first.Unwrap(), I->second}; + return Result; + } + + ValueTypeProxy operator->() const { + return operator*(); + } + + bool operator==(const ValueMapConstIterator &RHS) const { + return I == RHS.I; + } + bool operator!=(const ValueMapConstIterator &RHS) const { + return I != RHS.I; + } + + inline ValueMapConstIterator& operator++() { // Preincrement + ++I; + return *this; + } + ValueMapConstIterator operator++(int) { // Postincrement + ValueMapConstIterator tmp = *this; ++*this; return tmp; + } +}; + +} // end namespace llvm + +#endif diff --git a/include/llvm/Analysis/CFGPrinter.h b/include/llvm/Analysis/CFGPrinter.h index 6a479d1..435f8ea 100644 --- a/include/llvm/Analysis/CFGPrinter.h +++ b/include/llvm/Analysis/CFGPrinter.h @@ -15,6 +15,67 @@ #ifndef LLVM_ANALYSIS_CFGPRINTER_H #define LLVM_ANALYSIS_CFGPRINTER_H +#include "llvm/Function.h" +#include "llvm/Instructions.h" +#include "llvm/Assembly/Writer.h" +#include "llvm/Support/CFG.h" +#include "llvm/Support/GraphWriter.h" + +namespace llvm { +template<> +struct DOTGraphTraits<const Function*> : public DefaultDOTGraphTraits { + static std::string getGraphName(const Function *F) { + return "CFG for '" + F->getNameStr() + "' function"; + } + + static std::string getNodeLabel(const BasicBlock *Node, + const Function *Graph, + bool ShortNames) { + if (ShortNames && !Node->getName().empty()) + return Node->getNameStr() + ":"; + + std::string Str; + raw_string_ostream OS(Str); + + if (ShortNames) { + WriteAsOperand(OS, Node, false); + return OS.str(); + } + + if (Node->getName().empty()) { + WriteAsOperand(OS, Node, false); + OS << ":"; + } + + OS << *Node; + std::string OutStr = OS.str(); + if (OutStr[0] == '\n') OutStr.erase(OutStr.begin()); + + // Process string output to make it nicer... + for (unsigned i = 0; i != OutStr.length(); ++i) + if (OutStr[i] == '\n') { // Left justify + OutStr[i] = '\\'; + OutStr.insert(OutStr.begin()+i+1, 'l'); + } else if (OutStr[i] == ';') { // Delete comments! + unsigned Idx = OutStr.find('\n', i+1); // Find end of line + OutStr.erase(OutStr.begin()+i, OutStr.begin()+Idx); + --i; + } + + return OutStr; + } + + static std::string getEdgeSourceLabel(const BasicBlock *Node, + succ_const_iterator I) { + // Label source of conditional branches with "T" or "F" + if (const BranchInst *BI = dyn_cast<BranchInst>(Node->getTerminator())) + if (BI->isConditional()) + return (I == succ_begin(Node)) ? "T" : "F"; + return ""; + } +}; +} // End llvm namespace + namespace llvm { class FunctionPass; FunctionPass *createCFGPrinterPass (); diff --git a/include/llvm/Analysis/CallGraph.h b/include/llvm/Analysis/CallGraph.h index bcb6dee..287fe4f 100644 --- a/include/llvm/Analysis/CallGraph.h +++ b/include/llvm/Analysis/CallGraph.h @@ -51,9 +51,10 @@ #ifndef LLVM_ANALYSIS_CALLGRAPH_H #define LLVM_ANALYSIS_CALLGRAPH_H +#include "llvm/Function.h" +#include "llvm/Pass.h" #include "llvm/ADT/GraphTraits.h" #include "llvm/ADT/STLExtras.h" -#include "llvm/Pass.h" #include "llvm/Support/CallSite.h" #include "llvm/Support/ValueHandle.h" #include "llvm/System/IncludeFile.h" diff --git a/include/llvm/Analysis/ConstantFolding.h b/include/llvm/Analysis/ConstantFolding.h index 9805c6c..78a16da 100644 --- a/include/llvm/Analysis/ConstantFolding.h +++ b/include/llvm/Analysis/ConstantFolding.h @@ -62,6 +62,10 @@ Constant *ConstantFoldCompareInstOperands(unsigned Predicate, LLVMContext &Context, const TargetData *TD = 0); +/// ConstantFoldLoadFromConstPtr - Return the value that a load from C would +/// produce if it is constant and determinable. If this is not determinable, +/// return null. +Constant *ConstantFoldLoadFromConstPtr(Constant *C, const TargetData *TD = 0); /// ConstantFoldLoadThroughGEPConstantExpr - Given a constant and a /// getelementptr constantexpr, return the constant value being addressed by the diff --git a/include/llvm/Analysis/DomPrinter.h b/include/llvm/Analysis/DomPrinter.h new file mode 100644 index 0000000..0ed2899 --- /dev/null +++ b/include/llvm/Analysis/DomPrinter.h @@ -0,0 +1,30 @@ +//===-- DomPrinter.h - Dom printer external interface ------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines external functions that can be called to explicitly +// instantiate the dominance tree printer. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ANALYSIS_DOMPRINTER_H +#define LLVM_ANALYSIS_DOMPRINTER_H + +namespace llvm { + class FunctionPass; + FunctionPass *createDomPrinterPass(); + FunctionPass *createDomOnlyPrinterPass(); + FunctionPass *createDomViewerPass(); + FunctionPass *createDomOnlyViewerPass(); + FunctionPass *createPostDomPrinterPass(); + FunctionPass *createPostDomOnlyPrinterPass(); + FunctionPass *createPostDomViewerPass(); + FunctionPass *createPostDomOnlyViewerPass(); +} // End llvm namespace + +#endif diff --git a/include/llvm/Analysis/Dominators.h b/include/llvm/Analysis/Dominators.h index f63e31c..59ce6e7 100644 --- a/include/llvm/Analysis/Dominators.h +++ b/include/llvm/Analysis/Dominators.h @@ -25,6 +25,7 @@ #include "llvm/Function.h" #include "llvm/Instructions.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/DepthFirstIterator.h" #include "llvm/ADT/GraphTraits.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" @@ -824,26 +825,44 @@ public: /// DominatorTree GraphTraits specialization so the DominatorTree can be /// iterable by generic graph iterators. /// -template <> struct GraphTraits<DomTreeNode *> { +template <> struct GraphTraits<DomTreeNode*> { typedef DomTreeNode NodeType; typedef NodeType::iterator ChildIteratorType; static NodeType *getEntryNode(NodeType *N) { return N; } - static inline ChildIteratorType child_begin(NodeType* N) { + static inline ChildIteratorType child_begin(NodeType *N) { return N->begin(); } - static inline ChildIteratorType child_end(NodeType* N) { + static inline ChildIteratorType child_end(NodeType *N) { return N->end(); } + + typedef df_iterator<DomTreeNode*> nodes_iterator; + + static nodes_iterator nodes_begin(DomTreeNode *N) { + return df_begin(getEntryNode(N)); + } + + static nodes_iterator nodes_end(DomTreeNode *N) { + return df_end(getEntryNode(N)); + } }; template <> struct GraphTraits<DominatorTree*> - : public GraphTraits<DomTreeNode *> { + : public GraphTraits<DomTreeNode*> { static NodeType *getEntryNode(DominatorTree *DT) { return DT->getRootNode(); } + + static nodes_iterator nodes_begin(DominatorTree *N) { + return df_begin(getEntryNode(N)); + } + + static nodes_iterator nodes_end(DominatorTree *N) { + return df_end(getEntryNode(N)); + } }; diff --git a/include/llvm/Analysis/MallocHelper.h b/include/llvm/Analysis/MallocHelper.h index 0588dff..e0c4d2c 100644 --- a/include/llvm/Analysis/MallocHelper.h +++ b/include/llvm/Analysis/MallocHelper.h @@ -46,9 +46,9 @@ CallInst* extractMallocCallFromBitCast(Value* I); /// matches the malloc call IR generated by CallInst::CreateMalloc(). This /// means that it is a malloc call with one bitcast use AND the malloc call's /// size argument is: -/// 1. a constant not equal to the malloc's allocated type +/// 1. a constant not equal to the size of the malloced type /// or -/// 2. the result of a multiplication by the malloc's allocated type +/// 2. the result of a multiplication by the size of the malloced type /// Otherwise it returns NULL. /// The unique bitcast is needed to determine the type/size of the array /// allocation. @@ -66,18 +66,17 @@ const PointerType* getMallocType(const CallInst* CI); /// unique bitcast use, then return NULL. const Type* getMallocAllocatedType(const CallInst* CI); -/// getMallocArraySize - Returns the array size of a malloc call. The array -/// size is computated in 1 of 3 ways: -/// 1. If the element type if of size 1, then array size is the argument to +/// getMallocArraySize - Returns the array size of a malloc call. For array +/// mallocs, the size is computated in 1 of 3 ways: +/// 1. If the element type is of size 1, then array size is the argument to /// malloc. /// 2. Else if the malloc's argument is a constant, the array size is that /// argument divided by the element type's size. /// 3. Else the malloc argument must be a multiplication and the array size is /// the first operand of the multiplication. -/// This function returns constant 1 if: -/// 1. The malloc call's allocated type cannot be determined. -/// 2. IR wasn't created by a call to CallInst::CreateMalloc() with a non-NULL -/// ArraySize. +/// For non-array mallocs, the computed size is constant 1. +/// This function returns NULL for all mallocs whose array size cannot be +/// determined. Value* getMallocArraySize(CallInst* CI, LLVMContext &Context, const TargetData* TD); diff --git a/include/llvm/Analysis/PostDominators.h b/include/llvm/Analysis/PostDominators.h index 171cfdb..42a16e7 100644 --- a/include/llvm/Analysis/PostDominators.h +++ b/include/llvm/Analysis/PostDominators.h @@ -74,6 +74,21 @@ struct PostDominatorTree : public FunctionPass { FunctionPass* createPostDomTree(); +template <> struct GraphTraits<PostDominatorTree*> + : public GraphTraits<DomTreeNode*> { + static NodeType *getEntryNode(PostDominatorTree *DT) { + return DT->getRootNode(); + } + + static nodes_iterator nodes_begin(PostDominatorTree *N) { + return df_begin(getEntryNode(N)); + } + + static nodes_iterator nodes_end(PostDominatorTree *N) { + return df_end(getEntryNode(N)); + } +}; + /// PostDominanceFrontier Class - Concrete subclass of DominanceFrontier that is /// used to compute the a post-dominance frontier. /// diff --git a/include/llvm/CodeGen/MachineFrameInfo.h b/include/llvm/CodeGen/MachineFrameInfo.h index b5479ba..a04189c 100644 --- a/include/llvm/CodeGen/MachineFrameInfo.h +++ b/include/llvm/CodeGen/MachineFrameInfo.h @@ -86,6 +86,10 @@ class MachineFrameInfo { // StackObject - Represent a single object allocated on the stack. struct StackObject { + // SPOffset - The offset of this object from the stack pointer on entry to + // the function. This field has no meaning for a variable sized element. + int64_t SPOffset; + // The size of this object on the stack. 0 means a variable sized object, // ~0ULL means a dead object. uint64_t Size; @@ -98,12 +102,14 @@ class MachineFrameInfo { // default, fixed objects are immutable unless marked otherwise. bool isImmutable; - // SPOffset - The offset of this object from the stack pointer on entry to - // the function. This field has no meaning for a variable sized element. - int64_t SPOffset; - - StackObject(uint64_t Sz, unsigned Al, int64_t SP = 0, bool IM = false) - : Size(Sz), Alignment(Al), isImmutable(IM), SPOffset(SP) {} + // isSpillSlot - If true, the stack object is used as spill slot. It + // cannot alias any other memory objects. + bool isSpillSlot; + + StackObject(uint64_t Sz, unsigned Al, int64_t SP = 0, bool IM = false, + bool isSS = false) + : SPOffset(SP), Size(Sz), Alignment(Al), isImmutable(IM), + isSpillSlot(isSS) {} }; /// Objects - The list of stack objects allocated... @@ -352,6 +358,14 @@ public: return Objects[ObjectIdx+NumFixedObjects].isImmutable; } + /// isSpillSlotObjectIndex - Returns true if the specified index corresponds + /// to a spill slot.. + bool isSpillSlotObjectIndex(int ObjectIdx) const { + assert(unsigned(ObjectIdx+NumFixedObjects) < Objects.size() && + "Invalid Object Idx!"); + return Objects[ObjectIdx+NumFixedObjects].isSpillSlot;; + } + /// isDeadObjectIndex - Returns true if the specified index corresponds to /// a dead object. bool isDeadObjectIndex(int ObjectIdx) const { @@ -363,9 +377,9 @@ public: /// CreateStackObject - Create a new statically sized stack object, returning /// a nonnegative identifier to represent it. /// - int CreateStackObject(uint64_t Size, unsigned Alignment) { + int CreateStackObject(uint64_t Size, unsigned Alignment, bool isSS = false) { assert(Size != 0 && "Cannot allocate zero size stack objects!"); - Objects.push_back(StackObject(Size, Alignment)); + Objects.push_back(StackObject(Size, Alignment, 0, false, isSS)); return (int)Objects.size()-NumFixedObjects-1; } diff --git a/include/llvm/CodeGen/MachineFunction.h b/include/llvm/CodeGen/MachineFunction.h index ba831ca..40260ea 100644 --- a/include/llvm/CodeGen/MachineFunction.h +++ b/include/llvm/CodeGen/MachineFunction.h @@ -267,6 +267,9 @@ public: void splice(iterator InsertPt, iterator MBBI) { BasicBlocks.splice(InsertPt, BasicBlocks, MBBI); } + void splice(iterator InsertPt, iterator MBBI, iterator MBBE) { + BasicBlocks.splice(InsertPt, BasicBlocks, MBBI, MBBE); + } void remove(iterator MBBI) { BasicBlocks.remove(MBBI); diff --git a/include/llvm/CodeGen/MachineLoopInfo.h b/include/llvm/CodeGen/MachineLoopInfo.h index 65ad4e4..d3df805 100644 --- a/include/llvm/CodeGen/MachineLoopInfo.h +++ b/include/llvm/CodeGen/MachineLoopInfo.h @@ -38,6 +38,17 @@ namespace llvm { class MachineLoop : public LoopBase<MachineBasicBlock, MachineLoop> { public: MachineLoop(); + + /// getTopBlock - Return the "top" block in the loop, which is the first + /// block in the linear layout, ignoring any parts of the loop not + /// contiguous with the part the contains the header. + MachineBasicBlock *getTopBlock(); + + /// getBottomBlock - Return the "bottom" block in the loop, which is the last + /// block in the linear layout, ignoring any parts of the loop not + /// contiguous with the part the contains the header. + MachineBasicBlock *getBottomBlock(); + private: friend class LoopInfoBase<MachineBasicBlock, MachineLoop>; explicit MachineLoop(MachineBasicBlock *MBB) diff --git a/include/llvm/CodeGen/MachineModuleInfo.h b/include/llvm/CodeGen/MachineModuleInfo.h index 5878d67..1b924f2 100644 --- a/include/llvm/CodeGen/MachineModuleInfo.h +++ b/include/llvm/CodeGen/MachineModuleInfo.h @@ -150,7 +150,8 @@ class MachineModuleInfo : public ImmutablePass { public: static char ID; // Pass identification, replacement for typeid - typedef SmallVector< std::pair< WeakMetadataVH, unsigned>, 4 > VariableDbgInfoMapTy; + typedef SmallVector< std::pair<TrackingVH<MDNode>, unsigned>, 4 > + VariableDbgInfoMapTy; VariableDbgInfoMapTy VariableDbgInfo; MachineModuleInfo(); diff --git a/include/llvm/CodeGen/Passes.h b/include/llvm/CodeGen/Passes.h index 1e7115e..d0d6103 100644 --- a/include/llvm/CodeGen/Passes.h +++ b/include/llvm/CodeGen/Passes.h @@ -15,13 +15,13 @@ #ifndef LLVM_CODEGEN_PASSES_H #define LLVM_CODEGEN_PASSES_H +#include "llvm/Target/TargetMachine.h" #include <string> namespace llvm { class FunctionPass; class PassInfo; - class TargetMachine; class TargetLowering; class RegisterCoalescer; class raw_ostream; @@ -119,8 +119,9 @@ namespace llvm { /// FunctionPass *createLowerSubregsPass(); - /// createPostRAScheduler - under development. - FunctionPass *createPostRAScheduler(); + /// createPostRAScheduler - This pass performs post register allocation + /// scheduling. + FunctionPass *createPostRAScheduler(CodeGenOpt::Level OptLevel); /// BranchFolding Pass - This pass performs machine code CFG based /// optimizations to delete branches to branches, eliminate branches to diff --git a/include/llvm/CodeGen/PseudoSourceValue.h b/include/llvm/CodeGen/PseudoSourceValue.h index c6be645..7a9122d 100644 --- a/include/llvm/CodeGen/PseudoSourceValue.h +++ b/include/llvm/CodeGen/PseudoSourceValue.h @@ -39,6 +39,10 @@ namespace llvm { /// virtual bool isConstant(const MachineFrameInfo *) const; + /// isAliased - Test whether the memory pointed to by this + /// PseudoSourceValue may also be pointed to by an LLVM IR Value. + virtual bool isAliased(const MachineFrameInfo *) const; + /// classof - Methods for support type inquiry through isa, cast, and /// dyn_cast: /// diff --git a/include/llvm/CompilerDriver/Common.td b/include/llvm/CompilerDriver/Common.td index 5b7c543..79edb02 100644 --- a/include/llvm/CompilerDriver/Common.td +++ b/include/llvm/CompilerDriver/Common.td @@ -68,6 +68,9 @@ def not_empty; def default; def single_input_file; def multiple_input_files; +def any_switch_on; +def any_not_empty; +def any_empty; // Possible actions. @@ -76,7 +79,9 @@ def forward; def forward_as; def stop_compilation; def unpack_values; +def warning; def error; +def unset_option; // Increase/decrease the edge weight. def inc_weight; @@ -90,11 +95,16 @@ class PluginPriority<int p> { int priority = p; } -// Option list - used to specify aliases and sometimes help strings. +// Option list - a single place to specify options. class OptionList<list<dag> l> { list<dag> options = l; } +// Option preprocessor - actions taken during plugin loading. +class OptionPreprocessor<dag d> { + dag preprocessor = d; +} + // Map from suffixes to language names class LangToSuffixes<string str, list<string> lst> { diff --git a/include/llvm/CompilerDriver/Plugin.h b/include/llvm/CompilerDriver/Plugin.h index 9f9eee3..e9a2048 100644 --- a/include/llvm/CompilerDriver/Plugin.h +++ b/include/llvm/CompilerDriver/Plugin.h @@ -29,6 +29,11 @@ namespace llvmc { /// first. virtual int Priority() const { return 0; } + /// PreprocessOptions - The auto-generated function that performs various + /// consistency checks on options (like ensuring that -O2 and -O3 are not + /// used together). + virtual void PreprocessOptions() const = 0; + /// PopulateLanguageMap - The auto-generated function that fills in /// the language map (map from file extensions to language names). virtual void PopulateLanguageMap(LanguageMap&) const = 0; @@ -60,13 +65,10 @@ namespace llvmc { PluginLoader(); ~PluginLoader(); - /// PopulateLanguageMap - Fills in the language map by calling - /// PopulateLanguageMap methods of all plugins. - void PopulateLanguageMap(LanguageMap& langMap); - - /// PopulateCompilationGraph - Populates the compilation graph by - /// calling PopulateCompilationGraph methods of all plugins. - void PopulateCompilationGraph(CompilationGraph& tools); + /// RunInitialization - Calls PreprocessOptions, PopulateLanguageMap and + /// PopulateCompilationGraph methods of all plugins. This populates the + /// global language map and the compilation graph. + void RunInitialization(LanguageMap& langMap, CompilationGraph& graph) const; private: // noncopyable diff --git a/include/llvm/Config/AsmParsers.def b/include/llvm/Config/AsmParsers.def new file mode 100644 index 0000000..63590b3 --- /dev/null +++ b/include/llvm/Config/AsmParsers.def @@ -0,0 +1,29 @@ +//===- llvm/Config/AsmParsers.def - LLVM Assembly Parsers -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file enumerates all of the assembly-language parsers +// supported by this build of LLVM. Clients of this file should define +// the LLVM_ASM_PARSER macro to be a function-like macro with a +// single parameter (the name of the target whose assembly can be +// generated); including this file will then enumerate all of the +// targets with assembly parsers. +// +// The set of targets supported by LLVM is generated at configuration +// time, at which point this header is generated. Do not modify this +// header directly. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ASM_PARSER +# error Please define the macro LLVM_ASM_PARSER(TargetName) +#endif + +LLVM_ASM_PARSER(ARM) LLVM_ASM_PARSER(X86) + +#undef LLVM_ASM_PARSER diff --git a/include/llvm/Config/AsmPrinters.def b/include/llvm/Config/AsmPrinters.def new file mode 100644 index 0000000..953af51 --- /dev/null +++ b/include/llvm/Config/AsmPrinters.def @@ -0,0 +1,29 @@ +//===- llvm/Config/AsmPrinters.def - LLVM Assembly Printers -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file enumerates all of the assembly-language printers +// supported by this build of LLVM. Clients of this file should define +// the LLVM_ASM_PRINTER macro to be a function-like macro with a +// single parameter (the name of the target whose assembly can be +// generated); including this file will then enumerate all of the +// targets with assembly printers. +// +// The set of targets supported by LLVM is generated at configuration +// time, at which point this header is generated. Do not modify this +// header directly. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ASM_PRINTER +# error Please define the macro LLVM_ASM_PRINTER(TargetName) +#endif + +LLVM_ASM_PRINTER(Blackfin) LLVM_ASM_PRINTER(SystemZ) LLVM_ASM_PRINTER(MSP430) LLVM_ASM_PRINTER(XCore) LLVM_ASM_PRINTER(PIC16) LLVM_ASM_PRINTER(CellSPU) LLVM_ASM_PRINTER(Mips) LLVM_ASM_PRINTER(ARM) LLVM_ASM_PRINTER(Alpha) LLVM_ASM_PRINTER(PowerPC) LLVM_ASM_PRINTER(Sparc) LLVM_ASM_PRINTER(X86) + +#undef LLVM_ASM_PRINTER diff --git a/include/llvm/Config/Targets.def b/include/llvm/Config/Targets.def new file mode 100644 index 0000000..2008c0c --- /dev/null +++ b/include/llvm/Config/Targets.def @@ -0,0 +1,28 @@ +/*===- llvm/Config/Targets.def - LLVM Target Architectures ------*- C++ -*-===*\ +|* *| +|* The LLVM Compiler Infrastructure *| +|* *| +|* This file is distributed under the University of Illinois Open Source *| +|* License. See LICENSE.TXT for details. *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* This file enumerates all of the target architectures supported by *| +|* this build of LLVM. Clients of this file should define the *| +|* LLVM_TARGET macro to be a function-like macro with a single *| +|* parameter (the name of the target); including this file will then *| +|* enumerate all of the targets. *| +|* *| +|* The set of targets supported by LLVM is generated at configuration *| +|* time, at which point this header is generated. Do not modify this *| +|* header directly. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#ifndef LLVM_TARGET +# error Please define the macro LLVM_TARGET(TargetName) +#endif + +LLVM_TARGET(CppBackend) LLVM_TARGET(MSIL) LLVM_TARGET(CBackend) LLVM_TARGET(Blackfin) LLVM_TARGET(SystemZ) LLVM_TARGET(MSP430) LLVM_TARGET(XCore) LLVM_TARGET(PIC16) LLVM_TARGET(CellSPU) LLVM_TARGET(Mips) LLVM_TARGET(ARM) LLVM_TARGET(Alpha) LLVM_TARGET(PowerPC) LLVM_TARGET(Sparc) LLVM_TARGET(X86) + +#undef LLVM_TARGET diff --git a/include/llvm/Config/config.h b/include/llvm/Config/config.h new file mode 100644 index 0000000..b5a8713 --- /dev/null +++ b/include/llvm/Config/config.h @@ -0,0 +1,612 @@ +/* include/llvm/Config/config.h. Generated from config.h.in by configure. */ +/* include/llvm/Config/config.h.in. Generated from autoconf/configure.ac by autoheader. */ + +/* Define if dlopen(0) will open the symbols of the program */ +#define CAN_DLOPEN_SELF 1 + +/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP + systems. This function is required for `alloca.c' support on those systems. + */ +/* #undef CRAY_STACKSEG_END */ + +/* Define to 1 if using `alloca.c'. */ +/* #undef C_ALLOCA */ + +/* Define if CBE is enabled for printf %a output */ +#define ENABLE_CBE_PRINTF_A 1 + +/* Define if position independent code is enabled */ +#define ENABLE_PIC 1 + +/* Define if threads enabled */ +#define ENABLE_THREADS 1 + +/* Define to 1 if you have `alloca', as a function or macro. */ +#define HAVE_ALLOCA 1 + +/* Define to 1 if you have <alloca.h> and it should be used (not on Ultrix). + */ +/* #undef HAVE_ALLOCA_H */ + +/* Define to 1 if you have the `argz_append' function. */ +/* #undef HAVE_ARGZ_APPEND */ + +/* Define to 1 if you have the `argz_create_sep' function. */ +/* #undef HAVE_ARGZ_CREATE_SEP */ + +/* Define to 1 if you have the <argz.h> header file. */ +/* #undef HAVE_ARGZ_H */ + +/* Define to 1 if you have the `argz_insert' function. */ +/* #undef HAVE_ARGZ_INSERT */ + +/* Define to 1 if you have the `argz_next' function. */ +/* #undef HAVE_ARGZ_NEXT */ + +/* Define to 1 if you have the `argz_stringify' function. */ +/* #undef HAVE_ARGZ_STRINGIFY */ + +/* Define to 1 if you have the <assert.h> header file. */ +#define HAVE_ASSERT_H 1 + +/* Define to 1 if you have the `backtrace' function. */ +/* #undef HAVE_BACKTRACE */ + +/* Define to 1 if you have the `bcopy' function. */ +/* #undef HAVE_BCOPY */ + +/* Does not have bi-directional iterator */ +#define HAVE_BI_ITERATOR 0 + +/* Define to 1 if you have the `ceilf' function. */ +#define HAVE_CEILF 1 + +/* Define if the neat program is available */ +/* #undef HAVE_CIRCO */ + +/* Define to 1 if you have the `closedir' function. */ +#define HAVE_CLOSEDIR 1 + +/* Define to 1 if you have the <ctype.h> header file. */ +#define HAVE_CTYPE_H 1 + +/* Define to 1 if you have the <dirent.h> header file, and it defines `DIR'. + */ +#define HAVE_DIRENT_H 1 + +/* Define if you have the GNU dld library. */ +/* #undef HAVE_DLD */ + +/* Define to 1 if you have the <dld.h> header file. */ +/* #undef HAVE_DLD_H */ + +/* Define to 1 if you have the `dlerror' function. */ +#define HAVE_DLERROR 1 + +/* Define to 1 if you have the <dlfcn.h> header file. */ +#define HAVE_DLFCN_H 1 + +/* Define if dlopen() is available on this platform. */ +#define HAVE_DLOPEN 1 + +/* Define to 1 if you have the <dl.h> header file. */ +/* #undef HAVE_DL_H */ + +/* Define if the dot program is available */ +/* #undef HAVE_DOT */ + +/* Define if the dotty program is available */ +/* #undef HAVE_DOTTY */ + +/* Define if you have the _dyld_func_lookup function. */ +/* #undef HAVE_DYLD */ + +/* Define to 1 if you have the <errno.h> header file. */ +#define HAVE_ERRNO_H 1 + +/* Define to 1 if the system has the type `error_t'. */ +/* #undef HAVE_ERROR_T */ + +/* Define to 1 if you have the <execinfo.h> header file. */ +/* #undef HAVE_EXECINFO_H */ + +/* Define to 1 if you have the <fcntl.h> header file. */ +#define HAVE_FCNTL_H 1 + +/* Define if the neat program is available */ +/* #undef HAVE_FDP */ + +/* Define if libffi is available on this platform. */ +/* #undef HAVE_FFI_CALL */ + +/* Define to 1 if you have the <ffi/ffi.h> header file. */ +/* #undef HAVE_FFI_FFI_H */ + +/* Define to 1 if you have the <ffi.h> header file. */ +/* #undef HAVE_FFI_H */ + +/* Set to 1 if the finite function is found in <ieeefp.h> */ +/* #undef HAVE_FINITE_IN_IEEEFP_H */ + +/* Define to 1 if you have the `floorf' function. */ +#define HAVE_FLOORF 1 + +/* Define to 1 if you have the `fmodf' function. */ +#define HAVE_FMODF 1 + +/* Does not have forward iterator */ +#define HAVE_FWD_ITERATOR 0 + +/* Define to 1 if you have the `getcwd' function. */ +#define HAVE_GETCWD 1 + +/* Define to 1 if you have the `getpagesize' function. */ +#define HAVE_GETPAGESIZE 1 + +/* Define to 1 if you have the `getrlimit' function. */ +#define HAVE_GETRLIMIT 1 + +/* Define to 1 if you have the `getrusage' function. */ +#define HAVE_GETRUSAGE 1 + +/* Define to 1 if you have the `gettimeofday' function. */ +#define HAVE_GETTIMEOFDAY 1 + +/* Define if the Graphviz program is available */ +/* #undef HAVE_GRAPHVIZ */ + +/* Define if the gv program is available */ +/* #undef HAVE_GV */ + +/* Define to 1 if you have the `index' function. */ +/* #undef HAVE_INDEX */ + +/* Define to 1 if the system has the type `int64_t'. */ +#define HAVE_INT64_T 1 + +/* Define to 1 if you have the <inttypes.h> header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the `isatty' function. */ +#define HAVE_ISATTY 1 + +/* Set to 1 if the isinf function is found in <cmath> */ +#define HAVE_ISINF_IN_CMATH 1 + +/* Set to 1 if the isinf function is found in <math.h> */ +#define HAVE_ISINF_IN_MATH_H 1 + +/* Set to 1 if the isnan function is found in <cmath> */ +#define HAVE_ISNAN_IN_CMATH 1 + +/* Set to 1 if the isnan function is found in <math.h> */ +#define HAVE_ISNAN_IN_MATH_H 1 + +/* Define if you have the libdl library or equivalent. */ +#define HAVE_LIBDL 1 + +/* Define to 1 if you have the `imagehlp' library (-limagehlp). */ +/* #undef HAVE_LIBIMAGEHLP */ + +/* Define to 1 if you have the `m' library (-lm). */ +#define HAVE_LIBM 1 + +/* Define to 1 if you have the `psapi' library (-lpsapi). */ +/* #undef HAVE_LIBPSAPI */ + +/* Define to 1 if you have the `pthread' library (-lpthread). */ +#define HAVE_LIBPTHREAD 1 + +/* Define to 1 if you have the `udis86' library (-ludis86). */ +/* #undef HAVE_LIBUDIS86 */ + +/* Define to 1 if you have the <limits.h> header file. */ +#define HAVE_LIMITS_H 1 + +/* Define if you can use -Wl,-export-dynamic. */ +#define HAVE_LINK_EXPORT_DYNAMIC 1 + +/* Define to 1 if you have the <link.h> header file. */ +#define HAVE_LINK_H 1 + +/* Define if you can use -Wl,-R. to pass -R. to the linker, in order to add + the current directory to the dynamic linker search path. */ +#define HAVE_LINK_R 1 + +/* Define to 1 if you have the `longjmp' function. */ +#define HAVE_LONGJMP 1 + +/* Define to 1 if you have the <mach/mach.h> header file. */ +/* #undef HAVE_MACH_MACH_H */ + +/* Define to 1 if you have the <mach-o/dyld.h> header file. */ +/* #undef HAVE_MACH_O_DYLD_H */ + +/* Define if mallinfo() is available on this platform. */ +/* #undef HAVE_MALLINFO */ + +/* Define to 1 if you have the <malloc.h> header file. */ +/* #undef HAVE_MALLOC_H */ + +/* Define to 1 if you have the <malloc/malloc.h> header file. */ +/* #undef HAVE_MALLOC_MALLOC_H */ + +/* Define to 1 if you have the `malloc_zone_statistics' function. */ +/* #undef HAVE_MALLOC_ZONE_STATISTICS */ + +/* Define to 1 if you have the `memcpy' function. */ +#define HAVE_MEMCPY 1 + +/* Define to 1 if you have the `memmove' function. */ +#define HAVE_MEMMOVE 1 + +/* Define to 1 if you have the <memory.h> header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the `mkdtemp' function. */ +#define HAVE_MKDTEMP 1 + +/* Define to 1 if you have the `mkstemp' function. */ +#define HAVE_MKSTEMP 1 + +/* Define to 1 if you have the `mktemp' function. */ +#define HAVE_MKTEMP 1 + +/* Define to 1 if you have a working `mmap' system call. */ +#define HAVE_MMAP 1 + +/* Define if mmap() uses MAP_ANONYMOUS to map anonymous pages, or undefine if + it uses MAP_ANON */ +/* #undef HAVE_MMAP_ANONYMOUS */ + +/* Define if mmap() can map files into memory */ +#define HAVE_MMAP_FILE + +/* define if the compiler implements namespaces */ +#define HAVE_NAMESPACES + +/* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */ +/* #undef HAVE_NDIR_H */ + +/* Define to 1 if you have the `nearbyintf' function. */ +#define HAVE_NEARBYINTF 1 + +/* Define if the neat program is available */ +/* #undef HAVE_NEATO */ + +/* Define to 1 if you have the `opendir' function. */ +#define HAVE_OPENDIR 1 + +/* Define to 1 if you have the `powf' function. */ +#define HAVE_POWF 1 + +/* Define if libtool can extract symbol lists from object files. */ +#define HAVE_PRELOADED_SYMBOLS 1 + +/* Define to have the %a format string */ +#define HAVE_PRINTF_A 1 + +/* Have pthread_getspecific */ +#define HAVE_PTHREAD_GETSPECIFIC 1 + +/* Define to 1 if you have the <pthread.h> header file. */ +#define HAVE_PTHREAD_H 1 + +/* Have pthread_mutex_lock */ +#define HAVE_PTHREAD_MUTEX_LOCK 1 + +/* Have pthread_rwlock_init */ +#define HAVE_PTHREAD_RWLOCK_INIT 1 + +/* Define to 1 if srand48/lrand48/drand48 exist in <stdlib.h> */ +#define HAVE_RAND48 1 + +/* Define to 1 if you have the `readdir' function. */ +#define HAVE_READDIR 1 + +/* Define to 1 if you have the `realpath' function. */ +#define HAVE_REALPATH 1 + +/* Define to 1 if you have the `rindex' function. */ +/* #undef HAVE_RINDEX */ + +/* Define to 1 if you have the `rintf' function. */ +#define HAVE_RINTF 1 + +/* Define to 1 if you have the `round' function. */ +#define HAVE_ROUND 1 + +/* Define to 1 if you have the `roundf' function. */ +#define HAVE_ROUNDF 1 + +/* Define to 1 if you have the `sbrk' function. */ +#define HAVE_SBRK 1 + +/* Define to 1 if you have the `setenv' function. */ +#define HAVE_SETENV 1 + +/* Define to 1 if you have the `setjmp' function. */ +#define HAVE_SETJMP 1 + +/* Define to 1 if you have the <setjmp.h> header file. */ +#define HAVE_SETJMP_H 1 + +/* Define to 1 if you have the `setrlimit' function. */ +#define HAVE_SETRLIMIT 1 + +/* Define if you have the shl_load function. */ +/* #undef HAVE_SHL_LOAD */ + +/* Define to 1 if you have the `siglongjmp' function. */ +#define HAVE_SIGLONGJMP 1 + +/* Define to 1 if you have the <signal.h> header file. */ +#define HAVE_SIGNAL_H 1 + +/* Define to 1 if you have the `sigsetjmp' function. */ +#define HAVE_SIGSETJMP 1 + +/* Define to 1 if you have the <stdint.h> header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the <stdio.h> header file. */ +#define HAVE_STDIO_H 1 + +/* Define to 1 if you have the <stdlib.h> header file. */ +#define HAVE_STDLIB_H 1 + +/* Set to 1 if the std::isinf function is found in <cmath> */ +/* #undef HAVE_STD_ISINF_IN_CMATH */ + +/* Set to 1 if the std::isnan function is found in <cmath> */ +#define HAVE_STD_ISNAN_IN_CMATH 1 + +/* Does not have std namespace iterator */ +#define HAVE_STD_ITERATOR 1 + +/* Define to 1 if you have the `strchr' function. */ +#define HAVE_STRCHR 1 + +/* Define to 1 if you have the `strcmp' function. */ +#define HAVE_STRCMP 1 + +/* Define to 1 if you have the `strdup' function. */ +#define HAVE_STRDUP 1 + +/* Define to 1 if you have the `strerror' function. */ +#define HAVE_STRERROR 1 + +/* Define to 1 if you have the `strerror_r' function. */ +#define HAVE_STRERROR_R 1 + +/* Define to 1 if you have the `strerror_s' function. */ +/* #undef HAVE_STRERROR_S */ + +/* Define to 1 if you have the <strings.h> header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the <string.h> header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the `strrchr' function. */ +#define HAVE_STRRCHR 1 + +/* Define to 1 if you have the `strtof' function. */ +#define HAVE_STRTOF 1 + +/* Define to 1 if you have the `strtoll' function. */ +#define HAVE_STRTOLL 1 + +/* Define to 1 if you have the `strtoq' function. */ +#define HAVE_STRTOQ 1 + +/* Define to 1 if you have the `sysconf' function. */ +#define HAVE_SYSCONF 1 + +/* Define to 1 if you have the <sys/dir.h> header file, and it defines `DIR'. + */ +/* #undef HAVE_SYS_DIR_H */ + +/* Define to 1 if you have the <sys/dl.h> header file. */ +/* #undef HAVE_SYS_DL_H */ + +/* Define to 1 if you have the <sys/ioctl.h> header file. */ +#define HAVE_SYS_IOCTL_H 1 + +/* Define to 1 if you have the <sys/mman.h> header file. */ +#define HAVE_SYS_MMAN_H 1 + +/* Define to 1 if you have the <sys/ndir.h> header file, and it defines `DIR'. + */ +/* #undef HAVE_SYS_NDIR_H */ + +/* Define to 1 if you have the <sys/param.h> header file. */ +#define HAVE_SYS_PARAM_H 1 + +/* Define to 1 if you have the <sys/resource.h> header file. */ +#define HAVE_SYS_RESOURCE_H 1 + +/* Define to 1 if you have the <sys/stat.h> header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the <sys/time.h> header file. */ +#define HAVE_SYS_TIME_H 1 + +/* Define to 1 if you have the <sys/types.h> header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */ +#define HAVE_SYS_WAIT_H 1 + +/* Define to 1 if you have the <termios.h> header file. */ +#define HAVE_TERMIOS_H 1 + +/* Define if the neat program is available */ +/* #undef HAVE_TWOPI */ + +/* Define to 1 if the system has the type `uint64_t'. */ +#define HAVE_UINT64_T 1 + +/* Define to 1 if you have the <unistd.h> header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to 1 if you have the <utime.h> header file. */ +#define HAVE_UTIME_H 1 + +/* Define to 1 if the system has the type `u_int64_t'. */ +/* #undef HAVE_U_INT64_T */ + +/* Define to 1 if you have the <windows.h> header file. */ +/* #undef HAVE_WINDOWS_H */ + +/* Define to 1 if you have the `__dso_handle' function. */ +#define HAVE___DSO_HANDLE 1 + +/* Installation directory for binary executables */ +#define LLVM_BINDIR "/usr/local/bin" + +/* Time at which LLVM was configured */ +#define LLVM_CONFIGTIME "Sat Oct 17 00:31:27 CEST 2009" + +/* Installation directory for data files */ +#define LLVM_DATADIR "/usr/local/share/llvm" + +/* Installation directory for documentation */ +#define LLVM_DOCSDIR "/usr/local/docs/llvm" + +/* Installation directory for config files */ +#define LLVM_ETCDIR "/usr/local/etc/llvm" + +/* Host triple we were built on */ +#define LLVM_HOSTTRIPLE "x86_64-unknown-freebsd7.2" + +/* Installation directory for include files */ +#define LLVM_INCLUDEDIR "/usr/local/include" + +/* Installation directory for .info files */ +#define LLVM_INFODIR "/usr/local/info" + +/* Installation directory for libraries */ +#define LLVM_LIBDIR "/usr/local/lib" + +/* Installation directory for man pages */ +#define LLVM_MANDIR "/usr/local/man" + +/* Build multithreading support into LLVM */ +#define LLVM_MULTITHREADED 1 + +/* LLVM architecture name for the native architecture, if available */ +#define LLVM_NATIVE_ARCH X86Target + +/* Define if this is Unixish platform */ +#define LLVM_ON_UNIX 1 + +/* Define if this is Win32ish platform */ +/* #undef LLVM_ON_WIN32 */ + +/* Define to path to circo program if found or 'echo circo' otherwise */ +/* #undef LLVM_PATH_CIRCO */ + +/* Define to path to dot program if found or 'echo dot' otherwise */ +/* #undef LLVM_PATH_DOT */ + +/* Define to path to dotty program if found or 'echo dotty' otherwise */ +/* #undef LLVM_PATH_DOTTY */ + +/* Define to path to fdp program if found or 'echo fdp' otherwise */ +/* #undef LLVM_PATH_FDP */ + +/* Define to path to Graphviz program if found or 'echo Graphviz' otherwise */ +/* #undef LLVM_PATH_GRAPHVIZ */ + +/* Define to path to gv program if found or 'echo gv' otherwise */ +/* #undef LLVM_PATH_GV */ + +/* Define to path to neato program if found or 'echo neato' otherwise */ +/* #undef LLVM_PATH_NEATO */ + +/* Define to path to twopi program if found or 'echo twopi' otherwise */ +/* #undef LLVM_PATH_TWOPI */ + +/* Installation prefix directory */ +#define LLVM_PREFIX "/usr/local" + +/* Define if the OS needs help to load dependent libraries for dlopen(). */ +#define LTDL_DLOPEN_DEPLIBS 1 + +/* Define to the sub-directory in which libtool stores uninstalled libraries. + */ +#define LTDL_OBJDIR ".libs/" + +/* Define to the name of the environment variable that determines the dynamic + library search path. */ +#define LTDL_SHLIBPATH_VAR "LD_LIBRARY_PATH" + +/* Define to the extension used for shared libraries, say, ".so". */ +#define LTDL_SHLIB_EXT ".so" + +/* Define to the system default library search path. */ +#define LTDL_SYSSEARCHPATH "/lib:/usr/lib" + +/* Define if /dev/zero should be used when mapping RWX memory, or undefine if + its not necessary */ +/* #undef NEED_DEV_ZERO_FOR_MMAP */ + +/* Define if dlsym() requires a leading underscore in symbol names. */ +/* #undef NEED_USCORE */ + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "llvmbugs@cs.uiuc.edu" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "llvm" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "llvm 2.7svn" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "-llvm-" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "2.7svn" + +/* Define as the return type of signal handlers (`int' or `void'). */ +#define RETSIGTYPE void + +/* If using the C implementation of alloca, define if you know the + direction of stack growth for your system; otherwise it will be + automatically deduced at runtime. + STACK_DIRECTION > 0 => grows toward higher addresses + STACK_DIRECTION < 0 => grows toward lower addresses + STACK_DIRECTION = 0 => direction of growth unknown */ +/* #undef STACK_DIRECTION */ + +/* Define to 1 if the `S_IS*' macros in <sys/stat.h> do not work properly. */ +/* #undef STAT_MACROS_BROKEN */ + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */ +#define TIME_WITH_SYS_TIME 1 + +/* Define to 1 if your <sys/time.h> declares `struct tm'. */ +/* #undef TM_IN_SYS_TIME */ + +/* Define if we have the oprofile JIT-support library */ +#define USE_OPROFILE 0 + +/* Define if use udis86 library */ +#define USE_UDIS86 0 + +/* Define to empty if `const' does not conform to ANSI C. */ +/* #undef const */ + +/* Define to a type to use for `error_t' if it is not otherwise available. */ +#define error_t int + +/* Define to `int' if <sys/types.h> does not define. */ +/* #undef pid_t */ + +/* Define to `unsigned int' if <sys/types.h> does not define. */ +/* #undef size_t */ diff --git a/include/llvm/Constants.h b/include/llvm/Constants.h index 7715286..2855fdc 100644 --- a/include/llvm/Constants.h +++ b/include/llvm/Constants.h @@ -22,15 +22,16 @@ #define LLVM_CONSTANTS_H #include "llvm/Constant.h" -#include "llvm/Type.h" #include "llvm/OperandTraits.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/APFloat.h" #include "llvm/ADT/SmallVector.h" +#include <vector> namespace llvm { class ArrayType; +class IntegerType; class StructType; class PointerType; class VectorType; diff --git a/include/llvm/ExecutionEngine/JITEventListener.h b/include/llvm/ExecutionEngine/JITEventListener.h index 8d3a1d7..e895e73 100644 --- a/include/llvm/ExecutionEngine/JITEventListener.h +++ b/include/llvm/ExecutionEngine/JITEventListener.h @@ -67,8 +67,7 @@ public: virtual void NotifyFreeingMachineCode(const Function &F, void *OldPtr) {} }; -// These return NULL if support isn't available. -JITEventListener *createMacOSJITEventListener(); +// This returns NULL if support isn't available. JITEventListener *createOProfileJITEventListener(); } // end namespace llvm. diff --git a/include/llvm/ExecutionEngine/JITMemoryManager.h b/include/llvm/ExecutionEngine/JITMemoryManager.h index 9f6fb63..56851889 100644 --- a/include/llvm/ExecutionEngine/JITMemoryManager.h +++ b/include/llvm/ExecutionEngine/JITMemoryManager.h @@ -132,9 +132,11 @@ public: /// virtual uint8_t *allocateGlobal(uintptr_t Size, unsigned Alignment) = 0; - /// deallocateMemForFunction - Free JIT memory for the specified function. - /// This is never called when the JIT is currently emitting a function. - virtual void deallocateMemForFunction(const Function *F) = 0; + /// deallocateFunctionBody - Free the specified function body. The argument + /// must be the return value from a call to startFunctionBody() that hasn't + /// been deallocated yet. This is never called when the JIT is currently + /// emitting a function. + virtual void deallocateFunctionBody(void *Body) = 0; /// startExceptionTable - When we finished JITing the function, if exception /// handling is set, we emit the exception table. @@ -146,6 +148,12 @@ public: virtual void endExceptionTable(const Function *F, uint8_t *TableStart, uint8_t *TableEnd, uint8_t* FrameRegister) = 0; + /// deallocateExceptionTable - Free the specified exception table's memory. + /// The argument must be the return value from a call to startExceptionTable() + /// that hasn't been deallocated yet. This is never called when the JIT is + /// currently emitting an exception table. + virtual void deallocateExceptionTable(void *ET) = 0; + /// CheckInvariants - For testing only. Return true if all internal /// invariants are preserved, or return false and set ErrorStr to a helpful /// error message. diff --git a/include/llvm/InlineAsm.h b/include/llvm/InlineAsm.h index bc55031..d54870e 100644 --- a/include/llvm/InlineAsm.h +++ b/include/llvm/InlineAsm.h @@ -31,11 +31,11 @@ class InlineAsm : public Value { std::string AsmString, Constraints; bool HasSideEffects; - bool IsMsAsm; + bool IsAlignStack; InlineAsm(const FunctionType *Ty, const StringRef &AsmString, const StringRef &Constraints, bool hasSideEffects, - bool isMsAsm = false); + bool isAlignStack = false); virtual ~InlineAsm(); public: @@ -43,10 +43,10 @@ public: /// static InlineAsm *get(const FunctionType *Ty, const StringRef &AsmString, const StringRef &Constraints, bool hasSideEffects, - bool isMsAsm = false); + bool isAlignStack = false); bool hasSideEffects() const { return HasSideEffects; } - bool isMsAsm() const { return IsMsAsm; } + bool isAlignStack() const { return IsAlignStack; } /// getType - InlineAsm's are always pointers. /// diff --git a/include/llvm/InstrTypes.h b/include/llvm/InstrTypes.h index cc923de..45d366f 100644 --- a/include/llvm/InstrTypes.h +++ b/include/llvm/InstrTypes.h @@ -116,8 +116,7 @@ public: // Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const UnaryInstruction *) { return true; } static inline bool classof(const Instruction *I) { - return I->getOpcode() == Instruction::Malloc || - I->getOpcode() == Instruction::Alloca || + return I->getOpcode() == Instruction::Alloca || I->getOpcode() == Instruction::Free || I->getOpcode() == Instruction::Load || I->getOpcode() == Instruction::VAArg || diff --git a/include/llvm/Instruction.def b/include/llvm/Instruction.def index e603c12..5c8fe3e 100644 --- a/include/llvm/Instruction.def +++ b/include/llvm/Instruction.def @@ -128,49 +128,48 @@ HANDLE_BINARY_INST(24, Xor , BinaryOperator) // Memory operators... FIRST_MEMORY_INST(25) -HANDLE_MEMORY_INST(25, Malloc, MallocInst) // Heap management instructions -HANDLE_MEMORY_INST(26, Free , FreeInst ) -HANDLE_MEMORY_INST(27, Alloca, AllocaInst) // Stack management -HANDLE_MEMORY_INST(28, Load , LoadInst ) // Memory manipulation instrs -HANDLE_MEMORY_INST(29, Store , StoreInst ) -HANDLE_MEMORY_INST(30, GetElementPtr, GetElementPtrInst) - LAST_MEMORY_INST(30) +HANDLE_MEMORY_INST(25, Free , FreeInst ) // Heap management instructions +HANDLE_MEMORY_INST(26, Alloca, AllocaInst) // Stack management +HANDLE_MEMORY_INST(27, Load , LoadInst ) // Memory manipulation instrs +HANDLE_MEMORY_INST(28, Store , StoreInst ) +HANDLE_MEMORY_INST(29, GetElementPtr, GetElementPtrInst) + LAST_MEMORY_INST(29) // Cast operators ... // NOTE: The order matters here because CastInst::isEliminableCastPair // NOTE: (see Instructions.cpp) encodes a table based on this ordering. - FIRST_CAST_INST(31) -HANDLE_CAST_INST(31, Trunc , TruncInst ) // Truncate integers -HANDLE_CAST_INST(32, ZExt , ZExtInst ) // Zero extend integers -HANDLE_CAST_INST(33, SExt , SExtInst ) // Sign extend integers -HANDLE_CAST_INST(34, FPToUI , FPToUIInst ) // floating point -> UInt -HANDLE_CAST_INST(35, FPToSI , FPToSIInst ) // floating point -> SInt -HANDLE_CAST_INST(36, UIToFP , UIToFPInst ) // UInt -> floating point -HANDLE_CAST_INST(37, SIToFP , SIToFPInst ) // SInt -> floating point -HANDLE_CAST_INST(38, FPTrunc , FPTruncInst ) // Truncate floating point -HANDLE_CAST_INST(39, FPExt , FPExtInst ) // Extend floating point -HANDLE_CAST_INST(40, PtrToInt, PtrToIntInst) // Pointer -> Integer -HANDLE_CAST_INST(41, IntToPtr, IntToPtrInst) // Integer -> Pointer -HANDLE_CAST_INST(42, BitCast , BitCastInst ) // Type cast - LAST_CAST_INST(42) + FIRST_CAST_INST(30) +HANDLE_CAST_INST(30, Trunc , TruncInst ) // Truncate integers +HANDLE_CAST_INST(31, ZExt , ZExtInst ) // Zero extend integers +HANDLE_CAST_INST(32, SExt , SExtInst ) // Sign extend integers +HANDLE_CAST_INST(33, FPToUI , FPToUIInst ) // floating point -> UInt +HANDLE_CAST_INST(34, FPToSI , FPToSIInst ) // floating point -> SInt +HANDLE_CAST_INST(35, UIToFP , UIToFPInst ) // UInt -> floating point +HANDLE_CAST_INST(36, SIToFP , SIToFPInst ) // SInt -> floating point +HANDLE_CAST_INST(37, FPTrunc , FPTruncInst ) // Truncate floating point +HANDLE_CAST_INST(38, FPExt , FPExtInst ) // Extend floating point +HANDLE_CAST_INST(39, PtrToInt, PtrToIntInst) // Pointer -> Integer +HANDLE_CAST_INST(40, IntToPtr, IntToPtrInst) // Integer -> Pointer +HANDLE_CAST_INST(41, BitCast , BitCastInst ) // Type cast + LAST_CAST_INST(41) // Other operators... - FIRST_OTHER_INST(43) -HANDLE_OTHER_INST(43, ICmp , ICmpInst ) // Integer comparison instruction -HANDLE_OTHER_INST(44, FCmp , FCmpInst ) // Floating point comparison instr. -HANDLE_OTHER_INST(45, PHI , PHINode ) // PHI node instruction -HANDLE_OTHER_INST(46, Call , CallInst ) // Call a function -HANDLE_OTHER_INST(47, Select , SelectInst ) // select instruction -HANDLE_OTHER_INST(48, UserOp1, Instruction) // May be used internally in a pass -HANDLE_OTHER_INST(49, UserOp2, Instruction) // Internal to passes only -HANDLE_OTHER_INST(50, VAArg , VAArgInst ) // vaarg instruction -HANDLE_OTHER_INST(51, ExtractElement, ExtractElementInst)// extract from vector -HANDLE_OTHER_INST(52, InsertElement, InsertElementInst) // insert into vector -HANDLE_OTHER_INST(53, ShuffleVector, ShuffleVectorInst) // shuffle two vectors. -HANDLE_OTHER_INST(54, ExtractValue, ExtractValueInst)// extract from aggregate -HANDLE_OTHER_INST(55, InsertValue, InsertValueInst) // insert into aggregate - - LAST_OTHER_INST(55) + FIRST_OTHER_INST(42) +HANDLE_OTHER_INST(42, ICmp , ICmpInst ) // Integer comparison instruction +HANDLE_OTHER_INST(43, FCmp , FCmpInst ) // Floating point comparison instr. +HANDLE_OTHER_INST(44, PHI , PHINode ) // PHI node instruction +HANDLE_OTHER_INST(45, Call , CallInst ) // Call a function +HANDLE_OTHER_INST(46, Select , SelectInst ) // select instruction +HANDLE_OTHER_INST(47, UserOp1, Instruction) // May be used internally in a pass +HANDLE_OTHER_INST(48, UserOp2, Instruction) // Internal to passes only +HANDLE_OTHER_INST(49, VAArg , VAArgInst ) // vaarg instruction +HANDLE_OTHER_INST(50, ExtractElement, ExtractElementInst)// extract from vector +HANDLE_OTHER_INST(51, InsertElement, InsertElementInst) // insert into vector +HANDLE_OTHER_INST(52, ShuffleVector, ShuffleVectorInst) // shuffle two vectors. +HANDLE_OTHER_INST(53, ExtractValue, ExtractValueInst)// extract from aggregate +HANDLE_OTHER_INST(54, InsertValue, InsertValueInst) // insert into aggregate + + LAST_OTHER_INST(54) #undef FIRST_TERM_INST #undef HANDLE_TERM_INST diff --git a/include/llvm/Instructions.h b/include/llvm/Instructions.h index b28fcbb..dbeb9e1 100644 --- a/include/llvm/Instructions.h +++ b/include/llvm/Instructions.h @@ -37,8 +37,7 @@ class DominatorTree; // AllocationInst Class //===----------------------------------------------------------------------===// -/// AllocationInst - This class is the common base class of MallocInst and -/// AllocaInst. +/// AllocationInst - This class is the base class of AllocaInst. /// class AllocationInst : public UnaryInstruction { protected: @@ -85,56 +84,7 @@ public: // Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const AllocationInst *) { return true; } static inline bool classof(const Instruction *I) { - return I->getOpcode() == Instruction::Alloca || - I->getOpcode() == Instruction::Malloc; - } - static inline bool classof(const Value *V) { - return isa<Instruction>(V) && classof(cast<Instruction>(V)); - } -}; - - -//===----------------------------------------------------------------------===// -// MallocInst Class -//===----------------------------------------------------------------------===// - -/// MallocInst - an instruction to allocated memory on the heap -/// -class MallocInst : public AllocationInst { -public: - explicit MallocInst(const Type *Ty, Value *ArraySize = 0, - const Twine &NameStr = "", - Instruction *InsertBefore = 0) - : AllocationInst(Ty, ArraySize, Malloc, - 0, NameStr, InsertBefore) {} - MallocInst(const Type *Ty, Value *ArraySize, - const Twine &NameStr, BasicBlock *InsertAtEnd) - : AllocationInst(Ty, ArraySize, Malloc, 0, NameStr, InsertAtEnd) {} - - MallocInst(const Type *Ty, const Twine &NameStr, - Instruction *InsertBefore = 0) - : AllocationInst(Ty, 0, Malloc, 0, NameStr, InsertBefore) {} - MallocInst(const Type *Ty, const Twine &NameStr, - BasicBlock *InsertAtEnd) - : AllocationInst(Ty, 0, Malloc, 0, NameStr, InsertAtEnd) {} - - MallocInst(const Type *Ty, Value *ArraySize, - unsigned Align, const Twine &NameStr, - BasicBlock *InsertAtEnd) - : AllocationInst(Ty, ArraySize, Malloc, - Align, NameStr, InsertAtEnd) {} - MallocInst(const Type *Ty, Value *ArraySize, - unsigned Align, const Twine &NameStr = "", - Instruction *InsertBefore = 0) - : AllocationInst(Ty, ArraySize, - Malloc, Align, NameStr, InsertBefore) {} - - virtual MallocInst *clone() const; - - // Methods for support type inquiry through isa, cast, and dyn_cast: - static inline bool classof(const MallocInst *) { return true; } - static inline bool classof(const Instruction *I) { - return (I->getOpcode() == Instruction::Malloc); + return I->getOpcode() == Instruction::Alloca; } static inline bool classof(const Value *V) { return isa<Instruction>(V) && classof(cast<Instruction>(V)); @@ -1042,12 +992,14 @@ public: /// constant 1. /// 2. Call malloc with that argument. /// 3. Bitcast the result of the malloc call to the specified type. - static Value *CreateMalloc(Instruction *InsertBefore, const Type *IntPtrTy, - const Type *AllocTy, Value *ArraySize = 0, - const Twine &Name = ""); - static Value *CreateMalloc(BasicBlock *InsertAtEnd, const Type *IntPtrTy, - const Type *AllocTy, Value *ArraySize = 0, - const Twine &Name = ""); + static Instruction *CreateMalloc(Instruction *InsertBefore, + const Type *IntPtrTy, const Type *AllocTy, + Value *ArraySize = 0, + const Twine &Name = ""); + static Instruction *CreateMalloc(BasicBlock *InsertAtEnd, + const Type *IntPtrTy, const Type *AllocTy, + Value *ArraySize = 0, Function* MallocF = 0, + const Twine &Name = ""); ~CallInst(); @@ -1148,10 +1100,15 @@ public: } /// getCalledValue - Get a pointer to the function that is invoked by this - /// instruction + /// instruction. const Value *getCalledValue() const { return Op<0>(); } Value *getCalledValue() { return Op<0>(); } + /// setCalledFunction - Set the function called. + void setCalledFunction(Value* Fn) { + Op<0>() = Fn; + } + // Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const CallInst *) { return true; } static inline bool classof(const Instruction *I) { diff --git a/include/llvm/Intrinsics.td b/include/llvm/Intrinsics.td index 38ac4c2..e6d8007 100644 --- a/include/llvm/Intrinsics.td +++ b/include/llvm/Intrinsics.td @@ -474,4 +474,3 @@ include "llvm/IntrinsicsARM.td" include "llvm/IntrinsicsCellSPU.td" include "llvm/IntrinsicsAlpha.td" include "llvm/IntrinsicsXCore.td" -include "llvm/IntrinsicsBlackfin.td" diff --git a/include/llvm/LLVMContext.h b/include/llvm/LLVMContext.h index a135f67..b9ffeb0 100644 --- a/include/llvm/LLVMContext.h +++ b/include/llvm/LLVMContext.h @@ -33,7 +33,6 @@ class LLVMContext { public: LLVMContextImpl* const pImpl; MetadataContext &getMetadata(); - bool RemoveDeadMetadata(); LLVMContext(); ~LLVMContext(); }; diff --git a/include/llvm/LinkAllPasses.h b/include/llvm/LinkAllPasses.h index e9a0542..3342ea8 100644 --- a/include/llvm/LinkAllPasses.h +++ b/include/llvm/LinkAllPasses.h @@ -16,6 +16,7 @@ #define LLVM_LINKALLPASSES_H #include "llvm/Analysis/AliasSetTracker.h" +#include "llvm/Analysis/DomPrinter.h" #include "llvm/Analysis/FindUsedTypes.h" #include "llvm/Analysis/IntervalPartition.h" #include "llvm/Analysis/Passes.h" @@ -62,6 +63,10 @@ namespace { (void) llvm::createDeadInstEliminationPass(); (void) llvm::createDeadStoreEliminationPass(); (void) llvm::createDeadTypeEliminationPass(); + (void) llvm::createDomOnlyPrinterPass(); + (void) llvm::createDomPrinterPass(); + (void) llvm::createDomOnlyViewerPass(); + (void) llvm::createDomViewerPass(); (void) llvm::createEdgeProfilerPass(); (void) llvm::createOptimalEdgeProfilerPass(); (void) llvm::createFunctionInliningPass(); @@ -98,6 +103,10 @@ namespace { (void) llvm::createPromoteMemoryToRegisterPass(); (void) llvm::createDemoteRegisterToMemoryPass(); (void) llvm::createPruneEHPass(); + (void) llvm::createPostDomOnlyPrinterPass(); + (void) llvm::createPostDomPrinterPass(); + (void) llvm::createPostDomOnlyViewerPass(); + (void) llvm::createPostDomViewerPass(); (void) llvm::createRaiseAllocationsPass(); (void) llvm::createReassociatePass(); (void) llvm::createSCCPPass(); @@ -115,7 +124,6 @@ namespace { (void) llvm::createCondPropagationPass(); (void) llvm::createNullProfilerRSPass(); (void) llvm::createRSProfilingPass(); - (void) llvm::createIndMemRemPass(); (void) llvm::createInstCountPass(); (void) llvm::createCodeGenLICMPass(); (void) llvm::createCodeGenPreparePass(); diff --git a/include/llvm/MC/MCAssembler.h b/include/llvm/MC/MCAssembler.h index 892f548..76ed3df 100644 --- a/include/llvm/MC/MCAssembler.h +++ b/include/llvm/MC/MCAssembler.h @@ -13,7 +13,6 @@ #include "llvm/ADT/SmallString.h" #include "llvm/ADT/ilist.h" #include "llvm/ADT/ilist_node.h" -#include "llvm/MC/MCValue.h" #include "llvm/Support/Casting.h" #include "llvm/Support/DataTypes.h" #include <vector> // FIXME: Shouldn't be needed. @@ -22,8 +21,10 @@ namespace llvm { class raw_ostream; class MCAssembler; class MCContext; +class MCExpr; class MCSection; class MCSectionData; +class MCSymbol; class MCFragment : public ilist_node<MCFragment> { MCFragment(const MCFragment&); // DO NOT IMPLEMENT @@ -174,7 +175,7 @@ public: class MCFillFragment : public MCFragment { /// Value - Value to use for filling bytes. - MCValue Value; + const MCExpr *Value; /// ValueSize - The size (in bytes) of \arg Value to use when filling. unsigned ValueSize; @@ -183,10 +184,10 @@ class MCFillFragment : public MCFragment { uint64_t Count; public: - MCFillFragment(MCValue _Value, unsigned _ValueSize, uint64_t _Count, + MCFillFragment(const MCExpr &_Value, unsigned _ValueSize, uint64_t _Count, MCSectionData *SD = 0) : MCFragment(FT_Fill, SD), - Value(_Value), ValueSize(_ValueSize), Count(_Count) {} + Value(&_Value), ValueSize(_ValueSize), Count(_Count) {} /// @name Accessors /// @{ @@ -195,7 +196,7 @@ public: return ValueSize * Count; } - MCValue getValue() const { return Value; } + const MCExpr &getValue() const { return *Value; } unsigned getValueSize() const { return ValueSize; } @@ -211,15 +212,15 @@ public: class MCOrgFragment : public MCFragment { /// Offset - The offset this fragment should start at. - MCValue Offset; + const MCExpr *Offset; /// Value - Value to use for filling bytes. int8_t Value; public: - MCOrgFragment(MCValue _Offset, int8_t _Value, MCSectionData *SD = 0) + MCOrgFragment(const MCExpr &_Offset, int8_t _Value, MCSectionData *SD = 0) : MCFragment(FT_Org, SD), - Offset(_Offset), Value(_Value) {} + Offset(&_Offset), Value(_Value) {} /// @name Accessors /// @{ @@ -229,7 +230,7 @@ public: return ~UINT64_C(0); } - MCValue getOffset() const { return Offset; } + const MCExpr &getOffset() const { return *Offset; } uint8_t getValue() const { return Value; } @@ -294,10 +295,7 @@ public: uint64_t Offset; /// Value - The expression to eventually write into the fragment. - // - // FIXME: We could probably get away with requiring the client to pass in an - // owned reference whose lifetime extends past that of the fixup. - MCValue Value; + const MCExpr *Value; /// Size - The fixup size. unsigned Size; @@ -308,9 +306,9 @@ public: uint64_t FixedValue; public: - Fixup(MCFragment &_Fragment, uint64_t _Offset, const MCValue &_Value, + Fixup(MCFragment &_Fragment, uint64_t _Offset, const MCExpr &_Value, unsigned _Size) - : Fragment(&_Fragment), Offset(_Offset), Value(_Value), Size(_Size), + : Fragment(&_Fragment), Offset(_Offset), Value(&_Value), Size(_Size), FixedValue(0) {} }; diff --git a/include/llvm/MC/MCContext.h b/include/llvm/MC/MCContext.h index 955aa8b..fa20f45 100644 --- a/include/llvm/MC/MCContext.h +++ b/include/llvm/MC/MCContext.h @@ -15,10 +15,11 @@ #include "llvm/Support/Allocator.h" namespace llvm { - class MCValue; + class MCExpr; class MCSection; class MCSymbol; class StringRef; + class Twine; /// MCContext - Context object for machine code objects. This class owns all /// of the sections that it creates. @@ -33,11 +34,6 @@ namespace llvm { /// Symbols - Bindings of names to symbols. StringMap<MCSymbol*> Symbols; - /// SymbolValues - Bindings of symbols to values. - // - // FIXME: Is there a good reason to not just put this in the MCSymbol? - DenseMap<const MCSymbol*, MCValue> SymbolValues; - /// Allocator - Allocator object used for creating machine code objects. /// /// We use a bump pointer allocator to avoid the need to track all allocated @@ -63,7 +59,8 @@ namespace llvm { /// @param IsTemporary - Whether this symbol is an assembler temporary, /// which should not survive into the symbol table for the translation unit. MCSymbol *GetOrCreateSymbol(const StringRef &Name); - + MCSymbol *GetOrCreateSymbol(const Twine &Name); + /// CreateTemporarySymbol - Create a new temporary symbol with the specified /// @param Name. /// @@ -76,25 +73,11 @@ namespace llvm { MCSymbol *LookupSymbol(const StringRef &Name) const; /// @} - /// @name Symbol Value Table - /// @{ - - /// ClearSymbolValue - Erase a value binding for @arg Symbol, if one exists. - void ClearSymbolValue(const MCSymbol *Symbol); - - /// SetSymbolValue - Set the value binding for @arg Symbol to @arg Value. - void SetSymbolValue(const MCSymbol *Symbol, const MCValue &Value); - - /// GetSymbolValue - Return the current value for @arg Symbol, or null if - /// none exists. - const MCValue *GetSymbolValue(const MCSymbol *Symbol) const; - - /// @} void *Allocate(unsigned Size, unsigned Align = 8) { return Allocator.Allocate(Size, Align); } - void Deallocate(void *Ptr) { + void Deallocate(void *Ptr) { } }; diff --git a/include/llvm/MC/MCExpr.h b/include/llvm/MC/MCExpr.h index 19a32e7..7a2a0d5 100644 --- a/include/llvm/MC/MCExpr.h +++ b/include/llvm/MC/MCExpr.h @@ -62,14 +62,14 @@ public: /// /// @param Res - The absolute value, if evaluation succeeds. /// @result - True on success. - bool EvaluateAsAbsolute(MCContext &Ctx, int64_t &Res) const; + bool EvaluateAsAbsolute(int64_t &Res) const; /// EvaluateAsRelocatable - Try to evaluate the expression to a relocatable /// value, i.e. an expression of the fixed form (a - b + constant). /// /// @param Res - The relocatable value, if evaluation succeeds. /// @result - True on success. - bool EvaluateAsRelocatable(MCContext &Ctx, MCValue &Res) const; + bool EvaluateAsRelocatable(MCValue &Res) const; /// @} @@ -121,9 +121,7 @@ public: static const MCSymbolRefExpr *Create(const MCSymbol *Symbol, MCContext &Ctx); static const MCSymbolRefExpr *Create(const StringRef &Name, MCContext &Ctx); - - - + /// @} /// @name Accessors /// @{ diff --git a/include/llvm/MC/MCSymbol.h b/include/llvm/MC/MCSymbol.h index 5dd7d68..d08f0e5 100644 --- a/include/llvm/MC/MCSymbol.h +++ b/include/llvm/MC/MCSymbol.h @@ -20,6 +20,7 @@ namespace llvm { class MCAsmInfo; + class MCExpr; class MCSection; class MCContext; class raw_ostream; @@ -45,6 +46,9 @@ namespace llvm { /// absolute symbols. const MCSection *Section; + /// Value - If non-null, the value for a variable symbol. + const MCExpr *Value; + /// IsTemporary - True if this is an assembler temporary label, which /// typically does not survive in the .o file's symbol table. Usually /// "Lfoo" or ".foo". @@ -52,9 +56,9 @@ namespace llvm { private: // MCContext creates and uniques these. friend class MCContext; - MCSymbol(const StringRef &_Name, bool _IsTemporary) - : Name(_Name), Section(0), IsTemporary(_IsTemporary) {} - + MCSymbol(const StringRef &_Name, bool _IsTemporary) + : Name(_Name), Section(0), Value(0), IsTemporary(_IsTemporary) {} + MCSymbol(const MCSymbol&); // DO NOT IMPLEMENT void operator=(const MCSymbol&); // DO NOT IMPLEMENT public: @@ -69,6 +73,10 @@ namespace llvm { return IsTemporary; } + /// @} + /// @name Associated Sections + /// @{ + /// isDefined - Check if this symbol is defined (i.e., it has an address). /// /// Defined symbols are either absolute or in some section. @@ -105,6 +113,23 @@ namespace llvm { void setAbsolute() { Section = AbsolutePseudoSection; } /// @} + /// @name Variable Symbols + /// @{ + + /// isVariable - Check if this is a variable symbol. + bool isVariable() const { + return Value != 0; + } + + /// getValue() - Get the value for variable symbols, or null if the symbol + /// is not a variable. + const MCExpr *getValue() const { return Value; } + + void setValue(const MCExpr *Value) { + this->Value = Value; + } + + /// @} /// print - Print the value to the stream \arg OS. void print(raw_ostream &OS, const MCAsmInfo *MAI) const; diff --git a/include/llvm/Metadata.h b/include/llvm/Metadata.h index 13b97b9..c983015 100644 --- a/include/llvm/Metadata.h +++ b/include/llvm/Metadata.h @@ -13,46 +13,30 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_MDNODE_H -#define LLVM_MDNODE_H +#ifndef LLVM_METADATA_H +#define LLVM_METADATA_H -#include "llvm/User.h" +#include "llvm/Value.h" #include "llvm/Type.h" -#include "llvm/OperandTraits.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/SmallPtrSet.h" -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/StringMap.h" #include "llvm/ADT/ilist_node.h" -#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ValueHandle.h" namespace llvm { class Constant; class Instruction; class LLVMContext; +class MetadataContextImpl; //===----------------------------------------------------------------------===// // MetadataBase - A base class for MDNode, MDString and NamedMDNode. -class MetadataBase : public User { -private: - /// ReservedSpace - The number of operands actually allocated. NumOperands is - /// the number actually in use. - unsigned ReservedSpace; - +class MetadataBase : public Value { protected: MetadataBase(const Type *Ty, unsigned scid) - : User(Ty, scid, NULL, 0), ReservedSpace(0) {} + : Value(Ty, scid) {} - void resizeOperands(unsigned NumOps); public: - /// isNullValue - Return true if this is the value that would be returned by - /// getNullValue. This always returns false because getNullValue will never - /// produce metadata. - virtual bool isNullValue() const { - return false; - } /// Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const MetadataBase *) { return true; } @@ -68,32 +52,28 @@ public: /// MDString is always unnamd. class MDString : public MetadataBase { MDString(const MDString &); // DO NOT IMPLEMENT - void *operator new(size_t, unsigned); // DO NOT IMPLEMENT - unsigned getNumOperands(); // DO NOT IMPLEMENT StringRef Str; protected: - explicit MDString(LLVMContext &C, const char *begin, unsigned l) - : MetadataBase(Type::getMetadataTy(C), Value::MDStringVal), Str(begin, l) {} + explicit MDString(LLVMContext &C, StringRef S) + : MetadataBase(Type::getMetadataTy(C), Value::MDStringVal), Str(S) {} public: - // Do not allocate any space for operands. - void *operator new(size_t s) { - return User::operator new(s, 0); - } - static MDString *get(LLVMContext &Context, const StringRef &Str); + static MDString *get(LLVMContext &Context, StringRef Str); StringRef getString() const { return Str; } - unsigned length() const { return Str.size(); } + unsigned getLength() const { return Str.size(); } + typedef StringRef::iterator iterator; + /// begin() - Pointer to the first byte of the string. /// - const char *begin() const { return Str.begin(); } + iterator begin() const { return Str.begin(); } /// end() - Pointer to one byte past the end of the string. /// - const char *end() const { return Str.end(); } + iterator end() const { return Str.end(); } /// Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const MDString *) { return true; } @@ -108,14 +88,12 @@ public: /// MDNode is always unnamed. class MDNode : public MetadataBase, public FoldingSetNode { MDNode(const MDNode &); // DO NOT IMPLEMENT - void *operator new(size_t, unsigned); // DO NOT IMPLEMENT - // getNumOperands - Make this only available for private uses. - unsigned getNumOperands() { return User::getNumOperands(); } friend class ElementVH; // Use CallbackVH to hold MDNOde elements. struct ElementVH : public CallbackVH { MDNode *Parent; + ElementVH() {} ElementVH(Value *V, MDNode *P) : CallbackVH(V), Parent(P) {} ~ElementVH() {} @@ -130,61 +108,32 @@ class MDNode : public MetadataBase, public FoldingSetNode { // Replace each instance of F from the element list of this node with T. void replaceElement(Value *F, Value *T); - SmallVector<ElementVH, 4> Node; + ElementVH *Node; + unsigned NodeSize; protected: - explicit MDNode(LLVMContext &C, Value*const* Vals, unsigned NumVals); + explicit MDNode(LLVMContext &C, Value *const *Vals, unsigned NumVals); public: - // Do not allocate any space for operands. - void *operator new(size_t s) { - return User::operator new(s, 0); - } // Constructors and destructors. static MDNode *get(LLVMContext &Context, - Value* const* Vals, unsigned NumVals); - - /// dropAllReferences - Remove all uses and clear node vector. - void dropAllReferences(); + Value *const *Vals, unsigned NumVals); /// ~MDNode - Destroy MDNode. ~MDNode(); /// getElement - Return specified element. Value *getElement(unsigned i) const { - assert (getNumElements() > i && "Invalid element number!"); + assert(i < getNumElements() && "Invalid element number!"); return Node[i]; } /// getNumElements - Return number of MDNode elements. - unsigned getNumElements() const { - return Node.size(); - } - - // Element access - typedef SmallVectorImpl<ElementVH>::const_iterator const_elem_iterator; - typedef SmallVectorImpl<ElementVH>::iterator elem_iterator; - /// elem_empty - Return true if MDNode is empty. - bool elem_empty() const { return Node.empty(); } - const_elem_iterator elem_begin() const { return Node.begin(); } - const_elem_iterator elem_end() const { return Node.end(); } - elem_iterator elem_begin() { return Node.begin(); } - elem_iterator elem_end() { return Node.end(); } - - /// isNullValue - Return true if this is the value that would be returned by - /// getNullValue. This always returns false because getNullValue will never - /// produce metadata. - virtual bool isNullValue() const { - return false; - } + unsigned getNumElements() const { return NodeSize; } /// Profile - calculate a unique identifier for this MDNode to collapse /// duplicates void Profile(FoldingSetNodeID &ID) const; - virtual void replaceUsesOfWithOnConstant(Value *, Value *, Use *) { - llvm_unreachable("This should never be called because MDNodes have no ops"); - } - /// Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const MDNode *) { return true; } static bool classof(const Value *V) { @@ -193,23 +142,6 @@ public: }; //===----------------------------------------------------------------------===// -/// WeakMetadataVH - a weak value handle for metadata. -class WeakMetadataVH : public WeakVH { -public: - WeakMetadataVH() : WeakVH() {} - WeakMetadataVH(MetadataBase *M) : WeakVH(M) {} - WeakMetadataVH(const WeakMetadataVH &RHS) : WeakVH(RHS) {} - - operator Value*() const { - llvm_unreachable("WeakMetadataVH only handles Metadata"); - } - - operator MetadataBase*() const { - return dyn_cast_or_null<MetadataBase>(getValPtr()); - } -}; - -//===----------------------------------------------------------------------===// /// NamedMDNode - a tuple of other metadata. /// NamedMDNode is always named. All NamedMDNode element has a type of metadata. template<typename ValueSubClass, typename ItemParentClass> @@ -220,24 +152,17 @@ class NamedMDNode : public MetadataBase, public ilist_node<NamedMDNode> { friend class LLVMContextImpl; NamedMDNode(const NamedMDNode &); // DO NOT IMPLEMENT - void *operator new(size_t, unsigned); // DO NOT IMPLEMENT - // getNumOperands - Make this only available for private uses. - unsigned getNumOperands() { return User::getNumOperands(); } Module *Parent; - SmallVector<WeakMetadataVH, 4> Node; - typedef SmallVectorImpl<WeakMetadataVH>::iterator elem_iterator; + SmallVector<TrackingVH<MetadataBase>, 4> Node; + void setParent(Module *M) { Parent = M; } protected: - explicit NamedMDNode(LLVMContext &C, const Twine &N, MetadataBase*const* Vals, + explicit NamedMDNode(LLVMContext &C, const Twine &N, MetadataBase*const *Vals, unsigned NumVals, Module *M = 0); public: - // Do not allocate any space for operands. - void *operator new(size_t s) { - return User::operator new(s, 0); - } static NamedMDNode *Create(LLVMContext &C, const Twine &N, - MetadataBase*const*MDs, + MetadataBase *const *MDs, unsigned NumMDs, Module *M = 0) { return new NamedMDNode(C, N, MDs, NumMDs, M); } @@ -257,11 +182,10 @@ public: /// getParent - Get the module that holds this named metadata collection. inline Module *getParent() { return Parent; } inline const Module *getParent() const { return Parent; } - void setParent(Module *M) { Parent = M; } /// getElement - Return specified element. MetadataBase *getElement(unsigned i) const { - assert (getNumElements() > i && "Invalid element number!"); + assert(i < getNumElements() && "Invalid element number!"); return Node[i]; } @@ -272,30 +196,18 @@ public: /// addElement - Add metadata element. void addElement(MetadataBase *M) { - resizeOperands(0); - OperandList[NumOperands++] = M; - Node.push_back(WeakMetadataVH(M)); + Node.push_back(TrackingVH<MetadataBase>(M)); } - typedef SmallVectorImpl<WeakMetadataVH>::const_iterator const_elem_iterator; + typedef SmallVectorImpl<TrackingVH<MetadataBase> >::iterator elem_iterator; + typedef SmallVectorImpl<TrackingVH<MetadataBase> >::const_iterator + const_elem_iterator; bool elem_empty() const { return Node.empty(); } const_elem_iterator elem_begin() const { return Node.begin(); } const_elem_iterator elem_end() const { return Node.end(); } elem_iterator elem_begin() { return Node.begin(); } elem_iterator elem_end() { return Node.end(); } - /// isNullValue - Return true if this is the value that would be returned by - /// getNullValue. This always returns false because getNullValue will never - /// produce metadata. - virtual bool isNullValue() const { - return false; - } - - virtual void replaceUsesOfWithOnConstant(Value *, Value *, Use *) { - llvm_unreachable( - "This should never be called because NamedMDNodes have no ops"); - } - /// Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const NamedMDNode *) { return true; } static bool classof(const Value *V) { @@ -310,61 +222,55 @@ public: /// must start with an alphabet. The regular expression used to check name /// is [a-zA-Z$._][a-zA-Z$._0-9]* class MetadataContext { -public: - typedef std::pair<unsigned, WeakVH> MDPairTy; - typedef SmallVector<MDPairTy, 2> MDMapTy; - typedef DenseMap<const Instruction *, MDMapTy> MDStoreTy; - friend class BitcodeReader; -private: - - /// MetadataStore - Collection of metadata used in this context. - MDStoreTy MetadataStore; - - /// MDHandlerNames - Map to hold metadata handler names. - StringMap<unsigned> MDHandlerNames; + // DO NOT IMPLEMENT + MetadataContext(MetadataContext&); + void operator=(MetadataContext&); + MetadataContextImpl *const pImpl; public: - /// RegisterMDKind - Register a new metadata kind and return its ID. + MetadataContext(); + ~MetadataContext(); + + /// registerMDKind - Register a new metadata kind and return its ID. /// A metadata kind can be registered only once. - unsigned RegisterMDKind(const char *Name); + unsigned registerMDKind(StringRef Name); /// getMDKind - Return metadata kind. If the requested metadata kind /// is not registered then return 0. - unsigned getMDKind(const char *Name); + unsigned getMDKind(StringRef Name) const; - /// validName - Return true if Name is a valid custom metadata handler name. - bool validName(const char *Name); + /// isValidName - Return true if Name is a valid custom metadata handler name. + static bool isValidName(StringRef Name); - /// getMD - Get the metadata of given kind attached with an Instruction. + /// getMD - Get the metadata of given kind attached to an Instruction. /// If the metadata is not found then return 0. MDNode *getMD(unsigned Kind, const Instruction *Inst); - /// getMDs - Get the metadata attached with an Instruction. - const MDMapTy *getMDs(const Instruction *Inst); + /// getMDs - Get the metadata attached to an Instruction. + void getMDs(const Instruction *Inst, + SmallVectorImpl<std::pair<unsigned, TrackingVH<MDNode> > > &MDs) const; - /// addMD - Attach the metadata of given kind with an Instruction. + /// addMD - Attach the metadata of given kind to an Instruction. void addMD(unsigned Kind, MDNode *Node, Instruction *Inst); /// removeMD - Remove metadata of given kind attached with an instuction. void removeMD(unsigned Kind, Instruction *Inst); - /// removeMDs - Remove all metadata attached with an instruction. - void removeMDs(const Instruction *Inst); + /// removeAllMetadata - Remove all metadata attached with an instruction. + void removeAllMetadata(Instruction *Inst); /// copyMD - If metadata is attached with Instruction In1 then attach /// the same metadata to In2. void copyMD(Instruction *In1, Instruction *In2); - /// getHandlerNames - Get handler names. This is used by bitcode - /// writer. - const StringMap<unsigned> *getHandlerNames(); + /// getHandlerNames - Populate client supplied smallvector using custome + /// metadata name and ID. + void getHandlerNames(SmallVectorImpl<std::pair<unsigned, StringRef> >&) const; /// ValueIsDeleted - This handler is used to update metadata store /// when a value is deleted. void ValueIsDeleted(const Value *) {} - void ValueIsDeleted(const Instruction *Inst) { - removeMDs(Inst); - } + void ValueIsDeleted(Instruction *Inst); void ValueIsRAUWd(Value *V1, Value *V2); /// ValueIsCloned - This handler is used to update metadata store diff --git a/include/llvm/PassAnalysisSupport.h b/include/llvm/PassAnalysisSupport.h index f339481..690d080 100644 --- a/include/llvm/PassAnalysisSupport.h +++ b/include/llvm/PassAnalysisSupport.h @@ -20,14 +20,13 @@ #define LLVM_PASS_ANALYSIS_SUPPORT_H #include <vector> +#include "llvm/Pass.h" #include "llvm/ADT/SmallVector.h" namespace llvm { class StringRef; -// No need to include Pass.h, we are being included by it! - //===----------------------------------------------------------------------===// // AnalysisUsage - Represent the analysis usage information of a pass. This // tracks analyses that the pass REQUIRES (must be available when the pass diff --git a/include/llvm/PassSupport.h b/include/llvm/PassSupport.h index b5e581a..d7f3097 100644 --- a/include/llvm/PassSupport.h +++ b/include/llvm/PassSupport.h @@ -21,7 +21,7 @@ #ifndef LLVM_PASS_SUPPORT_H #define LLVM_PASS_SUPPORT_H -// No need to include Pass.h, we are being included by it! +#include "Pass.h" namespace llvm { diff --git a/include/llvm/Support/DataTypes.h b/include/llvm/Support/DataTypes.h new file mode 100644 index 0000000..0a763e0 --- /dev/null +++ b/include/llvm/Support/DataTypes.h @@ -0,0 +1,148 @@ +/* include/llvm/Support/DataTypes.h. Generated from DataTypes.h.in by configure. */ +/*===-- include/Support/DataTypes.h - Define fixed size types -----*- C -*-===*\ +|* *| +|* The LLVM Compiler Infrastructure *| +|* *| +|* This file is distributed under the University of Illinois Open Source *| +|* License. See LICENSE.TXT for details. *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* This file contains definitions to figure out the size of _HOST_ data types.*| +|* This file is important because different host OS's define different macros,*| +|* which makes portability tough. This file exports the following *| +|* definitions: *| +|* *| +|* [u]int(32|64)_t : typedefs for signed and unsigned 32/64 bit system types*| +|* [U]INT(8|16|32|64)_(MIN|MAX) : Constants for the min and max values. *| +|* *| +|* No library is required when using these functinons. *| +|* *| +|*===----------------------------------------------------------------------===*/ + +/* Please leave this file C-compatible. */ + +#ifndef SUPPORT_DATATYPES_H +#define SUPPORT_DATATYPES_H + +#define HAVE_SYS_TYPES_H 1 +#define HAVE_INTTYPES_H 1 +#define HAVE_STDINT_H 1 +#define HAVE_UINT64_T 1 +/* #undef HAVE_U_INT64_T */ + +#ifdef __cplusplus +#include <cmath> +#else +#include <math.h> +#endif + +#ifndef _MSC_VER + +/* Note that this header's correct operation depends on __STDC_LIMIT_MACROS + being defined. We would define it here, but in order to prevent Bad Things + happening when system headers or C++ STL headers include stdint.h before we + define it here, we define it on the g++ command line (in Makefile.rules). */ +#if !defined(__STDC_LIMIT_MACROS) +# error "Must #define __STDC_LIMIT_MACROS before #including Support/DataTypes.h" +#endif + +#if !defined(__STDC_CONSTANT_MACROS) +# error "Must #define __STDC_CONSTANT_MACROS before " \ + "#including Support/DataTypes.h" +#endif + +/* Note that <inttypes.h> includes <stdint.h>, if this is a C99 system. */ +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif + +#ifdef HAVE_INTTYPES_H +#include <inttypes.h> +#endif + +#ifdef HAVE_STDINT_H +#include <stdint.h> +#endif + +#ifdef _AIX +#include "llvm/Support/AIXDataTypesFix.h" +#endif + +/* Handle incorrect definition of uint64_t as u_int64_t */ +#ifndef HAVE_UINT64_T +#ifdef HAVE_U_INT64_T +typedef u_int64_t uint64_t; +#else +# error "Don't have a definition for uint64_t on this platform" +#endif +#endif + +#ifdef _OpenBSD_ +#define INT8_MAX 127 +#define INT8_MIN -128 +#define UINT8_MAX 255 +#define INT16_MAX 32767 +#define INT16_MIN -32768 +#define UINT16_MAX 65535 +#define INT32_MAX 2147483647 +#define INT32_MIN -2147483648 +#define UINT32_MAX 4294967295U +#endif + +#else /* _MSC_VER */ +/* Visual C++ doesn't provide standard integer headers, but it does provide + built-in data types. */ +#include <stdlib.h> +#include <stddef.h> +#include <sys/types.h> +typedef __int64 int64_t; +typedef unsigned __int64 uint64_t; +typedef signed int int32_t; +typedef unsigned int uint32_t; +typedef short int16_t; +typedef unsigned short uint16_t; +typedef signed char int8_t; +typedef unsigned char uint8_t; +typedef signed int ssize_t; +#define INT8_MAX 127 +#define INT8_MIN -128 +#define UINT8_MAX 255 +#define INT16_MAX 32767 +#define INT16_MIN -32768 +#define UINT16_MAX 65535 +#define INT32_MAX 2147483647 +#define INT32_MIN -2147483648 +#define UINT32_MAX 4294967295U +#define INT8_C(C) C +#define UINT8_C(C) C +#define INT16_C(C) C +#define UINT16_C(C) C +#define INT32_C(C) C +#define UINT32_C(C) C ## U +#define INT64_C(C) ((int64_t) C ## LL) +#define UINT64_C(C) ((uint64_t) C ## ULL) +#endif /* _MSC_VER */ + +/* Set defaults for constants which we cannot find. */ +#if !defined(INT64_MAX) +# define INT64_MAX 9223372036854775807LL +#endif +#if !defined(INT64_MIN) +# define INT64_MIN ((-INT64_MAX)-1) +#endif +#if !defined(UINT64_MAX) +# define UINT64_MAX 0xffffffffffffffffULL +#endif + +#if __GNUC__ > 3 +#define END_WITH_NULL __attribute__((sentinel)) +#else +#define END_WITH_NULL +#endif + +#ifndef HUGE_VALF +#define HUGE_VALF (float)HUGE_VAL +#endif + +#endif /* SUPPORT_DATATYPES_H */ diff --git a/include/llvm/Support/IRBuilder.h b/include/llvm/Support/IRBuilder.h index 1f65978..83df9ed 100644 --- a/include/llvm/Support/IRBuilder.h +++ b/include/llvm/Support/IRBuilder.h @@ -139,7 +139,7 @@ public: if (MDKind == 0) MDKind = Context.getMetadata().getMDKind("dbg"); if (MDKind == 0) - MDKind = Context.getMetadata().RegisterMDKind("dbg"); + MDKind = Context.getMetadata().registerMDKind("dbg"); CurDbgLocation = L; } @@ -429,10 +429,6 @@ public: // Instruction creation methods: Memory Instructions //===--------------------------------------------------------------------===// - MallocInst *CreateMalloc(const Type *Ty, Value *ArraySize = 0, - const Twine &Name = "") { - return Insert(new MallocInst(Ty, ArraySize), Name); - } AllocaInst *CreateAlloca(const Type *Ty, Value *ArraySize = 0, const Twine &Name = "") { return Insert(new AllocaInst(Ty, ArraySize), Name); diff --git a/include/llvm/Support/InstVisitor.h b/include/llvm/Support/InstVisitor.h index 5d7c2f7..440657c 100644 --- a/include/llvm/Support/InstVisitor.h +++ b/include/llvm/Support/InstVisitor.h @@ -46,17 +46,17 @@ namespace llvm { /// /// Declare the class. Note that we derive from InstVisitor instantiated /// /// with _our new subclasses_ type. /// /// -/// struct CountMallocVisitor : public InstVisitor<CountMallocVisitor> { +/// struct CountAllocaVisitor : public InstVisitor<CountAllocaVisitor> { /// unsigned Count; -/// CountMallocVisitor() : Count(0) {} +/// CountAllocaVisitor() : Count(0) {} /// -/// void visitMallocInst(MallocInst &MI) { ++Count; } +/// void visitAllocaInst(AllocaInst &AI) { ++Count; } /// }; /// /// And this class would be used like this: -/// CountMallocVistor CMV; -/// CMV.visit(function); -/// NumMallocs = CMV.Count; +/// CountAllocaVisitor CAV; +/// CAV.visit(function); +/// NumAllocas = CAV.Count; /// /// The defined has 'visit' methods for Instruction, and also for BasicBlock, /// Function, and Module, which recursively process all contained instructions. @@ -165,7 +165,6 @@ public: RetTy visitUnreachableInst(UnreachableInst &I) { DELEGATE(TerminatorInst);} RetTy visitICmpInst(ICmpInst &I) { DELEGATE(CmpInst);} RetTy visitFCmpInst(FCmpInst &I) { DELEGATE(CmpInst);} - RetTy visitMallocInst(MallocInst &I) { DELEGATE(AllocationInst);} RetTy visitAllocaInst(AllocaInst &I) { DELEGATE(AllocationInst);} RetTy visitFreeInst(FreeInst &I) { DELEGATE(Instruction); } RetTy visitLoadInst(LoadInst &I) { DELEGATE(Instruction); } diff --git a/include/llvm/Support/ValueHandle.h b/include/llvm/Support/ValueHandle.h index e6363ff..a9872a7 100644 --- a/include/llvm/Support/ValueHandle.h +++ b/include/llvm/Support/ValueHandle.h @@ -238,6 +238,31 @@ template<> struct simplify_type<const AssertingVH<Value> > { template<> struct simplify_type<AssertingVH<Value> > : public simplify_type<const AssertingVH<Value> > {}; +// Specialize DenseMapInfo to allow AssertingVH to participate in DenseMap. +template<typename T> +struct DenseMapInfo<AssertingVH<T> > { + typedef DenseMapInfo<T*> PointerInfo; + static inline AssertingVH<T> getEmptyKey() { + return AssertingVH<T>(PointerInfo::getEmptyKey()); + } + static inline T* getTombstoneKey() { + return AssertingVH<T>(PointerInfo::getTombstoneKey()); + } + static unsigned getHashValue(const AssertingVH<T> &Val) { + return PointerInfo::getHashValue(Val); + } + static bool isEqual(const AssertingVH<T> &LHS, const AssertingVH<T> &RHS) { + return LHS == RHS; + } + static bool isPod() { +#ifdef NDEBUG + return true; +#else + return false; +#endif + } +}; + /// TrackingVH - This is a value handle that tracks a Value (or Value subclass), /// even across RAUW operations. /// @@ -361,7 +386,7 @@ public: /// _before_ any of the uses have actually been replaced. If WeakVH were /// implemented as a CallbackVH, it would use this method to call /// setValPtr(new_value). AssertingVH would do nothing in this method. - virtual void allUsesReplacedWith(Value *new_value) {} + virtual void allUsesReplacedWith(Value *) {} }; // Specialize simplify_type to allow CallbackVH to participate in diff --git a/include/llvm/Support/raw_ostream.h b/include/llvm/Support/raw_ostream.h index 8012b6f..e67ff85 100644 --- a/include/llvm/Support/raw_ostream.h +++ b/include/llvm/Support/raw_ostream.h @@ -216,6 +216,10 @@ public: /// write_hex - Output \arg N in hexadecimal, without any prefix or padding. raw_ostream &write_hex(unsigned long long N); + /// write_escaped - Output \arg Str, turning '\\', '\t', '\n', '"', and + /// anything that doesn't satisfy std::isprint into an escape sequence. + raw_ostream &write_escaped(StringRef Str); + raw_ostream &write(unsigned char C); raw_ostream &write(const char *Ptr, size_t Size); diff --git a/include/llvm/Support/type_traits.h b/include/llvm/Support/type_traits.h index 5f799b8..cfaae4b 100644 --- a/include/llvm/Support/type_traits.h +++ b/include/llvm/Support/type_traits.h @@ -87,6 +87,15 @@ struct is_base_of { sizeof(char) == sizeof(dont_use::base_of_helper<Base>((Derived*)0)); }; +// remove_pointer - Metafunction to turn Foo* into Foo. Defined in +// C++0x [meta.trans.ptr]. +template <typename T> struct remove_pointer { typedef T type; }; +template <typename T> struct remove_pointer<T*> { typedef T type; }; +template <typename T> struct remove_pointer<T*const> { typedef T type; }; +template <typename T> struct remove_pointer<T*volatile> { typedef T type; }; +template <typename T> struct remove_pointer<T*const volatile> { + typedef T type; }; + } #endif diff --git a/include/llvm/Target/TargetIntrinsicInfo.h b/include/llvm/Target/TargetIntrinsicInfo.h index c14275f..d70aa7e 100644 --- a/include/llvm/Target/TargetIntrinsicInfo.h +++ b/include/llvm/Target/TargetIntrinsicInfo.h @@ -25,35 +25,21 @@ class Type; /// TargetIntrinsicInfo - Interface to description of machine instruction set /// class TargetIntrinsicInfo { - - const char **Intrinsics; // Raw array to allow static init'n - unsigned NumIntrinsics; // Number of entries in the desc array - - TargetIntrinsicInfo(const TargetIntrinsicInfo &); // DO NOT IMPLEMENT - void operator=(const TargetIntrinsicInfo &); // DO NOT IMPLEMENT + TargetIntrinsicInfo(const TargetIntrinsicInfo &); // DO NOT IMPLEMENT + void operator=(const TargetIntrinsicInfo &); // DO NOT IMPLEMENT public: - TargetIntrinsicInfo(const char **desc, unsigned num); + TargetIntrinsicInfo(); virtual ~TargetIntrinsicInfo(); - unsigned getNumIntrinsics() const { return NumIntrinsics; } - - virtual Function *getDeclaration(Module *M, const char *BuiltinName) const { - return 0; - } - - // Returns the Function declaration for intrinsic BuiltinName. If the - // intrinsic can be overloaded, uses Tys to return the correct function. - virtual Function *getDeclaration(Module *M, const char *BuiltinName, - const Type **Tys, unsigned numTys) const { - return 0; - } + /// Return the name of a target intrinsic, e.g. "llvm.bfin.ssync". + virtual const char *getName(unsigned IntrID) const =0; - // Returns true if the Builtin can be overloaded. - virtual bool isOverloaded(Module *M, const char *BuiltinName) const { - return false; - } + /// Look up target intrinsic by name. Return intrinsic ID or 0 for unknown + /// names. + virtual unsigned lookupName(const char *Name, unsigned Len) const =0; - virtual unsigned getIntrinsicID(Function *F) const { return 0; } + /// Return the target intrinsic ID of a function, or 0. + virtual unsigned getIntrinsicID(Function *F) const; }; } // End llvm namespace diff --git a/include/llvm/Target/TargetMachine.h b/include/llvm/Target/TargetMachine.h index 92b648c..1104635 100644 --- a/include/llvm/Target/TargetMachine.h +++ b/include/llvm/Target/TargetMachine.h @@ -74,9 +74,10 @@ namespace FileModel { // Code generation optimization level. namespace CodeGenOpt { enum Level { - Default, - None, - Aggressive + None, // -O0 + Less, // -O1 + Default, // -O2, -Os + Aggressive // -O3 }; } diff --git a/include/llvm/Target/TargetRegisterInfo.h b/include/llvm/Target/TargetRegisterInfo.h index e90fc6c..b7e8af9 100644 --- a/include/llvm/Target/TargetRegisterInfo.h +++ b/include/llvm/Target/TargetRegisterInfo.h @@ -641,24 +641,17 @@ public: virtual void processFunctionBeforeFrameFinalized(MachineFunction &MF) const { } - /// saveScavengerRegister - Save the register so it can be used by the - /// register scavenger. Return true if the register was saved, false - /// otherwise. If this function does not save the register, the scavenger + /// saveScavengerRegister - Spill the register so it can be used by the + /// register scavenger. Return true if the register was spilled, false + /// otherwise. If this function does not spill the register, the scavenger /// will instead spill it to the emergency spill slot. /// virtual bool saveScavengerRegister(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, + MachineBasicBlock::iterator &UseMI, const TargetRegisterClass *RC, unsigned Reg) const {return false;} - /// restoreScavengerRegister - Restore a register saved by - /// saveScavengerRegister(). - /// - virtual void restoreScavengerRegister(MachineBasicBlock &MBB, - MachineBasicBlock::iterator I, - const TargetRegisterClass *RC, - unsigned Reg) const {} - /// eliminateFrameIndex - This method must be overriden to eliminate abstract /// frame indices from instructions which may use them. The instruction /// referenced by the iterator contains an MO_FrameIndex operand which must be diff --git a/include/llvm/Target/TargetRegistry.h b/include/llvm/Target/TargetRegistry.h index 8042d23..395526f 100644 --- a/include/llvm/Target/TargetRegistry.h +++ b/include/llvm/Target/TargetRegistry.h @@ -387,6 +387,15 @@ namespace llvm { T.MCDisassemblerCtorFn = Fn; } + /// RegisterMCInstPrinter - Register a MCInstPrinter implementation for the + /// given target. + /// + /// Clients are responsible for ensuring that registration doesn't occur + /// while another thread is attempting to access the registry. Typically + /// this is done by initializing all targets at program startup. + /// + /// @param T - The target being registered. + /// @param Fn - A function to construct an MCInstPrinter for the target. static void RegisterMCInstPrinter(Target &T, Target::MCInstPrinterCtorTy Fn) { if (!T.MCInstPrinterCtorFn) @@ -395,7 +404,7 @@ namespace llvm { /// RegisterCodeEmitter - Register a MCCodeEmitter implementation for the /// given target. - /// + /// /// Clients are responsible for ensuring that registration doesn't occur /// while another thread is attempting to access the registry. Typically /// this is done by initializing all targets at program startup. diff --git a/include/llvm/Target/TargetSubtarget.h b/include/llvm/Target/TargetSubtarget.h index ac094f6..fd107e0 100644 --- a/include/llvm/Target/TargetSubtarget.h +++ b/include/llvm/Target/TargetSubtarget.h @@ -14,6 +14,8 @@ #ifndef LLVM_TARGET_TARGETSUBTARGET_H #define LLVM_TARGET_TARGETSUBTARGET_H +#include "llvm/Target/TargetMachine.h" + namespace llvm { class SDep; @@ -31,6 +33,10 @@ class TargetSubtarget { protected: // Can only create subclasses... TargetSubtarget(); public: + // AntiDepBreakMode - Type of anti-dependence breaking that should + // be performed before post-RA scheduling. + typedef enum { ANTIDEP_NONE, ANTIDEP_CRITICAL, ANTIDEP_ALL } AntiDepBreakMode; + virtual ~TargetSubtarget(); /// getSpecialAddressLatency - For targets where it is beneficial to @@ -39,9 +45,14 @@ public: /// should be attempted. virtual unsigned getSpecialAddressLatency() const { return 0; } - // enablePostRAScheduler - Return true to enable - // post-register-allocation scheduling. - virtual bool enablePostRAScheduler() const { return false; } + // enablePostRAScheduler - If the target can benefit from post-regalloc + // scheduling and the specified optimization level meets the requirement + // return true to enable post-register-allocation scheduling. + virtual bool enablePostRAScheduler(CodeGenOpt::Level OptLevel, + AntiDepBreakMode& mode) const { + mode = ANTIDEP_NONE; + return false; + } // adjustSchedDependency - Perform target specific adjustments to // the latency of a schedule dependency. diff --git a/include/llvm/Transforms/IPO.h b/include/llvm/Transforms/IPO.h index d66ed89..9189c43 100644 --- a/include/llvm/Transforms/IPO.h +++ b/include/llvm/Transforms/IPO.h @@ -185,10 +185,6 @@ Pass *createSingleLoopExtractorPass(); /// ModulePass *createBlockExtractorPass(const std::vector<BasicBlock*> &BTNE); -/// createIndMemRemPass - This pass removes potential indirect calls of -/// malloc and free -ModulePass *createIndMemRemPass(); - /// createStripDeadPrototypesPass - This pass removes any function declarations /// (prototypes) that are not used. ModulePass *createStripDeadPrototypesPass(); diff --git a/include/llvm/Transforms/Scalar.h b/include/llvm/Transforms/Scalar.h index 2483768..fee4e65 100644 --- a/include/llvm/Transforms/Scalar.h +++ b/include/llvm/Transforms/Scalar.h @@ -225,12 +225,11 @@ extern const PassInfo *const LoopSimplifyID; //===----------------------------------------------------------------------===// // -// LowerAllocations - Turn malloc and free instructions into @malloc and @free -// calls. +// LowerAllocations - Turn free instructions into @free calls. // // AU.addRequiredID(LowerAllocationsID); // -Pass *createLowerAllocationsPass(bool LowerMallocArgToInteger = false); +Pass *createLowerAllocationsPass(); extern const PassInfo *const LowerAllocationsID; //===----------------------------------------------------------------------===// diff --git a/include/llvm/Transforms/Utils/SSAUpdater.h b/include/llvm/Transforms/Utils/SSAUpdater.h index 11b90d4..ad99c74 100644 --- a/include/llvm/Transforms/Utils/SSAUpdater.h +++ b/include/llvm/Transforms/Utils/SSAUpdater.h @@ -21,7 +21,7 @@ namespace llvm { class PHINode; template<typename T> class SmallVectorImpl; - + /// SSAUpdater - This class updates SSA form for a set of values defined in /// multiple blocks. This is used when code duplication or another unstructured /// transformation wants to rewrite a set of uses of one value with uses of a @@ -33,17 +33,17 @@ class SSAUpdater { /// eliminate them, and want the WeakVH to track this. //typedef DenseMap<BasicBlock*, TrackingVH<Value> > AvailableValsTy; void *AV; - + /// PrototypeValue is an arbitrary representative value, which we derive names /// and a type for PHI nodes. Value *PrototypeValue; - + /// IncomingPredInfo - We use this as scratch space when doing our recursive /// walk. This should only be used in GetValueInBlockInternal, normally it /// should be empty. //std::vector<std::pair<BasicBlock*, TrackingVH<Value> > > IncomingPredInfo; void *IPI; - + /// InsertedPHIs - If this is non-null, the SSAUpdater adds all PHI nodes that /// it creates to the vector. SmallVectorImpl<PHINode*> *InsertedPHIs; @@ -52,11 +52,11 @@ public: /// in with all PHI Nodes created by rewriting. SSAUpdater(SmallVectorImpl<PHINode*> *InsertedPHIs = 0); ~SSAUpdater(); - + /// Initialize - Reset this object to get ready for a new set of SSA /// updates. ProtoValue is the value used to name PHI nodes. void Initialize(Value *ProtoValue); - + /// AddAvailableValue - Indicate that a rewritten value is available at the /// end of the specified block with the specified value. void AddAvailableValue(BasicBlock *BB, Value *V); @@ -64,11 +64,11 @@ public: /// HasValueForBlock - Return true if the SSAUpdater already has a value for /// the specified block. bool HasValueForBlock(BasicBlock *BB) const; - + /// GetValueAtEndOfBlock - Construct SSA form, materializing a value that is /// live at the end of the specified block. Value *GetValueAtEndOfBlock(BasicBlock *BB); - + /// GetValueInMiddleOfBlock - Construct SSA form, materializing a value that /// is live in the middle of the specified block. /// @@ -89,14 +89,14 @@ public: /// merge the appropriate values, and this value isn't live out of the block. /// Value *GetValueInMiddleOfBlock(BasicBlock *BB); - + /// RewriteUse - Rewrite a use of the symbolic value. This handles PHI nodes, /// which use their value in the corresponding predecessor. Note that this /// will not work if the use is supposed to be rewritten to a value defined in /// the same block as the use, but above it. Any 'AddAvailableValue's added /// for the use's block will be considered to be below it. void RewriteUse(Use &U); - + private: Value *GetValueAtEndOfBlockInternal(BasicBlock *BB); void operator=(const SSAUpdater&); // DO NOT IMPLEMENT diff --git a/include/llvm/Value.h b/include/llvm/Value.h index 6b393f6..c09fdfb 100644 --- a/include/llvm/Value.h +++ b/include/llvm/Value.h @@ -42,7 +42,7 @@ class raw_ostream; class AssemblyAnnotationWriter; class ValueHandleBase; class LLVMContext; -class MetadataContext; +class MetadataContextImpl; //===----------------------------------------------------------------------===// // Value Class @@ -83,7 +83,7 @@ private: friend class ValueSymbolTable; // Allow ValueSymbolTable to directly mod Name. friend class SymbolTable; // Allow SymbolTable to directly poke Name. friend class ValueHandleBase; - friend class MetadataContext; + friend class MetadataContextImpl; friend class AbstractTypeUser; ValueName *Name; diff --git a/lib/Analysis/BasicAliasAnalysis.cpp b/lib/Analysis/BasicAliasAnalysis.cpp index c5be616..756ffea 100644 --- a/lib/Analysis/BasicAliasAnalysis.cpp +++ b/lib/Analysis/BasicAliasAnalysis.cpp @@ -40,10 +40,6 @@ using namespace llvm; // Useful predicates //===----------------------------------------------------------------------===// -static const GEPOperator *isGEP(const Value *V) { - return dyn_cast<GEPOperator>(V); -} - static const Value *GetGEPOperands(const Value *V, SmallVector<Value*, 16> &GEPOps) { assert(GEPOps.empty() && "Expect empty list to populate!"); @@ -53,7 +49,7 @@ static const Value *GetGEPOperands(const Value *V, // Accumulate all of the chained indexes into the operand array V = cast<User>(V)->getOperand(0); - while (const User *G = isGEP(V)) { + while (const GEPOperator *G = dyn_cast<GEPOperator>(V)) { if (!isa<Constant>(GEPOps[0]) || isa<GlobalValue>(GEPOps[0]) || !cast<Constant>(GEPOps[0])->isNullValue()) break; // Don't handle folding arbitrary pointer offsets yet... @@ -222,7 +218,7 @@ namespace { private: // VisitedPHIs - Track PHI nodes visited by a aliasCheck() call. - SmallSet<const PHINode*, 16> VisitedPHIs; + SmallPtrSet<const PHINode*, 16> VisitedPHIs; // aliasGEP - Provide a bunch of ad-hoc rules to disambiguate a GEP instruction // against another. @@ -358,11 +354,13 @@ BasicAliasAnalysis::getModRefInfo(CallSite CS, Value *P, unsigned Size) { if (alias(II->getOperand(2), PtrSize, P, Size) == NoAlias) return NoModRef; } + break; case Intrinsic::invariant_end: { unsigned PtrSize = cast<ConstantInt>(II->getOperand(2))->getZExtValue(); if (alias(II->getOperand(3), PtrSize, P, Size) == NoAlias) return NoModRef; } + break; } } } @@ -400,7 +398,7 @@ BasicAliasAnalysis::aliasGEP(const Value *V1, unsigned V1Size, // Note that we also handle chains of getelementptr instructions as well as // constant expression getelementptrs here. // - if (isGEP(V1) && isGEP(V2)) { + if (isa<GEPOperator>(V1) && isa<GEPOperator>(V2)) { const User *GEP1 = cast<User>(V1); const User *GEP2 = cast<User>(V2); @@ -419,13 +417,13 @@ BasicAliasAnalysis::aliasGEP(const Value *V1, unsigned V1Size, // Drill down into the first non-gep value, to test for must-aliasing of // the base pointers. - while (isGEP(GEP1->getOperand(0)) && + while (isa<GEPOperator>(GEP1->getOperand(0)) && GEP1->getOperand(1) == Constant::getNullValue(GEP1->getOperand(1)->getType())) GEP1 = cast<User>(GEP1->getOperand(0)); const Value *BasePtr1 = GEP1->getOperand(0); - while (isGEP(GEP2->getOperand(0)) && + while (isa<GEPOperator>(GEP2->getOperand(0)) && GEP2->getOperand(1) == Constant::getNullValue(GEP2->getOperand(1)->getType())) GEP2 = cast<User>(GEP2->getOperand(0)); @@ -531,7 +529,7 @@ BasicAliasAnalysis::aliasPHI(const PHINode *PN, unsigned PNSize, if (!VisitedPHIs.insert(PN)) return MayAlias; - SmallSet<Value*, 4> UniqueSrc; + SmallPtrSet<Value*, 4> UniqueSrc; SmallVector<Value*, 4> V1Srcs; for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i) { Value *PV1 = PN->getIncomingValue(i); @@ -555,7 +553,7 @@ BasicAliasAnalysis::aliasPHI(const PHINode *PN, unsigned PNSize, // NoAlias / MustAlias. Otherwise, returns MayAlias. for (unsigned i = 1, e = V1Srcs.size(); i != e; ++i) { Value *V = V1Srcs[i]; - AliasResult ThisAlias = aliasCheck(V, PNSize, V2, V2Size); + AliasResult ThisAlias = aliasCheck(V2, V2Size, V, PNSize); if (ThisAlias != Alias || ThisAlias == MayAlias) return MayAlias; } @@ -617,11 +615,11 @@ BasicAliasAnalysis::aliasCheck(const Value *V1, unsigned V1Size, isNonEscapingLocalObject(O1) && O1 != O2) return NoAlias; - if (!isGEP(V1) && isGEP(V2)) { + if (!isa<GEPOperator>(V1) && isa<GEPOperator>(V2)) { std::swap(V1, V2); std::swap(V1Size, V2Size); } - if (isGEP(V1)) + if (isa<GEPOperator>(V1)) return aliasGEP(V1, V1Size, V2, V2Size); if (isa<PHINode>(V2) && !isa<PHINode>(V1)) { diff --git a/lib/Analysis/CFGPrinter.cpp b/lib/Analysis/CFGPrinter.cpp index 6fed400..08f070c 100644 --- a/lib/Analysis/CFGPrinter.cpp +++ b/lib/Analysis/CFGPrinter.cpp @@ -17,71 +17,12 @@ // //===----------------------------------------------------------------------===// -#include "llvm/Function.h" -#include "llvm/Instructions.h" -#include "llvm/Pass.h" #include "llvm/Analysis/CFGPrinter.h" -#include "llvm/Assembly/Writer.h" -#include "llvm/Support/CFG.h" + +#include "llvm/Pass.h" #include "llvm/Support/Compiler.h" -#include "llvm/Support/GraphWriter.h" using namespace llvm; -namespace llvm { -template<> -struct DOTGraphTraits<const Function*> : public DefaultDOTGraphTraits { - static std::string getGraphName(const Function *F) { - return "CFG for '" + F->getNameStr() + "' function"; - } - - static std::string getNodeLabel(const BasicBlock *Node, - const Function *Graph, - bool ShortNames) { - if (ShortNames && !Node->getName().empty()) - return Node->getNameStr() + ":"; - - std::string Str; - raw_string_ostream OS(Str); - - if (ShortNames) { - WriteAsOperand(OS, Node, false); - return OS.str(); - } - - if (Node->getName().empty()) { - WriteAsOperand(OS, Node, false); - OS << ":"; - } - - OS << *Node; - std::string OutStr = OS.str(); - if (OutStr[0] == '\n') OutStr.erase(OutStr.begin()); - - // Process string output to make it nicer... - for (unsigned i = 0; i != OutStr.length(); ++i) - if (OutStr[i] == '\n') { // Left justify - OutStr[i] = '\\'; - OutStr.insert(OutStr.begin()+i+1, 'l'); - } else if (OutStr[i] == ';') { // Delete comments! - unsigned Idx = OutStr.find('\n', i+1); // Find end of line - OutStr.erase(OutStr.begin()+i, OutStr.begin()+Idx); - --i; - } - - return OutStr; - } - - static std::string getEdgeSourceLabel(const BasicBlock *Node, - succ_const_iterator I) { - // Label source of conditional branches with "T" or "F" - if (const BranchInst *BI = dyn_cast<BranchInst>(Node->getTerminator())) - if (BI->isConditional()) - return (I == succ_begin(Node)) ? "T" : "F"; - return ""; - } -}; -} - namespace { struct VISIBILITY_HIDDEN CFGViewer : public FunctionPass { static char ID; // Pass identifcation, replacement for typeid diff --git a/lib/Analysis/CMakeLists.txt b/lib/Analysis/CMakeLists.txt index 1d2f118..d4be986 100644 --- a/lib/Analysis/CMakeLists.txt +++ b/lib/Analysis/CMakeLists.txt @@ -11,6 +11,7 @@ add_llvm_library(LLVMAnalysis ConstantFolding.cpp DbgInfoPrinter.cpp DebugInfo.cpp + DomPrinter.cpp IVUsers.cpp InlineCost.cpp InstCount.cpp diff --git a/lib/Analysis/ConstantFolding.cpp b/lib/Analysis/ConstantFolding.cpp index 0ce1c24..214caeb 100644 --- a/lib/Analysis/ConstantFolding.cpp +++ b/lib/Analysis/ConstantFolding.cpp @@ -24,9 +24,10 @@ #include "llvm/Instructions.h" #include "llvm/Intrinsics.h" #include "llvm/LLVMContext.h" +#include "llvm/Analysis/ValueTracking.h" +#include "llvm/Target/TargetData.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringMap.h" -#include "llvm/Target/TargetData.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/GetElementPtrTypeIterator.h" #include "llvm/Support/MathExtras.h" @@ -92,6 +93,265 @@ static bool IsConstantOffsetFromGlobal(Constant *C, GlobalValue *&GV, return false; } +/// ReadDataFromGlobal - Recursive helper to read bits out of global. C is the +/// constant being copied out of. ByteOffset is an offset into C. CurPtr is the +/// pointer to copy results into and BytesLeft is the number of bytes left in +/// the CurPtr buffer. TD is the target data. +static bool ReadDataFromGlobal(Constant *C, uint64_t ByteOffset, + unsigned char *CurPtr, unsigned BytesLeft, + const TargetData &TD) { + assert(ByteOffset <= TD.getTypeAllocSize(C->getType()) && + "Out of range access"); + + if (isa<ConstantAggregateZero>(C) || isa<UndefValue>(C)) + return true; + + if (ConstantInt *CI = dyn_cast<ConstantInt>(C)) { + if (CI->getBitWidth() > 64 || + (CI->getBitWidth() & 7) != 0) + return false; + + uint64_t Val = CI->getZExtValue(); + unsigned IntBytes = unsigned(CI->getBitWidth()/8); + + for (unsigned i = 0; i != BytesLeft && ByteOffset != IntBytes; ++i) { + CurPtr[i] = (unsigned char)(Val >> ByteOffset * 8); + ++ByteOffset; + } + return true; + } + + if (ConstantFP *CFP = dyn_cast<ConstantFP>(C)) { + if (CFP->getType()->isDoubleTy()) { + C = ConstantExpr::getBitCast(C, Type::getInt64Ty(C->getContext())); + return ReadDataFromGlobal(C, ByteOffset, CurPtr, BytesLeft, TD); + } + if (CFP->getType()->isFloatTy()){ + C = ConstantExpr::getBitCast(C, Type::getInt32Ty(C->getContext())); + return ReadDataFromGlobal(C, ByteOffset, CurPtr, BytesLeft, TD); + } + } + + if (ConstantStruct *CS = dyn_cast<ConstantStruct>(C)) { + const StructLayout *SL = TD.getStructLayout(CS->getType()); + unsigned Index = SL->getElementContainingOffset(ByteOffset); + uint64_t CurEltOffset = SL->getElementOffset(Index); + ByteOffset -= CurEltOffset; + + while (1) { + // If the element access is to the element itself and not to tail padding, + // read the bytes from the element. + uint64_t EltSize = TD.getTypeAllocSize(CS->getOperand(Index)->getType()); + + if (ByteOffset < EltSize && + !ReadDataFromGlobal(CS->getOperand(Index), ByteOffset, CurPtr, + BytesLeft, TD)) + return false; + + ++Index; + + // Check to see if we read from the last struct element, if so we're done. + if (Index == CS->getType()->getNumElements()) + return true; + + // If we read all of the bytes we needed from this element we're done. + uint64_t NextEltOffset = SL->getElementOffset(Index); + + if (BytesLeft <= NextEltOffset-CurEltOffset-ByteOffset) + return true; + + // Move to the next element of the struct. + BytesLeft -= NextEltOffset-CurEltOffset-ByteOffset; + ByteOffset = 0; + CurEltOffset = NextEltOffset; + } + // not reached. + } + + if (ConstantArray *CA = dyn_cast<ConstantArray>(C)) { + uint64_t EltSize = TD.getTypeAllocSize(CA->getType()->getElementType()); + uint64_t Index = ByteOffset / EltSize; + uint64_t Offset = ByteOffset - Index * EltSize; + for (; Index != CA->getType()->getNumElements(); ++Index) { + if (!ReadDataFromGlobal(CA->getOperand(Index), Offset, CurPtr, + BytesLeft, TD)) + return false; + if (EltSize >= BytesLeft) + return true; + + Offset = 0; + BytesLeft -= EltSize; + CurPtr += EltSize; + } + return true; + } + + if (ConstantVector *CV = dyn_cast<ConstantVector>(C)) { + uint64_t EltSize = TD.getTypeAllocSize(CV->getType()->getElementType()); + uint64_t Index = ByteOffset / EltSize; + uint64_t Offset = ByteOffset - Index * EltSize; + for (; Index != CV->getType()->getNumElements(); ++Index) { + if (!ReadDataFromGlobal(CV->getOperand(Index), Offset, CurPtr, + BytesLeft, TD)) + return false; + if (EltSize >= BytesLeft) + return true; + + Offset = 0; + BytesLeft -= EltSize; + CurPtr += EltSize; + } + return true; + } + + // Otherwise, unknown initializer type. + return false; +} + +static Constant *FoldReinterpretLoadFromConstPtr(Constant *C, + const TargetData &TD) { + const Type *LoadTy = cast<PointerType>(C->getType())->getElementType(); + const IntegerType *IntType = dyn_cast<IntegerType>(LoadTy); + + // If this isn't an integer load we can't fold it directly. + if (!IntType) { + // If this is a float/double load, we can try folding it as an int32/64 load + // and then bitcast the result. This can be useful for union cases. Note + // that address spaces don't matter here since we're not going to result in + // an actual new load. + const Type *MapTy; + if (LoadTy->isFloatTy()) + MapTy = Type::getInt32PtrTy(C->getContext()); + else if (LoadTy->isDoubleTy()) + MapTy = Type::getInt64PtrTy(C->getContext()); + else if (isa<VectorType>(LoadTy)) { + MapTy = IntegerType::get(C->getContext(), + TD.getTypeAllocSizeInBits(LoadTy)); + MapTy = PointerType::getUnqual(MapTy); + } else + return 0; + + C = ConstantExpr::getBitCast(C, MapTy); + if (Constant *Res = FoldReinterpretLoadFromConstPtr(C, TD)) + return ConstantExpr::getBitCast(Res, LoadTy); + return 0; + } + + unsigned BytesLoaded = (IntType->getBitWidth() + 7) / 8; + if (BytesLoaded > 32 || BytesLoaded == 0) return 0; + + GlobalValue *GVal; + int64_t Offset; + if (!IsConstantOffsetFromGlobal(C, GVal, Offset, TD)) + return 0; + + GlobalVariable *GV = dyn_cast<GlobalVariable>(GVal); + if (!GV || !GV->isConstant() || !GV->hasInitializer() || + !GV->hasDefinitiveInitializer() || + !GV->getInitializer()->getType()->isSized()) + return 0; + + // If we're loading off the beginning of the global, some bytes may be valid, + // but we don't try to handle this. + if (Offset < 0) return 0; + + // If we're not accessing anything in this constant, the result is undefined. + if (uint64_t(Offset) >= TD.getTypeAllocSize(GV->getInitializer()->getType())) + return UndefValue::get(IntType); + + unsigned char RawBytes[32] = {0}; + if (!ReadDataFromGlobal(GV->getInitializer(), Offset, RawBytes, + BytesLoaded, TD)) + return 0; + + APInt ResultVal(IntType->getBitWidth(), 0); + for (unsigned i = 0; i != BytesLoaded; ++i) { + ResultVal <<= 8; + ResultVal |= APInt(IntType->getBitWidth(), RawBytes[BytesLoaded-1-i]); + } + + return ConstantInt::get(IntType->getContext(), ResultVal); +} + +/// ConstantFoldLoadFromConstPtr - Return the value that a load from C would +/// produce if it is constant and determinable. If this is not determinable, +/// return null. +Constant *llvm::ConstantFoldLoadFromConstPtr(Constant *C, + const TargetData *TD) { + // First, try the easy cases: + if (GlobalVariable *GV = dyn_cast<GlobalVariable>(C)) + if (GV->isConstant() && GV->hasDefinitiveInitializer()) + return GV->getInitializer(); + + // If the loaded value isn't a constant expr, we can't handle it. + ConstantExpr *CE = dyn_cast<ConstantExpr>(C); + if (!CE) return 0; + + if (CE->getOpcode() == Instruction::GetElementPtr) { + if (GlobalVariable *GV = dyn_cast<GlobalVariable>(CE->getOperand(0))) + if (GV->isConstant() && GV->hasDefinitiveInitializer()) + if (Constant *V = + ConstantFoldLoadThroughGEPConstantExpr(GV->getInitializer(), CE)) + return V; + } + + // Instead of loading constant c string, use corresponding integer value + // directly if string length is small enough. + std::string Str; + if (TD && GetConstantStringInfo(CE->getOperand(0), Str) && !Str.empty()) { + unsigned StrLen = Str.length(); + const Type *Ty = cast<PointerType>(CE->getType())->getElementType(); + unsigned NumBits = Ty->getPrimitiveSizeInBits(); + // Replace LI with immediate integer store. + if ((NumBits >> 3) == StrLen + 1) { + APInt StrVal(NumBits, 0); + APInt SingleChar(NumBits, 0); + if (TD->isLittleEndian()) { + for (signed i = StrLen-1; i >= 0; i--) { + SingleChar = (uint64_t) Str[i] & UCHAR_MAX; + StrVal = (StrVal << 8) | SingleChar; + } + } else { + for (unsigned i = 0; i < StrLen; i++) { + SingleChar = (uint64_t) Str[i] & UCHAR_MAX; + StrVal = (StrVal << 8) | SingleChar; + } + // Append NULL at the end. + SingleChar = 0; + StrVal = (StrVal << 8) | SingleChar; + } + return ConstantInt::get(CE->getContext(), StrVal); + } + } + + // If this load comes from anywhere in a constant global, and if the global + // is all undef or zero, we know what it loads. + if (GlobalVariable *GV = dyn_cast<GlobalVariable>(CE->getUnderlyingObject())){ + if (GV->isConstant() && GV->hasDefinitiveInitializer()) { + const Type *ResTy = cast<PointerType>(C->getType())->getElementType(); + if (GV->getInitializer()->isNullValue()) + return Constant::getNullValue(ResTy); + if (isa<UndefValue>(GV->getInitializer())) + return UndefValue::get(ResTy); + } + } + + // Try hard to fold loads from bitcasted strange and non-type-safe things. We + // currently don't do any of this for big endian systems. It can be + // generalized in the future if someone is interested. + if (TD && TD->isLittleEndian()) + return FoldReinterpretLoadFromConstPtr(CE, *TD); + return 0; +} + +static Constant *ConstantFoldLoadInst(const LoadInst *LI, const TargetData *TD){ + if (LI->isVolatile()) return 0; + + if (Constant *C = dyn_cast<Constant>(LI->getOperand(0))) + return ConstantFoldLoadFromConstPtr(C, TD); + + return 0; +} /// SymbolicallyEvaluateBinop - One of Op0/Op1 is a constant expression. /// Attempt to symbolically evaluate the result of a binary operator merging @@ -380,6 +640,9 @@ Constant *llvm::ConstantFoldInstruction(Instruction *I, LLVMContext &Context, Ops.data(), Ops.size(), Context, TD); + if (const LoadInst *LI = dyn_cast<LoadInst>(I)) + return ConstantFoldLoadInst(LI, TD); + return ConstantFoldInstOperands(I->getOpcode(), I->getType(), Ops.data(), Ops.size(), Context, TD); } @@ -640,15 +903,15 @@ Constant *llvm::ConstantFoldLoadThroughGEPConstantExpr(Constant *C, C = UndefValue::get(ATy->getElementType()); else return 0; - } else if (const VectorType *PTy = dyn_cast<VectorType>(*I)) { - if (CI->getZExtValue() >= PTy->getNumElements()) + } else if (const VectorType *VTy = dyn_cast<VectorType>(*I)) { + if (CI->getZExtValue() >= VTy->getNumElements()) return 0; if (ConstantVector *CP = dyn_cast<ConstantVector>(C)) C = CP->getOperand(CI->getZExtValue()); else if (isa<ConstantAggregateZero>(C)) - C = Constant::getNullValue(PTy->getElementType()); + C = Constant::getNullValue(VTy->getElementType()); else if (isa<UndefValue>(C)) - C = UndefValue::get(PTy->getElementType()); + C = UndefValue::get(VTy->getElementType()); else return 0; } else { diff --git a/lib/Analysis/DomPrinter.cpp b/lib/Analysis/DomPrinter.cpp new file mode 100644 index 0000000..f1b44d0 --- /dev/null +++ b/lib/Analysis/DomPrinter.cpp @@ -0,0 +1,265 @@ +//===- DomPrinter.cpp - DOT printer for the dominance trees ------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines '-dot-dom' and '-dot-postdom' analysis passes, which emit +// a dom.<fnname>.dot or postdom.<fnname>.dot file for each function in the +// program, with a graph of the dominance/postdominance tree of that +// function. +// +// There are also passes available to directly call dotty ('-view-dom' or +// '-view-postdom'). By appending '-only' like '-dot-dom-only' only the +// names of the bbs are printed, but the content is hidden. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Analysis/DomPrinter.h" +#include "llvm/Pass.h" +#include "llvm/Function.h" +#include "llvm/Analysis/CFGPrinter.h" +#include "llvm/Analysis/Dominators.h" +#include "llvm/Analysis/PostDominators.h" + +using namespace llvm; + +namespace llvm { +template<> +struct DOTGraphTraits<DomTreeNode*> : public DefaultDOTGraphTraits { + static std::string getNodeLabel(DomTreeNode *Node, DomTreeNode *Graph, + bool ShortNames) { + + BasicBlock *BB = Node->getBlock(); + + if (!BB) + return "Post dominance root node"; + + return DOTGraphTraits<const Function*>::getNodeLabel(BB, BB->getParent(), + ShortNames); + } +}; + +template<> +struct DOTGraphTraits<DominatorTree*> : public DOTGraphTraits<DomTreeNode*> { + + static std::string getGraphName(DominatorTree *DT) { + return "Dominator tree"; + } + + static std::string getNodeLabel(DomTreeNode *Node, + DominatorTree *G, + bool ShortNames) { + return DOTGraphTraits<DomTreeNode*>::getNodeLabel(Node, G->getRootNode(), + ShortNames); + } +}; + +template<> +struct DOTGraphTraits<PostDominatorTree*> + : public DOTGraphTraits<DomTreeNode*> { + static std::string getGraphName(PostDominatorTree *DT) { + return "Post dominator tree"; + } + static std::string getNodeLabel(DomTreeNode *Node, + PostDominatorTree *G, + bool ShortNames) { + return DOTGraphTraits<DomTreeNode*>::getNodeLabel(Node, + G->getRootNode(), + ShortNames); + } +}; +} + +namespace { +template <class Analysis, bool OnlyBBS> +struct GenericGraphViewer : public FunctionPass { + std::string Name; + + GenericGraphViewer(std::string GraphName, const void *ID) : FunctionPass(ID) { + Name = GraphName; + } + + virtual bool runOnFunction(Function &F) { + Analysis *Graph; + + Graph = &getAnalysis<Analysis>(); + ViewGraph(Graph, Name, OnlyBBS); + + return false; + } + + virtual void getAnalysisUsage(AnalysisUsage &AU) const { + AU.setPreservesAll(); + AU.addRequired<Analysis>(); + } +}; + +struct DomViewer + : public GenericGraphViewer<DominatorTree, false> { + static char ID; + DomViewer() : GenericGraphViewer<DominatorTree, false>("dom", &ID){} +}; + +struct DomOnlyViewer + : public GenericGraphViewer<DominatorTree, true> { + static char ID; + DomOnlyViewer() : GenericGraphViewer<DominatorTree, true>("domonly", &ID){} +}; + +struct PostDomViewer + : public GenericGraphViewer<PostDominatorTree, false> { + static char ID; + PostDomViewer() : + GenericGraphViewer<PostDominatorTree, false>("postdom", &ID){} +}; + +struct PostDomOnlyViewer + : public GenericGraphViewer<PostDominatorTree, true> { + static char ID; + PostDomOnlyViewer() : + GenericGraphViewer<PostDominatorTree, true>("postdomonly", &ID){} +}; +} // end anonymous namespace + +char DomViewer::ID = 0; +RegisterPass<DomViewer> A("view-dom", + "View dominance tree of function"); + +char DomOnlyViewer::ID = 0; +RegisterPass<DomOnlyViewer> B("view-dom-only", + "View dominance tree of function " + "(with no function bodies)"); + +char PostDomViewer::ID = 0; +RegisterPass<PostDomViewer> C("view-postdom", + "View postdominance tree of function"); + +char PostDomOnlyViewer::ID = 0; +RegisterPass<PostDomOnlyViewer> D("view-postdom-only", + "View postdominance tree of function " + "(with no function bodies)"); + +namespace { +template <class Analysis, bool OnlyBBS> +struct GenericGraphPrinter : public FunctionPass { + + std::string Name; + + GenericGraphPrinter(std::string GraphName, const void *ID) + : FunctionPass(ID) { + Name = GraphName; + } + + virtual bool runOnFunction(Function &F) { + Analysis *Graph; + std::string Filename = Name + "." + F.getNameStr() + ".dot"; + errs() << "Writing '" << Filename << "'..."; + + std::string ErrorInfo; + raw_fd_ostream File(Filename.c_str(), ErrorInfo); + Graph = &getAnalysis<Analysis>(); + + if (ErrorInfo.empty()) + WriteGraph(File, Graph, OnlyBBS); + else + errs() << " error opening file for writing!"; + errs() << "\n"; + return false; + } + + virtual void getAnalysisUsage(AnalysisUsage &AU) const { + AU.setPreservesAll(); + AU.addRequired<Analysis>(); + } +}; + +struct DomPrinter + : public GenericGraphPrinter<DominatorTree, false> { + static char ID; + DomPrinter() : GenericGraphPrinter<DominatorTree, false>("dom", &ID) {} +}; + +struct DomOnlyPrinter + : public GenericGraphPrinter<DominatorTree, true> { + static char ID; + DomOnlyPrinter() : GenericGraphPrinter<DominatorTree, true>("domonly", &ID) {} +}; + +struct PostDomPrinter + : public GenericGraphPrinter<PostDominatorTree, false> { + static char ID; + PostDomPrinter() : + GenericGraphPrinter<PostDominatorTree, false>("postdom", &ID) {} +}; + +struct PostDomOnlyPrinter + : public GenericGraphPrinter<PostDominatorTree, true> { + static char ID; + PostDomOnlyPrinter() : + GenericGraphPrinter<PostDominatorTree, true>("postdomonly", &ID) {} +}; +} // end anonymous namespace + + + +char DomPrinter::ID = 0; +RegisterPass<DomPrinter> E("dot-dom", + "Print dominance tree of function " + "to 'dot' file"); + +char DomOnlyPrinter::ID = 0; +RegisterPass<DomOnlyPrinter> F("dot-dom-only", + "Print dominance tree of function " + "to 'dot' file " + "(with no function bodies)"); + +char PostDomPrinter::ID = 0; +RegisterPass<PostDomPrinter> G("dot-postdom", + "Print postdominance tree of function " + "to 'dot' file"); + +char PostDomOnlyPrinter::ID = 0; +RegisterPass<PostDomOnlyPrinter> H("dot-postdom-only", + "Print postdominance tree of function " + "to 'dot' file " + "(with no function bodies)"); + +// Create methods available outside of this file, to use them +// "include/llvm/LinkAllPasses.h". Otherwise the pass would be deleted by +// the link time optimization. + +FunctionPass *llvm::createDomPrinterPass() { + return new DomPrinter(); +} + +FunctionPass *llvm::createDomOnlyPrinterPass() { + return new DomOnlyPrinter(); +} + +FunctionPass *llvm::createDomViewerPass() { + return new DomViewer(); +} + +FunctionPass *llvm::createDomOnlyViewerPass() { + return new DomOnlyViewer(); +} + +FunctionPass *llvm::createPostDomPrinterPass() { + return new PostDomPrinter(); +} + +FunctionPass *llvm::createPostDomOnlyPrinterPass() { + return new PostDomOnlyPrinter(); +} + +FunctionPass *llvm::createPostDomViewerPass() { + return new PostDomViewer(); +} + +FunctionPass *llvm::createPostDomOnlyViewerPass() { + return new PostDomOnlyViewer(); +} diff --git a/lib/Analysis/IPA/GlobalsModRef.cpp b/lib/Analysis/IPA/GlobalsModRef.cpp index f5c1108..7949288 100644 --- a/lib/Analysis/IPA/GlobalsModRef.cpp +++ b/lib/Analysis/IPA/GlobalsModRef.cpp @@ -303,7 +303,7 @@ bool GlobalsModRef::AnalyzeIndirectGlobalMemory(GlobalValue *GV) { // Check the value being stored. Value *Ptr = SI->getOperand(0)->getUnderlyingObject(); - if (isa<MallocInst>(Ptr) || isMalloc(Ptr)) { + if (isMalloc(Ptr)) { // Okay, easy case. } else if (CallInst *CI = dyn_cast<CallInst>(Ptr)) { Function *F = CI->getCalledFunction(); @@ -439,8 +439,7 @@ void GlobalsModRef::AnalyzeCallGraph(CallGraph &CG, Module &M) { if (cast<StoreInst>(*II).isVolatile()) // Treat volatile stores as reading memory somewhere. FunctionEffect |= Ref; - } else if (isa<MallocInst>(*II) || isa<FreeInst>(*II) || - isMalloc(&cast<Instruction>(*II))) { + } else if (isMalloc(&cast<Instruction>(*II)) || isa<FreeInst>(*II)) { FunctionEffect |= ModRef; } diff --git a/lib/Analysis/InlineCost.cpp b/lib/Analysis/InlineCost.cpp index 3b0d2c9..b833baa 100644 --- a/lib/Analysis/InlineCost.cpp +++ b/lib/Analysis/InlineCost.cpp @@ -131,7 +131,7 @@ void CodeMetrics::analyzeBasicBlock(const BasicBlock *BB) { } // These, too, are calls. - if (isa<MallocInst>(II) || isa<FreeInst>(II)) + if (isa<FreeInst>(II)) NumInsts += InlineConstants::CallPenalty; if (const AllocaInst *AI = dyn_cast<AllocaInst>(II)) { diff --git a/lib/Analysis/InstCount.cpp b/lib/Analysis/InstCount.cpp index 83724ca..4cde793 100644 --- a/lib/Analysis/InstCount.cpp +++ b/lib/Analysis/InstCount.cpp @@ -76,11 +76,11 @@ FunctionPass *llvm::createInstCountPass() { return new InstCount(); } bool InstCount::runOnFunction(Function &F) { unsigned StartMemInsts = NumGetElementPtrInst + NumLoadInst + NumStoreInst + NumCallInst + - NumInvokeInst + NumAllocaInst + NumMallocInst + NumFreeInst; + NumInvokeInst + NumAllocaInst + NumFreeInst; visit(F); unsigned EndMemInsts = NumGetElementPtrInst + NumLoadInst + NumStoreInst + NumCallInst + - NumInvokeInst + NumAllocaInst + NumMallocInst + NumFreeInst; + NumInvokeInst + NumAllocaInst + NumFreeInst; TotalMemInst += EndMemInsts-StartMemInsts; return false; } diff --git a/lib/Analysis/LoopInfo.cpp b/lib/Analysis/LoopInfo.cpp index ce2d29f..e9256b7 100644 --- a/lib/Analysis/LoopInfo.cpp +++ b/lib/Analysis/LoopInfo.cpp @@ -292,6 +292,9 @@ bool Loop::isLoopSimplifyForm() const { // Normal-form loops have a single backedge. if (!getLoopLatch()) return false; + // Sort the blocks vector so that we can use binary search to do quick + // lookups. + SmallPtrSet<BasicBlock *, 16> LoopBBs(block_begin(), block_end()); // Each predecessor of each exit block of a normal loop is contained // within the loop. SmallVector<BasicBlock *, 4> ExitBlocks; @@ -299,7 +302,7 @@ bool Loop::isLoopSimplifyForm() const { for (unsigned i = 0, e = ExitBlocks.size(); i != e; ++i) for (pred_iterator PI = pred_begin(ExitBlocks[i]), PE = pred_end(ExitBlocks[i]); PI != PE; ++PI) - if (!contains(*PI)) + if (!LoopBBs.count(*PI)) return false; // All the requirements are met. return true; diff --git a/lib/Analysis/MallocHelper.cpp b/lib/Analysis/MallocHelper.cpp index 89051d1..e7bb41e 100644 --- a/lib/Analysis/MallocHelper.cpp +++ b/lib/Analysis/MallocHelper.cpp @@ -130,9 +130,9 @@ static bool isArrayMallocHelper(const CallInst *CI, LLVMContext &Context, /// matches the malloc call IR generated by CallInst::CreateMalloc(). This /// means that it is a malloc call with one bitcast use AND the malloc call's /// size argument is: -/// 1. a constant not equal to the malloc's allocated type +/// 1. a constant not equal to the size of the malloced type /// or -/// 2. the result of a multiplication by the malloc's allocated type +/// 2. the result of a multiplication by the size of the malloced type /// Otherwise it returns NULL. /// The unique bitcast is needed to determine the type/size of the array /// allocation. @@ -183,25 +183,60 @@ const Type* llvm::getMallocAllocatedType(const CallInst* CI) { return PT ? PT->getElementType() : NULL; } +/// isSafeToGetMallocArraySize - Returns true if the array size of a malloc can +/// be determined. It can be determined in these 3 cases of malloc codegen: +/// 1. non-array malloc: The malloc's size argument is a constant and equals the /// size of the type being malloced. +/// 2. array malloc: This is a malloc call with one bitcast use AND the malloc +/// call's size argument is a constant multiple of the size of the malloced +/// type. +/// 3. array malloc: This is a malloc call with one bitcast use AND the malloc +/// call's size argument is the result of a multiplication by the size of the +/// malloced type. +/// Otherwise returns false. +static bool isSafeToGetMallocArraySize(const CallInst *CI, + LLVMContext &Context, + const TargetData* TD) { + if (!CI) + return false; + + // Type must be known to determine array size. + const Type* T = getMallocAllocatedType(CI); + if (!T) return false; + + Value* MallocArg = CI->getOperand(1); + Constant *ElementSize = ConstantExpr::getSizeOf(T); + ElementSize = ConstantExpr::getTruncOrBitCast(ElementSize, + MallocArg->getType()); + + // First, check if it is a non-array malloc. + if (isa<ConstantExpr>(MallocArg) && (MallocArg == ElementSize)) + return true; + + // Second, check if it can be determined that this is an array malloc. + return isArrayMallocHelper(CI, Context, TD); +} + /// isConstantOne - Return true only if val is constant int 1. static bool isConstantOne(Value *val) { return isa<ConstantInt>(val) && cast<ConstantInt>(val)->isOne(); } -/// getMallocArraySize - Returns the array size of a malloc call. The array -/// size is computated in 1 of 3 ways: -/// 1. If the element type if of size 1, then array size is the argument to +/// getMallocArraySize - Returns the array size of a malloc call. For array +/// mallocs, the size is computated in 1 of 3 ways: +/// 1. If the element type is of size 1, then array size is the argument to /// malloc. /// 2. Else if the malloc's argument is a constant, the array size is that /// argument divided by the element type's size. /// 3. Else the malloc argument must be a multiplication and the array size is /// the first operand of the multiplication. -/// This function returns constant 1 if: -/// 1. The malloc call's allocated type cannot be determined. -/// 2. IR wasn't created by a call to CallInst::CreateMalloc() with a non-NULL -/// ArraySize. +/// For non-array mallocs, the computed size is constant 1. +/// This function returns NULL for all mallocs whose array size cannot be +/// determined. Value* llvm::getMallocArraySize(CallInst* CI, LLVMContext &Context, const TargetData* TD) { + if (!isSafeToGetMallocArraySize(CI, Context, TD)) + return NULL; + // Match CreateMalloc's use of constant 1 array-size for non-array mallocs. if (!isArrayMalloc(CI, Context, TD)) return ConstantInt::get(CI->getOperand(1)->getType(), 1); diff --git a/lib/Analysis/PointerTracking.cpp b/lib/Analysis/PointerTracking.cpp index 43f4af3..2309fbc 100644 --- a/lib/Analysis/PointerTracking.cpp +++ b/lib/Analysis/PointerTracking.cpp @@ -102,8 +102,9 @@ const SCEV *PointerTracking::computeAllocationCount(Value *P, if (CallInst *CI = extractMallocCall(V)) { Value *arraySize = getMallocArraySize(CI, P->getContext(), TD); - Ty = getMallocAllocatedType(CI); - if (!Ty || !arraySize) return SE->getCouldNotCompute(); + const Type* AllocTy = getMallocAllocatedType(CI); + if (!AllocTy || !arraySize) return SE->getCouldNotCompute(); + Ty = AllocTy; // arraySize elements of type Ty. return SE->getSCEV(arraySize); } diff --git a/lib/Analysis/ValueTracking.cpp b/lib/Analysis/ValueTracking.cpp index baa347a..dc0d489 100644 --- a/lib/Analysis/ValueTracking.cpp +++ b/lib/Analysis/ValueTracking.cpp @@ -469,26 +469,11 @@ void llvm::ComputeMaskedBits(Value *V, const APInt &Mask, break; } - case Instruction::Alloca: - case Instruction::Malloc: { + case Instruction::Alloca: { AllocationInst *AI = cast<AllocationInst>(V); unsigned Align = AI->getAlignment(); - if (Align == 0 && TD) { - if (isa<AllocaInst>(AI)) - Align = TD->getABITypeAlignment(AI->getType()->getElementType()); - else if (isa<MallocInst>(AI)) { - // Malloc returns maximally aligned memory. - Align = TD->getABITypeAlignment(AI->getType()->getElementType()); - Align = - std::max(Align, - (unsigned)TD->getABITypeAlignment( - Type::getDoubleTy(V->getContext()))); - Align = - std::max(Align, - (unsigned)TD->getABITypeAlignment( - Type::getInt64Ty(V->getContext()))); - } - } + if (Align == 0 && TD) + Align = TD->getABITypeAlignment(AI->getType()->getElementType()); if (Align > 0) KnownZero = Mask & APInt::getLowBitsSet(BitWidth, diff --git a/lib/AsmParser/LLLexer.cpp b/lib/AsmParser/LLLexer.cpp index 0e9f1a0..f6cea88 100644 --- a/lib/AsmParser/LLLexer.cpp +++ b/lib/AsmParser/LLLexer.cpp @@ -529,7 +529,7 @@ lltok::Kind LLLexer::LexIdentifier() { KEYWORD(module); KEYWORD(asm); KEYWORD(sideeffect); - KEYWORD(msasm); + KEYWORD(alignstack); KEYWORD(gc); KEYWORD(ccc); @@ -602,6 +602,10 @@ lltok::Kind LLLexer::LexIdentifier() { // Scan CurPtr ahead, seeing if there is just whitespace before the newline. if (JustWhitespaceNewLine(CurPtr)) return lltok::kw_zeroext; + } else if (Len == 6 && !memcmp(StartChar, "malloc", 6)) { + // FIXME: Remove in LLVM 3.0. + // Autoupgrade malloc instruction. + return lltok::kw_malloc; } // Keywords for instructions. @@ -641,7 +645,6 @@ lltok::Kind LLLexer::LexIdentifier() { INSTKEYWORD(unwind, Unwind); INSTKEYWORD(unreachable, Unreachable); - INSTKEYWORD(malloc, Malloc); INSTKEYWORD(alloca, Alloca); INSTKEYWORD(free, Free); INSTKEYWORD(load, Load); diff --git a/lib/AsmParser/LLParser.cpp b/lib/AsmParser/LLParser.cpp index 09bc5f7..271567b 100644 --- a/lib/AsmParser/LLParser.cpp +++ b/lib/AsmParser/LLParser.cpp @@ -69,6 +69,23 @@ bool LLParser::Run() { /// ValidateEndOfModule - Do final validity and sanity checks at the end of the /// module. bool LLParser::ValidateEndOfModule() { + // Update auto-upgraded malloc calls to "malloc". + // FIXME: Remove in LLVM 3.0. + if (MallocF) { + MallocF->setName("malloc"); + // If setName() does not set the name to "malloc", then there is already a + // declaration of "malloc". In that case, iterate over all calls to MallocF + // and get them to call the declared "malloc" instead. + if (MallocF->getName() != "malloc") { + Constant* RealMallocF = M->getFunction("malloc"); + if (RealMallocF->getType() != MallocF->getType()) + RealMallocF = ConstantExpr::getBitCast(RealMallocF, MallocF->getType()); + MallocF->replaceAllUsesWith(RealMallocF); + MallocF->eraseFromParent(); + MallocF = NULL; + } + } + if (!ForwardRefTypes.empty()) return Error(ForwardRefTypes.begin()->second.second, "use of undefined type named '" + @@ -1029,14 +1046,12 @@ bool LLParser::ParseOptionalCallingConv(CallingConv::ID &CC) { /// ::= /* empty */ /// ::= !dbg !42 bool LLParser::ParseOptionalCustomMetadata() { - - std::string Name; - if (Lex.getKind() == lltok::NamedOrCustomMD) { - Name = Lex.getStrVal(); - Lex.Lex(); - } else + if (Lex.getKind() != lltok::NamedOrCustomMD) return false; + std::string Name = Lex.getStrVal(); + Lex.Lex(); + if (Lex.getKind() != lltok::Metadata) return TokError("Expected '!' here"); Lex.Lex(); @@ -1047,7 +1062,7 @@ bool LLParser::ParseOptionalCustomMetadata() { MetadataContext &TheMetadata = M->getContext().getMetadata(); unsigned MDK = TheMetadata.getMDKind(Name.c_str()); if (!MDK) - MDK = TheMetadata.RegisterMDKind(Name.c_str()); + MDK = TheMetadata.registerMDKind(Name.c_str()); MDsOnInst.push_back(std::make_pair(MDK, cast<MDNode>(Node))); return false; @@ -1959,17 +1974,17 @@ bool LLParser::ParseValID(ValID &ID) { return false; case lltok::kw_asm: { - // ValID ::= 'asm' SideEffect? MsAsm? STRINGCONSTANT ',' STRINGCONSTANT - bool HasSideEffect, MsAsm; + // ValID ::= 'asm' SideEffect? AlignStack? STRINGCONSTANT ',' STRINGCONSTANT + bool HasSideEffect, AlignStack; Lex.Lex(); if (ParseOptionalToken(lltok::kw_sideeffect, HasSideEffect) || - ParseOptionalToken(lltok::kw_msasm, MsAsm) || + ParseOptionalToken(lltok::kw_alignstack, AlignStack) || ParseStringConstant(ID.StrVal) || ParseToken(lltok::comma, "expected comma in inline asm expression") || ParseToken(lltok::StringConstant, "expected constraint string")) return true; ID.StrVal2 = Lex.getStrVal(); - ID.UIntVal = HasSideEffect | ((unsigned)MsAsm<<1); + ID.UIntVal = HasSideEffect | ((unsigned)AlignStack<<1); ID.Kind = ValID::t_InlineAsm; return false; } @@ -2783,8 +2798,8 @@ bool LLParser::ParseInstruction(Instruction *&Inst, BasicBlock *BB, case lltok::kw_call: return ParseCall(Inst, PFS, false); case lltok::kw_tail: return ParseCall(Inst, PFS, true); // Memory. - case lltok::kw_alloca: - case lltok::kw_malloc: return ParseAlloc(Inst, PFS, KeywordVal); + case lltok::kw_alloca: return ParseAlloc(Inst, PFS); + case lltok::kw_malloc: return ParseAlloc(Inst, PFS, BB, false); case lltok::kw_free: return ParseFree(Inst, PFS); case lltok::kw_load: return ParseLoad(Inst, PFS, false); case lltok::kw_store: return ParseStore(Inst, PFS, false); @@ -2858,8 +2873,6 @@ bool LLParser::ParseRet(Instruction *&Inst, BasicBlock *BB, if (ParseType(Ty, true /*void allowed*/)) return true; if (Ty->isVoidTy()) { - if (EatIfPresent(lltok::comma)) - if (ParseOptionalCustomMetadata()) return true; Inst = ReturnInst::Create(Context); return false; } @@ -2895,8 +2908,6 @@ bool LLParser::ParseRet(Instruction *&Inst, BasicBlock *BB, } } } - if (EatIfPresent(lltok::comma)) - if (ParseOptionalCustomMetadata()) return true; Inst = ReturnInst::Create(Context, RV); return false; @@ -3294,7 +3305,7 @@ bool LLParser::ParseShuffleVector(Instruction *&Inst, PerFunctionState &PFS) { } /// ParsePHI -/// ::= 'phi' Type '[' Value ',' Value ']' (',' '[' Value ',' Valueß ']')* +/// ::= 'phi' Type '[' Value ',' Value ']' (',' '[' Value ',' Value ']')* bool LLParser::ParsePHI(Instruction *&Inst, PerFunctionState &PFS) { PATypeHolder Ty(Type::getVoidTy(Context)); Value *Op0, *Op1; @@ -3315,6 +3326,9 @@ bool LLParser::ParsePHI(Instruction *&Inst, PerFunctionState &PFS) { if (!EatIfPresent(lltok::comma)) break; + if (Lex.getKind() == lltok::NamedOrCustomMD) + break; + if (ParseToken(lltok::lsquare, "expected '[' in phi value list") || ParseValue(Ty, Op0, PFS) || ParseToken(lltok::comma, "expected ',' after insertelement value") || @@ -3323,6 +3337,9 @@ bool LLParser::ParsePHI(Instruction *&Inst, PerFunctionState &PFS) { return true; } + if (Lex.getKind() == lltok::NamedOrCustomMD) + if (ParseOptionalCustomMetadata()) return true; + if (!Ty->isFirstClassType()) return Error(TypeLoc, "phi node must have first class type"); @@ -3439,7 +3456,7 @@ bool LLParser::ParseCall(Instruction *&Inst, PerFunctionState &PFS, /// ::= 'malloc' Type (',' TypeAndValue)? (',' OptionalInfo)? /// ::= 'alloca' Type (',' TypeAndValue)? (',' OptionalInfo)? bool LLParser::ParseAlloc(Instruction *&Inst, PerFunctionState &PFS, - unsigned Opc) { + BasicBlock* BB, bool isAlloca) { PATypeHolder Ty(Type::getVoidTy(Context)); Value *Size = 0; LocTy SizeLoc; @@ -3460,10 +3477,20 @@ bool LLParser::ParseAlloc(Instruction *&Inst, PerFunctionState &PFS, if (Size && Size->getType() != Type::getInt32Ty(Context)) return Error(SizeLoc, "element count must be i32"); - if (Opc == Instruction::Malloc) - Inst = new MallocInst(Ty, Size, Alignment); - else + if (isAlloca) { Inst = new AllocaInst(Ty, Size, Alignment); + return false; + } + + // Autoupgrade old malloc instruction to malloc call. + // FIXME: Remove in LLVM 3.0. + const Type *IntPtrTy = Type::getInt32Ty(Context); + if (!MallocF) + // Prototype malloc as "void *(int32)". + // This function is renamed as "malloc" in ValidateEndOfModule(). + MallocF = cast<Function>( + M->getOrInsertFunction("", Type::getInt8PtrTy(Context), IntPtrTy, NULL)); + Inst = CallInst::CreateMalloc(BB, IntPtrTy, Ty, Size, MallocF); return false; } diff --git a/lib/AsmParser/LLParser.h b/lib/AsmParser/LLParser.h index 97bf2f3..5dd6a2e 100644 --- a/lib/AsmParser/LLParser.h +++ b/lib/AsmParser/LLParser.h @@ -75,9 +75,11 @@ namespace llvm { std::map<std::string, std::pair<GlobalValue*, LocTy> > ForwardRefVals; std::map<unsigned, std::pair<GlobalValue*, LocTy> > ForwardRefValIDs; std::vector<GlobalValue*> NumberedVals; + Function* MallocF; public: LLParser(MemoryBuffer *F, SourceMgr &SM, SMDiagnostic &Err, Module *m) : - Context(m->getContext()), Lex(F, SM, Err, m->getContext()), M(m) {} + Context(m->getContext()), Lex(F, SM, Err, m->getContext()), + M(m), MallocF(NULL) {} bool Run(); LLVMContext& getContext() { return Context; } @@ -276,7 +278,8 @@ namespace llvm { bool ParseShuffleVector(Instruction *&I, PerFunctionState &PFS); bool ParsePHI(Instruction *&I, PerFunctionState &PFS); bool ParseCall(Instruction *&I, PerFunctionState &PFS, bool isTail); - bool ParseAlloc(Instruction *&I, PerFunctionState &PFS, unsigned Opc); + bool ParseAlloc(Instruction *&I, PerFunctionState &PFS, + BasicBlock *BB = 0, bool isAlloca = true); bool ParseFree(Instruction *&I, PerFunctionState &PFS); bool ParseLoad(Instruction *&I, PerFunctionState &PFS, bool isVolatile); bool ParseStore(Instruction *&I, PerFunctionState &PFS, bool isVolatile); diff --git a/lib/AsmParser/LLToken.h b/lib/AsmParser/LLToken.h index b3c59ee..f5072fe 100644 --- a/lib/AsmParser/LLToken.h +++ b/lib/AsmParser/LLToken.h @@ -62,9 +62,8 @@ namespace lltok { kw_module, kw_asm, kw_sideeffect, - kw_msasm, + kw_alignstack, kw_gc, - kw_dbg, kw_c, kw_cc, kw_ccc, kw_fastcc, kw_coldcc, diff --git a/lib/Bitcode/Reader/BitcodeReader.cpp b/lib/Bitcode/Reader/BitcodeReader.cpp index 4eb12c6..3a385cb 100644 --- a/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/lib/Bitcode/Reader/BitcodeReader.cpp @@ -840,7 +840,15 @@ bool BitcodeReader::ParseMetadata() { for (unsigned i = 1; i != RecordLength; ++i) Name[i-1] = Record[i]; MetadataContext &TheMetadata = Context.getMetadata(); - TheMetadata.MDHandlerNames[Name.str()] = Kind; + unsigned ExistingKind = TheMetadata.getMDKind(Name.str()); + if (ExistingKind == 0) { + unsigned NewKind = TheMetadata.registerMDKind(Name.str()); + assert (Kind == NewKind + && "Unable to handle custom metadata mismatch!"); + } else { + assert (ExistingKind == Kind + && "Unable to handle custom metadata mismatch!"); + } break; } } @@ -1165,7 +1173,7 @@ bool BitcodeReader::ParseConstants() { if (Record.size() < 2) return Error("Invalid INLINEASM record"); std::string AsmStr, ConstrStr; bool HasSideEffects = Record[0] & 1; - bool IsMsAsm = Record[0] >> 1; + bool IsAlignStack = Record[0] >> 1; unsigned AsmStrSize = Record[1]; if (2+AsmStrSize >= Record.size()) return Error("Invalid INLINEASM record"); @@ -1179,7 +1187,7 @@ bool BitcodeReader::ParseConstants() { ConstrStr += (char)Record[3+AsmStrSize+i]; const PointerType *PTy = cast<PointerType>(CurTy); V = InlineAsm::get(cast<FunctionType>(PTy->getElementType()), - AsmStr, ConstrStr, HasSideEffects, IsMsAsm); + AsmStr, ConstrStr, HasSideEffects, IsAlignStack); break; } } @@ -2044,14 +2052,18 @@ bool BitcodeReader::ParseFunctionBody(Function *F) { } case bitc::FUNC_CODE_INST_MALLOC: { // MALLOC: [instty, op, align] + // Autoupgrade malloc instruction to malloc call. + // FIXME: Remove in LLVM 3.0. if (Record.size() < 3) return Error("Invalid MALLOC record"); const PointerType *Ty = dyn_cast_or_null<PointerType>(getTypeByID(Record[0])); Value *Size = getFnValueByID(Record[1], Type::getInt32Ty(Context)); - unsigned Align = Record[2]; if (!Ty || !Size) return Error("Invalid MALLOC record"); - I = new MallocInst(Ty->getElementType(), Size, (1 << Align) >> 1); + if (!CurBB) return Error("Invalid malloc instruction with no BB"); + const Type *Int32Ty = IntegerType::getInt32Ty(CurBB->getContext()); + I = CallInst::CreateMalloc(CurBB, Int32Ty, Ty->getElementType(), + Size, NULL); InstructionList.push_back(I); break; } diff --git a/lib/Bitcode/Writer/BitcodeWriter.cpp b/lib/Bitcode/Writer/BitcodeWriter.cpp index 12a1f5e..037854e 100644 --- a/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -517,9 +517,7 @@ static void WriteModuleMetadata(const ValueEnumerator &VE, } // Code: [strchar x N] - const char *StrBegin = MDS->begin(); - for (unsigned i = 0, e = MDS->length(); i != e; ++i) - Record.push_back(StrBegin[i]); + Record.append(MDS->begin(), MDS->end()); // Emit the finished record. Stream.EmitRecord(bitc::METADATA_STRING, Record, MDSAbbrev); @@ -563,22 +561,22 @@ static void WriteMetadataAttachment(const Function &F, // Write metadata attachments // METADATA_ATTACHMENT - [m x [value, [n x [id, mdnode]]] MetadataContext &TheMetadata = F.getContext().getMetadata(); + typedef SmallVector<std::pair<unsigned, TrackingVH<MDNode> >, 2> MDMapTy; + MDMapTy MDs; for (Function::const_iterator BB = F.begin(), E = F.end(); BB != E; ++BB) for (BasicBlock::const_iterator I = BB->begin(), E = BB->end(); I != E; ++I) { - const MetadataContext::MDMapTy *P = TheMetadata.getMDs(I); - if (!P) continue; + MDs.clear(); + TheMetadata.getMDs(I, MDs); bool RecordedInstruction = false; - for (MetadataContext::MDMapTy::const_iterator PI = P->begin(), - PE = P->end(); PI != PE; ++PI) { - if (MDNode *ND = dyn_cast_or_null<MDNode>(PI->second)) { - if (RecordedInstruction == false) { - Record.push_back(VE.getInstructionID(I)); - RecordedInstruction = true; - } - Record.push_back(PI->first); - Record.push_back(VE.getValueID(ND)); + for (MDMapTy::const_iterator PI = MDs.begin(), PE = MDs.end(); + PI != PE; ++PI) { + if (RecordedInstruction == false) { + Record.push_back(VE.getInstructionID(I)); + RecordedInstruction = true; } + Record.push_back(PI->first); + Record.push_back(VE.getValueID(PI->second)); } if (!Record.empty()) { if (!StartedMetadataBlock) { @@ -604,11 +602,13 @@ static void WriteModuleMetadataStore(const Module *M, // Write metadata kinds // METADATA_KIND - [n x [id, name]] MetadataContext &TheMetadata = M->getContext().getMetadata(); - const StringMap<unsigned> *Kinds = TheMetadata.getHandlerNames(); - for (StringMap<unsigned>::const_iterator - I = Kinds->begin(), E = Kinds->end(); I != E; ++I) { - Record.push_back(I->second); - StringRef KName = I->first(); + SmallVector<std::pair<unsigned, StringRef>, 4> Names; + TheMetadata.getHandlerNames(Names); + for (SmallVector<std::pair<unsigned, StringRef>, 4>::iterator + I = Names.begin(), + E = Names.end(); I != E; ++I) { + Record.push_back(I->first); + StringRef KName = I->second; for (unsigned i = 0, e = KName.size(); i != e; ++i) Record.push_back(KName[i]); if (!StartedMetadataBlock) { @@ -680,7 +680,7 @@ static void WriteConstants(unsigned FirstVal, unsigned LastVal, if (const InlineAsm *IA = dyn_cast<InlineAsm>(V)) { Record.push_back(unsigned(IA->hasSideEffects()) | - unsigned(IA->isMsAsm()) << 1); + unsigned(IA->isAlignStack()) << 1); // Add the asm string. const std::string &AsmStr = IA->getAsmString(); @@ -1054,13 +1054,6 @@ static void WriteInstruction(const Instruction &I, unsigned InstID, Vals.push_back(VE.getValueID(I.getOperand(i))); break; - case Instruction::Malloc: - Code = bitc::FUNC_CODE_INST_MALLOC; - Vals.push_back(VE.getTypeID(I.getType())); - Vals.push_back(VE.getValueID(I.getOperand(0))); // size. - Vals.push_back(Log2_32(cast<MallocInst>(I).getAlignment())+1); - break; - case Instruction::Free: Code = bitc::FUNC_CODE_INST_FREE; PushValueAndType(I.getOperand(0), InstID, Vals, VE); diff --git a/lib/Bitcode/Writer/ValueEnumerator.cpp b/lib/Bitcode/Writer/ValueEnumerator.cpp index 60253ad..85aa5fa 100644 --- a/lib/Bitcode/Writer/ValueEnumerator.cpp +++ b/lib/Bitcode/Writer/ValueEnumerator.cpp @@ -87,6 +87,8 @@ ValueEnumerator::ValueEnumerator(const Module *M) { EnumerateType(I->getType()); MetadataContext &TheMetadata = F->getContext().getMetadata(); + typedef SmallVector<std::pair<unsigned, TrackingVH<MDNode> >, 2> MDMapTy; + MDMapTy MDs; for (Function::const_iterator BB = F->begin(), E = F->end(); BB != E; ++BB) for (BasicBlock::const_iterator I = BB->begin(), E = BB->end(); I!=E;++I){ for (User::const_op_iterator OI = I->op_begin(), E = I->op_end(); @@ -99,12 +101,11 @@ ValueEnumerator::ValueEnumerator(const Module *M) { EnumerateAttributes(II->getAttributes()); // Enumerate metadata attached with this instruction. - const MetadataContext::MDMapTy *MDs = TheMetadata.getMDs(I); - if (MDs) - for (MetadataContext::MDMapTy::const_iterator MI = MDs->begin(), - ME = MDs->end(); MI != ME; ++MI) - if (MDNode *MDN = dyn_cast_or_null<MDNode>(MI->second)) - EnumerateMetadata(MDN); + MDs.clear(); + TheMetadata.getMDs(I, MDs); + for (MDMapTy::const_iterator MI = MDs.begin(), ME = MDs.end(); MI != ME; + ++MI) + EnumerateMetadata(MI->second); } } @@ -214,10 +215,9 @@ void ValueEnumerator::EnumerateMetadata(const MetadataBase *MD) { MDValues.push_back(std::make_pair(MD, 1U)); MDValueMap[MD] = MDValues.size(); MDValueID = MDValues.size(); - for (MDNode::const_elem_iterator I = N->elem_begin(), E = N->elem_end(); - I != E; ++I) { - if (*I) - EnumerateValue(*I); + for (unsigned i = 0, e = N->getNumElements(); i != e; ++i) { + if (Value *V = N->getElement(i)) + EnumerateValue(V); else EnumerateType(Type::getVoidTy(MD->getContext())); } diff --git a/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/lib/CodeGen/AsmPrinter/DwarfDebug.cpp index 2914851..d50e5e3 100644 --- a/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ b/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -923,7 +923,7 @@ void DwarfDebug::ConstructTypeDIE(CompileUnit *DW_Unit, DIE &Buffer, AddType(DW_Unit, &Buffer, FromTy); // Add name if not anonymous or intermediate type. - if (Name) + if (Name && Tag != dwarf::DW_TAG_pointer_type) AddString(&Buffer, dwarf::DW_AT_name, dwarf::DW_FORM_string, Name); // Add size if non-zero (derived types might be zero-sized.) @@ -1811,10 +1811,18 @@ void DwarfDebug::CollectVariableInfo() { DIVariable DV (Var); if (DV.isNull()) continue; unsigned VSlot = VI->second; + DbgScope *Scope = NULL; DenseMap<MDNode *, DbgScope *>::iterator DSI = DbgScopeMap.find(DV.getContext().getNode()); - assert (DSI != DbgScopeMap.end() && "Unable to find variable scope!"); - DbgScope *Scope = DSI->second; + if (DSI != DbgScopeMap.end()) + Scope = DSI->second; + else + // There is not any instruction assocated with this scope, so get + // a new scope. + Scope = getDbgScope(DV.getContext().getNode(), + NULL /* Not an instruction */, + NULL /* Not inlined */); + assert (Scope && "Unable to find variable scope!"); Scope->AddVariable(new DbgVariable(DV, VSlot, false)); } } diff --git a/lib/CodeGen/AsmPrinter/DwarfException.cpp b/lib/CodeGen/AsmPrinter/DwarfException.cpp index 626523b..6c03b55 100644 --- a/lib/CodeGen/AsmPrinter/DwarfException.cpp +++ b/lib/CodeGen/AsmPrinter/DwarfException.cpp @@ -871,28 +871,7 @@ void DwarfException::EmitExceptionTable() { Asm->EOL("Next action"); } - // Emit the Catch Clauses. The code for the catch clauses following the same - // try is similar to a switch statement. The catch clause action record - // informs the runtime about the type of a catch clause and about the - // associated switch value. - // - // Action Record Fields: - // - // * Filter Value - // Positive value, starting at 1. Index in the types table of the - // __typeinfo for the catch-clause type. 1 is the first word preceding - // TTBase, 2 is the second word, and so on. Used by the runtime to check - // if the thrown exception type matches the catch-clause type. Back-end - // generated switch statements check against this value. - // - // * Next - // Signed offset, in bytes from the start of this field, to the next - // chained action record, or zero if none. - // - // The order of the action records determined by the next field is the order - // of the catch clauses as they appear in the source code, and must be kept in - // the same order. As a result, changing the order of the catch clause would - // change the semantics of the program. + // Emit the Catch TypeInfos. for (std::vector<GlobalVariable *>::const_reverse_iterator I = TypeInfos.rbegin(), E = TypeInfos.rend(); I != E; ++I) { const GlobalVariable *GV = *I; @@ -907,12 +886,15 @@ void DwarfException::EmitExceptionTable() { Asm->EOL("TypeInfo"); } - // Emit the Type Table. + // Emit the Exception Specifications. for (std::vector<unsigned>::const_iterator I = FilterIds.begin(), E = FilterIds.end(); I < E; ++I) { unsigned TypeID = *I; Asm->EmitULEB128Bytes(TypeID); - Asm->EOL("Filter TypeInfo index"); + if (TypeID != 0) + Asm->EOL("Exception specification"); + else + Asm->EOL(); } Asm->EmitAlignment(2, 0, 0, false); diff --git a/lib/CodeGen/BranchFolding.cpp b/lib/CodeGen/BranchFolding.cpp index f9abeac..66c5aa5 100644 --- a/lib/CodeGen/BranchFolding.cpp +++ b/lib/CodeGen/BranchFolding.cpp @@ -945,15 +945,15 @@ bool BranchFolder::OptimizeBlock(MachineBasicBlock *MBB) { } } - // If this block doesn't fall through (e.g. it ends with an uncond branch or - // has no successors) and if the pred falls through into this block, and if - // it would otherwise fall through into the block after this, move this - // block to the end of the function. + // If this block has no successors (e.g. it is a return block or ends with + // a call to a no-return function like abort or __cxa_throw) and if the pred + // falls through into this block, and if it would otherwise fall through + // into the block after this, move this block to the end of the function. // // We consider it more likely that execution will stay in the function (e.g. // due to loops) than it is to exit it. This asserts in loops etc, moving // the assert condition out of the loop body. - if (!PriorCond.empty() && PriorFBB == 0 && + if (MBB->succ_empty() && !PriorCond.empty() && PriorFBB == 0 && MachineFunction::iterator(PriorTBB) == FallThrough && !CanFallThrough(MBB)) { bool DoTransform = true; diff --git a/lib/CodeGen/CodePlacementOpt.cpp b/lib/CodeGen/CodePlacementOpt.cpp index 42b24a6..6fff12c 100644 --- a/lib/CodeGen/CodePlacementOpt.cpp +++ b/lib/CodeGen/CodePlacementOpt.cpp @@ -34,14 +34,6 @@ namespace { const TargetInstrInfo *TII; const TargetLowering *TLI; - /// ChangedMBBs - BBs which are modified by OptimizeIntraLoopEdges. - SmallPtrSet<MachineBasicBlock*, 8> ChangedMBBs; - - /// UncondJmpMBBs - A list of BBs which are in loops and end with - /// unconditional branches. - SmallVector<std::pair<MachineBasicBlock*,MachineBasicBlock*>, 4> - UncondJmpMBBs; - public: static char ID; CodePlacementOpt() : MachineFunctionPass(&ID) {} @@ -58,7 +50,19 @@ namespace { } private: - bool OptimizeIntraLoopEdges(); + bool HasFallthrough(MachineBasicBlock *MBB); + bool HasAnalyzableTerminator(MachineBasicBlock *MBB); + void Splice(MachineFunction &MF, + MachineFunction::iterator InsertPt, + MachineFunction::iterator Begin, + MachineFunction::iterator End); + void UpdateTerminator(MachineBasicBlock *MBB); + bool EliminateUnconditionalJumpsToTop(MachineFunction &MF, + MachineLoop *L); + bool MoveDiscontiguousLoopBlocks(MachineFunction &MF, + MachineLoop *L); + bool OptimizeIntraLoopEdgesInLoopNest(MachineFunction &MF, MachineLoop *L); + bool OptimizeIntraLoopEdges(MachineFunction &MF); bool AlignLoops(MachineFunction &MF); bool AlignLoop(MachineFunction &MF, MachineLoop *L, unsigned Align); }; @@ -70,168 +74,354 @@ FunctionPass *llvm::createCodePlacementOptPass() { return new CodePlacementOpt(); } -/// OptimizeBackEdges - Place loop back edges to move unconditional branches -/// out of the loop. -/// -/// A: -/// ... -/// <fallthrough to B> +/// HasFallthrough - Test whether the given branch has a fallthrough, either as +/// a plain fallthrough or as a fallthrough case of a conditional branch. /// -/// B: --> loop header -/// ... -/// jcc <cond> C, [exit] -/// -/// C: -/// ... -/// jmp B +bool CodePlacementOpt::HasFallthrough(MachineBasicBlock *MBB) { + MachineBasicBlock *TBB = 0, *FBB = 0; + SmallVector<MachineOperand, 4> Cond; + if (TII->AnalyzeBranch(*MBB, TBB, FBB, Cond)) + return false; + // This conditional branch has no fallthrough. + if (FBB) + return false; + // An unconditional branch has no fallthrough. + if (Cond.empty() && TBB) + return false; + // It has a fallthrough. + return true; +} + +/// HasAnalyzableTerminator - Test whether AnalyzeBranch will succeed on MBB. +/// This is called before major changes are begun to test whether it will be +/// possible to complete the changes. /// -/// ==> +/// Target-specific code is hereby encouraged to make AnalyzeBranch succeed +/// whenever possible. /// -/// A: -/// ... -/// jmp B +bool CodePlacementOpt::HasAnalyzableTerminator(MachineBasicBlock *MBB) { + // Conservatively ignore EH landing pads. + if (MBB->isLandingPad()) return false; + + // Ignore blocks which look like they might have EH-related control flow. + // At the time of this writing, there are blocks which AnalyzeBranch + // thinks end in single uncoditional branches, yet which have two CFG + // successors. Code in this file is not prepared to reason about such things. + if (!MBB->empty() && MBB->back().getOpcode() == TargetInstrInfo::EH_LABEL) + return false; + + // Aggressively handle return blocks and similar constructs. + if (MBB->succ_empty()) return true; + + // Ask the target's AnalyzeBranch if it can handle this block. + MachineBasicBlock *TBB = 0, *FBB = 0; + SmallVector<MachineOperand, 4> Cond; + // Make the the terminator is understood. + if (TII->AnalyzeBranch(*MBB, TBB, FBB, Cond)) + return false; + // Make sure we have the option of reversing the condition. + if (!Cond.empty() && TII->ReverseBranchCondition(Cond)) + return false; + return true; +} + +/// Splice - Move the sequence of instructions [Begin,End) to just before +/// InsertPt. Update branch instructions as needed to account for broken +/// fallthrough edges and to take advantage of newly exposed fallthrough +/// opportunities. /// -/// C: -/// ... -/// <fallthough to B> -/// -/// B: --> loop header -/// ... -/// jcc <cond> C, [exit] +void CodePlacementOpt::Splice(MachineFunction &MF, + MachineFunction::iterator InsertPt, + MachineFunction::iterator Begin, + MachineFunction::iterator End) { + assert(Begin != MF.begin() && End != MF.begin() && InsertPt != MF.begin() && + "Splice can't change the entry block!"); + MachineFunction::iterator OldBeginPrior = prior(Begin); + MachineFunction::iterator OldEndPrior = prior(End); + + MF.splice(InsertPt, Begin, End); + + UpdateTerminator(prior(Begin)); + UpdateTerminator(OldBeginPrior); + UpdateTerminator(OldEndPrior); +} + +/// UpdateTerminator - Update the terminator instructions in MBB to account +/// for changes to the layout. If the block previously used a fallthrough, +/// it may now need a branch, and if it previously used branching it may now +/// be able to use a fallthrough. /// -bool CodePlacementOpt::OptimizeIntraLoopEdges() { - if (!TLI->shouldOptimizeCodePlacement()) - return false; +void CodePlacementOpt::UpdateTerminator(MachineBasicBlock *MBB) { + // A block with no successors has no concerns with fall-through edges. + if (MBB->succ_empty()) return; + + MachineBasicBlock *TBB = 0, *FBB = 0; + SmallVector<MachineOperand, 4> Cond; + bool B = TII->AnalyzeBranch(*MBB, TBB, FBB, Cond); + (void) B; + assert(!B && "UpdateTerminators requires analyzable predecessors!"); + if (Cond.empty()) { + if (TBB) { + // The block has an unconditional branch. If its successor is now + // its layout successor, delete the branch. + if (MBB->isLayoutSuccessor(TBB)) + TII->RemoveBranch(*MBB); + } else { + // The block has an unconditional fallthrough. If its successor is not + // its layout successor, insert a branch. + TBB = *MBB->succ_begin(); + if (!MBB->isLayoutSuccessor(TBB)) + TII->InsertBranch(*MBB, TBB, 0, Cond); + } + } else { + if (FBB) { + // The block has a non-fallthrough conditional branch. If one of its + // successors is its layout successor, rewrite it to a fallthrough + // conditional branch. + if (MBB->isLayoutSuccessor(TBB)) { + TII->RemoveBranch(*MBB); + TII->ReverseBranchCondition(Cond); + TII->InsertBranch(*MBB, FBB, 0, Cond); + } else if (MBB->isLayoutSuccessor(FBB)) { + TII->RemoveBranch(*MBB); + TII->InsertBranch(*MBB, TBB, 0, Cond); + } + } else { + // The block has a fallthrough conditional branch. + MachineBasicBlock *MBBA = *MBB->succ_begin(); + MachineBasicBlock *MBBB = *next(MBB->succ_begin()); + if (MBBA == TBB) std::swap(MBBB, MBBA); + if (MBB->isLayoutSuccessor(TBB)) { + TII->RemoveBranch(*MBB); + TII->ReverseBranchCondition(Cond); + TII->InsertBranch(*MBB, MBBA, 0, Cond); + } else if (!MBB->isLayoutSuccessor(MBBA)) { + TII->RemoveBranch(*MBB); + TII->InsertBranch(*MBB, TBB, MBBA, Cond); + } + } + } +} +/// EliminateUnconditionalJumpsToTop - Move blocks which unconditionally jump +/// to the loop top to the top of the loop so that they have a fall through. +/// This can introduce a branch on entry to the loop, but it can eliminate a +/// branch within the loop. See the @simple case in +/// test/CodeGen/X86/loop_blocks.ll for an example of this. +bool CodePlacementOpt::EliminateUnconditionalJumpsToTop(MachineFunction &MF, + MachineLoop *L) { bool Changed = false; - for (unsigned i = 0, e = UncondJmpMBBs.size(); i != e; ++i) { - MachineBasicBlock *MBB = UncondJmpMBBs[i].first; - MachineBasicBlock *SuccMBB = UncondJmpMBBs[i].second; - MachineLoop *L = MLI->getLoopFor(MBB); - assert(L && "BB is expected to be in a loop!"); - - if (ChangedMBBs.count(MBB)) { - // BB has been modified, re-analyze. - MachineBasicBlock *TBB = 0, *FBB = 0; - SmallVector<MachineOperand, 4> Cond; - if (TII->AnalyzeBranch(*MBB, TBB, FBB, Cond) || !Cond.empty()) + MachineBasicBlock *TopMBB = L->getTopBlock(); + + bool BotHasFallthrough = HasFallthrough(L->getBottomBlock()); + + if (TopMBB == MF.begin() || + HasAnalyzableTerminator(prior(MachineFunction::iterator(TopMBB)))) { + new_top: + for (MachineBasicBlock::pred_iterator PI = TopMBB->pred_begin(), + PE = TopMBB->pred_end(); PI != PE; ++PI) { + MachineBasicBlock *Pred = *PI; + if (Pred == TopMBB) continue; + if (HasFallthrough(Pred)) continue; + if (!L->contains(Pred)) continue; + + // Verify that we can analyze all the loop entry edges before beginning + // any changes which will require us to be able to analyze them. + if (Pred == MF.begin()) continue; - if (MLI->getLoopFor(TBB) != L || TBB->isLandingPad()) + if (!HasAnalyzableTerminator(Pred)) + continue; + if (!HasAnalyzableTerminator(prior(MachineFunction::iterator(Pred)))) continue; - SuccMBB = TBB; - } else { - assert(MLI->getLoopFor(SuccMBB) == L && - "Successor is not in the same loop!"); - } - if (MBB->isLayoutSuccessor(SuccMBB)) { - // Successor is right after MBB, just eliminate the unconditional jmp. - // Can this happen? - TII->RemoveBranch(*MBB); - ChangedMBBs.insert(MBB); - ++NumIntraElim; + // Move the block. Changed = true; - continue; - } - // Now check if the predecessor is fallthrough from any BB. If there is, - // that BB should be from outside the loop since edge will become a jmp. - bool OkToMove = true; - MachineBasicBlock *FtMBB = 0, *FtTBB = 0, *FtFBB = 0; - SmallVector<MachineOperand, 4> FtCond; - for (MachineBasicBlock::pred_iterator PI = SuccMBB->pred_begin(), - PE = SuccMBB->pred_end(); PI != PE; ++PI) { - MachineBasicBlock *PredMBB = *PI; - if (PredMBB->isLayoutSuccessor(SuccMBB)) { - if (TII->AnalyzeBranch(*PredMBB, FtTBB, FtFBB, FtCond)) { - OkToMove = false; + // Move it and all the blocks that can reach it via fallthrough edges + // exclusively, to keep existing fallthrough edges intact. + MachineFunction::iterator Begin = Pred; + MachineFunction::iterator End = next(Begin); + while (Begin != MF.begin()) { + MachineFunction::iterator Prior = prior(Begin); + if (Prior == MF.begin()) + break; + // Stop when a non-fallthrough edge is found. + if (!HasFallthrough(Prior)) + break; + // Stop if a block which could fall-through out of the loop is found. + if (Prior->isSuccessor(End)) + break; + // If we've reached the top, stop scanning. + if (Prior == MachineFunction::iterator(TopMBB)) { + // We know top currently has a fall through (because we just checked + // it) which would be lost if we do the transformation, so it isn't + // worthwhile to do the transformation unless it would expose a new + // fallthrough edge. + if (!Prior->isSuccessor(End)) + goto next_pred; + // Otherwise we can stop scanning and procede to move the blocks. break; } - if (!FtTBB) - FtTBB = SuccMBB; - else if (!FtFBB) { - assert(FtFBB != SuccMBB && "Unexpected control flow!"); - FtFBB = SuccMBB; - } - - // A fallthrough. - FtMBB = PredMBB; - MachineLoop *PL = MLI->getLoopFor(PredMBB); - if (PL && (PL == L || PL->getLoopDepth() >= L->getLoopDepth())) - OkToMove = false; - - break; + // If we hit a switch or something complicated, don't move anything + // for this predecessor. + if (!HasAnalyzableTerminator(prior(MachineFunction::iterator(Prior)))) + break; + // Ok, the block prior to Begin will be moved along with the rest. + // Extend the range to include it. + Begin = Prior; + ++NumIntraMoved; } + + // Move the blocks. + Splice(MF, TopMBB, Begin, End); + + // Update TopMBB. + TopMBB = L->getTopBlock(); + + // We have a new loop top. Iterate on it. We shouldn't have to do this + // too many times if BranchFolding has done a reasonable job. + goto new_top; + next_pred:; } + } + + // If the loop previously didn't exit with a fall-through and it now does, + // we eliminated a branch. + if (Changed && + !BotHasFallthrough && + HasFallthrough(L->getBottomBlock())) { + ++NumIntraElim; + BotHasFallthrough = true; + } + + return Changed; +} + +/// MoveDiscontiguousLoopBlocks - Move any loop blocks that are not in the +/// portion of the loop contiguous with the header. This usually makes the loop +/// contiguous, provided that AnalyzeBranch can handle all the relevant +/// branching. See the @cfg_islands case in test/CodeGen/X86/loop_blocks.ll +/// for an example of this. +bool CodePlacementOpt::MoveDiscontiguousLoopBlocks(MachineFunction &MF, + MachineLoop *L) { + bool Changed = false; + MachineBasicBlock *TopMBB = L->getTopBlock(); + MachineBasicBlock *BotMBB = L->getBottomBlock(); + + // Determine a position to move orphaned loop blocks to. If TopMBB is not + // entered via fallthrough and BotMBB is exited via fallthrough, prepend them + // to the top of the loop to avoid loosing that fallthrough. Otherwise append + // them to the bottom, even if it previously had a fallthrough, on the theory + // that it's worth an extra branch to keep the loop contiguous. + MachineFunction::iterator InsertPt = next(MachineFunction::iterator(BotMBB)); + bool InsertAtTop = false; + if (TopMBB != MF.begin() && + !HasFallthrough(prior(MachineFunction::iterator(TopMBB))) && + HasFallthrough(BotMBB)) { + InsertPt = TopMBB; + InsertAtTop = true; + } + + // Keep a record of which blocks are in the portion of the loop contiguous + // with the loop header. + SmallPtrSet<MachineBasicBlock *, 8> ContiguousBlocks; + for (MachineFunction::iterator I = TopMBB, + E = next(MachineFunction::iterator(BotMBB)); I != E; ++I) + ContiguousBlocks.insert(I); + + // Find non-contigous blocks and fix them. + if (InsertPt != MF.begin() && HasAnalyzableTerminator(prior(InsertPt))) + for (MachineLoop::block_iterator BI = L->block_begin(), BE = L->block_end(); + BI != BE; ++BI) { + MachineBasicBlock *BB = *BI; + + // Verify that we can analyze all the loop entry edges before beginning + // any changes which will require us to be able to analyze them. + if (!HasAnalyzableTerminator(BB)) + continue; + if (!HasAnalyzableTerminator(prior(MachineFunction::iterator(BB)))) + continue; + + // If the layout predecessor is part of the loop, this block will be + // processed along with it. This keeps them in their relative order. + if (BB != MF.begin() && + L->contains(prior(MachineFunction::iterator(BB)))) + continue; - if (!OkToMove) - continue; - - // Is it profitable? If SuccMBB can fallthrough itself, that can be changed - // into a jmp. - MachineBasicBlock *TBB = 0, *FBB = 0; - SmallVector<MachineOperand, 4> Cond; - if (TII->AnalyzeBranch(*SuccMBB, TBB, FBB, Cond)) - continue; - if (!TBB && Cond.empty()) - TBB = next(MachineFunction::iterator(SuccMBB)); - else if (!FBB && !Cond.empty()) - FBB = next(MachineFunction::iterator(SuccMBB)); - - // This calculate the cost of the transformation. Also, it finds the *only* - // intra-loop edge if there is one. - int Cost = 0; - bool HasOneIntraSucc = true; - MachineBasicBlock *IntraSucc = 0; - for (MachineBasicBlock::succ_iterator SI = SuccMBB->succ_begin(), - SE = SuccMBB->succ_end(); SI != SE; ++SI) { - MachineBasicBlock *SSMBB = *SI; - if (MLI->getLoopFor(SSMBB) == L) { - if (!IntraSucc) - IntraSucc = SSMBB; - else - HasOneIntraSucc = false; + // Check to see if this block is already contiguous with the main + // portion of the loop. + if (!ContiguousBlocks.insert(BB)) + continue; + + // Move the block. + Changed = true; + + // Process this block and all loop blocks contiguous with it, to keep + // them in their relative order. + MachineFunction::iterator Begin = BB; + MachineFunction::iterator End = next(MachineFunction::iterator(BB)); + for (; End != MF.end(); ++End) { + if (!L->contains(End)) break; + if (!HasAnalyzableTerminator(End)) break; + ContiguousBlocks.insert(End); + ++NumIntraMoved; } - if (SuccMBB->isLayoutSuccessor(SSMBB)) - // This will become a jmp. - ++Cost; - else if (MBB->isLayoutSuccessor(SSMBB)) { - // One of the successor will become the new fallthrough. - if (SSMBB == FBB) { - FBB = 0; - --Cost; - } else if (!FBB && SSMBB == TBB && Cond.empty()) { - TBB = 0; - --Cost; - } else if (!Cond.empty() && !TII->ReverseBranchCondition(Cond)) { - assert(SSMBB == TBB); - TBB = FBB; - FBB = 0; - --Cost; + // If we're inserting at the bottom of the loop, and the code we're + // moving originally had fall-through successors, bring the sucessors + // up with the loop blocks to preserve the fall-through edges. + if (!InsertAtTop) + for (; End != MF.end(); ++End) { + if (L->contains(End)) break; + if (!HasAnalyzableTerminator(End)) break; + if (!HasFallthrough(prior(End))) break; } - } - } - if (Cost) - continue; - - // Now, let's move the successor to below the BB to eliminate the jmp. - SuccMBB->moveAfter(MBB); - TII->RemoveBranch(*MBB); - TII->RemoveBranch(*SuccMBB); - if (TBB) - TII->InsertBranch(*SuccMBB, TBB, FBB, Cond); - ChangedMBBs.insert(MBB); - ChangedMBBs.insert(SuccMBB); - if (FtMBB) { - TII->RemoveBranch(*FtMBB); - TII->InsertBranch(*FtMBB, FtTBB, FtFBB, FtCond); - ChangedMBBs.insert(FtMBB); + + // Move the blocks. This may invalidate TopMBB and/or BotMBB, but + // we don't need them anymore at this point. + Splice(MF, InsertPt, Begin, End); } - Changed = true; - } - ++NumIntraMoved; + return Changed; +} + +/// OptimizeIntraLoopEdgesInLoopNest - Reposition loop blocks to minimize +/// intra-loop branching and to form contiguous loops. +/// +/// This code takes the approach of making minor changes to the existing +/// layout to fix specific loop-oriented problems. Also, it depends on +/// AnalyzeBranch, which can't understand complex control instructions. +/// +bool CodePlacementOpt::OptimizeIntraLoopEdgesInLoopNest(MachineFunction &MF, + MachineLoop *L) { + bool Changed = false; + + // Do optimization for nested loops. + for (MachineLoop::iterator I = L->begin(), E = L->end(); I != E; ++I) + Changed |= OptimizeIntraLoopEdgesInLoopNest(MF, *I); + + // Do optimization for this loop. + Changed |= EliminateUnconditionalJumpsToTop(MF, L); + Changed |= MoveDiscontiguousLoopBlocks(MF, L); + + return Changed; +} + +/// OptimizeIntraLoopEdges - Reposition loop blocks to minimize +/// intra-loop branching and to form contiguous loops. +/// +bool CodePlacementOpt::OptimizeIntraLoopEdges(MachineFunction &MF) { + bool Changed = false; + + if (!TLI->shouldOptimizeCodePlacement()) + return Changed; + + // Do optimization for each loop in the function. + for (MachineLoopInfo::iterator I = MLI->begin(), E = MLI->end(); + I != E; ++I) + if (!(*I)->getParentLoop()) + Changed |= OptimizeIntraLoopEdgesInLoopNest(MF, *I); + return Changed; } @@ -255,6 +445,8 @@ bool CodePlacementOpt::AlignLoops(MachineFunction &MF) { return Changed; } +/// AlignLoop - Align loop headers to target preferred alignments. +/// bool CodePlacementOpt::AlignLoop(MachineFunction &MF, MachineLoop *L, unsigned Align) { bool Changed = false; @@ -263,17 +455,7 @@ bool CodePlacementOpt::AlignLoop(MachineFunction &MF, MachineLoop *L, for (MachineLoop::iterator I = L->begin(), E = L->end(); I != E; ++I) Changed |= AlignLoop(MF, *I, Align); - MachineBasicBlock *TopMBB = L->getHeader(); - if (TopMBB == MF.begin()) return Changed; - - MachineBasicBlock *PredMBB = prior(MachineFunction::iterator(TopMBB)); - while (MLI->getLoopFor(PredMBB) == L) { - TopMBB = PredMBB; - if (TopMBB == MF.begin()) return Changed; - PredMBB = prior(MachineFunction::iterator(TopMBB)); - } - - TopMBB->setAlignment(Align); + L->getTopBlock()->setAlignment(Align); Changed = true; ++NumLoopsAligned; @@ -288,30 +470,9 @@ bool CodePlacementOpt::runOnMachineFunction(MachineFunction &MF) { TLI = MF.getTarget().getTargetLowering(); TII = MF.getTarget().getInstrInfo(); - // Analyze the BBs first and keep track of BBs that - // end with an unconditional jmp to another block in the same loop. - for (MachineFunction::iterator I = MF.begin(), E = MF.end(); I != E; ++I) { - MachineBasicBlock *MBB = I; - if (MBB->isLandingPad()) - continue; - MachineLoop *L = MLI->getLoopFor(MBB); - if (!L) - continue; - - MachineBasicBlock *TBB = 0, *FBB = 0; - SmallVector<MachineOperand, 4> Cond; - if (TII->AnalyzeBranch(*MBB, TBB, FBB, Cond) || !Cond.empty()) - continue; - if (MLI->getLoopFor(TBB) == L && !TBB->isLandingPad()) - UncondJmpMBBs.push_back(std::make_pair(MBB, TBB)); - } - - bool Changed = OptimizeIntraLoopEdges(); + bool Changed = OptimizeIntraLoopEdges(MF); Changed |= AlignLoops(MF); - ChangedMBBs.clear(); - UncondJmpMBBs.clear(); - return Changed; } diff --git a/lib/CodeGen/ExactHazardRecognizer.cpp b/lib/CodeGen/ExactHazardRecognizer.cpp index 4f32c2b..f35d196 100644 --- a/lib/CodeGen/ExactHazardRecognizer.cpp +++ b/lib/CodeGen/ExactHazardRecognizer.cpp @@ -22,7 +22,8 @@ using namespace llvm; -ExactHazardRecognizer::ExactHazardRecognizer(const InstrItineraryData &LItinData) : +ExactHazardRecognizer:: +ExactHazardRecognizer(const InstrItineraryData &LItinData) : ScheduleHazardRecognizer(), ItinData(LItinData) { // Determine the maximum depth of any itinerary. This determines the diff --git a/lib/CodeGen/LLVMTargetMachine.cpp b/lib/CodeGen/LLVMTargetMachine.cpp index 4e713a6..e58a9ca 100644 --- a/lib/CodeGen/LLVMTargetMachine.cpp +++ b/lib/CodeGen/LLVMTargetMachine.cpp @@ -323,7 +323,7 @@ bool LLVMTargetMachine::addCommonCodeGenPasses(PassManagerBase &PM, // Second pass scheduler. if (OptLevel != CodeGenOpt::None) { - PM.add(createPostRAScheduler()); + PM.add(createPostRAScheduler(OptLevel)); printAndVerify(PM); } diff --git a/lib/CodeGen/LiveIntervalAnalysis.cpp b/lib/CodeGen/LiveIntervalAnalysis.cpp index 93d3d4c..79f46f3 100644 --- a/lib/CodeGen/LiveIntervalAnalysis.cpp +++ b/lib/CodeGen/LiveIntervalAnalysis.cpp @@ -28,7 +28,6 @@ #include "llvm/CodeGen/MachineMemOperand.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/Passes.h" -#include "llvm/CodeGen/PseudoSourceValue.h" #include "llvm/Target/TargetRegisterInfo.h" #include "llvm/Target/TargetInstrInfo.h" #include "llvm/Target/TargetMachine.h" @@ -2603,7 +2602,19 @@ bool LiveIntervals::spillPhysRegAroundRegDefsUses(const LiveInterval &li, tri_->isSuperRegister(*AS, SpillReg)); bool Cut = false; - LiveInterval &pli = getInterval(SpillReg); + SmallVector<unsigned, 4> PRegs; + if (hasInterval(SpillReg)) + PRegs.push_back(SpillReg); + else { + SmallSet<unsigned, 4> Added; + for (const unsigned* AS = tri_->getSubRegisters(SpillReg); *AS; ++AS) + if (Added.insert(*AS) && hasInterval(*AS)) { + PRegs.push_back(*AS); + for (const unsigned* ASS = tri_->getSubRegisters(*AS); *ASS; ++ASS) + Added.insert(*ASS); + } + } + SmallPtrSet<MachineInstr*, 8> SeenMIs; for (MachineRegisterInfo::reg_iterator I = mri_->reg_begin(li.reg), E = mri_->reg_end(); I != E; ++I) { @@ -2613,8 +2624,12 @@ bool LiveIntervals::spillPhysRegAroundRegDefsUses(const LiveInterval &li, continue; SeenMIs.insert(MI); LiveIndex Index = getInstructionIndex(MI); - if (pli.liveAt(Index)) { - vrm.addEmergencySpill(SpillReg, MI); + for (unsigned i = 0, e = PRegs.size(); i != e; ++i) { + unsigned PReg = PRegs[i]; + LiveInterval &pli = getInterval(PReg); + if (!pli.liveAt(Index)) + continue; + vrm.addEmergencySpill(PReg, MI); LiveIndex StartIdx = getLoadIndex(Index); LiveIndex EndIdx = getNextSlot(getStoreIndex(Index)); if (pli.isInOneLiveRange(StartIdx, EndIdx)) { @@ -2626,12 +2641,12 @@ bool LiveIntervals::spillPhysRegAroundRegDefsUses(const LiveInterval &li, Msg << "Ran out of registers during register allocation!"; if (MI->getOpcode() == TargetInstrInfo::INLINEASM) { Msg << "\nPlease check your inline asm statement for invalid " - << "constraints:\n"; + << "constraints:\n"; MI->print(Msg, tm_); } llvm_report_error(Msg.str()); } - for (const unsigned* AS = tri_->getSubRegisters(SpillReg); *AS; ++AS) { + for (const unsigned* AS = tri_->getSubRegisters(PReg); *AS; ++AS) { if (!hasInterval(*AS)) continue; LiveInterval &spli = getInterval(*AS); diff --git a/lib/CodeGen/MachineInstr.cpp b/lib/CodeGen/MachineInstr.cpp index b9d3ba7..1f85e92 100644 --- a/lib/CodeGen/MachineInstr.cpp +++ b/lib/CodeGen/MachineInstr.cpp @@ -220,8 +220,10 @@ void MachineOperand::print(raw_ostream &OS, const TargetMachine *TM) const { OS << "imp-"; OS << "def"; NeedComma = true; - } else if (isImplicit()) + } else if (isImplicit()) { OS << "imp-use"; + NeedComma = true; + } if (isKill() || isDead() || isUndef()) { if (NeedComma) OS << ','; diff --git a/lib/CodeGen/MachineLoopInfo.cpp b/lib/CodeGen/MachineLoopInfo.cpp index 2da8e37..db77d19 100644 --- a/lib/CodeGen/MachineLoopInfo.cpp +++ b/lib/CodeGen/MachineLoopInfo.cpp @@ -43,3 +43,31 @@ void MachineLoopInfo::getAnalysisUsage(AnalysisUsage &AU) const { AU.addRequired<MachineDominatorTree>(); MachineFunctionPass::getAnalysisUsage(AU); } + +MachineBasicBlock *MachineLoop::getTopBlock() { + MachineBasicBlock *TopMBB = getHeader(); + MachineFunction::iterator Begin = TopMBB->getParent()->begin(); + if (TopMBB != Begin) { + MachineBasicBlock *PriorMBB = prior(MachineFunction::iterator(TopMBB)); + while (contains(PriorMBB)) { + TopMBB = PriorMBB; + if (TopMBB == Begin) break; + PriorMBB = prior(MachineFunction::iterator(TopMBB)); + } + } + return TopMBB; +} + +MachineBasicBlock *MachineLoop::getBottomBlock() { + MachineBasicBlock *BotMBB = getHeader(); + MachineFunction::iterator End = BotMBB->getParent()->end(); + if (BotMBB != prior(End)) { + MachineBasicBlock *NextMBB = next(MachineFunction::iterator(BotMBB)); + while (contains(NextMBB)) { + BotMBB = NextMBB; + if (BotMBB == next(MachineFunction::iterator(BotMBB))) break; + NextMBB = next(MachineFunction::iterator(BotMBB)); + } + } + return BotMBB; +} diff --git a/lib/CodeGen/MachineSink.cpp b/lib/CodeGen/MachineSink.cpp index 0f3b33f..a00bebb 100644 --- a/lib/CodeGen/MachineSink.cpp +++ b/lib/CodeGen/MachineSink.cpp @@ -34,10 +34,8 @@ STATISTIC(NumSunk, "Number of machine instructions sunk"); namespace { class VISIBILITY_HIDDEN MachineSinking : public MachineFunctionPass { - const TargetMachine *TM; const TargetInstrInfo *TII; const TargetRegisterInfo *TRI; - MachineFunction *CurMF; // Current MachineFunction MachineRegisterInfo *RegInfo; // Machine register information MachineDominatorTree *DT; // Machine dominator tree AliasAnalysis *AA; @@ -92,19 +90,16 @@ bool MachineSinking::AllUsesDominatedByBlock(unsigned Reg, return true; } - - bool MachineSinking::runOnMachineFunction(MachineFunction &MF) { DEBUG(errs() << "******** Machine Sinking ********\n"); - CurMF = &MF; - TM = &CurMF->getTarget(); - TII = TM->getInstrInfo(); - TRI = TM->getRegisterInfo(); - RegInfo = &CurMF->getRegInfo(); + const TargetMachine &TM = MF.getTarget(); + TII = TM.getInstrInfo(); + TRI = TM.getRegisterInfo(); + RegInfo = &MF.getRegInfo(); DT = &getAnalysis<MachineDominatorTree>(); AA = &getAnalysis<AliasAnalysis>(); - AllocatableSet = TRI->getAllocatableSet(*CurMF); + AllocatableSet = TRI->getAllocatableSet(MF); bool EverMadeChange = false; @@ -112,7 +107,7 @@ bool MachineSinking::runOnMachineFunction(MachineFunction &MF) { bool MadeChange = false; // Process all basic blocks. - for (MachineFunction::iterator I = CurMF->begin(), E = CurMF->end(); + for (MachineFunction::iterator I = MF.begin(), E = MF.end(); I != E; ++I) MadeChange |= ProcessBlock(*I); @@ -256,7 +251,7 @@ bool MachineSinking::SinkInstruction(MachineInstr *MI, bool &SawStore) { if (SuccToSinkTo->isLandingPad()) return false; - // If is not possible to sink an instruction into its own block. This can + // It is not possible to sink an instruction into its own block. This can // happen with loops. if (MI->getParent() == SuccToSinkTo) return false; diff --git a/lib/CodeGen/PostRASchedulerList.cpp b/lib/CodeGen/PostRASchedulerList.cpp index e52158c..8fdbe9b 100644 --- a/lib/CodeGen/PostRASchedulerList.cpp +++ b/lib/CodeGen/PostRASchedulerList.cpp @@ -78,10 +78,12 @@ DebugMod("postra-sched-debugmod", namespace { class VISIBILITY_HIDDEN PostRAScheduler : public MachineFunctionPass { AliasAnalysis *AA; + CodeGenOpt::Level OptLevel; public: static char ID; - PostRAScheduler() : MachineFunctionPass(&ID) {} + PostRAScheduler(CodeGenOpt::Level ol) : + MachineFunctionPass(&ID), OptLevel(ol) {} void getAnalysisUsage(AnalysisUsage &AU) const { AU.setPreservesCFG(); @@ -126,6 +128,9 @@ namespace { /// AA - AliasAnalysis for making memory reference queries. AliasAnalysis *AA; + /// AntiDepMode - Anti-dependence breaking mode + TargetSubtarget::AntiDepBreakMode AntiDepMode; + /// Classes - For live regs that are only used in one register class in a /// live range, the register class. If the register is not live, the /// corresponding value is null. If the register is live but used in @@ -154,10 +159,11 @@ namespace { const MachineLoopInfo &MLI, const MachineDominatorTree &MDT, ScheduleHazardRecognizer *HR, - AliasAnalysis *aa) + AliasAnalysis *aa, + TargetSubtarget::AntiDepBreakMode adm) : ScheduleDAGInstrs(MF, MLI, MDT), Topo(SUnits), AllocatableSet(TRI->getAllocatableSet(MF)), - HazardRec(HR), AA(aa) {} + HazardRec(HR), AA(aa), AntiDepMode(adm) {} ~SchedulePostRATDList() { delete HazardRec; @@ -232,14 +238,21 @@ bool PostRAScheduler::runOnMachineFunction(MachineFunction &Fn) { AA = &getAnalysis<AliasAnalysis>(); // Check for explicit enable/disable of post-ra scheduling. + TargetSubtarget::AntiDepBreakMode AntiDepMode = TargetSubtarget::ANTIDEP_NONE; if (EnablePostRAScheduler.getPosition() > 0) { if (!EnablePostRAScheduler) - return true; + return false; } else { - // Check that post-RA scheduling is enabled for this function + // Check that post-RA scheduling is enabled for this target. const TargetSubtarget &ST = Fn.getTarget().getSubtarget<TargetSubtarget>(); - if (!ST.enablePostRAScheduler()) - return true; + if (!ST.enablePostRAScheduler(OptLevel, AntiDepMode)) + return false; + } + + // Check for antidep breaking override... + if (EnableAntiDepBreaking.getPosition() > 0) { + AntiDepMode = (EnableAntiDepBreaking) ? + TargetSubtarget::ANTIDEP_CRITICAL : TargetSubtarget::ANTIDEP_NONE; } DEBUG(errs() << "PostRAScheduler\n"); @@ -251,7 +264,7 @@ bool PostRAScheduler::runOnMachineFunction(MachineFunction &Fn) { (ScheduleHazardRecognizer *)new ExactHazardRecognizer(InstrItins) : (ScheduleHazardRecognizer *)new SimpleHazardRecognizer(); - SchedulePostRATDList Scheduler(Fn, MLI, MDT, HR, AA); + SchedulePostRATDList Scheduler(Fn, MLI, MDT, HR, AA, AntiDepMode); // Loop over all of the basic blocks for (MachineFunction::iterator MBB = Fn.begin(), MBBe = Fn.end(); @@ -391,7 +404,7 @@ void SchedulePostRATDList::Schedule() { // Build the scheduling graph. BuildSchedGraph(AA); - if (EnableAntiDepBreaking) { + if (AntiDepMode != TargetSubtarget::ANTIDEP_NONE) { if (BreakAntiDependencies()) { // We made changes. Update the dependency graph. // Theoretically we could update the graph in place: @@ -1195,6 +1208,6 @@ void SchedulePostRATDList::ListScheduleTopDown() { // Public Constructor Functions //===----------------------------------------------------------------------===// -FunctionPass *llvm::createPostRAScheduler() { - return new PostRAScheduler(); +FunctionPass *llvm::createPostRAScheduler(CodeGenOpt::Level OptLevel) { + return new PostRAScheduler(OptLevel); } diff --git a/lib/CodeGen/PreAllocSplitting.cpp b/lib/CodeGen/PreAllocSplitting.cpp index 8fa07d4..726869a 100644 --- a/lib/CodeGen/PreAllocSplitting.cpp +++ b/lib/CodeGen/PreAllocSplitting.cpp @@ -952,7 +952,7 @@ MachineInstr* PreAllocSplitting::FoldSpill(unsigned vreg, if (I != IntervalSSMap.end()) { SS = I->second; } else { - SS = MFI->CreateStackObject(RC->getSize(), RC->getAlignment()); + SS = MFI->CreateStackObject(RC->getSize(), RC->getAlignment()); } MachineInstr* FMI = TII->foldMemoryOperand(*MBB->getParent(), diff --git a/lib/CodeGen/PrologEpilogInserter.cpp b/lib/CodeGen/PrologEpilogInserter.cpp index 7af0bba..a0860a1 100644 --- a/lib/CodeGen/PrologEpilogInserter.cpp +++ b/lib/CodeGen/PrologEpilogInserter.cpp @@ -259,7 +259,7 @@ void PEI::calculateCalleeSavedRegisters(MachineFunction &Fn) { // the TargetRegisterClass if the stack alignment is smaller. Use the // min. Align = std::min(Align, StackAlign); - FrameIdx = FFI->CreateStackObject(RC->getSize(), Align); + FrameIdx = FFI->CreateStackObject(RC->getSize(), Align, true); if ((unsigned)FrameIdx < MinCSFrameIndex) MinCSFrameIndex = FrameIdx; if ((unsigned)FrameIdx > MaxCSFrameIndex) MaxCSFrameIndex = FrameIdx; } else { @@ -729,10 +729,12 @@ void PEI::replaceFrameIndices(MachineFunction &Fn) { /// the instruciton range. Return the operand number of the kill in Operand. static MachineBasicBlock::iterator findLastUseReg(MachineBasicBlock::iterator I, MachineBasicBlock::iterator ME, - unsigned Reg, unsigned *Operand) { + unsigned Reg) { // Scan forward to find the last use of this virtual register for (++I; I != ME; ++I) { MachineInstr *MI = I; + bool isDefInsn = false; + bool isKillInsn = false; for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) if (MI->getOperand(i).isReg()) { unsigned OpReg = MI->getOperand(i).getReg(); @@ -740,13 +742,14 @@ findLastUseReg(MachineBasicBlock::iterator I, MachineBasicBlock::iterator ME, continue; assert (OpReg == Reg && "overlapping use of scavenged index register!"); - // If this is the killing use, we're done - if (MI->getOperand(i).isKill()) { - if (Operand) - *Operand = i; - return I; - } + // If this is the killing use, we have a candidate. + if (MI->getOperand(i).isKill()) + isKillInsn = true; + else if (MI->getOperand(i).isDef()) + isDefInsn = true; } + if (isKillInsn && !isDefInsn) + return I; } // If we hit the end of the basic block, there was no kill of // the virtual register, which is wrong. @@ -763,10 +766,13 @@ void PEI::scavengeFrameVirtualRegs(MachineFunction &Fn) { E = Fn.end(); BB != E; ++BB) { RS->enterBasicBlock(BB); + // FIXME: The logic flow in this function is still too convoluted. + // It needs a cleanup refactoring. Do that in preparation for tracking + // more than one scratch register value and using ranges to find + // available scratch registers. unsigned CurrentVirtReg = 0; unsigned CurrentScratchReg = 0; bool havePrevValue = false; - unsigned PrevScratchReg = 0; int PrevValue = 0; MachineInstr *PrevLastUseMI = NULL; unsigned PrevLastUseOp = 0; @@ -776,37 +782,39 @@ void PEI::scavengeFrameVirtualRegs(MachineFunction &Fn) { // The instruction stream may change in the loop, so check BB->end() // directly. - for (MachineBasicBlock::iterator I = BB->begin(); I != BB->end(); ++I) { + for (MachineBasicBlock::iterator I = BB->begin(); I != BB->end(); ) { MachineInstr *MI = I; - for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) + bool isDefInsn = false; + bool isKillInsn = false; + bool clobbersScratchReg = false; + bool DoIncr = true; + for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { if (MI->getOperand(i).isReg()) { MachineOperand &MO = MI->getOperand(i); unsigned Reg = MO.getReg(); if (Reg == 0) continue; if (!TargetRegisterInfo::isVirtualRegister(Reg)) { - // If we have an active scavenged register, we shouldn't be - // seeing any references to it. - assert (Reg != CurrentScratchReg - && "overlapping use of scavenged frame index register!"); - // If we have a previous scratch reg, check and see if anything // here kills whatever value is in there. - if (Reg == PrevScratchReg) { + if (Reg == CurrentScratchReg) { if (MO.isUse()) { // Two-address operands implicitly kill - if (MO.isKill() || MI->isRegTiedToDefOperand(i)) { - havePrevValue = false; - PrevScratchReg = 0; - } + if (MO.isKill() || MI->isRegTiedToDefOperand(i)) + clobbersScratchReg = true; } else { assert (MO.isDef()); - havePrevValue = false; - PrevScratchReg = 0; + clobbersScratchReg = true; } } continue; } + // If this is a def, remember that this insn defines the value. + // This lets us properly consider insns which re-use the scratch + // register, such as r2 = sub r2, #imm, in the middle of the + // scratch range. + if (MO.isDef()) + isDefInsn = true; // Have we already allocated a scratch register for this virtual? if (Reg != CurrentVirtReg) { @@ -837,50 +845,75 @@ void PEI::scavengeFrameVirtualRegs(MachineFunction &Fn) { // for the virtual register are exclusively for the purpose // of populating the value in the register. That's reasonable // for these frame index registers, but it's still a very, very - // strong assumption. Perhaps this implies that the frame index - // elimination should be before register allocation, with - // conservative heuristics since we'll know less then, and - // the reuse calculations done directly when doing the code-gen? + // strong assumption. rdar://7322732. Better would be to + // explicitly check each instruction in the range for references + // to the virtual register. Only delete those insns that + // touch the virtual register. // Find the last use of the new virtual register. Remove all // instruction between here and there, and update the current // instruction to reference the last use insn instead. MachineBasicBlock::iterator LastUseMI = - findLastUseReg(I, BB->end(), Reg, &i); + findLastUseReg(I, BB->end(), Reg); + // Remove all instructions up 'til the last use, since they're // just calculating the value we already have. BB->erase(I, LastUseMI); MI = I = LastUseMI; - e = MI->getNumOperands(); - CurrentScratchReg = PrevScratchReg; - // Extend the live range of the register + // Extend the live range of the scratch register PrevLastUseMI->getOperand(PrevLastUseOp).setIsKill(false); RS->setUsed(CurrentScratchReg); - } else { CurrentVirtReg = Reg; - const TargetRegisterClass *RC = Fn.getRegInfo().getRegClass(Reg); - CurrentScratchReg = RS->FindUnusedReg(RC); - if (CurrentScratchReg == 0) - // No register is "free". Scavenge a register. - CurrentScratchReg = RS->scavengeRegister(RC, I, SPAdj); - PrevValue = Value; + // We deleted the instruction we were scanning the operands of. + // Jump back to the instruction iterator loop. Don't increment + // past this instruction since we updated the iterator already. + DoIncr = false; + break; } + + // Scavenge a new scratch register + CurrentVirtReg = Reg; + const TargetRegisterClass *RC = Fn.getRegInfo().getRegClass(Reg); + CurrentScratchReg = RS->FindUnusedReg(RC); + if (CurrentScratchReg == 0) + // No register is "free". Scavenge a register. + CurrentScratchReg = RS->scavengeRegister(RC, I, SPAdj); + + PrevValue = Value; } + // replace this reference to the virtual register with the + // scratch register. assert (CurrentScratchReg && "Missing scratch register!"); MI->getOperand(i).setReg(CurrentScratchReg); - // If this is the last use of the register, stop tracking it. if (MI->getOperand(i).isKill()) { - PrevScratchReg = CurrentScratchReg; - PrevLastUseMI = MI; + isKillInsn = true; PrevLastUseOp = i; - CurrentScratchReg = CurrentVirtReg = 0; - havePrevValue = trackingCurrentValue; + PrevLastUseMI = MI; } } - RS->forward(MI); + } + // If this is the last use of the scratch, stop tracking it. The + // last use will be a kill operand in an instruction that does + // not also define the scratch register. + if (isKillInsn && !isDefInsn) { + CurrentVirtReg = 0; + havePrevValue = trackingCurrentValue; + } + // Similarly, notice if instruction clobbered the value in the + // register we're tracking for possible later reuse. This is noted + // above, but enforced here since the value is still live while we + // process the rest of the operands of the instruction. + if (clobbersScratchReg) { + havePrevValue = false; + CurrentScratchReg = 0; + } + if (DoIncr) { + RS->forward(I); + ++I; + } } } } diff --git a/lib/CodeGen/PseudoSourceValue.cpp b/lib/CodeGen/PseudoSourceValue.cpp index 00c5d46..70e8640 100644 --- a/lib/CodeGen/PseudoSourceValue.cpp +++ b/lib/CodeGen/PseudoSourceValue.cpp @@ -63,6 +63,8 @@ namespace { virtual bool isConstant(const MachineFrameInfo *MFI) const; + virtual bool isAliased(const MachineFrameInfo *MFI) const; + virtual void printCustom(raw_ostream &OS) const { OS << "FixedStack" << FI; } @@ -89,6 +91,26 @@ bool PseudoSourceValue::isConstant(const MachineFrameInfo *) const { return false; } +bool PseudoSourceValue::isAliased(const MachineFrameInfo *MFI) const { + if (this == getStack() || + this == getGOT() || + this == getConstantPool() || + this == getJumpTable()) + return false; + llvm_unreachable("Unknown PseudoSourceValue!"); + return true; +} + bool FixedStackPseudoSourceValue::isConstant(const MachineFrameInfo *MFI) const{ return MFI && MFI->isImmutableObjectIndex(FI); } + +bool FixedStackPseudoSourceValue::isAliased(const MachineFrameInfo *MFI) const { + // Negative frame indices are used for special things that don't + // appear in LLVM IR. Non-negative indices may be used for things + // like static allocas. + if (!MFI) + return FI >= 0; + // Spill slots should not alias others. + return !MFI->isFixedObjectIndex(FI) && !MFI->isSpillSlotObjectIndex(FI); +} diff --git a/lib/CodeGen/RegAllocLocal.cpp b/lib/CodeGen/RegAllocLocal.cpp index 6caa2d3..28ede55 100644 --- a/lib/CodeGen/RegAllocLocal.cpp +++ b/lib/CodeGen/RegAllocLocal.cpp @@ -263,7 +263,7 @@ int RALocal::getStackSpaceFor(unsigned VirtReg, const TargetRegisterClass *RC) { // Allocate a new stack object for this spill location... int FrameIdx = MF->getFrameInfo()->CreateStackObject(RC->getSize(), - RC->getAlignment()); + RC->getAlignment(),true); // Assign the slot... StackSlotForVirtReg[VirtReg] = FrameIdx; diff --git a/lib/CodeGen/RegisterScavenging.cpp b/lib/CodeGen/RegisterScavenging.cpp index 5f1c4e2..2518ce1 100644 --- a/lib/CodeGen/RegisterScavenging.cpp +++ b/lib/CodeGen/RegisterScavenging.cpp @@ -300,7 +300,7 @@ unsigned RegScavenger::scavengeRegister(const TargetRegisterClass *RC, // If the target knows how to save/restore the register, let it do so; // otherwise, use the emergency stack spill slot. - if (!TRI->saveScavengerRegister(*MBB, I, RC, SReg)) { + if (!TRI->saveScavengerRegister(*MBB, I, UseMI, RC, SReg)) { // Spill the scavenged register before I. assert(ScavengingFrameIndex >= 0 && "Cannot scavenge register without an emergency spill slot!"); @@ -310,8 +310,9 @@ unsigned RegScavenger::scavengeRegister(const TargetRegisterClass *RC, // Restore the scavenged register before its use (or first terminator). TII->loadRegFromStackSlot(*MBB, UseMI, SReg, ScavengingFrameIndex, RC); - } else - TRI->restoreScavengerRegister(*MBB, UseMI, RC, SReg); + II = prior(UseMI); + TRI->eliminateFrameIndex(II, SPAdj, NULL, this); + } ScavengeRestore = prior(UseMI); diff --git a/lib/CodeGen/ScheduleDAGInstrs.cpp b/lib/CodeGen/ScheduleDAGInstrs.cpp index 44e9296..43454dd 100644 --- a/lib/CodeGen/ScheduleDAGInstrs.cpp +++ b/lib/CodeGen/ScheduleDAGInstrs.cpp @@ -32,7 +32,9 @@ using namespace llvm; ScheduleDAGInstrs::ScheduleDAGInstrs(MachineFunction &mf, const MachineLoopInfo &mli, const MachineDominatorTree &mdt) - : ScheduleDAG(mf), MLI(mli), MDT(mdt), LoopRegs(MLI, MDT) {} + : ScheduleDAG(mf), MLI(mli), MDT(mdt), LoopRegs(MLI, MDT) { + MFI = mf.getFrameInfo(); +} /// Run - perform scheduling. /// @@ -95,7 +97,8 @@ static const Value *getUnderlyingObject(const Value *V) { /// getUnderlyingObjectForInstr - If this machine instr has memory reference /// information and it can be tracked to a normal reference to a known /// object, return the Value for that object. Otherwise return null. -static const Value *getUnderlyingObjectForInstr(const MachineInstr *MI) { +static const Value *getUnderlyingObjectForInstr(const MachineInstr *MI, + const MachineFrameInfo *MFI) { if (!MI->hasOneMemOperand() || !(*MI->memoperands_begin())->getValue() || (*MI->memoperands_begin())->isVolatile()) @@ -106,10 +109,19 @@ static const Value *getUnderlyingObjectForInstr(const MachineInstr *MI) { return 0; V = getUnderlyingObject(V); - if (!isa<PseudoSourceValue>(V) && !isIdentifiedObject(V)) - return 0; + if (const PseudoSourceValue *PSV = dyn_cast<PseudoSourceValue>(V)) { + // For now, ignore PseudoSourceValues which may alias LLVM IR values + // because the code that uses this function has no way to cope with + // such aliases. + if (PSV->isAliased(MFI)) + return 0; + return V; + } - return V; + if (isIdentifiedObject(V)) + return V; + + return 0; } void ScheduleDAGInstrs::StartBlock(MachineBasicBlock *BB) { @@ -344,7 +356,7 @@ void ScheduleDAGInstrs::BuildSchedGraph(AliasAnalysis *AA) { // Unknown memory accesses. Assume the worst. ChainMMO = 0; } else if (TID.mayStore()) { - if (const Value *V = getUnderlyingObjectForInstr(MI)) { + if (const Value *V = getUnderlyingObjectForInstr(MI, MFI)) { // A store to a specific PseudoSourceValue. Add precise dependencies. // Handle the def in MemDefs, if there is one. std::map<const Value *, SUnit *>::iterator I = MemDefs.find(V); @@ -377,7 +389,7 @@ void ScheduleDAGInstrs::BuildSchedGraph(AliasAnalysis *AA) { } else if (TID.mayLoad()) { if (MI->isInvariantLoad(AA)) { // Invariant load, no chain dependencies needed! - } else if (const Value *V = getUnderlyingObjectForInstr(MI)) { + } else if (const Value *V = getUnderlyingObjectForInstr(MI, MFI)) { // A load from a specific PseudoSourceValue. Add precise dependencies. std::map<const Value *, SUnit *>::iterator I = MemDefs.find(V); if (I != MemDefs.end()) diff --git a/lib/CodeGen/ScheduleDAGInstrs.h b/lib/CodeGen/ScheduleDAGInstrs.h index 29e1c98..366c3a8 100644 --- a/lib/CodeGen/ScheduleDAGInstrs.h +++ b/lib/CodeGen/ScheduleDAGInstrs.h @@ -98,6 +98,7 @@ namespace llvm { class VISIBILITY_HIDDEN ScheduleDAGInstrs : public ScheduleDAG { const MachineLoopInfo &MLI; const MachineDominatorTree &MDT; + const MachineFrameInfo *MFI; /// Defs, Uses - Remember where defs and uses of each physical register /// are as we iterate upward through the instructions. This is allocated diff --git a/lib/CodeGen/ScheduleDAGPrinter.cpp b/lib/CodeGen/ScheduleDAGPrinter.cpp index 95ad05e..4851d49 100644 --- a/lib/CodeGen/ScheduleDAGPrinter.cpp +++ b/lib/CodeGen/ScheduleDAGPrinter.cpp @@ -18,7 +18,6 @@ #include "llvm/CodeGen/MachineConstantPool.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineModuleInfo.h" -#include "llvm/CodeGen/PseudoSourceValue.h" #include "llvm/Target/TargetRegisterInfo.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Support/Debug.h" diff --git a/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/lib/CodeGen/SelectionDAG/DAGCombiner.cpp index 1ed3082..e3f8f0f 100644 --- a/lib/CodeGen/SelectionDAG/DAGCombiner.cpp +++ b/lib/CodeGen/SelectionDAG/DAGCombiner.cpp @@ -4381,15 +4381,17 @@ SDValue DAGCombiner::visitFP_EXTEND(SDNode *N) { SDValue DAGCombiner::visitFNEG(SDNode *N) { SDValue N0 = N->getOperand(0); + EVT VT = N->getValueType(0); if (isNegatibleForFree(N0, LegalOperations)) return GetNegatedExpression(N0, DAG, LegalOperations); // Transform fneg(bitconvert(x)) -> bitconvert(x^sign) to avoid loading // constant pool values. - if (N0.getOpcode() == ISD::BIT_CONVERT && N0.getNode()->hasOneUse() && - N0.getOperand(0).getValueType().isInteger() && - !N0.getOperand(0).getValueType().isVector()) { + if (N0.getOpcode() == ISD::BIT_CONVERT && + !VT.isVector() && + N0.getNode()->hasOneUse() && + N0.getOperand(0).getValueType().isInteger()) { SDValue Int = N0.getOperand(0); EVT IntVT = Int.getValueType(); if (IntVT.isInteger() && !IntVT.isVector()) { @@ -4397,7 +4399,7 @@ SDValue DAGCombiner::visitFNEG(SDNode *N) { DAG.getConstant(APInt::getSignBit(IntVT.getSizeInBits()), IntVT)); AddToWorkList(Int.getNode()); return DAG.getNode(ISD::BIT_CONVERT, N->getDebugLoc(), - N->getValueType(0), Int); + VT, Int); } } diff --git a/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp b/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp index fc01b07..7138dd2 100644 --- a/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp +++ b/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp @@ -1655,8 +1655,7 @@ void SelectionDAGLegalize::ExpandDYNAMIC_STACKALLOC(SDNode* Node, } /// LegalizeSetCCCondCode - Legalize a SETCC with given LHS and RHS and -/// condition code CC on the current target. This routine assumes LHS and rHS -/// have already been legalized by LegalizeSetCCOperands. It expands SETCC with +/// condition code CC on the current target. This routine expands SETCC with /// illegal condition code into AND / OR of multiple SETCC values. void SelectionDAGLegalize::LegalizeSetCCCondCode(EVT VT, SDValue &LHS, SDValue &RHS, diff --git a/lib/CodeGen/SelectionDAG/LegalizeTypes.h b/lib/CodeGen/SelectionDAG/LegalizeTypes.h index 859c656..e1b7022 100644 --- a/lib/CodeGen/SelectionDAG/LegalizeTypes.h +++ b/lib/CodeGen/SelectionDAG/LegalizeTypes.h @@ -617,6 +617,7 @@ private: SDValue WidenVecOp_BIT_CONVERT(SDNode *N); SDValue WidenVecOp_CONCAT_VECTORS(SDNode *N); SDValue WidenVecOp_EXTRACT_VECTOR_ELT(SDNode *N); + SDValue WidenVecOp_EXTRACT_SUBVECTOR(SDNode *N); SDValue WidenVecOp_STORE(SDNode* N); SDValue WidenVecOp_Convert(SDNode *N); diff --git a/lib/CodeGen/SelectionDAG/LegalizeTypesGeneric.cpp b/lib/CodeGen/SelectionDAG/LegalizeTypesGeneric.cpp index 0eafe62..dbd3e39 100644 --- a/lib/CodeGen/SelectionDAG/LegalizeTypesGeneric.cpp +++ b/lib/CodeGen/SelectionDAG/LegalizeTypesGeneric.cpp @@ -115,7 +115,8 @@ void DAGTypeLegalizer::ExpandRes_BIT_CONVERT(SDNode *N, SDValue &Lo, // Create the stack frame object. Make sure it is aligned for both // the source and expanded destination types. unsigned Alignment = - TLI.getTargetData()->getPrefTypeAlignment(NOutVT.getTypeForEVT(*DAG.getContext())); + TLI.getTargetData()->getPrefTypeAlignment(NOutVT. + getTypeForEVT(*DAG.getContext())); SDValue StackPtr = DAG.CreateStackTemporary(InVT, Alignment); int SPFI = cast<FrameIndexSDNode>(StackPtr.getNode())->getIndex(); const Value *SV = PseudoSourceValue::getFixedStack(SPFI); diff --git a/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp b/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp index a03f825..75e1239 100644 --- a/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp +++ b/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp @@ -1789,6 +1789,7 @@ bool DAGTypeLegalizer::WidenVectorOperand(SDNode *N, unsigned ResNo) { case ISD::BIT_CONVERT: Res = WidenVecOp_BIT_CONVERT(N); break; case ISD::CONCAT_VECTORS: Res = WidenVecOp_CONCAT_VECTORS(N); break; + case ISD::EXTRACT_SUBVECTOR: Res = WidenVecOp_EXTRACT_SUBVECTOR(N); break; case ISD::EXTRACT_VECTOR_ELT: Res = WidenVecOp_EXTRACT_VECTOR_ELT(N); break; case ISD::STORE: Res = WidenVecOp_STORE(N); break; @@ -1893,6 +1894,12 @@ SDValue DAGTypeLegalizer::WidenVecOp_CONCAT_VECTORS(SDNode *N) { return DAG.getNode(ISD::BUILD_VECTOR, dl, VT, &Ops[0], NumElts); } +SDValue DAGTypeLegalizer::WidenVecOp_EXTRACT_SUBVECTOR(SDNode *N) { + SDValue InOp = GetWidenedVector(N->getOperand(0)); + return DAG.getNode(ISD::EXTRACT_SUBVECTOR, N->getDebugLoc(), + N->getValueType(0), InOp, N->getOperand(1)); +} + SDValue DAGTypeLegalizer::WidenVecOp_EXTRACT_VECTOR_ELT(SDNode *N) { SDValue InOp = GetWidenedVector(N->getOperand(0)); return DAG.getNode(ISD::EXTRACT_VECTOR_ELT, N->getDebugLoc(), diff --git a/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/lib/CodeGen/SelectionDAG/SelectionDAG.cpp index 542bf64..37736c0 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAG.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAG.cpp @@ -30,6 +30,7 @@ #include "llvm/Target/TargetLowering.h" #include "llvm/Target/TargetOptions.h" #include "llvm/Target/TargetInstrInfo.h" +#include "llvm/Target/TargetIntrinsicInfo.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/ErrorHandling.h" @@ -4600,7 +4601,7 @@ SDNode *SelectionDAG::MorphNodeTo(SDNode *N, unsigned Opc, N->InitOperands(new SDUse[NumOps], Ops, NumOps); N->OperandsNeedDelete = true; } else - MN->InitOperands(MN->OperandList, Ops, NumOps); + N->InitOperands(N->OperandList, Ops, NumOps); } // Delete any nodes that are still dead after adding the uses for the @@ -5404,14 +5405,16 @@ std::string SDNode::getOperationName(const SelectionDAG *G) const { case ISD::EH_RETURN: return "EH_RETURN"; case ISD::ConstantPool: return "ConstantPool"; case ISD::ExternalSymbol: return "ExternalSymbol"; - case ISD::INTRINSIC_WO_CHAIN: { - unsigned IID = cast<ConstantSDNode>(getOperand(0))->getZExtValue(); - return Intrinsic::getName((Intrinsic::ID)IID); - } + case ISD::INTRINSIC_WO_CHAIN: case ISD::INTRINSIC_VOID: case ISD::INTRINSIC_W_CHAIN: { - unsigned IID = cast<ConstantSDNode>(getOperand(1))->getZExtValue(); - return Intrinsic::getName((Intrinsic::ID)IID); + unsigned OpNo = getOpcode() == ISD::INTRINSIC_WO_CHAIN ? 0 : 1; + unsigned IID = cast<ConstantSDNode>(getOperand(OpNo))->getZExtValue(); + if (IID < Intrinsic::num_intrinsics) + return Intrinsic::getName((Intrinsic::ID)IID); + else if (const TargetIntrinsicInfo *TII = G->getTarget().getIntrinsicInfo()) + return TII->getName(IID); + llvm_unreachable("Invalid intrinsic ID"); } case ISD::BUILD_VECTOR: return "BUILD_VECTOR"; diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGBuild.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGBuild.cpp index 9017e43..adcc532 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGBuild.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAGBuild.cpp @@ -5485,48 +5485,6 @@ void SelectionDAGLowering::visitInlineAsm(CallSite CS) { DAG.setRoot(Chain); } - -void SelectionDAGLowering::visitMalloc(MallocInst &I) { - SDValue Src = getValue(I.getOperand(0)); - - // Scale up by the type size in the original i32 type width. Various - // mid-level optimizers may make assumptions about demanded bits etc from the - // i32-ness of the optimizer: we do not want to promote to i64 and then - // multiply on 64-bit targets. - // FIXME: Malloc inst should go away: PR715. - uint64_t ElementSize = TD->getTypeAllocSize(I.getType()->getElementType()); - if (ElementSize != 1) { - // Src is always 32-bits, make sure the constant fits. - assert(Src.getValueType() == MVT::i32); - ElementSize = (uint32_t)ElementSize; - Src = DAG.getNode(ISD::MUL, getCurDebugLoc(), Src.getValueType(), - Src, DAG.getConstant(ElementSize, Src.getValueType())); - } - - EVT IntPtr = TLI.getPointerTy(); - - Src = DAG.getZExtOrTrunc(Src, getCurDebugLoc(), IntPtr); - - TargetLowering::ArgListTy Args; - TargetLowering::ArgListEntry Entry; - Entry.Node = Src; - Entry.Ty = TLI.getTargetData()->getIntPtrType(*DAG.getContext()); - Args.push_back(Entry); - - bool isTailCall = PerformTailCallOpt && - isInTailCallPosition(&I, Attribute::None, TLI); - std::pair<SDValue,SDValue> Result = - TLI.LowerCallTo(getRoot(), I.getType(), false, false, false, false, - 0, CallingConv::C, isTailCall, - /*isReturnValueUsed=*/true, - DAG.getExternalSymbol("malloc", IntPtr), - Args, DAG, getCurDebugLoc()); - if (Result.first.getNode()) - setValue(&I, Result.first); // Pointers always fit in registers - if (Result.second.getNode()) - DAG.setRoot(Result.second); -} - void SelectionDAGLowering::visitFree(FreeInst &I) { TargetLowering::ArgListTy Args; TargetLowering::ArgListEntry Entry; diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGBuild.h b/lib/CodeGen/SelectionDAG/SelectionDAGBuild.h index 06acc8a..722b1d8 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGBuild.h +++ b/lib/CodeGen/SelectionDAG/SelectionDAGBuild.h @@ -60,7 +60,6 @@ class MachineFunction; class MachineInstr; class MachineModuleInfo; class MachineRegisterInfo; -class MallocInst; class PHINode; class PtrToIntInst; class ReturnInst; @@ -529,7 +528,6 @@ private: void visitGetElementPtr(User &I); void visitSelect(User &I); - void visitMalloc(MallocInst &I); void visitFree(FreeInst &I); void visitAlloca(AllocaInst &I); void visitLoad(LoadInst &I); diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp index ae98da5..72e7f58 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp @@ -226,7 +226,7 @@ static void EmitLiveInCopy(MachineBasicBlock *MBB, assert(Emitted && "Unable to issue a live-in copy instruction!\n"); (void) Emitted; -CopyRegMap.insert(std::make_pair(prior(Pos), VirtReg)); + CopyRegMap.insert(std::make_pair(prior(Pos), VirtReg)); if (Coalesced) { if (&*InsertPos == UseMI) ++InsertPos; MBB->erase(UseMI); diff --git a/lib/CodeGen/StackProtector.cpp b/lib/CodeGen/StackProtector.cpp index 350bc6e..0204969 100644 --- a/lib/CodeGen/StackProtector.cpp +++ b/lib/CodeGen/StackProtector.cpp @@ -111,11 +111,16 @@ bool StackProtector::RequiresStackProtector() const { // protectors. return true; - if (const ArrayType *AT = dyn_cast<ArrayType>(AI->getAllocatedType())) + if (const ArrayType *AT = dyn_cast<ArrayType>(AI->getAllocatedType())) { + // We apparently only care about character arrays. + if (AT->getElementType() != Type::getInt8Ty(AT->getContext())) + continue; + // If an array has more than SSPBufferSize bytes of allocated space, // then we emit stack protectors. if (SSPBufferSize <= TD->getTypeAllocSize(AT)) return true; + } } } diff --git a/lib/CodeGen/VirtRegMap.cpp b/lib/CodeGen/VirtRegMap.cpp index c78f35b..cac098b 100644 --- a/lib/CodeGen/VirtRegMap.cpp +++ b/lib/CodeGen/VirtRegMap.cpp @@ -118,7 +118,7 @@ int VirtRegMap::assignVirt2StackSlot(unsigned virtReg) { "attempt to assign stack slot to already spilled register"); const TargetRegisterClass* RC = MF->getRegInfo().getRegClass(virtReg); int SS = MF->getFrameInfo()->CreateStackObject(RC->getSize(), - RC->getAlignment()); + RC->getAlignment(), /*isSS*/true); if (LowSpillSlot == NO_STACK_SLOT) LowSpillSlot = SS; if (HighSpillSlot == NO_STACK_SLOT || SS > HighSpillSlot) @@ -162,7 +162,7 @@ int VirtRegMap::getEmergencySpillSlot(const TargetRegisterClass *RC) { if (I != EmergencySpillSlots.end()) return I->second; int SS = MF->getFrameInfo()->CreateStackObject(RC->getSize(), - RC->getAlignment()); + RC->getAlignment(), /*isSS*/true); if (LowSpillSlot == NO_STACK_SLOT) LowSpillSlot = SS; if (HighSpillSlot == NO_STACK_SLOT || SS > HighSpillSlot) diff --git a/lib/CompilerDriver/Main.cpp b/lib/CompilerDriver/Main.cpp index 3e1fc9f..c581809 100644 --- a/lib/CompilerDriver/Main.cpp +++ b/lib/CompilerDriver/Main.cpp @@ -95,8 +95,7 @@ int Main(int argc, char** argv) { (argc, argv, "LLVM Compiler Driver (Work In Progress)", true); PluginLoader Plugins; - Plugins.PopulateLanguageMap(langMap); - Plugins.PopulateCompilationGraph(graph); + Plugins.RunInitialization(langMap, graph); if (CheckGraph) { int ret = graph.Check(); diff --git a/lib/CompilerDriver/Plugin.cpp b/lib/CompilerDriver/Plugin.cpp index 7310d12..0fdfef4 100644 --- a/lib/CompilerDriver/Plugin.cpp +++ b/lib/CompilerDriver/Plugin.cpp @@ -62,18 +62,17 @@ namespace llvmc { pluginListInitialized = false; } - void PluginLoader::PopulateLanguageMap(LanguageMap& langMap) { + void PluginLoader::RunInitialization(LanguageMap& langMap, + CompilationGraph& graph) const + { llvm::sys::SmartScopedLock<true> Lock(*PluginMutex); for (PluginList::iterator B = Plugins.begin(), E = Plugins.end(); - B != E; ++B) - (*B)->PopulateLanguageMap(langMap); - } - - void PluginLoader::PopulateCompilationGraph(CompilationGraph& graph) { - llvm::sys::SmartScopedLock<true> Lock(*PluginMutex); - for (PluginList::iterator B = Plugins.begin(), E = Plugins.end(); - B != E; ++B) - (*B)->PopulateCompilationGraph(graph); + B != E; ++B) { + const BasePlugin* BP = *B; + BP->PreprocessOptions(); + BP->PopulateLanguageMap(langMap); + BP->PopulateCompilationGraph(graph); + } } } diff --git a/lib/ExecutionEngine/JIT/CMakeLists.txt b/lib/ExecutionEngine/JIT/CMakeLists.txt index 41b3b4e..42020d6 100644 --- a/lib/ExecutionEngine/JIT/CMakeLists.txt +++ b/lib/ExecutionEngine/JIT/CMakeLists.txt @@ -8,7 +8,6 @@ add_llvm_library(LLVMJIT JITDwarfEmitter.cpp JITEmitter.cpp JITMemoryManager.cpp - MacOSJITEventListener.cpp OProfileJITEventListener.cpp TargetSelect.cpp ) diff --git a/lib/ExecutionEngine/JIT/JITDebugRegisterer.cpp b/lib/ExecutionEngine/JIT/JITDebugRegisterer.cpp index fa64010..49faf64 100644 --- a/lib/ExecutionEngine/JIT/JITDebugRegisterer.cpp +++ b/lib/ExecutionEngine/JIT/JITDebugRegisterer.cpp @@ -22,6 +22,7 @@ #include "llvm/Target/TargetOptions.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/OwningPtr.h" +#include "llvm/Support/Compiler.h" #include "llvm/Support/MutexGuard.h" #include "llvm/Support/raw_ostream.h" #include "llvm/System/Mutex.h" diff --git a/lib/ExecutionEngine/JIT/JITEmitter.cpp b/lib/ExecutionEngine/JIT/JITEmitter.cpp index eacd9f9..073d6fb 100644 --- a/lib/ExecutionEngine/JIT/JITEmitter.cpp +++ b/lib/ExecutionEngine/JIT/JITEmitter.cpp @@ -42,6 +42,7 @@ #include "llvm/System/Disassembler.h" #include "llvm/System/Memory.h" #include "llvm/Target/TargetInstrInfo.h" +#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Statistic.h" @@ -63,17 +64,20 @@ static JIT *TheJIT = 0; namespace { class JITResolverState { public: - typedef std::map<AssertingVH<Function>, void*> FunctionToStubMapTy; - typedef std::map<void*, AssertingVH<Function> > StubToFunctionMapTy; + typedef DenseMap<AssertingVH<Function>, void*> FunctionToStubMapTy; + typedef std::map<void*, AssertingVH<Function> > CallSiteToFunctionMapTy; + typedef DenseMap<AssertingVH<Function>, SmallPtrSet<void*, 1> > + FunctionToCallSitesMapTy; typedef std::map<AssertingVH<GlobalValue>, void*> GlobalToIndirectSymMapTy; private: /// FunctionToStubMap - Keep track of the stub created for a particular /// function so that we can reuse them if necessary. FunctionToStubMapTy FunctionToStubMap; - /// StubToFunctionMap - Keep track of the function that each stub - /// corresponds to. - StubToFunctionMapTy StubToFunctionMap; + /// CallSiteToFunctionMap - Keep track of the function that each lazy call + /// site corresponds to, and vice versa. + CallSiteToFunctionMapTy CallSiteToFunctionMap; + FunctionToCallSitesMapTy FunctionToCallSitesMap; /// GlobalToIndirectSymMap - Keep track of the indirect symbol created for a /// particular GlobalVariable so that we can reuse them if necessary. @@ -85,14 +89,78 @@ namespace { return FunctionToStubMap; } - StubToFunctionMapTy& getStubToFunctionMap(const MutexGuard& locked) { + GlobalToIndirectSymMapTy& getGlobalToIndirectSymMap(const MutexGuard& locked) { assert(locked.holds(TheJIT->lock)); - return StubToFunctionMap; + return GlobalToIndirectSymMap; } - GlobalToIndirectSymMapTy& getGlobalToIndirectSymMap(const MutexGuard& locked) { + pair<void *, Function *> LookupFunctionFromCallSite( + const MutexGuard &locked, void *CallSite) const { assert(locked.holds(TheJIT->lock)); - return GlobalToIndirectSymMap; + + // The address given to us for the stub may not be exactly right, it might be + // a little bit after the stub. As such, use upper_bound to find it. + CallSiteToFunctionMapTy::const_iterator I = + CallSiteToFunctionMap.upper_bound(CallSite); + assert(I != CallSiteToFunctionMap.begin() && + "This is not a known call site!"); + --I; + return *I; + } + + void AddCallSite(const MutexGuard &locked, void *CallSite, Function *F) { + assert(locked.holds(TheJIT->lock)); + + assert(CallSiteToFunctionMap.insert(std::make_pair(CallSite, F)).second && + "Pair was already in CallSiteToFunctionMap"); + FunctionToCallSitesMap[F].insert(CallSite); + } + + // Returns the Function of the stub if a stub was erased, or NULL if there + // was no stub. This function uses the call-site->function map to find a + // relevant function, but asserts that only stubs and not other call sites + // will be passed in. + Function *EraseStub(const MutexGuard &locked, void *Stub) { + CallSiteToFunctionMapTy::iterator C2F_I = + CallSiteToFunctionMap.find(Stub); + if (C2F_I == CallSiteToFunctionMap.end()) { + // Not a stub. + return NULL; + } + + Function *const F = C2F_I->second; +#ifndef NDEBUG + void *RealStub = FunctionToStubMap.lookup(F); + assert(RealStub == Stub && + "Call-site that wasn't a stub pass in to EraseStub"); +#endif + FunctionToStubMap.erase(F); + CallSiteToFunctionMap.erase(C2F_I); + + // Remove the stub from the function->call-sites map, and remove the whole + // entry from the map if that was the last call site. + FunctionToCallSitesMapTy::iterator F2C_I = FunctionToCallSitesMap.find(F); + assert(F2C_I != FunctionToCallSitesMap.end() && + "FunctionToCallSitesMap broken"); + assert(F2C_I->second.erase(Stub) && + "FunctionToCallSitesMap broken"); + if (F2C_I->second.empty()) + FunctionToCallSitesMap.erase(F2C_I); + + return F; + } + + void EraseAllCallSites(const MutexGuard &locked, Function *F) { + assert(locked.holds(TheJIT->lock)); + FunctionToCallSitesMapTy::iterator F2C = FunctionToCallSitesMap.find(F); + if (F2C == FunctionToCallSitesMap.end()) + return; + for (SmallPtrSet<void*, 1>::const_iterator I = F2C->second.begin(), + E = F2C->second.end(); I != E; ++I) { + assert(CallSiteToFunctionMap.erase(*I) == 1 && + "Missing call site->function mapping"); + } + FunctionToCallSitesMap.erase(F2C); } }; @@ -100,7 +168,7 @@ namespace { /// have not yet been compiled. class JITResolver { typedef JITResolverState::FunctionToStubMapTy FunctionToStubMapTy; - typedef JITResolverState::StubToFunctionMapTy StubToFunctionMapTy; + typedef JITResolverState::CallSiteToFunctionMapTy CallSiteToFunctionMapTy; typedef JITResolverState::GlobalToIndirectSymMapTy GlobalToIndirectSymMapTy; /// LazyResolverFn - The target lazy resolver function that we actually @@ -154,7 +222,7 @@ namespace { void *AddCallbackAtLocation(Function *F, void *Location) { MutexGuard locked(TheJIT->lock); /// Get the target-specific JIT resolver function. - state.getStubToFunctionMap(locked)[Location] = F; + state.AddCallSite(locked, Location, F); return (void*)(intptr_t)LazyResolverFn; } @@ -183,8 +251,7 @@ void *JITResolver::getFunctionStubIfAvailable(Function *F) { MutexGuard locked(TheJIT->lock); // If we already have a stub for this function, recycle it. - void *&Stub = state.getFunctionToStubMap(locked)[F]; - return Stub; + return state.getFunctionToStubMap(locked).lookup(F); } /// getFunctionStub - This returns a pointer to a function stub, creating @@ -230,7 +297,7 @@ void *JITResolver::getFunctionStub(Function *F) { // Finally, keep track of the stub-to-Function mapping so that the // JITCompilerFn knows which function to compile! - state.getStubToFunctionMap(locked)[Stub] = F; + state.AddCallSite(locked, Stub, F); // If we are JIT'ing non-lazily but need to call a function that does not // exist yet, add it to the JIT's work list so that we can fill in the stub @@ -291,10 +358,11 @@ void JITResolver::getRelocatableGVs(SmallVectorImpl<GlobalValue*> &GVs, SmallVectorImpl<void*> &Ptrs) { MutexGuard locked(TheJIT->lock); - FunctionToStubMapTy &FM = state.getFunctionToStubMap(locked); + const FunctionToStubMapTy &FM = state.getFunctionToStubMap(locked); GlobalToIndirectSymMapTy &GM = state.getGlobalToIndirectSymMap(locked); - for (FunctionToStubMapTy::iterator i = FM.begin(), e = FM.end(); i != e; ++i){ + for (FunctionToStubMapTy::const_iterator i = FM.begin(), e = FM.end(); + i != e; ++i){ Function *F = i->first; if (F->isDeclaration() && F->hasExternalLinkage()) { GVs.push_back(i->first); @@ -310,20 +378,15 @@ void JITResolver::getRelocatableGVs(SmallVectorImpl<GlobalValue*> &GVs, GlobalValue *JITResolver::invalidateStub(void *Stub) { MutexGuard locked(TheJIT->lock); - - FunctionToStubMapTy &FM = state.getFunctionToStubMap(locked); - StubToFunctionMapTy &SM = state.getStubToFunctionMap(locked); + GlobalToIndirectSymMapTy &GM = state.getGlobalToIndirectSymMap(locked); - + // Look up the cheap way first, to see if it's a function stub we are // invalidating. If so, remove it from both the forward and reverse maps. - if (SM.find(Stub) != SM.end()) { - Function *F = SM[Stub]; - SM.erase(Stub); - FM.erase(F); + if (Function *F = state.EraseStub(locked, Stub)) { return F; } - + // Otherwise, it might be an indirect symbol stub. Find it and remove it. for (GlobalToIndirectSymMapTy::iterator i = GM.begin(), e = GM.end(); i != e; ++i) { @@ -361,14 +424,12 @@ void *JITResolver::JITCompilerFn(void *Stub) { // JIT lock to be unlocked. MutexGuard locked(TheJIT->lock); - // The address given to us for the stub may not be exactly right, it might be - // a little bit after the stub. As such, use upper_bound to find it. - StubToFunctionMapTy::iterator I = - JR.state.getStubToFunctionMap(locked).upper_bound(Stub); - assert(I != JR.state.getStubToFunctionMap(locked).begin() && - "This is not a known stub!"); - F = (--I)->second; - ActualPtr = I->first; + // The address given to us for the stub may not be exactly right, it might + // be a little bit after the stub. As such, use upper_bound to find it. + pair<void*, Function*> I = + JR.state.LookupFunctionFromCallSite(locked, Stub); + F = I.second; + ActualPtr = I.first; } // If we have already code generated the function, just return the address. @@ -383,25 +444,21 @@ void *JITResolver::JITCompilerFn(void *Stub) { + F->getName() + "' when lazy compiles are disabled!"); } - // We might like to remove the stub from the StubToFunction map. - // We can't do that! Multiple threads could be stuck, waiting to acquire the - // lock above. As soon as the 1st function finishes compiling the function, - // the next one will be released, and needs to be able to find the function - // it needs to call. - //JR.state.getStubToFunctionMap(locked).erase(I); - DEBUG(errs() << "JIT: Lazily resolving function '" << F->getName() << "' In stub ptr = " << Stub << " actual ptr = " << ActualPtr << "\n"); Result = TheJIT->getPointerToFunction(F); } - - // Reacquire the lock to erase the stub in the map. + + // Reacquire the lock to update the GOT map. MutexGuard locked(TheJIT->lock); - // We don't need to reuse this stub in the future, as F is now compiled. - JR.state.getFunctionToStubMap(locked).erase(F); + // We might like to remove the call site from the CallSiteToFunction map, but + // we can't do that! Multiple threads could be stuck, waiting to acquire the + // lock above. As soon as the 1st function finishes compiling the function, + // the next one will be released, and needs to be able to find the function it + // needs to call. // FIXME: We could rewrite all references to this stub if we knew them. @@ -492,6 +549,13 @@ namespace { /// finishFunction. JITEvent_EmittedFunctionDetails EmissionDetails; + struct EmittedCode { + void *FunctionBody; + void *ExceptionTable; + EmittedCode() : FunctionBody(0), ExceptionTable(0) {} + }; + DenseMap<const Function *, EmittedCode> EmittedFunctions; + // CurFnStubUses - For a given Function, a vector of stubs that it // references. This facilitates the JIT detecting that a stub is no // longer used, so that it may be deallocated. @@ -955,7 +1019,8 @@ void JITEmitter::startFunction(MachineFunction &F) { BufferBegin = CurBufferPtr = MemMgr->startFunctionBody(F.getFunction(), ActualSize); BufferEnd = BufferBegin+ActualSize; - + EmittedFunctions[F.getFunction()].FunctionBody = BufferBegin; + // Ensure the constant pool/jump table info is at least 4-byte aligned. emitAlignment(16); @@ -1145,6 +1210,7 @@ bool JITEmitter::finishFunction(MachineFunction &F) { BufferBegin = CurBufferPtr = MemMgr->startExceptionTable(F.getFunction(), ActualSize); BufferEnd = BufferBegin+ActualSize; + EmittedFunctions[F.getFunction()].ExceptionTable = BufferBegin; uint8_t *EhStart; uint8_t *FrameRegister = DE->EmitDwarfTable(F, *this, FnStart, FnEnd, EhStart); @@ -1188,7 +1254,13 @@ void JITEmitter::retryWithMoreMemory(MachineFunction &F) { /// deallocateMemForFunction - Deallocate all memory for the specified /// function body. Also drop any references the function has to stubs. void JITEmitter::deallocateMemForFunction(const Function *F) { - MemMgr->deallocateMemForFunction(F); + DenseMap<const Function *, EmittedCode>::iterator Emitted = + EmittedFunctions.find(F); + if (Emitted != EmittedFunctions.end()) { + MemMgr->deallocateFunctionBody(Emitted->second.FunctionBody); + MemMgr->deallocateExceptionTable(Emitted->second.ExceptionTable); + EmittedFunctions.erase(Emitted); + } // TODO: Do we need to unregister exception handling information from libgcc // here? diff --git a/lib/ExecutionEngine/JIT/JITMemoryManager.cpp b/lib/ExecutionEngine/JIT/JITMemoryManager.cpp index 474843f..3796624 100644 --- a/lib/ExecutionEngine/JIT/JITMemoryManager.cpp +++ b/lib/ExecutionEngine/JIT/JITMemoryManager.cpp @@ -297,9 +297,6 @@ namespace { uint8_t *GOTBase; // Target Specific reserved memory void *DlsymTable; // Stub external symbol information - - std::map<const Function*, MemoryRangeHeader*> FunctionBlocks; - std::map<const Function*, MemoryRangeHeader*> TableBlocks; public: DefaultJITMemoryManager(); ~DefaultJITMemoryManager(); @@ -414,7 +411,6 @@ namespace { "Mismatched function start/end!"); uintptr_t BlockSize = FunctionEnd - (uint8_t *)CurBlock; - FunctionBlocks[F] = CurBlock; // Release the memory at the end of this block that isn't needed. FreeMemoryList =CurBlock->TrimAllocationToSize(FreeMemoryList, BlockSize); @@ -464,7 +460,6 @@ namespace { "Mismatched table start/end!"); uintptr_t BlockSize = TableEnd - (uint8_t *)CurBlock; - TableBlocks[F] = CurBlock; // Release the memory at the end of this block that isn't needed. FreeMemoryList =CurBlock->TrimAllocationToSize(FreeMemoryList, BlockSize); @@ -478,15 +473,9 @@ namespace { return DlsymTable; } - /// deallocateMemForFunction - Deallocate all memory for the specified - /// function body. - void deallocateMemForFunction(const Function *F) { - std::map<const Function*, MemoryRangeHeader*>::iterator - I = FunctionBlocks.find(F); - if (I == FunctionBlocks.end()) return; - + void deallocateBlock(void *Block) { // Find the block that is allocated for this function. - MemoryRangeHeader *MemRange = I->second; + MemoryRangeHeader *MemRange = static_cast<MemoryRangeHeader*>(Block) - 1; assert(MemRange->ThisAllocated && "Block isn't allocated!"); // Fill the buffer with garbage! @@ -496,27 +485,18 @@ namespace { // Free the memory. FreeMemoryList = MemRange->FreeBlock(FreeMemoryList); - - // Finally, remove this entry from FunctionBlocks. - FunctionBlocks.erase(I); - - I = TableBlocks.find(F); - if (I == TableBlocks.end()) return; - - // Find the block that is allocated for this function. - MemRange = I->second; - assert(MemRange->ThisAllocated && "Block isn't allocated!"); + } - // Fill the buffer with garbage! - if (PoisonMemory) { - memset(MemRange+1, 0xCD, MemRange->BlockSize-sizeof(*MemRange)); - } + /// deallocateFunctionBody - Deallocate all memory for the specified + /// function body. + void deallocateFunctionBody(void *Body) { + if (Body) deallocateBlock(Body); + } - // Free the memory. - FreeMemoryList = MemRange->FreeBlock(FreeMemoryList); - - // Finally, remove this entry from TableBlocks. - TableBlocks.erase(I); + /// deallocateExceptionTable - Deallocate memory for the specified + /// exception table. + void deallocateExceptionTable(void *ET) { + if (ET) deallocateBlock(ET); } /// setMemoryWritable - When code generation is in progress, diff --git a/lib/ExecutionEngine/JIT/OProfileJITEventListener.cpp b/lib/ExecutionEngine/JIT/OProfileJITEventListener.cpp index 69398be..00c4af7 100644 --- a/lib/ExecutionEngine/JIT/OProfileJITEventListener.cpp +++ b/lib/ExecutionEngine/JIT/OProfileJITEventListener.cpp @@ -69,16 +69,16 @@ OProfileJITEventListener::~OProfileJITEventListener() { } class FilenameCache { - // Holds the filename of each CompileUnit, so that we can pass the + // Holds the filename of each Scope, so that we can pass the // pointer into oprofile. These char*s are freed in the destructor. DenseMap<MDNode*, char*> Filenames; public: - const char *getFilename(MDNode *CompileUnit) { - char *&Filename = Filenames[CompileUnit]; + const char *getFilename(MDNode *Scope) { + char *&Filename = Filenames[Scope]; if (Filename == NULL) { - DICompileUnit CU(CompileUnit); - Filename = strdup(CU.getFilename()); + DIScope S(Scope); + Filename = strdup(S.getFilename()); } return Filename; } @@ -97,7 +97,7 @@ static debug_line_info LineStartToOProfileFormat( Result.vma = Address; const DebugLocTuple &tuple = MF.getDebugLocTuple(Loc); Result.lineno = tuple.Line; - Result.filename = Filenames.getFilename(tuple.CompileUnit); + Result.filename = Filenames.getFilename(tuple.Scope); DEBUG(errs() << "Mapping " << reinterpret_cast<void*>(Result.vma) << " to " << Result.filename << ":" << Result.lineno << "\n"); return Result; diff --git a/lib/MC/MCAsmStreamer.cpp b/lib/MC/MCAsmStreamer.cpp index e56e968..e939f37 100644 --- a/lib/MC/MCAsmStreamer.cpp +++ b/lib/MC/MCAsmStreamer.cpp @@ -123,23 +123,27 @@ void MCAsmStreamer::EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) { OS << " = "; Value->print(OS, &MAI); OS << '\n'; + + // FIXME: Lift context changes into super class. + // FIXME: Set associated section. + Symbol->setValue(Value); } -void MCAsmStreamer::EmitSymbolAttribute(MCSymbol *Symbol, +void MCAsmStreamer::EmitSymbolAttribute(MCSymbol *Symbol, SymbolAttr Attribute) { switch (Attribute) { - case Global: OS << ".globl"; break; - case Hidden: OS << ".hidden"; break; + case Global: OS << ".globl"; break; + case Hidden: OS << ".hidden"; break; case IndirectSymbol: OS << ".indirect_symbol"; break; - case Internal: OS << ".internal"; break; - case LazyReference: OS << ".lazy_reference"; break; - case NoDeadStrip: OS << ".no_dead_strip"; break; - case PrivateExtern: OS << ".private_extern"; break; - case Protected: OS << ".protected"; break; - case Reference: OS << ".reference"; break; - case Weak: OS << ".weak"; break; + case Internal: OS << ".internal"; break; + case LazyReference: OS << ".lazy_reference"; break; + case NoDeadStrip: OS << ".no_dead_strip"; break; + case PrivateExtern: OS << ".private_extern"; break; + case Protected: OS << ".protected"; break; + case Reference: OS << ".reference"; break; + case Weak: OS << ".weak"; break; case WeakDefinition: OS << ".weak_definition"; break; - case WeakReference: OS << ".weak_reference"; break; + case WeakReference: OS << ".weak_reference"; break; } OS << ' '; diff --git a/lib/MC/MCAssembler.cpp b/lib/MC/MCAssembler.cpp index 0afdf98..4f39f1e 100644 --- a/lib/MC/MCAssembler.cpp +++ b/lib/MC/MCAssembler.cpp @@ -9,7 +9,10 @@ #define DEBUG_TYPE "assembler" #include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCExpr.h" #include "llvm/MC/MCSectionMachO.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/MC/MCValue.h" #include "llvm/Target/TargetMachOWriterInfo.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallString.h" @@ -48,7 +51,7 @@ class MachObjectWriter { Header_Magic32 = 0xFEEDFACE, Header_Magic64 = 0xFEEDFACF }; - + static const unsigned Header32Size = 28; static const unsigned Header64Size = 32; static const unsigned SegmentLoadCommand32Size = 56; @@ -127,7 +130,7 @@ class MachObjectWriter { bool IsLSB; public: - MachObjectWriter(raw_ostream &_OS, bool _IsLSB = true) + MachObjectWriter(raw_ostream &_OS, bool _IsLSB = true) : OS(_OS), IsLSB(_IsLSB) { } @@ -170,10 +173,10 @@ public: void WriteZeros(unsigned N) { const char Zeros[16] = { 0 }; - + for (unsigned i = 0, e = N / 16; i != e; ++i) OS << StringRef(Zeros, 16); - + OS << StringRef(Zeros, N % 16); } @@ -184,7 +187,7 @@ public: } /// @} - + void WriteHeader32(unsigned NumLoadCommands, unsigned LoadCommandsSize, bool SubsectionsViaSymbols) { uint32_t Flags = 0; @@ -384,7 +387,7 @@ public: Write32(MSD.StringIndex); Write8(Type); Write8(MSD.SectionIndex); - + // The Mach-O streamer uses the lowest 16-bits of the flags for the 'desc' // value. Write16(Flags); @@ -397,6 +400,7 @@ public: }; void ComputeScatteredRelocationInfo(MCAssembler &Asm, MCSectionData::Fixup &Fixup, + const MCValue &Target, DenseMap<const MCSymbol*,MCSymbolData*> &SymbolMap, std::vector<MachRelocationEntry> &Relocs) { uint32_t Address = Fixup.Fragment->getOffset() + Fixup.Offset; @@ -404,13 +408,12 @@ public: unsigned Type = RIT_Vanilla; // See <reloc.h>. - - const MCSymbol *A = Fixup.Value.getSymA(); + const MCSymbol *A = Target.getSymA(); MCSymbolData *SD = SymbolMap.lookup(A); uint32_t Value = SD->getFragment()->getAddress() + SD->getOffset(); uint32_t Value2 = 0; - if (const MCSymbol *B = Fixup.Value.getSymB()) { + if (const MCSymbol *B = Target.getSymB()) { Type = RIT_LocalDifference; MCSymbolData *SD = SymbolMap.lookup(B); @@ -421,7 +424,7 @@ public: assert((1U << Log2Size) == Fixup.Size && "Invalid fixup size!"); // The value which goes in the fixup is current value of the expression. - Fixup.FixedValue = Value - Value2 + Fixup.Value.getConstant(); + Fixup.FixedValue = Value - Value2 + Target.getConstant(); MachRelocationEntry MRE; MRE.Word0 = ((Address << 0) | @@ -450,14 +453,18 @@ public: MCSectionData::Fixup &Fixup, DenseMap<const MCSymbol*,MCSymbolData*> &SymbolMap, std::vector<MachRelocationEntry> &Relocs) { - // If this is a local symbol plus an offset or a difference, then we need a + MCValue Target; + if (!Fixup.Value->EvaluateAsRelocatable(Target)) + llvm_report_error("expected relocatable expression"); + + // If this is a difference or a local symbol plus an offset, then we need a // scattered relocation entry. - if (Fixup.Value.getSymB()) // a - b - return ComputeScatteredRelocationInfo(Asm, Fixup, SymbolMap, Relocs); - if (Fixup.Value.getSymA() && Fixup.Value.getConstant()) - if (!Fixup.Value.getSymA()->isUndefined()) - return ComputeScatteredRelocationInfo(Asm, Fixup, SymbolMap, Relocs); - + if (Target.getSymB() || + (Target.getSymA() && !Target.getSymA()->isUndefined() && + Target.getConstant())) + return ComputeScatteredRelocationInfo(Asm, Fixup, Target, + SymbolMap, Relocs); + // See <reloc.h>. uint32_t Address = Fixup.Fragment->getOffset() + Fixup.Offset; uint32_t Value = 0; @@ -466,15 +473,15 @@ public: unsigned IsExtern = 0; unsigned Type = 0; - if (Fixup.Value.isAbsolute()) { // constant + if (Target.isAbsolute()) { // constant // SymbolNum of 0 indicates the absolute section. Type = RIT_Vanilla; Value = 0; llvm_unreachable("FIXME: Not yet implemented!"); } else { - const MCSymbol *Symbol = Fixup.Value.getSymA(); + const MCSymbol *Symbol = Target.getSymA(); MCSymbolData *SD = SymbolMap.lookup(Symbol); - + if (Symbol->isUndefined()) { IsExtern = 1; Index = SD->getIndex(); @@ -495,7 +502,7 @@ public: } // The value which goes in the fixup is current value of the expression. - Fixup.FixedValue = Value + Fixup.Value.getConstant(); + Fixup.FixedValue = Value + Target.getConstant(); unsigned Log2Size = Log2_32(Fixup.Size); assert((1U << Log2Size) == Fixup.Size && "Invalid fixup size!"); @@ -510,7 +517,7 @@ public: (Type << 28)); Relocs.push_back(MRE); } - + void BindIndirectSymbols(MCAssembler &Asm, DenseMap<const MCSymbol*,MCSymbolData*> &SymbolMap) { // This is the point where 'as' creates actual symbols for indirect symbols @@ -703,7 +710,7 @@ public: if (NumSymbols) ComputeSymbolTable(Asm, StringTable, LocalSymbolData, ExternalSymbolData, UndefinedSymbolData); - + // The section data starts after the header, the segment load command (and // section headers) and the symbol table. unsigned NumLoadCommands = 1; @@ -733,7 +740,7 @@ public: SectionDataSize = std::max(SectionDataSize, SD.getAddress() + SD.getSize()); - SectionDataFileSize = std::max(SectionDataFileSize, + SectionDataFileSize = std::max(SectionDataFileSize, SD.getAddress() + SD.getFileSize()); } @@ -748,9 +755,9 @@ public: Asm.getSubsectionsViaSymbols()); WriteSegmentLoadCommand32(NumSections, VMSize, SectionDataStart, SectionDataSize); - + // ... and then the section headers. - // + // // We also compute the section relocations while we do this. Note that // compute relocation info will also update the fixup to have the correct // value; this will be overwrite the appropriate data in the fragment when @@ -774,7 +781,7 @@ public: WriteSection32(SD, SectionStart, RelocTableEnd, NumRelocs); RelocTableEnd += NumRelocs * RelocationInfoSize; } - + // Write the symbol table load command, if used. if (NumSymbols) { unsigned FirstLocalSymbol = 0; @@ -923,7 +930,7 @@ MCSectionData::LookupFixup(const MCFragment *Fragment, uint64_t Offset) const { return 0; } - + /* *** */ MCSymbolData::MCSymbolData() : Symbol(0) {} @@ -960,7 +967,7 @@ void MCAssembler::LayoutSection(MCSectionData &SD) { switch (F.getKind()) { case MCFragment::FT_Align: { MCAlignFragment &AF = cast<MCAlignFragment>(F); - + uint64_t Size = OffsetToAlignment(Address, AF.getAlignment()); if (Size > AF.getMaxBytesToEmit()) AF.setFileSize(0); @@ -978,8 +985,12 @@ void MCAssembler::LayoutSection(MCSectionData &SD) { F.setFileSize(F.getMaxFileSize()); + MCValue Target; + if (!FF.getValue().EvaluateAsRelocatable(Target)) + llvm_report_error("expected relocatable expression"); + // If the fill value is constant, thats it. - if (FF.getValue().isAbsolute()) + if (Target.isAbsolute()) break; // Otherwise, add fixups for the values. @@ -994,19 +1005,23 @@ void MCAssembler::LayoutSection(MCSectionData &SD) { case MCFragment::FT_Org: { MCOrgFragment &OF = cast<MCOrgFragment>(F); - if (!OF.getOffset().isAbsolute()) + MCValue Target; + if (!OF.getOffset().EvaluateAsRelocatable(Target)) + llvm_report_error("expected relocatable expression"); + + if (!Target.isAbsolute()) llvm_unreachable("FIXME: Not yet implemented!"); - uint64_t OrgOffset = OF.getOffset().getConstant(); + uint64_t OrgOffset = Target.getConstant(); uint64_t Offset = Address - SD.getAddress(); // FIXME: We need a way to communicate this error. if (OrgOffset < Offset) - llvm_report_error("invalid .org offset '" + Twine(OrgOffset) + + llvm_report_error("invalid .org offset '" + Twine(OrgOffset) + "' (at offset '" + Twine(Offset) + "'"); - + F.setFileSize(OrgOffset - Offset); break; - } + } case MCFragment::FT_ZeroFill: { MCZeroFillFragment &ZFF = cast<MCZeroFillFragment>(F); @@ -1038,7 +1053,7 @@ static void WriteFileData(raw_ostream &OS, const MCFragment &F, MachObjectWriter &MOW) { uint64_t Start = OS.tell(); (void) Start; - + ++EmittedFragments; // FIXME: Embed in fragments instead? @@ -1051,8 +1066,8 @@ static void WriteFileData(raw_ostream &OS, const MCFragment &F, // multiple .align directives to enforce the semantics it wants), but is // severe enough that we want to report it. How to handle this? if (Count * AF.getValueSize() != AF.getFileSize()) - llvm_report_error("undefined .align directive, value size '" + - Twine(AF.getValueSize()) + + llvm_report_error("undefined .align directive, value size '" + + Twine(AF.getValueSize()) + "' is not a divisor of padding size '" + Twine(AF.getFileSize()) + "'"); @@ -1077,10 +1092,15 @@ static void WriteFileData(raw_ostream &OS, const MCFragment &F, MCFillFragment &FF = cast<MCFillFragment>(F); int64_t Value = 0; - if (FF.getValue().isAbsolute()) - Value = FF.getValue().getConstant(); + + MCValue Target; + if (!FF.getValue().EvaluateAsRelocatable(Target)) + llvm_report_error("expected relocatable expression"); + + if (Target.isAbsolute()) + Value = Target.getConstant(); for (uint64_t i = 0, e = FF.getCount(); i != e; ++i) { - if (!FF.getValue().isAbsolute()) { + if (!Target.isAbsolute()) { // Find the fixup. // // FIXME: Find a better way to write in the fixes. @@ -1101,7 +1121,7 @@ static void WriteFileData(raw_ostream &OS, const MCFragment &F, } break; } - + case MCFragment::FT_Org: { MCOrgFragment &OF = cast<MCOrgFragment>(F); @@ -1131,7 +1151,7 @@ static void WriteFileData(raw_ostream &OS, const MCSectionData &SD, uint64_t Start = OS.tell(); (void) Start; - + for (MCSectionData::const_iterator it = SD.begin(), ie = SD.end(); it != ie; ++it) WriteFileData(OS, *it, MOW); diff --git a/lib/MC/MCContext.cpp b/lib/MC/MCContext.cpp index f36564a..09479c5 100644 --- a/lib/MC/MCContext.cpp +++ b/lib/MC/MCContext.cpp @@ -8,10 +8,11 @@ //===----------------------------------------------------------------------===// #include "llvm/MC/MCContext.h" - #include "llvm/MC/MCSection.h" #include "llvm/MC/MCSymbol.h" #include "llvm/MC/MCValue.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/Twine.h" using namespace llvm; MCContext::MCContext() { @@ -38,6 +39,13 @@ MCSymbol *MCContext::GetOrCreateSymbol(const StringRef &Name) { return Entry = new (*this) MCSymbol(Name, false); } +MCSymbol *MCContext::GetOrCreateSymbol(const Twine &Name) { + SmallString<128> NameSV; + Name.toVector(NameSV); + return GetOrCreateSymbol(NameSV.str()); +} + + MCSymbol *MCContext::CreateTemporarySymbol(const StringRef &Name) { // If unnamed, just create a symbol. if (Name.empty()) @@ -52,20 +60,3 @@ MCSymbol *MCContext::CreateTemporarySymbol(const StringRef &Name) { MCSymbol *MCContext::LookupSymbol(const StringRef &Name) const { return Symbols.lookup(Name); } - -void MCContext::ClearSymbolValue(const MCSymbol *Sym) { - SymbolValues.erase(Sym); -} - -void MCContext::SetSymbolValue(const MCSymbol *Sym, const MCValue &Value) { - SymbolValues[Sym] = Value; -} - -const MCValue *MCContext::GetSymbolValue(const MCSymbol *Sym) const { - DenseMap<const MCSymbol*, MCValue>::iterator it = SymbolValues.find(Sym); - - if (it == SymbolValues.end()) - return 0; - - return &it->second; -} diff --git a/lib/MC/MCExpr.cpp b/lib/MC/MCExpr.cpp index 0f3e053..c950ff2 100644 --- a/lib/MC/MCExpr.cpp +++ b/lib/MC/MCExpr.cpp @@ -141,10 +141,10 @@ const MCSymbolRefExpr *MCSymbolRefExpr::Create(const StringRef &Name, /* *** */ -bool MCExpr::EvaluateAsAbsolute(MCContext &Ctx, int64_t &Res) const { +bool MCExpr::EvaluateAsAbsolute(int64_t &Res) const { MCValue Value; - if (!EvaluateAsRelocatable(Ctx, Value) || !Value.isAbsolute()) + if (!EvaluateAsRelocatable(Value) || !Value.isAbsolute()) return false; Res = Value.getConstant(); @@ -173,7 +173,7 @@ static bool EvaluateSymbolicAdd(const MCValue &LHS, const MCSymbol *RHS_A, return true; } -bool MCExpr::EvaluateAsRelocatable(MCContext &Ctx, MCValue &Res) const { +bool MCExpr::EvaluateAsRelocatable(MCValue &Res) const { switch (getKind()) { case Constant: Res = MCValue::get(cast<MCConstantExpr>(this)->getValue()); @@ -181,10 +181,12 @@ bool MCExpr::EvaluateAsRelocatable(MCContext &Ctx, MCValue &Res) const { case SymbolRef: { const MCSymbol &Sym = cast<MCSymbolRefExpr>(this)->getSymbol(); - if (const MCValue *Value = Ctx.GetSymbolValue(&Sym)) - Res = *Value; - else - Res = MCValue::get(&Sym, 0, 0); + + // Evaluate recursively if this is a variable. + if (Sym.isVariable()) + return Sym.getValue()->EvaluateAsRelocatable(Res); + + Res = MCValue::get(&Sym, 0, 0); return true; } @@ -192,7 +194,7 @@ bool MCExpr::EvaluateAsRelocatable(MCContext &Ctx, MCValue &Res) const { const MCUnaryExpr *AUE = cast<MCUnaryExpr>(this); MCValue Value; - if (!AUE->getSubExpr()->EvaluateAsRelocatable(Ctx, Value)) + if (!AUE->getSubExpr()->EvaluateAsRelocatable(Value)) return false; switch (AUE->getOpcode()) { @@ -225,8 +227,8 @@ bool MCExpr::EvaluateAsRelocatable(MCContext &Ctx, MCValue &Res) const { const MCBinaryExpr *ABE = cast<MCBinaryExpr>(this); MCValue LHSValue, RHSValue; - if (!ABE->getLHS()->EvaluateAsRelocatable(Ctx, LHSValue) || - !ABE->getRHS()->EvaluateAsRelocatable(Ctx, RHSValue)) + if (!ABE->getLHS()->EvaluateAsRelocatable(LHSValue) || + !ABE->getRHS()->EvaluateAsRelocatable(RHSValue)) return false; // We only support a few operations on non-constant expressions, handle diff --git a/lib/MC/MCMachOStreamer.cpp b/lib/MC/MCMachOStreamer.cpp index e04bd1f..189f072 100644 --- a/lib/MC/MCMachOStreamer.cpp +++ b/lib/MC/MCMachOStreamer.cpp @@ -198,7 +198,9 @@ void MCMachOStreamer::EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) { assert((Symbol->isUndefined() || Symbol->isAbsolute()) && "Cannot define a symbol twice!"); - llvm_unreachable("FIXME: Not yet implemented!"); + // FIXME: Lift context changes into super class. + // FIXME: Set associated section. + Symbol->setValue(Value); } void MCMachOStreamer::EmitSymbolAttribute(MCSymbol *Symbol, @@ -321,12 +323,7 @@ void MCMachOStreamer::EmitBytes(const StringRef &Data) { } void MCMachOStreamer::EmitValue(const MCExpr *Value, unsigned Size) { - MCValue RelocValue; - - if (!AddValueSymbols(Value)->EvaluateAsRelocatable(getContext(), RelocValue)) - return llvm_report_error("expected relocatable expression"); - - new MCFillFragment(RelocValue, Size, 1, CurSectionData); + new MCFillFragment(*AddValueSymbols(Value), Size, 1, CurSectionData); } void MCMachOStreamer::EmitValueToAlignment(unsigned ByteAlignment, @@ -344,13 +341,7 @@ void MCMachOStreamer::EmitValueToAlignment(unsigned ByteAlignment, void MCMachOStreamer::EmitValueToOffset(const MCExpr *Offset, unsigned char Value) { - MCValue RelocOffset; - - if (!AddValueSymbols(Offset)->EvaluateAsRelocatable(getContext(), - RelocOffset)) - return llvm_report_error("expected relocatable expression"); - - new MCOrgFragment(RelocOffset, Value, CurSectionData); + new MCOrgFragment(*Offset, Value, CurSectionData); } void MCMachOStreamer::EmitInstruction(const MCInst &Inst) { diff --git a/lib/Support/APFloat.cpp b/lib/Support/APFloat.cpp index e431d27..7e42e2d 100644 --- a/lib/Support/APFloat.cpp +++ b/lib/Support/APFloat.cpp @@ -48,6 +48,7 @@ namespace llvm { unsigned int arithmeticOK; }; + const fltSemantics APFloat::IEEEhalf = { 15, -14, 11, true }; const fltSemantics APFloat::IEEEsingle = { 127, -126, 24, true }; const fltSemantics APFloat::IEEEdouble = { 1023, -1022, 53, true }; const fltSemantics APFloat::IEEEquad = { 16383, -16382, 113, true }; @@ -2812,6 +2813,35 @@ APFloat::convertFloatAPFloatToAPInt() const (mysignificand & 0x7fffff))); } +APInt +APFloat::convertHalfAPFloatToAPInt() const +{ + assert(semantics == (const llvm::fltSemantics*)&IEEEhalf); + assert (partCount()==1); + + uint32_t myexponent, mysignificand; + + if (category==fcNormal) { + myexponent = exponent+15; //bias + mysignificand = (uint32_t)*significandParts(); + if (myexponent == 1 && !(mysignificand & 0x400)) + myexponent = 0; // denormal + } else if (category==fcZero) { + myexponent = 0; + mysignificand = 0; + } else if (category==fcInfinity) { + myexponent = 0x1f; + mysignificand = 0; + } else { + assert(category == fcNaN && "Unknown category!"); + myexponent = 0x1f; + mysignificand = (uint32_t)*significandParts(); + } + + return APInt(16, (((sign&1) << 15) | ((myexponent&0x1f) << 10) | + (mysignificand & 0x3ff))); +} + // This function creates an APInt that is just a bit map of the floating // point constant as it would appear in memory. It is not a conversion, // and treating the result as a normal integer is unlikely to be useful. @@ -2819,6 +2849,9 @@ APFloat::convertFloatAPFloatToAPInt() const APInt APFloat::bitcastToAPInt() const { + if (semantics == (const llvm::fltSemantics*)&IEEEhalf) + return convertHalfAPFloatToAPInt(); + if (semantics == (const llvm::fltSemantics*)&IEEEsingle) return convertFloatAPFloatToAPInt(); @@ -3051,6 +3084,39 @@ APFloat::initFromFloatAPInt(const APInt & api) } } +void +APFloat::initFromHalfAPInt(const APInt & api) +{ + assert(api.getBitWidth()==16); + uint32_t i = (uint32_t)*api.getRawData(); + uint32_t myexponent = (i >> 10) & 0x1f; + uint32_t mysignificand = i & 0x3ff; + + initialize(&APFloat::IEEEhalf); + assert(partCount()==1); + + sign = i >> 15; + if (myexponent==0 && mysignificand==0) { + // exponent, significand meaningless + category = fcZero; + } else if (myexponent==0x1f && mysignificand==0) { + // exponent, significand meaningless + category = fcInfinity; + } else if (myexponent==0x1f && mysignificand!=0) { + // sign, exponent, significand meaningless + category = fcNaN; + *significandParts() = mysignificand; + } else { + category = fcNormal; + exponent = myexponent - 15; //bias + *significandParts() = mysignificand; + if (myexponent==0) // denormal + exponent = -14; + else + *significandParts() |= 0x400; // integer bit + } +} + /// Treat api as containing the bits of a floating point number. Currently /// we infer the floating point type from the size of the APInt. The /// isIEEE argument distinguishes between PPC128 and IEEE128 (not meaningful @@ -3058,7 +3124,9 @@ APFloat::initFromFloatAPInt(const APInt & api) void APFloat::initFromAPInt(const APInt& api, bool isIEEE) { - if (api.getBitWidth() == 32) + if (api.getBitWidth() == 16) + return initFromHalfAPInt(api); + else if (api.getBitWidth() == 32) return initFromFloatAPInt(api); else if (api.getBitWidth()==64) return initFromDoubleAPInt(api); diff --git a/lib/Support/StringExtras.cpp b/lib/Support/StringExtras.cpp index 1618086..c72f121 100644 --- a/lib/Support/StringExtras.cpp +++ b/lib/Support/StringExtras.cpp @@ -56,59 +56,3 @@ void llvm::SplitString(const std::string &Source, S2 = getToken(S, Delimiters); } } - - - -/// UnescapeString - Modify the argument string, turning two character sequences -/// @verbatim -/// like '\\' 'n' into '\n'. This handles: \e \a \b \f \n \r \t \v \' \ and -/// \num (where num is a 1-3 byte octal value). -/// @endverbatim -void llvm::UnescapeString(std::string &Str) { - for (unsigned i = 0; i != Str.size(); ++i) { - if (Str[i] == '\\' && i != Str.size()-1) { - switch (Str[i+1]) { - default: continue; // Don't execute the code after the switch. - case 'a': Str[i] = '\a'; break; - case 'b': Str[i] = '\b'; break; - case 'e': Str[i] = 27; break; - case 'f': Str[i] = '\f'; break; - case 'n': Str[i] = '\n'; break; - case 'r': Str[i] = '\r'; break; - case 't': Str[i] = '\t'; break; - case 'v': Str[i] = '\v'; break; - case '"': Str[i] = '\"'; break; - case '\'': Str[i] = '\''; break; - case '\\': Str[i] = '\\'; break; - } - // Nuke the second character. - Str.erase(Str.begin()+i+1); - } - } -} - -/// EscapeString - Modify the argument string, turning '\\' and anything that -/// doesn't satisfy std::isprint into an escape sequence. -void llvm::EscapeString(std::string &Str) { - for (unsigned i = 0; i != Str.size(); ++i) { - if (Str[i] == '\\') { - ++i; - Str.insert(Str.begin()+i, '\\'); - } else if (Str[i] == '\t') { - Str[i++] = '\\'; - Str.insert(Str.begin()+i, 't'); - } else if (Str[i] == '"') { - Str.insert(Str.begin()+i++, '\\'); - } else if (Str[i] == '\n') { - Str[i++] = '\\'; - Str.insert(Str.begin()+i, 'n'); - } else if (!std::isprint(Str[i])) { - // Always expand to a 3-digit octal escape. - unsigned Char = Str[i]; - Str[i++] = '\\'; - Str.insert(Str.begin()+i++, '0'+((Char/64) & 7)); - Str.insert(Str.begin()+i++, '0'+((Char/8) & 7)); - Str.insert(Str.begin()+i , '0'+( Char & 7)); - } - } -} diff --git a/lib/Support/StringMap.cpp b/lib/Support/StringMap.cpp index 040308b..a729d3d 100644 --- a/lib/Support/StringMap.cpp +++ b/lib/Support/StringMap.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringExtras.h" #include <cassert> using namespace llvm; @@ -46,20 +47,6 @@ void StringMapImpl::init(unsigned InitSize) { } -/// HashString - Compute a hash code for the specified string. -/// -static unsigned HashString(const char *Start, const char *End) { - // Bernstein hash function. - unsigned int Result = 0; - // TODO: investigate whether a modified bernstein hash function performs - // better: http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx - // X*33+c -> X*33^c - while (Start != End) - Result = Result * 33 + *Start++; - Result = Result + (Result >> 5); - return Result; -} - /// LookupBucketFor - Look up the bucket that the specified string should end /// up in. If it already exists as a key in the map, the Item pointer for the /// specified bucket will be non-null. Otherwise, it will be null. In either @@ -71,7 +58,7 @@ unsigned StringMapImpl::LookupBucketFor(const StringRef &Name) { init(16); HTSize = NumBuckets; } - unsigned FullHashValue = HashString(Name.begin(), Name.end()); + unsigned FullHashValue = HashString(Name); unsigned BucketNo = FullHashValue & (HTSize-1); unsigned ProbeAmt = 1; @@ -126,7 +113,7 @@ unsigned StringMapImpl::LookupBucketFor(const StringRef &Name) { int StringMapImpl::FindKey(const StringRef &Key) const { unsigned HTSize = NumBuckets; if (HTSize == 0) return -1; // Really empty table? - unsigned FullHashValue = HashString(Key.begin(), Key.end()); + unsigned FullHashValue = HashString(Key); unsigned BucketNo = FullHashValue & (HTSize-1); unsigned ProbeAmt = 1; diff --git a/lib/Support/Triple.cpp b/lib/Support/Triple.cpp index 6f805da..26a1a4e 100644 --- a/lib/Support/Triple.cpp +++ b/lib/Support/Triple.cpp @@ -96,6 +96,7 @@ const char *Triple::getOSTypeName(OSType Kind) { case OpenBSD: return "openbsd"; case Solaris: return "solaris"; case Win32: return "win32"; + case Haiku: return "haiku"; } return "<invalid>"; @@ -276,6 +277,8 @@ void Triple::Parse() const { OS = Solaris; else if (OSName.startswith("win32")) OS = Win32; + else if (OSName.startswith("haiku")) + OS = Haiku; else OS = UnknownOS; diff --git a/lib/Support/raw_ostream.cpp b/lib/Support/raw_ostream.cpp index 0a82cc1..31451cc 100644 --- a/lib/Support/raw_ostream.cpp +++ b/lib/Support/raw_ostream.cpp @@ -168,6 +168,40 @@ raw_ostream &raw_ostream::write_hex(unsigned long long N) { return write(CurPtr, EndPtr-CurPtr); } +raw_ostream &raw_ostream::write_escaped(StringRef Str) { + for (unsigned i = 0, e = Str.size(); i != e; ++i) { + unsigned char c = Str[i]; + + switch (c) { + case '\\': + *this << '\\' << '\\'; + break; + case '\t': + *this << '\\' << 't'; + break; + case '\n': + *this << '\\' << 'n'; + break; + case '"': + *this << '\\' << '"'; + break; + default: + if (std::isprint(c)) { + *this << c; + break; + } + + // Always expand to a 3-character octal escape. + *this << '\\'; + *this << char('0' + ((c >> 6) & 7)); + *this << char('0' + ((c >> 3) & 7)); + *this << char('0' + ((c >> 0) & 7)); + } + } + + return *this; +} + raw_ostream &raw_ostream::operator<<(const void *P) { *this << '0' << 'x'; diff --git a/lib/System/Unix/Program.inc b/lib/System/Unix/Program.inc index 56dea25..c52f3a8 100644 --- a/lib/System/Unix/Program.inc +++ b/lib/System/Unix/Program.inc @@ -244,7 +244,7 @@ Program::Wait(unsigned secondsToWait, int status; uint64_t pid = reinterpret_cast<uint64_t>(Data_); pid_t child = static_cast<pid_t>(pid); - while (wait(&status) != child) + while (waitpid(pid, &status, 0) != child) if (secondsToWait && errno == EINTR) { // Kill the child. kill(child, SIGKILL); diff --git a/lib/Target/ARM/ARMAddressingModes.h b/lib/Target/ARM/ARMAddressingModes.h index 1839153..c603708 100644 --- a/lib/Target/ARM/ARMAddressingModes.h +++ b/lib/Target/ARM/ARMAddressingModes.h @@ -15,7 +15,6 @@ #define LLVM_TARGET_ARM_ARMADDRESSINGMODES_H #include "llvm/CodeGen/SelectionDAGNodes.h" -#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MathExtras.h" #include <cassert> @@ -38,7 +37,7 @@ namespace ARM_AM { static inline const char *getShiftOpcStr(ShiftOpc Op) { switch (Op) { - default: llvm_unreachable("Unknown shift opc!"); + default: assert(0 && "Unknown shift opc!"); case ARM_AM::asr: return "asr"; case ARM_AM::lsl: return "lsl"; case ARM_AM::lsr: return "lsr"; @@ -71,7 +70,7 @@ namespace ARM_AM { static inline const char *getAMSubModeStr(AMSubMode Mode) { switch (Mode) { - default: llvm_unreachable("Unknown addressing sub-mode!"); + default: assert(0 && "Unknown addressing sub-mode!"); case ARM_AM::ia: return "ia"; case ARM_AM::ib: return "ib"; case ARM_AM::da: return "da"; @@ -81,7 +80,7 @@ namespace ARM_AM { static inline const char *getAMSubModeAltStr(AMSubMode Mode, bool isLD) { switch (Mode) { - default: llvm_unreachable("Unknown addressing sub-mode!"); + default: assert(0 && "Unknown addressing sub-mode!"); case ARM_AM::ia: return isLD ? "fd" : "ea"; case ARM_AM::ib: return isLD ? "ed" : "fa"; case ARM_AM::da: return isLD ? "fa" : "ed"; @@ -342,6 +341,66 @@ namespace ARM_AM { return -1; } + static inline unsigned getT2SOImmValRotate(unsigned V) { + if ((V & ~255U) == 0) return 0; + // Use CTZ to compute the rotate amount. + unsigned RotAmt = CountTrailingZeros_32(V); + return (32 - RotAmt) & 31; + } + + static inline bool isT2SOImmTwoPartVal (unsigned Imm) { + unsigned V = Imm; + // Passing values can be any combination of splat values and shifter + // values. If this can be handled with a single shifter or splat, bail + // out. Those should be handled directly, not with a two-part val. + if (getT2SOImmValSplatVal(V) != -1) + return false; + V = rotr32 (~255U, getT2SOImmValRotate(V)) & V; + if (V == 0) + return false; + + // If this can be handled as an immediate, accept. + if (getT2SOImmVal(V) != -1) return true; + + // Likewise, try masking out a splat value first. + V = Imm; + if (getT2SOImmValSplatVal(V & 0xff00ff00U) != -1) + V &= ~0xff00ff00U; + else if (getT2SOImmValSplatVal(V & 0x00ff00ffU) != -1) + V &= ~0x00ff00ffU; + // If what's left can be handled as an immediate, accept. + if (getT2SOImmVal(V) != -1) return true; + + // Otherwise, do not accept. + return false; + } + + static inline unsigned getT2SOImmTwoPartFirst(unsigned Imm) { + assert (isT2SOImmTwoPartVal(Imm) && + "Immedate cannot be encoded as two part immediate!"); + // Try a shifter operand as one part + unsigned V = rotr32 (~255, getT2SOImmValRotate(Imm)) & Imm; + // If the rest is encodable as an immediate, then return it. + if (getT2SOImmVal(V) != -1) return V; + + // Try masking out a splat value first. + if (getT2SOImmValSplatVal(Imm & 0xff00ff00U) != -1) + return Imm & 0xff00ff00U; + + // The other splat is all that's left as an option. + assert (getT2SOImmValSplatVal(Imm & 0x00ff00ffU) != -1); + return Imm & 0x00ff00ffU; + } + + static inline unsigned getT2SOImmTwoPartSecond(unsigned Imm) { + // Mask out the first hunk + Imm ^= getT2SOImmTwoPartFirst(Imm); + // Return what's left + assert (getT2SOImmVal(Imm) != -1 && + "Unable to encode second part of T2 two part SO immediate"); + return Imm; + } + //===--------------------------------------------------------------------===// // Addressing Mode #2 diff --git a/lib/Target/ARM/ARMBaseRegisterInfo.cpp b/lib/Target/ARM/ARMBaseRegisterInfo.cpp index 42ef183..00e7531 100644 --- a/lib/Target/ARM/ARMBaseRegisterInfo.cpp +++ b/lib/Target/ARM/ARMBaseRegisterInfo.cpp @@ -36,8 +36,18 @@ #include "llvm/Target/TargetOptions.h" #include "llvm/ADT/BitVector.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/Support/CommandLine.h" using namespace llvm; +static cl::opt<bool> +ScavengeFrameIndexVals("arm-virtual-frame-index-vals", cl::Hidden, + cl::init(false), + cl::desc("Resolve frame index values via scavenging in PEI")); + +static cl::opt<bool> +ReuseFrameIndexVals("arm-reuse-frame-index-vals", cl::Hidden, cl::init(false), + cl::desc("Reuse repeated frame index values")); + unsigned ARMBaseRegisterInfo::getRegisterNumbering(unsigned RegEnum, bool *isSPVFP) { if (isSPVFP) @@ -740,8 +750,7 @@ unsigned ARMBaseRegisterInfo::getRegisterPairEven(unsigned Reg, case ARM::R1: return ARM::R0; case ARM::R3: - // FIXME! - return STI.isThumb1Only() ? 0 : ARM::R2; + return ARM::R2; case ARM::R5: return ARM::R4; case ARM::R7: @@ -830,8 +839,7 @@ unsigned ARMBaseRegisterInfo::getRegisterPairOdd(unsigned Reg, case ARM::R0: return ARM::R1; case ARM::R2: - // FIXME! - return STI.isThumb1Only() ? 0 : ARM::R3; + return ARM::R3; case ARM::R4: return ARM::R5; case ARM::R6: @@ -937,6 +945,11 @@ requiresRegisterScavenging(const MachineFunction &MF) const { return true; } +bool ARMBaseRegisterInfo:: +requiresFrameIndexScavenging(const MachineFunction &MF) const { + return ScavengeFrameIndexVals; +} + // hasReservedCallFrame - Under normal circumstances, when a frame pointer is // not required, we reserve argument space for call sites in the function // immediately on entry to the current function. This eliminates the need for @@ -1077,14 +1090,7 @@ ARMBaseRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, (MI.getDesc().TSFlags & ARMII::AddrModeMask) == ARMII::AddrMode4) && "This code isn't needed if offset already handled!"); - // Insert a set of r12 with the full address: r12 = sp + offset - // If the offset we have is too large to fit into the instruction, we need - // to form it with a series of ADDri's. Do this by taking 8-bit chunks - // out of 'Offset'. - unsigned ScratchReg = findScratchRegister(RS, ARM::GPRRegisterClass, AFI); - if (ScratchReg == 0) - // No register is "free". Scavenge a register. - ScratchReg = RS->scavengeRegister(ARM::GPRRegisterClass, II, SPAdj); + unsigned ScratchReg = 0; int PIdx = MI.findFirstPredOperandIdx(); ARMCC::CondCodes Pred = (PIdx == -1) ? ARMCC::AL : (ARMCC::CondCodes)MI.getOperand(PIdx).getImm(); @@ -1093,6 +1099,19 @@ ARMBaseRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, // Must be addrmode4. MI.getOperand(i).ChangeToRegister(FrameReg, false, false, false); else { + if (!ScavengeFrameIndexVals) { + // Insert a set of r12 with the full address: r12 = sp + offset + // If the offset we have is too large to fit into the instruction, we need + // to form it with a series of ADDri's. Do this by taking 8-bit chunks + // out of 'Offset'. + ScratchReg = findScratchRegister(RS, ARM::GPRRegisterClass, AFI); + if (ScratchReg == 0) + // No register is "free". Scavenge a register. + ScratchReg = RS->scavengeRegister(ARM::GPRRegisterClass, II, SPAdj); + } else { + ScratchReg = MF.getRegInfo().createVirtualRegister(ARM::GPRRegisterClass); + *Value = Offset; + } if (!AFI->isThumbFunction()) emitARMRegPlusImmediate(MBB, II, MI.getDebugLoc(), ScratchReg, FrameReg, Offset, Pred, PredReg, TII); @@ -1102,8 +1121,10 @@ ARMBaseRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, Offset, Pred, PredReg, TII); } MI.getOperand(i).ChangeToRegister(ScratchReg, false, false, true); + if (!ReuseFrameIndexVals || !ScavengeFrameIndexVals) + ScratchReg = 0; } - return 0; + return ScratchReg; } /// Move iterator pass the next bunch of callee save load / store ops for diff --git a/lib/Target/ARM/ARMBaseRegisterInfo.h b/lib/Target/ARM/ARMBaseRegisterInfo.h index da703fb..f7d38e5 100644 --- a/lib/Target/ARM/ARMBaseRegisterInfo.h +++ b/lib/Target/ARM/ARMBaseRegisterInfo.h @@ -122,6 +122,8 @@ public: virtual bool requiresRegisterScavenging(const MachineFunction &MF) const; + virtual bool requiresFrameIndexScavenging(const MachineFunction &MF) const; + virtual bool hasReservedCallFrame(MachineFunction &MF) const; virtual void eliminateCallFramePseudoInstr(MachineFunction &MF, diff --git a/lib/Target/ARM/ARMConstantIslandPass.cpp b/lib/Target/ARM/ARMConstantIslandPass.cpp index b0bd04b..c995ff2 100644 --- a/lib/Target/ARM/ARMConstantIslandPass.cpp +++ b/lib/Target/ARM/ARMConstantIslandPass.cpp @@ -28,9 +28,11 @@ #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Statistic.h" +#include <algorithm> using namespace llvm; STATISTIC(NumCPEs, "Number of constpool entries"); @@ -70,6 +72,10 @@ namespace { /// to a return, unreachable, or unconditional branch). std::vector<MachineBasicBlock*> WaterList; + /// NewWaterList - The subset of WaterList that was created since the + /// previous iteration by inserting unconditional branches. + SmallSet<MachineBasicBlock*, 4> NewWaterList; + typedef std::vector<MachineBasicBlock*>::iterator water_iterator; /// CPUser - One user of a constant pool, keeping the machine instruction @@ -175,9 +181,7 @@ namespace { void AdjustBBOffsetsAfter(MachineBasicBlock *BB, int delta); bool DecrementOldEntry(unsigned CPI, MachineInstr* CPEMI); int LookForExistingCPEntry(CPUser& U, unsigned UserOffset); - bool LookForWater(CPUser&U, unsigned UserOffset, - MachineBasicBlock *&NewMBB); - MachineBasicBlock *AcceptWater(water_iterator IP); + bool LookForWater(CPUser&U, unsigned UserOffset, water_iterator &WaterIter); void CreateNewWater(unsigned CPUserIndex, unsigned UserOffset, MachineBasicBlock *&NewMBB); bool HandleConstantPoolUser(MachineFunction &MF, unsigned CPUserIndex); @@ -297,6 +301,10 @@ bool ARMConstantIslands::runOnMachineFunction(MachineFunction &MF) { if (CPChange && ++NoCPIters > 30) llvm_unreachable("Constant Island pass failed to converge!"); DEBUG(dumpBBs()); + + // Clear NewWaterList now. If we split a block for branches, it should + // appear as "new water" for the next iteration of constant pool placement. + NewWaterList.clear(); bool BRChange = false; for (unsigned i = 0, e = ImmBranches.size(); i != e; ++i) @@ -629,7 +637,7 @@ void ARMConstantIslands::UpdateForInsertedWaterBlock(MachineBasicBlock *NewBB) { /// Split the basic block containing MI into two blocks, which are joined by -/// an unconditional branch. Update datastructures and renumber blocks to +/// an unconditional branch. Update data structures and renumber blocks to /// account for this change and returns the newly created block. MachineBasicBlock *ARMConstantIslands::SplitBlockBeforeInstr(MachineInstr *MI) { MachineBasicBlock *OrigBB = MI->getParent(); @@ -691,6 +699,7 @@ MachineBasicBlock *ARMConstantIslands::SplitBlockBeforeInstr(MachineInstr *MI) { WaterList.insert(next(IP), NewBB); else WaterList.insert(IP, OrigBB); + NewWaterList.insert(OrigBB); // Figure out how large the first NewMBB is. (It cannot // contain a constpool_entry or tablejump.) @@ -941,30 +950,16 @@ static inline unsigned getUnconditionalBrDisp(int Opc) { return ((1<<23)-1)*4; } -/// AcceptWater - Small amount of common code factored out of the following. -/// -MachineBasicBlock *ARMConstantIslands::AcceptWater(water_iterator IP) { - DEBUG(errs() << "found water in range\n"); - MachineBasicBlock *WaterBB = *IP; - // Remove the original WaterList entry; we want subsequent - // insertions in this vicinity to go after the one we're - // about to insert. This considerably reduces the number - // of times we have to move the same CPE more than once. - WaterList.erase(IP); - // CPE goes before following block (NewMBB). - return next(MachineFunction::iterator(WaterBB)); -} - -/// LookForWater - look for an existing entry in the WaterList in which +/// LookForWater - Look for an existing entry in the WaterList in which /// we can place the CPE referenced from U so it's within range of U's MI. -/// Returns true if found, false if not. If it returns true, NewMBB +/// Returns true if found, false if not. If it returns true, WaterIter /// is set to the WaterList entry. For Thumb, prefer water that will not /// introduce padding to water that will. To ensure that this pass /// terminates, the CPE location for a particular CPUser is only allowed to /// move to a lower address, so search backward from the end of the list and /// prefer the first water that is in range. bool ARMConstantIslands::LookForWater(CPUser &U, unsigned UserOffset, - MachineBasicBlock *&NewMBB) { + water_iterator &WaterIter) { if (WaterList.empty()) return false; @@ -973,9 +968,17 @@ bool ARMConstantIslands::LookForWater(CPUser &U, unsigned UserOffset, for (water_iterator IP = prior(WaterList.end()), B = WaterList.begin();; --IP) { MachineBasicBlock* WaterBB = *IP; - // Check if water is in range and at a lower address than the current one. - if (WaterBB->getNumber() < U.HighWaterMark->getNumber() && - WaterIsInRange(UserOffset, WaterBB, U)) { + // Check if water is in range and is either at a lower address than the + // current "high water mark" or a new water block that was created since + // the previous iteration by inserting an unconditional branch. In the + // latter case, we want to allow resetting the high water mark back to + // this new water since we haven't seen it before. Inserting branches + // should be relatively uncommon and when it does happen, we want to be + // sure to take advantage of it for all the CPEs near that block, so that + // we don't insert more branches than necessary. + if (WaterIsInRange(UserOffset, WaterBB, U) && + (WaterBB->getNumber() < U.HighWaterMark->getNumber() || + NewWaterList.count(WaterBB))) { unsigned WBBId = WaterBB->getNumber(); if (isThumb && (BBOffsets[WBBId] + BBSizes[WBBId])%4 != 0) { @@ -986,7 +989,7 @@ bool ARMConstantIslands::LookForWater(CPUser &U, unsigned UserOffset, IPThatWouldPad = IP; } } else { - NewMBB = AcceptWater(IP); + WaterIter = IP; return true; } } @@ -994,7 +997,7 @@ bool ARMConstantIslands::LookForWater(CPUser &U, unsigned UserOffset, break; } if (FoundWaterThatWouldPad) { - NewMBB = AcceptWater(IPThatWouldPad); + WaterIter = IPThatWouldPad; return true; } return false; @@ -1107,7 +1110,6 @@ bool ARMConstantIslands::HandleConstantPoolUser(MachineFunction &MF, MachineInstr *CPEMI = U.CPEMI; unsigned CPI = CPEMI->getOperand(1).getIndex(); unsigned Size = CPEMI->getOperand(2).getImm(); - MachineBasicBlock *NewMBB; // Compute this only once, it's expensive. The 4 or 8 is the value the // hardware keeps in the PC. unsigned UserOffset = GetOffsetOf(UserMI) + (isThumb ? 4 : 8); @@ -1123,14 +1125,50 @@ bool ARMConstantIslands::HandleConstantPoolUser(MachineFunction &MF, unsigned ID = AFI->createConstPoolEntryUId(); // Look for water where we can place this CPE. - if (!LookForWater(U, UserOffset, NewMBB)) { + MachineBasicBlock *NewIsland = MF.CreateMachineBasicBlock(); + MachineBasicBlock *NewMBB; + water_iterator IP; + if (LookForWater(U, UserOffset, IP)) { + DEBUG(errs() << "found water in range\n"); + MachineBasicBlock *WaterBB = *IP; + + // If the original WaterList entry was "new water" on this iteration, + // propagate that to the new island. This is just keeping NewWaterList + // updated to match the WaterList, which will be updated below. + if (NewWaterList.count(WaterBB)) { + NewWaterList.erase(WaterBB); + NewWaterList.insert(NewIsland); + } + // The new CPE goes before the following block (NewMBB). + NewMBB = next(MachineFunction::iterator(WaterBB)); + + } else { // No water found. DEBUG(errs() << "No water found\n"); CreateNewWater(CPUserIndex, UserOffset, NewMBB); + + // SplitBlockBeforeInstr adds to WaterList, which is important when it is + // called while handling branches so that the water will be seen on the + // next iteration for constant pools, but in this context, we don't want + // it. Check for this so it will be removed from the WaterList. + // Also remove any entry from NewWaterList. + MachineBasicBlock *WaterBB = prior(MachineFunction::iterator(NewMBB)); + IP = std::find(WaterList.begin(), WaterList.end(), WaterBB); + if (IP != WaterList.end()) + NewWaterList.erase(WaterBB); + + // We are adding new water. Update NewWaterList. + NewWaterList.insert(NewIsland); } + // Remove the original WaterList entry; we want subsequent insertions in + // this vicinity to go after the one we're about to insert. This + // considerably reduces the number of times we have to move the same CPE + // more than once and is also important to ensure the algorithm terminates. + if (IP != WaterList.end()) + WaterList.erase(IP); + // Okay, we know we can put an island before NewMBB now, do it! - MachineBasicBlock *NewIsland = MF.CreateMachineBasicBlock(); MF.insert(NewMBB, NewIsland); // Update internal data structures to account for the newly inserted MBB. diff --git a/lib/Target/ARM/ARMISelDAGToDAG.cpp b/lib/Target/ARM/ARMISelDAGToDAG.cpp index c39de0a..5c1835b 100644 --- a/lib/Target/ARM/ARMISelDAGToDAG.cpp +++ b/lib/Target/ARM/ARMISelDAGToDAG.cpp @@ -1287,7 +1287,7 @@ SDNode *ARMDAGToDAGISel::SelectV6T2BitfieldExtractOp(SDValue Op, assert(Srl_imm > 0 && Srl_imm < 32 && "bad amount in shift node!"); unsigned Width = 32 - Srl_imm; int LSB = Srl_imm - Shl_imm; - if ((LSB + Width) > 32) + if (LSB < 0) return NULL; SDValue Reg0 = CurDAG->getRegister(0, MVT::i32); SDValue Ops[] = { Op.getOperand(0).getOperand(0), @@ -1427,6 +1427,43 @@ SDNode *ARMDAGToDAGISel::Select(SDValue Op) { } } break; + case ISD::AND: { + // (and (or x, c2), c1) and top 16-bits of c1 and c2 match, lower 16-bits + // of c1 are 0xffff, and lower 16-bit of c2 are 0. That is, the top 16-bits + // are entirely contributed by c2 and lower 16-bits are entirely contributed + // by x. That's equal to (or (and x, 0xffff), (and c1, 0xffff0000)). + // Select it to: "movt x, ((c1 & 0xffff) >> 16) + EVT VT = Op.getValueType(); + if (VT != MVT::i32) + break; + unsigned Opc = (Subtarget->isThumb() && Subtarget->hasThumb2()) + ? ARM::t2MOVTi16 + : (Subtarget->hasV6T2Ops() ? ARM::MOVTi16 : 0); + if (!Opc) + break; + SDValue N0 = Op.getOperand(0), N1 = Op.getOperand(1); + ConstantSDNode *N1C = dyn_cast<ConstantSDNode>(N1); + if (!N1C) + break; + if (N0.getOpcode() == ISD::OR && N0.getNode()->hasOneUse()) { + SDValue N2 = N0.getOperand(1); + ConstantSDNode *N2C = dyn_cast<ConstantSDNode>(N2); + if (!N2C) + break; + unsigned N1CVal = N1C->getZExtValue(); + unsigned N2CVal = N2C->getZExtValue(); + if ((N1CVal & 0xffff0000U) == (N2CVal & 0xffff0000U) && + (N1CVal & 0xffffU) == 0xffffU && + (N2CVal & 0xffffU) == 0x0U) { + SDValue Imm16 = CurDAG->getTargetConstant((N2CVal & 0xFFFF0000U) >> 16, + MVT::i32); + SDValue Ops[] = { N0.getOperand(0), Imm16, + getAL(CurDAG), CurDAG->getRegister(0, MVT::i32) }; + return CurDAG->getMachineNode(Opc, dl, VT, Ops, 4); + } + } + break; + } case ARMISD::FMRRD: return CurDAG->getMachineNode(ARM::FMRRD, dl, MVT::i32, MVT::i32, Op.getOperand(0), getAL(CurDAG), diff --git a/lib/Target/ARM/ARMISelLowering.cpp b/lib/Target/ARM/ARMISelLowering.cpp index 426cecb..6a264fd 100644 --- a/lib/Target/ARM/ARMISelLowering.cpp +++ b/lib/Target/ARM/ARMISelLowering.cpp @@ -25,9 +25,10 @@ #include "llvm/CallingConv.h" #include "llvm/Constants.h" #include "llvm/Function.h" +#include "llvm/GlobalValue.h" #include "llvm/Instruction.h" #include "llvm/Intrinsics.h" -#include "llvm/GlobalValue.h" +#include "llvm/Type.h" #include "llvm/CodeGen/CallingConvLower.h" #include "llvm/CodeGen/MachineBasicBlock.h" #include "llvm/CodeGen/MachineFrameInfo.h" @@ -2360,8 +2361,11 @@ static bool isVREVMask(const SmallVectorImpl<int> &M, EVT VT, assert((BlockSize==16 || BlockSize==32 || BlockSize==64) && "Only possible block sizes for VREV are: 16, 32, 64"); - unsigned NumElts = VT.getVectorNumElements(); unsigned EltSz = VT.getVectorElementType().getSizeInBits(); + if (EltSz == 64) + return false; + + unsigned NumElts = VT.getVectorNumElements(); unsigned BlockElts = M[0] + 1; if (BlockSize <= EltSz || BlockSize != BlockElts * EltSz) @@ -2378,6 +2382,10 @@ static bool isVREVMask(const SmallVectorImpl<int> &M, EVT VT, static bool isVTRNMask(const SmallVectorImpl<int> &M, EVT VT, unsigned &WhichResult) { + unsigned EltSz = VT.getVectorElementType().getSizeInBits(); + if (EltSz == 64) + return false; + unsigned NumElts = VT.getVectorNumElements(); WhichResult = (M[0] == 0 ? 0 : 1); for (unsigned i = 0; i < NumElts; i += 2) { @@ -2390,6 +2398,10 @@ static bool isVTRNMask(const SmallVectorImpl<int> &M, EVT VT, static bool isVUZPMask(const SmallVectorImpl<int> &M, EVT VT, unsigned &WhichResult) { + unsigned EltSz = VT.getVectorElementType().getSizeInBits(); + if (EltSz == 64) + return false; + unsigned NumElts = VT.getVectorNumElements(); WhichResult = (M[0] == 0 ? 0 : 1); for (unsigned i = 0; i != NumElts; ++i) { @@ -2398,7 +2410,7 @@ static bool isVUZPMask(const SmallVectorImpl<int> &M, EVT VT, } // VUZP.32 for 64-bit vectors is a pseudo-instruction alias for VTRN.32. - if (VT.is64BitVector() && VT.getVectorElementType().getSizeInBits() == 32) + if (VT.is64BitVector() && EltSz == 32) return false; return true; @@ -2406,6 +2418,10 @@ static bool isVUZPMask(const SmallVectorImpl<int> &M, EVT VT, static bool isVZIPMask(const SmallVectorImpl<int> &M, EVT VT, unsigned &WhichResult) { + unsigned EltSz = VT.getVectorElementType().getSizeInBits(); + if (EltSz == 64) + return false; + unsigned NumElts = VT.getVectorNumElements(); WhichResult = (M[0] == 0 ? 0 : 1); unsigned Idx = WhichResult * NumElts / 2; @@ -2417,7 +2433,7 @@ static bool isVZIPMask(const SmallVectorImpl<int> &M, EVT VT, } // VZIP.32 for 64-bit vectors is a pseudo-instruction alias for VTRN.32. - if (VT.is64BitVector() && VT.getVectorElementType().getSizeInBits() == 32) + if (VT.is64BitVector() && EltSz == 32) return false; return true; @@ -2695,18 +2711,10 @@ static SDValue LowerEXTRACT_VECTOR_ELT(SDValue Op, SelectionDAG &DAG) { DebugLoc dl = Op.getDebugLoc(); SDValue Vec = Op.getOperand(0); SDValue Lane = Op.getOperand(1); - - // FIXME: This is invalid for 8 and 16-bit elements - the information about - // sign / zero extension is lost! - Op = DAG.getNode(ARMISD::VGETLANEu, dl, MVT::i32, Vec, Lane); - Op = DAG.getNode(ISD::AssertZext, dl, MVT::i32, Op, DAG.getValueType(VT)); - - if (VT.bitsLT(MVT::i32)) - Op = DAG.getNode(ISD::TRUNCATE, dl, VT, Op); - else if (VT.bitsGT(MVT::i32)) - Op = DAG.getNode(ISD::ANY_EXTEND, dl, VT, Op); - - return Op; + assert(VT == MVT::i32 && + Vec.getValueType().getVectorElementType().getSizeInBits() < 32 && + "unexpected type for custom-lowering vector extract"); + return DAG.getNode(ARMISD::VGETLANEu, dl, MVT::i32, Vec, Lane); } static SDValue LowerCONCAT_VECTORS(SDValue Op, SelectionDAG &DAG) { @@ -3029,7 +3037,6 @@ static SDValue PerformSUBCombine(SDNode *N, return SDValue(); } - /// PerformFMRRDCombine - Target-specific dag combine xforms for ARMISD::FMRRD. static SDValue PerformFMRRDCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI) { diff --git a/lib/Target/ARM/ARMInstrFormats.td b/lib/Target/ARM/ARMInstrFormats.td index 3d19f23..8225fd7 100644 --- a/lib/Target/ARM/ARMInstrFormats.td +++ b/lib/Target/ARM/ARMInstrFormats.td @@ -1220,6 +1220,10 @@ class NLdSt<bit op23, bits<2> op21_20, bits<4> op11_8, bits<4> op7_4, string asm, string cstr, list<dag> pattern> : NeonI<oops, iops, AddrMode6, IndexModeNone, itin, asm, cstr, pattern> { let Inst{31-24} = 0b11110100; + let Inst{23} = op23; + let Inst{21-20} = op21_20; + let Inst{11-8} = op11_8; + let Inst{7-4} = op7_4; } class NDataI<dag oops, dag iops, InstrItinClass itin, @@ -1258,15 +1262,26 @@ class N2V<bits<2> op24_23, bits<2> op21_20, bits<2> op19_18, bits<2> op17_16, let Inst{4} = op4; } +// NEON Vector Duplicate (scalar). +// Inst{19-16} is specified by subclasses. +class N2VDup<bits<2> op24_23, bits<2> op21_20, bits<5> op11_7, bit op6, bit op4, + dag oops, dag iops, InstrItinClass itin, + string asm, string cstr, list<dag> pattern> + : NDataI<oops, iops, itin, asm, cstr, pattern> { + let Inst{24-23} = op24_23; + let Inst{21-20} = op21_20; + let Inst{11-7} = op11_7; + let Inst{6} = op6; + let Inst{4} = op4; +} + // NEON 2 vector register with immediate. -class N2VImm<bit op24, bit op23, bits<6> op21_16, bits<4> op11_8, bit op7, - bit op6, bit op4, +class N2VImm<bit op24, bit op23, bits<4> op11_8, bit op7, bit op6, bit op4, dag oops, dag iops, InstrItinClass itin, string asm, string cstr, list<dag> pattern> : NDataI<oops, iops, itin, asm, cstr, pattern> { let Inst{24} = op24; let Inst{23} = op23; - let Inst{21-16} = op21_16; let Inst{11-8} = op11_8; let Inst{7} = op7; let Inst{6} = op6; @@ -1286,6 +1301,20 @@ class N3V<bit op24, bit op23, bits<2> op21_20, bits<4> op11_8, bit op6, bit op4, let Inst{4} = op4; } +// NEON 3 vector register with immediate. This is only used for VEXT where +// op11_8 represents the starting byte index of the extracted result in the +// concatenation of the operands and is left unspecified. +class N3VImm<bit op24, bit op23, bits<2> op21_20, bit op6, bit op4, + dag oops, dag iops, InstrItinClass itin, + string asm, string cstr, list<dag> pattern> + : NDataI<oops, iops, itin, asm, cstr, pattern> { + let Inst{24} = op24; + let Inst{23} = op23; + let Inst{21-20} = op21_20; + let Inst{6} = op6; + let Inst{4} = op4; +} + // NEON VMOVs between scalar and core registers. class NVLaneOp<bits<8> opcod1, bits<4> opcod2, bits<2> opcod3, dag oops, dag iops, Format f, InstrItinClass itin, diff --git a/lib/Target/ARM/ARMInstrInfo.cpp b/lib/Target/ARM/ARMInstrInfo.cpp index 4c92891..dd4123b 100644 --- a/lib/Target/ARM/ARMInstrInfo.cpp +++ b/lib/Target/ARM/ARMInstrInfo.cpp @@ -22,7 +22,6 @@ #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineJumpTableInfo.h" #include "llvm/MC/MCAsmInfo.h" -#include "llvm/Support/CommandLine.h" using namespace llvm; ARMInstrInfo::ARMInstrInfo(const ARMSubtarget &STI) diff --git a/lib/Target/ARM/ARMInstrInfo.td b/lib/Target/ARM/ARMInstrInfo.td index 6ec78bc..384b98c 100644 --- a/lib/Target/ARM/ARMInstrInfo.td +++ b/lib/Target/ARM/ARMInstrInfo.td @@ -980,6 +980,9 @@ def MOVTi16 : AI1<0b1010, (outs GPR:$dst), (ins GPR:$src, i32imm:$imm), let Inst{25} = 1; } +def : ARMPat<(or GPR:$src, 0xffff0000), (MOVTi16 GPR:$src, 0xffff)>, + Requires<[IsARM, HasV6T2]>; + let Uses = [CPSR] in def MOVrx : AsI1<0b1101, (outs GPR:$dst), (ins GPR:$src), Pseudo, IIC_iMOVsi, "mov", " $dst, $src, rrx", @@ -1580,10 +1583,17 @@ def : ARMPat<(or GPR:$LHS, so_imm2part:$RHS), def : ARMPat<(xor GPR:$LHS, so_imm2part:$RHS), (EORri (EORri GPR:$LHS, (so_imm2part_1 imm:$RHS)), (so_imm2part_2 imm:$RHS))>; +def : ARMPat<(add GPR:$LHS, so_imm2part:$RHS), + (ADDri (ADDri GPR:$LHS, (so_imm2part_1 imm:$RHS)), + (so_imm2part_2 imm:$RHS))>; +def : ARMPat<(sub GPR:$LHS, so_imm2part:$RHS), + (SUBri (SUBri GPR:$LHS, (so_imm2part_1 imm:$RHS)), + (so_imm2part_2 imm:$RHS))>; // 32-bit immediate using movw + movt. -// This is a single pseudo instruction to make it re-materializable. Remove -// when we can do generalized remat. +// This is a single pseudo instruction, the benefit is that it can be remat'd +// as a single unit instead of having to handle reg inputs. +// FIXME: Remove this when we can do generalized remat. let isReMaterializable = 1 in def MOVi32imm : AI1x2<(outs GPR:$dst), (ins i32imm:$src), Pseudo, IIC_iMOVi, "movw", " $dst, ${src:lo16}\n\tmovt${p} $dst, ${src:hi16}", diff --git a/lib/Target/ARM/ARMInstrNEON.td b/lib/Target/ARM/ARMInstrNEON.td index b34aff7..822950c 100644 --- a/lib/Target/ARM/ARMInstrNEON.td +++ b/lib/Target/ARM/ARMInstrNEON.td @@ -456,17 +456,17 @@ class VST2LN<bits<4> op11_8, string OpcodeStr> !strconcat(OpcodeStr, "\t\\{$src1[$lane],$src2[$lane]\\}, $addr"), "", []>; -def VST2LNd8 : VST2LN<0b0000, "vst2.8">; -def VST2LNd16 : VST2LN<0b0100, "vst2.16">; -def VST2LNd32 : VST2LN<0b1000, "vst2.32">; +def VST2LNd8 : VST2LN<0b0001, "vst2.8">; +def VST2LNd16 : VST2LN<0b0101, "vst2.16">; +def VST2LNd32 : VST2LN<0b1001, "vst2.32">; // vst2 to double-spaced even registers. -def VST2LNq16a: VST2LN<0b0100, "vst2.16">; -def VST2LNq32a: VST2LN<0b1000, "vst2.32">; +def VST2LNq16a: VST2LN<0b0101, "vst2.16">; +def VST2LNq32a: VST2LN<0b1001, "vst2.32">; // vst2 to double-spaced odd registers. -def VST2LNq16b: VST2LN<0b0100, "vst2.16">; -def VST2LNq32b: VST2LN<0b1000, "vst2.32">; +def VST2LNq16b: VST2LN<0b0101, "vst2.16">; +def VST2LNq32b: VST2LN<0b1001, "vst2.32">; // VST3LN : Vector Store (single 3-element structure from one lane) class VST3LN<bits<4> op11_8, string OpcodeStr> @@ -623,12 +623,12 @@ class N2VNInt<bits<2> op24_23, bits<2> op21_20, bits<2> op19_18, (ins QPR:$src), itin, !strconcat(OpcodeStr, "\t$dst, $src"), "", [(set DPR:$dst, (TyD (IntOp (TyQ QPR:$src))))]>; -// Long 2-register intrinsics. (This is currently only used for VMOVL and is -// derived from N2VImm instead of N2V because of the way the size is encoded.) -class N2VLInt<bit op24, bit op23, bits<6> op21_16, bits<4> op11_8, bit op7, - bit op6, bit op4, InstrItinClass itin, string OpcodeStr, +// Long 2-register intrinsics (currently only used for VMOVL). +class N2VLInt<bits<2> op24_23, bits<2> op21_20, bits<2> op19_18, + bits<2> op17_16, bits<5> op11_7, bit op6, bit op4, + InstrItinClass itin, string OpcodeStr, ValueType TyQ, ValueType TyD, Intrinsic IntOp> - : N2VImm<op24, op23, op21_16, op11_8, op7, op6, op4, (outs QPR:$dst), + : N2V<op24_23, op21_20, op19_18, op17_16, op11_7, op6, op4, (outs QPR:$dst), (ins DPR:$src), itin, !strconcat(OpcodeStr, "\t$dst, $src"), "", [(set QPR:$dst, (TyQ (IntOp (TyD DPR:$src))))]>; @@ -1016,36 +1016,33 @@ class N2VQPLInt2<bits<2> op24_23, bits<2> op21_20, bits<2> op19_18, // Shift by immediate, // both double- and quad-register. -class N2VDSh<bit op24, bit op23, bits<6> op21_16, bits<4> op11_8, bit op7, - bit op4, InstrItinClass itin, string OpcodeStr, - ValueType Ty, SDNode OpNode> - : N2VImm<op24, op23, op21_16, op11_8, op7, 0, op4, +class N2VDSh<bit op24, bit op23, bits<4> op11_8, bit op7, bit op4, + InstrItinClass itin, string OpcodeStr, ValueType Ty, SDNode OpNode> + : N2VImm<op24, op23, op11_8, op7, 0, op4, (outs DPR:$dst), (ins DPR:$src, i32imm:$SIMM), itin, !strconcat(OpcodeStr, "\t$dst, $src, $SIMM"), "", [(set DPR:$dst, (Ty (OpNode (Ty DPR:$src), (i32 imm:$SIMM))))]>; -class N2VQSh<bit op24, bit op23, bits<6> op21_16, bits<4> op11_8, bit op7, - bit op4, InstrItinClass itin, string OpcodeStr, - ValueType Ty, SDNode OpNode> - : N2VImm<op24, op23, op21_16, op11_8, op7, 1, op4, +class N2VQSh<bit op24, bit op23, bits<4> op11_8, bit op7, bit op4, + InstrItinClass itin, string OpcodeStr, ValueType Ty, SDNode OpNode> + : N2VImm<op24, op23, op11_8, op7, 1, op4, (outs QPR:$dst), (ins QPR:$src, i32imm:$SIMM), itin, !strconcat(OpcodeStr, "\t$dst, $src, $SIMM"), "", [(set QPR:$dst, (Ty (OpNode (Ty QPR:$src), (i32 imm:$SIMM))))]>; // Long shift by immediate. -class N2VLSh<bit op24, bit op23, bits<6> op21_16, bits<4> op11_8, bit op7, - bit op6, bit op4, string OpcodeStr, ValueType ResTy, - ValueType OpTy, SDNode OpNode> - : N2VImm<op24, op23, op21_16, op11_8, op7, op6, op4, +class N2VLSh<bit op24, bit op23, bits<4> op11_8, bit op7, bit op6, bit op4, + string OpcodeStr, ValueType ResTy, ValueType OpTy, SDNode OpNode> + : N2VImm<op24, op23, op11_8, op7, op6, op4, (outs QPR:$dst), (ins DPR:$src, i32imm:$SIMM), IIC_VSHLiD, !strconcat(OpcodeStr, "\t$dst, $src, $SIMM"), "", [(set QPR:$dst, (ResTy (OpNode (OpTy DPR:$src), (i32 imm:$SIMM))))]>; // Narrow shift by immediate. -class N2VNSh<bit op24, bit op23, bits<6> op21_16, bits<4> op11_8, bit op7, - bit op6, bit op4, InstrItinClass itin, string OpcodeStr, +class N2VNSh<bit op24, bit op23, bits<4> op11_8, bit op7, bit op6, bit op4, + InstrItinClass itin, string OpcodeStr, ValueType ResTy, ValueType OpTy, SDNode OpNode> - : N2VImm<op24, op23, op21_16, op11_8, op7, op6, op4, + : N2VImm<op24, op23, op11_8, op7, op6, op4, (outs DPR:$dst), (ins QPR:$src, i32imm:$SIMM), itin, !strconcat(OpcodeStr, "\t$dst, $src, $SIMM"), "", [(set DPR:$dst, (ResTy (OpNode (OpTy QPR:$src), @@ -1053,53 +1050,49 @@ class N2VNSh<bit op24, bit op23, bits<6> op21_16, bits<4> op11_8, bit op7, // Shift right by immediate and accumulate, // both double- and quad-register. -class N2VDShAdd<bit op24, bit op23, bits<6> op21_16, bits<4> op11_8, bit op7, - bit op4, string OpcodeStr, ValueType Ty, SDNode ShOp> - : N2VImm<op24, op23, op21_16, op11_8, op7, 0, op4, - (outs DPR:$dst), (ins DPR:$src1, DPR:$src2, i32imm:$SIMM), - IIC_VPALiD, +class N2VDShAdd<bit op24, bit op23, bits<4> op11_8, bit op7, bit op4, + string OpcodeStr, ValueType Ty, SDNode ShOp> + : N2VImm<op24, op23, op11_8, op7, 0, op4, (outs DPR:$dst), + (ins DPR:$src1, DPR:$src2, i32imm:$SIMM), IIC_VPALiD, !strconcat(OpcodeStr, "\t$dst, $src2, $SIMM"), "$src1 = $dst", [(set DPR:$dst, (Ty (add DPR:$src1, (Ty (ShOp DPR:$src2, (i32 imm:$SIMM))))))]>; -class N2VQShAdd<bit op24, bit op23, bits<6> op21_16, bits<4> op11_8, bit op7, - bit op4, string OpcodeStr, ValueType Ty, SDNode ShOp> - : N2VImm<op24, op23, op21_16, op11_8, op7, 1, op4, - (outs QPR:$dst), (ins QPR:$src1, QPR:$src2, i32imm:$SIMM), - IIC_VPALiD, +class N2VQShAdd<bit op24, bit op23, bits<4> op11_8, bit op7, bit op4, + string OpcodeStr, ValueType Ty, SDNode ShOp> + : N2VImm<op24, op23, op11_8, op7, 1, op4, (outs QPR:$dst), + (ins QPR:$src1, QPR:$src2, i32imm:$SIMM), IIC_VPALiD, !strconcat(OpcodeStr, "\t$dst, $src2, $SIMM"), "$src1 = $dst", [(set QPR:$dst, (Ty (add QPR:$src1, (Ty (ShOp QPR:$src2, (i32 imm:$SIMM))))))]>; // Shift by immediate and insert, // both double- and quad-register. -class N2VDShIns<bit op24, bit op23, bits<6> op21_16, bits<4> op11_8, bit op7, - bit op4, string OpcodeStr, ValueType Ty, SDNode ShOp> - : N2VImm<op24, op23, op21_16, op11_8, op7, 0, op4, - (outs DPR:$dst), (ins DPR:$src1, DPR:$src2, i32imm:$SIMM), - IIC_VSHLiD, +class N2VDShIns<bit op24, bit op23, bits<4> op11_8, bit op7, bit op4, + string OpcodeStr, ValueType Ty, SDNode ShOp> + : N2VImm<op24, op23, op11_8, op7, 0, op4, (outs DPR:$dst), + (ins DPR:$src1, DPR:$src2, i32imm:$SIMM), IIC_VSHLiD, !strconcat(OpcodeStr, "\t$dst, $src2, $SIMM"), "$src1 = $dst", [(set DPR:$dst, (Ty (ShOp DPR:$src1, DPR:$src2, (i32 imm:$SIMM))))]>; -class N2VQShIns<bit op24, bit op23, bits<6> op21_16, bits<4> op11_8, bit op7, - bit op4, string OpcodeStr, ValueType Ty, SDNode ShOp> - : N2VImm<op24, op23, op21_16, op11_8, op7, 1, op4, - (outs QPR:$dst), (ins QPR:$src1, QPR:$src2, i32imm:$SIMM), - IIC_VSHLiQ, +class N2VQShIns<bit op24, bit op23, bits<4> op11_8, bit op7, bit op4, + string OpcodeStr, ValueType Ty, SDNode ShOp> + : N2VImm<op24, op23, op11_8, op7, 1, op4, (outs QPR:$dst), + (ins QPR:$src1, QPR:$src2, i32imm:$SIMM), IIC_VSHLiQ, !strconcat(OpcodeStr, "\t$dst, $src2, $SIMM"), "$src1 = $dst", [(set QPR:$dst, (Ty (ShOp QPR:$src1, QPR:$src2, (i32 imm:$SIMM))))]>; // Convert, with fractional bits immediate, // both double- and quad-register. -class N2VCvtD<bit op24, bit op23, bits<6> op21_16, bits<4> op11_8, bit op7, - bit op4, string OpcodeStr, ValueType ResTy, ValueType OpTy, +class N2VCvtD<bit op24, bit op23, bits<4> op11_8, bit op7, bit op4, + string OpcodeStr, ValueType ResTy, ValueType OpTy, Intrinsic IntOp> - : N2VImm<op24, op23, op21_16, op11_8, op7, 0, op4, + : N2VImm<op24, op23, op11_8, op7, 0, op4, (outs DPR:$dst), (ins DPR:$src, i32imm:$SIMM), IIC_VUNAD, !strconcat(OpcodeStr, "\t$dst, $src, $SIMM"), "", [(set DPR:$dst, (ResTy (IntOp (OpTy DPR:$src), (i32 imm:$SIMM))))]>; -class N2VCvtQ<bit op24, bit op23, bits<6> op21_16, bits<4> op11_8, bit op7, - bit op4, string OpcodeStr, ValueType ResTy, ValueType OpTy, +class N2VCvtQ<bit op24, bit op23, bits<4> op11_8, bit op7, bit op4, + string OpcodeStr, ValueType ResTy, ValueType OpTy, Intrinsic IntOp> - : N2VImm<op24, op23, op21_16, op11_8, op7, 1, op4, + : N2VImm<op24, op23, op11_8, op7, 1, op4, (outs QPR:$dst), (ins QPR:$src, i32imm:$SIMM), IIC_VUNAQ, !strconcat(OpcodeStr, "\t$dst, $src, $SIMM"), "", [(set QPR:$dst, (ResTy (IntOp (OpTy QPR:$src), (i32 imm:$SIMM))))]>; @@ -1175,14 +1168,14 @@ multiclass N2VNInt_HSD<bits<2> op24_23, bits<2> op21_20, bits<2> op17_16, // Neon Lengthening 2-register vector intrinsic (currently specific to VMOVL). // source operand element sizes of 16, 32 and 64 bits: -multiclass N2VLInt_QHS<bit op24, bit op23, bits<4> op11_8, bit op7, bit op6, - bit op4, string OpcodeStr, Intrinsic IntOp> { - def v8i16 : N2VLInt<op24, op23, 0b001000, op11_8, op7, op6, op4, - IIC_VQUNAiD, !strconcat(OpcodeStr, "8"), v8i16, v8i8, IntOp>; - def v4i32 : N2VLInt<op24, op23, 0b010000, op11_8, op7, op6, op4, - IIC_VQUNAiD, !strconcat(OpcodeStr, "16"), v4i32, v4i16, IntOp>; - def v2i64 : N2VLInt<op24, op23, 0b100000, op11_8, op7, op6, op4, - IIC_VQUNAiD, !strconcat(OpcodeStr, "32"), v2i64, v2i32, IntOp>; +multiclass N2VLInt_QHS<bits<2> op24_23, bits<5> op11_7, bit op6, bit op4, + string OpcodeStr, Intrinsic IntOp> { + def v8i16 : N2VLInt<op24_23, 0b00, 0b10, 0b00, op11_7, op6, op4, IIC_VQUNAiD, + !strconcat(OpcodeStr, "8"), v8i16, v8i8, IntOp>; + def v4i32 : N2VLInt<op24_23, 0b01, 0b00, 0b00, op11_7, op6, op4, IIC_VQUNAiD, + !strconcat(OpcodeStr, "16"), v4i32, v4i16, IntOp>; + def v2i64 : N2VLInt<op24_23, 0b10, 0b00, 0b00, op11_7, op6, op4, IIC_VQUNAiD, + !strconcat(OpcodeStr, "32"), v2i64, v2i32, IntOp>; } @@ -1381,7 +1374,7 @@ multiclass N3VLInt3SL_HS<bit op24, bits<4> op11_8, multiclass N3VLInt3_QHS<bit op24, bit op23, bits<4> op11_8, bit op4, string OpcodeStr, Intrinsic IntOp> : N3VLInt3_HS<op24, op23, op11_8, op4, OpcodeStr, IntOp> { - def v8i16 : N3VLInt3<op24, op23, 0b01, op11_8, op4, IIC_VMACi16D, + def v8i16 : N3VLInt3<op24, op23, 0b00, op11_8, op4, IIC_VMACi16D, !strconcat(OpcodeStr, "8"), v8i16, v8i8, IntOp>; } @@ -1461,24 +1454,38 @@ multiclass N2VPLInt2_QHS<bits<2> op24_23, bits<2> op21_20, bits<2> op17_16, multiclass N2VSh_QHSD<bit op24, bit op23, bits<4> op11_8, bit op4, InstrItinClass itin, string OpcodeStr, SDNode OpNode> { // 64-bit vector types. - def v8i8 : N2VDSh<op24, op23, 0b001000, op11_8, 0, op4, itin, - !strconcat(OpcodeStr, "8"), v8i8, OpNode>; - def v4i16 : N2VDSh<op24, op23, 0b010000, op11_8, 0, op4, itin, - !strconcat(OpcodeStr, "16"), v4i16, OpNode>; - def v2i32 : N2VDSh<op24, op23, 0b100000, op11_8, 0, op4, itin, - !strconcat(OpcodeStr, "32"), v2i32, OpNode>; - def v1i64 : N2VDSh<op24, op23, 0b000000, op11_8, 1, op4, itin, + def v8i8 : N2VDSh<op24, op23, op11_8, 0, op4, itin, + !strconcat(OpcodeStr, "8"), v8i8, OpNode> { + let Inst{21-19} = 0b001; // imm6 = 001xxx + } + def v4i16 : N2VDSh<op24, op23, op11_8, 0, op4, itin, + !strconcat(OpcodeStr, "16"), v4i16, OpNode> { + let Inst{21-20} = 0b01; // imm6 = 01xxxx + } + def v2i32 : N2VDSh<op24, op23, op11_8, 0, op4, itin, + !strconcat(OpcodeStr, "32"), v2i32, OpNode> { + let Inst{21} = 0b1; // imm6 = 1xxxxx + } + def v1i64 : N2VDSh<op24, op23, op11_8, 1, op4, itin, !strconcat(OpcodeStr, "64"), v1i64, OpNode>; + // imm6 = xxxxxx // 128-bit vector types. - def v16i8 : N2VQSh<op24, op23, 0b001000, op11_8, 0, op4, itin, - !strconcat(OpcodeStr, "8"), v16i8, OpNode>; - def v8i16 : N2VQSh<op24, op23, 0b010000, op11_8, 0, op4, itin, - !strconcat(OpcodeStr, "16"), v8i16, OpNode>; - def v4i32 : N2VQSh<op24, op23, 0b100000, op11_8, 0, op4, itin, - !strconcat(OpcodeStr, "32"), v4i32, OpNode>; - def v2i64 : N2VQSh<op24, op23, 0b000000, op11_8, 1, op4, itin, + def v16i8 : N2VQSh<op24, op23, op11_8, 0, op4, itin, + !strconcat(OpcodeStr, "8"), v16i8, OpNode> { + let Inst{21-19} = 0b001; // imm6 = 001xxx + } + def v8i16 : N2VQSh<op24, op23, op11_8, 0, op4, itin, + !strconcat(OpcodeStr, "16"), v8i16, OpNode> { + let Inst{21-20} = 0b01; // imm6 = 01xxxx + } + def v4i32 : N2VQSh<op24, op23, op11_8, 0, op4, itin, + !strconcat(OpcodeStr, "32"), v4i32, OpNode> { + let Inst{21} = 0b1; // imm6 = 1xxxxx + } + def v2i64 : N2VQSh<op24, op23, op11_8, 1, op4, itin, !strconcat(OpcodeStr, "64"), v2i64, OpNode>; + // imm6 = xxxxxx } @@ -1487,24 +1494,38 @@ multiclass N2VSh_QHSD<bit op24, bit op23, bits<4> op11_8, bit op4, multiclass N2VShAdd_QHSD<bit op24, bit op23, bits<4> op11_8, bit op4, string OpcodeStr, SDNode ShOp> { // 64-bit vector types. - def v8i8 : N2VDShAdd<op24, op23, 0b001000, op11_8, 0, op4, - !strconcat(OpcodeStr, "8"), v8i8, ShOp>; - def v4i16 : N2VDShAdd<op24, op23, 0b010000, op11_8, 0, op4, - !strconcat(OpcodeStr, "16"), v4i16, ShOp>; - def v2i32 : N2VDShAdd<op24, op23, 0b100000, op11_8, 0, op4, - !strconcat(OpcodeStr, "32"), v2i32, ShOp>; - def v1i64 : N2VDShAdd<op24, op23, 0b000000, op11_8, 1, op4, + def v8i8 : N2VDShAdd<op24, op23, op11_8, 0, op4, + !strconcat(OpcodeStr, "8"), v8i8, ShOp> { + let Inst{21-19} = 0b001; // imm6 = 001xxx + } + def v4i16 : N2VDShAdd<op24, op23, op11_8, 0, op4, + !strconcat(OpcodeStr, "16"), v4i16, ShOp> { + let Inst{21-20} = 0b01; // imm6 = 01xxxx + } + def v2i32 : N2VDShAdd<op24, op23, op11_8, 0, op4, + !strconcat(OpcodeStr, "32"), v2i32, ShOp> { + let Inst{21} = 0b1; // imm6 = 1xxxxx + } + def v1i64 : N2VDShAdd<op24, op23, op11_8, 1, op4, !strconcat(OpcodeStr, "64"), v1i64, ShOp>; + // imm6 = xxxxxx // 128-bit vector types. - def v16i8 : N2VQShAdd<op24, op23, 0b001000, op11_8, 0, op4, - !strconcat(OpcodeStr, "8"), v16i8, ShOp>; - def v8i16 : N2VQShAdd<op24, op23, 0b010000, op11_8, 0, op4, - !strconcat(OpcodeStr, "16"), v8i16, ShOp>; - def v4i32 : N2VQShAdd<op24, op23, 0b100000, op11_8, 0, op4, - !strconcat(OpcodeStr, "32"), v4i32, ShOp>; - def v2i64 : N2VQShAdd<op24, op23, 0b000000, op11_8, 1, op4, + def v16i8 : N2VQShAdd<op24, op23, op11_8, 0, op4, + !strconcat(OpcodeStr, "8"), v16i8, ShOp> { + let Inst{21-19} = 0b001; // imm6 = 001xxx + } + def v8i16 : N2VQShAdd<op24, op23, op11_8, 0, op4, + !strconcat(OpcodeStr, "16"), v8i16, ShOp> { + let Inst{21-20} = 0b01; // imm6 = 01xxxx + } + def v4i32 : N2VQShAdd<op24, op23, op11_8, 0, op4, + !strconcat(OpcodeStr, "32"), v4i32, ShOp> { + let Inst{21} = 0b1; // imm6 = 1xxxxx + } + def v2i64 : N2VQShAdd<op24, op23, op11_8, 1, op4, !strconcat(OpcodeStr, "64"), v2i64, ShOp>; + // imm6 = xxxxxx } @@ -1513,24 +1534,75 @@ multiclass N2VShAdd_QHSD<bit op24, bit op23, bits<4> op11_8, bit op4, multiclass N2VShIns_QHSD<bit op24, bit op23, bits<4> op11_8, bit op4, string OpcodeStr, SDNode ShOp> { // 64-bit vector types. - def v8i8 : N2VDShIns<op24, op23, 0b001000, op11_8, 0, op4, - !strconcat(OpcodeStr, "8"), v8i8, ShOp>; - def v4i16 : N2VDShIns<op24, op23, 0b010000, op11_8, 0, op4, - !strconcat(OpcodeStr, "16"), v4i16, ShOp>; - def v2i32 : N2VDShIns<op24, op23, 0b100000, op11_8, 0, op4, - !strconcat(OpcodeStr, "32"), v2i32, ShOp>; - def v1i64 : N2VDShIns<op24, op23, 0b000000, op11_8, 1, op4, + def v8i8 : N2VDShIns<op24, op23, op11_8, 0, op4, + !strconcat(OpcodeStr, "8"), v8i8, ShOp> { + let Inst{21-19} = 0b001; // imm6 = 001xxx + } + def v4i16 : N2VDShIns<op24, op23, op11_8, 0, op4, + !strconcat(OpcodeStr, "16"), v4i16, ShOp> { + let Inst{21-20} = 0b01; // imm6 = 01xxxx + } + def v2i32 : N2VDShIns<op24, op23, op11_8, 0, op4, + !strconcat(OpcodeStr, "32"), v2i32, ShOp> { + let Inst{21} = 0b1; // imm6 = 1xxxxx + } + def v1i64 : N2VDShIns<op24, op23, op11_8, 1, op4, !strconcat(OpcodeStr, "64"), v1i64, ShOp>; + // imm6 = xxxxxx // 128-bit vector types. - def v16i8 : N2VQShIns<op24, op23, 0b001000, op11_8, 0, op4, - !strconcat(OpcodeStr, "8"), v16i8, ShOp>; - def v8i16 : N2VQShIns<op24, op23, 0b010000, op11_8, 0, op4, - !strconcat(OpcodeStr, "16"), v8i16, ShOp>; - def v4i32 : N2VQShIns<op24, op23, 0b100000, op11_8, 0, op4, - !strconcat(OpcodeStr, "32"), v4i32, ShOp>; - def v2i64 : N2VQShIns<op24, op23, 0b000000, op11_8, 1, op4, + def v16i8 : N2VQShIns<op24, op23, op11_8, 0, op4, + !strconcat(OpcodeStr, "8"), v16i8, ShOp> { + let Inst{21-19} = 0b001; // imm6 = 001xxx + } + def v8i16 : N2VQShIns<op24, op23, op11_8, 0, op4, + !strconcat(OpcodeStr, "16"), v8i16, ShOp> { + let Inst{21-20} = 0b01; // imm6 = 01xxxx + } + def v4i32 : N2VQShIns<op24, op23, op11_8, 0, op4, + !strconcat(OpcodeStr, "32"), v4i32, ShOp> { + let Inst{21} = 0b1; // imm6 = 1xxxxx + } + def v2i64 : N2VQShIns<op24, op23, op11_8, 1, op4, !strconcat(OpcodeStr, "64"), v2i64, ShOp>; + // imm6 = xxxxxx +} + +// Neon Shift Long operations, +// element sizes of 8, 16, 32 bits: +multiclass N2VLSh_QHS<bit op24, bit op23, bits<4> op11_8, bit op7, bit op6, + bit op4, string OpcodeStr, SDNode OpNode> { + def v8i16 : N2VLSh<op24, op23, op11_8, op7, op6, op4, + !strconcat(OpcodeStr, "8"), v8i16, v8i8, OpNode> { + let Inst{21-19} = 0b001; // imm6 = 001xxx + } + def v4i32 : N2VLSh<op24, op23, op11_8, op7, op6, op4, + !strconcat(OpcodeStr, "16"), v4i32, v4i16, OpNode> { + let Inst{21-20} = 0b01; // imm6 = 01xxxx + } + def v2i64 : N2VLSh<op24, op23, op11_8, op7, op6, op4, + !strconcat(OpcodeStr, "32"), v2i64, v2i32, OpNode> { + let Inst{21} = 0b1; // imm6 = 1xxxxx + } +} + +// Neon Shift Narrow operations, +// element sizes of 16, 32, 64 bits: +multiclass N2VNSh_HSD<bit op24, bit op23, bits<4> op11_8, bit op7, bit op6, + bit op4, InstrItinClass itin, string OpcodeStr, + SDNode OpNode> { + def v8i8 : N2VNSh<op24, op23, op11_8, op7, op6, op4, itin, + !strconcat(OpcodeStr, "16"), v8i8, v8i16, OpNode> { + let Inst{21-19} = 0b001; // imm6 = 001xxx + } + def v4i16 : N2VNSh<op24, op23, op11_8, op7, op6, op4, itin, + !strconcat(OpcodeStr, "32"), v4i16, v4i32, OpNode> { + let Inst{21-20} = 0b01; // imm6 = 01xxxx + } + def v2i32 : N2VNSh<op24, op23, op11_8, op7, op6, op4, itin, + !strconcat(OpcodeStr, "64"), v2i32, v2i64, OpNode> { + let Inst{21} = 0b1; // imm6 = 1xxxxx + } } //===----------------------------------------------------------------------===// @@ -1903,8 +1975,8 @@ defm VABDLs : N3VLInt_QHS<0,1,0b0111,0, IIC_VBINi4Q, "vabdl.s", int_arm_neon_v defm VABDLu : N3VLInt_QHS<1,1,0b0111,0, IIC_VBINi4Q, "vabdl.u", int_arm_neon_vabdlu, 0>; // VABA : Vector Absolute Difference and Accumulate -defm VABAs : N3VInt3_QHS<0,1,0b0101,0, "vaba.s", int_arm_neon_vabas>; -defm VABAu : N3VInt3_QHS<1,1,0b0101,0, "vaba.u", int_arm_neon_vabau>; +defm VABAs : N3VInt3_QHS<0,0,0b0111,1, "vaba.s", int_arm_neon_vabas>; +defm VABAu : N3VInt3_QHS<1,0,0b0111,1, "vaba.u", int_arm_neon_vabau>; // VABAL : Vector Absolute Difference and Accumulate Long (Q += | D - D |) defm VABALs : N3VLInt3_QHS<0,1,0b0101,0, "vabal.s", int_arm_neon_vabals>; @@ -2044,34 +2116,25 @@ defm VSHRs : N2VSh_QHSD<0, 1, 0b0000, 1, IIC_VSHLiD, "vshr.s", NEONvshrs>; defm VSHRu : N2VSh_QHSD<1, 1, 0b0000, 1, IIC_VSHLiD, "vshr.u", NEONvshru>; // VSHLL : Vector Shift Left Long -def VSHLLs8 : N2VLSh<0, 1, 0b001000, 0b1010, 0, 0, 1, "vshll.s8", - v8i16, v8i8, NEONvshlls>; -def VSHLLs16 : N2VLSh<0, 1, 0b010000, 0b1010, 0, 0, 1, "vshll.s16", - v4i32, v4i16, NEONvshlls>; -def VSHLLs32 : N2VLSh<0, 1, 0b100000, 0b1010, 0, 0, 1, "vshll.s32", - v2i64, v2i32, NEONvshlls>; -def VSHLLu8 : N2VLSh<1, 1, 0b001000, 0b1010, 0, 0, 1, "vshll.u8", - v8i16, v8i8, NEONvshllu>; -def VSHLLu16 : N2VLSh<1, 1, 0b010000, 0b1010, 0, 0, 1, "vshll.u16", - v4i32, v4i16, NEONvshllu>; -def VSHLLu32 : N2VLSh<1, 1, 0b100000, 0b1010, 0, 0, 1, "vshll.u32", - v2i64, v2i32, NEONvshllu>; +defm VSHLLs : N2VLSh_QHS<0, 1, 0b1010, 0, 0, 1, "vshll.s", NEONvshlls>; +defm VSHLLu : N2VLSh_QHS<1, 1, 0b1010, 0, 0, 1, "vshll.u", NEONvshllu>; // VSHLL : Vector Shift Left Long (with maximum shift count) -def VSHLLi8 : N2VLSh<1, 1, 0b110010, 0b0011, 0, 0, 0, "vshll.i8", - v8i16, v8i8, NEONvshlli>; -def VSHLLi16 : N2VLSh<1, 1, 0b110110, 0b0011, 0, 0, 0, "vshll.i16", - v4i32, v4i16, NEONvshlli>; -def VSHLLi32 : N2VLSh<1, 1, 0b111010, 0b0011, 0, 0, 0, "vshll.i32", - v2i64, v2i32, NEONvshlli>; +class N2VLShMax<bit op24, bit op23, bits<6> op21_16, bits<4> op11_8, bit op7, + bit op6, bit op4, string OpcodeStr, ValueType ResTy, + ValueType OpTy, SDNode OpNode> + : N2VLSh<op24, op23, op11_8, op7, op6, op4, OpcodeStr, ResTy, OpTy, OpNode> { + let Inst{21-16} = op21_16; +} +def VSHLLi8 : N2VLShMax<1, 1, 0b110010, 0b0011, 0, 0, 0, "vshll.i8", + v8i16, v8i8, NEONvshlli>; +def VSHLLi16 : N2VLShMax<1, 1, 0b110110, 0b0011, 0, 0, 0, "vshll.i16", + v4i32, v4i16, NEONvshlli>; +def VSHLLi32 : N2VLShMax<1, 1, 0b111010, 0b0011, 0, 0, 0, "vshll.i32", + v2i64, v2i32, NEONvshlli>; // VSHRN : Vector Shift Right and Narrow -def VSHRN16 : N2VNSh<0, 1, 0b001000, 0b1000, 0, 0, 1, - IIC_VSHLiD, "vshrn.i16", v8i8, v8i16, NEONvshrn>; -def VSHRN32 : N2VNSh<0, 1, 0b010000, 0b1000, 0, 0, 1, - IIC_VSHLiD, "vshrn.i32", v4i16, v4i32, NEONvshrn>; -def VSHRN64 : N2VNSh<0, 1, 0b100000, 0b1000, 0, 0, 1, - IIC_VSHLiD, "vshrn.i64", v2i32, v2i64, NEONvshrn>; +defm VSHRN : N2VNSh_HSD<0,1,0b1000,0,0,1, IIC_VSHLiD, "vshrn.i", NEONvshrn>; // VRSHL : Vector Rounding Shift defm VRSHLs : N3VInt_QHSD<0,0,0b0101,0, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, @@ -2083,12 +2146,8 @@ defm VRSHRs : N2VSh_QHSD<0, 1, 0b0010, 1, IIC_VSHLi4D, "vrshr.s", NEONvrshrs>; defm VRSHRu : N2VSh_QHSD<1, 1, 0b0010, 1, IIC_VSHLi4D, "vrshr.u", NEONvrshru>; // VRSHRN : Vector Rounding Shift Right and Narrow -def VRSHRN16 : N2VNSh<0, 1, 0b001000, 0b1000, 0, 1, 1, - IIC_VSHLi4D, "vrshrn.i16", v8i8, v8i16, NEONvrshrn>; -def VRSHRN32 : N2VNSh<0, 1, 0b010000, 0b1000, 0, 1, 1, - IIC_VSHLi4D, "vrshrn.i32", v4i16, v4i32, NEONvrshrn>; -def VRSHRN64 : N2VNSh<0, 1, 0b100000, 0b1000, 0, 1, 1, - IIC_VSHLi4D, "vrshrn.i64", v2i32, v2i64, NEONvrshrn>; +defm VRSHRN : N2VNSh_HSD<0, 1, 0b1000, 0, 1, 1, IIC_VSHLi4D, "vrshrn.i", + NEONvrshrn>; // VQSHL : Vector Saturating Shift defm VQSHLs : N3VInt_QHSD<0,0,0b0100,1, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, @@ -2102,26 +2161,14 @@ defm VQSHLui : N2VSh_QHSD<1, 1, 0b0111, 1, IIC_VSHLi4D, "vqshl.u", NEONvqshlu>; defm VQSHLsu : N2VSh_QHSD<1, 1, 0b0110, 1, IIC_VSHLi4D, "vqshlu.s", NEONvqshlsu>; // VQSHRN : Vector Saturating Shift Right and Narrow -def VQSHRNs16 : N2VNSh<0, 1, 0b001000, 0b1001, 0, 0, 1, - IIC_VSHLi4D, "vqshrn.s16", v8i8, v8i16, NEONvqshrns>; -def VQSHRNs32 : N2VNSh<0, 1, 0b010000, 0b1001, 0, 0, 1, - IIC_VSHLi4D, "vqshrn.s32", v4i16, v4i32, NEONvqshrns>; -def VQSHRNs64 : N2VNSh<0, 1, 0b100000, 0b1001, 0, 0, 1, - IIC_VSHLi4D, "vqshrn.s64", v2i32, v2i64, NEONvqshrns>; -def VQSHRNu16 : N2VNSh<1, 1, 0b001000, 0b1001, 0, 0, 1, - IIC_VSHLi4D, "vqshrn.u16", v8i8, v8i16, NEONvqshrnu>; -def VQSHRNu32 : N2VNSh<1, 1, 0b010000, 0b1001, 0, 0, 1, - IIC_VSHLi4D, "vqshrn.u32", v4i16, v4i32, NEONvqshrnu>; -def VQSHRNu64 : N2VNSh<1, 1, 0b100000, 0b1001, 0, 0, 1, - IIC_VSHLi4D, "vqshrn.u64", v2i32, v2i64, NEONvqshrnu>; +defm VQSHRNs : N2VNSh_HSD<0, 1, 0b1001, 0, 0, 1, IIC_VSHLi4D, "vqshrn.s", + NEONvqshrns>; +defm VQSHRNu : N2VNSh_HSD<1, 1, 0b1001, 0, 0, 1, IIC_VSHLi4D, "vqshrn.u", + NEONvqshrnu>; // VQSHRUN : Vector Saturating Shift Right and Narrow (Unsigned) -def VQSHRUN16 : N2VNSh<1, 1, 0b001000, 0b1000, 0, 0, 1, - IIC_VSHLi4D, "vqshrun.s16", v8i8, v8i16, NEONvqshrnsu>; -def VQSHRUN32 : N2VNSh<1, 1, 0b010000, 0b1000, 0, 0, 1, - IIC_VSHLi4D, "vqshrun.s32", v4i16, v4i32, NEONvqshrnsu>; -def VQSHRUN64 : N2VNSh<1, 1, 0b100000, 0b1000, 0, 0, 1, - IIC_VSHLi4D, "vqshrun.s64", v2i32, v2i64, NEONvqshrnsu>; +defm VQSHRUN : N2VNSh_HSD<1, 1, 0b1000, 0, 0, 1, IIC_VSHLi4D, "vqshrun.s", + NEONvqshrnsu>; // VQRSHL : Vector Saturating Rounding Shift defm VQRSHLs : N3VInt_QHSD<0, 0, 0b0101, 1, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, @@ -2130,26 +2177,14 @@ defm VQRSHLu : N3VInt_QHSD<1, 0, 0b0101, 1, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi IIC_VSHLi4Q, "vqrshl.u", int_arm_neon_vqrshiftu, 0>; // VQRSHRN : Vector Saturating Rounding Shift Right and Narrow -def VQRSHRNs16: N2VNSh<0, 1, 0b001000, 0b1001, 0, 1, 1, - IIC_VSHLi4D, "vqrshrn.s16", v8i8, v8i16, NEONvqrshrns>; -def VQRSHRNs32: N2VNSh<0, 1, 0b010000, 0b1001, 0, 1, 1, - IIC_VSHLi4D, "vqrshrn.s32", v4i16, v4i32, NEONvqrshrns>; -def VQRSHRNs64: N2VNSh<0, 1, 0b100000, 0b1001, 0, 1, 1, - IIC_VSHLi4D, "vqrshrn.s64", v2i32, v2i64, NEONvqrshrns>; -def VQRSHRNu16: N2VNSh<1, 1, 0b001000, 0b1001, 0, 1, 1, - IIC_VSHLi4D, "vqrshrn.u16", v8i8, v8i16, NEONvqrshrnu>; -def VQRSHRNu32: N2VNSh<1, 1, 0b010000, 0b1001, 0, 1, 1, - IIC_VSHLi4D, "vqrshrn.u32", v4i16, v4i32, NEONvqrshrnu>; -def VQRSHRNu64: N2VNSh<1, 1, 0b100000, 0b1001, 0, 1, 1, - IIC_VSHLi4D, "vqrshrn.u64", v2i32, v2i64, NEONvqrshrnu>; +defm VQRSHRNs : N2VNSh_HSD<0, 1, 0b1001, 0, 1, 1, IIC_VSHLi4D, "vqrshrn.s", + NEONvqrshrns>; +defm VQRSHRNu : N2VNSh_HSD<1, 1, 0b1001, 0, 1, 1, IIC_VSHLi4D, "vqrshrn.u", + NEONvqrshrnu>; // VQRSHRUN : Vector Saturating Rounding Shift Right and Narrow (Unsigned) -def VQRSHRUN16: N2VNSh<1, 1, 0b001000, 0b1000, 0, 1, 1, - IIC_VSHLi4D, "vqrshrun.s16", v8i8, v8i16, NEONvqrshrnsu>; -def VQRSHRUN32: N2VNSh<1, 1, 0b010000, 0b1000, 0, 1, 1, - IIC_VSHLi4D, "vqrshrun.s32", v4i16, v4i32, NEONvqrshrnsu>; -def VQRSHRUN64: N2VNSh<1, 1, 0b100000, 0b1000, 0, 1, 1, - IIC_VSHLi4D, "vqrshrun.s64", v2i32, v2i64, NEONvqrshrnsu>; +defm VQRSHRUN : N2VNSh_HSD<1, 1, 0b1000, 0, 1, 1, IIC_VSHLi4D, "vqrshrun.s", + NEONvqrshrnsu>; // VSRA : Vector Shift Right and Accumulate defm VSRAs : N2VShAdd_QHSD<0, 1, 0b0001, 1, "vsra.s", NEONvshrs>; @@ -2491,27 +2526,28 @@ def VDUPfq : NVDup<0b11101010, 0b1011, 0b00, (outs QPR:$dst), (ins GPR:$src), // VDUP : Vector Duplicate Lane (from scalar to all elements) -class VDUPLND<bits<2> op19_18, bits<2> op17_16, string OpcodeStr, ValueType Ty> - : N2V<0b11, 0b11, op19_18, op17_16, 0b11000, 0, 0, +class VDUPLND<string OpcodeStr, ValueType Ty> + : N2VDup<0b11, 0b11, 0b11000, 0, 0, (outs DPR:$dst), (ins DPR:$src, nohash_imm:$lane), IIC_VMOVD, !strconcat(OpcodeStr, "\t$dst, $src[$lane]"), "", [(set DPR:$dst, (Ty (NEONvduplane (Ty DPR:$src), imm:$lane)))]>; -class VDUPLNQ<bits<2> op19_18, bits<2> op17_16, string OpcodeStr, - ValueType ResTy, ValueType OpTy> - : N2V<0b11, 0b11, op19_18, op17_16, 0b11000, 1, 0, +class VDUPLNQ<string OpcodeStr, ValueType ResTy, ValueType OpTy> + : N2VDup<0b11, 0b11, 0b11000, 1, 0, (outs QPR:$dst), (ins DPR:$src, nohash_imm:$lane), IIC_VMOVD, !strconcat(OpcodeStr, "\t$dst, $src[$lane]"), "", [(set QPR:$dst, (ResTy (NEONvduplane (OpTy DPR:$src), imm:$lane)))]>; -def VDUPLN8d : VDUPLND<0b00, 0b01, "vdup.8", v8i8>; -def VDUPLN16d : VDUPLND<0b00, 0b10, "vdup.16", v4i16>; -def VDUPLN32d : VDUPLND<0b01, 0b00, "vdup.32", v2i32>; -def VDUPLNfd : VDUPLND<0b01, 0b00, "vdup.32", v2f32>; -def VDUPLN8q : VDUPLNQ<0b00, 0b01, "vdup.8", v16i8, v8i8>; -def VDUPLN16q : VDUPLNQ<0b00, 0b10, "vdup.16", v8i16, v4i16>; -def VDUPLN32q : VDUPLNQ<0b01, 0b00, "vdup.32", v4i32, v2i32>; -def VDUPLNfq : VDUPLNQ<0b01, 0b00, "vdup.32", v4f32, v2f32>; +// Inst{19-16} is partially specified depending on the element size. + +def VDUPLN8d : VDUPLND<"vdup.8", v8i8> { let Inst{16} = 1; } +def VDUPLN16d : VDUPLND<"vdup.16", v4i16> { let Inst{17-16} = 0b10; } +def VDUPLN32d : VDUPLND<"vdup.32", v2i32> { let Inst{18-16} = 0b100; } +def VDUPLNfd : VDUPLND<"vdup.32", v2f32> { let Inst{18-16} = 0b100; } +def VDUPLN8q : VDUPLNQ<"vdup.8", v16i8, v8i8> { let Inst{16} = 1; } +def VDUPLN16q : VDUPLNQ<"vdup.16", v8i16, v4i16> { let Inst{17-16} = 0b10; } +def VDUPLN32q : VDUPLNQ<"vdup.32", v4i32, v2i32> { let Inst{18-16} = 0b100; } +def VDUPLNfq : VDUPLNQ<"vdup.32", v4f32, v2f32> { let Inst{18-16} = 0b100; } def : Pat<(v16i8 (NEONvduplane (v16i8 QPR:$src), imm:$lane)), (v16i8 (VDUPLN8q (v8i8 (EXTRACT_SUBREG QPR:$src, @@ -2530,15 +2566,19 @@ def : Pat<(v4f32 (NEONvduplane (v4f32 QPR:$src), imm:$lane)), (DSubReg_i32_reg imm:$lane))), (SubReg_i32_lane imm:$lane)))>; -def VDUPfdf : N2V<0b11, 0b11, 0b01, 0b00, 0b11000, 0, 0, - (outs DPR:$dst), (ins SPR:$src), - IIC_VMOVD, "vdup.32\t$dst, ${src:lane}", "", - [(set DPR:$dst, (v2f32 (NEONvdup (f32 SPR:$src))))]>; +def VDUPfdf : N2VDup<0b11, 0b11, 0b11000, 0, 0, + (outs DPR:$dst), (ins SPR:$src), + IIC_VMOVD, "vdup.32\t$dst, ${src:lane}", "", + [(set DPR:$dst, (v2f32 (NEONvdup (f32 SPR:$src))))]> { + let Inst{18-16} = 0b100; +} -def VDUPfqf : N2V<0b11, 0b11, 0b01, 0b00, 0b11000, 1, 0, - (outs QPR:$dst), (ins SPR:$src), - IIC_VMOVD, "vdup.32\t$dst, ${src:lane}", "", - [(set QPR:$dst, (v4f32 (NEONvdup (f32 SPR:$src))))]>; +def VDUPfqf : N2VDup<0b11, 0b11, 0b11000, 1, 0, + (outs QPR:$dst), (ins SPR:$src), + IIC_VMOVD, "vdup.32\t$dst, ${src:lane}", "", + [(set QPR:$dst, (v4f32 (NEONvdup (f32 SPR:$src))))]> { + let Inst{18-16} = 0b100; +} def : Pat<(v2i64 (NEONvduplane (v2i64 QPR:$src), imm:$lane)), (INSERT_SUBREG QPR:$src, @@ -2560,8 +2600,8 @@ defm VQMOVNu : N2VNInt_HSD<0b11,0b11,0b10,0b00101,1,0, IIC_VQUNAiD, "vqmovn.u", defm VQMOVNsu : N2VNInt_HSD<0b11,0b11,0b10,0b00100,1,0, IIC_VQUNAiD, "vqmovun.s", int_arm_neon_vqmovnsu>; // VMOVL : Vector Lengthening Move -defm VMOVLs : N2VLInt_QHS<0,1,0b1010,0,0,1, "vmovl.s", int_arm_neon_vmovls>; -defm VMOVLu : N2VLInt_QHS<1,1,0b1010,0,0,1, "vmovl.u", int_arm_neon_vmovlu>; +defm VMOVLs : N2VLInt_QHS<0b01,0b10100,0,1, "vmovl.s", int_arm_neon_vmovls>; +defm VMOVLu : N2VLInt_QHS<0b11,0b10100,0,1, "vmovl.u", int_arm_neon_vmovlu>; // Vector Conversions. @@ -2585,24 +2625,22 @@ def VCVTu2fq : N2VQ<0b11, 0b11, 0b10, 0b11, 0b01101, 0, "vcvt.f32.u32", v4f32, v4i32, uint_to_fp>; // VCVT : Vector Convert Between Floating-Point and Fixed-Point. -// Note: Some of the opcode bits in the following VCVT instructions need to -// be encoded based on the immed values. -def VCVTf2xsd : N2VCvtD<0, 1, 0b000000, 0b1111, 0, 1, "vcvt.s32.f32", +def VCVTf2xsd : N2VCvtD<0, 1, 0b1111, 0, 1, "vcvt.s32.f32", v2i32, v2f32, int_arm_neon_vcvtfp2fxs>; -def VCVTf2xud : N2VCvtD<1, 1, 0b000000, 0b1111, 0, 1, "vcvt.u32.f32", +def VCVTf2xud : N2VCvtD<1, 1, 0b1111, 0, 1, "vcvt.u32.f32", v2i32, v2f32, int_arm_neon_vcvtfp2fxu>; -def VCVTxs2fd : N2VCvtD<0, 1, 0b000000, 0b1110, 0, 1, "vcvt.f32.s32", +def VCVTxs2fd : N2VCvtD<0, 1, 0b1110, 0, 1, "vcvt.f32.s32", v2f32, v2i32, int_arm_neon_vcvtfxs2fp>; -def VCVTxu2fd : N2VCvtD<1, 1, 0b000000, 0b1110, 0, 1, "vcvt.f32.u32", +def VCVTxu2fd : N2VCvtD<1, 1, 0b1110, 0, 1, "vcvt.f32.u32", v2f32, v2i32, int_arm_neon_vcvtfxu2fp>; -def VCVTf2xsq : N2VCvtQ<0, 1, 0b000000, 0b1111, 0, 1, "vcvt.s32.f32", +def VCVTf2xsq : N2VCvtQ<0, 1, 0b1111, 0, 1, "vcvt.s32.f32", v4i32, v4f32, int_arm_neon_vcvtfp2fxs>; -def VCVTf2xuq : N2VCvtQ<1, 1, 0b000000, 0b1111, 0, 1, "vcvt.u32.f32", +def VCVTf2xuq : N2VCvtQ<1, 1, 0b1111, 0, 1, "vcvt.u32.f32", v4i32, v4f32, int_arm_neon_vcvtfp2fxu>; -def VCVTxs2fq : N2VCvtQ<0, 1, 0b000000, 0b1110, 0, 1, "vcvt.f32.s32", +def VCVTxs2fq : N2VCvtQ<0, 1, 0b1110, 0, 1, "vcvt.f32.s32", v4f32, v4i32, int_arm_neon_vcvtfxs2fp>; -def VCVTxu2fq : N2VCvtQ<1, 1, 0b000000, 0b1110, 0, 1, "vcvt.f32.u32", +def VCVTxu2fq : N2VCvtQ<1, 1, 0b1110, 0, 1, "vcvt.f32.u32", v4f32, v4i32, int_arm_neon_vcvtfxu2fp>; // Vector Reverse. @@ -2670,18 +2708,18 @@ def VREV16q8 : VREV16Q<0b00, "vrev16.8", v16i8>; // VEXT : Vector Extract class VEXTd<string OpcodeStr, ValueType Ty> - : N3V<0,1,0b11,0b0000,0,0, (outs DPR:$dst), - (ins DPR:$lhs, DPR:$rhs, i32imm:$index), IIC_VEXTD, - !strconcat(OpcodeStr, "\t$dst, $lhs, $rhs, $index"), "", - [(set DPR:$dst, (Ty (NEONvext (Ty DPR:$lhs), - (Ty DPR:$rhs), imm:$index)))]>; + : N3VImm<0,1,0b11,0,0, (outs DPR:$dst), + (ins DPR:$lhs, DPR:$rhs, i32imm:$index), IIC_VEXTD, + !strconcat(OpcodeStr, "\t$dst, $lhs, $rhs, $index"), "", + [(set DPR:$dst, (Ty (NEONvext (Ty DPR:$lhs), + (Ty DPR:$rhs), imm:$index)))]>; class VEXTq<string OpcodeStr, ValueType Ty> - : N3V<0,1,0b11,0b0000,1,0, (outs QPR:$dst), - (ins QPR:$lhs, QPR:$rhs, i32imm:$index), IIC_VEXTQ, - !strconcat(OpcodeStr, "\t$dst, $lhs, $rhs, $index"), "", - [(set QPR:$dst, (Ty (NEONvext (Ty QPR:$lhs), - (Ty QPR:$rhs), imm:$index)))]>; + : N3VImm<0,1,0b11,1,0, (outs QPR:$dst), + (ins QPR:$lhs, QPR:$rhs, i32imm:$index), IIC_VEXTQ, + !strconcat(OpcodeStr, "\t$dst, $lhs, $rhs, $index"), "", + [(set QPR:$dst, (Ty (NEONvext (Ty QPR:$lhs), + (Ty QPR:$rhs), imm:$index)))]>; def VEXTd8 : VEXTd<"vext.8", v8i8>; def VEXTd16 : VEXTd<"vext.16", v4i16>; diff --git a/lib/Target/ARM/ARMInstrThumb2.td b/lib/Target/ARM/ARMInstrThumb2.td index 0750dcc..2b6fa98 100644 --- a/lib/Target/ARM/ARMInstrThumb2.td +++ b/lib/Target/ARM/ARMInstrThumb2.td @@ -69,6 +69,25 @@ def t2_so_imm_neg : Operand<i32>, return ARM_AM::getT2SOImmVal(-((int)N->getZExtValue())) != -1; }], t2_so_imm_neg_XFORM>; +// Break t2_so_imm's up into two pieces. This handles immediates with up to 16 +// bits set in them. This uses t2_so_imm2part to match and t2_so_imm2part_[12] +// to get the first/second pieces. +def t2_so_imm2part : Operand<i32>, + PatLeaf<(imm), [{ + return ARM_AM::isT2SOImmTwoPartVal((unsigned)N->getZExtValue()); + }]> { +} + +def t2_so_imm2part_1 : SDNodeXForm<imm, [{ + unsigned V = ARM_AM::getT2SOImmTwoPartFirst((unsigned)N->getZExtValue()); + return CurDAG->getTargetConstant(V, MVT::i32); +}]>; + +def t2_so_imm2part_2 : SDNodeXForm<imm, [{ + unsigned V = ARM_AM::getT2SOImmTwoPartSecond((unsigned)N->getZExtValue()); + return CurDAG->getTargetConstant(V, MVT::i32); +}]>; + /// imm1_31 predicate - True if the 32-bit immediate is in the range [1,31]. def imm1_31 : PatLeaf<(i32 imm), [{ return (int32_t)N->getZExtValue() >= 1 && (int32_t)N->getZExtValue() < 32; @@ -666,6 +685,8 @@ def t2MOVTi16 : T2I<(outs GPR:$dst), (ins GPR:$src, i32imm:$imm), IIC_iMOVi, [(set GPR:$dst, (or (and GPR:$src, 0xffff), lo16AllZero:$imm))]>; +def : T2Pat<(or GPR:$src, 0xffff0000), (t2MOVTi16 GPR:$src, 0xffff)>; + //===----------------------------------------------------------------------===// // Extend Instructions. // @@ -1129,6 +1150,20 @@ def t2IT : Thumb2XI<(outs), (ins it_pred:$cc, it_mask:$mask), // Non-Instruction Patterns // +// Two piece so_imms. +def : T2Pat<(or GPR:$LHS, t2_so_imm2part:$RHS), + (t2ORRri (t2ORRri GPR:$LHS, (t2_so_imm2part_1 imm:$RHS)), + (t2_so_imm2part_2 imm:$RHS))>; +def : T2Pat<(xor GPR:$LHS, t2_so_imm2part:$RHS), + (t2EORri (t2EORri GPR:$LHS, (t2_so_imm2part_1 imm:$RHS)), + (t2_so_imm2part_2 imm:$RHS))>; +def : T2Pat<(add GPR:$LHS, t2_so_imm2part:$RHS), + (t2ADDri (t2ADDri GPR:$LHS, (t2_so_imm2part_1 imm:$RHS)), + (t2_so_imm2part_2 imm:$RHS))>; +def : T2Pat<(sub GPR:$LHS, t2_so_imm2part:$RHS), + (t2SUBri (t2SUBri GPR:$LHS, (t2_so_imm2part_1 imm:$RHS)), + (t2_so_imm2part_2 imm:$RHS))>; + // ConstantPool, GlobalAddress, and JumpTable def : T2Pat<(ARMWrapper tglobaladdr :$dst), (t2LEApcrel tglobaladdr :$dst)>; def : T2Pat<(ARMWrapper tconstpool :$dst), (t2LEApcrel tconstpool :$dst)>; diff --git a/lib/Target/ARM/ARMLoadStoreOptimizer.cpp b/lib/Target/ARM/ARMLoadStoreOptimizer.cpp index d2ec9ee..c9b9e84 100644 --- a/lib/Target/ARM/ARMLoadStoreOptimizer.cpp +++ b/lib/Target/ARM/ARMLoadStoreOptimizer.cpp @@ -974,6 +974,9 @@ bool ARMLoadStoreOpt::LoadStoreMultipleOpti(MachineBasicBlock &MBB) { if (Advance) { ++Position; ++MBBI; + if (MBBI == E) + // Reach the end of the block, try merging the memory instructions. + TryMerge = true; } else TryMerge = true; diff --git a/lib/Target/ARM/ARMRegisterInfo.td b/lib/Target/ARM/ARMRegisterInfo.td index 20a7355..e0be784 100644 --- a/lib/Target/ARM/ARMRegisterInfo.td +++ b/lib/Target/ARM/ARMRegisterInfo.td @@ -222,12 +222,9 @@ def tGPR : RegisterClass<"ARM", [i32], 32, [R0, R1, R2, R3, R4, R5, R6, R7]> { iterator allocation_order_begin(const MachineFunction &MF) const; iterator allocation_order_end(const MachineFunction &MF) const; }]; - // FIXME: We are reserving r3 in Thumb mode in case the PEI needs to use it - // to generate large stack offset. Make it available once we have register - // scavenging. let MethodBodies = [{ static const unsigned THUMB_tGPR_AO[] = { - ARM::R0, ARM::R1, ARM::R2, + ARM::R0, ARM::R1, ARM::R2, ARM::R3, ARM::R4, ARM::R5, ARM::R6, ARM::R7 }; // FP is R7, only low registers available. diff --git a/lib/Target/ARM/ARMSubtarget.cpp b/lib/Target/ARM/ARMSubtarget.cpp index cf1ee3f..5af95c3 100644 --- a/lib/Target/ARM/ARMSubtarget.cpp +++ b/lib/Target/ARM/ARMSubtarget.cpp @@ -27,11 +27,11 @@ UseNEONFP("arm-use-neon-fp", cl::init(false), cl::Hidden); ARMSubtarget::ARMSubtarget(const std::string &TT, const std::string &FS, - bool isThumb) + bool isT) : ARMArchVersion(V4T) , ARMFPUType(None) , UseNEONForSinglePrecisionFP(UseNEONFP) - , IsThumb(isThumb) + , IsThumb(isT) , ThumbMode(Thumb1) , PostRAScheduler(false) , IsR9Reserved(ReserveR9) @@ -98,9 +98,13 @@ ARMSubtarget::ARMSubtarget(const std::string &TT, const std::string &FS, if (isTargetDarwin()) IsR9Reserved = ReserveR9 | (ARMArchVersion < V6); + if (!isThumb() || hasThumb2()) + PostRAScheduler = true; + // Set CPU specific features. if (CPUString == "cortex-a8") { - PostRAScheduler = true; + // On Cortex-a8, it's faster to perform some single-precision FP + // operations with NEON instructions. if (UseNEONFP.getPosition() == 0) UseNEONForSinglePrecisionFP = true; } diff --git a/lib/Target/ARM/ARMSubtarget.h b/lib/Target/ARM/ARMSubtarget.h index 7098fd4..7478159 100644 --- a/lib/Target/ARM/ARMSubtarget.h +++ b/lib/Target/ARM/ARMSubtarget.h @@ -126,9 +126,13 @@ protected: const std::string & getCPUString() const { return CPUString; } - /// enablePostRAScheduler - From TargetSubtarget, return true to - /// enable post-RA scheduler. - bool enablePostRAScheduler() const { return PostRAScheduler; } + /// enablePostRAScheduler - True at 'More' optimization except + /// for Thumb1. + bool enablePostRAScheduler(CodeGenOpt::Level OptLevel, + TargetSubtarget::AntiDepBreakMode& mode) const { + mode = TargetSubtarget::ANTIDEP_NONE; + return PostRAScheduler && OptLevel >= CodeGenOpt::Default; + } /// getInstrItins - Return the instruction itineraies based on subtarget /// selection. diff --git a/lib/Target/ARM/ARMTargetMachine.cpp b/lib/Target/ARM/ARMTargetMachine.cpp index 32ddc20..c1da6ce 100644 --- a/lib/Target/ARM/ARMTargetMachine.cpp +++ b/lib/Target/ARM/ARMTargetMachine.cpp @@ -16,7 +16,6 @@ #include "ARM.h" #include "llvm/PassManager.h" #include "llvm/CodeGen/Passes.h" -#include "llvm/Support/CommandLine.h" #include "llvm/Support/FormattedStream.h" #include "llvm/Target/TargetOptions.h" #include "llvm/Target/TargetRegistry.h" diff --git a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp index 7438ea9..403f96c 100644 --- a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp @@ -56,6 +56,14 @@ private: bool ParseDirectiveWord(unsigned Size, SMLoc L); + bool ParseDirectiveThumb(SMLoc L); + + bool ParseDirectiveThumbFunc(SMLoc L); + + bool ParseDirectiveCode(SMLoc L); + + bool ParseDirectiveSyntax(SMLoc L); + // TODO - For now hacked versions of the next two are in here in this file to // allow some parser testing until the table gen versions are implemented. @@ -230,8 +238,8 @@ bool ARMAsmParser::ParseRegister(ARMOperand &Op) { return false; } -// Try to parse a register list. The first token must be a '{' when called -// for now. +// Parse a register list, return false if successful else return true or an +// error. The first token must be a '{' when called. bool ARMAsmParser::ParseRegisterList(ARMOperand &Op) { assert(getLexer().getTok().is(AsmToken::LCurly) && "Token is not an Left Curly Brace"); @@ -277,7 +285,8 @@ bool ARMAsmParser::ParseRegisterList(ARMOperand &Op) { return false; } -// Try to parse an arm memory expression. It must start with a '[' token. +// Parse an arm memory expression, return false if successful else return true +// or an error. The first token must be a '[' when called. // TODO Only preindexing and postindexing addressing are started, unindexed // with option, etc are still to do. bool ARMAsmParser::ParseMemory(ARMOperand &Op) { @@ -374,50 +383,55 @@ bool ARMAsmParser::ParseMemory(ARMOperand &Op) { Writeback = true; getLexer().Lex(); // Eat right bracket token. - const AsmToken &CommaTok = getLexer().getTok(); - if (CommaTok.isNot(AsmToken::Comma)) - return Error(CommaTok.getLoc(), "',' expected"); - getLexer().Lex(); // Eat comma token. - - const AsmToken &NextTok = getLexer().getTok(); - if (NextTok.is(AsmToken::Plus)) - getLexer().Lex(); // Eat plus token. - else if (NextTok.is(AsmToken::Minus)) { - Negative = true; - getLexer().Lex(); // Eat minus token - } - - // See if there is a register following the "[Rn]," we have so far. - const AsmToken &OffsetRegTok = getLexer().getTok(); - int OffsetRegNum = MatchRegisterName(OffsetRegTok.getString()); + int OffsetRegNum = 0; bool OffsetRegShifted = false; enum ShiftType ShiftType; const MCExpr *ShiftAmount; const MCExpr *Offset; - if (OffsetRegNum != -1) { - OffsetIsReg = true; - getLexer().Lex(); // Eat identifier token for the offset register. - // Look for a comma then a shift - const AsmToken &Tok = getLexer().getTok(); - if (Tok.is(AsmToken::Comma)) { - getLexer().Lex(); // Eat comma token. - const AsmToken &Tok = getLexer().getTok(); - if (ParseShift(&ShiftType, ShiftAmount)) - return Error(Tok.getLoc(), "shift expected"); - OffsetRegShifted = true; + const AsmToken &NextTok = getLexer().getTok(); + if (NextTok.isNot(AsmToken::EndOfStatement)) { + if (NextTok.isNot(AsmToken::Comma)) + return Error(NextTok.getLoc(), "',' expected"); + getLexer().Lex(); // Eat comma token. + + const AsmToken &PlusMinusTok = getLexer().getTok(); + if (PlusMinusTok.is(AsmToken::Plus)) + getLexer().Lex(); // Eat plus token. + else if (PlusMinusTok.is(AsmToken::Minus)) { + Negative = true; + getLexer().Lex(); // Eat minus token } - } - else { // "[Rn]," we have so far was not followed by "Rm" - // Look for #offset following the "[Rn]," - const AsmToken &HashTok = getLexer().getTok(); - if (HashTok.isNot(AsmToken::Hash)) - return Error(HashTok.getLoc(), "'#' expected"); - getLexer().Lex(); // Eat hash token. - if (getParser().ParseExpression(Offset)) - return true; + // See if there is a register following the "[Rn]," we have so far. + const AsmToken &OffsetRegTok = getLexer().getTok(); + OffsetRegNum = MatchRegisterName(OffsetRegTok.getString()); + if (OffsetRegNum != -1) { + OffsetIsReg = true; + getLexer().Lex(); // Eat identifier token for the offset register. + // Look for a comma then a shift + const AsmToken &Tok = getLexer().getTok(); + if (Tok.is(AsmToken::Comma)) { + getLexer().Lex(); // Eat comma token. + + const AsmToken &Tok = getLexer().getTok(); + if (ParseShift(&ShiftType, ShiftAmount)) + return Error(Tok.getLoc(), "shift expected"); + OffsetRegShifted = true; + } + } + else { // "[Rn]," we have so far was not followed by "Rm" + // Look for #offset following the "[Rn]," + const AsmToken &HashTok = getLexer().getTok(); + if (HashTok.isNot(AsmToken::Hash)) + return Error(HashTok.getLoc(), "'#' expected"); + getLexer().Lex(); // Eat hash token. + + if (getParser().ParseExpression(Offset)) + return true; + } } + Op = ARMOperand::CreateMem(BaseRegNum, OffsetIsReg, Offset, OffsetRegNum, OffsetRegShifted, ShiftType, ShiftAmount, Preindexed, Postindexed, Negative, Writeback); @@ -465,7 +479,7 @@ bool ARMAsmParser::ParseShift(ShiftType *St, const MCExpr *&ShiftAmount) { return false; } -// A hack to allow some testing +// A hack to allow some testing, to be replaced by a real table gen version. int ARMAsmParser::MatchRegisterName(const StringRef &Name) { if (Name == "r0" || Name == "R0") return 0; @@ -504,7 +518,7 @@ int ARMAsmParser::MatchRegisterName(const StringRef &Name) { return -1; } -// A hack to allow some testing +// A hack to allow some testing, to be replaced by a real table gen version. bool ARMAsmParser::MatchInstruction(SmallVectorImpl<ARMOperand> &Operands, MCInst &Inst) { struct ARMOperand Op0 = Operands[0]; @@ -516,40 +530,58 @@ bool ARMAsmParser::MatchInstruction(SmallVectorImpl<ARMOperand> &Operands, Mnemonic == "ldmfd" || Mnemonic == "ldr" || Mnemonic == "mov" || - Mnemonic == "sub") + Mnemonic == "sub" || + Mnemonic == "bl" || + Mnemonic == "push" || + Mnemonic == "blx" || + Mnemonic == "pop") { + // Hard-coded to a valid instruction, till we have a real matcher. + Inst = MCInst(); + Inst.setOpcode(ARM::MOVr); + Inst.addOperand(MCOperand::CreateReg(2)); + Inst.addOperand(MCOperand::CreateReg(2)); + Inst.addOperand(MCOperand::CreateImm(0)); + Inst.addOperand(MCOperand::CreateImm(0)); + Inst.addOperand(MCOperand::CreateReg(0)); return false; + } return true; } -// TODO - this is a work in progress +// Parse a arm instruction operand. For now this parses the operand regardless +// of the mnemonic. bool ARMAsmParser::ParseOperand(ARMOperand &Op) { switch (getLexer().getKind()) { case AsmToken::Identifier: if (!ParseRegister(Op)) return false; - // TODO parse other operands that start with an identifier like labels - return Error(getLexer().getTok().getLoc(), "labels not yet supported"); + // This was not a register so parse other operands that start with an + // identifier (like labels) as expressions and create them as immediates. + const MCExpr *IdVal; + if (getParser().ParseExpression(IdVal)) + return true; + Op = ARMOperand::CreateImm(IdVal); + return false; case AsmToken::LBrac: - if (!ParseMemory(Op)) - return false; + return ParseMemory(Op); case AsmToken::LCurly: - if (!ParseRegisterList(Op)) - return false; + return ParseRegisterList(Op); case AsmToken::Hash: // #42 -> immediate. // TODO: ":lower16:" and ":upper16:" modifiers after # before immediate getLexer().Lex(); - const MCExpr *Val; - if (getParser().ParseExpression(Val)) + const MCExpr *ImmVal; + if (getParser().ParseExpression(ImmVal)) return true; - Op = ARMOperand::CreateImm(Val); + Op = ARMOperand::CreateImm(ImmVal); return false; default: return Error(getLexer().getTok().getLoc(), "unexpected token in operand"); } } +// Parse an arm instruction mnemonic followed by its operands. bool ARMAsmParser::ParseInstruction(const StringRef &Name, MCInst &Inst) { SmallVector<ARMOperand, 7> Operands; @@ -579,10 +611,19 @@ bool ARMAsmParser::ParseInstruction(const StringRef &Name, MCInst &Inst) { return true; } +/// ParseDirective parses the arm specific directives bool ARMAsmParser::ParseDirective(AsmToken DirectiveID) { StringRef IDVal = DirectiveID.getIdentifier(); if (IDVal == ".word") return ParseDirectiveWord(4, DirectiveID.getLoc()); + else if (IDVal == ".thumb") + return ParseDirectiveThumb(DirectiveID.getLoc()); + else if (IDVal == ".thumb_func") + return ParseDirectiveThumbFunc(DirectiveID.getLoc()); + else if (IDVal == ".code") + return ParseDirectiveCode(DirectiveID.getLoc()); + else if (IDVal == ".syntax") + return ParseDirectiveSyntax(DirectiveID.getLoc()); return true; } @@ -611,6 +652,93 @@ bool ARMAsmParser::ParseDirectiveWord(unsigned Size, SMLoc L) { return false; } +/// ParseDirectiveThumb +/// ::= .thumb +bool ARMAsmParser::ParseDirectiveThumb(SMLoc L) { + if (getLexer().isNot(AsmToken::EndOfStatement)) + return Error(L, "unexpected token in directive"); + getLexer().Lex(); + + // TODO: set thumb mode + // TODO: tell the MC streamer the mode + // getParser().getStreamer().Emit???(); + return false; +} + +/// ParseDirectiveThumbFunc +/// ::= .thumbfunc symbol_name +bool ARMAsmParser::ParseDirectiveThumbFunc(SMLoc L) { + const AsmToken &Tok = getLexer().getTok(); + if (Tok.isNot(AsmToken::Identifier) && Tok.isNot(AsmToken::String)) + return Error(L, "unexpected token in .syntax directive"); + StringRef SymbolName = getLexer().getTok().getIdentifier(); + getLexer().Lex(); // Consume the identifier token. + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return Error(L, "unexpected token in directive"); + getLexer().Lex(); + + // TODO: mark symbol as a thumb symbol + // getParser().getStreamer().Emit???(); + return false; +} + +/// ParseDirectiveSyntax +/// ::= .syntax unified | divided +bool ARMAsmParser::ParseDirectiveSyntax(SMLoc L) { + const AsmToken &Tok = getLexer().getTok(); + if (Tok.isNot(AsmToken::Identifier)) + return Error(L, "unexpected token in .syntax directive"); + const StringRef &Mode = Tok.getString(); + bool unified_syntax; + if (Mode == "unified" || Mode == "UNIFIED") { + getLexer().Lex(); + unified_syntax = true; + } + else if (Mode == "divided" || Mode == "DIVIDED") { + getLexer().Lex(); + unified_syntax = false; + } + else + return Error(L, "unrecognized syntax mode in .syntax directive"); + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return Error(getLexer().getTok().getLoc(), "unexpected token in directive"); + getLexer().Lex(); + + // TODO tell the MC streamer the mode + // getParser().getStreamer().Emit???(); + return false; +} + +/// ParseDirectiveCode +/// ::= .code 16 | 32 +bool ARMAsmParser::ParseDirectiveCode(SMLoc L) { + const AsmToken &Tok = getLexer().getTok(); + if (Tok.isNot(AsmToken::Integer)) + return Error(L, "unexpected token in .code directive"); + int64_t Val = getLexer().getTok().getIntVal(); + bool thumb_mode; + if (Val == 16) { + getLexer().Lex(); + thumb_mode = true; + } + else if (Val == 32) { + getLexer().Lex(); + thumb_mode = false; + } + else + return Error(L, "invalid operand to .code directive"); + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return Error(getLexer().getTok().getLoc(), "unexpected token in directive"); + getLexer().Lex(); + + // TODO tell the MC streamer the mode + // getParser().getStreamer().Emit???(); + return false; +} + // Force static initialization. extern "C" void LLVMInitializeARMAsmParser() { RegisterAsmParser<ARMAsmParser> X(TheARMTarget); diff --git a/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp b/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp index 546731b..8719e4c 100644 --- a/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp +++ b/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp @@ -1,3 +1,5 @@ +//===-- ARMAsmPrinter.cpp - Print machine code to an ARM .s file ----------===// +// // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source @@ -13,21 +15,25 @@ #define DEBUG_TYPE "asm-printer" #include "ARM.h" #include "ARMBuildAttrs.h" -#include "ARMTargetMachine.h" #include "ARMAddressingModes.h" #include "ARMConstantPoolValue.h" +#include "ARMInstPrinter.h" #include "ARMMachineFunctionInfo.h" +#include "ARMMCInstLower.h" +#include "ARMTargetMachine.h" #include "llvm/Constants.h" #include "llvm/Module.h" #include "llvm/Assembly/Writer.h" #include "llvm/CodeGen/AsmPrinter.h" #include "llvm/CodeGen/DwarfWriter.h" -#include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/CodeGen/MachineModuleInfoImpls.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineJumpTableInfo.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCInst.h" #include "llvm/MC/MCSectionMachO.h" #include "llvm/MC/MCStreamer.h" -#include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCSymbol.h" #include "llvm/Target/TargetData.h" #include "llvm/Target/TargetLoweringObjectFile.h" @@ -38,18 +44,22 @@ #include "llvm/ADT/SmallString.h" #include "llvm/ADT/Statistic.h" #include "llvm/ADT/StringSet.h" -#include "llvm/Support/Compiler.h" +#include "llvm/Support/CommandLine.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/FormattedStream.h" #include "llvm/Support/Mangler.h" #include "llvm/Support/MathExtras.h" -#include "llvm/Support/FormattedStream.h" #include <cctype> using namespace llvm; STATISTIC(EmittedInsts, "Number of machine instrs printed"); +static cl::opt<bool> +EnableMCInst("enable-arm-mcinst-printer", cl::Hidden, + cl::desc("enable experimental asmprinter gunk in the arm backend")); + namespace { - class VISIBILITY_HIDDEN ARMAsmPrinter : public AsmPrinter { + class ARMAsmPrinter : public AsmPrinter { /// Subtarget - Keep a pointer to the ARMSubtarget around so that we can /// make the right decision when printing asm code for different targets. @@ -63,34 +73,23 @@ namespace { /// MachineFunction. const MachineConstantPool *MCP; - /// 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; - - /// GVNonLazyPtrs - Keeps the set of GlobalValues that require - /// non-lazy-pointers for indirect access. - StringMap<std::string> GVNonLazyPtrs; - - /// HiddenGVNonLazyPtrs - Keeps the set of GlobalValues with hidden - /// visibility that require non-lazy-pointers for indirect access. - StringMap<std::string> HiddenGVNonLazyPtrs; - - /// True if asm printer is printing a series of CONSTPOOL_ENTRY. - bool InCPMode; public: explicit ARMAsmPrinter(formatted_raw_ostream &O, TargetMachine &TM, const MCAsmInfo *T, bool V) - : AsmPrinter(O, TM, T, V), AFI(NULL), MCP(NULL), - InCPMode(false) { + : AsmPrinter(O, TM, T, V), AFI(NULL), MCP(NULL) { Subtarget = &TM.getSubtarget<ARMSubtarget>(); } virtual const char *getPassName() const { return "ARM Assembly Printer"; } + + void printMCInst(const MCInst *MI) { + ARMInstPrinter(O, *MAI, VerboseAsm).printInstruction(MI); + } + + void printInstructionThroughMCStreamer(const MachineInstr *MI); + void printOperand(const MachineInstr *MI, int OpNum, const char *Modifier = 0); @@ -149,8 +148,8 @@ namespace { void printMachineInstruction(const MachineInstr *MI); bool runOnMachineFunction(MachineFunction &F); - bool doFinalization(Module &M); void EmitStartOfAsmFile(Module &M); + void EmitEndOfAsmFile(Module &M); /// EmitMachineConstantPoolValue - Print a machine constantpool value to /// the .s file. @@ -173,12 +172,19 @@ namespace { Name = Mang->getMangledName(GV); else { // FIXME: Remove this when Darwin transition to @GOT like syntax. - std::string SymName = Mang->getMangledName(GV); Name = Mang->getMangledName(GV, "$non_lazy_ptr", true); - if (GV->hasHiddenVisibility()) - HiddenGVNonLazyPtrs[SymName] = Name; - else - GVNonLazyPtrs[SymName] = Name; + MCSymbol *Sym = OutContext.GetOrCreateSymbol(StringRef(Name)); + + MachineModuleInfoMachO &MMIMachO = + MMI->getObjFileInfo<MachineModuleInfoMachO>(); + const MCSymbol *&StubSym = + GV->hasHiddenVisibility() ? MMIMachO.getHiddenGVStubEntry(Sym) : + MMIMachO.getGVStubEntry(Sym); + if (StubSym == 0) { + SmallString<128> NameStr; + Mang->getNameWithPrefix(NameStr, GV, false); + StubSym = OutContext.GetOrCreateSymbol(NameStr.str()); + } } } else Name = Mang->makeNameProper(ACPV->getSymbol()); @@ -260,7 +266,6 @@ bool ARMAsmPrinter::runOnMachineFunction(MachineFunction &MF) { if (Subtarget->isTargetDarwin()) O << "\t" << CurrentFnName; O << "\n"; - InCPMode = false; } else { EmitAlignment(FnAlign, F); } @@ -283,14 +288,13 @@ bool ARMAsmPrinter::runOnMachineFunction(MachineFunction &MF) { for (MachineFunction::const_iterator I = MF.begin(), E = MF.end(); I != E; ++I) { // Print a label for the basic block. - if (I != MF.begin()) { + if (I != MF.begin()) EmitBasicBlockStart(I); - } + + // Print the assembly for the instruction. for (MachineBasicBlock::const_iterator II = I->begin(), E = I->end(); - II != E; ++II) { - // Print the assembly for the instruction. + II != E; ++II) printMachineInstruction(II); - } } if (MAI->hasDotTypeDotSizeDirective()) @@ -306,25 +310,25 @@ void ARMAsmPrinter::printOperand(const MachineInstr *MI, int OpNum, const char *Modifier) { const MachineOperand &MO = MI->getOperand(OpNum); switch (MO.getType()) { + default: + assert(0 && "<unknown operand type>"); case MachineOperand::MO_Register: { unsigned Reg = MO.getReg(); - if (TargetRegisterInfo::isPhysicalRegister(Reg)) { - if (Modifier && strcmp(Modifier, "dregpair") == 0) { - unsigned DRegLo = TRI->getSubReg(Reg, 5); // arm_dsubreg_0 - unsigned DRegHi = TRI->getSubReg(Reg, 6); // arm_dsubreg_1 - O << '{' - << getRegisterName(DRegLo) << ',' << getRegisterName(DRegHi) - << '}'; - } else if (Modifier && strcmp(Modifier, "lane") == 0) { - unsigned RegNum = ARMRegisterInfo::getRegisterNumbering(Reg); - unsigned DReg = TRI->getMatchingSuperReg(Reg, RegNum & 1 ? 2 : 1, - &ARM::DPR_VFP2RegClass); - O << getRegisterName(DReg) << '[' << (RegNum & 1) << ']'; - } else { - O << getRegisterName(Reg); - } - } else - llvm_unreachable("not implemented"); + assert(TargetRegisterInfo::isPhysicalRegister(Reg)); + if (Modifier && strcmp(Modifier, "dregpair") == 0) { + unsigned DRegLo = TRI->getSubReg(Reg, 5); // arm_dsubreg_0 + unsigned DRegHi = TRI->getSubReg(Reg, 6); // arm_dsubreg_1 + O << '{' + << getRegisterName(DRegLo) << ',' << getRegisterName(DRegHi) + << '}'; + } else if (Modifier && strcmp(Modifier, "lane") == 0) { + unsigned RegNum = ARMRegisterInfo::getRegisterNumbering(Reg); + unsigned DReg = TRI->getMatchingSuperReg(Reg, RegNum & 1 ? 2 : 1, + &ARM::DPR_VFP2RegClass); + O << getRegisterName(DReg) << '[' << (RegNum & 1) << ']'; + } else { + O << getRegisterName(Reg); + } break; } case MachineOperand::MO_Immediate: { @@ -372,8 +376,6 @@ void ARMAsmPrinter::printOperand(const MachineInstr *MI, int OpNum, O << MAI->getPrivateGlobalPrefix() << "JTI" << getFunctionNumber() << '_' << MO.getIndex(); break; - default: - O << "<unknown operand type>"; abort (); break; } } @@ -1027,22 +1029,19 @@ bool ARMAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, void ARMAsmPrinter::printMachineInstruction(const MachineInstr *MI) { ++EmittedInsts; - int Opc = MI->getOpcode(); - switch (Opc) { - case ARM::CONSTPOOL_ENTRY: - if (!InCPMode && AFI->isThumbFunction()) { - EmitAlignment(2); - InCPMode = true; - } - break; - default: { - if (InCPMode && AFI->isThumbFunction()) - InCPMode = false; - }} - // Call the autogenerated instruction printer routines. processDebugLoc(MI, true); - printInstruction(MI); + + if (EnableMCInst) { + printInstructionThroughMCStreamer(MI); + } else { + int Opc = MI->getOpcode(); + if (Opc == ARM::CONSTPOOL_ENTRY) + EmitAlignment(2); + + printInstruction(MI); + } + if (VerboseAsm && !MI->getDebugLoc().isUnknown()) EmitComments(*MI); O << '\n'; @@ -1256,34 +1255,40 @@ void ARMAsmPrinter::PrintGlobalVariable(const GlobalVariable* GVar) { } -bool ARMAsmPrinter::doFinalization(Module &M) { +void ARMAsmPrinter::EmitEndOfAsmFile(Module &M) { if (Subtarget->isTargetDarwin()) { // All darwin targets use mach-o. TargetLoweringObjectFileMachO &TLOFMacho = static_cast<TargetLoweringObjectFileMachO &>(getObjFileLowering()); + MachineModuleInfoMachO &MMIMacho = + MMI->getObjFileInfo<MachineModuleInfoMachO>(); O << '\n'; // Output non-lazy-pointers for external and common global variables. - if (!GVNonLazyPtrs.empty()) { + MachineModuleInfoMachO::SymbolListTy Stubs = MMIMacho.GetGVStubList(); + + if (!Stubs.empty()) { // Switch with ".non_lazy_symbol_pointer" directive. OutStreamer.SwitchSection(TLOFMacho.getNonLazySymbolPointerSection()); EmitAlignment(2); - for (StringMap<std::string>::iterator I = GVNonLazyPtrs.begin(), - E = GVNonLazyPtrs.end(); I != E; ++I) { - O << I->second << ":\n"; - O << "\t.indirect_symbol " << I->getKeyData() << "\n"; - O << "\t.long\t0\n"; + for (unsigned i = 0, e = Stubs.size(); i != e; ++i) { + Stubs[i].first->print(O, MAI); + O << ":\n\t.indirect_symbol "; + Stubs[i].second->print(O, MAI); + O << "\n\t.long\t0\n"; } } - if (!HiddenGVNonLazyPtrs.empty()) { + Stubs = MMIMacho.GetHiddenGVStubList(); + if (!Stubs.empty()) { OutStreamer.SwitchSection(getObjFileLowering().getDataSection()); EmitAlignment(2); - for (StringMap<std::string>::iterator I = HiddenGVNonLazyPtrs.begin(), - E = HiddenGVNonLazyPtrs.end(); I != E; ++I) { - O << I->second << ":\n"; - O << "\t.long " << I->getKeyData() << "\n"; + for (unsigned i = 0, e = Stubs.size(); i != e; ++i) { + Stubs[i].first->print(O, MAI); + O << ":\n\t.long "; + Stubs[i].second->print(O, MAI); + O << "\n"; } } @@ -1292,14 +1297,179 @@ bool ARMAsmPrinter::doFinalization(Module &M) { // implementation of multiple entry points). If this doesn't occur, the // linker can safely perform dead code stripping. Since LLVM never // generates code that does this, it is always safe to set. - O << "\t.subsections_via_symbols\n"; + OutStreamer.EmitAssemblerFlag(MCStreamer::SubsectionsViaSymbols); + } +} + +//===----------------------------------------------------------------------===// + +void ARMAsmPrinter::printInstructionThroughMCStreamer(const MachineInstr *MI) { + ARMMCInstLower MCInstLowering(OutContext, *Mang, *this); + switch (MI->getOpcode()) { + case ARM::t2MOVi32imm: + assert(0 && "Should be lowered by thumb2it pass"); + default: break; + case TargetInstrInfo::DBG_LABEL: + case TargetInstrInfo::EH_LABEL: + case TargetInstrInfo::GC_LABEL: + printLabel(MI); + return; + case TargetInstrInfo::KILL: + return; + case TargetInstrInfo::INLINEASM: + O << '\t'; + printInlineAsm(MI); + return; + case TargetInstrInfo::IMPLICIT_DEF: + printImplicitDef(MI); + return; + case ARM::PICADD: { // FIXME: Remove asm string from td file. + // This is a pseudo op for a label + instruction sequence, which looks like: + // LPC0: + // add r0, pc, r0 + // This adds the address of LPC0 to r0. + + // Emit the label. + // FIXME: MOVE TO SHARED PLACE. + unsigned Id = (unsigned)MI->getOperand(2).getImm(); + const char *Prefix = MAI->getPrivateGlobalPrefix(); + MCSymbol *Label =OutContext.GetOrCreateSymbol(Twine(Prefix)+"PC"+Twine(Id)); + OutStreamer.EmitLabel(Label); + + + // Form and emit tha dd. + MCInst AddInst; + AddInst.setOpcode(ARM::ADDrr); + AddInst.addOperand(MCOperand::CreateReg(MI->getOperand(0).getReg())); + AddInst.addOperand(MCOperand::CreateReg(ARM::PC)); + AddInst.addOperand(MCOperand::CreateReg(MI->getOperand(1).getReg())); + printMCInst(&AddInst); + return; + } + case ARM::CONSTPOOL_ENTRY: { // FIXME: Remove asm string from td file. + /// CONSTPOOL_ENTRY - This instruction represents a floating constant pool + /// in the function. The first operand is the ID# for this instruction, the + /// second is the index into the MachineConstantPool that this is, the third + /// is the size in bytes of this constant pool entry. + unsigned LabelId = (unsigned)MI->getOperand(0).getImm(); + unsigned CPIdx = (unsigned)MI->getOperand(1).getIndex(); + + EmitAlignment(2); + + const char *Prefix = MAI->getPrivateGlobalPrefix(); + MCSymbol *Label = OutContext.GetOrCreateSymbol(Twine(Prefix)+"CPI"+ + Twine(getFunctionNumber())+ + "_"+ Twine(LabelId)); + OutStreamer.EmitLabel(Label); + + const MachineConstantPoolEntry &MCPE = MCP->getConstants()[CPIdx]; + if (MCPE.isMachineConstantPoolEntry()) + EmitMachineConstantPoolValue(MCPE.Val.MachineCPVal); + else + EmitGlobalConstant(MCPE.Val.ConstVal); + + return; } + case ARM::MOVi2pieces: { // FIXME: Remove asmstring from td file. + // This is a hack that lowers as a two instruction sequence. + unsigned DstReg = MI->getOperand(0).getReg(); + unsigned ImmVal = (unsigned)MI->getOperand(1).getImm(); + + unsigned SOImmValV1 = ARM_AM::getSOImmTwoPartFirst(ImmVal); + unsigned SOImmValV2 = ARM_AM::getSOImmTwoPartSecond(ImmVal); + + { + MCInst TmpInst; + TmpInst.setOpcode(ARM::MOVi); + TmpInst.addOperand(MCOperand::CreateReg(DstReg)); + TmpInst.addOperand(MCOperand::CreateImm(SOImmValV1)); + + // Predicate. + TmpInst.addOperand(MCOperand::CreateImm(MI->getOperand(2).getImm())); + TmpInst.addOperand(MCOperand::CreateReg(MI->getOperand(3).getReg())); + + TmpInst.addOperand(MCOperand::CreateReg(0)); // cc_out + printMCInst(&TmpInst); + O << '\n'; + } - return AsmPrinter::doFinalization(M); + { + MCInst TmpInst; + TmpInst.setOpcode(ARM::ORRri); + TmpInst.addOperand(MCOperand::CreateReg(DstReg)); // dstreg + TmpInst.addOperand(MCOperand::CreateReg(DstReg)); // inreg + TmpInst.addOperand(MCOperand::CreateImm(SOImmValV2)); // so_imm + // Predicate. + TmpInst.addOperand(MCOperand::CreateImm(MI->getOperand(2).getImm())); + TmpInst.addOperand(MCOperand::CreateReg(MI->getOperand(3).getReg())); + + TmpInst.addOperand(MCOperand::CreateReg(0)); // cc_out + printMCInst(&TmpInst); + } + return; + } + case ARM::MOVi32imm: { // FIXME: Remove asmstring from td file. + // This is a hack that lowers as a two instruction sequence. + unsigned DstReg = MI->getOperand(0).getReg(); + unsigned ImmVal = (unsigned)MI->getOperand(1).getImm(); + + { + MCInst TmpInst; + TmpInst.setOpcode(ARM::MOVi16); + TmpInst.addOperand(MCOperand::CreateReg(DstReg)); // dstreg + TmpInst.addOperand(MCOperand::CreateImm(ImmVal & 65535)); // lower16(imm) + + // Predicate. + TmpInst.addOperand(MCOperand::CreateImm(MI->getOperand(2).getImm())); + TmpInst.addOperand(MCOperand::CreateReg(MI->getOperand(3).getReg())); + + printMCInst(&TmpInst); + O << '\n'; + } + + { + MCInst TmpInst; + TmpInst.setOpcode(ARM::MOVTi16); + TmpInst.addOperand(MCOperand::CreateReg(DstReg)); // dstreg + TmpInst.addOperand(MCOperand::CreateReg(DstReg)); // srcreg + TmpInst.addOperand(MCOperand::CreateImm(ImmVal >> 16)); // upper16(imm) + + // Predicate. + TmpInst.addOperand(MCOperand::CreateImm(MI->getOperand(2).getImm())); + TmpInst.addOperand(MCOperand::CreateReg(MI->getOperand(3).getReg())); + + printMCInst(&TmpInst); + } + + return; + } + } + + MCInst TmpInst; + MCInstLowering.Lower(MI, TmpInst); + + printMCInst(&TmpInst); +} + +//===----------------------------------------------------------------------===// +// Target Registry Stuff +//===----------------------------------------------------------------------===// + +static MCInstPrinter *createARMMCInstPrinter(const Target &T, + unsigned SyntaxVariant, + const MCAsmInfo &MAI, + raw_ostream &O) { + if (SyntaxVariant == 0) + return new ARMInstPrinter(O, MAI, false); + return 0; } // Force static initialization. extern "C" void LLVMInitializeARMAsmPrinter() { RegisterAsmPrinter<ARMAsmPrinter> X(TheARMTarget); RegisterAsmPrinter<ARMAsmPrinter> Y(TheThumbTarget); + + TargetRegistry::RegisterMCInstPrinter(TheARMTarget, createARMMCInstPrinter); + TargetRegistry::RegisterMCInstPrinter(TheThumbTarget, createARMMCInstPrinter); } + diff --git a/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp b/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp new file mode 100644 index 0000000..f422798 --- /dev/null +++ b/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp @@ -0,0 +1,358 @@ +//===-- ARMInstPrinter.cpp - Convert ARM MCInst to assembly syntax --------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This class prints an ARM MCInst to a .s file. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "asm-printer" +#include "ARM.h" // FIXME: FACTOR ENUMS BETTER. +#include "ARMInstPrinter.h" +#include "ARMAddressingModes.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/Support/raw_ostream.h" +using namespace llvm; + +// Include the auto-generated portion of the assembly writer. +#define MachineInstr MCInst +#define ARMAsmPrinter ARMInstPrinter // FIXME: REMOVE. +#define NO_ASM_WRITER_BOILERPLATE +#include "ARMGenAsmWriter.inc" +#undef MachineInstr +#undef ARMAsmPrinter + +void ARMInstPrinter::printInst(const MCInst *MI) { printInstruction(MI); } + +void ARMInstPrinter::printOperand(const MCInst *MI, unsigned OpNo, + const char *Modifier) { + const MCOperand &Op = MI->getOperand(OpNo); + if (Op.isReg()) { + unsigned Reg = Op.getReg(); + if (Modifier && strcmp(Modifier, "dregpair") == 0) { + // FIXME: Breaks e.g. ARM/vmul.ll. + assert(0); + /* + unsigned DRegLo = TRI->getSubReg(Reg, 5); // arm_dsubreg_0 + unsigned DRegHi = TRI->getSubReg(Reg, 6); // arm_dsubreg_1 + O << '{' + << getRegisterName(DRegLo) << ',' << getRegisterName(DRegHi) + << '}';*/ + } else if (Modifier && strcmp(Modifier, "lane") == 0) { + assert(0); + /* + unsigned RegNum = ARMRegisterInfo::getRegisterNumbering(Reg); + unsigned DReg = TRI->getMatchingSuperReg(Reg, RegNum & 1 ? 2 : 1, + &ARM::DPR_VFP2RegClass); + O << getRegisterName(DReg) << '[' << (RegNum & 1) << ']'; + */ + } else { + O << getRegisterName(Reg); + } + } else if (Op.isImm()) { + assert((Modifier == 0 || Modifier[0] == 0) && "No modifiers supported"); + O << '#' << Op.getImm(); + } else { + assert((Modifier == 0 || Modifier[0] == 0) && "No modifiers supported"); + assert(Op.isExpr() && "unknown operand kind in printOperand"); + Op.getExpr()->print(O, &MAI); + } +} + +static void printSOImm(raw_ostream &O, int64_t V, bool VerboseAsm, + const MCAsmInfo *MAI) { + // Break it up into two parts that make up a shifter immediate. + V = ARM_AM::getSOImmVal(V); + assert(V != -1 && "Not a valid so_imm value!"); + + unsigned Imm = ARM_AM::getSOImmValImm(V); + unsigned Rot = ARM_AM::getSOImmValRot(V); + + // Print low-level immediate formation info, per + // A5.1.3: "Data-processing operands - Immediate". + if (Rot) { + O << "#" << Imm << ", " << Rot; + // Pretty printed version. + if (VerboseAsm) + O << ' ' << MAI->getCommentString() + << ' ' << (int)ARM_AM::rotr32(Imm, Rot); + } else { + O << "#" << Imm; + } +} + + +/// printSOImmOperand - SOImm is 4-bit rotate amount in bits 8-11 with 8-bit +/// immediate in bits 0-7. +void ARMInstPrinter::printSOImmOperand(const MCInst *MI, unsigned OpNum) { + const MCOperand &MO = MI->getOperand(OpNum); + assert(MO.isImm() && "Not a valid so_imm value!"); + printSOImm(O, MO.getImm(), VerboseAsm, &MAI); +} + +/// printSOImm2PartOperand - SOImm is broken into two pieces using a 'mov' +/// followed by an 'orr' to materialize. +void ARMInstPrinter::printSOImm2PartOperand(const MCInst *MI, unsigned OpNum) { + // FIXME: REMOVE this method. + abort(); +} + +// so_reg is a 4-operand unit corresponding to register forms of the A5.1 +// "Addressing Mode 1 - Data-processing operands" forms. This includes: +// REG 0 0 - e.g. R5 +// REG REG 0,SH_OPC - e.g. R5, ROR R3 +// REG 0 IMM,SH_OPC - e.g. R5, LSL #3 +void ARMInstPrinter::printSORegOperand(const MCInst *MI, unsigned OpNum) { + const MCOperand &MO1 = MI->getOperand(OpNum); + const MCOperand &MO2 = MI->getOperand(OpNum+1); + const MCOperand &MO3 = MI->getOperand(OpNum+2); + + O << getRegisterName(MO1.getReg()); + + // Print the shift opc. + O << ", " + << ARM_AM::getShiftOpcStr(ARM_AM::getSORegShOp(MO3.getImm())) + << ' '; + + if (MO2.getReg()) { + O << getRegisterName(MO2.getReg()); + assert(ARM_AM::getSORegOffset(MO3.getImm()) == 0); + } else { + O << "#" << ARM_AM::getSORegOffset(MO3.getImm()); + } +} + + +void ARMInstPrinter::printAddrMode2Operand(const MCInst *MI, unsigned Op) { + const MCOperand &MO1 = MI->getOperand(Op); + const MCOperand &MO2 = MI->getOperand(Op+1); + const MCOperand &MO3 = MI->getOperand(Op+2); + + if (!MO1.isReg()) { // FIXME: This is for CP entries, but isn't right. + printOperand(MI, Op); + return; + } + + O << "[" << getRegisterName(MO1.getReg()); + + if (!MO2.getReg()) { + if (ARM_AM::getAM2Offset(MO3.getImm())) // Don't print +0. + O << ", #" + << (char)ARM_AM::getAM2Op(MO3.getImm()) + << ARM_AM::getAM2Offset(MO3.getImm()); + O << "]"; + return; + } + + O << ", " + << (char)ARM_AM::getAM2Op(MO3.getImm()) + << getRegisterName(MO2.getReg()); + + if (unsigned ShImm = ARM_AM::getAM2Offset(MO3.getImm())) + O << ", " + << ARM_AM::getShiftOpcStr(ARM_AM::getAM2ShiftOpc(MO3.getImm())) + << " #" << ShImm; + O << "]"; +} + +void ARMInstPrinter::printAddrMode2OffsetOperand(const MCInst *MI, + unsigned OpNum) { + const MCOperand &MO1 = MI->getOperand(OpNum); + const MCOperand &MO2 = MI->getOperand(OpNum+1); + + if (!MO1.getReg()) { + unsigned ImmOffs = ARM_AM::getAM2Offset(MO2.getImm()); + assert(ImmOffs && "Malformed indexed load / store!"); + O << '#' << (char)ARM_AM::getAM2Op(MO2.getImm()) << ImmOffs; + return; + } + + O << (char)ARM_AM::getAM2Op(MO2.getImm()) << getRegisterName(MO1.getReg()); + + if (unsigned ShImm = ARM_AM::getAM2Offset(MO2.getImm())) + O << ", " + << ARM_AM::getShiftOpcStr(ARM_AM::getAM2ShiftOpc(MO2.getImm())) + << " #" << ShImm; +} + +void ARMInstPrinter::printAddrMode3Operand(const MCInst *MI, unsigned OpNum) { + const MCOperand &MO1 = MI->getOperand(OpNum); + const MCOperand &MO2 = MI->getOperand(OpNum+1); + const MCOperand &MO3 = MI->getOperand(OpNum+2); + + O << '[' << getRegisterName(MO1.getReg()); + + if (MO2.getReg()) { + O << ", " << (char)ARM_AM::getAM3Op(MO3.getImm()) + << getRegisterName(MO2.getReg()) << ']'; + return; + } + + if (unsigned ImmOffs = ARM_AM::getAM3Offset(MO3.getImm())) + O << ", #" + << (char)ARM_AM::getAM3Op(MO3.getImm()) + << ImmOffs; + O << ']'; +} + +void ARMInstPrinter::printAddrMode3OffsetOperand(const MCInst *MI, + unsigned OpNum) { + const MCOperand &MO1 = MI->getOperand(OpNum); + const MCOperand &MO2 = MI->getOperand(OpNum+1); + + if (MO1.getReg()) { + O << (char)ARM_AM::getAM3Op(MO2.getImm()) + << getRegisterName(MO1.getReg()); + return; + } + + unsigned ImmOffs = ARM_AM::getAM3Offset(MO2.getImm()); + assert(ImmOffs && "Malformed indexed load / store!"); + O << "#" + << (char)ARM_AM::getAM3Op(MO2.getImm()) + << ImmOffs; +} + + +void ARMInstPrinter::printAddrMode4Operand(const MCInst *MI, unsigned OpNum, + const char *Modifier) { + const MCOperand &MO1 = MI->getOperand(OpNum); + const MCOperand &MO2 = MI->getOperand(OpNum+1); + ARM_AM::AMSubMode Mode = ARM_AM::getAM4SubMode(MO2.getImm()); + if (Modifier && strcmp(Modifier, "submode") == 0) { + if (MO1.getReg() == ARM::SP) { + // FIXME + bool isLDM = (MI->getOpcode() == ARM::LDM || + MI->getOpcode() == ARM::LDM_RET || + MI->getOpcode() == ARM::t2LDM || + MI->getOpcode() == ARM::t2LDM_RET); + O << ARM_AM::getAMSubModeAltStr(Mode, isLDM); + } else + O << ARM_AM::getAMSubModeStr(Mode); + } else if (Modifier && strcmp(Modifier, "wide") == 0) { + ARM_AM::AMSubMode Mode = ARM_AM::getAM4SubMode(MO2.getImm()); + if (Mode == ARM_AM::ia) + O << ".w"; + } else { + printOperand(MI, OpNum); + if (ARM_AM::getAM4WBFlag(MO2.getImm())) + O << "!"; + } +} + +void ARMInstPrinter::printAddrMode5Operand(const MCInst *MI, unsigned OpNum, + const char *Modifier) { + const MCOperand &MO1 = MI->getOperand(OpNum); + const MCOperand &MO2 = MI->getOperand(OpNum+1); + + if (!MO1.isReg()) { // FIXME: This is for CP entries, but isn't right. + printOperand(MI, OpNum); + return; + } + + if (Modifier && strcmp(Modifier, "submode") == 0) { + ARM_AM::AMSubMode Mode = ARM_AM::getAM5SubMode(MO2.getImm()); + if (MO1.getReg() == ARM::SP) { + bool isFLDM = (MI->getOpcode() == ARM::FLDMD || + MI->getOpcode() == ARM::FLDMS); + O << ARM_AM::getAMSubModeAltStr(Mode, isFLDM); + } else + O << ARM_AM::getAMSubModeStr(Mode); + return; + } else if (Modifier && strcmp(Modifier, "base") == 0) { + // Used for FSTM{D|S} and LSTM{D|S} operations. + O << getRegisterName(MO1.getReg()); + if (ARM_AM::getAM5WBFlag(MO2.getImm())) + O << "!"; + return; + } + + O << "[" << getRegisterName(MO1.getReg()); + + if (unsigned ImmOffs = ARM_AM::getAM5Offset(MO2.getImm())) { + O << ", #" + << (char)ARM_AM::getAM5Op(MO2.getImm()) + << ImmOffs*4; + } + O << "]"; +} + +void ARMInstPrinter::printAddrMode6Operand(const MCInst *MI, unsigned OpNum) { + const MCOperand &MO1 = MI->getOperand(OpNum); + const MCOperand &MO2 = MI->getOperand(OpNum+1); + const MCOperand &MO3 = MI->getOperand(OpNum+2); + + // FIXME: No support yet for specifying alignment. + O << '[' << getRegisterName(MO1.getReg()) << ']'; + + if (ARM_AM::getAM6WBFlag(MO3.getImm())) { + if (MO2.getReg() == 0) + O << '!'; + else + O << ", " << getRegisterName(MO2.getReg()); + } +} + +void ARMInstPrinter::printAddrModePCOperand(const MCInst *MI, unsigned OpNum, + const char *Modifier) { + assert(0 && "FIXME: Implement printAddrModePCOperand"); +} + +void ARMInstPrinter::printBitfieldInvMaskImmOperand (const MCInst *MI, + unsigned OpNum) { + const MCOperand &MO = MI->getOperand(OpNum); + uint32_t v = ~MO.getImm(); + int32_t lsb = CountTrailingZeros_32(v); + int32_t width = (32 - CountLeadingZeros_32 (v)) - lsb; + assert(MO.isImm() && "Not a valid bf_inv_mask_imm value!"); + O << '#' << lsb << ", #" << width; +} + +void ARMInstPrinter::printRegisterList(const MCInst *MI, unsigned OpNum) { + O << "{"; + // Always skip the first operand, it's the optional (and implicit writeback). + for (unsigned i = OpNum+1, e = MI->getNumOperands(); i != e; ++i) { + if (i != OpNum+1) O << ", "; + O << getRegisterName(MI->getOperand(i).getReg()); + } + O << "}"; +} + +void ARMInstPrinter::printPredicateOperand(const MCInst *MI, unsigned OpNum) { + ARMCC::CondCodes CC = (ARMCC::CondCodes)MI->getOperand(OpNum).getImm(); + if (CC != ARMCC::AL) + O << ARMCondCodeToString(CC); +} + +void ARMInstPrinter::printSBitModifierOperand(const MCInst *MI, unsigned OpNum){ + if (MI->getOperand(OpNum).getReg()) { + assert(MI->getOperand(OpNum).getReg() == ARM::CPSR && + "Expect ARM CPSR register!"); + O << 's'; + } +} + + + +void ARMInstPrinter::printCPInstOperand(const MCInst *MI, unsigned OpNum, + const char *Modifier) { + // FIXME: remove this. + abort(); +} + +void ARMInstPrinter::printNoHashImmediate(const MCInst *MI, unsigned OpNum) { + O << MI->getOperand(OpNum).getImm(); +} + + +void ARMInstPrinter::printPCLabel(const MCInst *MI, unsigned OpNum) { + // FIXME: remove this. + abort(); +} diff --git a/lib/Target/ARM/AsmPrinter/ARMInstPrinter.h b/lib/Target/ARM/AsmPrinter/ARMInstPrinter.h new file mode 100644 index 0000000..4925137 --- /dev/null +++ b/lib/Target/ARM/AsmPrinter/ARMInstPrinter.h @@ -0,0 +1,89 @@ +//===-- ARMInstPrinter.h - Convert ARM MCInst to assembly syntax ----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This class prints an ARM MCInst to a .s file. +// +//===----------------------------------------------------------------------===// + +#ifndef ARMINSTPRINTER_H +#define ARMINSTPRINTER_H + +#include "llvm/MC/MCInstPrinter.h" + +namespace llvm { + class MCOperand; + +class ARMInstPrinter : public MCInstPrinter { + bool VerboseAsm; +public: + ARMInstPrinter(raw_ostream &O, const MCAsmInfo &MAI, bool verboseAsm) + : MCInstPrinter(O, MAI), VerboseAsm(verboseAsm) {} + + virtual void printInst(const MCInst *MI); + + // Autogenerated by tblgen. + void printInstruction(const MCInst *MI); + static const char *getRegisterName(unsigned RegNo); + + + void printOperand(const MCInst *MI, unsigned OpNo, + const char *Modifier = 0); + + void printSOImmOperand(const MCInst *MI, unsigned OpNum); + void printSOImm2PartOperand(const MCInst *MI, unsigned OpNum); + + void printSORegOperand(const MCInst *MI, unsigned OpNum); + void printAddrMode2Operand(const MCInst *MI, unsigned OpNum); + void printAddrMode2OffsetOperand(const MCInst *MI, unsigned OpNum); + void printAddrMode3Operand(const MCInst *MI, unsigned OpNum); + void printAddrMode3OffsetOperand(const MCInst *MI, unsigned OpNum); + void printAddrMode4Operand(const MCInst *MI, unsigned OpNum, + const char *Modifier = 0); + void printAddrMode5Operand(const MCInst *MI, unsigned OpNum, + const char *Modifier = 0); + void printAddrMode6Operand(const MCInst *MI, unsigned OpNum); + void printAddrModePCOperand(const MCInst *MI, unsigned OpNum, + const char *Modifier = 0); + + void printBitfieldInvMaskImmOperand(const MCInst *MI, unsigned OpNum); + + void printThumbITMask(const MCInst *MI, unsigned OpNum) {} + void printThumbAddrModeRROperand(const MCInst *MI, unsigned OpNum) {} + void printThumbAddrModeRI5Operand(const MCInst *MI, unsigned OpNum, + unsigned Scale) {} + void printThumbAddrModeS1Operand(const MCInst *MI, unsigned OpNum) {} + void printThumbAddrModeS2Operand(const MCInst *MI, unsigned OpNum) {} + void printThumbAddrModeS4Operand(const MCInst *MI, unsigned OpNum) {} + void printThumbAddrModeSPOperand(const MCInst *MI, unsigned OpNum) {} + + void printT2SOOperand(const MCInst *MI, unsigned OpNum) {} + void printT2AddrModeImm12Operand(const MCInst *MI, unsigned OpNum) {} + void printT2AddrModeImm8Operand(const MCInst *MI, unsigned OpNum) {} + void printT2AddrModeImm8s4Operand(const MCInst *MI, unsigned OpNum) {} + void printT2AddrModeImm8OffsetOperand(const MCInst *MI, unsigned OpNum) {} + void printT2AddrModeSoRegOperand(const MCInst *MI, unsigned OpNum) {} + + void printPredicateOperand(const MCInst *MI, unsigned OpNum); + void printSBitModifierOperand(const MCInst *MI, unsigned OpNum); + void printRegisterList(const MCInst *MI, unsigned OpNum); + void printCPInstOperand(const MCInst *MI, unsigned OpNum, + const char *Modifier); + void printJTBlockOperand(const MCInst *MI, unsigned OpNum) {} + void printJT2BlockOperand(const MCInst *MI, unsigned OpNum) {} + void printTBAddrMode(const MCInst *MI, unsigned OpNum) {} + void printNoHashImmediate(const MCInst *MI, unsigned OpNum); + + void printPCLabel(const MCInst *MI, unsigned OpNum); + // FIXME: Implement. + void PrintSpecial(const MCInst *MI, const char *Kind) {} +}; + +} + +#endif diff --git a/lib/Target/ARM/AsmPrinter/ARMMCInstLower.cpp b/lib/Target/ARM/AsmPrinter/ARMMCInstLower.cpp new file mode 100644 index 0000000..757164e --- /dev/null +++ b/lib/Target/ARM/AsmPrinter/ARMMCInstLower.cpp @@ -0,0 +1,166 @@ +//===-- ARMMCInstLower.cpp - Convert ARM MachineInstr to an MCInst --------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains code to lower ARM MachineInstrs to their corresponding +// MCInst records. +// +//===----------------------------------------------------------------------===// + +#include "ARMMCInstLower.h" +//#include "llvm/CodeGen/MachineModuleInfoImpls.h" +#include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/CodeGen/MachineBasicBlock.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCInst.h" +//#include "llvm/MC/MCStreamer.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/Mangler.h" +#include "llvm/ADT/SmallString.h" +using namespace llvm; + + +#if 0 +const ARMSubtarget &ARMMCInstLower::getSubtarget() const { + return AsmPrinter.getSubtarget(); +} + +MachineModuleInfoMachO &ARMMCInstLower::getMachOMMI() const { + assert(getSubtarget().isTargetDarwin() &&"Can only get MachO info on darwin"); + return AsmPrinter.MMI->getObjFileInfo<MachineModuleInfoMachO>(); +} +#endif + +MCSymbol *ARMMCInstLower:: +GetGlobalAddressSymbol(const MachineOperand &MO) const { + const GlobalValue *GV = MO.getGlobal(); + + SmallString<128> Name; + Mang.getNameWithPrefix(Name, GV, false); + + // FIXME: HANDLE PLT references how?? + switch (MO.getTargetFlags()) { + default: assert(0 && "Unknown target flag on GV operand"); + case 0: break; + } + + return Ctx.GetOrCreateSymbol(Name.str()); +} + +MCSymbol *ARMMCInstLower:: +GetExternalSymbolSymbol(const MachineOperand &MO) const { + SmallString<128> Name; + Name += Printer.MAI->getGlobalPrefix(); + Name += MO.getSymbolName(); + + // FIXME: HANDLE PLT references how?? + switch (MO.getTargetFlags()) { + default: assert(0 && "Unknown target flag on GV operand"); + case 0: break; + } + + return Ctx.GetOrCreateSymbol(Name.str()); +} + + + +MCSymbol *ARMMCInstLower:: +GetJumpTableSymbol(const MachineOperand &MO) const { + SmallString<256> Name; + raw_svector_ostream(Name) << Printer.MAI->getPrivateGlobalPrefix() << "JTI" + << Printer.getFunctionNumber() << '_' << MO.getIndex(); + +#if 0 + switch (MO.getTargetFlags()) { + default: llvm_unreachable("Unknown target flag on GV operand"); + } +#endif + + // Create a symbol for the name. + return Ctx.GetOrCreateSymbol(Name.str()); +} + +MCSymbol *ARMMCInstLower:: +GetConstantPoolIndexSymbol(const MachineOperand &MO) const { + SmallString<256> Name; + raw_svector_ostream(Name) << Printer.MAI->getPrivateGlobalPrefix() << "CPI" + << Printer.getFunctionNumber() << '_' << MO.getIndex(); + +#if 0 + switch (MO.getTargetFlags()) { + default: llvm_unreachable("Unknown target flag on GV operand"); + } +#endif + + // Create a symbol for the name. + return Ctx.GetOrCreateSymbol(Name.str()); +} + +MCOperand ARMMCInstLower:: +LowerSymbolOperand(const MachineOperand &MO, MCSymbol *Sym) const { + // FIXME: We would like an efficient form for this, so we don't have to do a + // lot of extra uniquing. + const MCExpr *Expr = MCSymbolRefExpr::Create(Sym, Ctx); + +#if 0 + switch (MO.getTargetFlags()) { + default: llvm_unreachable("Unknown target flag on GV operand"); + } +#endif + + if (!MO.isJTI() && MO.getOffset()) + Expr = MCBinaryExpr::CreateAdd(Expr, + MCConstantExpr::Create(MO.getOffset(), Ctx), + Ctx); + return MCOperand::CreateExpr(Expr); +} + + +void ARMMCInstLower::Lower(const MachineInstr *MI, MCInst &OutMI) const { + OutMI.setOpcode(MI->getOpcode()); + + for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { + const MachineOperand &MO = MI->getOperand(i); + + MCOperand MCOp; + switch (MO.getType()) { + default: + MI->dump(); + assert(0 && "unknown operand type"); + case MachineOperand::MO_Register: + // Ignore all implicit register operands. + if (MO.isImplicit()) continue; + MCOp = MCOperand::CreateReg(MO.getReg()); + break; + case MachineOperand::MO_Immediate: + MCOp = MCOperand::CreateImm(MO.getImm()); + break; + case MachineOperand::MO_MachineBasicBlock: + MCOp = MCOperand::CreateExpr(MCSymbolRefExpr::Create( + Printer.GetMBBSymbol(MO.getMBB()->getNumber()), Ctx)); + break; + case MachineOperand::MO_GlobalAddress: + MCOp = LowerSymbolOperand(MO, GetGlobalAddressSymbol(MO)); + break; + case MachineOperand::MO_ExternalSymbol: + MCOp = LowerSymbolOperand(MO, GetExternalSymbolSymbol(MO)); + break; + case MachineOperand::MO_JumpTableIndex: + MCOp = LowerSymbolOperand(MO, GetJumpTableSymbol(MO)); + break; + case MachineOperand::MO_ConstantPoolIndex: + MCOp = LowerSymbolOperand(MO, GetConstantPoolIndexSymbol(MO)); + break; + } + + OutMI.addOperand(MCOp); + } + +} diff --git a/lib/Target/ARM/AsmPrinter/ARMMCInstLower.h b/lib/Target/ARM/AsmPrinter/ARMMCInstLower.h new file mode 100644 index 0000000..383d30d --- /dev/null +++ b/lib/Target/ARM/AsmPrinter/ARMMCInstLower.h @@ -0,0 +1,56 @@ +//===-- ARMMCInstLower.h - Lower MachineInstr to MCInst -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef ARM_MCINSTLOWER_H +#define ARM_MCINSTLOWER_H + +#include "llvm/Support/Compiler.h" + +namespace llvm { + class AsmPrinter; + class MCAsmInfo; + class MCContext; + class MCInst; + class MCOperand; + class MCSymbol; + class MachineInstr; + class MachineModuleInfoMachO; + class MachineOperand; + class Mangler; + //class ARMSubtarget; + +/// ARMMCInstLower - This class is used to lower an MachineInstr into an MCInst. +class VISIBILITY_HIDDEN ARMMCInstLower { + MCContext &Ctx; + Mangler &Mang; + AsmPrinter &Printer; + + //const ARMSubtarget &getSubtarget() const; +public: + ARMMCInstLower(MCContext &ctx, Mangler &mang, AsmPrinter &printer) + : Ctx(ctx), Mang(mang), Printer(printer) {} + + void Lower(const MachineInstr *MI, MCInst &OutMI) const; + + //MCSymbol *GetPICBaseSymbol() const; + MCSymbol *GetGlobalAddressSymbol(const MachineOperand &MO) const; + MCSymbol *GetExternalSymbolSymbol(const MachineOperand &MO) const; + MCSymbol *GetJumpTableSymbol(const MachineOperand &MO) const; + MCSymbol *GetConstantPoolIndexSymbol(const MachineOperand &MO) const; + MCOperand LowerSymbolOperand(const MachineOperand &MO, MCSymbol *Sym) const; + +/* +private: + MachineModuleInfoMachO &getMachOMMI() const; + */ +}; + +} + +#endif diff --git a/lib/Target/ARM/AsmPrinter/CMakeLists.txt b/lib/Target/ARM/AsmPrinter/CMakeLists.txt index a67fc84..4e299f8 100644 --- a/lib/Target/ARM/AsmPrinter/CMakeLists.txt +++ b/lib/Target/ARM/AsmPrinter/CMakeLists.txt @@ -2,5 +2,7 @@ include_directories( ${CMAKE_CURRENT_BINARY_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/ add_llvm_library(LLVMARMAsmPrinter ARMAsmPrinter.cpp + ARMInstPrinter.cpp + ARMMCInstLower.cpp ) -add_dependencies(LLVMARMAsmPrinter ARMCodeGenTable_gen)
\ No newline at end of file +add_dependencies(LLVMARMAsmPrinter ARMCodeGenTable_gen) diff --git a/lib/Target/ARM/README-Thumb.txt b/lib/Target/ARM/README-Thumb.txt index a961a57..e7770b2 100644 --- a/lib/Target/ARM/README-Thumb.txt +++ b/lib/Target/ARM/README-Thumb.txt @@ -196,14 +196,6 @@ This is especially bad when dynamic alloca is used. The all fixed size stack objects are referenced off the frame pointer with negative offsets. See oggenc for an example. -//===---------------------------------------------------------------------===// - -We are reserving R3 as a scratch register under thumb mode. So if it is live in -to the function, we save / restore R3 to / from R12. Until register scavenging -is done, we should save R3 to a high callee saved reg at emitPrologue time -(when hasFP is true or stack size is large) and restore R3 from that register -instead. This allows us to at least get rid of the save to r12 everytime it is -used. //===---------------------------------------------------------------------===// diff --git a/lib/Target/ARM/Thumb1RegisterInfo.cpp b/lib/Target/ARM/Thumb1RegisterInfo.cpp index 3c896da..6207177 100644 --- a/lib/Target/ARM/Thumb1RegisterInfo.cpp +++ b/lib/Target/ARM/Thumb1RegisterInfo.cpp @@ -32,7 +32,6 @@ #include "llvm/Target/TargetMachine.h" #include "llvm/ADT/BitVector.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/Support/CommandLine.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; @@ -394,31 +393,48 @@ rewriteFrameIndex(MachineInstr &MI, unsigned FrameRegIdx, return 0; } -/// saveScavengerRegister - Save the register so it can be used by the +/// saveScavengerRegister - Spill the register so it can be used by the /// register scavenger. Return true. -bool Thumb1RegisterInfo::saveScavengerRegister(MachineBasicBlock &MBB, - MachineBasicBlock::iterator I, - const TargetRegisterClass *RC, - unsigned Reg) const { +bool +Thumb1RegisterInfo::saveScavengerRegister(MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, + MachineBasicBlock::iterator &UseMI, + const TargetRegisterClass *RC, + unsigned Reg) const { // Thumb1 can't use the emergency spill slot on the stack because // ldr/str immediate offsets must be positive, and if we're referencing // off the frame pointer (if, for example, there are alloca() calls in // the function, the offset will be negative. Use R12 instead since that's // a call clobbered register that we know won't be used in Thumb1 mode. + DebugLoc DL = DebugLoc::getUnknownLoc(); + BuildMI(MBB, I, DL, TII.get(ARM::tMOVtgpr2gpr)). + addReg(ARM::R12, RegState::Define).addReg(Reg, RegState::Kill); + + // The UseMI is where we would like to restore the register. If there's + // interference with R12 before then, however, we'll need to restore it + // before that instead and adjust the UseMI. + bool done = false; + for (MachineBasicBlock::iterator II = I; !done && II != UseMI ; ++II) { + // If this instruction affects R12, adjust our restore point. + for (unsigned i = 0, e = II->getNumOperands(); i != e; ++i) { + const MachineOperand &MO = II->getOperand(i); + if (!MO.isReg() || MO.isUndef() || !MO.getReg() || + TargetRegisterInfo::isVirtualRegister(MO.getReg())) + continue; + if (MO.getReg() == ARM::R12) { + UseMI = II; + done = true; + break; + } + } + } + // Restore the register from R12 + BuildMI(MBB, UseMI, DL, TII.get(ARM::tMOVgpr2tgpr)). + addReg(Reg, RegState::Define).addReg(ARM::R12, RegState::Kill); - TII.copyRegToReg(MBB, I, ARM::R12, Reg, ARM::GPRRegisterClass, RC); return true; } -/// restoreScavengerRegister - restore a registers saved by -// saveScavengerRegister(). -void Thumb1RegisterInfo::restoreScavengerRegister(MachineBasicBlock &MBB, - MachineBasicBlock::iterator I, - const TargetRegisterClass *RC, - unsigned Reg) const { - TII.copyRegToReg(MBB, I, Reg, ARM::R12, RC, ARM::GPRRegisterClass); -} - unsigned Thumb1RegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, int SPAdj, int *Value, @@ -828,7 +844,6 @@ void Thumb1RegisterInfo::emitEpilogue(MachineFunction &MF, if (VARegSaveSize) { // Epilogue for vararg functions: pop LR to R3 and branch off it. - // FIXME: Verify this is still ok when R3 is no longer being reserved. AddDefaultPred(BuildMI(MBB, MBBI, dl, TII.get(ARM::tPOP))) .addReg(0) // No write back. .addReg(ARM::R3, RegState::Define); diff --git a/lib/Target/ARM/Thumb1RegisterInfo.h b/lib/Target/ARM/Thumb1RegisterInfo.h index bb7a619..570a5bc 100644 --- a/lib/Target/ARM/Thumb1RegisterInfo.h +++ b/lib/Target/ARM/Thumb1RegisterInfo.h @@ -57,12 +57,9 @@ public: bool saveScavengerRegister(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, + MachineBasicBlock::iterator &UseMI, const TargetRegisterClass *RC, unsigned Reg) const; - void restoreScavengerRegister(MachineBasicBlock &MBB, - MachineBasicBlock::iterator I, - const TargetRegisterClass *RC, - unsigned Reg) const; unsigned eliminateFrameIndex(MachineBasicBlock::iterator II, int SPAdj, int *Value = NULL, RegScavenger *RS = NULL) const; diff --git a/lib/Target/ARM/Thumb2ITBlockPass.cpp b/lib/Target/ARM/Thumb2ITBlockPass.cpp index 98b5cbd..427c0bb 100644 --- a/lib/Target/ARM/Thumb2ITBlockPass.cpp +++ b/lib/Target/ARM/Thumb2ITBlockPass.cpp @@ -107,8 +107,12 @@ bool Thumb2ITBlockPass::InsertITBlocks(MachineBasicBlock &MBB) { // Finalize IT mask. ARMCC::CondCodes OCC = ARMCC::getOppositeCondition(CC); unsigned Mask = 0, Pos = 3; - while (MBBI != E && Pos) { + // Branches, including tricky ones like LDM_RET, need to end an IT + // block so check the instruction we just put in the block. + while (MBBI != E && Pos && + (!MI->getDesc().isBranch() && !MI->getDesc().isReturn())) { MachineInstr *NMI = &*MBBI; + MI = NMI; DebugLoc ndl = NMI->getDebugLoc(); unsigned NPredReg = 0; ARMCC::CondCodes NCC = getPredicate(NMI, NPredReg); diff --git a/lib/Target/ARM/Thumb2RegisterInfo.cpp b/lib/Target/ARM/Thumb2RegisterInfo.cpp index 6c4c15d..f217e0e 100644 --- a/lib/Target/ARM/Thumb2RegisterInfo.cpp +++ b/lib/Target/ARM/Thumb2RegisterInfo.cpp @@ -32,7 +32,6 @@ #include "llvm/Target/TargetMachine.h" #include "llvm/ADT/BitVector.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/Support/CommandLine.h" #include "llvm/Support/ErrorHandling.h" using namespace llvm; diff --git a/lib/Target/Blackfin/Blackfin.td b/lib/Target/Blackfin/Blackfin.td index b904638..cd90962 100644 --- a/lib/Target/Blackfin/Blackfin.td +++ b/lib/Target/Blackfin/Blackfin.td @@ -74,6 +74,7 @@ def WA_IND_CALL : SubtargetFeature<"ind-call-anomaly", "wa_ind_call", "true", include "BlackfinRegisterInfo.td" include "BlackfinCallingConv.td" +include "BlackfinIntrinsics.td" include "BlackfinInstrInfo.td" def BlackfinInstrInfo : InstrInfo {} diff --git a/lib/Target/Blackfin/BlackfinIntrinsicInfo.cpp b/lib/Target/Blackfin/BlackfinIntrinsicInfo.cpp new file mode 100644 index 0000000..544dc68 --- /dev/null +++ b/lib/Target/Blackfin/BlackfinIntrinsicInfo.cpp @@ -0,0 +1,53 @@ +//===- BlackfinIntrinsicInfo.cpp - Intrinsic Information --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the Blackfin implementation of TargetIntrinsicInfo. +// +//===----------------------------------------------------------------------===// + +#include "BlackfinIntrinsicInfo.h" +#include "llvm/Intrinsics.h" +#include "llvm/Support/raw_ostream.h" +#include <cstring> + +using namespace llvm; + +namespace bfinIntrinsic { + + enum ID { + last_non_bfin_intrinsic = Intrinsic::num_intrinsics-1, +#define GET_INTRINSIC_ENUM_VALUES +#include "BlackfinGenIntrinsics.inc" +#undef GET_INTRINSIC_ENUM_VALUES + , num_bfin_intrinsics + }; + +} + +const char *BlackfinIntrinsicInfo::getName(unsigned IntrID) const { + static const char *const names[] = { +#define GET_INTRINSIC_NAME_TABLE +#include "BlackfinGenIntrinsics.inc" +#undef GET_INTRINSIC_NAME_TABLE + }; + + if (IntrID < Intrinsic::num_intrinsics) + return 0; + assert(IntrID < bfinIntrinsic::num_bfin_intrinsics && "Invalid intrinsic ID"); + + return names[IntrID - Intrinsic::num_intrinsics]; +} + +unsigned +BlackfinIntrinsicInfo::lookupName(const char *Name, unsigned Len) const { +#define GET_FUNCTION_RECOGNIZER +#include "BlackfinGenIntrinsics.inc" +#undef GET_FUNCTION_RECOGNIZER + return 0; +} diff --git a/lib/Target/Blackfin/BlackfinIntrinsicInfo.h b/lib/Target/Blackfin/BlackfinIntrinsicInfo.h new file mode 100644 index 0000000..3b59a60 --- /dev/null +++ b/lib/Target/Blackfin/BlackfinIntrinsicInfo.h @@ -0,0 +1,28 @@ +//===- BlackfinIntrinsicInfo.h - Blackfin Intrinsic Information -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the Blackfin implementation of TargetIntrinsicInfo. +// +//===----------------------------------------------------------------------===// +#ifndef BLACKFININTRINSICS_H +#define BLACKFININTRINSICS_H + +#include "llvm/Target/TargetIntrinsicInfo.h" + +namespace llvm { + + class BlackfinIntrinsicInfo : public TargetIntrinsicInfo { + public: + const char *getName(unsigned IntrID) const; + unsigned lookupName(const char *Name, unsigned Len) const; + }; + +} + +#endif diff --git a/lib/Target/Blackfin/BlackfinIntrinsics.td b/lib/Target/Blackfin/BlackfinIntrinsics.td new file mode 100644 index 0000000..bf02cfe --- /dev/null +++ b/lib/Target/Blackfin/BlackfinIntrinsics.td @@ -0,0 +1,34 @@ +//===- BlackfinIntrinsics.td - Defines Blackfin intrinsics -*- tablegen -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines all of the blackfin-specific intrinsics. +// +//===----------------------------------------------------------------------===// + +let TargetPrefix = "bfin", isTarget = 1 in { + +//===----------------------------------------------------------------------===// +// Core synchronisation etc. +// +// These intrinsics have sideeffects. Each represent a single instruction, but +// workarounds are sometimes required depending on the cpu. + +// Execute csync instruction with workarounds +def int_bfin_csync : GCCBuiltin<"__builtin_bfin_csync">, + Intrinsic<[llvm_void_ty]>; + +// Execute ssync instruction with workarounds +def int_bfin_ssync : GCCBuiltin<"__builtin_bfin_ssync">, + Intrinsic<[llvm_void_ty]>; + +// Execute idle instruction with workarounds +def int_bfin_idle : GCCBuiltin<"__builtin_bfin_idle">, + Intrinsic<[llvm_void_ty]>; + +} diff --git a/lib/Target/Blackfin/BlackfinTargetMachine.h b/lib/Target/Blackfin/BlackfinTargetMachine.h index 73ed314..a14052b 100644 --- a/lib/Target/Blackfin/BlackfinTargetMachine.h +++ b/lib/Target/Blackfin/BlackfinTargetMachine.h @@ -20,6 +20,7 @@ #include "BlackfinInstrInfo.h" #include "BlackfinSubtarget.h" #include "BlackfinISelLowering.h" +#include "BlackfinIntrinsicInfo.h" namespace llvm { @@ -29,6 +30,7 @@ namespace llvm { BlackfinTargetLowering TLInfo; BlackfinInstrInfo InstrInfo; TargetFrameInfo FrameInfo; + BlackfinIntrinsicInfo IntrinsicInfo; public: BlackfinTargetMachine(const Target &T, const std::string &TT, const std::string &FS); @@ -47,6 +49,9 @@ namespace llvm { virtual const TargetData *getTargetData() const { return &DataLayout; } virtual bool addInstSelector(PassManagerBase &PM, CodeGenOpt::Level OptLevel); + const TargetIntrinsicInfo *getIntrinsicInfo() const { + return &IntrinsicInfo; + } }; } // end namespace llvm diff --git a/lib/Target/Blackfin/CMakeLists.txt b/lib/Target/Blackfin/CMakeLists.txt index 6c3b244..deb005d 100644 --- a/lib/Target/Blackfin/CMakeLists.txt +++ b/lib/Target/Blackfin/CMakeLists.txt @@ -9,9 +9,11 @@ tablegen(BlackfinGenAsmWriter.inc -gen-asm-writer) tablegen(BlackfinGenDAGISel.inc -gen-dag-isel) tablegen(BlackfinGenSubtarget.inc -gen-subtarget) tablegen(BlackfinGenCallingConv.inc -gen-callingconv) +tablegen(BlackfinGenIntrinsics.inc -gen-tgt-intrinsic) add_llvm_target(BlackfinCodeGen BlackfinInstrInfo.cpp + BlackfinIntrinsicInfo.cpp BlackfinISelDAGToDAG.cpp BlackfinISelLowering.cpp BlackfinMCAsmInfo.cpp diff --git a/lib/Target/Blackfin/Makefile b/lib/Target/Blackfin/Makefile index c0c1bce..c68760b 100644 --- a/lib/Target/Blackfin/Makefile +++ b/lib/Target/Blackfin/Makefile @@ -15,7 +15,7 @@ BUILT_SOURCES = BlackfinGenRegisterInfo.h.inc BlackfinGenRegisterNames.inc \ BlackfinGenRegisterInfo.inc BlackfinGenInstrNames.inc \ BlackfinGenInstrInfo.inc BlackfinGenAsmWriter.inc \ BlackfinGenDAGISel.inc BlackfinGenSubtarget.inc \ - BlackfinGenCallingConv.inc + BlackfinGenCallingConv.inc BlackfinGenIntrinsics.inc DIRS = AsmPrinter TargetInfo diff --git a/lib/Target/CBackend/CBackend.cpp b/lib/Target/CBackend/CBackend.cpp index fe63edf..cbf769b 100644 --- a/lib/Target/CBackend/CBackend.cpp +++ b/lib/Target/CBackend/CBackend.cpp @@ -302,7 +302,6 @@ namespace { void visitInlineAsm(CallInst &I); bool visitBuiltinCall(CallInst &I, Intrinsic::ID ID, bool &WroteCallee); - void visitMallocInst(MallocInst &I); void visitAllocaInst(AllocaInst &I); void visitFreeInst (FreeInst &I); void visitLoadInst (LoadInst &I); @@ -3405,10 +3404,6 @@ void CWriter::visitInlineAsm(CallInst &CI) { Out << ")"; } -void CWriter::visitMallocInst(MallocInst &I) { - llvm_unreachable("lowerallocations pass didn't work!"); -} - void CWriter::visitAllocaInst(AllocaInst &I) { Out << '('; printType(Out, I.getType()); @@ -3690,7 +3685,7 @@ bool CTargetMachine::addPassesToEmitWholeFile(PassManager &PM, if (FileType != TargetMachine::AssemblyFile) return true; PM.add(createGCLoweringPass()); - PM.add(createLowerAllocationsPass(true)); + PM.add(createLowerAllocationsPass()); PM.add(createLowerInvokePass()); PM.add(createCFGSimplificationPass()); // clean up after lower invoke. PM.add(new CBackendNameAllUsedStructsAndMergeFunctions()); diff --git a/lib/Target/CppBackend/CPPBackend.cpp b/lib/Target/CppBackend/CPPBackend.cpp index 14ad451..45c2a7b 100644 --- a/lib/Target/CppBackend/CPPBackend.cpp +++ b/lib/Target/CppBackend/CPPBackend.cpp @@ -1258,20 +1258,6 @@ namespace { Out << "\");"; break; } - case Instruction::Malloc: { - const MallocInst* mallocI = cast<MallocInst>(I); - Out << "MallocInst* " << iName << " = new MallocInst(" - << getCppName(mallocI->getAllocatedType()) << ", "; - if (mallocI->isArrayAllocation()) - Out << opNames[0] << ", " ; - Out << "\""; - printEscapedString(mallocI->getName()); - Out << "\", " << bbname << ");"; - if (mallocI->getAlignment()) - nl(Out) << iName << "->setAlignment(" - << mallocI->getAlignment() << ");"; - break; - } case Instruction::Free: { Out << "FreeInst* " << iName << " = new FreeInst(" << getCppName(I->getOperand(0)) << ", " << bbname << ");"; diff --git a/lib/Target/MSIL/MSILWriter.cpp b/lib/Target/MSIL/MSILWriter.cpp index 26d637b..cf08a97 100644 --- a/lib/Target/MSIL/MSILWriter.cpp +++ b/lib/Target/MSIL/MSILWriter.cpp @@ -1191,9 +1191,6 @@ void MSILWriter::printInstruction(const Instruction* Inst) { case Instruction::Alloca: printAllocaInstruction(cast<AllocaInst>(Inst)); break; - case Instruction::Malloc: - llvm_unreachable("LowerAllocationsPass used"); - break; case Instruction::Free: llvm_unreachable("LowerAllocationsPass used"); break; @@ -1702,7 +1699,7 @@ bool MSILTarget::addPassesToEmitWholeFile(PassManager &PM, if (FileType != TargetMachine::AssemblyFile) return true; MSILWriter* Writer = new MSILWriter(o); PM.add(createGCLoweringPass()); - PM.add(createLowerAllocationsPass(true)); + PM.add(createLowerAllocationsPass()); // FIXME: Handle switch trougth native IL instruction "switch" PM.add(createLowerSwitchPass()); PM.add(createCFGSimplificationPass()); diff --git a/lib/Target/MSP430/AsmPrinter/CMakeLists.txt b/lib/Target/MSP430/AsmPrinter/CMakeLists.txt index 6e66887..f1eb885 100644 --- a/lib/Target/MSP430/AsmPrinter/CMakeLists.txt +++ b/lib/Target/MSP430/AsmPrinter/CMakeLists.txt @@ -1,6 +1,8 @@ include_directories( ${CMAKE_CURRENT_BINARY_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/.. ) add_llvm_library(LLVMMSP430AsmPrinter + MSP430InstPrinter.cpp MSP430AsmPrinter.cpp + MSP430MCInstLower.cpp ) add_dependencies(LLVMMSP430AsmPrinter MSP430CodeGenTable_gen) diff --git a/lib/Target/MSP430/AsmPrinter/MSP430AsmPrinter.cpp b/lib/Target/MSP430/AsmPrinter/MSP430AsmPrinter.cpp index 852019f..ace358e 100644 --- a/lib/Target/MSP430/AsmPrinter/MSP430AsmPrinter.cpp +++ b/lib/Target/MSP430/AsmPrinter/MSP430AsmPrinter.cpp @@ -15,7 +15,9 @@ #define DEBUG_TYPE "asm-printer" #include "MSP430.h" #include "MSP430InstrInfo.h" +#include "MSP430InstPrinter.h" #include "MSP430MCAsmInfo.h" +#include "MSP430MCInstLower.h" #include "MSP430TargetMachine.h" #include "llvm/Constants.h" #include "llvm/DerivedTypes.h" @@ -26,12 +28,14 @@ #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineConstantPool.h" #include "llvm/CodeGen/MachineInstr.h" +#include "llvm/MC/MCInst.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSymbol.h" #include "llvm/Target/TargetData.h" #include "llvm/Target/TargetLoweringObjectFile.h" #include "llvm/Target/TargetRegistry.h" #include "llvm/ADT/Statistic.h" +#include "llvm/Support/CommandLine.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/FormattedStream.h" #include "llvm/Support/Mangler.h" @@ -41,6 +45,10 @@ using namespace llvm; STATISTIC(EmittedInsts, "Number of machine instrs printed"); +static cl::opt<bool> +EnableMCInst("enable-msp430-mcinst-printer", cl::Hidden, + cl::desc("enable experimental mcinst gunk in the msp430 backend")); + namespace { class VISIBILITY_HIDDEN MSP430AsmPrinter : public AsmPrinter { public: @@ -52,8 +60,14 @@ namespace { return "MSP430 Assembly Printer"; } + void printMCInst(const MCInst *MI) { + MSP430InstPrinter(O, *MAI).printInstruction(MI); + } void printOperand(const MachineInstr *MI, int OpNum, const char* Modifier = 0); + void printPCRelImmOperand(const MachineInstr *MI, int OpNum) { + printOperand(MI, OpNum); + } void printSrcMemOperand(const MachineInstr *MI, int OpNum, const char* Modifier = 0); void printCCOperand(const MachineInstr *MI, int OpNum); @@ -67,6 +81,7 @@ namespace { bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, unsigned AsmVariant, const char *ExtraCode); + void printInstructionThroughMCStreamer(const MachineInstr *MI); void emitFunctionHeader(const MachineFunction &MF); bool runOnMachineFunction(MachineFunction &F); @@ -148,7 +163,11 @@ void MSP430AsmPrinter::printMachineInstruction(const MachineInstr *MI) { processDebugLoc(MI, true); // Call the autogenerated instruction printer routines. - printInstruction(MI); + if (EnableMCInst) { + printInstructionThroughMCStreamer(MI); + } else { + printInstruction(MI); + } if (VerboseAsm && !MI->getDebugLoc().isUnknown()) EmitComments(*MI); @@ -231,22 +250,22 @@ void MSP430AsmPrinter::printCCOperand(const MachineInstr *MI, int OpNum) { default: llvm_unreachable("Unsupported CC code"); break; - case MSP430::COND_E: + case MSP430CC::COND_E: O << "eq"; break; - case MSP430::COND_NE: + case MSP430CC::COND_NE: O << "ne"; break; - case MSP430::COND_HS: + case MSP430CC::COND_HS: O << "hs"; break; - case MSP430::COND_LO: + case MSP430CC::COND_LO: O << "lo"; break; - case MSP430::COND_GE: + case MSP430CC::COND_GE: O << "ge"; break; - case MSP430::COND_L: + case MSP430CC::COND_L: O << 'l'; break; } @@ -275,6 +294,36 @@ bool MSP430AsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, return false; } +//===----------------------------------------------------------------------===// +void MSP430AsmPrinter::printInstructionThroughMCStreamer(const MachineInstr *MI) +{ + + MSP430MCInstLower MCInstLowering(OutContext, *Mang, *this); + + switch (MI->getOpcode()) { + case TargetInstrInfo::DBG_LABEL: + case TargetInstrInfo::EH_LABEL: + case TargetInstrInfo::GC_LABEL: + printLabel(MI); + return; + case TargetInstrInfo::KILL: + return; + case TargetInstrInfo::INLINEASM: + O << '\t'; + printInlineAsm(MI); + return; + case TargetInstrInfo::IMPLICIT_DEF: + printImplicitDef(MI); + return; + default: break; + } + + MCInst TmpInst; + MCInstLowering.Lower(MI, TmpInst); + + printMCInst(&TmpInst); +} + // Force static initialization. extern "C" void LLVMInitializeMSP430AsmPrinter() { RegisterAsmPrinter<MSP430AsmPrinter> X(TheMSP430Target); diff --git a/lib/Target/MSP430/AsmPrinter/MSP430InstPrinter.cpp b/lib/Target/MSP430/AsmPrinter/MSP430InstPrinter.cpp new file mode 100644 index 0000000..a3ecc67 --- /dev/null +++ b/lib/Target/MSP430/AsmPrinter/MSP430InstPrinter.cpp @@ -0,0 +1,116 @@ +//===-- MSP430InstPrinter.cpp - Convert MSP430 MCInst to assembly syntax --===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This class prints an MSP430 MCInst to a .s file. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "asm-printer" +#include "MSP430.h" +#include "MSP430InstrInfo.h" +#include "MSP430InstPrinter.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/FormattedStream.h" +using namespace llvm; + + +// Include the auto-generated portion of the assembly writer. +#define MachineInstr MCInst +#define MSP430AsmPrinter MSP430InstPrinter // FIXME: REMOVE. +#define NO_ASM_WRITER_BOILERPLATE +#include "MSP430GenAsmWriter.inc" +#undef MachineInstr +#undef MSP430AsmPrinter + +void MSP430InstPrinter::printInst(const MCInst *MI) { + printInstruction(MI); +} + +void MSP430InstPrinter::printPCRelImmOperand(const MCInst *MI, unsigned OpNo) { + const MCOperand &Op = MI->getOperand(OpNo); + if (Op.isImm()) + O << Op.getImm(); + else { + assert(Op.isExpr() && "unknown pcrel immediate operand"); + Op.getExpr()->print(O, &MAI); + } +} + +void MSP430InstPrinter::printOperand(const MCInst *MI, unsigned OpNo, + const char *Modifier) { + assert((Modifier == 0 || Modifier[0] == 0) && "No modifiers supported"); + const MCOperand &Op = MI->getOperand(OpNo); + if (Op.isReg()) { + O << getRegisterName(Op.getReg()); + } else if (Op.isImm()) { + O << '#' << Op.getImm(); + } else { + assert(Op.isExpr() && "unknown operand kind in printOperand"); + O << '#'; + Op.getExpr()->print(O, &MAI); + } +} + +void MSP430InstPrinter::printSrcMemOperand(const MCInst *MI, unsigned OpNo, + const char *Modifier) { + const MCOperand &Base = MI->getOperand(OpNo); + const MCOperand &Disp = MI->getOperand(OpNo+1); + + // FIXME: move global to displacement field! + if (Base.isExpr()) { + O << '&'; + Base.getExpr()->print(O, &MAI); + } else if (Disp.isImm() && !Base.isReg()) + printOperand(MI, OpNo); + else if (Base.isReg()) { + if (Disp.getImm()) { + O << Disp.getImm() << '('; + printOperand(MI, OpNo); + O << ')'; + } else { + O << '@'; + printOperand(MI, OpNo); + } + } else { + Base.dump(); + Disp.dump(); + llvm_unreachable("Unsupported memory operand"); + } +} + +void MSP430InstPrinter::printCCOperand(const MCInst *MI, unsigned OpNo) { + unsigned CC = MI->getOperand(OpNo).getImm(); + + switch (CC) { + default: + llvm_unreachable("Unsupported CC code"); + break; + case MSP430CC::COND_E: + O << "eq"; + break; + case MSP430CC::COND_NE: + O << "ne"; + break; + case MSP430CC::COND_HS: + O << "hs"; + break; + case MSP430CC::COND_LO: + O << "lo"; + break; + case MSP430CC::COND_GE: + O << "ge"; + break; + case MSP430CC::COND_L: + O << 'l'; + break; + } +} diff --git a/lib/Target/MSP430/AsmPrinter/MSP430InstPrinter.h b/lib/Target/MSP430/AsmPrinter/MSP430InstPrinter.h new file mode 100644 index 0000000..2fac800 --- /dev/null +++ b/lib/Target/MSP430/AsmPrinter/MSP430InstPrinter.h @@ -0,0 +1,46 @@ +//===-- MSP430InstPrinter.h - Convert MSP430 MCInst to assembly syntax ----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This class prints a MSP430 MCInst to a .s file. +// +//===----------------------------------------------------------------------===// + +#ifndef MSP430INSTPRINTER_H +#define MSP430INSTPRINTER_H + +#include "llvm/MC/MCInstPrinter.h" + +namespace llvm +{ + + class MCOperand; + + class MSP430InstPrinter : public MCInstPrinter { + public: + MSP430InstPrinter(raw_ostream &O, const MCAsmInfo &MAI) : + MCInstPrinter(O, MAI){ + } + + virtual void printInst(const MCInst *MI); + + // Autogenerated by tblgen. + void printInstruction(const MCInst *MI); + static const char *getRegisterName(unsigned RegNo); + + void printOperand(const MCInst *MI, unsigned OpNo, + const char *Modifier = 0); + void printPCRelImmOperand(const MCInst *MI, unsigned OpNo); + void printSrcMemOperand(const MCInst *MI, unsigned OpNo, + const char *Modifier = 0); + void printCCOperand(const MCInst *MI, unsigned OpNo); + + }; +} + +#endif diff --git a/lib/Target/MSP430/AsmPrinter/MSP430MCInstLower.cpp b/lib/Target/MSP430/AsmPrinter/MSP430MCInstLower.cpp new file mode 100644 index 0000000..f505b23 --- /dev/null +++ b/lib/Target/MSP430/AsmPrinter/MSP430MCInstLower.cpp @@ -0,0 +1,147 @@ +//===-- MSP430MCInstLower.cpp - Convert MSP430 MachineInstr to an MCInst---===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains code to lower MSP430 MachineInstrs to their corresponding +// MCInst records. +// +//===----------------------------------------------------------------------===// + +#include "MSP430MCInstLower.h" +#include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/CodeGen/MachineBasicBlock.h" +#include "llvm/CodeGen/MachineInstr.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCInst.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/Mangler.h" +#include "llvm/ADT/SmallString.h" +using namespace llvm; + +MCSymbol *MSP430MCInstLower:: +GetGlobalAddressSymbol(const MachineOperand &MO) const { + const GlobalValue *GV = MO.getGlobal(); + + SmallString<128> Name; + Mang.getNameWithPrefix(Name, GV, false); + + switch (MO.getTargetFlags()) { + default: llvm_unreachable(0 && "Unknown target flag on GV operand"); + case 0: break; + } + + return Ctx.GetOrCreateSymbol(Name.str()); +} + +MCSymbol *MSP430MCInstLower:: +GetExternalSymbolSymbol(const MachineOperand &MO) const { + SmallString<128> Name; + Name += Printer.MAI->getGlobalPrefix(); + Name += MO.getSymbolName(); + + switch (MO.getTargetFlags()) { + default: assert(0 && "Unknown target flag on GV operand"); + case 0: break; + } + + return Ctx.GetOrCreateSymbol(Name.str()); +} + +MCSymbol *MSP430MCInstLower:: +GetJumpTableSymbol(const MachineOperand &MO) const { + SmallString<256> Name; + raw_svector_ostream(Name) << Printer.MAI->getPrivateGlobalPrefix() << "JTI" + << Printer.getFunctionNumber() << '_' + << MO.getIndex(); + + switch (MO.getTargetFlags()) { + default: llvm_unreachable("Unknown target flag on GV operand"); + case 0: break; + } + + // Create a symbol for the name. + return Ctx.GetOrCreateSymbol(Name.str()); +} + +MCSymbol *MSP430MCInstLower:: +GetConstantPoolIndexSymbol(const MachineOperand &MO) const { + SmallString<256> Name; + raw_svector_ostream(Name) << Printer.MAI->getPrivateGlobalPrefix() << "CPI" + << Printer.getFunctionNumber() << '_' + << MO.getIndex(); + + switch (MO.getTargetFlags()) { + default: llvm_unreachable("Unknown target flag on GV operand"); + case 0: break; + } + + // Create a symbol for the name. + return Ctx.GetOrCreateSymbol(Name.str()); +} + +MCOperand MSP430MCInstLower:: +LowerSymbolOperand(const MachineOperand &MO, MCSymbol *Sym) const { + // FIXME: We would like an efficient form for this, so we don't have to do a + // lot of extra uniquing. + const MCExpr *Expr = MCSymbolRefExpr::Create(Sym, Ctx); + + switch (MO.getTargetFlags()) { + default: llvm_unreachable("Unknown target flag on GV operand"); + case 0: break; + } + + if (!MO.isJTI() && MO.getOffset()) + Expr = MCBinaryExpr::CreateAdd(Expr, + MCConstantExpr::Create(MO.getOffset(), Ctx), + Ctx); + return MCOperand::CreateExpr(Expr); +} + +void MSP430MCInstLower::Lower(const MachineInstr *MI, MCInst &OutMI) const { + OutMI.setOpcode(MI->getOpcode()); + + for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { + const MachineOperand &MO = MI->getOperand(i); + + MCOperand MCOp; + switch (MO.getType()) { + default: + MI->dump(); + assert(0 && "unknown operand type"); + case MachineOperand::MO_Register: + // Ignore all implicit register operands. + if (MO.isImplicit()) continue; + MCOp = MCOperand::CreateReg(MO.getReg()); + break; + case MachineOperand::MO_Immediate: + MCOp = MCOperand::CreateImm(MO.getImm()); + break; + case MachineOperand::MO_MachineBasicBlock: + MCOp = MCOperand::CreateExpr(MCSymbolRefExpr::Create( + Printer.GetMBBSymbol(MO.getMBB()->getNumber()), Ctx)); + break; + case MachineOperand::MO_GlobalAddress: + MCOp = LowerSymbolOperand(MO, GetGlobalAddressSymbol(MO)); + break; + case MachineOperand::MO_ExternalSymbol: + MCOp = LowerSymbolOperand(MO, GetExternalSymbolSymbol(MO)); + break; + case MachineOperand::MO_JumpTableIndex: + MCOp = LowerSymbolOperand(MO, GetJumpTableSymbol(MO)); + break; + case MachineOperand::MO_ConstantPoolIndex: + MCOp = LowerSymbolOperand(MO, GetConstantPoolIndexSymbol(MO)); + break; + } + + OutMI.addOperand(MCOp); + } +} diff --git a/lib/Target/MSP430/AsmPrinter/MSP430MCInstLower.h b/lib/Target/MSP430/AsmPrinter/MSP430MCInstLower.h new file mode 100644 index 0000000..a2b99ae --- /dev/null +++ b/lib/Target/MSP430/AsmPrinter/MSP430MCInstLower.h @@ -0,0 +1,49 @@ +//===-- MSP430MCInstLower.h - Lower MachineInstr to MCInst ----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef MSP430_MCINSTLOWER_H +#define MSP430_MCINSTLOWER_H + +#include "llvm/Support/Compiler.h" + +namespace llvm { + class AsmPrinter; + class MCAsmInfo; + class MCContext; + class MCInst; + class MCOperand; + class MCSymbol; + class MachineInstr; + class MachineModuleInfoMachO; + class MachineOperand; + class Mangler; + + /// MSP430MCInstLower - This class is used to lower an MachineInstr + /// into an MCInst. +class VISIBILITY_HIDDEN MSP430MCInstLower { + MCContext &Ctx; + Mangler &Mang; + + AsmPrinter &Printer; +public: + MSP430MCInstLower(MCContext &ctx, Mangler &mang, AsmPrinter &printer) + : Ctx(ctx), Mang(mang), Printer(printer) {} + void Lower(const MachineInstr *MI, MCInst &OutMI) const; + + MCOperand LowerSymbolOperand(const MachineOperand &MO, MCSymbol *Sym) const; + + MCSymbol *GetGlobalAddressSymbol(const MachineOperand &MO) const; + MCSymbol *GetExternalSymbolSymbol(const MachineOperand &MO) const; + MCSymbol *GetJumpTableSymbol(const MachineOperand &MO) const; + MCSymbol *GetConstantPoolIndexSymbol(const MachineOperand &MO) const; +}; + +} + +#endif diff --git a/lib/Target/MSP430/MSP430.h b/lib/Target/MSP430/MSP430.h index d9f5f86..1ff178d 100644 --- a/lib/Target/MSP430/MSP430.h +++ b/lib/Target/MSP430/MSP430.h @@ -17,6 +17,20 @@ #include "llvm/Target/TargetMachine.h" +namespace MSP430CC { + // MSP430 specific condition code. + enum CondCodes { + COND_E = 0, // aka COND_Z + COND_NE = 1, // aka COND_NZ + COND_HS = 2, // aka COND_C + COND_LO = 3, // aka COND_NC + COND_GE = 4, + COND_L = 5, + + COND_INVALID = -1 + }; +} + namespace llvm { class MSP430TargetMachine; class FunctionPass; diff --git a/lib/Target/MSP430/MSP430ISelDAGToDAG.cpp b/lib/Target/MSP430/MSP430ISelDAGToDAG.cpp index 4195a88..b7d9282 100644 --- a/lib/Target/MSP430/MSP430ISelDAGToDAG.cpp +++ b/lib/Target/MSP430/MSP430ISelDAGToDAG.cpp @@ -26,6 +26,7 @@ #include "llvm/CodeGen/SelectionDAG.h" #include "llvm/CodeGen/SelectionDAGISel.h" #include "llvm/Target/TargetLowering.h" +#include "llvm/Support/CommandLine.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" @@ -34,6 +35,14 @@ using namespace llvm; +#ifndef NDEBUG +static cl::opt<bool> +ViewRMWDAGs("view-msp430-rmw-dags", cl::Hidden, + cl::desc("Pop up a window to show isel dags after RMW preprocess")); +#else +static const bool ViewRMWDAGs = false; +#endif + STATISTIC(NumLoadMoved, "Number of loads moved below TokenFactor"); /// MSP430DAGToDAGISel - MSP430 specific code to select MSP430 machine @@ -56,6 +65,9 @@ namespace { return "MSP430 DAG->DAG Pattern Instruction Selection"; } + bool IsLegalAndProfitableToFold(SDNode *N, SDNode *U, + SDNode *Root) const; + virtual bool SelectInlineAsmMemoryOperand(const SDValue &Op, char ConstraintCode, std::vector<SDValue> &OutOps); @@ -64,6 +76,7 @@ namespace { #include "MSP430GenDAGISel.inc" private: + DenseMap<SDNode*, SDNode*> RMWStores; void PreprocessForRMW(); SDNode *Select(SDValue Op); bool SelectAddr(SDValue Op, SDValue Addr, SDValue &Base, SDValue &Disp); @@ -130,7 +143,6 @@ bool MSP430DAGToDAGISel::SelectAddr(SDValue Op, SDValue Addr, return true; } - bool MSP430DAGToDAGISel:: SelectInlineAsmMemoryOperand(const SDValue &Op, char ConstraintCode, std::vector<SDValue> &OutOps) { @@ -148,31 +160,54 @@ SelectInlineAsmMemoryOperand(const SDValue &Op, char ConstraintCode, return false; } +bool MSP430DAGToDAGISel::IsLegalAndProfitableToFold(SDNode *N, SDNode *U, + SDNode *Root) const { + if (OptLevel == CodeGenOpt::None) return false; + + /// RMW preprocessing creates the following code: + /// [Load1] + /// ^ ^ + /// / | + /// / | + /// [Load2] | + /// ^ ^ | + /// | | | + /// | \-| + /// | | + /// | [Op] + /// | ^ + /// | | + /// \ / + /// \ / + /// [Store] + /// + /// The path Store => Load2 => Load1 is via chain. Note that in general it is + /// not allowed to fold Load1 into Op (and Store) since it will creates a + /// cycle. However, this is perfectly legal for the loads moved below the + /// TokenFactor by PreprocessForRMW. Query the map Store => Load1 (created + /// during preprocessing) to determine whether it's legal to introduce such + /// "cycle" for a moment. + DenseMap<SDNode*, SDNode*>::iterator I = RMWStores.find(Root); + if (I != RMWStores.end() && I->second == N) + return true; + + // Proceed to 'generic' cycle finder code + return SelectionDAGISel::IsLegalAndProfitableToFold(N, U, Root); +} + + /// MoveBelowTokenFactor - Replace TokenFactor operand with load's chain operand /// and move load below the TokenFactor. Replace store's chain operand with /// load's chain result. -/// Shamelessly stolen from X86. static void MoveBelowTokenFactor(SelectionDAG *CurDAG, SDValue Load, SDValue Store, SDValue TF) { SmallVector<SDValue, 4> Ops; - bool isRMW = false; - SDValue TF0, TF1, NewTF; for (unsigned i = 0, e = TF.getNode()->getNumOperands(); i != e; ++i) - if (Load.getNode() == TF.getOperand(i).getNode()) { - TF0 = Load.getOperand(0); - Ops.push_back(TF0); - } else { - TF1 = TF.getOperand(i); - Ops.push_back(TF1); - if (LoadSDNode* LD = dyn_cast<LoadSDNode>(TF1)) - isRMW = !LD->isVolatile(); - } - - if (isRMW && TF1.getOperand(0).getNode() == TF0.getNode()) - NewTF = TF0; - else - NewTF = CurDAG->UpdateNodeOperands(TF, &Ops[0], Ops.size()); - + if (Load.getNode() == TF.getOperand(i).getNode()) + Ops.push_back(Load.getOperand(0)); + else + Ops.push_back(TF.getOperand(i)); + SDValue NewTF = CurDAG->UpdateNodeOperands(TF, &Ops[0], Ops.size()); SDValue NewLoad = CurDAG->UpdateNodeOperands(Load, NewTF, Load.getOperand(1), Load.getOperand(2)); @@ -180,12 +215,43 @@ static void MoveBelowTokenFactor(SelectionDAG *CurDAG, SDValue Load, Store.getOperand(2), Store.getOperand(3)); } -/// isRMWLoad - Return true if N is a load that's part of RMW sub-DAG. The chain -/// produced by the load must only be used by the store's chain operand, -/// otherwise this may produce a cycle in the DAG. -/// Shamelessly stolen from X86. FIXME: Should we make this function common? -static bool isRMWLoad(SDValue N, SDValue Chain, SDValue Address, - SDValue &Load) { +/// MoveBelowTokenFactor2 - Replace TokenFactor operand with load's chain operand +/// and move load below the TokenFactor. Replace store's chain operand with +/// load's chain result. This a version which sinks two loads below token factor. +/// Look into PreprocessForRMW comments for explanation of transform. +static void MoveBelowTokenFactor2(SelectionDAG *CurDAG, + SDValue Load1, SDValue Load2, + SDValue Store, SDValue TF) { + SmallVector<SDValue, 4> Ops; + for (unsigned i = 0, e = TF.getNode()->getNumOperands(); i != e; ++i) { + SDNode* N = TF.getOperand(i).getNode(); + if (Load2.getNode() == N) + Ops.push_back(Load2.getOperand(0)); + else if (Load1.getNode() != N) + Ops.push_back(TF.getOperand(i)); + } + + SDValue NewTF = SDValue(CurDAG->MorphNodeTo(TF.getNode(), + TF.getOpcode(), + TF.getNode()->getVTList(), + &Ops[0], Ops.size()), TF.getResNo()); + SDValue NewLoad2 = CurDAG->UpdateNodeOperands(Load2, NewTF, + Load2.getOperand(1), + Load2.getOperand(2)); + + SDValue NewLoad1 = CurDAG->UpdateNodeOperands(Load1, NewLoad2.getValue(1), + Load1.getOperand(1), + Load1.getOperand(2)); + + CurDAG->UpdateNodeOperands(Store, + NewLoad1.getValue(1), + Store.getOperand(1), + Store.getOperand(2), Store.getOperand(3)); +} + +/// isAllowedToSink - return true if N a load which can be moved below token +/// factor. Basically, the load should be non-volatile and has single use. +static bool isLoadAllowedToSink(SDValue N, SDValue Chain) { if (N.getOpcode() == ISD::BIT_CONVERT) N = N.getOperand(0); @@ -199,10 +265,19 @@ static bool isRMWLoad(SDValue N, SDValue Chain, SDValue Address, if (ExtType != ISD::NON_EXTLOAD && ExtType != ISD::EXTLOAD) return false; - if (N.hasOneUse() && - LD->hasNUsesOfValue(1, 1) && - N.getOperand(1) == Address && - LD->isOperandOf(Chain.getNode())) { + return (N.hasOneUse() && + LD->hasNUsesOfValue(1, 1) && + LD->isOperandOf(Chain.getNode())); +} + + +/// isRMWLoad - Return true if N is a load that's part of RMW sub-DAG. +/// The chain produced by the load must only be used by the store's chain +/// operand, otherwise this may produce a cycle in the DAG. +static bool isRMWLoad(SDValue N, SDValue Chain, SDValue Address, + SDValue &Load) { + if (isLoadAllowedToSink(N, Chain) && + N.getOperand(1) == Address) { Load = N; return true; } @@ -210,57 +285,140 @@ static bool isRMWLoad(SDValue N, SDValue Chain, SDValue Address, } /// PreprocessForRMW - Preprocess the DAG to make instruction selection better. -/// Shamelessly stolen from X86. +/// This is only run if not in -O0 mode. +/// This allows the instruction selector to pick more read-modify-write +/// instructions. This is a common case: +/// +/// [Load chain] +/// ^ +/// | +/// [Load] +/// ^ ^ +/// | | +/// / \- +/// / | +/// [TokenFactor] [Op] +/// ^ ^ +/// | | +/// \ / +/// \ / +/// [Store] +/// +/// The fact the store's chain operand != load's chain will prevent the +/// (store (op (load))) instruction from being selected. We can transform it to: +/// +/// [Load chain] +/// ^ +/// | +/// [TokenFactor] +/// ^ +/// | +/// [Load] +/// ^ ^ +/// | | +/// | \- +/// | | +/// | [Op] +/// | ^ +/// | | +/// \ / +/// \ / +/// [Store] +/// +/// We also recognize the case where second operand of Op is load as well and +/// move it below token factor as well creating DAG as follows: +/// +/// [Load chain] +/// ^ +/// | +/// [TokenFactor] +/// ^ +/// | +/// [Load1] +/// ^ ^ +/// / | +/// / | +/// [Load2] | +/// ^ ^ | +/// | | | +/// | \-| +/// | | +/// | [Op] +/// | ^ +/// | | +/// \ / +/// \ / +/// [Store] +/// +/// This allows selection of mem-mem instructions. Yay! + void MSP430DAGToDAGISel::PreprocessForRMW() { for (SelectionDAG::allnodes_iterator I = CurDAG->allnodes_begin(), E = CurDAG->allnodes_end(); I != E; ++I) { if (!ISD::isNON_TRUNCStore(I)) continue; - SDValue Chain = I->getOperand(0); + if (Chain.getNode()->getOpcode() != ISD::TokenFactor) continue; - SDValue N1 = I->getOperand(1); // Value to store - SDValue N2 = I->getOperand(2); // Address of store - - if (!N1.hasOneUse()) + SDValue N1 = I->getOperand(1); + SDValue N2 = I->getOperand(2); + if ((N1.getValueType().isFloatingPoint() && + !N1.getValueType().isVector()) || + !N1.hasOneUse()) continue; - bool RModW = false; - SDValue Load; + unsigned RModW = 0; + SDValue Load1, Load2; unsigned Opcode = N1.getNode()->getOpcode(); switch (Opcode) { - case ISD::ADD: - case ISD::AND: - case ISD::OR: - case ISD::XOR: - case ISD::ADDC: - case ISD::ADDE: { - SDValue N10 = N1.getOperand(0); - SDValue N11 = N1.getOperand(1); - RModW = isRMWLoad(N10, Chain, N2, Load); - - if (!RModW && isRMWLoad(N11, Chain, N2, Load)) { - // Swap the operands, making the RMW load the first operand seems - // to help selection and prevent token chain loops. - N1 = CurDAG->UpdateNodeOperands(N1, N11, N10); - RModW = true; - } - break; + case ISD::ADD: + case ISD::AND: + case ISD::OR: + case ISD::XOR: + case ISD::ADDC: + case ISD::ADDE: { + SDValue N10 = N1.getOperand(0); + SDValue N11 = N1.getOperand(1); + if (isRMWLoad(N10, Chain, N2, Load1)) { + if (isLoadAllowedToSink(N11, Chain)) { + Load2 = N11; + RModW = 2; + } else + RModW = 1; + } else if (isRMWLoad(N11, Chain, N2, Load1)) { + if (isLoadAllowedToSink(N10, Chain)) { + Load2 = N10; + RModW = 2; + } else + RModW = 1; } - case ISD::SUB: - case ISD::SUBC: - case ISD::SUBE: { - SDValue N10 = N1.getOperand(0); - RModW = isRMWLoad(N10, Chain, N2, Load); - break; + break; + } + case ISD::SUB: + case ISD::SUBC: + case ISD::SUBE: { + SDValue N10 = N1.getOperand(0); + SDValue N11 = N1.getOperand(1); + if (isRMWLoad(N10, Chain, N2, Load1)) { + if (isLoadAllowedToSink(N11, Chain)) { + Load2 = N11; + RModW = 2; + } else + RModW = 1; } + break; + } } - if (RModW) { - MoveBelowTokenFactor(CurDAG, Load, SDValue(I, 0), Chain); - ++NumLoadMoved; + NumLoadMoved += RModW; + if (RModW == 1) + MoveBelowTokenFactor(CurDAG, Load1, SDValue(I, 0), Chain); + else if (RModW == 2) { + MoveBelowTokenFactor2(CurDAG, Load1, Load2, SDValue(I, 0), Chain); + SDNode* Store = I; + RMWStores[Store] = Load2.getNode(); } } } @@ -268,8 +426,15 @@ void MSP430DAGToDAGISel::PreprocessForRMW() { /// InstructionSelect - This callback is invoked by /// SelectionDAGISel when it has created a SelectionDAG for us to codegen. void MSP430DAGToDAGISel::InstructionSelect() { + std::string BlockName; + if (ViewRMWDAGs) + BlockName = MF->getFunction()->getNameStr() + ":" + + BB->getBasicBlock()->getNameStr(); + PreprocessForRMW(); + if (ViewRMWDAGs) CurDAG->viewGraph("RMW preprocessed:" + BlockName); + DEBUG(errs() << "Selection DAG after RMW preprocessing:\n"); DEBUG(CurDAG->dump()); @@ -282,6 +447,7 @@ void MSP430DAGToDAGISel::InstructionSelect() { DEBUG(errs() << "===== Instruction selection ends:\n"); CurDAG->RemoveDeadNodes(); + RMWStores.clear(); } SDNode *MSP430DAGToDAGISel::Select(SDValue Op) { diff --git a/lib/Target/MSP430/MSP430ISelLowering.cpp b/lib/Target/MSP430/MSP430ISelLowering.cpp index b56f069..34e6d2c 100644 --- a/lib/Target/MSP430/MSP430ISelLowering.cpp +++ b/lib/Target/MSP430/MSP430ISelLowering.cpp @@ -567,44 +567,45 @@ SDValue MSP430TargetLowering::LowerExternalSymbol(SDValue Op, return DAG.getNode(MSP430ISD::Wrapper, dl, getPointerTy(), Result);; } -static SDValue EmitCMP(SDValue &LHS, SDValue &RHS, unsigned &TargetCC, +static SDValue EmitCMP(SDValue &LHS, SDValue &RHS, SDValue &TargetCC, ISD::CondCode CC, DebugLoc dl, SelectionDAG &DAG) { // FIXME: Handle bittests someday assert(!LHS.getValueType().isFloatingPoint() && "We don't handle FP yet"); // FIXME: Handle jump negative someday - TargetCC = MSP430::COND_INVALID; + MSP430CC::CondCodes TCC = MSP430CC::COND_INVALID; switch (CC) { default: llvm_unreachable("Invalid integer condition!"); case ISD::SETEQ: - TargetCC = MSP430::COND_E; // aka COND_Z + TCC = MSP430CC::COND_E; // aka COND_Z break; case ISD::SETNE: - TargetCC = MSP430::COND_NE; // aka COND_NZ + TCC = MSP430CC::COND_NE; // aka COND_NZ break; case ISD::SETULE: std::swap(LHS, RHS); // FALLTHROUGH case ISD::SETUGE: - TargetCC = MSP430::COND_HS; // aka COND_C + TCC = MSP430CC::COND_HS; // aka COND_C break; case ISD::SETUGT: std::swap(LHS, RHS); // FALLTHROUGH case ISD::SETULT: - TargetCC = MSP430::COND_LO; // aka COND_NC + TCC = MSP430CC::COND_LO; // aka COND_NC break; case ISD::SETLE: std::swap(LHS, RHS); // FALLTHROUGH case ISD::SETGE: - TargetCC = MSP430::COND_GE; + TCC = MSP430CC::COND_GE; break; case ISD::SETGT: std::swap(LHS, RHS); // FALLTHROUGH case ISD::SETLT: - TargetCC = MSP430::COND_L; + TCC = MSP430CC::COND_L; break; } + TargetCC = DAG.getConstant(TCC, MVT::i8); return DAG.getNode(MSP430ISD::CMP, dl, MVT::Flag, LHS, RHS); } @@ -617,13 +618,11 @@ SDValue MSP430TargetLowering::LowerBR_CC(SDValue Op, SelectionDAG &DAG) { SDValue Dest = Op.getOperand(4); DebugLoc dl = Op.getDebugLoc(); - unsigned TargetCC = MSP430::COND_INVALID; + SDValue TargetCC; SDValue Flag = EmitCMP(LHS, RHS, TargetCC, CC, dl, DAG); return DAG.getNode(MSP430ISD::BR_CC, dl, Op.getValueType(), - Chain, - Dest, DAG.getConstant(TargetCC, MVT::i8), - Flag); + Chain, Dest, TargetCC, Flag); } SDValue MSP430TargetLowering::LowerSELECT_CC(SDValue Op, SelectionDAG &DAG) { @@ -634,14 +633,14 @@ SDValue MSP430TargetLowering::LowerSELECT_CC(SDValue Op, SelectionDAG &DAG) { ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(4))->get(); DebugLoc dl = Op.getDebugLoc(); - unsigned TargetCC = MSP430::COND_INVALID; + SDValue TargetCC; SDValue Flag = EmitCMP(LHS, RHS, TargetCC, CC, dl, DAG); SDVTList VTs = DAG.getVTList(Op.getValueType(), MVT::Flag); SmallVector<SDValue, 4> Ops; Ops.push_back(TrueV); Ops.push_back(FalseV); - Ops.push_back(DAG.getConstant(TargetCC, MVT::i8)); + Ops.push_back(TargetCC); Ops.push_back(Flag); return DAG.getNode(MSP430ISD::SELECT_CC, dl, VTs, &Ops[0], Ops.size()); diff --git a/lib/Target/MSP430/MSP430InstrInfo.cpp b/lib/Target/MSP430/MSP430InstrInfo.cpp index 37fbb6d..a6d9638 100644 --- a/lib/Target/MSP430/MSP430InstrInfo.cpp +++ b/lib/Target/MSP430/MSP430InstrInfo.cpp @@ -151,6 +151,163 @@ MSP430InstrInfo::restoreCalleeSavedRegisters(MachineBasicBlock &MBB, return true; } +unsigned MSP430InstrInfo::RemoveBranch(MachineBasicBlock &MBB) const { + MachineBasicBlock::iterator I = MBB.end(); + unsigned Count = 0; + + while (I != MBB.begin()) { + --I; + if (I->getOpcode() != MSP430::JMP && + I->getOpcode() != MSP430::JCC) + break; + // Remove the branch. + I->eraseFromParent(); + I = MBB.end(); + ++Count; + } + + return Count; +} + +bool MSP430InstrInfo:: +ReverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const { + assert(Cond.size() == 1 && "Invalid Xbranch condition!"); + + MSP430CC::CondCodes CC = static_cast<MSP430CC::CondCodes>(Cond[0].getImm()); + + switch (CC) { + default: + assert(0 && "Invalid branch condition!"); + break; + case MSP430CC::COND_E: + CC = MSP430CC::COND_NE; + break; + case MSP430CC::COND_NE: + CC = MSP430CC::COND_E; + break; + case MSP430CC::COND_L: + CC = MSP430CC::COND_GE; + break; + case MSP430CC::COND_GE: + CC = MSP430CC::COND_L; + break; + case MSP430CC::COND_HS: + CC = MSP430CC::COND_LO; + break; + case MSP430CC::COND_LO: + CC = MSP430CC::COND_HS; + break; + } + + Cond[0].setImm(CC); + return false; +} + +bool MSP430InstrInfo::BlockHasNoFallThrough(const MachineBasicBlock &MBB)const{ + if (MBB.empty()) return false; + + switch (MBB.back().getOpcode()) { + case MSP430::RET: // Return. + case MSP430::JMP: // Uncond branch. + return true; + default: return false; + } +} + +bool MSP430InstrInfo::isUnpredicatedTerminator(const MachineInstr *MI) const { + const TargetInstrDesc &TID = MI->getDesc(); + if (!TID.isTerminator()) return false; + + // Conditional branch is a special case. + if (TID.isBranch() && !TID.isBarrier()) + return true; + if (!TID.isPredicable()) + return true; + return !isPredicated(MI); +} + +bool MSP430InstrInfo::AnalyzeBranch(MachineBasicBlock &MBB, + MachineBasicBlock *&TBB, + MachineBasicBlock *&FBB, + SmallVectorImpl<MachineOperand> &Cond, + bool AllowModify) const { + // Start from the bottom of the block and work up, examining the + // terminator instructions. + MachineBasicBlock::iterator I = MBB.end(); + while (I != MBB.begin()) { + --I; + // Working from the bottom, when we see a non-terminator + // instruction, we're done. + if (!isUnpredicatedTerminator(I)) + break; + + // A terminator that isn't a branch can't easily be handled + // by this analysis. + if (!I->getDesc().isBranch()) + return true; + + // Handle unconditional branches. + if (I->getOpcode() == MSP430::JMP) { + if (!AllowModify) { + TBB = I->getOperand(0).getMBB(); + continue; + } + + // If the block has any instructions after a JMP, delete them. + while (next(I) != MBB.end()) + next(I)->eraseFromParent(); + Cond.clear(); + FBB = 0; + + // Delete the JMP if it's equivalent to a fall-through. + if (MBB.isLayoutSuccessor(I->getOperand(0).getMBB())) { + TBB = 0; + I->eraseFromParent(); + I = MBB.end(); + continue; + } + + // TBB is used to indicate the unconditinal destination. + TBB = I->getOperand(0).getMBB(); + continue; + } + + // Handle conditional branches. + assert(I->getOpcode() == MSP430::JCC && "Invalid conditional branch"); + MSP430CC::CondCodes BranchCode = + static_cast<MSP430CC::CondCodes>(I->getOperand(1).getImm()); + if (BranchCode == MSP430CC::COND_INVALID) + return true; // Can't handle weird stuff. + + // Working from the bottom, handle the first conditional branch. + if (Cond.empty()) { + FBB = TBB; + TBB = I->getOperand(0).getMBB(); + Cond.push_back(MachineOperand::CreateImm(BranchCode)); + continue; + } + + // Handle subsequent conditional branches. Only handle the case where all + // conditional branches branch to the same destination. + assert(Cond.size() == 1); + assert(TBB); + + // Only handle the case where all conditional branches branch to + // the same destination. + if (TBB != I->getOperand(0).getMBB()) + return true; + + MSP430CC::CondCodes OldBranchCode = (MSP430CC::CondCodes)Cond[0].getImm(); + // If the conditions are the same, we can leave them alone. + if (OldBranchCode == BranchCode) + continue; + + return true; + } + + return false; +} + unsigned MSP430InstrInfo::InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB, MachineBasicBlock *FBB, @@ -172,7 +329,13 @@ MSP430InstrInfo::InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB, // Conditional branch. unsigned Count = 0; - llvm_unreachable("Implement conditional branches!"); + BuildMI(&MBB, dl, get(MSP430::JCC)).addMBB(TBB).addImm(Cond[0].getImm()); + ++Count; + if (FBB) { + // Two-way Conditional branch. Insert the second branch. + BuildMI(&MBB, dl, get(MSP430::JMP)).addMBB(FBB); + ++Count; + } return Count; } diff --git a/lib/Target/MSP430/MSP430InstrInfo.h b/lib/Target/MSP430/MSP430InstrInfo.h index e07aaca..35e35db 100644 --- a/lib/Target/MSP430/MSP430InstrInfo.h +++ b/lib/Target/MSP430/MSP430InstrInfo.h @@ -21,20 +21,6 @@ namespace llvm { class MSP430TargetMachine; -namespace MSP430 { - // MSP430 specific condition code. - enum CondCode { - COND_E = 0, // aka COND_Z - COND_NE = 1, // aka COND_NZ - COND_HS = 2, // aka COND_C - COND_LO = 3, // aka COND_NC - COND_GE = 4, - COND_L = 5, - - COND_INVALID - }; -} - class MSP430InstrInfo : public TargetInstrInfoImpl { const MSP430RegisterInfo RI; MSP430TargetMachine &TM; @@ -73,9 +59,19 @@ public: MachineBasicBlock::iterator MI, const std::vector<CalleeSavedInfo> &CSI) const; - virtual unsigned InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB, - MachineBasicBlock *FBB, - const SmallVectorImpl<MachineOperand> &Cond) const; + // Branch folding goodness + bool ReverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const; + bool BlockHasNoFallThrough(const MachineBasicBlock &MBB) const; + bool isUnpredicatedTerminator(const MachineInstr *MI) const; + bool AnalyzeBranch(MachineBasicBlock &MBB, + MachineBasicBlock *&TBB, MachineBasicBlock *&FBB, + SmallVectorImpl<MachineOperand> &Cond, + bool AllowModify) const; + + unsigned RemoveBranch(MachineBasicBlock &MBB) const; + unsigned InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB, + MachineBasicBlock *FBB, + const SmallVectorImpl<MachineOperand> &Cond) const; }; diff --git a/lib/Target/MSP430/MSP430InstrInfo.td b/lib/Target/MSP430/MSP430InstrInfo.td index f7e0d2b..e202175 100644 --- a/lib/Target/MSP430/MSP430InstrInfo.td +++ b/lib/Target/MSP430/MSP430InstrInfo.td @@ -71,7 +71,9 @@ def memdst : Operand<i16> { } // Branch targets have OtherVT type. -def brtarget : Operand<OtherVT>; +def brtarget : Operand<OtherVT> { + let PrintMethod = "printPCRelImmOperand"; +} // Operand for printing out a condition code. def cc : Operand<i8> { diff --git a/lib/Target/MSP430/MSP430TargetMachine.cpp b/lib/Target/MSP430/MSP430TargetMachine.cpp index 5e21f8e..da54507 100644 --- a/lib/Target/MSP430/MSP430TargetMachine.cpp +++ b/lib/Target/MSP430/MSP430TargetMachine.cpp @@ -32,7 +32,7 @@ MSP430TargetMachine::MSP430TargetMachine(const Target &T, LLVMTargetMachine(T, TT), Subtarget(TT, FS), // FIXME: Check TargetData string. - DataLayout("e-p:16:8:8-i8:8:8-i16:8:8-i32:8:8"), + DataLayout("e-p:16:16:16-i8:8:8-i16:16:16-i32:16:32"), InstrInfo(*this), TLInfo(*this), FrameInfo(TargetFrameInfo::StackGrowsDown, 2, -2) { } diff --git a/lib/Target/PIC16/AsmPrinter/PIC16AsmPrinter.cpp b/lib/Target/PIC16/AsmPrinter/PIC16AsmPrinter.cpp index 3f415af..ea0f494 100644 --- a/lib/Target/PIC16/AsmPrinter/PIC16AsmPrinter.cpp +++ b/lib/Target/PIC16/AsmPrinter/PIC16AsmPrinter.cpp @@ -12,8 +12,9 @@ // //===----------------------------------------------------------------------===// +#include "PIC16ABINames.h" #include "PIC16AsmPrinter.h" -#include "MCSectionPIC16.h" +#include "PIC16Section.h" #include "PIC16MCAsmInfo.h" #include "llvm/DerivedTypes.h" #include "llvm/Function.h" @@ -39,7 +40,7 @@ PIC16AsmPrinter::PIC16AsmPrinter(formatted_raw_ostream &O, TargetMachine &TM, : AsmPrinter(O, TM, T, V), DbgInfo(O, T) { PTLI = static_cast<PIC16TargetLowering*>(TM.getTargetLowering()); PMAI = static_cast<const PIC16MCAsmInfo*>(T); - PTOF = (PIC16TargetObjectFile*)&PTLI->getObjFileLowering(); + PTOF = (PIC16TargetObjectFile *)&PTLI->getObjFileLowering(); } bool PIC16AsmPrinter::printMachineInstruction(const MachineInstr *MI) { @@ -52,6 +53,45 @@ bool PIC16AsmPrinter::printMachineInstruction(const MachineInstr *MI) { return true; } +static int getFunctionColor(const Function *F) { + if (F->hasSection()) { + std::string Sectn = F->getSection(); + std::string StrToFind = "Overlay="; + std::string::size_type Pos = Sectn.find(StrToFind); + + // Retreive the color number if the key is found. + if (Pos != std::string::npos) { + Pos += StrToFind.length(); + std::string Color = ""; + char c = Sectn.at(Pos); + // A Color can only consist of digits. + while (c >= '0' && c<= '9') { + Color.append(1,c); + Pos++; + if (Pos >= Sectn.length()) + break; + c = Sectn.at(Pos); + } + return atoi(Color.c_str()); + } + } + + // Color was not set for function, so return -1. + return -1; +} + +// Color the Auto section of the given function. +void PIC16AsmPrinter::ColorAutoSection(const Function *F) { + std::string SectionName = PAN::getAutosSectionName(CurrentFnName); + PIC16Section* Section = PTOF->findPIC16Section(SectionName); + if (Section != NULL) { + int Color = getFunctionColor(F); + if (Color >= 0) + Section->setColor(Color); + } +} + + /// runOnMachineFunction - This emits the frame section, autos section and /// assembly for each instruction. Also takes care of function begin debug /// directive and file begin debug directive (if required) for the function. @@ -67,17 +107,18 @@ bool PIC16AsmPrinter::runOnMachineFunction(MachineFunction &MF) { const Function *F = MF.getFunction(); CurrentFnName = Mang->getMangledName(F); + // Put the color information from function to its auto section. + ColorAutoSection(F); + // Emit the function frame (args and temps). EmitFunctionFrame(MF); DbgInfo.BeginFunction(MF); - // Emit the autos section of function. - EmitAutos(CurrentFnName); - // Now emit the instructions of function in its code section. - const MCSection *fCodeSection = - getObjFileLowering().getSectionForFunction(CurrentFnName); + const MCSection *fCodeSection + = getObjFileLowering().SectionForCode(CurrentFnName); + // Start the Code Section. O << "\n"; OutStreamer.SwitchSection(fCodeSection); @@ -229,12 +270,26 @@ bool PIC16AsmPrinter::doInitialization(Module &M) { // Set the section names for all globals. for (Module::global_iterator I = M.global_begin(), E = M.global_end(); - I != E; ++I) - if (!I->isDeclaration() && !I->hasAvailableExternallyLinkage()) { + I != E; ++I) { + + // Record External Var Decls. + if (I->isDeclaration()) { + ExternalVarDecls.push_back(I); + continue; + } + + // Record Exteranl Var Defs. + if (I->hasExternalLinkage() || I->hasCommonLinkage()) { + ExternalVarDefs.push_back(I); + } + + // Sectionify actual data. + if (!I->hasAvailableExternallyLinkage()) { const MCSection *S = getObjFileLowering().SectionForGlobal(I, Mang, TM); - I->setSection(((const MCSectionPIC16*)S)->getName()); + I->setSection(((const PIC16Section *)S)->getName()); } + } DbgInfo.BeginModule(M); EmitFunctionDecls(M); @@ -243,6 +298,7 @@ bool PIC16AsmPrinter::doInitialization(Module &M) { EmitIData(M); EmitUData(M); EmitRomData(M); + EmitUserSections(M); return Result; } @@ -287,7 +343,7 @@ void PIC16AsmPrinter::EmitFunctionDecls(Module &M) { // Emit variables imported from other Modules. void PIC16AsmPrinter::EmitUndefinedVars(Module &M) { - std::vector<const GlobalVariable*> Items = PTOF->ExternalVarDecls->Items; + std::vector<const GlobalVariable*> Items = ExternalVarDecls; if (!Items.size()) return; O << "\n" << MAI->getCommentString() << "Imported Variables - BEGIN" << "\n"; @@ -299,7 +355,7 @@ void PIC16AsmPrinter::EmitUndefinedVars(Module &M) { // Emit variables defined in this module and are available to other modules. void PIC16AsmPrinter::EmitDefinedVars(Module &M) { - std::vector<const GlobalVariable*> Items = PTOF->ExternalVarDefs->Items; + std::vector<const GlobalVariable*> Items = ExternalVarDefs; if (!Items.size()) return; O << "\n" << MAI->getCommentString() << "Exported Variables - BEGIN" << "\n"; @@ -311,25 +367,12 @@ void PIC16AsmPrinter::EmitDefinedVars(Module &M) { // Emit initialized data placed in ROM. void PIC16AsmPrinter::EmitRomData(Module &M) { - // Print ROM Data section. - const std::vector<PIC16Section*> &ROSections = PTOF->ROSections; - for (unsigned i = 0; i < ROSections.size(); i++) { - const std::vector<const GlobalVariable*> &Items = ROSections[i]->Items; - if (!Items.size()) continue; - O << "\n"; - OutStreamer.SwitchSection(PTOF->ROSections[i]->S_); - for (unsigned j = 0; j < Items.size(); j++) { - O << Mang->getMangledName(Items[j]); - Constant *C = Items[j]->getInitializer(); - int AddrSpace = Items[j]->getType()->getAddressSpace(); - EmitGlobalConstant(C, AddrSpace); - } - } + EmitSingleSection(PTOF->ROMDATASection()); } bool PIC16AsmPrinter::doFinalization(Module &M) { + EmitAllAutos(M); printLibcallDecls(); - EmitRemainingAutos(); DbgInfo.EndModule(M); O << "\n\t" << "END\n"; return AsmPrinter::doFinalization(M); @@ -342,8 +385,10 @@ void PIC16AsmPrinter::EmitFunctionFrame(MachineFunction &MF) { // Emit the data section name. O << "\n"; - const MCSection *fPDataSection = - getObjFileLowering().getSectionForFunctionFrame(CurrentFnName); + PIC16Section *fPDataSection = const_cast<PIC16Section *>(getObjFileLowering(). + SectionForFrame(CurrentFnName)); + + fPDataSection->setColor(getFunctionColor(F)); OutStreamer.SwitchSection(fPDataSection); // Emit function frame label @@ -379,106 +424,86 @@ void PIC16AsmPrinter::EmitFunctionFrame(MachineFunction &MF) { O << PAN::getTempdataLabel(CurrentFnName) << " RES " << TempSize << '\n'; } -void PIC16AsmPrinter::EmitIData(Module &M) { - // Print all IDATA sections. - const std::vector<PIC16Section*> &IDATASections = PTOF->IDATASections; - for (unsigned i = 0; i < IDATASections.size(); i++) { - O << "\n"; - if (IDATASections[i]->S_->getName().find("llvm.") != std::string::npos) - continue; - OutStreamer.SwitchSection(IDATASections[i]->S_); - std::vector<const GlobalVariable*> Items = IDATASections[i]->Items; +void PIC16AsmPrinter::EmitInitializedDataSection(const PIC16Section *S) { + /// Emit Section header. + OutStreamer.SwitchSection(S); + + std::vector<const GlobalVariable*> Items = S->Items; for (unsigned j = 0; j < Items.size(); j++) { std::string Name = Mang->getMangledName(Items[j]); Constant *C = Items[j]->getInitializer(); int AddrSpace = Items[j]->getType()->getAddressSpace(); O << Name; EmitGlobalConstant(C, AddrSpace); - } - } + } } -void PIC16AsmPrinter::EmitUData(Module &M) { - const TargetData *TD = TM.getTargetData(); +// Print all IDATA sections. +void PIC16AsmPrinter::EmitIData(Module &M) { + EmitSectionList (M, PTOF->IDATASections()); +} - // Print all BSS sections. - const std::vector<PIC16Section*> &BSSSections = PTOF->BSSSections; - for (unsigned i = 0; i < BSSSections.size(); i++) { - O << "\n"; - OutStreamer.SwitchSection(BSSSections[i]->S_); - std::vector<const GlobalVariable*> Items = BSSSections[i]->Items; +void PIC16AsmPrinter:: +EmitUninitializedDataSection(const PIC16Section *S) { + const TargetData *TD = TM.getTargetData(); + OutStreamer.SwitchSection(S); + std::vector<const GlobalVariable*> Items = S->Items; for (unsigned j = 0; j < Items.size(); j++) { std::string Name = Mang->getMangledName(Items[j]); Constant *C = Items[j]->getInitializer(); const Type *Ty = C->getType(); unsigned Size = TD->getTypeAllocSize(Ty); - O << Name << " RES " << Size << "\n"; } - } } -void PIC16AsmPrinter::EmitAutos(std::string FunctName) { - // Section names for all globals are already set. - const TargetData *TD = TM.getTargetData(); +// Print all UDATA sections. +void PIC16AsmPrinter::EmitUData(Module &M) { + EmitSectionList (M, PTOF->UDATASections()); +} - // Now print Autos section for this function. - std::string SectionName = PAN::getAutosSectionName(FunctName); - const std::vector<PIC16Section*> &AutosSections = PTOF->AutosSections; - for (unsigned i = 0; i < AutosSections.size(); i++) { - O << "\n"; - if (AutosSections[i]->S_->getName() == SectionName) { - // Set the printing status to true - AutosSections[i]->setPrintedStatus(true); - OutStreamer.SwitchSection(AutosSections[i]->S_); - const std::vector<const GlobalVariable*> &Items = AutosSections[i]->Items; - for (unsigned j = 0; j < Items.size(); j++) { - std::string VarName = Mang->getMangledName(Items[j]); - Constant *C = Items[j]->getInitializer(); - const Type *Ty = C->getType(); - unsigned Size = TD->getTypeAllocSize(Ty); - // Emit memory reserve directive. - O << VarName << " RES " << Size << "\n"; - } - break; - } - } +// Print all USER sections. +void PIC16AsmPrinter::EmitUserSections(Module &M) { + EmitSectionList (M, PTOF->USERSections()); } -// Print autos that were not printed during the code printing of functions. -// As the functions might themselves would have got deleted by the optimizer. -void PIC16AsmPrinter::EmitRemainingAutos() { - const TargetData *TD = TM.getTargetData(); +// Print all AUTO sections. +void PIC16AsmPrinter::EmitAllAutos(Module &M) { + EmitSectionList (M, PTOF->AUTOSections()); +} - // Now print Autos section for this function. - std::vector <PIC16Section *>AutosSections = PTOF->AutosSections; - for (unsigned i = 0; i < AutosSections.size(); i++) { - - // if the section is already printed then don't print again - if (AutosSections[i]->isPrinted()) - continue; +extern "C" void LLVMInitializePIC16AsmPrinter() { + RegisterAsmPrinter<PIC16AsmPrinter> X(ThePIC16Target); +} - // Set status as printed - AutosSections[i]->setPrintedStatus(true); +// Emit one data section using correct section emitter based on section type. +void PIC16AsmPrinter::EmitSingleSection(const PIC16Section *S) { + if (S == NULL) return; - O << "\n"; - OutStreamer.SwitchSection(AutosSections[i]->S_); - const std::vector<const GlobalVariable*> &Items = AutosSections[i]->Items; - for (unsigned j = 0; j < Items.size(); j++) { - std::string VarName = Mang->getMangledName(Items[j]); - Constant *C = Items[j]->getInitializer(); - const Type *Ty = C->getType(); - unsigned Size = TD->getTypeAllocSize(Ty); - // Emit memory reserve directive. - O << VarName << " RES " << Size << "\n"; - } + switch (S->getType()) { + default: llvm_unreachable ("unknow user section type"); + case UDATA: + case UDATA_SHR: + case UDATA_OVR: + EmitUninitializedDataSection(S); + break; + case IDATA: + case ROMDATA: + EmitInitializedDataSection(S); + break; } } - -extern "C" void LLVMInitializePIC16AsmPrinter() { - RegisterAsmPrinter<PIC16AsmPrinter> X(ThePIC16Target); +// Emit a list of sections. +void PIC16AsmPrinter:: +EmitSectionList(Module &M, const std::vector<PIC16Section *> &SList) { + for (unsigned i = 0; i < SList.size(); i++) { + // Exclude llvm specific metadata sections. + if (SList[i]->getName().find("llvm.") != std::string::npos) + continue; + O << "\n"; + EmitSingleSection(SList[i]); + } } - diff --git a/lib/Target/PIC16/AsmPrinter/PIC16AsmPrinter.h b/lib/Target/PIC16/AsmPrinter/PIC16AsmPrinter.h index 2dd4600..b13d9ce 100644 --- a/lib/Target/PIC16/AsmPrinter/PIC16AsmPrinter.h +++ b/lib/Target/PIC16/AsmPrinter/PIC16AsmPrinter.h @@ -53,11 +53,17 @@ namespace llvm { void EmitDefinedVars (Module &M); void EmitIData (Module &M); void EmitUData (Module &M); - void EmitAutos (std::string FunctName); - void EmitRemainingAutos (); + void EmitAllAutos (Module &M); void EmitRomData (Module &M); + void EmitUserSections (Module &M); void EmitFunctionFrame(MachineFunction &MF); void printLibcallDecls(); + void EmitUninitializedDataSection(const PIC16Section *S); + void EmitInitializedDataSection(const PIC16Section *S); + void EmitSingleSection(const PIC16Section *S); + void EmitSectionList(Module &M, + const std::vector< PIC16Section *> &SList); + void ColorAutoSection(const Function *F); protected: bool doInitialization(Module &M); bool doFinalization(Module &M); @@ -74,6 +80,8 @@ namespace llvm { PIC16DbgInfo DbgInfo; const PIC16MCAsmInfo *PMAI; std::list<const char *> LibcallDecls; // List of extern decls. + std::vector<const GlobalVariable *> ExternalVarDecls; + std::vector<const GlobalVariable *> ExternalVarDefs; }; } // end of namespace diff --git a/lib/Target/PIC16/CMakeLists.txt b/lib/Target/PIC16/CMakeLists.txt index 0ee88f9..208b067 100644 --- a/lib/Target/PIC16/CMakeLists.txt +++ b/lib/Target/PIC16/CMakeLists.txt @@ -18,6 +18,7 @@ add_llvm_target(PIC16 PIC16MemSelOpt.cpp PIC16MCAsmInfo.cpp PIC16RegisterInfo.cpp + PIC16Section.cpp PIC16Subtarget.cpp PIC16TargetMachine.cpp PIC16TargetObjectFile.cpp diff --git a/lib/Target/PIC16/Makefile b/lib/Target/PIC16/Makefile index f913675..4382eba7 100644 --- a/lib/Target/PIC16/Makefile +++ b/lib/Target/PIC16/Makefile @@ -17,7 +17,7 @@ BUILT_SOURCES = PIC16GenRegisterInfo.h.inc PIC16GenRegisterNames.inc \ PIC16GenDAGISel.inc PIC16GenCallingConv.inc \ PIC16GenSubtarget.inc -DIRS = AsmPrinter TargetInfo +DIRS = AsmPrinter TargetInfo PIC16Passes include $(LEVEL)/Makefile.common diff --git a/lib/Target/PIC16/PIC16.h b/lib/Target/PIC16/PIC16.h index 8a3704d..e46c9b2 100644 --- a/lib/Target/PIC16/PIC16.h +++ b/lib/Target/PIC16/PIC16.h @@ -42,266 +42,15 @@ namespace PIC16CC { UGE }; } - // A Central class to manage all ABI naming conventions. - // PAN - [P]ic16 [A]BI [N]ames - class PAN { - public: - // Map the name of the symbol to its section name. - // Current ABI: - // ----------------------------------------------------- - // ALL Names are prefixed with the symobl '@'. - // ------------------------------------------------------ - // Global variables do not have any '.' in their names. - // These are maily function names and global variable names. - // Example - @foo, @i - // ------------------------------------------------------- - // Functions and auto variables. - // Names are mangled as <prefix><funcname>.<tag>.<varname> - // Where <prefix> is '@' and <tag> is any one of - // the following - // .auto. - an automatic var of a function. - // .temp. - temproray data of a function. - // .ret. - return value label for a function. - // .frame. - Frame label for a function where retval, args - // and temps are stored. - // .args. - Label used to pass arguments to a direct call. - // Example - Function name: @foo - // Its frame: @foo.frame. - // Its retval: @foo.ret. - // Its local vars: @foo.auto.a - // Its temp data: @foo.temp. - // Its arg passing: @foo.args. - //---------------------------------------------- - // Libcall - compiler generated libcall names must start with .lib. - // This id will be used to emit extern decls for libcalls. - // Example - libcall name: @.lib.sra.i8 - // To pass args: @.lib.sra.i8.args. - // To return val: @.lib.sra.i8.ret. - //---------------------------------------------- - // SECTION Names - // uninitialized globals - @udata.<num>.# - // initialized globals - @idata.<num>.# - // Function frame - @<func>.frame_section. - // Function autos - @<func>.autos_section. - // Declarations - Enclosed in comments. No section for them. - //---------------------------------------------------------- - - // Tags used to mangle different names. - enum TAGS { - PREFIX_SYMBOL, - GLOBAL, - STATIC_LOCAL, - AUTOS_LABEL, - FRAME_LABEL, - RET_LABEL, - ARGS_LABEL, - TEMPS_LABEL, - - LIBCALL, - - FRAME_SECTION, - AUTOS_SECTION, - CODE_SECTION - }; - - // Textual names of the tags. - inline static const char *getTagName(TAGS tag) { - switch (tag) { - default: return ""; - case PREFIX_SYMBOL: return "@"; - case AUTOS_LABEL: return ".auto."; - case FRAME_LABEL: return ".frame."; - case TEMPS_LABEL: return ".temp."; - case ARGS_LABEL: return ".args."; - case RET_LABEL: return ".ret."; - case LIBCALL: return ".lib."; - case FRAME_SECTION: return ".frame_section."; - case AUTOS_SECTION: return ".autos_section."; - case CODE_SECTION: return ".code_section."; - } - } - - // Get tag type for the Symbol. - inline static TAGS getSymbolTag(const std::string &Sym) { - if (Sym.find(getTagName(TEMPS_LABEL)) != std::string::npos) - return TEMPS_LABEL; - - if (Sym.find(getTagName(FRAME_LABEL)) != std::string::npos) - return FRAME_LABEL; - - if (Sym.find(getTagName(RET_LABEL)) != std::string::npos) - return RET_LABEL; - - if (Sym.find(getTagName(ARGS_LABEL)) != std::string::npos) - return ARGS_LABEL; - - if (Sym.find(getTagName(AUTOS_LABEL)) != std::string::npos) - return AUTOS_LABEL; - - if (Sym.find(getTagName(LIBCALL)) != std::string::npos) - return LIBCALL; - - // It does not have any Tag. So its a true global or static local. - if (Sym.find(".") == std::string::npos) - return GLOBAL; - - // If a . is there, then it may be static local. - // We should mangle these as well in clang. - if (Sym.find(".") != std::string::npos) - return STATIC_LOCAL; - - assert (0 && "Could not determine Symbol's tag"); - return PREFIX_SYMBOL; // Silence warning when assertions are turned off. - } - - // addPrefix - add prefix symbol to a name if there isn't one already. - inline static std::string addPrefix (const std::string &Name) { - std::string prefix = getTagName (PREFIX_SYMBOL); - - // If this name already has a prefix, nothing to do. - if (Name.compare(0, prefix.size(), prefix) == 0) - return Name; - - return prefix + Name; - } - - // Get mangled func name from a mangled sym name. - // In all cases func name is the first component before a '.'. - static inline std::string getFuncNameForSym(const std::string &Sym1) { - assert (getSymbolTag(Sym1) != GLOBAL && "not belongs to a function"); - - std::string Sym = addPrefix(Sym1); - - // Position of the . after func name. That's where func name ends. - size_t func_name_end = Sym.find ('.'); - - return Sym.substr (0, func_name_end); - } - - // Get Frame start label for a func. - static std::string getFrameLabel(const std::string &Func) { - std::string Func1 = addPrefix(Func); - std::string tag = getTagName(FRAME_LABEL); - return Func1 + tag; - } - - static std::string getRetvalLabel(const std::string &Func) { - std::string Func1 = addPrefix(Func); - std::string tag = getTagName(RET_LABEL); - return Func1 + tag; - } - - static std::string getArgsLabel(const std::string &Func) { - std::string Func1 = addPrefix(Func); - std::string tag = getTagName(ARGS_LABEL); - return Func1 + tag; - } - - static std::string getTempdataLabel(const std::string &Func) { - std::string Func1 = addPrefix(Func); - std::string tag = getTagName(TEMPS_LABEL); - return Func1 + tag; - } - static std::string getFrameSectionName(const std::string &Func) { - std::string Func1 = addPrefix(Func); - std::string tag = getTagName(FRAME_SECTION); - return Func1 + tag + "# UDATA_OVR"; - } - - static std::string getAutosSectionName(const std::string &Func) { - std::string Func1 = addPrefix(Func); - std::string tag = getTagName(AUTOS_SECTION); - return Func1 + tag + "# UDATA_OVR"; - } - - static std::string getCodeSectionName(const std::string &Func) { - std::string Func1 = addPrefix(Func); - std::string tag = getTagName(CODE_SECTION); - return Func1 + tag + "# CODE"; - } - - // udata, romdata and idata section names are generated by a given number. - // @udata.<num>.# - static std::string getUdataSectionName(unsigned num, - std::string prefix = "") { - std::ostringstream o; - o << getTagName(PREFIX_SYMBOL) << prefix << "udata." << num - << ".# UDATA"; - return o.str(); - } - - static std::string getRomdataSectionName(unsigned num, - std::string prefix = "") { - std::ostringstream o; - o << getTagName(PREFIX_SYMBOL) << prefix << "romdata." << num - << ".# ROMDATA"; - return o.str(); - } - - static std::string getIdataSectionName(unsigned num, - std::string prefix = "") { - std::ostringstream o; - o << getTagName(PREFIX_SYMBOL) << prefix << "idata." << num - << ".# IDATA"; - return o.str(); - } - - inline static bool isLocalName (const std::string &Name) { - if (getSymbolTag(Name) == AUTOS_LABEL) - return true; - - return false; - } - - inline static bool isMemIntrinsic (const std::string &Name) { - if (Name.compare("@memcpy") == 0 || Name.compare("@memset") == 0 || - Name.compare("@memmove") == 0) { - return true; - } - - return false; - } - - inline static bool isLocalToFunc (std::string &Func, std::string &Var) { - if (! isLocalName(Var)) return false; - - std::string Func1 = addPrefix(Func); - // Extract func name of the varilable. - const std::string &fname = getFuncNameForSym(Var); - - if (fname.compare(Func1) == 0) - return true; - - return false; - } - - - // Get the section for the given external symbol names. - // This tries to find the type (Tag) of the symbol from its mangled name - // and return appropriate section name for it. - static inline std::string getSectionNameForSym(const std::string &Sym1) { - std::string Sym = addPrefix(Sym1); - - std::string SectionName; - - std::string Fname = getFuncNameForSym (Sym); - TAGS id = getSymbolTag (Sym); - - switch (id) { - default : assert (0 && "Could not determine external symbol type"); - case FRAME_LABEL: - case RET_LABEL: - case TEMPS_LABEL: - case ARGS_LABEL: { - return getFrameSectionName(Fname); - } - case AUTOS_LABEL: { - return getAutosSectionName(Fname); - } - } - } - }; // class PAN. + enum PIC16SectionType { + CODE, + UDATA, + IDATA, + ROMDATA, + UDATA_OVR, + UDATA_SHR + }; // External symbol names require memory to live till the program end. diff --git a/lib/Target/PIC16/PIC16ABINames.h b/lib/Target/PIC16/PIC16ABINames.h new file mode 100644 index 0000000..7f4c2f1 --- /dev/null +++ b/lib/Target/PIC16/PIC16ABINames.h @@ -0,0 +1,325 @@ +//===-- PIC16ABINames.h - PIC16 Naming conventios for ABI----- --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the functions to manage ABI Naming conventions for PIC16. +// +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TARGET_PIC16ABINAMES_H +#define LLVM_TARGET_PIC16ABINAMES_H + +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Target/TargetMachine.h" +#include <cassert> +#include <sstream> +#include <cstring> +#include <string> + +namespace llvm { + class PIC16TargetMachine; + class FunctionPass; + class MachineCodeEmitter; + class formatted_raw_ostream; + + // A Central class to manage all ABI naming conventions. + // PAN - [P]ic16 [A]BI [N]ames + class PAN { + public: + // Map the name of the symbol to its section name. + // Current ABI: + // ----------------------------------------------------- + // ALL Names are prefixed with the symobl '@'. + // ------------------------------------------------------ + // Global variables do not have any '.' in their names. + // These are maily function names and global variable names. + // Example - @foo, @i + // Static local variables - @<func>.<var> + // ------------------------------------------------------- + // Functions and auto variables. + // Names are mangled as <prefix><funcname>.<tag>.<varname> + // Where <prefix> is '@' and <tag> is any one of + // the following + // .auto. - an automatic var of a function. + // .temp. - temproray data of a function. + // .ret. - return value label for a function. + // .frame. - Frame label for a function where retval, args + // and temps are stored. + // .args. - Label used to pass arguments to a direct call. + // Example - Function name: @foo + // Its frame: @foo.frame. + // Its retval: @foo.ret. + // Its local vars: @foo.auto.a + // Its temp data: @foo.temp. + // Its arg passing: @foo.args. + //---------------------------------------------- + // Libcall - compiler generated libcall names must start with .lib. + // This id will be used to emit extern decls for libcalls. + // Example - libcall name: @.lib.sra.i8 + // To pass args: @.lib.sra.i8.args. + // To return val: @.lib.sra.i8.ret. + //---------------------------------------------- + // SECTION Names + // uninitialized globals - @udata.<num>.# + // initialized globals - @idata.<num>.# + // Program memory data - @romdata.# + // Variables with user defined section name - <user_defined_section> + // Variables with user defined address - @<var>.user_section.<address>.# + // Function frame - @<func>.frame_section. + // Function autos - @<func>.autos_section. + // Overlay sections - @<color>.## + // Declarations - Enclosed in comments. No section for them. + //---------------------------------------------------------- + + // Tags used to mangle different names. + enum TAGS { + PREFIX_SYMBOL, + GLOBAL, + STATIC_LOCAL, + AUTOS_LABEL, + FRAME_LABEL, + RET_LABEL, + ARGS_LABEL, + TEMPS_LABEL, + + LIBCALL, + + FRAME_SECTION, + AUTOS_SECTION, + CODE_SECTION, + USER_SECTION + }; + + // Textual names of the tags. + inline static const char *getTagName(TAGS tag) { + switch (tag) { + default: return ""; + case PREFIX_SYMBOL: return "@"; + case AUTOS_LABEL: return ".auto."; + case FRAME_LABEL: return ".frame."; + case TEMPS_LABEL: return ".temp."; + case ARGS_LABEL: return ".args."; + case RET_LABEL: return ".ret."; + case LIBCALL: return ".lib."; + case FRAME_SECTION: return ".frame_section."; + case AUTOS_SECTION: return ".autos_section."; + case CODE_SECTION: return ".code_section."; + case USER_SECTION: return ".user_section."; + } + } + + // Get tag type for the Symbol. + inline static TAGS getSymbolTag(const std::string &Sym) { + if (Sym.find(getTagName(TEMPS_LABEL)) != std::string::npos) + return TEMPS_LABEL; + + if (Sym.find(getTagName(FRAME_LABEL)) != std::string::npos) + return FRAME_LABEL; + + if (Sym.find(getTagName(RET_LABEL)) != std::string::npos) + return RET_LABEL; + + if (Sym.find(getTagName(ARGS_LABEL)) != std::string::npos) + return ARGS_LABEL; + + if (Sym.find(getTagName(AUTOS_LABEL)) != std::string::npos) + return AUTOS_LABEL; + + if (Sym.find(getTagName(LIBCALL)) != std::string::npos) + return LIBCALL; + + // It does not have any Tag. So its a true global or static local. + if (Sym.find(".") == std::string::npos) + return GLOBAL; + + // If a . is there, then it may be static local. + // We should mangle these as well in clang. + if (Sym.find(".") != std::string::npos) + return STATIC_LOCAL; + + assert (0 && "Could not determine Symbol's tag"); + return PREFIX_SYMBOL; // Silence warning when assertions are turned off. + } + + // addPrefix - add prefix symbol to a name if there isn't one already. + inline static std::string addPrefix (const std::string &Name) { + std::string prefix = getTagName (PREFIX_SYMBOL); + + // If this name already has a prefix, nothing to do. + if (Name.compare(0, prefix.size(), prefix) == 0) + return Name; + + return prefix + Name; + } + + // Get mangled func name from a mangled sym name. + // In all cases func name is the first component before a '.'. + static inline std::string getFuncNameForSym(const std::string &Sym1) { + assert (getSymbolTag(Sym1) != GLOBAL && "not belongs to a function"); + + std::string Sym = addPrefix(Sym1); + + // Position of the . after func name. That's where func name ends. + size_t func_name_end = Sym.find ('.'); + + return Sym.substr (0, func_name_end); + } + + // Get Frame start label for a func. + static std::string getFrameLabel(const std::string &Func) { + std::string Func1 = addPrefix(Func); + std::string tag = getTagName(FRAME_LABEL); + return Func1 + tag; + } + + static std::string getRetvalLabel(const std::string &Func) { + std::string Func1 = addPrefix(Func); + std::string tag = getTagName(RET_LABEL); + return Func1 + tag; + } + + static std::string getArgsLabel(const std::string &Func) { + std::string Func1 = addPrefix(Func); + std::string tag = getTagName(ARGS_LABEL); + return Func1 + tag; + } + + static std::string getTempdataLabel(const std::string &Func) { + std::string Func1 = addPrefix(Func); + std::string tag = getTagName(TEMPS_LABEL); + return Func1 + tag; + } + + static std::string getFrameSectionName(const std::string &Func) { + std::string Func1 = addPrefix(Func); + std::string tag = getTagName(FRAME_SECTION); + return Func1 + tag + "#"; + } + + static std::string getAutosSectionName(const std::string &Func) { + std::string Func1 = addPrefix(Func); + std::string tag = getTagName(AUTOS_SECTION); + return Func1 + tag + "#"; + } + + static std::string getCodeSectionName(const std::string &Func) { + std::string Func1 = addPrefix(Func); + std::string tag = getTagName(CODE_SECTION); + return Func1 + tag + "#"; + } + + static std::string getUserSectionName(const std::string &Name) { + std::string sname = addPrefix(Name);; + std::string tag = getTagName(USER_SECTION); + return sname + tag + "#"; + } + + // udata, romdata and idata section names are generated by a given number. + // @udata.<num>.# + static std::string getUdataSectionName(unsigned num, + std::string prefix = "") { + std::ostringstream o; + o << getTagName(PREFIX_SYMBOL) << prefix << "udata." << num + << ".#"; + return o.str(); + } + + static std::string getRomdataSectionName() { + return "romdata.#"; + } + + static std::string getRomdataSectionName(unsigned num, + std::string prefix = "") { + std::ostringstream o; + o << getTagName(PREFIX_SYMBOL) << prefix << "romdata." << num + << ".#"; + return o.str(); + } + + static std::string getIdataSectionName(unsigned num, + std::string prefix = "") { + std::ostringstream o; + o << getTagName(PREFIX_SYMBOL) << prefix << "idata." << num + << ".#"; + return o.str(); + } + + inline static bool isLocalName (const std::string &Name) { + if (getSymbolTag(Name) == AUTOS_LABEL) + return true; + + return false; + } + + inline static bool isMemIntrinsic (const std::string &Name) { + if (Name.compare("@memcpy") == 0 || Name.compare("@memset") == 0 || + Name.compare("@memmove") == 0) { + return true; + } + + return false; + } + + inline static bool isLocalToFunc (std::string &Func, std::string &Var) { + if (! isLocalName(Var)) return false; + + std::string Func1 = addPrefix(Func); + // Extract func name of the varilable. + const std::string &fname = getFuncNameForSym(Var); + + if (fname.compare(Func1) == 0) + return true; + + return false; + } + + + // Get the section for the given external symbol names. + // This tries to find the type (Tag) of the symbol from its mangled name + // and return appropriate section name for it. + static inline std::string getSectionNameForSym(const std::string &Sym1) { + std::string Sym = addPrefix(Sym1); + + std::string SectionName; + + std::string Fname = getFuncNameForSym (Sym); + TAGS id = getSymbolTag (Sym); + + switch (id) { + default : assert (0 && "Could not determine external symbol type"); + case FRAME_LABEL: + case RET_LABEL: + case TEMPS_LABEL: + case ARGS_LABEL: { + return getFrameSectionName(Fname); + } + case AUTOS_LABEL: { + return getAutosSectionName(Fname); + } + } + } + + /// Return Overlay Name for the section. + /// The ABI Convention is: @<Color>.##.<section_tag> + /// The section_tag is retrieved from the SectName parameter and + /// and Color is passed in parameter. + static inline std::string getOverlayName(std::string SectName, int Color) { + // FIXME: Only autos_section and frame_section are colored. + // So check and assert if the passed SectName does not have AUTOS_SECTION + // or FRAME_SECTION tag in it. + std::ostringstream o; + o << getTagName(PREFIX_SYMBOL) << Color << ".##" + << SectName.substr(SectName.find(".")); + + return o.str(); + } + }; // class PAN. +} // end namespace llvm; + +#endif diff --git a/lib/Target/PIC16/PIC16DebugInfo.cpp b/lib/Target/PIC16/PIC16DebugInfo.cpp index 961caed..0ed44d2 100644 --- a/lib/Target/PIC16/PIC16DebugInfo.cpp +++ b/lib/Target/PIC16/PIC16DebugInfo.cpp @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "PIC16.h" +#include "PIC16ABINames.h" #include "PIC16DebugInfo.h" #include "llvm/GlobalVariable.h" #include "llvm/CodeGen/MachineFunction.h" @@ -30,10 +31,10 @@ void PIC16DbgInfo::PopulateDebugInfo (DIType Ty, unsigned short &TypeNo, std::string &TagName) { if (Ty.isBasicType()) PopulateBasicTypeInfo (Ty, TypeNo); - else if (Ty.isDerivedType()) - PopulateDerivedTypeInfo (Ty, TypeNo, HasAux, Aux, TagName); else if (Ty.isCompositeType()) PopulateCompositeTypeInfo (Ty, TypeNo, HasAux, Aux, TagName); + else if (Ty.isDerivedType()) + PopulateDerivedTypeInfo (Ty, TypeNo, HasAux, Aux, TagName); else { TypeNo = PIC16Dbg::T_NULL; HasAux = false; @@ -190,7 +191,7 @@ unsigned PIC16DbgInfo::GetTypeDebugNumber(std::string &type) { /// short PIC16DbgInfo::getStorageClass(DIGlobalVariable DIGV) { short ClassNo; - if (PAN::isLocalName(DIGV.getGlobal()->getName())) { + if (PAN::isLocalName(DIGV.getName())) { // Generating C_AUTO here fails due to error in linker. Change it once // linker is fixed. ClassNo = PIC16Dbg::C_STAT; @@ -446,7 +447,8 @@ void PIC16DbgInfo::EmitVarDebugInfo(Module &M) { bool HasAux = false; int Aux[PIC16Dbg::AuxSize] = { 0 }; std::string TagName = ""; - std::string VarName = MAI->getGlobalPrefix()+DIGV.getGlobal()->getNameStr(); + std::string VarName = DIGV.getName(); + VarName = MAI->getGlobalPrefix() + VarName; PopulateDebugInfo(Ty, TypeNo, HasAux, Aux, TagName); // Emit debug info only if type information is availaible. if (TypeNo != PIC16Dbg::T_NULL) { diff --git a/lib/Target/PIC16/PIC16ISelLowering.cpp b/lib/Target/PIC16/PIC16ISelLowering.cpp index bf986b1..635befe 100644 --- a/lib/Target/PIC16/PIC16ISelLowering.cpp +++ b/lib/Target/PIC16/PIC16ISelLowering.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #define DEBUG_TYPE "pic16-lower" +#include "PIC16ABINames.h" #include "PIC16ISelLowering.h" #include "PIC16TargetObjectFile.h" #include "PIC16TargetMachine.h" diff --git a/lib/Target/PIC16/PIC16InstrInfo.cpp b/lib/Target/PIC16/PIC16InstrInfo.cpp index cb0c41b..87bd3d9 100644 --- a/lib/Target/PIC16/PIC16InstrInfo.cpp +++ b/lib/Target/PIC16/PIC16InstrInfo.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "PIC16.h" +#include "PIC16ABINames.h" #include "PIC16InstrInfo.h" #include "PIC16TargetMachine.h" #include "PIC16GenInstrInfo.inc" diff --git a/lib/Target/PIC16/PIC16MCAsmInfo.cpp b/lib/Target/PIC16/PIC16MCAsmInfo.cpp index a17d1a8..827315e 100644 --- a/lib/Target/PIC16/PIC16MCAsmInfo.cpp +++ b/lib/Target/PIC16/PIC16MCAsmInfo.cpp @@ -16,6 +16,7 @@ // FIXME: Layering violation to get enums and static function, should be moved // to separate headers. #include "PIC16.h" +#include "PIC16ABINames.h" #include "PIC16ISelLowering.h" using namespace llvm; diff --git a/lib/Target/PIC16/PIC16MemSelOpt.cpp b/lib/Target/PIC16/PIC16MemSelOpt.cpp index c9ebb57..a97dc35 100644 --- a/lib/Target/PIC16/PIC16MemSelOpt.cpp +++ b/lib/Target/PIC16/PIC16MemSelOpt.cpp @@ -21,6 +21,7 @@ #define DEBUG_TYPE "pic16-codegen" #include "PIC16.h" +#include "PIC16ABINames.h" #include "PIC16InstrInfo.h" #include "PIC16MCAsmInfo.h" #include "PIC16TargetMachine.h" diff --git a/lib/Target/PIC16/PIC16Passes/Makefile b/lib/Target/PIC16/PIC16Passes/Makefile new file mode 100644 index 0000000..cbb34b3 --- /dev/null +++ b/lib/Target/PIC16/PIC16Passes/Makefile @@ -0,0 +1,17 @@ +##===- lib/Target/PIC16/PIC16Passes/Makefile -----------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## +LEVEL = ../../../.. +TARGET = PIC16 +LIBRARYNAME = LLVMpic16passes +BUILD_ARCHIVE = 1 + + + +include $(LEVEL)/Makefile.common + diff --git a/lib/Target/PIC16/PIC16Passes/PIC16Overlay.cpp b/lib/Target/PIC16/PIC16Passes/PIC16Overlay.cpp new file mode 100644 index 0000000..197c398 --- /dev/null +++ b/lib/Target/PIC16/PIC16Passes/PIC16Overlay.cpp @@ -0,0 +1,181 @@ +//===-- PIC16Overlay.cpp - Implementation for PIC16 Frame Overlay===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the PIC16 Frame Overlay implementation. +// +//===----------------------------------------------------------------------===// + + +#include "llvm/Analysis/CallGraph.h" +#include "llvm/Pass.h" +#include "llvm/Module.h" +#include "llvm/Instructions.h" +#include "llvm/Value.h" +#include "PIC16Overlay.h" +#include "llvm/Function.h" +#include <cstdlib> +#include <sstream> +using namespace llvm; + +namespace llvm { + char PIC16FrameOverlay::ID = 0; + ModulePass *createPIC16OverlayPass() { return new PIC16FrameOverlay(); } +} + +void PIC16FrameOverlay::getAnalysisUsage(AnalysisUsage &AU) const { + AU.setPreservesAll(); + AU.addRequired<CallGraph>(); +} + +void PIC16FrameOverlay::DFSTraverse(CallGraphNode *CGN, unsigned Depth) { + // Do not set any color for external calling node. + if (Depth != 0 && CGN->getFunction()) { + unsigned Color = getColor(CGN->getFunction()); + + // Handle indirectly called functions + if (Color >= PIC16Overlay::StartIndirectCallColor || + Depth >= PIC16Overlay::StartIndirectCallColor) { + // All functions called from an indirectly called function are given + // an unique color. + if (Color < PIC16Overlay::StartIndirectCallColor && + Depth >= PIC16Overlay::StartIndirectCallColor) + setColor(CGN->getFunction(), Depth); + + for (unsigned int i = 0; i < CGN->size(); i++) + DFSTraverse((*CGN)[i], ++IndirectCallColor); + return; + } + // Just return if the node already has a color greater than the current + // depth. A node must be colored with the maximum depth that it has. + if (Color >= Depth) + return; + + Depth = ModifyDepthForInterrupt(CGN, Depth); + setColor(CGN->getFunction(), Depth); + } + + // Color all children of this node with color depth+1. + for (unsigned int i = 0; i < CGN->size(); i++) + DFSTraverse((*CGN)[i], Depth+1); +} + +unsigned PIC16FrameOverlay::ModifyDepthForInterrupt(CallGraphNode *CGN, + unsigned Depth) { + Function *Fn = CGN->getFunction(); + + // Return original Depth if function or section for function do not exist. + if (!Fn || !Fn->hasSection()) + return Depth; + + // Return original Depth if this function is not marked as interrupt. + if (Fn->getSection().find("interrupt") == string::npos) + return Depth; + + Depth = Depth + InterruptDepth; + return Depth; +} + +void PIC16FrameOverlay::setColor(Function *Fn, unsigned Color) { + std::string Section = ""; + if (Fn->hasSection()) + Section = Fn->getSection(); + + size_t Pos = Section.find(OverlayStr); + + // Convert Color to string. + std::stringstream ss; + ss << Color; + std::string ColorString = ss.str(); + + // If color is already set then reset it with the new value. Else append + // the Color string to section. + if (Pos != std::string::npos) { + Pos += OverlayStr.length(); + char c = Section.at(Pos); + unsigned OldColorLength = 0; + while (c >= '0' && c<= '9') { + OldColorLength++; + if (Pos < Section.length() - 1) + Pos++; + else + break; + c = Section.at(Pos); + } + // Replace old color with new one. + Section.replace(Pos-OldColorLength +1, OldColorLength, ColorString); + } + else { + // Append Color information to section string. + if (Fn->hasSection()) + Section.append(" "); + Section.append(OverlayStr + ColorString); + } + Fn->setSection(Section); +} + +unsigned PIC16FrameOverlay::getColor(Function *Fn) { + int Color = 0; + if (!Fn->hasSection()) + return 0; + + std::string Section = Fn->getSection(); + size_t Pos = Section.find(OverlayStr); + + // Return 0 if Color is not set. + if (Pos == std::string::npos) + return 0; + + // Set Pos to after "Overlay=". + Pos += OverlayStr.length(); + char c = Section.at(Pos); + std::string ColorString = ""; + + // Find the string representing Color. A Color can only consist of digits. + while (c >= '0' && c<= '9') { + ColorString.append(1,c); + if (Pos < Section.length() - 1) + Pos++; + else + break; + c = Section.at(Pos); + } + Color = atoi(ColorString.c_str()); + + return Color; +} + +bool PIC16FrameOverlay::runOnModule(Module &M) { + CallGraph &CG = getAnalysis<CallGraph>(); + CallGraphNode *ECN = CG.getExternalCallingNode(); + + MarkIndirectlyCalledFunctions(M); + // Since External Calling Node is the base function, do a depth first + // traversal of CallGraph with ECN as root. Each node with be marked with + // a color that is max(color(callers)) + 1. + if(ECN) { + DFSTraverse(ECN, 0); + } + return false; +} + +void PIC16FrameOverlay::MarkIndirectlyCalledFunctions(Module &M) { + // If the use of a function is not a call instruction then this + // function might be called indirectly. In that case give it + // an unique color. + for (Module::iterator MI = M.begin(), E = M.end(); MI != E; ++MI) { + for (Value::use_iterator I = MI->use_begin(), E = MI->use_end(); I != E; + ++I) { + if ((!isa<CallInst>(I) && !isa<InvokeInst>(I)) + || !CallSite(cast<Instruction>(I)).isCallee(I)) { + setColor(MI, ++IndirectCallColor); + break; + } + } + } +} diff --git a/lib/Target/PIC16/PIC16Passes/PIC16Overlay.h b/lib/Target/PIC16/PIC16Passes/PIC16Overlay.h new file mode 100644 index 0000000..d70c4e7 --- /dev/null +++ b/lib/Target/PIC16/PIC16Passes/PIC16Overlay.h @@ -0,0 +1,55 @@ +//===-- PIC16FrameOverlay.h - Interface for PIC16 Frame Overlay -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the PIC16 Overlay infrastructure. +// +//===----------------------------------------------------------------------===// + +#ifndef PIC16FRAMEOVERLAY_H +#define PIC16FRAMEOVERLAY_H + +#include "llvm/Analysis/CallGraph.h" +#include "llvm/Pass.h" +#include "llvm/CallGraphSCCPass.h" + +using std::string; +using namespace llvm; + +namespace llvm { + namespace PIC16Overlay { + enum OverlayConsts { + StartInterruptColor = 200, + StartIndirectCallColor = 300 + }; + } + class PIC16FrameOverlay : public ModulePass { + std::string OverlayStr; + unsigned InterruptDepth; + unsigned IndirectCallColor; + public: + static char ID; // Class identification + PIC16FrameOverlay() : ModulePass(&ID) { + OverlayStr = "Overlay="; + InterruptDepth = PIC16Overlay::StartInterruptColor; + IndirectCallColor = PIC16Overlay::StartIndirectCallColor; + } + + virtual void getAnalysisUsage(AnalysisUsage &AU) const; + virtual bool runOnModule(Module &M); + + private: + unsigned getColor(Function *Fn); + void setColor(Function *Fn, unsigned Color); + unsigned ModifyDepthForInterrupt(CallGraphNode *CGN, unsigned Depth); + void MarkIndirectlyCalledFunctions(Module &M); + void DFSTraverse(CallGraphNode *CGN, unsigned Depth); + }; +} // End of namespace + +#endif diff --git a/lib/Target/PIC16/PIC16Section.cpp b/lib/Target/PIC16/PIC16Section.cpp new file mode 100644 index 0000000..a96ebb8 --- /dev/null +++ b/lib/Target/PIC16/PIC16Section.cpp @@ -0,0 +1,96 @@ +//===-- PIC16Section.cpp - PIC16 Section ----------- --------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "PIC16.h" +#include "PIC16ABINames.h" +#include "PIC16Section.h" +#include "llvm/MC/MCContext.h" +#include "llvm/Support/raw_ostream.h" +using namespace llvm; + + +// This is the only way to create a PIC16Section. Sections created here +// do not need to be explicitly deleted as they are managed by auto_ptrs. +PIC16Section *PIC16Section::Create(const StringRef &Name, + PIC16SectionType Ty, + const std::string &Address, + int Color, MCContext &Ctx) { + + /// Determine the internal SectionKind info. + /// Users of PIC16Section class should not need to know the internal + /// SectionKind. They should work only with PIC16SectionType. + /// + /// PIC16 Terminology for section kinds is as below. + /// UDATA - BSS + /// IDATA - initialized data (equiv to Metadata) + /// ROMDATA - ReadOnly. + /// UDATA_OVR - Sections that can be overlaid. Section of such type is + /// used to contain function autos an frame. We can think of + /// it as equiv to llvm ThreadBSS) + /// UDATA_SHR - Shared RAM. Memory area that is mapped to all banks. + + SectionKind K; + switch (Ty) { + default: llvm_unreachable ("can not create unknown section type"); + case UDATA_OVR: { + K = SectionKind::getThreadBSS(); + break; + } + case UDATA_SHR: + case UDATA: { + K = SectionKind::getBSS(); + break; + } + case ROMDATA: + case IDATA: { + K = SectionKind::getMetadata(); + break; + } + case CODE: { + K = SectionKind::getText(); + break; + } + + } + + // Create the Section. + PIC16Section *S = new (Ctx) PIC16Section(Name, K, Address, Color); + S->T = Ty; + return S; +} + +// A generic way to print all types of sections. +void PIC16Section::PrintSwitchToSection(const MCAsmInfo &MAI, + raw_ostream &OS) const { + + // If the section is overlaid(i.e. it has a color), print overlay name for + // it. Otherwise print its normal name. + if (Color != -1) + OS << PAN::getOverlayName(getName(), Color) << '\t'; + else + OS << getName() << '\t'; + + // Print type. + switch (getType()) { + default : llvm_unreachable ("unknown section type"); + case UDATA: OS << "UDATA"; break; + case IDATA: OS << "IDATA"; break; + case ROMDATA: OS << "ROMDATA"; break; + case UDATA_SHR: OS << "UDATA_SHR"; break; + case UDATA_OVR: OS << "UDATA_OVR"; break; + case CODE: OS << "CODE"; break; + } + + OS << '\t'; + + // Print Address. + OS << Address; + + OS << '\n'; +} diff --git a/lib/Target/PIC16/PIC16Section.h b/lib/Target/PIC16/PIC16Section.h new file mode 100644 index 0000000..3a8bbfb --- /dev/null +++ b/lib/Target/PIC16/PIC16Section.h @@ -0,0 +1,92 @@ +//===- PIC16Section.h - PIC16-specific section representation -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the PIC16Section class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_PIC16SECTION_H +#define LLVM_PIC16SECTION_H + +#include "llvm/MC/MCSection.h" +#include "llvm/GlobalVariable.h" +#include <vector> + +namespace llvm { + /// PIC16Section - Represents a physical section in PIC16 COFF. + /// Contains data objects. + /// + class PIC16Section : public MCSection { + /// PIC16 Sections does not really use the SectionKind class to + /// to distinguish between various types of sections. PIC16 maintain + /// its own Section Type info. See the PIC16SectionType enum in PIC16.h + /// for various section types. + PIC16SectionType T; + + /// Name of the section to uniquely identify it. + std::string Name; + + /// User can specify an address at which a section should be placed. + /// Negative value here means user hasn't specified any. + std::string Address; + + /// Overlay information - Sections with same color can be overlaid on + /// one another. + int Color; + + /// Total size of all data objects contained here. + unsigned Size; + + PIC16Section(const StringRef &name, SectionKind K, const std::string &addr, + int color) + : MCSection(K), Name(name), Address(addr), Color(color) { + } + + public: + /// Return the name of the section. + const std::string &getName() const { return Name; } + + /// Return the Address of the section. + const std::string &getAddress() const { return Address; } + + /// Return the Color of the section. + int getColor() const { return Color; } + void setColor(int color) { Color = color; } + + /// Return the size of the section. + unsigned getSize() const { return Size; } + void setSize(unsigned size) { Size = size; } + + /// Conatined data objects. + std::vector<const GlobalVariable *>Items; + + /// Check section type. + bool isUDATA_Type() const { return T == UDATA; } + bool isIDATA_Type() const { return T == IDATA; } + bool isROMDATA_Type() const { return T == ROMDATA; } + bool isUDATA_OVR_Type() const { return T == UDATA_OVR; } + bool isUDATA_SHR_Type() const { return T == UDATA_SHR; } + bool isCODE_Type() const { return T == CODE; } + + PIC16SectionType getType() const { return T; } + + /// This would be the only way to create a section. + static PIC16Section *Create(const StringRef &Name, PIC16SectionType Ty, + const std::string &Address, int Color, + MCContext &Ctx); + + /// Override this as PIC16 has its own way of printing switching + /// to a section. + virtual void PrintSwitchToSection(const MCAsmInfo &MAI, + raw_ostream &OS) const; + }; + +} // end namespace llvm + +#endif diff --git a/lib/Target/PIC16/PIC16TargetObjectFile.cpp b/lib/Target/PIC16/PIC16TargetObjectFile.cpp index a2a4c09..7eedf7f 100644 --- a/lib/Target/PIC16/PIC16TargetObjectFile.cpp +++ b/lib/Target/PIC16/PIC16TargetObjectFile.cpp @@ -8,9 +8,9 @@ //===----------------------------------------------------------------------===// #include "PIC16TargetObjectFile.h" -#include "MCSectionPIC16.h" #include "PIC16ISelLowering.h" #include "PIC16TargetMachine.h" +#include "PIC16Section.h" #include "llvm/DerivedTypes.h" #include "llvm/Module.h" #include "llvm/MC/MCSection.h" @@ -19,75 +19,118 @@ using namespace llvm; -MCSectionPIC16 *MCSectionPIC16::Create(const StringRef &Name, SectionKind K, - int Address, int Color, MCContext &Ctx) { - return new (Ctx) MCSectionPIC16(Name, K, Address, Color); +PIC16TargetObjectFile::PIC16TargetObjectFile() { } +PIC16TargetObjectFile::~PIC16TargetObjectFile() { +} -void MCSectionPIC16::PrintSwitchToSection(const MCAsmInfo &MAI, - raw_ostream &OS) const { - OS << getName() << '\n'; +/// Find a pic16 section. Return null if not found. Do not create one. +PIC16Section *PIC16TargetObjectFile:: +findPIC16Section(const std::string &Name) { + /// Return if we have an already existing one. + PIC16Section *Entry = SectionsByName[Name]; + if (Entry) + return Entry; + + return NULL; } +/// Find a pic16 section. If not found, create one. +PIC16Section *PIC16TargetObjectFile:: +getPIC16Section(const std::string &Name, PIC16SectionType Ty, + const std::string &Address, int Color) const { + /// Return if we have an already existing one. + PIC16Section *&Entry = SectionsByName[Name]; + if (Entry) + return Entry; -PIC16TargetObjectFile::PIC16TargetObjectFile() - : ExternalVarDecls(0), ExternalVarDefs(0) { + + Entry = PIC16Section::Create(Name, Ty, Address, Color, getContext()); + return Entry; } -const MCSectionPIC16 *PIC16TargetObjectFile:: -getPIC16Section(const char *Name, SectionKind Kind, - int Address, int Color) const { - MCSectionPIC16 *&Entry = SectionsByName[Name]; +/// Find a standard pic16 data section. If not found, create one and keep +/// track of it by adding it to appropriate std section list. +PIC16Section *PIC16TargetObjectFile:: +getPIC16DataSection(const std::string &Name, PIC16SectionType Ty, + const std::string &Address, int Color) const { + + /// Return if we have an already existing one. + PIC16Section *&Entry = SectionsByName[Name]; if (Entry) return Entry; - return Entry = MCSectionPIC16::Create(Name, Kind, Address, Color, - getContext()); -} + /// Else create a new one and add it to appropriate section list. + Entry = PIC16Section::Create(Name, Ty, Address, Color, getContext()); -void PIC16TargetObjectFile::Initialize(MCContext &Ctx, const TargetMachine &tm){ - TargetLoweringObjectFile::Initialize(Ctx, tm); - TM = &tm; - - BSSSection = getPIC16Section("udata.# UDATA", MCSectionPIC16::UDATA_Kind()); - ReadOnlySection = getPIC16Section("romdata.# ROMDATA", - MCSectionPIC16::ROMDATA_Kind()); - DataSection = getPIC16Section("idata.# IDATA", MCSectionPIC16::IDATA_Kind()); - - // Need because otherwise a .text symbol is emitted by DwarfWriter - // in BeginModule, and gpasm cribbs for that .text symbol. - TextSection = getPIC16Section("", SectionKind::getText()); + switch (Ty) { + default: llvm_unreachable ("unknow standard section type."); + case UDATA: UDATASections_.push_back(Entry); break; + case IDATA: IDATASections_.push_back(Entry); break; + case ROMDATA: ROMDATASection_ = Entry; break; + } - ROSections.push_back(new PIC16Section((MCSectionPIC16*)ReadOnlySection)); - - // FIXME: I don't know what the classification of these sections really is. - // These aren't really objects belonging to any section. Just emit them - // in AsmPrinter and remove this code from here. - ExternalVarDecls = new PIC16Section(getPIC16Section("ExternalVarDecls", - SectionKind::getMetadata())); - ExternalVarDefs = new PIC16Section(getPIC16Section("ExternalVarDefs", - SectionKind::getMetadata())); + return Entry; } + -const MCSection *PIC16TargetObjectFile:: -getSectionForFunction(const std::string &FnName) const { - std::string T = PAN::getCodeSectionName(FnName); - return getPIC16Section(T.c_str(), SectionKind::getText()); +/// Find a standard pic16 autos section. If not found, create one and keep +/// track of it by adding it to appropriate std section list. +PIC16Section *PIC16TargetObjectFile:: +getPIC16AutoSection(const std::string &Name, PIC16SectionType Ty, + const std::string &Address, int Color) const { + + /// Return if we have an already existing one. + PIC16Section *&Entry = SectionsByName[Name]; + if (Entry) + return Entry; + + + /// Else create a new one and add it to appropriate section list. + Entry = PIC16Section::Create(Name, Ty, Address, Color, getContext()); + + assert (Ty == UDATA_OVR && "incorrect section type for autos"); + AUTOSections_.push_back(Entry); + + return Entry; } + +/// Find a pic16 user section. If not found, create one and keep +/// track of it by adding it to appropriate std section list. +PIC16Section *PIC16TargetObjectFile:: +getPIC16UserSection(const std::string &Name, PIC16SectionType Ty, + const std::string &Address, int Color) const { + + /// Return if we have an already existing one. + PIC16Section *&Entry = SectionsByName[Name]; + if (Entry) + return Entry; -const MCSection *PIC16TargetObjectFile:: -getSectionForFunctionFrame(const std::string &FnName) const { - std::string T = PAN::getFrameSectionName(FnName); - return getPIC16Section(T.c_str(), SectionKind::getDataRel()); + /// Else create a new one and add it to appropriate section list. + Entry = PIC16Section::Create(Name, Ty, Address, Color, getContext()); + + USERSections_.push_back(Entry); + + return Entry; } +/// Do some standard initialization. +void PIC16TargetObjectFile::Initialize(MCContext &Ctx, const TargetMachine &tm){ + TargetLoweringObjectFile::Initialize(Ctx, tm); + TM = &tm; + + ROMDATASection_ = NULL; +} + +/// allocateUDATA - Allocate a un-initialized global to an existing or new UDATA +/// section and return that section. const MCSection * -PIC16TargetObjectFile::getBSSSectionForGlobal(const GlobalVariable *GV) const { +PIC16TargetObjectFile::allocateUDATA(const GlobalVariable *GV) const { assert(GV->hasInitializer() && "This global doesn't need space"); Constant *C = GV->getInitializer(); assert(C->isNullValue() && "Unitialized globals has non-zero initializer"); @@ -97,41 +140,37 @@ PIC16TargetObjectFile::getBSSSectionForGlobal(const GlobalVariable *GV) const { const Type *Ty = C->getType(); unsigned ValSize = TD->getTypeAllocSize(Ty); - // Go through all BSS Sections and assign this variable + // Go through all UDATA Sections and assign this variable // to the first available section having enough space. - PIC16Section *FoundBSS = NULL; - for (unsigned i = 0; i < BSSSections.size(); i++) { - if (DataBankSize - BSSSections[i]->Size >= ValSize) { - FoundBSS = BSSSections[i]; + PIC16Section *Found = NULL; + for (unsigned i = 0; i < UDATASections_.size(); i++) { + if (DataBankSize - UDATASections_[i]->getSize() >= ValSize) { + Found = UDATASections_[i]; break; } } - // No BSS section spacious enough was found. Crate a new one. - if (!FoundBSS) { - std::string name = PAN::getUdataSectionName(BSSSections.size()); - const MCSectionPIC16 *NewSection - = getPIC16Section(name.c_str(), MCSectionPIC16::UDATA_Kind()); - - FoundBSS = new PIC16Section(NewSection); - - // Add this newly created BSS section to the list of BSSSections. - BSSSections.push_back(FoundBSS); + // No UDATA section spacious enough was found. Crate a new one. + if (!Found) { + std::string name = PAN::getUdataSectionName(UDATASections_.size()); + Found = getPIC16DataSection(name.c_str(), UDATA); } - // Insert the GV into this BSS. - FoundBSS->Items.push_back(GV); - FoundBSS->Size += ValSize; - return FoundBSS->S_; + // Insert the GV into this UDATA section. + Found->Items.push_back(GV); + Found->setSize(Found->getSize() + ValSize); + return Found; } +/// allocateIDATA - allocate an initialized global into an existing +/// or new section and return that section. const MCSection * -PIC16TargetObjectFile::getIDATASectionForGlobal(const GlobalVariable *GV) const{ +PIC16TargetObjectFile::allocateIDATA(const GlobalVariable *GV) const{ assert(GV->hasInitializer() && "This global doesn't need space"); Constant *C = GV->getInitializer(); assert(!C->isNullValue() && "initialized globals has zero initializer"); assert(GV->getType()->getAddressSpace() == PIC16ISD::RAM_SPACE && - "can split initialized RAM data only"); + "can allocate initialized RAM data only"); // Find how much space this global needs. const TargetData *TD = TM->getTargetData(); @@ -140,64 +179,47 @@ PIC16TargetObjectFile::getIDATASectionForGlobal(const GlobalVariable *GV) const{ // Go through all IDATA Sections and assign this variable // to the first available section having enough space. - PIC16Section *FoundIDATA = NULL; - for (unsigned i = 0; i < IDATASections.size(); i++) { - if (DataBankSize - IDATASections[i]->Size >= ValSize) { - FoundIDATA = IDATASections[i]; + PIC16Section *Found = NULL; + for (unsigned i = 0; i < IDATASections_.size(); i++) { + if (DataBankSize - IDATASections_[i]->getSize() >= ValSize) { + Found = IDATASections_[i]; break; } } // No IDATA section spacious enough was found. Crate a new one. - if (!FoundIDATA) { - std::string name = PAN::getIdataSectionName(IDATASections.size()); - const MCSectionPIC16 *NewSection = - getPIC16Section(name.c_str(), MCSectionPIC16::IDATA_Kind()); - - FoundIDATA = new PIC16Section(NewSection); - - // Add this newly created IDATA section to the list of IDATASections. - IDATASections.push_back(FoundIDATA); + if (!Found) { + std::string name = PAN::getIdataSectionName(IDATASections_.size()); + Found = getPIC16DataSection(name.c_str(), IDATA); } // Insert the GV into this IDATA. - FoundIDATA->Items.push_back(GV); - FoundIDATA->Size += ValSize; - return FoundIDATA->S_; + Found->Items.push_back(GV); + Found->setSize(Found->getSize() + ValSize); + return Found; } -// Get the section for an automatic variable of a function. -// For PIC16 they are globals only with mangled names. +// Allocate a program memory variable into ROMDATA section. const MCSection * -PIC16TargetObjectFile::getSectionForAuto(const GlobalVariable *GV) const { +PIC16TargetObjectFile::allocateROMDATA(const GlobalVariable *GV) const { - const std::string name = PAN::getSectionNameForSym(GV->getName()); + std::string name = PAN::getRomdataSectionName(); + PIC16Section *S = getPIC16DataSection(name.c_str(), ROMDATA); - // Go through all Auto Sections and assign this variable - // to the appropriate section. - PIC16Section *FoundAutoSec = NULL; - for (unsigned i = 0; i < AutosSections.size(); i++) { - if (AutosSections[i]->S_->getName() == name) { - FoundAutoSec = AutosSections[i]; - break; - } - } - - // No Auto section was found. Crate a new one. - if (!FoundAutoSec) { - const MCSectionPIC16 *NewSection = - getPIC16Section(name.c_str(), MCSectionPIC16::UDATA_OVR_Kind()); - - FoundAutoSec = new PIC16Section(NewSection); + S->Items.push_back(GV); + return S; +} - // Add this newly created autos section to the list of AutosSections. - AutosSections.push_back(FoundAutoSec); - } +// Get the section for an automatic variable of a function. +// For PIC16 they are globals only with mangled names. +const MCSection * +PIC16TargetObjectFile::allocateAUTO(const GlobalVariable *GV) const { - // Insert the auto into this section. - FoundAutoSec->Items.push_back(GV); + const std::string name = PAN::getSectionNameForSym(GV->getName()); + PIC16Section *S = getPIC16AutoSection(name.c_str()); - return FoundAutoSec->S_; + S->Items.push_back(GV); + return S; } @@ -214,56 +236,35 @@ PIC16TargetObjectFile::SelectSectionForGlobal(const GlobalValue *GV1, if (!GV) return TargetLoweringObjectFile::SelectSectionForGlobal(GV1, Kind, Mang,TM); - // Record External Var Decls. - if (GV->isDeclaration()) { - ExternalVarDecls->Items.push_back(GV); - return ExternalVarDecls->S_; - } - assert(GV->hasInitializer() && "A def without initializer?"); // First, if this is an automatic variable for a function, get the section // name for it and return. std::string name = GV->getName(); if (PAN::isLocalName(name)) - return getSectionForAuto(GV); - - // Record Exteranl Var Defs. - if (GV->hasExternalLinkage() || GV->hasCommonLinkage()) - ExternalVarDefs->Items.push_back(GV); + return allocateAUTO(GV); // See if this is an uninitialized global. const Constant *C = GV->getInitializer(); if (C->isNullValue()) - return getBSSSectionForGlobal(GV); + return allocateUDATA(GV); // If this is initialized data in RAM. Put it in the correct IDATA section. if (GV->getType()->getAddressSpace() == PIC16ISD::RAM_SPACE) - return getIDATASectionForGlobal(GV); + return allocateIDATA(GV); // This is initialized data in rom, put it in the readonly section. if (GV->getType()->getAddressSpace() == PIC16ISD::ROM_SPACE) - return getROSectionForGlobal(GV); + return allocateROMDATA(GV); // Else let the default implementation take care of it. return TargetLoweringObjectFile::SelectSectionForGlobal(GV, Kind, Mang,TM); } -PIC16TargetObjectFile::~PIC16TargetObjectFile() { - for (unsigned i = 0; i < BSSSections.size(); i++) - delete BSSSections[i]; - for (unsigned i = 0; i < IDATASections.size(); i++) - delete IDATASections[i]; - for (unsigned i = 0; i < AutosSections.size(); i++) - delete AutosSections[i]; - for (unsigned i = 0; i < ROSections.size(); i++) - delete ROSections[i]; - delete ExternalVarDecls; - delete ExternalVarDefs; -} -/// getSpecialCasedSectionGlobals - Allow the target to completely override + +/// getExplicitSectionGlobal - Allow the target to completely override /// section assignment of a global. const MCSection *PIC16TargetObjectFile:: getExplicitSectionGlobal(const GlobalValue *GV, SectionKind Kind, @@ -274,167 +275,83 @@ getExplicitSectionGlobal(const GlobalValue *GV, SectionKind Kind, std::string SectName = GVar->getSection(); // If address for a variable is specified, get the address and create // section. + // FIXME: move this attribute checking in PAN. std::string AddrStr = "Address="; if (SectName.compare(0, AddrStr.length(), AddrStr) == 0) { std::string SectAddr = SectName.substr(AddrStr.length()); - return CreateSectionForGlobal(GVar, Mang, SectAddr); + return allocateAtGivenAddress(GVar, SectAddr); } // Create the section specified with section attribute. - return CreateSectionForGlobal(GVar, Mang); + return allocateInGivenSection(GVar); } - return getPIC16Section(GV->getSection().c_str(), Kind); + return getPIC16DataSection(GV->getSection().c_str(), UDATA); +} + +// Interface used by AsmPrinter to get a code section for a function. +const PIC16Section * +PIC16TargetObjectFile::SectionForCode(const std::string &FnName) const { + const std::string &sec_name = PAN::getCodeSectionName(FnName); + return getPIC16Section(sec_name, CODE); +} + +// Interface used by AsmPrinter to get a frame section for a function. +const PIC16Section * +PIC16TargetObjectFile::SectionForFrame(const std::string &FnName) const { + const std::string &sec_name = PAN::getFrameSectionName(FnName); + return getPIC16Section(sec_name, UDATA_OVR); } -// Create a new section for global variable. If Addr is given then create -// section at that address else create by name. +// Allocate a global var in existing or new section of given name. const MCSection * -PIC16TargetObjectFile::CreateSectionForGlobal(const GlobalVariable *GV, - Mangler *Mang, - const std::string &Addr) const { +PIC16TargetObjectFile::allocateInGivenSection(const GlobalVariable *GV) const { + // Determine the type of section that we need to create. + PIC16SectionType SecTy; + // See if this is an uninitialized global. const Constant *C = GV->getInitializer(); if (C->isNullValue()) - return CreateBSSSectionForGlobal(GV, Addr); - + SecTy = UDATA; // If this is initialized data in RAM. Put it in the correct IDATA section. - if (GV->getType()->getAddressSpace() == PIC16ISD::RAM_SPACE) - return CreateIDATASectionForGlobal(GV, Addr); - + else if (GV->getType()->getAddressSpace() == PIC16ISD::RAM_SPACE) + SecTy = IDATA; // This is initialized data in rom, put it in the readonly section. - if (GV->getType()->getAddressSpace() == PIC16ISD::ROM_SPACE) - return CreateROSectionForGlobal(GV, Addr); - - // Else let the default implementation take care of it. - return TargetLoweringObjectFile::SectionForGlobal(GV, Mang, *TM); + else if (GV->getType()->getAddressSpace() == PIC16ISD::ROM_SPACE) + SecTy = ROMDATA; + else + llvm_unreachable ("Could not determine section type for global"); + + PIC16Section *S = getPIC16UserSection(GV->getSection().c_str(), SecTy); + S->Items.push_back(GV); + return S; } -// Create uninitialized section for a variable. +// Allocate a global var in a new absolute sections at given address. const MCSection * -PIC16TargetObjectFile::CreateBSSSectionForGlobal(const GlobalVariable *GV, - std::string Addr) const { - assert(GV->hasInitializer() && "This global doesn't need space"); - assert(GV->getInitializer()->isNullValue() && - "Unitialized global has non-zero initializer"); - std::string Name; - // If address is given then create a section at that address else create a - // section by section name specified in GV. - PIC16Section *FoundBSS = NULL; - if (Addr.empty()) { - Name = GV->getSection() + " UDATA"; - for (unsigned i = 0; i < BSSSections.size(); i++) { - if (BSSSections[i]->S_->getName() == Name) { - FoundBSS = BSSSections[i]; - break; - } - } - } else { - std::string Prefix = GV->getNameStr() + "." + Addr + "."; - Name = PAN::getUdataSectionName(BSSSections.size(), Prefix) + " " + Addr; - } - - PIC16Section *NewBSS = FoundBSS; - if (NewBSS == NULL) { - const MCSectionPIC16 *NewSection = - getPIC16Section(Name.c_str(), MCSectionPIC16::UDATA_Kind()); - NewBSS = new PIC16Section(NewSection); - BSSSections.push_back(NewBSS); - } +PIC16TargetObjectFile::allocateAtGivenAddress(const GlobalVariable *GV, + const std::string &Addr) const { + // Determine the type of section that we need to create. + PIC16SectionType SecTy; - // Insert the GV into this BSS. - NewBSS->Items.push_back(GV); - - // We do not want to put any GV without explicit section into this section - // so set its size to DatabankSize. - NewBSS->Size = DataBankSize; - return NewBSS->S_; -} - -// Get rom section for a variable. Currently there can be only one rom section -// unless a variable explicitly requests a section. -const MCSection * -PIC16TargetObjectFile::getROSectionForGlobal(const GlobalVariable *GV) const { - ROSections[0]->Items.push_back(GV); - return ROSections[0]->S_; -} - -// Create initialized data section for a variable. -const MCSection * -PIC16TargetObjectFile::CreateIDATASectionForGlobal(const GlobalVariable *GV, - std::string Addr) const { - assert(GV->hasInitializer() && "This global doesn't need space"); - assert(!GV->getInitializer()->isNullValue() && - "initialized global has zero initializer"); - assert(GV->getType()->getAddressSpace() == PIC16ISD::RAM_SPACE && - "can be used for initialized RAM data only"); - - std::string Name; - // If address is given then create a section at that address else create a - // section by section name specified in GV. - PIC16Section *FoundIDATASec = NULL; - if (Addr.empty()) { - Name = GV->getSection() + " IDATA"; - for (unsigned i = 0; i < IDATASections.size(); i++) { - if (IDATASections[i]->S_->getName() == Name) { - FoundIDATASec = IDATASections[i]; - break; - } - } - } else { - std::string Prefix = GV->getNameStr() + "." + Addr + "."; - Name = PAN::getIdataSectionName(IDATASections.size(), Prefix) + " " + Addr; - } - - PIC16Section *NewIDATASec = FoundIDATASec; - if (NewIDATASec == NULL) { - const MCSectionPIC16 *NewSection = - getPIC16Section(Name.c_str(), MCSectionPIC16::IDATA_Kind()); - NewIDATASec = new PIC16Section(NewSection); - IDATASections.push_back(NewIDATASec); - } - // Insert the GV into this IDATA Section. - NewIDATASec->Items.push_back(GV); - // We do not want to put any GV without explicit section into this section - // so set its size to DatabankSize. - NewIDATASec->Size = DataBankSize; - return NewIDATASec->S_; + // See if this is an uninitialized global. + const Constant *C = GV->getInitializer(); + if (C->isNullValue()) + SecTy = UDATA; + // If this is initialized data in RAM. Put it in the correct IDATA section. + else if (GV->getType()->getAddressSpace() == PIC16ISD::RAM_SPACE) + SecTy = IDATA; + // This is initialized data in rom, put it in the readonly section. + else if (GV->getType()->getAddressSpace() == PIC16ISD::ROM_SPACE) + SecTy = ROMDATA; + else + llvm_unreachable ("Could not determine section type for global"); + + std::string Prefix = GV->getNameStr() + "." + Addr + "."; + std::string SName = PAN::getUserSectionName(Prefix); + PIC16Section *S = getPIC16UserSection(SName.c_str(), SecTy, Addr.c_str()); + S->Items.push_back(GV); + return S; } -// Create a section in rom for a variable. -const MCSection * -PIC16TargetObjectFile::CreateROSectionForGlobal(const GlobalVariable *GV, - std::string Addr) const { - assert(GV->getType()->getAddressSpace() == PIC16ISD::ROM_SPACE && - "can be used for ROM data only"); - - std::string Name; - // If address is given then create a section at that address else create a - // section by section name specified in GV. - PIC16Section *FoundROSec = NULL; - if (Addr.empty()) { - Name = GV->getSection() + " ROMDATA"; - for (unsigned i = 1; i < ROSections.size(); i++) { - if (ROSections[i]->S_->getName() == Name) { - FoundROSec = ROSections[i]; - break; - } - } - } else { - std::string Prefix = GV->getNameStr() + "." + Addr + "."; - Name = PAN::getRomdataSectionName(ROSections.size(), Prefix) + " " + Addr; - } - - PIC16Section *NewRomSec = FoundROSec; - if (NewRomSec == NULL) { - const MCSectionPIC16 *NewSection = - getPIC16Section(Name.c_str(), MCSectionPIC16::ROMDATA_Kind()); - NewRomSec = new PIC16Section(NewSection); - ROSections.push_back(NewRomSec); - } - - // Insert the GV into this ROM Section. - NewRomSec->Items.push_back(GV); - return NewRomSec->S_; -} diff --git a/lib/Target/PIC16/PIC16TargetObjectFile.h b/lib/Target/PIC16/PIC16TargetObjectFile.h index 75f6cce..ca07bed 100644 --- a/lib/Target/PIC16/PIC16TargetObjectFile.h +++ b/lib/Target/PIC16/PIC16TargetObjectFile.h @@ -10,6 +10,8 @@ #ifndef LLVM_TARGET_PIC16_TARGETOBJECTFILE_H #define LLVM_TARGET_PIC16_TARGETOBJECTFILE_H +#include "PIC16.h" +#include "PIC16ABINames.h" #include "llvm/Target/TargetLoweringObjectFile.h" #include "llvm/ADT/StringMap.h" #include <vector> @@ -19,7 +21,7 @@ namespace llvm { class GlobalVariable; class Module; class PIC16TargetMachine; - class MCSectionPIC16; + class PIC16Section; enum { DataBankSize = 80 }; @@ -29,91 +31,128 @@ namespace llvm { /// again and printing only those that match the current section. /// Keeping values inside the sections make printing a section much easier. /// - /// FIXME: MOVE ALL THIS STUFF TO MCSectionPIC16. + /// FIXME: MOVE ALL THIS STUFF TO PIC16Section. /// - struct PIC16Section { - const MCSectionPIC16 *S_; // Connection to actual Section. - unsigned Size; // Total size of the objects contained. - bool SectionPrinted; - std::vector<const GlobalVariable*> Items; - - PIC16Section(const MCSectionPIC16 *s) { - S_ = s; - Size = 0; - SectionPrinted = false; - } - bool isPrinted() const { return SectionPrinted; } - void setPrintedStatus(bool status) { SectionPrinted = status; } - }; - + + /// PIC16TargetObjectFile - PIC16 Object file. Contains data and code + /// sections. + // PIC16 Object File has two types of sections. + // 1. Standard Sections + // 1.1 un-initialized global data + // 1.2 initialized global data + // 1.3 program memory data + // 1.4 local variables of functions. + // 2. User defined sections + // 2.1 Objects placed in a specific section. (By _Section() macro) + // 2.2 Objects placed at a specific address. (By _Address() macro) class PIC16TargetObjectFile : public TargetLoweringObjectFile { /// SectionsByName - Bindings of names to allocated sections. - mutable StringMap<MCSectionPIC16*> SectionsByName; + mutable StringMap<PIC16Section*> SectionsByName; const TargetMachine *TM; - const MCSectionPIC16 *getPIC16Section(const char *Name, - SectionKind K, - int Address = -1, - int Color = -1) const; - public: - mutable std::vector<PIC16Section*> BSSSections; - mutable std::vector<PIC16Section*> IDATASections; - mutable std::vector<PIC16Section*> AutosSections; - mutable std::vector<PIC16Section*> ROSections; - mutable PIC16Section *ExternalVarDecls; - mutable PIC16Section *ExternalVarDefs; + /// Lists of sections. + /// Standard Data Sections. + mutable std::vector<PIC16Section *> UDATASections_; + mutable std::vector<PIC16Section *> IDATASections_; + mutable PIC16Section * ROMDATASection_; + + /// Standard Auto Sections. + mutable std::vector<PIC16Section *> AUTOSections_; + + /// User specified sections. + mutable std::vector<PIC16Section *> USERSections_; + + + /// Find or Create a PIC16 Section, without adding it to any + /// section list. + PIC16Section *getPIC16Section(const std::string &Name, + PIC16SectionType Ty, + const std::string &Address = "", + int Color = -1) const; + + /// Convenience functions. These wrappers also take care of adding + /// the newly created section to the appropriate sections list. + + /// Find or Create PIC16 Standard Data Section. + PIC16Section *getPIC16DataSection(const std::string &Name, + PIC16SectionType Ty, + const std::string &Address = "", + int Color = -1) const; + + /// Find or Create PIC16 Standard Auto Section. + PIC16Section *getPIC16AutoSection(const std::string &Name, + PIC16SectionType Ty = UDATA_OVR, + const std::string &Address = "", + int Color = -1) const; + + /// Find or Create PIC16 Standard Auto Section. + PIC16Section *getPIC16UserSection(const std::string &Name, + PIC16SectionType Ty, + const std::string &Address = "", + int Color = -1) const; + + /// Allocate Un-initialized data to a standard UDATA section. + const MCSection *allocateUDATA(const GlobalVariable *GV) const; + + /// Allocate Initialized data to a standard IDATA section. + const MCSection *allocateIDATA(const GlobalVariable *GV) const; + /// Allocate ROM data to the standard ROMDATA section. + const MCSection *allocateROMDATA(const GlobalVariable *GV) const; + + /// Allocate an AUTO variable to an AUTO section. + const MCSection *allocateAUTO(const GlobalVariable *GV) const; + + /// Allocate DATA in user specified section. + const MCSection *allocateInGivenSection(const GlobalVariable *GV) const; + + /// Allocate DATA at user specified address. + const MCSection *allocateAtGivenAddress(const GlobalVariable *GV, + const std::string &Addr) const; + + public: PIC16TargetObjectFile(); ~PIC16TargetObjectFile(); - void Initialize(MCContext &Ctx, const TargetMachine &TM); - + /// Return the section with the given Name. Null if not found. + PIC16Section *findPIC16Section(const std::string &Name); + + /// Override section allocations for user specified sections. virtual const MCSection * getExplicitSectionGlobal(const GlobalValue *GV, SectionKind Kind, Mangler *Mang, const TargetMachine &TM) const; + /// Select sections for Data and Auto variables(globals). virtual const MCSection *SelectSectionForGlobal(const GlobalValue *GV, SectionKind Kind, Mangler *Mang, const TargetMachine&) const; - const MCSection *getSectionForFunction(const std::string &FnName) const; - const MCSection *getSectionForFunctionFrame(const std::string &FnName)const; - - - private: - std::string getSectionNameForSym(const std::string &Sym) const; - - const MCSection *getBSSSectionForGlobal(const GlobalVariable *GV) const; - const MCSection *getIDATASectionForGlobal(const GlobalVariable *GV) const; - const MCSection *getSectionForAuto(const GlobalVariable *GV) const; - const MCSection *CreateBSSSectionForGlobal(const GlobalVariable *GV, - std::string Addr = "") const; - const MCSection *CreateIDATASectionForGlobal(const GlobalVariable *GV, - std::string Addr = "") const; - const MCSection *getROSectionForGlobal(const GlobalVariable *GV) const; - const MCSection *CreateROSectionForGlobal(const GlobalVariable *GV, - std::string Addr = "") const; - const MCSection *CreateSectionForGlobal(const GlobalVariable *GV, - Mangler *Mang, - const std::string &Addr = "") const; - public: - void SetSectionForGVs(Module &M); - const std::vector<PIC16Section*> &getBSSSections() const { - return BSSSections; + + /// Return a code section for a function. + const PIC16Section *SectionForCode (const std::string &FnName) const; + + /// Return a frame section for a function. + const PIC16Section *SectionForFrame (const std::string &FnName) const; + + /// Accessors for various section lists. + const std::vector<PIC16Section *> &UDATASections() const { + return UDATASections_; } - const std::vector<PIC16Section*> &getIDATASections() const { - return IDATASections; + const std::vector<PIC16Section *> &IDATASections() const { + return IDATASections_; } - const std::vector<PIC16Section*> &getAutosSections() const { - return AutosSections; + const PIC16Section *ROMDATASection() const { + return ROMDATASection_; } - const std::vector<PIC16Section*> &getROSections() const { - return ROSections; + const std::vector<PIC16Section *> &AUTOSections() const { + return AUTOSections_; + } + const std::vector<PIC16Section *> &USERSections() const { + return USERSections_; } - }; } // end namespace llvm diff --git a/lib/Target/PowerPC/AsmPrinter/PPCAsmPrinter.cpp b/lib/Target/PowerPC/AsmPrinter/PPCAsmPrinter.cpp index a0fba86..dc6b852 100644 --- a/lib/Target/PowerPC/AsmPrinter/PPCAsmPrinter.cpp +++ b/lib/Target/PowerPC/AsmPrinter/PPCAsmPrinter.cpp @@ -1129,7 +1129,7 @@ bool PPCDarwinAsmPrinter::doFinalization(Module &M) { // implementation of multiple entry points). If this doesn't occur, the // linker can safely perform dead code stripping. Since LLVM never generates // code that does this, it is always safe to set. - O << "\t.subsections_via_symbols\n"; + OutStreamer.EmitAssemblerFlag(MCStreamer::SubsectionsViaSymbols); return AsmPrinter::doFinalization(M); } diff --git a/lib/Target/README.txt b/lib/Target/README.txt index 89ea9d0..2740387 100644 --- a/lib/Target/README.txt +++ b/lib/Target/README.txt @@ -1594,23 +1594,8 @@ int int_char(char m) {if(m>7) return 0; return m;} //===---------------------------------------------------------------------===// -Instcombine should replace the load with a constant in: - - static const char x[4] = {'a', 'b', 'c', 'd'}; - - unsigned int y(void) { - return *(unsigned int *)x; - } - -It currently only does this transformation when the size of the constant -is the same as the size of the integer (so, try x[5]) and the last byte -is a null (making it a C string). There's no need for these restrictions. - -//===---------------------------------------------------------------------===// - -InstCombine's "turn load from constant into constant" optimization should be -more aggressive in the presence of bitcasts. For example, because of unions, -this code: +libanalysis is not aggressively folding vector bitcasts. For example, the +constant expressions generated when compiling this code: union vec2d { double e[2]; @@ -1624,23 +1609,29 @@ vec2d foo () { return (vec2d){ .v = a.v + b.v * (vec2d){{5,5}}.v }; } -Compiles into: +in X86-32 end up being: -@a = internal constant %0 { [2 x double] - [double 1.000000e+00, double 2.000000e+00] }, align 16 -@b = internal constant %0 { [2 x double] - [double 3.000000e+00, double 4.000000e+00] }, align 16 -... -define void @foo(%struct.vec2d* noalias nocapture sret %agg.result) nounwind { +define void @foo(%union.vec2d* noalias nocapture sret %agg.result) nounwind ssp { entry: - %0 = load <2 x double>* getelementptr (%struct.vec2d* - bitcast (%0* @a to %struct.vec2d*), i32 0, i32 0), align 16 - %1 = load <2 x double>* getelementptr (%struct.vec2d* - bitcast (%0* @b to %struct.vec2d*), i32 0, i32 0), align 16 + %agg.result.0 = getelementptr %union.vec2d* %agg.result, i32 0, i32 0 ; <<2 x double>*> [#uses=1] + store <2 x double> fadd (<2 x double> bitcast (<1 x i128> <i128 85070591730234615870450834276742070272> to <2 x double>), <2 x double> fmul (<2 x double> bitcast (<1 x i128> <i128 85153668479971173112514077617450647552> to <2 x double>), <2 x double> <double 5.000000e+00, double 5.000000e+00>)), <2 x double>* %agg.result.0, align 16 + ret void +} +and in X86-64 mode: -Instcombine should be able to optimize away the loads (and thus the globals). +define %0 @foo() nounwind readnone ssp { +entry: + %mrv5 = insertvalue %0 undef, double extractelement (<2 x double> fadd (<2 x double> bitcast (<1 x i128> <i128 85070591730234615870450834276742070272> to <2 x double>), <2 x double> fmul (<2 x double> bitcast (<1 x i128> <i128 85153668479971173112514077617450647552> to <2 x double>), <2 x double> bitcast (<1 x i128> <i128 85174437667405312423031577302488055808> to <2 x double>))), i32 0), 0 ; <%0> [#uses=1] + %mrv6 = insertvalue %0 %mrv5, double extractelement (<2 x double> fadd (<2 x double> bitcast (<1 x i128> <i128 85070591730234615870450834276742070272> to <2 x double>), <2 x double> fmul (<2 x double> bitcast (<1 x i128> <i128 85153668479971173112514077617450647552> to <2 x double>), <2 x double> bitcast (<1 x i128> <i128 85174437667405312423031577302488055808> to <2 x double>))), i32 1), 1 ; <%0> [#uses=1] + ret %0 %mrv6 +} -See also PR4973 +//===---------------------------------------------------------------------===// + +IPSCCP is propagating elements of first class aggregates, but is not propagating +the entire aggregate itself. This leads it to miss opportunities, for example +in test/Transforms/SCCP/ipsccp-basic.ll:test5b. //===---------------------------------------------------------------------===// + diff --git a/lib/Target/TargetIntrinsicInfo.cpp b/lib/Target/TargetIntrinsicInfo.cpp index d8da08e..e049a1d 100644 --- a/lib/Target/TargetIntrinsicInfo.cpp +++ b/lib/Target/TargetIntrinsicInfo.cpp @@ -12,11 +12,19 @@ //===----------------------------------------------------------------------===// #include "llvm/Target/TargetIntrinsicInfo.h" +#include "llvm/Function.h" +#include "llvm/ADT/StringMap.h" using namespace llvm; -TargetIntrinsicInfo::TargetIntrinsicInfo(const char **desc, unsigned count) - : Intrinsics(desc), NumIntrinsics(count) { +TargetIntrinsicInfo::TargetIntrinsicInfo() { } TargetIntrinsicInfo::~TargetIntrinsicInfo() { } + +unsigned TargetIntrinsicInfo::getIntrinsicID(Function *F) const { + const ValueName *ValName = F->getValueName(); + if (!ValName) + return 0; + return lookupName(ValName->getKeyData(), ValName->getKeyLength()); +} diff --git a/lib/Target/X86/AsmPrinter/X86ATTInstPrinter.cpp b/lib/Target/X86/AsmPrinter/X86ATTInstPrinter.cpp index bc70ffe..8ec5b62 100644 --- a/lib/Target/X86/AsmPrinter/X86ATTInstPrinter.cpp +++ b/lib/Target/X86/AsmPrinter/X86ATTInstPrinter.cpp @@ -57,9 +57,7 @@ void X86ATTInstPrinter::print_pcrel_imm(const MCInst *MI, unsigned OpNo) { } } -void X86ATTInstPrinter::printOperand(const MCInst *MI, unsigned OpNo, - const char *Modifier) { - assert(Modifier == 0 && "Modifiers should not be used"); +void X86ATTInstPrinter::printOperand(const MCInst *MI, unsigned OpNo) { const MCOperand &Op = MI->getOperand(OpNo); if (Op.isReg()) { diff --git a/lib/Target/X86/AsmPrinter/X86ATTInstPrinter.h b/lib/Target/X86/AsmPrinter/X86ATTInstPrinter.h index 5f28fa4..3180618 100644 --- a/lib/Target/X86/AsmPrinter/X86ATTInstPrinter.h +++ b/lib/Target/X86/AsmPrinter/X86ATTInstPrinter.h @@ -32,8 +32,7 @@ public: static const char *getRegisterName(unsigned RegNo); - void printOperand(const MCInst *MI, unsigned OpNo, - const char *Modifier = 0); + void printOperand(const MCInst *MI, unsigned OpNo); void printMemReference(const MCInst *MI, unsigned Op); void printLeaMemReference(const MCInst *MI, unsigned Op); void printSSECC(const MCInst *MI, unsigned Op); diff --git a/lib/Target/X86/AsmPrinter/X86AsmPrinter.cpp b/lib/Target/X86/AsmPrinter/X86AsmPrinter.cpp index 2a0290d..ae8e6d3 100644 --- a/lib/Target/X86/AsmPrinter/X86AsmPrinter.cpp +++ b/lib/Target/X86/AsmPrinter/X86AsmPrinter.cpp @@ -225,7 +225,7 @@ void X86AsmPrinter::printSymbolOperand(const MachineOperand &MO) { std::string Name = Mang->getMangledName(GV, Suffix, Suffix[0] != '\0'); if (Subtarget->isTargetCygMing()) { - X86COFFMachineModuleInfo &COFFMMI = + X86COFFMachineModuleInfo &COFFMMI = MMI->getObjFileInfo<X86COFFMachineModuleInfo>(); COFFMMI.DecorateCygMingName(Name, GV, *TM.getTargetData()); } @@ -288,12 +288,12 @@ void X86AsmPrinter::printSymbolOperand(const MachineOperand &MO) { std::string Name = Mang->makeNameProper(MO.getSymbolName()); if (MO.getTargetFlags() == X86II::MO_DARWIN_STUB) { Name += "$stub"; - MCSymbol *Sym = OutContext.GetOrCreateSymbol(Name); + MCSymbol *Sym = OutContext.GetOrCreateSymbol(StringRef(Name)); const MCSymbol *&StubSym = MMI->getObjFileInfo<MachineModuleInfoMachO>().getFnStubEntry(Sym); if (StubSym == 0) { Name.erase(Name.end()-5, Name.end()); - StubSym = OutContext.GetOrCreateSymbol(Name); + StubSym = OutContext.GetOrCreateSymbol(StringRef(Name)); } } @@ -870,49 +870,55 @@ void X86AsmPrinter::EmitEndOfAsmFile(Module &M) { // implementation of multiple entry points). If this doesn't occur, the // linker can safely perform dead code stripping. Since LLVM never // generates code that does this, it is always safe to set. - O << "\t.subsections_via_symbols\n"; - } - - if (Subtarget->isTargetCOFF()) { - // Necessary for dllexport support - std::vector<std::string> DLLExportedFns, DLLExportedGlobals; + OutStreamer.EmitAssemblerFlag(MCStreamer::SubsectionsViaSymbols); + } - X86COFFMachineModuleInfo &COFFMMI = + if (Subtarget->isTargetCOFF()) { + X86COFFMachineModuleInfo &COFFMMI = MMI->getObjFileInfo<X86COFFMachineModuleInfo>(); - TargetLoweringObjectFileCOFF &TLOFCOFF = - static_cast<TargetLoweringObjectFileCOFF&>(getObjFileLowering()); - for (Module::const_iterator I = M.begin(), E = M.end(); I != E; ++I) - if (I->hasDLLExportLinkage()) - DLLExportedFns.push_back(Mang->getMangledName(I)); - - for (Module::const_global_iterator I = M.global_begin(), E = M.global_end(); - I != E; ++I) - if (I->hasDLLExportLinkage()) - DLLExportedGlobals.push_back(Mang->getMangledName(I)); - - if (Subtarget->isTargetCygMing()) { - // Emit type information for external functions - for (X86COFFMachineModuleInfo::stub_iterator I = COFFMMI.stub_begin(), + // Emit type information for external functions + for (X86COFFMachineModuleInfo::stub_iterator I = COFFMMI.stub_begin(), E = COFFMMI.stub_end(); I != E; ++I) { - O << "\t.def\t " << I->getKeyData() + O << "\t.def\t " << I->getKeyData() << ";\t.scl\t" << COFF::C_EXT << ";\t.type\t" << (COFF::DT_FCN << COFF::N_BTSHFT) << ";\t.endef\n"; - } } - - // Output linker support code for dllexported globals on windows. - if (!DLLExportedGlobals.empty() || !DLLExportedFns.empty()) { - OutStreamer.SwitchSection(TLOFCOFF.getCOFFSection(".section .drectve", - true, + + if (Subtarget->isTargetCygMing()) { + // Necessary for dllexport support + std::vector<std::string> DLLExportedFns, DLLExportedGlobals; + + TargetLoweringObjectFileCOFF &TLOFCOFF = + static_cast<TargetLoweringObjectFileCOFF&>(getObjFileLowering()); + + for (Module::const_iterator I = M.begin(), E = M.end(); I != E; ++I) + if (I->hasDLLExportLinkage()) { + std::string Name = Mang->getMangledName(I); + COFFMMI.DecorateCygMingName(Name, I, *TM.getTargetData()); + DLLExportedFns.push_back(Name); + } + + for (Module::const_global_iterator I = M.global_begin(), + E = M.global_end(); I != E; ++I) + if (I->hasDLLExportLinkage()) { + std::string Name = Mang->getMangledName(I); + COFFMMI.DecorateCygMingName(Name, I, *TM.getTargetData()); + DLLExportedGlobals.push_back(Mang->getMangledName(I)); + } + + // Output linker support code for dllexported globals on windows. + if (!DLLExportedGlobals.empty() || !DLLExportedFns.empty()) { + OutStreamer.SwitchSection(TLOFCOFF.getCOFFSection(".section .drectve", + true, SectionKind::getMetadata())); - - for (unsigned i = 0, e = DLLExportedGlobals.size(); i != e; ++i) - O << "\t.ascii \" -export:" << DLLExportedGlobals[i] << ",data\"\n"; - - for (unsigned i = 0, e = DLLExportedFns.size(); i != e; ++i) - O << "\t.ascii \" -export:" << DLLExportedFns[i] << "\"\n"; + for (unsigned i = 0, e = DLLExportedGlobals.size(); i != e; ++i) + O << "\t.ascii \" -export:" << DLLExportedGlobals[i] << ",data\"\n"; + + for (unsigned i = 0, e = DLLExportedFns.size(); i != e; ++i) + O << "\t.ascii \" -export:" << DLLExportedFns[i] << "\"\n"; + } } } } diff --git a/lib/Target/X86/AsmPrinter/X86MCInstLower.cpp b/lib/Target/X86/AsmPrinter/X86MCInstLower.cpp index 5ccddf5..d498c57 100644 --- a/lib/Target/X86/AsmPrinter/X86MCInstLower.cpp +++ b/lib/Target/X86/AsmPrinter/X86MCInstLower.cpp @@ -38,10 +38,8 @@ MachineModuleInfoMachO &X86MCInstLower::getMachOMMI() const { MCSymbol *X86MCInstLower::GetPICBaseSymbol() const { - SmallString<60> Name; - raw_svector_ostream(Name) << AsmPrinter.MAI->getPrivateGlobalPrefix() - << AsmPrinter.getFunctionNumber() << "$pb"; - return Ctx.GetOrCreateSymbol(Name.str()); + return Ctx.GetOrCreateSymbol(Twine(AsmPrinter.MAI->getPrivateGlobalPrefix())+ + Twine(AsmPrinter.getFunctionNumber())+"$pb"); } @@ -308,6 +306,8 @@ void X86MCInstLower::Lower(const MachineInstr *MI, MCInst &OutMI) const { MI->dump(); llvm_unreachable("unknown operand type"); case MachineOperand::MO_Register: + // Ignore all implicit register operands. + if (MO.isImplicit()) continue; MCOp = MCOperand::CreateReg(MO.getReg()); break; case MachineOperand::MO_Immediate: @@ -449,10 +449,9 @@ void X86AsmPrinter::printInstructionThroughMCStreamer(const MachineInstr *MI) { // MYGLOBAL + (. - PICBASE) // However, we can't generate a ".", so just emit a new label here and refer // to it. We know that this operand flag occurs at most once per function. - SmallString<64> Name; - raw_svector_ostream(Name) << MAI->getPrivateGlobalPrefix() - << "picbaseref" << getFunctionNumber(); - MCSymbol *DotSym = OutContext.GetOrCreateSymbol(Name.str()); + const char *Prefix = MAI->getPrivateGlobalPrefix(); + MCSymbol *DotSym = OutContext.GetOrCreateSymbol(Twine(Prefix)+"picbaseref"+ + Twine(getFunctionNumber())); OutStreamer.EmitLabel(DotSym); // Now that we have emitted the label, lower the complex operand expression. diff --git a/lib/Target/X86/X86ISelLowering.cpp b/lib/Target/X86/X86ISelLowering.cpp index fadc818..e5e7bc8 100644 --- a/lib/Target/X86/X86ISelLowering.cpp +++ b/lib/Target/X86/X86ISelLowering.cpp @@ -2286,6 +2286,8 @@ static unsigned TranslateX86CC(ISD::CondCode SetCCOpcode, bool isFP, case ISD::SETNE: return X86::COND_NE; case ISD::SETUO: return X86::COND_P; case ISD::SETO: return X86::COND_NP; + case ISD::SETOEQ: + case ISD::SETUNE: return X86::COND_INVALID; } } @@ -2389,6 +2391,56 @@ bool X86::isPSHUFLWMask(ShuffleVectorSDNode *N) { return ::isPSHUFLWMask(M, N->getValueType(0)); } +/// isPALIGNRMask - Return true if the node specifies a shuffle of elements that +/// is suitable for input to PALIGNR. +static bool isPALIGNRMask(const SmallVectorImpl<int> &Mask, EVT VT, + bool hasSSSE3) { + int i, e = VT.getVectorNumElements(); + + // Do not handle v2i64 / v2f64 shuffles with palignr. + if (e < 4 || !hasSSSE3) + return false; + + for (i = 0; i != e; ++i) + if (Mask[i] >= 0) + break; + + // All undef, not a palignr. + if (i == e) + return false; + + // Determine if it's ok to perform a palignr with only the LHS, since we + // don't have access to the actual shuffle elements to see if RHS is undef. + bool Unary = Mask[i] < (int)e; + bool NeedsUnary = false; + + int s = Mask[i] - i; + + // Check the rest of the elements to see if they are consecutive. + for (++i; i != e; ++i) { + int m = Mask[i]; + if (m < 0) + continue; + + Unary = Unary && (m < (int)e); + NeedsUnary = NeedsUnary || (m < s); + + if (NeedsUnary && !Unary) + return false; + if (Unary && m != ((s+i) & (e-1))) + return false; + if (!Unary && m != (s+i)) + return false; + } + return true; +} + +bool X86::isPALIGNRMask(ShuffleVectorSDNode *N) { + SmallVector<int, 8> M; + N->getMask(M); + return ::isPALIGNRMask(M, N->getValueType(0), true); +} + /// isSHUFPMask - Return true if the specified VECTOR_SHUFFLE operand /// specifies a shuffle of elements that is suitable for input to SHUFP*. static bool isSHUFPMask(const SmallVectorImpl<int> &Mask, EVT VT) { @@ -2733,8 +2785,7 @@ bool X86::isMOVDDUPMask(ShuffleVectorSDNode *N) { } /// getShuffleSHUFImmediate - Return the appropriate immediate to shuffle -/// the specified isShuffleMask VECTOR_SHUFFLE mask with PSHUF* and SHUFP* -/// instructions. +/// the specified VECTOR_SHUFFLE mask with PSHUF* and SHUFP* instructions. unsigned X86::getShuffleSHUFImmediate(SDNode *N) { ShuffleVectorSDNode *SVOp = cast<ShuffleVectorSDNode>(N); int NumOperands = SVOp->getValueType(0).getVectorNumElements(); @@ -2753,8 +2804,7 @@ unsigned X86::getShuffleSHUFImmediate(SDNode *N) { } /// getShufflePSHUFHWImmediate - Return the appropriate immediate to shuffle -/// the specified isShuffleMask VECTOR_SHUFFLE mask with PSHUFHW -/// instructions. +/// the specified VECTOR_SHUFFLE mask with the PSHUFHW instruction. unsigned X86::getShufflePSHUFHWImmediate(SDNode *N) { ShuffleVectorSDNode *SVOp = cast<ShuffleVectorSDNode>(N); unsigned Mask = 0; @@ -2770,8 +2820,7 @@ unsigned X86::getShufflePSHUFHWImmediate(SDNode *N) { } /// getShufflePSHUFLWImmediate - Return the appropriate immediate to shuffle -/// the specified isShuffleMask VECTOR_SHUFFLE mask with PSHUFLW -/// instructions. +/// the specified VECTOR_SHUFFLE mask with the PSHUFLW instruction. unsigned X86::getShufflePSHUFLWImmediate(SDNode *N) { ShuffleVectorSDNode *SVOp = cast<ShuffleVectorSDNode>(N); unsigned Mask = 0; @@ -2786,6 +2835,23 @@ unsigned X86::getShufflePSHUFLWImmediate(SDNode *N) { return Mask; } +/// getShufflePALIGNRImmediate - Return the appropriate immediate to shuffle +/// the specified VECTOR_SHUFFLE mask with the PALIGNR instruction. +unsigned X86::getShufflePALIGNRImmediate(SDNode *N) { + ShuffleVectorSDNode *SVOp = cast<ShuffleVectorSDNode>(N); + EVT VVT = N->getValueType(0); + unsigned EltSize = VVT.getVectorElementType().getSizeInBits() >> 3; + int Val = 0; + + unsigned i, e; + for (i = 0, e = VVT.getVectorNumElements(); i != e; ++i) { + Val = SVOp->getMaskElt(i); + if (Val >= 0) + break; + } + return (Val - i) * EltSize; +} + /// isZeroNode - Returns true if Elt is a constant zero or a floating point /// constant +0.0. bool X86::isZeroNode(SDValue Elt) { @@ -5502,6 +5568,8 @@ SDValue X86TargetLowering::LowerSETCC(SDValue Op, SelectionDAG &DAG) { bool isFP = Op.getOperand(1).getValueType().isFloatingPoint(); unsigned X86CC = TranslateX86CC(CC, isFP, Op0, Op1, DAG); + if (X86CC == X86::COND_INVALID) + return SDValue(); SDValue Cond = EmitCmp(Op0, Op1, X86CC, DAG); return DAG.getNode(X86ISD::SETCC, dl, MVT::i8, @@ -5650,8 +5718,11 @@ SDValue X86TargetLowering::LowerSELECT(SDValue Op, SelectionDAG &DAG) { DebugLoc dl = Op.getDebugLoc(); SDValue CC; - if (Cond.getOpcode() == ISD::SETCC) - Cond = LowerSETCC(Cond, DAG); + if (Cond.getOpcode() == ISD::SETCC) { + SDValue NewCond = LowerSETCC(Cond, DAG); + if (NewCond.getNode()) + Cond = NewCond; + } // If condition flag is set by a X86ISD::CMP, then use it as the condition // setting operand in place of the X86ISD::SETCC. @@ -5724,8 +5795,11 @@ SDValue X86TargetLowering::LowerBRCOND(SDValue Op, SelectionDAG &DAG) { DebugLoc dl = Op.getDebugLoc(); SDValue CC; - if (Cond.getOpcode() == ISD::SETCC) - Cond = LowerSETCC(Cond, DAG); + if (Cond.getOpcode() == ISD::SETCC) { + SDValue NewCond = LowerSETCC(Cond, DAG); + if (NewCond.getNode()) + Cond = NewCond; + } #if 0 // FIXME: LowerXALUO doesn't handle these!! else if (Cond.getOpcode() == X86ISD::ADD || @@ -6274,6 +6348,7 @@ X86TargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op, SelectionDAG &DAG) { SDValue LHS = Op.getOperand(1); SDValue RHS = Op.getOperand(2); unsigned X86CC = TranslateX86CC(CC, true, LHS, RHS, DAG); + assert(X86CC != X86::COND_INVALID && "Unexpected illegal condition!"); SDValue Cond = DAG.getNode(Opc, dl, MVT::i32, LHS, RHS); SDValue SetCC = DAG.getNode(X86ISD::SETCC, dl, MVT::i8, DAG.getConstant(X86CC, MVT::i8), Cond); @@ -7274,7 +7349,7 @@ X86TargetLowering::isShuffleMaskLegal(const SmallVectorImpl<int> &M, if (VT.getSizeInBits() == 64) return false; - // FIXME: pshufb, blends, palignr, shifts. + // FIXME: pshufb, blends, shifts. return (VT.getVectorNumElements() == 2 || ShuffleVectorSDNode::isSplatMask(&M[0], VT) || isMOVLMask(M, VT) || @@ -7282,6 +7357,7 @@ X86TargetLowering::isShuffleMaskLegal(const SmallVectorImpl<int> &M, isPSHUFDMask(M, VT) || isPSHUFHWMask(M, VT) || isPSHUFLWMask(M, VT) || + isPALIGNRMask(M, VT, Subtarget->hasSSSE3()) || isUNPCKLMask(M, VT) || isUNPCKHMask(M, VT) || isUNPCKL_v_undef_Mask(M, VT) || diff --git a/lib/Target/X86/X86ISelLowering.h b/lib/Target/X86/X86ISelLowering.h index 2f7b8ba..66a9107 100644 --- a/lib/Target/X86/X86ISelLowering.h +++ b/lib/Target/X86/X86ISelLowering.h @@ -323,21 +323,27 @@ namespace llvm { /// specifies a shuffle of elements that is suitable for input to MOVDDUP. bool isMOVDDUPMask(ShuffleVectorSDNode *N); + /// isPALIGNRMask - Return true if the specified VECTOR_SHUFFLE operand + /// specifies a shuffle of elements that is suitable for input to PALIGNR. + bool isPALIGNRMask(ShuffleVectorSDNode *N); + /// getShuffleSHUFImmediate - Return the appropriate immediate to shuffle /// the specified isShuffleMask VECTOR_SHUFFLE mask with PSHUF* and SHUFP* /// instructions. unsigned getShuffleSHUFImmediate(SDNode *N); /// getShufflePSHUFHWImmediate - Return the appropriate immediate to shuffle - /// the specified isShuffleMask VECTOR_SHUFFLE mask with PSHUFHW - /// instructions. + /// the specified VECTOR_SHUFFLE mask with PSHUFHW instruction. unsigned getShufflePSHUFHWImmediate(SDNode *N); - /// getShufflePSHUFKWImmediate - Return the appropriate immediate to shuffle - /// the specified isShuffleMask VECTOR_SHUFFLE mask with PSHUFLW - /// instructions. + /// getShufflePSHUFLWImmediate - Return the appropriate immediate to shuffle + /// the specified VECTOR_SHUFFLE mask with PSHUFLW instruction. unsigned getShufflePSHUFLWImmediate(SDNode *N); + /// getShufflePALIGNRImmediate - Return the appropriate immediate to shuffle + /// the specified VECTOR_SHUFFLE mask with the PALIGNR instruction. + unsigned getShufflePALIGNRImmediate(SDNode *N); + /// isZeroNode - Returns true if Elt is a constant zero or a floating point /// constant +0.0. bool isZeroNode(SDValue Elt); diff --git a/lib/Target/X86/X86Instr64bit.td b/lib/Target/X86/X86Instr64bit.td index ef19823..c1b7b8f 100644 --- a/lib/Target/X86/X86Instr64bit.td +++ b/lib/Target/X86/X86Instr64bit.td @@ -368,19 +368,15 @@ def MOVSX64rm32: RI<0x63, MRMSrcMem, (outs GR64:$dst), (ins i32mem:$src), // Use movzbl instead of movzbq when the destination is a register; it's // equivalent due to implicit zero-extending, and it has a smaller encoding. def MOVZX64rr8 : I<0xB6, MRMSrcReg, (outs GR64:$dst), (ins GR8 :$src), - "movz{bl|x}\t{$src, ${dst:subreg32}|${dst:subreg32}, $src}", - [(set GR64:$dst, (zext GR8:$src))]>, TB; + "", [(set GR64:$dst, (zext GR8:$src))]>, TB; def MOVZX64rm8 : I<0xB6, MRMSrcMem, (outs GR64:$dst), (ins i8mem :$src), - "movz{bl|x}\t{$src, ${dst:subreg32}|${dst:subreg32}, $src}", - [(set GR64:$dst, (zextloadi64i8 addr:$src))]>, TB; + "", [(set GR64:$dst, (zextloadi64i8 addr:$src))]>, TB; // Use movzwl instead of movzwq when the destination is a register; it's // equivalent due to implicit zero-extending, and it has a smaller encoding. def MOVZX64rr16: I<0xB7, MRMSrcReg, (outs GR64:$dst), (ins GR16:$src), - "movz{wl|x}\t{$src, ${dst:subreg32}|${dst:subreg32}, $src}", - [(set GR64:$dst, (zext GR16:$src))]>, TB; + "", [(set GR64:$dst, (zext GR16:$src))]>, TB; def MOVZX64rm16: I<0xB7, MRMSrcMem, (outs GR64:$dst), (ins i16mem:$src), - "movz{wl|x}\t{$src, ${dst:subreg32}|${dst:subreg32}, $src}", - [(set GR64:$dst, (zextloadi64i16 addr:$src))]>, TB; + "", [(set GR64:$dst, (zextloadi64i16 addr:$src))]>, TB; // There's no movzlq instruction, but movl can be used for this purpose, using // implicit zero-extension. The preferred way to do 32-bit-to-64-bit zero @@ -390,11 +386,9 @@ def MOVZX64rm16: I<0xB7, MRMSrcMem, (outs GR64:$dst), (ins i16mem:$src), // necessarily all zero. In such cases, we fall back to these explicit zext // instructions. def MOVZX64rr32 : I<0x89, MRMDestReg, (outs GR64:$dst), (ins GR32:$src), - "mov{l}\t{$src, ${dst:subreg32}|${dst:subreg32}, $src}", - [(set GR64:$dst, (zext GR32:$src))]>; + "", [(set GR64:$dst, (zext GR32:$src))]>; def MOVZX64rm32 : I<0x8B, MRMSrcMem, (outs GR64:$dst), (ins i32mem:$src), - "mov{l}\t{$src, ${dst:subreg32}|${dst:subreg32}, $src}", - [(set GR64:$dst, (zextloadi64i32 addr:$src))]>; + "", [(set GR64:$dst, (zextloadi64i32 addr:$src))]>; // Any instruction that defines a 32-bit result leaves the high half of the // register. Truncate can be lowered to EXTRACT_SUBREG. CopyFromReg may @@ -1455,8 +1449,7 @@ def : Pat<(i64 0), // Materialize i64 constant where top 32-bits are zero. let AddedComplexity = 1, isReMaterializable = 1, isAsCheapAsAMove = 1 in def MOV64ri64i32 : Ii32<0xB8, AddRegFrm, (outs GR64:$dst), (ins i64i32imm:$src), - "mov{l}\t{$src, ${dst:subreg32}|${dst:subreg32}, $src}", - [(set GR64:$dst, i64immZExt32:$src)]>; + "", [(set GR64:$dst, i64immZExt32:$src)]>; //===----------------------------------------------------------------------===// // Thread Local Storage Instructions @@ -1515,6 +1508,7 @@ def XCHG64rm : RI<0x87, MRMSrcMem, (outs GR64:$dst), (ins i64mem:$ptr,GR64:$val) } // Optimized codegen when the non-memory output is not used. +let Defs = [EFLAGS] in { // FIXME: Use normal add / sub instructions and add lock prefix dynamically. def LOCK_ADD64mr : RI<0x03, MRMDestMem, (outs), (ins i64mem:$dst, GR64:$src2), "lock\n\t" @@ -1544,7 +1538,7 @@ def LOCK_INC64m : RI<0xFF, MRM0m, (outs), (ins i64mem:$dst), def LOCK_DEC64m : RI<0xFF, MRM1m, (outs), (ins i64mem:$dst), "lock\n\t" "dec{q}\t$dst", []>, LOCK; - +} // Atomic exchange, and, or, xor let Constraints = "$val = $dst", Defs = [EFLAGS], usesCustomDAGSchedInserter = 1 in { diff --git a/lib/Target/X86/X86InstrFormats.td b/lib/Target/X86/X86InstrFormats.td index abdb313..2f14bb0 100644 --- a/lib/Target/X86/X86InstrFormats.td +++ b/lib/Target/X86/X86InstrFormats.td @@ -224,10 +224,10 @@ class S3I<bits<8> o, Format F, dag outs, dag ins, string asm, list<dag> pattern> class SS38I<bits<8> o, Format F, dag outs, dag ins, string asm, list<dag> pattern> - : I<o, F, outs, ins, asm, pattern>, T8, Requires<[HasSSSE3]>; + : Ii8<o, F, outs, ins, asm, pattern>, T8, Requires<[HasSSSE3]>; class SS3AI<bits<8> o, Format F, dag outs, dag ins, string asm, list<dag> pattern> - : I<o, F, outs, ins, asm, pattern>, TA, Requires<[HasSSSE3]>; + : Ii8<o, F, outs, ins, asm, pattern>, TA, Requires<[HasSSSE3]>; // SSE4.1 Instruction Templates: // diff --git a/lib/Target/X86/X86InstrInfo.td b/lib/Target/X86/X86InstrInfo.td index 30b57d8..16b2af7 100644 --- a/lib/Target/X86/X86InstrInfo.td +++ b/lib/Target/X86/X86InstrInfo.td @@ -3392,11 +3392,9 @@ def BT32mi8 : Ii8<0xBA, MRM4m, (outs), (ins i32mem:$src1, i32i8imm:$src2), // of the register here. This has a smaller encoding and avoids a // partial-register update. def MOVSX16rr8 : I<0xBE, MRMSrcReg, (outs GR16:$dst), (ins GR8 :$src), - "movs{bl|x}\t{$src, ${dst:subreg32}|${dst:subreg32}, $src}", - [(set GR16:$dst, (sext GR8:$src))]>, TB; + "", [(set GR16:$dst, (sext GR8:$src))]>, TB; def MOVSX16rm8 : I<0xBE, MRMSrcMem, (outs GR16:$dst), (ins i8mem :$src), - "movs{bl|x}\t{$src, ${dst:subreg32}|${dst:subreg32}, $src}", - [(set GR16:$dst, (sextloadi16i8 addr:$src))]>, TB; + "", [(set GR16:$dst, (sextloadi16i8 addr:$src))]>, TB; def MOVSX32rr8 : I<0xBE, MRMSrcReg, (outs GR32:$dst), (ins GR8 :$src), "movs{bl|x}\t{$src, $dst|$dst, $src}", [(set GR32:$dst, (sext GR8:$src))]>, TB; @@ -3414,11 +3412,9 @@ def MOVSX32rm16: I<0xBF, MRMSrcMem, (outs GR32:$dst), (ins i16mem:$src), // of the register here. This has a smaller encoding and avoids a // partial-register update. def MOVZX16rr8 : I<0xB6, MRMSrcReg, (outs GR16:$dst), (ins GR8 :$src), - "movz{bl|x}\t{$src, ${dst:subreg32}|${dst:subreg32}, $src}", - [(set GR16:$dst, (zext GR8:$src))]>, TB; + "", [(set GR16:$dst, (zext GR8:$src))]>, TB; def MOVZX16rm8 : I<0xB6, MRMSrcMem, (outs GR16:$dst), (ins i8mem :$src), - "movz{bl|x}\t{$src, ${dst:subreg32}|${dst:subreg32}, $src}", - [(set GR16:$dst, (zextloadi16i8 addr:$src))]>, TB; + "", [(set GR16:$dst, (zextloadi16i8 addr:$src))]>, TB; def MOVZX32rr8 : I<0xB6, MRMSrcReg, (outs GR32:$dst), (ins GR8 :$src), "movz{bl|x}\t{$src, $dst|$dst, $src}", [(set GR32:$dst, (zext GR8:$src))]>, TB; @@ -3474,9 +3470,8 @@ def MOV8r0 : I<0x30, MRMInitReg, (outs GR8 :$dst), (ins), [(set GR8:$dst, 0)]>; // Use xorl instead of xorw since we don't care about the high 16 bits, // it's smaller, and it avoids a partial-register update. -def MOV16r0 : I<0x31, MRMInitReg, (outs GR16:$dst), (ins), - "xor{l}\t${dst:subreg32}, ${dst:subreg32}", - [(set GR16:$dst, 0)]>; +def MOV16r0 : I<0x31, MRMInitReg, (outs GR16:$dst), (ins), + "", [(set GR16:$dst, 0)]>; def MOV32r0 : I<0x31, MRMInitReg, (outs GR32:$dst), (ins), "xor{l}\t$dst, $dst", [(set GR32:$dst, 0)]>; @@ -3598,6 +3593,7 @@ def LXADD8 : I<0xC0, MRMSrcMem, (outs GR8:$dst), (ins i8mem:$ptr, GR8:$val), // Optimized codegen when the non-memory output is not used. // FIXME: Use normal add / sub instructions and add lock prefix dynamically. +let Defs = [EFLAGS] in { def LOCK_ADD8mr : I<0x00, MRMDestMem, (outs), (ins i8mem:$dst, GR8:$src2), "lock\n\t" "add{b}\t{$src2, $dst|$dst, $src2}", []>, LOCK; @@ -3667,6 +3663,7 @@ def LOCK_DEC16m : I<0xFF, MRM1m, (outs), (ins i16mem:$dst), def LOCK_DEC32m : I<0xFF, MRM1m, (outs), (ins i32mem:$dst), "lock\n\t" "dec{l}\t$dst", []>, LOCK; +} // Atomic exchange, and, or, xor let Constraints = "$val = $dst", Defs = [EFLAGS], diff --git a/lib/Target/X86/X86InstrSSE.td b/lib/Target/X86/X86InstrSSE.td index 96fc932..f4e97c9 100644 --- a/lib/Target/X86/X86InstrSSE.td +++ b/lib/Target/X86/X86InstrSSE.td @@ -197,6 +197,12 @@ def SHUFFLE_get_pshuflw_imm : SDNodeXForm<vector_shuffle, [{ return getI8Imm(X86::getShufflePSHUFLWImmediate(N)); }]>; +// SHUFFLE_get_palign_imm xform function: convert vector_shuffle mask to +// a PALIGNR imm. +def SHUFFLE_get_palign_imm : SDNodeXForm<vector_shuffle, [{ + return getI8Imm(X86::getShufflePALIGNRImmediate(N)); +}]>; + def splat_lo : PatFrag<(ops node:$lhs, node:$rhs), (vector_shuffle node:$lhs, node:$rhs), [{ ShuffleVectorSDNode *SVOp = cast<ShuffleVectorSDNode>(N); @@ -283,6 +289,11 @@ def pshuflw : PatFrag<(ops node:$lhs, node:$rhs), return X86::isPSHUFLWMask(cast<ShuffleVectorSDNode>(N)); }], SHUFFLE_get_pshuflw_imm>; +def palign : PatFrag<(ops node:$lhs, node:$rhs), + (vector_shuffle node:$lhs, node:$rhs), [{ + return X86::isPALIGNRMask(cast<ShuffleVectorSDNode>(N)); +}], SHUFFLE_get_palign_imm>; + //===----------------------------------------------------------------------===// // SSE scalar FP Instructions //===----------------------------------------------------------------------===// @@ -2062,6 +2073,7 @@ defm PACKSSDW : PDI_binop_rm_int<0x6B, "packssdw", int_x86_sse2_packssdw_128>; defm PACKUSWB : PDI_binop_rm_int<0x67, "packuswb", int_x86_sse2_packuswb_128>; // Shuffle and unpack instructions +let AddedComplexity = 5 in { def PSHUFDri : PDIi8<0x70, MRMSrcReg, (outs VR128:$dst), (ins VR128:$src1, i8imm:$src2), "pshufd\t{$src2, $src1, $dst|$dst, $src1, $src2}", @@ -2073,6 +2085,7 @@ def PSHUFDmi : PDIi8<0x70, MRMSrcMem, [(set VR128:$dst, (v4i32 (pshufd:$src2 (bc_v4i32(memopv2i64 addr:$src1)), (undef))))]>; +} // SSE2 with ImmT == Imm8 and XS prefix. def PSHUFHWri : Ii8<0x70, MRMSrcReg, @@ -2839,6 +2852,26 @@ let Constraints = "$src1 = $dst" in { imm:$src3))]>, OpSize; } +// palignr patterns. +let AddedComplexity = 5 in { +def : Pat<(v4i32 (palign:$src3 VR128:$src1, VR128:$src2)), + (PALIGNR128rr VR128:$src2, VR128:$src1, + (SHUFFLE_get_palign_imm VR128:$src3))>, + Requires<[HasSSSE3]>; +def : Pat<(v4f32 (palign:$src3 VR128:$src1, VR128:$src2)), + (PALIGNR128rr VR128:$src2, VR128:$src1, + (SHUFFLE_get_palign_imm VR128:$src3))>, + Requires<[HasSSSE3]>; +def : Pat<(v8i16 (palign:$src3 VR128:$src1, VR128:$src2)), + (PALIGNR128rr VR128:$src2, VR128:$src1, + (SHUFFLE_get_palign_imm VR128:$src3))>, + Requires<[HasSSSE3]>; +def : Pat<(v16i8 (palign:$src3 VR128:$src1, VR128:$src2)), + (PALIGNR128rr VR128:$src2, VR128:$src1, + (SHUFFLE_get_palign_imm VR128:$src3))>, + Requires<[HasSSSE3]>; +} + def : Pat<(X86pshufb VR128:$src, VR128:$mask), (PSHUFBrr128 VR128:$src, VR128:$mask)>, Requires<[HasSSSE3]>; def : Pat<(X86pshufb VR128:$src, (bc_v16i8 (memopv2i64 addr:$mask))), diff --git a/lib/Target/X86/X86Subtarget.cpp b/lib/Target/X86/X86Subtarget.cpp index fb76aeb..9525f04 100644 --- a/lib/Target/X86/X86Subtarget.cpp +++ b/lib/Target/X86/X86Subtarget.cpp @@ -382,7 +382,6 @@ X86Subtarget::X86Subtarget(const std::string &TT, const std::string &FS, , HasFMA4(false) , IsBTMemSlow(false) , DarwinVers(0) - , IsLinux(false) , stackAlignment(8) // FIXME: this is a known good value for Yonah. How about others? , MaxInlineSizeThreshold(128) @@ -434,7 +433,6 @@ X86Subtarget::X86Subtarget(const std::string &TT, const std::string &FS, } else if (TT.find("linux") != std::string::npos) { // Linux doesn't imply ELF, but we don't currently support anything else. TargetType = isELF; - IsLinux = true; } else if (TT.find("cygwin") != std::string::npos) { TargetType = isCygwin; } else if (TT.find("mingw") != std::string::npos) { diff --git a/lib/Target/X86/X86Subtarget.h b/lib/Target/X86/X86Subtarget.h index a2e368d..e64b854 100644 --- a/lib/Target/X86/X86Subtarget.h +++ b/lib/Target/X86/X86Subtarget.h @@ -82,9 +82,6 @@ protected: /// version of the platform, e.g. 8 = 10.4 (Tiger), 9 = 10.5 (Leopard), etc. unsigned char DarwinVers; // Is any darwin-x86 platform. - /// isLinux - true if this is a "linux" platform. - bool IsLinux; - /// stackAlignment - The minimum alignment known to hold of the stack frame on /// entry to the function and which must be maintained by every function. unsigned stackAlignment; @@ -195,11 +192,7 @@ public: /// getDarwinVers - Return the darwin version number, 8 = Tiger, 9 = Leopard, /// 10 = Snow Leopard, etc. unsigned getDarwinVers() const { return DarwinVers; } - - /// isLinux - Return true if the target is "Linux". - bool isLinux() const { return IsLinux; } - - + /// ClassifyGlobalReference - Classify a global variable reference for the /// current subtarget according to how we should reference it in a non-pcrel /// context. @@ -222,6 +215,14 @@ public: /// indicating the number of scheduling cycles of backscheduling that /// should be attempted. unsigned getSpecialAddressLatency() const; + + /// enablePostRAScheduler - X86 target is enabling post-alloc scheduling + /// at 'More' optimization level. + bool enablePostRAScheduler(CodeGenOpt::Level OptLevel, + TargetSubtarget::AntiDepBreakMode& mode) const { + mode = TargetSubtarget::ANTIDEP_CRITICAL; + return OptLevel >= CodeGenOpt::Default; + } }; } // End llvm namespace diff --git a/lib/Transforms/Hello/Hello.cpp b/lib/Transforms/Hello/Hello.cpp index 8000d0d..91534a7 100644 --- a/lib/Transforms/Hello/Hello.cpp +++ b/lib/Transforms/Hello/Hello.cpp @@ -30,9 +30,8 @@ namespace { virtual bool runOnFunction(Function &F) { HelloCounter++; - std::string fname = F.getName(); - EscapeString(fname); - errs() << "Hello: " << fname << "\n"; + errs() << "Hello: "; + errs().write_escaped(F.getName()) << '\n'; return false; } }; @@ -49,9 +48,8 @@ namespace { virtual bool runOnFunction(Function &F) { HelloCounter++; - std::string fname = F.getName(); - EscapeString(fname); - errs() << "Hello: " << fname << "\n"; + errs() << "Hello: "; + errs().write_escaped(F.getName()) << '\n'; return false; } diff --git a/lib/Transforms/IPO/CMakeLists.txt b/lib/Transforms/IPO/CMakeLists.txt index ec0f1e1..5c28801 100644 --- a/lib/Transforms/IPO/CMakeLists.txt +++ b/lib/Transforms/IPO/CMakeLists.txt @@ -9,7 +9,6 @@ add_llvm_library(LLVMipo GlobalOpt.cpp IPConstantPropagation.cpp IPO.cpp - IndMemRemoval.cpp InlineAlways.cpp InlineSimple.cpp Inliner.cpp diff --git a/lib/Transforms/IPO/FunctionAttrs.cpp b/lib/Transforms/IPO/FunctionAttrs.cpp index 7edaa7f..0701b94 100644 --- a/lib/Transforms/IPO/FunctionAttrs.cpp +++ b/lib/Transforms/IPO/FunctionAttrs.cpp @@ -153,7 +153,7 @@ bool FunctionAttrs::AddReadAttrs(const std::vector<CallGraphNode *> &SCC) { // Writes memory. Just give up. return false; - if (isa<MallocInst>(I)) + if (isMalloc(I)) // malloc claims not to write memory! PR3754. return false; @@ -267,11 +267,8 @@ bool FunctionAttrs::IsFunctionMallocLike(Function *F, // Check whether the pointer came from an allocation. case Instruction::Alloca: - case Instruction::Malloc: break; case Instruction::Call: - if (isMalloc(RVI)) - break; case Instruction::Invoke: { CallSite CS(RVI); if (CS.paramHasAttr(0, Attribute::NoAlias)) diff --git a/lib/Transforms/IPO/GlobalDCE.cpp b/lib/Transforms/IPO/GlobalDCE.cpp index 09f9e7c..8f4e8b3 100644 --- a/lib/Transforms/IPO/GlobalDCE.cpp +++ b/lib/Transforms/IPO/GlobalDCE.cpp @@ -149,8 +149,6 @@ bool GlobalDCE::runOnModule(Module &M) { // Make sure that all memory is released AliveGlobals.clear(); - // Remove dead metadata. - Changed |= M.getContext().RemoveDeadMetadata(); return Changed; } diff --git a/lib/Transforms/IPO/GlobalOpt.cpp b/lib/Transforms/IPO/GlobalOpt.cpp index a44386e..9ced2e8 100644 --- a/lib/Transforms/IPO/GlobalOpt.cpp +++ b/lib/Transforms/IPO/GlobalOpt.cpp @@ -822,140 +822,18 @@ static void ConstantPropUsersOf(Value *V, LLVMContext &Context) { /// malloc, there is no reason to actually DO the malloc. Instead, turn the /// malloc into a global, and any loads of GV as uses of the new global. static GlobalVariable *OptimizeGlobalAddressOfMalloc(GlobalVariable *GV, - MallocInst *MI, - LLVMContext &Context) { - DEBUG(errs() << "PROMOTING MALLOC GLOBAL: " << *GV << " MALLOC = " << *MI); - ConstantInt *NElements = cast<ConstantInt>(MI->getArraySize()); - - if (NElements->getZExtValue() != 1) { - // If we have an array allocation, transform it to a single element - // allocation to make the code below simpler. - Type *NewTy = ArrayType::get(MI->getAllocatedType(), - NElements->getZExtValue()); - MallocInst *NewMI = - new MallocInst(NewTy, Constant::getNullValue(Type::getInt32Ty(Context)), - MI->getAlignment(), MI->getName(), MI); - Value* Indices[2]; - Indices[0] = Indices[1] = Constant::getNullValue(Type::getInt32Ty(Context)); - Value *NewGEP = GetElementPtrInst::Create(NewMI, Indices, Indices + 2, - NewMI->getName()+".el0", MI); - MI->replaceAllUsesWith(NewGEP); - MI->eraseFromParent(); - MI = NewMI; - } - - // Create the new global variable. The contents of the malloc'd memory is - // undefined, so initialize with an undef value. - // FIXME: This new global should have the alignment returned by malloc. Code - // could depend on malloc returning large alignment (on the mac, 16 bytes) but - // this would only guarantee some lower alignment. - Constant *Init = UndefValue::get(MI->getAllocatedType()); - GlobalVariable *NewGV = new GlobalVariable(*GV->getParent(), - MI->getAllocatedType(), false, - GlobalValue::InternalLinkage, Init, - GV->getName()+".body", - GV, - GV->isThreadLocal()); - - // Anything that used the malloc now uses the global directly. - MI->replaceAllUsesWith(NewGV); - - Constant *RepValue = NewGV; - if (NewGV->getType() != GV->getType()->getElementType()) - RepValue = ConstantExpr::getBitCast(RepValue, - GV->getType()->getElementType()); - - // If there is a comparison against null, we will insert a global bool to - // keep track of whether the global was initialized yet or not. - GlobalVariable *InitBool = - new GlobalVariable(Context, Type::getInt1Ty(Context), false, - GlobalValue::InternalLinkage, - ConstantInt::getFalse(Context), GV->getName()+".init", - GV->isThreadLocal()); - bool InitBoolUsed = false; - - // Loop over all uses of GV, processing them in turn. - std::vector<StoreInst*> Stores; - while (!GV->use_empty()) - if (LoadInst *LI = dyn_cast<LoadInst>(GV->use_back())) { - while (!LI->use_empty()) { - Use &LoadUse = LI->use_begin().getUse(); - if (!isa<ICmpInst>(LoadUse.getUser())) - LoadUse = RepValue; - else { - ICmpInst *CI = cast<ICmpInst>(LoadUse.getUser()); - // Replace the cmp X, 0 with a use of the bool value. - Value *LV = new LoadInst(InitBool, InitBool->getName()+".val", CI); - InitBoolUsed = true; - switch (CI->getPredicate()) { - default: llvm_unreachable("Unknown ICmp Predicate!"); - case ICmpInst::ICMP_ULT: - case ICmpInst::ICMP_SLT: - LV = ConstantInt::getFalse(Context); // X < null -> always false - break; - case ICmpInst::ICMP_ULE: - case ICmpInst::ICMP_SLE: - case ICmpInst::ICMP_EQ: - LV = BinaryOperator::CreateNot(LV, "notinit", CI); - break; - case ICmpInst::ICMP_NE: - case ICmpInst::ICMP_UGE: - case ICmpInst::ICMP_SGE: - case ICmpInst::ICMP_UGT: - case ICmpInst::ICMP_SGT: - break; // no change. - } - CI->replaceAllUsesWith(LV); - CI->eraseFromParent(); - } - } - LI->eraseFromParent(); - } else { - StoreInst *SI = cast<StoreInst>(GV->use_back()); - // The global is initialized when the store to it occurs. - new StoreInst(ConstantInt::getTrue(Context), InitBool, SI); - SI->eraseFromParent(); - } - - // If the initialization boolean was used, insert it, otherwise delete it. - if (!InitBoolUsed) { - while (!InitBool->use_empty()) // Delete initializations - cast<Instruction>(InitBool->use_back())->eraseFromParent(); - delete InitBool; - } else - GV->getParent()->getGlobalList().insert(GV, InitBool); - - - // Now the GV is dead, nuke it and the malloc. - GV->eraseFromParent(); - MI->eraseFromParent(); - - // To further other optimizations, loop over all users of NewGV and try to - // constant prop them. This will promote GEP instructions with constant - // indices into GEP constant-exprs, which will allow global-opt to hack on it. - ConstantPropUsersOf(NewGV, Context); - if (RepValue != NewGV) - ConstantPropUsersOf(RepValue, Context); - - return NewGV; -} - -/// OptimizeGlobalAddressOfMalloc - This function takes the specified global -/// variable, and transforms the program as if it always contained the result of -/// the specified malloc. Because it is always the result of the specified -/// malloc, there is no reason to actually DO the malloc. Instead, turn the -/// malloc into a global, and any loads of GV as uses of the new global. -static GlobalVariable *OptimizeGlobalAddressOfMalloc(GlobalVariable *GV, CallInst *CI, BitCastInst *BCI, LLVMContext &Context, TargetData* TD) { + DEBUG(errs() << "PROMOTING MALLOC GLOBAL: " << *GV + << " CALL = " << *CI << " BCI = " << *BCI << '\n'); + const Type *IntPtrTy = TD->getIntPtrType(Context); - DEBUG(errs() << "PROMOTING MALLOC GLOBAL: " << *GV << " MALLOC = " << *CI); - - ConstantInt *NElements = cast<ConstantInt>(getMallocArraySize(CI, - Context, TD)); + Value* ArraySize = getMallocArraySize(CI, Context, TD); + assert(ArraySize && "not a malloc whose array size can be determined"); + ConstantInt *NElements = cast<ConstantInt>(ArraySize); if (NElements->getZExtValue() != 1) { // If we have an array allocation, transform it to a single element // allocation to make the code below simpler. @@ -976,9 +854,6 @@ static GlobalVariable *OptimizeGlobalAddressOfMalloc(GlobalVariable *GV, // Create the new global variable. The contents of the malloc'd memory is // undefined, so initialize with an undef value. - // FIXME: This new global should have the alignment returned by malloc. Code - // could depend on malloc returning large alignment (on the mac, 16 bytes) but - // this would only guarantee some lower alignment. const Type *MAT = getMallocAllocatedType(CI); Constant *Init = UndefValue::get(MAT); GlobalVariable *NewGV = new GlobalVariable(*GV->getParent(), @@ -1398,185 +1273,6 @@ static void RewriteUsesOfLoadForHeapSRoA(LoadInst *Load, } } -/// PerformHeapAllocSRoA - MI is an allocation of an array of structures. Break -/// it up into multiple allocations of arrays of the fields. -static GlobalVariable *PerformHeapAllocSRoA(GlobalVariable *GV, MallocInst *MI, - LLVMContext &Context){ - DEBUG(errs() << "SROA HEAP ALLOC: " << *GV << " MALLOC = " << *MI); - const StructType *STy = cast<StructType>(MI->getAllocatedType()); - - // There is guaranteed to be at least one use of the malloc (storing - // it into GV). If there are other uses, change them to be uses of - // the global to simplify later code. This also deletes the store - // into GV. - ReplaceUsesOfMallocWithGlobal(MI, GV); - - // Okay, at this point, there are no users of the malloc. Insert N - // new mallocs at the same place as MI, and N globals. - std::vector<Value*> FieldGlobals; - std::vector<MallocInst*> FieldMallocs; - - for (unsigned FieldNo = 0, e = STy->getNumElements(); FieldNo != e;++FieldNo){ - const Type *FieldTy = STy->getElementType(FieldNo); - const Type *PFieldTy = PointerType::getUnqual(FieldTy); - - GlobalVariable *NGV = - new GlobalVariable(*GV->getParent(), - PFieldTy, false, GlobalValue::InternalLinkage, - Constant::getNullValue(PFieldTy), - GV->getName() + ".f" + Twine(FieldNo), GV, - GV->isThreadLocal()); - FieldGlobals.push_back(NGV); - - MallocInst *NMI = new MallocInst(FieldTy, MI->getArraySize(), - MI->getName() + ".f" + Twine(FieldNo), MI); - FieldMallocs.push_back(NMI); - new StoreInst(NMI, NGV, MI); - } - - // The tricky aspect of this transformation is handling the case when malloc - // fails. In the original code, malloc failing would set the result pointer - // of malloc to null. In this case, some mallocs could succeed and others - // could fail. As such, we emit code that looks like this: - // F0 = malloc(field0) - // F1 = malloc(field1) - // F2 = malloc(field2) - // if (F0 == 0 || F1 == 0 || F2 == 0) { - // if (F0) { free(F0); F0 = 0; } - // if (F1) { free(F1); F1 = 0; } - // if (F2) { free(F2); F2 = 0; } - // } - Value *RunningOr = 0; - for (unsigned i = 0, e = FieldMallocs.size(); i != e; ++i) { - Value *Cond = new ICmpInst(MI, ICmpInst::ICMP_EQ, FieldMallocs[i], - Constant::getNullValue(FieldMallocs[i]->getType()), - "isnull"); - if (!RunningOr) - RunningOr = Cond; // First seteq - else - RunningOr = BinaryOperator::CreateOr(RunningOr, Cond, "tmp", MI); - } - - // Split the basic block at the old malloc. - BasicBlock *OrigBB = MI->getParent(); - BasicBlock *ContBB = OrigBB->splitBasicBlock(MI, "malloc_cont"); - - // Create the block to check the first condition. Put all these blocks at the - // end of the function as they are unlikely to be executed. - BasicBlock *NullPtrBlock = BasicBlock::Create(Context, "malloc_ret_null", - OrigBB->getParent()); - - // Remove the uncond branch from OrigBB to ContBB, turning it into a cond - // branch on RunningOr. - OrigBB->getTerminator()->eraseFromParent(); - BranchInst::Create(NullPtrBlock, ContBB, RunningOr, OrigBB); - - // Within the NullPtrBlock, we need to emit a comparison and branch for each - // pointer, because some may be null while others are not. - for (unsigned i = 0, e = FieldGlobals.size(); i != e; ++i) { - Value *GVVal = new LoadInst(FieldGlobals[i], "tmp", NullPtrBlock); - Value *Cmp = new ICmpInst(*NullPtrBlock, ICmpInst::ICMP_NE, GVVal, - Constant::getNullValue(GVVal->getType()), - "tmp"); - BasicBlock *FreeBlock = BasicBlock::Create(Context, "free_it", - OrigBB->getParent()); - BasicBlock *NextBlock = BasicBlock::Create(Context, "next", - OrigBB->getParent()); - BranchInst::Create(FreeBlock, NextBlock, Cmp, NullPtrBlock); - - // Fill in FreeBlock. - new FreeInst(GVVal, FreeBlock); - new StoreInst(Constant::getNullValue(GVVal->getType()), FieldGlobals[i], - FreeBlock); - BranchInst::Create(NextBlock, FreeBlock); - - NullPtrBlock = NextBlock; - } - - BranchInst::Create(ContBB, NullPtrBlock); - - // MI is no longer needed, remove it. - MI->eraseFromParent(); - - /// InsertedScalarizedLoads - As we process loads, if we can't immediately - /// update all uses of the load, keep track of what scalarized loads are - /// inserted for a given load. - DenseMap<Value*, std::vector<Value*> > InsertedScalarizedValues; - InsertedScalarizedValues[GV] = FieldGlobals; - - std::vector<std::pair<PHINode*, unsigned> > PHIsToRewrite; - - // Okay, the malloc site is completely handled. All of the uses of GV are now - // loads, and all uses of those loads are simple. Rewrite them to use loads - // of the per-field globals instead. - for (Value::use_iterator UI = GV->use_begin(), E = GV->use_end(); UI != E;) { - Instruction *User = cast<Instruction>(*UI++); - - if (LoadInst *LI = dyn_cast<LoadInst>(User)) { - RewriteUsesOfLoadForHeapSRoA(LI, InsertedScalarizedValues, PHIsToRewrite, - Context); - continue; - } - - // Must be a store of null. - StoreInst *SI = cast<StoreInst>(User); - assert(isa<ConstantPointerNull>(SI->getOperand(0)) && - "Unexpected heap-sra user!"); - - // Insert a store of null into each global. - for (unsigned i = 0, e = FieldGlobals.size(); i != e; ++i) { - const PointerType *PT = cast<PointerType>(FieldGlobals[i]->getType()); - Constant *Null = Constant::getNullValue(PT->getElementType()); - new StoreInst(Null, FieldGlobals[i], SI); - } - // Erase the original store. - SI->eraseFromParent(); - } - - // While we have PHIs that are interesting to rewrite, do it. - while (!PHIsToRewrite.empty()) { - PHINode *PN = PHIsToRewrite.back().first; - unsigned FieldNo = PHIsToRewrite.back().second; - PHIsToRewrite.pop_back(); - PHINode *FieldPN = cast<PHINode>(InsertedScalarizedValues[PN][FieldNo]); - assert(FieldPN->getNumIncomingValues() == 0 &&"Already processed this phi"); - - // Add all the incoming values. This can materialize more phis. - for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i) { - Value *InVal = PN->getIncomingValue(i); - InVal = GetHeapSROAValue(InVal, FieldNo, InsertedScalarizedValues, - PHIsToRewrite, Context); - FieldPN->addIncoming(InVal, PN->getIncomingBlock(i)); - } - } - - // Drop all inter-phi links and any loads that made it this far. - for (DenseMap<Value*, std::vector<Value*> >::iterator - I = InsertedScalarizedValues.begin(), E = InsertedScalarizedValues.end(); - I != E; ++I) { - if (PHINode *PN = dyn_cast<PHINode>(I->first)) - PN->dropAllReferences(); - else if (LoadInst *LI = dyn_cast<LoadInst>(I->first)) - LI->dropAllReferences(); - } - - // Delete all the phis and loads now that inter-references are dead. - for (DenseMap<Value*, std::vector<Value*> >::iterator - I = InsertedScalarizedValues.begin(), E = InsertedScalarizedValues.end(); - I != E; ++I) { - if (PHINode *PN = dyn_cast<PHINode>(I->first)) - PN->eraseFromParent(); - else if (LoadInst *LI = dyn_cast<LoadInst>(I->first)) - LI->eraseFromParent(); - } - - // The old global is now dead, remove it. - GV->eraseFromParent(); - - ++NumHeapSRA; - return cast<GlobalVariable>(FieldGlobals[0]); -} - /// PerformHeapAllocSRoA - CI is an allocation of an array of structures. Break /// it up into multiple allocations of arrays of the fields. static GlobalVariable *PerformHeapAllocSRoA(GlobalVariable *GV, @@ -1587,6 +1283,8 @@ static GlobalVariable *PerformHeapAllocSRoA(GlobalVariable *GV, << " BITCAST = " << *BCI << '\n'); const Type* MAT = getMallocAllocatedType(CI); const StructType *STy = cast<StructType>(MAT); + Value* ArraySize = getMallocArraySize(CI, Context, TD); + assert(ArraySize && "not a malloc whose array size can be determined"); // There is guaranteed to be at least one use of the malloc (storing // it into GV). If there are other uses, change them to be uses of @@ -1611,8 +1309,8 @@ static GlobalVariable *PerformHeapAllocSRoA(GlobalVariable *GV, GV->isThreadLocal()); FieldGlobals.push_back(NGV); - Value *NMI = CallInst::CreateMalloc(CI, TD->getIntPtrType(Context), FieldTy, - getMallocArraySize(CI, Context, TD), + Value *NMI = CallInst::CreateMalloc(CI, TD->getIntPtrType(Context), + FieldTy, ArraySize, BCI->getName() + ".f" + Twine(FieldNo)); FieldMallocs.push_back(NMI); new StoreInst(NMI, NGV, BCI); @@ -1766,95 +1464,6 @@ static GlobalVariable *PerformHeapAllocSRoA(GlobalVariable *GV, /// pointer global variable with a single value stored it that is a malloc or /// cast of malloc. static bool TryToOptimizeStoreOfMallocToGlobal(GlobalVariable *GV, - MallocInst *MI, - Module::global_iterator &GVI, - TargetData *TD, - LLVMContext &Context) { - // If this is a malloc of an abstract type, don't touch it. - if (!MI->getAllocatedType()->isSized()) - return false; - - // We can't optimize this global unless all uses of it are *known* to be - // of the malloc value, not of the null initializer value (consider a use - // that compares the global's value against zero to see if the malloc has - // been reached). To do this, we check to see if all uses of the global - // would trap if the global were null: this proves that they must all - // happen after the malloc. - if (!AllUsesOfLoadedValueWillTrapIfNull(GV)) - return false; - - // We can't optimize this if the malloc itself is used in a complex way, - // for example, being stored into multiple globals. This allows the - // malloc to be stored into the specified global, loaded setcc'd, and - // GEP'd. These are all things we could transform to using the global - // for. - { - SmallPtrSet<PHINode*, 8> PHIs; - if (!ValueIsOnlyUsedLocallyOrStoredToOneGlobal(MI, GV, PHIs)) - return false; - } - - - // If we have a global that is only initialized with a fixed size malloc, - // transform the program to use global memory instead of malloc'd memory. - // This eliminates dynamic allocation, avoids an indirection accessing the - // data, and exposes the resultant global to further GlobalOpt. - if (ConstantInt *NElements = dyn_cast<ConstantInt>(MI->getArraySize())) { - // Restrict this transformation to only working on small allocations - // (2048 bytes currently), as we don't want to introduce a 16M global or - // something. - if (TD && - NElements->getZExtValue()* - TD->getTypeAllocSize(MI->getAllocatedType()) < 2048) { - GVI = OptimizeGlobalAddressOfMalloc(GV, MI, Context); - return true; - } - } - - // If the allocation is an array of structures, consider transforming this - // into multiple malloc'd arrays, one for each field. This is basically - // SRoA for malloc'd memory. - const Type *AllocTy = MI->getAllocatedType(); - - // If this is an allocation of a fixed size array of structs, analyze as a - // variable size array. malloc [100 x struct],1 -> malloc struct, 100 - if (!MI->isArrayAllocation()) - if (const ArrayType *AT = dyn_cast<ArrayType>(AllocTy)) - AllocTy = AT->getElementType(); - - if (const StructType *AllocSTy = dyn_cast<StructType>(AllocTy)) { - // This the structure has an unreasonable number of fields, leave it - // alone. - if (AllocSTy->getNumElements() <= 16 && AllocSTy->getNumElements() != 0 && - AllGlobalLoadUsesSimpleEnoughForHeapSRA(GV, MI)) { - - // If this is a fixed size array, transform the Malloc to be an alloc of - // structs. malloc [100 x struct],1 -> malloc struct, 100 - if (const ArrayType *AT = dyn_cast<ArrayType>(MI->getAllocatedType())) { - MallocInst *NewMI = - new MallocInst(AllocSTy, - ConstantInt::get(Type::getInt32Ty(Context), - AT->getNumElements()), - "", MI); - NewMI->takeName(MI); - Value *Cast = new BitCastInst(NewMI, MI->getType(), "tmp", MI); - MI->replaceAllUsesWith(Cast); - MI->eraseFromParent(); - MI = NewMI; - } - - GVI = PerformHeapAllocSRoA(GV, MI, Context); - return true; - } - } - - return false; -} - -/// TryToOptimizeStoreOfMallocToGlobal - This function is called when we see a -/// pointer global variable with a single value stored it that is a malloc or -/// cast of malloc. -static bool TryToOptimizeStoreOfMallocToGlobal(GlobalVariable *GV, CallInst *CI, BitCastInst *BCI, Module::global_iterator &GVI, @@ -1892,52 +1501,55 @@ static bool TryToOptimizeStoreOfMallocToGlobal(GlobalVariable *GV, // transform the program to use global memory instead of malloc'd memory. // This eliminates dynamic allocation, avoids an indirection accessing the // data, and exposes the resultant global to further GlobalOpt. - if (ConstantInt *NElements = - dyn_cast<ConstantInt>(getMallocArraySize(CI, Context, TD))) { - // Restrict this transformation to only working on small allocations - // (2048 bytes currently), as we don't want to introduce a 16M global or - // something. - if (TD && - NElements->getZExtValue() * TD->getTypeAllocSize(AllocTy) < 2048) { - GVI = OptimizeGlobalAddressOfMalloc(GV, CI, BCI, Context, TD); - return true; - } - } - - // If the allocation is an array of structures, consider transforming this - // into multiple malloc'd arrays, one for each field. This is basically - // SRoA for malloc'd memory. - - // If this is an allocation of a fixed size array of structs, analyze as a - // variable size array. malloc [100 x struct],1 -> malloc struct, 100 - if (!isArrayMalloc(CI, Context, TD)) - if (const ArrayType *AT = dyn_cast<ArrayType>(AllocTy)) - AllocTy = AT->getElementType(); - - if (const StructType *AllocSTy = dyn_cast<StructType>(AllocTy)) { - // This the structure has an unreasonable number of fields, leave it - // alone. - if (AllocSTy->getNumElements() <= 16 && AllocSTy->getNumElements() != 0 && - AllGlobalLoadUsesSimpleEnoughForHeapSRA(GV, BCI)) { - - // If this is a fixed size array, transform the Malloc to be an alloc of - // structs. malloc [100 x struct],1 -> malloc struct, 100 - if (const ArrayType *AT = dyn_cast<ArrayType>(getMallocAllocatedType(CI))) { - Value* NumElements = ConstantInt::get(Type::getInt32Ty(Context), - AT->getNumElements()); - Value* NewMI = CallInst::CreateMalloc(CI, TD->getIntPtrType(Context), - AllocSTy, NumElements, - BCI->getName()); - Value *Cast = new BitCastInst(NewMI, getMallocType(CI), "tmp", CI); - BCI->replaceAllUsesWith(Cast); - BCI->eraseFromParent(); - CI->eraseFromParent(); - BCI = cast<BitCastInst>(NewMI); - CI = extractMallocCallFromBitCast(NewMI); + Value *NElems = getMallocArraySize(CI, Context, TD); + // We cannot optimize the malloc if we cannot determine malloc array size. + if (NElems) { + if (ConstantInt *NElements = dyn_cast<ConstantInt>(NElems)) + // Restrict this transformation to only working on small allocations + // (2048 bytes currently), as we don't want to introduce a 16M global or + // something. + if (TD && + NElements->getZExtValue() * TD->getTypeAllocSize(AllocTy) < 2048) { + GVI = OptimizeGlobalAddressOfMalloc(GV, CI, BCI, Context, TD); + return true; } + + // If the allocation is an array of structures, consider transforming this + // into multiple malloc'd arrays, one for each field. This is basically + // SRoA for malloc'd memory. + + // If this is an allocation of a fixed size array of structs, analyze as a + // variable size array. malloc [100 x struct],1 -> malloc struct, 100 + if (!isArrayMalloc(CI, Context, TD)) + if (const ArrayType *AT = dyn_cast<ArrayType>(AllocTy)) + AllocTy = AT->getElementType(); + + if (const StructType *AllocSTy = dyn_cast<StructType>(AllocTy)) { + // This the structure has an unreasonable number of fields, leave it + // alone. + if (AllocSTy->getNumElements() <= 16 && AllocSTy->getNumElements() != 0 && + AllGlobalLoadUsesSimpleEnoughForHeapSRA(GV, BCI)) { + + // If this is a fixed size array, transform the Malloc to be an alloc of + // structs. malloc [100 x struct],1 -> malloc struct, 100 + if (const ArrayType *AT = + dyn_cast<ArrayType>(getMallocAllocatedType(CI))) { + Value* NumElements = ConstantInt::get(Type::getInt32Ty(Context), + AT->getNumElements()); + Value* NewMI = CallInst::CreateMalloc(CI, TD->getIntPtrType(Context), + AllocSTy, NumElements, + BCI->getName()); + Value *Cast = new BitCastInst(NewMI, getMallocType(CI), "tmp", CI); + BCI->replaceAllUsesWith(Cast); + BCI->eraseFromParent(); + CI->eraseFromParent(); + BCI = cast<BitCastInst>(NewMI); + CI = extractMallocCallFromBitCast(NewMI); + } - GVI = PerformHeapAllocSRoA(GV, CI, BCI, Context, TD); - return true; + GVI = PerformHeapAllocSRoA(GV, CI, BCI, Context, TD); + return true; + } } } @@ -1966,9 +1578,6 @@ static bool OptimizeOnceStoredGlobal(GlobalVariable *GV, Value *StoredOnceVal, // Optimize away any trapping uses of the loaded value. if (OptimizeAwayTrappingUsesOfLoads(GV, SOVC, Context)) return true; - } else if (MallocInst *MI = dyn_cast<MallocInst>(StoredOnceVal)) { - if (TryToOptimizeStoreOfMallocToGlobal(GV, MI, GVI, TD, Context)) - return true; } else if (CallInst *CI = extractMallocCall(StoredOnceVal)) { if (getMallocAllocatedType(CI)) { BitCastInst* BCI = NULL; diff --git a/lib/Transforms/IPO/RaiseAllocations.cpp b/lib/Transforms/IPO/RaiseAllocations.cpp index 4c1f26d..deb4405 100644 --- a/lib/Transforms/IPO/RaiseAllocations.cpp +++ b/lib/Transforms/IPO/RaiseAllocations.cpp @@ -1,4 +1,4 @@ -//===- RaiseAllocations.cpp - Convert @malloc & @free calls to insts ------===// +//===- RaiseAllocations.cpp - Convert @free calls to insts ------===// // // The LLVM Compiler Infrastructure // @@ -7,8 +7,8 @@ // //===----------------------------------------------------------------------===// // -// This file defines the RaiseAllocations pass which convert malloc and free -// calls to malloc and free instructions. +// This file defines the RaiseAllocations pass which convert free calls to free +// instructions. // //===----------------------------------------------------------------------===// @@ -29,19 +29,19 @@ using namespace llvm; STATISTIC(NumRaised, "Number of allocations raised"); namespace { - // RaiseAllocations - Turn @malloc and @free calls into the appropriate + // RaiseAllocations - Turn @free calls into the appropriate // instruction. // class VISIBILITY_HIDDEN RaiseAllocations : public ModulePass { - Function *MallocFunc; // Functions in the module we are processing - Function *FreeFunc; // Initialized by doPassInitializationVirt + Function *FreeFunc; // Functions in the module we are processing + // Initialized by doPassInitializationVirt public: static char ID; // Pass identification, replacement for typeid RaiseAllocations() - : ModulePass(&ID), MallocFunc(0), FreeFunc(0) {} + : ModulePass(&ID), FreeFunc(0) {} // doPassInitialization - For the raise allocations pass, this finds a - // declaration for malloc and free if they exist. + // declaration for free if it exists. // void doInitialization(Module &M); @@ -61,50 +61,16 @@ ModulePass *llvm::createRaiseAllocationsPass() { } -// If the module has a symbol table, they might be referring to the malloc and -// free functions. If this is the case, grab the method pointers that the -// module is using. +// If the module has a symbol table, they might be referring to the free +// function. If this is the case, grab the method pointers that the module is +// using. // -// Lookup @malloc and @free in the symbol table, for later use. If they don't +// Lookup @free in the symbol table, for later use. If they don't // exist, or are not external, we do not worry about converting calls to that // function into the appropriate instruction. // void RaiseAllocations::doInitialization(Module &M) { - // Get Malloc and free prototypes if they exist! - MallocFunc = M.getFunction("malloc"); - if (MallocFunc) { - const FunctionType* TyWeHave = MallocFunc->getFunctionType(); - - // Get the expected prototype for malloc - const FunctionType *Malloc1Type = - FunctionType::get(Type::getInt8PtrTy(M.getContext()), - std::vector<const Type*>(1, - Type::getInt64Ty(M.getContext())), false); - - // Chck to see if we got the expected malloc - if (TyWeHave != Malloc1Type) { - // Check to see if the prototype is wrong, giving us i8*(i32) * malloc - // This handles the common declaration of: 'void *malloc(unsigned);' - const FunctionType *Malloc2Type = - FunctionType::get(PointerType::getUnqual( - Type::getInt8Ty(M.getContext())), - std::vector<const Type*>(1, - Type::getInt32Ty(M.getContext())), false); - if (TyWeHave != Malloc2Type) { - // Check to see if the prototype is missing, giving us - // i8*(...) * malloc - // This handles the common declaration of: 'void *malloc();' - const FunctionType *Malloc3Type = - FunctionType::get(PointerType::getUnqual( - Type::getInt8Ty(M.getContext())), - true); - if (TyWeHave != Malloc3Type) - // Give up - MallocFunc = 0; - } - } - } - + // Get free prototype if it exists! FreeFunc = M.getFunction("free"); if (FreeFunc) { const FunctionType* TyWeHave = FreeFunc->getFunctionType(); @@ -138,72 +104,18 @@ void RaiseAllocations::doInitialization(Module &M) { } // Don't mess with locally defined versions of these functions... - if (MallocFunc && !MallocFunc->isDeclaration()) MallocFunc = 0; if (FreeFunc && !FreeFunc->isDeclaration()) FreeFunc = 0; } // run - Transform calls into instructions... // bool RaiseAllocations::runOnModule(Module &M) { - // Find the malloc/free prototypes... + // Find the free prototype... doInitialization(M); bool Changed = false; - // First, process all of the malloc calls... - if (MallocFunc) { - std::vector<User*> Users(MallocFunc->use_begin(), MallocFunc->use_end()); - std::vector<Value*> EqPointers; // Values equal to MallocFunc - while (!Users.empty()) { - User *U = Users.back(); - Users.pop_back(); - - if (Instruction *I = dyn_cast<Instruction>(U)) { - CallSite CS = CallSite::get(I); - if (CS.getInstruction() && !CS.arg_empty() && - (CS.getCalledFunction() == MallocFunc || - std::find(EqPointers.begin(), EqPointers.end(), - CS.getCalledValue()) != EqPointers.end())) { - - Value *Source = *CS.arg_begin(); - - // If no prototype was provided for malloc, we may need to cast the - // source size. - if (Source->getType() != Type::getInt32Ty(M.getContext())) - Source = - CastInst::CreateIntegerCast(Source, - Type::getInt32Ty(M.getContext()), - false/*ZExt*/, - "MallocAmtCast", I); - - MallocInst *MI = new MallocInst(Type::getInt8Ty(M.getContext()), - Source, "", I); - MI->takeName(I); - I->replaceAllUsesWith(MI); - - // If the old instruction was an invoke, add an unconditional branch - // before the invoke, which will become the new terminator. - if (InvokeInst *II = dyn_cast<InvokeInst>(I)) - BranchInst::Create(II->getNormalDest(), I); - - // Delete the old call site - I->eraseFromParent(); - Changed = true; - ++NumRaised; - } - } else if (GlobalValue *GV = dyn_cast<GlobalValue>(U)) { - Users.insert(Users.end(), GV->use_begin(), GV->use_end()); - EqPointers.push_back(GV); - } else if (ConstantExpr *CE = dyn_cast<ConstantExpr>(U)) { - if (CE->isCast()) { - Users.insert(Users.end(), CE->use_begin(), CE->use_end()); - EqPointers.push_back(CE); - } - } - } - } - - // Next, process all free calls... + // Process all free calls... if (FreeFunc) { std::vector<User*> Users(FreeFunc->use_begin(), FreeFunc->use_end()); std::vector<Value*> EqPointers; // Values equal to FreeFunc diff --git a/lib/Transforms/IPO/StripSymbols.cpp b/lib/Transforms/IPO/StripSymbols.cpp index 77d44b2..57aaf43 100644 --- a/lib/Transforms/IPO/StripSymbols.cpp +++ b/lib/Transforms/IPO/StripSymbols.cpp @@ -250,8 +250,6 @@ static bool StripDebugInfo(Module &M) { if (NMD) NMD->eraseFromParent(); - // Remove dead metadata. - M.getContext().RemoveDeadMetadata(); return true; } diff --git a/lib/Transforms/Scalar/CodeGenPrepare.cpp b/lib/Transforms/Scalar/CodeGenPrepare.cpp index a3e3fea..42209b8 100644 --- a/lib/Transforms/Scalar/CodeGenPrepare.cpp +++ b/lib/Transforms/Scalar/CodeGenPrepare.cpp @@ -73,6 +73,7 @@ namespace { DenseMap<Value*,Value*> &SunkAddrs); bool OptimizeInlineAsmInst(Instruction *I, CallSite CS, DenseMap<Value*,Value*> &SunkAddrs); + bool MoveExtToFormExtLoad(Instruction *I); bool OptimizeExtUses(Instruction *I); void findLoopBackEdges(const Function &F); }; @@ -731,6 +732,43 @@ bool CodeGenPrepare::OptimizeInlineAsmInst(Instruction *I, CallSite CS, return MadeChange; } +/// MoveExtToFormExtLoad - Move a zext or sext fed by a load into the same +/// basic block as the load, unless conditions are unfavorable. This allows +/// SelectionDAG to fold the extend into the load. +/// +bool CodeGenPrepare::MoveExtToFormExtLoad(Instruction *I) { + // Look for a load being extended. + LoadInst *LI = dyn_cast<LoadInst>(I->getOperand(0)); + if (!LI) return false; + + // If they're already in the same block, there's nothing to do. + if (LI->getParent() == I->getParent()) + return false; + + // If the load has other users and the truncate is not free, this probably + // isn't worthwhile. + if (!LI->hasOneUse() && + TLI && !TLI->isTruncateFree(I->getType(), LI->getType())) + return false; + + // Check whether the target supports casts folded into loads. + unsigned LType; + if (isa<ZExtInst>(I)) + LType = ISD::ZEXTLOAD; + else { + assert(isa<SExtInst>(I) && "Unexpected ext type!"); + LType = ISD::SEXTLOAD; + } + if (TLI && !TLI->isLoadExtLegal(LType, TLI->getValueType(LI->getType()))) + return false; + + // Move the extend into the same block as the load, so that SelectionDAG + // can fold it. + I->removeFromParent(); + I->insertAfter(LI); + return true; +} + bool CodeGenPrepare::OptimizeExtUses(Instruction *I) { BasicBlock *DefBB = I->getParent(); @@ -846,8 +884,10 @@ bool CodeGenPrepare::OptimizeBlock(BasicBlock &BB) { MadeChange |= Change; } - if (!Change && (isa<ZExtInst>(I) || isa<SExtInst>(I))) + if (!Change && (isa<ZExtInst>(I) || isa<SExtInst>(I))) { + MadeChange |= MoveExtToFormExtLoad(I); MadeChange |= OptimizeExtUses(I); + } } else if (CmpInst *CI = dyn_cast<CmpInst>(I)) { MadeChange |= OptimizeCmpExpression(CI); } else if (LoadInst *LI = dyn_cast<LoadInst>(I)) { diff --git a/lib/Transforms/Scalar/GVN.cpp b/lib/Transforms/Scalar/GVN.cpp index 2ed4a63..8859324 100644 --- a/lib/Transforms/Scalar/GVN.cpp +++ b/lib/Transforms/Scalar/GVN.cpp @@ -78,13 +78,10 @@ namespace { SHUFFLE, SELECT, TRUNC, ZEXT, SEXT, FPTOUI, FPTOSI, UITOFP, SITOFP, FPTRUNC, FPEXT, PTRTOINT, INTTOPTR, BITCAST, GEP, CALL, CONSTANT, - EMPTY, TOMBSTONE }; + INSERTVALUE, EXTRACTVALUE, EMPTY, TOMBSTONE }; ExpressionOpcode opcode; const Type* type; - uint32_t firstVN; - uint32_t secondVN; - uint32_t thirdVN; SmallVector<uint32_t, 4> varargs; Value *function; @@ -100,12 +97,6 @@ namespace { return false; else if (function != other.function) return false; - else if (firstVN != other.firstVN) - return false; - else if (secondVN != other.secondVN) - return false; - else if (thirdVN != other.thirdVN) - return false; else { if (varargs.size() != other.varargs.size()) return false; @@ -146,6 +137,10 @@ namespace { Expression create_expression(GetElementPtrInst* G); Expression create_expression(CallInst* C); Expression create_expression(Constant* C); + Expression create_expression(ExtractValueInst* C); + Expression create_expression(InsertValueInst* C); + + uint32_t lookup_or_add_call(CallInst* C); public: ValueTable() : nextValueNumber(1) { } uint32_t lookup_or_add(Value *V); @@ -176,13 +171,8 @@ template <> struct DenseMapInfo<Expression> { static unsigned getHashValue(const Expression e) { unsigned hash = e.opcode; - hash = e.firstVN + hash * 37; - hash = e.secondVN + hash * 37; - hash = e.thirdVN + hash * 37; - hash = ((unsigned)((uintptr_t)e.type >> 4) ^ - (unsigned)((uintptr_t)e.type >> 9)) + - hash * 37; + (unsigned)((uintptr_t)e.type >> 9)); for (SmallVector<uint32_t, 4>::const_iterator I = e.varargs.begin(), E = e.varargs.end(); I != E; ++I) @@ -290,9 +280,6 @@ Expression ValueTable::create_expression(CallInst* C) { Expression e; e.type = C->getType(); - e.firstVN = 0; - e.secondVN = 0; - e.thirdVN = 0; e.function = C->getCalledFunction(); e.opcode = Expression::CALL; @@ -305,10 +292,8 @@ Expression ValueTable::create_expression(CallInst* C) { Expression ValueTable::create_expression(BinaryOperator* BO) { Expression e; - - e.firstVN = lookup_or_add(BO->getOperand(0)); - e.secondVN = lookup_or_add(BO->getOperand(1)); - e.thirdVN = 0; + e.varargs.push_back(lookup_or_add(BO->getOperand(0))); + e.varargs.push_back(lookup_or_add(BO->getOperand(1))); e.function = 0; e.type = BO->getType(); e.opcode = getOpcode(BO); @@ -319,9 +304,8 @@ Expression ValueTable::create_expression(BinaryOperator* BO) { Expression ValueTable::create_expression(CmpInst* C) { Expression e; - e.firstVN = lookup_or_add(C->getOperand(0)); - e.secondVN = lookup_or_add(C->getOperand(1)); - e.thirdVN = 0; + e.varargs.push_back(lookup_or_add(C->getOperand(0))); + e.varargs.push_back(lookup_or_add(C->getOperand(1))); e.function = 0; e.type = C->getType(); e.opcode = getOpcode(C); @@ -332,9 +316,7 @@ Expression ValueTable::create_expression(CmpInst* C) { Expression ValueTable::create_expression(CastInst* C) { Expression e; - e.firstVN = lookup_or_add(C->getOperand(0)); - e.secondVN = 0; - e.thirdVN = 0; + e.varargs.push_back(lookup_or_add(C->getOperand(0))); e.function = 0; e.type = C->getType(); e.opcode = getOpcode(C); @@ -345,9 +327,9 @@ Expression ValueTable::create_expression(CastInst* C) { Expression ValueTable::create_expression(ShuffleVectorInst* S) { Expression e; - e.firstVN = lookup_or_add(S->getOperand(0)); - e.secondVN = lookup_or_add(S->getOperand(1)); - e.thirdVN = lookup_or_add(S->getOperand(2)); + e.varargs.push_back(lookup_or_add(S->getOperand(0))); + e.varargs.push_back(lookup_or_add(S->getOperand(1))); + e.varargs.push_back(lookup_or_add(S->getOperand(2))); e.function = 0; e.type = S->getType(); e.opcode = Expression::SHUFFLE; @@ -358,9 +340,8 @@ Expression ValueTable::create_expression(ShuffleVectorInst* S) { Expression ValueTable::create_expression(ExtractElementInst* E) { Expression e; - e.firstVN = lookup_or_add(E->getOperand(0)); - e.secondVN = lookup_or_add(E->getOperand(1)); - e.thirdVN = 0; + e.varargs.push_back(lookup_or_add(E->getOperand(0))); + e.varargs.push_back(lookup_or_add(E->getOperand(1))); e.function = 0; e.type = E->getType(); e.opcode = Expression::EXTRACT; @@ -371,9 +352,9 @@ Expression ValueTable::create_expression(ExtractElementInst* E) { Expression ValueTable::create_expression(InsertElementInst* I) { Expression e; - e.firstVN = lookup_or_add(I->getOperand(0)); - e.secondVN = lookup_or_add(I->getOperand(1)); - e.thirdVN = lookup_or_add(I->getOperand(2)); + e.varargs.push_back(lookup_or_add(I->getOperand(0))); + e.varargs.push_back(lookup_or_add(I->getOperand(1))); + e.varargs.push_back(lookup_or_add(I->getOperand(2))); e.function = 0; e.type = I->getType(); e.opcode = Expression::INSERT; @@ -384,9 +365,9 @@ Expression ValueTable::create_expression(InsertElementInst* I) { Expression ValueTable::create_expression(SelectInst* I) { Expression e; - e.firstVN = lookup_or_add(I->getCondition()); - e.secondVN = lookup_or_add(I->getTrueValue()); - e.thirdVN = lookup_or_add(I->getFalseValue()); + e.varargs.push_back(lookup_or_add(I->getCondition())); + e.varargs.push_back(lookup_or_add(I->getTrueValue())); + e.varargs.push_back(lookup_or_add(I->getFalseValue())); e.function = 0; e.type = I->getType(); e.opcode = Expression::SELECT; @@ -397,9 +378,7 @@ Expression ValueTable::create_expression(SelectInst* I) { Expression ValueTable::create_expression(GetElementPtrInst* G) { Expression e; - e.firstVN = lookup_or_add(G->getPointerOperand()); - e.secondVN = 0; - e.thirdVN = 0; + e.varargs.push_back(lookup_or_add(G->getPointerOperand())); e.function = 0; e.type = G->getType(); e.opcode = Expression::GEP; @@ -411,6 +390,35 @@ Expression ValueTable::create_expression(GetElementPtrInst* G) { return e; } +Expression ValueTable::create_expression(ExtractValueInst* E) { + Expression e; + + e.varargs.push_back(lookup_or_add(E->getAggregateOperand())); + for (ExtractValueInst::idx_iterator II = E->idx_begin(), IE = E->idx_end(); + II != IE; ++II) + e.varargs.push_back(*II); + e.function = 0; + e.type = E->getType(); + e.opcode = Expression::EXTRACTVALUE; + + return e; +} + +Expression ValueTable::create_expression(InsertValueInst* E) { + Expression e; + + e.varargs.push_back(lookup_or_add(E->getAggregateOperand())); + e.varargs.push_back(lookup_or_add(E->getInsertedValueOperand())); + for (InsertValueInst::idx_iterator II = E->idx_begin(), IE = E->idx_end(); + II != IE; ++II) + e.varargs.push_back(*II); + e.function = 0; + e.type = E->getType(); + e.opcode = Expression::INSERTVALUE; + + return e; +} + //===----------------------------------------------------------------------===// // ValueTable External Functions //===----------------------------------------------------------------------===// @@ -420,232 +428,197 @@ void ValueTable::add(Value *V, uint32_t num) { valueNumbering.insert(std::make_pair(V, num)); } -/// lookup_or_add - Returns the value number for the specified value, assigning -/// it a new number if it did not have one before. -uint32_t ValueTable::lookup_or_add(Value *V) { - DenseMap<Value*, uint32_t>::iterator VI = valueNumbering.find(V); - if (VI != valueNumbering.end()) - return VI->second; - - if (CallInst* C = dyn_cast<CallInst>(V)) { - if (AA->doesNotAccessMemory(C)) { - Expression e = create_expression(C); - - DenseMap<Expression, uint32_t>::iterator EI = expressionNumbering.find(e); - if (EI != expressionNumbering.end()) { - valueNumbering.insert(std::make_pair(V, EI->second)); - return EI->second; - } else { - expressionNumbering.insert(std::make_pair(e, nextValueNumber)); - valueNumbering.insert(std::make_pair(V, nextValueNumber)); - - return nextValueNumber++; - } - } else if (AA->onlyReadsMemory(C)) { - Expression e = create_expression(C); - - if (expressionNumbering.find(e) == expressionNumbering.end()) { - expressionNumbering.insert(std::make_pair(e, nextValueNumber)); - valueNumbering.insert(std::make_pair(V, nextValueNumber)); - return nextValueNumber++; - } - - MemDepResult local_dep = MD->getDependency(C); - - if (!local_dep.isDef() && !local_dep.isNonLocal()) { - valueNumbering.insert(std::make_pair(V, nextValueNumber)); - return nextValueNumber++; - } - - if (local_dep.isDef()) { - CallInst* local_cdep = cast<CallInst>(local_dep.getInst()); - - if (local_cdep->getNumOperands() != C->getNumOperands()) { - valueNumbering.insert(std::make_pair(V, nextValueNumber)); - return nextValueNumber++; - } - - for (unsigned i = 1; i < C->getNumOperands(); ++i) { - uint32_t c_vn = lookup_or_add(C->getOperand(i)); - uint32_t cd_vn = lookup_or_add(local_cdep->getOperand(i)); - if (c_vn != cd_vn) { - valueNumbering.insert(std::make_pair(V, nextValueNumber)); - return nextValueNumber++; - } - } - - uint32_t v = lookup_or_add(local_cdep); - valueNumbering.insert(std::make_pair(V, v)); - return v; - } - - // Non-local case. - const MemoryDependenceAnalysis::NonLocalDepInfo &deps = - MD->getNonLocalCallDependency(CallSite(C)); - // FIXME: call/call dependencies for readonly calls should return def, not - // clobber! Move the checking logic to MemDep! - CallInst* cdep = 0; - - // Check to see if we have a single dominating call instruction that is - // identical to C. - for (unsigned i = 0, e = deps.size(); i != e; ++i) { - const MemoryDependenceAnalysis::NonLocalDepEntry *I = &deps[i]; - // Ignore non-local dependencies. - if (I->second.isNonLocal()) - continue; +uint32_t ValueTable::lookup_or_add_call(CallInst* C) { + if (AA->doesNotAccessMemory(C)) { + Expression exp = create_expression(C); + uint32_t& e = expressionNumbering[exp]; + if (!e) e = nextValueNumber++; + valueNumbering[C] = e; + return e; + } else if (AA->onlyReadsMemory(C)) { + Expression exp = create_expression(C); + uint32_t& e = expressionNumbering[exp]; + if (!e) { + e = nextValueNumber++; + valueNumbering[C] = e; + return e; + } - // We don't handle non-depedencies. If we already have a call, reject - // instruction dependencies. - if (I->second.isClobber() || cdep != 0) { - cdep = 0; - break; - } + MemDepResult local_dep = MD->getDependency(C); - CallInst *NonLocalDepCall = dyn_cast<CallInst>(I->second.getInst()); - // FIXME: All duplicated with non-local case. - if (NonLocalDepCall && DT->properlyDominates(I->first, C->getParent())){ - cdep = NonLocalDepCall; - continue; - } + if (!local_dep.isDef() && !local_dep.isNonLocal()) { + valueNumbering[C] = nextValueNumber; + return nextValueNumber++; + } - cdep = 0; - break; - } + if (local_dep.isDef()) { + CallInst* local_cdep = cast<CallInst>(local_dep.getInst()); - if (!cdep) { - valueNumbering.insert(std::make_pair(V, nextValueNumber)); + if (local_cdep->getNumOperands() != C->getNumOperands()) { + valueNumbering[C] = nextValueNumber; return nextValueNumber++; } - if (cdep->getNumOperands() != C->getNumOperands()) { - valueNumbering.insert(std::make_pair(V, nextValueNumber)); - return nextValueNumber++; - } for (unsigned i = 1; i < C->getNumOperands(); ++i) { uint32_t c_vn = lookup_or_add(C->getOperand(i)); - uint32_t cd_vn = lookup_or_add(cdep->getOperand(i)); + uint32_t cd_vn = lookup_or_add(local_cdep->getOperand(i)); if (c_vn != cd_vn) { - valueNumbering.insert(std::make_pair(V, nextValueNumber)); + valueNumbering[C] = nextValueNumber; return nextValueNumber++; } } - uint32_t v = lookup_or_add(cdep); - valueNumbering.insert(std::make_pair(V, v)); + uint32_t v = lookup_or_add(local_cdep); + valueNumbering[C] = v; return v; - - } else { - valueNumbering.insert(std::make_pair(V, nextValueNumber)); - return nextValueNumber++; } - } else if (BinaryOperator* BO = dyn_cast<BinaryOperator>(V)) { - Expression e = create_expression(BO); - DenseMap<Expression, uint32_t>::iterator EI = expressionNumbering.find(e); - if (EI != expressionNumbering.end()) { - valueNumbering.insert(std::make_pair(V, EI->second)); - return EI->second; - } else { - expressionNumbering.insert(std::make_pair(e, nextValueNumber)); - valueNumbering.insert(std::make_pair(V, nextValueNumber)); + // Non-local case. + const MemoryDependenceAnalysis::NonLocalDepInfo &deps = + MD->getNonLocalCallDependency(CallSite(C)); + // FIXME: call/call dependencies for readonly calls should return def, not + // clobber! Move the checking logic to MemDep! + CallInst* cdep = 0; + + // Check to see if we have a single dominating call instruction that is + // identical to C. + for (unsigned i = 0, e = deps.size(); i != e; ++i) { + const MemoryDependenceAnalysis::NonLocalDepEntry *I = &deps[i]; + // Ignore non-local dependencies. + if (I->second.isNonLocal()) + continue; - return nextValueNumber++; - } - } else if (CmpInst* C = dyn_cast<CmpInst>(V)) { - Expression e = create_expression(C); + // We don't handle non-depedencies. If we already have a call, reject + // instruction dependencies. + if (I->second.isClobber() || cdep != 0) { + cdep = 0; + break; + } - DenseMap<Expression, uint32_t>::iterator EI = expressionNumbering.find(e); - if (EI != expressionNumbering.end()) { - valueNumbering.insert(std::make_pair(V, EI->second)); - return EI->second; - } else { - expressionNumbering.insert(std::make_pair(e, nextValueNumber)); - valueNumbering.insert(std::make_pair(V, nextValueNumber)); + CallInst *NonLocalDepCall = dyn_cast<CallInst>(I->second.getInst()); + // FIXME: All duplicated with non-local case. + if (NonLocalDepCall && DT->properlyDominates(I->first, C->getParent())){ + cdep = NonLocalDepCall; + continue; + } - return nextValueNumber++; + cdep = 0; + break; } - } else if (ShuffleVectorInst* U = dyn_cast<ShuffleVectorInst>(V)) { - Expression e = create_expression(U); - - DenseMap<Expression, uint32_t>::iterator EI = expressionNumbering.find(e); - if (EI != expressionNumbering.end()) { - valueNumbering.insert(std::make_pair(V, EI->second)); - return EI->second; - } else { - expressionNumbering.insert(std::make_pair(e, nextValueNumber)); - valueNumbering.insert(std::make_pair(V, nextValueNumber)); + if (!cdep) { + valueNumbering[C] = nextValueNumber; return nextValueNumber++; } - } else if (ExtractElementInst* U = dyn_cast<ExtractElementInst>(V)) { - Expression e = create_expression(U); - - DenseMap<Expression, uint32_t>::iterator EI = expressionNumbering.find(e); - if (EI != expressionNumbering.end()) { - valueNumbering.insert(std::make_pair(V, EI->second)); - return EI->second; - } else { - expressionNumbering.insert(std::make_pair(e, nextValueNumber)); - valueNumbering.insert(std::make_pair(V, nextValueNumber)); + if (cdep->getNumOperands() != C->getNumOperands()) { + valueNumbering[C] = nextValueNumber; return nextValueNumber++; } - } else if (InsertElementInst* U = dyn_cast<InsertElementInst>(V)) { - Expression e = create_expression(U); - - DenseMap<Expression, uint32_t>::iterator EI = expressionNumbering.find(e); - if (EI != expressionNumbering.end()) { - valueNumbering.insert(std::make_pair(V, EI->second)); - return EI->second; - } else { - expressionNumbering.insert(std::make_pair(e, nextValueNumber)); - valueNumbering.insert(std::make_pair(V, nextValueNumber)); - - return nextValueNumber++; + for (unsigned i = 1; i < C->getNumOperands(); ++i) { + uint32_t c_vn = lookup_or_add(C->getOperand(i)); + uint32_t cd_vn = lookup_or_add(cdep->getOperand(i)); + if (c_vn != cd_vn) { + valueNumbering[C] = nextValueNumber; + return nextValueNumber++; + } } - } else if (SelectInst* U = dyn_cast<SelectInst>(V)) { - Expression e = create_expression(U); - DenseMap<Expression, uint32_t>::iterator EI = expressionNumbering.find(e); - if (EI != expressionNumbering.end()) { - valueNumbering.insert(std::make_pair(V, EI->second)); - return EI->second; - } else { - expressionNumbering.insert(std::make_pair(e, nextValueNumber)); - valueNumbering.insert(std::make_pair(V, nextValueNumber)); + uint32_t v = lookup_or_add(cdep); + valueNumbering[C] = v; + return v; - return nextValueNumber++; - } - } else if (CastInst* U = dyn_cast<CastInst>(V)) { - Expression e = create_expression(U); - - DenseMap<Expression, uint32_t>::iterator EI = expressionNumbering.find(e); - if (EI != expressionNumbering.end()) { - valueNumbering.insert(std::make_pair(V, EI->second)); - return EI->second; - } else { - expressionNumbering.insert(std::make_pair(e, nextValueNumber)); - valueNumbering.insert(std::make_pair(V, nextValueNumber)); - - return nextValueNumber++; - } - } else if (GetElementPtrInst* U = dyn_cast<GetElementPtrInst>(V)) { - Expression e = create_expression(U); + } else { + valueNumbering[C] = nextValueNumber; + return nextValueNumber++; + } +} - DenseMap<Expression, uint32_t>::iterator EI = expressionNumbering.find(e); - if (EI != expressionNumbering.end()) { - valueNumbering.insert(std::make_pair(V, EI->second)); - return EI->second; - } else { - expressionNumbering.insert(std::make_pair(e, nextValueNumber)); - valueNumbering.insert(std::make_pair(V, nextValueNumber)); +/// lookup_or_add - Returns the value number for the specified value, assigning +/// it a new number if it did not have one before. +uint32_t ValueTable::lookup_or_add(Value *V) { + DenseMap<Value*, uint32_t>::iterator VI = valueNumbering.find(V); + if (VI != valueNumbering.end()) + return VI->second; - return nextValueNumber++; - } - } else { - valueNumbering.insert(std::make_pair(V, nextValueNumber)); + if (!isa<Instruction>(V)) { + valueNumbering[V] = nextValueNumber; return nextValueNumber++; } + + Instruction* I = cast<Instruction>(V); + Expression exp; + switch (I->getOpcode()) { + case Instruction::Call: + return lookup_or_add_call(cast<CallInst>(I)); + case Instruction::Add: + case Instruction::FAdd: + case Instruction::Sub: + case Instruction::FSub: + case Instruction::Mul: + case Instruction::FMul: + case Instruction::UDiv: + case Instruction::SDiv: + case Instruction::FDiv: + case Instruction::URem: + case Instruction::SRem: + case Instruction::FRem: + case Instruction::Shl: + case Instruction::LShr: + case Instruction::AShr: + case Instruction::And: + case Instruction::Or : + case Instruction::Xor: + exp = create_expression(cast<BinaryOperator>(I)); + break; + case Instruction::ICmp: + case Instruction::FCmp: + exp = create_expression(cast<CmpInst>(I)); + break; + case Instruction::Trunc: + case Instruction::ZExt: + case Instruction::SExt: + case Instruction::FPToUI: + case Instruction::FPToSI: + case Instruction::UIToFP: + case Instruction::SIToFP: + case Instruction::FPTrunc: + case Instruction::FPExt: + case Instruction::PtrToInt: + case Instruction::IntToPtr: + case Instruction::BitCast: + exp = create_expression(cast<CastInst>(I)); + break; + case Instruction::Select: + exp = create_expression(cast<SelectInst>(I)); + break; + case Instruction::ExtractElement: + exp = create_expression(cast<ExtractElementInst>(I)); + break; + case Instruction::InsertElement: + exp = create_expression(cast<InsertElementInst>(I)); + break; + case Instruction::ShuffleVector: + exp = create_expression(cast<ShuffleVectorInst>(I)); + break; + case Instruction::ExtractValue: + exp = create_expression(cast<ExtractValueInst>(I)); + break; + case Instruction::InsertValue: + exp = create_expression(cast<InsertValueInst>(I)); + break; + case Instruction::GetElementPtr: + exp = create_expression(cast<GetElementPtrInst>(I)); + break; + default: + valueNumbering[V] = nextValueNumber; + return nextValueNumber++; + } + + uint32_t& e = expressionNumbering[exp]; + if (!e) e = nextValueNumber++; + valueNumbering[V] = e; + return e; } /// lookup - Returns the value number of the specified value. Fails if @@ -1557,15 +1530,18 @@ bool GVN::processLoad(LoadInst *L, SmallVectorImpl<Instruction*> &toErase) { // actually have the same type. See if we know how to reuse the stored // value (depending on its type). const TargetData *TD = 0; - if (StoredVal->getType() != L->getType() && - (TD = getAnalysisIfAvailable<TargetData>())) { - StoredVal = CoerceAvailableValueToLoadType(StoredVal, L->getType(), - L, *TD); - if (StoredVal == 0) + if (StoredVal->getType() != L->getType()) { + if ((TD = getAnalysisIfAvailable<TargetData>())) { + StoredVal = CoerceAvailableValueToLoadType(StoredVal, L->getType(), + L, *TD); + if (StoredVal == 0) + return false; + + DEBUG(errs() << "GVN COERCED STORE:\n" << *DepSI << '\n' << *StoredVal + << '\n' << *L << "\n\n\n"); + } + else return false; - - DEBUG(errs() << "GVN COERCED STORE:\n" << *DepSI << '\n' << *StoredVal - << '\n' << *L << "\n\n\n"); } // Remove it! @@ -1584,14 +1560,17 @@ bool GVN::processLoad(LoadInst *L, SmallVectorImpl<Instruction*> &toErase) { // the same type. See if we know how to reuse the previously loaded value // (depending on its type). const TargetData *TD = 0; - if (DepLI->getType() != L->getType() && - (TD = getAnalysisIfAvailable<TargetData>())) { - AvailableVal = CoerceAvailableValueToLoadType(DepLI, L->getType(), L,*TD); - if (AvailableVal == 0) - return false; + if (DepLI->getType() != L->getType()) { + if ((TD = getAnalysisIfAvailable<TargetData>())) { + AvailableVal = CoerceAvailableValueToLoadType(DepLI, L->getType(), L,*TD); + if (AvailableVal == 0) + return false; - DEBUG(errs() << "GVN COERCED LOAD:\n" << *DepLI << "\n" << *AvailableVal - << "\n" << *L << "\n\n\n"); + DEBUG(errs() << "GVN COERCED LOAD:\n" << *DepLI << "\n" << *AvailableVal + << "\n" << *L << "\n\n\n"); + } + else + return false; } // Remove it! diff --git a/lib/Transforms/Scalar/InstructionCombining.cpp b/lib/Transforms/Scalar/InstructionCombining.cpp index f635af3..b41b5d4 100644 --- a/lib/Transforms/Scalar/InstructionCombining.cpp +++ b/lib/Transforms/Scalar/InstructionCombining.cpp @@ -6300,25 +6300,33 @@ Instruction *InstCombiner::visitICmpInst(ICmpInst &I) { return SelectInst::Create(LHSI->getOperand(0), Op1, Op2); break; } - case Instruction::Malloc: - // If we have (malloc != null), and if the malloc has a single use, we - // can assume it is successful and remove the malloc. - if (LHSI->hasOneUse() && isa<ConstantPointerNull>(RHSC)) { - Worklist.Add(LHSI); - return ReplaceInstUsesWith(I, - ConstantInt::get(Type::getInt1Ty(*Context), - !I.isTrueWhenEqual())); - } - break; case Instruction::Call: // If we have (malloc != null), and if the malloc has a single use, we // can assume it is successful and remove the malloc. if (isMalloc(LHSI) && LHSI->hasOneUse() && isa<ConstantPointerNull>(RHSC)) { - Worklist.Add(LHSI); - return ReplaceInstUsesWith(I, + // Need to explicitly erase malloc call here, instead of adding it to + // Worklist, because it won't get DCE'd from the Worklist since + // isInstructionTriviallyDead() returns false for function calls. + // It is OK to replace LHSI/MallocCall with Undef because the + // instruction that uses it will be erased via Worklist. + if (extractMallocCall(LHSI)) { + LHSI->replaceAllUsesWith(UndefValue::get(LHSI->getType())); + EraseInstFromFunction(*LHSI); + return ReplaceInstUsesWith(I, ConstantInt::get(Type::getInt1Ty(*Context), !I.isTrueWhenEqual())); + } + if (CallInst* MallocCall = extractMallocCallFromBitCast(LHSI)) + if (MallocCall->hasOneUse()) { + MallocCall->replaceAllUsesWith( + UndefValue::get(MallocCall->getType())); + EraseInstFromFunction(*MallocCall); + Worklist.Add(LHSI); // The malloc's bitcast use. + return ReplaceInstUsesWith(I, + ConstantInt::get(Type::getInt1Ty(*Context), + !I.isTrueWhenEqual())); + } } break; } @@ -7809,11 +7817,7 @@ Instruction *InstCombiner::PromoteCastOfAllocation(BitCastInst &CI, Amt = AllocaBuilder.CreateAdd(Amt, Off, "tmp"); } - AllocationInst *New; - if (isa<MallocInst>(AI)) - New = AllocaBuilder.CreateMalloc(CastElTy, Amt); - else - New = AllocaBuilder.CreateAlloca(CastElTy, Amt); + AllocationInst *New = AllocaBuilder.CreateAlloca(CastElTy, Amt); New->setAlignment(AI.getAlignment()); New->takeName(&AI); @@ -9270,14 +9274,44 @@ Instruction *InstCombiner::visitSelectInstWithICmp(SelectInst &SI, return Changed ? &SI : 0; } -/// isDefinedInBB - Return true if the value is an instruction defined in the -/// specified basicblock. -static bool isDefinedInBB(const Value *V, const BasicBlock *BB) { + +/// CanSelectOperandBeMappingIntoPredBlock - SI is a select whose condition is a +/// PHI node (but the two may be in different blocks). See if the true/false +/// values (V) are live in all of the predecessor blocks of the PHI. For +/// example, cases like this cannot be mapped: +/// +/// X = phi [ C1, BB1], [C2, BB2] +/// Y = add +/// Z = select X, Y, 0 +/// +/// because Y is not live in BB1/BB2. +/// +static bool CanSelectOperandBeMappingIntoPredBlock(const Value *V, + const SelectInst &SI) { + // If the value is a non-instruction value like a constant or argument, it + // can always be mapped. const Instruction *I = dyn_cast<Instruction>(V); - return I != 0 && I->getParent() == BB; + if (I == 0) return true; + + // If V is a PHI node defined in the same block as the condition PHI, we can + // map the arguments. + const PHINode *CondPHI = cast<PHINode>(SI.getCondition()); + + if (const PHINode *VP = dyn_cast<PHINode>(I)) + if (VP->getParent() == CondPHI->getParent()) + return true; + + // Otherwise, if the PHI and select are defined in the same block and if V is + // defined in a different block, then we can transform it. + if (SI.getParent() == CondPHI->getParent() && + I->getParent() != CondPHI->getParent()) + return true; + + // Otherwise we have a 'hard' case and we can't tell without doing more + // detailed dominator based analysis, punt. + return false; } - Instruction *InstCombiner::visitSelectInst(SelectInst &SI) { Value *CondVal = SI.getCondition(); Value *TrueVal = SI.getTrueValue(); @@ -9489,16 +9523,13 @@ Instruction *InstCombiner::visitSelectInst(SelectInst &SI) { return FoldI; } - // See if we can fold the select into a phi node. The true/false values have - // to be live in the predecessor blocks. If they are instructions in SI's - // block, we can't map to the predecessor. - if (isa<PHINode>(SI.getCondition()) && - (!isDefinedInBB(SI.getTrueValue(), SI.getParent()) || - isa<PHINode>(SI.getTrueValue())) && - (!isDefinedInBB(SI.getFalseValue(), SI.getParent()) || - isa<PHINode>(SI.getFalseValue()))) - if (Instruction *NV = FoldOpIntoPhi(SI)) - return NV; + // See if we can fold the select into a phi node if the condition is a select. + if (isa<PHINode>(SI.getCondition())) + // The true/false values have to be live in the PHI predecessor's blocks. + if (CanSelectOperandBeMappingIntoPredBlock(TrueVal, SI) && + CanSelectOperandBeMappingIntoPredBlock(FalseVal, SI)) + if (Instruction *NV = FoldOpIntoPhi(SI)) + return NV; if (BinaryOperator::isNot(CondVal)) { SI.setOperand(0, BinaryOperator::getNotArgument(CondVal)); @@ -11213,15 +11244,8 @@ Instruction *InstCombiner::visitAllocationInst(AllocationInst &AI) { if (const ConstantInt *C = dyn_cast<ConstantInt>(AI.getArraySize())) { const Type *NewTy = ArrayType::get(AI.getAllocatedType(), C->getZExtValue()); - AllocationInst *New = 0; - - // Create and insert the replacement instruction... - if (isa<MallocInst>(AI)) - New = Builder->CreateMalloc(NewTy, 0, AI.getName()); - else { - assert(isa<AllocaInst>(AI) && "Unknown type of allocation inst!"); - New = Builder->CreateAlloca(NewTy, 0, AI.getName()); - } + assert(isa<AllocaInst>(AI) && "Unknown type of allocation inst!"); + AllocationInst *New = Builder->CreateAlloca(NewTy, 0, AI.getName()); New->setAlignment(AI.getAlignment()); // Scan to the end of the allocation instructions, to skip over a block of @@ -11294,12 +11318,6 @@ Instruction *InstCombiner::visitFreeInst(FreeInst &FI) { } } - // Change free(malloc) into nothing, if the malloc has a single use. - if (MallocInst *MI = dyn_cast<MallocInst>(Op)) - if (MI->hasOneUse()) { - EraseInstFromFunction(FI); - return EraseInstFromFunction(*MI); - } if (isMalloc(Op)) { if (CallInst* CI = extractMallocCallFromBitCast(Op)) { if (Op->hasOneUse() && CI->hasOneUse()) { @@ -11327,40 +11345,6 @@ static Instruction *InstCombineLoadCast(InstCombiner &IC, LoadInst &LI, Value *CastOp = CI->getOperand(0); LLVMContext *Context = IC.getContext(); - if (TD) { - if (ConstantExpr *CE = dyn_cast<ConstantExpr>(CI)) { - // Instead of loading constant c string, use corresponding integer value - // directly if string length is small enough. - std::string Str; - if (GetConstantStringInfo(CE->getOperand(0), Str) && !Str.empty()) { - unsigned len = Str.length(); - const Type *Ty = cast<PointerType>(CE->getType())->getElementType(); - unsigned numBits = Ty->getPrimitiveSizeInBits(); - // Replace LI with immediate integer store. - if ((numBits >> 3) == len + 1) { - APInt StrVal(numBits, 0); - APInt SingleChar(numBits, 0); - if (TD->isLittleEndian()) { - for (signed i = len-1; i >= 0; i--) { - SingleChar = (uint64_t) Str[i] & UCHAR_MAX; - StrVal = (StrVal << 8) | SingleChar; - } - } else { - for (unsigned i = 0; i < len; i++) { - SingleChar = (uint64_t) Str[i] & UCHAR_MAX; - StrVal = (StrVal << 8) | SingleChar; - } - // Append NULL at the end. - SingleChar = 0; - StrVal = (StrVal << 8) | SingleChar; - } - Value *NL = ConstantInt::get(*Context, StrVal); - return IC.ReplaceInstUsesWith(LI, NL); - } - } - } - } - const PointerType *DestTy = cast<PointerType>(CI->getType()); const Type *DestPTy = DestTy->getElementType(); if (const PointerType *SrcTy = dyn_cast<PointerType>(CastOp->getType())) { @@ -11380,7 +11364,8 @@ static Instruction *InstCombineLoadCast(InstCombiner &IC, LoadInst &LI, if (Constant *CSrc = dyn_cast<Constant>(CastOp)) if (ASrcTy->getNumElements() != 0) { Value *Idxs[2]; - Idxs[0] = Idxs[1] = Constant::getNullValue(Type::getInt32Ty(*Context)); + Idxs[0] = Constant::getNullValue(Type::getInt32Ty(*Context)); + Idxs[1] = Idxs[0]; CastOp = ConstantExpr::getGetElementPtr(CSrc, Idxs, 2); SrcTy = cast<PointerType>(CastOp->getType()); SrcPTy = SrcTy->getElementType(); @@ -11436,6 +11421,7 @@ Instruction *InstCombiner::visitLoadInst(LoadInst &LI) { if (Value *AvailableVal = FindAvailableLoadedValue(Op, LI.getParent(), BBI,6)) return ReplaceInstUsesWith(LI, AvailableVal); + // load(gep null, ...) -> unreachable if (GetElementPtrInst *GEPI = dyn_cast<GetElementPtrInst>(Op)) { const Value *GEPI0 = GEPI->getOperand(0); // TODO: Consider a target hook for valid address spaces for this xform. @@ -11450,60 +11436,24 @@ Instruction *InstCombiner::visitLoadInst(LoadInst &LI) { } } - if (Constant *C = dyn_cast<Constant>(Op)) { - // load null/undef -> undef - // TODO: Consider a target hook for valid address spaces for this xform. - if (isa<UndefValue>(C) || - (C->isNullValue() && LI.getPointerAddressSpace() == 0)) { - // Insert a new store to null instruction before the load to indicate that - // this code is not reachable. We do this instead of inserting an - // unreachable instruction directly because we cannot modify the CFG. - new StoreInst(UndefValue::get(LI.getType()), - Constant::getNullValue(Op->getType()), &LI); - return ReplaceInstUsesWith(LI, UndefValue::get(LI.getType())); - } - - // Instcombine load (constant global) into the value loaded. - if (GlobalVariable *GV = dyn_cast<GlobalVariable>(Op)) - if (GV->isConstant() && GV->hasDefinitiveInitializer()) - return ReplaceInstUsesWith(LI, GV->getInitializer()); - - // Instcombine load (constantexpr_GEP global, 0, ...) into the value loaded. - if (ConstantExpr *CE = dyn_cast<ConstantExpr>(Op)) { - if (CE->getOpcode() == Instruction::GetElementPtr) { - if (GlobalVariable *GV = dyn_cast<GlobalVariable>(CE->getOperand(0))) - if (GV->isConstant() && GV->hasDefinitiveInitializer()) - if (Constant *V = - ConstantFoldLoadThroughGEPConstantExpr(GV->getInitializer(), CE)) - return ReplaceInstUsesWith(LI, V); - if (CE->getOperand(0)->isNullValue()) { - // Insert a new store to null instruction before the load to indicate - // that this code is not reachable. We do this instead of inserting - // an unreachable instruction directly because we cannot modify the - // CFG. - new StoreInst(UndefValue::get(LI.getType()), - Constant::getNullValue(Op->getType()), &LI); - return ReplaceInstUsesWith(LI, UndefValue::get(LI.getType())); - } - - } else if (CE->isCast()) { - if (Instruction *Res = InstCombineLoadCast(*this, LI, TD)) - return Res; - } - } - } - - // If this load comes from anywhere in a constant global, and if the global - // is all undef or zero, we know what it loads. - if (GlobalVariable *GV = dyn_cast<GlobalVariable>(Op->getUnderlyingObject())){ - if (GV->isConstant() && GV->hasDefinitiveInitializer()) { - if (GV->getInitializer()->isNullValue()) - return ReplaceInstUsesWith(LI, Constant::getNullValue(LI.getType())); - else if (isa<UndefValue>(GV->getInitializer())) - return ReplaceInstUsesWith(LI, UndefValue::get(LI.getType())); - } + // load null/undef -> unreachable + // TODO: Consider a target hook for valid address spaces for this xform. + if (isa<UndefValue>(Op) || + (isa<ConstantPointerNull>(Op) && LI.getPointerAddressSpace() == 0)) { + // Insert a new store to null instruction before the load to indicate that + // this code is not reachable. We do this instead of inserting an + // unreachable instruction directly because we cannot modify the CFG. + new StoreInst(UndefValue::get(LI.getType()), + Constant::getNullValue(Op->getType()), &LI); + return ReplaceInstUsesWith(LI, UndefValue::get(LI.getType())); } + // Instcombine load (constantexpr_cast global) -> cast (load global) + if (ConstantExpr *CE = dyn_cast<ConstantExpr>(Op)) + if (CE->isCast()) + if (Instruction *Res = InstCombineLoadCast(*this, LI, TD)) + return Res; + if (Op->hasOneUse()) { // Change select and PHI nodes to select values instead of addresses: this // helps alias analysis out a lot, allows many others simplifications, and diff --git a/lib/Transforms/Scalar/LoopUnswitch.cpp b/lib/Transforms/Scalar/LoopUnswitch.cpp index f6de362..223d2b9 100644 --- a/lib/Transforms/Scalar/LoopUnswitch.cpp +++ b/lib/Transforms/Scalar/LoopUnswitch.cpp @@ -138,7 +138,6 @@ namespace { void SplitExitEdges(Loop *L, const SmallVector<BasicBlock *, 8> &ExitBlocks); bool UnswitchIfProfitable(Value *LoopCond, Constant *Val); - unsigned getLoopUnswitchCost(Value *LIC); void UnswitchTrivialCondition(Loop *L, Value *Cond, Constant *Val, BasicBlock *ExitBlock); void UnswitchNontrivialCondition(Value *LIC, Constant *OnVal, Loop *L); @@ -400,25 +399,6 @@ bool LoopUnswitch::IsTrivialUnswitchCondition(Value *Cond, Constant **Val, return true; } -/// getLoopUnswitchCost - Return the cost (code size growth) that will happen if -/// we choose to unswitch current loop on the specified value. -/// -unsigned LoopUnswitch::getLoopUnswitchCost(Value *LIC) { - // If the condition is trivial, always unswitch. There is no code growth for - // this case. - if (IsTrivialUnswitchCondition(LIC)) - return 0; - - // FIXME: This is overly conservative because it does not take into - // consideration code simplification opportunities. - CodeMetrics Metrics; - for (Loop::block_iterator I = currentLoop->block_begin(), - E = currentLoop->block_end(); - I != E; ++I) - Metrics.analyzeBasicBlock(*I); - return Metrics.NumInsts; -} - /// UnswitchIfProfitable - We have found that we can unswitch currentLoop when /// LoopCond == Val to simplify the loop. If we decide that this is profitable, /// unswitch the loop, reprocess the pieces, then return true. @@ -427,24 +407,35 @@ bool LoopUnswitch::UnswitchIfProfitable(Value *LoopCond, Constant *Val){ initLoopData(); Function *F = loopHeader->getParent(); + // If the condition is trivial, always unswitch. There is no code growth for + // this case. + if (!IsTrivialUnswitchCondition(LoopCond)) { + // Check to see if it would be profitable to unswitch current loop. - // Check to see if it would be profitable to unswitch current loop. - unsigned Cost = getLoopUnswitchCost(LoopCond); - - // Do not do non-trivial unswitch while optimizing for size. - if (Cost && OptimizeForSize) - return false; - if (Cost && !F->isDeclaration() && F->hasFnAttr(Attribute::OptimizeForSize)) - return false; + // Do not do non-trivial unswitch while optimizing for size. + if (OptimizeForSize || F->hasFnAttr(Attribute::OptimizeForSize)) + return false; - if (Cost > Threshold) { - // FIXME: this should estimate growth by the amount of code shared by the - // resultant unswitched loops. - // - DEBUG(errs() << "NOT unswitching loop %" - << currentLoop->getHeader()->getName() << ", cost too high: " - << currentLoop->getBlocks().size() << "\n"); - return false; + // FIXME: This is overly conservative because it does not take into + // consideration code simplification opportunities and code that can + // be shared by the resultant unswitched loops. + CodeMetrics Metrics; + for (Loop::block_iterator I = currentLoop->block_begin(), + E = currentLoop->block_end(); + I != E; ++I) + Metrics.analyzeBasicBlock(*I); + + // Limit the number of instructions to avoid causing significant code + // expansion, and the number of basic blocks, to avoid loops with + // large numbers of branches which cause loop unswitching to go crazy. + // This is a very ad-hoc heuristic. + if (Metrics.NumInsts > Threshold || + Metrics.NumBlocks * 5 > Threshold) { + DEBUG(errs() << "NOT unswitching loop %" + << currentLoop->getHeader()->getName() << ", cost too high: " + << currentLoop->getBlocks().size() << "\n"); + return false; + } } Constant *CondVal; diff --git a/lib/Transforms/Scalar/Reassociate.cpp b/lib/Transforms/Scalar/Reassociate.cpp index e6ffac2..af29f97 100644 --- a/lib/Transforms/Scalar/Reassociate.cpp +++ b/lib/Transforms/Scalar/Reassociate.cpp @@ -121,7 +121,6 @@ static bool isUnmovableInstruction(Instruction *I) { if (I->getOpcode() == Instruction::PHI || I->getOpcode() == Instruction::Alloca || I->getOpcode() == Instruction::Load || - I->getOpcode() == Instruction::Malloc || I->getOpcode() == Instruction::Invoke || (I->getOpcode() == Instruction::Call && !isa<DbgInfoIntrinsic>(I)) || diff --git a/lib/Transforms/Scalar/SCCP.cpp b/lib/Transforms/Scalar/SCCP.cpp index b5edf4e..b745097 100644 --- a/lib/Transforms/Scalar/SCCP.cpp +++ b/lib/Transforms/Scalar/SCCP.cpp @@ -1229,7 +1229,10 @@ CallOverdefined: TMRVI = TrackedMultipleRetVals.find(std::make_pair(F, 0)); if (TMRVI == TrackedMultipleRetVals.end()) goto CallOverdefined; - + + // Need to mark as overdefined, otherwise it stays undefined which + // creates extractvalue undef, <idx> + markOverdefined(I); // If we are tracking this callee, propagate the return values of the call // into this call site. We do this by walking all the uses. Single-index // ExtractValueInst uses can be tracked; anything more complicated is @@ -1271,7 +1274,6 @@ CallOverdefined: } } - void SCCPSolver::Solve() { // Process the work lists until they are empty! while (!BBWorkList.empty() || !InstWorkList.empty() || diff --git a/lib/Transforms/Utils/BasicBlockUtils.cpp b/lib/Transforms/Utils/BasicBlockUtils.cpp index 4931ab3..35907fd 100644 --- a/lib/Transforms/Utils/BasicBlockUtils.cpp +++ b/lib/Transforms/Utils/BasicBlockUtils.cpp @@ -425,14 +425,26 @@ BasicBlock *llvm::SplitBlockPredecessors(BasicBlock *BB, if (L) { if (IsLoopEntry) { - if (Loop *PredLoop = LI->getLoopFor(Preds[0])) { - // Add the new block to the nearest enclosing loop (and not an - // adjacent loop). - while (PredLoop && !PredLoop->contains(BB)) - PredLoop = PredLoop->getParentLoop(); - if (PredLoop) - PredLoop->addBasicBlockToLoop(NewBB, LI->getBase()); - } + // Add the new block to the nearest enclosing loop (and not an + // adjacent loop). To find this, examine each of the predecessors and + // determine which loops enclose them, and select the most-nested loop + // which contains the loop containing the block being split. + Loop *InnermostPredLoop = 0; + for (unsigned i = 0; i != NumPreds; ++i) + if (Loop *PredLoop = LI->getLoopFor(Preds[i])) { + // Seek a loop which actually contains the block being split (to + // avoid adjacent loops). + while (PredLoop && !PredLoop->contains(BB)) + PredLoop = PredLoop->getParentLoop(); + // Select the most-nested of these loops which contains the block. + if (PredLoop && + PredLoop->contains(BB) && + (!InnermostPredLoop || + InnermostPredLoop->getLoopDepth() < PredLoop->getLoopDepth())) + InnermostPredLoop = PredLoop; + } + if (InnermostPredLoop) + InnermostPredLoop->addBasicBlockToLoop(NewBB, LI->getBase()); } else { L->addBasicBlockToLoop(NewBB, LI->getBase()); if (SplitMakesNewLoopHeader) diff --git a/lib/Transforms/Utils/InlineFunction.cpp b/lib/Transforms/Utils/InlineFunction.cpp index 0d00d69..619c939 100644 --- a/lib/Transforms/Utils/InlineFunction.cpp +++ b/lib/Transforms/Utils/InlineFunction.cpp @@ -444,18 +444,15 @@ bool llvm::InlineFunction(CallSite CS, CallGraph *CG, const TargetData *TD, if (InlinedFunctionInfo.ContainsDynamicAllocas) { Module *M = Caller->getParent(); // Get the two intrinsics we care about. - Constant *StackSave, *StackRestore; - StackSave = Intrinsic::getDeclaration(M, Intrinsic::stacksave); - StackRestore = Intrinsic::getDeclaration(M, Intrinsic::stackrestore); + Function *StackSave = Intrinsic::getDeclaration(M, Intrinsic::stacksave); + Function *StackRestore=Intrinsic::getDeclaration(M,Intrinsic::stackrestore); // If we are preserving the callgraph, add edges to the stacksave/restore // functions for the calls we insert. CallGraphNode *StackSaveCGN = 0, *StackRestoreCGN = 0, *CallerNode = 0; if (CG) { - // We know that StackSave/StackRestore are Function*'s, because they are - // intrinsics which must have the right types. - StackSaveCGN = CG->getOrInsertFunction(cast<Function>(StackSave)); - StackRestoreCGN = CG->getOrInsertFunction(cast<Function>(StackRestore)); + StackSaveCGN = CG->getOrInsertFunction(StackSave); + StackRestoreCGN = CG->getOrInsertFunction(StackRestore); CallerNode = (*CG)[Caller]; } @@ -480,7 +477,8 @@ bool llvm::InlineFunction(CallSite CS, CallGraph *CG, const TargetData *TD, for (Function::iterator BB = FirstNewBlock, E = Caller->end(); BB != E; ++BB) if (UnwindInst *UI = dyn_cast<UnwindInst>(BB->getTerminator())) { - CallInst::Create(StackRestore, SavedPtr, "", UI); + CallInst *CI = CallInst::Create(StackRestore, SavedPtr, "", UI); + if (CG) CallerNode->addCalledFunction(CI, StackRestoreCGN); ++NumStackRestores; } } diff --git a/lib/Transforms/Utils/InstructionNamer.cpp b/lib/Transforms/Utils/InstructionNamer.cpp index 1fa51a3..7f11acf 100644 --- a/lib/Transforms/Utils/InstructionNamer.cpp +++ b/lib/Transforms/Utils/InstructionNamer.cpp @@ -33,11 +33,11 @@ namespace { for (Function::arg_iterator AI = F.arg_begin(), AE = F.arg_end(); AI != AE; ++AI) if (!AI->hasName() && AI->getType() != Type::getVoidTy(F.getContext())) - AI->setName("tmp"); + AI->setName("arg"); for (Function::iterator BB = F.begin(), E = F.end(); BB != E; ++BB) { if (!BB->hasName()) - BB->setName("BB"); + BB->setName("bb"); for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ++I) if (!I->hasName() && I->getType() != Type::getVoidTy(F.getContext())) diff --git a/lib/Transforms/Utils/LowerAllocations.cpp b/lib/Transforms/Utils/LowerAllocations.cpp index f26d7c1..9c9113d 100644 --- a/lib/Transforms/Utils/LowerAllocations.cpp +++ b/lib/Transforms/Utils/LowerAllocations.cpp @@ -1,4 +1,4 @@ -//===- LowerAllocations.cpp - Reduce malloc & free insts to calls ---------===// +//===- LowerAllocations.cpp - Reduce free insts to calls ------------------===// // // The LLVM Compiler Infrastructure // @@ -29,18 +29,15 @@ using namespace llvm; STATISTIC(NumLowered, "Number of allocations lowered"); namespace { - /// LowerAllocations - Turn malloc and free instructions into @malloc and - /// @free calls. + /// LowerAllocations - Turn free instructions into @free calls. /// class VISIBILITY_HIDDEN LowerAllocations : public BasicBlockPass { Constant *FreeFunc; // Functions in the module we are processing // Initialized by doInitialization - bool LowerMallocArgToInteger; public: static char ID; // Pass ID, replacement for typeid - explicit LowerAllocations(bool LowerToInt = false) - : BasicBlockPass(&ID), FreeFunc(0), - LowerMallocArgToInteger(LowerToInt) {} + explicit LowerAllocations() + : BasicBlockPass(&ID), FreeFunc(0) {} virtual void getAnalysisUsage(AnalysisUsage &AU) const { AU.addRequired<TargetData>(); @@ -54,7 +51,7 @@ namespace { } /// doPassInitialization - For the lower allocations pass, this ensures that - /// a module contains a declaration for a malloc and a free function. + /// a module contains a declaration for a free function. /// bool doInitialization(Module &M); @@ -76,13 +73,13 @@ X("lowerallocs", "Lower allocations from instructions to calls"); // Publically exposed interface to pass... const PassInfo *const llvm::LowerAllocationsID = &X; // createLowerAllocationsPass - Interface to this file... -Pass *llvm::createLowerAllocationsPass(bool LowerMallocArgToInteger) { - return new LowerAllocations(LowerMallocArgToInteger); +Pass *llvm::createLowerAllocationsPass() { + return new LowerAllocations(); } // doInitialization - For the lower allocations pass, this ensures that a -// module contains a declaration for a malloc and a free function. +// module contains a declaration for a free function. // // This function is always successful. // @@ -102,25 +99,9 @@ bool LowerAllocations::runOnBasicBlock(BasicBlock &BB) { BasicBlock::InstListType &BBIL = BB.getInstList(); - const TargetData &TD = getAnalysis<TargetData>(); - const Type *IntPtrTy = TD.getIntPtrType(BB.getContext()); - - // Loop over all of the instructions, looking for malloc or free instructions + // Loop over all of the instructions, looking for free instructions for (BasicBlock::iterator I = BB.begin(), E = BB.end(); I != E; ++I) { - if (MallocInst *MI = dyn_cast<MallocInst>(I)) { - Value *ArraySize = MI->getOperand(0); - if (ArraySize->getType() != IntPtrTy) - ArraySize = CastInst::CreateIntegerCast(ArraySize, IntPtrTy, - false /*ZExt*/, "", I); - Value *MCast = CallInst::CreateMalloc(I, IntPtrTy, - MI->getAllocatedType(), ArraySize); - - // Replace all uses of the old malloc inst with the cast inst - MI->replaceAllUsesWith(MCast); - I = --BBIL.erase(I); // remove and delete the malloc instr... - Changed = true; - ++NumLowered; - } else if (FreeInst *FI = dyn_cast<FreeInst>(I)) { + if (FreeInst *FI = dyn_cast<FreeInst>(I)) { Value *PtrCast = new BitCastInst(FI->getOperand(0), Type::getInt8PtrTy(BB.getContext()), "", I); diff --git a/lib/Transforms/Utils/SSAUpdater.cpp b/lib/Transforms/Utils/SSAUpdater.cpp index 780ee26..8a07c35 100644 --- a/lib/Transforms/Utils/SSAUpdater.cpp +++ b/lib/Transforms/Utils/SSAUpdater.cpp @@ -48,7 +48,7 @@ void SSAUpdater::Initialize(Value *ProtoValue) { AV = new AvailableValsTy(); else getAvailableVals(AV).clear(); - + if (IPI == 0) IPI = new IncomingPredInfoTy(); else @@ -104,12 +104,12 @@ Value *SSAUpdater::GetValueInMiddleOfBlock(BasicBlock *BB) { // GetValueAtEndOfBlock to do our work. if (!getAvailableVals(AV).count(BB)) return GetValueAtEndOfBlock(BB); - + // Otherwise, we have the hard case. Get the live-in values for each // predecessor. SmallVector<std::pair<BasicBlock*, Value*>, 8> PredValues; Value *SingularValue = 0; - + // We can get our predecessor info by walking the pred_iterator list, but it // is relatively slow. If we already have PHI nodes in this block, walk one // of them to get the predecessor list instead. @@ -118,7 +118,7 @@ Value *SSAUpdater::GetValueInMiddleOfBlock(BasicBlock *BB) { BasicBlock *PredBB = SomePhi->getIncomingBlock(i); Value *PredVal = GetValueAtEndOfBlock(PredBB); PredValues.push_back(std::make_pair(PredBB, PredVal)); - + // Compute SingularValue. if (i == 0) SingularValue = PredVal; @@ -131,7 +131,7 @@ Value *SSAUpdater::GetValueInMiddleOfBlock(BasicBlock *BB) { BasicBlock *PredBB = *PI; Value *PredVal = GetValueAtEndOfBlock(PredBB); PredValues.push_back(std::make_pair(PredBB, PredVal)); - + // Compute SingularValue. if (isFirstPred) { SingularValue = PredVal; @@ -140,25 +140,25 @@ Value *SSAUpdater::GetValueInMiddleOfBlock(BasicBlock *BB) { SingularValue = 0; } } - + // If there are no predecessors, just return undef. if (PredValues.empty()) return UndefValue::get(PrototypeValue->getType()); - + // Otherwise, if all the merged values are the same, just use it. if (SingularValue != 0) return SingularValue; - + // Otherwise, we do need a PHI: insert one now. PHINode *InsertedPHI = PHINode::Create(PrototypeValue->getType(), PrototypeValue->getName(), &BB->front()); InsertedPHI->reserveOperandSpace(PredValues.size()); - + // Fill in all the predecessors of the PHI. for (unsigned i = 0, e = PredValues.size(); i != e; ++i) InsertedPHI->addIncoming(PredValues[i].second, PredValues[i].first); - + // See if the PHI node can be merged to a single value. This can happen in // loop cases when we get a PHI of itself and one other value. if (Value *ConstVal = InsertedPHI->hasConstantValue()) { @@ -168,7 +168,7 @@ Value *SSAUpdater::GetValueInMiddleOfBlock(BasicBlock *BB) { // If the client wants to know about all new instructions, tell it. if (InsertedPHIs) InsertedPHIs->push_back(InsertedPHI); - + DEBUG(errs() << " Inserted PHI: " << *InsertedPHI << "\n"); return InsertedPHI; } @@ -177,11 +177,14 @@ Value *SSAUpdater::GetValueInMiddleOfBlock(BasicBlock *BB) { /// which use their value in the corresponding predecessor. void SSAUpdater::RewriteUse(Use &U) { Instruction *User = cast<Instruction>(U.getUser()); - BasicBlock *UseBB = User->getParent(); - if (PHINode *UserPN = dyn_cast<PHINode>(User)) - UseBB = UserPN->getIncomingBlock(U); - U.set(GetValueInMiddleOfBlock(UseBB)); + Value *V; + if (PHINode *UserPN = dyn_cast<PHINode>(User)) + V = GetValueAtEndOfBlock(UserPN->getIncomingBlock(U)); + else + V = GetValueInMiddleOfBlock(User->getParent()); + + U.set(V); } @@ -192,11 +195,11 @@ void SSAUpdater::RewriteUse(Use &U) { /// Value *SSAUpdater::GetValueAtEndOfBlockInternal(BasicBlock *BB) { AvailableValsTy &AvailableVals = getAvailableVals(AV); - + // Query AvailableVals by doing an insertion of null. std::pair<AvailableValsTy::iterator, bool> InsertRes = AvailableVals.insert(std::make_pair(BB, WeakVH())); - + // Handle the case when the insertion fails because we have already seen BB. if (!InsertRes.second) { // If the insertion failed, there are two cases. The first case is that the @@ -204,7 +207,7 @@ Value *SSAUpdater::GetValueAtEndOfBlockInternal(BasicBlock *BB) { // return the value. if (InsertRes.first->second != 0) return InsertRes.first->second; - + // Otherwise, if the value we find is null, then this is the value is not // known but it is being computed elsewhere in our recursion. This means // that we have a cycle. Handle this by inserting a PHI node and returning @@ -214,7 +217,7 @@ Value *SSAUpdater::GetValueAtEndOfBlockInternal(BasicBlock *BB) { PHINode::Create(PrototypeValue->getType(), PrototypeValue->getName(), &BB->front()); } - + // Okay, the value isn't in the map and we just inserted a null in the entry // to indicate that we're processing the block. Since we have no idea what // value is in this block, we have to recurse through our predecessors. @@ -225,13 +228,13 @@ Value *SSAUpdater::GetValueAtEndOfBlockInternal(BasicBlock *BB) { // of the recursion, just use IncomingPredInfo as an explicit stack. IncomingPredInfoTy &IncomingPredInfo = getIncomingPredInfo(IPI); unsigned FirstPredInfoEntry = IncomingPredInfo.size(); - + // As we're walking the predecessors, keep track of whether they are all // producing the same value. If so, this value will capture it, if not, it // will get reset to null. We distinguish the no-predecessor case explicitly // below. TrackingVH<Value> SingularValue; - + // We can get our predecessor info by walking the pred_iterator list, but it // is relatively slow. If we already have PHI nodes in this block, walk one // of them to get the predecessor list instead. @@ -240,7 +243,7 @@ Value *SSAUpdater::GetValueAtEndOfBlockInternal(BasicBlock *BB) { BasicBlock *PredBB = SomePhi->getIncomingBlock(i); Value *PredVal = GetValueAtEndOfBlockInternal(PredBB); IncomingPredInfo.push_back(std::make_pair(PredBB, PredVal)); - + // Compute SingularValue. if (i == 0) SingularValue = PredVal; @@ -253,7 +256,7 @@ Value *SSAUpdater::GetValueAtEndOfBlockInternal(BasicBlock *BB) { BasicBlock *PredBB = *PI; Value *PredVal = GetValueAtEndOfBlockInternal(PredBB); IncomingPredInfo.push_back(std::make_pair(PredBB, PredVal)); - + // Compute SingularValue. if (isFirstPred) { SingularValue = PredVal; @@ -262,19 +265,19 @@ Value *SSAUpdater::GetValueAtEndOfBlockInternal(BasicBlock *BB) { SingularValue = 0; } } - + // If there are no predecessors, then we must have found an unreachable block // just return 'undef'. Since there are no predecessors, InsertRes must not // be invalidated. if (IncomingPredInfo.size() == FirstPredInfoEntry) return InsertRes.first->second = UndefValue::get(PrototypeValue->getType()); - + /// Look up BB's entry in AvailableVals. 'InsertRes' may be invalidated. If /// this block is involved in a loop, a no-entry PHI node will have been /// inserted as InsertedVal. Otherwise, we'll still have the null we inserted /// above. TrackingVH<Value> &InsertedVal = AvailableVals[BB]; - + // If all the predecessor values are the same then we don't need to insert a // PHI. This is the simple and common case. if (SingularValue) { @@ -291,31 +294,31 @@ Value *SSAUpdater::GetValueAtEndOfBlockInternal(BasicBlock *BB) { } else { InsertedVal = SingularValue; } - + // Drop the entries we added in IncomingPredInfo to restore the stack. IncomingPredInfo.erase(IncomingPredInfo.begin()+FirstPredInfoEntry, IncomingPredInfo.end()); return InsertedVal; } - + // Otherwise, we do need a PHI: insert one now if we don't already have one. if (InsertedVal == 0) InsertedVal = PHINode::Create(PrototypeValue->getType(), PrototypeValue->getName(), &BB->front()); - + PHINode *InsertedPHI = cast<PHINode>(InsertedVal); InsertedPHI->reserveOperandSpace(IncomingPredInfo.size()-FirstPredInfoEntry); - + // Fill in all the predecessors of the PHI. for (IncomingPredInfoTy::iterator I = IncomingPredInfo.begin()+FirstPredInfoEntry, E = IncomingPredInfo.end(); I != E; ++I) InsertedPHI->addIncoming(I->second, I->first); - + // Drop the entries we added in IncomingPredInfo to restore the stack. IncomingPredInfo.erase(IncomingPredInfo.begin()+FirstPredInfoEntry, IncomingPredInfo.end()); - + // See if the PHI node can be merged to a single value. This can happen in // loop cases when we get a PHI of itself and one other value. if (Value *ConstVal = InsertedPHI->hasConstantValue()) { @@ -324,12 +327,10 @@ Value *SSAUpdater::GetValueAtEndOfBlockInternal(BasicBlock *BB) { InsertedVal = ConstVal; } else { DEBUG(errs() << " Inserted PHI: " << *InsertedPHI << "\n"); - + // If the client wants to know about all new instructions, tell it. if (InsertedPHIs) InsertedPHIs->push_back(InsertedPHI); } - + return InsertedVal; } - - diff --git a/lib/VMCore/AsmWriter.cpp b/lib/VMCore/AsmWriter.cpp index b5ae81b..d8a708d 100644 --- a/lib/VMCore/AsmWriter.cpp +++ b/lib/VMCore/AsmWriter.cpp @@ -680,6 +680,8 @@ void SlotTracker::processFunction() { ST_DEBUG("Inserting Instructions:\n"); MetadataContext &TheMetadata = TheFunction->getContext().getMetadata(); + typedef SmallVector<std::pair<unsigned, TrackingVH<MDNode> >, 2> MDMapTy; + MDMapTy MDs; // Add all of the basic blocks and instructions with no names. for (Function::const_iterator BB = TheFunction->begin(), @@ -696,12 +698,11 @@ void SlotTracker::processFunction() { CreateMetadataSlot(N); // Process metadata attached with this instruction. - const MetadataContext::MDMapTy *MDs = TheMetadata.getMDs(I); - if (MDs) - for (MetadataContext::MDMapTy::const_iterator MI = MDs->begin(), - ME = MDs->end(); MI != ME; ++MI) - if (MDNode *MDN = dyn_cast_or_null<MDNode>(MI->second)) - CreateMetadataSlot(MDN); + MDs.clear(); + TheMetadata.getMDs(I, MDs); + for (MDMapTy::const_iterator MI = MDs.begin(), ME = MDs.end(); MI != ME; + ++MI) + CreateMetadataSlot(MI->second); } } @@ -818,9 +819,8 @@ void SlotTracker::CreateMetadataSlot(const MDNode *N) { unsigned DestSlot = mdnNext++; mdnMap[N] = DestSlot; - for (MDNode::const_elem_iterator MDI = N->elem_begin(), - MDE = N->elem_end(); MDI != MDE; ++MDI) { - const Value *TV = *MDI; + for (unsigned i = 0, e = N->getNumElements(); i != e; ++i) { + const Value *TV = N->getElement(i); if (TV) if (const MDNode *N2 = dyn_cast<MDNode>(TV)) CreateMetadataSlot(N2); @@ -906,9 +906,8 @@ static void WriteMDNodes(formatted_raw_ostream &Out, TypePrinting &TypePrinter, Out << '!' << i << " = metadata "; const MDNode *Node = Nodes[i]; Out << "!{"; - for (MDNode::const_elem_iterator NI = Node->elem_begin(), - NE = Node->elem_end(); NI != NE;) { - const Value *V = *NI; + for (unsigned mi = 0, me = Node->getNumElements(); mi != me; ++mi) { + const Value *V = Node->getElement(mi); if (!V) Out << "null"; else if (const MDNode *N = dyn_cast<MDNode>(V)) { @@ -916,11 +915,12 @@ static void WriteMDNodes(formatted_raw_ostream &Out, TypePrinting &TypePrinter, Out << '!' << Machine.getMetadataSlot(N); } else { - TypePrinter.print((*NI)->getType(), Out); + TypePrinter.print(V->getType(), Out); Out << ' '; - WriteAsOperandInternal(Out, *NI, &TypePrinter, &Machine); + WriteAsOperandInternal(Out, Node->getElement(mi), + &TypePrinter, &Machine); } - if (++NI != NE) + if (mi + 1 != me) Out << ", "; } @@ -1206,8 +1206,8 @@ static void WriteAsOperandInternal(raw_ostream &Out, const Value *V, Out << "asm "; if (IA->hasSideEffects()) Out << "sideeffect "; - if (IA->isMsAsm()) - Out << "msasm "; + if (IA->isAlignStack()) + Out << "alignstack "; Out << '"'; PrintEscapedString(IA->getAsmString(), Out); Out << "\", \""; @@ -1296,7 +1296,7 @@ class AssemblyWriter { TypePrinting TypePrinter; AssemblyAnnotationWriter *AnnotationWriter; std::vector<const Type*> NumberedTypes; - DenseMap<unsigned, const char *> MDNames; + DenseMap<unsigned, StringRef> MDNames; public: inline AssemblyWriter(formatted_raw_ostream &o, SlotTracker &Mac, @@ -1307,11 +1307,12 @@ public: // FIXME: Provide MDPrinter if (M) { MetadataContext &TheMetadata = M->getContext().getMetadata(); - const StringMap<unsigned> *Names = TheMetadata.getHandlerNames(); - for (StringMapConstIterator<unsigned> I = Names->begin(), - E = Names->end(); I != E; ++I) { - const StringMapEntry<unsigned> &Entry = *I; - MDNames[I->second] = Entry.getKeyData(); + SmallVector<std::pair<unsigned, StringRef>, 4> Names; + TheMetadata.getHandlerNames(Names); + for (SmallVector<std::pair<unsigned, StringRef>, 4>::iterator + I = Names.begin(), + E = Names.end(); I != E; ++I) { + MDNames[I->first] = I->second; } } } @@ -2035,13 +2036,13 @@ void AssemblyWriter::printInstruction(const Instruction &I) { // Print Metadata info if (!MDNames.empty()) { MetadataContext &TheMetadata = I.getContext().getMetadata(); - const MetadataContext::MDMapTy *MDMap = TheMetadata.getMDs(&I); - if (MDMap) - for (MetadataContext::MDMapTy::const_iterator MI = MDMap->begin(), - ME = MDMap->end(); MI != ME; ++MI) - if (const MDNode *MD = dyn_cast_or_null<MDNode>(MI->second)) - Out << ", !" << MDNames[MI->first] - << " !" << Machine.getMetadataSlot(MD); + typedef SmallVector<std::pair<unsigned, TrackingVH<MDNode> >, 2> MDMapTy; + MDMapTy MDs; + TheMetadata.getMDs(&I, MDs); + for (MDMapTy::const_iterator MI = MDs.begin(), ME = MDs.end(); MI != ME; + ++MI) + Out << ", !" << MDNames[MI->first] + << " !" << Machine.getMetadataSlot(MI->second); } printInfoComment(I); } diff --git a/lib/VMCore/ConstantFold.cpp b/lib/VMCore/ConstantFold.cpp index c1fcc5f..2c0a67f 100644 --- a/lib/VMCore/ConstantFold.cpp +++ b/lib/VMCore/ConstantFold.cpp @@ -179,6 +179,151 @@ static Constant *FoldBitCast(LLVMContext &Context, } +/// ExtractConstantBytes - V is an integer constant which only has a subset of +/// its bytes used. The bytes used are indicated by ByteStart (which is the +/// first byte used, counting from the least significant byte) and ByteSize, +/// which is the number of bytes used. +/// +/// This function analyzes the specified constant to see if the specified byte +/// range can be returned as a simplified constant. If so, the constant is +/// returned, otherwise null is returned. +/// +static Constant *ExtractConstantBytes(Constant *C, unsigned ByteStart, + unsigned ByteSize) { + assert(isa<IntegerType>(C->getType()) && + (cast<IntegerType>(C->getType())->getBitWidth() & 7) == 0 && + "Non-byte sized integer input"); + unsigned CSize = cast<IntegerType>(C->getType())->getBitWidth()/8; + assert(ByteSize && "Must be accessing some piece"); + assert(ByteStart+ByteSize <= CSize && "Extracting invalid piece from input"); + assert(ByteSize != CSize && "Should not extract everything"); + + // Constant Integers are simple. + if (ConstantInt *CI = dyn_cast<ConstantInt>(C)) { + APInt V = CI->getValue(); + if (ByteStart) + V = V.lshr(ByteStart*8); + V.trunc(ByteSize*8); + return ConstantInt::get(CI->getContext(), V); + } + + // In the input is a constant expr, we might be able to recursively simplify. + // If not, we definitely can't do anything. + ConstantExpr *CE = dyn_cast<ConstantExpr>(C); + if (CE == 0) return 0; + + switch (CE->getOpcode()) { + default: return 0; + case Instruction::Or: { + Constant *RHS = ExtractConstantBytes(C->getOperand(1), ByteStart, ByteSize); + if (RHS == 0) + return 0; + + // X | -1 -> -1. + if (ConstantInt *RHSC = dyn_cast<ConstantInt>(RHS)) + if (RHSC->isAllOnesValue()) + return RHSC; + + Constant *LHS = ExtractConstantBytes(C->getOperand(0), ByteStart, ByteSize); + if (LHS == 0) + return 0; + return ConstantExpr::getOr(LHS, RHS); + } + case Instruction::And: { + Constant *RHS = ExtractConstantBytes(C->getOperand(1), ByteStart, ByteSize); + if (RHS == 0) + return 0; + + // X & 0 -> 0. + if (RHS->isNullValue()) + return RHS; + + Constant *LHS = ExtractConstantBytes(C->getOperand(0), ByteStart, ByteSize); + if (LHS == 0) + return 0; + return ConstantExpr::getAnd(LHS, RHS); + } + case Instruction::LShr: { + ConstantInt *Amt = dyn_cast<ConstantInt>(CE->getOperand(1)); + if (Amt == 0) + return 0; + unsigned ShAmt = Amt->getZExtValue(); + // Cannot analyze non-byte shifts. + if ((ShAmt & 7) != 0) + return 0; + ShAmt >>= 3; + + // If the extract is known to be all zeros, return zero. + if (ByteStart >= CSize-ShAmt) + return Constant::getNullValue(IntegerType::get(CE->getContext(), + ByteSize*8)); + // If the extract is known to be fully in the input, extract it. + if (ByteStart+ByteSize+ShAmt <= CSize) + return ExtractConstantBytes(C->getOperand(0), ByteStart+ShAmt, ByteSize); + + // TODO: Handle the 'partially zero' case. + return 0; + } + + case Instruction::Shl: { + ConstantInt *Amt = dyn_cast<ConstantInt>(CE->getOperand(1)); + if (Amt == 0) + return 0; + unsigned ShAmt = Amt->getZExtValue(); + // Cannot analyze non-byte shifts. + if ((ShAmt & 7) != 0) + return 0; + ShAmt >>= 3; + + // If the extract is known to be all zeros, return zero. + if (ByteStart+ByteSize <= ShAmt) + return Constant::getNullValue(IntegerType::get(CE->getContext(), + ByteSize*8)); + // If the extract is known to be fully in the input, extract it. + if (ByteStart >= ShAmt) + return ExtractConstantBytes(C->getOperand(0), ByteStart-ShAmt, ByteSize); + + // TODO: Handle the 'partially zero' case. + return 0; + } + + case Instruction::ZExt: { + unsigned SrcBitSize = + cast<IntegerType>(C->getOperand(0)->getType())->getBitWidth(); + + // If extracting something that is completely zero, return 0. + if (ByteStart*8 >= SrcBitSize) + return Constant::getNullValue(IntegerType::get(CE->getContext(), + ByteSize*8)); + + // If exactly extracting the input, return it. + if (ByteStart == 0 && ByteSize*8 == SrcBitSize) + return C->getOperand(0); + + // If extracting something completely in the input, if if the input is a + // multiple of 8 bits, recurse. + if ((SrcBitSize&7) == 0 && (ByteStart+ByteSize)*8 <= SrcBitSize) + return ExtractConstantBytes(C->getOperand(0), ByteStart, ByteSize); + + // Otherwise, if extracting a subset of the input, which is not multiple of + // 8 bits, do a shift and trunc to get the bits. + if ((ByteStart+ByteSize)*8 < SrcBitSize) { + assert((SrcBitSize&7) && "Shouldn't get byte sized case here"); + Constant *Res = C->getOperand(0); + if (ByteStart) + Res = ConstantExpr::getLShr(Res, + ConstantInt::get(Res->getType(), ByteStart*8)); + return ConstantExpr::getTrunc(Res, IntegerType::get(C->getContext(), + ByteSize*8)); + } + + // TODO: Handle the 'partially zero' case. + return 0; + } + } +} + + Constant *llvm::ConstantFoldCastInstruction(LLVMContext &Context, unsigned opc, Constant *V, const Type *DestTy) { @@ -236,6 +381,8 @@ Constant *llvm::ConstantFoldCastInstruction(LLVMContext &Context, // We actually have to do a cast now. Perform the cast according to the // opcode specified. switch (opc) { + default: + llvm_unreachable("Failed to cast constant expression"); case Instruction::FPTrunc: case Instruction::FPExt: if (ConstantFP *FPC = dyn_cast<ConstantFP>(V)) { @@ -300,23 +447,27 @@ Constant *llvm::ConstantFoldCastInstruction(LLVMContext &Context, return ConstantInt::get(Context, Result); } return 0; - case Instruction::Trunc: + case Instruction::Trunc: { + uint32_t DestBitWidth = cast<IntegerType>(DestTy)->getBitWidth(); if (ConstantInt *CI = dyn_cast<ConstantInt>(V)) { - uint32_t BitWidth = cast<IntegerType>(DestTy)->getBitWidth(); APInt Result(CI->getValue()); - Result.trunc(BitWidth); + Result.trunc(DestBitWidth); return ConstantInt::get(Context, Result); } + + // The input must be a constantexpr. See if we can simplify this based on + // the bytes we are demanding. Only do this if the source and dest are an + // even multiple of a byte. + if ((DestBitWidth & 7) == 0 && + (cast<IntegerType>(V->getType())->getBitWidth() & 7) == 0) + if (Constant *Res = ExtractConstantBytes(V, 0, DestBitWidth / 8)) + return Res; + return 0; + } case Instruction::BitCast: return FoldBitCast(Context, V, DestTy); - default: - assert(!"Invalid CE CastInst opcode"); - break; } - - llvm_unreachable("Failed to cast constant expression"); - return 0; } Constant *llvm::ConstantFoldSelectInstruction(LLVMContext&, diff --git a/lib/VMCore/Constants.cpp b/lib/VMCore/Constants.cpp index 529c455..02c3352 100644 --- a/lib/VMCore/Constants.cpp +++ b/lib/VMCore/Constants.cpp @@ -232,7 +232,6 @@ ConstantInt::ConstantInt(const IntegerType *Ty, const APInt& V) ConstantInt* ConstantInt::getTrue(LLVMContext &Context) { LLVMContextImpl *pImpl = Context.pImpl; - sys::SmartScopedWriter<true>(pImpl->ConstantsLock); if (pImpl->TheTrueVal) return pImpl->TheTrueVal; else @@ -242,7 +241,6 @@ ConstantInt* ConstantInt::getTrue(LLVMContext &Context) { ConstantInt* ConstantInt::getFalse(LLVMContext &Context) { LLVMContextImpl *pImpl = Context.pImpl; - sys::SmartScopedWriter<true>(pImpl->ConstantsLock); if (pImpl->TheFalseVal) return pImpl->TheFalseVal; else @@ -261,22 +259,9 @@ ConstantInt *ConstantInt::get(LLVMContext &Context, const APInt& V) { const IntegerType *ITy = IntegerType::get(Context, V.getBitWidth()); // get an existing value or the insertion position DenseMapAPIntKeyInfo::KeyTy Key(V, ITy); - - Context.pImpl->ConstantsLock.reader_acquire(); ConstantInt *&Slot = Context.pImpl->IntConstants[Key]; - Context.pImpl->ConstantsLock.reader_release(); - - if (!Slot) { - sys::SmartScopedWriter<true> Writer(Context.pImpl->ConstantsLock); - ConstantInt *&NewSlot = Context.pImpl->IntConstants[Key]; - if (!Slot) { - NewSlot = new ConstantInt(ITy, V); - } - - return NewSlot; - } else { - return Slot; - } + if (!Slot) Slot = new ConstantInt(ITy, V); + return Slot; } Constant* ConstantInt::get(const Type* Ty, uint64_t V, bool isSigned) { @@ -405,32 +390,24 @@ ConstantFP* ConstantFP::get(LLVMContext &Context, const APFloat& V) { LLVMContextImpl* pImpl = Context.pImpl; - pImpl->ConstantsLock.reader_acquire(); ConstantFP *&Slot = pImpl->FPConstants[Key]; - pImpl->ConstantsLock.reader_release(); if (!Slot) { - sys::SmartScopedWriter<true> Writer(pImpl->ConstantsLock); - ConstantFP *&NewSlot = pImpl->FPConstants[Key]; - if (!NewSlot) { - const Type *Ty; - if (&V.getSemantics() == &APFloat::IEEEsingle) - Ty = Type::getFloatTy(Context); - else if (&V.getSemantics() == &APFloat::IEEEdouble) - Ty = Type::getDoubleTy(Context); - else if (&V.getSemantics() == &APFloat::x87DoubleExtended) - Ty = Type::getX86_FP80Ty(Context); - else if (&V.getSemantics() == &APFloat::IEEEquad) - Ty = Type::getFP128Ty(Context); - else { - assert(&V.getSemantics() == &APFloat::PPCDoubleDouble && - "Unknown FP format"); - Ty = Type::getPPC_FP128Ty(Context); - } - NewSlot = new ConstantFP(Ty, V); + const Type *Ty; + if (&V.getSemantics() == &APFloat::IEEEsingle) + Ty = Type::getFloatTy(Context); + else if (&V.getSemantics() == &APFloat::IEEEdouble) + Ty = Type::getDoubleTy(Context); + else if (&V.getSemantics() == &APFloat::x87DoubleExtended) + Ty = Type::getX86_FP80Ty(Context); + else if (&V.getSemantics() == &APFloat::IEEEquad) + Ty = Type::getFP128Ty(Context); + else { + assert(&V.getSemantics() == &APFloat::PPCDoubleDouble && + "Unknown FP format"); + Ty = Type::getPPC_FP128Ty(Context); } - - return NewSlot; + Slot = new ConstantFP(Ty, V); } return Slot; @@ -1908,7 +1885,6 @@ void ConstantArray::replaceUsesOfWithOnConstant(Value *From, Value *To, Replacement = ConstantAggregateZero::get(getType()); } else { // Check to see if we have this array type already. - sys::SmartScopedWriter<true> Writer(pImpl->ConstantsLock); bool Exists; LLVMContextImpl::ArrayConstantsTy::MapTy::iterator I = pImpl->ArrayConstants.InsertOrGetItem(Lookup, Exists); @@ -1987,7 +1963,6 @@ void ConstantStruct::replaceUsesOfWithOnConstant(Value *From, Value *To, Replacement = ConstantAggregateZero::get(getType()); } else { // Check to see if we have this array type already. - sys::SmartScopedWriter<true> Writer(pImpl->ConstantsLock); bool Exists; LLVMContextImpl::StructConstantsTy::MapTy::iterator I = pImpl->StructConstants.InsertOrGetItem(Lookup, Exists); diff --git a/lib/VMCore/Core.cpp b/lib/VMCore/Core.cpp index bff3087..a28037d 100644 --- a/lib/VMCore/Core.cpp +++ b/lib/VMCore/Core.cpp @@ -885,9 +885,9 @@ LLVMValueRef LLVMConstInsertValue(LLVMValueRef AggConstant, LLVMValueRef LLVMConstInlineAsm(LLVMTypeRef Ty, const char *AsmString, const char *Constraints, int HasSideEffects, - int IsMsAsm) { + int IsAlignStack) { return wrap(InlineAsm::get(dyn_cast<FunctionType>(unwrap(Ty)), AsmString, - Constraints, HasSideEffects, IsMsAsm)); + Constraints, HasSideEffects, IsAlignStack)); } /*--.. Operations on global variables, functions, and aliases (globals) ....--*/ @@ -1699,12 +1699,18 @@ LLVMValueRef LLVMBuildNot(LLVMBuilderRef B, LLVMValueRef V, const char *Name) { LLVMValueRef LLVMBuildMalloc(LLVMBuilderRef B, LLVMTypeRef Ty, const char *Name) { - return wrap(unwrap(B)->CreateMalloc(unwrap(Ty), 0, Name)); + const Type* IntPtrT = Type::getInt32Ty(unwrap(B)->GetInsertBlock()->getContext()); + return wrap(unwrap(B)->Insert(CallInst::CreateMalloc( + unwrap(B)->GetInsertBlock(), IntPtrT, unwrap(Ty), 0, 0, ""), + Twine(Name))); } LLVMValueRef LLVMBuildArrayMalloc(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Val, const char *Name) { - return wrap(unwrap(B)->CreateMalloc(unwrap(Ty), unwrap(Val), Name)); + const Type* IntPtrT = Type::getInt32Ty(unwrap(B)->GetInsertBlock()->getContext()); + return wrap(unwrap(B)->Insert(CallInst::CreateMalloc( + unwrap(B)->GetInsertBlock(), IntPtrT, unwrap(Ty), unwrap(Val), 0, ""), + Twine(Name))); } LLVMValueRef LLVMBuildAlloca(LLVMBuilderRef B, LLVMTypeRef Ty, diff --git a/lib/VMCore/InlineAsm.cpp b/lib/VMCore/InlineAsm.cpp index 0520dfa..3a36a1b 100644 --- a/lib/VMCore/InlineAsm.cpp +++ b/lib/VMCore/InlineAsm.cpp @@ -28,18 +28,20 @@ InlineAsm::~InlineAsm() { InlineAsm *InlineAsm::get(const FunctionType *Ty, const StringRef &AsmString, const StringRef &Constraints, bool hasSideEffects, - bool isMsAsm) { + bool isAlignStack) { // FIXME: memoize! - return new InlineAsm(Ty, AsmString, Constraints, hasSideEffects, isMsAsm); + return new InlineAsm(Ty, AsmString, Constraints, hasSideEffects, + isAlignStack); } InlineAsm::InlineAsm(const FunctionType *Ty, const StringRef &asmString, const StringRef &constraints, bool hasSideEffects, - bool isMsAsm) + bool isAlignStack) : Value(PointerType::getUnqual(Ty), Value::InlineAsmVal), AsmString(asmString), - Constraints(constraints), HasSideEffects(hasSideEffects), IsMsAsm(isMsAsm) { + Constraints(constraints), HasSideEffects(hasSideEffects), + IsAlignStack(isAlignStack) { // Do various checks on the constraint string and type. assert(Verify(Ty, constraints) && "Function type not legal for constraints!"); diff --git a/lib/VMCore/Instruction.cpp b/lib/VMCore/Instruction.cpp index 4df536e..dd8a543 100644 --- a/lib/VMCore/Instruction.cpp +++ b/lib/VMCore/Instruction.cpp @@ -127,7 +127,6 @@ const char *Instruction::getOpcodeName(unsigned OpCode) { case Xor: return "xor"; // Memory instructions... - case Malloc: return "malloc"; case Free: return "free"; case Alloca: return "alloca"; case Load: return "load"; @@ -442,7 +441,6 @@ bool Instruction::isSafeToSpeculativelyExecute() const { // overflow-checking arithmetic, etc.) case VAArg: case Alloca: - case Malloc: case Invoke: case PHI: case Store: diff --git a/lib/VMCore/Instructions.cpp b/lib/VMCore/Instructions.cpp index f3d15cb..e212d5c 100644 --- a/lib/VMCore/Instructions.cpp +++ b/lib/VMCore/Instructions.cpp @@ -460,9 +460,10 @@ static Value *checkArraySize(Value *Amt, const Type *IntPtrTy) { return Amt; } -static Value *createMalloc(Instruction *InsertBefore, BasicBlock *InsertAtEnd, - const Type *IntPtrTy, const Type *AllocTy, - Value *ArraySize, const Twine &NameStr) { +static Instruction *createMalloc(Instruction *InsertBefore, + BasicBlock *InsertAtEnd, const Type *IntPtrTy, + const Type *AllocTy, Value *ArraySize, + Function *MallocF, const Twine &NameStr) { assert(((!InsertBefore && InsertAtEnd) || (InsertBefore && !InsertAtEnd)) && "createMalloc needs either InsertBefore or InsertAtEnd"); @@ -499,27 +500,34 @@ static Value *createMalloc(Instruction *InsertBefore, BasicBlock *InsertAtEnd, BasicBlock* BB = InsertBefore ? InsertBefore->getParent() : InsertAtEnd; Module* M = BB->getParent()->getParent(); const Type *BPTy = Type::getInt8PtrTy(BB->getContext()); - // prototype malloc as "void *malloc(size_t)" - Constant *MallocF = M->getOrInsertFunction("malloc", BPTy, IntPtrTy, NULL); - if (!cast<Function>(MallocF)->doesNotAlias(0)) - cast<Function>(MallocF)->setDoesNotAlias(0); + if (!MallocF) + // prototype malloc as "void *malloc(size_t)" + MallocF = cast<Function>(M->getOrInsertFunction("malloc", BPTy, + IntPtrTy, NULL)); + if (!MallocF->doesNotAlias(0)) MallocF->setDoesNotAlias(0); const PointerType *AllocPtrType = PointerType::getUnqual(AllocTy); CallInst *MCall = NULL; - Value *MCast = NULL; + Instruction *Result = NULL; if (InsertBefore) { MCall = CallInst::Create(MallocF, AllocSize, "malloccall", InsertBefore); - // Create a cast instruction to convert to the right type... - MCast = new BitCastInst(MCall, AllocPtrType, NameStr, InsertBefore); + Result = MCall; + if (Result->getType() != AllocPtrType) + // Create a cast instruction to convert to the right type... + Result = new BitCastInst(MCall, AllocPtrType, NameStr, InsertBefore); } else { - MCall = CallInst::Create(MallocF, AllocSize, "malloccall", InsertAtEnd); - // Create a cast instruction to convert to the right type... - MCast = new BitCastInst(MCall, AllocPtrType, NameStr); + MCall = CallInst::Create(MallocF, AllocSize, "malloccall"); + Result = MCall; + if (Result->getType() != AllocPtrType) { + InsertAtEnd->getInstList().push_back(MCall); + // Create a cast instruction to convert to the right type... + Result = new BitCastInst(MCall, AllocPtrType, NameStr); + } } MCall->setTailCall(); assert(MCall->getType() != Type::getVoidTy(BB->getContext()) && "Malloc has void return type"); - return MCast; + return Result; } /// CreateMalloc - Generate the IR for a call to malloc: @@ -528,10 +536,11 @@ static Value *createMalloc(Instruction *InsertBefore, BasicBlock *InsertAtEnd, /// constant 1. /// 2. Call malloc with that argument. /// 3. Bitcast the result of the malloc call to the specified type. -Value *CallInst::CreateMalloc(Instruction *InsertBefore, const Type *IntPtrTy, - const Type *AllocTy, Value *ArraySize, - const Twine &Name) { - return createMalloc(InsertBefore, NULL, IntPtrTy, AllocTy, ArraySize, Name); +Instruction *CallInst::CreateMalloc(Instruction *InsertBefore, + const Type *IntPtrTy, const Type *AllocTy, + Value *ArraySize, const Twine &Name) { + return createMalloc(InsertBefore, NULL, IntPtrTy, AllocTy, + ArraySize, NULL, Name); } /// CreateMalloc - Generate the IR for a call to malloc: @@ -542,10 +551,12 @@ Value *CallInst::CreateMalloc(Instruction *InsertBefore, const Type *IntPtrTy, /// 3. Bitcast the result of the malloc call to the specified type. /// Note: This function does not add the bitcast to the basic block, that is the /// responsibility of the caller. -Value *CallInst::CreateMalloc(BasicBlock *InsertAtEnd, const Type *IntPtrTy, - const Type *AllocTy, Value *ArraySize, - const Twine &Name) { - return createMalloc(NULL, InsertAtEnd, IntPtrTy, AllocTy, ArraySize, Name); +Instruction *CallInst::CreateMalloc(BasicBlock *InsertAtEnd, + const Type *IntPtrTy, const Type *AllocTy, + Value *ArraySize, Function* MallocF, + const Twine &Name) { + return createMalloc(NULL, InsertAtEnd, IntPtrTy, AllocTy, + ArraySize, MallocF, Name); } //===----------------------------------------------------------------------===// @@ -837,7 +848,7 @@ static Value *getAISize(LLVMContext &Context, Value *Amt) { assert(!isa<BasicBlock>(Amt) && "Passed basic block into allocation size parameter! Use other ctor"); assert(Amt->getType() == Type::getInt32Ty(Context) && - "Malloc/Allocation array size is not a 32-bit integer!"); + "Allocation array size is not a 32-bit integer!"); } return Amt; } @@ -3073,18 +3084,6 @@ InsertValueInst *InsertValueInst::clone() const { return New; } -MallocInst *MallocInst::clone() const { - MallocInst *New = new MallocInst(getAllocatedType(), - (Value*)getOperand(0), - getAlignment()); - New->SubclassOptionalData = SubclassOptionalData; - if (hasMetadata()) { - LLVMContext &Context = getContext(); - Context.pImpl->TheMetadata.ValueIsCloned(this, New); - } - return New; -} - AllocaInst *AllocaInst::clone() const { AllocaInst *New = new AllocaInst(getAllocatedType(), (Value*)getOperand(0), diff --git a/lib/VMCore/LLVMContext.cpp b/lib/VMCore/LLVMContext.cpp index 39ed7ed..3b4a1a3 100644 --- a/lib/VMCore/LLVMContext.cpp +++ b/lib/VMCore/LLVMContext.cpp @@ -45,32 +45,6 @@ GetElementPtrConstantExpr::GetElementPtrConstantExpr OperandList[i+1] = IdxList[i]; } -bool LLVMContext::RemoveDeadMetadata() { - std::vector<WeakVH> DeadMDNodes; - bool Changed = false; - while (1) { - - for (FoldingSet<MDNode>::iterator - I = pImpl->MDNodeSet.begin(), - E = pImpl->MDNodeSet.end(); I != E; ++I) { - MDNode *N = &(*I); - if (N->use_empty()) - DeadMDNodes.push_back(WeakVH(N)); - } - - if (DeadMDNodes.empty()) - return Changed; - - while (!DeadMDNodes.empty()) { - Value *V = DeadMDNodes.back(); DeadMDNodes.pop_back(); - if (const MDNode *N = dyn_cast_or_null<MDNode>(V)) - if (N->use_empty()) - delete N; - } - } - return Changed; -} - MetadataContext &LLVMContext::getMetadata() { return pImpl->TheMetadata; } diff --git a/lib/VMCore/LLVMContextImpl.h b/lib/VMCore/LLVMContextImpl.h index 83888c3..84902d5 100644 --- a/lib/VMCore/LLVMContextImpl.h +++ b/lib/VMCore/LLVMContextImpl.h @@ -96,7 +96,6 @@ struct DenseMapAPFloatKeyInfo { class LLVMContextImpl { public: - sys::SmartRWMutex<true> ConstantsLock; typedef DenseMap<DenseMapAPIntKeyInfo::KeyTy, ConstantInt*, DenseMapAPIntKeyInfo> IntMapTy; IntMapTy IntConstants; @@ -204,9 +203,6 @@ public: AggZeroConstants.freeConstants(); NullPtrConstants.freeConstants(); UndefValueConstants.freeConstants(); - for (FoldingSet<MDNode>::iterator I = MDNodeSet.begin(), - E = MDNodeSet.end(); I != E; ++I) - I->dropAllReferences(); for (IntMapTy::iterator I = IntConstants.begin(), E = IntConstants.end(); I != E; ++I) { if (I->second->use_empty()) @@ -217,6 +213,7 @@ public: if (I->second->use_empty()) delete I->second; } + MDNodeSet.clear(); } }; diff --git a/lib/VMCore/Metadata.cpp b/lib/VMCore/Metadata.cpp index 110c5e3..ad9653f 100644 --- a/lib/VMCore/Metadata.cpp +++ b/lib/VMCore/Metadata.cpp @@ -16,73 +16,44 @@ #include "llvm/LLVMContext.h" #include "llvm/Module.h" #include "llvm/Instruction.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/StringMap.h" #include "SymbolTableListTraitsImpl.h" using namespace llvm; //===----------------------------------------------------------------------===// -//MetadataBase implementation +// MetadataBase implementation. // -/// resizeOperands - Metadata keeps track of other metadata uses using -/// OperandList. Resize this list to hold anticipated number of metadata -/// operands. -void MetadataBase::resizeOperands(unsigned NumOps) { - unsigned e = getNumOperands(); - if (NumOps == 0) { - NumOps = e*2; - if (NumOps < 2) NumOps = 2; - } else if (NumOps > NumOperands) { - // No resize needed. - if (ReservedSpace >= NumOps) return; - } else if (NumOps == NumOperands) { - if (ReservedSpace == NumOps) return; - } else { - return; - } - - ReservedSpace = NumOps; - Use *OldOps = OperandList; - Use *NewOps = allocHungoffUses(NumOps); - std::copy(OldOps, OldOps + e, NewOps); - OperandList = NewOps; - if (OldOps) Use::zap(OldOps, OldOps + e, true); -} //===----------------------------------------------------------------------===// -//MDString implementation +// MDString implementation. // -MDString *MDString::get(LLVMContext &Context, const StringRef &Str) { +MDString *MDString::get(LLVMContext &Context, StringRef Str) { LLVMContextImpl *pImpl = Context.pImpl; - sys::SmartScopedWriter<true> Writer(pImpl->ConstantsLock); StringMapEntry<MDString *> &Entry = pImpl->MDStringCache.GetOrCreateValue(Str); MDString *&S = Entry.getValue(); - if (!S) S = new MDString(Context, Entry.getKeyData(), - Entry.getKeyLength()); - - return S; + if (S) return S; + + return S = + new MDString(Context, Entry.getKey()); } //===----------------------------------------------------------------------===// -//MDNode implementation +// MDNode implementation. // -MDNode::MDNode(LLVMContext &C, Value*const* Vals, unsigned NumVals) +MDNode::MDNode(LLVMContext &C, Value *const *Vals, unsigned NumVals) : MetadataBase(Type::getMetadataTy(C), Value::MDNodeVal) { - NumOperands = 0; - resizeOperands(NumVals); - for (unsigned i = 0; i != NumVals; ++i) { - // Only record metadata uses. - if (MetadataBase *MB = dyn_cast_or_null<MetadataBase>(Vals[i])) - OperandList[NumOperands++] = MB; - else if(Vals[i] && - Vals[i]->getType()->getTypeID() == Type::MetadataTyID) - OperandList[NumOperands++] = Vals[i]; - Node.push_back(ElementVH(Vals[i], this)); - } + NodeSize = NumVals; + Node = new ElementVH[NodeSize]; + ElementVH *Ptr = Node; + for (unsigned i = 0; i != NumVals; ++i) + *Ptr++ = ElementVH(Vals[i], this); } void MDNode::Profile(FoldingSetNodeID &ID) const { - for (const_elem_iterator I = elem_begin(), E = elem_end(); I != E; ++I) - ID.AddPointer(*I); + for (unsigned i = 0, e = getNumElements(); i != e; ++i) + ID.AddPointer(getElement(i)); } MDNode *MDNode::get(LLVMContext &Context, Value*const* Vals, unsigned NumVals) { @@ -91,37 +62,31 @@ MDNode *MDNode::get(LLVMContext &Context, Value*const* Vals, unsigned NumVals) { for (unsigned i = 0; i != NumVals; ++i) ID.AddPointer(Vals[i]); - pImpl->ConstantsLock.reader_acquire(); void *InsertPoint; - MDNode *N = pImpl->MDNodeSet.FindNodeOrInsertPos(ID, InsertPoint); - pImpl->ConstantsLock.reader_release(); + MDNode *N; + { + N = pImpl->MDNodeSet.FindNodeOrInsertPos(ID, InsertPoint); + } + if (N) return N; + N = pImpl->MDNodeSet.FindNodeOrInsertPos(ID, InsertPoint); if (!N) { - sys::SmartScopedWriter<true> Writer(pImpl->ConstantsLock); - N = pImpl->MDNodeSet.FindNodeOrInsertPos(ID, InsertPoint); - if (!N) { - // InsertPoint will have been set by the FindNodeOrInsertPos call. - N = new MDNode(Context, Vals, NumVals); - pImpl->MDNodeSet.InsertNode(N, InsertPoint); - } + // InsertPoint will have been set by the FindNodeOrInsertPos call. + N = new MDNode(Context, Vals, NumVals); + pImpl->MDNodeSet.InsertNode(N, InsertPoint); } return N; } -/// dropAllReferences - Remove all uses and clear node vector. -void MDNode::dropAllReferences() { - User::dropAllReferences(); - Node.clear(); -} - +/// ~MDNode - Destroy MDNode. MDNode::~MDNode() { { LLVMContextImpl *pImpl = getType()->getContext().pImpl; - sys::SmartScopedWriter<true> Writer(pImpl->ConstantsLock); pImpl->MDNodeSet.RemoveNode(this); } - dropAllReferences(); + delete [] Node; + Node = NULL; } // Replace value from this node's element list. @@ -136,9 +101,8 @@ void MDNode::replaceElement(Value *From, Value *To) { // From in this MDNode's element list. SmallVector<unsigned, 4> Indexes; unsigned Index = 0; - for (SmallVector<ElementVH, 4>::iterator I = Node.begin(), - E = Node.end(); I != E; ++I, ++Index) { - Value *V = *I; + for (unsigned i = 0, e = getNumElements(); i != e; ++i, ++Index) { + Value *V = getElement(i); if (V && V == From) Indexes.push_back(Index); } @@ -147,31 +111,7 @@ void MDNode::replaceElement(Value *From, Value *To) { return; // Remove "this" from the context map. - { - sys::SmartScopedWriter<true> Writer(pImpl->ConstantsLock); - pImpl->MDNodeSet.RemoveNode(this); - } - - // MDNode only lists metadata elements in operand list, because MDNode - // used by MDNode is considered a valid use. However on the side, MDNode - // using a non-metadata value is not considered a "use" of non-metadata - // value. - SmallVector<unsigned, 4> OpIndexes; - unsigned OpIndex = 0; - for (User::op_iterator OI = op_begin(), OE = op_end(); - OI != OE; ++OI, OpIndex++) { - if (*OI == From) - OpIndexes.push_back(OpIndex); - } - if (MetadataBase *MDTo = dyn_cast_or_null<MetadataBase>(To)) { - for (SmallVector<unsigned, 4>::iterator OI = OpIndexes.begin(), - OE = OpIndexes.end(); OI != OE; ++OI) - setOperand(*OI, MDTo); - } else { - for (SmallVector<unsigned, 4>::iterator OI = OpIndexes.begin(), - OE = OpIndexes.end(); OI != OE; ++OI) - setOperand(*OI, 0); - } + pImpl->MDNodeSet.RemoveNode(this); // Replace From element(s) in place. for (SmallVector<unsigned, 4>::iterator I = Indexes.begin(), E = Indexes.end(); @@ -186,10 +126,8 @@ void MDNode::replaceElement(Value *From, Value *To) { // node with updated "this" node. FoldingSetNodeID ID; Profile(ID); - pImpl->ConstantsLock.reader_acquire(); void *InsertPoint; MDNode *N = pImpl->MDNodeSet.FindNodeOrInsertPos(ID, InsertPoint); - pImpl->ConstantsLock.reader_release(); if (N) { N->replaceAllUsesWith(this); @@ -197,39 +135,32 @@ void MDNode::replaceElement(Value *From, Value *To) { N = 0; } - { - sys::SmartScopedWriter<true> Writer(pImpl->ConstantsLock); - N = pImpl->MDNodeSet.FindNodeOrInsertPos(ID, InsertPoint); - if (!N) { - // InsertPoint will have been set by the FindNodeOrInsertPos call. - N = this; - pImpl->MDNodeSet.InsertNode(N, InsertPoint); - } + N = pImpl->MDNodeSet.FindNodeOrInsertPos(ID, InsertPoint); + if (!N) { + // InsertPoint will have been set by the FindNodeOrInsertPos call. + N = this; + pImpl->MDNodeSet.InsertNode(N, InsertPoint); } } //===----------------------------------------------------------------------===// -//NamedMDNode implementation +// NamedMDNode implementation. // NamedMDNode::NamedMDNode(LLVMContext &C, const Twine &N, - MetadataBase*const* MDs, + MetadataBase *const *MDs, unsigned NumMDs, Module *ParentModule) : MetadataBase(Type::getMetadataTy(C), Value::NamedMDNodeVal), Parent(0) { setName(N); - NumOperands = 0; - resizeOperands(NumMDs); - for (unsigned i = 0; i != NumMDs; ++i) { - if (MDs[i]) - OperandList[NumOperands++] = MDs[i]; - Node.push_back(WeakMetadataVH(MDs[i])); - } + for (unsigned i = 0; i != NumMDs; ++i) + Node.push_back(TrackingVH<MetadataBase>(MDs[i])); + if (ParentModule) ParentModule->getNamedMDList().push_back(this); } NamedMDNode *NamedMDNode::Create(const NamedMDNode *NMD, Module *M) { - assert (NMD && "Invalid source NamedMDNode!"); + assert(NMD && "Invalid source NamedMDNode!"); SmallVector<MetadataBase *, 4> Elems; for (unsigned i = 0, e = NMD->getNumElements(); i != e; ++i) Elems.push_back(NMD->getElement(i)); @@ -245,7 +176,6 @@ void NamedMDNode::eraseFromParent() { /// dropAllReferences - Remove all uses and clear node vector. void NamedMDNode::dropAllReferences() { - User::dropAllReferences(); Node.clear(); } @@ -254,65 +184,100 @@ NamedMDNode::~NamedMDNode() { } //===----------------------------------------------------------------------===// -//Metadata implementation +// MetadataContextImpl implementation. // +namespace llvm { +class MetadataContextImpl { +public: + typedef std::pair<unsigned, TrackingVH<MDNode> > MDPairTy; + typedef SmallVector<MDPairTy, 2> MDMapTy; + typedef DenseMap<const Instruction *, MDMapTy> MDStoreTy; + friend class BitcodeReader; +private: + + /// MetadataStore - Collection of metadata used in this context. + MDStoreTy MetadataStore; + + /// MDHandlerNames - Map to hold metadata handler names. + StringMap<unsigned> MDHandlerNames; + +public: + /// registerMDKind - Register a new metadata kind and return its ID. + /// A metadata kind can be registered only once. + unsigned registerMDKind(StringRef Name); + + /// getMDKind - Return metadata kind. If the requested metadata kind + /// is not registered then return 0. + unsigned getMDKind(StringRef Name) const; + + /// getMD - Get the metadata of given kind attached to an Instruction. + /// If the metadata is not found then return 0. + MDNode *getMD(unsigned Kind, const Instruction *Inst); + + /// getMDs - Get the metadata attached to an Instruction. + void getMDs(const Instruction *Inst, SmallVectorImpl<MDPairTy> &MDs) const; + + /// addMD - Attach the metadata of given kind to an Instruction. + void addMD(unsigned Kind, MDNode *Node, Instruction *Inst); + + /// removeMD - Remove metadata of given kind attached with an instuction. + void removeMD(unsigned Kind, Instruction *Inst); + + /// removeAllMetadata - Remove all metadata attached with an instruction. + void removeAllMetadata(Instruction *Inst); + + /// copyMD - If metadata is attached with Instruction In1 then attach + /// the same metadata to In2. + void copyMD(Instruction *In1, Instruction *In2); + + /// getHandlerNames - Populate client supplied smallvector using custome + /// metadata name and ID. + void getHandlerNames(SmallVectorImpl<std::pair<unsigned, StringRef> >&) const; + + /// ValueIsDeleted - This handler is used to update metadata store + /// when a value is deleted. + void ValueIsDeleted(const Value *) {} + void ValueIsDeleted(Instruction *Inst) { + removeAllMetadata(Inst); + } + void ValueIsRAUWd(Value *V1, Value *V2); -/// RegisterMDKind - Register a new metadata kind and return its ID. -/// A metadata kind can be registered only once. -unsigned MetadataContext::RegisterMDKind(const char *Name) { - assert (validName(Name) && "Invalid custome metadata name!"); - unsigned Count = MDHandlerNames.size(); - assert(MDHandlerNames.find(Name) == MDHandlerNames.end() - && "Already registered MDKind!"); - MDHandlerNames[Name] = Count + 1; - return Count + 1; + /// ValueIsCloned - This handler is used to update metadata store + /// when In1 is cloned to create In2. + void ValueIsCloned(const Instruction *In1, Instruction *In2); +}; } -/// validName - Return true if Name is a valid custom metadata handler name. -bool MetadataContext::validName(const char *Name) { - if (!Name) - return false; - - if (!isalpha(*Name)) - return false; - - unsigned Length = strlen(Name); - unsigned Count = 1; - ++Name; - while (Name && - (isalnum(*Name) || *Name == '_' || *Name == '-' || *Name == '.')) { - ++Name; - ++Count; - } - if (Length != Count) - return false; - return true; +/// registerMDKind - Register a new metadata kind and return its ID. +/// A metadata kind can be registered only once. +unsigned MetadataContextImpl::registerMDKind(StringRef Name) { + unsigned Count = MDHandlerNames.size(); + assert(MDHandlerNames.count(Name) == 0 && "Already registered MDKind!"); + return MDHandlerNames[Name] = Count + 1; } /// getMDKind - Return metadata kind. If the requested metadata kind /// is not registered then return 0. -unsigned MetadataContext::getMDKind(const char *Name) { - assert (validName(Name) && "Invalid custome metadata name!"); - StringMap<unsigned>::iterator I = MDHandlerNames.find(Name); +unsigned MetadataContextImpl::getMDKind(StringRef Name) const { + StringMap<unsigned>::const_iterator I = MDHandlerNames.find(Name); if (I == MDHandlerNames.end()) return 0; return I->getValue(); } -/// addMD - Attach the metadata of given kind with an Instruction. -void MetadataContext::addMD(unsigned MDKind, MDNode *Node, Instruction *Inst) { - assert (Node && "Unable to add custome metadata"); +/// addMD - Attach the metadata of given kind to an Instruction. +void MetadataContextImpl::addMD(unsigned MDKind, MDNode *Node, + Instruction *Inst) { + assert(Node && "Invalid null MDNode"); Inst->HasMetadata = true; - MDStoreTy::iterator I = MetadataStore.find(Inst); - if (I == MetadataStore.end()) { - MDMapTy Info; + MDMapTy &Info = MetadataStore[Inst]; + if (Info.empty()) { Info.push_back(std::make_pair(MDKind, Node)); MetadataStore.insert(std::make_pair(Inst, Info)); return; } - MDMapTy &Info = I->second; // If there is an entry for this MDKind then replace it. for (unsigned i = 0, e = Info.size(); i != e; ++i) { MDPairTy &P = Info[i]; @@ -324,11 +289,10 @@ void MetadataContext::addMD(unsigned MDKind, MDNode *Node, Instruction *Inst) { // Otherwise add a new entry. Info.push_back(std::make_pair(MDKind, Node)); - return; } /// removeMD - Remove metadata of given kind attached with an instuction. -void MetadataContext::removeMD(unsigned Kind, Instruction *Inst) { +void MetadataContextImpl::removeMD(unsigned Kind, Instruction *Inst) { MDStoreTy::iterator I = MetadataStore.find(Inst); if (I == MetadataStore.end()) return; @@ -341,87 +305,80 @@ void MetadataContext::removeMD(unsigned Kind, Instruction *Inst) { return; } } - - return; } -/// removeMDs - Remove all metadata attached with an instruction. -void MetadataContext::removeMDs(const Instruction *Inst) { - // Find Metadata handles for this instruction. - MDStoreTy::iterator I = MetadataStore.find(Inst); - assert (I != MetadataStore.end() && "Invalid custom metadata info!"); - MDMapTy &Info = I->second; - - // FIXME : Give all metadata handlers a chance to adjust. - - // Remove the entries for this instruction. - Info.clear(); - MetadataStore.erase(I); +/// removeAllMetadata - Remove all metadata attached with an instruction. +void MetadataContextImpl::removeAllMetadata(Instruction *Inst) { + MetadataStore.erase(Inst); + Inst->HasMetadata = false; } /// copyMD - If metadata is attached with Instruction In1 then attach /// the same metadata to In2. -void MetadataContext::copyMD(Instruction *In1, Instruction *In2) { - assert (In1 && In2 && "Invalid instruction!"); - MDStoreTy::iterator I = MetadataStore.find(In1); - if (I == MetadataStore.end()) +void MetadataContextImpl::copyMD(Instruction *In1, Instruction *In2) { + assert(In1 && In2 && "Invalid instruction!"); + MDMapTy &In1Info = MetadataStore[In1]; + if (In1Info.empty()) return; - MDMapTy &In1Info = I->second; - MDMapTy In2Info; for (MDMapTy::iterator I = In1Info.begin(), E = In1Info.end(); I != E; ++I) - if (MDNode *MD = dyn_cast_or_null<MDNode>(I->second)) - addMD(I->first, MD, In2); + addMD(I->first, I->second, In2); } -/// getMD - Get the metadata of given kind attached with an Instruction. +/// getMD - Get the metadata of given kind attached to an Instruction. /// If the metadata is not found then return 0. -MDNode *MetadataContext::getMD(unsigned MDKind, const Instruction *Inst) { - MDStoreTy::iterator I = MetadataStore.find(Inst); - if (I == MetadataStore.end()) +MDNode *MetadataContextImpl::getMD(unsigned MDKind, const Instruction *Inst) { + MDMapTy &Info = MetadataStore[Inst]; + if (Info.empty()) return NULL; - - MDMapTy &Info = I->second; + for (MDMapTy::iterator I = Info.begin(), E = Info.end(); I != E; ++I) if (I->first == MDKind) - return dyn_cast_or_null<MDNode>(I->second); + return I->second; return NULL; } -/// getMDs - Get the metadata attached with an Instruction. -const MetadataContext::MDMapTy *MetadataContext::getMDs(const Instruction *Inst) { +/// getMDs - Get the metadata attached to an Instruction. +void MetadataContextImpl:: +getMDs(const Instruction *Inst, SmallVectorImpl<MDPairTy> &MDs) const { MDStoreTy::iterator I = MetadataStore.find(Inst); if (I == MetadataStore.end()) - return NULL; - - return &(I->second); + return; + for (MDMapTy::iterator MI = I->second.begin(), ME = I->second.end(); + MI != ME; ++MI) + MDs.push_back(std::make_pair(MI->first, MI->second)); + std::sort(MDs.begin(), MDs.end()); } -/// getHandlerNames - Get handler names. This is used by bitcode -/// writer. -const StringMap<unsigned> *MetadataContext::getHandlerNames() { - return &MDHandlerNames; +/// getHandlerNames - Populate client supplied smallvector using custome +/// metadata name and ID. +void MetadataContextImpl:: +getHandlerNames(SmallVectorImpl<std::pair<unsigned, StringRef> >&Names) const { + for (StringMap<unsigned>::const_iterator I = MDHandlerNames.begin(), + E = MDHandlerNames.end(); I != E; ++I) + Names.push_back(std::make_pair(I->second, I->first())); + std::sort(Names.begin(), Names.end()); } /// ValueIsCloned - This handler is used to update metadata store /// when In1 is cloned to create In2. -void MetadataContext::ValueIsCloned(const Instruction *In1, Instruction *In2) { +void MetadataContextImpl::ValueIsCloned(const Instruction *In1, + Instruction *In2) { // Find Metadata handles for In1. MDStoreTy::iterator I = MetadataStore.find(In1); - assert (I != MetadataStore.end() && "Invalid custom metadata info!"); + assert(I != MetadataStore.end() && "Invalid custom metadata info!"); // FIXME : Give all metadata handlers a chance to adjust. MDMapTy &In1Info = I->second; MDMapTy In2Info; for (MDMapTy::iterator I = In1Info.begin(), E = In1Info.end(); I != E; ++I) - if (MDNode *MD = dyn_cast_or_null<MDNode>(I->second)) - addMD(I->first, MD, In2); + addMD(I->first, I->second, In2); } /// ValueIsRAUWd - This handler is used when V1's all uses are replaced by /// V2. -void MetadataContext::ValueIsRAUWd(Value *V1, Value *V2) { +void MetadataContextImpl::ValueIsRAUWd(Value *V1, Value *V2) { Instruction *I1 = dyn_cast<Instruction>(V1); Instruction *I2 = dyn_cast<Instruction>(V2); if (!I1 || !I2) @@ -431,3 +388,94 @@ void MetadataContext::ValueIsRAUWd(Value *V1, Value *V2) { ValueIsCloned(I1, I2); } +//===----------------------------------------------------------------------===// +// MetadataContext implementation. +// +MetadataContext::MetadataContext() + : pImpl(new MetadataContextImpl()) { } +MetadataContext::~MetadataContext() { delete pImpl; } + +/// isValidName - Return true if Name is a valid custom metadata handler name. +bool MetadataContext::isValidName(StringRef MDName) { + if (MDName.empty()) + return false; + + if (!isalpha(MDName[0])) + return false; + + for (StringRef::iterator I = MDName.begin() + 1, E = MDName.end(); I != E; + ++I) { + if (!isalnum(*I) && *I != '_' && *I != '-' && *I != '.') + return false; + } + return true; +} + +/// registerMDKind - Register a new metadata kind and return its ID. +/// A metadata kind can be registered only once. +unsigned MetadataContext::registerMDKind(StringRef Name) { + assert(isValidName(Name) && "Invalid custome metadata name!"); + return pImpl->registerMDKind(Name); +} + +/// getMDKind - Return metadata kind. If the requested metadata kind +/// is not registered then return 0. +unsigned MetadataContext::getMDKind(StringRef Name) const { + return pImpl->getMDKind(Name); +} + +/// getMD - Get the metadata of given kind attached to an Instruction. +/// If the metadata is not found then return 0. +MDNode *MetadataContext::getMD(unsigned Kind, const Instruction *Inst) { + return pImpl->getMD(Kind, Inst); +} + +/// getMDs - Get the metadata attached to an Instruction. +void MetadataContext:: +getMDs(const Instruction *Inst, + SmallVectorImpl<std::pair<unsigned, TrackingVH<MDNode> > > &MDs) const { + return pImpl->getMDs(Inst, MDs); +} + +/// addMD - Attach the metadata of given kind to an Instruction. +void MetadataContext::addMD(unsigned Kind, MDNode *Node, Instruction *Inst) { + pImpl->addMD(Kind, Node, Inst); +} + +/// removeMD - Remove metadata of given kind attached with an instuction. +void MetadataContext::removeMD(unsigned Kind, Instruction *Inst) { + pImpl->removeMD(Kind, Inst); +} + +/// removeAllMetadata - Remove all metadata attached with an instruction. +void MetadataContext::removeAllMetadata(Instruction *Inst) { + pImpl->removeAllMetadata(Inst); +} + +/// copyMD - If metadata is attached with Instruction In1 then attach +/// the same metadata to In2. +void MetadataContext::copyMD(Instruction *In1, Instruction *In2) { + pImpl->copyMD(In1, In2); +} + +/// getHandlerNames - Populate client supplied smallvector using custome +/// metadata name and ID. +void MetadataContext:: +getHandlerNames(SmallVectorImpl<std::pair<unsigned, StringRef> >&N) const { + pImpl->getHandlerNames(N); +} + +/// ValueIsDeleted - This handler is used to update metadata store +/// when a value is deleted. +void MetadataContext::ValueIsDeleted(Instruction *Inst) { + pImpl->ValueIsDeleted(Inst); +} +void MetadataContext::ValueIsRAUWd(Value *V1, Value *V2) { + pImpl->ValueIsRAUWd(V1, V2); +} + +/// ValueIsCloned - This handler is used to update metadata store +/// when In1 is cloned to create In2. +void MetadataContext::ValueIsCloned(const Instruction *In1, Instruction *In2) { + pImpl->ValueIsCloned(In1, In2); +} diff --git a/lib/VMCore/Pass.cpp b/lib/VMCore/Pass.cpp index a2831d3..a17eed8 100644 --- a/lib/VMCore/Pass.cpp +++ b/lib/VMCore/Pass.cpp @@ -18,6 +18,7 @@ #include "llvm/Module.h" #include "llvm/ModuleProvider.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringMap.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/raw_ostream.h" #include "llvm/System/Atomic.h" diff --git a/lib/VMCore/Value.cpp b/lib/VMCore/Value.cpp index ba72af6..35ec9be 100644 --- a/lib/VMCore/Value.cpp +++ b/lib/VMCore/Value.cpp @@ -27,7 +27,6 @@ #include "llvm/Support/LeakDetector.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/ValueHandle.h" -#include "llvm/Support/raw_ostream.h" #include "llvm/System/RWMutex.h" #include "llvm/System/Threading.h" #include "llvm/ADT/DenseMap.h" diff --git a/lib/VMCore/Verifier.cpp b/lib/VMCore/Verifier.cpp index 75ea4c3..3bfd47c 100644 --- a/lib/VMCore/Verifier.cpp +++ b/lib/VMCore/Verifier.cpp @@ -339,10 +339,10 @@ namespace { void WriteValue(const Value *V) { if (!V) return; if (isa<Instruction>(V)) { - MessagesStr << *V; + MessagesStr << *V << '\n'; } else { WriteAsOperand(MessagesStr, V, true, Mod); - MessagesStr << "\n"; + MessagesStr << '\n'; } } @@ -0,0 +1,7517 @@ +#! /bin/sh + +# mklibT - Provide generalized library-building support services. +# Generated automatically by (GNU ) +# NOTE: Changes made to this file will be lost: look at ltmain.sh. +# +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001 +# Free Software Foundation, Inc. +# +# This file is part of GNU Libtool: +# Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# A sed program that does not truncate output. +SED="/usr/bin/sed" + +# Sed that helps us avoid accidentally triggering echo(1) options like -n. +Xsed="/usr/bin/sed -e 1s/^X//" + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +# The names of the tagged configurations supported by this script. +available_tags=" CXX" + +# ### BEGIN LIBTOOL CONFIG + +# Libtool was configured on host pes.vlakno.cz: + +# Shell to use when invoking shell scripts. +SHELL="/bin/sh" + +# Whether or not to build shared libraries. +build_libtool_libs=yes + +# Whether or not to build static libraries. +build_old_libs=yes + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=no + +# Whether or not to disallow shared libs when runtime libs are static +allow_libtool_libs_with_static_runtimes=no + +# Whether or not to optimize for fast installation. +fast_install=needless + +# The host system. +host_alias= +host=x86_64-unknown-freebsd7.2 +host_os=freebsd7.2 + +# The build system. +build_alias= +build=x86_64-unknown-freebsd7.2 +build_os=freebsd7.2 + +# An echo program that does not interpret backslashes. +echo="echo" + +# The archiver. +AR="ar" +AR_FLAGS="cru" + +# A C compiler. +LTCC="gcc" + +# LTCC compiler flags. +LTCFLAGS="-g -O2" + +# A language-specific compiler. +CC="gcc" + +# Is the compiler the GNU C compiler? +with_gcc=yes + +# An ERE matcher. +EGREP="/usr/bin/grep -E" + +# The linker used to build libraries. +LD="/usr/bin/ld" + +# Whether we need hard or soft links. +LN_S="ln -s" + +# A BSD-compatible nm program. +NM="/usr/bin/nm -B" + +# A symbol stripping program +STRIP="strip" + +# Used to examine libraries when file_magic_cmd begins "file" +MAGIC_CMD=file + +# Used on cygwin: DLL creation program. +DLLTOOL="dlltool" + +# Used on cygwin: object dumper. +OBJDUMP="objdump" + +# Used on cygwin: assembler. +AS="as" + +# The name of the directory that contains temporary libtool files. +objdir=.libs + +# How to create reloadable object files. +reload_flag=" -r" +reload_cmds="\$LD\$reload_flag -o \$output\$reload_objs" + +# How to pass a linker flag through the compiler. +wl="-Wl," + +# Object file suffix (normally "o"). +objext="o" + +# Old archive suffix (normally "a"). +libext="a" + +# Shared library suffix (normally ".so"). +shrext_cmds='.so' + +# Executable file suffix (normally ""). +exeext="" + +# Additional compiler flags for building library objects. +pic_flag=" -fPIC -DPIC" +pic_mode=default + +# What is the maximum length of a command? +max_cmd_len=196608 + +# Does compiler simultaneously support -c and -o options? +compiler_c_o="yes" + +# Must we lock files when doing compilation? +need_locks="no" + +# Do we need the lib prefix for modules? +need_lib_prefix=no + +# Do we need a version for libraries? +need_version=no + +# Whether dlopen is supported. +dlopen_support=yes + +# Whether dlopen of programs is supported. +dlopen_self=yes + +# Whether dlopen of statically linked programs is supported. +dlopen_self_static=no + +# Compiler flag to prevent dynamic linking. +link_static_flag="-static" + +# Compiler flag to turn off builtin functions. +no_builtin_flag=" -fno-builtin" + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec="\${wl}--export-dynamic" + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec="\${wl}--whole-archive\$convenience \${wl}--no-whole-archive" + +# Compiler flag to generate thread-safe objects. +thread_safe_flag_spec="" + +# Library versioning type. +version_type=freebsd-elf + +# Format of library name prefix. +libname_spec="lib\$name" + +# List of archive names. First name is the real one, the rest are links. +# The last name is the one that the linker finds with -lNAME. +library_names_spec="\${libname}\${release}\${shared_ext}\$versuffix \${libname}\${release}\${shared_ext} \$libname\${shared_ext}" + +# The coded name of the library, if different from the real name. +soname_spec="" + +# Commands used to build and install an old-style archive. +RANLIB="ranlib" +old_archive_cmds="\$AR \$AR_FLAGS \$oldlib\$oldobjs\$old_deplibs~\$RANLIB \$oldlib" +old_postinstall_cmds="chmod 644 \$oldlib~\$RANLIB \$oldlib" +old_postuninstall_cmds="" + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds="" + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds="" + +# Commands used to build and install a shared archive. +archive_cmds="\$CC -shared \$libobjs \$deplibs \$compiler_flags \${wl}-soname \$wl\$soname -o \$lib" +archive_expsym_cmds="\$CC -shared \$libobjs \$deplibs \$compiler_flags \${wl}-soname \$wl\$soname \${wl}-retain-symbols-file \$wl\$export_symbols -o \$lib" +postinstall_cmds="" +postuninstall_cmds="" + +# Commands used to build a loadable module (assumed same as above if empty) +module_cmds="" +module_expsym_cmds="" + +# Commands to strip libraries. +old_striplib="strip --strip-debug" +striplib="strip --strip-unneeded" + +# Dependencies to place before the objects being linked to create a +# shared library. +predep_objects="" + +# Dependencies to place after the objects being linked to create a +# shared library. +postdep_objects="" + +# Dependencies to place before the objects being linked to create a +# shared library. +predeps="" + +# Dependencies to place after the objects being linked to create a +# shared library. +postdeps="" + +# The library search path used internally by the compiler when linking +# a shared library. +compiler_lib_search_path="" + +# Method to check whether dependent libraries are shared objects. +deplibs_check_method="pass_all" + +# Command to use when deplibs_check_method == file_magic. +file_magic_cmd="\$MAGIC_CMD" + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag="" + +# Flag that forces no undefined symbols. +no_undefined_flag="" + +# Commands used to finish a libtool library installation in a directory. +finish_cmds="" + +# Same as above, but a single script fragment to be evaled but not shown. +finish_eval="" + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe="sed -n -e 's/^.*[ ]\\([ABCDGIRSTW][ABCDGIRSTW]*\\)[ ][ ]*\\([_A-Za-z][_A-Za-z0-9]*\\)\$/\\1 \\2 \\2/p'" + +# Transform the output of nm in a proper C declaration +global_symbol_to_cdecl="sed -n -e 's/^. .* \\(.*\\)\$/extern int \\1;/p'" + +# Transform the output of nm in a C name address pair +global_symbol_to_c_name_address="sed -n -e 's/^: \\([^ ]*\\) \$/ {\\\"\\1\\\", (lt_ptr) 0},/p' -e 's/^[BCDEGRST] \\([^ ]*\\) \\([^ ]*\\)\$/ {\"\\2\", (lt_ptr) \\&\\2},/p'" + +# This is the shared library runtime path variable. +runpath_var=LD_RUN_PATH + +# This is the shared library path variable. +shlibpath_var=LD_LIBRARY_PATH + +# Is shlibpath searched before the hard-coded library search path? +shlibpath_overrides_runpath=yes + +# How to hardcode a shared library path into an executable. +hardcode_action=immediate + +# Whether we should hardcode library paths into libraries. +hardcode_into_libs=yes + +# Flag to hardcode $libdir into a binary during linking. +# This must work even if $libdir does not exist. +hardcode_libdir_flag_spec="\${wl}--rpath \${wl}\$libdir" + +# If ld is used when linking, flag to hardcode $libdir into +# a binary during linking. This must work even if $libdir does +# not exist. +hardcode_libdir_flag_spec_ld="" + +# Whether we need a single -rpath flag with a separated argument. +hardcode_libdir_separator="" + +# Set to yes if using DIR/libNAME during linking hardcodes DIR into the +# resulting binary. +hardcode_direct=no + +# Set to yes if using the -LDIR flag during linking hardcodes DIR into the +# resulting binary. +hardcode_minus_L=no + +# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into +# the resulting binary. +hardcode_shlibpath_var=unsupported + +# Set to yes if building a shared library automatically hardcodes DIR into the library +# and all subsequent libraries and executables linked against it. +hardcode_automatic=no + +# Variables whose values should be saved in libtool wrapper scripts and +# restored at relink time. +variables_saved_for_relink="PATH LD_LIBRARY_PATH LD_RUN_PATH GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=unknown + +# Compile-time system search path for libraries +sys_lib_search_path_spec=" /usr/lib/ /usr/lib/" + +# Run-time system search path for libraries +sys_lib_dlsearch_path_spec="/lib /usr/lib" + +# Fix the shell variable $srcfile for the compiler. +fix_srcfile_path="" + +# Set to yes if exported symbols are required. +always_export_symbols=no + +# The commands to list exported symbols. +export_symbols_cmds="\$NM \$libobjs \$convenience | \$global_symbol_pipe | \$SED 's/.* //' | sort | uniq > \$export_symbols" + +# The commands to extract the exported symbol list from a shared archive. +extract_expsyms_cmds="" + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms="_GLOBAL_OFFSET_TABLE_" + +# Symbols that must always be exported. +include_expsyms="" + +# ### END LIBTOOL CONFIG + +# ltmain.sh - Provide generalized library-building support services. +# NOTE: Changing this file will not affect anything until you rerun configure. +# +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005 +# Free Software Foundation, Inc. +# Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +basename="s,^.*/,,g" + +# Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh +# is ksh but when the shell is invoked as "sh" and the current value of +# the _XPG environment variable is not equal to 1 (one), the special +# positional parameter $0, within a function call, is the name of the +# function. +progpath="$0" + +# The name of this program: +progname=`echo "$progpath" | $SED $basename` +modename="$progname" + +# Global variables: +EXIT_SUCCESS=0 +EXIT_FAILURE=1 + +PROGRAM=ltmain.sh +PACKAGE=libtool +VERSION=1.5.22 +TIMESTAMP=" (1.1220.2.365 2005/12/18 22:14:06)" + +# See if we are running on zsh, and set the options which allow our +# commands through without removal of \ escapes. +if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST +fi + +# Check that we have a working $echo. +if test "X$1" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift +elif test "X$1" = X--fallback-echo; then + # Avoid inline document here, it may be left over + : +elif test "X`($echo '\t') 2>/dev/null`" = 'X\t'; then + # Yippee, $echo works! + : +else + # Restart under the correct shell, and then maybe $echo will work. + exec $SHELL "$progpath" --no-reexec ${1+"$@"} +fi + +if test "X$1" = X--fallback-echo; then + # used as fallback echo + shift + cat <<EOF +$* +EOF + exit $EXIT_SUCCESS +fi + +default_mode= +help="Try \`$progname --help' for more information." +magic="%%%MAGIC variable%%%" +mkdir="mkdir" +mv="mv -f" +rm="rm -f" + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +Xsed="${SED}"' -e 1s/^X//' +sed_quote_subst='s/\([\\`\\"$\\\\]\)/\\\1/g' +# test EBCDIC or ASCII +case `echo X|tr X '\101'` in + A) # ASCII based system + # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr + SP2NL='tr \040 \012' + NL2SP='tr \015\012 \040\040' + ;; + *) # EBCDIC based system + SP2NL='tr \100 \n' + NL2SP='tr \r\n \100\100' + ;; +esac + +# NLS nuisances. +# Only set LANG and LC_ALL to C if already set. +# These must not be set unconditionally because not all systems understand +# e.g. LANG=C (notably SCO). +# We save the old values to restore during execute mode. +if test "${LC_ALL+set}" = set; then + save_LC_ALL="$LC_ALL"; LC_ALL=C; export LC_ALL +fi +if test "${LANG+set}" = set; then + save_LANG="$LANG"; LANG=C; export LANG +fi + +# Make sure IFS has a sensible default +lt_nl=' +' +IFS=" $lt_nl" + +if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then + $echo "$modename: not configured to build any kind of library" 1>&2 + $echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2 + exit $EXIT_FAILURE +fi + +# Global variables. +mode=$default_mode +nonopt= +prev= +prevopt= +run= +show="$echo" +show_help= +execute_dlfiles= +duplicate_deps=no +preserve_args= +lo2o="s/\\.lo\$/.${objext}/" +o2lo="s/\\.${objext}\$/.lo/" + +##################################### +# Shell function definitions: +# This seems to be the best place for them + +# func_mktempdir [string] +# Make a temporary directory that won't clash with other running +# libtool processes, and avoids race conditions if possible. If +# given, STRING is the basename for that directory. +func_mktempdir () +{ + my_template="${TMPDIR-/tmp}/${1-$progname}" + + if test "$run" = ":"; then + # Return a directory name, but don't create it in dry-run mode + my_tmpdir="${my_template}-$$" + else + + # If mktemp works, use that first and foremost + my_tmpdir=`mktemp -d "${my_template}-XXXXXXXX" 2>/dev/null` + + if test ! -d "$my_tmpdir"; then + # Failing that, at least try and use $RANDOM to avoid a race + my_tmpdir="${my_template}-${RANDOM-0}$$" + + save_mktempdir_umask=`umask` + umask 0077 + $mkdir "$my_tmpdir" + umask $save_mktempdir_umask + fi + + # If we're not in dry-run mode, bomb out on failure + test -d "$my_tmpdir" || { + $echo "cannot create temporary directory \`$my_tmpdir'" 1>&2 + exit $EXIT_FAILURE + } + fi + + $echo "X$my_tmpdir" | $Xsed +} + + +# func_win32_libid arg +# return the library type of file 'arg' +# +# Need a lot of goo to handle *both* DLLs and import libs +# Has to be a shell function in order to 'eat' the argument +# that is supplied when $file_magic_command is called. +func_win32_libid () +{ + win32_libid_type="unknown" + win32_fileres=`file -L $1 2>/dev/null` + case $win32_fileres in + *ar\ archive\ import\ library*) # definitely import + win32_libid_type="x86 archive import" + ;; + *ar\ archive*) # could be an import, or static + if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null | \ + $EGREP -e 'file format pe-i386(.*architecture: i386)?' >/dev/null ; then + win32_nmres=`eval $NM -f posix -A $1 | \ + $SED -n -e '1,100{/ I /{s,.*,import,;p;q;};}'` + case $win32_nmres in + import*) win32_libid_type="x86 archive import";; + *) win32_libid_type="x86 archive static";; + esac + fi + ;; + *DLL*) + win32_libid_type="x86 DLL" + ;; + *executable*) # but shell scripts are "executable" too... + case $win32_fileres in + *MS\ Windows\ PE\ Intel*) + win32_libid_type="x86 DLL" + ;; + esac + ;; + esac + $echo $win32_libid_type +} + + +# func_infer_tag arg +# Infer tagged configuration to use if any are available and +# if one wasn't chosen via the "--tag" command line option. +# Only attempt this if the compiler in the base compile +# command doesn't match the default compiler. +# arg is usually of the form 'gcc ...' +func_infer_tag () +{ + if test -n "$available_tags" && test -z "$tagname"; then + CC_quoted= + for arg in $CC; do + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + CC_quoted="$CC_quoted $arg" + done + case $@ in + # Blanks in the command may have been stripped by the calling shell, + # but not from the CC environment variable when configure was run. + " $CC "* | "$CC "* | " `$echo $CC` "* | "`$echo $CC` "* | " $CC_quoted"* | "$CC_quoted "* | " `$echo $CC_quoted` "* | "`$echo $CC_quoted` "*) ;; + # Blanks at the start of $base_compile will cause this to fail + # if we don't check for them as well. + *) + for z in $available_tags; do + if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then + # Evaluate the configuration. + eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`" + CC_quoted= + for arg in $CC; do + # Double-quote args containing other shell metacharacters. + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + CC_quoted="$CC_quoted $arg" + done + case "$@ " in + " $CC "* | "$CC "* | " `$echo $CC` "* | "`$echo $CC` "* | " $CC_quoted"* | "$CC_quoted "* | " `$echo $CC_quoted` "* | "`$echo $CC_quoted` "*) + # The compiler in the base compile command matches + # the one in the tagged configuration. + # Assume this is the tagged configuration we want. + tagname=$z + break + ;; + esac + fi + done + # If $tagname still isn't set, then no tagged configuration + # was found and let the user know that the "--tag" command + # line option must be used. + if test -z "$tagname"; then + $echo "$modename: unable to infer tagged configuration" + $echo "$modename: specify a tag with \`--tag'" 1>&2 + exit $EXIT_FAILURE +# else +# $echo "$modename: using $tagname tagged configuration" + fi + ;; + esac + fi +} + + +# func_extract_an_archive dir oldlib +func_extract_an_archive () +{ + f_ex_an_ar_dir="$1"; shift + f_ex_an_ar_oldlib="$1" + + $show "(cd $f_ex_an_ar_dir && $AR x $f_ex_an_ar_oldlib)" + $run eval "(cd \$f_ex_an_ar_dir && $AR x \$f_ex_an_ar_oldlib)" || exit $? + if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then + : + else + $echo "$modename: ERROR: object name conflicts: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib" 1>&2 + exit $EXIT_FAILURE + fi +} + +# func_extract_archives gentop oldlib ... +func_extract_archives () +{ + my_gentop="$1"; shift + my_oldlibs=${1+"$@"} + my_oldobjs="" + my_xlib="" + my_xabs="" + my_xdir="" + my_status="" + + $show "${rm}r $my_gentop" + $run ${rm}r "$my_gentop" + $show "$mkdir $my_gentop" + $run $mkdir "$my_gentop" + my_status=$? + if test "$my_status" -ne 0 && test ! -d "$my_gentop"; then + exit $my_status + fi + + for my_xlib in $my_oldlibs; do + # Extract the objects. + case $my_xlib in + [\\/]* | [A-Za-z]:[\\/]*) my_xabs="$my_xlib" ;; + *) my_xabs=`pwd`"/$my_xlib" ;; + esac + my_xlib=`$echo "X$my_xlib" | $Xsed -e 's%^.*/%%'` + my_xdir="$my_gentop/$my_xlib" + + $show "${rm}r $my_xdir" + $run ${rm}r "$my_xdir" + $show "$mkdir $my_xdir" + $run $mkdir "$my_xdir" + exit_status=$? + if test "$exit_status" -ne 0 && test ! -d "$my_xdir"; then + exit $exit_status + fi + case $host in + *-darwin*) + $show "Extracting $my_xabs" + # Do not bother doing anything if just a dry run + if test -z "$run"; then + darwin_orig_dir=`pwd` + cd $my_xdir || exit $? + darwin_archive=$my_xabs + darwin_curdir=`pwd` + darwin_base_archive=`$echo "X$darwin_archive" | $Xsed -e 's%^.*/%%'` + darwin_arches=`lipo -info "$darwin_archive" 2>/dev/null | $EGREP Architectures 2>/dev/null` + if test -n "$darwin_arches"; then + darwin_arches=`echo "$darwin_arches" | $SED -e 's/.*are://'` + darwin_arch= + $show "$darwin_base_archive has multiple architectures $darwin_arches" + for darwin_arch in $darwin_arches ; do + mkdir -p "unfat-$$/${darwin_base_archive}-${darwin_arch}" + lipo -thin $darwin_arch -output "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" "${darwin_archive}" + cd "unfat-$$/${darwin_base_archive}-${darwin_arch}" + func_extract_an_archive "`pwd`" "${darwin_base_archive}" + cd "$darwin_curdir" + $rm "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" + done # $darwin_arches + ## Okay now we have a bunch of thin objects, gotta fatten them up :) + darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print| xargs basename | sort -u | $NL2SP` + darwin_file= + darwin_files= + for darwin_file in $darwin_filelist; do + darwin_files=`find unfat-$$ -name $darwin_file -print | $NL2SP` + lipo -create -output "$darwin_file" $darwin_files + done # $darwin_filelist + ${rm}r unfat-$$ + cd "$darwin_orig_dir" + else + cd "$darwin_orig_dir" + func_extract_an_archive "$my_xdir" "$my_xabs" + fi # $darwin_arches + fi # $run + ;; + *) + func_extract_an_archive "$my_xdir" "$my_xabs" + ;; + esac + my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | $NL2SP` + done + func_extract_archives_result="$my_oldobjs" +} +# End of Shell function definitions +##################################### + +# Darwin sucks +eval std_shrext=\"$shrext_cmds\" + +disable_libs=no + +# Parse our command line options once, thoroughly. +while test "$#" -gt 0 +do + arg="$1" + shift + + case $arg in + -*=*) optarg=`$echo "X$arg" | $Xsed -e 's/[-_a-zA-Z0-9]*=//'` ;; + *) optarg= ;; + esac + + # If the previous option needs an argument, assign it. + if test -n "$prev"; then + case $prev in + execute_dlfiles) + execute_dlfiles="$execute_dlfiles $arg" + ;; + tag) + tagname="$arg" + preserve_args="${preserve_args}=$arg" + + # Check whether tagname contains only valid characters + case $tagname in + *[!-_A-Za-z0-9,/]*) + $echo "$progname: invalid tag name: $tagname" 1>&2 + exit $EXIT_FAILURE + ;; + esac + + case $tagname in + CC) + # Don't test for the "default" C tag, as we know, it's there, but + # not specially marked. + ;; + *) + if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$" < "$progpath" > /dev/null; then + taglist="$taglist $tagname" + # Evaluate the configuration. + eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$tagname'$/,/^# ### END LIBTOOL TAG CONFIG: '$tagname'$/p' < $progpath`" + else + $echo "$progname: ignoring unknown tag $tagname" 1>&2 + fi + ;; + esac + ;; + *) + eval "$prev=\$arg" + ;; + esac + + prev= + prevopt= + continue + fi + + # Have we seen a non-optional argument yet? + case $arg in + --help) + show_help=yes + ;; + + --version) + $echo "$PROGRAM (GNU $PACKAGE) $VERSION$TIMESTAMP" + $echo + $echo "Copyright (C) 2005 Free Software Foundation, Inc." + $echo "This is free software; see the source for copying conditions. There is NO" + $echo "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + exit $? + ;; + + --config) + ${SED} -e '1,/^# ### BEGIN LIBTOOL CONFIG/d' -e '/^# ### END LIBTOOL CONFIG/,$d' $progpath + # Now print the configurations for the tags. + for tagname in $taglist; do + ${SED} -n -e "/^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$/,/^# ### END LIBTOOL TAG CONFIG: $tagname$/p" < "$progpath" + done + exit $? + ;; + + --debug) + $echo "$progname: enabling shell trace mode" + set -x + preserve_args="$preserve_args $arg" + ;; + + --dry-run | -n) + run=: + ;; + + --features) + $echo "host: $host" + if test "$build_libtool_libs" = yes; then + $echo "enable shared libraries" + else + $echo "disable shared libraries" + fi + if test "$build_old_libs" = yes; then + $echo "enable static libraries" + else + $echo "disable static libraries" + fi + exit $? + ;; + + --finish) mode="finish" ;; + + --mode) prevopt="--mode" prev=mode ;; + --mode=*) mode="$optarg" ;; + + --preserve-dup-deps) duplicate_deps="yes" ;; + + --quiet | --silent) + show=: + preserve_args="$preserve_args $arg" + ;; + + --tag) + prevopt="--tag" + prev=tag + preserve_args="$preserve_args --tag" + ;; + --tag=*) + set tag "$optarg" ${1+"$@"} + shift + prev=tag + preserve_args="$preserve_args --tag" + ;; + + -dlopen) + prevopt="-dlopen" + prev=execute_dlfiles + ;; + + -*) + $echo "$modename: unrecognized option \`$arg'" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + ;; + + *) + nonopt="$arg" + break + ;; + esac +done + +if test -n "$prevopt"; then + $echo "$modename: option \`$prevopt' requires an argument" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE +fi + +case $disable_libs in +no) + ;; +shared) + build_libtool_libs=no + build_old_libs=yes + ;; +static) + build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac` + ;; +esac + +# If this variable is set in any of the actions, the command in it +# will be execed at the end. This prevents here-documents from being +# left over by shells. +exec_cmd= + +if test -z "$show_help"; then + + # Infer the operation mode. + if test -z "$mode"; then + $echo "*** Warning: inferring the mode of operation is deprecated." 1>&2 + $echo "*** Future versions of Libtool will require --mode=MODE be specified." 1>&2 + case $nonopt in + *cc | cc* | *++ | gcc* | *-gcc* | g++* | xlc*) + mode=link + for arg + do + case $arg in + -c) + mode=compile + break + ;; + esac + done + ;; + *db | *dbx | *strace | *truss) + mode=execute + ;; + *install*|cp|mv) + mode=install + ;; + *rm) + mode=uninstall + ;; + *) + # If we have no mode, but dlfiles were specified, then do execute mode. + test -n "$execute_dlfiles" && mode=execute + + # Just use the default operation mode. + if test -z "$mode"; then + if test -n "$nonopt"; then + $echo "$modename: warning: cannot infer operation mode from \`$nonopt'" 1>&2 + else + $echo "$modename: warning: cannot infer operation mode without MODE-ARGS" 1>&2 + fi + fi + ;; + esac + fi + + # Only execute mode is allowed to have -dlopen flags. + if test -n "$execute_dlfiles" && test "$mode" != execute; then + $echo "$modename: unrecognized option \`-dlopen'" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + # Change the help message to a mode-specific one. + generic_help="$help" + help="Try \`$modename --help --mode=$mode' for more information." + + # These modes are in order of execution frequency so that they run quickly. + case $mode in + # libtool compile mode + compile) + modename="$modename: compile" + # Get the compilation command and the source file. + base_compile= + srcfile="$nonopt" # always keep a non-empty value in "srcfile" + suppress_opt=yes + suppress_output= + arg_mode=normal + libobj= + later= + + for arg + do + case $arg_mode in + arg ) + # do not "continue". Instead, add this to base_compile + lastarg="$arg" + arg_mode=normal + ;; + + target ) + libobj="$arg" + arg_mode=normal + continue + ;; + + normal ) + # Accept any command-line options. + case $arg in + -o) + if test -n "$libobj" ; then + $echo "$modename: you cannot specify \`-o' more than once" 1>&2 + exit $EXIT_FAILURE + fi + arg_mode=target + continue + ;; + + -static | -prefer-pic | -prefer-non-pic) + later="$later $arg" + continue + ;; + + -no-suppress) + suppress_opt=no + continue + ;; + + -Xcompiler) + arg_mode=arg # the next one goes into the "base_compile" arg list + continue # The current "srcfile" will either be retained or + ;; # replaced later. I would guess that would be a bug. + + -Wc,*) + args=`$echo "X$arg" | $Xsed -e "s/^-Wc,//"` + lastarg= + save_ifs="$IFS"; IFS=',' + for arg in $args; do + IFS="$save_ifs" + + # Double-quote args containing other shell metacharacters. + # Many Bourne shells cannot handle close brackets correctly + # in scan sets, so we specify it separately. + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + lastarg="$lastarg $arg" + done + IFS="$save_ifs" + lastarg=`$echo "X$lastarg" | $Xsed -e "s/^ //"` + + # Add the arguments to base_compile. + base_compile="$base_compile $lastarg" + continue + ;; + + * ) + # Accept the current argument as the source file. + # The previous "srcfile" becomes the current argument. + # + lastarg="$srcfile" + srcfile="$arg" + ;; + esac # case $arg + ;; + esac # case $arg_mode + + # Aesthetically quote the previous argument. + lastarg=`$echo "X$lastarg" | $Xsed -e "$sed_quote_subst"` + + case $lastarg in + # Double-quote args containing other shell metacharacters. + # Many Bourne shells cannot handle close brackets correctly + # in scan sets, and some SunOS ksh mistreat backslash-escaping + # in scan sets (worked around with variable expansion), + # and furthermore cannot handle '|' '&' '(' ')' in scan sets + # at all, so we specify them separately. + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + lastarg="\"$lastarg\"" + ;; + esac + + base_compile="$base_compile $lastarg" + done # for arg + + case $arg_mode in + arg) + $echo "$modename: you must specify an argument for -Xcompile" + exit $EXIT_FAILURE + ;; + target) + $echo "$modename: you must specify a target with \`-o'" 1>&2 + exit $EXIT_FAILURE + ;; + *) + # Get the name of the library object. + [ -z "$libobj" ] && libobj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%'` + ;; + esac + + # Recognize several different file suffixes. + # If the user specifies -o file.o, it is replaced with file.lo + xform='[cCFSifmso]' + case $libobj in + *.ada) xform=ada ;; + *.adb) xform=adb ;; + *.ads) xform=ads ;; + *.asm) xform=asm ;; + *.c++) xform=c++ ;; + *.cc) xform=cc ;; + *.ii) xform=ii ;; + *.class) xform=class ;; + *.cpp) xform=cpp ;; + *.cxx) xform=cxx ;; + *.f90) xform=f90 ;; + *.for) xform=for ;; + *.java) xform=java ;; + esac + + libobj=`$echo "X$libobj" | $Xsed -e "s/\.$xform$/.lo/"` + + case $libobj in + *.lo) obj=`$echo "X$libobj" | $Xsed -e "$lo2o"` ;; + *) + $echo "$modename: cannot determine name of library object from \`$libobj'" 1>&2 + exit $EXIT_FAILURE + ;; + esac + + func_infer_tag $base_compile + + for arg in $later; do + case $arg in + -static) + build_old_libs=yes + continue + ;; + + -prefer-pic) + pic_mode=yes + continue + ;; + + -prefer-non-pic) + pic_mode=no + continue + ;; + esac + done + + qlibobj=`$echo "X$libobj" | $Xsed -e "$sed_quote_subst"` + case $qlibobj in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + qlibobj="\"$qlibobj\"" ;; + esac + test "X$libobj" != "X$qlibobj" \ + && $echo "X$libobj" | grep '[]~#^*{};<>?"'"'"' &()|`$[]' \ + && $echo "$modename: libobj name \`$libobj' may not contain shell special characters." + objname=`$echo "X$obj" | $Xsed -e 's%^.*/%%'` + xdir=`$echo "X$obj" | $Xsed -e 's%/[^/]*$%%'` + if test "X$xdir" = "X$obj"; then + xdir= + else + xdir=$xdir/ + fi + lobj=${xdir}$objdir/$objname + + if test -z "$base_compile"; then + $echo "$modename: you must specify a compilation command" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + # Delete any leftover library objects. + if test "$build_old_libs" = yes; then + removelist="$obj $lobj $libobj ${libobj}T" + else + removelist="$lobj $libobj ${libobj}T" + fi + + $run $rm $removelist + trap "$run $rm $removelist; exit $EXIT_FAILURE" 1 2 15 + + # On Cygwin there's no "real" PIC flag so we must build both object types + case $host_os in + cygwin* | mingw* | pw32* | os2*) + pic_mode=default + ;; + esac + if test "$pic_mode" = no && test "$deplibs_check_method" != pass_all; then + # non-PIC code in shared libraries is not supported + pic_mode=default + fi + + # Calculate the filename of the output object if compiler does + # not support -o with -c + if test "$compiler_c_o" = no; then + output_obj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%' -e 's%\.[^.]*$%%'`.${objext} + lockfile="$output_obj.lock" + removelist="$removelist $output_obj $lockfile" + trap "$run $rm $removelist; exit $EXIT_FAILURE" 1 2 15 + else + output_obj= + need_locks=no + lockfile= + fi + + # Lock this critical section if it is needed + # We use this script file to make the link, it avoids creating a new file + if test "$need_locks" = yes; then + until $run ln "$progpath" "$lockfile" 2>/dev/null; do + $show "Waiting for $lockfile to be removed" + sleep 2 + done + elif test "$need_locks" = warn; then + if test -f "$lockfile"; then + $echo "\ +*** ERROR, $lockfile exists and contains: +`cat $lockfile 2>/dev/null` + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $run $rm $removelist + exit $EXIT_FAILURE + fi + $echo "$srcfile" > "$lockfile" + fi + + if test -n "$fix_srcfile_path"; then + eval srcfile=\"$fix_srcfile_path\" + fi + qsrcfile=`$echo "X$srcfile" | $Xsed -e "$sed_quote_subst"` + case $qsrcfile in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + qsrcfile="\"$qsrcfile\"" ;; + esac + + $run $rm "$libobj" "${libobj}T" + + # Create a libtool object file (analogous to a ".la" file), + # but don't create it if we're doing a dry run. + test -z "$run" && cat > ${libobj}T <<EOF +# $libobj - a libtool object file +# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# Name of the PIC object. +EOF + + # Only build a PIC object if we are building libtool libraries. + if test "$build_libtool_libs" = yes; then + # Without this assignment, base_compile gets emptied. + fbsd_hideous_sh_bug=$base_compile + + if test "$pic_mode" != no; then + command="$base_compile $qsrcfile $pic_flag" + else + # Don't build PIC code + command="$base_compile $qsrcfile" + fi + + if test ! -d "${xdir}$objdir"; then + $show "$mkdir ${xdir}$objdir" + $run $mkdir ${xdir}$objdir + exit_status=$? + if test "$exit_status" -ne 0 && test ! -d "${xdir}$objdir"; then + exit $exit_status + fi + fi + + if test -z "$output_obj"; then + # Place PIC objects in $objdir + command="$command -o $lobj" + fi + + $run $rm "$lobj" "$output_obj" + + $show "$command" + if $run eval "$command"; then : + else + test -n "$output_obj" && $run $rm $removelist + exit $EXIT_FAILURE + fi + + if test "$need_locks" = warn && + test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then + $echo "\ +*** ERROR, $lockfile contains: +`cat $lockfile 2>/dev/null` + +but it should contain: +$srcfile + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $run $rm $removelist + exit $EXIT_FAILURE + fi + + # Just move the object if needed, then go on to compile the next one + if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then + $show "$mv $output_obj $lobj" + if $run $mv $output_obj $lobj; then : + else + error=$? + $run $rm $removelist + exit $error + fi + fi + + # Append the name of the PIC object to the libtool object file. + test -z "$run" && cat >> ${libobj}T <<EOF +pic_object='$objdir/$objname' + +EOF + + # Allow error messages only from the first compilation. + if test "$suppress_opt" = yes; then + suppress_output=' >/dev/null 2>&1' + fi + else + # No PIC object so indicate it doesn't exist in the libtool + # object file. + test -z "$run" && cat >> ${libobj}T <<EOF +pic_object=none + +EOF + fi + + # Only build a position-dependent object if we build old libraries. + if test "$build_old_libs" = yes; then + if test "$pic_mode" != yes; then + # Don't build PIC code + command="$base_compile $qsrcfile" + else + command="$base_compile $qsrcfile $pic_flag" + fi + if test "$compiler_c_o" = yes; then + command="$command -o $obj" + fi + + # Suppress compiler output if we already did a PIC compilation. + command="$command$suppress_output" + $run $rm "$obj" "$output_obj" + $show "$command" + if $run eval "$command"; then : + else + $run $rm $removelist + exit $EXIT_FAILURE + fi + + if test "$need_locks" = warn && + test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then + $echo "\ +*** ERROR, $lockfile contains: +`cat $lockfile 2>/dev/null` + +but it should contain: +$srcfile + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $run $rm $removelist + exit $EXIT_FAILURE + fi + + # Just move the object if needed + if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then + $show "$mv $output_obj $obj" + if $run $mv $output_obj $obj; then : + else + error=$? + $run $rm $removelist + exit $error + fi + fi + + # Append the name of the non-PIC object the libtool object file. + # Only append if the libtool object file exists. + test -z "$run" && cat >> ${libobj}T <<EOF +# Name of the non-PIC object. +non_pic_object='$objname' + +EOF + else + # Append the name of the non-PIC object the libtool object file. + # Only append if the libtool object file exists. + test -z "$run" && cat >> ${libobj}T <<EOF +# Name of the non-PIC object. +non_pic_object=none + +EOF + fi + + $run $mv "${libobj}T" "${libobj}" + + # Unlock the critical section if it was locked + if test "$need_locks" != no; then + $run $rm "$lockfile" + fi + + exit $EXIT_SUCCESS + ;; + + # libtool link mode + link | relink) + modename="$modename: link" + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*) + # It is impossible to link a dll without this setting, and + # we shouldn't force the makefile maintainer to figure out + # which system we are compiling for in order to pass an extra + # flag for every libtool invocation. + # allow_undefined=no + + # FIXME: Unfortunately, there are problems with the above when trying + # to make a dll which has undefined symbols, in which case not + # even a static library is built. For now, we need to specify + # -no-undefined on the libtool link line when we can be certain + # that all symbols are satisfied, otherwise we get a static library. + allow_undefined=yes + ;; + *) + allow_undefined=yes + ;; + esac + libtool_args="$nonopt" + base_compile="$nonopt $@" + compile_command="$nonopt" + finalize_command="$nonopt" + + compile_rpath= + finalize_rpath= + compile_shlibpath= + finalize_shlibpath= + convenience= + old_convenience= + deplibs= + old_deplibs= + compiler_flags= + linker_flags= + dllsearchpath= + lib_search_path=`pwd` + inst_prefix_dir= + + avoid_version=no + dlfiles= + dlprefiles= + dlself=no + export_dynamic=no + export_symbols= + export_symbols_regex= + generated= + libobjs= + ltlibs= + module=no + no_install=no + objs= + non_pic_objects= + notinst_path= # paths that contain not-installed libtool libraries + precious_files_regex= + prefer_static_libs=no + preload=no + prev= + prevarg= + release= + rpath= + xrpath= + perm_rpath= + temp_rpath= + thread_safe=no + vinfo= + vinfo_number=no + + func_infer_tag $base_compile + + # We need to know -static, to get the right output filenames. + for arg + do + case $arg in + -all-static | -static) + if test "X$arg" = "X-all-static"; then + if test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then + $echo "$modename: warning: complete static linking is impossible in this configuration" 1>&2 + fi + if test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + prefer_static_libs=yes + else + if test -z "$pic_flag" && test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + prefer_static_libs=built + fi + build_libtool_libs=no + build_old_libs=yes + break + ;; + esac + done + + # See if our shared archives depend on static archives. + test -n "$old_archive_from_new_cmds" && build_old_libs=yes + + # Go through the arguments, transforming them on the way. + while test "$#" -gt 0; do + arg="$1" + shift + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + qarg=\"`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`\" ### testsuite: skip nested quoting test + ;; + *) qarg=$arg ;; + esac + libtool_args="$libtool_args $qarg" + + # If the previous option needs an argument, assign it. + if test -n "$prev"; then + case $prev in + output) + compile_command="$compile_command @OUTPUT@" + finalize_command="$finalize_command @OUTPUT@" + ;; + esac + + case $prev in + dlfiles|dlprefiles) + if test "$preload" = no; then + # Add the symbol object into the linking commands. + compile_command="$compile_command @SYMFILE@" + finalize_command="$finalize_command @SYMFILE@" + preload=yes + fi + case $arg in + *.la | *.lo) ;; # We handle these cases below. + force) + if test "$dlself" = no; then + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + self) + if test "$prev" = dlprefiles; then + dlself=yes + elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then + dlself=yes + else + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + *) + if test "$prev" = dlfiles; then + dlfiles="$dlfiles $arg" + else + dlprefiles="$dlprefiles $arg" + fi + prev= + continue + ;; + esac + ;; + expsyms) + export_symbols="$arg" + if test ! -f "$arg"; then + $echo "$modename: symbol file \`$arg' does not exist" + exit $EXIT_FAILURE + fi + prev= + continue + ;; + expsyms_regex) + export_symbols_regex="$arg" + prev= + continue + ;; + inst_prefix) + inst_prefix_dir="$arg" + prev= + continue + ;; + precious_regex) + precious_files_regex="$arg" + prev= + continue + ;; + release) + release="-$arg" + prev= + continue + ;; + objectlist) + if test -f "$arg"; then + save_arg=$arg + moreargs= + for fil in `cat $save_arg` + do +# moreargs="$moreargs $fil" + arg=$fil + # A libtool-controlled object. + + # Check to see that this really is a libtool object. + if (${SED} -e '2q' $arg | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + pic_object= + non_pic_object= + + # Read the .lo file + # If there is no directory component, then add one. + case $arg in + */* | *\\*) . $arg ;; + *) . ./$arg ;; + esac + + if test -z "$pic_object" || \ + test -z "$non_pic_object" || + test "$pic_object" = none && \ + test "$non_pic_object" = none; then + $echo "$modename: cannot find name of object for \`$arg'" 1>&2 + exit $EXIT_FAILURE + fi + + # Extract subdirectory from the argument. + xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'` + if test "X$xdir" = "X$arg"; then + xdir= + else + xdir="$xdir/" + fi + + if test "$pic_object" != none; then + # Prepend the subdirectory the object is found in. + pic_object="$xdir$pic_object" + + if test "$prev" = dlfiles; then + if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then + dlfiles="$dlfiles $pic_object" + prev= + continue + else + # If libtool objects are unsupported, then we need to preload. + prev=dlprefiles + fi + fi + + # CHECK ME: I think I busted this. -Ossama + if test "$prev" = dlprefiles; then + # Preload the old-style object. + dlprefiles="$dlprefiles $pic_object" + prev= + fi + + # A PIC object. + libobjs="$libobjs $pic_object" + arg="$pic_object" + fi + + # Non-PIC object. + if test "$non_pic_object" != none; then + # Prepend the subdirectory the object is found in. + non_pic_object="$xdir$non_pic_object" + + # A standard non-PIC object + non_pic_objects="$non_pic_objects $non_pic_object" + if test -z "$pic_object" || test "$pic_object" = none ; then + arg="$non_pic_object" + fi + else + # If the PIC object exists, use it instead. + # $xdir was prepended to $pic_object above. + non_pic_object="$pic_object" + non_pic_objects="$non_pic_objects $non_pic_object" + fi + else + # Only an error if not doing a dry-run. + if test -z "$run"; then + $echo "$modename: \`$arg' is not a valid libtool object" 1>&2 + exit $EXIT_FAILURE + else + # Dry-run case. + + # Extract subdirectory from the argument. + xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'` + if test "X$xdir" = "X$arg"; then + xdir= + else + xdir="$xdir/" + fi + + pic_object=`$echo "X${xdir}${objdir}/${arg}" | $Xsed -e "$lo2o"` + non_pic_object=`$echo "X${xdir}${arg}" | $Xsed -e "$lo2o"` + libobjs="$libobjs $pic_object" + non_pic_objects="$non_pic_objects $non_pic_object" + fi + fi + done + else + $echo "$modename: link input file \`$save_arg' does not exist" + exit $EXIT_FAILURE + fi + arg=$save_arg + prev= + continue + ;; + rpath | xrpath) + # We need an absolute path. + case $arg in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + $echo "$modename: only absolute run-paths are allowed" 1>&2 + exit $EXIT_FAILURE + ;; + esac + if test "$prev" = rpath; then + case "$rpath " in + *" $arg "*) ;; + *) rpath="$rpath $arg" ;; + esac + else + case "$xrpath " in + *" $arg "*) ;; + *) xrpath="$xrpath $arg" ;; + esac + fi + prev= + continue + ;; + xcompiler) + compiler_flags="$compiler_flags $qarg" + prev= + compile_command="$compile_command $qarg" + finalize_command="$finalize_command $qarg" + continue + ;; + xlinker) + linker_flags="$linker_flags $qarg" + compiler_flags="$compiler_flags $wl$qarg" + prev= + compile_command="$compile_command $wl$qarg" + finalize_command="$finalize_command $wl$qarg" + continue + ;; + xcclinker) + linker_flags="$linker_flags $qarg" + compiler_flags="$compiler_flags $qarg" + prev= + compile_command="$compile_command $qarg" + finalize_command="$finalize_command $qarg" + continue + ;; + shrext) + shrext_cmds="$arg" + prev= + continue + ;; + darwin_framework|darwin_framework_skip) + test "$prev" = "darwin_framework" && compiler_flags="$compiler_flags $arg" + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + prev= + continue + ;; + *) + eval "$prev=\"\$arg\"" + prev= + continue + ;; + esac + fi # test -n "$prev" + + prevarg="$arg" + + case $arg in + -all-static) + if test -n "$link_static_flag"; then + compile_command="$compile_command $link_static_flag" + finalize_command="$finalize_command $link_static_flag" + fi + continue + ;; + + -allow-undefined) + # FIXME: remove this flag sometime in the future. + $echo "$modename: \`-allow-undefined' is deprecated because it is the default" 1>&2 + continue + ;; + + -avoid-version) + avoid_version=yes + continue + ;; + + -dlopen) + prev=dlfiles + continue + ;; + + -dlpreopen) + prev=dlprefiles + continue + ;; + + -export-dynamic) + export_dynamic=yes + continue + ;; + + -export-symbols | -export-symbols-regex) + if test -n "$export_symbols" || test -n "$export_symbols_regex"; then + $echo "$modename: more than one -exported-symbols argument is not allowed" + exit $EXIT_FAILURE + fi + if test "X$arg" = "X-export-symbols"; then + prev=expsyms + else + prev=expsyms_regex + fi + continue + ;; + + -framework|-arch|-isysroot) + case " $CC " in + *" ${arg} ${1} "* | *" ${arg} ${1} "*) + prev=darwin_framework_skip ;; + *) compiler_flags="$compiler_flags $arg" + prev=darwin_framework ;; + esac + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + continue + ;; + + -inst-prefix-dir) + prev=inst_prefix + continue + ;; + + # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:* + # so, if we see these flags be careful not to treat them like -L + -L[A-Z][A-Z]*:*) + case $with_gcc/$host in + no/*-*-irix* | /*-*-irix*) + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + ;; + esac + continue + ;; + + -L*) + dir=`$echo "X$arg" | $Xsed -e 's/^-L//'` + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + absdir=`cd "$dir" && pwd` + if test -z "$absdir"; then + $echo "$modename: cannot determine absolute directory name of \`$dir'" 1>&2 + absdir="$dir" + notinst_path="$notinst_path $dir" + fi + dir="$absdir" + ;; + esac + case "$deplibs " in + *" -L$dir "*) ;; + *) + deplibs="$deplibs -L$dir" + lib_search_path="$lib_search_path $dir" + ;; + esac + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*) + testbindir=`$echo "X$dir" | $Xsed -e 's*/lib$*/bin*'` + case :$dllsearchpath: in + *":$dir:"*) ;; + *) dllsearchpath="$dllsearchpath:$dir";; + esac + case :$dllsearchpath: in + *":$testbindir:"*) ;; + *) dllsearchpath="$dllsearchpath:$testbindir";; + esac + ;; + esac + continue + ;; + + -l*) + if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos*) + # These systems don't actually have a C or math library (as such) + continue + ;; + *-*-os2*) + # These systems don't actually have a C library (as such) + test "X$arg" = "X-lc" && continue + ;; + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) + # Do not include libc due to us having libc/libc_r. + test "X$arg" = "X-lc" && continue + ;; + *-*-rhapsody* | *-*-darwin1.[012]) + # Rhapsody C and math libraries are in the System framework + deplibs="$deplibs -framework System" + continue + ;; + *-*-sco3.2v5* | *-*-sco5v6*) + # Causes problems with __ctype + test "X$arg" = "X-lc" && continue + ;; + *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) + # Compiler inserts libc in the correct place for threads to work + test "X$arg" = "X-lc" && continue + ;; + esac + elif test "X$arg" = "X-lc_r"; then + case $host in + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) + # Do not include libc_r directly, use -pthread flag. + continue + ;; + esac + fi + deplibs="$deplibs $arg" + continue + ;; + + # Tru64 UNIX uses -model [arg] to determine the layout of C++ + # classes, name mangling, and exception handling. + -model) + compile_command="$compile_command $arg" + compiler_flags="$compiler_flags $arg" + finalize_command="$finalize_command $arg" + prev=xcompiler + continue + ;; + + -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe) + compiler_flags="$compiler_flags $arg" + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + continue + ;; + + -module) + module=yes + continue + ;; + + # -64, -mips[0-9] enable 64-bit mode on the SGI compiler + # -r[0-9][0-9]* specifies the processor on the SGI compiler + # -xarch=*, -xtarget=* enable 64-bit mode on the Sun compiler + # +DA*, +DD* enable 64-bit mode on the HP compiler + # -q* pass through compiler args for the IBM compiler + # -m* pass through architecture-specific compiler args for GCC + # -m*, -t[45]*, -txscale* pass through architecture-specific + # compiler args for GCC + # -pg pass through profiling flag for GCC + # @file GCC response files + -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*|-pg| \ + -t[45]*|-txscale*|@*) + + # Unknown arguments in both finalize_command and compile_command need + # to be aesthetically quoted because they are evaled later. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + compiler_flags="$compiler_flags $arg" + continue + ;; + + -shrext) + prev=shrext + continue + ;; + + -no-fast-install) + fast_install=no + continue + ;; + + -no-install) + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*) + # The PATH hackery in wrapper scripts is required on Windows + # in order for the loader to find any dlls it needs. + $echo "$modename: warning: \`-no-install' is ignored for $host" 1>&2 + $echo "$modename: warning: assuming \`-no-fast-install' instead" 1>&2 + fast_install=no + ;; + *) no_install=yes ;; + esac + continue + ;; + + -no-undefined) + allow_undefined=no + continue + ;; + + -objectlist) + prev=objectlist + continue + ;; + + -o) prev=output ;; + + -precious-files-regex) + prev=precious_regex + continue + ;; + + -release) + prev=release + continue + ;; + + -rpath) + prev=rpath + continue + ;; + + -R) + prev=xrpath + continue + ;; + + -R*) + dir=`$echo "X$arg" | $Xsed -e 's/^-R//'` + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + $echo "$modename: only absolute run-paths are allowed" 1>&2 + exit $EXIT_FAILURE + ;; + esac + case "$xrpath " in + *" $dir "*) ;; + *) xrpath="$xrpath $dir" ;; + esac + continue + ;; + + -static) + # The effects of -static are defined in a previous loop. + # We used to do the same as -all-static on platforms that + # didn't have a PIC flag, but the assumption that the effects + # would be equivalent was wrong. It would break on at least + # Digital Unix and AIX. + continue + ;; + + -thread-safe) + thread_safe=yes + continue + ;; + + -version-info) + prev=vinfo + continue + ;; + -version-number) + prev=vinfo + vinfo_number=yes + continue + ;; + + -Wc,*) + args=`$echo "X$arg" | $Xsed -e "$sed_quote_subst" -e 's/^-Wc,//'` + arg= + save_ifs="$IFS"; IFS=',' + for flag in $args; do + IFS="$save_ifs" + case $flag in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + flag="\"$flag\"" + ;; + esac + arg="$arg $wl$flag" + compiler_flags="$compiler_flags $flag" + done + IFS="$save_ifs" + arg=`$echo "X$arg" | $Xsed -e "s/^ //"` + ;; + + -Wl,*) + args=`$echo "X$arg" | $Xsed -e "$sed_quote_subst" -e 's/^-Wl,//'` + arg= + save_ifs="$IFS"; IFS=',' + for flag in $args; do + IFS="$save_ifs" + case $flag in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + flag="\"$flag\"" + ;; + esac + arg="$arg $wl$flag" + compiler_flags="$compiler_flags $wl$flag" + linker_flags="$linker_flags $flag" + done + IFS="$save_ifs" + arg=`$echo "X$arg" | $Xsed -e "s/^ //"` + ;; + + -Xcompiler) + prev=xcompiler + continue + ;; + + -Xlinker) + prev=xlinker + continue + ;; + + -XCClinker) + prev=xcclinker + continue + ;; + + # Some other compiler flag. + -* | +*) + # Unknown arguments in both finalize_command and compile_command need + # to be aesthetically quoted because they are evaled later. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + ;; + + *.$objext) + # A standard object. + objs="$objs $arg" + ;; + + *.lo) + # A libtool-controlled object. + + # Check to see that this really is a libtool object. + if (${SED} -e '2q' $arg | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + pic_object= + non_pic_object= + + # Read the .lo file + # If there is no directory component, then add one. + case $arg in + */* | *\\*) . $arg ;; + *) . ./$arg ;; + esac + + if test -z "$pic_object" || \ + test -z "$non_pic_object" || + test "$pic_object" = none && \ + test "$non_pic_object" = none; then + $echo "$modename: cannot find name of object for \`$arg'" 1>&2 + exit $EXIT_FAILURE + fi + + # Extract subdirectory from the argument. + xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'` + if test "X$xdir" = "X$arg"; then + xdir= + else + xdir="$xdir/" + fi + + if test "$pic_object" != none; then + # Prepend the subdirectory the object is found in. + pic_object="$xdir$pic_object" + + if test "$prev" = dlfiles; then + if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then + dlfiles="$dlfiles $pic_object" + prev= + continue + else + # If libtool objects are unsupported, then we need to preload. + prev=dlprefiles + fi + fi + + # CHECK ME: I think I busted this. -Ossama + if test "$prev" = dlprefiles; then + # Preload the old-style object. + dlprefiles="$dlprefiles $pic_object" + prev= + fi + + # A PIC object. + libobjs="$libobjs $pic_object" + arg="$pic_object" + fi + + # Non-PIC object. + if test "$non_pic_object" != none; then + # Prepend the subdirectory the object is found in. + non_pic_object="$xdir$non_pic_object" + + # A standard non-PIC object + non_pic_objects="$non_pic_objects $non_pic_object" + if test -z "$pic_object" || test "$pic_object" = none ; then + arg="$non_pic_object" + fi + else + # If the PIC object exists, use it instead. + # $xdir was prepended to $pic_object above. + non_pic_object="$pic_object" + non_pic_objects="$non_pic_objects $non_pic_object" + fi + else + # Only an error if not doing a dry-run. + if test -z "$run"; then + $echo "$modename: \`$arg' is not a valid libtool object" 1>&2 + exit $EXIT_FAILURE + else + # Dry-run case. + + # Extract subdirectory from the argument. + xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'` + if test "X$xdir" = "X$arg"; then + xdir= + else + xdir="$xdir/" + fi + + pic_object=`$echo "X${xdir}${objdir}/${arg}" | $Xsed -e "$lo2o"` + non_pic_object=`$echo "X${xdir}${arg}" | $Xsed -e "$lo2o"` + libobjs="$libobjs $pic_object" + non_pic_objects="$non_pic_objects $non_pic_object" + fi + fi + ;; + + *.$libext) + # An archive. + deplibs="$deplibs $arg" + old_deplibs="$old_deplibs $arg" + continue + ;; + + *.la) + # A libtool-controlled library. + + if test "$prev" = dlfiles; then + # This library was specified with -dlopen. + dlfiles="$dlfiles $arg" + prev= + elif test "$prev" = dlprefiles; then + # The library was specified with -dlpreopen. + dlprefiles="$dlprefiles $arg" + prev= + else + deplibs="$deplibs $arg" + fi + continue + ;; + + # Some other compiler argument. + *) + # Unknown arguments in both finalize_command and compile_command need + # to be aesthetically quoted because they are evaled later. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + ;; + esac # arg + + # Now actually substitute the argument into the commands. + if test -n "$arg"; then + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + fi + done # argument parsing loop + + if test -n "$prev"; then + $echo "$modename: the \`$prevarg' option requires an argument" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then + eval arg=\"$export_dynamic_flag_spec\" + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + fi + + oldlibs= + # calculate the name of the file, without its directory + outputname=`$echo "X$output" | $Xsed -e 's%^.*/%%'` + libobjs_save="$libobjs" + + if test -n "$shlibpath_var"; then + # get the directories listed in $shlibpath_var + eval shlib_search_path=\`\$echo \"X\${$shlibpath_var}\" \| \$Xsed -e \'s/:/ /g\'\` + else + shlib_search_path= + fi + eval sys_lib_search_path=\"$sys_lib_search_path_spec\" + eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\" + + output_objdir=`$echo "X$output" | $Xsed -e 's%/[^/]*$%%'` + if test "X$output_objdir" = "X$output"; then + output_objdir="$objdir" + else + output_objdir="$output_objdir/$objdir" + fi + # Create the object directory. + if test ! -d "$output_objdir"; then + $show "$mkdir $output_objdir" + $run $mkdir $output_objdir + exit_status=$? + if test "$exit_status" -ne 0 && test ! -d "$output_objdir"; then + exit $exit_status + fi + fi + + # Determine the type of output + case $output in + "") + $echo "$modename: you must specify an output file" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + ;; + *.$libext) linkmode=oldlib ;; + *.lo | *.$objext) linkmode=obj ;; + *.la) linkmode=lib ;; + *) linkmode=prog ;; # Anything else should be a program. + esac + + case $host in + *cygwin* | *mingw* | *pw32*) + # don't eliminate duplications in $postdeps and $predeps + duplicate_compiler_generated_deps=yes + ;; + *) + duplicate_compiler_generated_deps=$duplicate_deps + ;; + esac + specialdeplibs= + + libs= + # Find all interdependent deplibs by searching for libraries + # that are linked more than once (e.g. -la -lb -la) + for deplib in $deplibs; do + if test "X$duplicate_deps" = "Xyes" ; then + case "$libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + libs="$libs $deplib" + done + + if test "$linkmode" = lib; then + libs="$predeps $libs $compiler_lib_search_path $postdeps" + + # Compute libraries that are listed more than once in $predeps + # $postdeps and mark them as special (i.e., whose duplicates are + # not to be eliminated). + pre_post_deps= + if test "X$duplicate_compiler_generated_deps" = "Xyes" ; then + for pre_post_dep in $predeps $postdeps; do + case "$pre_post_deps " in + *" $pre_post_dep "*) specialdeplibs="$specialdeplibs $pre_post_deps" ;; + esac + pre_post_deps="$pre_post_deps $pre_post_dep" + done + fi + pre_post_deps= + fi + + deplibs= + newdependency_libs= + newlib_search_path= + need_relink=no # whether we're linking any uninstalled libtool libraries + notinst_deplibs= # not-installed libtool libraries + case $linkmode in + lib) + passes="conv link" + for file in $dlfiles $dlprefiles; do + case $file in + *.la) ;; + *) + $echo "$modename: libraries can \`-dlopen' only libtool libraries: $file" 1>&2 + exit $EXIT_FAILURE + ;; + esac + done + ;; + prog) + compile_deplibs= + finalize_deplibs= + alldeplibs=no + newdlfiles= + newdlprefiles= + passes="conv scan dlopen dlpreopen link" + ;; + *) passes="conv" + ;; + esac + for pass in $passes; do + if test "$linkmode,$pass" = "lib,link" || + test "$linkmode,$pass" = "prog,scan"; then + libs="$deplibs" + deplibs= + fi + if test "$linkmode" = prog; then + case $pass in + dlopen) libs="$dlfiles" ;; + dlpreopen) libs="$dlprefiles" ;; + link) libs="$deplibs %DEPLIBS% $dependency_libs" ;; + esac + fi + if test "$pass" = dlopen; then + # Collect dlpreopened libraries + save_deplibs="$deplibs" + deplibs= + fi + for deplib in $libs; do + lib= + found=no + case $deplib in + -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe) + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + compiler_flags="$compiler_flags $deplib" + fi + continue + ;; + -l*) + if test "$linkmode" != lib && test "$linkmode" != prog; then + $echo "$modename: warning: \`-l' is ignored for archives/objects" 1>&2 + continue + fi + name=`$echo "X$deplib" | $Xsed -e 's/^-l//'` + for searchdir in $newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path; do + for search_ext in .la $std_shrext .so .a; do + # Search the libtool library + lib="$searchdir/lib${name}${search_ext}" + if test -f "$lib"; then + if test "$search_ext" = ".la"; then + found=yes + else + found=no + fi + break 2 + fi + done + done + if test "$found" != yes; then + # deplib doesn't seem to be a libtool library + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" + fi + continue + else # deplib is a libtool library + # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib, + # We need to do some special things here, and not later. + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + case " $predeps $postdeps " in + *" $deplib "*) + if (${SED} -e '2q' $lib | + grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + library_names= + old_library= + case $lib in + */* | *\\*) . $lib ;; + *) . ./$lib ;; + esac + for l in $old_library $library_names; do + ll="$l" + done + if test "X$ll" = "X$old_library" ; then # only static version available + found=no + ladir=`$echo "X$lib" | $Xsed -e 's%/[^/]*$%%'` + test "X$ladir" = "X$lib" && ladir="." + lib=$ladir/$old_library + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" + fi + continue + fi + fi + ;; + *) ;; + esac + fi + fi + ;; # -l + -L*) + case $linkmode in + lib) + deplibs="$deplib $deplibs" + test "$pass" = conv && continue + newdependency_libs="$deplib $newdependency_libs" + newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'` + ;; + prog) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + continue + fi + if test "$pass" = scan; then + deplibs="$deplib $deplibs" + else + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + fi + newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'` + ;; + *) + $echo "$modename: warning: \`-L' is ignored for archives/objects" 1>&2 + ;; + esac # linkmode + continue + ;; # -L + -R*) + if test "$pass" = link; then + dir=`$echo "X$deplib" | $Xsed -e 's/^-R//'` + # Make sure the xrpath contains only unique directories. + case "$xrpath " in + *" $dir "*) ;; + *) xrpath="$xrpath $dir" ;; + esac + fi + deplibs="$deplib $deplibs" + continue + ;; + *.la) lib="$deplib" ;; + *.$libext) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + continue + fi + case $linkmode in + lib) + valid_a_lib=no + case $deplibs_check_method in + match_pattern*) + set dummy $deplibs_check_method + match_pattern_regex=`expr "$deplibs_check_method" : "$2 \(.*\)"` + if eval $echo \"$deplib\" 2>/dev/null \ + | $SED 10q \ + | $EGREP "$match_pattern_regex" > /dev/null; then + valid_a_lib=yes + fi + ;; + pass_all) + valid_a_lib=yes + ;; + esac + if test "$valid_a_lib" != yes; then + $echo + $echo "*** Warning: Trying to link with static lib archive $deplib." + $echo "*** I have the capability to make that library automatically link in when" + $echo "*** you link to this library. But I can only do this if you have a" + $echo "*** shared version of the library, which you do not appear to have" + $echo "*** because the file extensions .$libext of this argument makes me believe" + $echo "*** that it is just a static archive that I should not used here." + else + $echo + $echo "*** Warning: Linking the shared library $output against the" + $echo "*** static library $deplib is not portable!" + deplibs="$deplib $deplibs" + fi + continue + ;; + prog) + if test "$pass" != link; then + deplibs="$deplib $deplibs" + else + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + fi + continue + ;; + esac # linkmode + ;; # *.$libext + *.lo | *.$objext) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + elif test "$linkmode" = prog; then + if test "$pass" = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then + # If there is no dlopen support or we're linking statically, + # we need to preload. + newdlprefiles="$newdlprefiles $deplib" + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + newdlfiles="$newdlfiles $deplib" + fi + fi + continue + ;; + %DEPLIBS%) + alldeplibs=yes + continue + ;; + esac # case $deplib + if test "$found" = yes || test -f "$lib"; then : + else + $echo "$modename: cannot find the library \`$lib' or unhandled argument \`$deplib'" 1>&2 + exit $EXIT_FAILURE + fi + + # Check to see that this really is a libtool archive. + if (${SED} -e '2q' $lib | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : + else + $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 + exit $EXIT_FAILURE + fi + + ladir=`$echo "X$lib" | $Xsed -e 's%/[^/]*$%%'` + test "X$ladir" = "X$lib" && ladir="." + + dlname= + dlopen= + dlpreopen= + libdir= + library_names= + old_library= + # If the library was installed with an old release of libtool, + # it will not redefine variables installed, or shouldnotlink + installed=yes + shouldnotlink=no + avoidtemprpath= + + + # Read the .la file + case $lib in + */* | *\\*) . $lib ;; + *) . ./$lib ;; + esac + + if test "$linkmode,$pass" = "lib,link" || + test "$linkmode,$pass" = "prog,scan" || + { test "$linkmode" != prog && test "$linkmode" != lib; }; then + test -n "$dlopen" && dlfiles="$dlfiles $dlopen" + test -n "$dlpreopen" && dlprefiles="$dlprefiles $dlpreopen" + fi + + if test "$pass" = conv; then + # Only check for convenience libraries + deplibs="$lib $deplibs" + if test -z "$libdir"; then + if test -z "$old_library"; then + $echo "$modename: cannot find name of link library for \`$lib'" 1>&2 + exit $EXIT_FAILURE + fi + # It is a libtool convenience library, so add in its objects. + convenience="$convenience $ladir/$objdir/$old_library" + old_convenience="$old_convenience $ladir/$objdir/$old_library" + tmp_libs= + for deplib in $dependency_libs; do + deplibs="$deplib $deplibs" + if test "X$duplicate_deps" = "Xyes" ; then + case "$tmp_libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + tmp_libs="$tmp_libs $deplib" + done + elif test "$linkmode" != prog && test "$linkmode" != lib; then + $echo "$modename: \`$lib' is not a convenience library" 1>&2 + exit $EXIT_FAILURE + fi + continue + fi # $pass = conv + + + # Get the name of the library we link against. + linklib= + for l in $old_library $library_names; do + linklib="$l" + done + if test -z "$linklib"; then + $echo "$modename: cannot find name of link library for \`$lib'" 1>&2 + exit $EXIT_FAILURE + fi + + # This library was specified with -dlopen. + if test "$pass" = dlopen; then + if test -z "$libdir"; then + $echo "$modename: cannot -dlopen a convenience library: \`$lib'" 1>&2 + exit $EXIT_FAILURE + fi + if test -z "$dlname" || + test "$dlopen_support" != yes || + test "$build_libtool_libs" = no; then + # If there is no dlname, no dlopen support or we're linking + # statically, we need to preload. We also need to preload any + # dependent libraries so libltdl's deplib preloader doesn't + # bomb out in the load deplibs phase. + dlprefiles="$dlprefiles $lib $dependency_libs" + else + newdlfiles="$newdlfiles $lib" + fi + continue + fi # $pass = dlopen + + # We need an absolute path. + case $ladir in + [\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;; + *) + abs_ladir=`cd "$ladir" && pwd` + if test -z "$abs_ladir"; then + $echo "$modename: warning: cannot determine absolute directory name of \`$ladir'" 1>&2 + $echo "$modename: passing it literally to the linker, although it might fail" 1>&2 + abs_ladir="$ladir" + fi + ;; + esac + laname=`$echo "X$lib" | $Xsed -e 's%^.*/%%'` + + # Find the relevant object directory and library name. + if test "X$installed" = Xyes; then + if test ! -f "$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then + $echo "$modename: warning: library \`$lib' was moved." 1>&2 + dir="$ladir" + absdir="$abs_ladir" + libdir="$abs_ladir" + else + dir="$libdir" + absdir="$libdir" + fi + test "X$hardcode_automatic" = Xyes && avoidtemprpath=yes + else + if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then + dir="$ladir" + absdir="$abs_ladir" + # Remove this search path later + notinst_path="$notinst_path $abs_ladir" + else + dir="$ladir/$objdir" + absdir="$abs_ladir/$objdir" + # Remove this search path later + notinst_path="$notinst_path $abs_ladir" + fi + fi # $installed = yes + name=`$echo "X$laname" | $Xsed -e 's/\.la$//' -e 's/^lib//'` + + # This library was specified with -dlpreopen. + if test "$pass" = dlpreopen; then + if test -z "$libdir"; then + $echo "$modename: cannot -dlpreopen a convenience library: \`$lib'" 1>&2 + exit $EXIT_FAILURE + fi + # Prefer using a static library (so that no silly _DYNAMIC symbols + # are required to link). + if test -n "$old_library"; then + newdlprefiles="$newdlprefiles $dir/$old_library" + # Otherwise, use the dlname, so that lt_dlopen finds it. + elif test -n "$dlname"; then + newdlprefiles="$newdlprefiles $dir/$dlname" + else + newdlprefiles="$newdlprefiles $dir/$linklib" + fi + fi # $pass = dlpreopen + + if test -z "$libdir"; then + # Link the convenience library + if test "$linkmode" = lib; then + deplibs="$dir/$old_library $deplibs" + elif test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$dir/$old_library $compile_deplibs" + finalize_deplibs="$dir/$old_library $finalize_deplibs" + else + deplibs="$lib $deplibs" # used for prog,scan pass + fi + continue + fi + + + if test "$linkmode" = prog && test "$pass" != link; then + newlib_search_path="$newlib_search_path $ladir" + deplibs="$lib $deplibs" + + linkalldeplibs=no + if test "$link_all_deplibs" != no || test -z "$library_names" || + test "$build_libtool_libs" = no; then + linkalldeplibs=yes + fi + + tmp_libs= + for deplib in $dependency_libs; do + case $deplib in + -L*) newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'`;; ### testsuite: skip nested quoting test + esac + # Need to link against all dependency_libs? + if test "$linkalldeplibs" = yes; then + deplibs="$deplib $deplibs" + else + # Need to hardcode shared library paths + # or/and link against static libraries + newdependency_libs="$deplib $newdependency_libs" + fi + if test "X$duplicate_deps" = "Xyes" ; then + case "$tmp_libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + tmp_libs="$tmp_libs $deplib" + done # for deplib + continue + fi # $linkmode = prog... + + if test "$linkmode,$pass" = "prog,link"; then + if test -n "$library_names" && + { test "$prefer_static_libs" = no || test -z "$old_library"; }; then + # We need to hardcode the library path + if test -n "$shlibpath_var" && test -z "$avoidtemprpath" ; then + # Make sure the rpath contains only unique directories. + case "$temp_rpath " in + *" $dir "*) ;; + *" $absdir "*) ;; + *) temp_rpath="$temp_rpath $absdir" ;; + esac + fi + + # Hardcode the library path. + # Skip directories that are in the system default run-time + # search path. + case " $sys_lib_dlsearch_path " in + *" $absdir "*) ;; + *) + case "$compile_rpath " in + *" $absdir "*) ;; + *) compile_rpath="$compile_rpath $absdir" + esac + ;; + esac + case " $sys_lib_dlsearch_path " in + *" $libdir "*) ;; + *) + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" + esac + ;; + esac + fi # $linkmode,$pass = prog,link... + + if test "$alldeplibs" = yes && + { test "$deplibs_check_method" = pass_all || + { test "$build_libtool_libs" = yes && + test -n "$library_names"; }; }; then + # We only need to search for static libraries + continue + fi + fi + + link_static=no # Whether the deplib will be linked statically + use_static_libs=$prefer_static_libs + if test "$use_static_libs" = built && test "$installed" = yes ; then + use_static_libs=no + fi + if test -n "$library_names" && + { test "$use_static_libs" = no || test -z "$old_library"; }; then + if test "$installed" = no; then + notinst_deplibs="$notinst_deplibs $lib" + need_relink=yes + fi + # This is a shared library + + # Warn about portability, can't link against -module's on + # some systems (darwin) + if test "$shouldnotlink" = yes && test "$pass" = link ; then + $echo + if test "$linkmode" = prog; then + $echo "*** Warning: Linking the executable $output against the loadable module" + else + $echo "*** Warning: Linking the shared library $output against the loadable module" + fi + $echo "*** $linklib is not portable!" + fi + if test "$linkmode" = lib && + test "$hardcode_into_libs" = yes; then + # Hardcode the library path. + # Skip directories that are in the system default run-time + # search path. + case " $sys_lib_dlsearch_path " in + *" $absdir "*) ;; + *) + case "$compile_rpath " in + *" $absdir "*) ;; + *) compile_rpath="$compile_rpath $absdir" + esac + ;; + esac + case " $sys_lib_dlsearch_path " in + *" $libdir "*) ;; + *) + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" + esac + ;; + esac + fi + + if test -n "$old_archive_from_expsyms_cmds"; then + # figure out the soname + set dummy $library_names + realname="$2" + shift; shift + libname=`eval \\$echo \"$libname_spec\"` + # use dlname if we got it. it's perfectly good, no? + if test -n "$dlname"; then + soname="$dlname" + elif test -n "$soname_spec"; then + # bleh windows + case $host in + *cygwin* | mingw*) + major=`expr $current - $age` + versuffix="-$major" + ;; + esac + eval soname=\"$soname_spec\" + else + soname="$realname" + fi + + # Make a new name for the extract_expsyms_cmds to use + soroot="$soname" + soname=`$echo $soroot | ${SED} -e 's/^.*\///'` + newlib="libimp-`$echo $soname | ${SED} 's/^lib//;s/\.dll$//'`.a" + + # If the library has no export list, then create one now + if test -f "$output_objdir/$soname-def"; then : + else + $show "extracting exported symbol list from \`$soname'" + save_ifs="$IFS"; IFS='~' + cmds=$extract_expsyms_cmds + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + fi + + # Create $newlib + if test -f "$output_objdir/$newlib"; then :; else + $show "generating import library for \`$soname'" + save_ifs="$IFS"; IFS='~' + cmds=$old_archive_from_expsyms_cmds + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + fi + # make sure the library variables are pointing to the new library + dir=$output_objdir + linklib=$newlib + fi # test -n "$old_archive_from_expsyms_cmds" + + if test "$linkmode" = prog || test "$mode" != relink; then + add_shlibpath= + add_dir= + add= + lib_linked=yes + case $hardcode_action in + immediate | unsupported) + if test "$hardcode_direct" = no; then + add="$dir/$linklib" + case $host in + *-*-sco3.2v5.0.[024]*) add_dir="-L$dir" ;; + *-*-sysv4*uw2*) add_dir="-L$dir" ;; + *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \ + *-*-unixware7*) add_dir="-L$dir" ;; + *-*-darwin* ) + # if the lib is a module then we can not link against + # it, someone is ignoring the new warnings I added + if /usr/bin/file -L $add 2> /dev/null | + $EGREP ": [^:]* bundle" >/dev/null ; then + $echo "** Warning, lib $linklib is a module, not a shared library" + if test -z "$old_library" ; then + $echo + $echo "** And there doesn't seem to be a static archive available" + $echo "** The link will probably fail, sorry" + else + add="$dir/$old_library" + fi + fi + esac + elif test "$hardcode_minus_L" = no; then + case $host in + *-*-sunos*) add_shlibpath="$dir" ;; + esac + add_dir="-L$dir" + add="-l$name" + elif test "$hardcode_shlibpath_var" = no; then + add_shlibpath="$dir" + add="-l$name" + else + lib_linked=no + fi + ;; + relink) + if test "$hardcode_direct" = yes; then + add="$dir/$linklib" + elif test "$hardcode_minus_L" = yes; then + add_dir="-L$dir" + # Try looking first in the location we're being installed to. + if test -n "$inst_prefix_dir"; then + case $libdir in + [\\/]*) + add_dir="$add_dir -L$inst_prefix_dir$libdir" + ;; + esac + fi + add="-l$name" + elif test "$hardcode_shlibpath_var" = yes; then + add_shlibpath="$dir" + add="-l$name" + else + lib_linked=no + fi + ;; + *) lib_linked=no ;; + esac + + if test "$lib_linked" != yes; then + $echo "$modename: configuration error: unsupported hardcode properties" + exit $EXIT_FAILURE + fi + + if test -n "$add_shlibpath"; then + case :$compile_shlibpath: in + *":$add_shlibpath:"*) ;; + *) compile_shlibpath="$compile_shlibpath$add_shlibpath:" ;; + esac + fi + if test "$linkmode" = prog; then + test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs" + test -n "$add" && compile_deplibs="$add $compile_deplibs" + else + test -n "$add_dir" && deplibs="$add_dir $deplibs" + test -n "$add" && deplibs="$add $deplibs" + if test "$hardcode_direct" != yes && \ + test "$hardcode_minus_L" != yes && \ + test "$hardcode_shlibpath_var" = yes; then + case :$finalize_shlibpath: in + *":$libdir:"*) ;; + *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;; + esac + fi + fi + fi + + if test "$linkmode" = prog || test "$mode" = relink; then + add_shlibpath= + add_dir= + add= + # Finalize command for both is simple: just hardcode it. + if test "$hardcode_direct" = yes; then + add="$libdir/$linklib" + elif test "$hardcode_minus_L" = yes; then + add_dir="-L$libdir" + add="-l$name" + elif test "$hardcode_shlibpath_var" = yes; then + case :$finalize_shlibpath: in + *":$libdir:"*) ;; + *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;; + esac + add="-l$name" + elif test "$hardcode_automatic" = yes; then + if test -n "$inst_prefix_dir" && + test -f "$inst_prefix_dir$libdir/$linklib" ; then + add="$inst_prefix_dir$libdir/$linklib" + else + add="$libdir/$linklib" + fi + else + # We cannot seem to hardcode it, guess we'll fake it. + add_dir="-L$libdir" + # Try looking first in the location we're being installed to. + if test -n "$inst_prefix_dir"; then + case $libdir in + [\\/]*) + add_dir="$add_dir -L$inst_prefix_dir$libdir" + ;; + esac + fi + add="-l$name" + fi + + if test "$linkmode" = prog; then + test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs" + test -n "$add" && finalize_deplibs="$add $finalize_deplibs" + else + test -n "$add_dir" && deplibs="$add_dir $deplibs" + test -n "$add" && deplibs="$add $deplibs" + fi + fi + elif test "$linkmode" = prog; then + # Here we assume that one of hardcode_direct or hardcode_minus_L + # is not unsupported. This is valid on all known static and + # shared platforms. + if test "$hardcode_direct" != unsupported; then + test -n "$old_library" && linklib="$old_library" + compile_deplibs="$dir/$linklib $compile_deplibs" + finalize_deplibs="$dir/$linklib $finalize_deplibs" + else + compile_deplibs="-l$name -L$dir $compile_deplibs" + finalize_deplibs="-l$name -L$dir $finalize_deplibs" + fi + elif test "$build_libtool_libs" = yes; then + # Not a shared library + if test "$deplibs_check_method" != pass_all; then + # We're trying link a shared library against a static one + # but the system doesn't support it. + + # Just print a warning and add the library to dependency_libs so + # that the program can be linked against the static library. + $echo + $echo "*** Warning: This system can not link to static lib archive $lib." + $echo "*** I have the capability to make that library automatically link in when" + $echo "*** you link to this library. But I can only do this if you have a" + $echo "*** shared version of the library, which you do not appear to have." + if test "$module" = yes; then + $echo "*** But as you try to build a module library, libtool will still create " + $echo "*** a static module, that should work as long as the dlopening application" + $echo "*** is linked with the -dlopen flag to resolve symbols at runtime." + if test -z "$global_symbol_pipe"; then + $echo + $echo "*** However, this would only work if libtool was able to extract symbol" + $echo "*** lists from a program, using \`nm' or equivalent, but libtool could" + $echo "*** not find such a program. So, this module is probably useless." + $echo "*** \`nm' from GNU binutils and a full rebuild may help." + fi + if test "$build_old_libs" = no; then + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + fi + else + deplibs="$dir/$old_library $deplibs" + link_static=yes + fi + fi # link shared/static library? + + if test "$linkmode" = lib; then + if test -n "$dependency_libs" && + { test "$hardcode_into_libs" != yes || + test "$build_old_libs" = yes || + test "$link_static" = yes; }; then + # Extract -R from dependency_libs + temp_deplibs= + for libdir in $dependency_libs; do + case $libdir in + -R*) temp_xrpath=`$echo "X$libdir" | $Xsed -e 's/^-R//'` + case " $xrpath " in + *" $temp_xrpath "*) ;; + *) xrpath="$xrpath $temp_xrpath";; + esac;; + *) temp_deplibs="$temp_deplibs $libdir";; + esac + done + dependency_libs="$temp_deplibs" + fi + + newlib_search_path="$newlib_search_path $absdir" + # Link against this library + test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs" + # ... and its dependency_libs + tmp_libs= + for deplib in $dependency_libs; do + newdependency_libs="$deplib $newdependency_libs" + if test "X$duplicate_deps" = "Xyes" ; then + case "$tmp_libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + tmp_libs="$tmp_libs $deplib" + done + + if test "$link_all_deplibs" != no; then + # Add the search paths of all dependency libraries + for deplib in $dependency_libs; do + case $deplib in + -L*) path="$deplib" ;; + *.la) + dir=`$echo "X$deplib" | $Xsed -e 's%/[^/]*$%%'` + test "X$dir" = "X$deplib" && dir="." + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;; + *) + absdir=`cd "$dir" && pwd` + if test -z "$absdir"; then + $echo "$modename: warning: cannot determine absolute directory name of \`$dir'" 1>&2 + absdir="$dir" + fi + ;; + esac + if grep "^installed=no" $deplib > /dev/null; then + path="$absdir/$objdir" + else + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` + if test -z "$libdir"; then + $echo "$modename: \`$deplib' is not a valid libtool archive" 1>&2 + exit $EXIT_FAILURE + fi + if test "$absdir" != "$libdir"; then + $echo "$modename: warning: \`$deplib' seems to be moved" 1>&2 + fi + path="$absdir" + fi + depdepl= + case $host in + *-*-darwin*) + # we do not want to link against static libs, + # but need to link against shared + eval deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib` + if test -n "$deplibrary_names" ; then + for tmp in $deplibrary_names ; do + depdepl=$tmp + done + if test -f "$path/$depdepl" ; then + depdepl="$path/$depdepl" + fi + # do not add paths which are already there + case " $newlib_search_path " in + *" $path "*) ;; + *) newlib_search_path="$newlib_search_path $path";; + esac + fi + path="" + ;; + *) + path="-L$path" + ;; + esac + ;; + -l*) + case $host in + *-*-darwin*) + # Again, we only want to link against shared libraries + eval tmp_libs=`$echo "X$deplib" | $Xsed -e "s,^\-l,,"` + for tmp in $newlib_search_path ; do + if test -f "$tmp/lib$tmp_libs.dylib" ; then + eval depdepl="$tmp/lib$tmp_libs.dylib" + break + fi + done + path="" + ;; + *) continue ;; + esac + ;; + *) continue ;; + esac + case " $deplibs " in + *" $path "*) ;; + *) deplibs="$path $deplibs" ;; + esac + case " $deplibs " in + *" $depdepl "*) ;; + *) deplibs="$depdepl $deplibs" ;; + esac + done + fi # link_all_deplibs != no + fi # linkmode = lib + done # for deplib in $libs + dependency_libs="$newdependency_libs" + if test "$pass" = dlpreopen; then + # Link the dlpreopened libraries before other libraries + for deplib in $save_deplibs; do + deplibs="$deplib $deplibs" + done + fi + if test "$pass" != dlopen; then + if test "$pass" != conv; then + # Make sure lib_search_path contains only unique directories. + lib_search_path= + for dir in $newlib_search_path; do + case "$lib_search_path " in + *" $dir "*) ;; + *) lib_search_path="$lib_search_path $dir" ;; + esac + done + newlib_search_path= + fi + + if test "$linkmode,$pass" != "prog,link"; then + vars="deplibs" + else + vars="compile_deplibs finalize_deplibs" + fi + for var in $vars dependency_libs; do + # Add libraries to $var in reverse order + eval tmp_libs=\"\$$var\" + new_libs= + for deplib in $tmp_libs; do + # FIXME: Pedantically, this is the right thing to do, so + # that some nasty dependency loop isn't accidentally + # broken: + #new_libs="$deplib $new_libs" + # Pragmatically, this seems to cause very few problems in + # practice: + case $deplib in + -L*) new_libs="$deplib $new_libs" ;; + -R*) ;; + *) + # And here is the reason: when a library appears more + # than once as an explicit dependence of a library, or + # is implicitly linked in more than once by the + # compiler, it is considered special, and multiple + # occurrences thereof are not removed. Compare this + # with having the same library being listed as a + # dependency of multiple other libraries: in this case, + # we know (pedantically, we assume) the library does not + # need to be listed more than once, so we keep only the + # last copy. This is not always right, but it is rare + # enough that we require users that really mean to play + # such unportable linking tricks to link the library + # using -Wl,-lname, so that libtool does not consider it + # for duplicate removal. + case " $specialdeplibs " in + *" $deplib "*) new_libs="$deplib $new_libs" ;; + *) + case " $new_libs " in + *" $deplib "*) ;; + *) new_libs="$deplib $new_libs" ;; + esac + ;; + esac + ;; + esac + done + tmp_libs= + for deplib in $new_libs; do + case $deplib in + -L*) + case " $tmp_libs " in + *" $deplib "*) ;; + *) tmp_libs="$tmp_libs $deplib" ;; + esac + ;; + *) tmp_libs="$tmp_libs $deplib" ;; + esac + done + eval $var=\"$tmp_libs\" + done # for var + fi + # Last step: remove runtime libs from dependency_libs + # (they stay in deplibs) + tmp_libs= + for i in $dependency_libs ; do + case " $predeps $postdeps $compiler_lib_search_path " in + *" $i "*) + i="" + ;; + esac + if test -n "$i" ; then + tmp_libs="$tmp_libs $i" + fi + done + dependency_libs=$tmp_libs + done # for pass + if test "$linkmode" = prog; then + dlfiles="$newdlfiles" + dlprefiles="$newdlprefiles" + fi + + case $linkmode in + oldlib) + if test -n "$deplibs"; then + $echo "$modename: warning: \`-l' and \`-L' are ignored for archives" 1>&2 + fi + + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + $echo "$modename: warning: \`-dlopen' is ignored for archives" 1>&2 + fi + + if test -n "$rpath"; then + $echo "$modename: warning: \`-rpath' is ignored for archives" 1>&2 + fi + + if test -n "$xrpath"; then + $echo "$modename: warning: \`-R' is ignored for archives" 1>&2 + fi + + if test -n "$vinfo"; then + $echo "$modename: warning: \`-version-info/-version-number' is ignored for archives" 1>&2 + fi + + if test -n "$release"; then + $echo "$modename: warning: \`-release' is ignored for archives" 1>&2 + fi + + if test -n "$export_symbols" || test -n "$export_symbols_regex"; then + $echo "$modename: warning: \`-export-symbols' is ignored for archives" 1>&2 + fi + + # Now set the variables for building old libraries. + build_libtool_libs=no + oldlibs="$output" + objs="$objs$old_deplibs" + ;; + + lib) + # Make sure we only generate libraries of the form `libNAME.la'. + case $outputname in + lib*) + name=`$echo "X$outputname" | $Xsed -e 's/\.la$//' -e 's/^lib//'` + eval shared_ext=\"$shrext_cmds\" + eval libname=\"$libname_spec\" + ;; + *) + if test "$module" = no; then + $echo "$modename: libtool library \`$output' must begin with \`lib'" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + if test "$need_lib_prefix" != no; then + # Add the "lib" prefix for modules if required + name=`$echo "X$outputname" | $Xsed -e 's/\.la$//'` + eval shared_ext=\"$shrext_cmds\" + eval libname=\"$libname_spec\" + else + libname=`$echo "X$outputname" | $Xsed -e 's/\.la$//'` + fi + ;; + esac + + if test -n "$objs"; then + if test "$deplibs_check_method" != pass_all; then + $echo "$modename: cannot build libtool library \`$output' from non-libtool objects on this host:$objs" 2>&1 + exit $EXIT_FAILURE + else + $echo + $echo "*** Warning: Linking the shared library $output against the non-libtool" + $echo "*** objects $objs is not portable!" + libobjs="$libobjs $objs" + fi + fi + + if test "$dlself" != no; then + $echo "$modename: warning: \`-dlopen self' is ignored for libtool libraries" 1>&2 + fi + + set dummy $rpath + if test "$#" -gt 2; then + $echo "$modename: warning: ignoring multiple \`-rpath's for a libtool library" 1>&2 + fi + install_libdir="$2" + + oldlibs= + if test -z "$rpath"; then + if test "$build_libtool_libs" = yes; then + # Building a libtool convenience library. + # Some compilers have problems with a `.al' extension so + # convenience libraries should have the same extension an + # archive normally would. + oldlibs="$output_objdir/$libname.$libext $oldlibs" + build_libtool_libs=convenience + build_old_libs=yes + fi + + if test -n "$vinfo"; then + $echo "$modename: warning: \`-version-info/-version-number' is ignored for convenience libraries" 1>&2 + fi + + if test -n "$release"; then + $echo "$modename: warning: \`-release' is ignored for convenience libraries" 1>&2 + fi + else + + # Parse the version information argument. + save_ifs="$IFS"; IFS=':' + set dummy $vinfo 0 0 0 + IFS="$save_ifs" + + if test -n "$8"; then + $echo "$modename: too many parameters to \`-version-info'" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + # convert absolute version numbers to libtool ages + # this retains compatibility with .la files and attempts + # to make the code below a bit more comprehensible + + case $vinfo_number in + yes) + number_major="$2" + number_minor="$3" + number_revision="$4" + # + # There are really only two kinds -- those that + # use the current revision as the major version + # and those that subtract age and use age as + # a minor version. But, then there is irix + # which has an extra 1 added just for fun + # + case $version_type in + darwin|linux|osf|windows) + current=`expr $number_major + $number_minor` + age="$number_minor" + revision="$number_revision" + ;; + freebsd-aout|freebsd-elf|sunos) + current="$number_major" + revision="$number_minor" + age="0" + ;; + irix|nonstopux) + current=`expr $number_major + $number_minor - 1` + age="$number_minor" + revision="$number_minor" + ;; + esac + ;; + no) + current="$2" + revision="$3" + age="$4" + ;; + esac + + # Check that each of the things are valid numbers. + case $current in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + $echo "$modename: CURRENT \`$current' must be a nonnegative integer" 1>&2 + $echo "$modename: \`$vinfo' is not valid version information" 1>&2 + exit $EXIT_FAILURE + ;; + esac + + case $revision in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + $echo "$modename: REVISION \`$revision' must be a nonnegative integer" 1>&2 + $echo "$modename: \`$vinfo' is not valid version information" 1>&2 + exit $EXIT_FAILURE + ;; + esac + + case $age in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + $echo "$modename: AGE \`$age' must be a nonnegative integer" 1>&2 + $echo "$modename: \`$vinfo' is not valid version information" 1>&2 + exit $EXIT_FAILURE + ;; + esac + + if test "$age" -gt "$current"; then + $echo "$modename: AGE \`$age' is greater than the current interface number \`$current'" 1>&2 + $echo "$modename: \`$vinfo' is not valid version information" 1>&2 + exit $EXIT_FAILURE + fi + + # Calculate the version variables. + major= + versuffix= + verstring= + case $version_type in + none) ;; + + darwin) + # Like Linux, but with the current version available in + # verstring for coding it into the library header + major=.`expr $current - $age` + versuffix="$major.$age.$revision" + # Darwin ld doesn't like 0 for these options... + minor_current=`expr $current + 1` + verstring="${wl}-compatibility_version ${wl}$minor_current ${wl}-current_version ${wl}$minor_current.$revision" + ;; + + freebsd-aout) + major=".$current" + versuffix=".$current.$revision"; + ;; + + freebsd-elf) + major=".$current" + versuffix=".$current"; + ;; + + irix | nonstopux) + major=`expr $current - $age + 1` + + case $version_type in + nonstopux) verstring_prefix=nonstopux ;; + *) verstring_prefix=sgi ;; + esac + verstring="$verstring_prefix$major.$revision" + + # Add in all the interfaces that we are compatible with. + loop=$revision + while test "$loop" -ne 0; do + iface=`expr $revision - $loop` + loop=`expr $loop - 1` + verstring="$verstring_prefix$major.$iface:$verstring" + done + + # Before this point, $major must not contain `.'. + major=.$major + versuffix="$major.$revision" + ;; + + linux) + major=.`expr $current - $age` + versuffix="$major.$age.$revision" + ;; + + osf) + major=.`expr $current - $age` + versuffix=".$current.$age.$revision" + verstring="$current.$age.$revision" + + # Add in all the interfaces that we are compatible with. + loop=$age + while test "$loop" -ne 0; do + iface=`expr $current - $loop` + loop=`expr $loop - 1` + verstring="$verstring:${iface}.0" + done + + # Make executables depend on our current version. + verstring="$verstring:${current}.0" + ;; + + sunos) + major=".$current" + versuffix=".$current.$revision" + ;; + + windows) + # Use '-' rather than '.', since we only want one + # extension on DOS 8.3 filesystems. + major=`expr $current - $age` + versuffix="-$major" + ;; + + *) + $echo "$modename: unknown library version type \`$version_type'" 1>&2 + $echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2 + exit $EXIT_FAILURE + ;; + esac + + # Clear the version info if we defaulted, and they specified a release. + if test -z "$vinfo" && test -n "$release"; then + major= + case $version_type in + darwin) + # we can't check for "0.0" in archive_cmds due to quoting + # problems, so we reset it completely + verstring= + ;; + *) + verstring="0.0" + ;; + esac + if test "$need_version" = no; then + versuffix= + else + versuffix=".0.0" + fi + fi + + # Remove version info from name if versioning should be avoided + if test "$avoid_version" = yes && test "$need_version" = no; then + major= + versuffix= + verstring="" + fi + + # Check to see if the archive will have undefined symbols. + if test "$allow_undefined" = yes; then + if test "$allow_undefined_flag" = unsupported; then + $echo "$modename: warning: undefined symbols not allowed in $host shared libraries" 1>&2 + build_libtool_libs=no + build_old_libs=yes + fi + else + # Don't allow undefined symbols. + allow_undefined_flag="$no_undefined_flag" + fi + fi + + if test "$mode" != relink; then + # Remove our outputs, but don't remove object files since they + # may have been created when compiling PIC objects. + removelist= + tempremovelist=`$echo "$output_objdir/*"` + for p in $tempremovelist; do + case $p in + *.$objext) + ;; + $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*) + if test "X$precious_files_regex" != "X"; then + if echo $p | $EGREP -e "$precious_files_regex" >/dev/null 2>&1 + then + continue + fi + fi + removelist="$removelist $p" + ;; + *) ;; + esac + done + if test -n "$removelist"; then + $show "${rm}r $removelist" + $run ${rm}r $removelist + fi + fi + + # Now set the variables for building old libraries. + if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then + oldlibs="$oldlibs $output_objdir/$libname.$libext" + + # Transform .lo files to .o files. + oldobjs="$objs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}'$/d' -e "$lo2o" | $NL2SP` + fi + + # Eliminate all temporary directories. + for path in $notinst_path; do + lib_search_path=`$echo "$lib_search_path " | ${SED} -e "s% $path % %g"` + deplibs=`$echo "$deplibs " | ${SED} -e "s% -L$path % %g"` + dependency_libs=`$echo "$dependency_libs " | ${SED} -e "s% -L$path % %g"` + done + + if test -n "$xrpath"; then + # If the user specified any rpath flags, then add them. + temp_xrpath= + for libdir in $xrpath; do + temp_xrpath="$temp_xrpath -R$libdir" + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" ;; + esac + done + if test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; then + dependency_libs="$temp_xrpath $dependency_libs" + fi + fi + + # Make sure dlfiles contains only unique files that won't be dlpreopened + old_dlfiles="$dlfiles" + dlfiles= + for lib in $old_dlfiles; do + case " $dlprefiles $dlfiles " in + *" $lib "*) ;; + *) dlfiles="$dlfiles $lib" ;; + esac + done + + # Make sure dlprefiles contains only unique files + old_dlprefiles="$dlprefiles" + dlprefiles= + for lib in $old_dlprefiles; do + case "$dlprefiles " in + *" $lib "*) ;; + *) dlprefiles="$dlprefiles $lib" ;; + esac + done + + if test "$build_libtool_libs" = yes; then + if test -n "$rpath"; then + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos*) + # these systems don't actually have a c library (as such)! + ;; + *-*-rhapsody* | *-*-darwin1.[012]) + # Rhapsody C library is in the System framework + deplibs="$deplibs -framework System" + ;; + *-*-netbsd*) + # Don't link with libc until the a.out ld.so is fixed. + ;; + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) + # Do not include libc due to us having libc/libc_r. + ;; + *-*-sco3.2v5* | *-*-sco5v6*) + # Causes problems with __ctype + ;; + *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) + # Compiler inserts libc in the correct place for threads to work + ;; + *) + # Add libc to deplibs on all other systems if necessary. + if test "$build_libtool_need_lc" = "yes"; then + deplibs="$deplibs -lc" + fi + ;; + esac + fi + + # Transform deplibs into only deplibs that can be linked in shared. + name_save=$name + libname_save=$libname + release_save=$release + versuffix_save=$versuffix + major_save=$major + # I'm not sure if I'm treating the release correctly. I think + # release should show up in the -l (ie -lgmp5) so we don't want to + # add it in twice. Is that correct? + release="" + versuffix="" + major="" + newdeplibs= + droppeddeps=no + case $deplibs_check_method in + pass_all) + # Don't check for shared/static. Everything works. + # This might be a little naive. We might want to check + # whether the library exists or not. But this is on + # osf3 & osf4 and I'm not really sure... Just + # implementing what was already the behavior. + newdeplibs=$deplibs + ;; + test_compile) + # This code stresses the "libraries are programs" paradigm to its + # limits. Maybe even breaks it. We compile a program, linking it + # against the deplibs as a proxy for the library. Then we can check + # whether they linked in statically or dynamically with ldd. + $rm conftest.c + cat > conftest.c <<EOF + int main() { return 0; } +EOF + $rm conftest + $LTCC $LTCFLAGS -o conftest conftest.c $deplibs + if test "$?" -eq 0 ; then + ldd_output=`ldd conftest` + for i in $deplibs; do + name=`expr $i : '-l\(.*\)'` + # If $name is empty we are operating on a -L argument. + if test "$name" != "" && test "$name" -ne "0"; then + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + case " $predeps $postdeps " in + *" $i "*) + newdeplibs="$newdeplibs $i" + i="" + ;; + esac + fi + if test -n "$i" ; then + libname=`eval \\$echo \"$libname_spec\"` + deplib_matches=`eval \\$echo \"$library_names_spec\"` + set dummy $deplib_matches + deplib_match=$2 + if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then + newdeplibs="$newdeplibs $i" + else + droppeddeps=yes + $echo + $echo "*** Warning: dynamic linker does not accept needed library $i." + $echo "*** I have the capability to make that library automatically link in when" + $echo "*** you link to this library. But I can only do this if you have a" + $echo "*** shared version of the library, which I believe you do not have" + $echo "*** because a test_compile did reveal that the linker did not use it for" + $echo "*** its dynamic dependency list that programs get resolved with at runtime." + fi + fi + else + newdeplibs="$newdeplibs $i" + fi + done + else + # Error occurred in the first compile. Let's try to salvage + # the situation: Compile a separate program for each library. + for i in $deplibs; do + name=`expr $i : '-l\(.*\)'` + # If $name is empty we are operating on a -L argument. + if test "$name" != "" && test "$name" != "0"; then + $rm conftest + $LTCC $LTCFLAGS -o conftest conftest.c $i + # Did it work? + if test "$?" -eq 0 ; then + ldd_output=`ldd conftest` + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + case " $predeps $postdeps " in + *" $i "*) + newdeplibs="$newdeplibs $i" + i="" + ;; + esac + fi + if test -n "$i" ; then + libname=`eval \\$echo \"$libname_spec\"` + deplib_matches=`eval \\$echo \"$library_names_spec\"` + set dummy $deplib_matches + deplib_match=$2 + if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then + newdeplibs="$newdeplibs $i" + else + droppeddeps=yes + $echo + $echo "*** Warning: dynamic linker does not accept needed library $i." + $echo "*** I have the capability to make that library automatically link in when" + $echo "*** you link to this library. But I can only do this if you have a" + $echo "*** shared version of the library, which you do not appear to have" + $echo "*** because a test_compile did reveal that the linker did not use this one" + $echo "*** as a dynamic dependency that programs can get resolved with at runtime." + fi + fi + else + droppeddeps=yes + $echo + $echo "*** Warning! Library $i is needed by this library but I was not able to" + $echo "*** make it link in! You will probably need to install it or some" + $echo "*** library that it depends on before this library will be fully" + $echo "*** functional. Installing it before continuing would be even better." + fi + else + newdeplibs="$newdeplibs $i" + fi + done + fi + ;; + file_magic*) + set dummy $deplibs_check_method + file_magic_regex=`expr "$deplibs_check_method" : "$2 \(.*\)"` + for a_deplib in $deplibs; do + name=`expr $a_deplib : '-l\(.*\)'` + # If $name is empty we are operating on a -L argument. + if test "$name" != "" && test "$name" != "0"; then + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + case " $predeps $postdeps " in + *" $a_deplib "*) + newdeplibs="$newdeplibs $a_deplib" + a_deplib="" + ;; + esac + fi + if test -n "$a_deplib" ; then + libname=`eval \\$echo \"$libname_spec\"` + for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do + potential_libs=`ls $i/$libname[.-]* 2>/dev/null` + for potent_lib in $potential_libs; do + # Follow soft links. + if ls -lLd "$potent_lib" 2>/dev/null \ + | grep " -> " >/dev/null; then + continue + fi + # The statement above tries to avoid entering an + # endless loop below, in case of cyclic links. + # We might still enter an endless loop, since a link + # loop can be closed while we follow links, + # but so what? + potlib="$potent_lib" + while test -h "$potlib" 2>/dev/null; do + potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'` + case $potliblink in + [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";; + *) potlib=`$echo "X$potlib" | $Xsed -e 's,[^/]*$,,'`"$potliblink";; + esac + done + if eval $file_magic_cmd \"\$potlib\" 2>/dev/null \ + | ${SED} 10q \ + | $EGREP "$file_magic_regex" > /dev/null; then + newdeplibs="$newdeplibs $a_deplib" + a_deplib="" + break 2 + fi + done + done + fi + if test -n "$a_deplib" ; then + droppeddeps=yes + $echo + $echo "*** Warning: linker path does not have real file for library $a_deplib." + $echo "*** I have the capability to make that library automatically link in when" + $echo "*** you link to this library. But I can only do this if you have a" + $echo "*** shared version of the library, which you do not appear to have" + $echo "*** because I did check the linker path looking for a file starting" + if test -z "$potlib" ; then + $echo "*** with $libname but no candidates were found. (...for file magic test)" + else + $echo "*** with $libname and none of the candidates passed a file format test" + $echo "*** using a file magic. Last file checked: $potlib" + fi + fi + else + # Add a -L argument. + newdeplibs="$newdeplibs $a_deplib" + fi + done # Gone through all deplibs. + ;; + match_pattern*) + set dummy $deplibs_check_method + match_pattern_regex=`expr "$deplibs_check_method" : "$2 \(.*\)"` + for a_deplib in $deplibs; do + name=`expr $a_deplib : '-l\(.*\)'` + # If $name is empty we are operating on a -L argument. + if test -n "$name" && test "$name" != "0"; then + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + case " $predeps $postdeps " in + *" $a_deplib "*) + newdeplibs="$newdeplibs $a_deplib" + a_deplib="" + ;; + esac + fi + if test -n "$a_deplib" ; then + libname=`eval \\$echo \"$libname_spec\"` + for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do + potential_libs=`ls $i/$libname[.-]* 2>/dev/null` + for potent_lib in $potential_libs; do + potlib="$potent_lib" # see symlink-check above in file_magic test + if eval $echo \"$potent_lib\" 2>/dev/null \ + | ${SED} 10q \ + | $EGREP "$match_pattern_regex" > /dev/null; then + newdeplibs="$newdeplibs $a_deplib" + a_deplib="" + break 2 + fi + done + done + fi + if test -n "$a_deplib" ; then + droppeddeps=yes + $echo + $echo "*** Warning: linker path does not have real file for library $a_deplib." + $echo "*** I have the capability to make that library automatically link in when" + $echo "*** you link to this library. But I can only do this if you have a" + $echo "*** shared version of the library, which you do not appear to have" + $echo "*** because I did check the linker path looking for a file starting" + if test -z "$potlib" ; then + $echo "*** with $libname but no candidates were found. (...for regex pattern test)" + else + $echo "*** with $libname and none of the candidates passed a file format test" + $echo "*** using a regex pattern. Last file checked: $potlib" + fi + fi + else + # Add a -L argument. + newdeplibs="$newdeplibs $a_deplib" + fi + done # Gone through all deplibs. + ;; + none | unknown | *) + newdeplibs="" + tmp_deplibs=`$echo "X $deplibs" | $Xsed -e 's/ -lc$//' \ + -e 's/ -[LR][^ ]*//g'` + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + for i in $predeps $postdeps ; do + # can't use Xsed below, because $i might contain '/' + tmp_deplibs=`$echo "X $tmp_deplibs" | ${SED} -e "1s,^X,," -e "s,$i,,"` + done + fi + if $echo "X $tmp_deplibs" | $Xsed -e 's/[ ]//g' \ + | grep . >/dev/null; then + $echo + if test "X$deplibs_check_method" = "Xnone"; then + $echo "*** Warning: inter-library dependencies are not supported in this platform." + else + $echo "*** Warning: inter-library dependencies are not known to be supported." + fi + $echo "*** All declared inter-library dependencies are being dropped." + droppeddeps=yes + fi + ;; + esac + versuffix=$versuffix_save + major=$major_save + release=$release_save + libname=$libname_save + name=$name_save + + case $host in + *-*-rhapsody* | *-*-darwin1.[012]) + # On Rhapsody replace the C library is the System framework + newdeplibs=`$echo "X $newdeplibs" | $Xsed -e 's/ -lc / -framework System /'` + ;; + esac + + if test "$droppeddeps" = yes; then + if test "$module" = yes; then + $echo + $echo "*** Warning: libtool could not satisfy all declared inter-library" + $echo "*** dependencies of module $libname. Therefore, libtool will create" + $echo "*** a static module, that should work as long as the dlopening" + $echo "*** application is linked with the -dlopen flag." + if test -z "$global_symbol_pipe"; then + $echo + $echo "*** However, this would only work if libtool was able to extract symbol" + $echo "*** lists from a program, using \`nm' or equivalent, but libtool could" + $echo "*** not find such a program. So, this module is probably useless." + $echo "*** \`nm' from GNU binutils and a full rebuild may help." + fi + if test "$build_old_libs" = no; then + oldlibs="$output_objdir/$libname.$libext" + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + else + $echo "*** The inter-library dependencies that have been dropped here will be" + $echo "*** automatically added whenever a program is linked with this library" + $echo "*** or is declared to -dlopen it." + + if test "$allow_undefined" = no; then + $echo + $echo "*** Since this library must not contain undefined symbols," + $echo "*** because either the platform does not support them or" + $echo "*** it was explicitly requested with -no-undefined," + $echo "*** libtool will only create a static version of it." + if test "$build_old_libs" = no; then + oldlibs="$output_objdir/$libname.$libext" + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + fi + fi + fi + # Done checking deplibs! + deplibs=$newdeplibs + fi + + + # move library search paths that coincide with paths to not yet + # installed libraries to the beginning of the library search list + new_libs= + for path in $notinst_path; do + case " $new_libs " in + *" -L$path/$objdir "*) ;; + *) + case " $deplibs " in + *" -L$path/$objdir "*) + new_libs="$new_libs -L$path/$objdir" ;; + esac + ;; + esac + done + for deplib in $deplibs; do + case $deplib in + -L*) + case " $new_libs " in + *" $deplib "*) ;; + *) new_libs="$new_libs $deplib" ;; + esac + ;; + *) new_libs="$new_libs $deplib" ;; + esac + done + deplibs="$new_libs" + + + # All the library-specific variables (install_libdir is set above). + library_names= + old_library= + dlname= + + # Test again, we may have decided not to build it any more + if test "$build_libtool_libs" = yes; then + if test "$hardcode_into_libs" = yes; then + # Hardcode the library paths + hardcode_libdirs= + dep_rpath= + rpath="$finalize_rpath" + test "$mode" != relink && rpath="$compile_rpath$rpath" + for libdir in $rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + dep_rpath="$dep_rpath $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) perm_rpath="$perm_rpath $libdir" ;; + esac + fi + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + if test -n "$hardcode_libdir_flag_spec_ld"; then + eval dep_rpath=\"$hardcode_libdir_flag_spec_ld\" + else + eval dep_rpath=\"$hardcode_libdir_flag_spec\" + fi + fi + if test -n "$runpath_var" && test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + rpath="$rpath$dir:" + done + eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var" + fi + test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs" + fi + + shlibpath="$finalize_shlibpath" + test "$mode" != relink && shlibpath="$compile_shlibpath$shlibpath" + if test -n "$shlibpath"; then + eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var" + fi + + # Get the real and link names of the library. + eval shared_ext=\"$shrext_cmds\" + eval library_names=\"$library_names_spec\" + set dummy $library_names + realname="$2" + shift; shift + + if test -n "$soname_spec"; then + eval soname=\"$soname_spec\" + else + soname="$realname" + fi + if test -z "$dlname"; then + dlname=$soname + fi + + lib="$output_objdir/$realname" + linknames= + for link + do + linknames="$linknames $link" + done + + # Use standard objects if they are pic + test -z "$pic_flag" && libobjs=`$echo "X$libobjs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + + # Prepare the list of exported symbols + if test -z "$export_symbols"; then + if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then + $show "generating symbol list for \`$libname.la'" + export_symbols="$output_objdir/$libname.exp" + $run $rm $export_symbols + cmds=$export_symbols_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + if len=`expr "X$cmd" : ".*"` && + test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then + $show "$cmd" + $run eval "$cmd" || exit $? + skipped_export=false + else + # The command line is too long to execute in one step. + $show "using reloadable object file for export list..." + skipped_export=: + # Break out early, otherwise skipped_export may be + # set to false by a later but shorter cmd. + break + fi + done + IFS="$save_ifs" + if test -n "$export_symbols_regex"; then + $show "$EGREP -e \"$export_symbols_regex\" \"$export_symbols\" > \"${export_symbols}T\"" + $run eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' + $show "$mv \"${export_symbols}T\" \"$export_symbols\"" + $run eval '$mv "${export_symbols}T" "$export_symbols"' + fi + fi + fi + + if test -n "$export_symbols" && test -n "$include_expsyms"; then + $run eval '$echo "X$include_expsyms" | $SP2NL >> "$export_symbols"' + fi + + tmp_deplibs= + for test_deplib in $deplibs; do + case " $convenience " in + *" $test_deplib "*) ;; + *) + tmp_deplibs="$tmp_deplibs $test_deplib" + ;; + esac + done + deplibs="$tmp_deplibs" + + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec"; then + save_libobjs=$libobjs + eval libobjs=\"\$libobjs $whole_archive_flag_spec\" + else + gentop="$output_objdir/${outputname}x" + generated="$generated $gentop" + + func_extract_archives $gentop $convenience + libobjs="$libobjs $func_extract_archives_result" + fi + fi + + if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then + eval flag=\"$thread_safe_flag_spec\" + linker_flags="$linker_flags $flag" + fi + + # Make a backup of the uninstalled library when relinking + if test "$mode" = relink; then + $run eval '(cd $output_objdir && $rm ${realname}U && $mv $realname ${realname}U)' || exit $? + fi + + # Do each of the archive commands. + if test "$module" = yes && test -n "$module_cmds" ; then + if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then + eval test_cmds=\"$module_expsym_cmds\" + cmds=$module_expsym_cmds + else + eval test_cmds=\"$module_cmds\" + cmds=$module_cmds + fi + else + if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then + eval test_cmds=\"$archive_expsym_cmds\" + cmds=$archive_expsym_cmds + else + eval test_cmds=\"$archive_cmds\" + cmds=$archive_cmds + fi + fi + + if test "X$skipped_export" != "X:" && + len=`expr "X$test_cmds" : ".*" 2>/dev/null` && + test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then + : + else + # The command line is too long to link in one step, link piecewise. + $echo "creating reloadable object files..." + + # Save the value of $output and $libobjs because we want to + # use them later. If we have whole_archive_flag_spec, we + # want to use save_libobjs as it was before + # whole_archive_flag_spec was expanded, because we can't + # assume the linker understands whole_archive_flag_spec. + # This may have to be revisited, in case too many + # convenience libraries get linked in and end up exceeding + # the spec. + if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then + save_libobjs=$libobjs + fi + save_output=$output + output_la=`$echo "X$output" | $Xsed -e "$basename"` + + # Clear the reloadable object creation command queue and + # initialize k to one. + test_cmds= + concat_cmds= + objlist= + delfiles= + last_robj= + k=1 + output=$output_objdir/$output_la-${k}.$objext + # Loop over the list of objects to be linked. + for obj in $save_libobjs + do + eval test_cmds=\"$reload_cmds $objlist $last_robj\" + if test "X$objlist" = X || + { len=`expr "X$test_cmds" : ".*" 2>/dev/null` && + test "$len" -le "$max_cmd_len"; }; then + objlist="$objlist $obj" + else + # The command $test_cmds is almost too long, add a + # command to the queue. + if test "$k" -eq 1 ; then + # The first file doesn't have a previous command to add. + eval concat_cmds=\"$reload_cmds $objlist $last_robj\" + else + # All subsequent reloadable object files will link in + # the last one created. + eval concat_cmds=\"\$concat_cmds~$reload_cmds $objlist $last_robj\" + fi + last_robj=$output_objdir/$output_la-${k}.$objext + k=`expr $k + 1` + output=$output_objdir/$output_la-${k}.$objext + objlist=$obj + len=1 + fi + done + # Handle the remaining objects by creating one last + # reloadable object file. All subsequent reloadable object + # files will link in the last one created. + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + eval concat_cmds=\"\${concat_cmds}$reload_cmds $objlist $last_robj\" + + if ${skipped_export-false}; then + $show "generating symbol list for \`$libname.la'" + export_symbols="$output_objdir/$libname.exp" + $run $rm $export_symbols + libobjs=$output + # Append the command to create the export file. + eval concat_cmds=\"\$concat_cmds~$export_symbols_cmds\" + fi + + # Set up a command to remove the reloadable object files + # after they are used. + i=0 + while test "$i" -lt "$k" + do + i=`expr $i + 1` + delfiles="$delfiles $output_objdir/$output_la-${i}.$objext" + done + + $echo "creating a temporary reloadable object file: $output" + + # Loop through the commands generated above and execute them. + save_ifs="$IFS"; IFS='~' + for cmd in $concat_cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + + libobjs=$output + # Restore the value of output. + output=$save_output + + if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then + eval libobjs=\"\$libobjs $whole_archive_flag_spec\" + fi + # Expand the library linking commands again to reset the + # value of $libobjs for piecewise linking. + + # Do each of the archive commands. + if test "$module" = yes && test -n "$module_cmds" ; then + if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then + cmds=$module_expsym_cmds + else + cmds=$module_cmds + fi + else + if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then + cmds=$archive_expsym_cmds + else + cmds=$archive_cmds + fi + fi + + # Append the command to remove the reloadable object files + # to the just-reset $cmds. + eval cmds=\"\$cmds~\$rm $delfiles\" + fi + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || { + lt_exit=$? + + # Restore the uninstalled library and exit + if test "$mode" = relink; then + $run eval '(cd $output_objdir && $rm ${realname}T && $mv ${realname}U $realname)' + fi + + exit $lt_exit + } + done + IFS="$save_ifs" + + # Restore the uninstalled library and exit + if test "$mode" = relink; then + $run eval '(cd $output_objdir && $rm ${realname}T && $mv $realname ${realname}T && $mv "$realname"U $realname)' || exit $? + + if test -n "$convenience"; then + if test -z "$whole_archive_flag_spec"; then + $show "${rm}r $gentop" + $run ${rm}r "$gentop" + fi + fi + + exit $EXIT_SUCCESS + fi + + # Create links to the real library. + for linkname in $linknames; do + if test "$realname" != "$linkname"; then + $show "(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)" + $run eval '(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)' || exit $? + fi + done + + # If -module or -export-dynamic was specified, set the dlname. + if test "$module" = yes || test "$export_dynamic" = yes; then + # On all known operating systems, these are identical. + dlname="$soname" + fi + fi + ;; + + obj) + if test -n "$deplibs"; then + $echo "$modename: warning: \`-l' and \`-L' are ignored for objects" 1>&2 + fi + + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + $echo "$modename: warning: \`-dlopen' is ignored for objects" 1>&2 + fi + + if test -n "$rpath"; then + $echo "$modename: warning: \`-rpath' is ignored for objects" 1>&2 + fi + + if test -n "$xrpath"; then + $echo "$modename: warning: \`-R' is ignored for objects" 1>&2 + fi + + if test -n "$vinfo"; then + $echo "$modename: warning: \`-version-info' is ignored for objects" 1>&2 + fi + + if test -n "$release"; then + $echo "$modename: warning: \`-release' is ignored for objects" 1>&2 + fi + + case $output in + *.lo) + if test -n "$objs$old_deplibs"; then + $echo "$modename: cannot build library object \`$output' from non-libtool objects" 1>&2 + exit $EXIT_FAILURE + fi + libobj="$output" + obj=`$echo "X$output" | $Xsed -e "$lo2o"` + ;; + *) + libobj= + obj="$output" + ;; + esac + + # Delete the old objects. + $run $rm $obj $libobj + + # Objects from convenience libraries. This assumes + # single-version convenience libraries. Whenever we create + # different ones for PIC/non-PIC, this we'll have to duplicate + # the extraction. + reload_conv_objs= + gentop= + # reload_cmds runs $LD directly, so let us get rid of + # -Wl from whole_archive_flag_spec + wl= + + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec"; then + eval reload_conv_objs=\"\$reload_objs $whole_archive_flag_spec\" + else + gentop="$output_objdir/${obj}x" + generated="$generated $gentop" + + func_extract_archives $gentop $convenience + reload_conv_objs="$reload_objs $func_extract_archives_result" + fi + fi + + # Create the old-style object. + reload_objs="$objs$old_deplibs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}$'/d' -e '/\.lib$/d' -e "$lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test + + output="$obj" + cmds=$reload_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + + # Exit if we aren't doing a library object file. + if test -z "$libobj"; then + if test -n "$gentop"; then + $show "${rm}r $gentop" + $run ${rm}r $gentop + fi + + exit $EXIT_SUCCESS + fi + + if test "$build_libtool_libs" != yes; then + if test -n "$gentop"; then + $show "${rm}r $gentop" + $run ${rm}r $gentop + fi + + # Create an invalid libtool object if no PIC, so that we don't + # accidentally link it into a program. + # $show "echo timestamp > $libobj" + # $run eval "echo timestamp > $libobj" || exit $? + exit $EXIT_SUCCESS + fi + + if test -n "$pic_flag" || test "$pic_mode" != default; then + # Only do commands if we really have different PIC objects. + reload_objs="$libobjs $reload_conv_objs" + output="$libobj" + cmds=$reload_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + fi + + if test -n "$gentop"; then + $show "${rm}r $gentop" + $run ${rm}r $gentop + fi + + exit $EXIT_SUCCESS + ;; + + prog) + case $host in + *cygwin*) output=`$echo $output | ${SED} -e 's,.exe$,,;s,$,.exe,'` ;; + esac + if test -n "$vinfo"; then + $echo "$modename: warning: \`-version-info' is ignored for programs" 1>&2 + fi + + if test -n "$release"; then + $echo "$modename: warning: \`-release' is ignored for programs" 1>&2 + fi + + if test "$preload" = yes; then + if test "$dlopen_support" = unknown && test "$dlopen_self" = unknown && + test "$dlopen_self_static" = unknown; then + $echo "$modename: warning: \`AC_LIBTOOL_DLOPEN' not used. Assuming no dlopen support." + fi + fi + + case $host in + *-*-rhapsody* | *-*-darwin1.[012]) + # On Rhapsody replace the C library is the System framework + compile_deplibs=`$echo "X $compile_deplibs" | $Xsed -e 's/ -lc / -framework System /'` + finalize_deplibs=`$echo "X $finalize_deplibs" | $Xsed -e 's/ -lc / -framework System /'` + ;; + esac + + case $host in + *darwin*) + # Don't allow lazy linking, it breaks C++ global constructors + if test "$tagname" = CXX ; then + compile_command="$compile_command ${wl}-bind_at_load" + finalize_command="$finalize_command ${wl}-bind_at_load" + fi + ;; + esac + + + # move library search paths that coincide with paths to not yet + # installed libraries to the beginning of the library search list + new_libs= + for path in $notinst_path; do + case " $new_libs " in + *" -L$path/$objdir "*) ;; + *) + case " $compile_deplibs " in + *" -L$path/$objdir "*) + new_libs="$new_libs -L$path/$objdir" ;; + esac + ;; + esac + done + for deplib in $compile_deplibs; do + case $deplib in + -L*) + case " $new_libs " in + *" $deplib "*) ;; + *) new_libs="$new_libs $deplib" ;; + esac + ;; + *) new_libs="$new_libs $deplib" ;; + esac + done + compile_deplibs="$new_libs" + + + compile_command="$compile_command $compile_deplibs" + finalize_command="$finalize_command $finalize_deplibs" + + if test -n "$rpath$xrpath"; then + # If the user specified any rpath flags, then add them. + for libdir in $rpath $xrpath; do + # This is the magic to use -rpath. + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" ;; + esac + done + fi + + # Now hardcode the library paths + rpath= + hardcode_libdirs= + for libdir in $compile_rpath $finalize_rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + rpath="$rpath $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) perm_rpath="$perm_rpath $libdir" ;; + esac + fi + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*) + testbindir=`$echo "X$libdir" | $Xsed -e 's*/lib$*/bin*'` + case :$dllsearchpath: in + *":$libdir:"*) ;; + *) dllsearchpath="$dllsearchpath:$libdir";; + esac + case :$dllsearchpath: in + *":$testbindir:"*) ;; + *) dllsearchpath="$dllsearchpath:$testbindir";; + esac + ;; + esac + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + eval rpath=\" $hardcode_libdir_flag_spec\" + fi + compile_rpath="$rpath" + + rpath= + hardcode_libdirs= + for libdir in $finalize_rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + rpath="$rpath $flag" + fi + elif test -n "$runpath_var"; then + case "$finalize_perm_rpath " in + *" $libdir "*) ;; + *) finalize_perm_rpath="$finalize_perm_rpath $libdir" ;; + esac + fi + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + eval rpath=\" $hardcode_libdir_flag_spec\" + fi + finalize_rpath="$rpath" + + if test -n "$libobjs" && test "$build_old_libs" = yes; then + # Transform all the library objects into standard objects. + compile_command=`$echo "X$compile_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + finalize_command=`$echo "X$finalize_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + fi + + dlsyms= + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + if test -n "$NM" && test -n "$global_symbol_pipe"; then + dlsyms="${outputname}S.c" + else + $echo "$modename: not configured to extract global symbols from dlpreopened files" 1>&2 + fi + fi + + if test -n "$dlsyms"; then + case $dlsyms in + "") ;; + *.c) + # Discover the nlist of each of the dlfiles. + nlist="$output_objdir/${outputname}.nm" + + $show "$rm $nlist ${nlist}S ${nlist}T" + $run $rm "$nlist" "${nlist}S" "${nlist}T" + + # Parse the name list into a source file. + $show "creating $output_objdir/$dlsyms" + + test -z "$run" && $echo > "$output_objdir/$dlsyms" "\ +/* $dlsyms - symbol resolution table for \`$outputname' dlsym emulation. */ +/* Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP */ + +#ifdef __cplusplus +extern \"C\" { +#endif + +/* Prevent the only kind of declaration conflicts we can make. */ +#define lt_preloaded_symbols some_other_symbol + +/* External symbol declarations for the compiler. */\ +" + + if test "$dlself" = yes; then + $show "generating symbol list for \`$output'" + + test -z "$run" && $echo ': @PROGRAM@ ' > "$nlist" + + # Add our own program objects to the symbol list. + progfiles=`$echo "X$objs$old_deplibs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + for arg in $progfiles; do + $show "extracting global C symbols from \`$arg'" + $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'" + done + + if test -n "$exclude_expsyms"; then + $run eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T' + $run eval '$mv "$nlist"T "$nlist"' + fi + + if test -n "$export_symbols_regex"; then + $run eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T' + $run eval '$mv "$nlist"T "$nlist"' + fi + + # Prepare the list of exported symbols + if test -z "$export_symbols"; then + export_symbols="$output_objdir/$outputname.exp" + $run $rm $export_symbols + $run eval "${SED} -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"' + case $host in + *cygwin* | *mingw* ) + $run eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' + $run eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"' + ;; + esac + else + $run eval "${SED} -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"' + $run eval 'grep -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T' + $run eval 'mv "$nlist"T "$nlist"' + case $host in + *cygwin* | *mingw* ) + $run eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' + $run eval 'cat "$nlist" >> "$output_objdir/$outputname.def"' + ;; + esac + fi + fi + + for arg in $dlprefiles; do + $show "extracting global C symbols from \`$arg'" + name=`$echo "$arg" | ${SED} -e 's%^.*/%%'` + $run eval '$echo ": $name " >> "$nlist"' + $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'" + done + + if test -z "$run"; then + # Make sure we have at least an empty file. + test -f "$nlist" || : > "$nlist" + + if test -n "$exclude_expsyms"; then + $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T + $mv "$nlist"T "$nlist" + fi + + # Try sorting and uniquifying the output. + if grep -v "^: " < "$nlist" | + if sort -k 3 </dev/null >/dev/null 2>&1; then + sort -k 3 + else + sort +2 + fi | + uniq > "$nlist"S; then + : + else + grep -v "^: " < "$nlist" > "$nlist"S + fi + + if test -f "$nlist"S; then + eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$dlsyms"' + else + $echo '/* NONE */' >> "$output_objdir/$dlsyms" + fi + + $echo >> "$output_objdir/$dlsyms" "\ + +#undef lt_preloaded_symbols + +#if defined (__STDC__) && __STDC__ +# define lt_ptr void * +#else +# define lt_ptr char * +# define const +#endif + +/* The mapping between symbol names and symbols. */ +" + + case $host in + *cygwin* | *mingw* ) + $echo >> "$output_objdir/$dlsyms" "\ +/* DATA imports from DLLs on WIN32 can't be const, because + runtime relocations are performed -- see ld's documentation + on pseudo-relocs */ +struct { +" + ;; + * ) + $echo >> "$output_objdir/$dlsyms" "\ +const struct { +" + ;; + esac + + + $echo >> "$output_objdir/$dlsyms" "\ + const char *name; + lt_ptr address; +} +lt_preloaded_symbols[] = +{\ +" + + eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$dlsyms" + + $echo >> "$output_objdir/$dlsyms" "\ + {0, (lt_ptr) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif\ +" + fi + + pic_flag_for_symtable= + case $host in + # compiling the symbol table file with pic_flag works around + # a FreeBSD bug that causes programs to crash when -lm is + # linked before any other PIC object. But we must not use + # pic_flag when linking with -static. The problem exists in + # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1. + *-*-freebsd2*|*-*-freebsd3.0*|*-*-freebsdelf3.0*) + case "$compile_command " in + *" -static "*) ;; + *) pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND";; + esac;; + *-*-hpux*) + case "$compile_command " in + *" -static "*) ;; + *) pic_flag_for_symtable=" $pic_flag";; + esac + esac + + # Now compile the dynamic symbol file. + $show "(cd $output_objdir && $LTCC $LTCFLAGS -c$no_builtin_flag$pic_flag_for_symtable \"$dlsyms\")" + $run eval '(cd $output_objdir && $LTCC $LTCFLAGS -c$no_builtin_flag$pic_flag_for_symtable "$dlsyms")' || exit $? + + # Clean up the generated files. + $show "$rm $output_objdir/$dlsyms $nlist ${nlist}S ${nlist}T" + $run $rm "$output_objdir/$dlsyms" "$nlist" "${nlist}S" "${nlist}T" + + # Transform the symbol file into the correct name. + case $host in + *cygwin* | *mingw* ) + if test -f "$output_objdir/${outputname}.def" ; then + compile_command=`$echo "X$compile_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}.def $output_objdir/${outputname}S.${objext}%"` + finalize_command=`$echo "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}.def $output_objdir/${outputname}S.${objext}%"` + else + compile_command=`$echo "X$compile_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"` + finalize_command=`$echo "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"` + fi + ;; + * ) + compile_command=`$echo "X$compile_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"` + finalize_command=`$echo "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"` + ;; + esac + ;; + *) + $echo "$modename: unknown suffix for \`$dlsyms'" 1>&2 + exit $EXIT_FAILURE + ;; + esac + else + # We keep going just in case the user didn't refer to + # lt_preloaded_symbols. The linker will fail if global_symbol_pipe + # really was required. + + # Nullify the symbol file. + compile_command=`$echo "X$compile_command" | $Xsed -e "s% @SYMFILE@%%"` + finalize_command=`$echo "X$finalize_command" | $Xsed -e "s% @SYMFILE@%%"` + fi + + if test "$need_relink" = no || test "$build_libtool_libs" != yes; then + # Replace the output file specification. + compile_command=`$echo "X$compile_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'` + link_command="$compile_command$compile_rpath" + + # We have no uninstalled library dependencies, so finalize right now. + $show "$link_command" + $run eval "$link_command" + exit_status=$? + + # Delete the generated files. + if test -n "$dlsyms"; then + $show "$rm $output_objdir/${outputname}S.${objext}" + $run $rm "$output_objdir/${outputname}S.${objext}" + fi + + exit $exit_status + fi + + if test -n "$shlibpath_var"; then + # We should set the shlibpath_var + rpath= + for dir in $temp_rpath; do + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) + # Absolute path. + rpath="$rpath$dir:" + ;; + *) + # Relative path: add a thisdir entry. + rpath="$rpath\$thisdir/$dir:" + ;; + esac + done + temp_rpath="$rpath" + fi + + if test -n "$compile_shlibpath$finalize_shlibpath"; then + compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command" + fi + if test -n "$finalize_shlibpath"; then + finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command" + fi + + compile_var= + finalize_var= + if test -n "$runpath_var"; then + if test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + rpath="$rpath$dir:" + done + compile_var="$runpath_var=\"$rpath\$$runpath_var\" " + fi + if test -n "$finalize_perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $finalize_perm_rpath; do + rpath="$rpath$dir:" + done + finalize_var="$runpath_var=\"$rpath\$$runpath_var\" " + fi + fi + + if test "$no_install" = yes; then + # We don't need to create a wrapper script. + link_command="$compile_var$compile_command$compile_rpath" + # Replace the output file specification. + link_command=`$echo "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'` + # Delete the old output file. + $run $rm $output + # Link the executable and exit + $show "$link_command" + $run eval "$link_command" || exit $? + exit $EXIT_SUCCESS + fi + + if test "$hardcode_action" = relink; then + # Fast installation is not supported + link_command="$compile_var$compile_command$compile_rpath" + relink_command="$finalize_var$finalize_command$finalize_rpath" + + $echo "$modename: warning: this platform does not like uninstalled shared libraries" 1>&2 + $echo "$modename: \`$output' will be relinked during installation" 1>&2 + else + if test "$fast_install" != no; then + link_command="$finalize_var$compile_command$finalize_rpath" + if test "$fast_install" = yes; then + relink_command=`$echo "X$compile_var$compile_command$compile_rpath" | $Xsed -e 's%@OUTPUT@%\$progdir/\$file%g'` + else + # fast_install is set to needless + relink_command= + fi + else + link_command="$compile_var$compile_command$compile_rpath" + relink_command="$finalize_var$finalize_command$finalize_rpath" + fi + fi + + # Replace the output file specification. + link_command=`$echo "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'` + + # Delete the old output files. + $run $rm $output $output_objdir/$outputname $output_objdir/lt-$outputname + + $show "$link_command" + $run eval "$link_command" || exit $? + + # Now create the wrapper script. + $show "creating $output" + + # Quote the relink command for shipping. + if test -n "$relink_command"; then + # Preserve any variables that may affect compiler behavior + for var in $variables_saved_for_relink; do + if eval test -z \"\${$var+set}\"; then + relink_command="{ test -z \"\${$var+set}\" || unset $var || { $var=; export $var; }; }; $relink_command" + elif eval var_value=\$$var; test -z "$var_value"; then + relink_command="$var=; export $var; $relink_command" + else + var_value=`$echo "X$var_value" | $Xsed -e "$sed_quote_subst"` + relink_command="$var=\"$var_value\"; export $var; $relink_command" + fi + done + relink_command="(cd `pwd`; $relink_command)" + relink_command=`$echo "X$relink_command" | $Xsed -e "$sed_quote_subst"` + fi + + # Quote $echo for shipping. + if test "X$echo" = "X$SHELL $progpath --fallback-echo"; then + case $progpath in + [\\/]* | [A-Za-z]:[\\/]*) qecho="$SHELL $progpath --fallback-echo";; + *) qecho="$SHELL `pwd`/$progpath --fallback-echo";; + esac + qecho=`$echo "X$qecho" | $Xsed -e "$sed_quote_subst"` + else + qecho=`$echo "X$echo" | $Xsed -e "$sed_quote_subst"` + fi + + # Only actually do things if our run command is non-null. + if test -z "$run"; then + # win32 will think the script is a binary if it has + # a .exe suffix, so we strip it off here. + case $output in + *.exe) output=`$echo $output|${SED} 's,.exe$,,'` ;; + esac + # test for cygwin because mv fails w/o .exe extensions + case $host in + *cygwin*) + exeext=.exe + outputname=`$echo $outputname|${SED} 's,.exe$,,'` ;; + *) exeext= ;; + esac + case $host in + *cygwin* | *mingw* ) + output_name=`basename $output` + output_path=`dirname $output` + cwrappersource="$output_path/$objdir/lt-$output_name.c" + cwrapper="$output_path/$output_name.exe" + $rm $cwrappersource $cwrapper + trap "$rm $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15 + + cat > $cwrappersource <<EOF + +/* $cwrappersource - temporary wrapper executable for $objdir/$outputname + Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP + + The $output program cannot be directly executed until all the libtool + libraries that it depends on are installed. + + This wrapper executable should never be moved out of the build directory. + If it is, it will not operate correctly. + + Currently, it simply execs the wrapper *script* "/bin/sh $output", + but could eventually absorb all of the scripts functionality and + exec $objdir/$outputname directly. +*/ +EOF + cat >> $cwrappersource<<"EOF" +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <malloc.h> +#include <stdarg.h> +#include <assert.h> +#include <string.h> +#include <ctype.h> +#include <sys/stat.h> + +#if defined(PATH_MAX) +# define LT_PATHMAX PATH_MAX +#elif defined(MAXPATHLEN) +# define LT_PATHMAX MAXPATHLEN +#else +# define LT_PATHMAX 1024 +#endif + +#ifndef DIR_SEPARATOR +# define DIR_SEPARATOR '/' +# define PATH_SEPARATOR ':' +#endif + +#if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \ + defined (__OS2__) +# define HAVE_DOS_BASED_FILE_SYSTEM +# ifndef DIR_SEPARATOR_2 +# define DIR_SEPARATOR_2 '\\' +# endif +# ifndef PATH_SEPARATOR_2 +# define PATH_SEPARATOR_2 ';' +# endif +#endif + +#ifndef DIR_SEPARATOR_2 +# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) +#else /* DIR_SEPARATOR_2 */ +# define IS_DIR_SEPARATOR(ch) \ + (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2)) +#endif /* DIR_SEPARATOR_2 */ + +#ifndef PATH_SEPARATOR_2 +# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR) +#else /* PATH_SEPARATOR_2 */ +# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2) +#endif /* PATH_SEPARATOR_2 */ + +#define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type))) +#define XFREE(stale) do { \ + if (stale) { free ((void *) stale); stale = 0; } \ +} while (0) + +/* -DDEBUG is fairly common in CFLAGS. */ +#undef DEBUG +#if defined DEBUGWRAPPER +# define DEBUG(format, ...) fprintf(stderr, format, __VA_ARGS__) +#else +# define DEBUG(format, ...) +#endif + +const char *program_name = NULL; + +void * xmalloc (size_t num); +char * xstrdup (const char *string); +const char * base_name (const char *name); +char * find_executable(const char *wrapper); +int check_executable(const char *path); +char * strendzap(char *str, const char *pat); +void lt_fatal (const char *message, ...); + +int +main (int argc, char *argv[]) +{ + char **newargz; + int i; + + program_name = (char *) xstrdup (base_name (argv[0])); + DEBUG("(main) argv[0] : %s\n",argv[0]); + DEBUG("(main) program_name : %s\n",program_name); + newargz = XMALLOC(char *, argc+2); +EOF + + cat >> $cwrappersource <<EOF + newargz[0] = (char *) xstrdup("$SHELL"); +EOF + + cat >> $cwrappersource <<"EOF" + newargz[1] = find_executable(argv[0]); + if (newargz[1] == NULL) + lt_fatal("Couldn't find %s", argv[0]); + DEBUG("(main) found exe at : %s\n",newargz[1]); + /* we know the script has the same name, without the .exe */ + /* so make sure newargz[1] doesn't end in .exe */ + strendzap(newargz[1],".exe"); + for (i = 1; i < argc; i++) + newargz[i+1] = xstrdup(argv[i]); + newargz[argc+1] = NULL; + + for (i=0; i<argc+1; i++) + { + DEBUG("(main) newargz[%d] : %s\n",i,newargz[i]); + ; + } + +EOF + + case $host_os in + mingw*) + cat >> $cwrappersource <<EOF + execv("$SHELL",(char const **)newargz); +EOF + ;; + *) + cat >> $cwrappersource <<EOF + execv("$SHELL",newargz); +EOF + ;; + esac + + cat >> $cwrappersource <<"EOF" + return 127; +} + +void * +xmalloc (size_t num) +{ + void * p = (void *) malloc (num); + if (!p) + lt_fatal ("Memory exhausted"); + + return p; +} + +char * +xstrdup (const char *string) +{ + return string ? strcpy ((char *) xmalloc (strlen (string) + 1), string) : NULL +; +} + +const char * +base_name (const char *name) +{ + const char *base; + +#if defined (HAVE_DOS_BASED_FILE_SYSTEM) + /* Skip over the disk name in MSDOS pathnames. */ + if (isalpha ((unsigned char)name[0]) && name[1] == ':') + name += 2; +#endif + + for (base = name; *name; name++) + if (IS_DIR_SEPARATOR (*name)) + base = name + 1; + return base; +} + +int +check_executable(const char * path) +{ + struct stat st; + + DEBUG("(check_executable) : %s\n", path ? (*path ? path : "EMPTY!") : "NULL!"); + if ((!path) || (!*path)) + return 0; + + if ((stat (path, &st) >= 0) && + ( + /* MinGW & native WIN32 do not support S_IXOTH or S_IXGRP */ +#if defined (S_IXOTH) + ((st.st_mode & S_IXOTH) == S_IXOTH) || +#endif +#if defined (S_IXGRP) + ((st.st_mode & S_IXGRP) == S_IXGRP) || +#endif + ((st.st_mode & S_IXUSR) == S_IXUSR)) + ) + return 1; + else + return 0; +} + +/* Searches for the full path of the wrapper. Returns + newly allocated full path name if found, NULL otherwise */ +char * +find_executable (const char* wrapper) +{ + int has_slash = 0; + const char* p; + const char* p_next; + /* static buffer for getcwd */ + char tmp[LT_PATHMAX + 1]; + int tmp_len; + char* concat_name; + + DEBUG("(find_executable) : %s\n", wrapper ? (*wrapper ? wrapper : "EMPTY!") : "NULL!"); + + if ((wrapper == NULL) || (*wrapper == '\0')) + return NULL; + + /* Absolute path? */ +#if defined (HAVE_DOS_BASED_FILE_SYSTEM) + if (isalpha ((unsigned char)wrapper[0]) && wrapper[1] == ':') + { + concat_name = xstrdup (wrapper); + if (check_executable(concat_name)) + return concat_name; + XFREE(concat_name); + } + else + { +#endif + if (IS_DIR_SEPARATOR (wrapper[0])) + { + concat_name = xstrdup (wrapper); + if (check_executable(concat_name)) + return concat_name; + XFREE(concat_name); + } +#if defined (HAVE_DOS_BASED_FILE_SYSTEM) + } +#endif + + for (p = wrapper; *p; p++) + if (*p == '/') + { + has_slash = 1; + break; + } + if (!has_slash) + { + /* no slashes; search PATH */ + const char* path = getenv ("PATH"); + if (path != NULL) + { + for (p = path; *p; p = p_next) + { + const char* q; + size_t p_len; + for (q = p; *q; q++) + if (IS_PATH_SEPARATOR(*q)) + break; + p_len = q - p; + p_next = (*q == '\0' ? q : q + 1); + if (p_len == 0) + { + /* empty path: current directory */ + if (getcwd (tmp, LT_PATHMAX) == NULL) + lt_fatal ("getcwd failed"); + tmp_len = strlen(tmp); + concat_name = XMALLOC(char, tmp_len + 1 + strlen(wrapper) + 1); + memcpy (concat_name, tmp, tmp_len); + concat_name[tmp_len] = '/'; + strcpy (concat_name + tmp_len + 1, wrapper); + } + else + { + concat_name = XMALLOC(char, p_len + 1 + strlen(wrapper) + 1); + memcpy (concat_name, p, p_len); + concat_name[p_len] = '/'; + strcpy (concat_name + p_len + 1, wrapper); + } + if (check_executable(concat_name)) + return concat_name; + XFREE(concat_name); + } + } + /* not found in PATH; assume curdir */ + } + /* Relative path | not found in path: prepend cwd */ + if (getcwd (tmp, LT_PATHMAX) == NULL) + lt_fatal ("getcwd failed"); + tmp_len = strlen(tmp); + concat_name = XMALLOC(char, tmp_len + 1 + strlen(wrapper) + 1); + memcpy (concat_name, tmp, tmp_len); + concat_name[tmp_len] = '/'; + strcpy (concat_name + tmp_len + 1, wrapper); + + if (check_executable(concat_name)) + return concat_name; + XFREE(concat_name); + return NULL; +} + +char * +strendzap(char *str, const char *pat) +{ + size_t len, patlen; + + assert(str != NULL); + assert(pat != NULL); + + len = strlen(str); + patlen = strlen(pat); + + if (patlen <= len) + { + str += len - patlen; + if (strcmp(str, pat) == 0) + *str = '\0'; + } + return str; +} + +static void +lt_error_core (int exit_status, const char * mode, + const char * message, va_list ap) +{ + fprintf (stderr, "%s: %s: ", program_name, mode); + vfprintf (stderr, message, ap); + fprintf (stderr, ".\n"); + + if (exit_status >= 0) + exit (exit_status); +} + +void +lt_fatal (const char *message, ...) +{ + va_list ap; + va_start (ap, message); + lt_error_core (EXIT_FAILURE, "FATAL", message, ap); + va_end (ap); +} +EOF + # we should really use a build-platform specific compiler + # here, but OTOH, the wrappers (shell script and this C one) + # are only useful if you want to execute the "real" binary. + # Since the "real" binary is built for $host, then this + # wrapper might as well be built for $host, too. + $run $LTCC $LTCFLAGS -s -o $cwrapper $cwrappersource + ;; + esac + $rm $output + trap "$rm $output; exit $EXIT_FAILURE" 1 2 15 + + $echo > $output "\ +#! $SHELL + +# $output - temporary wrapper script for $objdir/$outputname +# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP +# +# The $output program cannot be directly executed until all the libtool +# libraries that it depends on are installed. +# +# This wrapper script should never be moved out of the build directory. +# If it is, it will not operate correctly. + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +Xsed='${SED} -e 1s/^X//' +sed_quote_subst='$sed_quote_subst' + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +relink_command=\"$relink_command\" + +# This environment variable determines our operation mode. +if test \"\$libtool_install_magic\" = \"$magic\"; then + # install mode needs the following variable: + notinst_deplibs='$notinst_deplibs' +else + # When we are sourced in execute mode, \$file and \$echo are already set. + if test \"\$libtool_execute_magic\" != \"$magic\"; then + echo=\"$qecho\" + file=\"\$0\" + # Make sure echo works. + if test \"X\$1\" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift + elif test \"X\`(\$echo '\t') 2>/dev/null\`\" = 'X\t'; then + # Yippee, \$echo works! + : + else + # Restart under the correct shell, and then maybe \$echo will work. + exec $SHELL \"\$0\" --no-reexec \${1+\"\$@\"} + fi + fi\ +" + $echo >> $output "\ + + # Find the directory that this script lives in. + thisdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*$%%'\` + test \"x\$thisdir\" = \"x\$file\" && thisdir=. + + # Follow symbolic links until we get to the real thisdir. + file=\`ls -ld \"\$file\" | ${SED} -n 's/.*-> //p'\` + while test -n \"\$file\"; do + destdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*\$%%'\` + + # If there was a directory component, then change thisdir. + if test \"x\$destdir\" != \"x\$file\"; then + case \"\$destdir\" in + [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;; + *) thisdir=\"\$thisdir/\$destdir\" ;; + esac + fi + + file=\`\$echo \"X\$file\" | \$Xsed -e 's%^.*/%%'\` + file=\`ls -ld \"\$thisdir/\$file\" | ${SED} -n 's/.*-> //p'\` + done + + # Try to get the absolute directory name. + absdir=\`cd \"\$thisdir\" && pwd\` + test -n \"\$absdir\" && thisdir=\"\$absdir\" +" + + if test "$fast_install" = yes; then + $echo >> $output "\ + program=lt-'$outputname'$exeext + progdir=\"\$thisdir/$objdir\" + + if test ! -f \"\$progdir/\$program\" || \\ + { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\ + test \"X\$file\" != \"X\$progdir/\$program\"; }; then + + file=\"\$\$-\$program\" + + if test ! -d \"\$progdir\"; then + $mkdir \"\$progdir\" + else + $rm \"\$progdir/\$file\" + fi" + + $echo >> $output "\ + + # relink executable if necessary + if test -n \"\$relink_command\"; then + if relink_command_output=\`eval \$relink_command 2>&1\`; then : + else + $echo \"\$relink_command_output\" >&2 + $rm \"\$progdir/\$file\" + exit $EXIT_FAILURE + fi + fi + + $mv \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null || + { $rm \"\$progdir/\$program\"; + $mv \"\$progdir/\$file\" \"\$progdir/\$program\"; } + $rm \"\$progdir/\$file\" + fi" + else + $echo >> $output "\ + program='$outputname' + progdir=\"\$thisdir/$objdir\" +" + fi + + $echo >> $output "\ + + if test -f \"\$progdir/\$program\"; then" + + # Export our shlibpath_var if we have one. + if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then + $echo >> $output "\ + # Add our own library path to $shlibpath_var + $shlibpath_var=\"$temp_rpath\$$shlibpath_var\" + + # Some systems cannot cope with colon-terminated $shlibpath_var + # The second colon is a workaround for a bug in BeOS R4 sed + $shlibpath_var=\`\$echo \"X\$$shlibpath_var\" | \$Xsed -e 's/::*\$//'\` + + export $shlibpath_var +" + fi + + # fixup the dll searchpath if we need to. + if test -n "$dllsearchpath"; then + $echo >> $output "\ + # Add the dll search path components to the executable PATH + PATH=$dllsearchpath:\$PATH +" + fi + + $echo >> $output "\ + if test \"\$libtool_execute_magic\" != \"$magic\"; then + # Run the actual program with our arguments. +" + case $host in + # Backslashes separate directories on plain windows + *-*-mingw | *-*-os2*) + $echo >> $output "\ + exec \"\$progdir\\\\\$program\" \${1+\"\$@\"} +" + ;; + + *) + $echo >> $output "\ + exec \"\$progdir/\$program\" \${1+\"\$@\"} +" + ;; + esac + $echo >> $output "\ + \$echo \"\$0: cannot exec \$program \${1+\"\$@\"}\" + exit $EXIT_FAILURE + fi + else + # The program doesn't exist. + \$echo \"\$0: error: \\\`\$progdir/\$program' does not exist\" 1>&2 + \$echo \"This script is just a wrapper for \$program.\" 1>&2 + $echo \"See the $PACKAGE documentation for more information.\" 1>&2 + exit $EXIT_FAILURE + fi +fi\ +" + chmod +x $output + fi + exit $EXIT_SUCCESS + ;; + esac + + # See if we need to build an old-fashioned archive. + for oldlib in $oldlibs; do + + if test "$build_libtool_libs" = convenience; then + oldobjs="$libobjs_save" + addlibs="$convenience" + build_libtool_libs=no + else + if test "$build_libtool_libs" = module; then + oldobjs="$libobjs_save" + build_libtool_libs=no + else + oldobjs="$old_deplibs $non_pic_objects" + fi + addlibs="$old_convenience" + fi + + if test -n "$addlibs"; then + gentop="$output_objdir/${outputname}x" + generated="$generated $gentop" + + func_extract_archives $gentop $addlibs + oldobjs="$oldobjs $func_extract_archives_result" + fi + + # Do each command in the archive commands. + if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then + cmds=$old_archive_from_new_cmds + else + # POSIX demands no paths to be encoded in archives. We have + # to avoid creating archives with duplicate basenames if we + # might have to extract them afterwards, e.g., when creating a + # static archive out of a convenience library, or when linking + # the entirety of a libtool archive into another (currently + # not supported by libtool). + if (for obj in $oldobjs + do + $echo "X$obj" | $Xsed -e 's%^.*/%%' + done | sort | sort -uc >/dev/null 2>&1); then + : + else + $echo "copying selected object files to avoid basename conflicts..." + + if test -z "$gentop"; then + gentop="$output_objdir/${outputname}x" + generated="$generated $gentop" + + $show "${rm}r $gentop" + $run ${rm}r "$gentop" + $show "$mkdir $gentop" + $run $mkdir "$gentop" + exit_status=$? + if test "$exit_status" -ne 0 && test ! -d "$gentop"; then + exit $exit_status + fi + fi + + save_oldobjs=$oldobjs + oldobjs= + counter=1 + for obj in $save_oldobjs + do + objbase=`$echo "X$obj" | $Xsed -e 's%^.*/%%'` + case " $oldobjs " in + " ") oldobjs=$obj ;; + *[\ /]"$objbase "*) + while :; do + # Make sure we don't pick an alternate name that also + # overlaps. + newobj=lt$counter-$objbase + counter=`expr $counter + 1` + case " $oldobjs " in + *[\ /]"$newobj "*) ;; + *) if test ! -f "$gentop/$newobj"; then break; fi ;; + esac + done + $show "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj" + $run ln "$obj" "$gentop/$newobj" || + $run cp "$obj" "$gentop/$newobj" + oldobjs="$oldobjs $gentop/$newobj" + ;; + *) oldobjs="$oldobjs $obj" ;; + esac + done + fi + + eval cmds=\"$old_archive_cmds\" + + if len=`expr "X$cmds" : ".*"` && + test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then + cmds=$old_archive_cmds + else + # the command line is too long to link in one step, link in parts + $echo "using piecewise archive linking..." + save_RANLIB=$RANLIB + RANLIB=: + objlist= + concat_cmds= + save_oldobjs=$oldobjs + + # Is there a better way of finding the last object in the list? + for obj in $save_oldobjs + do + last_oldobj=$obj + done + for obj in $save_oldobjs + do + oldobjs="$objlist $obj" + objlist="$objlist $obj" + eval test_cmds=\"$old_archive_cmds\" + if len=`expr "X$test_cmds" : ".*" 2>/dev/null` && + test "$len" -le "$max_cmd_len"; then + : + else + # the above command should be used before it gets too long + oldobjs=$objlist + if test "$obj" = "$last_oldobj" ; then + RANLIB=$save_RANLIB + fi + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + eval concat_cmds=\"\${concat_cmds}$old_archive_cmds\" + objlist= + fi + done + RANLIB=$save_RANLIB + oldobjs=$objlist + if test "X$oldobjs" = "X" ; then + eval cmds=\"\$concat_cmds\" + else + eval cmds=\"\$concat_cmds~\$old_archive_cmds\" + fi + fi + fi + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + eval cmd=\"$cmd\" + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + done + + if test -n "$generated"; then + $show "${rm}r$generated" + $run ${rm}r$generated + fi + + # Now create the libtool archive. + case $output in + *.la) + old_library= + test "$build_old_libs" = yes && old_library="$libname.$libext" + $show "creating $output" + + # Preserve any variables that may affect compiler behavior + for var in $variables_saved_for_relink; do + if eval test -z \"\${$var+set}\"; then + relink_command="{ test -z \"\${$var+set}\" || unset $var || { $var=; export $var; }; }; $relink_command" + elif eval var_value=\$$var; test -z "$var_value"; then + relink_command="$var=; export $var; $relink_command" + else + var_value=`$echo "X$var_value" | $Xsed -e "$sed_quote_subst"` + relink_command="$var=\"$var_value\"; export $var; $relink_command" + fi + done + # Quote the link command for shipping. + relink_command="(cd `pwd`; $SHELL $progpath $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)" + relink_command=`$echo "X$relink_command" | $Xsed -e "$sed_quote_subst"` + if test "$hardcode_automatic" = yes ; then + relink_command= + fi + + + # Only create the output if not a dry run. + if test -z "$run"; then + for installed in no yes; do + if test "$installed" = yes; then + if test -z "$install_libdir"; then + break + fi + output="$output_objdir/$outputname"i + # Replace all uninstalled libtool libraries with the installed ones + newdependency_libs= + for deplib in $dependency_libs; do + case $deplib in + *.la) + name=`$echo "X$deplib" | $Xsed -e 's%^.*/%%'` + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` + if test -z "$libdir"; then + $echo "$modename: \`$deplib' is not a valid libtool archive" 1>&2 + exit $EXIT_FAILURE + fi + newdependency_libs="$newdependency_libs $libdir/$name" + ;; + *) newdependency_libs="$newdependency_libs $deplib" ;; + esac + done + dependency_libs="$newdependency_libs" + newdlfiles= + for lib in $dlfiles; do + name=`$echo "X$lib" | $Xsed -e 's%^.*/%%'` + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` + if test -z "$libdir"; then + $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 + exit $EXIT_FAILURE + fi + newdlfiles="$newdlfiles $libdir/$name" + done + dlfiles="$newdlfiles" + newdlprefiles= + for lib in $dlprefiles; do + name=`$echo "X$lib" | $Xsed -e 's%^.*/%%'` + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` + if test -z "$libdir"; then + $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 + exit $EXIT_FAILURE + fi + newdlprefiles="$newdlprefiles $libdir/$name" + done + dlprefiles="$newdlprefiles" + else + newdlfiles= + for lib in $dlfiles; do + case $lib in + [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; + *) abs=`pwd`"/$lib" ;; + esac + newdlfiles="$newdlfiles $abs" + done + dlfiles="$newdlfiles" + newdlprefiles= + for lib in $dlprefiles; do + case $lib in + [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; + *) abs=`pwd`"/$lib" ;; + esac + newdlprefiles="$newdlprefiles $abs" + done + dlprefiles="$newdlprefiles" + fi + $rm $output + # place dlname in correct position for cygwin + tdlname=$dlname + case $host,$output,$installed,$module,$dlname in + *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll) tdlname=../bin/$dlname ;; + esac + $echo > $output "\ +# $outputname - a libtool library file +# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# The name that we can dlopen(3). +dlname='$tdlname' + +# Names of this library. +library_names='$library_names' + +# The name of the static archive. +old_library='$old_library' + +# Libraries that this one depends upon. +dependency_libs='$dependency_libs' + +# Version information for $libname. +current=$current +age=$age +revision=$revision + +# Is this an already installed library? +installed=$installed + +# Should we warn about portability when linking against -modules? +shouldnotlink=$module + +# Files to dlopen/dlpreopen +dlopen='$dlfiles' +dlpreopen='$dlprefiles' + +# Directory that this library needs to be installed in: +libdir='$install_libdir'" + if test "$installed" = no && test "$need_relink" = yes; then + $echo >> $output "\ +relink_command=\"$relink_command\"" + fi + done + fi + + # Do a symbolic link so that the libtool archive can be found in + # LD_LIBRARY_PATH before the program is installed. + $show "(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)" + $run eval '(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)' || exit $? + ;; + esac + exit $EXIT_SUCCESS + ;; + + # libtool install mode + install) + modename="$modename: install" + + # There may be an optional sh(1) argument at the beginning of + # install_prog (especially on Windows NT). + if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh || + # Allow the use of GNU shtool's install command. + $echo "X$nonopt" | grep shtool > /dev/null; then + # Aesthetically quote it. + arg=`$echo "X$nonopt" | $Xsed -e "$sed_quote_subst"` + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + install_prog="$arg " + arg="$1" + shift + else + install_prog= + arg=$nonopt + fi + + # The real first argument should be the name of the installation program. + # Aesthetically quote it. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + install_prog="$install_prog$arg" + + # We need to accept at least all the BSD install flags. + dest= + files= + opts= + prev= + install_type= + isdir=no + stripme= + for arg + do + if test -n "$dest"; then + files="$files $dest" + dest=$arg + continue + fi + + case $arg in + -d) isdir=yes ;; + -f) + case " $install_prog " in + *[\\\ /]cp\ *) ;; + *) prev=$arg ;; + esac + ;; + -g | -m | -o) prev=$arg ;; + -s) + stripme=" -s" + continue + ;; + -*) + ;; + *) + # If the previous option needed an argument, then skip it. + if test -n "$prev"; then + prev= + else + dest=$arg + continue + fi + ;; + esac + + # Aesthetically quote the argument. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + install_prog="$install_prog $arg" + done + + if test -z "$install_prog"; then + $echo "$modename: you must specify an install program" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + if test -n "$prev"; then + $echo "$modename: the \`$prev' option requires an argument" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + if test -z "$files"; then + if test -z "$dest"; then + $echo "$modename: no file or destination specified" 1>&2 + else + $echo "$modename: you must specify a destination" 1>&2 + fi + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + # Strip any trailing slash from the destination. + dest=`$echo "X$dest" | $Xsed -e 's%/$%%'` + + # Check to see that the destination is a directory. + test -d "$dest" && isdir=yes + if test "$isdir" = yes; then + destdir="$dest" + destname= + else + destdir=`$echo "X$dest" | $Xsed -e 's%/[^/]*$%%'` + test "X$destdir" = "X$dest" && destdir=. + destname=`$echo "X$dest" | $Xsed -e 's%^.*/%%'` + + # Not a directory, so check to see that there is only one file specified. + set dummy $files + if test "$#" -gt 2; then + $echo "$modename: \`$dest' is not a directory" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + fi + case $destdir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + for file in $files; do + case $file in + *.lo) ;; + *) + $echo "$modename: \`$destdir' must be an absolute directory name" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + ;; + esac + done + ;; + esac + + # This variable tells wrapper scripts just to set variables rather + # than running their programs. + libtool_install_magic="$magic" + + staticlibs= + future_libdirs= + current_libdirs= + for file in $files; do + + # Do each installation. + case $file in + *.$libext) + # Do the static libraries later. + staticlibs="$staticlibs $file" + ;; + + *.la) + # Check to see that this really is a libtool archive. + if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : + else + $echo "$modename: \`$file' is not a valid libtool archive" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + library_names= + old_library= + relink_command= + # If there is no directory component, then add one. + case $file in + */* | *\\*) . $file ;; + *) . ./$file ;; + esac + + # Add the libdir to current_libdirs if it is the destination. + if test "X$destdir" = "X$libdir"; then + case "$current_libdirs " in + *" $libdir "*) ;; + *) current_libdirs="$current_libdirs $libdir" ;; + esac + else + # Note the libdir as a future libdir. + case "$future_libdirs " in + *" $libdir "*) ;; + *) future_libdirs="$future_libdirs $libdir" ;; + esac + fi + + dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`/ + test "X$dir" = "X$file/" && dir= + dir="$dir$objdir" + + if test -n "$relink_command"; then + # Determine the prefix the user has applied to our future dir. + inst_prefix_dir=`$echo "$destdir" | $SED "s%$libdir\$%%"` + + # Don't allow the user to place us outside of our expected + # location b/c this prevents finding dependent libraries that + # are installed to the same prefix. + # At present, this check doesn't affect windows .dll's that + # are installed into $libdir/../bin (currently, that works fine) + # but it's something to keep an eye on. + if test "$inst_prefix_dir" = "$destdir"; then + $echo "$modename: error: cannot install \`$file' to a directory not ending in $libdir" 1>&2 + exit $EXIT_FAILURE + fi + + if test -n "$inst_prefix_dir"; then + # Stick the inst_prefix_dir data into the link command. + relink_command=`$echo "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"` + else + relink_command=`$echo "$relink_command" | $SED "s%@inst_prefix_dir@%%"` + fi + + $echo "$modename: warning: relinking \`$file'" 1>&2 + $show "$relink_command" + if $run eval "$relink_command"; then : + else + $echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2 + exit $EXIT_FAILURE + fi + fi + + # See the names of the shared library. + set dummy $library_names + if test -n "$2"; then + realname="$2" + shift + shift + + srcname="$realname" + test -n "$relink_command" && srcname="$realname"T + + # Install the shared library and build the symlinks. + $show "$install_prog $dir/$srcname $destdir/$realname" + $run eval "$install_prog $dir/$srcname $destdir/$realname" || exit $? + if test -n "$stripme" && test -n "$striplib"; then + $show "$striplib $destdir/$realname" + $run eval "$striplib $destdir/$realname" || exit $? + fi + + if test "$#" -gt 0; then + # Delete the old symlinks, and create new ones. + # Try `ln -sf' first, because the `ln' binary might depend on + # the symlink we replace! Solaris /bin/ln does not understand -f, + # so we also need to try rm && ln -s. + for linkname + do + if test "$linkname" != "$realname"; then + $show "(cd $destdir && { $LN_S -f $realname $linkname || { $rm $linkname && $LN_S $realname $linkname; }; })" + $run eval "(cd $destdir && { $LN_S -f $realname $linkname || { $rm $linkname && $LN_S $realname $linkname; }; })" + fi + done + fi + + # Do each command in the postinstall commands. + lib="$destdir/$realname" + cmds=$postinstall_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || { + lt_exit=$? + + # Restore the uninstalled library and exit + if test "$mode" = relink; then + $run eval '(cd $output_objdir && $rm ${realname}T && $mv ${realname}U $realname)' + fi + + exit $lt_exit + } + done + IFS="$save_ifs" + fi + + # Install the pseudo-library for information purposes. + name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + instname="$dir/$name"i + $show "$install_prog $instname $destdir/$name" + $run eval "$install_prog $instname $destdir/$name" || exit $? + + # Maybe install the static library, too. + test -n "$old_library" && staticlibs="$staticlibs $dir/$old_library" + ;; + + *.lo) + # Install (i.e. copy) a libtool object. + + # Figure out destination file name, if it wasn't already specified. + if test -n "$destname"; then + destfile="$destdir/$destname" + else + destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + destfile="$destdir/$destfile" + fi + + # Deduce the name of the destination old-style object file. + case $destfile in + *.lo) + staticdest=`$echo "X$destfile" | $Xsed -e "$lo2o"` + ;; + *.$objext) + staticdest="$destfile" + destfile= + ;; + *) + $echo "$modename: cannot copy a libtool object to \`$destfile'" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + ;; + esac + + # Install the libtool object if requested. + if test -n "$destfile"; then + $show "$install_prog $file $destfile" + $run eval "$install_prog $file $destfile" || exit $? + fi + + # Install the old object if enabled. + if test "$build_old_libs" = yes; then + # Deduce the name of the old-style object file. + staticobj=`$echo "X$file" | $Xsed -e "$lo2o"` + + $show "$install_prog $staticobj $staticdest" + $run eval "$install_prog \$staticobj \$staticdest" || exit $? + fi + exit $EXIT_SUCCESS + ;; + + *) + # Figure out destination file name, if it wasn't already specified. + if test -n "$destname"; then + destfile="$destdir/$destname" + else + destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + destfile="$destdir/$destfile" + fi + + # If the file is missing, and there is a .exe on the end, strip it + # because it is most likely a libtool script we actually want to + # install + stripped_ext="" + case $file in + *.exe) + if test ! -f "$file"; then + file=`$echo $file|${SED} 's,.exe$,,'` + stripped_ext=".exe" + fi + ;; + esac + + # Do a test to see if this is really a libtool program. + case $host in + *cygwin*|*mingw*) + wrapper=`$echo $file | ${SED} -e 's,.exe$,,'` + ;; + *) + wrapper=$file + ;; + esac + if (${SED} -e '4q' $wrapper | grep "^# Generated by .*$PACKAGE")>/dev/null 2>&1; then + notinst_deplibs= + relink_command= + + # Note that it is not necessary on cygwin/mingw to append a dot to + # foo even if both foo and FILE.exe exist: automatic-append-.exe + # behavior happens only for exec(3), not for open(2)! Also, sourcing + # `FILE.' does not work on cygwin managed mounts. + # + # If there is no directory component, then add one. + case $wrapper in + */* | *\\*) . ${wrapper} ;; + *) . ./${wrapper} ;; + esac + + # Check the variables that should have been set. + if test -z "$notinst_deplibs"; then + $echo "$modename: invalid libtool wrapper script \`$wrapper'" 1>&2 + exit $EXIT_FAILURE + fi + + finalize=yes + for lib in $notinst_deplibs; do + # Check to see that each library is installed. + libdir= + if test -f "$lib"; then + # If there is no directory component, then add one. + case $lib in + */* | *\\*) . $lib ;; + *) . ./$lib ;; + esac + fi + libfile="$libdir/"`$echo "X$lib" | $Xsed -e 's%^.*/%%g'` ### testsuite: skip nested quoting test + if test -n "$libdir" && test ! -f "$libfile"; then + $echo "$modename: warning: \`$lib' has not been installed in \`$libdir'" 1>&2 + finalize=no + fi + done + + relink_command= + # Note that it is not necessary on cygwin/mingw to append a dot to + # foo even if both foo and FILE.exe exist: automatic-append-.exe + # behavior happens only for exec(3), not for open(2)! Also, sourcing + # `FILE.' does not work on cygwin managed mounts. + # + # If there is no directory component, then add one. + case $wrapper in + */* | *\\*) . ${wrapper} ;; + *) . ./${wrapper} ;; + esac + + outputname= + if test "$fast_install" = no && test -n "$relink_command"; then + if test "$finalize" = yes && test -z "$run"; then + tmpdir=`func_mktempdir` + file=`$echo "X$file$stripped_ext" | $Xsed -e 's%^.*/%%'` + outputname="$tmpdir/$file" + # Replace the output file specification. + relink_command=`$echo "X$relink_command" | $Xsed -e 's%@OUTPUT@%'"$outputname"'%g'` + + $show "$relink_command" + if $run eval "$relink_command"; then : + else + $echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2 + ${rm}r "$tmpdir" + continue + fi + file="$outputname" + else + $echo "$modename: warning: cannot relink \`$file'" 1>&2 + fi + else + # Install the binary that we compiled earlier. + file=`$echo "X$file$stripped_ext" | $Xsed -e "s%\([^/]*\)$%$objdir/\1%"` + fi + fi + + # remove .exe since cygwin /usr/bin/install will append another + # one anyway + case $install_prog,$host in + */usr/bin/install*,*cygwin*) + case $file:$destfile in + *.exe:*.exe) + # this is ok + ;; + *.exe:*) + destfile=$destfile.exe + ;; + *:*.exe) + destfile=`$echo $destfile | ${SED} -e 's,.exe$,,'` + ;; + esac + ;; + esac + $show "$install_prog$stripme $file $destfile" + $run eval "$install_prog\$stripme \$file \$destfile" || exit $? + test -n "$outputname" && ${rm}r "$tmpdir" + ;; + esac + done + + for file in $staticlibs; do + name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + + # Set up the ranlib parameters. + oldlib="$destdir/$name" + + $show "$install_prog $file $oldlib" + $run eval "$install_prog \$file \$oldlib" || exit $? + + if test -n "$stripme" && test -n "$old_striplib"; then + $show "$old_striplib $oldlib" + $run eval "$old_striplib $oldlib" || exit $? + fi + + # Do each command in the postinstall commands. + cmds=$old_postinstall_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + done + + if test -n "$future_libdirs"; then + $echo "$modename: warning: remember to run \`$progname --finish$future_libdirs'" 1>&2 + fi + + if test -n "$current_libdirs"; then + # Maybe just do a dry run. + test -n "$run" && current_libdirs=" -n$current_libdirs" + exec_cmd='$SHELL $progpath $preserve_args --finish$current_libdirs' + else + exit $EXIT_SUCCESS + fi + ;; + + # libtool finish mode + finish) + modename="$modename: finish" + libdirs="$nonopt" + admincmds= + + if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then + for dir + do + libdirs="$libdirs $dir" + done + + for libdir in $libdirs; do + if test -n "$finish_cmds"; then + # Do each command in the finish commands. + cmds=$finish_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || admincmds="$admincmds + $cmd" + done + IFS="$save_ifs" + fi + if test -n "$finish_eval"; then + # Do the single finish_eval. + eval cmds=\"$finish_eval\" + $run eval "$cmds" || admincmds="$admincmds + $cmds" + fi + done + fi + + # Exit here if they wanted silent mode. + test "$show" = : && exit $EXIT_SUCCESS + + $echo "X----------------------------------------------------------------------" | $Xsed + $echo "Libraries have been installed in:" + for libdir in $libdirs; do + $echo " $libdir" + done + $echo + $echo "If you ever happen to want to link against installed libraries" + $echo "in a given directory, LIBDIR, you must either use libtool, and" + $echo "specify the full pathname of the library, or use the \`-LLIBDIR'" + $echo "flag during linking and do at least one of the following:" + if test -n "$shlibpath_var"; then + $echo " - add LIBDIR to the \`$shlibpath_var' environment variable" + $echo " during execution" + fi + if test -n "$runpath_var"; then + $echo " - add LIBDIR to the \`$runpath_var' environment variable" + $echo " during linking" + fi + if test -n "$hardcode_libdir_flag_spec"; then + libdir=LIBDIR + eval flag=\"$hardcode_libdir_flag_spec\" + + $echo " - use the \`$flag' linker flag" + fi + if test -n "$admincmds"; then + $echo " - have your system administrator run these commands:$admincmds" + fi + if test -f /etc/ld.so.conf; then + $echo " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'" + fi + $echo + $echo "See any operating system documentation about shared libraries for" + $echo "more information, such as the ld(1) and ld.so(8) manual pages." + $echo "X----------------------------------------------------------------------" | $Xsed + exit $EXIT_SUCCESS + ;; + + # libtool execute mode + execute) + modename="$modename: execute" + + # The first argument is the command name. + cmd="$nonopt" + if test -z "$cmd"; then + $echo "$modename: you must specify a COMMAND" 1>&2 + $echo "$help" + exit $EXIT_FAILURE + fi + + # Handle -dlopen flags immediately. + for file in $execute_dlfiles; do + if test ! -f "$file"; then + $echo "$modename: \`$file' is not a file" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + dir= + case $file in + *.la) + # Check to see that this really is a libtool archive. + if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : + else + $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + # Read the libtool library. + dlname= + library_names= + + # If there is no directory component, then add one. + case $file in + */* | *\\*) . $file ;; + *) . ./$file ;; + esac + + # Skip this library if it cannot be dlopened. + if test -z "$dlname"; then + # Warn if it was a shared library. + test -n "$library_names" && $echo "$modename: warning: \`$file' was not linked with \`-export-dynamic'" + continue + fi + + dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` + test "X$dir" = "X$file" && dir=. + + if test -f "$dir/$objdir/$dlname"; then + dir="$dir/$objdir" + else + $echo "$modename: cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" 1>&2 + exit $EXIT_FAILURE + fi + ;; + + *.lo) + # Just add the directory containing the .lo file. + dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` + test "X$dir" = "X$file" && dir=. + ;; + + *) + $echo "$modename: warning \`-dlopen' is ignored for non-libtool libraries and objects" 1>&2 + continue + ;; + esac + + # Get the absolute pathname. + absdir=`cd "$dir" && pwd` + test -n "$absdir" && dir="$absdir" + + # Now add the directory to shlibpath_var. + if eval "test -z \"\$$shlibpath_var\""; then + eval "$shlibpath_var=\"\$dir\"" + else + eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\"" + fi + done + + # This variable tells wrapper scripts just to set shlibpath_var + # rather than running their programs. + libtool_execute_magic="$magic" + + # Check if any of the arguments is a wrapper script. + args= + for file + do + case $file in + -*) ;; + *) + # Do a test to see if this is really a libtool program. + if (${SED} -e '4q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + # If there is no directory component, then add one. + case $file in + */* | *\\*) . $file ;; + *) . ./$file ;; + esac + + # Transform arg to wrapped name. + file="$progdir/$program" + fi + ;; + esac + # Quote arguments (to preserve shell metacharacters). + file=`$echo "X$file" | $Xsed -e "$sed_quote_subst"` + args="$args \"$file\"" + done + + if test -z "$run"; then + if test -n "$shlibpath_var"; then + # Export the shlibpath_var. + eval "export $shlibpath_var" + fi + + # Restore saved environment variables + if test "${save_LC_ALL+set}" = set; then + LC_ALL="$save_LC_ALL"; export LC_ALL + fi + if test "${save_LANG+set}" = set; then + LANG="$save_LANG"; export LANG + fi + + # Now prepare to actually exec the command. + exec_cmd="\$cmd$args" + else + # Display what would be done. + if test -n "$shlibpath_var"; then + eval "\$echo \"\$shlibpath_var=\$$shlibpath_var\"" + $echo "export $shlibpath_var" + fi + $echo "$cmd$args" + exit $EXIT_SUCCESS + fi + ;; + + # libtool clean and uninstall mode + clean | uninstall) + modename="$modename: $mode" + rm="$nonopt" + files= + rmforce= + exit_status=0 + + # This variable tells wrapper scripts just to set variables rather + # than running their programs. + libtool_install_magic="$magic" + + for arg + do + case $arg in + -f) rm="$rm $arg"; rmforce=yes ;; + -*) rm="$rm $arg" ;; + *) files="$files $arg" ;; + esac + done + + if test -z "$rm"; then + $echo "$modename: you must specify an RM program" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + rmdirs= + + origobjdir="$objdir" + for file in $files; do + dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` + if test "X$dir" = "X$file"; then + dir=. + objdir="$origobjdir" + else + objdir="$dir/$origobjdir" + fi + name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + test "$mode" = uninstall && objdir="$dir" + + # Remember objdir for removal later, being careful to avoid duplicates + if test "$mode" = clean; then + case " $rmdirs " in + *" $objdir "*) ;; + *) rmdirs="$rmdirs $objdir" ;; + esac + fi + + # Don't error if the file doesn't exist and rm -f was used. + if (test -L "$file") >/dev/null 2>&1 \ + || (test -h "$file") >/dev/null 2>&1 \ + || test -f "$file"; then + : + elif test -d "$file"; then + exit_status=1 + continue + elif test "$rmforce" = yes; then + continue + fi + + rmfiles="$file" + + case $name in + *.la) + # Possibly a libtool archive, so verify it. + if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + . $dir/$name + + # Delete the libtool libraries and symlinks. + for n in $library_names; do + rmfiles="$rmfiles $objdir/$n" + done + test -n "$old_library" && rmfiles="$rmfiles $objdir/$old_library" + + case "$mode" in + clean) + case " $library_names " in + # " " in the beginning catches empty $dlname + *" $dlname "*) ;; + *) rmfiles="$rmfiles $objdir/$dlname" ;; + esac + test -n "$libdir" && rmfiles="$rmfiles $objdir/$name $objdir/${name}i" + ;; + uninstall) + if test -n "$library_names"; then + # Do each command in the postuninstall commands. + cmds=$postuninstall_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" + if test "$?" -ne 0 && test "$rmforce" != yes; then + exit_status=1 + fi + done + IFS="$save_ifs" + fi + + if test -n "$old_library"; then + # Do each command in the old_postuninstall commands. + cmds=$old_postuninstall_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" + if test "$?" -ne 0 && test "$rmforce" != yes; then + exit_status=1 + fi + done + IFS="$save_ifs" + fi + # FIXME: should reinstall the best remaining shared library. + ;; + esac + fi + ;; + + *.lo) + # Possibly a libtool object, so verify it. + if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + + # Read the .lo file + . $dir/$name + + # Add PIC object to the list of files to remove. + if test -n "$pic_object" \ + && test "$pic_object" != none; then + rmfiles="$rmfiles $dir/$pic_object" + fi + + # Add non-PIC object to the list of files to remove. + if test -n "$non_pic_object" \ + && test "$non_pic_object" != none; then + rmfiles="$rmfiles $dir/$non_pic_object" + fi + fi + ;; + + *) + if test "$mode" = clean ; then + noexename=$name + case $file in + *.exe) + file=`$echo $file|${SED} 's,.exe$,,'` + noexename=`$echo $name|${SED} 's,.exe$,,'` + # $file with .exe has already been added to rmfiles, + # add $file without .exe + rmfiles="$rmfiles $file" + ;; + esac + # Do a test to see if this is a libtool program. + if (${SED} -e '4q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + relink_command= + . $dir/$noexename + + # note $name still contains .exe if it was in $file originally + # as does the version of $file that was added into $rmfiles + rmfiles="$rmfiles $objdir/$name $objdir/${name}S.${objext}" + if test "$fast_install" = yes && test -n "$relink_command"; then + rmfiles="$rmfiles $objdir/lt-$name" + fi + if test "X$noexename" != "X$name" ; then + rmfiles="$rmfiles $objdir/lt-${noexename}.c" + fi + fi + fi + ;; + esac + $show "$rm $rmfiles" + $run $rm $rmfiles || exit_status=1 + done + objdir="$origobjdir" + + # Try to remove the ${objdir}s in the directories where we deleted files + for dir in $rmdirs; do + if test -d "$dir"; then + $show "rmdir $dir" + $run rmdir $dir >/dev/null 2>&1 + fi + done + + exit $exit_status + ;; + + "") + $echo "$modename: you must specify a MODE" 1>&2 + $echo "$generic_help" 1>&2 + exit $EXIT_FAILURE + ;; + esac + + if test -z "$exec_cmd"; then + $echo "$modename: invalid operation mode \`$mode'" 1>&2 + $echo "$generic_help" 1>&2 + exit $EXIT_FAILURE + fi +fi # test -z "$show_help" + +if test -n "$exec_cmd"; then + eval exec $exec_cmd + exit $EXIT_FAILURE +fi + +# We need to display help for each of the modes. +case $mode in +"") $echo \ +"Usage: $modename [OPTION]... [MODE-ARG]... + +Provide generalized library-building support services. + + --config show all configuration variables + --debug enable verbose shell tracing +-n, --dry-run display commands without modifying any files + --features display basic configuration information and exit + --finish same as \`--mode=finish' + --help display this help message and exit + --mode=MODE use operation mode MODE [default=inferred from MODE-ARGS] + --quiet same as \`--silent' + --silent don't print informational messages + --tag=TAG use configuration variables from tag TAG + --version print version information + +MODE must be one of the following: + + clean remove files from the build directory + compile compile a source file into a libtool object + execute automatically set library path, then run a program + finish complete the installation of libtool libraries + install install libraries or executables + link create a library or an executable + uninstall remove libraries from an installed directory + +MODE-ARGS vary depending on the MODE. Try \`$modename --help --mode=MODE' for +a more detailed description of MODE. + +Report bugs to <bug-libtool@gnu.org>." + exit $EXIT_SUCCESS + ;; + +clean) + $echo \ +"Usage: $modename [OPTION]... --mode=clean RM [RM-OPTION]... FILE... + +Remove files from the build directory. + +RM is the name of the program to use to delete files associated with each FILE +(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed +to RM. + +If FILE is a libtool library, object or program, all the files associated +with it are deleted. Otherwise, only FILE itself is deleted using RM." + ;; + +compile) + $echo \ +"Usage: $modename [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE + +Compile a source file into a libtool library object. + +This mode accepts the following additional options: + + -o OUTPUT-FILE set the output file name to OUTPUT-FILE + -prefer-pic try to building PIC objects only + -prefer-non-pic try to building non-PIC objects only + -static always build a \`.o' file suitable for static linking + +COMPILE-COMMAND is a command to be used in creating a \`standard' object file +from the given SOURCEFILE. + +The output file name is determined by removing the directory component from +SOURCEFILE, then substituting the C source code suffix \`.c' with the +library object suffix, \`.lo'." + ;; + +execute) + $echo \ +"Usage: $modename [OPTION]... --mode=execute COMMAND [ARGS]... + +Automatically set library path, then run a program. + +This mode accepts the following additional options: + + -dlopen FILE add the directory containing FILE to the library path + +This mode sets the library path environment variable according to \`-dlopen' +flags. + +If any of the ARGS are libtool executable wrappers, then they are translated +into their corresponding uninstalled binary, and any of their required library +directories are added to the library path. + +Then, COMMAND is executed, with ARGS as arguments." + ;; + +finish) + $echo \ +"Usage: $modename [OPTION]... --mode=finish [LIBDIR]... + +Complete the installation of libtool libraries. + +Each LIBDIR is a directory that contains libtool libraries. + +The commands that this mode executes may require superuser privileges. Use +the \`--dry-run' option if you just want to see what would be executed." + ;; + +install) + $echo \ +"Usage: $modename [OPTION]... --mode=install INSTALL-COMMAND... + +Install executables or libraries. + +INSTALL-COMMAND is the installation command. The first component should be +either the \`install' or \`cp' program. + +The rest of the components are interpreted as arguments to that command (only +BSD-compatible install options are recognized)." + ;; + +link) + $echo \ +"Usage: $modename [OPTION]... --mode=link LINK-COMMAND... + +Link object files or libraries together to form another library, or to +create an executable program. + +LINK-COMMAND is a command using the C compiler that you would use to create +a program from several object files. + +The following components of LINK-COMMAND are treated specially: + + -all-static do not do any dynamic linking at all + -avoid-version do not add a version suffix if possible + -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime + -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols + -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3) + -export-symbols SYMFILE + try to export only the symbols listed in SYMFILE + -export-symbols-regex REGEX + try to export only the symbols matching REGEX + -LLIBDIR search LIBDIR for required installed libraries + -lNAME OUTPUT-FILE requires the installed library libNAME + -module build a library that can dlopened + -no-fast-install disable the fast-install mode + -no-install link a not-installable executable + -no-undefined declare that a library does not refer to external symbols + -o OUTPUT-FILE create OUTPUT-FILE from the specified objects + -objectlist FILE Use a list of object files found in FILE to specify objects + -precious-files-regex REGEX + don't remove output files matching REGEX + -release RELEASE specify package release information + -rpath LIBDIR the created library will eventually be installed in LIBDIR + -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries + -static do not do any dynamic linking of libtool libraries + -version-info CURRENT[:REVISION[:AGE]] + specify library version info [each variable defaults to 0] + +All other options (arguments beginning with \`-') are ignored. + +Every other argument is treated as a filename. Files ending in \`.la' are +treated as uninstalled libtool libraries, other files are standard or library +object files. + +If the OUTPUT-FILE ends in \`.la', then a libtool library is created, +only library objects (\`.lo' files) may be specified, and \`-rpath' is +required, except when creating a convenience library. + +If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created +using \`ar' and \`ranlib', or on Windows using \`lib'. + +If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file +is created, otherwise an executable program is created." + ;; + +uninstall) + $echo \ +"Usage: $modename [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE... + +Remove libraries from an installation directory. + +RM is the name of the program to use to delete files associated with each FILE +(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed +to RM. + +If FILE is a libtool library, all the files associated with it are deleted. +Otherwise, only FILE itself is deleted using RM." + ;; + +*) + $echo "$modename: invalid operation mode \`$mode'" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + ;; +esac + +$echo +$echo "Try \`$modename --help' for more information about other modes." + +exit $? + +# The TAGs below are defined such that we never get into a situation +# in which we disable both kinds of libraries. Given conflicting +# choices, we go for a static library, that is the most portable, +# since we can't tell whether shared libraries were disabled because +# the user asked for that or because the platform doesn't support +# them. This is particularly important on AIX, because we don't +# support having both static and shared libraries enabled at the same +# time on that platform, so we default to a shared-only configuration. +# If a disable-shared tag is given, we'll fallback to a static-only +# configuration. But we'll never go from static-only to shared-only. + +# ### BEGIN LIBTOOL TAG CONFIG: disable-shared +disable_libs=shared +# ### END LIBTOOL TAG CONFIG: disable-shared + +# ### BEGIN LIBTOOL TAG CONFIG: disable-static +disable_libs=static +# ### END LIBTOOL TAG CONFIG: disable-static + +# Local Variables: +# mode:shell-script +# sh-indentation:2 +# End: +# ### BEGIN LIBTOOL TAG CONFIG: CXX + +# Libtool was configured on host pes.vlakno.cz: + +# Shell to use when invoking shell scripts. +SHELL="/bin/sh" + +# Whether or not to build shared libraries. +build_libtool_libs=yes + +# Whether or not to build static libraries. +build_old_libs=yes + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=no + +# Whether or not to disallow shared libs when runtime libs are static +allow_libtool_libs_with_static_runtimes=no + +# Whether or not to optimize for fast installation. +fast_install=needless + +# The host system. +host_alias= +host=x86_64-unknown-freebsd7.2 +host_os=freebsd7.2 + +# The build system. +build_alias= +build=x86_64-unknown-freebsd7.2 +build_os=freebsd7.2 + +# An echo program that does not interpret backslashes. +echo="echo" + +# The archiver. +AR="ar" +AR_FLAGS="cru" + +# A C compiler. +LTCC="gcc" + +# LTCC compiler flags. +LTCFLAGS="-g -O2" + +# A language-specific compiler. +CC="g++" + +# Is the compiler the GNU C compiler? +with_gcc=yes + +# An ERE matcher. +EGREP="/usr/bin/grep -E" + +# The linker used to build libraries. +LD="/usr/bin/ld" + +# Whether we need hard or soft links. +LN_S="ln -s" + +# A BSD-compatible nm program. +NM="/usr/bin/nm -B" + +# A symbol stripping program +STRIP="strip" + +# Used to examine libraries when file_magic_cmd begins "file" +MAGIC_CMD=file + +# Used on cygwin: DLL creation program. +DLLTOOL="dlltool" + +# Used on cygwin: object dumper. +OBJDUMP="objdump" + +# Used on cygwin: assembler. +AS="as" + +# The name of the directory that contains temporary libtool files. +objdir=.libs + +# How to create reloadable object files. +reload_flag=" -r" +reload_cmds="\$LD\$reload_flag -o \$output\$reload_objs" + +# How to pass a linker flag through the compiler. +wl="-Wl," + +# Object file suffix (normally "o"). +objext="o" + +# Old archive suffix (normally "a"). +libext="a" + +# Shared library suffix (normally ".so"). +shrext_cmds='.so' + +# Executable file suffix (normally ""). +exeext="" + +# Additional compiler flags for building library objects. +pic_flag=" -fPIC -DPIC" +pic_mode=default + +# What is the maximum length of a command? +max_cmd_len=196608 + +# Does compiler simultaneously support -c and -o options? +compiler_c_o="yes" + +# Must we lock files when doing compilation? +need_locks="no" + +# Do we need the lib prefix for modules? +need_lib_prefix=no + +# Do we need a version for libraries? +need_version=no + +# Whether dlopen is supported. +dlopen_support=yes + +# Whether dlopen of programs is supported. +dlopen_self=yes + +# Whether dlopen of statically linked programs is supported. +dlopen_self_static=no + +# Compiler flag to prevent dynamic linking. +link_static_flag="-static" + +# Compiler flag to turn off builtin functions. +no_builtin_flag=" -fno-builtin" + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec="\${wl}--export-dynamic" + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec="\${wl}--whole-archive\$convenience \${wl}--no-whole-archive" + +# Compiler flag to generate thread-safe objects. +thread_safe_flag_spec="" + +# Library versioning type. +version_type=freebsd-elf + +# Format of library name prefix. +libname_spec="lib\$name" + +# List of archive names. First name is the real one, the rest are links. +# The last name is the one that the linker finds with -lNAME. +library_names_spec="\${libname}\${release}\${shared_ext}\$versuffix \${libname}\${release}\${shared_ext} \$libname\${shared_ext}" + +# The coded name of the library, if different from the real name. +soname_spec="" + +# Commands used to build and install an old-style archive. +RANLIB="ranlib" +old_archive_cmds="\$AR \$AR_FLAGS \$oldlib\$oldobjs\$old_deplibs~\$RANLIB \$oldlib" +old_postinstall_cmds="chmod 644 \$oldlib~\$RANLIB \$oldlib" +old_postuninstall_cmds="" + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds="" + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds="" + +# Commands used to build and install a shared archive. +archive_cmds="\$CC -shared -nostdlib \$predep_objects \$libobjs \$deplibs \$postdep_objects \$compiler_flags \${wl}-soname \$wl\$soname -o \$lib" +archive_expsym_cmds="\$CC -shared -nostdlib \$predep_objects \$libobjs \$deplibs \$postdep_objects \$compiler_flags \${wl}-soname \$wl\$soname \${wl}-retain-symbols-file \$wl\$export_symbols -o \$lib" +postinstall_cmds="" +postuninstall_cmds="" + +# Commands used to build a loadable module (assumed same as above if empty) +module_cmds="" +module_expsym_cmds="" + +# Commands to strip libraries. +old_striplib="strip --strip-debug" +striplib="strip --strip-unneeded" + +# Dependencies to place before the objects being linked to create a +# shared library. +predep_objects="/usr/lib/crti.o /usr/lib/crtbeginS.o" + +# Dependencies to place after the objects being linked to create a +# shared library. +postdep_objects="/usr/lib/crtendS.o /usr/lib/crtn.o" + +# Dependencies to place before the objects being linked to create a +# shared library. +predeps="" + +# Dependencies to place after the objects being linked to create a +# shared library. +postdeps="-lstdc++ -lm -lgcc_s -lc -lgcc_s" + +# The library search path used internally by the compiler when linking +# a shared library. +compiler_lib_search_path="-L/usr/lib -L/usr/lib" + +# Method to check whether dependent libraries are shared objects. +deplibs_check_method="pass_all" + +# Command to use when deplibs_check_method == file_magic. +file_magic_cmd="\$MAGIC_CMD" + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag="" + +# Flag that forces no undefined symbols. +no_undefined_flag="" + +# Commands used to finish a libtool library installation in a directory. +finish_cmds="" + +# Same as above, but a single script fragment to be evaled but not shown. +finish_eval="" + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe="sed -n -e 's/^.*[ ]\\([ABCDGIRSTW][ABCDGIRSTW]*\\)[ ][ ]*\\([_A-Za-z][_A-Za-z0-9]*\\)\$/\\1 \\2 \\2/p'" + +# Transform the output of nm in a proper C declaration +global_symbol_to_cdecl="sed -n -e 's/^. .* \\(.*\\)\$/extern int \\1;/p'" + +# Transform the output of nm in a C name address pair +global_symbol_to_c_name_address="sed -n -e 's/^: \\([^ ]*\\) \$/ {\\\"\\1\\\", (lt_ptr) 0},/p' -e 's/^[BCDEGRST] \\([^ ]*\\) \\([^ ]*\\)\$/ {\"\\2\", (lt_ptr) \\&\\2},/p'" + +# This is the shared library runtime path variable. +runpath_var=LD_RUN_PATH + +# This is the shared library path variable. +shlibpath_var=LD_LIBRARY_PATH + +# Is shlibpath searched before the hard-coded library search path? +shlibpath_overrides_runpath=yes + +# How to hardcode a shared library path into an executable. +hardcode_action=immediate + +# Whether we should hardcode library paths into libraries. +hardcode_into_libs=yes + +# Flag to hardcode $libdir into a binary during linking. +# This must work even if $libdir does not exist. +hardcode_libdir_flag_spec="\${wl}--rpath \${wl}\$libdir" + +# If ld is used when linking, flag to hardcode $libdir into +# a binary during linking. This must work even if $libdir does +# not exist. +hardcode_libdir_flag_spec_ld="" + +# Whether we need a single -rpath flag with a separated argument. +hardcode_libdir_separator="" + +# Set to yes if using DIR/libNAME during linking hardcodes DIR into the +# resulting binary. +hardcode_direct=no + +# Set to yes if using the -LDIR flag during linking hardcodes DIR into the +# resulting binary. +hardcode_minus_L=no + +# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into +# the resulting binary. +hardcode_shlibpath_var=unsupported + +# Set to yes if building a shared library automatically hardcodes DIR into the library +# and all subsequent libraries and executables linked against it. +hardcode_automatic=no + +# Variables whose values should be saved in libtool wrapper scripts and +# restored at relink time. +variables_saved_for_relink="PATH LD_LIBRARY_PATH LD_RUN_PATH GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=unknown + +# Compile-time system search path for libraries +sys_lib_search_path_spec=" /usr/lib/ /usr/lib/" + +# Run-time system search path for libraries +sys_lib_dlsearch_path_spec="/lib /usr/lib" + +# Fix the shell variable $srcfile for the compiler. +fix_srcfile_path="" + +# Set to yes if exported symbols are required. +always_export_symbols=no + +# The commands to list exported symbols. +export_symbols_cmds="\$NM \$libobjs \$convenience | \$global_symbol_pipe | \$SED 's/.* //' | sort | uniq > \$export_symbols" + +# The commands to extract the exported symbol list from a shared archive. +extract_expsyms_cmds="" + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms="" + +# Symbols that must always be exported. +include_expsyms="" + +# ### END LIBTOOL TAG CONFIG: CXX + diff --git a/test/Analysis/BasicAA/modref.ll b/test/Analysis/BasicAA/modref.ll index 8f7c0a7..69b60d7 100644 --- a/test/Analysis/BasicAA/modref.ll +++ b/test/Analysis/BasicAA/modref.ll @@ -1,15 +1,91 @@ -; A very rudimentary test on AliasAnalysis::getModRefInfo. -; RUN: opt < %s -print-all-alias-modref-info -aa-eval -disable-output |& \ -; RUN: not grep NoModRef +; RUN: opt < %s -basicaa -gvn -dse -S | FileCheck %s -define i32 @callee() { - %X = alloca { i32, i32 } ; <{ i32, i32 }*> [#uses=1] - %Y = getelementptr { i32, i32 }* %X, i64 0, i32 0 ; <i32*> [#uses=1] - %Z = load i32* %Y ; <i32> [#uses=1] - ret i32 %Z +declare void @llvm.memset.i32(i8*, i8, i32, i32) +declare void @llvm.memset.i8(i8*, i8, i8, i32) +declare void @llvm.memcpy.i8(i8*, i8*, i8, i32) +declare void @llvm.lifetime.end(i64, i8* nocapture) + +declare void @external(i32*) + +define i32 @test0(i8* %P) { + %A = alloca i32 + call void @external(i32* %A) + + store i32 0, i32* %A + + call void @llvm.memset.i32(i8* %P, i8 0, i32 42, i32 1) + + %B = load i32* %A + ret i32 %B + +; CHECK: @test0 +; CHECK: ret i32 0 } -define i32 @caller() { - %X = call i32 @callee( ) ; <i32> [#uses=1] - ret i32 %X +declare void @llvm.memcpy.i8(i8*, i8*, i8, i32) + +define i8 @test1() { +; CHECK: @test1 + %A = alloca i8 + %B = alloca i8 + + store i8 2, i8* %B ;; Not written to by memcpy + + call void @llvm.memcpy.i8(i8* %A, i8* %B, i8 -1, i32 0) + + %C = load i8* %B + ret i8 %C +; CHECK: ret i8 2 } + +define i8 @test2(i8* %P) { +; CHECK: @test2 + %P2 = getelementptr i8* %P, i32 127 + store i8 1, i8* %P2 ;; Not dead across memset + call void @llvm.memset.i8(i8* %P, i8 2, i8 127, i32 0) + %A = load i8* %P2 + ret i8 %A +; CHECK: ret i8 1 +} + +define i8 @test2a(i8* %P) { +; CHECK: @test2 + %P2 = getelementptr i8* %P, i32 126 + + ;; FIXME: DSE isn't zapping this dead store. + store i8 1, i8* %P2 ;; Dead, clobbered by memset. + + call void @llvm.memset.i8(i8* %P, i8 2, i8 127, i32 0) + %A = load i8* %P2 + ret i8 %A +; CHECK: %A = load i8* %P2 +; CHECK: ret i8 %A +} + +define void @test3(i8* %P, i8 %X) { +; CHECK: @test3 +; CHECK-NOT: store +; CHECK-NOT: %Y + %Y = add i8 %X, 1 ;; Dead, because the only use (the store) is dead. + + %P2 = getelementptr i8* %P, i32 2 + store i8 %Y, i8* %P2 ;; Not read by lifetime.end, should be removed. +; CHECK: store i8 2, i8* %P2 + call void @llvm.lifetime.end(i64 1, i8* %P) + store i8 2, i8* %P2 +; CHECK-NOT: store + ret void +; CHECK: ret void +} + +define void @test3a(i8* %P, i8 %X) { +; CHECK: @test3a + %Y = add i8 %X, 1 ;; Dead, because the only use (the store) is dead. + + %P2 = getelementptr i8* %P, i32 2 + store i8 %Y, i8* %P2 ;; FIXME: Killed by llvm.lifetime.end, should be zapped. +; CHECK: store i8 %Y, i8* %P2 + call void @llvm.lifetime.end(i64 10, i8* %P) + ret void +; CHECK: ret void +}
\ No newline at end of file diff --git a/test/Assembler/alignstack.ll b/test/Assembler/alignstack.ll new file mode 100644 index 0000000..9f2059f --- /dev/null +++ b/test/Assembler/alignstack.ll @@ -0,0 +1,36 @@ +; RUN: llvm-as < %s | llvm-dis | FileCheck %s +target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128" +target triple = "i386-apple-darwin10.0" + +define void @test1() nounwind { +; CHECK: test1 +; CHECK: sideeffect +; CHECK-NOT: alignstack + tail call void asm sideeffect "mov", "~{dirflag},~{fpsr},~{flags}"() nounwind + ret void +; CHECK: ret +} +define void @test2() nounwind { +; CHECK: test2 +; CHECK: sideeffect +; CHECK: alignstack + tail call void asm sideeffect alignstack "mov", "~{dirflag},~{fpsr},~{flags}"() nounwind + ret void +; CHECK: ret +} +define void @test3() nounwind { +; CHECK: test3 +; CHECK-NOT: sideeffect +; CHECK: alignstack + tail call void asm alignstack "mov", "~{dirflag},~{fpsr},~{flags}"() nounwind + ret void +; CHECK: ret +} +define void @test4() nounwind { +; CHECK: test4 +; CHECK-NOT: sideeffect +; CHECK-NOT: alignstack + tail call void asm "mov", "~{dirflag},~{fpsr},~{flags}"() nounwind + ret void +; CHECK: ret +} diff --git a/test/Bindings/Ocaml/vmcore.ml b/test/Bindings/Ocaml/vmcore.ml index 9e976d3..dd0404a 100644 --- a/test/Bindings/Ocaml/vmcore.ml +++ b/test/Bindings/Ocaml/vmcore.ml @@ -936,9 +936,9 @@ let test_builder () = group "memory"; begin let bb08 = append_block context "Bb08" fn in let b = builder_at_end context bb08 in - - (* RUN: grep {Inst20.*malloc.*i8 } < %t.ll - * RUN: grep {Inst21.*malloc.*i8.*P1} < %t.ll + + (* RUN: grep {Inst20.*malloc} < %t.ll + * RUN: grep {Inst21.*malloc} < %t.ll * RUN: grep {Inst22.*alloca.*i32 } < %t.ll * RUN: grep {Inst23.*alloca.*i32.*P2} < %t.ll * RUN: grep {free.*Inst20} < %t.ll diff --git a/test/CodeGen/ARM/2009-10-21-InvalidFNeg.ll b/test/CodeGen/ARM/2009-10-21-InvalidFNeg.ll new file mode 100644 index 0000000..0f021d2 --- /dev/null +++ b/test/CodeGen/ARM/2009-10-21-InvalidFNeg.ll @@ -0,0 +1,48 @@ +; RUN: llc -mcpu=cortex-a8 -mattr=+neon < %s | grep vneg +target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64" +target triple = "armv7-eabi" + +%aaa = type { %fff, %fff } +%bbb = type { [6 x %ddd] } +%ccc = type { %eee, %fff } +%ddd = type { %fff } +%eee = type { %fff, %fff, %fff, %fff } +%fff = type { %struct.vec_float4 } +%struct.vec_float4 = type { <4 x float> } + +define linkonce_odr arm_aapcs_vfpcc void @foo(%eee* noalias sret %agg.result, i64 %tfrm.0.0, i64 %tfrm.0.1, i64 %tfrm.0.2, i64 %tfrm.0.3, i64 %tfrm.0.4, i64 %tfrm.0.5, i64 %tfrm.0.6, i64 %tfrm.0.7) nounwind noinline { +entry: + %tmp104 = zext i64 %tfrm.0.2 to i512 ; <i512> [#uses=1] + %tmp105 = shl i512 %tmp104, 128 ; <i512> [#uses=1] + %tmp118 = zext i64 %tfrm.0.3 to i512 ; <i512> [#uses=1] + %tmp119 = shl i512 %tmp118, 192 ; <i512> [#uses=1] + %ins121 = or i512 %tmp119, %tmp105 ; <i512> [#uses=1] + %tmp99 = zext i64 %tfrm.0.4 to i512 ; <i512> [#uses=1] + %tmp100 = shl i512 %tmp99, 256 ; <i512> [#uses=1] + %tmp123 = zext i64 %tfrm.0.5 to i512 ; <i512> [#uses=1] + %tmp124 = shl i512 %tmp123, 320 ; <i512> [#uses=1] + %tmp96 = zext i64 %tfrm.0.6 to i512 ; <i512> [#uses=1] + %tmp97 = shl i512 %tmp96, 384 ; <i512> [#uses=1] + %tmp128 = zext i64 %tfrm.0.7 to i512 ; <i512> [#uses=1] + %tmp129 = shl i512 %tmp128, 448 ; <i512> [#uses=1] + %mask.masked = or i512 %tmp124, %tmp100 ; <i512> [#uses=1] + %ins131 = or i512 %tmp129, %tmp97 ; <i512> [#uses=1] + %tmp109132 = zext i64 %tfrm.0.0 to i128 ; <i128> [#uses=1] + %tmp113134 = zext i64 %tfrm.0.1 to i128 ; <i128> [#uses=1] + %tmp114133 = shl i128 %tmp113134, 64 ; <i128> [#uses=1] + %tmp94 = or i128 %tmp114133, %tmp109132 ; <i128> [#uses=1] + %tmp95 = bitcast i128 %tmp94 to <4 x float> ; <<4 x float>> [#uses=0] + %tmp82 = lshr i512 %ins121, 128 ; <i512> [#uses=1] + %tmp83 = trunc i512 %tmp82 to i128 ; <i128> [#uses=1] + %tmp84 = bitcast i128 %tmp83 to <4 x float> ; <<4 x float>> [#uses=0] + %tmp86 = lshr i512 %mask.masked, 256 ; <i512> [#uses=1] + %tmp87 = trunc i512 %tmp86 to i128 ; <i128> [#uses=1] + %tmp88 = bitcast i128 %tmp87 to <4 x float> ; <<4 x float>> [#uses=0] + %tmp90 = lshr i512 %ins131, 384 ; <i512> [#uses=1] + %tmp91 = trunc i512 %tmp90 to i128 ; <i128> [#uses=1] + %tmp92 = bitcast i128 %tmp91 to <4 x float> ; <<4 x float>> [#uses=1] + %tmp = fsub <4 x float> <float -0.000000e+00, float -0.000000e+00, float -0.000000e+00, float -0.000000e+00>, %tmp92 ; <<4 x float>> [#uses=1] + %tmp28 = getelementptr inbounds %eee* %agg.result, i32 0, i32 3, i32 0, i32 0 ; <<4 x float>*> [#uses=1] + store <4 x float> %tmp, <4 x float>* %tmp28, align 16 + ret void +} diff --git a/test/CodeGen/ARM/globals.ll b/test/CodeGen/ARM/globals.ll new file mode 100644 index 0000000..8ed58bd --- /dev/null +++ b/test/CodeGen/ARM/globals.ll @@ -0,0 +1,75 @@ +; RUN: llc < %s -mtriple=arm-apple-darwin -relocation-model=static | FileCheck %s -check-prefix=DarwinStatic +; RUN: llc < %s -mtriple=arm-apple-darwin -relocation-model=dynamic-no-pic | FileCheck %s -check-prefix=DarwinDynamic +; RUN: llc < %s -mtriple=arm-apple-darwin -relocation-model=pic | FileCheck %s -check-prefix=DarwinPIC +; RUN: llc < %s -mtriple=arm-linux-gnueabi -relocation-model=pic | FileCheck %s -check-prefix=LinuxPIC + +@G = external global i32 + +define i32 @test1() { + %tmp = load i32* @G + ret i32 %tmp +} + +; DarwinStatic: _test1: +; DarwinStatic: ldr r0, LCPI1_0 +; DarwinStatic: ldr r0, [r0] +; DarwinStatic: bx lr + +; DarwinStatic: .align 2 +; DarwinStatic: LCPI1_0: +; DarwinStatic: .long {{_G$}} + + +; DarwinDynamic: _test1: +; DarwinDynamic: ldr r0, LCPI1_0 +; DarwinDynamic: ldr r0, [r0] +; DarwinDynamic: ldr r0, [r0] +; DarwinDynamic: bx lr + +; DarwinDynamic: .align 2 +; DarwinDynamic: LCPI1_0: +; DarwinDynamic: .long L_G$non_lazy_ptr + +; DarwinDynamic: .section __DATA,__nl_symbol_ptr,non_lazy_symbol_pointers +; DarwinDynamic: .align 2 +; DarwinDynamic: L_G$non_lazy_ptr: +; DarwinDynamic: .indirect_symbol _G +; DarwinDynamic: .long 0 + + + +; DarwinPIC: _test1: +; DarwinPIC: ldr r0, LCPI1_0 +; DarwinPIC: LPC0: +; DarwinPIC: ldr r0, [pc, +r0] +; DarwinPIC: ldr r0, [r0] +; DarwinPIC: bx lr + +; DarwinPIC: .align 2 +; DarwinPIC: LCPI1_0: +; DarwinPIC: .long L_G$non_lazy_ptr-(LPC0+8) + +; DarwinPIC: .section __DATA,__nl_symbol_ptr,non_lazy_symbol_pointers +; DarwinPIC: .align 2 +; DarwinPIC: L_G$non_lazy_ptr: +; DarwinPIC: .indirect_symbol _G +; DarwinPIC: .long 0 + + + +; LinuxPIC: test1: +; LinuxPIC: ldr r0, .LCPI1_0 +; LinuxPIC: ldr r1, .LCPI1_1 + +; LinuxPIC: .LPC0: +; LinuxPIC: add r0, pc, r0 +; LinuxPIC: ldr r0, [r1, +r0] +; LinuxPIC: ldr r0, [r0] +; LinuxPIC: bx lr + +; LinuxPIC: .align 2 +; LinuxPIC: .LCPI1_0: +; LinuxPIC: .long _GLOBAL_OFFSET_TABLE_-(.LPC0+8) +; LinuxPIC: .align 2 +; LinuxPIC: .LCPI1_1: +; LinuxPIC: .long G(GOT) diff --git a/test/CodeGen/ARM/ldrd.ll b/test/CodeGen/ARM/ldrd.ll index 8f7ae55..c366e2d 100644 --- a/test/CodeGen/ARM/ldrd.ll +++ b/test/CodeGen/ARM/ldrd.ll @@ -7,13 +7,13 @@ define i64 @t(i64 %a) nounwind readonly { entry: -;V6: ldrd r2, [r2] +;V6: ldrd r2, [r2] -;V5: ldr r3, [r2] -;V5-NEXT: ldr r2, [r2, #+4] +;V5: ldr r3, [r2] +;V5: ldr r2, [r2, #+4] -;EABI: ldr r3, [r2] -;EABI-NEXT: ldr r2, [r2, #+4] +;EABI: ldr r3, [r2] +;EABI: ldr r2, [r2, #+4] %0 = load i64** @b, align 4 %1 = load i64* %0, align 4 diff --git a/test/CodeGen/ARM/movt.ll b/test/CodeGen/ARM/movt.ll new file mode 100644 index 0000000..e82aca0 --- /dev/null +++ b/test/CodeGen/ARM/movt.ll @@ -0,0 +1,19 @@ +; RUN: llc < %s -march=arm -mattr=+thumb2 | FileCheck %s +; rdar://7317664 + +define i32 @t(i32 %X) nounwind { +; CHECK: t: +; CHECK: movt r0, #65535 +entry: + %0 = or i32 %X, -65536 + ret i32 %0 +} + +define i32 @t2(i32 %X) nounwind { +; CHECK: t2: +; CHECK: movt r0, #65534 +entry: + %0 = or i32 %X, -131072 + %1 = and i32 %0, -65537 + ret i32 %1 +} diff --git a/test/CodeGen/ARM/sbfx.ll b/test/CodeGen/ARM/sbfx.ll index 923f52a..6f1d87d 100644 --- a/test/CodeGen/ARM/sbfx.ll +++ b/test/CodeGen/ARM/sbfx.ll @@ -35,3 +35,13 @@ entry: %tmp2 = lshr i32 %tmp, 29 ret i32 %tmp2 } + +define i32 @f5(i32 %a) { +entry: +; CHECK: f5: +; CHECK-NOT: sbfx +; CHECK: bx + %tmp = shl i32 %a, 3 + %tmp2 = ashr i32 %tmp, 1 + ret i32 %tmp2 +} diff --git a/test/CodeGen/Blackfin/sync-intr.ll b/test/CodeGen/Blackfin/sync-intr.ll index 75084f0..0b103a3 100644 --- a/test/CodeGen/Blackfin/sync-intr.ll +++ b/test/CodeGen/Blackfin/sync-intr.ll @@ -2,8 +2,11 @@ define void @f() nounwind { entry: + ; CHECK-NOT: llvm.bfin ; CHECK: csync; call void @llvm.bfin.csync() + + ; CHECK-NOT: llvm.bfin ; CHECK: ssync; call void @llvm.bfin.ssync() ret void diff --git a/test/CodeGen/CellSPU/2009-01-01-BrCond.ll b/test/CodeGen/CellSPU/2009-01-01-BrCond.ll index 3542231..58e3190 100644 --- a/test/CodeGen/CellSPU/2009-01-01-BrCond.ll +++ b/test/CodeGen/CellSPU/2009-01-01-BrCond.ll @@ -1,4 +1,4 @@ -; RUN: llc < %s -march=cellspu -o - | grep brz +; RUN: llc < %s -march=cellspu -o - | grep brnz ; PR3274 target datalayout = "E-p:32:32:128-i1:8:128-i8:8:128-i16:16:128-i32:32:128-i64:32:128-f32:32:128-f64:64:128-v64:64:64-v128:128:128-a0:0:128-s0:128:128" diff --git a/test/CodeGen/CellSPU/useful-harnesses/lit.local.cfg b/test/CodeGen/CellSPU/useful-harnesses/lit.local.cfg new file mode 100644 index 0000000..e6f55ee --- /dev/null +++ b/test/CodeGen/CellSPU/useful-harnesses/lit.local.cfg @@ -0,0 +1 @@ +config.suffixes = [] diff --git a/test/CodeGen/Generic/switch-lower-feature-2.ll b/test/CodeGen/Generic/switch-lower-feature-2.ll index d6e5647..80e0618 100644 --- a/test/CodeGen/Generic/switch-lower-feature-2.ll +++ b/test/CodeGen/Generic/switch-lower-feature-2.ll @@ -5,9 +5,9 @@ ; RUN: grep 1023 %t | count 1 ; RUN: grep 119 %t | count 1 ; RUN: grep JTI %t | count 2 -; RUN: grep jg %t | count 1 +; RUN: grep jg %t | count 3 ; RUN: grep ja %t | count 1 -; RUN: grep js %t | count 1 +; RUN: grep jns %t | count 1 target triple = "i686-pc-linux-gnu" diff --git a/test/CodeGen/MSP430/Inst16ri.ll b/test/CodeGen/MSP430/Inst16ri.ll new file mode 100644 index 0000000..5115a23 --- /dev/null +++ b/test/CodeGen/MSP430/Inst16ri.ll @@ -0,0 +1,37 @@ +; RUN: llc -march=msp430 < %s | FileCheck %s +target datalayout = "e-p:16:8:8-i8:8:8-i16:8:8-i32:8:8" +target triple = "msp430-generic-generic" + +define i16 @mov() nounwind { +; CHECK: mov: +; CHECK: mov.w #1, r15 + ret i16 1 +} + +define i16 @add(i16 %a, i16 %b) nounwind { +; CHECK: add: +; CHECK: add.w #1, r15 + %1 = add i16 %a, 1 + ret i16 %1 +} + +define i16 @and(i16 %a, i16 %b) nounwind { +; CHECK: and: +; CHECK: and.w #1, r15 + %1 = and i16 %a, 1 + ret i16 %1 +} + +define i16 @bis(i16 %a, i16 %b) nounwind { +; CHECK: bis: +; CHECK: bis.w #1, r15 + %1 = or i16 %a, 1 + ret i16 %1 +} + +define i16 @xor(i16 %a, i16 %b) nounwind { +; CHECK: xor: +; CHECK: xor.w #1, r15 + %1 = xor i16 %a, 1 + ret i16 %1 +} diff --git a/test/CodeGen/MSP430/Inst8ri.ll b/test/CodeGen/MSP430/Inst8ri.ll new file mode 100644 index 0000000..ac3418a --- /dev/null +++ b/test/CodeGen/MSP430/Inst8ri.ll @@ -0,0 +1,37 @@ +; RUN: llc -march=msp430 < %s | FileCheck %s +target datalayout = "e-p:16:8:8-i8:8:8-i16:8:8-i32:8:8" +target triple = "msp430-generic-generic" + +define i8 @mov() nounwind { +; CHECK: mov: +; CHECK: mov.b #1, r15 + ret i8 1 +} + +define i8 @add(i8 %a, i8 %b) nounwind { +; CHECK: add: +; CHECK: add.b #1, r15 + %1 = add i8 %a, 1 + ret i8 %1 +} + +define i8 @and(i8 %a, i8 %b) nounwind { +; CHECK: and: +; CHECK: and.b #1, r15 + %1 = and i8 %a, 1 + ret i8 %1 +} + +define i8 @bis(i8 %a, i8 %b) nounwind { +; CHECK: bis: +; CHECK: bis.b #1, r15 + %1 = or i8 %a, 1 + ret i8 %1 +} + +define i8 @xor(i8 %a, i8 %b) nounwind { +; CHECK: xor: +; CHECK: xor.b #1, r15 + %1 = xor i8 %a, 1 + ret i8 %1 +} diff --git a/test/CodeGen/PIC16/globals.ll b/test/CodeGen/PIC16/globals.ll index 959eb25..b8c9116 100644 --- a/test/CodeGen/PIC16/globals.ll +++ b/test/CodeGen/PIC16/globals.ll @@ -1,15 +1,15 @@ ; RUN: llc < %s -march=pic16 | FileCheck %s @G1 = global i32 4712, section "Address=412" -; CHECK: @G1.412.idata.0.# IDATA 412 +; CHECK: @G1.412..user_section.# IDATA 412 ; CHECK: @G1 dl 4712 @G2 = global i32 0, section "Address=412" -; CHECK: @G2.412.udata.0.# UDATA 412 +; CHECK: @G2.412..user_section.# UDATA 412 ; CHECK: @G2 RES 4 @G3 = addrspace(1) constant i32 4712, section "Address=412" -; CHECK: @G3.412.romdata.1.# ROMDATA 412 +; CHECK: @G3.412..user_section.# ROMDATA 412 ; CHECK: @G3 rom_dl 4712 diff --git a/test/CodeGen/Thumb/2009-08-20-ISelBug.ll b/test/CodeGen/Thumb/2009-08-20-ISelBug.ll index 1627f61..c31b65b 100644 --- a/test/CodeGen/Thumb/2009-08-20-ISelBug.ll +++ b/test/CodeGen/Thumb/2009-08-20-ISelBug.ll @@ -11,7 +11,7 @@ define arm_apcscc i32 @t(%struct.asl_file_t* %s, i64 %off, i64* %out) nounwind optsize { ; CHECK: t: -; CHECK: adds r4, #8 +; CHECK: adds r3, #8 entry: %val = alloca i64, align 4 ; <i64*> [#uses=3] %0 = icmp eq %struct.asl_file_t* %s, null ; <i1> [#uses=1] diff --git a/test/CodeGen/Thumb2/2009-10-15-ITBlockBranch.ll b/test/CodeGen/Thumb2/2009-10-15-ITBlockBranch.ll new file mode 100644 index 0000000..b4b6ed9 --- /dev/null +++ b/test/CodeGen/Thumb2/2009-10-15-ITBlockBranch.ll @@ -0,0 +1,44 @@ +; RUN: llc < %s -mtriple=thumbv7-eabi -mcpu=cortex-a8 -float-abi=hard | FileCheck %s + +; A fix for PR5204 will require this check to be changed. + +%"struct.__gnu_cxx::__normal_iterator<char*,std::basic_string<char, std::char_traits<char>, std::allocator<char> > >" = type { i8* } +%"struct.__gnu_cxx::new_allocator<char>" = type <{ i8 }> +%"struct.std::basic_string<char,std::char_traits<char>,std::allocator<char> >" = type { %"struct.__gnu_cxx::__normal_iterator<char*,std::basic_string<char, std::char_traits<char>, std::allocator<char> > >" } +%"struct.std::basic_string<char,std::char_traits<char>,std::allocator<char> >::_Rep" = type { %"struct.std::basic_string<char,std::char_traits<char>,std::allocator<char> >::_Rep_base" } +%"struct.std::basic_string<char,std::char_traits<char>,std::allocator<char> >::_Rep_base" = type { i32, i32, i32 } + + +define weak arm_aapcs_vfpcc i32 @_ZNKSs7compareERKSs(%"struct.std::basic_string<char,std::char_traits<char>,std::allocator<char> >"* %this, %"struct.std::basic_string<char,std::char_traits<char>,std::allocator<char> >"* %__str) { +; CHECK: _ZNKSs7compareERKSs: +; CHECK: it ne +; CHECK-NEXT: ldmfdne.w +; CHECK-NEXT: itt eq +; CHECK-NEXT: subeq.w +; CHECK-NEXT: ldmfdeq.w +entry: + %0 = tail call arm_aapcs_vfpcc i32 @_ZNKSs4sizeEv(%"struct.std::basic_string<char,std::char_traits<char>,std::allocator<char> >"* %this) ; <i32> [#uses=3] + %1 = tail call arm_aapcs_vfpcc i32 @_ZNKSs4sizeEv(%"struct.std::basic_string<char,std::char_traits<char>,std::allocator<char> >"* %__str) ; <i32> [#uses=3] + %2 = icmp ult i32 %1, %0 ; <i1> [#uses=1] + %3 = select i1 %2, i32 %1, i32 %0 ; <i32> [#uses=1] + %4 = tail call arm_aapcs_vfpcc i8* @_ZNKSs7_M_dataEv(%"struct.std::basic_string<char,std::char_traits<char>,std::allocator<char> >"* %this) ; <i8*> [#uses=1] + %5 = tail call arm_aapcs_vfpcc i8* @_ZNKSs4dataEv(%"struct.std::basic_string<char,std::char_traits<char>,std::allocator<char> >"* %__str) ; <i8*> [#uses=1] + %6 = tail call arm_aapcs_vfpcc i32 @memcmp(i8* %4, i8* %5, i32 %3) nounwind readonly ; <i32> [#uses=2] + %7 = icmp eq i32 %6, 0 ; <i1> [#uses=1] + br i1 %7, label %bb, label %bb1 + +bb: ; preds = %entry + %8 = sub i32 %0, %1 ; <i32> [#uses=1] + ret i32 %8 + +bb1: ; preds = %entry + ret i32 %6 +} + +declare arm_aapcs_vfpcc i32 @memcmp(i8* nocapture, i8* nocapture, i32) nounwind readonly + +declare arm_aapcs_vfpcc i32 @_ZNKSs4sizeEv(%"struct.std::basic_string<char,std::char_traits<char>,std::allocator<char> >"* %this) + +declare arm_aapcs_vfpcc i8* @_ZNKSs7_M_dataEv(%"struct.std::basic_string<char,std::char_traits<char>,std::allocator<char> >"* %this) + +declare arm_aapcs_vfpcc i8* @_ZNKSs4dataEv(%"struct.std::basic_string<char,std::char_traits<char>,std::allocator<char> >"* %this) diff --git a/test/CodeGen/Thumb2/thumb2-mov.ll b/test/CodeGen/Thumb2/thumb2-mov.ll index e9fdec8..8606e32 100644 --- a/test/CodeGen/Thumb2/thumb2-mov.ll +++ b/test/CodeGen/Thumb2/thumb2-mov.ll @@ -10,29 +10,32 @@ define i32 @t2_const_var2_1_ok_1(i32 %lhs) { ret i32 %ret } -define i32 @t2_const_var2_1_fail_1(i32 %lhs) { -;CHECK: t2_const_var2_1_fail_1: -;CHECK: movt +define i32 @t2_const_var2_1_ok_2(i32 %lhs) { +;CHECK: t2_const_var2_1_ok_2: +;CHECK: #11206656 +;CHECK: #187 %ret = add i32 %lhs, 11206843 ; 0x00ab00bb ret i32 %ret } -define i32 @t2_const_var2_1_fail_2(i32 %lhs) { -;CHECK: t2_const_var2_1_fail_2: -;CHECK: movt +define i32 @t2_const_var2_1_ok_3(i32 %lhs) { +;CHECK: t2_const_var2_1_ok_3: +;CHECK: #11206827 +;CHECK: #16777216 %ret = add i32 %lhs, 27984043 ; 0x01ab00ab ret i32 %ret } -define i32 @t2_const_var2_1_fail_3(i32 %lhs) { -;CHECK: t2_const_var2_1_fail_3: -;CHECK: movt +define i32 @t2_const_var2_1_ok_4(i32 %lhs) { +;CHECK: t2_const_var2_1_ok_4: +;CHECK: #16777472 +;CHECK: #11206827 %ret = add i32 %lhs, 27984299 ; 0x01ab01ab ret i32 %ret } -define i32 @t2_const_var2_1_fail_4(i32 %lhs) { -;CHECK: t2_const_var2_1_fail_4: +define i32 @t2_const_var2_1_fail_1(i32 %lhs) { +;CHECK: t2_const_var2_1_fail_1: ;CHECK: movt %ret = add i32 %lhs, 28027649 ; 0x01abab01 ret i32 %ret @@ -46,29 +49,31 @@ define i32 @t2_const_var2_2_ok_1(i32 %lhs) { ret i32 %ret } -define i32 @t2_const_var2_2_fail_1(i32 %lhs) { -;CHECK: t2_const_var2_2_fail_1: -;CHECK: movt +define i32 @t2_const_var2_2_ok_2(i32 %lhs) { +;CHECK: t2_const_var2_2_ok_2: +;CHECK: #-1426063360 +;CHECK: #47616 %ret = add i32 %lhs, 2868951552 ; 0xab00ba00 ret i32 %ret } -define i32 @t2_const_var2_2_fail_2(i32 %lhs) { -;CHECK: t2_const_var2_2_fail_2: -;CHECK: movt +define i32 @t2_const_var2_2_ok_3(i32 %lhs) { +;CHECK: t2_const_var2_2_ok_3: +;CHECK: #-1426019584 %ret = add i32 %lhs, 2868947728 ; 0xab00ab10 ret i32 %ret } -define i32 @t2_const_var2_2_fail_3(i32 %lhs) { -;CHECK: t2_const_var2_2_fail_3: -;CHECK: movt +define i32 @t2_const_var2_2_ok_4(i32 %lhs) { +;CHECK: t2_const_var2_2_ok_4: +;CHECK: #-1426019584 +;CHECK: #1048592 %ret = add i32 %lhs, 2869996304 ; 0xab10ab10 ret i32 %ret } -define i32 @t2_const_var2_2_fail_4(i32 %lhs) { -;CHECK: t2_const_var2_2_fail_4: +define i32 @t2_const_var2_2_fail_1(i32 %lhs) { +;CHECK: t2_const_var2_2_fail_1: ;CHECK: movt %ret = add i32 %lhs, 279685904 ; 0x10abab10 ret i32 %ret @@ -125,9 +130,10 @@ define i32 @t2_const_var3_2_ok_1(i32 %lhs) { ret i32 %ret } -define i32 @t2_const_var3_2_fail_1(i32 %lhs) { -;CHECK: t2_const_var3_2_fail_1: -;CHECK: movt +define i32 @t2_const_var3_2_ok_2(i32 %lhs) { +;CHECK: t2_const_var3_2_ok_2: +;CHECK: #2097152 +;CHECK: #1843200 %ret = add i32 %lhs, 3940352 ; 0b00000000001111000010000000000000 ret i32 %ret } diff --git a/test/CodeGen/Thumb2/thumb2-mov2.ll b/test/CodeGen/Thumb2/thumb2-mov2.ll index a02f4f0..64e2ddc 100644 --- a/test/CodeGen/Thumb2/thumb2-mov2.ll +++ b/test/CodeGen/Thumb2/thumb2-mov2.ll @@ -2,10 +2,7 @@ define i32 @t2MOVTi16_ok_1(i32 %a) { ; CHECK: t2MOVTi16_ok_1: -; CHECK: movs r1, #0 -; CHECK-NEXT: movt r1, #1234 -; CHECK: movw r1, #65535 -; CHECK-NEXT: movt r1, #1234 +; CHECK: movt r0, #1234 %1 = and i32 %a, 65535 %2 = shl i32 1234, 16 %3 = or i32 %1, %2 @@ -15,10 +12,7 @@ define i32 @t2MOVTi16_ok_1(i32 %a) { define i32 @t2MOVTi16_test_1(i32 %a) { ; CHECK: t2MOVTi16_test_1: -; CHECK: movs r1, #0 -; CHECK-NEXT: movt r1, #1234 -; CHECK: movw r1, #65535 -; CHECK-NEXT: movt r1, #1234 +; CHECK: movt r0, #1234 %1 = shl i32 255, 8 %2 = shl i32 1234, 8 %3 = or i32 %1, 255 ; This give us 0xFFFF in %3 @@ -31,10 +25,7 @@ define i32 @t2MOVTi16_test_1(i32 %a) { define i32 @t2MOVTi16_test_2(i32 %a) { ; CHECK: t2MOVTi16_test_2: -; CHECK: movs r1, #0 -; CHECK-NEXT: movt r1, #1234 -; CHECK: movw r1, #65535 -; CHECK-NEXT: movt r1, #1234 +; CHECK: movt r0, #1234 %1 = shl i32 255, 8 %2 = shl i32 1234, 8 %3 = or i32 %1, 255 ; This give us 0xFFFF in %3 @@ -48,10 +39,7 @@ define i32 @t2MOVTi16_test_2(i32 %a) { define i32 @t2MOVTi16_test_3(i32 %a) { ; CHECK: t2MOVTi16_test_3: -; CHECK: movs r1, #0 -; CHECK-NEXT: movt r1, #1234 -; CHECK: movw r1, #65535 -; CHECK-NEXT: movt r1, #1234 +; CHECK: movt r0, #1234 %1 = shl i32 255, 8 %2 = shl i32 1234, 8 %3 = or i32 %1, 255 ; This give us 0xFFFF in %3 @@ -67,10 +55,10 @@ define i32 @t2MOVTi16_test_3(i32 %a) { define i32 @t2MOVTi16_test_nomatch_1(i32 %a) { ; CHECK: t2MOVTi16_test_nomatch_1: -; CHECK: movw r1, #16384 -; CHECK-NEXT: movt r1, #154 +; CHECK: #8388608 ; CHECK: movw r1, #65535 ; CHECK-NEXT: movt r1, #154 +; CHECK: #1720320 %1 = shl i32 255, 8 %2 = shl i32 1234, 8 %3 = or i32 %1, 255 ; This give us 0xFFFF in %3 diff --git a/test/CodeGen/X86/2007-01-08-InstrSched.ll b/test/CodeGen/X86/2007-01-08-InstrSched.ll index e1bae32..81f0a1d 100644 --- a/test/CodeGen/X86/2007-01-08-InstrSched.ll +++ b/test/CodeGen/X86/2007-01-08-InstrSched.ll @@ -11,9 +11,12 @@ define float @foo(float %x) nounwind { %tmp14 = fadd float %tmp12, %tmp7 ret float %tmp14 -; CHECK: mulss LCPI1_2(%rip) +; CHECK: mulss LCPI1_3(%rip) +; CHECK-NEXT: mulss LCPI1_0(%rip) +; CHECK-NEXT: mulss LCPI1_1(%rip) +; CHECK-NEXT: mulss LCPI1_2(%rip) +; CHECK-NEXT: addss ; CHECK-NEXT: addss -; CHECK-NEXT: mulss LCPI1_3(%rip) ; CHECK-NEXT: addss ; CHECK-NEXT: ret } diff --git a/test/CodeGen/X86/2008-07-11-SpillerBug.ll b/test/CodeGen/X86/2008-07-11-SpillerBug.ll index f75e605..88a5fde 100644 --- a/test/CodeGen/X86/2008-07-11-SpillerBug.ll +++ b/test/CodeGen/X86/2008-07-11-SpillerBug.ll @@ -1,4 +1,4 @@ -; RUN: llc < %s -march=x86 -relocation-model=static -disable-fp-elim | FileCheck %s +; RUN: llc < %s -march=x86 -relocation-model=static -disable-fp-elim -post-RA-scheduler=false | FileCheck %s ; PR2536 diff --git a/test/CodeGen/X86/2009-04-20-LinearScanOpt.ll b/test/CodeGen/X86/2009-04-20-LinearScanOpt.ll index 4d25b0f..d7b9463 100644 --- a/test/CodeGen/X86/2009-04-20-LinearScanOpt.ll +++ b/test/CodeGen/X86/2009-04-20-LinearScanOpt.ll @@ -1,4 +1,4 @@ -; RUN: llc < %s -mtriple=x86_64-apple-darwin10.0 -relocation-model=pic -disable-fp-elim -stats |& grep asm-printer | grep 84 +; RUN: llc < %s -mtriple=x86_64-apple-darwin10.0 -relocation-model=pic -disable-fp-elim -stats |& grep asm-printer | grep 83 ; rdar://6802189 ; Test if linearscan is unfavoring registers for allocation to allow more reuse diff --git a/test/CodeGen/X86/2009-04-21-NoReloadImpDef.ll b/test/CodeGen/X86/2009-04-21-NoReloadImpDef.ll index c6e6e50..5bd956a 100644 --- a/test/CodeGen/X86/2009-04-21-NoReloadImpDef.ll +++ b/test/CodeGen/X86/2009-04-21-NoReloadImpDef.ll @@ -1,5 +1,5 @@ ; RUN: llc -mtriple=i386-apple-darwin10.0 -relocation-model=pic \ -; RUN: -disable-fp-elim -mattr=-sse41,-sse3,+sse2 < %s | \ +; RUN: -disable-fp-elim -mattr=-sse41,-sse3,+sse2 -post-RA-scheduler=false < %s | \ ; RUN: FileCheck %s ; rdar://6808032 diff --git a/test/CodeGen/X86/2009-09-19-SchedCustomLoweringBug.ll b/test/CodeGen/X86/2009-09-19-SchedCustomLoweringBug.ll index 646806e..f3cf1d5 100644 --- a/test/CodeGen/X86/2009-09-19-SchedCustomLoweringBug.ll +++ b/test/CodeGen/X86/2009-09-19-SchedCustomLoweringBug.ll @@ -9,9 +9,7 @@ entry: br label %bb bb: ; preds = %bb1, %entry -; CHECK: movl %e -; CHECK-NEXT: addl $1 -; CHECK-NEXT: movl %e +; CHECK: addl $1 ; CHECK-NEXT: adcl $0 %i.0 = phi i64 [ 0, %entry ], [ %0, %bb1 ] ; <i64> [#uses=1] %0 = add nsw i64 %i.0, 1 ; <i64> [#uses=2] diff --git a/test/CodeGen/X86/2009-10-14-LiveVariablesBug.ll b/test/CodeGen/X86/2009-10-14-LiveVariablesBug.ll new file mode 100644 index 0000000..c1aa17c --- /dev/null +++ b/test/CodeGen/X86/2009-10-14-LiveVariablesBug.ll @@ -0,0 +1,15 @@ +; RUN: llc < %s -mtriple=i386-apple-darwin +; rdar://7299435 + +@i = internal global i32 0 ; <i32*> [#uses=1] +@llvm.used = appending global [1 x i8*] [i8* bitcast (void (i16)* @foo to i8*)], section "llvm.metadata" ; <[1 x i8*]*> [#uses=0] + +define void @foo(i16 signext %source) nounwind ssp { +entry: + %source_addr = alloca i16, align 2 ; <i16*> [#uses=2] + store i16 %source, i16* %source_addr + store i32 4, i32* @i, align 4 + call void asm sideeffect "# top of block", "~{dirflag},~{fpsr},~{flags},~{edi},~{esi},~{edx},~{ecx},~{eax}"() nounwind + %asmtmp = call i16 asm sideeffect "movw $1, $0", "=={ax},*m,~{dirflag},~{fpsr},~{flags},~{memory}"(i16* %source_addr) nounwind ; <i16> [#uses=0] + ret void +} diff --git a/test/CodeGen/X86/2009-10-19-EmergencySpill.ll b/test/CodeGen/X86/2009-10-19-EmergencySpill.ll new file mode 100644 index 0000000..ba44a2e --- /dev/null +++ b/test/CodeGen/X86/2009-10-19-EmergencySpill.ll @@ -0,0 +1,54 @@ +; RUN: llc < %s -mtriple=x86_64-apple-darwin10 -disable-fp-elim +; rdar://7291624 + +%union.RtreeCoord = type { float } +%struct.RtreeCell = type { i64, [10 x %union.RtreeCoord] } +%struct.Rtree = type { i32, i32*, i32, i32, i32, i32, i8*, i8* } +%struct.RtreeNode = type { i32*, i64, i32, i32, i8*, i32* } + +define fastcc void @nodeOverwriteCell(%struct.Rtree* nocapture %pRtree, %struct.RtreeNode* nocapture %pNode, %struct.RtreeCell* nocapture %pCell, i32 %iCell) nounwind ssp { +entry: + %0 = load i8** undef, align 8 ; <i8*> [#uses=2] + %1 = load i32* undef, align 8 ; <i32> [#uses=1] + %2 = mul i32 %1, %iCell ; <i32> [#uses=1] + %3 = add nsw i32 %2, 4 ; <i32> [#uses=1] + %4 = sext i32 %3 to i64 ; <i64> [#uses=2] + %5 = load i64* null, align 8 ; <i64> [#uses=2] + %6 = lshr i64 %5, 48 ; <i64> [#uses=1] + %7 = trunc i64 %6 to i8 ; <i8> [#uses=1] + store i8 %7, i8* undef, align 1 + %8 = lshr i64 %5, 8 ; <i64> [#uses=1] + %9 = trunc i64 %8 to i8 ; <i8> [#uses=1] + %.sum4 = add i64 %4, 6 ; <i64> [#uses=1] + %10 = getelementptr inbounds i8* %0, i64 %.sum4 ; <i8*> [#uses=1] + store i8 %9, i8* %10, align 1 + %11 = getelementptr inbounds %struct.Rtree* %pRtree, i64 0, i32 3 ; <i32*> [#uses=1] + br i1 undef, label %bb.nph, label %bb2 + +bb.nph: ; preds = %entry + %tmp25 = add i64 %4, 11 ; <i64> [#uses=1] + br label %bb + +bb: ; preds = %bb, %bb.nph + %indvar = phi i64 [ 0, %bb.nph ], [ %indvar.next, %bb ] ; <i64> [#uses=3] + %scevgep = getelementptr %struct.RtreeCell* %pCell, i64 0, i32 1, i64 %indvar ; <%union.RtreeCoord*> [#uses=1] + %scevgep12 = bitcast %union.RtreeCoord* %scevgep to i32* ; <i32*> [#uses=1] + %tmp = shl i64 %indvar, 2 ; <i64> [#uses=1] + %tmp26 = add i64 %tmp, %tmp25 ; <i64> [#uses=1] + %scevgep27 = getelementptr i8* %0, i64 %tmp26 ; <i8*> [#uses=1] + %12 = load i32* %scevgep12, align 4 ; <i32> [#uses=1] + %13 = lshr i32 %12, 24 ; <i32> [#uses=1] + %14 = trunc i32 %13 to i8 ; <i8> [#uses=1] + store i8 %14, i8* undef, align 1 + store i8 undef, i8* %scevgep27, align 1 + %15 = load i32* %11, align 4 ; <i32> [#uses=1] + %16 = shl i32 %15, 1 ; <i32> [#uses=1] + %17 = icmp sgt i32 %16, undef ; <i1> [#uses=1] + %indvar.next = add i64 %indvar, 1 ; <i64> [#uses=1] + br i1 %17, label %bb, label %bb2 + +bb2: ; preds = %bb, %entry + %18 = getelementptr inbounds %struct.RtreeNode* %pNode, i64 0, i32 3 ; <i32*> [#uses=1] + store i32 1, i32* %18, align 4 + ret void +} diff --git a/test/CodeGen/X86/2009-10-19-atomic-cmp-eflags.ll b/test/CodeGen/X86/2009-10-19-atomic-cmp-eflags.ll new file mode 100644 index 0000000..d7f0c1a --- /dev/null +++ b/test/CodeGen/X86/2009-10-19-atomic-cmp-eflags.ll @@ -0,0 +1,69 @@ +; RUN: llvm-as <%s | llc | FileCheck %s +; PR 5247 +; check that cmp is not scheduled before the add +target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128" +target triple = "x86_64-unknown-linux-gnu" + +@.str76843 = external constant [45 x i8] ; <[45 x i8]*> [#uses=1] +@__profiling_callsite_timestamps_live = external global [1216 x i64] ; <[1216 x i64]*> [#uses=2] + +define i32 @cl_init(i32 %initoptions) nounwind { +entry: + %retval.i = alloca i32 ; <i32*> [#uses=3] + %retval = alloca i32 ; <i32*> [#uses=2] + %initoptions.addr = alloca i32 ; <i32*> [#uses=2] + tail call void asm sideeffect "cpuid", "~{ax},~{bx},~{cx},~{dx},~{memory},~{dirflag},~{fpsr},~{flags}"() nounwind + %0 = tail call i64 @llvm.readcyclecounter() nounwind ; <i64> [#uses=1] + store i32 %initoptions, i32* %initoptions.addr + %1 = bitcast i32* %initoptions.addr to { }* ; <{ }*> [#uses=0] + call void asm sideeffect "cpuid", "~{ax},~{bx},~{cx},~{dx},~{memory},~{dirflag},~{fpsr},~{flags}"() nounwind + %2 = call i64 @llvm.readcyclecounter() nounwind ; <i64> [#uses=1] + %call.i = call i32 @lt_dlinit() nounwind ; <i32> [#uses=1] + %tobool.i = icmp ne i32 %call.i, 0 ; <i1> [#uses=1] + br i1 %tobool.i, label %if.then.i, label %if.end.i + +if.then.i: ; preds = %entry + %call1.i = call i32 @warn_dlerror(i8* getelementptr inbounds ([45 x i8]* @.str76843, i32 0, i32 0)) nounwind ; <i32> [#uses=0] + store i32 -1, i32* %retval.i + br label %lt_init.exit + +if.end.i: ; preds = %entry + store i32 0, i32* %retval.i + br label %lt_init.exit + +lt_init.exit: ; preds = %if.end.i, %if.then.i + %3 = load i32* %retval.i ; <i32> [#uses=1] + call void asm sideeffect "cpuid", "~{ax},~{bx},~{cx},~{dx},~{memory},~{dirflag},~{fpsr},~{flags}"() nounwind + %4 = call i64 @llvm.readcyclecounter() nounwind ; <i64> [#uses=1] + %5 = sub i64 %4, %2 ; <i64> [#uses=1] + %6 = call i64 @llvm.atomic.load.add.i64.p0i64(i64* getelementptr inbounds ([1216 x i64]* @__profiling_callsite_timestamps_live, i32 0, i32 51), i64 %5) nounwind ; <i64> [#uses=0] +;CHECK: lock +;CHECK-NEXT: {{xadd|addq}} %rdx, __profiling_callsite_timestamps_live +;CHECK-NEXT: cmpl $0, +;CHECK-NEXT: jne + %cmp = icmp eq i32 %3, 0 ; <i1> [#uses=1] + br i1 %cmp, label %if.then, label %if.end + +if.then: ; preds = %lt_init.exit + call void @cli_rarload() + br label %if.end + +if.end: ; preds = %if.then, %lt_init.exit + store i32 0, i32* %retval + %7 = load i32* %retval ; <i32> [#uses=1] + tail call void asm sideeffect "cpuid", "~{ax},~{bx},~{cx},~{dx},~{memory},~{dirflag},~{fpsr},~{flags}"() nounwind + %8 = tail call i64 @llvm.readcyclecounter() nounwind ; <i64> [#uses=1] + %9 = sub i64 %8, %0 ; <i64> [#uses=1] + %10 = call i64 @llvm.atomic.load.add.i64.p0i64(i64* getelementptr inbounds ([1216 x i64]* @__profiling_callsite_timestamps_live, i32 0, i32 50), i64 %9) ; <i64> [#uses=0] + ret i32 %7 +} + +declare void @cli_rarload() nounwind + +declare i32 @lt_dlinit() + +declare i32 @warn_dlerror(i8*) nounwind + +declare i64 @llvm.atomic.load.add.i64.p0i64(i64* nocapture, i64) nounwind + +declare i64 @llvm.readcyclecounter() nounwind diff --git a/test/CodeGen/X86/abi-isel.ll b/test/CodeGen/X86/abi-isel.ll index a6fd2d8..6d7b2d4 100644 --- a/test/CodeGen/X86/abi-isel.ll +++ b/test/CodeGen/X86/abi-isel.ll @@ -1,16 +1,16 @@ -; RUN: llc < %s -asm-verbose=0 -mtriple=i686-unknown-linux-gnu -march=x86 -relocation-model=static -code-model=small | FileCheck %s -check-prefix=LINUX-32-STATIC -; RUN: llc < %s -asm-verbose=0 -mtriple=i686-unknown-linux-gnu -march=x86 -relocation-model=static -code-model=small | FileCheck %s -check-prefix=LINUX-32-PIC +; RUN: llc < %s -asm-verbose=0 -mtriple=i686-unknown-linux-gnu -march=x86 -relocation-model=static -code-model=small -post-RA-scheduler=false | FileCheck %s -check-prefix=LINUX-32-STATIC +; RUN: llc < %s -asm-verbose=0 -mtriple=i686-unknown-linux-gnu -march=x86 -relocation-model=static -code-model=small -post-RA-scheduler=false | FileCheck %s -check-prefix=LINUX-32-PIC -; RUN: llc < %s -asm-verbose=0 -mtriple=x86_64-unknown-linux-gnu -march=x86-64 -relocation-model=static -code-model=small | FileCheck %s -check-prefix=LINUX-64-STATIC -; RUN: llc < %s -asm-verbose=0 -mtriple=x86_64-unknown-linux-gnu -march=x86-64 -relocation-model=pic -code-model=small | FileCheck %s -check-prefix=LINUX-64-PIC +; RUN: llc < %s -asm-verbose=0 -mtriple=x86_64-unknown-linux-gnu -march=x86-64 -relocation-model=static -code-model=small -post-RA-scheduler=false | FileCheck %s -check-prefix=LINUX-64-STATIC +; RUN: llc < %s -asm-verbose=0 -mtriple=x86_64-unknown-linux-gnu -march=x86-64 -relocation-model=pic -code-model=small -post-RA-scheduler=false | FileCheck %s -check-prefix=LINUX-64-PIC -; RUN: llc < %s -asm-verbose=0 -mtriple=i686-apple-darwin -march=x86 -relocation-model=static -code-model=small | FileCheck %s -check-prefix=DARWIN-32-STATIC -; RUN: llc < %s -asm-verbose=0 -mtriple=i686-apple-darwin -march=x86 -relocation-model=dynamic-no-pic -code-model=small | FileCheck %s -check-prefix=DARWIN-32-DYNAMIC -; RUN: llc < %s -asm-verbose=0 -mtriple=i686-apple-darwin -march=x86 -relocation-model=pic -code-model=small | FileCheck %s -check-prefix=DARWIN-32-PIC +; RUN: llc < %s -asm-verbose=0 -mtriple=i686-apple-darwin -march=x86 -relocation-model=static -code-model=small -post-RA-scheduler=false | FileCheck %s -check-prefix=DARWIN-32-STATIC +; RUN: llc < %s -asm-verbose=0 -mtriple=i686-apple-darwin -march=x86 -relocation-model=dynamic-no-pic -code-model=small -post-RA-scheduler=false | FileCheck %s -check-prefix=DARWIN-32-DYNAMIC +; RUN: llc < %s -asm-verbose=0 -mtriple=i686-apple-darwin -march=x86 -relocation-model=pic -code-model=small -post-RA-scheduler=false | FileCheck %s -check-prefix=DARWIN-32-PIC -; RUN: llc < %s -asm-verbose=0 -mtriple=x86_64-apple-darwin -march=x86-64 -relocation-model=static -code-model=small | FileCheck %s -check-prefix=DARWIN-64-STATIC -; RUN: llc < %s -asm-verbose=0 -mtriple=x86_64-apple-darwin -march=x86-64 -relocation-model=dynamic-no-pic -code-model=small | FileCheck %s -check-prefix=DARWIN-64-DYNAMIC -; RUN: llc < %s -asm-verbose=0 -mtriple=x86_64-apple-darwin -march=x86-64 -relocation-model=pic -code-model=small | FileCheck %s -check-prefix=DARWIN-64-PIC +; RUN: llc < %s -asm-verbose=0 -mtriple=x86_64-apple-darwin -march=x86-64 -relocation-model=static -code-model=small -post-RA-scheduler=false | FileCheck %s -check-prefix=DARWIN-64-STATIC +; RUN: llc < %s -asm-verbose=0 -mtriple=x86_64-apple-darwin -march=x86-64 -relocation-model=dynamic-no-pic -code-model=small -post-RA-scheduler=false | FileCheck %s -check-prefix=DARWIN-64-DYNAMIC +; RUN: llc < %s -asm-verbose=0 -mtriple=x86_64-apple-darwin -march=x86-64 -relocation-model=pic -code-model=small -post-RA-scheduler=false | FileCheck %s -check-prefix=DARWIN-64-PIC @src = external global [131072 x i32] @dst = external global [131072 x i32] diff --git a/test/CodeGen/X86/codegen-prepare-extload.ll b/test/CodeGen/X86/codegen-prepare-extload.ll new file mode 100644 index 0000000..9f57d53 --- /dev/null +++ b/test/CodeGen/X86/codegen-prepare-extload.ll @@ -0,0 +1,20 @@ +; RUN: llc < %s -march=x86-64 | FileCheck %s +; rdar://7304838 + +; CodeGenPrepare should move the zext into the block with the load +; so that SelectionDAG can select it with the load. + +; CHECK: movzbl (%rdi), %eax + +define void @foo(i8* %p, i32* %q) { +entry: + %t = load i8* %p + %a = icmp slt i8 %t, 20 + br i1 %a, label %true, label %false +true: + %s = zext i8 %t to i32 + store i32 %s, i32* %q + ret void +false: + ret void +} diff --git a/test/CodeGen/X86/discontiguous-loops.ll b/test/CodeGen/X86/discontiguous-loops.ll new file mode 100644 index 0000000..479c450 --- /dev/null +++ b/test/CodeGen/X86/discontiguous-loops.ll @@ -0,0 +1,72 @@ +; RUN: llc -verify-loop-info -verify-dom-info -march=x86-64 < %s +; PR5243 + +@.str96 = external constant [37 x i8], align 8 ; <[37 x i8]*> [#uses=1] + +define void @foo() nounwind { +bb: + br label %ybb1 + +ybb1: ; preds = %yybb13, %xbb6, %bb + switch i32 undef, label %bb18 [ + i32 150, label %ybb2 + i32 151, label %bb17 + i32 152, label %bb19 + i32 157, label %ybb8 + ] + +ybb2: ; preds = %ybb1 + %tmp = icmp eq i8** undef, null ; <i1> [#uses=1] + br i1 %tmp, label %bb3, label %xbb6 + +bb3: ; preds = %ybb2 + unreachable + +xbb4: ; preds = %xbb6 + store i32 0, i32* undef, align 8 + br i1 undef, label %xbb6, label %bb5 + +bb5: ; preds = %xbb4 + call fastcc void @decl_mode_check_failed() nounwind + unreachable + +xbb6: ; preds = %xbb4, %ybb2 + %tmp7 = icmp slt i32 undef, 0 ; <i1> [#uses=1] + br i1 %tmp7, label %xbb4, label %ybb1 + +ybb8: ; preds = %ybb1 + %tmp9 = icmp eq i8** undef, null ; <i1> [#uses=1] + br i1 %tmp9, label %bb10, label %ybb12 + +bb10: ; preds = %ybb8 + %tmp11 = load i8** undef, align 8 ; <i8*> [#uses=1] + call void (i8*, ...)* @fatal(i8* getelementptr inbounds ([37 x i8]* @.str96, i64 0, i64 0), i8* %tmp11) nounwind + unreachable + +ybb12: ; preds = %ybb8 + br i1 undef, label %bb15, label %ybb13 + +ybb13: ; preds = %ybb12 + %tmp14 = icmp sgt i32 undef, 0 ; <i1> [#uses=1] + br i1 %tmp14, label %bb16, label %ybb1 + +bb15: ; preds = %ybb12 + call void (i8*, ...)* @fatal(i8* getelementptr inbounds ([37 x i8]* @.str96, i64 0, i64 0), i8* undef) nounwind + unreachable + +bb16: ; preds = %ybb13 + unreachable + +bb17: ; preds = %ybb1 + unreachable + +bb18: ; preds = %ybb1 + unreachable + +bb19: ; preds = %ybb1 + unreachable +} + +declare void @fatal(i8*, ...) + +declare fastcc void @decl_mode_check_failed() nounwind diff --git a/test/CodeGen/X86/fastcc.ll b/test/CodeGen/X86/fastcc.ll index d538264..705ab7b 100644 --- a/test/CodeGen/X86/fastcc.ll +++ b/test/CodeGen/X86/fastcc.ll @@ -1,4 +1,4 @@ -; RUN: llc < %s -mtriple=i686-apple-darwin -mattr=+sse2 | FileCheck %s +; RUN: llc < %s -mtriple=i686-apple-darwin -mattr=+sse2 -post-RA-scheduler=false | FileCheck %s ; CHECK: movsd %xmm0, 8(%esp) ; CHECK: xorl %ecx, %ecx diff --git a/test/CodeGen/X86/legalize-fmp-oeq-vector-select.ll b/test/CodeGen/X86/legalize-fmp-oeq-vector-select.ll new file mode 100644 index 0000000..6a8c154 --- /dev/null +++ b/test/CodeGen/X86/legalize-fmp-oeq-vector-select.ll @@ -0,0 +1,11 @@ +; RUN: llc -march=x86-64 -enable-legalize-types-checking < %s +; PR5092 + +define <4 x float> @bug(float %a) nounwind { +entry: + %cmp = fcmp oeq float %a, 0.000000e+00 ; <i1> [#uses=1] + %temp = select i1 %cmp, <4 x float> <float 1.000000e+00, float 0.000000e+00, +float 0.000000e+00, float 0.000000e+00>, <4 x float> zeroinitializer + ret <4 x float> %temp +} + diff --git a/test/CodeGen/X86/loop-blocks.ll b/test/CodeGen/X86/loop-blocks.ll new file mode 100644 index 0000000..c0379d1 --- /dev/null +++ b/test/CodeGen/X86/loop-blocks.ll @@ -0,0 +1,207 @@ +; RUN: llc < %s -march=x86-64 -mtriple=x86_64-unknown-linux-gnu -asm-verbose=false | FileCheck %s + +; These tests check for loop branching structure, and that the loop align +; directive is placed in the expected place. + +; CodeGen should insert a branch into the middle of the loop in +; order to avoid a branch within the loop. + +; CHECK: simple: +; CHECK: jmp .LBB1_1 +; CHECK-NEXT: align +; CHECK-NEXT: .LBB1_2: +; CHECK-NEXT: call loop_latch +; CHECK-NEXT: .LBB1_1: +; CHECK-NEXT: call loop_header + +define void @simple() nounwind { +entry: + br label %loop + +loop: + call void @loop_header() + %t0 = tail call i32 @get() + %t1 = icmp slt i32 %t0, 0 + br i1 %t1, label %done, label %bb + +bb: + call void @loop_latch() + br label %loop + +done: + call void @exit() + ret void +} + +; CodeGen should move block_a to the top of the loop so that it +; falls through into the loop, avoiding a branch within the loop. + +; CHECK: slightly_more_involved: +; CHECK: jmp .LBB2_1 +; CHECK-NEXT: align +; CHECK-NEXT: .LBB2_4: +; CHECK-NEXT: call bar99 +; CHECK-NEXT: .LBB2_1: +; CHECK-NEXT: call body + +define void @slightly_more_involved() nounwind { +entry: + br label %loop + +loop: + call void @body() + %t0 = call i32 @get() + %t1 = icmp slt i32 %t0, 2 + br i1 %t1, label %block_a, label %bb + +bb: + %t2 = call i32 @get() + %t3 = icmp slt i32 %t2, 99 + br i1 %t3, label %exit, label %loop + +block_a: + call void @bar99() + br label %loop + +exit: + call void @exit() + ret void +} + +; Same as slightly_more_involved, but block_a is now a CFG diamond with +; fallthrough edges which should be preserved. + +; CHECK: yet_more_involved: +; CHECK: jmp .LBB3_1 +; CHECK-NEXT: align +; CHECK-NEXT: .LBB3_3: +; CHECK-NEXT: call bar99 +; CHECK-NEXT: call get +; CHECK-NEXT: cmpl $2999, %eax +; CHECK-NEXT: jg .LBB3_5 +; CHECK-NEXT: call block_a_true_func +; CHECK-NEXT: jmp .LBB3_6 +; CHECK-NEXT: .LBB3_5: +; CHECK-NEXT: call block_a_false_func +; CHECK-NEXT: .LBB3_6: +; CHECK-NEXT: call block_a_merge_func +; CHECK-NEXT: .LBB3_1: +; CHECK-NEXT: call body + +define void @yet_more_involved() nounwind { +entry: + br label %loop + +loop: + call void @body() + %t0 = call i32 @get() + %t1 = icmp slt i32 %t0, 2 + br i1 %t1, label %block_a, label %bb + +bb: + %t2 = call i32 @get() + %t3 = icmp slt i32 %t2, 99 + br i1 %t3, label %exit, label %loop + +block_a: + call void @bar99() + %z0 = call i32 @get() + %z1 = icmp slt i32 %z0, 3000 + br i1 %z1, label %block_a_true, label %block_a_false + +block_a_true: + call void @block_a_true_func() + br label %block_a_merge + +block_a_false: + call void @block_a_false_func() + br label %block_a_merge + +block_a_merge: + call void @block_a_merge_func() + br label %loop + +exit: + call void @exit() + ret void +} + +; CodeGen should move the CFG islands that are part of the loop but don't +; conveniently fit anywhere so that they are at least contiguous with the +; loop. + +; CHECK: cfg_islands: +; CHECK: jmp .LBB4_1 +; CHECK-NEXT: align +; CHECK-NEXT: .LBB4_7: +; CHECK-NEXT: call bar100 +; CHECK-NEXT: jmp .LBB4_1 +; CHECK-NEXT: .LBB4_8: +; CHECK-NEXT: call bar101 +; CHECK-NEXT: jmp .LBB4_1 +; CHECK-NEXT: .LBB4_9: +; CHECK-NEXT: call bar102 +; CHECK-NEXT: jmp .LBB4_1 +; CHECK-NEXT: .LBB4_5: +; CHECK-NEXT: call loop_latch +; CHECK-NEXT: .LBB4_1: +; CHECK-NEXT: call loop_header + +define void @cfg_islands() nounwind { +entry: + br label %loop + +loop: + call void @loop_header() + %t0 = call i32 @get() + %t1 = icmp slt i32 %t0, 100 + br i1 %t1, label %block100, label %bb + +bb: + %t2 = call i32 @get() + %t3 = icmp slt i32 %t2, 101 + br i1 %t3, label %block101, label %bb1 + +bb1: + %t4 = call i32 @get() + %t5 = icmp slt i32 %t4, 102 + br i1 %t5, label %block102, label %bb2 + +bb2: + %t6 = call i32 @get() + %t7 = icmp slt i32 %t6, 103 + br i1 %t7, label %exit, label %bb3 + +bb3: + call void @loop_latch() + br label %loop + +exit: + call void @exit() + ret void + +block100: + call void @bar100() + br label %loop + +block101: + call void @bar101() + br label %loop + +block102: + call void @bar102() + br label %loop +} + +declare void @bar99() nounwind +declare void @bar100() nounwind +declare void @bar101() nounwind +declare void @bar102() nounwind +declare void @body() nounwind +declare void @exit() nounwind +declare void @loop_header() nounwind +declare void @loop_latch() nounwind +declare i32 @get() nounwind +declare void @block_a_true_func() nounwind +declare void @block_a_false_func() nounwind +declare void @block_a_merge_func() nounwind diff --git a/test/CodeGen/X86/palignr.ll b/test/CodeGen/X86/palignr.ll new file mode 100644 index 0000000..3812c72 --- /dev/null +++ b/test/CodeGen/X86/palignr.ll @@ -0,0 +1,58 @@ +; RUN: llc < %s -march=x86 -mcpu=core2 | FileCheck %s +; RUN: llc < %s -march=x86 -mcpu=yonah | FileCheck --check-prefix=YONAH %s + +define <4 x i32> @test1(<4 x i32> %A, <4 x i32> %B) nounwind { +; CHECK: pshufd +; CHECK-YONAH: pshufd + %C = shufflevector <4 x i32> %A, <4 x i32> undef, <4 x i32> < i32 1, i32 2, i32 3, i32 0 > + ret <4 x i32> %C +} + +define <4 x i32> @test2(<4 x i32> %A, <4 x i32> %B) nounwind { +; CHECK: palignr +; CHECK-YONAH: shufps + %C = shufflevector <4 x i32> %A, <4 x i32> %B, <4 x i32> < i32 1, i32 2, i32 3, i32 4 > + ret <4 x i32> %C +} + +define <4 x i32> @test3(<4 x i32> %A, <4 x i32> %B) nounwind { +; CHECK: palignr + %C = shufflevector <4 x i32> %A, <4 x i32> %B, <4 x i32> < i32 1, i32 2, i32 undef, i32 4 > + ret <4 x i32> %C +} + +define <4 x i32> @test4(<4 x i32> %A, <4 x i32> %B) nounwind { +; CHECK: palignr + %C = shufflevector <4 x i32> %A, <4 x i32> %B, <4 x i32> < i32 6, i32 7, i32 undef, i32 1 > + ret <4 x i32> %C +} + +define <4 x float> @test5(<4 x float> %A, <4 x float> %B) nounwind { +; CHECK: palignr + %C = shufflevector <4 x float> %A, <4 x float> %B, <4 x i32> < i32 6, i32 7, i32 undef, i32 1 > + ret <4 x float> %C +} + +define <8 x i16> @test6(<8 x i16> %A, <8 x i16> %B) nounwind { +; CHECK: palignr + %C = shufflevector <8 x i16> %A, <8 x i16> %B, <8 x i32> < i32 3, i32 4, i32 undef, i32 6, i32 7, i32 8, i32 9, i32 10 > + ret <8 x i16> %C +} + +define <8 x i16> @test7(<8 x i16> %A, <8 x i16> %B) nounwind { +; CHECK: palignr + %C = shufflevector <8 x i16> %A, <8 x i16> %B, <8 x i32> < i32 undef, i32 6, i32 undef, i32 8, i32 9, i32 10, i32 11, i32 12 > + ret <8 x i16> %C +} + +define <8 x i16> @test8(<8 x i16> %A, <8 x i16> %B) nounwind { +; CHECK: palignr + %C = shufflevector <8 x i16> %A, <8 x i16> %B, <8 x i32> < i32 undef, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 0 > + ret <8 x i16> %C +} + +define <16 x i8> @test9(<16 x i8> %A, <16 x i8> %B) nounwind { +; CHECK: palignr + %C = shufflevector <16 x i8> %A, <16 x i8> %B, <16 x i32> < i32 5, i32 6, i32 7, i32 undef, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15, i32 16, i32 17, i32 18, i32 19, i32 20 > + ret <16 x i8> %C +} diff --git a/test/CodeGen/X86/peep-test-3.ll b/test/CodeGen/X86/peep-test-3.ll index 13a69ed..5aaf81b 100644 --- a/test/CodeGen/X86/peep-test-3.ll +++ b/test/CodeGen/X86/peep-test-3.ll @@ -1,4 +1,4 @@ -; RUN: llc < %s -march=x86 | FileCheck %s +; RUN: llc < %s -march=x86 -post-RA-scheduler=false | FileCheck %s ; rdar://7226797 ; LLVM should omit the testl and use the flags result from the orl. diff --git a/test/CodeGen/X86/pic.ll b/test/CodeGen/X86/pic.ll index 3a547f9..e886ba0 100644 --- a/test/CodeGen/X86/pic.ll +++ b/test/CodeGen/X86/pic.ll @@ -1,4 +1,4 @@ -; RUN: llc < %s -mtriple=i686-pc-linux-gnu -relocation-model=pic -asm-verbose=false | FileCheck %s -check-prefix=LINUX +; RUN: llc < %s -mtriple=i686-pc-linux-gnu -relocation-model=pic -asm-verbose=false -post-RA-scheduler=false | FileCheck %s -check-prefix=LINUX @ptr = external global i32* @dst = external global i32 diff --git a/test/CodeGen/X86/sink-hoist.ll b/test/CodeGen/X86/sink-hoist.ll index 0f4e63f..4042a09 100644 --- a/test/CodeGen/X86/sink-hoist.ll +++ b/test/CodeGen/X86/sink-hoist.ll @@ -6,10 +6,10 @@ ; that it's conditionally evaluated. ; CHECK: foo: -; CHECK-NEXT: divsd -; CHECK: testb $1, %dil -; CHECK-NEXT: jne ; CHECK: divsd +; CHECK-NEXT: testb $1, %dil +; CHECK-NEXT: jne +; CHECK-NEXT: divsd define double @foo(double %x, double %y, i1 %c) nounwind { %a = fdiv double %x, 3.2 diff --git a/test/CodeGen/X86/sse2.ll b/test/CodeGen/X86/sse2.ll index 9f926f2..58fe28b 100644 --- a/test/CodeGen/X86/sse2.ll +++ b/test/CodeGen/X86/sse2.ll @@ -10,10 +10,10 @@ define void @t1(<2 x double>* %r, <2 x double>* %A, double %B) nounwind { ; CHECK: t1: ; CHECK: movl 8(%esp), %eax +; CHECK-NEXT: movl 4(%esp), %ecx ; CHECK-NEXT: movapd (%eax), %xmm0 ; CHECK-NEXT: movlpd 12(%esp), %xmm0 -; CHECK-NEXT: movl 4(%esp), %eax -; CHECK-NEXT: movapd %xmm0, (%eax) +; CHECK-NEXT: movapd %xmm0, (%ecx) ; CHECK-NEXT: ret } @@ -26,9 +26,9 @@ define void @t2(<2 x double>* %r, <2 x double>* %A, double %B) nounwind { ; CHECK: t2: ; CHECK: movl 8(%esp), %eax +; CHECK-NEXT: movl 4(%esp), %ecx ; CHECK-NEXT: movapd (%eax), %xmm0 ; CHECK-NEXT: movhpd 12(%esp), %xmm0 -; CHECK-NEXT: movl 4(%esp), %eax -; CHECK-NEXT: movapd %xmm0, (%eax) +; CHECK-NEXT: movapd %xmm0, (%ecx) ; CHECK-NEXT: ret } diff --git a/test/CodeGen/X86/sse3.ll b/test/CodeGen/X86/sse3.ll index 703635c..6319cb8 100644 --- a/test/CodeGen/X86/sse3.ll +++ b/test/CodeGen/X86/sse3.ll @@ -17,8 +17,8 @@ entry: ; X64: t0: ; X64: movddup (%rsi), %xmm0 -; X64: pshuflw $0, %xmm0, %xmm0 ; X64: xorl %eax, %eax +; X64: pshuflw $0, %xmm0, %xmm0 ; X64: pinsrw $0, %eax, %xmm0 ; X64: movaps %xmm0, (%rdi) ; X64: ret @@ -167,18 +167,12 @@ define internal void @t10() nounwind { store <4 x i16> %6, <4 x i16>* @g2, align 8 ret void ; X64: t10: -; X64: movq _g1@GOTPCREL(%rip), %rax -; X64: movaps (%rax), %xmm0 ; X64: pextrw $4, %xmm0, %eax -; X64: movaps %xmm0, %xmm1 +; X64: pextrw $6, %xmm0, %edx ; X64: movlhps %xmm1, %xmm1 ; X64: pshuflw $8, %xmm1, %xmm1 ; X64: pinsrw $2, %eax, %xmm1 -; X64: pextrw $6, %xmm0, %eax -; X64: pinsrw $3, %eax, %xmm1 -; X64: movq _g2@GOTPCREL(%rip), %rax -; X64: movq %xmm1, (%rax) -; X64: ret +; X64: pinsrw $3, %edx, %xmm1 } @@ -189,8 +183,8 @@ entry: ret <8 x i16> %tmp7 ; X64: t11: -; X64: movd %xmm1, %eax ; X64: movlhps %xmm0, %xmm0 +; X64: movd %xmm1, %eax ; X64: pshuflw $1, %xmm0, %xmm0 ; X64: pinsrw $1, %eax, %xmm0 ; X64: ret @@ -203,8 +197,8 @@ entry: ret <8 x i16> %tmp9 ; X64: t12: -; X64: pextrw $3, %xmm1, %eax ; X64: movlhps %xmm0, %xmm0 +; X64: pextrw $3, %xmm1, %eax ; X64: pshufhw $3, %xmm0, %xmm0 ; X64: pinsrw $5, %eax, %xmm0 ; X64: ret @@ -256,18 +250,12 @@ entry: %tmp9 = shufflevector <16 x i8> %tmp8, <16 x i8> %T0, <16 x i32> < i32 0, i32 1, i32 2, i32 17, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef , i32 undef > ret <16 x i8> %tmp9 ; X64: t16: -; X64: movaps LCPI17_0(%rip), %xmm1 -; X64: movd %xmm1, %eax ; X64: pinsrw $0, %eax, %xmm1 ; X64: pextrw $8, %xmm0, %eax ; X64: pinsrw $1, %eax, %xmm1 ; X64: pextrw $1, %xmm1, %ecx ; X64: movd %xmm1, %edx ; X64: pinsrw $0, %edx, %xmm1 -; X64: movzbl %cl, %ecx -; X64: andw $-256, %ax -; X64: orw %cx, %ax -; X64: movaps %xmm1, %xmm0 ; X64: pinsrw $1, %eax, %xmm0 ; X64: ret } diff --git a/test/CodeGen/X86/stack-color-with-reg.ll b/test/CodeGen/X86/stack-color-with-reg.ll index 672f77e..0f32a50 100644 --- a/test/CodeGen/X86/stack-color-with-reg.ll +++ b/test/CodeGen/X86/stack-color-with-reg.ll @@ -1,6 +1,6 @@ ; RUN: llc < %s -mtriple=x86_64-apple-darwin10 -relocation-model=pic -disable-fp-elim -color-ss-with-regs -stats -info-output-file - > %t -; RUN: grep stackcoloring %t | grep "stack slot refs replaced with reg refs" | grep 5 -; RUN: grep asm-printer %t | grep 179 +; RUN: grep stackcoloring %t | grep "stack slot refs replaced with reg refs" | grep 6 +; RUN: grep asm-printer %t | grep 177 type { [62 x %struct.Bitvec*] } ; type %0 type { i8* } ; type %1 diff --git a/test/CodeGen/X86/tailcallstack64.ll b/test/CodeGen/X86/tailcallstack64.ll index 73c59bb..69018aa 100644 --- a/test/CodeGen/X86/tailcallstack64.ll +++ b/test/CodeGen/X86/tailcallstack64.ll @@ -3,19 +3,18 @@ ; Check that lowered arguments on the stack do not overwrite each other. ; Add %in1 %p1 to a different temporary register (%eax). ; CHECK: movl %edi, %eax -; CHECK: addl 32(%rsp), %eax ; Move param %in1 to temp register (%r10d). ; CHECK: movl 40(%rsp), %r10d -; Move result of addition to stack. -; CHECK: movl %eax, 40(%rsp) ; Move param %in2 to stack. ; CHECK: movl %r10d, 32(%rsp) +; Move result of addition to stack. +; CHECK: movl %eax, 40(%rsp) ; Eventually, do a TAILCALL ; CHECK: TAILCALL -declare fastcc i32 @tailcallee(i32 %p1, i32 %p2, i32 %p3, i32 %p4, i32 %p5, i32 %p6, i32 %a, i32 %b) +declare fastcc i32 @tailcallee(i32 %p1, i32 %p2, i32 %p3, i32 %p4, i32 %p5, i32 %p6, i32 %a, i32 %b) nounwind -define fastcc i32 @tailcaller(i32 %p1, i32 %p2, i32 %p3, i32 %p4, i32 %p5, i32 %p6, i32 %in1, i32 %in2) { +define fastcc i32 @tailcaller(i32 %p1, i32 %p2, i32 %p3, i32 %p4, i32 %p5, i32 %p6, i32 %in1, i32 %in2) nounwind { entry: %tmp = add i32 %in1, %p1 %retval = tail call fastcc i32 @tailcallee(i32 %p1, i32 %p2, i32 %p3, i32 %p4, i32 %p5, i32 %p6, i32 %in2,i32 %tmp) diff --git a/test/CodeGen/X86/vec_shuffle-22.ll b/test/CodeGen/X86/vec_shuffle-22.ll index 5307ced..1cf37d4 100644 --- a/test/CodeGen/X86/vec_shuffle-22.ll +++ b/test/CodeGen/X86/vec_shuffle-22.ll @@ -1,19 +1,15 @@ -; RUN: llc < %s -march=x86 -mcpu=pentium-m -o %t -; RUN: grep movlhps %t | count 1 -; RUN: grep pshufd %t | count 1 -; RUN: llc < %s -march=x86 -mcpu=core2 -o %t -; RUN: grep movlhps %t | count 1 -; RUN: grep movddup %t | count 1 +; RUN: llc < %s -march=x86 -mcpu=pentium-m | FileCheck %s define <4 x float> @t1(<4 x float> %a) nounwind { -entry: - %tmp1 = shufflevector <4 x float> %a, <4 x float> undef, <4 x i32> < i32 0, i32 1, i32 0, i32 1 > ; <<4 x float>> [#uses=1] - ret <4 x float> %tmp1 +; CHECK: movlhps + %tmp1 = shufflevector <4 x float> %a, <4 x float> undef, <4 x i32> < i32 0, i32 1, i32 0, i32 1 > ; <<4 x float>> [#uses=1] + ret <4 x float> %tmp1 } define <4 x i32> @t2(<4 x i32>* %a) nounwind { -entry: - %tmp1 = load <4 x i32>* %a; +; CHECK: pshufd +; CHECK: ret + %tmp1 = load <4 x i32>* %a; %tmp2 = shufflevector <4 x i32> %tmp1, <4 x i32> undef, <4 x i32> < i32 0, i32 1, i32 0, i32 1 > ; <<4 x i32>> [#uses=1] ret <4 x i32> %tmp2 } diff --git a/test/CodeGen/X86/vec_shuffle-9.ll b/test/CodeGen/X86/vec_shuffle-9.ll index 2bef24d..fc16a26 100644 --- a/test/CodeGen/X86/vec_shuffle-9.ll +++ b/test/CodeGen/X86/vec_shuffle-9.ll @@ -1,9 +1,10 @@ -; RUN: llc < %s -march=x86 -mattr=+sse2 -o %t -; RUN: grep punpck %t | count 2 -; RUN: not grep pextrw %t +; RUN: llc < %s -march=x86 -mattr=+sse2 | FileCheck %s define <4 x i32> @test(i8** %ptr) { -entry: +; CHECK: xorps +; CHECK: punpcklbw +; CHECK: punpcklwd + %tmp = load i8** %ptr ; <i8*> [#uses=1] %tmp.upgrd.1 = bitcast i8* %tmp to float* ; <float*> [#uses=1] %tmp.upgrd.2 = load float* %tmp.upgrd.1 ; <float> [#uses=1] diff --git a/test/CodeGen/X86/widen_arith-1.ll b/test/CodeGen/X86/widen_arith-1.ll index 8f607f5..f8d0690 100644 --- a/test/CodeGen/X86/widen_arith-1.ll +++ b/test/CodeGen/X86/widen_arith-1.ll @@ -1,14 +1,12 @@ -; RUN: llc < %s -march=x86 -mattr=+sse42 -disable-mmx -o %t -; RUN: grep paddb %t | count 1 -; RUN: grep pextrb %t | count 1 -; RUN: not grep pextrw %t +; RUN: llc < %s -march=x86 -mattr=+sse42 -disable-mmx | FileCheck %s ; Widen a v3i8 to v16i8 to use a vector add -target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128" - define void @update(<3 x i8>* %dst, <3 x i8>* %src, i32 %n) nounwind { entry: +; CHECK-NOT: pextrw +; CHECK: paddb +; CHECK: pextrb %dst.addr = alloca <3 x i8>* ; <<3 x i8>**> [#uses=2] %src.addr = alloca <3 x i8>* ; <<3 x i8>**> [#uses=2] %n.addr = alloca i32 ; <i32*> [#uses=2] diff --git a/test/CodeGen/X86/widen_arith-2.ll b/test/CodeGen/X86/widen_arith-2.ll index e2420f0..fdecaa3 100644 --- a/test/CodeGen/X86/widen_arith-2.ll +++ b/test/CodeGen/X86/widen_arith-2.ll @@ -1,9 +1,8 @@ -; RUN: llc < %s -march=x86 -mattr=+sse42 -disable-mmx -o %t -; RUN: grep paddb %t | count 1 -; RUN: grep pand %t | count 1 +; RUN: llc < %s -march=x86 -mattr=+sse42 -disable-mmx | FileCheck %s +; CHECK: paddb +; CHECK: pand ; widen v8i8 to v16i8 (checks even power of 2 widening with add & and) -target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128" define void @update(i64* %dst_i, i64* %src_i, i32 %n) nounwind { entry: diff --git a/test/CodeGen/X86/widen_arith-3.ll b/test/CodeGen/X86/widen_arith-3.ll index a22d254..a2b8b82 100644 --- a/test/CodeGen/X86/widen_arith-3.ll +++ b/test/CodeGen/X86/widen_arith-3.ll @@ -1,12 +1,10 @@ -; RUN: llc < %s -march=x86 -mattr=+sse42 -disable-mmx -o %t -; RUN: grep paddw %t | count 1 -; RUN: grep movd %t | count 2 -; RUN: grep pextrw %t | count 1 +; RUN: llc < %s -march=x86 -mattr=+sse42 -disable-mmx | FileCheck %s +; CHECK: paddw +; CHECK: pextrw +; CHECK: movd ; Widen a v3i16 to v8i16 to do a vector add -target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128" -target triple = "i686-apple-darwin10.0.0d2" @.str = internal constant [4 x i8] c"%d \00" ; <[4 x i8]*> [#uses=1] @.str1 = internal constant [2 x i8] c"\0A\00" ; <[2 x i8]*> [#uses=1] diff --git a/test/CodeGen/X86/widen_arith-4.ll b/test/CodeGen/X86/widen_arith-4.ll index 898bff0..f7506ae 100644 --- a/test/CodeGen/X86/widen_arith-4.ll +++ b/test/CodeGen/X86/widen_arith-4.ll @@ -1,11 +1,9 @@ -; RUN: llc < %s -march=x86 -mattr=+sse42 -disable-mmx -o %t -; RUN: grep psubw %t | count 1 -; RUN: grep pmullw %t | count 1 +; RUN: llc < %s -march=x86-64 -mattr=+sse42 -disable-mmx | FileCheck %s +; CHECK: psubw +; CHECK-NEXT: pmullw ; Widen a v5i16 to v8i16 to do a vector sub and multiple -target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128" - define void @update(<5 x i16>* %dst, <5 x i16>* %src, i32 %n) nounwind { entry: %dst.addr = alloca <5 x i16>* ; <<5 x i16>**> [#uses=2] diff --git a/test/CodeGen/X86/widen_arith-5.ll b/test/CodeGen/X86/widen_arith-5.ll index 1ecf09d..f7f3408 100644 --- a/test/CodeGen/X86/widen_arith-5.ll +++ b/test/CodeGen/X86/widen_arith-5.ll @@ -1,10 +1,9 @@ -; RUN: llc < %s -march=x86 -mattr=+sse42 -disable-mmx -o %t -; RUN: grep pmulld %t | count 1 -; RUN: grep psubd %t | count 1 -; RUN: grep movaps %t | count 1 +; RUN: llc < %s -march=x86-64 -mattr=+sse42 -disable-mmx | FileCheck %s +; CHECK: movaps +; CHECK: pmulld +; CHECK: psubd ; widen a v3i32 to v4i32 to do a vector multiple and a subtraction -target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128" define void @update(<3 x i32>* %dst, <3 x i32>* %src, i32 %n) nounwind { entry: diff --git a/test/CodeGen/X86/widen_arith-6.ll b/test/CodeGen/X86/widen_arith-6.ll index 3583258..538123f 100644 --- a/test/CodeGen/X86/widen_arith-6.ll +++ b/test/CodeGen/X86/widen_arith-6.ll @@ -1,9 +1,8 @@ -; RUN: llc < %s -march=x86 -mattr=+sse42 -disable-mmx -o %t -; RUN: grep mulps %t | count 1 -; RUN: grep addps %t | count 1 +; RUN: llc < %s -march=x86 -mattr=+sse42 -disable-mmx | FileCheck %s +; CHECK: mulps +; CHECK: addps ; widen a v3f32 to vfi32 to do a vector multiple and an add -target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128" define void @update(<3 x float>* %dst, <3 x float>* %src, i32 %n) nounwind { entry: diff --git a/test/CodeGen/X86/widen_cast-1.ll b/test/CodeGen/X86/widen_cast-1.ll index 441a360..d4ab174 100644 --- a/test/CodeGen/X86/widen_cast-1.ll +++ b/test/CodeGen/X86/widen_cast-1.ll @@ -1,7 +1,7 @@ -; RUN: llc < %s -march=x86 -mattr=+sse42 -disable-mmx -o %t -; RUN: grep paddw %t | count 1 -; RUN: grep movd %t | count 1 -; RUN: grep pextrd %t | count 1 +; RUN: llc -march=x86 -mattr=+sse42 < %s -disable-mmx | FileCheck %s +; CHECK: paddw +; CHECK: pextrd +; CHECK: movd ; bitcast a v4i16 to v2i32 diff --git a/test/CodeGen/X86/widen_cast-2.ll b/test/CodeGen/X86/widen_cast-2.ll index ded5707..e5d2c6a 100644 --- a/test/CodeGen/X86/widen_cast-2.ll +++ b/test/CodeGen/X86/widen_cast-2.ll @@ -1,6 +1,11 @@ -; RUN: llc < %s -march=x86 -mattr=+sse42 -disable-mmx -o %t -; RUN: grep pextrd %t | count 5 -; RUN: grep movd %t | count 3 +; RUN: llc < %s -march=x86 -mattr=+sse42 -disable-mmx | FileCheck %s +; CHECK: pextrd +; CHECK: pextrd +; CHECK: movd +; CHECK: pextrd +; CHECK: pextrd +; CHECK: pextrd +; CHECK: movd ; bitcast v14i16 to v7i32 diff --git a/test/CodeGen/X86/widen_cast-3.ll b/test/CodeGen/X86/widen_cast-3.ll index 67a760f..02674dd 100644 --- a/test/CodeGen/X86/widen_cast-3.ll +++ b/test/CodeGen/X86/widen_cast-3.ll @@ -1,6 +1,7 @@ -; RUN: llc < %s -march=x86 -mattr=+sse42 -disable-mmx -o %t -; RUN: grep paddd %t | count 1 -; RUN: grep pextrd %t | count 2 +; RUN: llc < %s -march=x86 -mattr=+sse42 -disable-mmx | FileCheck %s +; CHECK: paddd +; CHECK: pextrd +; CHECK: pextrd ; bitcast v12i8 to v3i32 diff --git a/test/CodeGen/X86/widen_cast-4.ll b/test/CodeGen/X86/widen_cast-4.ll index 614eeed..5f31e56 100644 --- a/test/CodeGen/X86/widen_cast-4.ll +++ b/test/CodeGen/X86/widen_cast-4.ll @@ -1,5 +1,12 @@ -; RUN: llc < %s -march=x86 -mattr=+sse42 -disable-mmx -o %t -; RUN: grep sarb %t | count 8 +; RUN: llc < %s -march=x86 -mattr=+sse42 -disable-mmx | FileCheck %s +; CHECK: sarb +; CHECK: sarb +; CHECK: sarb +; CHECK: sarb +; CHECK: sarb +; CHECK: sarb +; CHECK: sarb +; CHECK: sarb ; v8i8 that is widen to v16i8 then split ; FIXME: This is widen to v16i8 and split to 16 and we then rebuild the vector. diff --git a/test/CodeGen/X86/widen_cast-5.ll b/test/CodeGen/X86/widen_cast-5.ll index 92618d6..d1d7fec 100644 --- a/test/CodeGen/X86/widen_cast-5.ll +++ b/test/CodeGen/X86/widen_cast-5.ll @@ -1,4 +1,6 @@ -; RUN: llc < %s -march=x86 -mattr=+sse42 -disable-mmx -o %t +; RUN: llc < %s -march=x86 -mattr=+sse42 -disable-mmx | FileCheck %s +; CHECK: movl +; CHECK: movd ; bitcast a i64 to v2i32 diff --git a/test/CodeGen/X86/widen_cast-6.ll b/test/CodeGen/X86/widen_cast-6.ll index 386f749..08759bf 100644 --- a/test/CodeGen/X86/widen_cast-6.ll +++ b/test/CodeGen/X86/widen_cast-6.ll @@ -1,5 +1,5 @@ -; RUN: llc < %s -march=x86 -mattr=+sse41 -disable-mmx -o %t -; RUN: grep movd %t | count 1 +; RUN: llc < %s -march=x86 -mattr=+sse41 -disable-mmx | FileCheck %s +; CHECK: movd ; Test bit convert that requires widening in the operand. diff --git a/test/CodeGen/X86/widen_conv-1.ll b/test/CodeGen/X86/widen_conv-1.ll index ccc8b4f..a2029dd 100644 --- a/test/CodeGen/X86/widen_conv-1.ll +++ b/test/CodeGen/X86/widen_conv-1.ll @@ -1,6 +1,6 @@ -; RUN: llc < %s -march=x86 -mattr=+sse42 -disable-mmx -o %t -; RUN: grep pshufd %t | count 1 -; RUN: grep paddd %t | count 1 +; RUN: llc < %s -march=x86 -mattr=+sse42 -disable-mmx | FileCheck %s +; CHECK: pshufd +; CHECK: paddd ; truncate v2i64 to v2i32 diff --git a/test/CodeGen/X86/widen_conv-2.ll b/test/CodeGen/X86/widen_conv-2.ll index 9b7ab74..b24a9b3 100644 --- a/test/CodeGen/X86/widen_conv-2.ll +++ b/test/CodeGen/X86/widen_conv-2.ll @@ -1,4 +1,6 @@ -; RUN: llc < %s -march=x86 -mattr=+sse42 -disable-mmx -o %t +; RUN: llc < %s -march=x86 -mattr=+sse42 -disable-mmx | FileCheck %s +; CHECK: movswl +; CHECK: movswl ; sign extension v2i32 to v2i16 diff --git a/test/CodeGen/X86/widen_conv-3.ll b/test/CodeGen/X86/widen_conv-3.ll index 4ec76a9..1a40800 100644 --- a/test/CodeGen/X86/widen_conv-3.ll +++ b/test/CodeGen/X86/widen_conv-3.ll @@ -1,5 +1,6 @@ -; RUN: llc < %s -march=x86 -mattr=+sse42 -disable-mmx -o %t -; grep cvtsi2ss %t | count 1 +; RUN: llc < %s -march=x86 -mattr=+sse42 -disable-mmx | FileCheck %s +; CHECK: cvtsi2ss + ; sign to float v2i16 to v2f32 define void @convert(<2 x float>* %dst.addr, <2 x i16> %src) nounwind { diff --git a/test/CodeGen/X86/widen_conv-4.ll b/test/CodeGen/X86/widen_conv-4.ll index 61a26a8..e505b62 100644 --- a/test/CodeGen/X86/widen_conv-4.ll +++ b/test/CodeGen/X86/widen_conv-4.ll @@ -1,4 +1,5 @@ -; RUN: llc < %s -march=x86 -mattr=+sse42 -disable-mmx -o %t +; RUN: llc < %s -march=x86 -mattr=+sse42 -disable-mmx | FileCheck %s +; CHECK: cvtsi2ss ; unsigned to float v7i16 to v7f32 diff --git a/test/CodeGen/X86/widen_extract-1.ll b/test/CodeGen/X86/widen_extract-1.ll new file mode 100644 index 0000000..308e6b8 --- /dev/null +++ b/test/CodeGen/X86/widen_extract-1.ll @@ -0,0 +1,12 @@ +; RUN: llc < %s -march=x86-64 -mattr=+sse42 -disable-mmx | FileCheck %s +; widen extract subvector + +define void @convert(<2 x double>* %dst.addr, <3 x double> %src) { +entry: +; CHECK: convert: +; CHECK: unpcklpd {{%xmm[0-7]}}, {{%xmm[0-7]}} +; CHECK-NEXT: movapd + %val = shufflevector <3 x double> %src, <3 x double> undef, <2 x i32> < i32 0, i32 1> + store <2 x double> %val, <2 x double>* %dst.addr + ret void +} diff --git a/test/CodeGen/X86/widen_select-1.ll b/test/CodeGen/X86/widen_select-1.ll index aca0b67..4154433 100644 --- a/test/CodeGen/X86/widen_select-1.ll +++ b/test/CodeGen/X86/widen_select-1.ll @@ -1,4 +1,5 @@ -; RUN: llc < %s -march=x86 -mattr=+sse42 -disable-mmx -o %t +; RUN: llc < %s -march=x86 -mattr=+sse42 -disable-mmx | FileCheck %s +; CHECK: jne ; widening select v6i32 and then a sub diff --git a/test/CodeGen/X86/widen_shuffle-1.ll b/test/CodeGen/X86/widen_shuffle-1.ll index 15da870..dd02241 100644 --- a/test/CodeGen/X86/widen_shuffle-1.ll +++ b/test/CodeGen/X86/widen_shuffle-1.ll @@ -1,4 +1,6 @@ -; RUN: llc < %s -march=x86 -mattr=+sse42 -disable-mmx -o %t +; RUN: llc < %s -march=x86 -mattr=+sse42 -disable-mmx | FileCheck %s +; CHECK: insertps +; CHECK: extractps ; widening shuffle v3float and then a add diff --git a/test/CodeGen/X86/widen_shuffle-2.ll b/test/CodeGen/X86/widen_shuffle-2.ll index 617cc1de..d097e41 100644 --- a/test/CodeGen/X86/widen_shuffle-2.ll +++ b/test/CodeGen/X86/widen_shuffle-2.ll @@ -1,4 +1,6 @@ -; RUN: llc < %s -march=x86 -mattr=+sse42 -disable-mmx -o %t +; RUN: llc < %s -march=x86 -mattr=+sse42 -disable-mmx | FileCheck %s +; CHECK: insertps +; CHECK: extractps ; widening shuffle v3float and then a add diff --git a/test/DebugInfo/2009-10-16-Phi.ll b/test/DebugInfo/2009-10-16-Phi.ll new file mode 100644 index 0000000..fc03751 --- /dev/null +++ b/test/DebugInfo/2009-10-16-Phi.ll @@ -0,0 +1,13 @@ +; RUN: llvm-as %s -disable-output + +define i32 @foo() { +E: + br label %B2 +B1: + br label %B2 +B2: + %0 = phi i32 [ 0, %E ], [ 1, %B1 ], !dbg !0 + ret i32 %0 +} + +!0 = metadata !{i32 42}
\ No newline at end of file diff --git a/test/DebugInfo/2009-10-16-Scope.ll b/test/DebugInfo/2009-10-16-Scope.ll new file mode 100644 index 0000000..ea43249 --- /dev/null +++ b/test/DebugInfo/2009-10-16-Scope.ll @@ -0,0 +1,33 @@ +; RUN: llc %s -O0 -o /dev/null +; PR 5197 +; There is not any llvm instruction assocated with !5. The code generator +; should be able to handle this. + +define void @bar() nounwind ssp { +entry: + %count_ = alloca i32, align 4 ; <i32*> [#uses=2] + br label %do.body, !dbg !0 + +do.body: ; preds = %entry + %0 = bitcast i32* %count_ to { }* ; <{ }*> [#uses=1] + call void @llvm.dbg.declare({ }* %0, metadata !4) + %conv = ptrtoint i32* %count_ to i32, !dbg !0 ; <i32> [#uses=1] + %call = call i32 @foo(i32 %conv) ssp, !dbg !0 ; <i32> [#uses=0] + br label %do.end, !dbg !0 + +do.end: ; preds = %do.body + ret void, !dbg !7 +} + +declare void @llvm.dbg.declare({ }*, metadata) nounwind readnone + +declare i32 @foo(i32) ssp + +!0 = metadata !{i32 5, i32 2, metadata !1, null} +!1 = metadata !{i32 458763, metadata !2}; [DW_TAG_lexical_block ] +!2 = metadata !{i32 458798, i32 0, metadata !3, metadata !"bar", metadata !"bar", metadata !"bar", metadata !3, i32 4, null, i1 false, i1 true}; [DW_TAG_subprogram ] +!3 = metadata !{i32 458769, i32 0, i32 12, metadata !"genmodes.i", metadata !"/Users/yash/Downloads", metadata !"clang 1.1", i1 true, i1 false, metadata !"", i32 0}; [DW_TAG_compile_unit ] +!4 = metadata !{i32 459008, metadata !5, metadata !"count_", metadata !3, i32 5, metadata !6}; [ DW_TAG_auto_variable ] +!5 = metadata !{i32 458763, metadata !1}; [DW_TAG_lexical_block ] +!6 = metadata !{i32 458788, metadata !3, metadata !"int", metadata !3, i32 0, i64 32, i64 32, i64 0, i32 0, i32 5}; [DW_TAG_base_type ] +!7 = metadata !{i32 6, i32 1, metadata !2, null} diff --git a/test/Feature/md_on_instruction.ll b/test/Feature/md_on_instruction.ll index d765cd8..da9e49e 100644 --- a/test/Feature/md_on_instruction.ll +++ b/test/Feature/md_on_instruction.ll @@ -1,5 +1,4 @@ -; RUN: llvm-as < %s -disable-output - +; RUN: llvm-as < %s | llvm-dis | grep " !dbg " | count 4 define i32 @foo() nounwind ssp { entry: %retval = alloca i32 ; <i32*> [#uses=2] diff --git a/test/FrontendAda/negative_field_offset.adb b/test/FrontendAda/negative_field_offset.adb new file mode 100644 index 0000000..f8b8510 --- /dev/null +++ b/test/FrontendAda/negative_field_offset.adb @@ -0,0 +1,16 @@ +-- RUN: %llvmgcc -c %s +with System; +procedure Negative_Field_Offset (N : Integer) is + type String_Pointer is access String; + -- Force use of a thin pointer. + for String_Pointer'Size use System.Word_Size; + P : String_Pointer; + + procedure Q (P : String_Pointer) is + begin + P (1) := 'Z'; + end; +begin + P := new String (1 .. N); + Q (P); +end; diff --git a/test/FrontendC++/alignstack.cpp b/test/FrontendC++/alignstack.cpp new file mode 100644 index 0000000..4f993d6 --- /dev/null +++ b/test/FrontendC++/alignstack.cpp @@ -0,0 +1,23 @@ +// RUN: %llvmgxx %s -fasm-blocks -S -o - | FileCheck %s +// Complicated expression as jump target +// XFAIL: * +// XTARGET: x86,i386,i686,darwin + +void Method3() +{ +// CHECK: Method3 +// CHECK-NOT: alignstack + asm("foo:"); +// CHECK: return +} + +void Method4() +{ +// CHECK: Method4 +// CHECK: alignstack + asm { + bar: + } +// CHECK: return +} + diff --git a/test/FrontendC++/member-alignment.cpp b/test/FrontendC++/member-alignment.cpp index 01c90ca..6afc0aa 100644 --- a/test/FrontendC++/member-alignment.cpp +++ b/test/FrontendC++/member-alignment.cpp @@ -1,5 +1,5 @@ // RUN: %llvmgxx -S -emit-llvm %s -o - | FileCheck %s -// XFAIL: arm +// XFAIL: arm,powerpc // rdar://7268289 diff --git a/test/FrontendC++/varargs.cpp b/test/FrontendC++/varargs.cpp new file mode 100644 index 0000000..1c07aed --- /dev/null +++ b/test/FrontendC++/varargs.cpp @@ -0,0 +1,19 @@ +// RUN: %llvmgxx -S -emit-llvm %s -o - | FileCheck %s +// rdar://7309675 +// PR4678 + +// test1 should be compmiled to be a varargs function in the IR even +// though there is no way to do a va_begin. Otherwise, the optimizer +// will warn about 'dropped arguments' at the call site. + +// CHECK: define i32 @_Z5test1z(...) +int test1(...) { + return -1; +} + +// CHECK: call i32 (...)* @_Z5test1z(i32 0) +void test() { + test1(0); +} + + diff --git a/test/FrontendC/alignstack.c b/test/FrontendC/alignstack.c new file mode 100644 index 0000000..30c00ff --- /dev/null +++ b/test/FrontendC/alignstack.c @@ -0,0 +1,23 @@ +// RUN: %llvmgcc %s -fasm-blocks -S -o - | FileCheck %s +// Complicated expression as jump target +// XFAIL: * +// XTARGET: x86,i386,i686,darwin + +void Method3() +{ +// CHECK: Method3 +// CHECK-NOT: alignstack + asm("foo:"); +// CHECK: return +} + +void Method4() +{ +// CHECK: Method4 +// CHECK: alignstack + asm { + bar: + } +// CHECK: return +} + diff --git a/test/LLVMC/MultiplePluginPriorities.td b/test/LLVMC/MultiplePluginPriorities.td new file mode 100644 index 0000000..721b7cc --- /dev/null +++ b/test/LLVMC/MultiplePluginPriorities.td @@ -0,0 +1,10 @@ +// Check that multiple plugin priorities are not allowed. +// RUN: ignore tblgen -I %p/../../include --gen-llvmc %s |& grep "More than one 'PluginPriority' instance found" + +include "llvm/CompilerDriver/Common.td" + +def Graph : CompilationGraph<[]>; + +def Priority1 : PluginPriority<1>; + +def Priority2 : PluginPriority<2>; diff --git a/test/MC/AsmParser/labels.s b/test/MC/AsmParser/labels.s index 53da7ed..456d61f 100644 --- a/test/MC/AsmParser/labels.s +++ b/test/MC/AsmParser/labels.s @@ -12,21 +12,21 @@ a: .long 0 .text -foo: +foo: // CHECK: addl $24, a$b(%eax) - addl $24, "a$b"(%eax) + addl $24, "a$b"(%eax) // CHECK: addl $24, a$b+10(%eax) addl $24, ("a$b" + 10)(%eax) - + // CHECK: b$c = 10 "b$c" = 10 -// CHECK: addl $b$c, %eax +// CHECK: addl $10, %eax addl "b$c", %eax - + // CHECK: "a 0" = 11 .set "a 0", 11 - -// CHECK: .long "a 0" + +// CHECK: .long 11 .long "a 0" // XXCHCK: .section "a 1,a 2" @@ -48,12 +48,12 @@ foo: .lcomm "a 7", 1 // FIXME: We don't bother to support .lsym. - + // CHECX: .lsym "a 8",1 // .lsym "a 8", 1 // CHECK: "a 9" = a-b .set "a 9", a - b - + // CHECK: .long "a 9" .long "a 9" diff --git a/test/MC/AsmParser/variables-invalid.s b/test/MC/AsmParser/variables-invalid.s new file mode 100644 index 0000000..9656889 --- /dev/null +++ b/test/MC/AsmParser/variables-invalid.s @@ -0,0 +1,17 @@ +// RUN: not llvm-mc -triple i386-unknown-unknown %s 2> %t +// RUN: FileCheck --input-file %t %s + + .data +// CHECK: invalid assignment to 't0_v0' + t0_v0 = t0_v0 + 1 + + t1_v1 = 1 + t1_v1 = 2 + +t2_s0: +// CHECK: redefinition of 't2_s0' + t2_s0 = 2 + + t3_s0 = t2_s0 + 1 +// CHECK: invalid reassignment of non-absolute variable 't3_s0' + t3_s0 = 1 diff --git a/test/MC/AsmParser/variables.s b/test/MC/AsmParser/variables.s new file mode 100644 index 0000000..cb004d7 --- /dev/null +++ b/test/MC/AsmParser/variables.s @@ -0,0 +1,15 @@ +// RUN: llvm-mc -triple i386-unknown-unknown %s + + .data + t0_v0 = 1 + t0_v1 = t0_v0 + .if t0_v1 != 1 + .abort "invalid value" + .endif + + t1_v0 = 1 + t1_v1 = t0_v0 + t1_v0 = 2 + .if t0_v1 != 1 + .abort "invalid value" + .endif diff --git a/test/Transforms/ConstProp/constant-expr.ll b/test/Transforms/ConstProp/constant-expr.ll new file mode 100644 index 0000000..eece37f --- /dev/null +++ b/test/Transforms/ConstProp/constant-expr.ll @@ -0,0 +1,60 @@ +; RUN: llvm-as < %s | llvm-dis | FileCheck %s + +@X = external global i8 +@Y = external global i8 +@Z = external global i8 + +@A = global i1 add (i1 icmp ult (i8* @X, i8* @Y), i1 icmp ult (i8* @X, i8* @Z)) +; CHECK: @A = global i1 xor (i1 icmp ult (i8* @X, i8* @Y), i1 icmp ult (i8* @X, i8* @Z)) +@B = global i1 sub (i1 icmp ult (i8* @X, i8* @Y), i1 icmp ult (i8* @X, i8* @Z)), align 2 +; CHECK: @B = global i1 xor (i1 icmp ult (i8* @X, i8* @Y), i1 icmp ult (i8* @X, i8* @Z)) +@C = global i1 mul (i1 icmp ult (i8* @X, i8* @Y), i1 icmp ult (i8* @X, i8* @Z)) +; CHECK: @C = global i1 and (i1 icmp ult (i8* @X, i8* @Y), i1 icmp ult (i8* @X, i8* @Z)) + +@D = global i1 sdiv (i1 icmp ult (i8* @X, i8* @Y), i1 icmp ult (i8* @X, i8* @Z)) +; CHECK: @D = global i1 icmp ult (i8* @X, i8* @Y) +@E = global i1 udiv (i1 icmp ult (i8* @X, i8* @Y), i1 icmp ult (i8* @X, i8* @Z)) +; CHECK: @E = global i1 icmp ult (i8* @X, i8* @Y) +@F = global i1 srem (i1 icmp ult (i8* @X, i8* @Y), i1 icmp ult (i8* @X, i8* @Z)) +; CHECK: @F = global i1 false ; <i1*> [#uses=0] +@G = global i1 urem (i1 icmp ult (i8* @X, i8* @Y), i1 icmp ult (i8* @X, i8* @Z)) +; CHECK: @G = global i1 false ; <i1*> [#uses=0] + +@H = global i1 icmp ule (i32* bitcast (i8* @X to i32*), i32* bitcast (i8* @Y to i32*)) +; CHECK: @H = global i1 icmp ule (i8* @X, i8* @Y) + +@I = global i1 xor (i1 icmp ult (i8* @X, i8* @Y), i1 false) +; CHECK: @I = global i1 icmp ult (i8* @X, i8* @Y) +@J = global i1 xor (i1 icmp ult (i8* @X, i8* @Y), i1 true) +; CHECK: @J = global i1 icmp uge (i8* @X, i8* @Y) + +@K = global i1 icmp eq (i1 icmp ult (i8* @X, i8* @Y), i1 false) +; CHECK: @K = global i1 icmp uge (i8* @X, i8* @Y) +@L = global i1 icmp eq (i1 icmp ult (i8* @X, i8* @Y), i1 true) +; CHECK: @L = global i1 icmp ult (i8* @X, i8* @Y) +@M = global i1 icmp ne (i1 icmp ult (i8* @X, i8* @Y), i1 true) +; CHECK: @M = global i1 icmp uge (i8* @X, i8* @Y) +@N = global i1 icmp ne (i1 icmp ult (i8* @X, i8* @Y), i1 false) +; CHECK: @N = global i1 icmp ult (i8* @X, i8* @Y) + +@O = global i1 icmp eq (i32 zext (i1 icmp ult (i8* @X, i8* @Y) to i32), i32 0) +; CHECK: @O = global i1 icmp uge (i8* @X, i8* @Y) + + + +; PR5176 + +; CHECK: @T1 = global i1 true +@T1 = global i1 icmp eq (i64 and (i64 trunc (i256 lshr (i256 or (i256 and (i256 and (i256 shl (i256 zext (i64 ptrtoint (i1* @B to i64) to i256), i256 64), i256 -6277101735386680763495507056286727952638980837032266301441), i256 6277101735386680763835789423207666416102355444464034512895), i256 shl (i256 zext (i64 ptrtoint (i1* @A to i64) to i256), i256 192)), i256 64) to i64), i64 1), i64 0) + +; CHECK: @T2 = global i1* @B +@T2 = global i1* inttoptr (i64 add (i64 trunc (i256 lshr (i256 or (i256 and (i256 and (i256 shl (i256 zext (i64 ptrtoint (i1* @A to i64) to i256), i256 64), i256 -6277101735386680763495507056286727952638980837032266301441), i256 6277101735386680763835789423207666416102355444464034512895), i256 shl (i256 zext (i64 ptrtoint (i1* @B to i64) to i256), i256 192)), i256 192) to i64), i64 trunc (i256 lshr (i256 or (i256 and (i256 and (i256 shl (i256 zext (i64 ptrtoint (i1* @A to i64) to i256), i256 64), i256 -6277101735386680763495507056286727952638980837032266301441), i256 6277101735386680763835789423207666416102355444464034512895), i256 shl (i256 zext (i64 ptrtoint (i1* @B to i64) to i256), i256 192)), i256 128) to i64)) to i1*) + +; CHECK: @T3 = global i64 add (i64 ptrtoint (i1* @B to i64), i64 -1) +@T3 = global i64 add (i64 trunc (i256 lshr (i256 or (i256 and (i256 and (i256 shl (i256 zext (i64 ptrtoint (i1* @B to i64) to i256), i256 64), i256 -6277101735386680763495507056286727952638980837032266301441), i256 6277101735386680763835789423207666416102355444464034512895), i256 shl (i256 zext (i64 ptrtoint (i1* @A to i64) to i256), i256 192)), i256 64) to i64), i64 -1) + +; CHECK: @T4 = global i1* @B +@T4 = global i1* inttoptr (i64 trunc (i256 lshr (i256 or (i256 and (i256 and (i256 shl (i256 zext (i64 ptrtoint (i1* @B to i64) to i256), i256 64), i256 -6277101735386680763495507056286727952638980837032266301441), i256 6277101735386680763835789423207666416102355444464034512895), i256 shl (i256 zext (i64 ptrtoint (i1* @A to i64) to i256), i256 192)), i256 64) to i64) to i1*) + +; CHECK: @T5 = global i1* @A +@T5 = global i1* inttoptr (i64 add (i64 trunc (i256 lshr (i256 or (i256 and (i256 and (i256 shl (i256 zext (i64 ptrtoint (i1* @B to i64) to i256), i256 64), i256 -6277101735386680763495507056286727952638980837032266301441), i256 6277101735386680763835789423207666416102355444464034512895), i256 shl (i256 zext (i64 ptrtoint (i1* @A to i64) to i256), i256 192)), i256 192) to i64), i64 trunc (i256 lshr (i256 or (i256 and (i256 and (i256 shl (i256 zext (i64 ptrtoint (i1* @B to i64) to i256), i256 64), i256 -6277101735386680763495507056286727952638980837032266301441), i256 6277101735386680763835789423207666416102355444464034512895), i256 shl (i256 zext (i64 ptrtoint (i1* @A to i64) to i256), i256 192)), i256 128) to i64)) to i1*)
\ No newline at end of file diff --git a/test/Transforms/ConstProp/loads.ll b/test/Transforms/ConstProp/loads.ll new file mode 100644 index 0000000..f3e7f6a --- /dev/null +++ b/test/Transforms/ConstProp/loads.ll @@ -0,0 +1,89 @@ +; RUN: opt < %s -instcombine -S | FileCheck %s + +target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128" + +@test1 = constant {{i32,i8},i32} {{i32,i8} { i32 -559038737, i8 186 }, i32 -889275714 } +@test2 = constant double 1.0 +@test3 = constant {i64, i64} { i64 123, i64 112312312 } + +; Simple load +define i32 @test1() { + %r = load i32* getelementptr ({{i32,i8},i32}* @test1, i32 0, i32 0, i32 0) + ret i32 %r +; @test1 +; CHECK: ret i32 -559038737 +} + +; PR3152 +; Load of first 16 bits of 32-bit value. +define i16 @test2() { + %r = load i16* bitcast(i32* getelementptr ({{i32,i8},i32}* @test1, i32 0, i32 0, i32 0) to i16*) + ret i16 %r + +; @test2 +; CHECK: ret i16 -16657 +} + +; Load of second 16 bits of 32-bit value. +define i16 @test3() { + %r = load i16* getelementptr(i16* bitcast(i32* getelementptr ({{i32,i8},i32}* @test1, i32 0, i32 0, i32 0) to i16*), i32 1) + ret i16 %r + +; @test3 +; CHECK: ret i16 -8531 +} + +; Load of 8 bit field + tail padding. +define i16 @test4() { + %r = load i16* getelementptr(i16* bitcast(i32* getelementptr ({{i32,i8},i32}* @test1, i32 0, i32 0, i32 0) to i16*), i32 2) + ret i16 %r +; @test4 +; CHECK: ret i16 186 +} + +; Load of double bits. +define i64 @test6() { + %r = load i64* bitcast(double* @test2 to i64*) + ret i64 %r + +; @test6 +; CHECK: ret i64 4607182418800017408 +} + +; Load of double bits. +define i16 @test7() { + %r = load i16* bitcast(double* @test2 to i16*) + ret i16 %r + +; @test7 +; CHECK: ret i16 0 +} + +; Double load. +define double @test8() { + %r = load double* bitcast({{i32,i8},i32}* @test1 to double*) + ret double %r + +; @test8 +; CHECK: ret double 0xDEADBEBA +} + + +; i128 load. +define i128 @test9() { + %r = load i128* bitcast({i64, i64}* @test3 to i128*) + ret i128 %r + +; @test9 +; CHECK: ret i128 112312312 +} + +; vector load. +define <2 x i64> @test10() { + %r = load <2 x i64>* bitcast({i64, i64}* @test3 to <2 x i64>*) + ret <2 x i64> %r + +; @test10 +; CHECK: ret <2 x i64> <i64 112312312, i64 0> +} + diff --git a/test/Transforms/GVN/calls-readonly.ll b/test/Transforms/GVN/calls-readonly.ll index 28b5ff0..97ec915 100644 --- a/test/Transforms/GVN/calls-readonly.ll +++ b/test/Transforms/GVN/calls-readonly.ll @@ -6,22 +6,22 @@ target triple = "i386-apple-darwin7" define i8* @test(i8* %P, i8* %Q, i32 %x, i32 %y) nounwind readonly { entry: - %0 = tail call i32 @strlen(i8* %P) nounwind readonly ; <i32> [#uses=2] - %1 = icmp eq i32 %0, 0 ; <i1> [#uses=1] - br i1 %1, label %bb, label %bb1 + %0 = tail call i32 @strlen(i8* %P) ; <i32> [#uses=2] + %1 = icmp eq i32 %0, 0 ; <i1> [#uses=1] + br i1 %1, label %bb, label %bb1 -bb: ; preds = %entry - %2 = sdiv i32 %x, %y ; <i32> [#uses=1] - br label %bb1 +bb: ; preds = %entry + %2 = sdiv i32 %x, %y ; <i32> [#uses=1] + br label %bb1 -bb1: ; preds = %bb, %entry - %x_addr.0 = phi i32 [ %2, %bb ], [ %x, %entry ] ; <i32> [#uses=1] - %3 = tail call i8* @strchr(i8* %Q, i32 97) nounwind readonly ; <i8*> [#uses=1] - %4 = tail call i32 @strlen(i8* %P) nounwind readonly ; <i32> [#uses=1] - %5 = add i32 %x_addr.0, %0 ; <i32> [#uses=1] - %.sum = sub i32 %5, %4 ; <i32> [#uses=1] - %6 = getelementptr i8* %3, i32 %.sum ; <i8*> [#uses=1] - ret i8* %6 +bb1: ; preds = %bb, %entry + %x_addr.0 = phi i32 [ %2, %bb ], [ %x, %entry ] ; <i32> [#uses=1] + %3 = tail call i8* @strchr(i8* %Q, i32 97) ; <i8*> [#uses=1] + %4 = tail call i32 @strlen(i8* %P) ; <i32> [#uses=1] + %5 = add i32 %x_addr.0, %0 ; <i32> [#uses=1] + %.sum = sub i32 %5, %4 ; <i32> [#uses=1] + %6 = getelementptr i8* %3, i32 %.sum ; <i8*> [#uses=1] + ret i8* %6 } declare i32 @strlen(i8*) nounwind readonly diff --git a/test/Transforms/GlobalOpt/2009-11-16-BrokenPerformHeapAllocSRoA.ll b/test/Transforms/GlobalOpt/2009-11-16-BrokenPerformHeapAllocSRoA.ll new file mode 100644 index 0000000..54e8f90 --- /dev/null +++ b/test/Transforms/GlobalOpt/2009-11-16-BrokenPerformHeapAllocSRoA.ll @@ -0,0 +1,26 @@ +; RUN: opt < %s -globalopt -S | FileCheck %s + +target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128" +target triple = "x86_64-apple-darwin10.0" + +%struct.hashheader = type { i16, i16, i16, i16, i16, i16, i32, i32, i32, i32, i32, i32, i32, i32, i32, [5 x i8], [13 x i8], i8, i8, i8, [228 x i16], [228 x i8], [228 x i8], [228 x i8], [228 x i8], [228 x i8], [228 x i8], [128 x i8], [100 x [11 x i8]], [100 x i32], [100 x i32], i16 } +%struct.strchartype = type { i8*, i8*, i8* } + +@hashheader = internal global %struct.hashheader zeroinitializer, align 32 ; <%struct.hashheader*> [#uses=1] +@chartypes = internal global %struct.strchartype* null ; <%struct.strchartype**> [#uses=1] +; CHECK-NOT: @hashheader +; CHECK-NOT: @chartypes + +; based on linit in office-ispell +define void @test() nounwind ssp { + %1 = load i32* getelementptr inbounds (%struct.hashheader* @hashheader, i64 0, i32 13), align 8 ; <i32> [#uses=1] + %2 = sext i32 %1 to i64 ; <i64> [#uses=1] + %3 = mul i64 %2, ptrtoint (%struct.strchartype* getelementptr (%struct.strchartype* null, i64 1) to i64) ; <i64> [#uses=1] + %4 = tail call i8* @malloc(i64 %3) ; <i8*> [#uses=1] +; CHECK: call i8* @malloc(i64 + %5 = bitcast i8* %4 to %struct.strchartype* ; <%struct.strchartype*> [#uses=1] + store %struct.strchartype* %5, %struct.strchartype** @chartypes, align 8 + ret void +} + +declare noalias i8* @malloc(i64) diff --git a/test/Transforms/GlobalOpt/2009-11-16-MallocSingleStoreToGlobalVar.ll b/test/Transforms/GlobalOpt/2009-11-16-MallocSingleStoreToGlobalVar.ll new file mode 100644 index 0000000..c43565a --- /dev/null +++ b/test/Transforms/GlobalOpt/2009-11-16-MallocSingleStoreToGlobalVar.ll @@ -0,0 +1,30 @@ +; Test ensures that non-optimizable array mallocs are not optimized; specifically +; GlobalOpt was treating a non-optimizable array malloc as a non-array malloc +; and optimizing the global object that the malloc was stored to as a single +; element global. The global object @TOP in this test should not be optimized. +; RUN: opt < %s -globalopt -S | FileCheck %s + +target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128" +target triple = "x86_64-apple-darwin10.0" + +@TOP = internal global i64* null ; <i64**> [#uses=2] +; CHECK: @TOP = internal global i64* null +@channelColumns = internal global i64 0 ; <i64*> [#uses=2] + +; Derived from @DescribeChannel() in yacr2 +define void @test() nounwind ssp { + store i64 2335, i64* @channelColumns, align 8 + %1 = load i64* @channelColumns, align 8 ; <i64> [#uses=1] + %2 = shl i64 %1, 3 ; <i64> [#uses=1] + %3 = add i64 %2, 8 ; <i64> [#uses=1] + %4 = call noalias i8* @malloc(i64 %3) nounwind ; <i8*> [#uses=1] +; CHECK: call noalias i8* @malloc + %5 = bitcast i8* %4 to i64* ; <i64*> [#uses=1] + store i64* %5, i64** @TOP, align 8 + %6 = load i64** @TOP, align 8 ; <i64*> [#uses=1] + %7 = getelementptr inbounds i64* %6, i64 13 ; <i64*> [#uses=1] + store i64 0, i64* %7, align 8 + ret void +} + +declare noalias i8* @malloc(i64) nounwind diff --git a/test/Transforms/GlobalOpt/malloc-promote-2.ll b/test/Transforms/GlobalOpt/malloc-promote-2.ll index 0d03835..d3d2252 100644 --- a/test/Transforms/GlobalOpt/malloc-promote-2.ll +++ b/test/Transforms/GlobalOpt/malloc-promote-2.ll @@ -1,4 +1,6 @@ -; RUN: opt < %s -globalopt -S | not grep malloc +; RUN: opt < %s -globalopt -globaldce -S | not grep malloc +target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128" +target triple = "i686-apple-darwin8" @G = internal global i32* null ; <i32**> [#uses=3] diff --git a/test/Transforms/GlobalOpt/malloc-promote-3.ll b/test/Transforms/GlobalOpt/malloc-promote-3.ll index d4ee4e8..a920b61 100644 --- a/test/Transforms/GlobalOpt/malloc-promote-3.ll +++ b/test/Transforms/GlobalOpt/malloc-promote-3.ll @@ -1,4 +1,6 @@ -; RUN: opt < %s -globalopt -S | not grep malloc +; RUN: opt < %s -globalopt -globaldce -S | not grep malloc +target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128" +target triple = "i686-apple-darwin8" @G = internal global i32* null ; <i32**> [#uses=4] diff --git a/test/Transforms/Inline/crash.ll b/test/Transforms/Inline/crash.ll index 30eae7a..f34b44c 100644 --- a/test/Transforms/Inline/crash.ll +++ b/test/Transforms/Inline/crash.ll @@ -51,7 +51,38 @@ entry: unreachable } +declare fastcc void @list_Rplacd1284() nounwind ssp -declare fastcc void @list_Rplacd1284() nounwind ssp + +;============================ +; PR5208 + +define void @AAA() { +entry: + %A = alloca i8, i32 undef, align 1 + invoke fastcc void @XXX() + to label %invcont98 unwind label %lpad156 + +invcont98: + unreachable + +lpad156: + unreachable +} + +declare fastcc void @YYY() + +define internal fastcc void @XXX() { +entry: + %B = alloca i8, i32 undef, align 1 + invoke fastcc void @YYY() + to label %bb260 unwind label %lpad + +bb260: + ret void + +lpad: + unwind +} diff --git a/test/Transforms/InstCombine/cast.ll b/test/Transforms/InstCombine/cast.ll index 9835d65..c5266f3 100644 --- a/test/Transforms/InstCombine/cast.ll +++ b/test/Transforms/InstCombine/cast.ll @@ -102,8 +102,8 @@ define i32* @test12() { %p = malloc [4 x i8] ; <[4 x i8]*> [#uses=1] %c = bitcast [4 x i8]* %p to i32* ; <i32*> [#uses=1] ret i32* %c -; CHECK: %p = malloc i32 -; CHECK: ret i32* %p +; CHECK: %malloccall = tail call i8* @malloc(i32 ptrtoint ([4 x i8]* getelementptr ([4 x i8]* null, i32 1) to i32)) +; CHECK: ret i32* %c } define i8* @test13(i64 %A) { @@ -274,9 +274,9 @@ define void @test32(double** %tmp) { %tmp8.upgrd.1 = bitcast [16 x i8]* %tmp8 to double* ; <double*> [#uses=1] store double* %tmp8.upgrd.1, double** %tmp ret void -; CHECK: %tmp81 = malloc [2 x double] -; CHECK: %tmp81.sub = getelementptr inbounds [2 x double]* %tmp81, i64 0, i64 0 -; CHECK: store double* %tmp81.sub, double** %tmp +; CHECK: %malloccall = tail call i8* @malloc(i32 ptrtoint ([16 x i8]* getelementptr ([16 x i8]* null, i32 1) to i32)) +; CHECK: %tmp8.upgrd.1 = bitcast i8* %malloccall to double* +; CHECK: store double* %tmp8.upgrd.1, double** %tmp ; CHECK: ret void } diff --git a/test/Transforms/InstCombine/crash.ll b/test/Transforms/InstCombine/crash.ll index d475ab5..fbac472 100644 --- a/test/Transforms/InstCombine/crash.ll +++ b/test/Transforms/InstCombine/crash.ll @@ -1,4 +1,4 @@ -; RUN: opt < %s -instcombine | llvm-dis +; RUN: opt < %s -instcombine -S target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128" target triple = "i386-apple-darwin10.0" @@ -44,3 +44,84 @@ entry: store i32 %ins, i32* %arrayidx20 ret void } + +; PR5262 +@tmp2 = global i64 0 ; <i64*> [#uses=1] + +declare void @use(i64) nounwind + +define void @foo(i1) nounwind align 2 { +; <label>:1 + br i1 %0, label %2, label %3 + +; <label>:2 ; preds = %1 + br label %3 + +; <label>:3 ; preds = %2, %1 + %4 = phi i8 [ 1, %2 ], [ 0, %1 ] ; <i8> [#uses=1] + %5 = icmp eq i8 %4, 0 ; <i1> [#uses=1] + %6 = load i64* @tmp2, align 8 ; <i64> [#uses=1] + %7 = select i1 %5, i64 0, i64 %6 ; <i64> [#uses=1] + br label %8 + +; <label>:8 ; preds = %3 + call void @use(i64 %7) + ret void +} + +%t0 = type { i32, i32 } +%t1 = type { i32, i32, i32, i32, i32* } + +declare %t0* @bar2(i64) + +define void @bar3(i1, i1) nounwind align 2 { +; <label>:2 + br i1 %1, label %10, label %3 + +; <label>:3 ; preds = %2 + %4 = getelementptr inbounds %t0* null, i64 0, i32 1 ; <i32*> [#uses=0] + %5 = getelementptr inbounds %t1* null, i64 0, i32 4 ; <i32**> [#uses=1] + %6 = load i32** %5, align 8 ; <i32*> [#uses=1] + %7 = icmp ne i32* %6, null ; <i1> [#uses=1] + %8 = zext i1 %7 to i32 ; <i32> [#uses=1] + %9 = add i32 %8, 0 ; <i32> [#uses=1] + br label %10 + +; <label>:10 ; preds = %3, %2 + %11 = phi i32 [ %9, %3 ], [ 0, %2 ] ; <i32> [#uses=1] + br i1 %1, label %12, label %13 + +; <label>:12 ; preds = %10 + br label %13 + +; <label>:13 ; preds = %12, %10 + %14 = zext i32 %11 to i64 ; <i64> [#uses=1] + %15 = tail call %t0* @bar2(i64 %14) nounwind ; <%0*> [#uses=0] + ret void +} + + + + +; PR5262 +; Make sure the PHI node gets put in a place where all of its operands dominate +; it. +define i64 @test4(i1 %c, i64* %P) nounwind align 2 { +BB0: + br i1 %c, label %BB1, label %BB2 + +BB1: + br label %BB2 + +BB2: + %v5_ = phi i1 [ true, %BB0], [false, %BB1] + %v6 = load i64* %P + br label %l8 + +l8: + br label %l10 + +l10: + %v11 = select i1 %v5_, i64 0, i64 %v6 + ret i64 %v11 +} diff --git a/test/Transforms/InstCombine/getelementptr.ll b/test/Transforms/InstCombine/getelementptr.ll index ffaa6af..285e0ba 100644 --- a/test/Transforms/InstCombine/getelementptr.ll +++ b/test/Transforms/InstCombine/getelementptr.ll @@ -58,7 +58,7 @@ define i32* @test6() { %B = getelementptr i32* %A, i64 2 ret i32* %B ; CHECK: @test6 -; CHECK: getelementptr [4 x i32]* %M, i64 0, i64 2 +; CHECK: getelementptr i8* %malloccall, i64 8 } define i32* @test7(i32* %I, i64 %C, i64 %D) { diff --git a/test/Transforms/InstCombine/malloc-free-delete.ll b/test/Transforms/InstCombine/malloc-free-delete.ll index 2ed5ec6..fd91e44 100644 --- a/test/Transforms/InstCombine/malloc-free-delete.ll +++ b/test/Transforms/InstCombine/malloc-free-delete.ll @@ -1,5 +1,5 @@ ; RUN: opt < %s -instcombine -S | grep {ret i32 0} -; RUN: opt < %s -instcombine -S | not grep malloc +; RUN: opt < %s -instcombine -globaldce -S | not grep malloc ; PR1201 define i32 @main(i32 %argc, i8** %argv) { %c_19 = alloca i8* ; <i8**> [#uses=2] diff --git a/test/Transforms/InstCombine/malloc2.ll b/test/Transforms/InstCombine/malloc2.ll index 102422e..8462dac 100644 --- a/test/Transforms/InstCombine/malloc2.ll +++ b/test/Transforms/InstCombine/malloc2.ll @@ -1,19 +1,22 @@ -; RUN: opt < %s -instcombine -S | grep {ret i32 0} -; RUN: opt < %s -instcombine -S | not grep malloc +; RUN: opt < %s -instcombine -S | FileCheck %s ; PR1313 define i32 @test1(i32 %argc, i8* %argv, i8* %envp) { %tmp15.i.i.i23 = malloc [2564 x i32] ; <[2564 x i32]*> [#uses=1] +; CHECK-NOT: call i8* @malloc %c = icmp eq [2564 x i32]* %tmp15.i.i.i23, null ; <i1>:0 [#uses=1] %retval = zext i1 %c to i32 ; <i32> [#uses=1] ret i32 %retval +; CHECK: ret i32 0 } define i32 @test2(i32 %argc, i8* %argv, i8* %envp) { %tmp15.i.i.i23 = malloc [2564 x i32] ; <[2564 x i32]*> [#uses=1] +; CHECK-NOT: call i8* @malloc %X = bitcast [2564 x i32]* %tmp15.i.i.i23 to i32* %c = icmp ne i32* %X, null %retval = zext i1 %c to i32 ; <i32> [#uses=1] ret i32 %retval +; CHECK: ret i32 1 } diff --git a/test/Transforms/InstCombine/malloc3.ll b/test/Transforms/InstCombine/malloc3.ll index cd407ff..f1c0cae 100644 --- a/test/Transforms/InstCombine/malloc3.ll +++ b/test/Transforms/InstCombine/malloc3.ll @@ -1,4 +1,4 @@ -; RUN: opt < %s -instcombine -S | grep {malloc.*struct.foo} | count 2 +; RUN: opt < %s -instcombine -S | not grep load ; PR1728 target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128" diff --git a/test/Transforms/JumpThreading/crash.ll b/test/Transforms/JumpThreading/crash.ll index 0b6cd27..023c7d0 100644 --- a/test/Transforms/JumpThreading/crash.ll +++ b/test/Transforms/JumpThreading/crash.ll @@ -54,3 +54,38 @@ bb15: bb61: ret void } + + +; PR5258 +define i32 @test(i1 %cond, i1 %cond2, i32 %a) { +A: + br i1 %cond, label %F, label %A1 +F: + br label %A1 + +A1: + %d = phi i1 [false, %A], [true, %F] + %e = add i32 %a, %a + br i1 %d, label %B, label %G + +G: + br i1 %cond2, label %B, label %D + +B: + %f = phi i32 [%e, %G], [%e, %A1] + %b = add i32 0, 0 + switch i32 %a, label %C [ + i32 7, label %D + i32 8, label %D + i32 9, label %D + ] + +C: + br label %D + +D: + %c = phi i32 [%e, %B], [%e, %B], [%e, %B], [%f, %C], [%e, %G] + ret i32 %c +E: + ret i32 412 +}
\ No newline at end of file diff --git a/test/Transforms/LoopSimplify/unreachable-loop-pred.ll b/test/Transforms/LoopSimplify/unreachable-loop-pred.ll new file mode 100644 index 0000000..faaaf97 --- /dev/null +++ b/test/Transforms/LoopSimplify/unreachable-loop-pred.ll @@ -0,0 +1,20 @@ +; RUN: opt -S -loopsimplify -disable-output -verify-loop-info -verify-dom-info < %s +; PR5235 + +; When loopsimplify inserts a preheader for this loop, it should add the new +; block to the enclosing loop and not get confused by the unreachable +; bogus loop entry. + +define void @is_extract_cab() nounwind { +entry: + br label %header + +header: ; preds = %if.end206, %cond.end66, %if.end23 + br label %while.body115 + +while.body115: ; preds = %9, %if.end192, %if.end101 + br i1 undef, label %header, label %while.body115 + +foo: + br label %while.body115 +} diff --git a/test/Transforms/SCCP/ipsccp-basic.ll b/test/Transforms/SCCP/ipsccp-basic.ll index 7f0772e..d3584d1 100644 --- a/test/Transforms/SCCP/ipsccp-basic.ll +++ b/test/Transforms/SCCP/ipsccp-basic.ll @@ -1,13 +1,136 @@ -; RUN: opt < %s -ipsccp -S | \ -; RUN: grep -v {ret i32 17} | grep -v {ret i32 undef} | not grep ret +; RUN: opt < %s -ipsccp -S | FileCheck %s -define internal i32 @bar(i32 %A) { - %X = add i32 1, 2 ; <i32> [#uses=0] +;;======================== test1 + +define internal i32 @test1a(i32 %A) { + %X = add i32 1, 2 ret i32 %A } +; CHECK: define internal i32 @test1a +; CHECK: ret i32 undef -define i32 @foo() { - %X = call i32 @bar( i32 17 ) ; <i32> [#uses=1] +define i32 @test1b() { + %X = call i32 @test1a( i32 17 ) ret i32 %X + +; CHECK: define i32 @test1b +; CHECK: ret i32 17 +} + + + +;;======================== test2 + +define internal i32 @test2a(i32 %A) { + %C = icmp eq i32 %A, 0 + br i1 %C, label %T, label %F +T: + %B = call i32 @test2a( i32 0 ) + ret i32 0 +F: + %C.upgrd.1 = call i32 @test2a(i32 1) + ret i32 %C.upgrd.1 +} +; CHECK: define internal i32 @test2a +; CHECK-NEXT: br label %T +; CHECK: ret i32 undef + + +define i32 @test2b() { + %X = call i32 @test2a(i32 0) + ret i32 %X +} +; CHECK: define i32 @test2b +; CHECK-NEXT: %X = call i32 @test2a(i32 0) +; CHECK-NEXT: ret i32 0 + + +;;======================== test3 + +@G = internal global i32 undef + +define void @test3a() { + %X = load i32* @G + store i32 %X, i32* @G + ret void +} +; CHECK: define void @test3a +; CHECK-NEXT: ret void + + +define i32 @test3b() { + %V = load i32* @G + %C = icmp eq i32 %V, 17 + br i1 %C, label %T, label %F +T: + store i32 17, i32* @G + ret i32 %V +F: + store i32 123, i32* @G + ret i32 0 +} +; CHECK: define i32 @test3b +; CHECK-NOT: store +; CHECK: ret i32 0 + + +;;======================== test4 + +define internal {i64,i64} @test4a() { + %a = insertvalue {i64,i64} undef, i64 4, 1 + %b = insertvalue {i64,i64} %a, i64 5, 0 + ret {i64,i64} %b +} + +define i64 @test4b() { + %a = invoke {i64,i64} @test4a() + to label %A unwind label %B +A: + %b = extractvalue {i64,i64} %a, 0 + %c = call i64 @test4c(i64 %b) + ret i64 %c +B: + ret i64 0 +} +; CHECK: define i64 @test4b() +; CHECK: %c = call i64 @test4c(i64 5) +; CHECK-NEXT: ret i64 5 + + +define internal i64 @test4c(i64 %a) { + ret i64 %a +} +; CHECK: define internal i64 @test4c +; CHECK: ret i64 undef + + + +;;======================== test5 + +; PR4313 +define internal {i64,i64} @test5a() { + %a = insertvalue {i64,i64} undef, i64 4, 1 + %b = insertvalue {i64,i64} %a, i64 5, 0 + ret {i64,i64} %b +} + +define i64 @test5b() { + %a = invoke {i64,i64} @test5a() + to label %A unwind label %B +A: + %c = call i64 @test5c({i64,i64} %a) + ret i64 %c +B: + ret i64 0 +} + +; CHECK: define i64 @test5b() +; CHECK: A: +; CHECK-NEXT: %c = call i64 @test5c(%0 %a) +; CHECK-NEXT: ret i64 %c + +define internal i64 @test5c({i64,i64} %a) { + %b = extractvalue {i64,i64} %a, 0 + ret i64 %b } diff --git a/test/Transforms/SCCP/sccptest.ll b/test/Transforms/SCCP/sccptest.ll index 6f422f0..a719f6c 100644 --- a/test/Transforms/SCCP/sccptest.ll +++ b/test/Transforms/SCCP/sccptest.ll @@ -1,31 +1,58 @@ +; RUN: opt < %s -sccp -S | FileCheck %s + +; This is a basic sanity check for constant propagation. The add instruction +; should be eliminated. + +define i32 @test1(i1 %B) { + br i1 %B, label %BB1, label %BB2 +BB1: ; preds = %0 + %Val = add i32 0, 0 ; <i32> [#uses=1] + br label %BB3 +BB2: ; preds = %0 + br label %BB3 +BB3: ; preds = %BB2, %BB1 + %Ret = phi i32 [ %Val, %BB1 ], [ 1, %BB2 ] ; <i32> [#uses=1] + ret i32 %Ret + +; CHECK: @test1 +; CHECK: %Ret = phi i32 [ 0, %BB1 ], [ 1, %BB2 ] +} + ; This is the test case taken from appel's book that illustrates a hard case -; that SCCP gets right. BB3 should be completely eliminated. +; that SCCP gets right. ; -; RUN: opt < %s -sccp -constprop -dce -simplifycfg | \ -; RUN: llvm-dis | not grep BB3 - -define i32 @testfunction(i32 %i0, i32 %j0) { +define i32 @test2(i32 %i0, i32 %j0) { +; CHECK: @test2 BB1: br label %BB2 -BB2: ; preds = %BB7, %BB1 - %j2 = phi i32 [ %j4, %BB7 ], [ 1, %BB1 ] ; <i32> [#uses=2] - %k2 = phi i32 [ %k4, %BB7 ], [ 0, %BB1 ] ; <i32> [#uses=4] - %kcond = icmp slt i32 %k2, 100 ; <i1> [#uses=1] +BB2: + %j2 = phi i32 [ %j4, %BB7 ], [ 1, %BB1 ] + %k2 = phi i32 [ %k4, %BB7 ], [ 0, %BB1 ] + %kcond = icmp slt i32 %k2, 100 br i1 %kcond, label %BB3, label %BB4 -BB3: ; preds = %BB2 - %jcond = icmp slt i32 %j2, 20 ; <i1> [#uses=1] +BB3: + %jcond = icmp slt i32 %j2, 20 br i1 %jcond, label %BB5, label %BB6 -BB4: ; preds = %BB2 +; CHECK: BB3: +; CHECK-NEXT: br i1 true, label %BB5, label %BB6 +BB4: ret i32 %j2 -BB5: ; preds = %BB3 - %k3 = add i32 %k2, 1 ; <i32> [#uses=1] +; CHECK: BB4: +; CHECK-NEXT: ret i32 1 +BB5: + %k3 = add i32 %k2, 1 br label %BB7 -BB6: ; preds = %BB3 - %k5 = add i32 %k2, 1 ; <i32> [#uses=1] +BB6: + %k5 = add i32 %k2, 1 br label %BB7 -BB7: ; preds = %BB6, %BB5 - %j4 = phi i32 [ 1, %BB5 ], [ %k2, %BB6 ] ; <i32> [#uses=1] - %k4 = phi i32 [ %k3, %BB5 ], [ %k5, %BB6 ] ; <i32> [#uses=1] +; CHECK: BB6: +; CHECK-NEXT: br label %BB7 +BB7: + %j4 = phi i32 [ 1, %BB5 ], [ %k2, %BB6 ] + %k4 = phi i32 [ %k3, %BB5 ], [ %k5, %BB6 ] br label %BB2 +; CHECK: BB7: +; CHECK-NEXT: %k4 = phi i32 [ %k3, %BB5 ], [ undef, %BB6 ] +; CHECK-NEXT: br label %BB2 } diff --git a/tools/gold/gold-plugin.cpp b/tools/gold/gold-plugin.cpp index 6520617..b1562d1 100644 --- a/tools/gold/gold-plugin.cpp +++ b/tools/gold/gold-plugin.cpp @@ -12,6 +12,7 @@ // //===----------------------------------------------------------------------===// +#include "llvm/Config/config.h" #include "plugin-api.h" #include "llvm-c/lto.h" diff --git a/tools/llc/llc.cpp b/tools/llc/llc.cpp index b94e5fb..84e6867 100644 --- a/tools/llc/llc.cpp +++ b/tools/llc/llc.cpp @@ -298,7 +298,7 @@ int main(int argc, char **argv) { return 1; case ' ': break; case '0': OLvl = CodeGenOpt::None; break; - case '1': + case '1': OLvl = CodeGenOpt::Less; break; case '2': OLvl = CodeGenOpt::Default; break; case '3': OLvl = CodeGenOpt::Aggressive; break; } diff --git a/tools/lli/lli.cpp b/tools/lli/lli.cpp index e5c1070..4578c4e 100644 --- a/tools/lli/lli.cpp +++ b/tools/lli/lli.cpp @@ -148,7 +148,7 @@ int main(int argc, char **argv, char * const *envp) { return 1; case ' ': break; case '0': OLvl = CodeGenOpt::None; break; - case '1': + case '1': OLvl = CodeGenOpt::Less; break; case '2': OLvl = CodeGenOpt::Default; break; case '3': OLvl = CodeGenOpt::Aggressive; break; } @@ -163,7 +163,6 @@ int main(int argc, char **argv, char * const *envp) { exit(1); } - EE->RegisterJITEventListener(createMacOSJITEventListener()); EE->RegisterJITEventListener(createOProfileJITEventListener()); if (NoLazyCompilation) diff --git a/tools/llvm-as/llvm-as.cpp b/tools/llvm-as/llvm-as.cpp index d510297..d39d6c8 100644 --- a/tools/llvm-as/llvm-as.cpp +++ b/tools/llvm-as/llvm-as.cpp @@ -50,34 +50,7 @@ static cl::opt<bool> DisableVerify("disable-verify", cl::Hidden, cl::desc("Do not run verifier on input LLVM (dangerous!)")); -int main(int argc, char **argv) { - // Print a stack trace if we signal out. - sys::PrintStackTraceOnErrorSignal(); - PrettyStackTraceProgram X(argc, argv); - LLVMContext &Context = getGlobalContext(); - llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. - cl::ParseCommandLineOptions(argc, argv, "llvm .ll -> .bc assembler\n"); - - // Parse the file now... - SMDiagnostic Err; - std::auto_ptr<Module> M(ParseAssemblyFile(InputFilename, Err, Context)); - if (M.get() == 0) { - Err.Print(argv[0], errs()); - return 1; - } - - if (!DisableVerify) { - std::string Err; - if (verifyModule(*M.get(), ReturnStatusAction, &Err)) { - errs() << argv[0] - << ": assembly parsed, but does not verify as correct!\n"; - errs() << Err; - return 1; - } - } - - if (DumpAsm) errs() << "Here's the assembly:\n" << *M.get(); - +static void WriteOutputFile(const Module *M) { // Infer the output filename if needed. if (OutputFilename.empty()) { if (InputFilename == "-") { @@ -106,12 +79,43 @@ int main(int argc, char **argv) { raw_fd_ostream::F_Binary)); if (!ErrorInfo.empty()) { errs() << ErrorInfo << '\n'; + exit(1); + } + + if (Force || !CheckBitcodeOutputToConsole(*Out, true)) + WriteBitcodeToFile(M, *Out); +} + +int main(int argc, char **argv) { + // Print a stack trace if we signal out. + sys::PrintStackTraceOnErrorSignal(); + PrettyStackTraceProgram X(argc, argv); + LLVMContext &Context = getGlobalContext(); + llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. + cl::ParseCommandLineOptions(argc, argv, "llvm .ll -> .bc assembler\n"); + + // Parse the file now... + SMDiagnostic Err; + std::auto_ptr<Module> M(ParseAssemblyFile(InputFilename, Err, Context)); + if (M.get() == 0) { + Err.Print(argv[0], errs()); return 1; } + if (!DisableVerify) { + std::string Err; + if (verifyModule(*M.get(), ReturnStatusAction, &Err)) { + errs() << argv[0] + << ": assembly parsed, but does not verify as correct!\n"; + errs() << Err; + return 1; + } + } + + if (DumpAsm) errs() << "Here's the assembly:\n" << *M.get(); + if (!DisableOutput) - if (Force || !CheckBitcodeOutputToConsole(*Out, true)) - WriteBitcodeToFile(M.get(), *Out); + WriteOutputFile(M.get()); + return 0; } - diff --git a/tools/llvm-ld/CMakeLists.txt b/tools/llvm-ld/CMakeLists.txt index 51f0dc1..2ae4a1d 100644 --- a/tools/llvm-ld/CMakeLists.txt +++ b/tools/llvm-ld/CMakeLists.txt @@ -1,5 +1,4 @@ set(LLVM_LINK_COMPONENTS ipo scalaropts linker archive bitwriter) -set(LLVM_REQUIRES_EH 1) add_llvm_tool(llvm-ld Optimize.cpp diff --git a/tools/llvm-ld/Makefile b/tools/llvm-ld/Makefile index 92cac2a..1ef9bf1 100644 --- a/tools/llvm-ld/Makefile +++ b/tools/llvm-ld/Makefile @@ -11,6 +11,5 @@ LEVEL = ../.. TOOLNAME = llvm-ld LINK_COMPONENTS = ipo scalaropts linker archive bitwriter -REQUIRES_EH := 1 include $(LEVEL)/Makefile.common diff --git a/tools/llvm-ld/llvm-ld.cpp b/tools/llvm-ld/llvm-ld.cpp index ef3c250..e71aefc 100644 --- a/tools/llvm-ld/llvm-ld.cpp +++ b/tools/llvm-ld/llvm-ld.cpp @@ -513,205 +513,200 @@ int main(int argc, char **argv, char **envp) { LLVMContext &Context = getGlobalContext(); llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. - try { - // Initial global variable above for convenience printing of program name. - progname = sys::Path(argv[0]).getBasename(); - - // Parse the command line options - cl::ParseCommandLineOptions(argc, argv, "llvm linker\n"); - - // Construct a Linker (now that Verbose is set) - Linker TheLinker(progname, OutputFilename, Context, Verbose); - - // Keep track of the native link items (versus the bitcode items) - Linker::ItemList NativeLinkItems; - - // Add library paths to the linker - TheLinker.addPaths(LibPaths); - TheLinker.addSystemPaths(); - - // Remove any consecutive duplicates of the same library... - Libraries.erase(std::unique(Libraries.begin(), Libraries.end()), - Libraries.end()); - - if (LinkAsLibrary) { - std::vector<sys::Path> Files; - for (unsigned i = 0; i < InputFilenames.size(); ++i ) - Files.push_back(sys::Path(InputFilenames[i])); - if (TheLinker.LinkInFiles(Files)) - return 1; // Error already printed - - // The libraries aren't linked in but are noted as "dependent" in the - // module. - for (cl::list<std::string>::const_iterator I = Libraries.begin(), - E = Libraries.end(); I != E ; ++I) { - TheLinker.getModule()->addLibrary(*I); - } - } else { - // Build a list of the items from our command line - Linker::ItemList Items; - BuildLinkItems(Items, InputFilenames, Libraries); - - // Link all the items together - if (TheLinker.LinkInItems(Items, NativeLinkItems) ) - return 1; // Error already printed + + // Initial global variable above for convenience printing of program name. + progname = sys::Path(argv[0]).getBasename(); + + // Parse the command line options + cl::ParseCommandLineOptions(argc, argv, "llvm linker\n"); + + // Construct a Linker (now that Verbose is set) + Linker TheLinker(progname, OutputFilename, Context, Verbose); + + // Keep track of the native link items (versus the bitcode items) + Linker::ItemList NativeLinkItems; + + // Add library paths to the linker + TheLinker.addPaths(LibPaths); + TheLinker.addSystemPaths(); + + // Remove any consecutive duplicates of the same library... + Libraries.erase(std::unique(Libraries.begin(), Libraries.end()), + Libraries.end()); + + if (LinkAsLibrary) { + std::vector<sys::Path> Files; + for (unsigned i = 0; i < InputFilenames.size(); ++i ) + Files.push_back(sys::Path(InputFilenames[i])); + if (TheLinker.LinkInFiles(Files)) + return 1; // Error already printed + + // The libraries aren't linked in but are noted as "dependent" in the + // module. + for (cl::list<std::string>::const_iterator I = Libraries.begin(), + E = Libraries.end(); I != E ; ++I) { + TheLinker.getModule()->addLibrary(*I); } + } else { + // Build a list of the items from our command line + Linker::ItemList Items; + BuildLinkItems(Items, InputFilenames, Libraries); + + // Link all the items together + if (TheLinker.LinkInItems(Items, NativeLinkItems) ) + return 1; // Error already printed + } - std::auto_ptr<Module> Composite(TheLinker.releaseModule()); + std::auto_ptr<Module> Composite(TheLinker.releaseModule()); - // Optimize the module - Optimize(Composite.get()); + // Optimize the module + Optimize(Composite.get()); #if defined(_WIN32) || defined(__CYGWIN__) - if (!LinkAsLibrary) { - // Default to "a.exe" instead of "a.out". - if (OutputFilename.getNumOccurrences() == 0) - OutputFilename = "a.exe"; - - // If there is no suffix add an "exe" one. - sys::Path ExeFile( OutputFilename ); - if (ExeFile.getSuffix() == "") { - ExeFile.appendSuffix("exe"); - OutputFilename = ExeFile.str(); - } + if (!LinkAsLibrary) { + // Default to "a.exe" instead of "a.out". + if (OutputFilename.getNumOccurrences() == 0) + OutputFilename = "a.exe"; + + // If there is no suffix add an "exe" one. + sys::Path ExeFile( OutputFilename ); + if (ExeFile.getSuffix() == "") { + ExeFile.appendSuffix("exe"); + OutputFilename = ExeFile.str(); } + } #endif - // Generate the bitcode for the optimized module. - // If -b wasn't specified, use the name specified - // with -o to construct BitcodeOutputFilename. - if (BitcodeOutputFilename.empty()) { - BitcodeOutputFilename = OutputFilename; - if (!LinkAsLibrary) BitcodeOutputFilename += ".bc"; - } + // Generate the bitcode for the optimized module. + // If -b wasn't specified, use the name specified + // with -o to construct BitcodeOutputFilename. + if (BitcodeOutputFilename.empty()) { + BitcodeOutputFilename = OutputFilename; + if (!LinkAsLibrary) BitcodeOutputFilename += ".bc"; + } - GenerateBitcode(Composite.get(), BitcodeOutputFilename); - - // If we are not linking a library, generate either a native executable - // or a JIT shell script, depending upon what the user wants. - if (!LinkAsLibrary) { - // If the user wants to run a post-link optimization, run it now. - if (!PostLinkOpts.empty()) { - std::vector<std::string> opts = PostLinkOpts; - for (std::vector<std::string>::iterator I = opts.begin(), - E = opts.end(); I != E; ++I) { - sys::Path prog(*I); - if (!prog.canExecute()) { - prog = sys::Program::FindProgramByName(*I); - if (prog.isEmpty()) - PrintAndExit(std::string("Optimization program '") + *I + - "' is not found or not executable."); - } - // Get the program arguments - sys::Path tmp_output("opt_result"); - std::string ErrMsg; - if (tmp_output.createTemporaryFileOnDisk(true, &ErrMsg)) - PrintAndExit(ErrMsg); - - const char* args[4]; - args[0] = I->c_str(); - args[1] = BitcodeOutputFilename.c_str(); - args[2] = tmp_output.c_str(); - args[3] = 0; - if (0 == sys::Program::ExecuteAndWait(prog, args, 0,0,0,0, &ErrMsg)) { - if (tmp_output.isBitcodeFile() || tmp_output.isBitcodeFile()) { - sys::Path target(BitcodeOutputFilename); - target.eraseFromDisk(); - if (tmp_output.renamePathOnDisk(target, &ErrMsg)) - PrintAndExit(ErrMsg, 2); - } else - PrintAndExit("Post-link optimization output is not bitcode"); - } else { - PrintAndExit(ErrMsg); - } + GenerateBitcode(Composite.get(), BitcodeOutputFilename); + + // If we are not linking a library, generate either a native executable + // or a JIT shell script, depending upon what the user wants. + if (!LinkAsLibrary) { + // If the user wants to run a post-link optimization, run it now. + if (!PostLinkOpts.empty()) { + std::vector<std::string> opts = PostLinkOpts; + for (std::vector<std::string>::iterator I = opts.begin(), + E = opts.end(); I != E; ++I) { + sys::Path prog(*I); + if (!prog.canExecute()) { + prog = sys::Program::FindProgramByName(*I); + if (prog.isEmpty()) + PrintAndExit(std::string("Optimization program '") + *I + + "' is not found or not executable."); } - } - - // If the user wants to generate a native executable, compile it from the - // bitcode file. - // - // Otherwise, create a script that will run the bitcode through the JIT. - if (Native) { - // Name of the Assembly Language output file - sys::Path AssemblyFile ( OutputFilename); - AssemblyFile.appendSuffix("s"); - - // Mark the output files for removal if we get an interrupt. - sys::RemoveFileOnSignal(AssemblyFile); - sys::RemoveFileOnSignal(sys::Path(OutputFilename)); - - // Determine the locations of the llc and gcc programs. - sys::Path llc = FindExecutable("llc", argv[0], - (void *)(intptr_t)&Optimize); - if (llc.isEmpty()) - PrintAndExit("Failed to find llc"); - - sys::Path gcc = sys::Program::FindProgramByName("gcc"); - if (gcc.isEmpty()) - PrintAndExit("Failed to find gcc"); - - // Generate an assembly language file for the bitcode. + // Get the program arguments + sys::Path tmp_output("opt_result"); std::string ErrMsg; - if (0 != GenerateAssembly(AssemblyFile.str(), BitcodeOutputFilename, - llc, ErrMsg)) + if (tmp_output.createTemporaryFileOnDisk(true, &ErrMsg)) PrintAndExit(ErrMsg); - if (0 != GenerateNative(OutputFilename, AssemblyFile.str(), - NativeLinkItems, gcc, envp, ErrMsg)) + const char* args[4]; + args[0] = I->c_str(); + args[1] = BitcodeOutputFilename.c_str(); + args[2] = tmp_output.c_str(); + args[3] = 0; + if (0 == sys::Program::ExecuteAndWait(prog, args, 0,0,0,0, &ErrMsg)) { + if (tmp_output.isBitcodeFile() || tmp_output.isBitcodeFile()) { + sys::Path target(BitcodeOutputFilename); + target.eraseFromDisk(); + if (tmp_output.renamePathOnDisk(target, &ErrMsg)) + PrintAndExit(ErrMsg, 2); + } else + PrintAndExit("Post-link optimization output is not bitcode"); + } else { PrintAndExit(ErrMsg); + } + } + } - // Remove the assembly language file. - AssemblyFile.eraseFromDisk(); - } else if (NativeCBE) { - sys::Path CFile (OutputFilename); - CFile.appendSuffix("cbe.c"); - - // Mark the output files for removal if we get an interrupt. - sys::RemoveFileOnSignal(CFile); - sys::RemoveFileOnSignal(sys::Path(OutputFilename)); - - // Determine the locations of the llc and gcc programs. - sys::Path llc = FindExecutable("llc", argv[0], - (void *)(intptr_t)&Optimize); - if (llc.isEmpty()) - PrintAndExit("Failed to find llc"); + // If the user wants to generate a native executable, compile it from the + // bitcode file. + // + // Otherwise, create a script that will run the bitcode through the JIT. + if (Native) { + // Name of the Assembly Language output file + sys::Path AssemblyFile ( OutputFilename); + AssemblyFile.appendSuffix("s"); + + // Mark the output files for removal if we get an interrupt. + sys::RemoveFileOnSignal(AssemblyFile); + sys::RemoveFileOnSignal(sys::Path(OutputFilename)); + + // Determine the locations of the llc and gcc programs. + sys::Path llc = FindExecutable("llc", argv[0], + (void *)(intptr_t)&Optimize); + if (llc.isEmpty()) + PrintAndExit("Failed to find llc"); + + sys::Path gcc = sys::Program::FindProgramByName("gcc"); + if (gcc.isEmpty()) + PrintAndExit("Failed to find gcc"); + + // Generate an assembly language file for the bitcode. + std::string ErrMsg; + if (0 != GenerateAssembly(AssemblyFile.str(), BitcodeOutputFilename, + llc, ErrMsg)) + PrintAndExit(ErrMsg); - sys::Path gcc = sys::Program::FindProgramByName("gcc"); - if (gcc.isEmpty()) - PrintAndExit("Failed to find gcc"); + if (0 != GenerateNative(OutputFilename, AssemblyFile.str(), + NativeLinkItems, gcc, envp, ErrMsg)) + PrintAndExit(ErrMsg); - // Generate an assembly language file for the bitcode. - std::string ErrMsg; - if (GenerateCFile(CFile.str(), BitcodeOutputFilename, llc, ErrMsg)) - PrintAndExit(ErrMsg); + // Remove the assembly language file. + AssemblyFile.eraseFromDisk(); + } else if (NativeCBE) { + sys::Path CFile (OutputFilename); + CFile.appendSuffix("cbe.c"); - if (GenerateNative(OutputFilename, CFile.str(), - NativeLinkItems, gcc, envp, ErrMsg)) - PrintAndExit(ErrMsg); + // Mark the output files for removal if we get an interrupt. + sys::RemoveFileOnSignal(CFile); + sys::RemoveFileOnSignal(sys::Path(OutputFilename)); - // Remove the assembly language file. - CFile.eraseFromDisk(); + // Determine the locations of the llc and gcc programs. + sys::Path llc = FindExecutable("llc", argv[0], + (void *)(intptr_t)&Optimize); + if (llc.isEmpty()) + PrintAndExit("Failed to find llc"); - } else { - EmitShellScript(argv); - } + sys::Path gcc = sys::Program::FindProgramByName("gcc"); + if (gcc.isEmpty()) + PrintAndExit("Failed to find gcc"); - // Make the script executable... + // Generate an assembly language file for the bitcode. std::string ErrMsg; - if (sys::Path(OutputFilename).makeExecutableOnDisk(&ErrMsg)) + if (GenerateCFile(CFile.str(), BitcodeOutputFilename, llc, ErrMsg)) PrintAndExit(ErrMsg); - // Make the bitcode file readable and directly executable in LLEE as well - if (sys::Path(BitcodeOutputFilename).makeExecutableOnDisk(&ErrMsg)) + if (GenerateNative(OutputFilename, CFile.str(), + NativeLinkItems, gcc, envp, ErrMsg)) PrintAndExit(ErrMsg); - if (sys::Path(BitcodeOutputFilename).makeReadableOnDisk(&ErrMsg)) - PrintAndExit(ErrMsg); + // Remove the assembly language file. + CFile.eraseFromDisk(); + + } else { + EmitShellScript(argv); } - } catch (const std::string& msg) { - PrintAndExit(msg,2); - } catch (...) { - PrintAndExit("Unexpected unknown exception occurred.", 2); + + // Make the script executable... + std::string ErrMsg; + if (sys::Path(OutputFilename).makeExecutableOnDisk(&ErrMsg)) + PrintAndExit(ErrMsg); + + // Make the bitcode file readable and directly executable in LLEE as well + if (sys::Path(BitcodeOutputFilename).makeExecutableOnDisk(&ErrMsg)) + PrintAndExit(ErrMsg); + + if (sys::Path(BitcodeOutputFilename).makeReadableOnDisk(&ErrMsg)) + PrintAndExit(ErrMsg); } // Graceful exit diff --git a/tools/llvm-mc/AsmParser.cpp b/tools/llvm-mc/AsmParser.cpp index aae27f5d..436f17d 100644 --- a/tools/llvm-mc/AsmParser.cpp +++ b/tools/llvm-mc/AsmParser.cpp @@ -21,6 +21,7 @@ #include "llvm/MC/MCSectionMachO.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSymbol.h" +#include "llvm/MC/MCValue.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetAsmParser.h" @@ -220,12 +221,22 @@ bool AsmParser::ParsePrimaryExpr(const MCExpr *&Res) { Res = MCUnaryExpr::CreateLNot(Res, getContext()); return false; case AsmToken::String: - case AsmToken::Identifier: - // This is a label, this should be parsed as part of an expression, to - // handle things like LFOO+4. - Res = MCSymbolRefExpr::Create(Lexer.getTok().getIdentifier(), getContext()); + case AsmToken::Identifier: { + // This is a symbol reference. + MCSymbol *Sym = CreateSymbol(Lexer.getTok().getIdentifier()); Lexer.Lex(); // Eat identifier. + + // If this is an absolute variable reference, substitute it now to preserve + // semantics in the face of reassignment. + if (Sym->getValue() && isa<MCConstantExpr>(Sym->getValue())) { + Res = Sym->getValue(); + return false; + } + + // Otherwise create a symbol ref. + Res = MCSymbolRefExpr::Create(Sym, getContext()); return false; + } case AsmToken::Integer: Res = MCConstantExpr::Create(Lexer.getTok().getIntVal(), getContext()); Lexer.Lex(); // Eat token. @@ -281,7 +292,7 @@ bool AsmParser::ParseAbsoluteExpression(int64_t &Res) { if (ParseExpression(Expr)) return true; - if (!Expr->EvaluateAsAbsolute(Ctx, Res)) + if (!Expr->EvaluateAsAbsolute(Res)) return Error(StartLoc, "expected absolute expression"); return false; @@ -730,14 +741,25 @@ bool AsmParser::ParseAssignment(const StringRef &Name) { // Eat the end of statement marker. Lexer.Lex(); - // Diagnose assignment to a label. - // - // FIXME: Diagnostics. Note the location of the definition as a label. + // Validate that the LHS is allowed to be a variable (either it has not been + // used as a symbol, or it is an absolute symbol). + MCSymbol *Sym = getContext().LookupSymbol(Name); + if (Sym) { + // Diagnose assignment to a label. + // + // FIXME: Diagnostics. Note the location of the definition as a label. + // FIXME: Diagnose assignment to protected identifier (e.g., register name). + if (!Sym->isUndefined() && !Sym->isAbsolute()) + return Error(EqualLoc, "redefinition of '" + Name + "'"); + else if (!Sym->isVariable()) + return Error(EqualLoc, "invalid assignment to '" + Name + "'"); + else if (!isa<MCConstantExpr>(Sym->getValue())) + return Error(EqualLoc, "invalid reassignment of non-absolute variable '" + + Name + "'"); + } else + Sym = CreateSymbol(Name); + // FIXME: Handle '.'. - // FIXME: Diagnose assignment to protected identifier (e.g., register name). - MCSymbol *Sym = CreateSymbol(Name); - if (!Sym->isUndefined() && !Sym->isAbsolute()) - return Error(EqualLoc, "symbol has already been defined"); // Do the assignment. Out.EmitAssignment(Sym, Value); diff --git a/tools/llvm-prof/CMakeLists.txt b/tools/llvm-prof/CMakeLists.txt index 9a51150..442112b 100644 --- a/tools/llvm-prof/CMakeLists.txt +++ b/tools/llvm-prof/CMakeLists.txt @@ -1,5 +1,4 @@ set(LLVM_LINK_COMPONENTS bitreader analysis) -set(LLVM_REQUIRES_EH 1) add_llvm_tool(llvm-prof llvm-prof.cpp diff --git a/tools/llvm-prof/Makefile b/tools/llvm-prof/Makefile index 3c4948e..86eb54d 100644 --- a/tools/llvm-prof/Makefile +++ b/tools/llvm-prof/Makefile @@ -10,7 +10,6 @@ LEVEL = ../.. TOOLNAME = llvm-prof LINK_COMPONENTS = bitreader analysis -REQUIRES_EH := 1 # This tool has no plugins, optimize startup time. TOOL_NO_EXPORTS = 1 diff --git a/tools/llvm-prof/llvm-prof.cpp b/tools/llvm-prof/llvm-prof.cpp index cff139e..88adeb4 100644 --- a/tools/llvm-prof/llvm-prof.cpp +++ b/tools/llvm-prof/llvm-prof.cpp @@ -255,41 +255,34 @@ int main(int argc, char **argv) { LLVMContext &Context = getGlobalContext(); llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. - try { - cl::ParseCommandLineOptions(argc, argv, "llvm profile dump decoder\n"); - - // Read in the bitcode file... - std::string ErrorMessage; - Module *M = 0; - if (MemoryBuffer *Buffer = MemoryBuffer::getFileOrSTDIN(BitcodeFile, - &ErrorMessage)) { - M = ParseBitcodeFile(Buffer, Context, &ErrorMessage); - delete Buffer; - } - if (M == 0) { - errs() << argv[0] << ": " << BitcodeFile << ": " - << ErrorMessage << "\n"; - return 1; - } - - // Read the profiling information. This is redundant since we load it again - // using the standard profile info provider pass, but for now this gives us - // access to additional information not exposed via the ProfileInfo - // interface. - ProfileInfoLoader PIL(argv[0], ProfileDataFile, *M); - - // Run the printer pass. - PassManager PassMgr; - PassMgr.add(createProfileLoaderPass(ProfileDataFile)); - PassMgr.add(new ProfileInfoPrinterPass(PIL)); - PassMgr.run(*M); - - return 0; - } catch (const std::string& msg) { - errs() << argv[0] << ": " << msg << "\n"; - } catch (...) { - errs() << argv[0] << ": Unexpected unknown exception occurred.\n"; - } - return 1; + cl::ParseCommandLineOptions(argc, argv, "llvm profile dump decoder\n"); + + // Read in the bitcode file... + std::string ErrorMessage; + Module *M = 0; + if (MemoryBuffer *Buffer = MemoryBuffer::getFileOrSTDIN(BitcodeFile, + &ErrorMessage)) { + M = ParseBitcodeFile(Buffer, Context, &ErrorMessage); + delete Buffer; + } + if (M == 0) { + errs() << argv[0] << ": " << BitcodeFile << ": " + << ErrorMessage << "\n"; + return 1; + } + + // Read the profiling information. This is redundant since we load it again + // using the standard profile info provider pass, but for now this gives us + // access to additional information not exposed via the ProfileInfo + // interface. + ProfileInfoLoader PIL(argv[0], ProfileDataFile, *M); + + // Run the printer pass. + PassManager PassMgr; + PassMgr.add(createProfileLoaderPass(ProfileDataFile)); + PassMgr.add(new ProfileInfoPrinterPass(PIL)); + PassMgr.run(*M); + + return 0; } diff --git a/tools/llvmc/doc/LLVMC-Reference.rst b/tools/llvmc/doc/LLVMC-Reference.rst index fad2ccc..7041bd1 100644 --- a/tools/llvmc/doc/LLVMC-Reference.rst +++ b/tools/llvmc/doc/LLVMC-Reference.rst @@ -349,8 +349,9 @@ separate option groups syntactically. - ``multi_val n`` - this option takes *n* arguments (can be useful in some special cases). Usage example: ``(parameter_list_option "foo", (multi_val - 3))``. Only list options can have this attribute; you can, however, use - the ``one_or_more`` and ``zero_or_one`` properties. + 3))``; the command-line syntax is '-foo a b c'. Only list options can have + this attribute; you can, however, use the ``one_or_more``, ``zero_or_one`` + and ``required`` properties. - ``init`` - this option has a default value, either a string (if it is a parameter), or a boolean (if it is a switch; boolean constants are called diff --git a/tools/llvmc/example/mcc16/driver/Main.cpp b/tools/llvmc/example/mcc16/driver/Main.cpp index f42e17f..5d50f9d 100644 --- a/tools/llvmc/example/mcc16/driver/Main.cpp +++ b/tools/llvmc/example/mcc16/driver/Main.cpp @@ -13,18 +13,31 @@ // //===----------------------------------------------------------------------===// +#include "llvm/Config/config.h" #include "llvm/CompilerDriver/BuiltinOptions.h" #include "llvm/CompilerDriver/ForceLinkage.h" #include "llvm/System/Path.h" +#include <iostream> namespace llvmc { int Main(int argc, char** argv); } +// Modify the PACKAGE_VERSION to use build number in top level configure file. +void PIC16VersionPrinter(void) { + std::cout << "MPLAB C16 1.0 " << PACKAGE_VERSION << "\n"; +} + int main(int argc, char** argv) { // HACK SaveTemps.setHiddenFlag(llvm::cl::Hidden); + TempDirname.setHiddenFlag(llvm::cl::Hidden); + Languages.setHiddenFlag(llvm::cl::Hidden); + DryRun.setHiddenFlag(llvm::cl::Hidden); + + llvm::cl::SetVersionPrinter(PIC16VersionPrinter); + TempDirname = "tmp-objs"; // Remove the temp dir if already exists. diff --git a/tools/llvmc/example/mcc16/plugins/PIC16Base/PIC16Base.td b/tools/llvmc/example/mcc16/plugins/PIC16Base/PIC16Base.td index 3d25ab6..df9b99e 100644 --- a/tools/llvmc/example/mcc16/plugins/PIC16Base/PIC16Base.td +++ b/tools/llvmc/example/mcc16/plugins/PIC16Base/PIC16Base.td @@ -11,85 +11,149 @@ include "llvm/CompilerDriver/Common.td" def OptionList : OptionList<[ (switch_option "g", (help "Enable Debugging")), + (switch_option "E", + (help "Stop after preprocessing, do not compile")), (switch_option "S", (help "Stop after compilation, do not assemble")), + (switch_option "bc", + (help "Stop after b-code generation, do not compile")), (switch_option "c", (help "Stop after assemble, do not link")), - (parameter_option "I", + (prefix_list_option "I", (help "Add a directory to include path")), - (parameter_option "pre-RA-sched", - (help "Example of an option that is passed to llc")), + (prefix_list_option "L", + (help "Add a directory to library path")), + (prefix_list_option "K", + (help "Add a directory to linker script search path")), + (parameter_option "l", + (help "Specify a library to link")), + (parameter_option "k", + (help "Specify a linker script")), + (parameter_option "m", + (help "Generate linker map file with the given name")), + (prefix_list_option "D", + (help "Define a macro")), + (switch_option "O0", + (help "Do not optimize")), +// (switch_option "O1", +// (help "Optimization level 1")), +// (switch_option "O2", +// (help "Optimization level 2. (Default)")), +// (parameter_option "pre-RA-sched", +// (help "Example of an option that is passed to llc")), (prefix_list_option "Wa,", (help "Pass options to native assembler")), (prefix_list_option "Wl,", - (help "Pass options to native linker")), - (prefix_list_option "Wllc,", - (help "Pass options to llc")), - (prefix_list_option "Wo,", - (help "Pass options to llvm-ld")) + (help "Pass options to native linker")) +// (prefix_list_option "Wllc,", +// (help "Pass options to llc")), +// (prefix_list_option "Wo,", +// (help "Pass options to llvm-ld")) ]>; // Tools - -def clang_cc : Tool<[ - (in_language "c"), +class clang_based<string language, string cmd, string ext_E> : Tool< +[(in_language language), (out_language "llvm-bitcode"), (output_suffix "bc"), - (cmd_line "$CALL(GetBinDir)clang-cc -I $CALL(GetStdHeadersDir) -triple=pic16- -emit-llvm-bc $INFILE -o $OUTFILE"), - (actions (case - (not_empty "I"), (forward "I"))), + (cmd_line (case + (switch_on "E"), + (case + (not_empty "o"), !strconcat(cmd, " -E $INFILE -o $OUTFILE"), + (default), !strconcat(cmd, " -E $INFILE")), + (default), !strconcat(cmd, " $INFILE -o $OUTFILE"))), + (actions (case + (and (multiple_input_files), (or (switch_on "S"), (switch_on "c"))), + (error "cannot specify -o with -c or -S with multiple files"), + (switch_on "E"), [(stop_compilation), (output_suffix ext_E)], + (switch_on "bc"),[(stop_compilation), (output_suffix "bc")], + (switch_on "g"), (append_cmd "-g"), + (not_empty "D"), (forward "D"), + (not_empty "I"), (forward "I"))), (sink) ]>; +def clang_cc : clang_based<"c", "$CALL(GetBinDir)clang-cc -I $CALL(GetStdHeadersDir) -triple=pic16- -emit-llvm-bc ", "i">; + +//def clang_cc : Tool<[ +// (in_language "c"), +// (out_language "llvm-bitcode"), +// (output_suffix "bc"), +// (cmd_line "$CALL(GetBinDir)clang-cc -I $CALL(GetStdHeadersDir) -triple=pic16- -emit-llvm-bc "), +// (cmd_line kkkkk +// (actions (case +// (switch_on "g"), (append_cmd "g"), +// (not_empty "I"), (forward "I"))), +// (sink) +//]>; + + +// pre-link-and-lto step. def llvm_ld : Tool<[ (in_language "llvm-bitcode"), (out_language "llvm-bitcode"), (output_suffix "bc"), - (cmd_line "$CALL(GetBinDir)llvm-ld -link-as-library $INFILE -o $OUTFILE"), + (cmd_line "$CALL(GetBinDir)llvm-ld -L $CALL(GetStdLibsDir) -disable-gvn -instcombine -disable-inlining $INFILE -b $OUTFILE -l std"), (actions (case - (switch_on "g"), (append_cmd "-disable-opt"), - (not_empty "Wo,"), (unpack_values "Wo,"))) + (switch_on "O0"), (append_cmd "-disable-opt"))), + (join) ]>; -def llvm_ld_lto : Tool<[ +// optimize single file +def llvm_ld_optimizer : Tool<[ (in_language "llvm-bitcode"), (out_language "llvm-bitcode"), (output_suffix "bc"), - (cmd_line "$CALL(GetBinDir)llvm-ld -L $CALL(GetStdLibsDir) -l std $INFILE -b $OUTFILE"), + (cmd_line "$CALL(GetBinDir)llvm-ld -disable-gvn -instcombine -disable-inlining $INFILE -b $OUTFILE"), (actions (case - (switch_on "g"), (append_cmd "-disable-opt"), - (not_empty "Wo,"), (unpack_values "Wo,"))), - (join) + (switch_on "O0"), (append_cmd "-disable-opt"))) +]>; + +// optimizer step. +def pic16passes : Tool<[ + (in_language "llvm-bitcode"), + (out_language "llvm-bitcode"), + (output_suffix "obc"), + (cmd_line "$CALL(GetBinDir)opt -pic16cg -pic16overlay $INFILE -f -o $OUTFILE"), + (actions (case + (switch_on "O0"), (append_cmd "-disable-opt"))) ]>; def llc : Tool<[ (in_language "llvm-bitcode"), (out_language "assembler"), (output_suffix "s"), - (cmd_line "$CALL(GetBinDir)llc -march=pic16 -disable-jump-tables -f $INFILE -o $OUTFILE"), + (cmd_line "$CALL(GetBinDir)llc -march=pic16 -disable-jump-tables -pre-RA-sched=list-burr -regalloc=pbqp -f $INFILE -o $OUTFILE"), (actions (case - (switch_on "S"), (stop_compilation), - (not_empty "Wllc,"), (unpack_values "Wllc,"), - (not_empty "pre-RA-sched"), (forward "pre-RA-sched"))) + (switch_on "S"), (stop_compilation))) +// (not_empty "Wllc,"), (unpack_values "Wllc,"), +// (not_empty "pre-RA-sched"), (forward "pre-RA-sched"))) ]>; def gpasm : Tool<[ (in_language "assembler"), (out_language "object-code"), (output_suffix "o"), - (cmd_line "$CALL(GetBinDir)gpasm -r decimal -p p16F1937 -I $CALL(GetStdAsmHeadersDir) -C -c $INFILE -o $OUTFILE"), + (cmd_line "$CALL(GetBinDir)gpasm -r decimal -p p16F1937 -I $CALL(GetStdAsmHeadersDir) -C -c -q $INFILE -o $OUTFILE"), (actions (case (switch_on "c"), (stop_compilation), + (switch_on "g"), (append_cmd "-g"), (not_empty "Wa,"), (unpack_values "Wa,"))) ]>; def mplink : Tool<[ (in_language "object-code"), (out_language "executable"), - (output_suffix "out"), - (cmd_line "$CALL(GetBinDir)mplink.exe -k $CALL(GetStdLinkerScriptsDir) -l $CALL(GetStdLibsDir) 16f1937_g.lkr intrinsics.lib devices.lib $INFILE -o $OUTFILE"), + (output_suffix "cof"), + (cmd_line "$CALL(GetBinDir)mplink.exe -k $CALL(GetStdLinkerScriptsDir) -l $CALL(GetStdLibsDir) -p 16f1937 intrinsics.lib devices.lib $INFILE -o $OUTFILE"), (actions (case - (not_empty "Wl,"), (unpack_values "Wl,"))), + (not_empty "Wl,"), (unpack_values "Wl,"), + (not_empty "L"), (forward_as "L", "-l"), + (not_empty "K"), (forward_as "K", "-k"), + (not_empty "m"), (forward "m"), +// (not_empty "l"), [(unpack_values "l"),(append_cmd ".lib")])), + (not_empty "k"), (unpack_values "k"), + (not_empty "l"), (unpack_values "l"))), (join) ]>; @@ -103,19 +167,26 @@ def LanguageMap : LanguageMap<[ LangToSuffixes<"llvm-assembler", ["ll"]>, LangToSuffixes<"llvm-bitcode", ["bc"]>, LangToSuffixes<"object-code", ["o"]>, - LangToSuffixes<"executable", ["out"]> + LangToSuffixes<"executable", ["cof"]> ]>; // Compilation graph def CompilationGraph : CompilationGraph<[ Edge<"root", "clang_cc">, - Edge<"clang_cc", "llvm_ld_lto">, - Edge<"llvm_ld_lto", "llc">, - OptionalEdge<"clang_cc", "llvm_ld", (case + Edge<"root", "llvm_ld">, + OptionalEdge<"root", "llvm_ld_optimizer", (case + (switch_on "S"), (inc_weight), + (switch_on "c"), (inc_weight))>, + Edge<"root", "gpasm">, + Edge<"root", "mplink">, + Edge<"clang_cc", "llvm_ld">, + OptionalEdge<"clang_cc", "llvm_ld_optimizer", (case (switch_on "S"), (inc_weight), (switch_on "c"), (inc_weight))>, - Edge<"llvm_ld", "llc">, + Edge<"llvm_ld", "pic16passes">, + Edge<"llvm_ld_optimizer", "pic16passes">, + Edge<"pic16passes", "llc">, Edge<"llc", "gpasm">, Edge<"gpasm", "mplink"> ]>; diff --git a/tools/llvmc/example/mcc16/plugins/PIC16Base/PluginMain.cpp b/tools/llvmc/example/mcc16/plugins/PIC16Base/PluginMain.cpp index f8492ed..a6d2ff6 100644 --- a/tools/llvmc/example/mcc16/plugins/PIC16Base/PluginMain.cpp +++ b/tools/llvmc/example/mcc16/plugins/PIC16Base/PluginMain.cpp @@ -10,11 +10,13 @@ namespace llvmc { } // Returns the platform specific directory separator via #ifdefs. +// FIXME: This currently work on linux and windows only. It does not +// work on other unices. static std::string GetDirSeparator() { -#ifdef _WIN32 - return "\\"; -#else +#if __linux__ || __APPLE__ return "/"; +#else + return "\\"; #endif } diff --git a/tools/llvmc/plugins/Base/Base.td.in b/tools/llvmc/plugins/Base/Base.td.in index be325a0..c26a567 100644 --- a/tools/llvmc/plugins/Base/Base.td.in +++ b/tools/llvmc/plugins/Base/Base.td.in @@ -24,6 +24,14 @@ def OptList : OptionList<[ (help "Stop after checking the input for syntax errors")), (switch_option "opt", (help "Enable opt")), + (switch_option "O0", + (help "Turn off optimization")), + (switch_option "O1", + (help "Optimization level 1")), + (switch_option "O2", + (help "Optimization level 2")), + (switch_option "O3", + (help "Optimization level 3")), (switch_option "S", (help "Stop after compilation, do not assemble")), (switch_option "c", @@ -57,6 +65,18 @@ def OptList : OptionList<[ (help "Pass options to opt")) ]>; +// Option preprocessor. + +def Preprocess : OptionPreprocessor< +(case (and (switch_on "O3"), (any_switch_on ["O0", "O1", "O2"])), + (unset_option ["O0", "O1", "O2"]), + (and (switch_on "O2"), (any_switch_on ["O0", "O1"])), + (unset_option ["O0", "O1"]), + (and (switch_on "O1"), (switch_on "O0")), + (unset_option "O0")) +>; + + // Tools class llvm_gcc_based <string cmd_prefix, string in_lang, string E_ext> : Tool< @@ -87,6 +107,9 @@ class llvm_gcc_based <string cmd_prefix, string in_lang, string E_ext> : Tool< (not_empty "include"), (forward "include"), (not_empty "I"), (forward "I"), (not_empty "D"), (forward "D"), + (switch_on "O1"), (forward "O1"), + (switch_on "O2"), (forward "O2"), + (switch_on "O3"), (forward "O3"), (not_empty "MF"), (forward "MF"), (not_empty "MT"), (forward "MT"))), (sink) @@ -103,7 +126,10 @@ def opt : Tool< [(in_language "llvm-bitcode"), (out_language "llvm-bitcode"), (output_suffix "bc"), - (actions (case (not_empty "Wo,"), (unpack_values "Wo,"))), + (actions (case (not_empty "Wo,"), (unpack_values "Wo,"), + (switch_on "O1"), (forward "O1"), + (switch_on "O2"), (forward "O2"), + (switch_on "O3"), (forward "O3"))), (cmd_line "opt -f $INFILE -o $OUTFILE") ]>; @@ -132,6 +158,10 @@ def llc : Tool< (cmd_line "llc -f $INFILE -o $OUTFILE"), (actions (case (switch_on "S"), (stop_compilation), + (switch_on "O0"), (forward "O0"), + (switch_on "O1"), (forward "O1"), + (switch_on "O2"), (forward "O2"), + (switch_on "O3"), (forward "O3"), (not_empty "Wllc,"), (unpack_values "Wllc,"))) ]>; diff --git a/tools/opt/CMakeLists.txt b/tools/opt/CMakeLists.txt index b75cda0..0570d0e 100644 --- a/tools/opt/CMakeLists.txt +++ b/tools/opt/CMakeLists.txt @@ -1,4 +1,3 @@ -set(LLVM_REQUIRES_EH 1) set(LLVM_LINK_COMPONENTS bitreader asmparser bitwriter instrumentation scalaropts ipo) add_llvm_tool(opt diff --git a/tools/opt/Makefile b/tools/opt/Makefile index b17be34..726cad8 100644 --- a/tools/opt/Makefile +++ b/tools/opt/Makefile @@ -8,7 +8,6 @@ ##===----------------------------------------------------------------------===## LEVEL = ../.. TOOLNAME = opt -REQUIRES_EH := 1 LINK_COMPONENTS := bitreader bitwriter asmparser instrumentation scalaropts ipo diff --git a/tools/opt/opt.cpp b/tools/opt/opt.cpp index 5bf39e5..1950a73 100644 --- a/tools/opt/opt.cpp +++ b/tools/opt/opt.cpp @@ -127,6 +127,15 @@ QuietA("quiet", cl::desc("Alias for -q"), cl::aliasopt(Quiet)); static cl::opt<bool> AnalyzeOnly("analyze", cl::desc("Only perform analysis, no optimization")); +static cl::opt<std::string> +DefaultDataLayout("default-data-layout", + cl::desc("data layout string to use if not specified by module"), + cl::value_desc("layout-string"), cl::init("")); + +static cl::opt<bool> +NoDefaultDataLayout("no-default-data-layout", + cl::desc("no data layout assumptions unless module specifies data layout")); + // ---------- Define Printers for module and function passes ------------ namespace { @@ -337,189 +346,187 @@ void AddStandardLinkPasses(PassManager &PM) { int main(int argc, char **argv) { llvm_shutdown_obj X; // Call llvm_shutdown() on exit. LLVMContext &Context = getGlobalContext(); - try { - cl::ParseCommandLineOptions(argc, argv, - "llvm .bc -> .bc modular optimizer and analysis printer\n"); - sys::PrintStackTraceOnErrorSignal(); + + cl::ParseCommandLineOptions(argc, argv, + "llvm .bc -> .bc modular optimizer and analysis printer\n"); + sys::PrintStackTraceOnErrorSignal(); - // Allocate a full target machine description only if necessary. - // FIXME: The choice of target should be controllable on the command line. - std::auto_ptr<TargetMachine> target; + // Allocate a full target machine description only if necessary. + // FIXME: The choice of target should be controllable on the command line. + std::auto_ptr<TargetMachine> target; - SMDiagnostic Err; + SMDiagnostic Err; - // Load the input module... - std::auto_ptr<Module> M; - M.reset(ParseIRFile(InputFilename, Err, Context)); + // Load the input module... + std::auto_ptr<Module> M; + M.reset(ParseIRFile(InputFilename, Err, Context)); - if (M.get() == 0) { - Err.Print(argv[0], errs()); - return 1; - } - - // Figure out what stream we are supposed to write to... - // FIXME: outs() is not binary! - raw_ostream *Out = &outs(); // Default to printing to stdout... - if (OutputFilename != "-") { - // Make sure that the Output file gets unlinked from the disk if we get a - // SIGINT - sys::RemoveFileOnSignal(sys::Path(OutputFilename)); - - std::string ErrorInfo; - Out = new raw_fd_ostream(OutputFilename.c_str(), ErrorInfo, - raw_fd_ostream::F_Binary); - if (!ErrorInfo.empty()) { - errs() << ErrorInfo << '\n'; - delete Out; - return 1; - } - } + if (M.get() == 0) { + Err.Print(argv[0], errs()); + return 1; + } - // If the output is set to be emitted to standard out, and standard out is a - // console, print out a warning message and refuse to do it. We don't - // impress anyone by spewing tons of binary goo to a terminal. - if (!Force && !NoOutput && !OutputAssembly) - if (CheckBitcodeOutputToConsole(*Out, !Quiet)) - NoOutput = true; - - // Create a PassManager to hold and optimize the collection of passes we are - // about to build... - // - PassManager Passes; - - // Add an appropriate TargetData instance for this module... - Passes.add(new TargetData(M.get())); - - FunctionPassManager *FPasses = NULL; - if (OptLevelO1 || OptLevelO2 || OptLevelO3) { - FPasses = new FunctionPassManager(new ExistingModuleProvider(M.get())); - FPasses->add(new TargetData(M.get())); + // Figure out what stream we are supposed to write to... + // FIXME: outs() is not binary! + raw_ostream *Out = &outs(); // Default to printing to stdout... + if (OutputFilename != "-") { + // Make sure that the Output file gets unlinked from the disk if we get a + // SIGINT + sys::RemoveFileOnSignal(sys::Path(OutputFilename)); + + std::string ErrorInfo; + Out = new raw_fd_ostream(OutputFilename.c_str(), ErrorInfo, + raw_fd_ostream::F_Binary); + if (!ErrorInfo.empty()) { + errs() << ErrorInfo << '\n'; + delete Out; + return 1; } + } - // If the -strip-debug command line option was specified, add it. If - // -std-compile-opts was also specified, it will handle StripDebug. - if (StripDebug && !StandardCompileOpts) - addPass(Passes, createStripSymbolsPass(true)); - - // Create a new optimization pass for each one specified on the command line - for (unsigned i = 0; i < PassList.size(); ++i) { - // Check to see if -std-compile-opts was specified before this option. If - // so, handle it. - if (StandardCompileOpts && - StandardCompileOpts.getPosition() < PassList.getPosition(i)) { - AddStandardCompilePasses(Passes); - StandardCompileOpts = false; - } - - if (StandardLinkOpts && - StandardLinkOpts.getPosition() < PassList.getPosition(i)) { - AddStandardLinkPasses(Passes); - StandardLinkOpts = false; - } - - if (OptLevelO1 && OptLevelO1.getPosition() < PassList.getPosition(i)) { - AddOptimizationPasses(Passes, *FPasses, 1); - OptLevelO1 = false; - } - - if (OptLevelO2 && OptLevelO2.getPosition() < PassList.getPosition(i)) { - AddOptimizationPasses(Passes, *FPasses, 2); - OptLevelO2 = false; - } - - if (OptLevelO3 && OptLevelO3.getPosition() < PassList.getPosition(i)) { - AddOptimizationPasses(Passes, *FPasses, 3); - OptLevelO3 = false; - } - - const PassInfo *PassInf = PassList[i]; - Pass *P = 0; - if (PassInf->getNormalCtor()) - P = PassInf->getNormalCtor()(); - else - errs() << argv[0] << ": cannot create pass: " - << PassInf->getPassName() << "\n"; - if (P) { - bool isBBPass = dynamic_cast<BasicBlockPass*>(P) != 0; - bool isLPass = !isBBPass && dynamic_cast<LoopPass*>(P) != 0; - bool isFPass = !isLPass && dynamic_cast<FunctionPass*>(P) != 0; - bool isCGSCCPass = !isFPass && dynamic_cast<CallGraphSCCPass*>(P) != 0; - - addPass(Passes, P); - - if (AnalyzeOnly) { - if (isBBPass) - Passes.add(new BasicBlockPassPrinter(PassInf)); - else if (isLPass) - Passes.add(new LoopPassPrinter(PassInf)); - else if (isFPass) - Passes.add(new FunctionPassPrinter(PassInf)); - else if (isCGSCCPass) - Passes.add(new CallGraphSCCPassPrinter(PassInf)); - else - Passes.add(new ModulePassPrinter(PassInf)); - } - } - - if (PrintEachXForm) - Passes.add(createPrintModulePass(&errs())); - } + // If the output is set to be emitted to standard out, and standard out is a + // console, print out a warning message and refuse to do it. We don't + // impress anyone by spewing tons of binary goo to a terminal. + if (!Force && !NoOutput && !OutputAssembly) + if (CheckBitcodeOutputToConsole(*Out, !Quiet)) + NoOutput = true; + + // Create a PassManager to hold and optimize the collection of passes we are + // about to build... + // + PassManager Passes; + + // Add an appropriate TargetData instance for this module... + TargetData *TD = 0; + const std::string &ModuleDataLayout = M.get()->getDataLayout(); + if (!ModuleDataLayout.empty()) + TD = new TargetData(ModuleDataLayout); + else if (!NoDefaultDataLayout) + TD = new TargetData(DefaultDataLayout); + + if (TD) + Passes.add(TD); + + FunctionPassManager *FPasses = NULL; + if (OptLevelO1 || OptLevelO2 || OptLevelO3) { + FPasses = new FunctionPassManager(new ExistingModuleProvider(M.get())); + if (TD) + FPasses->add(new TargetData(*TD)); + } - // If -std-compile-opts was specified at the end of the pass list, add them. - if (StandardCompileOpts) { + // If the -strip-debug command line option was specified, add it. If + // -std-compile-opts was also specified, it will handle StripDebug. + if (StripDebug && !StandardCompileOpts) + addPass(Passes, createStripSymbolsPass(true)); + + // Create a new optimization pass for each one specified on the command line + for (unsigned i = 0; i < PassList.size(); ++i) { + // Check to see if -std-compile-opts was specified before this option. If + // so, handle it. + if (StandardCompileOpts && + StandardCompileOpts.getPosition() < PassList.getPosition(i)) { AddStandardCompilePasses(Passes); StandardCompileOpts = false; } - if (StandardLinkOpts) { + if (StandardLinkOpts && + StandardLinkOpts.getPosition() < PassList.getPosition(i)) { AddStandardLinkPasses(Passes); StandardLinkOpts = false; } - if (OptLevelO1) { + if (OptLevelO1 && OptLevelO1.getPosition() < PassList.getPosition(i)) { AddOptimizationPasses(Passes, *FPasses, 1); + OptLevelO1 = false; } - if (OptLevelO2) { + if (OptLevelO2 && OptLevelO2.getPosition() < PassList.getPosition(i)) { AddOptimizationPasses(Passes, *FPasses, 2); + OptLevelO2 = false; } - if (OptLevelO3) { + if (OptLevelO3 && OptLevelO3.getPosition() < PassList.getPosition(i)) { AddOptimizationPasses(Passes, *FPasses, 3); + OptLevelO3 = false; } - if (OptLevelO1 || OptLevelO2 || OptLevelO3) { - FPasses->doInitialization(); - for (Module::iterator I = M.get()->begin(), E = M.get()->end(); - I != E; ++I) - FPasses->run(*I); + const PassInfo *PassInf = PassList[i]; + Pass *P = 0; + if (PassInf->getNormalCtor()) + P = PassInf->getNormalCtor()(); + else + errs() << argv[0] << ": cannot create pass: " + << PassInf->getPassName() << "\n"; + if (P) { + bool isBBPass = dynamic_cast<BasicBlockPass*>(P) != 0; + bool isLPass = !isBBPass && dynamic_cast<LoopPass*>(P) != 0; + bool isFPass = !isLPass && dynamic_cast<FunctionPass*>(P) != 0; + bool isCGSCCPass = !isFPass && dynamic_cast<CallGraphSCCPass*>(P) != 0; + + addPass(Passes, P); + + if (AnalyzeOnly) { + if (isBBPass) + Passes.add(new BasicBlockPassPrinter(PassInf)); + else if (isLPass) + Passes.add(new LoopPassPrinter(PassInf)); + else if (isFPass) + Passes.add(new FunctionPassPrinter(PassInf)); + else if (isCGSCCPass) + Passes.add(new CallGraphSCCPassPrinter(PassInf)); + else + Passes.add(new ModulePassPrinter(PassInf)); + } } - // Check that the module is well formed on completion of optimization - if (!NoVerify && !VerifyEach) - Passes.add(createVerifierPass()); + if (PrintEachXForm) + Passes.add(createPrintModulePass(&errs())); + } - // Write bitcode or assembly out to disk or outs() as the last step... - if (!NoOutput && !AnalyzeOnly) { - if (OutputAssembly) - Passes.add(createPrintModulePass(Out)); - else - Passes.add(createBitcodeWriterPass(*Out)); - } + // If -std-compile-opts was specified at the end of the pass list, add them. + if (StandardCompileOpts) { + AddStandardCompilePasses(Passes); + StandardCompileOpts = false; + } - // Now that we have all of the passes ready, run them. - Passes.run(*M.get()); + if (StandardLinkOpts) { + AddStandardLinkPasses(Passes); + StandardLinkOpts = false; + } - // Delete the raw_fd_ostream. - if (Out != &outs()) - delete Out; - return 0; + if (OptLevelO1) + AddOptimizationPasses(Passes, *FPasses, 1); + + if (OptLevelO2) + AddOptimizationPasses(Passes, *FPasses, 2); + + if (OptLevelO3) + AddOptimizationPasses(Passes, *FPasses, 3); - } catch (const std::string& msg) { - errs() << argv[0] << ": " << msg << "\n"; - } catch (...) { - errs() << argv[0] << ": Unexpected unknown exception occurred.\n"; + if (OptLevelO1 || OptLevelO2 || OptLevelO3) { + FPasses->doInitialization(); + for (Module::iterator I = M.get()->begin(), E = M.get()->end(); + I != E; ++I) + FPasses->run(*I); } - llvm_shutdown(); - return 1; + + // Check that the module is well formed on completion of optimization + if (!NoVerify && !VerifyEach) + Passes.add(createVerifierPass()); + + // Write bitcode or assembly out to disk or outs() as the last step... + if (!NoOutput && !AnalyzeOnly) { + if (OutputAssembly) + Passes.add(createPrintModulePass(Out)); + else + Passes.add(createBitcodeWriterPass(*Out)); + } + + // Now that we have all of the passes ready, run them. + Passes.run(*M.get()); + + // Delete the raw_fd_ostream. + if (Out != &outs()) + delete Out; + return 0; } diff --git a/unittests/ADT/ValueMapTest.cpp b/unittests/ADT/ValueMapTest.cpp new file mode 100644 index 0000000..9de340c --- /dev/null +++ b/unittests/ADT/ValueMapTest.cpp @@ -0,0 +1,291 @@ +//===- llvm/unittest/ADT/ValueMapTest.cpp - ValueMap unit tests -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/ValueMap.h" + +#include "llvm/Instructions.h" +#include "llvm/ADT/OwningPtr.h" + +#include "gtest/gtest.h" + +using namespace llvm; + +namespace { + +// Test fixture +template<typename T> +class ValueMapTest : public testing::Test { +protected: + Constant *ConstantV; + OwningPtr<BitCastInst> BitcastV; + OwningPtr<BinaryOperator> AddV; + + ValueMapTest() : + ConstantV(ConstantInt::get(Type::getInt32Ty(getGlobalContext()), 0)), + BitcastV(new BitCastInst(ConstantV, Type::getInt32Ty(getGlobalContext()))), + AddV(BinaryOperator::CreateAdd(ConstantV, ConstantV)) { + } +}; + +// Run everything on Value*, a subtype to make sure that casting works as +// expected, and a const subtype to make sure we cast const correctly. +typedef ::testing::Types<Value, Instruction, const Instruction> KeyTypes; +TYPED_TEST_CASE(ValueMapTest, KeyTypes); + +TYPED_TEST(ValueMapTest, Null) { + ValueMap<TypeParam*, int> VM1; + VM1[NULL] = 7; + EXPECT_EQ(7, VM1.lookup(NULL)); +} + +TYPED_TEST(ValueMapTest, FollowsValue) { + ValueMap<TypeParam*, int> VM; + VM[this->BitcastV.get()] = 7; + EXPECT_EQ(7, VM.lookup(this->BitcastV.get())); + EXPECT_EQ(0, VM.count(this->AddV.get())); + this->BitcastV->replaceAllUsesWith(this->AddV.get()); + EXPECT_EQ(7, VM.lookup(this->AddV.get())); + EXPECT_EQ(0, VM.count(this->BitcastV.get())); + this->AddV.reset(); + EXPECT_EQ(0, VM.count(this->AddV.get())); + EXPECT_EQ(0, VM.count(this->BitcastV.get())); + EXPECT_EQ(0U, VM.size()); +} + +TYPED_TEST(ValueMapTest, OperationsWork) { + ValueMap<TypeParam*, int> VM; + ValueMap<TypeParam*, int> VM2(16); + typename ValueMapConfig<TypeParam*>::ExtraData Data; + ValueMap<TypeParam*, int> VM3(Data, 16); + EXPECT_TRUE(VM.empty()); + + VM[this->BitcastV.get()] = 7; + + // Find: + typename ValueMap<TypeParam*, int>::iterator I = + VM.find(this->BitcastV.get()); + ASSERT_TRUE(I != VM.end()); + EXPECT_EQ(this->BitcastV.get(), I->first); + EXPECT_EQ(7, I->second); + EXPECT_TRUE(VM.find(this->AddV.get()) == VM.end()); + + // Const find: + const ValueMap<TypeParam*, int> &CVM = VM; + typename ValueMap<TypeParam*, int>::const_iterator CI = + CVM.find(this->BitcastV.get()); + ASSERT_TRUE(CI != CVM.end()); + EXPECT_EQ(this->BitcastV.get(), CI->first); + EXPECT_EQ(7, CI->second); + EXPECT_TRUE(CVM.find(this->AddV.get()) == CVM.end()); + + // Insert: + std::pair<typename ValueMap<TypeParam*, int>::iterator, bool> InsertResult1 = + VM.insert(std::make_pair(this->AddV.get(), 3)); + EXPECT_EQ(this->AddV.get(), InsertResult1.first->first); + EXPECT_EQ(3, InsertResult1.first->second); + EXPECT_TRUE(InsertResult1.second); + EXPECT_EQ(true, VM.count(this->AddV.get())); + std::pair<typename ValueMap<TypeParam*, int>::iterator, bool> InsertResult2 = + VM.insert(std::make_pair(this->AddV.get(), 5)); + EXPECT_EQ(this->AddV.get(), InsertResult2.first->first); + EXPECT_EQ(3, InsertResult2.first->second); + EXPECT_FALSE(InsertResult2.second); + + // Erase: + VM.erase(InsertResult2.first); + EXPECT_EQ(false, VM.count(this->AddV.get())); + EXPECT_EQ(true, VM.count(this->BitcastV.get())); + VM.erase(this->BitcastV.get()); + EXPECT_EQ(false, VM.count(this->BitcastV.get())); + EXPECT_EQ(0U, VM.size()); + + // Range insert: + SmallVector<std::pair<Instruction*, int>, 2> Elems; + Elems.push_back(std::make_pair(this->AddV.get(), 1)); + Elems.push_back(std::make_pair(this->BitcastV.get(), 2)); + VM.insert(Elems.begin(), Elems.end()); + EXPECT_EQ(1, VM.lookup(this->AddV.get())); + EXPECT_EQ(2, VM.lookup(this->BitcastV.get())); +} + +template<typename ExpectedType, typename VarType> +void CompileAssertHasType(VarType) { + typedef char assert[is_same<ExpectedType, VarType>::value ? 1 : -1]; +} + +TYPED_TEST(ValueMapTest, Iteration) { + ValueMap<TypeParam*, int> VM; + VM[this->BitcastV.get()] = 2; + VM[this->AddV.get()] = 3; + size_t size = 0; + for (typename ValueMap<TypeParam*, int>::iterator I = VM.begin(), E = VM.end(); + I != E; ++I) { + ++size; + std::pair<TypeParam*, int> value = *I; + CompileAssertHasType<TypeParam*>(I->first); + if (I->second == 2) { + EXPECT_EQ(this->BitcastV.get(), I->first); + I->second = 5; + } else if (I->second == 3) { + EXPECT_EQ(this->AddV.get(), I->first); + I->second = 6; + } else { + ADD_FAILURE() << "Iterated through an extra value."; + } + } + EXPECT_EQ(2U, size); + EXPECT_EQ(5, VM[this->BitcastV.get()]); + EXPECT_EQ(6, VM[this->AddV.get()]); + + size = 0; + // Cast to const ValueMap to avoid a bug in DenseMap's iterators. + const ValueMap<TypeParam*, int>& CVM = VM; + for (typename ValueMap<TypeParam*, int>::const_iterator I = CVM.begin(), + E = CVM.end(); I != E; ++I) { + ++size; + std::pair<TypeParam*, int> value = *I; + CompileAssertHasType<TypeParam*>(I->first); + if (I->second == 5) { + EXPECT_EQ(this->BitcastV.get(), I->first); + } else if (I->second == 6) { + EXPECT_EQ(this->AddV.get(), I->first); + } else { + ADD_FAILURE() << "Iterated through an extra value."; + } + } + EXPECT_EQ(2U, size); +} + +TYPED_TEST(ValueMapTest, DefaultCollisionBehavior) { + // By default, we overwrite the old value with the replaced value. + ValueMap<TypeParam*, int> VM; + VM[this->BitcastV.get()] = 7; + VM[this->AddV.get()] = 9; + this->BitcastV->replaceAllUsesWith(this->AddV.get()); + EXPECT_EQ(0, VM.count(this->BitcastV.get())); + EXPECT_EQ(9, VM.lookup(this->AddV.get())); +} + +TYPED_TEST(ValueMapTest, ConfiguredCollisionBehavior) { + // TODO: Implement this when someone needs it. +} + +template<typename KeyT> +struct LockMutex : ValueMapConfig<KeyT> { + struct ExtraData { + sys::Mutex *M; + bool *CalledRAUW; + bool *CalledDeleted; + }; + static void onRAUW(const ExtraData &Data, KeyT Old, KeyT New) { + *Data.CalledRAUW = true; + EXPECT_FALSE(Data.M->tryacquire()) << "Mutex should already be locked."; + } + static void onDeleted(const ExtraData &Data, KeyT Old) { + *Data.CalledDeleted = true; + EXPECT_FALSE(Data.M->tryacquire()) << "Mutex should already be locked."; + } + static sys::Mutex *getMutex(const ExtraData &Data) { return Data.M; } +}; +TYPED_TEST(ValueMapTest, LocksMutex) { + sys::Mutex M(false); // Not recursive. + bool CalledRAUW = false, CalledDeleted = false; + typename LockMutex<TypeParam*>::ExtraData Data = + {&M, &CalledRAUW, &CalledDeleted}; + ValueMap<TypeParam*, int, LockMutex<TypeParam*> > VM(Data); + VM[this->BitcastV.get()] = 7; + this->BitcastV->replaceAllUsesWith(this->AddV.get()); + this->AddV.reset(); + EXPECT_TRUE(CalledRAUW); + EXPECT_TRUE(CalledDeleted); +} + +template<typename KeyT> +struct NoFollow : ValueMapConfig<KeyT> { + enum { FollowRAUW = false }; +}; + +TYPED_TEST(ValueMapTest, NoFollowRAUW) { + ValueMap<TypeParam*, int, NoFollow<TypeParam*> > VM; + VM[this->BitcastV.get()] = 7; + EXPECT_EQ(7, VM.lookup(this->BitcastV.get())); + EXPECT_EQ(0, VM.count(this->AddV.get())); + this->BitcastV->replaceAllUsesWith(this->AddV.get()); + EXPECT_EQ(7, VM.lookup(this->BitcastV.get())); + EXPECT_EQ(0, VM.lookup(this->AddV.get())); + this->AddV.reset(); + EXPECT_EQ(7, VM.lookup(this->BitcastV.get())); + EXPECT_EQ(0, VM.lookup(this->AddV.get())); + this->BitcastV.reset(); + EXPECT_EQ(0, VM.lookup(this->BitcastV.get())); + EXPECT_EQ(0, VM.lookup(this->AddV.get())); + EXPECT_EQ(0U, VM.size()); +} + +template<typename KeyT> +struct CountOps : ValueMapConfig<KeyT> { + struct ExtraData { + int *Deletions; + int *RAUWs; + }; + + static void onRAUW(const ExtraData &Data, KeyT Old, KeyT New) { + ++*Data.RAUWs; + } + static void onDeleted(const ExtraData &Data, KeyT Old) { + ++*Data.Deletions; + } +}; + +TYPED_TEST(ValueMapTest, CallsConfig) { + int Deletions = 0, RAUWs = 0; + typename CountOps<TypeParam*>::ExtraData Data = {&Deletions, &RAUWs}; + ValueMap<TypeParam*, int, CountOps<TypeParam*> > VM(Data); + VM[this->BitcastV.get()] = 7; + this->BitcastV->replaceAllUsesWith(this->AddV.get()); + EXPECT_EQ(0, Deletions); + EXPECT_EQ(1, RAUWs); + this->AddV.reset(); + EXPECT_EQ(1, Deletions); + EXPECT_EQ(1, RAUWs); + this->BitcastV.reset(); + EXPECT_EQ(1, Deletions); + EXPECT_EQ(1, RAUWs); +} + +template<typename KeyT> +struct ModifyingConfig : ValueMapConfig<KeyT> { + // We'll put a pointer here back to the ValueMap this key is in, so + // that we can modify it (and clobber *this) before the ValueMap + // tries to do the same modification. In previous versions of + // ValueMap, that exploded. + typedef ValueMap<KeyT, int, ModifyingConfig<KeyT> > **ExtraData; + + static void onRAUW(ExtraData Map, KeyT Old, KeyT New) { + (*Map)->erase(Old); + } + static void onDeleted(ExtraData Map, KeyT Old) { + (*Map)->erase(Old); + } +}; +TYPED_TEST(ValueMapTest, SurvivesModificationByConfig) { + ValueMap<TypeParam*, int, ModifyingConfig<TypeParam*> > *MapAddress; + ValueMap<TypeParam*, int, ModifyingConfig<TypeParam*> > VM(&MapAddress); + MapAddress = &VM; + // Now the ModifyingConfig can modify the Map inside a callback. + VM[this->BitcastV.get()] = 7; + this->BitcastV->replaceAllUsesWith(this->AddV.get()); + EXPECT_FALSE(VM.count(this->BitcastV.get())); + EXPECT_FALSE(VM.count(this->AddV.get())); + VM[this->AddV.get()] = 7; + this->AddV.reset(); + EXPECT_FALSE(VM.count(this->AddV.get())); +} + +} diff --git a/unittests/ExecutionEngine/JIT/JITMemoryManagerTest.cpp b/unittests/ExecutionEngine/JIT/JITMemoryManagerTest.cpp index 89a4be7..f0c491f 100644 --- a/unittests/ExecutionEngine/JIT/JITMemoryManagerTest.cpp +++ b/unittests/ExecutionEngine/JIT/JITMemoryManagerTest.cpp @@ -32,37 +32,36 @@ TEST(JITMemoryManagerTest, NoAllocations) { OwningPtr<JITMemoryManager> MemMgr( JITMemoryManager::CreateDefaultMemManager()); uintptr_t size; - uint8_t *start; std::string Error; // Allocate the functions. OwningPtr<Function> F1(makeFakeFunction()); size = 1024; - start = MemMgr->startFunctionBody(F1.get(), size); - memset(start, 0xFF, 1024); - MemMgr->endFunctionBody(F1.get(), start, start + 1024); + uint8_t *FunctionBody1 = MemMgr->startFunctionBody(F1.get(), size); + memset(FunctionBody1, 0xFF, 1024); + MemMgr->endFunctionBody(F1.get(), FunctionBody1, FunctionBody1 + 1024); EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error; OwningPtr<Function> F2(makeFakeFunction()); size = 1024; - start = MemMgr->startFunctionBody(F2.get(), size); - memset(start, 0xFF, 1024); - MemMgr->endFunctionBody(F2.get(), start, start + 1024); + uint8_t *FunctionBody2 = MemMgr->startFunctionBody(F2.get(), size); + memset(FunctionBody2, 0xFF, 1024); + MemMgr->endFunctionBody(F2.get(), FunctionBody2, FunctionBody2 + 1024); EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error; OwningPtr<Function> F3(makeFakeFunction()); size = 1024; - start = MemMgr->startFunctionBody(F3.get(), size); - memset(start, 0xFF, 1024); - MemMgr->endFunctionBody(F3.get(), start, start + 1024); + uint8_t *FunctionBody3 = MemMgr->startFunctionBody(F3.get(), size); + memset(FunctionBody3, 0xFF, 1024); + MemMgr->endFunctionBody(F3.get(), FunctionBody3, FunctionBody3 + 1024); EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error; // Deallocate them out of order, in case that matters. - MemMgr->deallocateMemForFunction(F2.get()); + MemMgr->deallocateFunctionBody(FunctionBody2); EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error; - MemMgr->deallocateMemForFunction(F1.get()); + MemMgr->deallocateFunctionBody(FunctionBody1); EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error; - MemMgr->deallocateMemForFunction(F3.get()); + MemMgr->deallocateFunctionBody(FunctionBody3); EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error; } @@ -72,7 +71,6 @@ TEST(JITMemoryManagerTest, TestCodeAllocation) { OwningPtr<JITMemoryManager> MemMgr( JITMemoryManager::CreateDefaultMemManager()); uintptr_t size; - uint8_t *start; std::string Error; // Big functions are a little less than the largest block size. @@ -83,26 +81,26 @@ TEST(JITMemoryManagerTest, TestCodeAllocation) { // Allocate big functions OwningPtr<Function> F1(makeFakeFunction()); size = bigFuncSize; - start = MemMgr->startFunctionBody(F1.get(), size); + uint8_t *FunctionBody1 = MemMgr->startFunctionBody(F1.get(), size); ASSERT_LE(bigFuncSize, size); - memset(start, 0xFF, bigFuncSize); - MemMgr->endFunctionBody(F1.get(), start, start + bigFuncSize); + memset(FunctionBody1, 0xFF, bigFuncSize); + MemMgr->endFunctionBody(F1.get(), FunctionBody1, FunctionBody1 + bigFuncSize); EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error; OwningPtr<Function> F2(makeFakeFunction()); size = bigFuncSize; - start = MemMgr->startFunctionBody(F2.get(), size); + uint8_t *FunctionBody2 = MemMgr->startFunctionBody(F2.get(), size); ASSERT_LE(bigFuncSize, size); - memset(start, 0xFF, bigFuncSize); - MemMgr->endFunctionBody(F2.get(), start, start + bigFuncSize); + memset(FunctionBody2, 0xFF, bigFuncSize); + MemMgr->endFunctionBody(F2.get(), FunctionBody2, FunctionBody2 + bigFuncSize); EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error; OwningPtr<Function> F3(makeFakeFunction()); size = bigFuncSize; - start = MemMgr->startFunctionBody(F3.get(), size); + uint8_t *FunctionBody3 = MemMgr->startFunctionBody(F3.get(), size); ASSERT_LE(bigFuncSize, size); - memset(start, 0xFF, bigFuncSize); - MemMgr->endFunctionBody(F3.get(), start, start + bigFuncSize); + memset(FunctionBody3, 0xFF, bigFuncSize); + MemMgr->endFunctionBody(F3.get(), FunctionBody3, FunctionBody3 + bigFuncSize); EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error; // Check that each large function took it's own slab. @@ -111,43 +109,46 @@ TEST(JITMemoryManagerTest, TestCodeAllocation) { // Allocate small functions OwningPtr<Function> F4(makeFakeFunction()); size = smallFuncSize; - start = MemMgr->startFunctionBody(F4.get(), size); + uint8_t *FunctionBody4 = MemMgr->startFunctionBody(F4.get(), size); ASSERT_LE(smallFuncSize, size); - memset(start, 0xFF, smallFuncSize); - MemMgr->endFunctionBody(F4.get(), start, start + smallFuncSize); + memset(FunctionBody4, 0xFF, smallFuncSize); + MemMgr->endFunctionBody(F4.get(), FunctionBody4, + FunctionBody4 + smallFuncSize); EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error; OwningPtr<Function> F5(makeFakeFunction()); size = smallFuncSize; - start = MemMgr->startFunctionBody(F5.get(), size); + uint8_t *FunctionBody5 = MemMgr->startFunctionBody(F5.get(), size); ASSERT_LE(smallFuncSize, size); - memset(start, 0xFF, smallFuncSize); - MemMgr->endFunctionBody(F5.get(), start, start + smallFuncSize); + memset(FunctionBody5, 0xFF, smallFuncSize); + MemMgr->endFunctionBody(F5.get(), FunctionBody5, + FunctionBody5 + smallFuncSize); EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error; OwningPtr<Function> F6(makeFakeFunction()); size = smallFuncSize; - start = MemMgr->startFunctionBody(F6.get(), size); + uint8_t *FunctionBody6 = MemMgr->startFunctionBody(F6.get(), size); ASSERT_LE(smallFuncSize, size); - memset(start, 0xFF, smallFuncSize); - MemMgr->endFunctionBody(F6.get(), start, start + smallFuncSize); + memset(FunctionBody6, 0xFF, smallFuncSize); + MemMgr->endFunctionBody(F6.get(), FunctionBody6, + FunctionBody6 + smallFuncSize); EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error; // Check that the small functions didn't allocate any new slabs. EXPECT_EQ(3U, MemMgr->GetNumCodeSlabs()); // Deallocate them out of order, in case that matters. - MemMgr->deallocateMemForFunction(F2.get()); + MemMgr->deallocateFunctionBody(FunctionBody2); EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error; - MemMgr->deallocateMemForFunction(F1.get()); + MemMgr->deallocateFunctionBody(FunctionBody1); EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error; - MemMgr->deallocateMemForFunction(F4.get()); + MemMgr->deallocateFunctionBody(FunctionBody4); EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error; - MemMgr->deallocateMemForFunction(F3.get()); + MemMgr->deallocateFunctionBody(FunctionBody3); EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error; - MemMgr->deallocateMemForFunction(F5.get()); + MemMgr->deallocateFunctionBody(FunctionBody5); EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error; - MemMgr->deallocateMemForFunction(F6.get()); + MemMgr->deallocateFunctionBody(FunctionBody6); EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error; } diff --git a/unittests/ExecutionEngine/JIT/JITTest.cpp b/unittests/ExecutionEngine/JIT/JITTest.cpp index d7aaea7..8f9b65a 100644 --- a/unittests/ExecutionEngine/JIT/JITTest.cpp +++ b/unittests/ExecutionEngine/JIT/JITTest.cpp @@ -166,7 +166,7 @@ TEST_F(JITTest, FarCallToKnownFunction) { EXPECT_EQ(8, TestFunctionPtr()); } -#if !defined(__arm__) && !defined(__ppc__) +#if !defined(__arm__) && !defined(__powerpc__) && !defined(__ppc__) // Test a function C which calls A and B which call each other. TEST_F(JITTest, NonLazyCompilationStillNeedsStubs) { TheJIT->DisableLazyCompilation(); @@ -221,7 +221,6 @@ TEST_F(JITTest, NonLazyCompilationStillNeedsStubs) { F1Ptr(); } -#endif // Regression test for PR5162. This used to trigger an AssertingVH inside the // JIT's Function to stub mapping. @@ -263,6 +262,7 @@ TEST_F(JITTest, NonLazyLeaksNoStubs) { EXPECT_EQ(Func2->getNumUses(), 0u); Func2->eraseFromParent(); } +#endif // This code is copied from JITEventListenerTest, but it only runs once for all // the tests in this directory. Everything seems fine, but that's strange diff --git a/unittests/Support/raw_ostream_test.cpp b/unittests/Support/raw_ostream_test.cpp index bd2e95c..2b797b4 100644 --- a/unittests/Support/raw_ostream_test.cpp +++ b/unittests/Support/raw_ostream_test.cpp @@ -127,4 +127,20 @@ TEST(raw_ostreamTest, TinyBuffer) { EXPECT_EQ("hello1world", OS.str()); } +TEST(raw_ostreamTest, WriteEscaped) { + std::string Str; + + Str = ""; + raw_string_ostream(Str).write_escaped("hi"); + EXPECT_EQ("hi", Str); + + Str = ""; + raw_string_ostream(Str).write_escaped("\\\t\n\""); + EXPECT_EQ("\\\\\\t\\n\\\"", Str); + + Str = ""; + raw_string_ostream(Str).write_escaped("\1\10\200"); + EXPECT_EQ("\\001\\010\\200", Str); +} + } diff --git a/utils/NewNightlyTest.pl b/utils/NewNightlyTest.pl index 477df8f..ed22b77 100755 --- a/utils/NewNightlyTest.pl +++ b/utils/NewNightlyTest.pl @@ -15,19 +15,48 @@ use Socket; # Syntax: NightlyTest.pl [OPTIONS] [CVSROOT BUILDDIR WEBDIR] # where # OPTIONS may include one or more of the following: +# +# MAIN OPTIONS: +# -config LLVMPATH If specified, use an existing LLVM build and only run and +# report the test information. The LLVMCONFIG argument should +# be the path to the llvm-config executable in the LLVM build. +# This should be the first argument if given. NOT YET +# IMPLEMENTED. +# -nickname NAME The NAME argument specifieds the nickname this script +# will submit to the nightlytest results repository. +# -submit-server Specifies a server to submit the test results too. If this +# option is not specified it defaults to +# llvm.org. This is basically just the address of the +# webserver +# -submit-script Specifies which script to call on the submit server. If +# this option is not specified it defaults to +# /nightlytest/NightlyTestAccept.php. This is basically +# everything after the www.yourserver.org. +# -submit-aux If specified, an auxiliary script to run in addition to the +# normal submit script. The script will be passed the path to +# the "sentdata.txt" file as its sole argument. +# -nosubmit Do not report the test results back to a submit server. +# +# +# BUILD OPTIONS (not used with -config): # -nocheckout Do not create, checkout, update, or configure # the source tree. # -noremove Do not remove the BUILDDIR after it has been built. # -noremoveresults Do not remove the WEBDIR after it has been built. # -nobuild Do not build llvm. If tests are enabled perform them # on the llvm build specified in the build directory -# -notest Do not even attempt to run the test programs. -# -nodejagnu Do not run feature or regression tests -# -parallel Run parallel jobs with GNU Make (see -parallel-jobs). -# -parallel-jobs The number of parallel Make jobs to use (default is two). -# -with-clang Checkout Clang source into tools/clang. # -release Build an LLVM Release version # -release-asserts Build an LLVM ReleaseAsserts version +# -disable-bindings Disable building LLVM bindings. +# -with-clang Checkout Clang source into tools/clang. +# -compileflags Next argument specifies extra options passed to make when +# building LLVM. +# -use-gmake Use gmake instead of the default make command to build +# llvm and run tests. +# +# TESTING OPTIONS: +# -notest Do not even attempt to run the test programs. +# -nodejagnu Do not run feature or regression tests # -enable-llcbeta Enable testing of beta features in llc. # -enable-lli Enable testing of lli (interpreter) features, default is off # -disable-pic Disable building with Position Independent Code. @@ -35,19 +64,25 @@ use Socket; # -disable-jit Disable JIT tests in the nightly tester. # -disable-cbe Disable C backend tests in the nightly tester. # -disable-lto Disable link time optimization. -# -disable-bindings Disable building LLVM bindings. +# -test-cflags Next argument specifies that C compilation options that +# override the default when running the testsuite. +# -test-cxxflags Next argument specifies that C++ compilation options that +# override the default when running the testsuite. +# -extraflags Next argument specifies extra options that are passed to +# compile the tests. +# -noexternals Do not run the external tests (for cases where povray +# or SPEC are not installed) +# -with-externals Specify a directory where the external tests are located. +# +# OTHER OPTIONS: +# -parallel Run parallel jobs with GNU Make (see -parallel-jobs). +# -parallel-jobs The number of parallel Make jobs to use (default is two). +# -parallel-test Allow parallel execution of llvm-test # -verbose Turn on some debug output -# -debug Print information useful only to maintainers of this script. # -nice Checkout/Configure/Build with "nice" to reduce impact # on busy servers. # -f2c Next argument specifies path to F2C utility -# -nickname The next argument specifieds the nickname this script -# will submit to the nightlytest results repository. # -gccpath Path to gcc/g++ used to build LLVM -# -cvstag Check out a specific CVS tag to build LLVM (useful for -# testing release branches) -# -usecvs Check code out from the (old) CVS Repository instead of from -# the standard Subversion repository. # -target Specify the target triplet # -cflags Next argument specifies that C compilation options that # override the default. @@ -55,40 +90,11 @@ use Socket; # override the default. # -ldflags Next argument specifies that linker options that override # the default. -# -test-cflags Next argument specifies that C compilation options that -# override the default when running the testsuite. -# -test-cxxflags Next argument specifies that C++ compilation options that -# override the default when running the testsuite. -# -compileflags Next argument specifies extra options passed to make when -# building LLVM. -# -use-gmake Use gmake instead of the default make command to build -# llvm and run tests. -# -# ---------------- Options to configure llvm-test ---------------------------- -# -extraflags Next argument specifies extra options that are passed to -# compile the tests. -# -noexternals Do not run the external tests (for cases where povray -# or SPEC are not installed) -# -with-externals Specify a directory where the external tests are located. -# -submit-server Specifies a server to submit the test results too. If this -# option is not specified it defaults to -# llvm.org. This is basically just the address of the -# webserver -# -submit-script Specifies which script to call on the submit server. If -# this option is not specified it defaults to -# /nightlytest/NightlyTestAccept.php. This is basically -# everything after the www.yourserver.org. -# -submit-aux If specified, an auxiliary script to run in addition to the -# normal submit script. The script will be passed the path to -# the "sentdata.txt" file as its sole argument. -# -nosubmit Do not report the test results back to a submit server. # -# CVSROOT is the CVS repository from which the tree will be checked out, -# specified either in the full :method:user@host:/dir syntax, or -# just /dir if using a local repo. +# CVSROOT is ignored, it is passed for backwards compatibility. # BUILDDIR is the directory where sources for this test run will be checked out # AND objects for this test run will be built. This directory MUST NOT -# exist before the script is run; it will be created by the cvs checkout +# exist before the script is run; it will be created by the svn checkout # process and erased (unless -noremove is specified; see above.) # WEBDIR is the directory into which the test results web page will be written, # AND in which the "index.html" is assumed to be a symlink to the most recent @@ -106,12 +112,8 @@ my $SVNURL = $ENV{"SVNURL"}; $SVNURL = 'http://llvm.org/svn/llvm-project' unless $SVNURL; my $TestSVNURL = $ENV{"TestSVNURL"}; $TestSVNURL = 'http://llvm.org/svn/llvm-project' unless $TestSVNURL; -my $CVSRootDir = $ENV{'CVSROOT'}; -$CVSRootDir = "/home/vadve/shared/PublicCVS" unless $CVSRootDir; my $BuildDir = $ENV{'BUILDDIR'}; -$BuildDir = "$HOME/buildtest" unless $BuildDir; my $WebDir = $ENV{'WEBDIR'}; -$WebDir = "$HOME/cvs/testresults-X86" unless $WebDir; my $LLVMSrcDir = $ENV{'LLVMSRCDIR'}; $LLVMSrcDir = "$BuildDir/llvm" unless $LLVMSrcDir; @@ -133,10 +135,10 @@ my $DATE = sprintf "%4d-%02d-%02d_%02d-%02d", $TIME[5]+1900, $TIME[4]+1, $TIME[3 # Parse arguments... # ############################################################## +$CONFIG_PATH=""; $CONFIGUREARGS=""; $nickname=""; $NOTEST=0; -$USESVN=1; $MAKECMD="make"; $SUBMITSERVER = "llvm.org"; $SUBMITSCRIPT = "/nightlytest/NightlyTestAccept.php"; @@ -150,22 +152,22 @@ while (scalar(@ARGV) and ($_ = $ARGV[0], /^[-+]/)) { last if /^--$/; # Stop processing arguments on -- # List command line options here... + if (/^-config$/) { $CONFIG_PATH = "$ARGV[0]"; shift; next; } if (/^-nocheckout$/) { $NOCHECKOUT = 1; next; } - if (/^-nocvsstats$/) { $NOCVSSTATS = 1; next; } if (/^-noremove$/) { $NOREMOVE = 1; next; } if (/^-noremoveatend$/) { $NOREMOVEATEND = 1; next; } if (/^-noremoveresults$/){ $NOREMOVERESULTS = 1; next; } if (/^-notest$/) { $NOTEST = 1; next; } if (/^-norunningtests$/) { next; } # Backward compatibility, ignored. if (/^-parallel-jobs$/) { $PARALLELJOBS = "$ARGV[0]"; shift; next;} - if (/^-parallel$/) { $MAKEOPTS = "$MAKEOPTS -j$PARALLELJOBS -l3.0"; next; } + if (/^-parallel$/) { $MAKEOPTS = "$MAKEOPTS -j$PARALLELJOBS"; next; } + if (/^-parallel-test$/) { $PROGTESTOPTS .= " ENABLE_PARALLEL_REPORT=1"; next; } if (/^-with-clang$/) { $WITHCLANG = 1; next; } if (/^-release$/) { $MAKEOPTS = "$MAKEOPTS ENABLE_OPTIMIZED=1 ". - "OPTIMIZE_OPTION=-O2"; $BUILDTYPE="release"; next;} + "OPTIMIZE_OPTION=-O2"; next;} if (/^-release-asserts$/){ $MAKEOPTS = "$MAKEOPTS ENABLE_OPTIMIZED=1 ". "DISABLE_ASSERTIONS=1 ". - "OPTIMIZE_OPTION=-O2"; - $BUILDTYPE="release-asserts"; next;} + "OPTIMIZE_OPTION=-O2"; next;} if (/^-enable-llcbeta$/) { $PROGTESTOPTS .= " ENABLE_LLCBETA=1"; next; } if (/^-disable-pic$/) { $CONFIGUREARGS .= " --enable-pic=no"; next; } if (/^-enable-lli$/) { $PROGTESTOPTS .= " ENABLE_LLI=1"; @@ -180,7 +182,6 @@ while (scalar(@ARGV) and ($_ = $ARGV[0], /^[-+]/)) { if (/^-test-opts$/) { $PROGTESTOPTS .= " $ARGV[0]"; shift; next; } if (/^-verbose$/) { $VERBOSE = 1; next; } if (/^-teelogs$/) { $TEELOGS = 1; next; } - if (/^-debug$/) { $DEBUG = 1; next; } if (/^-nice$/) { $NICE = "nice "; next; } if (/^-f2c$/) { $CONFIGUREARGS .= " --with-f2c=$ARGV[0]"; shift; next; } @@ -197,9 +198,6 @@ while (scalar(@ARGV) and ($_ = $ARGV[0], /^[-+]/)) { " CC=$ARGV[0]/gcc CXX=$ARGV[0]/g++"; $GCCPATH=$ARGV[0]; shift; next; } else { $GCCPATH=""; } - if (/^-cvstag/) { $CVSCOOPT .= " -r $ARGV[0]"; shift; next; } - else { $CVSCOOPT="";} - if (/^-usecvs/) { $USESVN = 0; } if (/^-target/) { $CONFIGUREARGS .= " --target=$ARGV[0]"; shift; next; } if (/^-cflags/) { $MAKEOPTS = "$MAKEOPTS C.Flags=\'$ARGV[0]\'"; @@ -234,75 +232,62 @@ if ($CONFIGUREARGS !~ /--disable-jit/) { $CONFIGUREARGS .= " --enable-jit"; } -if (@ARGV != 0 and @ARGV != 3 and $VERBOSE) { - foreach $x (@ARGV) { - print "$x\n"; - } - print "Must specify 0 or 3 options!"; +if (@ARGV != 0 and @ARGV != 3) { + die "error: must specify 0 or 3 options!"; } if (@ARGV == 3) { - $CVSRootDir = $ARGV[0]; + if ($CONFIG_PATH ne "") { + die "error: arguments are unsupported in -config mode,"; + } + + # ARGV[0] used to be the CVS root, ignored for backward compatibility. $BuildDir = $ARGV[1]; $WebDir = $ARGV[2]; } -if ($CVSRootDir eq "" or - $BuildDir eq "" or - $WebDir eq "") { - die("please specify a cvs root directory, a build directory, and a ". - "web directory"); - } +if ($CONFIG_PATH ne "") { + $BuildDir = ""; + $SVNURL = $TestSVNURL = ""; + if ($WebDir eq "") { + die("please specify a web directory"); + } +} else { + if ($BuildDir eq "" or + $WebDir eq "") { + die("please specify a build directory, and a web directory"); + } +} if ($nickname eq "") { die ("Please invoke NewNightlyTest.pl with command line option " . "\"-nickname <nickname>\""); } -if ($BUILDTYPE ne "release" && $BUILDTYPE ne "release-asserts") { - $BUILDTYPE = "debug"; -} - ############################################################## # -#define the file names we'll use +# Define the file names we'll use # ############################################################## + my $Prefix = "$WebDir/$DATE"; -my $BuildLog = "$Prefix-Build-Log.txt"; -my $COLog = "$Prefix-CVS-Log.txt"; my $SingleSourceLog = "$Prefix-SingleSource-ProgramTest.txt.gz"; my $MultiSourceLog = "$Prefix-MultiSource-ProgramTest.txt.gz"; my $ExternalLog = "$Prefix-External-ProgramTest.txt.gz"; -my $DejagnuLog = "$Prefix-Dejagnu-testrun.log"; -my $DejagnuSum = "$Prefix-Dejagnu-testrun.sum"; -my $DejagnuTestsLog = "$Prefix-DejagnuTests-Log.txt"; -if (! -d $WebDir) { - mkdir $WebDir, 0777; - if($VERBOSE){ - warn "$WebDir did not exist; creating it.\n"; - } -} -if ($VERBOSE) { - print "INITIALIZED\n"; - if ($USESVN) { - print "SVN URL = $SVNURL\n"; - } else { - print "CVS Root = $CVSRootDir\n"; - } - print "COLog = $COLog\n"; - print "BuildDir = $BuildDir\n"; - print "WebDir = $WebDir\n"; - print "Prefix = $Prefix\n"; - print "BuildLog = $BuildLog\n"; -} +# These are only valid in non-config mode. +my $ConfigureLog = "", $BuildLog = "", $COLog = ""; +my $DejagnuLog = "", $DejagnuSum = "", $DejagnuLog = ""; + +# Are we in config mode? +my $ConfigMode = 0; ############################################################## # # Helper functions # ############################################################## + sub GetDir { my $Suffix = shift; opendir DH, $WebDir; @@ -349,61 +334,25 @@ sub RunAppendingLoggedCommand { } } -#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -# -# DiffFiles - Diff the current version of the file against the last version of -# the file, reporting things added and removed. This is used to report, for -# example, added and removed warnings. This returns a pair (added, removed) -# -#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -sub DiffFiles { - my $Suffix = shift; - my @Others = GetDir $Suffix; - if (@Others == 0) { # No other files? We added all entries... - return (`cat $WebDir/$DATE$Suffix`, ""); - } -# Diff the files now... - my @Diffs = split "\n", `diff $WebDir/$DATE$Suffix $WebDir/$Others[0]`; - my $Added = join "\n", grep /^</, @Diffs; - my $Removed = join "\n", grep /^>/, @Diffs; - $Added =~ s/^< //gm; - $Removed =~ s/^> //gm; - return ($Added, $Removed); -} - -#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ sub GetRegex { # (Regex with ()'s, value) - $_[1] =~ /$_[0]/m; - return $1 - if (defined($1)); + if ($_[1] =~ /$_[0]/m) { + return $1; + } return "0"; } -#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -sub GetRegexNum { - my ($Regex, $Num, $Regex2, $File) = @_; - my @Items = split "\n", `grep '$Regex' $File`; - return GetRegex $Regex2, $Items[$Num]; -} - -#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ sub ChangeDir { # directory, logical name my ($dir,$name) = @_; chomp($dir); if ( $VERBOSE ) { print "Changing To: $name ($dir)\n"; } $result = chdir($dir); if (!$result) { - print "ERROR!!! Cannot change directory to: $name ($dir) because $!"; + print "ERROR!!! Cannot change directory to: $name ($dir) because $!\n"; return false; } return true; } -#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ sub ReadFile { if (open (FILE, $_[0])) { undef $/; @@ -417,16 +366,12 @@ sub ReadFile { } } -#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ sub WriteFile { # (filename, contents) open (FILE, ">$_[0]") or die "Could not open file '$_[0]' for writing!\n"; print FILE $_[1]; close FILE; } -#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ sub CopyFile { #filename, newfile my ($file, $newfile) = @_; chomp($file); @@ -435,32 +380,6 @@ sub CopyFile { #filename, newfile } #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -sub AddRecord { - my ($Val, $Filename,$WebDir) = @_; - my @Records; - if (open FILE, "$WebDir/$Filename") { - @Records = grep !/$DATE/, split "\n", <FILE>; - close FILE; - } - push @Records, "$DATE: $Val"; - WriteFile "$WebDir/$Filename", (join "\n", @Records) . "\n"; -} - -#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -# -# FormatTime - Convert a time from 1m23.45 into 83.45 -# -#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -sub FormatTime { - my $Time = shift; - if ($Time =~ m/([0-9]+)m([0-9.]+)/) { - $Time = sprintf("%7.4f", $1*60.0+$2); - } - return $Time; -} - -#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # # This function is meant to read in the dejagnu sum file and # return a string with only the results (i.e. PASS/FAIL/XPASS/ @@ -499,10 +418,10 @@ sub GetDejagnuTestResults { # (filename, log) # to our central server via the post method # #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -sub SendData{ +sub SendData { $host = $_[0]; $file = $_[1]; - $variables=$_[2]; + $variables = $_[2]; # Write out the "...-sentdata.txt" file. @@ -517,7 +436,7 @@ sub SendData{ system "$SUBMITAUX \"$Prefix-sentdata.txt\""; } - if (!$SUBMIT) { + if (!$SUBMIT) { return "Skipped standard submit.\n"; } @@ -531,9 +450,9 @@ sub SendData{ } # Send the data to the server. - # + # # FIXME: This code should be more robust? - + $port=80; $socketaddr= sockaddr_in $port, inet_aton $host or die "Bad hostname\n"; socket SOCK, PF_INET, SOCK_STREAM, getprotobyname('tcp') or @@ -561,17 +480,13 @@ sub SendData{ ############################################################## # -# Getting Start timestamp +# Individual Build & Test Functions # ############################################################## -$starttime = `date "+20%y-%m-%d %H:%M:%S"`; -############################################################## -# -# Create the CVS repository directory -# -############################################################## -if (!$NOCHECKOUT) { +# Create the source repository directory. +sub CheckoutSource { + die "Invalid call!" unless $ConfigMode == 0; if (-d $BuildDir) { if (!$NOREMOVE) { if ( $VERBOSE ) { @@ -587,341 +502,54 @@ if (!$NOCHECKOUT) { } else { mkdir $BuildDir or die "Could not create checkout directory $BuildDir!"; } -} - -############################################################## -# -# Check out the llvm tree, using either SVN or CVS -# -############################################################## -if (!$NOCHECKOUT) { ChangeDir( $BuildDir, "checkout directory" ); - if ($USESVN) { - my $SVNCMD = "$NICE svn co --non-interactive $SVNURL"; - my $SVNCMD2 = "$NICE svn co --non-interactive $TestSVNURL"; - RunLoggedCommand("( time -p $SVNCMD/llvm/trunk llvm; cd llvm/projects ; " . - "$SVNCMD2/test-suite/trunk llvm-test )", $COLog, - "CHECKOUT LLVM"); - if ($WITHCLANG) { - my $SVNCMD = "$NICE svn co --non-interactive $SVNURL/cfe/trunk"; - RunLoggedCommand("( time -p cd llvm/tools ; $SVNCMD clang )", $COLog, - "CHECKOUT CLANG"); - } - } else { - my $CVSOPT = ""; - $CVSOPT = "-z3" # Use compression if going over ssh. - if $CVSRootDir =~ /^:ext:/; - my $CVSCMD = "$NICE cvs $CVSOPT -d $CVSRootDir co -P $CVSCOOPT"; - RunLoggedCommand("( time -p $CVSCMD llvm; cd llvm/projects ; " . - "$CVSCMD llvm-test )", $COLog, - "CHECKOUT LLVM-TEST"); + my $SVNCMD = "$NICE svn co --non-interactive"; + RunLoggedCommand("( time -p $SVNCMD $SVNURL/llvm/trunk llvm; cd llvm/projects ; " . + " $SVNCMD $TestSVNURL/test-suite/trunk llvm-test )", $COLog, + "CHECKOUT LLVM"); + if ($WITHCLANG) { + RunLoggedCommand("( cd llvm/tools ; " . + " $SVNCMD $SVNURL/cfe/trunk clang )", $COLog, + "CHECKOUT CLANG"); } } -ChangeDir( $LLVMSrcDir , "llvm source directory") ; -############################################################## -# -# Get some static statistics about the current state of CVS -# -# This can probably be put on the server side -# -############################################################## -my $CheckoutTime_Wall = GetRegex "([0-9.]+)", `grep '^real' $COLog`; -my $CheckoutTime_User = GetRegex "([0-9.]+)", `grep '^user' $COLog`; -my $CheckoutTime_Sys = GetRegex "([0-9.]+)", `grep '^sys' $COLog`; -my $CheckoutTime_CPU = $CVSCheckoutTime_User + $CVSCheckoutTime_Sys; - -my $NumFilesInCVS = 0; -my $NumDirsInCVS = 0; -if ($USESVN) { - $NumFilesInCVS = `egrep '^A' $COLog | wc -l` + 0; - $NumDirsInCVS = `sed -e 's#/[^/]*\$##' $COLog | sort | uniq | wc -l` + 0; -} else { - $NumFilesInCVS = `egrep '^U' $COLog | wc -l` + 0; - $NumDirsInCVS = `egrep '^cvs (checkout|server|update):' $COLog | wc -l` + 0; -} - -############################################################## -# -# Extract some information from the CVS history... use a hash so no duplicate -# stuff is stored. This gets the history from the previous days worth -# of cvs activity and parses it. -# -############################################################## - -# This just computes a reasonably accurate #of seconds since 2000. It doesn't -# have to be perfect as its only used for comparing date ranges within a couple -# of days. -sub ConvertToSeconds { - my ($sec, $min, $hour, $day, $mon, $yr) = @_; - my $Result = ($yr - 2000) * 12; - $Result += $mon; - $Result *= 31; - $Result += $day; - $Result *= 24; - $Result += $hour; - $Result *= 60; - $Result += $min; - $Result *= 60; - $Result += $sec; - return $Result; -} - -my (%AddedFiles, %ModifiedFiles, %RemovedFiles, %UsersCommitted, %UsersUpdated); - -if (!$NOCVSSTATS) { - if ($VERBOSE) { print "CHANGE HISTORY ANALYSIS STAGE\n"; } - - if ($USESVN) { - @SVNHistory = split /<logentry/, `svn log --non-interactive --xml --verbose -r{$DATE}:HEAD`; - # Skip very first entry because it is the XML header cruft - shift @SVNHistory; - my $Now = time(); - foreach $Record (@SVNHistory) { - my @Lines = split "\n", $Record; - my ($Author, $Date, $Revision); - # Get the date and see if its one we want to process. - my ($Year, $Month, $Day, $Hour, $Min, $Sec); - if ($Lines[3] =~ /<date>(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})/){ - $Year = $1; $Month = $2; $Day = $3; $Hour = $4; $Min = $5; $Sec = $6; - } - my $Then = ConvertToSeconds($Sec, $Min, $Hour, $Day, $Month, $Year); - # Get the current date and compute when "yesterday" is. - my ($NSec, $NMin, $NHour, $NDay, $NMon, $NYear) = gmtime(); - my $Now = ConvertToSeconds( $NSec, $NMin, $NHour, $NDay, $NMon, $NYear); - if (($Now - 24*60*60) > $Then) { - next; - } - if ($Lines[1] =~ / revision="([0-9]*)">/) { - $Revision = $1; - } - if ($Lines[2] =~ /<author>([^<]*)<\/author>/) { - $Author = $1; - } - $UsersCommitted{$Author} = 1; - $Date = $Year . "-" . $Month . "-" . $Day; - $Time = $Hour . ":" . $Min . ":" . $Sec; - print "Rev: $Revision, Author: $Author, Date: $Date, Time: $Time\n"; - for ($i = 6; $i < $#Lines; $i += 2 ) { - if ($Lines[$i] =~ /^ action="(.)">([^<]*)</) { - if ($1 == "A") { - $AddedFiles{$2} = 1; - } elsif ($1 == 'D') { - $RemovedFiles{$2} = 1; - } elsif ($1 == 'M' || $1 == 'R' || $1 == 'C') { - $ModifiedFiles{$2} = 1; - } else { - print "UNMATCHABLE: $Lines[$i]\n"; - } - } - } - } - } else { - @CVSHistory = split "\n", `cvs history -D '1 day ago' -a -xAMROCGUW`; -#print join "\n", @CVSHistory; print "\n"; - - my $DateRE = '[-/:0-9 ]+\+[0-9]+'; - -# Loop over every record from the CVS history, filling in the hashes. - foreach $File (@CVSHistory) { - my ($Type, $Date, $UID, $Rev, $Filename); - if ($File =~ /([AMRUGC]) ($DateRE) ([^ ]+) +([^ ]+) +([^ ]+) +([^ ]+)/) { - ($Type, $Date, $UID, $Rev, $Filename) = ($1, $2, $3, $4, "$6/$5"); - } elsif ($File =~ /([W]) ($DateRE) ([^ ]+)/) { - ($Type, $Date, $UID, $Rev, $Filename) = ($1, $2, $3, "", ""); - } elsif ($File =~ /([O]) ($DateRE) ([^ ]+) +([^ ]+)/) { - ($Type, $Date, $UID, $Rev, $Filename) = ($1, $2, $3, "", "$4/"); - } else { - print "UNMATCHABLE: $File\n"; - next; - } - # print "$File\nTy = $Type Date = '$Date' UID=$UID Rev=$Rev File = '$Filename'\n"; - - if ($Filename =~ /^llvm/) { - if ($Type eq 'M') { # Modified - $ModifiedFiles{$Filename} = 1; - $UsersCommitted{$UID} = 1; - } elsif ($Type eq 'A') { # Added - $AddedFiles{$Filename} = 1; - $UsersCommitted{$UID} = 1; - } elsif ($Type eq 'R') { # Removed - $RemovedFiles{$Filename} = 1; - $UsersCommitted{$UID} = 1; - } else { - $UsersUpdated{$UID} = 1; - } - } - } - - my $TestError = 1; - } #$USESVN -}#!NOCVSSTATS - -my $CVSAddedFiles = join "\n", sort keys %AddedFiles; -my $CVSModifiedFiles = join "\n", sort keys %ModifiedFiles; -my $CVSRemovedFiles = join "\n", sort keys %RemovedFiles; -my $UserCommitList = join "\n", sort keys %UsersCommitted; -my $UserUpdateList = join "\n", sort keys %UsersUpdated; - -############################################################## -# -# Build the entire tree, saving build messages to the build log -# -############################################################## -if (!$NOCHECKOUT && !$NOBUILD) { +# Build the entire tree, saving build messages to the build log. Returns false +# on build failure. +sub BuildLLVM { + die "Invalid call!" unless $ConfigMode == 0; my $EXTRAFLAGS = "--enable-spec --with-objroot=."; RunLoggedCommand("(time -p $NICE ./configure $CONFIGUREARGS $EXTRAFLAGS) ", - $BuildLog, "CONFIGURE"); + $ConfigureLog, "CONFIGURE"); # Build the entire tree, capturing the output into $BuildLog - RunAppendingLoggedCommand("(time -p $NICE $MAKECMD clean)", $BuildLog, "BUILD CLEAN"); + RunAppendingLoggedCommand("($NICE $MAKECMD $MAKEOPTS clean)", $BuildLog, "BUILD CLEAN"); RunAppendingLoggedCommand("(time -p $NICE $MAKECMD $MAKEOPTS)", $BuildLog, "BUILD"); -} -############################################################## -# -# Get some statistics about the build... -# -############################################################## -#this can de done on server -#my @Linked = split '\n', `grep Linking $BuildLog`; -#my $NumExecutables = scalar(grep(/executable/, @Linked)); -#my $NumLibraries = scalar(grep(!/executable/, @Linked)); -#my $NumObjects = `grep ']\: Compiling ' $BuildLog | wc -l` + 0; - -# Get the number of lines of source code. Must be here after the build is done -# because countloc.sh uses the llvm-config script which must be built. -my $LOC = `utils/countloc.sh -topdir $LLVMSrcDir`; - -# Get the time taken by the configure script -my $ConfigTimeU = GetRegexNum "^user", 0, "([0-9.]+)", "$BuildLog"; -my $ConfigTimeS = GetRegexNum "^sys", 0, "([0-9.]+)", "$BuildLog"; -my $ConfigTime = $ConfigTimeU+$ConfigTimeS; # ConfigTime = User+System -my $ConfigWallTime = GetRegexNum "^real", 0,"([0-9.]+)","$BuildLog"; - -$ConfigTime=-1 unless $ConfigTime; -$ConfigWallTime=-1 unless $ConfigWallTime; - -my $BuildTimeU = GetRegexNum "^user", 1, "([0-9.]+)", "$BuildLog"; -my $BuildTimeS = GetRegexNum "^sys", 1, "([0-9.]+)", "$BuildLog"; -my $BuildTime = $BuildTimeU+$BuildTimeS; # BuildTime = User+System -my $BuildWallTime = GetRegexNum "^real", 1, "([0-9.]+)","$BuildLog"; - -$BuildTime=-1 unless $BuildTime; -$BuildWallTime=-1 unless $BuildWallTime; - -my $BuildError = 0, $BuildStatus = "OK"; -if ($NOBUILD) { - $BuildStatus = "Skipped by user"; -} -elsif (`grep '^$MAKECMD\[^:]*: .*Error' $BuildLog | wc -l` + 0 || - `grep '^$MAKECMD: \*\*\*.*Stop.' $BuildLog | wc -l`+0) { - $BuildStatus = "Error: compilation aborted"; - $BuildError = 1; - if( $VERBOSE) { print "\n***ERROR BUILDING TREE\n\n"; } -} -if ($BuildError) { $NODEJAGNU=1; } - -my $a_file_sizes=""; -my $o_file_sizes=""; -if (!$BuildError) { - print "Organizing size of .o and .a files\n" - if ( $VERBOSE ); - ChangeDir( "$LLVMObjDir", "Build Directory" ); - - my @dirs = ('utils', 'lib', 'tools'); - if($BUILDTYPE eq "release"){ - push @dirs, 'Release'; - } elsif($BUILDTYPE eq "release-asserts") { - push @dirs, 'Release-Asserts'; - } else { - push @dirs, 'Debug'; + if (`grep '^$MAKECMD\[^:]*: .*Error' $BuildLog | wc -l` + 0 || + `grep '^$MAKECMD: \*\*\*.*Stop.' $BuildLog | wc -l` + 0) { + return 0; } - find(sub { - $a_file_sizes .= (-s $_)." $File::Find::name $BUILDTYPE\n" if /\.a$/i; - $o_file_sizes .= (-s $_)." $File::Find::name $BUILDTYPE\n" if /\.o$/i; - }, @dirs); -} else { - $a_file_sizes="No data due to a bad build."; - $o_file_sizes="No data due to a bad build."; + return 1; } -############################################################## -# -# Running dejagnu tests -# -############################################################## -my $DejangnuTestResults=""; # String containing the results of the dejagnu -my $dejagnu_output = "$DejagnuTestsLog"; -if (!$NODEJAGNU) { - #Run the feature and regression tests, results are put into testrun.sum - #Full log in testrun.log - RunLoggedCommand("(time -p $MAKECMD $MAKEOPTS check)", $dejagnu_output, "DEJAGNU"); - - #Copy the testrun.log and testrun.sum to our webdir +# Running dejagnu tests and save results to log. +sub RunDejaGNUTests { + die "Invalid call!" unless $ConfigMode == 0; + # Run the feature and regression tests, results are put into testrun.sum and + # the full log in testrun.log. + system "rm -f test/testrun.log test/testrun.sum"; + RunLoggedCommand("(time -p $MAKECMD $MAKEOPTS check)", $DejagnuLog, "DEJAGNU"); + + # Copy the testrun.log and testrun.sum to our webdir. CopyFile("test/testrun.log", $DejagnuLog); CopyFile("test/testrun.sum", $DejagnuSum); - #can be done on server - $DejagnuTestResults = GetDejagnuTestResults($DejagnuSum, $DejagnuLog); - $unexpfail_tests = $DejagnuTestResults; -} - -#Extract time of dejagnu tests -my $DejagnuTimeU = GetRegexNum "^user", 0, "([0-9.]+)", "$dejagnu_output"; -my $DejagnuTimeS = GetRegexNum "^sys", 0, "([0-9.]+)", "$dejagnu_output"; -$DejagnuTime = $DejagnuTimeU+$DejagnuTimeS; # DejagnuTime = User+System -$DejagnuWallTime = GetRegexNum "^real", 0,"([0-9.]+)","$dejagnu_output"; -$DejagnuTestResults = - "Dejagnu skipped by user choice." unless $DejagnuTestResults; -$DejagnuTime = "0.0" unless $DejagnuTime; -$DejagnuWallTime = "0.0" unless $DejagnuWallTime; -############################################################## -# -# Get warnings from the build -# -############################################################## -if (!$NODEJAGNU) { - if ( $VERBOSE ) { print "BUILD INFORMATION COLLECTION STAGE\n"; } - my @Warn = split "\n", `egrep 'warning:|Entering dir' $BuildLog`; - my @Warnings; - my $CurDir = ""; - - foreach $Warning (@Warn) { - if ($Warning =~ m/Entering directory \`([^\`]+)\'/) { - $CurDir = $1; # Keep track of directory warning is in... - # Remove buildir prefix if included - if ($CurDir =~ m#$LLVMSrcDir/(.*)#) { $CurDir = $1; } - } else { - push @Warnings, "$CurDir/$Warning"; # Add directory to warning... - } - } - my $WarningsFile = join "\n", @Warnings; - $WarningsFile =~ s/:[0-9]+:/::/g; - - # Emit the warnings file, so we can diff... - WriteFile "$WebDir/$DATE-Warnings.txt", $WarningsFile . "\n"; - my ($WarningsAdded, $WarningsRemoved) = DiffFiles "-Warnings.txt"; - - # Output something to stdout if something has changed - #print "ADDED WARNINGS:\n$WarningsAdded\n\n" if (length $WarningsAdded); - #print "REMOVED WARNINGS:\n$WarningsRemoved\n\n" if (length $WarningsRemoved); - - #my @TmpWarningsAdded = split "\n", $WarningsAdded; ~PJ on upgrade - #my @TmpWarningsRemoved = split "\n", $WarningsRemoved; ~PJ on upgrade - -} #endif !NODEGAGNU - -############################################################## -# -# If we built the tree successfully, run the nightly programs tests... -# -# A set of tests to run is passed in (i.e. "SingleSource" "MultiSource" -# "External") -# -############################################################## + return GetDejagnuTestResults($DejagnuSum, $DejagnuLog); +} +# Run the named tests (i.e. "SingleSource" "MultiSource" "External") sub TestDirectory { my $SubDir = shift; ChangeDir( "$LLVMTestDir/$SubDir", @@ -929,55 +557,47 @@ sub TestDirectory { my $ProgramTestLog = "$Prefix-$SubDir-ProgramTest.txt"; - # Run the programs tests... creating a report.nightly.csv file - if (!$NOTEST) { - if( $VERBOSE) { - print "$MAKECMD -k $MAKEOPTS $PROGTESTOPTS report.nightly.csv ". - "$TESTFLAGS TEST=nightly > $ProgramTestLog 2>&1\n"; - } - RunLoggedCommand("$MAKECMD -k $MAKEOPTS $PROGTESTOPTS report.nightly.csv ". - "$TESTFLAGS TEST=nightly", + # Make sure to clean things if in non-config mode. + if ($ConfigMode == 1) { + RunLoggedCommand("$MAKECMD -k $MAKEOPTS $PROGTESTOPTS clean $TESTFLAGS", $ProgramTestLog, "TEST DIRECTORY $SubDir"); - $llcbeta_options=`$MAKECMD print-llcbeta-option`; } + # Run the programs tests... creating a report.nightly.csv file. + my $LLCBetaOpts = ""; + RunLoggedCommand("$MAKECMD -k $MAKEOPTS $PROGTESTOPTS report.nightly.csv ". + "$TESTFLAGS TEST=nightly", + $ProgramTestLog, "TEST DIRECTORY $SubDir"); + $LLCBetaOpts = `$MAKECMD print-llcbeta-option`; + my $ProgramsTable; if (`grep '^$MAKECMD\[^:]: .*Error' $ProgramTestLog | wc -l` + 0) { - $TestError = 1; $ProgramsTable="Error running test $SubDir\n"; print "ERROR TESTING\n"; } elsif (`grep '^$MAKECMD\[^:]: .*No rule to make target' $ProgramTestLog | wc -l` + 0) { - $TestError = 1; $ProgramsTable="Makefile error running tests $SubDir!\n"; print "ERROR TESTING\n"; } else { - $TestError = 0; - # - # Create a list of the tests which were run... - # - system "egrep 'TEST-(PASS|FAIL)' < $ProgramTestLog ". - "| sort > $Prefix-$SubDir-Tests.txt"; + # Create a list of the tests which were run... + system "egrep 'TEST-(PASS|FAIL)' < $ProgramTestLog ". + "| sort > $Prefix-$SubDir-Tests.txt"; } $ProgramsTable = ReadFile "report.nightly.csv"; ChangeDir( "../../..", "Programs Test Parent Directory" ); - return ($ProgramsTable, $llcbeta_options); -} #end sub TestDirectory + return ($ProgramsTable, $LLCBetaOpts); +} -############################################################## -# -# Calling sub TestDirectory -# -############################################################## -if (!$BuildError) { - ($SingleSourceProgramsTable, $llcbeta_options) = - TestDirectory("SingleSource"); - WriteFile "$Prefix-SingleSource-Performance.txt", $SingleSourceProgramsTable; - ($MultiSourceProgramsTable, $llcbeta_options) = TestDirectory("MultiSource"); - WriteFile "$Prefix-MultiSource-Performance.txt", $MultiSourceProgramsTable; +# Run all the nightly tests and return the program tables and the list of tests, +# passes, fails, and xfails. +sub RunNightlyTest() { + ($SSProgs, $llcbeta_options) = TestDirectory("SingleSource"); + WriteFile "$Prefix-SingleSource-Performance.txt", $SSProgs; + ($MSProgs, $llcbeta_options) = TestDirectory("MultiSource"); + WriteFile "$Prefix-MultiSource-Performance.txt", $MSProgs; if ( ! $NOEXTERNALS ) { - ($ExternalProgramsTable, $llcbeta_options) = TestDirectory("External"); - WriteFile "$Prefix-External-Performance.txt", $ExternalProgramsTable; + ($ExtProgs, $llcbeta_options) = TestDirectory("External"); + WriteFile "$Prefix-External-Performance.txt", $ExtProgs; system "cat $Prefix-SingleSource-Tests.txt " . "$Prefix-MultiSource-Tests.txt ". "$Prefix-External-Tests.txt | sort > $Prefix-Tests.txt"; @@ -985,7 +605,7 @@ if (!$BuildError) { "$Prefix-MultiSource-Performance.txt ". "$Prefix-External-Performance.txt | sort > $Prefix-Performance.txt"; } else { - $ExternalProgramsTable = "External TEST STAGE SKIPPED\n"; + $ExtProgs = "External TEST STAGE SKIPPED\n"; if ( $VERBOSE ) { print "External TEST STAGE SKIPPED\n"; } @@ -997,46 +617,126 @@ if (!$BuildError) { " | sort > $Prefix-Performance.txt"; } - ############################################################## - # - # - # gathering tests added removed broken information here - # - # - ############################################################## - my $dejagnu_test_list = ReadFile "$Prefix-Tests.txt"; - my @DEJAGNU = split "\n", $dejagnu_test_list; - my ($passes, $fails, $xfails) = ""; - - if(!$NODEJAGNU) { - for ($x=0; $x<@DEJAGNU; $x++) { - if ($DEJAGNU[$x] =~ m/^PASS:/) { - $passes.="$DEJAGNU[$x]\n"; - } - elsif ($DEJAGNU[$x] =~ m/^FAIL:/) { - $fails.="$DEJAGNU[$x]\n"; - } - elsif ($DEJAGNU[$x] =~ m/^XFAIL:/) { - $xfails.="$DEJAGNU[$x]\n"; - } + # Compile passes, fails, xfails. + my $All = (ReadFile "$Prefix-Tests.txt"); + my @TestSuiteResultLines = split "\n", $All; + my ($Passes, $Fails, $XFails) = ""; + + for ($x=0; $x < @TestSuiteResultLines; $x++) { + if (@TestSuiteResultLines[$x] =~ m/^PASS:/) { + $Passes .= "$TestSuiteResultLines[$x]\n"; + } + elsif (@TestSuiteResultLines[$x] =~ m/^FAIL:/) { + $Fails .= "$TestSuiteResultLines[$x]\n"; + } + elsif (@TestSuiteResultLines[$x] =~ m/^XFAIL:/) { + $XFails .= "$TestSuiteResultLines[$x]\n"; } } -} #end if !$BuildError + return ($SSProgs, $MSProgs, $ExtProgs, $All, $Passes, $Fails, $XFails); +} + +############################################################## +# +# Initialize filenames +# +############################################################## + +if (! -d $WebDir) { + mkdir $WebDir, 0777 or die "Unable to create web directory: '$WebDir'."; + if($VERBOSE){ + warn "$WebDir did not exist; creating it.\n"; + } +} + +if ($CONFIG_PATH ne "") { + $ConfigMode = 1; + $LLVMSrcDir = GetRegex "^(.*)\\s+", `$CONFIG_PATH --src-root`; + $LLVMObjDir = GetRegex "^(.*)\\s+", `$CONFIG_PATH --obj-root`; + # FIXME: Add llvm-config hook for this? + $LLVMTestDir = $LLVMObjDir . "/projects/test-suite"; +} else { + $ConfigureLog = "$Prefix-Configure-Log.txt"; + $BuildLog = "$Prefix-Build-Log.txt"; + $COLog = "$Prefix-CVS-Log.txt"; + $DejagnuLog = "$Prefix-Dejagnu-testrun.log"; + $DejagnuSum = "$Prefix-Dejagnu-testrun.sum"; + $DejagnuLog = "$Prefix-DejagnuTests-Log.txt"; +} + +if ($VERBOSE) { + if ($CONFIG_PATH ne "") { + print "INITIALIZED (config mode)\n"; + print "WebDir = $WebDir\n"; + print "Prefix = $Prefix\n"; + print "LLVM Src = $LLVMSrcDir\n"; + print "LLVM Obj = $LLVMObjDir\n"; + print "LLVM Test = $LLVMTestDir\n"; + } else { + print "INITIALIZED\n"; + print "SVN URL = $SVNURL\n"; + print "COLog = $COLog\n"; + print "BuildDir = $BuildDir\n"; + print "WebDir = $WebDir\n"; + print "Prefix = $Prefix\n"; + print "BuildLog = $BuildLog\n"; + } +} ############################################################## # -# Getting end timestamp +# The actual NewNightlyTest logic. # ############################################################## + +$starttime = `date "+20%y-%m-%d %H:%M:%S"`; + +my $BuildError = 0, $BuildStatus = "OK"; +my $DejagnuTestResults = "Dejagnu skipped by user choice."; +if ($ConfigMode == 0) { + if (!$NOCHECKOUT) { + CheckoutSource(); + } + + # Build LLVM. + ChangeDir( $LLVMSrcDir , "llvm source directory") ; + if ($NOCHECKOUT || $NOBUILD) { + $BuildStatus = "Skipped by user"; + } else { + if (!BuildLLVM()) { + if( $VERBOSE) { print "\n***ERROR BUILDING TREE\n\n"; } + $BuildError = 1; + $BuildStatus = "Error: compilation aborted"; + $NODEJAGNU=1; + } + } + + # Run DejaGNU. + if (!$NODEJAGNU && !$BuildError) { + $DejagnuTestResults = RunDejaGNUTests(); + } +} + +# Run the llvm-test tests. +my ($SingleSourceProgramsTable, $MultiSourceProgramsTable, $ExternalProgramsTable, + $all_tests, $passes, $fails, $xfails) = ""; +if (!$NOTEST && !$BuildError) { + ($SingleSourceProgramsTable, $MultiSourceProgramsTable, $ExternalProgramsTable, + $all_tests, $passes, $fails, $xfails) = RunNightlyTest(); +} + $endtime = `date "+20%y-%m-%d %H:%M:%S"`; +# The last bit of logic is to remove the build and web dirs, after sending data +# to the server. ############################################################## # -# Place all the logs neatly into one humungous file +# Accumulate the information to send to the server. # ############################################################## + if ( $VERBOSE ) { print "PREPARING LOGS TO BE SENT TO SERVER\n"; } $machine_data = "uname: ".`uname -a`. @@ -1046,63 +746,71 @@ $machine_data = "uname: ".`uname -a`. "date: ".`date \"+20%y-%m-%d\"`. "time: ".`date +\"%H:%M:%S\"`; -my @CVS_DATA; -my $cvs_data; -@CVS_DATA = ReadFile "$COLog"; -$cvs_data = join("\n", @CVS_DATA); - -my @BUILD_DATA; -my $build_data; -@BUILD_DATA = ReadFile "$BuildLog"; -$build_data = join("\n", @BUILD_DATA); - -my (@DEJAGNU_LOG, @DEJAGNU_SUM, @DEJAGNULOG_FULL, @GCC_VERSION); -my ($dejagnutests_log ,$dejagnutests_sum, $dejagnulog_full) = ""; -my ($gcc_version, $gcc_version_long) = ""; - -$gcc_version_long=""; +# Get gcc version. +my $gcc_version_long = ""; if ($GCCPATH ne "") { - $gcc_version_long = `$GCCPATH/gcc --version`; + $gcc_version_long = `$GCCPATH/gcc --version`; } elsif ($ENV{"CC"}) { - $gcc_version_long = `$ENV{"CC"} --version`; + $gcc_version_long = `$ENV{"CC"} --version`; } else { - $gcc_version_long = `gcc --version`; + $gcc_version_long = `gcc --version`; } -@GCC_VERSION = split '\n', $gcc_version_long; -$gcc_version = $GCC_VERSION[0]; +my $gcc_version = (split '\n', $gcc_version_long)[0]; -$llvmgcc_version_long=""; +# Get llvm-gcc target triple. +my $llvmgcc_version_long = ""; if ($LLVMGCCPATH ne "") { $llvmgcc_version_long = `$LLVMGCCPATH/llvm-gcc -v 2>&1`; } else { $llvmgcc_version_long = `llvm-gcc -v 2>&1`; } -@LLVMGCC_VERSION = split '\n', $llvmgcc_version_long; -$llvmgcc_versionTarget = $LLVMGCC_VERSION[1]; -$llvmgcc_versionTarget =~ /Target: (.+)/; -$targetTriple = $1; - -if(!$BuildError){ - @DEJAGNU_LOG = ReadFile "$DejagnuLog"; - @DEJAGNU_SUM = ReadFile "$DejagnuSum"; - $dejagnutests_log = join("\n", @DEJAGNU_LOG); - $dejagnutests_sum = join("\n", @DEJAGNU_SUM); - - @DEJAGNULOG_FULL = ReadFile "$DejagnuTestsLog"; - $dejagnulog_full = join("\n", @DEJAGNULOG_FULL); +(split '\n', $llvmgcc_version_long)[1] =~ /Target: (.+)/; +my $targetTriple = $1; + +# Logs. +my ($ConfigureLogData, $BuildLogData, $DejagnuLogData, $CheckoutLogData) = ""; +if ($ConfigMode == 0) { + $ConfigureLogData = ReadFile $ConfigureLog; + $BuildLogData = ReadFile $BuildLog; + $DejagnuLogData = ReadFile $DejagnuLog; + $CheckoutLogData = ReadFile $COLog; } -############################################################## -# -# Send data via a post request -# -############################################################## +# Checkout info. +my $CheckoutTime_Wall = GetRegex "^real ([0-9.]+)", $CheckoutLogData; +my $CheckoutTime_User = GetRegex "^user ([0-9.]+)", $CheckoutLogData; +my $CheckoutTime_Sys = GetRegex "^sys ([0-9.]+)", $CheckoutLogData; +my $CheckoutTime_CPU = $CVSCheckoutTime_User + $CVSCheckoutTime_Sys; + +# Configure info. +my $ConfigTimeU = GetRegex "^user ([0-9.]+)", $ConfigureLogData; +my $ConfigTimeS = GetRegex "^sys ([0-9.]+)", $ConfigureLogData; +my $ConfigTime = $ConfigTimeU+$ConfigTimeS; # ConfigTime = User+System +my $ConfigWallTime = GetRegex "^real ([0-9.]+)",$ConfigureLogData; +$ConfigTime=-1 unless $ConfigTime; +$ConfigWallTime=-1 unless $ConfigWallTime; + +# Build info. +my $BuildTimeU = GetRegex "^user ([0-9.]+)", $BuildLogData; +my $BuildTimeS = GetRegex "^sys ([0-9.]+)", $BuildLogData; +my $BuildTime = $BuildTimeU+$BuildTimeS; # BuildTime = User+System +my $BuildWallTime = GetRegex "^real ([0-9.]+)", $BuildLogData; +$BuildTime=-1 unless $BuildTime; +$BuildWallTime=-1 unless $BuildWallTime; + +# DejaGNU info. +my $DejagnuTimeU = GetRegex "^user ([0-9.]+)", $DejagnuLogData; +my $DejagnuTimeS = GetRegex "^sys ([0-9.]+)", $DejagnuLogData; +$DejagnuTime = $DejagnuTimeU+$DejagnuTimeS; # DejagnuTime = User+System +$DejagnuWallTime = GetRegex "^real ([0-9.]+)", $DejagnuLogData; +$DejagnuTime = "0.0" unless $DejagnuTime; +$DejagnuWallTime = "0.0" unless $DejagnuWallTime; if ( $VERBOSE ) { print "SEND THE DATA VIA THE POST REQUEST\n"; } my %hash_of_data = ( 'machine_data' => $machine_data, - 'build_data' => $build_data, + 'build_data' => $ConfigureLogData . $BuildLogData, 'gcc_version' => $gcc_version, 'nickname' => $nickname, 'dejagnutime_wall' => $DejagnuWallTime, @@ -1113,35 +821,37 @@ my %hash_of_data = ( 'configtime_cpu'=> $ConfigTime, 'buildtime_wall' => $BuildWallTime, 'buildtime_cpu' => $BuildTime, - 'warnings' => $WarningsFile, - 'cvsusercommitlist' => $UserCommitList, - 'cvsuserupdatelist' => $UserUpdateList, - 'cvsaddedfiles' => $CVSAddedFiles, - 'cvsmodifiedfiles' => $CVSModifiedFiles, - 'cvsremovedfiles' => $CVSRemovedFiles, - 'lines_of_code' => $LOC, - 'cvs_file_count' => $NumFilesInCVS, - 'cvs_dir_count' => $NumDirsInCVS, 'buildstatus' => $BuildStatus, 'singlesource_programstable' => $SingleSourceProgramsTable, 'multisource_programstable' => $MultiSourceProgramsTable, 'externalsource_programstable' => $ExternalProgramsTable, - 'llcbeta_options' => $multisource_llcbeta_options, - 'warnings_removed' => $WarningsRemoved, - 'warnings_added' => $WarningsAdded, + 'llcbeta_options' => $llcbeta_options, 'passing_tests' => $passes, 'expfail_tests' => $xfails, 'unexpfail_tests' => $fails, - 'all_tests' => $dejagnu_test_list, - 'new_tests' => "", - 'removed_tests' => "", + 'all_tests' => $all_tests, 'dejagnutests_results' => $DejagnuTestResults, - 'dejagnutests_log' => $dejagnulog_full, + 'dejagnutests_log' => $DejagnuLogData, 'starttime' => $starttime, 'endtime' => $endtime, - 'o_file_sizes' => $o_file_sizes, - 'a_file_sizes' => $a_file_sizes, - 'target_triple' => $targetTriple + 'target_triple' => $targetTriple, + + # Unused, but left around for backwards compatability. + 'warnings' => "", + 'cvsusercommitlist' => "", + 'cvsuserupdatelist' => "", + 'cvsaddedfiles' => "", + 'cvsmodifiedfiles' => "", + 'cvsremovedfiles' => "", + 'lines_of_code' => "", + 'cvs_file_count' => 0, + 'cvs_dir_count' => 0, + 'warnings_removed' => "", + 'warnings_added' => "", + 'new_tests' => "", + 'removed_tests' => "", + 'o_file_sizes' => "", + 'a_file_sizes' => "" ); if ($SUBMIT || !($SUBMITAUX eq "")) { @@ -1156,7 +866,7 @@ if ($SUBMIT || !($SUBMITAUX eq "")) { ############################################################## # -# Remove the cvs tree... +# Remove the source tree... # ############################################################## system ( "$NICE rm -rf $BuildDir") diff --git a/utils/TableGen/AsmWriterEmitter.cpp b/utils/TableGen/AsmWriterEmitter.cpp index 84a647b..ff348e8 100644 --- a/utils/TableGen/AsmWriterEmitter.cpp +++ b/utils/TableGen/AsmWriterEmitter.cpp @@ -538,6 +538,29 @@ FindUniqueOperandCommands(std::vector<std::string> &UniqueOperandCommands, } +static void UnescapeString(std::string &Str) { + for (unsigned i = 0; i != Str.size(); ++i) { + if (Str[i] == '\\' && i != Str.size()-1) { + switch (Str[i+1]) { + default: continue; // Don't execute the code after the switch. + case 'a': Str[i] = '\a'; break; + case 'b': Str[i] = '\b'; break; + case 'e': Str[i] = 27; break; + case 'f': Str[i] = '\f'; break; + case 'n': Str[i] = '\n'; break; + case 'r': Str[i] = '\r'; break; + case 't': Str[i] = '\t'; break; + case 'v': Str[i] = '\v'; break; + case '"': Str[i] = '\"'; break; + case '\'': Str[i] = '\''; break; + case '\\': Str[i] = '\\'; break; + } + // Nuke the second character. + Str.erase(Str.begin()+i+1); + } + } +} + /// EmitPrintInstruction - Generate the code for the "printInstruction" method /// implementation. void AsmWriterEmitter::EmitPrintInstruction(raw_ostream &O) { diff --git a/utils/TableGen/ClangDiagnosticsEmitter.cpp b/utils/TableGen/ClangDiagnosticsEmitter.cpp index c127afd..6f1080e 100644 --- a/utils/TableGen/ClangDiagnosticsEmitter.cpp +++ b/utils/TableGen/ClangDiagnosticsEmitter.cpp @@ -52,15 +52,12 @@ void ClangDiagsDefsEmitter::run(raw_ostream &OS) { // Description string. OS << ", \""; - std::string S = R.getValueAsString("Text"); - EscapeString(S); - OS << S << "\""; + OS.write_escaped(R.getValueAsString("Text")) << '"'; // Warning associated with the diagnostic. if (DefInit *DI = dynamic_cast<DefInit*>(R.getValueInit("Group"))) { - S = DI->getDef()->getValueAsString("GroupName"); - EscapeString(S); - OS << ", \"" << S << "\""; + OS << ", \""; + OS.write_escaped(DI->getDef()->getValueAsString("GroupName")) << '"'; } else { OS << ", 0"; } @@ -151,11 +148,10 @@ void ClangDiagGroupsEmitter::run(raw_ostream &OS) { OS << "\n#ifdef GET_DIAG_TABLE\n"; for (std::map<std::string, GroupInfo>::iterator I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I) { - std::string S = I->first; - EscapeString(S); // Group option string. - OS << " { \"" << S << "\"," - << std::string(MaxLen-I->first.size()+1, ' '); + OS << " { \""; + OS.write_escaped(I->first) << "\"," + << std::string(MaxLen-I->first.size()+1, ' '); // Diagnostics in the group. if (I->second.DiagsInGroup.empty()) diff --git a/utils/TableGen/CodeGenDAGPatterns.h b/utils/TableGen/CodeGenDAGPatterns.h index 9b53ecc5..398764b 100644 --- a/utils/TableGen/CodeGenDAGPatterns.h +++ b/utils/TableGen/CodeGenDAGPatterns.h @@ -584,6 +584,8 @@ public: return intrinsic_wo_chain_sdnode; } + bool hasTargetIntrinsics() { return !TgtIntrinsics.empty(); } + private: void ParseNodeInfo(); void ParseNodeTransforms(); diff --git a/utils/TableGen/DAGISelEmitter.cpp b/utils/TableGen/DAGISelEmitter.cpp index dcf64e4..bbb8a18 100644 --- a/utils/TableGen/DAGISelEmitter.cpp +++ b/utils/TableGen/DAGISelEmitter.cpp @@ -2067,8 +2067,16 @@ void DAGISelEmitter::EmitInstructionSelector(raw_ostream &OS) { << " errs() << \"Cannot yet select: \";\n" << " unsigned iid = cast<ConstantSDNode>(N.getOperand(" << "N.getOperand(0).getValueType() == MVT::Other))->getZExtValue();\n" - << " llvm_report_error(\"Cannot yet select: intrinsic %\" +\n" - << "Intrinsic::getName((Intrinsic::ID)iid));\n" + << " if (iid < Intrinsic::num_intrinsics)\n" + << " llvm_report_error(\"Cannot yet select: intrinsic %\" + " + << "Intrinsic::getName((Intrinsic::ID)iid));\n"; + if (CGP.hasTargetIntrinsics()) { + OS << " else if (const TargetIntrinsicInfo *tii = TM.getIntrinsicInfo())\n" + << " llvm_report_error(Twine(\"Cannot yet select: target intrinsic " + << "%\") + tii->getName(iid));\n"; + } + OS << " else\n" + << " llvm_report_error(\"Cannot yet select: invalid intrinsic\");\n" << "}\n\n"; } diff --git a/utils/TableGen/LLVMCConfigurationEmitter.cpp b/utils/TableGen/LLVMCConfigurationEmitter.cpp index 06afaf7..f5d1139 100644 --- a/utils/TableGen/LLVMCConfigurationEmitter.cpp +++ b/utils/TableGen/LLVMCConfigurationEmitter.cpp @@ -56,8 +56,14 @@ const char * SinkOptionName = "AutoGeneratedSinkOption"; /// Id - An 'identity' function object. struct Id { - template<typename T> - void operator()(const T&) const { + template<typename T0> + void operator()(const T0&) const { + } + template<typename T0, typename T1> + void operator()(const T0&, const T1&) const { + } + template<typename T0, typename T1, typename T2> + void operator()(const T0&, const T1&, const T2&) const { } }; @@ -81,16 +87,24 @@ const DagInit& InitPtrToDag(const Init* ptr) { return val; } +const std::string GetOperatorName(const DagInit* D) { + return D->getOperator()->getAsString(); +} + +const std::string GetOperatorName(const DagInit& D) { + return GetOperatorName(&D); +} + // checkNumberOfArguments - Ensure that the number of args in d is // greater than or equal to min_arguments, otherwise throw an exception. void checkNumberOfArguments (const DagInit* d, unsigned min_arguments) { if (!d || d->getNumArgs() < min_arguments) - throw d->getOperator()->getAsString() + ": too few arguments!"; + throw GetOperatorName(d) + ": too few arguments!"; } // isDagEmpty - is this DAG marked with an empty marker? bool isDagEmpty (const DagInit* d) { - return d->getOperator()->getAsString() == "empty_dag_marker"; + return GetOperatorName(d) == "empty_dag_marker"; } // EscapeVariableName - Escape commas and other symbols not allowed @@ -132,6 +146,18 @@ void checkedIncrement(I& P, I E, S ErrorString) { throw ErrorString; } +// apply is needed because C++'s syntax doesn't let us construct a function +// object and call it in the same statement. +template<typename F, typename T0> +void apply(F Fun, T0& Arg0) { + return Fun(Arg0); +} + +template<typename F, typename T0, typename T1> +void apply(F Fun, T0& Arg0, T1& Arg1) { + return Fun(Arg0, Arg1); +} + //===----------------------------------------------------------------------===// /// Back-end specific code @@ -143,6 +169,10 @@ namespace OptionType { enum OptionType { Alias, Switch, Parameter, ParameterList, Prefix, PrefixList}; + bool IsAlias(OptionType t) { + return (t == Alias); + } + bool IsList (OptionType t) { return (t == ParameterList || t == PrefixList); } @@ -231,12 +261,12 @@ struct OptionDescription { bool isReallyHidden() const; void setReallyHidden(); - bool isParameter() const - { return OptionType::IsParameter(this->Type); } - bool isSwitch() const { return OptionType::IsSwitch(this->Type); } + bool isParameter() const + { return OptionType::IsParameter(this->Type); } + bool isList() const { return OptionType::IsList(this->Type); } @@ -258,7 +288,7 @@ void OptionDescription::Merge (const OptionDescription& other) } bool OptionDescription::isAlias() const { - return Type == OptionType::Alias; + return OptionType::IsAlias(this->Type); } bool OptionDescription::isMultiVal() const { @@ -352,6 +382,14 @@ public: /// FindOption - exception-throwing wrapper for find(). const OptionDescription& FindOption(const std::string& OptName) const; + // Wrappers for FindOption that throw an exception in case the option has a + // wrong type. + const OptionDescription& FindSwitch(const std::string& OptName) const; + const OptionDescription& FindParameter(const std::string& OptName) const; + const OptionDescription& FindList(const std::string& OptName) const; + const OptionDescription& + FindListOrParameter(const std::string& OptName) const; + /// insertDescription - Insert new OptionDescription into /// OptionDescriptions list void InsertDescription (const OptionDescription& o); @@ -363,8 +401,7 @@ public: }; const OptionDescription& -OptionDescriptions::FindOption(const std::string& OptName) const -{ +OptionDescriptions::FindOption(const std::string& OptName) const { const_iterator I = Descriptions.find(OptName); if (I != Descriptions.end()) return I->second; @@ -372,8 +409,40 @@ OptionDescriptions::FindOption(const std::string& OptName) const throw OptName + ": no such option!"; } -void OptionDescriptions::InsertDescription (const OptionDescription& o) -{ +const OptionDescription& +OptionDescriptions::FindSwitch(const std::string& OptName) const { + const OptionDescription& OptDesc = this->FindOption(OptName); + if (!OptDesc.isSwitch()) + throw OptName + ": incorrect option type - should be a switch!"; + return OptDesc; +} + +const OptionDescription& +OptionDescriptions::FindList(const std::string& OptName) const { + const OptionDescription& OptDesc = this->FindOption(OptName); + if (!OptDesc.isList()) + throw OptName + ": incorrect option type - should be a list!"; + return OptDesc; +} + +const OptionDescription& +OptionDescriptions::FindParameter(const std::string& OptName) const { + const OptionDescription& OptDesc = this->FindOption(OptName); + if (!OptDesc.isParameter()) + throw OptName + ": incorrect option type - should be a parameter!"; + return OptDesc; +} + +const OptionDescription& +OptionDescriptions::FindListOrParameter(const std::string& OptName) const { + const OptionDescription& OptDesc = this->FindOption(OptName); + if (!OptDesc.isList() && !OptDesc.isParameter()) + throw OptName + + ": incorrect option type - should be a list or parameter!"; + return OptDesc; +} + +void OptionDescriptions::InsertDescription (const OptionDescription& o) { container_type::iterator I = Descriptions.find(o.Name); if (I != Descriptions.end()) { OptionDescription& D = I->second; @@ -409,7 +478,7 @@ public: /// handler. void operator() (Init* i) { const DagInit& property = InitPtrToDag(i); - const std::string& property_name = property.getOperator()->getAsString(); + const std::string& property_name = GetOperatorName(property); typename HandlerMap::iterator method = Handlers_.find(property_name); if (method != Handlers_.end()) { @@ -558,7 +627,7 @@ public: checkNumberOfArguments(&d, 1); const OptionType::OptionType Type = - stringToOptionType(d.getOperator()->getAsString()); + stringToOptionType(GetOperatorName(d)); const std::string& Name = InitPtrToString(d.getArg(0)); OptionDescription OD(Type, Name); @@ -678,7 +747,7 @@ private: checkNumberOfArguments(d, 1); Init* Case = d->getArg(0); if (typeid(*Case) != typeid(DagInit) || - static_cast<DagInit*>(Case)->getOperator()->getAsString() != "case") + GetOperatorName(static_cast<DagInit*>(Case)) != "case") throw std::string("The argument to (actions) should be a 'case' construct!"); toolDesc_.Actions = Case; @@ -775,11 +844,17 @@ void FillInEdgeVector(RecordVector::const_iterator B, /// CalculatePriority - Calculate the priority of this plugin. int CalculatePriority(RecordVector::const_iterator B, RecordVector::const_iterator E) { - int total = 0; - for (; B!=E; ++B) { - total += static_cast<int>((*B)->getValueAsInt("priority")); + int priority = 0; + + if (B != E) { + priority = static_cast<int>((*B)->getValueAsInt("priority")); + + if (++B != E) + throw std::string("More than one 'PluginPriority' instance found: " + "most probably an error!"); } - return total; + + return priority; } /// NotInGraph - Helper function object for FilterNotInGraph. @@ -874,22 +949,60 @@ void TypecheckGraph (const RecordVector& EdgeVector, /// WalkCase - Walks the 'case' expression DAG and invokes /// TestCallback on every test, and StatementCallback on every /// statement. Handles 'case' nesting, but not the 'and' and 'or' -/// combinators. -// TODO: Re-implement EmitCaseConstructHandler on top of this function? +/// combinators (that is, they are passed directly to TestCallback). +/// TestCallback must have type 'void TestCallback(const DagInit*, unsigned +/// IndentLevel, bool FirstTest)'. +/// StatementCallback must have type 'void StatementCallback(const Init*, +/// unsigned IndentLevel)'. template <typename F1, typename F2> -void WalkCase(Init* Case, F1 TestCallback, F2 StatementCallback) { +void WalkCase(const Init* Case, F1 TestCallback, F2 StatementCallback, + unsigned IndentLevel = 0) +{ const DagInit& d = InitPtrToDag(Case); + + // Error checks. + if (GetOperatorName(d) != "case") + throw std::string("WalkCase should be invoked only on 'case' expressions!"); + + if (d.getNumArgs() < 2) + throw "There should be at least one clause in the 'case' expression:\n" + + d.getAsString(); + + // Main loop. bool even = false; + const unsigned numArgs = d.getNumArgs(); + unsigned i = 1; for (DagInit::const_arg_iterator B = d.arg_begin(), E = d.arg_end(); B != E; ++B) { Init* arg = *B; - if (even && dynamic_cast<DagInit*>(arg) - && static_cast<DagInit*>(arg)->getOperator()->getAsString() == "case") - WalkCase(arg, TestCallback, StatementCallback); - else if (!even) - TestCallback(arg); + + if (!even) + { + // Handle test. + const DagInit& Test = InitPtrToDag(arg); + + if (GetOperatorName(Test) == "default" && (i+1 != numArgs)) + throw std::string("The 'default' clause should be the last in the" + "'case' construct!"); + if (i == numArgs) + throw "Case construct handler: no corresponding action " + "found for the test " + Test.getAsString() + '!'; + + TestCallback(&Test, IndentLevel, (i == 1)); + } else - StatementCallback(arg); + { + if (dynamic_cast<DagInit*>(arg) + && GetOperatorName(static_cast<DagInit*>(arg)) == "case") { + // Nested 'case'. + WalkCase(arg, TestCallback, StatementCallback, IndentLevel + Indent1); + } + + // Handle statement. + StatementCallback(arg, IndentLevel); + } + + ++i; even = !even; } } @@ -901,7 +1014,7 @@ class ExtractOptionNames { void processDag(const Init* Statement) { const DagInit& Stmt = InitPtrToDag(Statement); - const std::string& ActionName = Stmt.getOperator()->getAsString(); + const std::string& ActionName = GetOperatorName(Stmt); if (ActionName == "forward" || ActionName == "forward_as" || ActionName == "unpack_values" || ActionName == "switch_on" || ActionName == "parameter_equals" || ActionName == "element_in_list" || @@ -932,6 +1045,13 @@ public: this->processDag(Statement); } } + + void operator()(const DagInit* Test, unsigned, bool) { + this->operator()(Test); + } + void operator()(const Init* Statement, unsigned) { + this->operator()(Statement); + } }; /// CheckForSuperfluousOptions - Check that there are no side @@ -990,51 +1110,137 @@ bool EmitCaseTest0Args(const std::string& TestName, raw_ostream& O) { return false; } +/// EmitListTest - Helper function used by EmitCaseTest1ArgList(). +template <typename F> +void EmitListTest(const ListInit& L, const char* LogicOp, + F Callback, raw_ostream& O) +{ + // This is a lot like EmitLogicalOperationTest, but works on ListInits instead + // of Dags... + bool isFirst = true; + for (ListInit::const_iterator B = L.begin(), E = L.end(); B != E; ++B) { + if (isFirst) + isFirst = false; + else + O << " || "; + Callback(InitPtrToString(*B), O); + } +} + +// Callbacks for use with EmitListTest. -/// EmitCaseTest1Arg - Helper function used by EmitCaseConstructHandler(). -bool EmitCaseTest1Arg(const std::string& TestName, - const DagInit& d, - const OptionDescriptions& OptDescs, - raw_ostream& O) { - checkNumberOfArguments(&d, 1); +class EmitSwitchOn { + const OptionDescriptions& OptDescs_; +public: + EmitSwitchOn(const OptionDescriptions& OptDescs) : OptDescs_(OptDescs) + {} + + void operator()(const std::string& OptName, raw_ostream& O) const { + const OptionDescription& OptDesc = OptDescs_.FindSwitch(OptName); + O << OptDesc.GenVariableName(); + } +}; + +class EmitEmptyTest { + bool EmitNegate_; + const OptionDescriptions& OptDescs_; +public: + EmitEmptyTest(bool EmitNegate, const OptionDescriptions& OptDescs) + : EmitNegate_(EmitNegate), OptDescs_(OptDescs) + {} + + void operator()(const std::string& OptName, raw_ostream& O) const { + const char* Neg = (EmitNegate_ ? "!" : ""); + if (OptName == "o") { + O << Neg << "OutputFilename.empty()"; + } + else { + const OptionDescription& OptDesc = OptDescs_.FindListOrParameter(OptName); + O << Neg << OptDesc.GenVariableName() << ".empty()"; + } + } +}; + + +/// EmitCaseTest1ArgList - Helper function used by EmitCaseTest1Arg(); +bool EmitCaseTest1ArgList(const std::string& TestName, + const DagInit& d, + const OptionDescriptions& OptDescs, + raw_ostream& O) { + const ListInit& L = *static_cast<ListInit*>(d.getArg(0)); + + if (TestName == "any_switch_on") { + EmitListTest(L, "||", EmitSwitchOn(OptDescs), O); + return true; + } + else if (TestName == "switch_on") { + EmitListTest(L, "&&", EmitSwitchOn(OptDescs), O); + return true; + } + else if (TestName == "any_not_empty") { + EmitListTest(L, "||", EmitEmptyTest(true, OptDescs), O); + return true; + } + else if (TestName == "any_empty") { + EmitListTest(L, "||", EmitEmptyTest(false, OptDescs), O); + return true; + } + else if (TestName == "not_empty") { + EmitListTest(L, "&&", EmitEmptyTest(true, OptDescs), O); + return true; + } + else if (TestName == "empty") { + EmitListTest(L, "&&", EmitEmptyTest(false, OptDescs), O); + return true; + } + + return false; +} + +/// EmitCaseTest1ArgStr - Helper function used by EmitCaseTest1Arg(); +bool EmitCaseTest1ArgStr(const std::string& TestName, + const DagInit& d, + const OptionDescriptions& OptDescs, + raw_ostream& O) { const std::string& OptName = InitPtrToString(d.getArg(0)); if (TestName == "switch_on") { - const OptionDescription& OptDesc = OptDescs.FindOption(OptName); - if (!OptDesc.isSwitch()) - throw OptName + ": incorrect option type - should be a switch!"; - O << OptDesc.GenVariableName(); + apply(EmitSwitchOn(OptDescs), OptName, O); return true; - } else if (TestName == "input_languages_contain") { + } + else if (TestName == "input_languages_contain") { O << "InLangs.count(\"" << OptName << "\") != 0"; return true; - } else if (TestName == "in_language") { + } + else if (TestName == "in_language") { // This works only for single-argument Tool::GenerateAction. Join // tools can process several files in different languages simultaneously. // TODO: make this work with Edge::Weight (if possible). O << "LangMap.GetLanguage(inFile) == \"" << OptName << '\"'; return true; - } else if (TestName == "not_empty" || TestName == "empty") { - const char* Test = (TestName == "empty") ? "" : "!"; - - if (OptName == "o") { - O << Test << "OutputFilename.empty()"; - return true; - } - else { - const OptionDescription& OptDesc = OptDescs.FindOption(OptName); - if (OptDesc.isSwitch()) - throw OptName - + ": incorrect option type - should be a list or parameter!"; - O << Test << OptDesc.GenVariableName() << ".empty()"; - return true; - } + } + else if (TestName == "not_empty" || TestName == "empty") { + bool EmitNegate = (TestName == "not_empty"); + apply(EmitEmptyTest(EmitNegate, OptDescs), OptName, O); + return true; } return false; } +/// EmitCaseTest1Arg - Helper function used by EmitCaseConstructHandler(); +bool EmitCaseTest1Arg(const std::string& TestName, + const DagInit& d, + const OptionDescriptions& OptDescs, + raw_ostream& O) { + checkNumberOfArguments(&d, 1); + if (typeid(*d.getArg(0)) == typeid(ListInit)) + return EmitCaseTest1ArgList(TestName, d, OptDescs, O); + else + return EmitCaseTest1ArgStr(TestName, d, OptDescs, O); +} + /// EmitCaseTest2Args - Helper function used by EmitCaseConstructHandler(). bool EmitCaseTest2Args(const std::string& TestName, const DagInit& d, @@ -1044,17 +1250,14 @@ bool EmitCaseTest2Args(const std::string& TestName, checkNumberOfArguments(&d, 2); const std::string& OptName = InitPtrToString(d.getArg(0)); const std::string& OptArg = InitPtrToString(d.getArg(1)); - const OptionDescription& OptDesc = OptDescs.FindOption(OptName); if (TestName == "parameter_equals") { - if (!OptDesc.isParameter()) - throw OptName + ": incorrect option type - should be a parameter!"; + const OptionDescription& OptDesc = OptDescs.FindParameter(OptName); O << OptDesc.GenVariableName() << " == \"" << OptArg << "\""; return true; } else if (TestName == "element_in_list") { - if (!OptDesc.isList()) - throw OptName + ": incorrect option type - should be a list!"; + const OptionDescription& OptDesc = OptDescs.FindList(OptName); const std::string& VarName = OptDesc.GenVariableName(); O << "std::find(" << VarName << ".begin(),\n"; O.indent(IndentLevel + Indent1) @@ -1106,7 +1309,7 @@ void EmitLogicalNot(const DagInit& d, unsigned IndentLevel, void EmitCaseTest(const DagInit& d, unsigned IndentLevel, const OptionDescriptions& OptDescs, raw_ostream& O) { - const std::string& TestName = d.getOperator()->getAsString(); + const std::string& TestName = GetOperatorName(d); if (TestName == "and") EmitLogicalOperationTest(d, "&&", IndentLevel, OptDescs, O); @@ -1124,59 +1327,79 @@ void EmitCaseTest(const DagInit& d, unsigned IndentLevel, throw TestName + ": unknown edge property!"; } -// Emit code that handles the 'case' construct. -// Takes a function object that should emit code for every case clause. -// Callback's type is -// void F(Init* Statement, unsigned IndentLevel, raw_ostream& O). -template <typename F> -void EmitCaseConstructHandler(const Init* Dag, unsigned IndentLevel, - F Callback, bool EmitElseIf, - const OptionDescriptions& OptDescs, - raw_ostream& O) { - const DagInit* d = &InitPtrToDag(Dag); - if (d->getOperator()->getAsString() != "case") - throw std::string("EmitCaseConstructHandler should be invoked" - " only on 'case' expressions!"); - unsigned numArgs = d->getNumArgs(); - if (d->getNumArgs() < 2) - throw "There should be at least one clause in the 'case' expression:\n" - + d->getAsString(); +/// EmitCaseTestCallback - Callback used by EmitCaseConstructHandler. +class EmitCaseTestCallback { + bool EmitElseIf_; + const OptionDescriptions& OptDescs_; + raw_ostream& O_; +public: - for (unsigned i = 0; i != numArgs; ++i) { - const DagInit& Test = InitPtrToDag(d->getArg(i)); + EmitCaseTestCallback(bool EmitElseIf, + const OptionDescriptions& OptDescs, raw_ostream& O) + : EmitElseIf_(EmitElseIf), OptDescs_(OptDescs), O_(O) + {} - // Emit the test. - if (Test.getOperator()->getAsString() == "default") { - if (i+2 != numArgs) - throw std::string("The 'default' clause should be the last in the" - "'case' construct!"); - O.indent(IndentLevel) << "else {\n"; + void operator()(const DagInit* Test, unsigned IndentLevel, bool FirstTest) + { + if (GetOperatorName(Test) == "default") { + O_.indent(IndentLevel) << "else {\n"; } else { - O.indent(IndentLevel) << ((i != 0 && EmitElseIf) ? "else if (" : "if ("); - EmitCaseTest(Test, IndentLevel, OptDescs, O); - O << ") {\n"; + O_.indent(IndentLevel) + << ((!FirstTest && EmitElseIf_) ? "else if (" : "if ("); + EmitCaseTest(*Test, IndentLevel, OptDescs_, O_); + O_ << ") {\n"; } + } +}; - // Emit the corresponding statement. - ++i; - if (i == numArgs) - throw "Case construct handler: no corresponding action " - "found for the test " + Test.getAsString() + '!'; - - Init* arg = d->getArg(i); - const DagInit* nd = dynamic_cast<DagInit*>(arg); - if (nd && (nd->getOperator()->getAsString() == "case")) { - // Handle the nested 'case'. - EmitCaseConstructHandler(nd, (IndentLevel + Indent1), - Callback, EmitElseIf, OptDescs, O); - } - else { - Callback(arg, (IndentLevel + Indent1), O); +/// EmitCaseStatementCallback - Callback used by EmitCaseConstructHandler. +template <typename F> +class EmitCaseStatementCallback { + F Callback_; + raw_ostream& O_; +public: + + EmitCaseStatementCallback(F Callback, raw_ostream& O) + : Callback_(Callback), O_(O) + {} + + void operator() (const Init* Statement, unsigned IndentLevel) { + + // Ignore nested 'case' DAG. + if (!(dynamic_cast<const DagInit*>(Statement) && + GetOperatorName(static_cast<const DagInit*>(Statement)) == "case")) { + if (typeid(*Statement) == typeid(ListInit)) { + const ListInit& DagList = *static_cast<const ListInit*>(Statement); + for (ListInit::const_iterator B = DagList.begin(), E = DagList.end(); + B != E; ++B) + Callback_(*B, (IndentLevel + Indent1), O_); + } + else { + Callback_(Statement, (IndentLevel + Indent1), O_); + } } - O.indent(IndentLevel) << "}\n"; + O_.indent(IndentLevel) << "}\n"; } + +}; + +/// EmitCaseConstructHandler - Emit code that handles the 'case' +/// construct. Takes a function object that should emit code for every case +/// clause. Implemented on top of WalkCase. +/// Callback's type is void F(Init* Statement, unsigned IndentLevel, +/// raw_ostream& O). +/// EmitElseIf parameter controls the type of condition that is emitted ('if +/// (..) {..} else if (..) {} .. else {..}' vs. 'if (..) {..} if(..) {..} +/// .. else {..}'). +template <typename F> +void EmitCaseConstructHandler(const Init* Case, unsigned IndentLevel, + F Callback, bool EmitElseIf, + const OptionDescriptions& OptDescs, + raw_ostream& O) { + WalkCase(Case, EmitCaseTestCallback(EmitElseIf, OptDescs, O), + EmitCaseStatementCallback<F>(Callback, O), IndentLevel); } /// TokenizeCmdline - converts from "$CALL(HookName, 'Arg1', 'Arg2')/path" to @@ -1474,17 +1697,40 @@ void EmitForwardOptionPropertyHandlingCode (const OptionDescription& D, } } -/// EmitActionHandler - Emit code that handles actions. Used by -/// EmitGenerateActionMethod() as an argument to -/// EmitCaseConstructHandler(). -class EmitActionHandler { +/// ActionHandlingCallbackBase - Base class of EmitActionHandlersCallback and +/// EmitPreprocessOptionsCallback. +struct ActionHandlingCallbackBase { + + void onErrorDag(const DagInit& d, + unsigned IndentLevel, raw_ostream& O) const + { + O.indent(IndentLevel) + << "throw std::runtime_error(\"" << + (d.getNumArgs() >= 1 ? InitPtrToString(d.getArg(0)) + : "Unknown error!") + << "\");\n"; + } + + void onWarningDag(const DagInit& d, + unsigned IndentLevel, raw_ostream& O) const + { + checkNumberOfArguments(&d, 1); + O.indent(IndentLevel) << "llvm::errs() << \"" + << InitPtrToString(d.getArg(0)) << "\";\n"; + } + +}; + +/// EmitActionHandlersCallback - Emit code that handles actions. Used by +/// EmitGenerateActionMethod() as an argument to EmitCaseConstructHandler(). +class EmitActionHandlersCallback : ActionHandlingCallbackBase { const OptionDescriptions& OptDescs; void processActionDag(const Init* Statement, unsigned IndentLevel, raw_ostream& O) const { const DagInit& Dag = InitPtrToDag(Statement); - const std::string& ActionName = Dag.getOperator()->getAsString(); + const std::string& ActionName = GetOperatorName(Dag); if (ActionName == "append_cmd") { checkNumberOfArguments(&Dag, 1); @@ -1497,10 +1743,10 @@ class EmitActionHandler { O.indent(IndentLevel) << "vec.push_back(\"" << *B << "\");\n"; } else if (ActionName == "error") { - O.indent(IndentLevel) << "throw std::runtime_error(\"" << - (Dag.getNumArgs() >= 1 ? InitPtrToString(Dag.getArg(0)) - : "Unknown error!") - << "\");\n"; + this->onErrorDag(Dag, IndentLevel, O); + } + else if (ActionName == "warning") { + this->onWarningDag(Dag, IndentLevel, O); } else if (ActionName == "forward") { checkNumberOfArguments(&Dag, 1); @@ -1554,21 +1800,13 @@ class EmitActionHandler { } } public: - EmitActionHandler(const OptionDescriptions& OD) + EmitActionHandlersCallback(const OptionDescriptions& OD) : OptDescs(OD) {} - void operator()(const Init* Statement, unsigned IndentLevel, - raw_ostream& O) const + void operator()(const Init* Statement, + unsigned IndentLevel, raw_ostream& O) const { - if (typeid(*Statement) == typeid(ListInit)) { - const ListInit& DagList = *static_cast<const ListInit*>(Statement); - for (ListInit::const_iterator B = DagList.begin(), E = DagList.end(); - B != E; ++B) - this->processActionDag(*B, IndentLevel, O); - } - else { - this->processActionDag(Statement, IndentLevel, O); - } + this->processActionDag(Statement, IndentLevel, O); } }; @@ -1593,9 +1831,20 @@ public: {} void operator()(const Init* CmdLine) { + // Ignore nested 'case' DAG. + if (typeid(*CmdLine) == typeid(DagInit)) + return; + if (IsOutFileIndexCheckRequiredStr(CmdLine)) *ret_ = true; } + + void operator()(const DagInit* Test, unsigned, bool) { + this->operator()(Test); + } + void operator()(const Init* Statement, unsigned) { + this->operator()(Statement); + } }; bool IsOutFileIndexCheckRequiredCase (Init* CmdLine) { @@ -1652,7 +1901,7 @@ void EmitGenerateActionMethod (const ToolDescription& D, // For every understood option, emit handling code. if (D.Actions) - EmitCaseConstructHandler(D.Actions, Indent2, EmitActionHandler(OptDescs), + EmitCaseConstructHandler(D.Actions, Indent2, EmitActionHandlersCallback(OptDescs), false, OptDescs, O); O << '\n'; @@ -1870,10 +2119,93 @@ void EmitOptionDefinitions (const OptionDescriptions& descs, O << '\n'; } -/// EmitPopulateLanguageMap - Emit the PopulateLanguageMap() function. +/// EmitPreprocessOptionsCallback - Helper function passed to +/// EmitCaseConstructHandler() by EmitPreprocessOptions(). +class EmitPreprocessOptionsCallback : ActionHandlingCallbackBase { + const OptionDescriptions& OptDescs_; + + void onUnsetOption(Init* i, unsigned IndentLevel, raw_ostream& O) { + const std::string& OptName = InitPtrToString(i); + const OptionDescription& OptDesc = OptDescs_.FindOption(OptName); + + if (OptDesc.isSwitch()) { + O.indent(IndentLevel) << OptDesc.GenVariableName() << " = false;\n"; + } + else if (OptDesc.isParameter()) { + O.indent(IndentLevel) << OptDesc.GenVariableName() << " = \"\";\n"; + } + else if (OptDesc.isList()) { + O.indent(IndentLevel) << OptDesc.GenVariableName() << ".clear();\n"; + } + else { + throw "Can't apply 'unset_option' to alias option '" + OptName + "'"; + } + } + + void processDag(const Init* I, unsigned IndentLevel, raw_ostream& O) + { + const DagInit& d = InitPtrToDag(I); + const std::string& OpName = GetOperatorName(d); + + if (OpName == "warning") { + this->onWarningDag(d, IndentLevel, O); + } + else if (OpName == "error") { + this->onWarningDag(d, IndentLevel, O); + } + else if (OpName == "unset_option") { + checkNumberOfArguments(&d, 1); + Init* I = d.getArg(0); + if (typeid(*I) == typeid(ListInit)) { + const ListInit& DagList = *static_cast<const ListInit*>(I); + for (ListInit::const_iterator B = DagList.begin(), E = DagList.end(); + B != E; ++B) + this->onUnsetOption(*B, IndentLevel, O); + } + else { + this->onUnsetOption(I, IndentLevel, O); + } + } + else { + throw "Unknown operator in the option preprocessor: '" + OpName + "'!" + "\nOnly 'warning', 'error' and 'unset_option' are allowed."; + } + } + +public: + + void operator()(const Init* I, unsigned IndentLevel, raw_ostream& O) { + this->processDag(I, IndentLevel, O); + } + + EmitPreprocessOptionsCallback(const OptionDescriptions& OptDescs) + : OptDescs_(OptDescs) + {} +}; + +/// EmitPreprocessOptions - Emit the PreprocessOptionsLocal() function. +void EmitPreprocessOptions (const RecordKeeper& Records, + const OptionDescriptions& OptDecs, raw_ostream& O) +{ + O << "void PreprocessOptionsLocal() {\n"; + + const RecordVector& OptionPreprocessors = + Records.getAllDerivedDefinitions("OptionPreprocessor"); + + for (RecordVector::const_iterator B = OptionPreprocessors.begin(), + E = OptionPreprocessors.end(); B!=E; ++B) { + DagInit* Case = (*B)->getValueAsDag("preprocessor"); + EmitCaseConstructHandler(Case, Indent1, + EmitPreprocessOptionsCallback(OptDecs), + false, OptDecs, O); + } + + O << "}\n\n"; +} + +/// EmitPopulateLanguageMap - Emit the PopulateLanguageMapLocal() function. void EmitPopulateLanguageMap (const RecordKeeper& Records, raw_ostream& O) { - // Generate code O << "void PopulateLanguageMapLocal(LanguageMap& langMap) {\n"; // Get the relevant field out of RecordKeeper @@ -1907,7 +2239,7 @@ void EmitPopulateLanguageMap (const RecordKeeper& Records, raw_ostream& O) void IncDecWeight (const Init* i, unsigned IndentLevel, raw_ostream& O) { const DagInit& d = InitPtrToDag(i); - const std::string& OpName = d.getOperator()->getAsString(); + const std::string& OpName = GetOperatorName(d); if (OpName == "inc_weight") { O.indent(IndentLevel) << "ret += "; @@ -1916,17 +2248,16 @@ void IncDecWeight (const Init* i, unsigned IndentLevel, O.indent(IndentLevel) << "ret -= "; } else if (OpName == "error") { - O.indent(IndentLevel) - << "throw std::runtime_error(\"" << - (d.getNumArgs() >= 1 ? InitPtrToString(d.getArg(0)) - : "Unknown error!") - << "\");\n"; + checkNumberOfArguments(&d, 1); + O.indent(IndentLevel) << "throw std::runtime_error(\"" + << InitPtrToString(d.getArg(0)) + << "\");\n"; return; } - - else - throw "Unknown operator in edge properties list: " + OpName + '!' + + else { + throw "Unknown operator in edge properties list: '" + OpName + "'!" "\nOnly 'inc_weight', 'dec_weight' and 'error' are allowed."; + } if (d.getNumArgs() > 0) O << InitPtrToInt(d.getArg(0)) << ";\n"; @@ -1975,7 +2306,7 @@ void EmitEdgeClasses (const RecordVector& EdgeVector, } } -/// EmitPopulateCompilationGraph - Emit the PopulateCompilationGraph() +/// EmitPopulateCompilationGraph - Emit the PopulateCompilationGraphLocal() /// function. void EmitPopulateCompilationGraph (const RecordVector& EdgeVector, const ToolDescriptions& ToolDescs, @@ -2024,6 +2355,11 @@ public: void operator()(const Init* CmdLine) { StrVector cmds; + + // Ignore nested 'case' DAG. + if (typeid(*CmdLine) == typeid(DagInit)) + return; + TokenizeCmdline(InitPtrToString(CmdLine), cmds); for (StrVector::const_iterator B = cmds.begin(), E = cmds.end(); B != E; ++B) { @@ -2053,6 +2389,13 @@ public: } } } + + void operator()(const DagInit* Test, unsigned, bool) { + this->operator()(Test); + } + void operator()(const Init* Statement, unsigned) { + this->operator()(Statement); + } }; /// FillInHookNames - Actually extract the hook names from all command @@ -2104,6 +2447,8 @@ void EmitRegisterPlugin(int Priority, raw_ostream& O) { O << "struct Plugin : public llvmc::BasePlugin {\n\n"; O.indent(Indent1) << "int Priority() const { return " << Priority << "; }\n\n"; + O.indent(Indent1) << "void PreprocessOptions() const\n"; + O.indent(Indent1) << "{ PreprocessOptionsLocal(); }\n\n"; O.indent(Indent1) << "void PopulateLanguageMap(LanguageMap& langMap) const\n"; O.indent(Indent1) << "{ PopulateLanguageMapLocal(langMap); }\n\n"; O.indent(Indent1) @@ -2123,7 +2468,8 @@ void EmitIncludes(raw_ostream& O) { << "#include \"llvm/CompilerDriver/Tool.h\"\n\n" << "#include \"llvm/ADT/StringExtras.h\"\n" - << "#include \"llvm/Support/CommandLine.h\"\n\n" + << "#include \"llvm/Support/CommandLine.h\"\n" + << "#include \"llvm/Support/raw_ostream.h\"\n\n" << "#include <cstdlib>\n" << "#include <stdexcept>\n\n" @@ -2223,8 +2569,11 @@ void EmitPluginCode(const PluginData& Data, raw_ostream& O) { O << "namespace {\n\n"; - // Emit PopulateLanguageMap() function - // (a language map maps from file extensions to language names). + // Emit PreprocessOptionsLocal() function. + EmitPreprocessOptions(Records, Data.OptDescs, O); + + // Emit PopulateLanguageMapLocal() function + // (language map maps from file extensions to language names). EmitPopulateLanguageMap(Records, O); // Emit Tool classes. @@ -2235,7 +2584,7 @@ void EmitPluginCode(const PluginData& Data, raw_ostream& O) { // Emit Edge# classes. EmitEdgeClasses(Data.Edges, Data.OptDescs, O); - // Emit PopulateCompilationGraph() function. + // Emit PopulateCompilationGraphLocal() function. EmitPopulateCompilationGraph(Data.Edges, Data.ToolDescs, O); // Emit code for plugin registration. diff --git a/utils/TableGen/LLVMCConfigurationEmitter.h b/utils/TableGen/LLVMCConfigurationEmitter.h index 347f6f1..b37b83f 100644 --- a/utils/TableGen/LLVMCConfigurationEmitter.h +++ b/utils/TableGen/LLVMCConfigurationEmitter.h @@ -21,9 +21,8 @@ namespace llvm { /// LLVMCConfigurationEmitter - TableGen backend that generates /// configuration code for LLVMC. class LLVMCConfigurationEmitter : public TableGenBackend { - RecordKeeper &Records; public: - explicit LLVMCConfigurationEmitter(RecordKeeper &R) : Records(R) {} + explicit LLVMCConfigurationEmitter(RecordKeeper&) {} // run - Output the asmwriter, returning true on failure. void run(raw_ostream &o); diff --git a/utils/TableGen/StringToOffsetTable.h b/utils/TableGen/StringToOffsetTable.h index d9d7cf4..ac9422c 100644 --- a/utils/TableGen/StringToOffsetTable.h +++ b/utils/TableGen/StringToOffsetTable.h @@ -10,9 +10,10 @@ #ifndef TBLGEN_STRING_TO_OFFSET_TABLE_H #define TBLGEN_STRING_TO_OFFSET_TABLE_H +#include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringMap.h" -#include "llvm/Support/raw_ostream.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/Support/raw_ostream.h" namespace llvm { @@ -38,9 +39,13 @@ public: } void EmitString(raw_ostream &O) { + // Escape the string. + SmallString<256> Str; + raw_svector_ostream(Str).write_escaped(AggregateString); + AggregateString = Str.str(); + O << " \""; unsigned CharsPrinted = 0; - EscapeString(AggregateString); for (unsigned i = 0, e = AggregateString.size(); i != e; ++i) { if (CharsPrinted > 70) { O << "\"\n \""; diff --git a/utils/buildit/GNUmakefile b/utils/buildit/GNUmakefile index e3b334a..9971883 100644 --- a/utils/buildit/GNUmakefile +++ b/utils/buildit/GNUmakefile @@ -59,7 +59,7 @@ endif # NOTE : Always put version numbers at the end because they are optional. install: $(OBJROOT) $(SYMROOT) $(DSTROOT) cd $(OBJROOT) && \ - $(SRC)/build_llvm "$(RC_ARCHS)" "$(TARGETS)" \ + $(SRC)/utils/buildit/build_llvm "$(RC_ARCHS)" "$(TARGETS)" \ $(SRC) $(PREFIX) $(DSTROOT) $(SYMROOT) \ $(LLVM_ASSERTIONS) $(LLVM_OPTIMIZED) \ $(RC_ProjectSourceVersion) $(RC_ProjectSourceSubversion) diff --git a/utils/buildit/build_llvm b/utils/buildit/build_llvm index 91fbe15..2bdb208 100755 --- a/utils/buildit/build_llvm +++ b/utils/buildit/build_llvm @@ -82,6 +82,10 @@ SRC_DIR=$DIR/src rm -rf $SRC_DIR || exit 1 mkdir $SRC_DIR || exit 1 ln -s $ORIG_SRC_DIR/* $SRC_DIR/ || exit 1 +# We can't use the top-level Makefile as-is. Remove the soft link: +rm $SRC_DIR/Makefile || exit 1 +# Now create our own by editing the top-level Makefile, deleting every line marked "Apple-style": +sed -e '/[Aa]pple-style/d' -e '/include.*GNUmakefile/d' $ORIG_SRC_DIR/Makefile > $SRC_DIR/Makefile || exit 1 # Build the LLVM tree universal. mkdir -p $DIR/obj-llvm || exit 1 diff --git a/utils/emacs/tablegen-mode.el b/utils/emacs/tablegen-mode.el index 08f7f25..833c16c 100644 --- a/utils/emacs/tablegen-mode.el +++ b/utils/emacs/tablegen-mode.el @@ -112,6 +112,8 @@ ) (set-syntax-table tablegen-mode-syntax-table) + (make-local-variable 'comment-start) + (setq comment-start "//") (run-hooks 'tablegen-mode-hook)) ; Finally, this permits the user to ; customize the mode with a hook. diff --git a/utils/lit/LitConfig.py b/utils/lit/LitConfig.py index 4fb0ccc..c334109 100644 --- a/utils/lit/LitConfig.py +++ b/utils/lit/LitConfig.py @@ -29,6 +29,7 @@ class LitConfig: self.noExecute = noExecute self.debug = debug self.isWindows = bool(isWindows) + self.bashPath = None self.numErrors = 0 self.numWarnings = 0 @@ -41,6 +42,27 @@ class LitConfig: mustExist = True, config = config) + def getBashPath(self): + """getBashPath - Get the path to 'bash'""" + import os, Util + + if self.bashPath is not None: + return self.bashPath + + self.bashPath = Util.which('bash', os.pathsep.join(self.path)) + if self.bashPath is None: + # Check some known paths. + for path in ('/bin/bash', '/usr/bin/bash'): + if os.path.exists(path): + self.bashPath = path + break + + if self.bashPath is None: + self.warning("Unable to find 'bash', running Tcl tests internally.") + self.bashPath = '' + + return self.bashPath + def _write_message(self, kind, message): import inspect, os, sys diff --git a/utils/lit/TestFormats.py b/utils/lit/TestFormats.py index 61bdb18..7e638b4 100644 --- a/utils/lit/TestFormats.py +++ b/utils/lit/TestFormats.py @@ -53,6 +53,10 @@ class GoogleTest(object): def execute(self, test, litConfig): testPath,testName = os.path.split(test.getSourcePath()) + if not os.path.exists(testPath): + # Handle GTest typed tests, whose name includes a '/'. + testPath, namePrefix = os.path.split(testPath) + testName = os.path.join(namePrefix, testName) cmd = [testPath, '--gtest_filter=' + testName] out, err, exitCode = TestRunner.executeCommand(cmd) diff --git a/utils/lit/TestRunner.py b/utils/lit/TestRunner.py index 7b549ac..34e828b 100644 --- a/utils/lit/TestRunner.py +++ b/utils/lit/TestRunner.py @@ -237,7 +237,9 @@ def executeTclScriptInternal(test, litConfig, tmpBase, commands, cwd): for c in cmds[1:]: cmd = ShUtil.Seq(cmd, '&&', c) - if litConfig.useTclAsSh: + # FIXME: This is lame, we shouldn't need bash. See PR5240. + bashPath = litConfig.getBashPath() + if litConfig.useTclAsSh and bashPath: script = tmpBase + '.script' # Write script file @@ -252,7 +254,7 @@ def executeTclScriptInternal(test, litConfig, tmpBase, commands, cwd): print >>sys.stdout return '', '', 0 - command = ['/bin/bash', script] + command = [litConfig.getBashPath(), script] out,err,exitCode = executeCommand(command, cwd=cwd, env=test.config.environment) |