From gaeke at cs.uiuc.edu Mon Mar 1 00:44:01 2004 From: gaeke at cs.uiuc.edu (Brian Gaeke) Date: Mon Mar 1 00:44:01 2004 Subject: [llvm-commits] CVS: llvm/lib/Target/SparcV9/SparcV9AsmPrinter.cpp SparcV9Internals.h SparcV9TargetMachine.cpp SparcV9TargetMachine.h Message-ID: <200403010643.AAA27928@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/SparcV9: SparcV9AsmPrinter.cpp updated: 1.108 -> 1.109 SparcV9Internals.h updated: 1.111 -> 1.112 SparcV9TargetMachine.cpp updated: 1.102 -> 1.103 SparcV9TargetMachine.h updated: 1.5 -> 1.6 --- Log message: TargetCacheInfo has been removed; its only uses were to propagate a constant (16) into certain areas of the SPARC V9 back-end. I'm fairly sure the US IIIi's dcache has 32-byte lines, so I'm not sure where the 16 came from. However, in the interest of not breaking things any more than they already are, I'm going to leave the constant alone. --- Diffs of the changes: (+1 -18) Index: llvm/lib/Target/SparcV9/SparcV9AsmPrinter.cpp diff -u llvm/lib/Target/SparcV9/SparcV9AsmPrinter.cpp:1.108 llvm/lib/Target/SparcV9/SparcV9AsmPrinter.cpp:1.109 --- llvm/lib/Target/SparcV9/SparcV9AsmPrinter.cpp:1.108 Wed Feb 25 12:44:15 2004 +++ llvm/lib/Target/SparcV9/SparcV9AsmPrinter.cpp Mon Mar 1 00:43:28 2004 @@ -119,7 +119,7 @@ /// inline unsigned int SizeToAlignment(unsigned int size, const TargetMachine& target) { - unsigned short cacheLineSize = target.getCacheInfo().getCacheLineSize(1); + const unsigned short cacheLineSize = 16; if (size > (unsigned) cacheLineSize / 2) return cacheLineSize; else Index: llvm/lib/Target/SparcV9/SparcV9Internals.h diff -u llvm/lib/Target/SparcV9/SparcV9Internals.h:1.111 llvm/lib/Target/SparcV9/SparcV9Internals.h:1.112 --- llvm/lib/Target/SparcV9/SparcV9Internals.h:1.111 Wed Feb 25 12:44:15 2004 +++ llvm/lib/Target/SparcV9/SparcV9Internals.h Mon Mar 1 00:43:29 2004 @@ -19,7 +19,6 @@ #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetSchedInfo.h" #include "llvm/Target/TargetFrameInfo.h" -#include "llvm/Target/TargetCacheInfo.h" #include "llvm/Target/TargetRegInfo.h" #include "llvm/Type.h" #include "SparcV9RegClassInfo.h" @@ -88,19 +87,6 @@ protected: virtual void initializeResources(); }; - -//--------------------------------------------------------------------------- -// class SparcV9CacheInfo -// -// Purpose: -// Interface to cache parameters for the UltraSPARC. -// Just use defaults for now. -//--------------------------------------------------------------------------- - -struct SparcV9CacheInfo: public TargetCacheInfo { - SparcV9CacheInfo(const TargetMachine &T) : TargetCacheInfo(T) {} -}; - /// createStackSlotsPass - External interface to stack-slots pass that enters 2 /// empty slots at the top of each function stack Index: llvm/lib/Target/SparcV9/SparcV9TargetMachine.cpp diff -u llvm/lib/Target/SparcV9/SparcV9TargetMachine.cpp:1.102 llvm/lib/Target/SparcV9/SparcV9TargetMachine.cpp:1.103 --- llvm/lib/Target/SparcV9/SparcV9TargetMachine.cpp:1.102 Fri Feb 27 15:15:40 2004 +++ llvm/lib/Target/SparcV9/SparcV9TargetMachine.cpp Mon Mar 1 00:43:29 2004 @@ -116,7 +116,6 @@ schedInfo(*this), regInfo(*this), frameInfo(*this), - cacheInfo(*this), jitInfo(*this) { } Index: llvm/lib/Target/SparcV9/SparcV9TargetMachine.h diff -u llvm/lib/Target/SparcV9/SparcV9TargetMachine.h:1.5 llvm/lib/Target/SparcV9/SparcV9TargetMachine.h:1.6 --- llvm/lib/Target/SparcV9/SparcV9TargetMachine.h:1.5 Wed Feb 25 12:44:15 2004 +++ llvm/lib/Target/SparcV9/SparcV9TargetMachine.h Mon Mar 1 00:43:29 2004 @@ -30,7 +30,6 @@ SparcV9SchedInfo schedInfo; SparcV9RegInfo regInfo; SparcV9FrameInfo frameInfo; - SparcV9CacheInfo cacheInfo; SparcV9JITInfo jitInfo; public: SparcV9TargetMachine(IntrinsicLowering *IL); @@ -39,7 +38,6 @@ virtual const TargetSchedInfo &getSchedInfo() const { return schedInfo; } virtual const TargetRegInfo &getRegInfo() const { return regInfo; } virtual const TargetFrameInfo &getFrameInfo() const { return frameInfo; } - virtual const TargetCacheInfo &getCacheInfo() const { return cacheInfo; } virtual TargetJITInfo *getJITInfo() { return &jitInfo; } virtual bool addPassesToEmitAssembly(PassManager &PM, std::ostream &Out); From gaeke at cs.uiuc.edu Mon Mar 1 00:44:04 2004 From: gaeke at cs.uiuc.edu (Brian Gaeke) Date: Mon Mar 1 00:44:04 2004 Subject: [llvm-commits] CVS: llvm/lib/Target/PowerPC/PowerPCTargetMachine.h Message-ID: <200403010643.AAA27898@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/PowerPC: PowerPCTargetMachine.h updated: 1.3 -> 1.4 --- Log message: TargetCacheInfo has been removed; its only uses were to propagate a constant (16) into certain areas of the SPARC V9 back-end. I'm fairly sure the US IIIi's dcache has 32-byte lines, so I'm not sure where the 16 came from. However, in the interest of not breaking things any more than they already are, I'm going to leave the constant alone. --- Diffs of the changes: (+0 -1) Index: llvm/lib/Target/PowerPC/PowerPCTargetMachine.h diff -u llvm/lib/Target/PowerPC/PowerPCTargetMachine.h:1.3 llvm/lib/Target/PowerPC/PowerPCTargetMachine.h:1.4 --- llvm/lib/Target/PowerPC/PowerPCTargetMachine.h:1.3 Fri Jan 23 00:39:30 2004 +++ llvm/lib/Target/PowerPC/PowerPCTargetMachine.h Mon Mar 1 00:43:28 2004 @@ -42,7 +42,6 @@ virtual const TargetSchedInfo &getSchedInfo() const { abort(); } virtual const TargetRegInfo &getRegInfo() const { abort(); } - virtual const TargetCacheInfo &getCacheInfo() const { abort(); } /// addPassesToEmitMachineCode - Add passes to the specified pass manager to /// get machine code emitted. This uses a MachineCodeEmitter object to handle From gaeke at cs.uiuc.edu Mon Mar 1 00:44:06 2004 From: gaeke at cs.uiuc.edu (Brian Gaeke) Date: Mon Mar 1 00:44:06 2004 Subject: [llvm-commits] CVS: llvm/lib/Target/SparcV8/SparcV8TargetMachine.h Message-ID: <200403010643.AAA27910@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/SparcV8: SparcV8TargetMachine.h updated: 1.1 -> 1.2 --- Log message: TargetCacheInfo has been removed; its only uses were to propagate a constant (16) into certain areas of the SPARC V9 back-end. I'm fairly sure the US IIIi's dcache has 32-byte lines, so I'm not sure where the 16 came from. However, in the interest of not breaking things any more than they already are, I'm going to leave the constant alone. --- Diffs of the changes: (+0 -1) Index: llvm/lib/Target/SparcV8/SparcV8TargetMachine.h diff -u llvm/lib/Target/SparcV8/SparcV8TargetMachine.h:1.1 llvm/lib/Target/SparcV8/SparcV8TargetMachine.h:1.2 --- llvm/lib/Target/SparcV8/SparcV8TargetMachine.h:1.1 Wed Feb 25 13:28:19 2004 +++ llvm/lib/Target/SparcV8/SparcV8TargetMachine.h Mon Mar 1 00:43:28 2004 @@ -42,7 +42,6 @@ virtual const TargetSchedInfo &getSchedInfo() const { abort(); } virtual const TargetRegInfo &getRegInfo() const { abort(); } - virtual const TargetCacheInfo &getCacheInfo() const { abort(); } /// addPassesToEmitMachineCode - Add passes to the specified pass manager to /// get machine code emitted. This uses a MachineCodeEmitter object to handle From gaeke at cs.uiuc.edu Mon Mar 1 00:44:07 2004 From: gaeke at cs.uiuc.edu (Brian Gaeke) Date: Mon Mar 1 00:44:07 2004 Subject: [llvm-commits] CVS: llvm/lib/Target/TargetMachine.cpp Message-ID: <200403010643.AAA27885@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target: TargetMachine.cpp updated: 1.21 -> 1.22 --- Log message: TargetCacheInfo has been removed; its only uses were to propagate a constant (16) into certain areas of the SPARC V9 back-end. I'm fairly sure the US IIIi's dcache has 32-byte lines, so I'm not sure where the 16 came from. However, in the interest of not breaking things any more than they already are, I'm going to leave the constant alone. --- Diffs of the changes: (+0 -19) Index: llvm/lib/Target/TargetMachine.cpp diff -u llvm/lib/Target/TargetMachine.cpp:1.21 llvm/lib/Target/TargetMachine.cpp:1.22 --- llvm/lib/Target/TargetMachine.cpp:1.21 Sun Dec 28 15:23:38 2003 +++ llvm/lib/Target/TargetMachine.cpp Mon Mar 1 00:43:28 2004 @@ -8,12 +8,10 @@ //===----------------------------------------------------------------------===// // // This file describes the general parts of a Target machine. -// This file also implements TargetCacheInfo. // //===----------------------------------------------------------------------===// #include "llvm/Target/TargetMachine.h" -#include "llvm/Target/TargetCacheInfo.h" #include "llvm/Type.h" #include "llvm/IntrinsicLowering.h" using namespace llvm; @@ -33,31 +31,14 @@ IL = il ? il : new DefaultIntrinsicLowering(); } - - TargetMachine::~TargetMachine() { delete IL; } - - - unsigned TargetMachine::findOptimalStorageSize(const Type *Ty) const { // All integer types smaller than ints promote to 4 byte integers. if (Ty->isIntegral() && Ty->getPrimitiveSize() < 4) return 4; return DataLayout.getTypeSize(Ty); -} - - -//--------------------------------------------------------------------------- -// TargetCacheInfo Class -// - -void TargetCacheInfo::Initialize() { - numLevels = 2; - cacheLineSizes.push_back(16); cacheLineSizes.push_back(32); - cacheSizes.push_back(1 << 15); cacheSizes.push_back(1 << 20); - cacheAssoc.push_back(1); cacheAssoc.push_back(4); } From gaeke at cs.uiuc.edu Mon Mar 1 00:44:09 2004 From: gaeke at cs.uiuc.edu (Brian Gaeke) Date: Mon Mar 1 00:44:09 2004 Subject: [llvm-commits] CVS: llvm/lib/CodeGen/MachineFunction.cpp Message-ID: <200403010643.AAA27880@zion.cs.uiuc.edu> Changes in directory llvm/lib/CodeGen: MachineFunction.cpp updated: 1.53 -> 1.54 --- Log message: TargetCacheInfo has been removed; its only uses were to propagate a constant (16) into certain areas of the SPARC V9 back-end. I'm fairly sure the US IIIi's dcache has 32-byte lines, so I'm not sure where the 16 came from. However, in the interest of not breaking things any more than they already are, I'm going to leave the constant alone. --- Diffs of the changes: (+1 -2) Index: llvm/lib/CodeGen/MachineFunction.cpp diff -u llvm/lib/CodeGen/MachineFunction.cpp:1.53 llvm/lib/CodeGen/MachineFunction.cpp:1.54 --- llvm/lib/CodeGen/MachineFunction.cpp:1.53 Sun Feb 29 13:04:31 2004 +++ llvm/lib/CodeGen/MachineFunction.cpp Mon Mar 1 00:43:28 2004 @@ -22,7 +22,6 @@ #include "llvm/CodeGen/Passes.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetFrameInfo.h" -#include "llvm/Target/TargetCacheInfo.h" #include "llvm/Function.h" #include "llvm/iOther.h" using namespace llvm; @@ -273,7 +272,7 @@ inline unsigned SizeToAlignment(unsigned size, const TargetMachine& target) { - unsigned short cacheLineSize = target.getCacheInfo().getCacheLineSize(1); + const unsigned short cacheLineSize = 16; if (size > (unsigned) cacheLineSize / 2) return cacheLineSize; else From gaeke at cs.uiuc.edu Mon Mar 1 00:44:11 2004 From: gaeke at cs.uiuc.edu (Brian Gaeke) Date: Mon Mar 1 00:44:11 2004 Subject: [llvm-commits] CVS: llvm/include/llvm/Target/TargetMachine.h TargetCacheInfo.h Message-ID: <200403010643.AAA27882@zion.cs.uiuc.edu> Changes in directory llvm/include/llvm/Target: TargetMachine.h updated: 1.42 -> 1.43 TargetCacheInfo.h (r1.12) removed --- Log message: TargetCacheInfo has been removed; its only uses were to propagate a constant (16) into certain areas of the SPARC V9 back-end. I'm fairly sure the US IIIi's dcache has 32-byte lines, so I'm not sure where the 16 came from. However, in the interest of not breaking things any more than they already are, I'm going to leave the constant alone. --- Diffs of the changes: (+0 -2) Index: llvm/include/llvm/Target/TargetMachine.h diff -u llvm/include/llvm/Target/TargetMachine.h:1.42 llvm/include/llvm/Target/TargetMachine.h:1.43 --- llvm/include/llvm/Target/TargetMachine.h:1.42 Sun Dec 28 15:22:35 2003 +++ llvm/include/llvm/Target/TargetMachine.h Mon Mar 1 00:43:28 2004 @@ -25,7 +25,6 @@ class TargetSchedInfo; class TargetRegInfo; class TargetFrameInfo; -class TargetCacheInfo; class MachineCodeEmitter; class MRegisterInfo; class FunctionPassManager; @@ -75,7 +74,6 @@ virtual const TargetSchedInfo& getSchedInfo() const = 0; virtual const TargetRegInfo& getRegInfo() const = 0; virtual const TargetFrameInfo& getFrameInfo() const = 0; - virtual const TargetCacheInfo& getCacheInfo() const = 0; const TargetData &getTargetData() const { return DataLayout; } /// getRegisterInfo - If register information is available, return it. If From gaeke at cs.uiuc.edu Mon Mar 1 00:44:13 2004 From: gaeke at cs.uiuc.edu (Brian Gaeke) Date: Mon Mar 1 00:44:13 2004 Subject: [llvm-commits] CVS: llvm/lib/Target/CBackend/CTargetMachine.h Message-ID: <200403010643.AAA27890@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/CBackend: CTargetMachine.h updated: 1.1 -> 1.2 --- Log message: TargetCacheInfo has been removed; its only uses were to propagate a constant (16) into certain areas of the SPARC V9 back-end. I'm fairly sure the US IIIi's dcache has 32-byte lines, so I'm not sure where the 16 came from. However, in the interest of not breaking things any more than they already are, I'm going to leave the constant alone. --- Diffs of the changes: (+0 -1) Index: llvm/lib/Target/CBackend/CTargetMachine.h diff -u llvm/lib/Target/CBackend/CTargetMachine.h:1.1 llvm/lib/Target/CBackend/CTargetMachine.h:1.2 --- llvm/lib/Target/CBackend/CTargetMachine.h:1.1 Fri Feb 13 17:18:48 2004 +++ llvm/lib/Target/CBackend/CTargetMachine.h Mon Mar 1 00:43:28 2004 @@ -27,7 +27,6 @@ virtual const TargetFrameInfo &getFrameInfo() const { abort(); } virtual const TargetSchedInfo &getSchedInfo() const { abort(); } virtual const TargetRegInfo &getRegInfo() const { abort(); } - virtual const TargetCacheInfo &getCacheInfo() const { abort(); } // This is the only thing that actually does anything here. virtual bool addPassesToEmitAssembly(PassManager &PM, std::ostream &Out); From gaeke at cs.uiuc.edu Mon Mar 1 00:44:15 2004 From: gaeke at cs.uiuc.edu (Brian Gaeke) Date: Mon Mar 1 00:44:15 2004 Subject: [llvm-commits] CVS: llvm/lib/Target/X86/X86TargetMachine.h Message-ID: <200403010643.AAA27927@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/X86: X86TargetMachine.h updated: 1.21 -> 1.22 --- Log message: TargetCacheInfo has been removed; its only uses were to propagate a constant (16) into certain areas of the SPARC V9 back-end. I'm fairly sure the US IIIi's dcache has 32-byte lines, so I'm not sure where the 16 came from. However, in the interest of not breaking things any more than they already are, I'm going to leave the constant alone. --- Diffs of the changes: (+5 -9) Index: llvm/lib/Target/X86/X86TargetMachine.h diff -u llvm/lib/Target/X86/X86TargetMachine.h:1.21 llvm/lib/Target/X86/X86TargetMachine.h:1.22 --- llvm/lib/Target/X86/X86TargetMachine.h:1.21 Sun Dec 28 15:23:38 2003 +++ llvm/lib/Target/X86/X86TargetMachine.h Mon Mar 1 00:43:29 2004 @@ -32,18 +32,14 @@ virtual const X86InstrInfo &getInstrInfo() const { return InstrInfo; } virtual const TargetFrameInfo &getFrameInfo() const { return FrameInfo; } - virtual const MRegisterInfo *getRegisterInfo() const { + virtual TargetJITInfo *getJITInfo() { return &JITInfo; } + virtual const MRegisterInfo *getRegisterInfo() const { return &InstrInfo.getRegisterInfo(); } - virtual TargetJITInfo *getJITInfo() { - return &JITInfo; - } - - - virtual const TargetSchedInfo &getSchedInfo() const { abort(); } - virtual const TargetRegInfo &getRegInfo() const { abort(); } - virtual const TargetCacheInfo &getCacheInfo() const { abort(); } + // deprecated interfaces + virtual const TargetSchedInfo &getSchedInfo() const { abort(); } + virtual const TargetRegInfo &getRegInfo() const { abort(); } /// addPassesToEmitMachineCode - Add passes to the specified pass manager to /// get machine code emitted. This uses a MachineCodeEmitter object to handle From tbrethou at cs.uiuc.edu Mon Mar 1 09:06:03 2004 From: tbrethou at cs.uiuc.edu (Tanya Brethour) Date: Mon Mar 1 09:06:03 2004 Subject: [llvm-commits] CVS: llvm/lib/Target/SparcV9/SparcV9Instr.def Message-ID: <200403011505.JAA11587@seraph.cs.uiuc.edu> Changes in directory llvm/lib/Target/SparcV9: SparcV9Instr.def updated: 1.24 -> 1.25 --- Log message: fix bug in previous checkin --- Diffs of the changes: (+1 -1) Index: llvm/lib/Target/SparcV9/SparcV9Instr.def diff -u llvm/lib/Target/SparcV9/SparcV9Instr.def:1.24 llvm/lib/Target/SparcV9/SparcV9Instr.def:1.25 --- llvm/lib/Target/SparcV9/SparcV9Instr.def:1.24 Sat Feb 28 23:58:30 2004 +++ llvm/lib/Target/SparcV9/SparcV9Instr.def Mon Mar 1 09:05:17 2004 @@ -538,7 +538,7 @@ // Synthetic phi operation for near-SSA form of machine code // Number of operands is variable, indicated by -1. Result is the first op. -I(PHI, "", -1, 0, 0, false, 0, 0, SPARC_INV, M_DUMMY_PHI_FLAG) +I(PHI, "", -1, 0, 0, false, 0, 0, SPARC_NONE, M_DUMMY_PHI_FLAG) #undef B5 From lattner at cs.uiuc.edu Mon Mar 1 09:29:01 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon Mar 1 09:29:01 2004 Subject: [llvm-commits] CVS: llvm/lib/Target/SparcV9/SparcV9TargetMachine.cpp Message-ID: <200403011528.JAA09734@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/SparcV9: SparcV9TargetMachine.cpp updated: 1.103 -> 1.104 --- Log message: Add this back, as its absence introduces assertions, and it seems to work now that Instructions are annotable again --- Diffs of the changes: (+1 -4) Index: llvm/lib/Target/SparcV9/SparcV9TargetMachine.cpp diff -u llvm/lib/Target/SparcV9/SparcV9TargetMachine.cpp:1.103 llvm/lib/Target/SparcV9/SparcV9TargetMachine.cpp:1.104 --- llvm/lib/Target/SparcV9/SparcV9TargetMachine.cpp:1.103 Mon Mar 1 00:43:29 2004 +++ llvm/lib/Target/SparcV9/SparcV9TargetMachine.cpp Mon Mar 1 09:28:27 2004 @@ -177,11 +177,8 @@ // function has been emitted. PM.add(createAsmPrinterPass(Out, *this)); - // FIXME: this pass crashes if added; there is a double deletion going on - // somewhere inside it. This is caught when running the SparcV9 code generator - // on X86, but is typically ignored when running natively. // Free machine-code IR which is no longer needed: - // PM.add(createSparcV9MachineCodeDestructionPass()); + PM.add(createSparcV9MachineCodeDestructionPass()); // Emit bytecode to the assembly file into its special section next if (EmitMappingInfo) From lattner at cs.uiuc.edu Mon Mar 1 09:47:01 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon Mar 1 09:47:01 2004 Subject: [llvm-commits] CVS: llvm/test/Programs/External/SPEC/Makefile Message-ID: <200403011546.JAA09942@zion.cs.uiuc.edu> Changes in directory llvm/test/Programs/External/SPEC: Makefile updated: 1.9 -> 1.10 --- Log message: Move spec95 to the end of the list so that it doesn't kill spec 2k if it has issues --- Diffs of the changes: (+1 -1) Index: llvm/test/Programs/External/SPEC/Makefile diff -u llvm/test/Programs/External/SPEC/Makefile:1.9 llvm/test/Programs/External/SPEC/Makefile:1.10 --- llvm/test/Programs/External/SPEC/Makefile:1.9 Wed Feb 25 17:19:24 2004 +++ llvm/test/Programs/External/SPEC/Makefile Mon Mar 1 09:46:27 2004 @@ -1,5 +1,5 @@ LEVEL = ../../../.. -DIRS := CINT95 CFP2000 CINT2000 +DIRS := CFP2000 CINT2000 CINT95 include ${LEVEL}/Makefile.config # From alkis at niobe.cs.uiuc.edu Mon Mar 1 09:58:01 2004 From: alkis at niobe.cs.uiuc.edu (Alkis Evlogimenos) Date: Mon Mar 1 09:58:01 2004 Subject: [llvm-commits] CVS: llvm/test/Programs/External/SPEC/CINT95/099.go/Makefile Message-ID: <200403011557.i21Fvcr08745@niobe.cs.uiuc.edu> Changes in directory llvm/test/Programs/External/SPEC/CINT95/099.go: Makefile updated: 1.1 -> 1.2 --- Log message: Work with both test and train inputs --- Diffs of the changes: (+6 -0) Index: llvm/test/Programs/External/SPEC/CINT95/099.go/Makefile diff -u llvm/test/Programs/External/SPEC/CINT95/099.go/Makefile:1.1 llvm/test/Programs/External/SPEC/CINT95/099.go/Makefile:1.2 --- llvm/test/Programs/External/SPEC/CINT95/099.go/Makefile:1.1 Tue Feb 10 11:23:00 2004 +++ llvm/test/Programs/External/SPEC/CINT95/099.go/Makefile Mon Mar 1 09:57:28 2004 @@ -1,6 +1,12 @@ LEVEL = ../../../../../.. BM=099.go + +ifeq ($(RUN_TYPE),test) STDIN_FILENAME = /dev/null STDOUT_FILENAME = null.out RUN_OPTIONS = 40 19 +else +STDIN_FILENAME = 2stone9.in +STDOUT_FILENAME = 2stone9.out +endif include ../../Makefile.spec95 From criswell at cs.uiuc.edu Mon Mar 1 10:17:01 2004 From: criswell at cs.uiuc.edu (John Criswell) Date: Mon Mar 1 10:17:01 2004 Subject: [llvm-commits] CVS: llvm/test/Programs/MultiSource/Applications/d/grammar.g Message-ID: <200403011616.KAA25996@choi.cs.uiuc.edu> Changes in directory llvm/test/Programs/MultiSource/Applications/d: grammar.g added (r1.1) --- Log message: Test input file that I forgot to commit. Lo siento. --- Diffs of the changes: (+185 -0) Index: llvm/test/Programs/MultiSource/Applications/d/grammar.g diff -c /dev/null llvm/test/Programs/MultiSource/Applications/d/grammar.g:1.1 *** /dev/null Mon Mar 1 10:16:34 2004 --- llvm/test/Programs/MultiSource/Applications/d/grammar.g Mon Mar 1 10:16:24 2004 *************** *** 0 **** --- 1,185 ---- + /* + Grammar Grammar + */ + { + #include "gramgram.h" + #include "d.h" + } + + grammar: global_code* (production global_code*)+; + + global_code: curly_code { + add_global_code($g, $n0.start_loc.s+1, $n0.end-1, + $n0.start_loc.line); + } + | '${scanner' balanced_code+ '}' { + $g->scanner.code = dup_str($n1.start_loc.s, $n1.end); + $g->scanner.line = $n0.start_loc.line; + } + | '${declare' declarationtype identifier* '}' { + if (!d_get_number_of_children(&$n2)) + add_declaration($g, $n2.start_loc.s, $n2.end, $1.kind, $n2.start_loc.line); + else { + int i, n = d_get_number_of_children(&$n2); + for (i = 0; i < n; i++) { + D_ParseNode *pn = d_get_child(&$n2, i); + add_declaration($g, pn->start_loc.s, pn->end, $1.kind, pn->start_loc.line); + } + } + } + | '${token' token_identifier+ '}' + | '${action}' { $g->action_index++; } + | '${pass' identifier pass_types '}' { + add_pass($g, $n1.start_loc.s, $n1.end, $2.kind, $n1.start_loc.line); + } + ; + + pass_types: + | pass_type pass_types { $$.kind = $0.kind | $1.kind; } + ; + + pass_type : 'preorder' { $$.kind |= D_PASS_PRE_ORDER; } + | 'postorder' { $$.kind |= D_PASS_POST_ORDER; } + | 'manual' { $$.kind |= D_PASS_MANUAL; } + | 'for_all' { $$.kind |= D_PASS_FOR_ALL; } + | 'for_undefined' { $$.kind |= D_PASS_FOR_UNDEFINED; } + ; + + declarationtype: 'tokenize' { $$.kind = DECLARE_TOKENIZE; } + | 'longest_match' { $$.kind = DECLARE_LONGEST_MATCH; } + | 'whitespace' { $$.kind = DECLARE_WHITESPACE; } + | 'all_matches' { $$.kind = DECLARE_ALL_MATCHES; } + | 'set_op_priority_from_rule' { $$.kind = DECLARE_SET_OP_PRIORITY; } + | 'all_subparsers' { $$.kind = DECLARE_STATES_FOR_ALL_NTERMS; } + | 'subparser' { $$.kind = DECLARE_STATE_FOR; } + | 'save_parse_tree' { $$.kind = DECLARE_SAVE_PARSE_TREE; } + ; + + token_identifier: identifier { new_token($g, $n0.start_loc.s, $n0.end); }; + + production : production_name ':' rules ';' + | production_name regex_production rules ';' + | ';'; + regex_production : '::=' { $g->p->regex = 1; }; + + production_name : (identifier | '_') + { $g->p = new_production($g, dup_str($n0.start_loc.s, $n0.end)); } + ; + + rules : rule ('|' rule)*; + + rule : new_rule ((element element_modifier*)* simple_element element_modifier*)? rule_modifier* rule_code { + vec_add(&$g->p->rules, $g->r); + }; + + new_rule : { $g->r = new_rule($g, $g->p); }; + + simple_element + : string { $g->e = new_string($g, $n0.start_loc.s, $n0.end, $g->r); } + | regex { $g->e = new_string($g, $n0.start_loc.s, $n0.end, $g->r); } + | identifier { $g->e = new_ident($n0.start_loc.s, $n0.end, $g->r); } + | '${scan' balanced_code+ '}' { $g->e = new_code($g, $n1.start_loc.s, $n1.end, $g->r); } + | '(' new_subrule rules ')' { + $g->e = new_elem_nterm($g->p, $1.r); + $g->p = $1.p; + $g->r = $1.r; + vec_add(&$g->r->elems, $g->e); + } + ; + + element + : simple_element + | bracket_code { + Production *p = new_internal_production($g, NULL); + Rule *r = new_rule($g, p); + vec_add(&p->rules, r); + r->speculative_code.code = dup_str($n0.start_loc.s + 1, $n0.end - 1); + r->speculative_code.line = $n0.start_loc.line; + $g->e = new_elem_nterm(p, $g->r); + vec_add(&$g->r->elems, $g->e); + } + | curly_code { + Production *p = new_internal_production($g, NULL); + Rule *r = new_rule($g, p); + vec_add(&p->rules, r); + r->final_code.code = dup_str($n0.start_loc.s + 1, $n0.end - 1); + r->final_code.line = $n0.start_loc.line; + $g->e = new_elem_nterm(p, $g->r); + vec_add(&$g->r->elems, $g->e); + } + ; + + new_subrule : { + $$.p = $g->p; + $$.r = $g->r; + $g->p = new_internal_production($g, $g->p); + $g->r = new_rule($g, $g->p); + }; + + element_modifier + : '$term' integer { + if ($g->e->kind != ELEM_TERM) + d_fail("terminal priority on non-terminal"); + $g->e->e.term->term_priority = strtol($n1.start_loc.s, NULL, 0); + } + | '/i' { + if ($g->e->kind != ELEM_TERM) + d_fail("ignore-case (/i) on non-terminal"); + $g->e->e.term->ignore_case = 1; + } + | '?' { conditional_EBNF($g); } + | '*' { star_EBNF($g); } + | '+' { plus_EBNF($g); } ; + + rule_modifier : rule_assoc rule_priority; + + rule_assoc + : '$unary_op_right' { $g->r->op_assoc = ASSOC_UNARY_RIGHT; } + | '$unary_op_left' { $g->r->op_assoc = ASSOC_UNARY_LEFT; } + | '$binary_op_right' { $g->r->op_assoc = ASSOC_BINARY_RIGHT; } + | '$binary_op_left' { $g->r->op_assoc = ASSOC_BINARY_LEFT; } + | '$unary_right' { $g->r->rule_assoc = ASSOC_UNARY_RIGHT; } + | '$unary_left' { $g->r->rule_assoc = ASSOC_UNARY_LEFT; } + | '$binary_right' { $g->r->rule_assoc = ASSOC_BINARY_RIGHT; } + | '$binary_left' { $g->r->rule_assoc = ASSOC_BINARY_LEFT; } + | '$right' { $g->r->rule_assoc = ASSOC_NARY_RIGHT; } + | '$left' { $g->r->rule_assoc = ASSOC_NARY_LEFT; } + ; + + rule_priority : integer { + if ($g->r->op_assoc) $g->r->op_priority = strtol($n0.start_loc.s, NULL, 0); + else $g->r->rule_priority = strtol($n0.start_loc.s, NULL, 0); + }; + + rule_code : speculative_code? final_code? pass_code* ; + + speculative_code : bracket_code { + $g->r->speculative_code.code = dup_str($n0.start_loc.s + 1, $n0.end - 1); + $g->r->speculative_code.line = $n0.start_loc.line; + }; + + final_code : curly_code { + $g->r->final_code.code = dup_str($n0.start_loc.s + 1, $n0.end - 1); + $g->r->final_code.line = $n0.start_loc.line; + }; + + pass_code : identifier ':' curly_code { + add_pass_code($g, $g->r, $n0.start_loc.s, $n0.end, $n2.start_loc.s+1, + $n2.end-1, $n0.start_loc.line, $n2.start_loc.line); + }; + + curly_code: '{' balanced_code* '}'; + bracket_code: '[' balanced_code* ']'; + balanced_code : '(' balanced_code* ')' + | '[' balanced_code* ']' + | '{' balanced_code* '}' + | string | identifier | regex | integer | symbols; + symbols : "[!~`@#$%^&*\-_+=|:;\\<,>.?/]"; + string: "'([^'\\]|\\[^])*'"; + regex: "\"([^\"\\]|\\[^])*\""; + identifier: "[a-zA-Z_][a-zA-Z_0-9]*" $term -1; + integer: decimalint | hexint | octalint; + decimalint: "-?[1-9][0-9]*[uUlL]?"; + hexint: "-?(0x|0X)[0-9a-fA-F]+[uUlL]?"; + octalint: "-?0[0-7]*[uUlL]?"; + From criswell at cs.uiuc.edu Mon Mar 1 11:46:02 2004 From: criswell at cs.uiuc.edu (John Criswell) Date: Mon Mar 1 11:46:02 2004 Subject: [llvm-commits] CVS: llvm/test/Programs/TEST.vtl.Makefile Message-ID: <200403011745.LAA13219@zion.cs.uiuc.edu> Changes in directory llvm/test/Programs: TEST.vtl.Makefile updated: 1.1 -> 1.2 --- Log message: Switched over to Pentium 4 events. Added code to run pool allocation tests as well. Updated comment. --- Diffs of the changes: (+18 -6) Index: llvm/test/Programs/TEST.vtl.Makefile diff -u llvm/test/Programs/TEST.vtl.Makefile:1.1 llvm/test/Programs/TEST.vtl.Makefile:1.2 --- llvm/test/Programs/TEST.vtl.Makefile:1.1 Tue Feb 24 15:34:32 2004 +++ llvm/test/Programs/TEST.vtl.Makefile Mon Mar 1 11:45:32 2004 @@ -1,7 +1,6 @@ -##===- test/Programs/TEST.example.Makefile -----------------*- Makefile -*-===## +##===- test/Programs/TEST.vtl.Makefile ---------------------*- Makefile -*-===## # -# Example to show a custom test. This test just prints the size of the bytecode -# file for each program. +# Makefile for getting performance metrics using Intel's VTune. # ##===----------------------------------------------------------------------===## @@ -17,7 +16,7 @@ P4_EVENTS := "-ec en='2nd Level Cache Read Misses' en='2nd-Level Cache Read References'" P3_EVENTS := "-ec en='L2 Cache Request Misses (highly correlated)'" -EVENTS := $(P3_EVENTS) +EVENTS := $(P4_EVENTS) # # Generate events for LLC @@ -31,8 +30,22 @@ #-$(VERB) $(VTL) view > $@ #$(VERB) $(VTL) delete $* -f +test:: $(PROGRAMS_TO_TEST:%=test.$(TEST).pa.%) + # -# Generate events for CBE +# Generate events for Pool Allocated CBE +# +$(PROGRAMS_TO_TEST:%=test.$(TEST).pa.%): \ +test.$(TEST).pa.%: Output/%.poolalloc.cbe + @echo "=========================================" + @echo "Running '$(TEST)' test on '$(TESTNAME)' program" + $(VERB) $(VTL) activity $* -d 50 -c sampling -o $(EVENTS) -app $< + -$(VERB) $(VTL) run $* + -$(VERB) $(VTL) view > $@ + $(VERB) $(VTL) delete $* -f + +# +# Generate events for Pool Allocated CBE # $(PROGRAMS_TO_TEST:%=test.$(TEST).%): \ test.$(TEST).%: Output/%.cbe @@ -42,5 +55,4 @@ -$(VERB) $(VTL) run $* -$(VERB) $(VTL) view > $@ $(VERB) $(VTL) delete $* -f - From brukman at cs.uiuc.edu Mon Mar 1 11:48:02 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Mar 1 11:48:02 2004 Subject: [llvm-commits] CVS: llvm/docs/LangRef.html Message-ID: <200403011747.LAA18237@zion.cs.uiuc.edu> Changes in directory llvm/docs: LangRef.html updated: 1.50 -> 1.51 --- Log message: HTML 4.01 Strict compliance. --- Diffs of the changes: (+39 -33) Index: llvm/docs/LangRef.html diff -u llvm/docs/LangRef.html:1.50 llvm/docs/LangRef.html:1.51 --- llvm/docs/LangRef.html:1.50 Tue Feb 24 10:13:56 2004 +++ llvm/docs/LangRef.html Mon Mar 1 11:47:27 2004 @@ -1,4 +1,5 @@ - + LLVM Assembly Language Reference Manual @@ -255,12 +256,12 @@

The primitive types are the fundemental building blocks of the LLVM system. The current set of primitive types are as follows:

-

- + +
- +
@@ -294,7 +295,7 @@
void
- +
@@ -326,7 +327,7 @@
bool
-

+
Type @@ -334,8 +335,8 @@

These different primitive types fall into a few useful classifications:

-

- + +
@@ -364,7 +365,7 @@
signed
-

+

The first class types are perhaps the most important. Values of these types are the only ones which can be produced by instructions, passed as arguments, or used as operands to @@ -396,7 +397,7 @@ [40 x uint]: Array of 40 unsigned integer values.

Here are some examples of multidimensional arrays:

-

+ @@ -413,7 +414,7 @@
-

+
@@ -435,7 +436,7 @@ Variable argument functions can access their arguments with the variable argument handling intrinsic functions.

Examples:
-

+ @@ -457,7 +458,7 @@
-

+
@@ -474,7 +475,7 @@
Syntax:
  { <type list> }
Examples:
-

+ @@ -490,7 +491,7 @@
-

+ @@ -501,7 +502,7 @@
Syntax:
  <type> *
Examples:
-

+ @@ -517,7 +518,7 @@
-

+
- +
+ Valid CSS! + Valid HTML 4.01! + + Chris Lattner
+ The LLVM Compiler Infrastructure
+ Last modified: $Date: 2004/03/01 17:47:27 $ +
From brukman at cs.uiuc.edu Mon Mar 1 12:22:01 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Mar 1 12:22:01 2004 Subject: [llvm-commits] CVS: llvm/docs/TestingGuide.html Message-ID: <200403011821.MAA31689@zion.cs.uiuc.edu> Changes in directory llvm/docs: TestingGuide.html updated: 1.6 -> 1.7 --- Log message: * HTML 4.01 Strict compliance * Removed unnecessary tabs in the entire file --- Diffs of the changes: (+355 -401) Index: llvm/docs/TestingGuide.html diff -u llvm/docs/TestingGuide.html:1.6 llvm/docs/TestingGuide.html:1.7 --- llvm/docs/TestingGuide.html:1.6 Mon Nov 3 08:59:59 2003 +++ llvm/docs/TestingGuide.html Mon Mar 1 12:21:04 2004 @@ -1,11 +1,10 @@ - + - - - LLVM Test Suite Guide + LLVM Test Suite Guide + -
@@ -16,414 +15,369 @@
  • Overview
  • Requirements
  • Quick Start
  • -
  • LLVM Test Suite Organization
  • +
  • LLVM Test Suite Organization +
  • LLVM Test Suite Tree
  • QMTest Structure
  • Programs Structure
  • Running the LLVM Tests
  • -

    Written by John T. Criswell

    - - - - -
    -

    - This document is the reference manual for the LLVM test suite. It - documents the structure of the LLVM test suite, the tools needed to - use it, and how to add and run tests. -

    -
    - - - - - -
    -

    - In order to use the LLVM test suite, you will need all of the software - required to build LLVM, plus the following: -

    -
    -
    QMTest
    -
    The LLVM test suite uses QMTest to organize and - run tests.
    - -
    Python
    -
    You will need a Python interpreter that works with - QMTest. Python will need zlib and SAX support - enabled.
    -
    -
    - - - - - -
    -

    - The tests are located in the LLVM source tree under the directory - llvm/test. To run all of the tests in LLVM, use the Master - Makefile in that directory: -

    -
    -	 % gmake -C llvm/test
    -	
    - -

    - To run only the code fragment tests (i.e. those that do basic testing of - LLVM), run the tests organized by QMTest: -

    - -
    -	 % gmake -C llvm/test qmtest
    -	
    - -

    - To run only the tests that compile and execute whole programs, run the - Programs tests: -

    - -
    -	 % gmake -C llvm/test/Programs
    -	
    -
    - - - - - -
    -

    The LLVM test suite contains two major categories of tests: code - fragments and whole programs.

    -
    - - - -
    -

    - Code fragments are small pieces of code that test a specific - feature of LLVM or trigger a specific bug in LLVM. They are - usually written in LLVM assembly language, but can be - written in other languages if the test targets a - particular language front end. -

    - Code fragments are not complete programs, and they are - never executed to determine correct behavior. -

    - The tests in the Features and - Regression directories contain code fragments. -

    -
    - - - -
    -

    - Whole Programs are pieces of code which can be compiled and - linked into a stand-alone program that can be executed. These - programs are generally written in high level languages such as C - or C++, but sometimes they are written straight in LLVM - assembly. -

    - These programs are compiled and then executed using several - different methods (native compiler, LLVM C backend, LLVM JIT, - LLVM native code generation, etc). The output of these programs - is compared to ensure that LLVM is compiling the program - correctly. -

    - In addition to compiling and executing programs, whole program - tests serve as a way of benchmarking LLVM performance, both in - terms of the efficiency of the programs generated as well as the - speed with which LLVM compiles, optimizes, and generates code. -

    - The Programs directory contains all tests which compile and - benchmark whole programs. -

    -
    - - - - - -
    -

    Each type of test in the LLVM test suite has its own directory. The - major subtrees of the test suite directory tree are as follows:

    +

    Written by John T. Criswell

    + + + + + +
    + +

    This document is the reference manual for the LLVM test suite. It documents +the structure of the LLVM test suite, the tools needed to use it, and how to add +and run tests.

    + +
    + + + + + +
    + +

    In order to use the LLVM test suite, you will need all of the software +required to build LLVM, plus the following:

    + +
    +
    QMTest
    +
    The LLVM test suite uses QMTest to organize and run tests.
    + +
    Python
    +
    You will need a Python interpreter that works with QMTest. Python will + need zlib and SAX support enabled.
    +
    + +
    + + + + + +
    + +

    The tests are located in the LLVM source tree under the directory +llvm/test. To run all of the tests in LLVM, use the Master Makefile in +that directory:

    + +
    + % gmake -C llvm/test
    +
    + +

    To run only the code fragment tests (i.e. those that do basic testing of +LLVM), run the tests organized by QMTest:

    + +
    + % gmake -C llvm/test qmtest
    +
    + +

    To run only the tests that compile and execute whole programs, run the +Programs tests:

    + +
    + % gmake -C llvm/test/Programs
    +
    + +
    + + + + + +
    + +

    The LLVM test suite contains two major categories of tests: code +fragments and whole programs.

    + +
    + + + +
    + +

    Code fragments are small pieces of code that test a specific feature of LLVM +or trigger a specific bug in LLVM. They are usually written in LLVM assembly +language, but can be written in other languages if the test targets a particular +language front end.

    + +

    Code fragments are not complete programs, and they are never executed to +determine correct behavior.

    + +

    The tests in the Features and Regression directories contain code +fragments.

    + +
    + + + +
    + +

    Whole Programs are pieces of code which can be compiled and linked into a +stand-alone program that can be executed. These programs are generally written +in high level languages such as C or C++, but sometimes they are written +straight in LLVM assembly.

    + +

    These programs are compiled and then executed using several different +methods (native compiler, LLVM C backend, LLVM JIT, LLVM native code generation, +etc). The output of these programs is compared to ensure that LLVM is compiling +the program correctly.

    + +

    In addition to compiling and executing programs, whole program tests serve as +a way of benchmarking LLVM performance, both in terms of the efficiency of the +programs generated as well as the speed with which LLVM compiles, optimizes, and +generates code.

    + +

    The Programs directory contains all tests which compile and benchmark whole +programs.

    + +
    + + + + + +
    + +

    Each type of test in the LLVM test suite has its own directory. The major +subtrees of the test suite directory tree are as follows:

    + +
      +
    • Features +

      This directory contains sample codes that test various features of the + LLVM language. These pieces of sample code are run through various + assembler, disassembler, and optimizer passes.

      + +
    • Regression +

      This directory contains regression tests for LLVM. When a bug is found + in LLVM, a regression test containing just enough code to reproduce the + problem should be written and placed somewhere underneath this directory. + In most cases, this will be a small piece of LLVM assembly language code, + often distilled from an actual application or benchmark.

      + +
    • Programs +

      The Programs directory contains programs that can be compiled with LLVM + and executed. These programs are compiled using the native compiler and + various LLVM backends. The output from the program compiled with the native + compiler is assumed correct; the results from the other programs are + compared to the native program output and pass if they match.

      + +

      In addition for testing correctness, the Programs directory also + performs timing tests of various LLVM optimizations. It also records + compilation times for the compilers and the JIT. This information can be + used to compare the effectiveness of LLVM's optimizations and code + generation.

      + +

      The Programs directory is subdivided into several smaller subdirectories: +

      + +
        +
      • Programs/SingleSource +

        The SingleSource directory contains test programs that are only a + single source file in size. These are usually small benchmark programs + or small programs that calculate a particular value. Several such + programs are grouped together in each directory.

      • + +
      • Programs/MultiSource +

        The MultiSource directory contains subdirectories which contain + entire programs with multiple source files. Large benchmarks and whole + applications go here.

      • + +
      • Programs/External +

        The External directory contains Makefiles for building code that is + external to (i.e. not distributed with) LLVM. The most prominent member + of this directory is the SPEC 2000 benchmark suite. The presence and + location of these external programs is configured by the LLVM + configure script.

      • -
          -
        • Features -

          - This directory contains sample codes that test various features - of the LLVM language. These pieces of sample code are run - through various assembler, disassembler, and optimizer passes. -

          - -
        • Regression -

          - This directory contains regression tests for LLVM. When a bug - is found in LLVM, a regression test containing just enough - code to reproduce the problem should be written and placed - somewhere underneath this directory. In most cases, this - will be a small piece of LLVM assembly language code, often - distilled from an actual application or benchmark. -

          - -
        • Programs -

          - The Programs directory contains programs that can be compiled - with LLVM and executed. These programs are compiled using the - native compiler and various LLVM backends. The output from the - program compiled with the native compiler is assumed correct; - the results from the other programs are compared to the native - program output and pass if they match. -

          - In addition for testing correctness, the Programs directory - also performs timing tests of various LLVM optimizations. - It also records compilation times for the compilers and the - JIT. This information can be used to compare the - effectiveness of LLVM's optimizations and code generation. -

          - The Programs directory is subdivided into several smaller - subdirectories: -

          - -
            -
          • Programs/SingleSource -

            - The SingleSource directory contains test programs that - are only a single source file in size. These are - usually small benchmark programs or small programs that - calculate a particular value. Several such programs are - grouped together in each directory. -

            - -
          • Programs/MultiSource -

            - The MultiSource directory contains subdirectories which - contain entire programs with multiple source files. - Large benchmarks and whole applications go here. -

            - -
          • Programs/External -

            - The External directory contains Makefiles for building - code that is external to (i.e. not distributed with) - LLVM. The most prominent member of this directory is - the SPEC 2000 benchmark suite. The presence and - location of these external programs is configured by the - LLVM configure script. -

            -
          - -

          - -

        • QMTest -

          - This directory contains the QMTest information files. Inside - this directory are QMTest administration files and the Python - code that implements the LLVM test and database classes. -

          -
        -
    - - - - - -
    -

    - The LLVM test suite is partially driven by QMTest and partially - driven by GNU Make. Specifically, the Features and Regression tests - are all driven by QMTest. The Programs directory is currently - driven by a set of Makefiles. -

    - The QMTest system needs to have several pieces of information - available; these pieces of configuration information are known - collectively as the "context" in QMTest parlance. Since the context - for LLVM is relatively large, the master Makefile in llvm/test - sets it for you. -

    - The LLVM database class makes the subdirectories of llvm/test a - QMTest test database. For each directory that contains tests driven by - QMTest, it knows what type of test the source file is and how to run it. -

    - Hence, the QMTest namespace is essentially what you see in the - Feature and Regression directories, but there is some magic that - the database class performs (as described below). -

    - The QMTest namespace is currently composed of the following tests and - test suites: -

    - -
      -
    • Feature -

      - These are the feature tests found in the Feature directory. - They are broken up into the following categories: -

      -
        -
      • ad -

        - Assembler/Disassembler tests. These tests verify that a - piece of LLVM assembly language can be assembled into - bytecode and then disassembled into the original - assembly language code. It does this several times to - ensure that assembled output can be disassembled and - disassembler output can be assembled. It also verifies - that the give assembly language file can be assembled - correctly. -

        - -
      • opt -

        - Optimizer tests. These tests verify that two of the - optimizer passes completely optimize a program (i.e. - after a single pass, they cannot optimize a program - any further). -

        - -
      • mc -

        - Machine code tests. These tests verify that the LLVM - assembly language file can be translated into native - assembly code. -

        - -
      • cc -

        - C code tests. These tests verify that the specified - LLVM assembly code can be converted into C source code - using the C backend. -

        -
      - -

      - The LLVM database class looks at every file in the Feature - directory and creates a fake test hierarchy containing - Feature.<testtype>.<testname>. So, if you - add an LLVM assembly language file to the Feature directory, it - actually creates 5 new tests: assembler/disassembler, assembler, - optimizer, machine code, and C code. -

      - -
    • Regression -

      - These are the regression tests. There is one suite for each - subdirectory of the Regression directory. If you add a new - subdirectory there, you will need to modify, at least, the - RegressionMap variable in QMTest/llvmdb.py so - that QMTest knows how to run the tests in the new subdirectory. -

      -
    -
    - - - - - -
    -

    - As mentioned previously, the Programs tree in llvm/test provides three - types of tests: MultiSource, SingleSource, and External. Each tree is - then subdivided into several categories, including applications, - benchmarks, regression tests, code that is strange grammatically, etc. - These organizations should be relatively self explanatory. -

    - In addition to the regular Programs tests, the Programs tree also - provides a mechanism for compiling the programs in different ways. If - the variable TEST is defined on the gmake command line, the test system - will include a Makefile named TEST.<value of TEST - variable>.Makefile. This Makefile can modify build rules to - yield different results. -

    - For example, the LLVM nightly tester uses TEST.nightly.Makefile - to create the nightly test reports. To run the nightly tests, run - gmake TEST=nightly. -

    - There are several TEST Makefiles available in the tree. Some of them - are designed for internal LLVM research and will not work outside of the - LLVM research group. They may still be valuable, however, as a guide to - writing your own TEST Makefile for any optimization or analysis passes - that you develop with LLVM. -

    -
    - - - - - -
    -

    - First, all tests are executed within the LLVM object directory tree. - They are not executed inside of the LLVM source tree. This is - because the test suite creates temporary files during execution. -

    - The master Makefile in llvm/test is capable of running both the - QMTest driven tests and the Programs tests. By default, it will run - all of the tests. -

    - To run only the QMTest driven tests, run gmake qmtest at the - command line in llvm/tests. To run a specific qmtest, suffix the test - name with ".t" when running gmake. -

    - For example, to run the Regression.LLC tests, type - gmake Regression.LLC.t in llvm/tests. -

    - Note that the Makefiles in llvm/test/Features and llvm/test/Regression - are gone. You must now use QMTest from the llvm/test directory to run - them. -

    - To run the Programs test, cd into the llvm/test/Programs directory and - type gmake. Alternatively, you can type gmake - TEST=<type> test to run one of the specialized tests in - llvm/test/Programs/TEST.<type>.Makefile. For example, you could - run the nightly tester tests using the following commands: -

    - -
    -	 % cd llvm/test/Programs
    -	 % gmake TEST=nightly test
    -	
    - -

    - Regardless of which test you're running, the results are printed on - standard output and standard error. You can redirect these results to a - file if you choose. -

    - Some tests are known to fail. Some are bugs that we have not fixed yet; - others are features that we haven't added yet (or may never add). In - QMTest, the result for such tests will be XFAIL (eXpected FAILure). In - this way, you can tell the difference between an expected and unexpected - failure. -

    - The Programs tests have no such feature as of this time. If the test - passes, only warnings and other miscellaneous output will be generated. - If a test fails, a large <program> FAILED message will be - displayed. This will help you separate benign warnings from actual test - failures. -

    -
    + - +
  • QMTest +

    This directory contains the QMTest information files. Inside this + directory are QMTest administration files and the Python code that + implements the LLVM test and database classes.

    + + + +
  • + + + + + +
    + +

    The LLVM test suite is partially driven by QMTest and partially +driven by GNU Make. Specifically, the Features and Regression tests +are all driven by QMTest. The Programs directory is currently +driven by a set of Makefiles.

    + +

    The QMTest system needs to have several pieces of information +available; these pieces of configuration information are known +collectively as the "context" in QMTest parlance. Since the context +for LLVM is relatively large, the master Makefile in llvm/test +sets it for you.

    + +

    The LLVM database class makes the subdirectories of llvm/test a +QMTest test database. For each directory that contains tests driven by +QMTest, it knows what type of test the source file is and how to run it.

    + +

    Hence, the QMTest namespace is essentially what you see in the +Feature and Regression directories, but there is some magic that +the database class performs (as described below).

    + +

    The QMTest namespace is currently composed of the following tests and test +suites:

    + +
      +
    • Feature +

      + These are the feature tests found in the Feature directory. + They are broken up into the following categories: +

      +
        +
      • ad +

        Assembler/Disassembler tests. These tests verify that a piece of LLVM + assembly language can be assembled into bytecode and then disassembled + into the original assembly language code. It does this several times to + ensure that assembled output can be disassembled and disassembler output + can be assembled. It also verifies that the give assembly language file + can be assembled correctly.

      • + +
      • opt +

        Optimizer tests. These tests verify that two of the optimizer passes + completely optimize a program (i.e. after a single pass, they cannot + optimize a program any further).

      • + +
      • mc +

        Machine code tests. These tests verify that the LLVM assembly + language file can be translated into native assembly code.

      • + +
      • cc +

        C code tests. These tests verify that the specified LLVM assembly + code can be converted into C source code using the C backend.

      • +
      + +

      The LLVM database class looks at every file in the Feature directory and + creates a fake test hierarchy containing + Feature.<testtype>.<testname>. So, if you add an LLVM + assembly language file to the Feature directory, it actually creates 5 new + tests: assembler/disassembler, assembler, optimizer, machine code, and C code. +

      + +
    • Regression +

      These are the regression tests. There is one suite for each + subdirectory of the Regression directory. If you add a new subdirectory + there, you will need to modify, at least, the RegressionMap + variable in QMTest/llvmdb.py so that QMTest knows how to run the + tests in the new subdirectory.

      + +
    + +
    + + + + + +
    + +

    As mentioned previously, the Programs tree in llvm/test provides three types +of tests: MultiSource, SingleSource, and External. Each tree is then subdivided +into several categories, including applications, benchmarks, regression tests, +code that is strange grammatically, etc. These organizations should be +relatively self explanatory.

    + +

    In addition to the regular Programs tests, the Programs tree also provides a +mechanism for compiling the programs in different ways. If the variable TEST is +defined on the gmake command line, the test system will include a Makefile named +TEST.<value of TEST variable>.Makefile. This Makefile can modify +build rules to yield different results.

    + +

    For example, the LLVM nightly tester uses TEST.nightly.Makefile to +create the nightly test reports. To run the nightly tests, run gmake +TEST=nightly.

    + +

    There are several TEST Makefiles available in the tree. Some of them are +designed for internal LLVM research and will not work outside of the LLVM +research group. They may still be valuable, however, as a guide to writing your +own TEST Makefile for any optimization or analysis passes that you develop with +LLVM.

    + +
    -
    -
    John T. Criswell
    -The LLVM Compiler Infrastructure -
    -Last modified: $Date: 2003/11/03 14:59:59 $ -
    + + + + +
    + +

    First, all tests are executed within the LLVM object directory tree. They +are not executed inside of the LLVM source tree. This is because the +test suite creates temporary files during execution.

    + +

    The master Makefile in llvm/test is capable of running both the QMTest driven +tests and the Programs tests. By default, it will run all of the tests.

    + +

    To run only the QMTest driven tests, run gmake qmtest at the +command line in llvm/tests. To run a specific qmtest, suffix the test name with +".t" when running gmake.

    + +

    For example, to run the Regression.LLC tests, type gmake +Regression.LLC.t in llvm/tests.

    + +

    Note that the Makefiles in llvm/test/Features and llvm/test/Regression are +gone. You must now use QMTest from the llvm/test directory to run them.

    + +

    To run the Programs test, cd into the llvm/test/Programs directory and type +gmake. Alternatively, you can type gmake TEST=<type> +test to run one of the specialized tests in +llvm/test/Programs/TEST.<type>.Makefile. For example, you could run the +nightly tester tests using the following commands:

    + +
    + % cd llvm/test/Programs
    + % gmake TEST=nightly test
    +
    + +

    Regardless of which test you're running, the results are printed on standard +output and standard error. You can redirect these results to a file if you +choose.

    + +

    Some tests are known to fail. Some are bugs that we have not fixed yet; +others are features that we haven't added yet (or may never add). In QMTest, +the result for such tests will be XFAIL (eXpected FAILure). In this way, you +can tell the difference between an expected and unexpected failure.

    + +

    The Programs tests have no such feature as of this time. If the test passes, +only warnings and other miscellaneous output will be generated. If a test +fails, a large <program> FAILED message will be displayed. This will help +you separate benign warnings from actual test failures.

    + +
    + + +
    +
    + Valid CSS! + Valid HTML 4.01! + + John T. Criswell
    + The LLVM Compiler Infrastructure
    + Last modified: $Date: 2004/03/01 18:21:04 $ +
    From brukman at cs.uiuc.edu Mon Mar 1 12:28:02 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Mar 1 12:28:02 2004 Subject: [llvm-commits] CVS: llvm/include/llvm/Transforms/Utils/FunctionUtils.h Message-ID: <200403011827.MAA32336@zion.cs.uiuc.edu> Changes in directory llvm/include/llvm/Transforms/Utils: FunctionUtils.h updated: 1.1 -> 1.2 --- Log message: Add ability to extract a single basic block into a new function. --- Diffs of the changes: (+4 -0) Index: llvm/include/llvm/Transforms/Utils/FunctionUtils.h diff -u llvm/include/llvm/Transforms/Utils/FunctionUtils.h:1.1 llvm/include/llvm/Transforms/Utils/FunctionUtils.h:1.2 --- llvm/include/llvm/Transforms/Utils/FunctionUtils.h:1.1 Fri Feb 27 21:33:30 2004 +++ llvm/include/llvm/Transforms/Utils/FunctionUtils.h Mon Mar 1 12:27:13 2004 @@ -23,6 +23,10 @@ /// Function* ExtractLoop(Loop *L); +/// ExtractBasicBlock - rip out a basic block into a new function +/// +Function* ExtractBasicBlock(BasicBlock *BB); + } #endif From brukman at cs.uiuc.edu Mon Mar 1 12:29:01 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Mar 1 12:29:01 2004 Subject: [llvm-commits] CVS: llvm/lib/Transforms/Utils/CodeExtractor.cpp Message-ID: <200403011828.MAA32465@zion.cs.uiuc.edu> Changes in directory llvm/lib/Transforms/Utils: CodeExtractor.cpp updated: 1.1 -> 1.2 --- Log message: * Add implementation of ExtractBasicBlock() * Add comments to ExtractLoop() --- Diffs of the changes: (+10 -0) Index: llvm/lib/Transforms/Utils/CodeExtractor.cpp diff -u llvm/lib/Transforms/Utils/CodeExtractor.cpp:1.1 llvm/lib/Transforms/Utils/CodeExtractor.cpp:1.2 --- llvm/lib/Transforms/Utils/CodeExtractor.cpp:1.1 Fri Feb 27 21:26:20 2004 +++ llvm/lib/Transforms/Utils/CodeExtractor.cpp Mon Mar 1 12:28:34 2004 @@ -566,8 +566,18 @@ return newFunction; } +/// ExtractBasicBlock - slurp a natural loop into a brand new function +/// Function* llvm::ExtractLoop(Loop *L) { CodeExtractor CE; return CE.ExtractCodeRegion(L->getBlocks()); } +/// ExtractBasicBlock - slurp a basic block into a brand new function +/// +Function* llvm::ExtractBasicBlock(BasicBlock *BB) { + CodeExtractor CE; + std::vector Blocks; + Blocks.push_back(BB); + return CE.ExtractCodeRegion(Blocks); +} From brukman at cs.uiuc.edu Mon Mar 1 12:32:02 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Mar 1 12:32:02 2004 Subject: [llvm-commits] CVS: llvm/include/llvm/Function.h Message-ID: <200403011831.MAA00621@zion.cs.uiuc.edu> Changes in directory llvm/include/llvm: Function.h updated: 1.50 -> 1.51 --- Log message: Fix grammar and doxygenify comments. --- Diffs of the changes: (+6 -6) Index: llvm/include/llvm/Function.h diff -u llvm/include/llvm/Function.h:1.50 llvm/include/llvm/Function.h:1.51 --- llvm/include/llvm/Function.h:1.50 Thu Feb 26 02:08:38 2004 +++ llvm/include/llvm/Function.h Mon Mar 1 12:31:19 2004 @@ -62,7 +62,6 @@ typedef std::reverse_iterator reverse_aiterator; private: - // Important things that make up a function! BasicBlockListType BasicBlocks; // The basic blocks ArgumentListType ArgumentList; // The formal arguments @@ -91,8 +90,8 @@ const Type *getReturnType() const; // Return the type of the ret val const FunctionType *getFunctionType() const; // Return the FunctionType for me - /// isExternal - Is the body of this function unknown? (the basic block list - /// is empty if so) this is true for external functions, defined as forward + /// isExternal - Is the body of this function unknown? (The basic block list + /// is empty if so.) This is true for external functions, defined as forward /// "declare"ations /// virtual bool isExternal() const { return BasicBlocks.empty(); } @@ -109,6 +108,7 @@ /// deleteBody - This method deletes the body of the function, and converts /// the linkage to external. + /// void deleteBody() { dropAllReferences(); setLinkage(ExternalLinkage); @@ -197,8 +197,8 @@ /// viewCFGOnly - This function is meant for use from the debugger. It works /// just like viewCFG, but it does not include the contents of basic blocks - /// into the nodes, just the label. If you are only interested in the CFG t - /// his can make the graph smaller. + /// into the nodes, just the label. If you are only interested in the CFG + /// this can make the graph smaller. /// void viewCFGOnly() const; @@ -212,7 +212,7 @@ /// go" of all references that they are maintaining. This allows one to /// 'delete' a whole module at a time, even though there may be circular /// references... first all references are dropped, and all use counts go to - /// zero. Then everything is delete'd for real. Note that no operations are + /// zero. Then everything is deleted for real. Note that no operations are /// valid on an object that has "dropped all references", except operator /// delete. /// From lattner at cs.uiuc.edu Mon Mar 1 13:04:03 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon Mar 1 13:04:03 2004 Subject: [llvm-commits] CVS: llvm/lib/Analysis/DataStructure/Local.cpp Message-ID: <200403011903.NAA05112@zion.cs.uiuc.edu> Changes in directory llvm/lib/Analysis/DataStructure: Local.cpp updated: 1.94 -> 1.95 --- Log message: Correctly add an array marker on a node when appropriate! --- Diffs of the changes: (+4 -0) Index: llvm/lib/Analysis/DataStructure/Local.cpp diff -u llvm/lib/Analysis/DataStructure/Local.cpp:1.94 llvm/lib/Analysis/DataStructure/Local.cpp:1.95 --- llvm/lib/Analysis/DataStructure/Local.cpp:1.94 Fri Feb 27 14:04:48 2004 +++ llvm/lib/Analysis/DataStructure/Local.cpp Mon Mar 1 13:02:54 2004 @@ -383,6 +383,10 @@ if (const StructType *STy = dyn_cast(*I)) { unsigned FieldNo = cast(I.getOperand())->getValue(); Offset += TD.getStructLayout(STy)->MemberOffsets[FieldNo]; + } else if (const PointerType *PTy = dyn_cast(*I)) { + if (!isa(I.getOperand()) || + !cast(I.getOperand())->isNullValue()) + Value.getNode()->setArrayMarker(); } From lattner at cs.uiuc.edu Mon Mar 1 13:37:01 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon Mar 1 13:37:01 2004 Subject: [llvm-commits] CVS: llvm/include/llvm/Analysis/DSNode.h Message-ID: <200403011937.NAA09303@zion.cs.uiuc.edu> Changes in directory llvm/include/llvm/Analysis: DSNode.h updated: 1.39 -> 1.40 --- Log message: Add new method --- Diffs of the changes: (+1 -0) Index: llvm/include/llvm/Analysis/DSNode.h diff -u llvm/include/llvm/Analysis/DSNode.h:1.39 llvm/include/llvm/Analysis/DSNode.h:1.40 --- llvm/include/llvm/Analysis/DSNode.h:1.39 Sat Feb 7 19:27:13 2004 +++ llvm/include/llvm/Analysis/DSNode.h Mon Mar 1 13:36:50 2004 @@ -305,6 +305,7 @@ DSNode *setIncompleteMarker() { NodeType |= Incomplete; return this; } DSNode *setModifiedMarker() { NodeType |= Modified; return this; } DSNode *setReadMarker() { NodeType |= Read; return this; } + DSNode *setArrayMarker() { NodeType |= Array; return this; } void makeNodeDead() { Globals.clear(); From brukman at cs.uiuc.edu Mon Mar 1 13:49:01 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Mar 1 13:49:01 2004 Subject: [llvm-commits] CVS: llvm/lib/VMCore/AsmWriter.cpp Message-ID: <200403011948.NAA11918@zion.cs.uiuc.edu> Changes in directory llvm/lib/VMCore: AsmWriter.cpp updated: 1.122 -> 1.123 --- Log message: * If a badref has a name, print it out for ease of debugging * Doxygenify (some) comments --- Diffs of the changes: (+17 -15) Index: llvm/lib/VMCore/AsmWriter.cpp diff -u llvm/lib/VMCore/AsmWriter.cpp:1.122 llvm/lib/VMCore/AsmWriter.cpp:1.123 --- llvm/lib/VMCore/AsmWriter.cpp:1.122 Sat Feb 14 23:55:15 2004 +++ llvm/lib/VMCore/AsmWriter.cpp Mon Mar 1 13:48:13 2004 @@ -142,7 +142,6 @@ // This is another base case for the recursion. In this case, we know // that we have looped back to a type that we have previously visited. // Generate the appropriate upreference to handle this. - // if (Slot < CurSize) return "\\" + utostr(CurSize-Slot); // Here's the upreference @@ -200,9 +199,9 @@ } -// printTypeInt - The internal guts of printing out a type that has a -// potentially named portion. -// +/// printTypeInt - The internal guts of printing out a type that has a +/// potentially named portion. +/// static std::ostream &printTypeInt(std::ostream &Out, const Type *Ty, std::map &TypeNames) { // Primitive types always print out their description, regardless of whether @@ -226,10 +225,10 @@ } -// WriteTypeSymbolic - This attempts to write the specified type as a symbolic -// type, iff there is an entry in the modules symbol table for the specified -// type or one of it's component types. This is slower than a simple x << Type; -// +/// WriteTypeSymbolic - This attempts to write the specified type as a symbolic +/// type, iff there is an entry in the modules symbol table for the specified +/// type or one of it's component types. This is slower than a simple x << Type +/// std::ostream &llvm::WriteTypeSymbolic(std::ostream &Out, const Type *Ty, const Module *M) { Out << " "; @@ -414,20 +413,23 @@ } if (Slot >= 0) Out << "%" << Slot; else if (PrintName) - Out << ""; // Not embedded into a location? + if (V->hasName()) + Out << "getName()) << ">"; + else + Out << ""; // Not embedded into a location? } } } -// WriteAsOperand - Write the name of the specified value out to the specified -// ostream. This can be useful when you just want to print int %reg126, not the -// whole instruction that generated it. -// +/// WriteAsOperand - Write the name of the specified value out to the specified +/// ostream. This can be useful when you just want to print int %reg126, not +/// the whole instruction that generated it. +/// std::ostream &llvm::WriteAsOperand(std::ostream &Out, const Value *V, - bool PrintType, - bool PrintName, const Module *Context) { + bool PrintType, bool PrintName, + const Module *Context) { std::map TypeNames; if (Context == 0) Context = getModuleFromVal(V); From alkis at cs.uiuc.edu Mon Mar 1 14:10:07 2004 From: alkis at cs.uiuc.edu (Alkis Evlogimenos) Date: Mon Mar 1 14:10:07 2004 Subject: [llvm-commits] CVS: llvm/lib/CodeGen/LiveIntervals.h LiveIntervals.cpp VirtRegMap.h VirtRegMap.cpp RegAllocLinearScan.cpp Message-ID: <200403012005.OAA12426@zion.cs.uiuc.edu> Changes in directory llvm/lib/CodeGen: LiveIntervals.h updated: 1.21 -> 1.22 LiveIntervals.cpp updated: 1.64 -> 1.65 VirtRegMap.h updated: 1.7 -> 1.8 VirtRegMap.cpp updated: 1.6 -> 1.7 RegAllocLinearScan.cpp updated: 1.67 -> 1.68 --- Log message: Add the long awaited memory operand folding support for linear scan --- Diffs of the changes: (+87 -29) Index: llvm/lib/CodeGen/LiveIntervals.h diff -u llvm/lib/CodeGen/LiveIntervals.h:1.21 llvm/lib/CodeGen/LiveIntervals.h:1.22 --- llvm/lib/CodeGen/LiveIntervals.h:1.21 Sat Feb 21 22:05:13 2004 +++ llvm/lib/CodeGen/LiveIntervals.h Mon Mar 1 14:05:10 2004 @@ -28,6 +28,7 @@ class LiveVariables; class MRegisterInfo; + class VirtRegMap; class LiveIntervals : public MachineFunctionPass { @@ -164,7 +165,7 @@ Intervals& getIntervals() { return intervals_; } - void updateSpilledInterval(Interval& i, int slot); + void updateSpilledInterval(Interval& i, VirtRegMap& vrm, int slot); private: /// computeIntervals - compute live intervals Index: llvm/lib/CodeGen/LiveIntervals.cpp diff -u llvm/lib/CodeGen/LiveIntervals.cpp:1.64 llvm/lib/CodeGen/LiveIntervals.cpp:1.65 --- llvm/lib/CodeGen/LiveIntervals.cpp:1.64 Thu Feb 26 16:00:20 2004 +++ llvm/lib/CodeGen/LiveIntervals.cpp Mon Mar 1 14:05:10 2004 @@ -31,6 +31,7 @@ #include "Support/Debug.h" #include "Support/Statistic.h" #include "Support/STLExtras.h" +#include "VirtRegMap.h" #include #include #include @@ -184,7 +185,9 @@ return true; } -void LiveIntervals::updateSpilledInterval(Interval& li, int slot) +void LiveIntervals::updateSpilledInterval(Interval& li, + VirtRegMap& vrm, + int slot) { assert(li.weight != std::numeric_limits::infinity() && "attempt to spill already spilled interval!"); @@ -202,27 +205,40 @@ while (!getInstructionFromIndex(index)) index += InstrSlots::NUM; MachineBasicBlock::iterator mi = getInstructionFromIndex(index); + for_operand: for (unsigned i = 0; i < mi->getNumOperands(); ++i) { MachineOperand& mop = mi->getOperand(i); if (mop.isRegister() && mop.getReg() == li.reg) { - // This is tricky. We need to add information in - // the interval about the spill code so we have to - // use our extra load/store slots. - // - // If we have a use we are going to have a load so - // we start the interval from the load slot - // onwards. Otherwise we start from the def slot. - unsigned start = (mop.isUse() ? - getLoadIndex(index) : - getDefIndex(index)); - // If we have a def we are going to have a store - // right after it so we end the interval after the - // use of the next instruction. Otherwise we end - // after the use of this instruction. - unsigned end = 1 + (mop.isDef() ? - getUseIndex(index+InstrSlots::NUM) : - getUseIndex(index)); - li.addRange(start, end); + MachineInstr* old = mi; + if (mri_->foldMemoryOperand(mi, i, slot)) { + lv_->instructionChanged(old, mi); + vrm.virtFolded(li.reg, old, mi); + mi2iMap_.erase(old); + i2miMap_[index/InstrSlots::NUM] = mi; + mi2iMap_[mi] = index; + ++numFolded; + goto for_operand; + } + else { + // This is tricky. We need to add information in + // the interval about the spill code so we have to + // use our extra load/store slots. + // + // If we have a use we are going to have a load so + // we start the interval from the load slot + // onwards. Otherwise we start from the def slot. + unsigned start = (mop.isUse() ? + getLoadIndex(index) : + getDefIndex(index)); + // If we have a def we are going to have a store + // right after it so we end the interval after the + // use of the next instruction. Otherwise we end + // after the use of this instruction. + unsigned end = 1 + (mop.isDef() ? + getUseIndex(index+InstrSlots::NUM) : + getUseIndex(index)); + li.addRange(start, end); + } } } } Index: llvm/lib/CodeGen/VirtRegMap.h diff -u llvm/lib/CodeGen/VirtRegMap.h:1.7 llvm/lib/CodeGen/VirtRegMap.h:1.8 --- llvm/lib/CodeGen/VirtRegMap.h:1.7 Fri Feb 27 00:11:15 2004 +++ llvm/lib/CodeGen/VirtRegMap.h Mon Mar 1 14:05:10 2004 @@ -22,18 +22,23 @@ #include "llvm/CodeGen/SSARegMap.h" #include "Support/DenseMap.h" #include +#include namespace llvm { + class MachineInstr; + class VirtRegMap { public: typedef DenseMap Virt2PhysMap; typedef DenseMap Virt2StackSlotMap; + typedef std::multimap MI2VirtMap; private: MachineFunction* mf_; Virt2PhysMap v2pMap_; Virt2StackSlotMap v2ssMap_; + MI2VirtMap mi2vMap_; // do not implement VirtRegMap(const VirtRegMap& rhs); @@ -88,6 +93,15 @@ } int assignVirt2StackSlot(unsigned virtReg); + + void virtFolded(unsigned virtReg, + MachineInstr* oldMI, + MachineInstr* newMI); + + std::pair + getFoldedVirts(MachineInstr* MI) const { + return mi2vMap_.equal_range(MI); + } friend std::ostream& operator<<(std::ostream& os, const VirtRegMap& li); }; Index: llvm/lib/CodeGen/VirtRegMap.cpp diff -u llvm/lib/CodeGen/VirtRegMap.cpp:1.6 llvm/lib/CodeGen/VirtRegMap.cpp:1.7 --- llvm/lib/CodeGen/VirtRegMap.cpp:1.6 Thu Feb 26 22:51:35 2004 +++ llvm/lib/CodeGen/VirtRegMap.cpp Mon Mar 1 14:05:10 2004 @@ -19,6 +19,7 @@ #include "VirtRegMap.h" #include "llvm/Function.h" #include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineInstr.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetInstrInfo.h" #include "Support/Statistic.h" @@ -49,6 +50,24 @@ return frameIndex; } +void VirtRegMap::virtFolded(unsigned virtReg, + MachineInstr* oldMI, + MachineInstr* newMI) +{ + // move previous memory references folded to new instruction + MI2VirtMap::iterator i, e; + std::vector regs; + for (tie(i, e) = mi2vMap_.equal_range(oldMI); i != e; ) { + regs.push_back(i->second); + mi2vMap_.erase(i++); + } + for (unsigned i = 0, e = regs.size(); i != e; ++i) + mi2vMap_.insert(std::make_pair(newMI, i)); + + // add new memory reference + mi2vMap_.insert(std::make_pair(newMI, virtReg)); +} + std::ostream& llvm::operator<<(std::ostream& os, const VirtRegMap& vrm) { const MRegisterInfo* mri = vrm.mf_->getTarget().getRegisterInfo(); @@ -129,9 +148,9 @@ vrm_.getStackSlot(virtReg), mri_.getRegClass(physReg)); ++numStores; - DEBUG(std::cerr << "\t\tadded: "; + DEBUG(std::cerr << "added: "; prior(nextLastRef)->print(std::cerr, tm_); - std::cerr << "\t\tafter: "; + std::cerr << "after: "; lastDef->print(std::cerr, tm_)); lastDef_[virtReg] = 0; } @@ -161,10 +180,8 @@ vrm_.getStackSlot(virtReg), mri_.getRegClass(physReg)); ++numLoads; - DEBUG(std::cerr << "\t\tadded: "; - prior(mii)->print(std::cerr,tm_); - std::cerr << "\t\tbefore: "; - mii->print(std::cerr, tm_)); + DEBUG(std::cerr << "added: "; + prior(mii)->print(std::cerr,tm_)); lastDef_[virtReg] = mii; } } @@ -186,6 +203,16 @@ void eliminateVirtRegsInMbb(MachineBasicBlock& mbb) { for (MachineBasicBlock::iterator mii = mbb.begin(), mie = mbb.end(); mii != mie; ++mii) { + + // if we have references to memory operands make sure + // we clear all physical registers that may contain + // the value of the spilled virtual register + VirtRegMap::MI2VirtMap::const_iterator i, e; + for (tie(i, e) = vrm_.getFoldedVirts(mii); i != e; ++i) { + unsigned physReg = vrm_.getPhys(i->second); + if (physReg) vacateJustPhysReg(mbb, mii, physReg); + } + // rewrite all used operands for (unsigned i = 0, e = mii->getNumOperands(); i != e; ++i) { MachineOperand& op = mii->getOperand(i); Index: llvm/lib/CodeGen/RegAllocLinearScan.cpp diff -u llvm/lib/CodeGen/RegAllocLinearScan.cpp:1.67 llvm/lib/CodeGen/RegAllocLinearScan.cpp:1.68 --- llvm/lib/CodeGen/RegAllocLinearScan.cpp:1.67 Fri Feb 27 00:11:15 2004 +++ llvm/lib/CodeGen/RegAllocLinearScan.cpp Mon Mar 1 14:05:10 2004 @@ -385,7 +385,7 @@ if (cur->weight <= minWeight) { DEBUG(std::cerr << "\t\t\tspilling(c): " << *cur << '\n';); int slot = vrm_->assignVirt2StackSlot(cur->reg); - li_->updateSpilledInterval(*cur, slot); + li_->updateSpilledInterval(*cur, *vrm_, slot); // if we didn't eliminate the interval find where to add it // back to unhandled. We need to scan since unhandled are @@ -424,7 +424,7 @@ DEBUG(std::cerr << "\t\t\tspilling(a): " << **i << '\n'); earliestStart = std::min(earliestStart, (*i)->start()); int slot = vrm_->assignVirt2StackSlot((*i)->reg); - li_->updateSpilledInterval(**i, slot); + li_->updateSpilledInterval(**i, *vrm_, slot); } } for (IntervalPtrs::iterator i = inactive_.begin(); @@ -436,7 +436,7 @@ DEBUG(std::cerr << "\t\t\tspilling(i): " << **i << '\n'); earliestStart = std::min(earliestStart, (*i)->start()); int slot = vrm_->assignVirt2StackSlot((*i)->reg); - li_->updateSpilledInterval(**i, slot); + li_->updateSpilledInterval(**i, *vrm_, slot); } } From criswell at cs.uiuc.edu Mon Mar 1 14:44:01 2004 From: criswell at cs.uiuc.edu (John Criswell) Date: Mon Mar 1 14:44:01 2004 Subject: [llvm-commits] CVS: llvm/test/Programs/TEST.vtl.Makefile Message-ID: <200403012043.OAA13780@zion.cs.uiuc.edu> Changes in directory llvm/test/Programs: TEST.vtl.Makefile updated: 1.2 -> 1.3 --- Log message: Added support for STDIN_FILENAME and RUN_OPTIONS. --- Diffs of the changes: (+10 -2) Index: llvm/test/Programs/TEST.vtl.Makefile diff -u llvm/test/Programs/TEST.vtl.Makefile:1.2 llvm/test/Programs/TEST.vtl.Makefile:1.3 --- llvm/test/Programs/TEST.vtl.Makefile:1.2 Mon Mar 1 11:45:32 2004 +++ llvm/test/Programs/TEST.vtl.Makefile Mon Mar 1 14:43:13 2004 @@ -39,7 +39,11 @@ test.$(TEST).pa.%: Output/%.poolalloc.cbe @echo "=========================================" @echo "Running '$(TEST)' test on '$(TESTNAME)' program" - $(VERB) $(VTL) activity $* -d 50 -c sampling -o $(EVENTS) -app $< +ifeq ($(RUN_OPTIONS),) + $(VERB) cat $(STDIN_FILENAME) | $(VTL) activity $* -d 50 -c sampling -o $(EVENTS) -app $< +else + $(VERB) cat $(STDIN_FILENAME) | $(VTL) activity $* -d 50 -c sampling -o $(EVENTS) -app $<,"$(RUN_OPTIONS)" +endif -$(VERB) $(VTL) run $* -$(VERB) $(VTL) view > $@ $(VERB) $(VTL) delete $* -f @@ -51,7 +55,11 @@ test.$(TEST).%: Output/%.cbe @echo "=========================================" @echo "Running '$(TEST)' test on '$(TESTNAME)' program" - $(VERB) $(VTL) activity $* -d 50 -c sampling -o $(EVENTS) -app $< +ifeq ($(RUN_OPTIONS),) + $(VERB) cat $(STDIN_FILENAME) | $(VTL) activity $* -d 50 -c sampling -o $(EVENTS) -app $< +else + $(VERB) cat $(STDIN_FILENAME) | $(VTL) activity $* -d 50 -c sampling -o $(EVENTS) -app $<,"$(RUN_OPTIONS)" +endif -$(VERB) $(VTL) run $* -$(VERB) $(VTL) view > $@ $(VERB) $(VTL) delete $* -f From gaeke at cs.uiuc.edu Mon Mar 1 15:21:01 2004 From: gaeke at cs.uiuc.edu (Brian Gaeke) Date: Mon Mar 1 15:21:01 2004 Subject: [llvm-commits] CVS: reopt/lib/LightWtProfiling/RuntimeOptimizations.cpp UnpackTraceFunction.cpp Message-ID: <200403012120.PAA18823@seraph.cs.uiuc.edu> Changes in directory reopt/lib/LightWtProfiling: RuntimeOptimizations.cpp updated: 1.20 -> 1.21 UnpackTraceFunction.cpp updated: 1.39 -> 1.40 --- Log message: More great renaming fallout. --- Diffs of the changes: (+8 -8) Index: reopt/lib/LightWtProfiling/RuntimeOptimizations.cpp diff -u reopt/lib/LightWtProfiling/RuntimeOptimizations.cpp:1.20 reopt/lib/LightWtProfiling/RuntimeOptimizations.cpp:1.21 --- reopt/lib/LightWtProfiling/RuntimeOptimizations.cpp:1.20 Fri Jan 30 15:53:57 2004 +++ reopt/lib/LightWtProfiling/RuntimeOptimizations.cpp Mon Mar 1 15:20:02 2004 @@ -51,7 +51,7 @@ // target machine, if there isn't one already. if (!MP) initModules (); if (!IL) IL = new DefaultIntrinsicLowering (); - if (!Target) Target = allocateSparcTargetMachine (*MP->getModule (), IL); + if (!Target) Target = allocateSparcV9TargetMachine (*MP->getModule (), IL); // Turn the vector of basic blocks into a Trace, and then turn the Trace into // a TraceFunction. Index: reopt/lib/LightWtProfiling/UnpackTraceFunction.cpp diff -u reopt/lib/LightWtProfiling/UnpackTraceFunction.cpp:1.39 reopt/lib/LightWtProfiling/UnpackTraceFunction.cpp:1.40 --- reopt/lib/LightWtProfiling/UnpackTraceFunction.cpp:1.39 Fri Feb 27 16:25:25 2004 +++ reopt/lib/LightWtProfiling/UnpackTraceFunction.cpp Mon Mar 1 15:20:02 2004 @@ -26,8 +26,8 @@ #include "../../../../lib/Target/SparcV9/RegAlloc/AllocInfo.h" #include "../../../../lib/Target/SparcV9/RegAlloc/PhyRegAlloc.h" -#include "../../../../lib/Target/SparcV9/SparcRegInfo.h" -#include "../../../../lib/Target/SparcV9/SparcTargetMachine.h" +#include "../../../../lib/Target/SparcV9/SparcV9RegInfo.h" +#include "../../../../lib/Target/SparcV9/SparcV9TargetMachine.h" namespace llvm { @@ -53,11 +53,11 @@ int RegType; // Guess what kind of reg the register was allocated to. if (Ty == Type::FloatTy) - RegType = SparcRegInfo::FPSingleRegType; + RegType = SparcV9RegInfo::FPSingleRegType; else if (Ty == Type::DoubleTy) - RegType = SparcRegInfo::FPDoubleRegType; + RegType = SparcV9RegInfo::FPDoubleRegType; else - RegType = SparcRegInfo::IntRegType; + RegType = SparcV9RegInfo::IntRegType; const unsigned FramePtrReg = TRI.getFramePointer (); const unsigned StackPtrReg = TRI.getStackPointer (); if (Source.AllocState == AllocInfo::Spilled @@ -77,8 +77,8 @@ } else if (Source.AllocState == AllocInfo::Spilled && Target.AllocState == AllocInfo::Spilled) { const unsigned TempReg = - TRI.getUnifiedRegNum (SparcRegInfo::IntRegClassID, - SparcIntRegClass::g1); // just pick one? + TRI.getUnifiedRegNum (SparcV9RegInfo::IntRegClassID, + SparcV9IntRegClass::g1); // just pick one? // Emit load instruction from stack loc. Source into register TempReg TRI.cpMem2RegMI (mvec, FramePtrReg, Source.Placement, TempReg, RegType); // Emit store instruction from register TempReg to stack loc. Target From criswell at cs.uiuc.edu Mon Mar 1 16:22:01 2004 From: criswell at cs.uiuc.edu (John Criswell) Date: Mon Mar 1 16:22:01 2004 Subject: [llvm-commits] CVS: poolalloc/test/Makefile Message-ID: <200403012221.QAA32075@choi.cs.uiuc.edu> Changes in directory poolalloc/test: Makefile updated: 1.6 -> 1.7 --- Log message: Added vtl target for taking Vtune statistics. --- Diffs of the changes: (+7 -1) Index: poolalloc/test/Makefile diff -u poolalloc/test/Makefile:1.6 poolalloc/test/Makefile:1.7 --- poolalloc/test/Makefile:1.6 Fri Nov 14 15:16:43 2003 +++ poolalloc/test/Makefile Mon Mar 1 16:21:36 2004 @@ -16,5 +16,11 @@ test:: (cd $(LLVM_OBJ_ROOT)/test/Programs/$(SUBDIR); \ PROJECT_DIR=$(BUILD_OBJ_ROOT) $(MAKE) TEST=poolalloc \ - report report.html ) + report report.html) + @printf "\a"; sleep 1; printf "\a"; sleep 1; printf "\a" + +vtl:: + (cd $(LLVM_OBJ_ROOT)/test/Programs/$(SUBDIR); \ + PROJECT_DIR=$(BUILD_OBJ_ROOT) $(MAKE) TEST=vtl DOPA=1 \ + test) @printf "\a"; sleep 1; printf "\a"; sleep 1; printf "\a" From lattner at cs.uiuc.edu Mon Mar 1 17:16:02 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon Mar 1 17:16:02 2004 Subject: [llvm-commits] CVS: poolalloc/test/TEST.poolalloc.Makefile TEST.poolalloc.report Message-ID: <200403012315.RAA22462@zion.cs.uiuc.edu> Changes in directory poolalloc/test: TEST.poolalloc.Makefile updated: 1.15 -> 1.16 TEST.poolalloc.report updated: 1.10 -> 1.11 --- Log message: Print user+sys time instead of 'real' time --- Diffs of the changes: (+33 -9) Index: poolalloc/test/TEST.poolalloc.Makefile diff -u poolalloc/test/TEST.poolalloc.Makefile:1.15 poolalloc/test/TEST.poolalloc.Makefile:1.16 --- poolalloc/test/TEST.poolalloc.Makefile:1.15 Thu Feb 26 02:04:07 2004 +++ poolalloc/test/TEST.poolalloc.Makefile Mon Mar 1 17:15:45 2004 @@ -9,6 +9,11 @@ EXTRA_PA_FLAGS := -poolalloc-force-simple-pool-init +ifdef DISABLE_PROFITABILITY +EXTRA_PA_FLAGS += -poolalloc-heuristic=AllPools +endif + + CURDIR := $(shell cd .; pwd) PROGDIR := $(shell cd $(LEVEL)/test/Programs; pwd)/ RELDIR := $(subst $(PROGDIR),,$(CURDIR)) @@ -83,10 +88,14 @@ Output/%.poolalloc.diff-cbe @echo > $@ @-if test -f Output/$*.poolalloc.diff-cbe; then \ - printf "CBE-RUN-TIME-NORMAL: " >> $@;\ - grep "^real" Output/$*.out-cbe.time >> $@;\ - printf "CBE-RUN-TIME-POOLALLOC: " >> $@;\ - grep "^real" Output/$*.poolalloc.out-cbe.time >> $@;\ + printf "CBE-RUN-TIME-NORMAL-USER: " >> $@;\ + grep "^user" Output/$*.out-cbe.time >> $@;\ + printf "CBE-RUN-TIME-NORMAL-SYS: " >> $@;\ + grep "^sys" Output/$*.out-cbe.time >> $@;\ + printf "CBE-RUN-TIME-POOLALLOC-USER: " >> $@;\ + grep "^user" Output/$*.poolalloc.out-cbe.time >> $@;\ + printf "CBE-RUN-TIME-POOLALLOC-SYS: " >> $@;\ + grep "^sys" Output/$*.poolalloc.out-cbe.time >> $@;\ fi @cat Output/$*.$(TEST).transformed.bc.info >> $@ Index: poolalloc/test/TEST.poolalloc.report diff -u poolalloc/test/TEST.poolalloc.report:1.10 poolalloc/test/TEST.poolalloc.report:1.11 --- poolalloc/test/TEST.poolalloc.report:1.10 Tue Feb 17 13:10:01 2004 +++ poolalloc/test/TEST.poolalloc.report Mon Mar 1 17:15:45 2004 @@ -10,14 +10,24 @@ sub Ratio { my ($Cols, $Col) = @_; - if ($Cols->[$Col-1] ne "*" and $Cols->[$Col-2] ne "*" and + if ($Cols->[$Col-1] ne "*" and $Cols->[$Col-4] ne "*" and $Cols->[$Col-1] != "0") { - return sprintf "%1.3f", $Cols->[$Col-2]/$Cols->[$Col-1]; + return sprintf "%1.3f", $Cols->[$Col-4]/$Cols->[$Col-1]; } else { return "n/a"; } } +sub Sum { + my ($Cols, $Col) = @_; + if ($Cols->[$Col-1] ne "*" and $Cols->[$Col-2] ne "*") { + return sprintf "%1.3f", $Cols->[$Col-2]+$Cols->[$Col-1]; + } else { + return "n/a"; + } +} + + sub FormatTime { my $Time = shift; if ($Time =~ m/([0-9]+)[m:]([0-9.]+)/) { @@ -68,13 +78,18 @@ ["Name:" , '\'([^\']+)\' Program'], [], # Times - ["Normal
    ExeTime" , 'CBE-RUN-TIME-NORMAL: real\s*([.0-9m:]+)', \&FormatTime], - ["PoolAlloc
    ExeTime", 'CBE-RUN-TIME-POOLALLOC: real\s*([.0-9m:]+)', \&FormatTime], + ["NormalUser", 'CBE-RUN-TIME-NORMAL-USER: user\s*([.0-9m:]+)', \&FormatTime], + ["NormalSys", 'CBE-RUN-TIME-NORMAL-SYS: sys\s*([.0-9m:]+)', \&FormatTime], + ["NormalSum", \&Sum], + ["PoolAllocUser", 'CBE-RUN-TIME-POOLALLOC-USER: user\s*([.0-9m:]+)', \&FormatTime], + ["PoolAllocSys", 'CBE-RUN-TIME-POOLALLOC-SYS: sys\s*([.0-9m:]+)', \&FormatTime], + ["NormalSum", \&Sum], ["Speedup", \&Ratio], ["NumPools", '([0-9]+).*Number of pools allocated'], ["NumTSPools", '([0-9]+).*Number of typesafe pools'], ["NumArgs", '([0-9]+).*Number of function arguments added'], - ["NumPRElide", '([0-9]+).*Number of poolfree.s elided'], + ["Nonprofit", '([0-9]+).*Number of DSNodes not profitable'], + ["NumPFElide", '([0-9]+).*Number of poolfree.s elided'], [] ); From alkis at cs.uiuc.edu Mon Mar 1 17:19:01 2004 From: alkis at cs.uiuc.edu (Alkis Evlogimenos) Date: Mon Mar 1 17:19:01 2004 Subject: [llvm-commits] CVS: llvm/docs/CommandGuide/llc.html Message-ID: <200403012318.RAA22575@zion.cs.uiuc.edu> Changes in directory llvm/docs/CommandGuide: llc.html updated: 1.8 -> 1.9 --- Log message: Add a spiller option to llc. A simple spiller will come soon. When we get CFG in the machine code represenation a global spiller will also be possible. Also document the linear scan register allocator but mark it as experimental for now. --- Diffs of the changes: (+13 -0) Index: llvm/docs/CommandGuide/llc.html diff -u llvm/docs/CommandGuide/llc.html:1.8 llvm/docs/CommandGuide/llc.html:1.9 --- llvm/docs/CommandGuide/llc.html:1.8 Wed Feb 18 17:30:02 2004 +++ llvm/docs/CommandGuide/llc.html Mon Mar 1 17:18:15 2004 @@ -150,6 +150,19 @@ local
    Local register allocator
    + + linearscan +
    Linear scan global register allocator (experimental)
    + +
  • -spiller=<sp> +
    + Specify the spiller to use for register allocators that support it. + Currently this option is used by the linear scan register + allocator. The default is local. + Valid spillers are: +
    + local +
    Local spiller

    From alkis at cs.uiuc.edu Mon Mar 1 17:19:04 2004 From: alkis at cs.uiuc.edu (Alkis Evlogimenos) Date: Mon Mar 1 17:19:04 2004 Subject: [llvm-commits] CVS: llvm/lib/CodeGen/RegAllocLinearScan.cpp VirtRegMap.h VirtRegMap.cpp Passes.cpp Message-ID: <200403012318.RAA22588@zion.cs.uiuc.edu> Changes in directory llvm/lib/CodeGen: RegAllocLinearScan.cpp updated: 1.68 -> 1.69 VirtRegMap.h updated: 1.8 -> 1.9 VirtRegMap.cpp updated: 1.7 -> 1.8 Passes.cpp updated: 1.5 -> 1.6 --- Log message: Add a spiller option to llc. A simple spiller will come soon. When we get CFG in the machine code represenation a global spiller will also be possible. Also document the linear scan register allocator but mark it as experimental for now. --- Diffs of the changes: (+74 -46) Index: llvm/lib/CodeGen/RegAllocLinearScan.cpp diff -u llvm/lib/CodeGen/RegAllocLinearScan.cpp:1.68 llvm/lib/CodeGen/RegAllocLinearScan.cpp:1.69 --- llvm/lib/CodeGen/RegAllocLinearScan.cpp:1.68 Mon Mar 1 14:05:10 2004 +++ llvm/lib/CodeGen/RegAllocLinearScan.cpp Mon Mar 1 17:18:15 2004 @@ -41,6 +41,7 @@ std::auto_ptr prt_; std::auto_ptr vrm_; + std::auto_ptr spiller_; typedef std::vector SpillWeights; SpillWeights spillWeights_; @@ -147,12 +148,13 @@ li_ = &getAnalysis(); if (!prt_.get()) prt_.reset(new PhysRegTracker(*mri_)); vrm_.reset(new VirtRegMap(*mf_)); + if (!spiller_.get()) spiller_.reset(createSpiller()); initIntervalSets(li_->getIntervals()); linearScan(); - eliminateVirtRegs(*mf_, *vrm_); + spiller_->runOnMachineFunction(*mf_, *vrm_); return true; } Index: llvm/lib/CodeGen/VirtRegMap.h diff -u llvm/lib/CodeGen/VirtRegMap.h:1.8 llvm/lib/CodeGen/VirtRegMap.h:1.9 --- llvm/lib/CodeGen/VirtRegMap.h:1.8 Mon Mar 1 14:05:10 2004 +++ llvm/lib/CodeGen/VirtRegMap.h Mon Mar 1 17:18:15 2004 @@ -108,7 +108,14 @@ std::ostream& operator<<(std::ostream& os, const VirtRegMap& li); - void eliminateVirtRegs(MachineFunction& mf, const VirtRegMap& vrm); + struct Spiller { + virtual ~Spiller(); + + virtual bool runOnMachineFunction(MachineFunction& mf, const VirtRegMap& vrm) = 0; + + }; + + Spiller* createSpiller(); } // End llvm namespace Index: llvm/lib/CodeGen/VirtRegMap.cpp diff -u llvm/lib/CodeGen/VirtRegMap.cpp:1.7 llvm/lib/CodeGen/VirtRegMap.cpp:1.8 --- llvm/lib/CodeGen/VirtRegMap.cpp:1.7 Mon Mar 1 14:05:10 2004 +++ llvm/lib/CodeGen/VirtRegMap.cpp Mon Mar 1 17:18:15 2004 @@ -22,9 +22,10 @@ #include "llvm/CodeGen/MachineInstr.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetInstrInfo.h" -#include "Support/Statistic.h" +#include "Support/CommandLine.h" #include "Support/Debug.h" #include "Support/DenseMap.h" +#include "Support/Statistic.h" #include "Support/STLExtras.h" #include @@ -35,6 +36,15 @@ Statistic<> numStores("spiller", "Number of stores added"); Statistic<> numLoads ("spiller", "Number of loads added"); + enum SpillerName { local }; + + cl::opt + SpillerOpt("spiller", + cl::desc("Spiller to use: (default: local)"), + cl::Prefix, + cl::values(clEnumVal(local, " local spiller"), + 0), + cl::init(local)); } int VirtRegMap::assignVirt2StackSlot(unsigned virtReg) @@ -88,41 +98,44 @@ return std::cerr << '\n'; } +Spiller::~Spiller() +{ + +} + namespace { - class Spiller { + class LocalSpiller : public Spiller { typedef std::vector Phys2VirtMap; typedef std::vector PhysFlag; typedef DenseMap Virt2MI; - MachineFunction& mf_; - const TargetMachine& tm_; - const TargetInstrInfo& tii_; - const MRegisterInfo& mri_; - const VirtRegMap& vrm_; + MachineFunction* mf_; + const TargetMachine* tm_; + const TargetInstrInfo* tii_; + const MRegisterInfo* mri_; + const VirtRegMap* vrm_; Phys2VirtMap p2vMap_; PhysFlag dirty_; Virt2MI lastDef_; public: - Spiller(MachineFunction& mf, const VirtRegMap& vrm) - : mf_(mf), - tm_(mf_.getTarget()), - tii_(tm_.getInstrInfo()), - mri_(*tm_.getRegisterInfo()), - vrm_(vrm), - p2vMap_(mri_.getNumRegs(), 0), - dirty_(mri_.getNumRegs(), false), - lastDef_() { + bool runOnMachineFunction(MachineFunction& mf, const VirtRegMap& vrm) { + mf_ = &mf; + tm_ = &mf_->getTarget(); + tii_ = &tm_->getInstrInfo(); + mri_ = tm_->getRegisterInfo(); + vrm_ = &vrm; + p2vMap_.assign(mri_->getNumRegs(), 0); + dirty_.assign(mri_->getNumRegs(), false); + DEBUG(std::cerr << "********** REWRITE MACHINE CODE **********\n"); DEBUG(std::cerr << "********** Function: " - << mf_.getFunction()->getName() << '\n'); - } + << mf_->getFunction()->getName() << '\n'); - void eliminateVirtRegs() { - for (MachineFunction::iterator mbbi = mf_.begin(), - mbbe = mf_.end(); mbbi != mbbe; ++mbbi) { - lastDef_.grow(mf_.getSSARegMap()->getLastVirtReg()); + for (MachineFunction::iterator mbbi = mf_->begin(), + mbbe = mf_->end(); mbbi != mbbe; ++mbbi) { + lastDef_.grow(mf_->getSSARegMap()->getLastVirtReg()); DEBUG(std::cerr << mbbi->getBasicBlock()->getName() << ":\n"); eliminateVirtRegsInMbb(*mbbi); // clear map, dirty flag and last ref @@ -130,6 +143,7 @@ dirty_.assign(dirty_.size(), false); lastDef_.clear(); } + return true; } private: @@ -137,21 +151,21 @@ MachineBasicBlock::iterator mii, unsigned physReg) { unsigned virtReg = p2vMap_[physReg]; - if (dirty_[physReg] && vrm_.hasStackSlot(virtReg)) { + if (dirty_[physReg] && vrm_->hasStackSlot(virtReg)) { assert(lastDef_[virtReg] && "virtual register is mapped " "to a register and but was not defined!"); MachineBasicBlock::iterator lastDef = lastDef_[virtReg]; MachineBasicBlock::iterator nextLastRef = next(lastDef); - mri_.storeRegToStackSlot(*lastDef->getParent(), + mri_->storeRegToStackSlot(*lastDef->getParent(), nextLastRef, physReg, - vrm_.getStackSlot(virtReg), - mri_.getRegClass(physReg)); + vrm_->getStackSlot(virtReg), + mri_->getRegClass(physReg)); ++numStores; DEBUG(std::cerr << "added: "; - prior(nextLastRef)->print(std::cerr, tm_); + prior(nextLastRef)->print(std::cerr, *tm_); std::cerr << "after: "; - lastDef->print(std::cerr, tm_)); + lastDef->print(std::cerr, *tm_)); lastDef_[virtReg] = 0; } p2vMap_[physReg] = 0; @@ -162,7 +176,7 @@ MachineBasicBlock::iterator mii, unsigned physReg) { vacateJustPhysReg(mbb, mii, physReg); - for (const unsigned* as = mri_.getAliasSet(physReg); *as; ++as) + for (const unsigned* as = mri_->getAliasSet(physReg); *as; ++as) vacateJustPhysReg(mbb, mii, *as); } @@ -175,13 +189,13 @@ vacatePhysReg(mbb, mii, physReg); p2vMap_[physReg] = virtReg; // load if necessary - if (vrm_.hasStackSlot(virtReg)) { - mri_.loadRegFromStackSlot(mbb, mii, physReg, - vrm_.getStackSlot(virtReg), - mri_.getRegClass(physReg)); + if (vrm_->hasStackSlot(virtReg)) { + mri_->loadRegFromStackSlot(mbb, mii, physReg, + vrm_->getStackSlot(virtReg), + mri_->getRegClass(physReg)); ++numLoads; DEBUG(std::cerr << "added: "; - prior(mii)->print(std::cerr,tm_)); + prior(mii)->print(std::cerr, *tm_)); lastDef_[virtReg] = mii; } } @@ -208,8 +222,8 @@ // we clear all physical registers that may contain // the value of the spilled virtual register VirtRegMap::MI2VirtMap::const_iterator i, e; - for (tie(i, e) = vrm_.getFoldedVirts(mii); i != e; ++i) { - unsigned physReg = vrm_.getPhys(i->second); + for (tie(i, e) = vrm_->getFoldedVirts(mii); i != e; ++i) { + unsigned physReg = vrm_->getPhys(i->second); if (physReg) vacateJustPhysReg(mbb, mii, physReg); } @@ -219,7 +233,7 @@ if (op.isRegister() && op.getReg() && op.isUse() && MRegisterInfo::isVirtualRegister(op.getReg())) { unsigned virtReg = op.getReg(); - unsigned physReg = vrm_.getPhys(virtReg); + unsigned physReg = vrm_->getPhys(virtReg); handleUse(mbb, mii, virtReg, physReg); mii->SetMachineOperandReg(i, physReg); // mark as dirty if this is def&use @@ -231,7 +245,7 @@ } // spill implicit defs - const TargetInstrDescriptor& tid =tii_.get(mii->getOpcode()); + const TargetInstrDescriptor& tid = tii_->get(mii->getOpcode()); for (const unsigned* id = tid.ImplicitDefs; *id; ++id) vacatePhysReg(mbb, mii, *id); @@ -243,13 +257,13 @@ if (MRegisterInfo::isPhysicalRegister(op.getReg())) vacatePhysReg(mbb, mii, op.getReg()); else { - unsigned physReg = vrm_.getPhys(op.getReg()); + unsigned physReg = vrm_->getPhys(op.getReg()); handleDef(mbb, mii, op.getReg(), physReg); mii->SetMachineOperandReg(i, physReg); } } - DEBUG(std::cerr << '\t'; mii->print(std::cerr, tm_)); + DEBUG(std::cerr << '\t'; mii->print(std::cerr, *tm_)); } for (unsigned i = 1, e = p2vMap_.size(); i != e; ++i) @@ -259,8 +273,13 @@ }; } - -void llvm::eliminateVirtRegs(MachineFunction& mf, const VirtRegMap& vrm) +llvm::Spiller* llvm::createSpiller() { - Spiller(mf, vrm).eliminateVirtRegs(); + switch (SpillerOpt) { + default: + std::cerr << "no spiller selected"; + abort(); + case local: + return new LocalSpiller(); + } } Index: llvm/lib/CodeGen/Passes.cpp diff -u llvm/lib/CodeGen/Passes.cpp:1.5 llvm/lib/CodeGen/Passes.cpp:1.6 --- llvm/lib/CodeGen/Passes.cpp:1.5 Sun Dec 28 01:59:53 2003 +++ llvm/lib/CodeGen/Passes.cpp Mon Mar 1 17:18:15 2004 @@ -26,7 +26,7 @@ cl::Prefix, cl::values(clEnumVal(simple, " simple register allocator"), clEnumVal(local, " local register allocator"), - clEnumVal(linearscan, " linear-scan global register allocator"), + clEnumVal(linearscan, " linear scan register allocator (experimental)"), 0), cl::init(local)); } From alkis at cs.uiuc.edu Mon Mar 1 17:26:01 2004 From: alkis at cs.uiuc.edu (Alkis Evlogimenos) Date: Mon Mar 1 17:26:01 2004 Subject: [llvm-commits] CVS: llvm/docs/CommandGuide/llc.html Message-ID: <200403012325.RAA22695@zion.cs.uiuc.edu> Changes in directory llvm/docs/CommandGuide: llc.html updated: 1.9 -> 1.10 --- Log message: Fix

    missing

    tag --- Diffs of the changes: (+1 -0) Index: llvm/docs/CommandGuide/llc.html diff -u llvm/docs/CommandGuide/llc.html:1.9 llvm/docs/CommandGuide/llc.html:1.10 --- llvm/docs/CommandGuide/llc.html:1.9 Mon Mar 1 17:18:15 2004 +++ llvm/docs/CommandGuide/llc.html Mon Mar 1 17:25:38 2004 @@ -153,6 +153,7 @@ linearscan

    Linear scan global register allocator (experimental)
    +

  • -spiller=<sp>
    From brukman at cs.uiuc.edu Mon Mar 1 17:54:02 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Mar 1 17:54:02 2004 Subject: [llvm-commits] CVS: llvm/lib/Target/X86/Printer.cpp InstSelectSimple.cpp Message-ID: <200403012353.RAA23376@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/X86: Printer.cpp updated: 1.90 -> 1.91 InstSelectSimple.cpp updated: 1.189 -> 1.190 --- Log message: Doxygenify some comments. --- Diffs of the changes: (+21 -9) Index: llvm/lib/Target/X86/Printer.cpp diff -u llvm/lib/Target/X86/Printer.cpp:1.90 llvm/lib/Target/X86/Printer.cpp:1.91 --- llvm/lib/Target/X86/Printer.cpp:1.90 Sun Feb 29 02:50:03 2004 +++ llvm/lib/Target/X86/Printer.cpp Mon Mar 1 17:53:11 2004 @@ -7,10 +7,10 @@ // //===----------------------------------------------------------------------===// // -// This file contains a printer that converts from our internal -// representation of machine-dependent LLVM code to Intel-format -// assembly language. This printer is the output mechanism used -// by `llc' and `lli -print-machineinstrs' on X86. +// This file contains a printer that converts from our internal representation +// of machine-dependent LLVM code to Intel-format assembly language. This +// printer is the output mechanism used by `llc' and `lli -print-machineinstrs' +// on X86. // //===----------------------------------------------------------------------===// Index: llvm/lib/Target/X86/InstSelectSimple.cpp diff -u llvm/lib/Target/X86/InstSelectSimple.cpp:1.189 llvm/lib/Target/X86/InstSelectSimple.cpp:1.190 --- llvm/lib/Target/X86/InstSelectSimple.cpp:1.189 Sun Feb 29 20:42:43 2004 +++ llvm/lib/Target/X86/InstSelectSimple.cpp Mon Mar 1 17:53:11 2004 @@ -107,6 +107,7 @@ /// LowerUnknownIntrinsicFunctionCalls - This performs a prepass over the /// function, lowering any calls to unknown intrinsic functions into the /// equivalent LLVM code. + /// void LowerUnknownIntrinsicFunctionCalls(Function &F); /// LoadArgumentsToVirtualRegs - Load all of the arguments to this function @@ -221,11 +222,13 @@ /// emitCastOperation - Common code shared between visitCastInst and /// constant expression cast support. + /// void emitCastOperation(MachineBasicBlock *BB,MachineBasicBlock::iterator IP, Value *Src, const Type *DestTy, unsigned TargetReg); /// emitSimpleBinaryOperation - Common code shared between visitSimpleBinary /// and constant expression support. + /// void emitSimpleBinaryOperation(MachineBasicBlock *BB, MachineBasicBlock::iterator IP, Value *Op0, Value *Op1, @@ -238,6 +241,7 @@ /// emitSetCCOperation - Common code shared between visitSetCondInst and /// constant expression support. + /// void emitSetCCOperation(MachineBasicBlock *BB, MachineBasicBlock::iterator IP, Value *Op0, Value *Op1, unsigned Opcode, @@ -245,6 +249,7 @@ /// emitShiftOperation - Common code shared between visitShiftInst and /// constant expression support. + /// void emitShiftOperation(MachineBasicBlock *MBB, MachineBasicBlock::iterator IP, Value *Op, Value *ShiftAmount, bool isLeftShift, @@ -887,6 +892,7 @@ /// emitSetCCOperation - Common code shared between visitSetCondInst and /// constant expression support. +/// void ISel::emitSetCCOperation(MachineBasicBlock *MBB, MachineBasicBlock::iterator IP, Value *Op0, Value *Op1, unsigned Opcode, @@ -913,6 +919,7 @@ /// promote32 - Emit instructions to turn a narrow operand into a 32-bit-wide /// operand, in the specified target register. +/// void ISel::promote32(unsigned targetReg, const ValueRecord &VR) { bool isUnsigned = VR.Ty->isUnsigned(); @@ -1221,6 +1228,7 @@ /// LowerUnknownIntrinsicFunctionCalls - This performs a prepass over the /// function, lowering any calls to unknown intrinsic functions into the /// equivalent LLVM code. +/// void ISel::LowerUnknownIntrinsicFunctionCalls(Function &F) { for (Function::iterator BB = F.begin(), E = F.end(); BB != E; ++BB) for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ) @@ -1404,6 +1412,7 @@ /// visitSimpleBinary - Implement simple binary operators for integral types... /// OperatorClass is one of: 0 for Add, 1 for Sub, 2 for And, 3 for Or, 4 for /// Xor. +/// void ISel::visitSimpleBinary(BinaryOperator &B, unsigned OperatorClass) { unsigned DestReg = getReg(B); MachineBasicBlock::iterator MI = BB->end(); @@ -2003,8 +2012,9 @@ } -/// visitCastInst - Here we have various kinds of copying with or without -/// sign extension going on. +/// visitCastInst - Here we have various kinds of copying with or without sign +/// extension going on. +/// void ISel::visitCastInst(CastInst &CI) { Value *Op = CI.getOperand(0); // If this is a cast from a 32-bit integer to a Long type, and the only uses @@ -2028,8 +2038,9 @@ emitCastOperation(BB, MI, Op, CI.getType(), DestReg); } -/// emitCastOperation - Common code shared between visitCastInst and -/// constant expression cast support. +/// emitCastOperation - Common code shared between visitCastInst and constant +/// expression cast support. +/// void ISel::emitCastOperation(MachineBasicBlock *BB, MachineBasicBlock::iterator IP, Value *Src, const Type *DestTy, @@ -2371,7 +2382,8 @@ } } - +/// visitGetElementPtrInst - instruction-select GEP instructions +/// void ISel::visitGetElementPtrInst(GetElementPtrInst &I) { // If this GEP instruction will be folded into all of its users, we don't need // to explicitly calculate it! From brukman at cs.uiuc.edu Mon Mar 1 17:55:02 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Mar 1 17:55:02 2004 Subject: [llvm-commits] [parallel] CVS: llvm/LICENSE.TXT Makefile Makefile.config.in Makefile.rules configure Message-ID: <200403012354.RAA23444@zion.cs.uiuc.edu> Changes in directory llvm: LICENSE.TXT updated: 1.4 -> 1.4.4.1 Makefile updated: 1.15 -> 1.15.2.1 Makefile.config.in updated: 1.16 -> 1.16.2.1 Makefile.rules updated: 1.169 -> 1.169.2.1 configure updated: 1.69 -> 1.69.2.1 --- Log message: Merge from trunk --- Diffs of the changes: (+836 -300) Index: llvm/LICENSE.TXT diff -u llvm/LICENSE.TXT:1.4 llvm/LICENSE.TXT:1.4.4.1 --- llvm/LICENSE.TXT:1.4 Mon Oct 27 11:56:26 2003 +++ llvm/LICENSE.TXT Mon Mar 1 17:54:05 2004 @@ -49,3 +49,48 @@ have its own individual LICENSE.TXT file in the directory in which it appears. This file will describe the copyrights, license, and restrictions which apply to that code. + +The disclaimer of warranty in the University of Illinois Open Source License +applies to all code in the LLVM Distribution, and nothing in any of the +other licenses gives permission to use the names of the LLVM Team or the +University of Illinois to endorse or promote products derived from this +Software. + +The following pieces of software have additional or alternate copyrights, +licenses, and/or restrictions: + +Program Directory +------- --------- +Autoconf: llvm/autoconf + llvm/projects/ModuleMaker/autoconf + llvm/projects/sample/autoconf +Burg: llvm/utils/Burg + llvm/test/Programs/MultiSource/Applications/Burg +Aha: llvm/test/Programs/MultiSource/Applications/aha +SGEFA: llvm/test/Programs/MultiSource/Applications/sgefa +SIOD: llvm/test/Programs/MultiSource/Applications/siod +D: llvm/test/Programs/MultiSource/Applications/d +Lambda: llvm/test/Programs/MultiSource/Applications/lambda-0.1.3 +hbd: llvm/test/Programs/MultiSource/Applications/hbd +Fhourstones: llvm/test/Programs/MultiSource/Benchmarks/Fhourstones +McCat: llvm/test/Programs/MultiSource/Benchmarks/McCat +Olden: llvm/test/Programs/MultiSource/Benchmarks/Olden +OptimizerEval: llvm/test/Programs/MultiSource/Benchmarks/OptimizerEval +Ptrdist: llvm/test/Programs/MultiSource/Benchmarks/Ptrdist +LLUBenchmark: llvm/test/Programs/MultiSource/Benchmarks/llubenchmark +SIM: llvm/test/Programs/MultiSource/Benchmarks/sim +cfrac: llvm/test/Programs/MultiSource/Benchmarks/MallocBench/cfrac +espresso: llvm/test/Programs/MultiSource/Benchmarks/MallocBench/espresso +gs: llvm/test/Programs/MultiSource/Benchmarks/MallocBench/gs +p2c: llvm/test/Programs/MultiSource/Benchmarks/MallocBench/p2c +gawk: llvm/test/Programs/MultiSource/Benchmarks/MallocBench/gawk +make: llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make +perl: llvm/test/Programs/MultiSource/Benchmarks/MallocBench/perl +Dhrystone: llvm/test/Programs/SingleSource/Benchmarks/Dhrystone +SingleSource Tests: llvm/test/Programs/SingleSource/Benchmarks/Misc + llvm/test/Programs/SingleSource/CustomChecked + llvm/test/Programs/SingleSource/Gizmos +GNU Libc: llvm/runtime/GCCLibraries/libc +Zlib Library: llvm/runtime/zlib +PNG Library: llvm/runtime/libpng + Index: llvm/Makefile diff -u llvm/Makefile:1.15 llvm/Makefile:1.15.2.1 --- llvm/Makefile:1.15 Tue Jan 13 01:09:56 2004 +++ llvm/Makefile Mon Mar 1 17:54:05 2004 @@ -7,9 +7,13 @@ # ##===----------------------------------------------------------------------===## LEVEL = . -DIRS = lib/Support utils lib tools runtime +DIRS = lib/Support utils lib tools OPTIONAL_DIRS = projects +ifneq ($(MAKECMDGOALS),tools-only) +DIRS += runtime +endif + include $(LEVEL)/Makefile.common test :: all @@ -22,22 +26,27 @@ $(LEVEL)/config.log \ $(LEVEL)/TAGS -tools-only: - @for dir in lib/Support utils lib tools; do $(MAKE) -C $$dir; done - -configure: autoconf/configure.ac autoconf/aclocal.m4 - cd autoconf && aclocal && autoconf -o ../configure configure.ac - -include/Config/config.h.in: autoconf/configure.ac autoconf/aclocal.m4 - autoheader -I autoconf autoconf/configure.ac - -# Install support for llvm include files. +tools-only: all +# Install support for llvm include files: .PHONY: install-includes install-includes: - $(MKDIR) $(includedir)/llvm - cd include && find * '!' '(' -name '*~' -o -name .cvsignore ')' -print | grep -v CVS | pax -rwdvpe $(includedir)/llvm + $(MKDIR) $(DESTDIR)$(includedir)/llvm + cd include && find * '!' '(' -name '*~' -o -name .cvsignore ')' -print | grep -v CVS | pax -rwdvpe $(DESTDIR)$(includedir)/llvm +ifneq ($(BUILD_SRC_ROOT),$(BUILD_OBJ_ROOT)) + cd $(BUILD_SRC_ROOT)/include && find * '!' '(' -name '*~' -o -name .cvsignore ')' -print | grep -v CVS | pax -rwdvpe $(DESTDIR)$(includedir)/llvm +endif install:: install-includes + +# Build tags database for Emacs/Xemacs: +.PHONY: tags + +TAGS: tags + +all:: tags + +tags: + $(ETAGS) $(ETAGSFLAGS) `find $(wildcard $(SourceDir)/include $(SourceDir)/lib $(SourceDir)/tools) -name '*.cpp' -o -name '*.h'` Index: llvm/Makefile.config.in diff -u llvm/Makefile.config.in:1.16 llvm/Makefile.config.in:1.16.2.1 --- llvm/Makefile.config.in:1.16 Fri Jan 16 15:31:34 2004 +++ llvm/Makefile.config.in Mon Mar 1 17:54:05 2004 @@ -11,6 +11,9 @@ # Target hardware architecture ARCH=@ARCH@ +# Endian-ness of the target +ENDIAN=@ENDIAN@ + # Path to the C++ compiler to use. This is an optional setting, which defaults # to whatever your gmake defaults to. # @@ -48,6 +51,7 @@ INSTALL = @INSTALL@ DOT = @DOT@ ETAGS = @ETAGS@ +ETAGSFLAGS = @ETAGSFLAGS@ # Determine the target for which LLVM should generate code. LLVMGCCARCH := @target@/3.4-llvm @@ -80,14 +84,18 @@ BYTECODE_REPOSITORY := @BCR@ # SPEC benchmarks: -# Set the USE_SPEC variable to enable the use of the SPEC benchmarks. +# If these are set then run the SPEC benchmarks. # You must provide the SPEC benchmarks on your own. - at USE_SPEC@ + at USE_SPEC2000@ + at USE_SPEC95@ -# Path to the SPEC benchmarks. If you have the SPEC benchmarks, place the -# path here. -#SPEC_ROOT := /home/vadve/shared/benchmarks/speccpu2000/benchspec -SPEC_ROOT := @SPEC_ROOT@ +# Path to the SPEC benchmarks. +SPEC2000_ROOT := @SPEC2000_ROOT@ +SPEC95_ROOT := @SPEC95_ROOT@ + +# Path to the Povray source code. + at USE_POVRAY@ +POVRAY_ROOT := @POVRAY_ROOT@ # Path to the PAPI code. This is used by the reoptimizer only. #PAPIDIR := /home/vadve/shared/papi-2.3.4.1 @@ -115,6 +123,9 @@ # Disable LLC diffs for testing. @DISABLE_LLC_DIFFS@ +# Shared library extension for this platform. +SHLIBEXT = @SHLIBEXT@ + ########################################################################### # Directory Configuration # This section of the Makefile determines what is where. To be @@ -183,6 +194,7 @@ sharedstatedir = @sharedstatedir@ localstatedir = @localstatedir@ libdir = @libdir@ +bytecode_libdir = $(LLVMGCCDIR)/bytecode-libs includedir = @includedir@ infodir = @infodir@ mandir = @mandir@ Index: llvm/Makefile.rules diff -u llvm/Makefile.rules:1.169 llvm/Makefile.rules:1.169.2.1 --- llvm/Makefile.rules:1.169 Fri Jan 16 15:31:20 2004 +++ llvm/Makefile.rules Mon Mar 1 17:54:05 2004 @@ -109,7 +109,7 @@ ########################################################################### .SUFFIXES: .SUFFIXES: .c .cpp .h .hpp .y .l -.SUFFIXES: .lo .o .a .so .bc .td +.SUFFIXES: .lo .o .a $(SHLIBEXT) .bc .td .SUFFIXES: .ps .dot .d # @@ -289,6 +289,9 @@ # Pull in limit macros from stdint.h, even in C++: CPPFLAGS += -D__STDC_LIMIT_MACROS +### FIXME: this is GCC specific +CPPFLAGS += -DDEPRECATED='__attribute__ ((deprecated))' + CompileCommonOpts := -Wall -W -Wwrite-strings -Wno-unused CompileOptimizeOpts := -O3 -DNDEBUG -finline-functions @@ -352,7 +355,7 @@ DependC := $(CC) -MM -I$(LEVEL)/include $(CPPFLAGS) # Archive a bunch of .o files into a .a file... -AR = ${AR_PATH} cq +AR = $(AR_PATH) cr #---------------------------------------------------------- @@ -454,15 +457,20 @@ # of it. For this reason, sometimes it's useful to use libraries as .a files. ########################################################################### +# Install rule for making bytecode library directory if it does not exist. +# Trigger this by making libraries that need to be installed here depend on it. +$(DESTDIR)$(bytecode_libdir): + $(MKDIR) $@ + ifdef LIBRARYNAME # Make sure there isn't any extranous whitespace on the LIBRARYNAME option LIBRARYNAME := $(strip $(LIBRARYNAME)) -LIBNAME_O := $(DESTLIBRELEASE)/lib$(LIBRARYNAME).so -LIBNAME_P := $(DESTLIBPROFILE)/lib$(LIBRARYNAME).so -LIBNAME_G := $(DESTLIBDEBUG)/lib$(LIBRARYNAME).so -LIBNAME_CUR := $(DESTLIBCURRENT)/lib$(LIBRARYNAME).so +LIBNAME_O := $(DESTLIBRELEASE)/lib$(LIBRARYNAME)$(SHLIBEXT) +LIBNAME_P := $(DESTLIBPROFILE)/lib$(LIBRARYNAME)$(SHLIBEXT) +LIBNAME_G := $(DESTLIBDEBUG)/lib$(LIBRARYNAME)$(SHLIBEXT) +LIBNAME_CUR := $(DESTLIBCURRENT)/lib$(LIBRARYNAME)$(SHLIBEXT) LIBNAME_AO := $(DESTLIBRELEASE)/lib$(LIBRARYNAME).a LIBNAME_AP := $(DESTLIBPROFILE)/lib$(LIBRARYNAME).a LIBNAME_AG := $(DESTLIBDEBUG)/lib$(LIBRARYNAME).a @@ -482,9 +490,9 @@ # dynamic target builds a shared object version of the library... dynamic:: $(LIBNAME_CUR) bytecodelib:: $(LIBNAME_BC) -install-bytecode-library:: $(LLVMGCCDIR)/bytecode-libs/lib$(LIBRARYNAME).bc +install-bytecode-library:: $(DESTDIR)$(bytecode_libdir)/lib$(LIBRARYNAME).bc -$(LLVMGCCDIR)/bytecode-libs/lib$(LIBRARYNAME).bc: $(LIBNAME_BC) +$(DESTDIR)$(bytecode_libdir)/lib$(LIBRARYNAME).bc: $(LIBNAME_BC) $(DESTDIR)$(bytecode_libdir) @${ECHO} ======= Installing $(LIBRARYNAME) bytecode library ======= cp $< $@ @@ -543,8 +551,8 @@ @${ECHO} ======= Finished building $(LIBRARYNAME) dynamic debug library ======= install-dynamic-library: $(LIBNAME_CUR) - $(MKDIR) $(libdir) - $(VERB) $(LIBTOOL) --mode=install $(INSTALL) $(LIBNAME_CUR) $(libdir)/lib$(LIBRARYNAME).so + $(MKDIR) $(DESTDIR)$(libdir) + $(VERB) $(LIBTOOL) --mode=install $(INSTALL) $(LIBNAME_CUR) $(DESTDIR)$(libdir)/lib$(LIBRARYNAME)$(SHLIBEXT) # # Rules for building static archive libraries. @@ -568,8 +576,8 @@ @${ECHO} ======= Finished building $(LIBRARYNAME) archive debug library ======= install-archive-library: $(LIBNAME_ACUR) - $(MKDIR) $(libdir) - $(VERB) $(LIBTOOL) --mode=install $(INSTALL) $(LIBNAME_ACUR) $(libdir)/lib$(LIBRARYNAME).a + $(MKDIR) $(DESTDIR)$(libdir) + $(VERB) $(LIBTOOL) --mode=install $(INSTALL) $(LIBNAME_ACUR) $(DESTDIR)$(libdir)/lib$(LIBRARYNAME).a # # Rules for building .o libraries. @@ -598,26 +606,9 @@ $(VERB) $(Relink) -o $@ $(RObjectsG) $(LibSubDirs) install-single-object-library: $(LIBNAME_OBJCUR) - $(MKDIR) $(libdir) - $(VERB) $(LIBTOOL) --mode=install $(INSTALL) $(LIBNAME_OBJCUR) $(libdir)/$(LIBRARYNAME).o - -endif - -#------------------------------------------------------------------------ -# Create a TAGS database for emacs -#------------------------------------------------------------------------ + $(MKDIR) $(DESTDIR)$(libdir) + $(VERB) $(LIBTOOL) --mode=install $(INSTALL) $(LIBNAME_OBJCUR) $(DESTDIR)$(libdir)/$(LIBRARYNAME).o -ifneq ($(ETAGS),false) -ifeq ($(LEVEL), .) -SRCDIRS := $(wildcard $(SourceDir)/include $(SourceDir)/lib $(SourceDir)/tools) - -tags: - $(ETAGS) -l c++ `find $(SRCDIRS) -name '*.cpp' -o -name '*.h'` -all:: tags -endif -else -tags: - ${ECHO} "Cannot build $@: The program etags is not installed" endif #------------------------------------------------------------------------ @@ -698,8 +689,8 @@ @${ECHO} ======= Finished building $(TOOLNAME) profile executable ======= install:: $(TOOLEXENAMES) - $(MKDIR) $(bindir) - $(LIBTOOL) --mode=install $(INSTALL_PROGRAM) -c -m 0755 $(TOOLEXENAMES) $(bindir)/$(TOOLNAME) + $(MKDIR) $(DESTDIR)$(bindir) + $(LIBTOOL) --mode=install $(INSTALL_PROGRAM) -c -m 0755 $(TOOLEXENAMES) $(DESTDIR)$(bindir)/$(TOOLNAME) endif @@ -813,7 +804,10 @@ $(VERB) $(RM) -rf $(BUILD_OBJ_DIR)/Debug $(BUILD_OBJ_DIR)/Release $(VERB) $(RM) -rf $(BUILD_OBJ_DIR)/Profile $(BUILD_OBJ_DIR)/Depend $(VERB) $(RM) -rf $(BUILD_OBJ_DIR)/BytecodeObj - $(VERB) $(RM) -f core core.[0-9][0-9]* *.o *.d *.so *~ *.flc + $(VERB) $(RM) -f core core.[0-9][0-9]* *.o *.d *~ *.flc +ifneq ($(strip $(SHLIBEXT)),) # Extra paranoia - make real sure SHLIBEXT is set + $(VERB) $(RM) -f *$(SHLIBEXT) +endif $(VERB) $(RM) -f $(LEX_OUTPUT) $(YACC_OUTPUT) ########################################################################### Index: llvm/configure diff -u llvm/configure:1.69 llvm/configure:1.69.2.1 --- llvm/configure:1.69 Fri Jan 16 15:31:21 2004 +++ llvm/configure Mon Mar 1 17:54:05 2004 @@ -465,7 +465,7 @@ #endif" ac_unique_file=""Makefile.config.in"" -ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS subdirs INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os OS LLVMGCCDIR ARCH CXX CXXFLAGS LDFLAGS CPPFLAGS ac_ct_CXX EXEEXT OBJEXT CC CFLAGS ac_ct_CC CPP ifGNUmake LEX LEXLIB LEX_OUTPUT_ROOT YACC BISON EGREP LN_S ECHO AR ac_ct_AR RANLIB ac_ct_RANLIB STRIP ac_ct_STRIP CXXCPP F77 FFLAGS ac_ct_F77 LIBTOOL DOT ETAGS PYTHON QMTEST ALLOCA MMAP_FILE ENABLE_OPTIMIZED SPEC_ROOT USE_SPEC UPB DISABLE_LLC_DIFFS JIT LLVMCC1 LLVMCC1PLUS BCR PAPIDIR LIBOBJS LTLIBOBJS' +ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS subdirs INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os OS LLVMGCCDIR ARCH CXX CXXFLAGS LDFLAGS CPPFLAGS ac_ct_CXX EXEEXT OBJEXT CC CFLAGS ac_ct_CC CPP ifGNUmake LEX LEXLIB LEX_OUTPUT_ROOT YACC BISON EGREP LN_S ECHO AR ac_ct_AR RANLIB ac_ct_RANLIB STRIP ac_ct_STRIP CXXCPP F77 FFLAGS ac_ct_F77 LIBTOOL DOT ETAGS ETAGSFLAGS PYTHON QMTEST HAVE_PTHREAD_MUTEX_LOCK INCLUDE_SYS_TYPES_H INCLUDE_INTTYPES_H ENDIAN HAVE_STD_EXT_HASH_MAP HAVE_GNU_EXT_HASH_MAP HAVE_GLOBAL_HASH_MAP HAVE_STD_EXT_HASH_SET HAVE_GNU_EXT_HASH_SET HAVE_GLOBAL_HASH_S! ET HAVE_STD_ITERATOR HAVE_BI_ITERATOR HAVE_FWD_ITERATOR ALLOCA MMAP_FILE ENABLE_OPTIMIZED SPEC2000_ROOT USE_SPEC2000 SPEC95_ROOT USE_SPEC95 POVRAY_ROOT USE_POVRAY UPB DISABLE_LLC_DIFFS JIT LLVMCC1 LLVMCC1PLUS BCR PAPIDIR SHLIBEXT LIBOBJS LTLIBOBJS' ac_subst_files='' # Initialize some variables set by options. @@ -1032,6 +1032,8 @@ --disable-libtool-lock avoid locking (might break parallel builds) --enable-optimized Compile with optimizations enabled (default is NO) --enable-spec2000 Compile SPEC 2000 benchmarks (default is NO) + --enable-spec95 Compile SPEC 95 benchmarks (default is NO) + --enable-povray Compile Povray benchmark (default is NO) --enable-precompiled_bytecode Use pre-compiled bytecode (default is NO) --enable-llc_diffs Enable LLC Diffs when testing (default is YES) @@ -1569,9 +1571,6 @@ ac_config_commands="$ac_config_commands test/Programs/TEST.dsgraph.report" - ac_config_commands="$ac_config_commands test/Programs/TEST.micro.report" - - ac_config_commands="$ac_config_commands test/Programs/TEST.aa.report" @@ -1602,7 +1601,7 @@ ac_config_commands="$ac_config_commands test/Programs/TEST.dsgraph.gnuplot" - ac_config_commands="$ac_config_commands test/Programs/TEST.micro.Makefile" + ac_config_commands="$ac_config_commands test/Programs/TEST.vtl.Makefile" ac_config_commands="$ac_config_commands test/Programs/External/Makefile" @@ -1614,6 +1613,12 @@ ac_config_commands="$ac_config_commands test/Programs/External/SPEC/Makefile.spec" + ac_config_commands="$ac_config_commands test/Programs/External/SPEC/Makefile.spec2000" + + + ac_config_commands="$ac_config_commands test/Programs/External/SPEC/Makefile.spec95" + + ac_config_commands="$ac_config_commands test/Programs/MultiSource/Makefile" @@ -1665,6 +1670,9 @@ ac_config_commands="$ac_config_commands test/Programs/SingleSource/Makefile.singlesrc" + ac_config_commands="$ac_config_commands test/Programs/SingleSource/UnitTests/SetjmpLongjmp/Makefile" + + ac_config_commands="$ac_config_commands tools/Makefile" @@ -4036,7 +4044,7 @@ ;; *-*-irix6*) # Find out which ABI we are using. - echo '#line 4039 "configure"' > conftest.$ac_ext + echo '#line 4047 "configure"' > conftest.$ac_ext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? @@ -4877,7 +4885,7 @@ # Provide some information about the compiler. -echo "$as_me:4880:" \ +echo "$as_me:4888:" \ "checking for Fortran 77 compiler version" >&5 ac_compiler=`set X $ac_compile; echo $2` { (eval echo "$as_me:$LINENO: \"$ac_compiler --version &5\"") >&5 @@ -5882,11 +5890,11 @@ -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:5885: $lt_compile\"" >&5) + (eval echo "\"\$as_me:5893: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:5889: \$? = $ac_status" >&5 + echo "$as_me:5897: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings @@ -6114,11 +6122,11 @@ -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:6117: $lt_compile\"" >&5) + (eval echo "\"\$as_me:6125: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:6121: \$? = $ac_status" >&5 + echo "$as_me:6129: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings @@ -6181,11 +6189,11 @@ -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:6184: $lt_compile\"" >&5) + (eval echo "\"\$as_me:6192: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:6188: \$? = $ac_status" >&5 + echo "$as_me:6196: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized @@ -8193,7 +8201,7 @@ lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext < conftest.$ac_ext <&5) + (eval echo "\"\$as_me:10434: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:10430: \$? = $ac_status" >&5 + echo "$as_me:10438: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings @@ -10490,11 +10498,11 @@ -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:10493: $lt_compile\"" >&5) + (eval echo "\"\$as_me:10501: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:10497: \$? = $ac_status" >&5 + echo "$as_me:10505: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized @@ -11733,7 +11741,7 @@ lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext < conftest.$ac_ext <&5) + (eval echo "\"\$as_me:12664: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:12660: \$? = $ac_status" >&5 + echo "$as_me:12668: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings @@ -12720,11 +12728,11 @@ -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:12723: $lt_compile\"" >&5) + (eval echo "\"\$as_me:12731: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:12727: \$? = $ac_status" >&5 + echo "$as_me:12735: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized @@ -14660,11 +14668,11 @@ -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:14663: $lt_compile\"" >&5) + (eval echo "\"\$as_me:14671: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:14667: \$? = $ac_status" >&5 + echo "$as_me:14675: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings @@ -14892,11 +14900,11 @@ -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:14895: $lt_compile\"" >&5) + (eval echo "\"\$as_me:14903: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:14899: \$? = $ac_status" >&5 + echo "$as_me:14907: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings @@ -14959,11 +14967,11 @@ -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:14962: $lt_compile\"" >&5) + (eval echo "\"\$as_me:14970: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:14966: \$? = $ac_status" >&5 + echo "$as_me:14974: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized @@ -16971,7 +16979,7 @@ lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext < conftest.$ac_ext <&6 fi +etags_version=`$ETAGS --version 2>&1` +case "$etags_version" in + *Eexuberant*) ETAGSFLAGS="--language-force=c++" ;; + *GNU\ Emacs*) ETAGSFLAGS="-l c++" ;; + *) ETAGSFLAGS="" ;; +esac +ETAGSFLAGS=$ETAGSFLAGS + # Extract the first word of "python", so it can be a program name with args. set dummy python; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 @@ -18661,14 +18677,13 @@ echo "${ECHO_T}$ac_cv_search_pthread_mutex_lock" >&6 if test "$ac_cv_search_pthread_mutex_lock" != no; then test "$ac_cv_search_pthread_mutex_lock" = "none required" || LIBS="$ac_cv_search_pthread_mutex_lock $LIBS" - -cat >>confdefs.h <<\_ACEOF -#define HAVE_PTHREAD_MUTEX_LOCK 1 -_ACEOF - + HAVE_PTHREAD_MUTEX_LOCK=1 +else + HAVE_PTHREAD_MUTEX_LOCK=0 fi + echo "$as_me:$LINENO: checking for ANSI C header files" >&5 echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6 if test "${ac_cv_header_stdc+set}" = set; then @@ -18901,7 +18916,8 @@ -for ac_header in fcntl.h limits.h sys/time.h unistd.h malloc.h sys/mman.h sys/resource.h dlfcn.h link.h + +for ac_header in fcntl.h limits.h sys/time.h unistd.h malloc.h sys/mman.h sys/resource.h dlfcn.h link.h execinfo.h do as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` if eval "test \"\${$as_ac_Header+set}\" = set"; then @@ -19043,6 +19059,281 @@ done +if test "${ac_cv_header_sys_types_h+set}" = set; then + echo "$as_me:$LINENO: checking for sys/types.h" >&5 +echo $ECHO_N "checking for sys/types.h... $ECHO_C" >&6 +if test "${ac_cv_header_sys_types_h+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: $ac_cv_header_sys_types_h" >&5 +echo "${ECHO_T}$ac_cv_header_sys_types_h" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking sys/types.h usability" >&5 +echo $ECHO_N "checking sys/types.h usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_header_compiler=no +fi +rm -f conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking sys/types.h presence" >&5 +echo $ECHO_N "checking sys/types.h presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc in + yes:no ) + { echo "$as_me:$LINENO: WARNING: sys/types.h: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: sys/types.h: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: sys/types.h: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: sys/types.h: proceeding with the preprocessor's result" >&2;} + ( + cat <<\_ASBOX +## ------------------------------------ ## +## Report this to bug-autoconf at gnu.org. ## +## ------------------------------------ ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; + no:yes ) + { echo "$as_me:$LINENO: WARNING: sys/types.h: present but cannot be compiled" >&5 +echo "$as_me: WARNING: sys/types.h: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: sys/types.h: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: sys/types.h: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: sys/types.h: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: sys/types.h: proceeding with the preprocessor's result" >&2;} + ( + cat <<\_ASBOX +## ------------------------------------ ## +## Report this to bug-autoconf at gnu.org. ## +## ------------------------------------ ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for sys/types.h" >&5 +echo $ECHO_N "checking for sys/types.h... $ECHO_C" >&6 +if test "${ac_cv_header_sys_types_h+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_header_sys_types_h=$ac_header_preproc +fi +echo "$as_me:$LINENO: result: $ac_cv_header_sys_types_h" >&5 +echo "${ECHO_T}$ac_cv_header_sys_types_h" >&6 + +fi +if test $ac_cv_header_sys_types_h = yes; then + INCLUDE_SYS_TYPES_H='#include ' +else + INCLUDE_SYS_TYPES_H='' +fi + + + +if test "${ac_cv_header_inttypes_h+set}" = set; then + echo "$as_me:$LINENO: checking for inttypes.h" >&5 +echo $ECHO_N "checking for inttypes.h... $ECHO_C" >&6 +if test "${ac_cv_header_inttypes_h+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: $ac_cv_header_inttypes_h" >&5 +echo "${ECHO_T}$ac_cv_header_inttypes_h" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking inttypes.h usability" >&5 +echo $ECHO_N "checking inttypes.h usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_header_compiler=no +fi +rm -f conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking inttypes.h presence" >&5 +echo $ECHO_N "checking inttypes.h presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc in + yes:no ) + { echo "$as_me:$LINENO: WARNING: inttypes.h: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: inttypes.h: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: inttypes.h: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: inttypes.h: proceeding with the preprocessor's result" >&2;} + ( + cat <<\_ASBOX +## ------------------------------------ ## +## Report this to bug-autoconf at gnu.org. ## +## ------------------------------------ ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; + no:yes ) + { echo "$as_me:$LINENO: WARNING: inttypes.h: present but cannot be compiled" >&5 +echo "$as_me: WARNING: inttypes.h: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: inttypes.h: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: inttypes.h: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: inttypes.h: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: inttypes.h: proceeding with the preprocessor's result" >&2;} + ( + cat <<\_ASBOX +## ------------------------------------ ## +## Report this to bug-autoconf at gnu.org. ## +## ------------------------------------ ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for inttypes.h" >&5 +echo $ECHO_N "checking for inttypes.h... $ECHO_C" >&6 +if test "${ac_cv_header_inttypes_h+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_header_inttypes_h=$ac_header_preproc +fi +echo "$as_me:$LINENO: result: $ac_cv_header_inttypes_h" >&5 +echo "${ECHO_T}$ac_cv_header_inttypes_h" >&6 + +fi +if test $ac_cv_header_inttypes_h = yes; then + INCLUDE_INTTYPES_H='#include ' +else + INCLUDE_INTTYPES_H='' +fi + + + + echo "$as_me:$LINENO: checking for pid_t" >&5 echo $ECHO_N "checking for pid_t... $ECHO_C" >&6 if test "${ac_cv_type_pid_t+set}" = set; then @@ -19469,31 +19760,29 @@ fi -echo "$as_me:$LINENO: checking whether the compiler implements namespaces" >&5 -echo $ECHO_N "checking whether the compiler implements namespaces... $ECHO_C" >&6 -if test "${ac_cv_cxx_namespaces+set}" = set; then +echo "$as_me:$LINENO: checking whether byte ordering is bigendian" >&5 +echo $ECHO_N "checking whether byte ordering is bigendian... $ECHO_C" >&6 +if test "${ac_cv_c_bigendian+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else - - - ac_ext=cc -ac_cpp='$CXXCPP $CPPFLAGS' -ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_cxx_compiler_gnu - - cat >conftest.$ac_ext <<_ACEOF + # See if sys/param.h defines the BYTE_ORDER macro. +cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ -namespace Outer { namespace Inner { int i = 0; }} +#include +#include + int main () { -using namespace Outer::Inner; return i; +#if !BYTE_ORDER || !BIG_ENDIAN || !LITTLE_ENDIAN + bogus endian macros +#endif + ; return 0; } @@ -19510,11 +19799,216 @@ ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then - ac_cv_cxx_namespaces=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - + # It does; now see whether it defined to BIG_ENDIAN or not. +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include + +int +main () +{ +#if BYTE_ORDER != BIG_ENDIAN + not big endian +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_c_bigendian=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_c_bigendian=no +fi +rm -f conftest.$ac_objext conftest.$ac_ext +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +# It does not; compile a test program. +if test "$cross_compiling" = yes; then + # try to guess the endianness by grepping values into an object file + ac_cv_c_bigendian=unknown + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +short ascii_mm[] = { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 }; +short ascii_ii[] = { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 }; +void _ascii () { char *s = (char *) ascii_mm; s = (char *) ascii_ii; } +short ebcdic_ii[] = { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 }; +short ebcdic_mm[] = { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 }; +void _ebcdic () { char *s = (char *) ebcdic_mm; s = (char *) ebcdic_ii; } +int +main () +{ + _ascii (); _ebcdic (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + if grep BIGenDianSyS conftest.$ac_objext >/dev/null ; then + ac_cv_c_bigendian=yes +fi +if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then + if test "$ac_cv_c_bigendian" = unknown; then + ac_cv_c_bigendian=no + else + # finding both strings is unlikely to happen, but who knows? + ac_cv_c_bigendian=unknown + fi +fi +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.$ac_objext conftest.$ac_ext +else + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +int +main () +{ + /* Are we little or big endian? From Harbison&Steele. */ + union + { + long l; + char c[sizeof (long)]; + } u; + u.l = 1; + exit (u.c[sizeof (long) - 1] == 1); +} +_ACEOF +rm -f conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_c_bigendian=no +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_c_bigendian=yes +fi +rm -f core core.* *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi +fi +rm -f conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_c_bigendian" >&5 +echo "${ECHO_T}$ac_cv_c_bigendian" >&6 +case $ac_cv_c_bigendian in + yes) + ENDIAN=big + ;; + no) + ENDIAN=little + ;; + *) + { { echo "$as_me:$LINENO: error: unknown endianness +presetting ac_cv_c_bigendian=no (or yes) will help" >&5 +echo "$as_me: error: unknown endianness +presetting ac_cv_c_bigendian=no (or yes) will help" >&2;} + { (exit 1); exit 1; }; } ;; +esac + + +echo "$as_me:$LINENO: checking whether the compiler implements namespaces" >&5 +echo $ECHO_N "checking whether the compiler implements namespaces... $ECHO_C" >&6 +if test "${ac_cv_cxx_namespaces+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + + + ac_ext=cc +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +namespace Outer { namespace Inner { int i = 0; }} +int +main () +{ +using namespace Outer::Inner; return i; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_cxx_namespaces=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + ac_cv_cxx_namespaces=no fi rm -f conftest.$ac_objext conftest.$ac_ext @@ -19598,13 +20092,12 @@ fi echo "$as_me:$LINENO: result: $ac_cv_cxx_have_std_ext_hash_map" >&5 echo "${ECHO_T}$ac_cv_cxx_have_std_ext_hash_map" >&6 - if test "$ac_cv_cxx_have_std_ext_hash_map" = yes; then - -cat >>confdefs.h <<\_ACEOF -#define HAVE_STD_EXT_HASH_MAP -_ACEOF - + HAVE_STD_EXT_HASH_MAP=0 + if test "$ac_cv_cxx_have_std_ext_hash_map" = yes + then + HAVE_STD_EXT_HASH_MAP=1 fi + echo "$as_me:$LINENO: checking whether the compiler has defining template class __gnu_cxx::hash_map" >&5 echo $ECHO_N "checking whether the compiler has defining template class __gnu_cxx::hash_map... $ECHO_C" >&6 if test "${ac_cv_cxx_have_gnu_ext_hash_map+set}" = set; then @@ -19667,13 +20160,12 @@ fi echo "$as_me:$LINENO: result: $ac_cv_cxx_have_gnu_ext_hash_map" >&5 echo "${ECHO_T}$ac_cv_cxx_have_gnu_ext_hash_map" >&6 - if test "$ac_cv_cxx_have_gnu_ext_hash_map" = yes; then - -cat >>confdefs.h <<\_ACEOF -#define HAVE_GNU_EXT_HASH_MAP -_ACEOF - + HAVE_GNU_EXT_HASH_MAP=0 + if test "$ac_cv_cxx_have_gnu_ext_hash_map" = yes + then + HAVE_GNU_EXT_HASH_MAP=1 fi + echo "$as_me:$LINENO: checking whether the compiler has defining template class ::hash_map" >&5 echo $ECHO_N "checking whether the compiler has defining template class ::hash_map... $ECHO_C" >&6 if test "${ac_cv_cxx_have_global_hash_map+set}" = set; then @@ -19733,13 +20225,12 @@ fi echo "$as_me:$LINENO: result: $ac_cv_cxx_have_global_hash_map" >&5 echo "${ECHO_T}$ac_cv_cxx_have_global_hash_map" >&6 - if test "$ac_cv_cxx_have_global_hash_map" = yes; then - -cat >>confdefs.h <<\_ACEOF -#define HAVE_GLOBAL_HASH_MAP -_ACEOF - + HAVE_GLOBAL_HASH_MAP=0 + if test "$ac_cv_cxx_have_global_hash_map" = yes + then + HAVE_GLOBAL_HASH_MAP=1 fi + echo "$as_me:$LINENO: checking whether the compiler has defining template class std::hash_set" >&5 echo $ECHO_N "checking whether the compiler has defining template class std::hash_set... $ECHO_C" >&6 if test "${ac_cv_cxx_have_std_ext_hash_set+set}" = set; then @@ -19802,13 +20293,12 @@ fi echo "$as_me:$LINENO: result: $ac_cv_cxx_have_std_ext_hash_set" >&5 echo "${ECHO_T}$ac_cv_cxx_have_std_ext_hash_set" >&6 - if test "$ac_cv_cxx_have_std_ext_hash_set" = yes; then - -cat >>confdefs.h <<\_ACEOF -#define HAVE_STD_EXT_HASH_SET -_ACEOF - + HAVE_STD_EXT_HASH_SET=0 + if test "$ac_cv_cxx_have_std_ext_hash_set" = yes + then + HAVE_STD_EXT_HASH_SET=1 fi + echo "$as_me:$LINENO: checking whether the compiler has defining template class __gnu_cxx::hash_set" >&5 echo $ECHO_N "checking whether the compiler has defining template class __gnu_cxx::hash_set... $ECHO_C" >&6 if test "${ac_cv_cxx_have_gnu_ext_hash_set+set}" = set; then @@ -19871,13 +20361,12 @@ fi echo "$as_me:$LINENO: result: $ac_cv_cxx_have_gnu_ext_hash_set" >&5 echo "${ECHO_T}$ac_cv_cxx_have_gnu_ext_hash_set" >&6 - if test "$ac_cv_cxx_have_gnu_ext_hash_set" = yes; then - -cat >>confdefs.h <<\_ACEOF -#define HAVE_GNU_EXT_HASH_SET -_ACEOF - + HAVE_GNU_EXT_HASH_SET=0 + if test "$ac_cv_cxx_have_gnu_ext_hash_set" = yes + then + HAVE_GNU_EXT_HASH_SET=1 fi + echo "$as_me:$LINENO: checking whether the compiler has defining template class ::hash_set" >&5 echo $ECHO_N "checking whether the compiler has defining template class ::hash_set... $ECHO_C" >&6 if test "${ac_cv_cxx_have_global_hash_set+set}" = set; then @@ -19937,130 +20426,11 @@ fi echo "$as_me:$LINENO: result: $ac_cv_cxx_have_global_hash_set" >&5 echo "${ECHO_T}$ac_cv_cxx_have_global_hash_set" >&6 - if test "$ac_cv_cxx_have_global_hash_set" = yes; then - -cat >>confdefs.h <<\_ACEOF -#define HAVE_GLOBAL_HASH_SET -_ACEOF - + HAVE_GLOBAL_HASH_SET=0 + if test "$ac_cv_cxx_have_global_hash_set" = yes + then + HAVE_GLOBAL_HASH_SET=1 fi -echo "$as_me:$LINENO: checking whether the compiler has ext/slist" >&5 -echo $ECHO_N "checking whether the compiler has ext/slist... $ECHO_C" >&6 -if test "${ac_cv_cxx_have_ext_slist+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - - - - ac_ext=cc -ac_cpp='$CXXCPP $CPPFLAGS' -ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_cxx_compiler_gnu - - cat >conftest.$ac_ext <<_ACEOF -#line $LINENO "configure" -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -#include -#ifdef HAVE_NAMESPACES -using namespace std; -#endif -int -main () -{ -slist s; return 0; - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_cv_cxx_have_ext_slist=std -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -ac_cv_cxx_have_ext_slist=no -fi -rm -f conftest.$ac_objext conftest.$ac_ext - cat >conftest.$ac_ext <<_ACEOF -#line $LINENO "configure" -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -#include -#ifdef HAVE_NAMESPACES -using namespace __gnu_cxx; -#endif -int -main () -{ -slist s; return 0; - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_cv_cxx_have_ext_slist=gnu -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -ac_cv_cxx_have_ext_slist=no -fi -rm -f conftest.$ac_objext conftest.$ac_ext - - ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - -fi -echo "$as_me:$LINENO: result: $ac_cv_cxx_have_ext_slist" >&5 -echo "${ECHO_T}$ac_cv_cxx_have_ext_slist" >&6 -if test "$ac_cv_cxx_have_ext_slist" = std; then - -cat >>confdefs.h <<\_ACEOF -#define HAVE_EXT_SLIST std -_ACEOF - -fi -if test "$ac_cv_cxx_have_ext_slist" = gnu; then - -cat >>confdefs.h <<\_ACEOF -#define HAVE_EXT_SLIST gnu -_ACEOF - -fi echo "$as_me:$LINENO: checking whether the compiler has the standard iterator" >&5 echo $ECHO_N "checking whether the compiler has the standard iterator... $ECHO_C" >&6 @@ -20125,12 +20495,10 @@ fi echo "$as_me:$LINENO: result: $ac_cv_cxx_have_std_iterator" >&5 echo "${ECHO_T}$ac_cv_cxx_have_std_iterator" >&6 -if test "$ac_cv_cxx_have_std_iterator" = yes; then - -cat >>confdefs.h <<\_ACEOF -#define HAVE_STD_ITERATOR -_ACEOF - +HAVE_STD_ITERATOR=0 +if test "$ac_cv_cxx_have_std_iterator" = yes +then + HAVE_STD_ITERATOR=1 fi echo "$as_me:$LINENO: checking whether the compiler has the bidirectional iterator" >&5 @@ -20196,12 +20564,10 @@ fi echo "$as_me:$LINENO: result: $ac_cv_cxx_have_bi_iterator" >&5 echo "${ECHO_T}$ac_cv_cxx_have_bi_iterator" >&6 -if test "$ac_cv_cxx_have_bi_iterator" = yes; then - -cat >>confdefs.h <<\_ACEOF -#define HAVE_BI_ITERATOR -_ACEOF - +HAVE_BI_ITERATOR=0 +if test "$ac_cv_cxx_have_bi_iterator" = yes +then + HAVE_BI_ITERATOR=1 fi echo "$as_me:$LINENO: checking whether the compiler has forward iterators" >&5 @@ -20267,12 +20633,10 @@ fi echo "$as_me:$LINENO: result: $ac_cv_cxx_have_fwd_iterator" >&5 echo "${ECHO_T}$ac_cv_cxx_have_fwd_iterator" >&6 -if test "$ac_cv_cxx_have_fwd_iterator" = yes; then - -cat >>confdefs.h <<\_ACEOF -#define HAVE_FWD_ITERATOR -_ACEOF - +HAVE_FWD_ITERATOR=0 +if test "$ac_cv_cxx_have_fwd_iterator" = yes +then + HAVE_FWD_ITERATOR=1 fi @@ -21234,7 +21598,8 @@ -for ac_func in getcwd gettimeofday strdup strtoq strtoll + +for ac_func in getcwd gettimeofday strdup strtoq strtoll backtrace do as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` echo "$as_me:$LINENO: checking for $ac_func" >&5 @@ -21476,28 +21841,95 @@ then if test -d /home/vadve/shared/benchmarks/speccpu2000/benchspec then - SPEC_ROOT=/home/vadve/shared/benchmarks/speccpu2000/benchspec + SPEC2000_ROOT=/home/vadve/shared/benchmarks/speccpu2000/benchspec + + USE_SPEC2000=USE_SPEC2000=1 + + else + USE_SPEC2000= + + + fi +else + if test ${enableval} = "" + then + SPEC2000_ROOT=/home/vadve/shared/benchmarks/speccpu2000/benchspec - USE_SPEC=USE_SPEC=1 + else + SPEC2000_ROOT=${enableval} + + fi + USE_SPEC2000=USE_SPEC2000=1 + +fi + +# Check whether --enable-spec95 or --disable-spec95 was given. +if test "${enable_spec95+set}" = set; then + enableval="$enable_spec95" + +else + enableval=no +fi; +if test ${enableval} = "no" +then + if test -d /home/vadve/shared/benchmarks/spec95/benchspec + then + SPEC95_ROOT=/home/vadve/shared/benchmarks/spec95/benchspec + + USE_SPEC95=USE_SPEC95=1 else - USE_SPEC= + USE_SPEC95= fi else if test ${enableval} = "" then - SPEC_ROOT=/home/vadve/shared/benchmarks/speccpu2000/benchspec + SPEC95_ROOT=/home/vadve/shared/benchmarks/spec95/benchspec else - SPEC_ROOT=${enableval} + SPEC95_ROOT=${enableval} fi - USE_SPEC=USE_SPEC=1 + USE_SPEC95=USE_SPEC95=1 fi +# Check whether --enable-povray or --disable-povray was given. +if test "${enable_povray+set}" = set; then + enableval="$enable_povray" + +else + enableval=no +fi; +if test ${enableval} = "no" +then + if test -d /home/vadve/shared/benchmarks/povray31 + then + POVRAY_ROOT=/home/vadve/shared/benchmarks/povray31 + + USE_POVRAY=USE_POVRAY=1 + + else + USE_POVRAY= + + + fi +else + if test ${enableval} = "" + then + POVRAY_ROOT=/home/vadve/shared/benchmarks/povray31 + + else + POVRAY_ROOT=${enableval} + + fi + USE_POVRAY=USE_POVRAY=1 + +fi + + # Check whether --enable-precompiled_bytecode or --disable-precompiled_bytecode was given. if test "${enable_precompiled_bytecode+set}" = set; then enableval="$enable_precompiled_bytecode" @@ -21595,10 +22027,10 @@ fi rm conftest.c llvmcc1path=`"$LLVM_GCC_CHECK" --print-prog-name=cc1` - LLVMCC1=$llvmcc1path + LLVMCC1=$llvmcc1path llvmcc1pluspath=`"$LLVM_GCC_CHECK" --print-prog-name=cc1plus` - LLVMCC1PLUS=$llvmcc1pluspath + LLVMCC1PLUS=$llvmcc1pluspath fi echo "$as_me:$LINENO: result: $LLVM_GCC_SANE" >&5 @@ -21630,7 +22062,20 @@ fi; - ac_config_files="$ac_config_files Makefile.config" +echo "$as_me:$LINENO: checking for shared library suffix" >&5 +echo $ECHO_N "checking for shared library suffix... $ECHO_C" >&6 +eval "SHLIBEXT=$shrext" +echo "$as_me:$LINENO: result: $SHLIBEXT" >&5 +echo "${ECHO_T}$SHLIBEXT" >&6 +SHLIBEXT=$SHLIBEXT + + +cat >>confdefs.h <<_ACEOF +#define SHLIBEXT "$SHLIBEXT" +_ACEOF + + + ac_config_files="$ac_config_files Makefile.config include/Support/DataTypes.h include/Support/ThreadSupport.h include/Support/hash_map include/Support/hash_set include/Support/iterator" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure @@ -22166,7 +22611,6 @@ ${srcdir}/autoconf/mkinstalldirs `dirname test/Programs/Makefile.programs` ${srcdir}/autoconf/mkinstalldirs `dirname test/Programs/TEST.aa.Makefile` ${srcdir}/autoconf/mkinstalldirs `dirname test/Programs/TEST.dsgraph.report` -${srcdir}/autoconf/mkinstalldirs `dirname test/Programs/TEST.micro.report` ${srcdir}/autoconf/mkinstalldirs `dirname test/Programs/TEST.aa.report` ${srcdir}/autoconf/mkinstalldirs `dirname test/Programs/TEST.example.Makefile` ${srcdir}/autoconf/mkinstalldirs `dirname test/Programs/TEST.nightly.Makefile` @@ -22177,10 +22621,12 @@ ${srcdir}/autoconf/mkinstalldirs `dirname test/Programs/TEST.jit.report` ${srcdir}/autoconf/mkinstalldirs `dirname test/Programs/TEST.typesafe.Makefile` ${srcdir}/autoconf/mkinstalldirs `dirname test/Programs/TEST.dsgraph.gnuplot` -${srcdir}/autoconf/mkinstalldirs `dirname test/Programs/TEST.micro.Makefile` +${srcdir}/autoconf/mkinstalldirs `dirname test/Programs/TEST.vtl.Makefile` ${srcdir}/autoconf/mkinstalldirs `dirname test/Programs/External/Makefile` ${srcdir}/autoconf/mkinstalldirs `dirname test/Programs/External/SPEC/Makefile` ${srcdir}/autoconf/mkinstalldirs `dirname test/Programs/External/SPEC/Makefile.spec` +${srcdir}/autoconf/mkinstalldirs `dirname test/Programs/External/SPEC/Makefile.spec2000` +${srcdir}/autoconf/mkinstalldirs `dirname test/Programs/External/SPEC/Makefile.spec95` ${srcdir}/autoconf/mkinstalldirs `dirname test/Programs/MultiSource/Makefile` ${srcdir}/autoconf/mkinstalldirs `dirname test/Programs/MultiSource/Makefile.multisrc` ${srcdir}/autoconf/mkinstalldirs `dirname test/Programs/MultiSource/Benchmarks/FreeBench/analyzer/test.in` @@ -22198,6 +22644,7 @@ ${srcdir}/autoconf/mkinstalldirs `dirname test/Programs/MultiSource/Benchmarks/FreeBench/pifft/test.in` ${srcdir}/autoconf/mkinstalldirs `dirname test/Programs/SingleSource/Makefile` ${srcdir}/autoconf/mkinstalldirs `dirname test/Programs/SingleSource/Makefile.singlesrc` +${srcdir}/autoconf/mkinstalldirs `dirname test/Programs/SingleSource/UnitTests/SetjmpLongjmp/Makefile` ${srcdir}/autoconf/mkinstalldirs `dirname tools/Makefile` ${srcdir}/autoconf/mkinstalldirs `dirname utils/Makefile` ${srcdir}/autoconf/mkinstalldirs `dirname projects/Makefile` @@ -22212,6 +22659,11 @@ case "$ac_config_target" in # Handling of arguments. "Makefile.config" ) CONFIG_FILES="$CONFIG_FILES Makefile.config" ;; + "include/Support/DataTypes.h" ) CONFIG_FILES="$CONFIG_FILES include/Support/DataTypes.h" ;; + "include/Support/ThreadSupport.h" ) CONFIG_FILES="$CONFIG_FILES include/Support/ThreadSupport.h" ;; + "include/Support/hash_map" ) CONFIG_FILES="$CONFIG_FILES include/Support/hash_map" ;; + "include/Support/hash_set" ) CONFIG_FILES="$CONFIG_FILES include/Support/hash_set" ;; + "include/Support/iterator" ) CONFIG_FILES="$CONFIG_FILES include/Support/iterator" ;; "Makefile" ) CONFIG_COMMANDS="$CONFIG_COMMANDS Makefile" ;; "Makefile.common" ) CONFIG_COMMANDS="$CONFIG_COMMANDS Makefile.common" ;; "lib/Makefile" ) CONFIG_COMMANDS="$CONFIG_COMMANDS lib/Makefile" ;; @@ -22224,7 +22676,6 @@ "test/Programs/Makefile.programs" ) CONFIG_COMMANDS="$CONFIG_COMMANDS test/Programs/Makefile.programs" ;; "test/Programs/TEST.aa.Makefile" ) CONFIG_COMMANDS="$CONFIG_COMMANDS test/Programs/TEST.aa.Makefile" ;; "test/Programs/TEST.dsgraph.report" ) CONFIG_COMMANDS="$CONFIG_COMMANDS test/Programs/TEST.dsgraph.report" ;; - "test/Programs/TEST.micro.report" ) CONFIG_COMMANDS="$CONFIG_COMMANDS test/Programs/TEST.micro.report" ;; "test/Programs/TEST.aa.report" ) CONFIG_COMMANDS="$CONFIG_COMMANDS test/Programs/TEST.aa.report" ;; "test/Programs/TEST.example.Makefile" ) CONFIG_COMMANDS="$CONFIG_COMMANDS test/Programs/TEST.example.Makefile" ;; "test/Programs/TEST.nightly.Makefile" ) CONFIG_COMMANDS="$CONFIG_COMMANDS test/Programs/TEST.nightly.Makefile" ;; @@ -22235,10 +22686,12 @@ "test/Programs/TEST.jit.report" ) CONFIG_COMMANDS="$CONFIG_COMMANDS test/Programs/TEST.jit.report" ;; "test/Programs/TEST.typesafe.Makefile" ) CONFIG_COMMANDS="$CONFIG_COMMANDS test/Programs/TEST.typesafe.Makefile" ;; "test/Programs/TEST.dsgraph.gnuplot" ) CONFIG_COMMANDS="$CONFIG_COMMANDS test/Programs/TEST.dsgraph.gnuplot" ;; - "test/Programs/TEST.micro.Makefile" ) CONFIG_COMMANDS="$CONFIG_COMMANDS test/Programs/TEST.micro.Makefile" ;; + "test/Programs/TEST.vtl.Makefile" ) CONFIG_COMMANDS="$CONFIG_COMMANDS test/Programs/TEST.vtl.Makefile" ;; "test/Programs/External/Makefile" ) CONFIG_COMMANDS="$CONFIG_COMMANDS test/Programs/External/Makefile" ;; "test/Programs/External/SPEC/Makefile" ) CONFIG_COMMANDS="$CONFIG_COMMANDS test/Programs/External/SPEC/Makefile" ;; "test/Programs/External/SPEC/Makefile.spec" ) CONFIG_COMMANDS="$CONFIG_COMMANDS test/Programs/External/SPEC/Makefile.spec" ;; + "test/Programs/External/SPEC/Makefile.spec2000" ) CONFIG_COMMANDS="$CONFIG_COMMANDS test/Programs/External/SPEC/Makefile.spec2000" ;; + "test/Programs/External/SPEC/Makefile.spec95" ) CONFIG_COMMANDS="$CONFIG_COMMANDS test/Programs/External/SPEC/Makefile.spec95" ;; "test/Programs/MultiSource/Makefile" ) CONFIG_COMMANDS="$CONFIG_COMMANDS test/Programs/MultiSource/Makefile" ;; "test/Programs/MultiSource/Makefile.multisrc" ) CONFIG_COMMANDS="$CONFIG_COMMANDS test/Programs/MultiSource/Makefile.multisrc" ;; "test/Programs/MultiSource/Benchmarks/FreeBench/analyzer/test.in" ) CONFIG_COMMANDS="$CONFIG_COMMANDS test/Programs/MultiSource/Benchmarks/FreeBench/analyzer/test.in" ;; @@ -22256,6 +22709,7 @@ "test/Programs/MultiSource/Benchmarks/FreeBench/pifft/test.in" ) CONFIG_COMMANDS="$CONFIG_COMMANDS test/Programs/MultiSource/Benchmarks/FreeBench/pifft/test.in" ;; "test/Programs/SingleSource/Makefile" ) CONFIG_COMMANDS="$CONFIG_COMMANDS test/Programs/SingleSource/Makefile" ;; "test/Programs/SingleSource/Makefile.singlesrc" ) CONFIG_COMMANDS="$CONFIG_COMMANDS test/Programs/SingleSource/Makefile.singlesrc" ;; + "test/Programs/SingleSource/UnitTests/SetjmpLongjmp/Makefile" ) CONFIG_COMMANDS="$CONFIG_COMMANDS test/Programs/SingleSource/UnitTests/SetjmpLongjmp/Makefile" ;; "tools/Makefile" ) CONFIG_COMMANDS="$CONFIG_COMMANDS tools/Makefile" ;; "utils/Makefile" ) CONFIG_COMMANDS="$CONFIG_COMMANDS utils/Makefile" ;; "projects/Makefile" ) CONFIG_COMMANDS="$CONFIG_COMMANDS projects/Makefile" ;; @@ -22397,13 +22851,31 @@ s, at LIBTOOL@,$LIBTOOL,;t t s, at DOT@,$DOT,;t t s, at ETAGS@,$ETAGS,;t t +s, at ETAGSFLAGS@,$ETAGSFLAGS,;t t s, at PYTHON@,$PYTHON,;t t s, at QMTEST@,$QMTEST,;t t +s, at HAVE_PTHREAD_MUTEX_LOCK@,$HAVE_PTHREAD_MUTEX_LOCK,;t t +s, at INCLUDE_SYS_TYPES_H@,$INCLUDE_SYS_TYPES_H,;t t +s, at INCLUDE_INTTYPES_H@,$INCLUDE_INTTYPES_H,;t t +s, at ENDIAN@,$ENDIAN,;t t +s, at HAVE_STD_EXT_HASH_MAP@,$HAVE_STD_EXT_HASH_MAP,;t t +s, at HAVE_GNU_EXT_HASH_MAP@,$HAVE_GNU_EXT_HASH_MAP,;t t +s, at HAVE_GLOBAL_HASH_MAP@,$HAVE_GLOBAL_HASH_MAP,;t t +s, at HAVE_STD_EXT_HASH_SET@,$HAVE_STD_EXT_HASH_SET,;t t +s, at HAVE_GNU_EXT_HASH_SET@,$HAVE_GNU_EXT_HASH_SET,;t t +s, at HAVE_GLOBAL_HASH_SET@,$HAVE_GLOBAL_HASH_SET,;t t +s, at HAVE_STD_ITERATOR@,$HAVE_STD_ITERATOR,;t t +s, at HAVE_BI_ITERATOR@,$HAVE_BI_ITERATOR,;t t +s, at HAVE_FWD_ITERATOR@,$HAVE_FWD_ITERATOR,;t t s, at ALLOCA@,$ALLOCA,;t t s, at MMAP_FILE@,$MMAP_FILE,;t t s, at ENABLE_OPTIMIZED@,$ENABLE_OPTIMIZED,;t t -s, at SPEC_ROOT@,$SPEC_ROOT,;t t -s, at USE_SPEC@,$USE_SPEC,;t t +s, at SPEC2000_ROOT@,$SPEC2000_ROOT,;t t +s, at USE_SPEC2000@,$USE_SPEC2000,;t t +s, at SPEC95_ROOT@,$SPEC95_ROOT,;t t +s, at USE_SPEC95@,$USE_SPEC95,;t t +s, at POVRAY_ROOT@,$POVRAY_ROOT,;t t +s, at USE_POVRAY@,$USE_POVRAY,;t t s, at UPB@,$UPB,;t t s, at DISABLE_LLC_DIFFS@,$DISABLE_LLC_DIFFS,;t t s, at JIT@,$JIT,;t t @@ -22411,6 +22883,7 @@ s, at LLVMCC1PLUS@,$LLVMCC1PLUS,;t t s, at BCR@,$BCR,;t t s, at PAPIDIR@,$PAPIDIR,;t t +s, at SHLIBEXT@,$SHLIBEXT,;t t s, at LIBOBJS@,$LIBOBJS,;t t s, at LTLIBOBJS@,$LTLIBOBJS,;t t CEOF @@ -22908,7 +23381,6 @@ test/Programs/Makefile.programs ) ${SHELL} ${srcdir}/autoconf/install-sh -c ${srcdir}/test/Programs/Makefile.programs test/Programs/Makefile.programs ;; test/Programs/TEST.aa.Makefile ) ${SHELL} ${srcdir}/autoconf/install-sh -c ${srcdir}/test/Programs/TEST.aa.Makefile test/Programs/TEST.aa.Makefile ;; test/Programs/TEST.dsgraph.report ) ${SHELL} ${srcdir}/autoconf/install-sh -c ${srcdir}/test/Programs/TEST.dsgraph.report test/Programs/TEST.dsgraph.report ;; - test/Programs/TEST.micro.report ) ${SHELL} ${srcdir}/autoconf/install-sh -c ${srcdir}/test/Programs/TEST.micro.report test/Programs/TEST.micro.report ;; test/Programs/TEST.aa.report ) ${SHELL} ${srcdir}/autoconf/install-sh -c ${srcdir}/test/Programs/TEST.aa.report test/Programs/TEST.aa.report ;; test/Programs/TEST.example.Makefile ) ${SHELL} ${srcdir}/autoconf/install-sh -c ${srcdir}/test/Programs/TEST.example.Makefile test/Programs/TEST.example.Makefile ;; test/Programs/TEST.nightly.Makefile ) ${SHELL} ${srcdir}/autoconf/install-sh -c ${srcdir}/test/Programs/TEST.nightly.Makefile test/Programs/TEST.nightly.Makefile ;; @@ -22919,10 +23391,12 @@ test/Programs/TEST.jit.report ) ${SHELL} ${srcdir}/autoconf/install-sh -c ${srcdir}/test/Programs/TEST.jit.report test/Programs/TEST.jit.report ;; test/Programs/TEST.typesafe.Makefile ) ${SHELL} ${srcdir}/autoconf/install-sh -c ${srcdir}/test/Programs/TEST.typesafe.Makefile test/Programs/TEST.typesafe.Makefile ;; test/Programs/TEST.dsgraph.gnuplot ) ${SHELL} ${srcdir}/autoconf/install-sh -c ${srcdir}/test/Programs/TEST.dsgraph.gnuplot test/Programs/TEST.dsgraph.gnuplot ;; - test/Programs/TEST.micro.Makefile ) ${SHELL} ${srcdir}/autoconf/install-sh -c ${srcdir}/test/Programs/TEST.micro.Makefile test/Programs/TEST.micro.Makefile ;; + test/Programs/TEST.vtl.Makefile ) ${SHELL} ${srcdir}/autoconf/install-sh -c ${srcdir}/test/Programs/TEST.vtl.Makefile test/Programs/TEST.vtl.Makefile ;; test/Programs/External/Makefile ) ${SHELL} ${srcdir}/autoconf/install-sh -c ${srcdir}/test/Programs/External/Makefile test/Programs/External/Makefile ;; test/Programs/External/SPEC/Makefile ) ${SHELL} ${srcdir}/autoconf/install-sh -c ${srcdir}/test/Programs/External/SPEC/Makefile test/Programs/External/SPEC/Makefile ;; test/Programs/External/SPEC/Makefile.spec ) ${SHELL} ${srcdir}/autoconf/install-sh -c ${srcdir}/test/Programs/External/SPEC/Makefile.spec test/Programs/External/SPEC/Makefile.spec ;; + test/Programs/External/SPEC/Makefile.spec2000 ) ${SHELL} ${srcdir}/autoconf/install-sh -c ${srcdir}/test/Programs/External/SPEC/Makefile.spec2000 test/Programs/External/SPEC/Makefile.spec2000 ;; + test/Programs/External/SPEC/Makefile.spec95 ) ${SHELL} ${srcdir}/autoconf/install-sh -c ${srcdir}/test/Programs/External/SPEC/Makefile.spec95 test/Programs/External/SPEC/Makefile.spec95 ;; test/Programs/MultiSource/Makefile ) ${SHELL} ${srcdir}/autoconf/install-sh -c ${srcdir}/test/Programs/MultiSource/Makefile test/Programs/MultiSource/Makefile ;; test/Programs/MultiSource/Makefile.multisrc ) ${SHELL} ${srcdir}/autoconf/install-sh -c ${srcdir}/test/Programs/MultiSource/Makefile.multisrc test/Programs/MultiSource/Makefile.multisrc ;; test/Programs/MultiSource/Benchmarks/FreeBench/analyzer/test.in ) ${SHELL} ${srcdir}/autoconf/install-sh -c ${srcdir}/test/Programs/MultiSource/Benchmarks/FreeBench/analyzer/test.in test/Programs/MultiSource/Benchmarks/FreeBench/analyzer/test.in ;; @@ -22940,6 +23414,7 @@ test/Programs/MultiSource/Benchmarks/FreeBench/pifft/test.in ) ${SHELL} ${srcdir}/autoconf/install-sh -c ${srcdir}/test/Programs/MultiSource/Benchmarks/FreeBench/pifft/test.in test/Programs/MultiSource/Benchmarks/FreeBench/pifft/test.in ;; test/Programs/SingleSource/Makefile ) ${SHELL} ${srcdir}/autoconf/install-sh -c ${srcdir}/test/Programs/SingleSource/Makefile test/Programs/SingleSource/Makefile ;; test/Programs/SingleSource/Makefile.singlesrc ) ${SHELL} ${srcdir}/autoconf/install-sh -c ${srcdir}/test/Programs/SingleSource/Makefile.singlesrc test/Programs/SingleSource/Makefile.singlesrc ;; + test/Programs/SingleSource/UnitTests/SetjmpLongjmp/Makefile ) ${SHELL} ${srcdir}/autoconf/install-sh -c ${srcdir}/test/Programs/SingleSource/UnitTests/SetjmpLongjmp/Makefile test/Programs/SingleSource/UnitTests/SetjmpLongjmp/Makefile ;; tools/Makefile ) ${SHELL} ${srcdir}/autoconf/install-sh -c ${srcdir}/tools/Makefile tools/Makefile ;; utils/Makefile ) ${SHELL} ${srcdir}/autoconf/install-sh -c ${srcdir}/utils/Makefile utils/Makefile ;; projects/Makefile ) ${SHELL} ${srcdir}/autoconf/install-sh -c ${srcdir}/projects/Makefile projects/Makefile ;; @@ -23136,3 +23611,4 @@ { echo "$as_me:$LINENO: WARNING: ***** but you should be able to build the llvm tools." >&5 echo "$as_me: WARNING: ***** but you should be able to build the llvm tools." >&2;} fi + From brukman at cs.uiuc.edu Mon Mar 1 17:56:01 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Mar 1 17:56:01 2004 Subject: [llvm-commits] [parallel] CVS: llvm/autoconf/AutoRegen.sh acinclude.m4 configure.ac Message-ID: <200403012355.RAA23507@zion.cs.uiuc.edu> Changes in directory llvm/autoconf: AutoRegen.sh added (r1.2.2.1) acinclude.m4 updated: 1.2 -> 1.2.2.1 configure.ac updated: 1.66 -> 1.66.2.1 --- Log message: Merge from trunk --- Diffs of the changes: (+174 -81) Index: llvm/autoconf/AutoRegen.sh diff -c /dev/null llvm/autoconf/AutoRegen.sh:1.2.2.1 *** /dev/null Mon Mar 1 17:55:36 2004 --- llvm/autoconf/AutoRegen.sh Mon Mar 1 17:55:26 2004 *************** *** 0 **** --- 1,21 ---- + #!/bin/sh + die () { + echo "$@" 1>&2 + exit 1 + } + test -d autoconf && test -f autoconf/configure.ac && cd autoconf + [ -f configure.ac ] || die "Can't find 'autoconf' dir; please cd into it first" + echo "Regenerating aclocal.m4 with aclocal" + aclocal || die "aclocal failed" + autoconf --version | egrep '2\.5[0-9]' > /dev/null + if test $? -ne 0 + then + die "Your autoconf was not detected as being 2.5x" + fi + echo "Note: Warnings about 'AC_CONFIG_SUBDIRS: you should use literals' are ok" + echo "Regenerating configure with autoconf 2.5x" + autoconf -o ../configure configure.ac || die "autoconf failed" + cd .. + echo "Regenerating config.h.in with autoheader 2.5x" + autoheader -I autoconf autoconf/configure.ac || die "autoheader failed" + exit 0 Index: llvm/autoconf/acinclude.m4 diff -u llvm/autoconf/acinclude.m4:1.2 llvm/autoconf/acinclude.m4:1.2.2.1 --- llvm/autoconf/acinclude.m4:1.2 Mon Jan 12 10:14:54 2004 +++ llvm/autoconf/acinclude.m4 Mon Mar 1 17:55:26 2004 @@ -5888,10 +5888,8 @@ fi ]) -# # Check for hash_map extension. This is from # http://www.gnu.org/software/ac-archive/htmldoc/ac_cxx_have_ext_hash_map.html -# AC_DEFUN([AC_CXX_HAVE_STD_EXT_HASH_MAP], [AC_CACHE_CHECK([whether the compiler has defining template class std::hash_map], ac_cv_cxx_have_std_ext_hash_map, @@ -5904,9 +5902,12 @@ #endif],[hash_map t;], [ac_cv_cxx_have_std_ext_hash_map=yes], [ac_cv_cxx_have_std_ext_hash_map=no]) AC_LANG_RESTORE]) - if test "$ac_cv_cxx_have_std_ext_hash_map" = yes; then - AC_DEFINE(HAVE_STD_EXT_HASH_MAP,,[Define if the compiler has a header that defines template class std::hash_map.]) - fi]) + HAVE_STD_EXT_HASH_MAP=0 + if test "$ac_cv_cxx_have_std_ext_hash_map" = yes + then + HAVE_STD_EXT_HASH_MAP=1 + fi + AC_SUBST(HAVE_STD_EXT_HASH_MAP)]) AC_DEFUN([AC_CXX_HAVE_GNU_EXT_HASH_MAP], [AC_CACHE_CHECK([whether the compiler has defining template class __gnu_cxx::hash_map], @@ -5920,9 +5921,12 @@ #endif],[hash_map t; ], [ac_cv_cxx_have_gnu_ext_hash_map=yes],[ac_cv_cxx_have_gnu_ext_hash_map=no]) AC_LANG_RESTORE]) - if test "$ac_cv_cxx_have_gnu_ext_hash_map" = yes; then - AC_DEFINE(HAVE_GNU_EXT_HASH_MAP,,[Define if the compiler has a header that defines template class __gnu_cxx::hash_map.]) - fi]) + HAVE_GNU_EXT_HASH_MAP=0 + if test "$ac_cv_cxx_have_gnu_ext_hash_map" = yes + then + HAVE_GNU_EXT_HASH_MAP=1 + fi + AC_SUBST(HAVE_GNU_EXT_HASH_MAP)]) AC_DEFUN([AC_CXX_HAVE_GLOBAL_HASH_MAP], [AC_CACHE_CHECK([whether the compiler has defining template class ::hash_map], @@ -5933,18 +5937,20 @@ AC_TRY_COMPILE([#include ],[hash_map t; ], [ac_cv_cxx_have_global_hash_map=yes], [ac_cv_cxx_have_global_hash_map=no]) AC_LANG_RESTORE]) - if test "$ac_cv_cxx_have_global_hash_map" = yes; then - AC_DEFINE(HAVE_GLOBAL_HASH_MAP,,[Define if the compiler has a header that defines template class ::hash_map.]) - fi]) + HAVE_GLOBAL_HASH_MAP=0 + if test "$ac_cv_cxx_have_global_hash_map" = yes + then + HAVE_GLOBAL_HASH_MAP=1 + fi + AC_SUBST(HAVE_GLOBAL_HASH_MAP)]) AC_DEFUN([AC_CXX_HAVE_HASH_MAP], [AC_CXX_HAVE_STD_EXT_HASH_MAP AC_CXX_HAVE_GNU_EXT_HASH_MAP AC_CXX_HAVE_GLOBAL_HASH_MAP]) -# + # Check for hash_set extension. This is modified from # http://www.gnu.org/software/ac-archive/htmldoc/ac_cxx_have_ext_hash_set.html -# AC_DEFUN([AC_CXX_HAVE_STD_EXT_HASH_SET], [AC_CACHE_CHECK([whether the compiler has defining template class std::hash_set], ac_cv_cxx_have_std_ext_hash_set, @@ -5957,9 +5963,12 @@ #endif],[hash_set t; ], [ac_cv_cxx_have_std_ext_hash_set=yes], [ac_cv_cxx_have_std_ext_hash_set=no]) AC_LANG_RESTORE]) - if test "$ac_cv_cxx_have_std_ext_hash_set" = yes; then - AC_DEFINE(HAVE_STD_EXT_HASH_SET,,[Define if the compiler has a header that defines template class std::hash_set.]) - fi]) + HAVE_STD_EXT_HASH_SET=0 + if test "$ac_cv_cxx_have_std_ext_hash_set" = yes + then + HAVE_STD_EXT_HASH_SET=1 + fi + AC_SUBST(HAVE_STD_EXT_HASH_SET)]) AC_DEFUN([AC_CXX_HAVE_GNU_EXT_HASH_SET], [AC_CACHE_CHECK( @@ -5974,9 +5983,12 @@ #endif],[hash_set t; ], [ac_cv_cxx_have_gnu_ext_hash_set=yes], [ac_cv_cxx_have_gnu_ext_hash_set=no]) AC_LANG_RESTORE]) - if test "$ac_cv_cxx_have_gnu_ext_hash_set" = yes; then - AC_DEFINE(HAVE_GNU_EXT_HASH_SET,,[Define if the compiler has a header that defines template class __gnu_cxx::hash_set.]) - fi]) + HAVE_GNU_EXT_HASH_SET=0 + if test "$ac_cv_cxx_have_gnu_ext_hash_set" = yes + then + HAVE_GNU_EXT_HASH_SET=1 + fi + AC_SUBST(HAVE_GNU_EXT_HASH_SET)]) AC_DEFUN([AC_CXX_HAVE_GLOBAL_HASH_SET], [AC_CACHE_CHECK([whether the compiler has defining template class ::hash_set], @@ -5987,19 +5999,20 @@ AC_TRY_COMPILE([#include ],[hash_set t; return 0;], [ac_cv_cxx_have_global_hash_set=yes], [ac_cv_cxx_have_global_hash_set=no]) AC_LANG_RESTORE]) - if test "$ac_cv_cxx_have_global_hash_set" = yes; then - AC_DEFINE(HAVE_GLOBAL_HASH_SET,,[Define if the compiler has a header that defines template class ::hash_set.]) - fi]) + HAVE_GLOBAL_HASH_SET=0 + if test "$ac_cv_cxx_have_global_hash_set" = yes + then + HAVE_GLOBAL_HASH_SET=1 + fi + AC_SUBST(HAVE_GLOBAL_HASH_SET)]) AC_DEFUN([AC_CXX_HAVE_HASH_SET], [AC_CXX_HAVE_STD_EXT_HASH_SET AC_CXX_HAVE_GNU_EXT_HASH_SET AC_CXX_HAVE_GLOBAL_HASH_SET]) -# # Check for standard iterator extension. This is modified from # http://www.gnu.org/software/ac-archive/htmldoc/ac_cxx_have_ext_hash_set.html -# AC_DEFUN([AC_CXX_HAVE_STD_ITERATOR], [AC_CACHE_CHECK(whether the compiler has the standard iterator, ac_cv_cxx_have_std_iterator, @@ -6013,10 +6026,12 @@ ac_cv_cxx_have_std_iterator=yes, ac_cv_cxx_have_std_iterator=no) AC_LANG_RESTORE ]) -if test "$ac_cv_cxx_have_std_iterator" = yes; then - AC_DEFINE(HAVE_STD_ITERATOR,,[define if the compiler has STL iterators]) +HAVE_STD_ITERATOR=0 +if test "$ac_cv_cxx_have_std_iterator" = yes +then + HAVE_STD_ITERATOR=1 fi -]) +AC_SUBST(HAVE_STD_ITERATOR)]) # # Check for bidirectional iterator extension. This is modified from @@ -6035,15 +6050,15 @@ ac_cv_cxx_have_bi_iterator=yes, ac_cv_cxx_have_bi_iterator=no) AC_LANG_RESTORE ]) -if test "$ac_cv_cxx_have_bi_iterator" = yes; then - AC_DEFINE(HAVE_BI_ITERATOR,,[define if the compiler has bidirectional iterator]) +HAVE_BI_ITERATOR=0 +if test "$ac_cv_cxx_have_bi_iterator" = yes +then + HAVE_BI_ITERATOR=1 fi -]) +AC_SUBST(HAVE_BI_ITERATOR)]) -# # Check for forward iterator extension. This is modified from # http://www.gnu.org/software/ac-archive/htmldoc/ac_cxx_have_ext_hash_set.html -# AC_DEFUN([AC_CXX_HAVE_FWD_ITERATOR], [AC_CACHE_CHECK(whether the compiler has forward iterators, ac_cv_cxx_have_fwd_iterator, @@ -6057,41 +6072,12 @@ ac_cv_cxx_have_fwd_iterator=yes, ac_cv_cxx_have_fwd_iterator=no) AC_LANG_RESTORE ]) -if test "$ac_cv_cxx_have_fwd_iterator" = yes; then - AC_DEFINE(HAVE_FWD_ITERATOR,,[define if the compiler has STL iterators]) -fi -]) - -# -# Check for slist extension. This is from -# http://www.gnu.org/software/ac-archive/htmldoc/ac_cxx_have_ext_slist.html -# -AC_DEFUN([AC_CXX_HAVE_EXT_SLIST], -[AC_CACHE_CHECK(whether the compiler has ext/slist, -ac_cv_cxx_have_ext_slist, -[AC_REQUIRE([AC_CXX_NAMESPACES]) - AC_LANG_SAVE - AC_LANG_CPLUSPLUS - AC_TRY_COMPILE([#include -#ifdef HAVE_NAMESPACES -using namespace std; -#endif],[slist s; return 0;], - ac_cv_cxx_have_ext_slist=std, ac_cv_cxx_have_ext_slist=no) - AC_TRY_COMPILE([#include -#ifdef HAVE_NAMESPACES -using namespace __gnu_cxx; -#endif],[slist s; return 0;], - ac_cv_cxx_have_ext_slist=gnu, ac_cv_cxx_have_ext_slist=no) - - AC_LANG_RESTORE -]) -if test "$ac_cv_cxx_have_ext_slist" = std; then - AC_DEFINE(HAVE_EXT_SLIST,std,[define if the compiler has ext/slist]) -fi -if test "$ac_cv_cxx_have_ext_slist" = gnu; then - AC_DEFINE(HAVE_EXT_SLIST,gnu,[define if the compiler has ext/slist]) +HAVE_FWD_ITERATOR=0 +if test "$ac_cv_cxx_have_fwd_iterator" = yes +then + HAVE_FWD_ITERATOR=1 fi -]) +AC_SUBST(HAVE_FWD_ITERATOR)]) # # Check for FLEX. This is modified from Index: llvm/autoconf/configure.ac diff -u llvm/autoconf/configure.ac:1.66 llvm/autoconf/configure.ac:1.66.2.1 --- llvm/autoconf/configure.ac:1.66 Fri Jan 16 15:31:22 2004 +++ llvm/autoconf/configure.ac Mon Mar 1 17:55:26 2004 @@ -40,7 +40,6 @@ AC_CONFIG_MAKEFILE(test/Programs/Makefile.programs) AC_CONFIG_MAKEFILE(test/Programs/TEST.aa.Makefile) AC_CONFIG_MAKEFILE(test/Programs/TEST.dsgraph.report) -AC_CONFIG_MAKEFILE(test/Programs/TEST.micro.report) AC_CONFIG_MAKEFILE(test/Programs/TEST.aa.report) AC_CONFIG_MAKEFILE(test/Programs/TEST.example.Makefile) AC_CONFIG_MAKEFILE(test/Programs/TEST.nightly.Makefile) @@ -51,10 +50,12 @@ AC_CONFIG_MAKEFILE(test/Programs/TEST.jit.report) AC_CONFIG_MAKEFILE(test/Programs/TEST.typesafe.Makefile) AC_CONFIG_MAKEFILE(test/Programs/TEST.dsgraph.gnuplot) -AC_CONFIG_MAKEFILE(test/Programs/TEST.micro.Makefile) +AC_CONFIG_MAKEFILE(test/Programs/TEST.vtl.Makefile) AC_CONFIG_MAKEFILE(test/Programs/External/Makefile) AC_CONFIG_MAKEFILE(test/Programs/External/SPEC/Makefile) AC_CONFIG_MAKEFILE(test/Programs/External/SPEC/Makefile.spec) +AC_CONFIG_MAKEFILE(test/Programs/External/SPEC/Makefile.spec2000) +AC_CONFIG_MAKEFILE(test/Programs/External/SPEC/Makefile.spec95) AC_CONFIG_MAKEFILE(test/Programs/MultiSource/Makefile) AC_CONFIG_MAKEFILE(test/Programs/MultiSource/Makefile.multisrc) AC_CONFIG_MAKEFILE(test/Programs/MultiSource/Benchmarks/FreeBench/analyzer/test.in) @@ -72,6 +73,7 @@ AC_CONFIG_MAKEFILE(test/Programs/MultiSource/Benchmarks/FreeBench/pifft/test.in) AC_CONFIG_MAKEFILE(test/Programs/SingleSource/Makefile) AC_CONFIG_MAKEFILE(test/Programs/SingleSource/Makefile.singlesrc) +AC_CONFIG_MAKEFILE(test/Programs/SingleSource/UnitTests/SetjmpLongjmp/Makefile) AC_CONFIG_MAKEFILE(tools/Makefile) AC_CONFIG_MAKEFILE(utils/Makefile) AC_CONFIG_MAKEFILE(projects/Makefile) @@ -169,6 +171,14 @@ dnl Checks for tools we can get away with not having: AC_PATH_PROG(DOT,[dot],[true dot]) AC_PATH_PROG(ETAGS,[etags],[true etags]) +dnl Check if we know how to tell etags we are using C++: +etags_version=`$ETAGS --version 2>&1` +case "$etags_version" in + *[Ee]xuberant*) ETAGSFLAGS="--language-force=c++" ;; + *GNU\ Emacs*) ETAGSFLAGS="-l c++" ;; + *) ETAGSFLAGS="" ;; +esac +AC_SUBST(ETAGSFLAGS,$ETAGSFLAGS) AC_PATH_PROG(PYTHON,[python],[true python]) if test "$PYTHON" = "false" then @@ -213,7 +223,8 @@ dnl pthread locking functions are optional - but llvm will not be thread-safe dnl without locks. -AC_SEARCH_LIBS(pthread_mutex_lock,pthread,AC_DEFINE(HAVE_PTHREAD_MUTEX_LOCK,1,[Define if PThread mutexes (e.g., pthread_mutex_lock) are available in the system's thread library.])) +AC_SEARCH_LIBS(pthread_mutex_lock,pthread,HAVE_PTHREAD_MUTEX_LOCK=1,HAVE_PTHREAD_MUTEX_LOCK=0) +AC_SUBST(HAVE_PTHREAD_MUTEX_LOCK) dnl Checks for header files. dnl We don't check for ancient stuff or things that are guaranteed to be there @@ -222,7 +233,19 @@ AC_HEADER_SYS_WAIT dnl Checks for POSIX and other various system-specific header files -AC_CHECK_HEADERS(fcntl.h limits.h sys/time.h unistd.h malloc.h sys/mman.h sys/resource.h dlfcn.h link.h) +AC_CHECK_HEADERS(fcntl.h limits.h sys/time.h unistd.h malloc.h sys/mman.h sys/resource.h dlfcn.h link.h execinfo.h) + +dnl Check for things that need to be included in public headers, and so +dnl for which we may not have access to a HAVE_* preprocessor #define. +dnl (primarily used in DataTypes.h) +AC_CHECK_HEADER([sys/types.h], + [INCLUDE_SYS_TYPES_H='#include '], + [INCLUDE_SYS_TYPES_H='']) +AC_SUBST(INCLUDE_SYS_TYPES_H) +AC_CHECK_HEADER([inttypes.h], + [INCLUDE_INTTYPES_H='#include '], + [INCLUDE_INTTYPES_H='']) +AC_SUBST(INCLUDE_INTTYPES_H) dnl Check for types AC_TYPE_PID_T @@ -235,10 +258,12 @@ dnl Check for various C features AC_C_PRINTF_A +dnl Check for the endianness of the target +AC_C_BIGENDIAN(AC_SUBST([ENDIAN],[big]),AC_SUBST([ENDIAN],[little])) + dnl Check for C++ extensions AC_CXX_HAVE_HASH_MAP AC_CXX_HAVE_HASH_SET -AC_CXX_HAVE_EXT_SLIST AC_CXX_HAVE_STD_ITERATOR AC_CXX_HAVE_BI_ITERATOR AC_CXX_HAVE_FWD_ITERATOR @@ -257,7 +282,7 @@ fi AC_HEADER_MMAP_ANONYMOUS AC_TYPE_SIGNAL -AC_CHECK_FUNCS(getcwd gettimeofday strdup strtoq strtoll) +AC_CHECK_FUNCS(getcwd gettimeofday strdup strtoq strtoll backtrace) AC_CHECK_FUNC(mprotect,,AC_MSG_ERROR([Function mprotect() required but not found])) dnl Determine if the linker supports the -R option. @@ -273,28 +298,73 @@ AC_SUBST(ENABLE_OPTIMIZED,[[ENABLE_OPTIMIZED=1]]) fi -dnl Spec Benchmarks +dnl Spec 2000 Benchmarks AC_ARG_ENABLE(spec2000,AC_HELP_STRING([--enable-spec2000],[Compile SPEC 2000 benchmarks (default is NO)]),,enableval=no) if test ${enableval} = "no" then if test -d /home/vadve/shared/benchmarks/speccpu2000/benchspec then - AC_SUBST(SPEC_ROOT,[/home/vadve/shared/benchmarks/speccpu2000/benchspec]) - AC_SUBST(USE_SPEC,[[USE_SPEC=1]]) + AC_SUBST(SPEC2000_ROOT,[/home/vadve/shared/benchmarks/speccpu2000/benchspec]) + AC_SUBST(USE_SPEC2000,[[USE_SPEC2000=1]]) + else + AC_SUBST(USE_SPEC2000,[[]]) + AC_SUBST(SPEC2000_ROOT,[]) + fi +else + if test ${enableval} = "" + then + AC_SUBST(SPEC2000_ROOT,[/home/vadve/shared/benchmarks/speccpu2000/benchspec]) + else + AC_SUBST(SPEC2000_ROOT,[${enableval}]) + fi + AC_SUBST(USE_SPEC2000,[[USE_SPEC2000=1]]) +fi + +dnl Spec 95 Benchmarks +AC_ARG_ENABLE(spec95,AC_HELP_STRING([--enable-spec95],[Compile SPEC 95 benchmarks (default is NO)]),,enableval=no) +if test ${enableval} = "no" +then + if test -d /home/vadve/shared/benchmarks/spec95/benchspec + then + AC_SUBST(SPEC95_ROOT,[/home/vadve/shared/benchmarks/spec95/benchspec]) + AC_SUBST(USE_SPEC95,[[USE_SPEC95=1]]) else - AC_SUBST(USE_SPEC,[[]]) - AC_SUBST(SPEC_ROOT,[]) + AC_SUBST(USE_SPEC95,[[]]) + AC_SUBST(SPEC95_ROOT,[]) fi else if test ${enableval} = "" then - AC_SUBST(SPEC_ROOT,[/home/vadve/shared/benchmarks/speccpu2000/benchspec]) + AC_SUBST(SPEC95_ROOT,[/home/vadve/shared/benchmarks/spec95/benchspec]) else - AC_SUBST(SPEC_ROOT,[${enableval}]) + AC_SUBST(SPEC95_ROOT,[${enableval}]) fi - AC_SUBST(USE_SPEC,[[USE_SPEC=1]]) + AC_SUBST(USE_SPEC95,[[USE_SPEC95=1]]) fi +dnl Povray External Benchmark +AC_ARG_ENABLE(povray,AC_HELP_STRING([--enable-povray],[Compile Povray benchmark (default is NO)]),,enableval=no) +if test ${enableval} = "no" +then + if test -d /home/vadve/shared/benchmarks/povray31 + then + AC_SUBST(POVRAY_ROOT,[/home/vadve/shared/benchmarks/povray31]) + AC_SUBST(USE_POVRAY,[[USE_POVRAY=1]]) + else + AC_SUBST(USE_POVRAY,[[]]) + AC_SUBST(POVRAY_ROOT,[]) + fi +else + if test ${enableval} = "" + then + AC_SUBST(POVRAY_ROOT,[/home/vadve/shared/benchmarks/povray31]) + else + AC_SUBST(POVRAY_ROOT,[${enableval}]) + fi + AC_SUBST(USE_POVRAY,[[USE_POVRAY=1]]) +fi + + dnl Precompiled Bytecode Option AC_ARG_ENABLE(precompiled_bytecode,AC_HELP_STRING([--enable-precompiled_bytecode],[Use pre-compiled bytecode (default is NO)]),,enableval=no) if test ${enableval} = "no" @@ -377,8 +447,23 @@ dnl Location of PAPI AC_ARG_WITH(papi,AC_HELP_STRING([--with-papi],[Location of PAPI]),AC_SUBST(PAPIDIR,[$withval]),AC_SUBST(PAPIDIR,[/home/vadve/shared/Sparc/papi-2.3.4.1])) +dnl Get libtool's idea of what the shared library suffix is. +dnl (This is a hack; it relies on undocumented behavior.) +AC_MSG_CHECKING([for shared library suffix]) +eval "SHLIBEXT=$shrext" +AC_MSG_RESULT($SHLIBEXT) +dnl Propagate it to the Makefiles and config.h (for gccld & bugpoint). +AC_SUBST(SHLIBEXT,$SHLIBEXT) +AC_DEFINE_UNQUOTED(SHLIBEXT,"$SHLIBEXT", + [Extension that shared libraries have, e.g., ".so".]) + dnl Create the output files -AC_OUTPUT(Makefile.config) +AC_OUTPUT(Makefile.config + include/Support/DataTypes.h + include/Support/ThreadSupport.h + include/Support/hash_map + include/Support/hash_set + include/Support/iterator) dnl Warn loudly if llvm-gcc was not obviously working if test $llvmgccwarn = yes @@ -390,3 +475,4 @@ AC_MSG_WARN([***** Runtime libraries (in llvm/runtime) will not be built,]) AC_MSG_WARN([***** but you should be able to build the llvm tools.]) fi + From brukman at cs.uiuc.edu Mon Mar 1 17:57:02 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Mar 1 17:57:02 2004 Subject: [llvm-commits] [parallel] CVS: llvm/docs/CommandGuide/analyze.html bugpoint.html extract.html gccld.html llc.html llvm-prof.html opt.html Message-ID: <200403012356.RAA03131@zion.cs.uiuc.edu> Changes in directory llvm/docs/CommandGuide: analyze.html updated: 1.8 -> 1.8.6.1 bugpoint.html updated: 1.19 -> 1.19.4.1 extract.html updated: 1.5 -> 1.5.6.1 gccld.html updated: 1.8 -> 1.8.4.1 llc.html updated: 1.6 -> 1.6.6.1 llvm-prof.html updated: 1.3 -> 1.3.4.1 opt.html updated: 1.8 -> 1.8.6.1 --- Log message: Merge from trunk --- Diffs of the changes: (+103 -58) Index: llvm/docs/CommandGuide/analyze.html diff -u llvm/docs/CommandGuide/analyze.html:1.8 llvm/docs/CommandGuide/analyze.html:1.8.6.1 --- llvm/docs/CommandGuide/analyze.html:1.8 Tue Oct 7 15:36:00 2003 +++ llvm/docs/CommandGuide/analyze.html Mon Mar 1 17:56:01 2004 @@ -51,16 +51,16 @@ Quiet mode. With this option, analysis pass names are not printed.

    -

  • -load <plugin.so> +
  • -load <plugin>
    - Load the specified dynamic object with name plugin.so. This file + Load the specified dynamic object with name plugin. This file should contain additional analysis passes that register themselves with the analyze program after being loaded.

    After being loaded, additional command line options are made available - for running the passes made available by plugin.so. Use - 'analyze -load <plugin.so> -help' to see the new + for running the passes made available by plugin. Use + 'analyze -load <plugin> -help' to see the new list of available analysis passes.

    Index: llvm/docs/CommandGuide/bugpoint.html diff -u llvm/docs/CommandGuide/bugpoint.html:1.19 llvm/docs/CommandGuide/bugpoint.html:1.19.4.1 --- llvm/docs/CommandGuide/bugpoint.html:1.19 Wed Nov 5 15:46:13 2003 +++ llvm/docs/CommandGuide/bugpoint.html Mon Mar 1 17:56:01 2004 @@ -47,43 +47,43 @@ bugpoint starts the crash debugger.

    Otherwise, if the -output option was not -specified, bugpoint runs the test program with the C backend (which -is assumed to generate good code) to generate a reference output. Once +specified, bugpoint runs the test program with the C backend (which is +assumed to generate good code) to generate a reference output. Once bugpoint has a reference output for the test program, it tries -executing it -with the selected code generator. If -the resulting output differs from the reference output, it assumes the -difference resulted from a code generator failure, and starts the -code generator debugger.

    - -Otherwise, bugpoint runs the test program after all of the LLVM passes -have been applied to it. If its output differs from the reference output, -it assumes the difference resulted from a failure in one of the LLVM passes, -and enters the -miscompilation debugger. Otherwise, -there is no problem bugpoint can debug.

    +executing it with the selected code generator. If the +selected code generator crashes, bugpoint starts the crash debugger on the code generator. Otherwise, if the +resulting output differs from the reference output, it assumes the difference +resulted from a code generator failure, and starts the code generator debugger.

    + +Finally, if the output of the selected code generator matches the reference +output, bugpoint runs the test program after all of the LLVM passes +have been applied to it. If its output differs from the reference output, it +assumes the difference resulted from a failure in one of the LLVM passes, and +enters the miscompilation +debugger. Otherwise, there is no problem bugpoint can debug.

    Crash debugger

    -If an optimizer crashes, bugpoint will try as hard as it can to -reduce the list of passes and the size of the test program. First, -bugpoint figures out which combination of passes triggers the bug. This -is useful when debugging a problem exposed by gccas, for example, -because it runs over 25 optimizations.

    +If an optimizer or code generator crashes, bugpoint will try as hard as +it can to reduce the list of passes (for optimizer crashes) and the size of the +test program. First, bugpoint figures out which combination of +optimizer passes triggers the bug. This is useful when debugging a problem +exposed by gccas, for example, because it runs over 25 +optimizations.

    Next, bugpoint tries removing functions from the test program, to -reduce its -size. Usually it is able to reduce a test program -to a single function, when debugging intraprocedural optimizations. Once the -number of +reduce its size. Usually it is able to reduce a test program to a single +function, when debugging intraprocedural optimizations. Once the number of functions has been reduced, it attempts to delete various edges in the control flow graph, to reduce the size of the function as much as possible. Finally, bugpoint deletes any individual LLVM instructions whose absence does not eliminate the failure. At the end, bugpoint should tell you what passes crash, give you a bytecode file, and give you instructions on how to -reproduce the failure with opt or -analyze.

    +reproduce the failure with opt, analyze, or llc.

    Code generator debugger

    @@ -152,14 +152,19 @@ bugpoint crashes before you see its "All input ok" message, you might try llvm-link -v on the same set of input files. If that also crashes, you may be experiencing a linker bug. + +
  • If your program is supposed to crash, bugpoint will be + confused. One way to deal with this is to cause bugpoint to ignore the exit + code from your program, by giving it the -check-exit-code=false + option.

    OPTIONS

  • Index: llvm/docs/GettingStarted.html diff -u llvm/docs/GettingStarted.html:1.48 llvm/docs/GettingStarted.html:1.48.2.1 --- llvm/docs/GettingStarted.html:1.48 Mon Jan 19 18:20:17 2004 +++ llvm/docs/GettingStarted.html Mon Mar 1 17:56:01 2004 @@ -264,12 +264,15 @@ LLVM:

      -
    • GNU Autoconf +
    • GNU Automake
    • +
    • GNU Autoconf
    • GNU M4

      If you want to make changes to the configure scripts, you will need GNU autoconf (2.57 or higher), and consequently, GNU M4 (version 1.4 or - higher).

    • + higher). You will also need automake. Any old version of + automake from 1.4p5 on should work; we only use aclocal from that + package.

    • QMTest
    • Python @@ -908,8 +911,7 @@ LLVM assembly to LLVM bytecode.

      llvm-dis
      The disassembler transforms the LLVM - bytecode to human readable LLVM assembly. Additionally, it can convert - LLVM bytecode to C, which is enabled with the -c option.

      + bytecode to human readable LLVM assembly.

      llvm-link
      llvm-link, not surprisingly, links multiple LLVM modules into a single program.

      @@ -923,8 +925,9 @@ functionality was compiled in), and will execute the code much faster than the interpreter.

      -

      llc
      llc is the LLVM backend compiler, - which translates LLVM bytecode to a SPARC or x86 assembly file.

      +

      llc
      llc is the LLVM backend compiler, which + translates LLVM bytecode to a SPARC or x86 assembly file, or to C code (with + the -march=c option).

      llvmgcc
      llvmgcc is a GCC-based C frontend that has been retargeted to emit LLVM code as the machine code output. It @@ -1144,7 +1147,7 @@ Chris Lattner
      The LLVM Compiler Infrastructure
      - Last modified: $Date: 2004/01/20 00:20:17 $ + Last modified: $Date: 2004/03/01 23:56:01 $ Index: llvm/docs/HowToSubmitABug.html diff -u llvm/docs/HowToSubmitABug.html:1.11 llvm/docs/HowToSubmitABug.html:1.11.2.1 --- llvm/docs/HowToSubmitABug.html:1.11 Thu Jan 15 13:03:47 2004 +++ llvm/docs/HowToSubmitABug.html Mon Mar 1 17:56:01 2004 @@ -281,7 +281,7 @@
    • Regenerate the shared object from the safe bytecode file:
      -  llvm-dis -c safe.bc -o safe.c
      + llc -march=c safe.bc -o safe.c
      gcc -shared safe.c -o safe.so
    • @@ -315,7 +315,7 @@ Chris Lattner
      The LLVM Compiler Infrastructure
      - Last modified: $Date: 2004/01/15 19:03:47 $ + Last modified: $Date: 2004/03/01 23:56:01 $ Index: llvm/docs/LLVMVsTheWorld.html diff -u llvm/docs/LLVMVsTheWorld.html:1.5 llvm/docs/LLVMVsTheWorld.html:1.5.4.1 --- llvm/docs/LLVMVsTheWorld.html:1.5 Wed Nov 12 15:39:31 2003 +++ llvm/docs/LLVMVsTheWorld.html Mon Mar 1 17:56:01 2004 @@ -60,8 +60,8 @@

      LLVM: Supports compilation of C and C++ (with more languages coming soon), strong SSA-based optimization at compile-time, link-time, run-time, and off-line, and multiple platform backends with Just-in-Time and ahead-of-time -compilation frameworks. (See our tech report on Lifelong +compilation frameworks. (See our document on Lifelong Code Optimization for more.)

      GCC: Many relatively mature platform backends support assembly-language code @@ -173,7 +173,7 @@

      Brian R. Gaeke
      The LLVM Compiler Infrastructure
      - Last modified: $Date: 2003/11/12 21:39:31 $ + Last modified: $Date: 2004/03/01 23:56:01 $ Index: llvm/docs/LangRef.html diff -u llvm/docs/LangRef.html:1.43 llvm/docs/LangRef.html:1.43.2.1 --- llvm/docs/LangRef.html:1.43 Mon Jan 5 23:31:32 2004 +++ llvm/docs/LangRef.html Mon Mar 1 17:56:01 2004 @@ -1,4 +1,5 @@ - + LLVM Assembly Language Reference Manual @@ -95,6 +96,19 @@
    • 'llvm.va_copy' Intrinsic
    • +
    • Code Generator Intrinsics +
        +
      1. 'llvm.returnaddress' Intrinsic
      2. +
      3. 'llvm.frameaddress' Intrinsic
      4. +
      +
    • +
    • Standard C Library Intrinsics +
        +
      1. 'llvm.memcpy' Intrinsic
      2. +
      3. 'llvm.memmove' Intrinsic
      4. +
      5. 'llvm.memset' Intrinsic
      6. +
      +
    • Debugger intrinsics
    • @@ -242,12 +256,12 @@

      The primitive types are the fundemental building blocks of the LLVM system. The current set of primitive types are as follows:

      -

      - + +
      - +
      @@ -281,7 +295,7 @@
      void
      - +
      @@ -313,7 +327,7 @@
      bool
      -

      +
      Type @@ -321,8 +335,8 @@

      These different primitive types fall into a few useful classifications:

      -

      - + +
      @@ -351,7 +365,7 @@
      signed
      -

      +

      The first class types are perhaps the most important. Values of these types are the only ones which can be produced by instructions, passed as arguments, or used as operands to @@ -383,7 +397,7 @@ [40 x uint]: Array of 40 unsigned integer values.

      Here are some examples of multidimensional arrays:

      -

      + @@ -400,7 +414,7 @@
      -

      +
      @@ -422,7 +436,7 @@ Variable argument functions can access their arguments with the variable argument handling intrinsic functions.

      Examples:
      -

      + @@ -444,7 +458,7 @@
      -

      +
      @@ -461,7 +475,7 @@
      Syntax:
        { <type list> }
      Examples:
      -

      + @@ -477,7 +491,7 @@
      -

      + @@ -488,7 +502,7 @@
      Syntax:
        <type> *
      Examples:
      -

      + @@ -504,7 +518,7 @@
      -

      + - + +
      Syntax:
      -
        switch uint <value>, label <defaultdest> [ int <val>, label &dest>, ... ]
      + +
      +  switch <intty> <value>, label <defaultdest> [ <intty> <val>, label <dest> ... ]
      +
      +
      Overview:
      -

      The 'switch' instruction is used to transfer control flow -to one of several different places. It is a generalization of the 'br' + +

      The 'switch' instruction is used to transfer control flow to one of +several different places. It is a generalization of the 'br' instruction, allowing a branch to occur to one of many possible destinations.

      + +
      Arguments:
      -

      The 'switch' instruction uses three parameters: a 'uint' -comparison value 'value', a default 'label' -destination, and an array of pairs of comparison value constants and 'label's.

      + +

      The 'switch' instruction uses three parameters: an integer +comparison value 'value', a default 'label' destination, and +an array of pairs of comparison value constants and 'label's. The +table is not allowed to contain duplicate constant entries.

      +
      Semantics:
      +

      The switch instruction specifies a table of values and destinations. When the 'switch' instruction is executed, this table is searched for the given value. If the value is found, the corresponding destination is branched to, otherwise the default value it transfered to.

      +
      Implementation:
      -

      Depending on properties of the target machine and the particular switch -instruction, this instruction may be code generated as a series of -chained conditional branches, or with a lookup table.

      -
      Example:
      -
        ; Emulate a conditional br instruction
      -  %Val = cast bool %value to uint
      switch uint %Val, label %truedest [int 0, label %falsedest ]

      ; Emulate an unconditional br instruction - switch uint 0, label %dest [ ] - - ; Implement a jump table: - switch uint %val, label %otherwise [ int 0, label %onzero, - int 1, label %onone, - int 2, label %ontwo ] + +

      Depending on properties of the target machine and the particular +switch instruction, this instruction may be code generated in different +ways, for example as a series of chained conditional branches, or with a lookup +table.

      + +
      Example:
      + +
      + ; Emulate a conditional br instruction
      + %Val = cast bool %value to int
      + switch int %Val, label %truedest [int 0, label %falsedest ]
      +
      + ; Emulate an unconditional br instruction
      + switch uint 0, label %dest [ ]
      +
      + ; Implement a jump table:
      + switch uint %val, label %otherwise [ uint 0, label %onzero 
      +                                      uint 1, label %onone 
      +                                      uint 2, label %ontwo ]
       
      @@ -1032,7 +1066,7 @@
      Semantics:

      The truth table used for the 'and' instruction is:

      -
      +
      @@ -1062,7 +1096,7 @@
      -
      +
      Example:
        <result> = and int 4, %var         ; yields {int}:result = 4 & %var
         <result> = and int 15, 40          ; yields {int}:result = 8
      @@ -1085,7 +1119,7 @@
       
      Semantics:

      The truth table used for the 'or' instruction is:

      -
      +
      @@ -1115,7 +1149,7 @@
      -
      +
      Example:
        <result> = or int 4, %var         ; yields {int}:result = 4 | %var
         <result> = or int 15, 40          ; yields {int}:result = 47
      @@ -1140,7 +1174,7 @@
       
      Semantics:

      The truth table used for the 'xor' instruction is:

      -
      +
      @@ -1170,7 +1204,7 @@
      -
      +

      Example:
        <result> = xor int 4, %var         ; yields {int}:result = 4 ^ %var
      @@ -1249,8 +1283,8 @@
       

      The 'malloc' instruction allocates memory from the system heap and returns a pointer to it.

      Arguments:
      -

      The the 'malloc' instruction allocates sizeof(<type>)*NumElements -bytes of memory from the operating system, and returns a pointer of the +

      The 'malloc' instruction allocates sizeof(<type>)*NumElements +bytes of memory from the operating system and returns a pointer of the appropriate type to the program. The second form of the instruction is a shorter version of the first instruction that defaults to allocating one element.

      @@ -1594,23 +1628,31 @@
      -

      LLVM supports the notion of an "intrinsic function". These -functions have well known names and semantics, and are required to -follow certain restrictions. Overall, these instructions represent an -extension mechanism for the LLVM language that does not require -changing all of the transformations in LLVM to add to the language (or -the bytecode reader/writer, the parser, etc...).

      -

      Intrinsic function names must all start with an "llvm." -prefix, this prefix is reserved in LLVM for intrinsic names, thus -functions may not be named this. Intrinsic functions must always be -external functions: you cannot define the body of intrinsic functions. -Intrinsic functions may only be used in call or invoke instructions: it -is illegal to take the address of an intrinsic function. Additionally, -because intrinsic functions are part of the LLVM language, it is -required that they all be documented here if any are added.

      -

      Unless an intrinsic function is target-specific, there must be a -lowering pass to eliminate the intrinsic or all backends must support -the intrinsic function.

      + +

      LLVM supports the notion of an "intrinsic function". These functions have +well known names and semantics, and are required to follow certain +restrictions. Overall, these instructions represent an extension mechanism for +the LLVM language that does not require changing all of the transformations in +LLVM to add to the language (or the bytecode reader/writer, the parser, +etc...).

      + +

      Intrinsic function names must all start with an "llvm." prefix, this +prefix is reserved in LLVM for intrinsic names, thus functions may not be named +this. Intrinsic functions must always be external functions: you cannot define +the body of intrinsic functions. Intrinsic functions may only be used in call +or invoke instructions: it is illegal to take the address of an intrinsic +function. Additionally, because intrinsic functions are part of the LLVM +language, it is required that they all be documented here if any are added.

      + + +

      +Adding an intrinsic to LLVM is straight-forward if it is possible to express the +concept in LLVM directly (ie, code generator support is not _required_). To do +this, extend the default implementation of the IntrinsicLowering class to handle +the intrinsic. Code generators use this class to lower intrinsics they do not +understand to raw LLVM instructions that they do. +

      +
      @@ -1631,11 +1673,26 @@

      This example shows how the vanext instruction and the variable argument handling intrinsic functions are used.

      -
      int %test(int %X, ...) {
      ; Initialize variable argument processing
      %ap = call sbyte*()* %llvm.va_start()

      ; Read a single integer argument
      %tmp = vaarg sbyte* %ap, int

      ; Advance to the next argument
      %ap2 = vanext sbyte* %ap, int

      ; Demonstrate usage of llvm.va_copy and llvm.va_end
      %aq = call sbyte* (sbyte*)* %llvm.va_copy(sbyte* %ap2)
      call void %llvm.va_end(sbyte* %aq)

      ; Stop processing of arguments.
      call void %llvm.va_end(sbyte* %ap2)
      ret int %tmp
      }
      +
      +int %test(int %X, ...) {
      +  ; Initialize variable argument processing
      +  %ap = call sbyte* %llvm.va_start()
      +
      +  ; Read a single integer argument
      +  %tmp = vaarg sbyte* %ap, int
      +
      +  ; Advance to the next argument
      +  %ap2 = vanext sbyte* %ap, int
      +
      +  ; Demonstrate usage of llvm.va_copy and llvm.va_end
      +  %aq = call sbyte* %llvm.va_copy(sbyte* %ap2)
      +  call void %llvm.va_end(sbyte* %aq)
      +
      +  ; Stop processing of arguments.
      +  call void %llvm.va_end(sbyte* %ap2)
      +  ret int %tmp
      +}
      +
      @@ -1704,6 +1761,277 @@ complex and require memory allocation, for example.

      + + + +
      +

      +These intrinsics are provided by LLVM to expose special features that may only +be implemented with code generator support. +

      + +
      + + + + +
      + +
      Syntax:
      +
      +  call void* ()* %llvm.returnaddress(uint <level>)
      +
      + +
      Overview:
      + +

      +The 'llvm.returnaddress' intrinsic returns a target-specific value +indicating the return address of the current function or one of its callers. +

      + +
      Arguments:
      + +

      +The argument to this intrinsic indicates which function to return the address +for. Zero indicates the calling function, one indicates its caller, etc. The +argument is required to be a constant integer value. +

      + +
      Semantics:
      + +

      +The 'llvm.returnaddress' intrinsic either returns a pointer indicating +the return address of the specified call frame, or zero if it cannot be +identified. The value returned by this intrinsic is likely to be incorrect or 0 +for arguments other than zero, so it should only be used for debugging purposes. +

      + +

      +Note that calling this intrinsic does not prevent function inlining or other +aggressive transformations, so the value returned may not that of the obvious +source-language caller. +

      +
      + + + + + +
      + +
      Syntax:
      +
      +  call void* ()* %llvm.frameaddress(uint <level>)
      +
      + +
      Overview:
      + +

      +The 'llvm.frameaddress' intrinsic returns the target-specific frame +pointer value for the specified stack frame. +

      + +
      Arguments:
      + +

      +The argument to this intrinsic indicates which function to return the frame +pointer for. Zero indicates the calling function, one indicates its caller, +etc. The argument is required to be a constant integer value. +

      + +
      Semantics:
      + +

      +The 'llvm.frameaddress' intrinsic either returns a pointer indicating +the frame address of the specified call frame, or zero if it cannot be +identified. The value returned by this intrinsic is likely to be incorrect or 0 +for arguments other than zero, so it should only be used for debugging purposes. +

      + +

      +Note that calling this intrinsic does not prevent function inlining or other +aggressive transformations, so the value returned may not that of the obvious +source-language caller. +

      +
      + + + + + +
      +

      +LLVM provides intrinsics for a few important standard C library functions. +These intrinsics allow source-language front-ends to pass information about the +alignment of the pointer arguments to the code generator, providing opportunity +for more efficient code generation. +

      + +
      + + + + +
      + +
      Syntax:
      +
      +  call void (sbyte*, sbyte*, uint, uint)* %llvm.memcpy(sbyte* <dest>, sbyte* <src>,
      +                                                       uint <len>, uint <align>)
      +
      + +
      Overview:
      + +

      +The 'llvm.memcpy' intrinsic copies a block of memory from the source +location to the destination location. +

      + +

      +Note that, unlike the standard libc function, the llvm.memcpy intrinsic +does not return a value, and takes an extra alignment argument. +

      + +
      Arguments:
      + +

      +The first argument is a pointer to the destination, the second is a pointer to +the source. The third argument is an (arbitrarily sized) integer argument +specifying the number of bytes to copy, and the fourth argument is the alignment +of the source and destination locations. +

      + +

      +If the call to this intrinisic has an alignment value that is not 0 or 1, then +the caller guarantees that the size of the copy is a multiple of the alignment +and that both the source and destination pointers are aligned to that boundary. +

      + +
      Semantics:
      + +

      +The 'llvm.memcpy' intrinsic copies a block of memory from the source +location to the destination location, which are not allowed to overlap. It +copies "len" bytes of memory over. If the argument is known to be aligned to +some boundary, this can be specified as the fourth argument, otherwise it should +be set to 0 or 1. +

      +
      + + + + + +
      + +
      Syntax:
      +
      +  call void (sbyte*, sbyte*, uint, uint)* %llvm.memmove(sbyte* <dest>, sbyte* <src>,
      +                                                       uint <len>, uint <align>)
      +
      + +
      Overview:
      + +

      +The 'llvm.memmove' intrinsic moves a block of memory from the source +location to the destination location. It is similar to the 'llvm.memcpy' +intrinsic but allows the two memory locations to overlap. +

      + +

      +Note that, unlike the standard libc function, the llvm.memmove intrinsic +does not return a value, and takes an extra alignment argument. +

      + +
      Arguments:
      + +

      +The first argument is a pointer to the destination, the second is a pointer to +the source. The third argument is an (arbitrarily sized) integer argument +specifying the number of bytes to copy, and the fourth argument is the alignment +of the source and destination locations. +

      + +

      +If the call to this intrinisic has an alignment value that is not 0 or 1, then +the caller guarantees that the size of the copy is a multiple of the alignment +and that both the source and destination pointers are aligned to that boundary. +

      + +
      Semantics:
      + +

      +The 'llvm.memmove' intrinsic copies a block of memory from the source +location to the destination location, which may overlap. It +copies "len" bytes of memory over. If the argument is known to be aligned to +some boundary, this can be specified as the fourth argument, otherwise it should +be set to 0 or 1. +

      +
      + + + + + +
      + +
      Syntax:
      +
      +  call void (sbyte*, ubyte, uint, uint)* %llvm.memset(sbyte* <dest>, ubyte <val>,
      +                                                      uint <len>, uint <align>)
      +
      + +
      Overview:
      + +

      +The 'llvm.memset' intrinsic fills a block of memory with a particular +byte value. +

      + +

      +Note that, unlike the standard libc function, the llvm.memset intrinsic +does not return a value, and takes an extra alignment argument. +

      + +
      Arguments:
      + +

      +The first argument is a pointer to the destination to fill, the second is the +byte value to fill it with, the third argument is an (arbitrarily sized) integer +argument specifying the number of bytes to fill, and the fourth argument is the +known alignment of destination location. +

      + +

      +If the call to this intrinisic has an alignment value that is not 0 or 1, then +the caller guarantees that the size of the copy is a multiple of the alignment +and that the destination pointer is aligned to that boundary. +

      + +
      Semantics:
      + +

      +The 'llvm.memset' intrinsic fills "len" bytes of memory starting at the +destination location. If the argument is known to be aligned to some boundary, +this can be specified as the fourth argument, otherwise it should be set to 0 or +1. +

      +
      +
      @@ -1722,9 +2050,15 @@
      - +
      + Valid CSS! + Valid HTML 4.01! + + Chris Lattner
      + The LLVM Compiler Infrastructure
      + Last modified: $Date: 2004/03/01 23:56:01 $ +
      Index: llvm/docs/ProgrammersManual.html diff -u llvm/docs/ProgrammersManual.html:1.53 llvm/docs/ProgrammersManual.html:1.53.2.1 --- llvm/docs/ProgrammersManual.html:1.53 Wed Jan 14 18:14:41 2004 +++ llvm/docs/ProgrammersManual.html Mon Mar 1 17:56:01 2004 @@ -1793,8 +1793,6 @@ function
    • const Type * getReturnType() const: Returns the return type of the function.
    • -
    • const ParamTypes &getParamTypes() const: - Returns a vector of parameter types.
    • const Type * getParamType (unsigned i): Returns the type of the ith parameter.
    • const unsigned getNumParams() const: Returns the @@ -1831,7 +1829,7 @@ Dinakar Dhurjati and Chris Lattner
      The LLVM Compiler Infrastructure
      - Last modified: $Date: 2004/01/15 00:14:41 $ + Last modified: $Date: 2004/03/01 23:56:01 $ Index: llvm/docs/ReleaseNotes.html diff -u llvm/docs/ReleaseNotes.html:1.102 llvm/docs/ReleaseNotes.html:1.102.2.1 --- llvm/docs/ReleaseNotes.html:1.102 Tue Jan 20 13:16:50 2004 +++ llvm/docs/ReleaseNotes.html Mon Mar 1 17:56:01 2004 @@ -69,34 +69,62 @@
      -

      This is the third public release of the LLVM compiler infrastructure. +

      +This is the third public release of the LLVM compiler infrastructure. This +release incorporates several new features (including +exception handling support for the native code generators, the start of a +source-level debugger, and profile guided optimizer components), many speedups and code quality +improvements, documentation improvements, and a small collection of important bug fixes. Overall, this is our highest quality release to +date, and we encourage you to upgrade if you are using LLVM 1.0 or 1.1.

      -

      At this time, LLVM is known to correctly compile and run all non-unwinding C +

      FIXME: UPDATE: +At this time, LLVM is known to correctly compile and run all C & C++ SPEC CPU2000 benchmarks, the Olden benchmarks, and the Ptrdist benchmarks. It has also been used to compile many other programs. LLVM now also works with a broad variety of C++ programs, though it has still -received much less testing than the C front-end. +received less testing than the C front-end.

      -

      -The LLVM native code generators are very stable but do not currently support -unwinding (exception throwing or longjmping), which prevent them from -working with programs like the 253.perlbmk in SPEC CPU2000. The C -backend and the rest of LLVM supports these programs, so you can -still use LLVM with them. Support for unwinding will be added in a future -release. -

      - -
      -This release implements the following new features: +This release implements the following new features:
        -
      1. -
      2. +
      3. A new LLVM source-level debugger has been started.
      4. +
      5. LLVM 1.2 encodes bytecode files for large programs in 10-30% less space.
      6. +
      7. LLVM can now feed profile information back into optimizers for Profile Guided Optimization, and includes a simple basic block reordering pass.
      8. +
      9. The LLVM JIT lazily initializes global variables, reducing startup time for programs with lots of globals (like C++ programs).
      10. + +
      11. The build and installation infrastructure in this release is dramatically +improved. There is now an autoconf/AutoRegen.sh script +that you can run to rebuild the configure script and its associated +files as well as beta support for "make install" and RPM package generation.
      12. + +
      13. The "tblgen" tool is now documented.
      14. +
      15. The LLVM code generator got a multitude of improvements: +
          +
        • It can now fold spill code into instructions on targets that support it.
        • +
        • A generic machine code spiller/rewriter was added. It provides an API for +global register allocators to eliminate virtual registers and add the +appropriate spill code.
        • +
        • The represenation of machine basic blocks got cleaned up and improved to +allow easier development and more efficient implementation.
        • +
        +
      16. +
      17. LLVM now no longer depends on the boost library.
      18. +
      19. The X86 backend now generates substantially better native code, and is faster.
      20. +
      21. The C backend has been turned moved from the "llvm-dis" tool to the "llc" +tool. You can activate it with "llc -march=c foo.bc -o foo.c".
      22. +
      23. LLVM includes a new interprocedural optimization that marks global variables +"constant" when they are provably never written to.
      @@ -106,14 +134,16 @@
        -
      1. -
      2. +
      3. Exception handling support in the X86 +& Sparc native code generators
      4. +
      5. The C/C++ front-end now support the GCC __builtin_return_address and __builtin_frame_address extensions.
      6. +
      7. [X86] Missing cast from ULong -> Double, cast FP -> bool and support for -9223372036854775808
      -In this release, the following Quality of Implementation issues were fixed: +In this release, the following Quality of Implementation issues were fixed:
        @@ -123,6 +153,11 @@
      1. [vmcore] OpaqueType objects memory leak
      2. [llvmgcc] C front-end does not compile "extern inline" into linkonce
      3. Bytecode format inconsistent
      4. +
      5. [loadvn/inline/scalarrepl] Slow optimizations with extremely large basic blocks
      6. +
      7. [asmparser] Really slow parsing of types with complex upreferences
      8. +
      9. [llvmgcc] C front-end does not emit 'zeroinitializer' when possible
      10. +
      11. [llvmgcc] Structure copies result in a LOT of code
      12. +
      13. LLVM is now much more memory efficient when handling large zero initialized arrays
      @@ -132,21 +167,28 @@
      1. [build] Makefiles break if C frontend target string has unexpected value
      2. +
      3. [build] hard-wired assumption that shared-library extension is ".so"
      4. +
      5. make tools-only doesn't make lib/Support
      -In this release, the following Code Quality issues were fixed: +In this release, the following Code Quality issues were fixed:
      1. [loopsimplify] Many pointless phi nodes are created
      2. +
      3. [x86] wierd stack/frame pointer manipulation
      4. + +
      5. The X86 backend now generate fchs to negate floating point numbers, +compiles memcpy() into the rep movs instruction, and makes much better +use of powerful addressing modes and instructions.
      -In this release, the following bugs in the previous release were fixed: +In this release, the following bugs in the previous release were fixed:

      Bugs in the LLVM Core:

      @@ -161,10 +203,22 @@
    • [constantmerge] Merging globals can cause use of invalid pointers!
    • [bcreader] Bytecode reader misreads 'long -9223372036854775808'!
    • - +
    • Tail duplication does not update SSA form correctly.
    • +
    • VMCore mishandles double -0.0
    • +
    • [X86] X86 backend code generates -0.0 as +0.0
    • +
    • [loopsimplify] Loopsimplify incorrectly updates dominator information
    • +
    • [pruneeh] -pruneeh pass removes invoke instructions it shouldn't
    • +
    • [sparc] Boolean constants are emitted as true and false
    • +
    • [interpreter] va_list values silently corrupted by function calls
    • +
    • Tablegen aborts on errors
    • +
    • [inliner] Error inlining intrinsic calls into invoke instructions
    • +
    • Linking weak and strong global variables is dependent on link order
    • +
    • Variables used to define non-printable FP constants are externally visible
    • +
    • CBE gives linkonce functions wrong linkage semantics
    • +

      Bugs in the C/C++ front-end:

        @@ -172,6 +226,9 @@ management functions in libc runtime to allow them to be overriden
      1. [llvm-gcc] asserts when an extern inline function is redefined
      2. [llvmg++] Dynamically initialized constants cannot be marked 'constant'
      3. +
      4. [llvmgcc] floating-point unary minus is incorrect for +0.0
      5. +
      6. [llvm-gcc] miscompilation of 'X = Y = Z' with aggregate values
      7. +
      8. [llvm-gcc] miscompilation when a function is re-declared as static
      @@ -242,24 +299,13 @@
    • LLVM cannot handle structures with more than 256 elements.
    • -
    • -The gccld program - -does not link objects/archives in the order specified on the command line. - -
    • - -
    • - -Tail duplication does not update SSA form correctly. - -
    • - -
    • [lowerinvoke] The -lowerinvoke pass -does not insert calls to setjmp/longjmp.
    • +
    • The gccld program does not link objects/archives in the order specified on the command line.
    • +
    • The lower-invoke pass does not mark +values live across a setjmp as volatile. This missing feature only effects +targets whose setjmp/longjmp libraries do not save and restore the entire +register file.
    • - @@ -286,21 +332,6 @@ with the largest union member. - -
    • - -Functions marked "extern inline" are not compiled into LLVM with linkonce -linkage. - -
    • - - -
    • -The memory management functions in the libc runtime -need weak linkage so that they can be -overridden. - -
    • @@ -340,7 +371,6 @@
    • Constraints: Constraints for asm operands.
    • Asm Labels: Specifying the assembler name to use for a C symbol.
    • Explicit Reg Vars: Defining variables residing in specified registers.
    • -
    • Return Address: Getting the return or frame address of a function.
    • Vector Extensions: Using vector instructions through built-in functions.
    • Target Builtins: Built-in functions specific to particular targets.
    • Thread-Local: Per-thread variables.
    • @@ -434,6 +464,7 @@
    • Alternate Keywords:__const__, __asm__, etc., for header files.
    • Incomplete Enums: enum foo;, with details to follow.
    • Function Names: Printable strings which are the name of the current function.
    • +
    • Return Address: Getting the return or frame address of a function.
    • Unnamed Fields: Unnamed struct/union fields within structs/unions.
    • Attribute Syntax: Formal syntax for attributes.
    • @@ -460,21 +491,13 @@ -
      - Bugs -
      +
      Bugs
      @@ -521,12 +544,7 @@
      @@ -539,17 +557,7 @@
      @@ -611,7 +619,7 @@ src="http://www.w3.org/Icons/valid-html401" alt="Valid HTML 4.01!" /> The LLVM Compiler Infrastructure
      - Last modified: $Date: 2004/01/20 19:16:50 $ + Last modified: $Date: 2004/03/01 23:56:01 $ Index: llvm/docs/TestingGuide.html diff -u llvm/docs/TestingGuide.html:1.6 llvm/docs/TestingGuide.html:1.6.4.1 --- llvm/docs/TestingGuide.html:1.6 Mon Nov 3 08:59:59 2003 +++ llvm/docs/TestingGuide.html Mon Mar 1 17:56:01 2004 @@ -1,11 +1,10 @@ - + - - - LLVM Test Suite Guide + LLVM Test Suite Guide + -
      @@ -16,414 +15,369 @@
    • Overview
    • Requirements
    • Quick Start
    • -
    • LLVM Test Suite Organization
    • +
    • LLVM Test Suite Organization +
    • LLVM Test Suite Tree
    • QMTest Structure
    • Programs Structure
    • Running the LLVM Tests
    • -

      Written by John T. Criswell

      - - - - -
      -

      - This document is the reference manual for the LLVM test suite. It - documents the structure of the LLVM test suite, the tools needed to - use it, and how to add and run tests. -

      -
      - - - - - -
      -

      - In order to use the LLVM test suite, you will need all of the software - required to build LLVM, plus the following: -

      -
      -
      QMTest
      -
      The LLVM test suite uses QMTest to organize and - run tests.
      - -
      Python
      -
      You will need a Python interpreter that works with - QMTest. Python will need zlib and SAX support - enabled.
      -
      -
      - - - - - -
      -

      - The tests are located in the LLVM source tree under the directory - llvm/test. To run all of the tests in LLVM, use the Master - Makefile in that directory: -

      -
      -	 % gmake -C llvm/test
      -	
      - -

      - To run only the code fragment tests (i.e. those that do basic testing of - LLVM), run the tests organized by QMTest: -

      - -
      -	 % gmake -C llvm/test qmtest
      -	
      - -

      - To run only the tests that compile and execute whole programs, run the - Programs tests: -

      - -
      -	 % gmake -C llvm/test/Programs
      -	
      -
      - - - - - -
      -

      The LLVM test suite contains two major categories of tests: code - fragments and whole programs.

      -
      - - - -
      -

      - Code fragments are small pieces of code that test a specific - feature of LLVM or trigger a specific bug in LLVM. They are - usually written in LLVM assembly language, but can be - written in other languages if the test targets a - particular language front end. -

      - Code fragments are not complete programs, and they are - never executed to determine correct behavior. -

      - The tests in the Features and - Regression directories contain code fragments. -

      -
      - - - -
      -

      - Whole Programs are pieces of code which can be compiled and - linked into a stand-alone program that can be executed. These - programs are generally written in high level languages such as C - or C++, but sometimes they are written straight in LLVM - assembly. -

      - These programs are compiled and then executed using several - different methods (native compiler, LLVM C backend, LLVM JIT, - LLVM native code generation, etc). The output of these programs - is compared to ensure that LLVM is compiling the program - correctly. -

      - In addition to compiling and executing programs, whole program - tests serve as a way of benchmarking LLVM performance, both in - terms of the efficiency of the programs generated as well as the - speed with which LLVM compiles, optimizes, and generates code. -

      - The Programs directory contains all tests which compile and - benchmark whole programs. -

      -
      - - - - - -
      -

      Each type of test in the LLVM test suite has its own directory. The - major subtrees of the test suite directory tree are as follows:

      +

      Written by John T. Criswell

      + + + + + +
      + +

      This document is the reference manual for the LLVM test suite. It documents +the structure of the LLVM test suite, the tools needed to use it, and how to add +and run tests.

      + +
      + + + + + +
      + +

      In order to use the LLVM test suite, you will need all of the software +required to build LLVM, plus the following:

      + +
      +
      QMTest
      +
      The LLVM test suite uses QMTest to organize and run tests.
      + +
      Python
      +
      You will need a Python interpreter that works with QMTest. Python will + need zlib and SAX support enabled.
      +
      + +
      + + + + + +
      + +

      The tests are located in the LLVM source tree under the directory +llvm/test. To run all of the tests in LLVM, use the Master Makefile in +that directory:

      + +
      + % gmake -C llvm/test
      +
      + +

      To run only the code fragment tests (i.e. those that do basic testing of +LLVM), run the tests organized by QMTest:

      + +
      + % gmake -C llvm/test qmtest
      +
      + +

      To run only the tests that compile and execute whole programs, run the +Programs tests:

      + +
      + % gmake -C llvm/test/Programs
      +
      + +
      + + + + + +
      + +

      The LLVM test suite contains two major categories of tests: code +fragments and whole programs.

      + +
      + + + +
      + +

      Code fragments are small pieces of code that test a specific feature of LLVM +or trigger a specific bug in LLVM. They are usually written in LLVM assembly +language, but can be written in other languages if the test targets a particular +language front end.

      + +

      Code fragments are not complete programs, and they are never executed to +determine correct behavior.

      + +

      The tests in the Features and Regression directories contain code +fragments.

      + +
      + + + +
      + +

      Whole Programs are pieces of code which can be compiled and linked into a +stand-alone program that can be executed. These programs are generally written +in high level languages such as C or C++, but sometimes they are written +straight in LLVM assembly.

      + +

      These programs are compiled and then executed using several different +methods (native compiler, LLVM C backend, LLVM JIT, LLVM native code generation, +etc). The output of these programs is compared to ensure that LLVM is compiling +the program correctly.

      + +

      In addition to compiling and executing programs, whole program tests serve as +a way of benchmarking LLVM performance, both in terms of the efficiency of the +programs generated as well as the speed with which LLVM compiles, optimizes, and +generates code.

      + +

      The Programs directory contains all tests which compile and benchmark whole +programs.

      + +
      + + + + + +
      + +

      Each type of test in the LLVM test suite has its own directory. The major +subtrees of the test suite directory tree are as follows:

      + +
        +
      • Features +

        This directory contains sample codes that test various features of the + LLVM language. These pieces of sample code are run through various + assembler, disassembler, and optimizer passes.

        + +
      • Regression +

        This directory contains regression tests for LLVM. When a bug is found + in LLVM, a regression test containing just enough code to reproduce the + problem should be written and placed somewhere underneath this directory. + In most cases, this will be a small piece of LLVM assembly language code, + often distilled from an actual application or benchmark.

        + +
      • Programs +

        The Programs directory contains programs that can be compiled with LLVM + and executed. These programs are compiled using the native compiler and + various LLVM backends. The output from the program compiled with the native + compiler is assumed correct; the results from the other programs are + compared to the native program output and pass if they match.

        + +

        In addition for testing correctness, the Programs directory also + performs timing tests of various LLVM optimizations. It also records + compilation times for the compilers and the JIT. This information can be + used to compare the effectiveness of LLVM's optimizations and code + generation.

        + +

        The Programs directory is subdivided into several smaller subdirectories: +

        + +
          +
        • Programs/SingleSource +

          The SingleSource directory contains test programs that are only a + single source file in size. These are usually small benchmark programs + or small programs that calculate a particular value. Several such + programs are grouped together in each directory.

        • + +
        • Programs/MultiSource +

          The MultiSource directory contains subdirectories which contain + entire programs with multiple source files. Large benchmarks and whole + applications go here.

        • + +
        • Programs/External +

          The External directory contains Makefiles for building code that is + external to (i.e. not distributed with) LLVM. The most prominent member + of this directory is the SPEC 2000 benchmark suite. The presence and + location of these external programs is configured by the LLVM + configure script.

        • -
            -
          • Features -

            - This directory contains sample codes that test various features - of the LLVM language. These pieces of sample code are run - through various assembler, disassembler, and optimizer passes. -

            - -
          • Regression -

            - This directory contains regression tests for LLVM. When a bug - is found in LLVM, a regression test containing just enough - code to reproduce the problem should be written and placed - somewhere underneath this directory. In most cases, this - will be a small piece of LLVM assembly language code, often - distilled from an actual application or benchmark. -

            - -
          • Programs -

            - The Programs directory contains programs that can be compiled - with LLVM and executed. These programs are compiled using the - native compiler and various LLVM backends. The output from the - program compiled with the native compiler is assumed correct; - the results from the other programs are compared to the native - program output and pass if they match. -

            - In addition for testing correctness, the Programs directory - also performs timing tests of various LLVM optimizations. - It also records compilation times for the compilers and the - JIT. This information can be used to compare the - effectiveness of LLVM's optimizations and code generation. -

            - The Programs directory is subdivided into several smaller - subdirectories: -

            - -
              -
            • Programs/SingleSource -

              - The SingleSource directory contains test programs that - are only a single source file in size. These are - usually small benchmark programs or small programs that - calculate a particular value. Several such programs are - grouped together in each directory. -

              - -
            • Programs/MultiSource -

              - The MultiSource directory contains subdirectories which - contain entire programs with multiple source files. - Large benchmarks and whole applications go here. -

              - -
            • Programs/External -

              - The External directory contains Makefiles for building - code that is external to (i.e. not distributed with) - LLVM. The most prominent member of this directory is - the SPEC 2000 benchmark suite. The presence and - location of these external programs is configured by the - LLVM configure script. -

              -
            - -

            - -

          • QMTest -

            - This directory contains the QMTest information files. Inside - this directory are QMTest administration files and the Python - code that implements the LLVM test and database classes. -

            -
          -
      - - - - - -
      -

      - The LLVM test suite is partially driven by QMTest and partially - driven by GNU Make. Specifically, the Features and Regression tests - are all driven by QMTest. The Programs directory is currently - driven by a set of Makefiles. -

      - The QMTest system needs to have several pieces of information - available; these pieces of configuration information are known - collectively as the "context" in QMTest parlance. Since the context - for LLVM is relatively large, the master Makefile in llvm/test - sets it for you. -

      - The LLVM database class makes the subdirectories of llvm/test a - QMTest test database. For each directory that contains tests driven by - QMTest, it knows what type of test the source file is and how to run it. -

      - Hence, the QMTest namespace is essentially what you see in the - Feature and Regression directories, but there is some magic that - the database class performs (as described below). -

      - The QMTest namespace is currently composed of the following tests and - test suites: -

      - -
        -
      • Feature -

        - These are the feature tests found in the Feature directory. - They are broken up into the following categories: -

        -
          -
        • ad -

          - Assembler/Disassembler tests. These tests verify that a - piece of LLVM assembly language can be assembled into - bytecode and then disassembled into the original - assembly language code. It does this several times to - ensure that assembled output can be disassembled and - disassembler output can be assembled. It also verifies - that the give assembly language file can be assembled - correctly. -

          - -
        • opt -

          - Optimizer tests. These tests verify that two of the - optimizer passes completely optimize a program (i.e. - after a single pass, they cannot optimize a program - any further). -

          - -
        • mc -

          - Machine code tests. These tests verify that the LLVM - assembly language file can be translated into native - assembly code. -

          - -
        • cc -

          - C code tests. These tests verify that the specified - LLVM assembly code can be converted into C source code - using the C backend. -

          -
        - -

        - The LLVM database class looks at every file in the Feature - directory and creates a fake test hierarchy containing - Feature.<testtype>.<testname>. So, if you - add an LLVM assembly language file to the Feature directory, it - actually creates 5 new tests: assembler/disassembler, assembler, - optimizer, machine code, and C code. -

        - -
      • Regression -

        - These are the regression tests. There is one suite for each - subdirectory of the Regression directory. If you add a new - subdirectory there, you will need to modify, at least, the - RegressionMap variable in QMTest/llvmdb.py so - that QMTest knows how to run the tests in the new subdirectory. -

        -
      -
      - - - - - -
      -

      - As mentioned previously, the Programs tree in llvm/test provides three - types of tests: MultiSource, SingleSource, and External. Each tree is - then subdivided into several categories, including applications, - benchmarks, regression tests, code that is strange grammatically, etc. - These organizations should be relatively self explanatory. -

      - In addition to the regular Programs tests, the Programs tree also - provides a mechanism for compiling the programs in different ways. If - the variable TEST is defined on the gmake command line, the test system - will include a Makefile named TEST.<value of TEST - variable>.Makefile. This Makefile can modify build rules to - yield different results. -

      - For example, the LLVM nightly tester uses TEST.nightly.Makefile - to create the nightly test reports. To run the nightly tests, run - gmake TEST=nightly. -

      - There are several TEST Makefiles available in the tree. Some of them - are designed for internal LLVM research and will not work outside of the - LLVM research group. They may still be valuable, however, as a guide to - writing your own TEST Makefile for any optimization or analysis passes - that you develop with LLVM. -

      -
      - - - - - -
      -

      - First, all tests are executed within the LLVM object directory tree. - They are not executed inside of the LLVM source tree. This is - because the test suite creates temporary files during execution. -

      - The master Makefile in llvm/test is capable of running both the - QMTest driven tests and the Programs tests. By default, it will run - all of the tests. -

      - To run only the QMTest driven tests, run gmake qmtest at the - command line in llvm/tests. To run a specific qmtest, suffix the test - name with ".t" when running gmake. -

      - For example, to run the Regression.LLC tests, type - gmake Regression.LLC.t in llvm/tests. -

      - Note that the Makefiles in llvm/test/Features and llvm/test/Regression - are gone. You must now use QMTest from the llvm/test directory to run - them. -

      - To run the Programs test, cd into the llvm/test/Programs directory and - type gmake. Alternatively, you can type gmake - TEST=<type> test to run one of the specialized tests in - llvm/test/Programs/TEST.<type>.Makefile. For example, you could - run the nightly tester tests using the following commands: -

      - -
      -	 % cd llvm/test/Programs
      -	 % gmake TEST=nightly test
      -	
      - -

      - Regardless of which test you're running, the results are printed on - standard output and standard error. You can redirect these results to a - file if you choose. -

      - Some tests are known to fail. Some are bugs that we have not fixed yet; - others are features that we haven't added yet (or may never add). In - QMTest, the result for such tests will be XFAIL (eXpected FAILure). In - this way, you can tell the difference between an expected and unexpected - failure. -

      - The Programs tests have no such feature as of this time. If the test - passes, only warnings and other miscellaneous output will be generated. - If a test fails, a large <program> FAILED message will be - displayed. This will help you separate benign warnings from actual test - failures. -

      -
      + - +
    • QMTest +

      This directory contains the QMTest information files. Inside this + directory are QMTest administration files and the Python code that + implements the LLVM test and database classes.

      + + + +
    • + + + + + +
      + +

      The LLVM test suite is partially driven by QMTest and partially +driven by GNU Make. Specifically, the Features and Regression tests +are all driven by QMTest. The Programs directory is currently +driven by a set of Makefiles.

      + +

      The QMTest system needs to have several pieces of information +available; these pieces of configuration information are known +collectively as the "context" in QMTest parlance. Since the context +for LLVM is relatively large, the master Makefile in llvm/test +sets it for you.

      + +

      The LLVM database class makes the subdirectories of llvm/test a +QMTest test database. For each directory that contains tests driven by +QMTest, it knows what type of test the source file is and how to run it.

      + +

      Hence, the QMTest namespace is essentially what you see in the +Feature and Regression directories, but there is some magic that +the database class performs (as described below).

      + +

      The QMTest namespace is currently composed of the following tests and test +suites:

      + +
        +
      • Feature +

        + These are the feature tests found in the Feature directory. + They are broken up into the following categories: +

        +
          +
        • ad +

          Assembler/Disassembler tests. These tests verify that a piece of LLVM + assembly language can be assembled into bytecode and then disassembled + into the original assembly language code. It does this several times to + ensure that assembled output can be disassembled and disassembler output + can be assembled. It also verifies that the give assembly language file + can be assembled correctly.

        • + +
        • opt +

          Optimizer tests. These tests verify that two of the optimizer passes + completely optimize a program (i.e. after a single pass, they cannot + optimize a program any further).

        • + +
        • mc +

          Machine code tests. These tests verify that the LLVM assembly + language file can be translated into native assembly code.

        • + +
        • cc +

          C code tests. These tests verify that the specified LLVM assembly + code can be converted into C source code using the C backend.

        • +
        + +

        The LLVM database class looks at every file in the Feature directory and + creates a fake test hierarchy containing + Feature.<testtype>.<testname>. So, if you add an LLVM + assembly language file to the Feature directory, it actually creates 5 new + tests: assembler/disassembler, assembler, optimizer, machine code, and C code. +

        + +
      • Regression +

        These are the regression tests. There is one suite for each + subdirectory of the Regression directory. If you add a new subdirectory + there, you will need to modify, at least, the RegressionMap + variable in QMTest/llvmdb.py so that QMTest knows how to run the + tests in the new subdirectory.

        + +
      + +
      + + + + + +
      + +

      As mentioned previously, the Programs tree in llvm/test provides three types +of tests: MultiSource, SingleSource, and External. Each tree is then subdivided +into several categories, including applications, benchmarks, regression tests, +code that is strange grammatically, etc. These organizations should be +relatively self explanatory.

      + +

      In addition to the regular Programs tests, the Programs tree also provides a +mechanism for compiling the programs in different ways. If the variable TEST is +defined on the gmake command line, the test system will include a Makefile named +TEST.<value of TEST variable>.Makefile. This Makefile can modify +build rules to yield different results.

      + +

      For example, the LLVM nightly tester uses TEST.nightly.Makefile to +create the nightly test reports. To run the nightly tests, run gmake +TEST=nightly.

      + +

      There are several TEST Makefiles available in the tree. Some of them are +designed for internal LLVM research and will not work outside of the LLVM +research group. They may still be valuable, however, as a guide to writing your +own TEST Makefile for any optimization or analysis passes that you develop with +LLVM.

      + +
      -
      -
      John T. Criswell
      -The LLVM Compiler Infrastructure -
      -Last modified: $Date: 2003/11/03 14:59:59 $ -
      + + + + +
      + +

      First, all tests are executed within the LLVM object directory tree. They +are not executed inside of the LLVM source tree. This is because the +test suite creates temporary files during execution.

      + +

      The master Makefile in llvm/test is capable of running both the QMTest driven +tests and the Programs tests. By default, it will run all of the tests.

      + +

      To run only the QMTest driven tests, run gmake qmtest at the +command line in llvm/tests. To run a specific qmtest, suffix the test name with +".t" when running gmake.

      + +

      For example, to run the Regression.LLC tests, type gmake +Regression.LLC.t in llvm/tests.

      + +

      Note that the Makefiles in llvm/test/Features and llvm/test/Regression are +gone. You must now use QMTest from the llvm/test directory to run them.

      + +

      To run the Programs test, cd into the llvm/test/Programs directory and type +gmake. Alternatively, you can type gmake TEST=<type> +test to run one of the specialized tests in +llvm/test/Programs/TEST.<type>.Makefile. For example, you could run the +nightly tester tests using the following commands:

      + +
      + % cd llvm/test/Programs
      + % gmake TEST=nightly test
      +
      + +

      Regardless of which test you're running, the results are printed on standard +output and standard error. You can redirect these results to a file if you +choose.

      + +

      Some tests are known to fail. Some are bugs that we have not fixed yet; +others are features that we haven't added yet (or may never add). In QMTest, +the result for such tests will be XFAIL (eXpected FAILure). In this way, you +can tell the difference between an expected and unexpected failure.

      + +

      The Programs tests have no such feature as of this time. If the test passes, +only warnings and other miscellaneous output will be generated. If a test +fails, a large <program> FAILED message will be displayed. This will help +you separate benign warnings from actual test failures.

      + +
      + + +
      +
      + Valid CSS! + Valid HTML 4.01! + + John T. Criswell
      + The LLVM Compiler Infrastructure
      + Last modified: $Date: 2004/03/01 23:56:01 $ +
      Index: llvm/docs/WritingAnLLVMPass.html diff -u llvm/docs/WritingAnLLVMPass.html:1.22 llvm/docs/WritingAnLLVMPass.html:1.22.2.1 --- llvm/docs/WritingAnLLVMPass.html:1.22 Thu Jan 15 12:34:11 2004 +++ llvm/docs/WritingAnLLVMPass.html Mon Mar 1 17:56:01 2004 @@ -173,6 +173,11 @@ lib/Debug/libhello.so shared object that can be dynamically loaded by the opt or analyze tools.

      +

      +Note that the suffix of the shared library may differ from the example above if +your system uses a different suffix by default. +

      +

      Now that we have the build scripts set up, we just need to write the code for the pass itself.

      @@ -282,7 +287,7 @@
      -

      Now that you have a brand new shiny .so file, we can use the +

      Now that you have a brand new shiny shared object file, we can use the opt command to run an LLVM program through your pass. Because you registered your pass with the RegisterOpt template, you will be able to use the opt tool to access it, once loaded.

      @@ -1421,7 +1426,7 @@ Chris Lattner
      The LLVM Compiler Infrastructure
      - Last modified: $Date: 2004/01/15 18:34:11 $ + Last modified: $Date: 2004/03/01 23:56:01 $ Index: llvm/docs/index.html diff -u llvm/docs/index.html:1.6 llvm/docs/index.html:1.6.4.1 --- llvm/docs/index.html:1.6 Mon Nov 24 21:32:57 2003 +++ llvm/docs/index.html Mon Mar 1 17:56:01 2004 @@ -120,11 +120,11 @@
      - LLVM : A Compilation Framework for Lifelong Program Analysis - and Transformation: + LLVM: A Compilation Framework for Lifelong Program Analysis + & Transformation
      - - http://llvm.cs.uiuc.edu/pubs/2003-09-30-LifelongOptimizationTR.html + + http://llvm.cs.uiuc.edu/pubs/2004-01-30-CGO-LLVM.html
      @@ -181,6 +181,20 @@
      llvm/docs/AliasAnalysis.html

      + +

      + Source Level Debugging with LLVM: +
      + llvm/docs/SourceLevelDebugging.html +

      + + +

      + TableGen Fundamentals: +
      + llvm/docs/TableGenFundamentals.html +

      +

      The Stacker Cronicles From brukman at cs.uiuc.edu Mon Mar 1 17:58:02 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Mar 1 17:58:02 2004 Subject: [llvm-commits] [parallel] CVS: llvm/include/boost/config/posix_features.hpp select_compiler_config.hpp select_platform_config.hpp select_stdlib_config.hpp suffix.hpp user.hpp Message-ID: <200403012357.RAA03245@zion.cs.uiuc.edu> Changes in directory llvm/include/boost/config: posix_features.hpp (r1.1) removed select_compiler_config.hpp (r1.1) removed select_platform_config.hpp (r1.1) removed select_stdlib_config.hpp (r1.1) removed suffix.hpp (r1.1) removed user.hpp (r1.1) removed --- Log message: Merge from trunk --- Diffs of the changes: (+0 -0) From brukman at cs.uiuc.edu Mon Mar 1 17:58:07 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Mar 1 17:58:07 2004 Subject: [llvm-commits] [parallel] CVS: llvm/include/Config/config.h.in Message-ID: <200403012357.RAA03206@zion.cs.uiuc.edu> Changes in directory llvm/include/Config: config.h.in updated: 1.10 -> 1.10.2.1 --- Log message: Merge from trunk --- Diffs of the changes: (+7 -38) Index: llvm/include/Config/config.h.in diff -u llvm/include/Config/config.h.in:1.10 llvm/include/Config/config.h.in:1.10.2.1 --- llvm/include/Config/config.h.in:1.10 Thu Jan 15 00:22:32 2004 +++ llvm/include/Config/config.h.in Mon Mar 1 17:57:18 2004 @@ -15,8 +15,8 @@ */ #undef HAVE_ALLOCA_H -/* define if the compiler has bidirectional iterator */ -#undef HAVE_BI_ITERATOR +/* Define to 1 if you have the `backtrace' function. */ +#undef HAVE_BACKTRACE /* Define to 1 if you have the header file. */ #undef HAVE_DLFCN_H @@ -24,15 +24,12 @@ /* Define if dlopen() is available on this platform. */ #undef HAVE_DLOPEN -/* define if the compiler has ext/slist */ -#undef HAVE_EXT_SLIST +/* Define to 1 if you have the header file. */ +#undef HAVE_EXECINFO_H /* Define to 1 if you have the header file. */ #undef HAVE_FCNTL_H -/* define if the compiler has STL iterators */ -#undef HAVE_FWD_ITERATOR - /* Define to 1 if you have the `getcwd' function. */ #undef HAVE_GETCWD @@ -42,22 +39,6 @@ /* Define to 1 if you have the `gettimeofday' function. */ #undef HAVE_GETTIMEOFDAY -/* Define if the compiler has a header that defines template class - ::hash_map. */ -#undef HAVE_GLOBAL_HASH_MAP - -/* Define if the compiler has a header that defines template class - ::hash_set. */ -#undef HAVE_GLOBAL_HASH_SET - -/* Define if the compiler has a header that defines template - class __gnu_cxx::hash_map. */ -#undef HAVE_GNU_EXT_HASH_MAP - -/* Define if the compiler has a header that defines template - class __gnu_cxx::hash_set. */ -#undef HAVE_GNU_EXT_HASH_SET - /* Define to 1 if the system has the type `int64_t'. */ #undef HAVE_INT64_T @@ -102,27 +83,12 @@ /* Define to have the %a format string */ #undef HAVE_PRINTF_A -/* Define if PThread mutexes (e.g., pthread_mutex_lock) are available in the - system's thread library. */ -#undef HAVE_PTHREAD_MUTEX_LOCK - /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H -/* Define if the compiler has a header that defines template - class std::hash_map. */ -#undef HAVE_STD_EXT_HASH_MAP - -/* Define if the compiler has a header that defines template - class std::hash_set. */ -#undef HAVE_STD_EXT_HASH_SET - -/* define if the compiler has STL iterators */ -#undef HAVE_STD_ITERATOR - /* Define to 1 if you have the `strdup' function. */ #undef HAVE_STRDUP @@ -179,6 +145,9 @@ /* Define as the return type of signal handlers (`int' or `void'). */ #undef RETSIGTYPE + +/* Extension that shared libraries have, e.g., ".so". */ +#undef SHLIBEXT /* If using the C implementation of alloca, define if you know the direction of stack growth for your system; otherwise it will be From brukman at cs.uiuc.edu Mon Mar 1 17:58:11 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Mar 1 17:58:11 2004 Subject: [llvm-commits] [parallel] CVS: llvm/include/Config/sys/resource.h stat.h time.h types.h wait.h Message-ID: <200403012357.RAA03219@zion.cs.uiuc.edu> Changes in directory llvm/include/Config/sys: resource.h updated: 1.3 -> 1.3.6.1 stat.h updated: 1.3 -> 1.3.6.1 time.h updated: 1.3 -> 1.3.6.1 types.h updated: 1.3 -> 1.3.6.1 wait.h updated: 1.3 -> 1.3.6.1 --- Log message: Merge from trunk --- Diffs of the changes: (+5 -5) Index: llvm/include/Config/sys/resource.h diff -u llvm/include/Config/sys/resource.h:1.3 llvm/include/Config/sys/resource.h:1.3.6.1 --- llvm/include/Config/sys/resource.h:1.3 Mon Oct 20 15:11:42 2003 +++ llvm/include/Config/sys/resource.h Mon Mar 1 17:57:18 2004 @@ -1,4 +1,4 @@ -/*===-- Config/sys/resource.h - Annotation classes --------------*- C++ -*-===// +/*===-- Config/sys/resource.h -----------------------------------*- C++ -*-===// * * The LLVM Compiler Infrastructure * Index: llvm/include/Config/sys/stat.h diff -u llvm/include/Config/sys/stat.h:1.3 llvm/include/Config/sys/stat.h:1.3.6.1 --- llvm/include/Config/sys/stat.h:1.3 Mon Oct 20 15:11:42 2003 +++ llvm/include/Config/sys/stat.h Mon Mar 1 17:57:18 2004 @@ -1,4 +1,4 @@ -/*===-- Config/sys/stat.h - Annotation classes --------------*- ----C++ -*-===// +/*===-- Config/sys/stat.h -----------------------------------*- ----C++ -*-===// * * The LLVM Compiler Infrastructure * Index: llvm/include/Config/sys/time.h diff -u llvm/include/Config/sys/time.h:1.3 llvm/include/Config/sys/time.h:1.3.6.1 --- llvm/include/Config/sys/time.h:1.3 Mon Oct 20 15:11:43 2003 +++ llvm/include/Config/sys/time.h Mon Mar 1 17:57:18 2004 @@ -1,4 +1,4 @@ -/*===-- Config/sys/time.h - Annotation classes ------------------*- C++ -*-===// +/*===-- Config/sys/time.h ---------------------------------------*- C++ -*-===// * * The LLVM Compiler Infrastructure * Index: llvm/include/Config/sys/types.h diff -u llvm/include/Config/sys/types.h:1.3 llvm/include/Config/sys/types.h:1.3.6.1 --- llvm/include/Config/sys/types.h:1.3 Mon Oct 20 15:11:43 2003 +++ llvm/include/Config/sys/types.h Mon Mar 1 17:57:18 2004 @@ -1,4 +1,4 @@ -/*===-- Config/sys/types.h - Annotation classes --------------*- C++ -*-===// +/*===-- Config/sys/types.h --------------------------------------*- C++ -*-===// * * The LLVM Compiler Infrastructure * Index: llvm/include/Config/sys/wait.h diff -u llvm/include/Config/sys/wait.h:1.3 llvm/include/Config/sys/wait.h:1.3.6.1 --- llvm/include/Config/sys/wait.h:1.3 Mon Oct 20 15:11:43 2003 +++ llvm/include/Config/sys/wait.h Mon Mar 1 17:57:18 2004 @@ -1,4 +1,4 @@ -/*===-- Config/sys/wait.h - Annotation classes ------------------*- C++ -*-===// +/*===-- Config/sys/wait.h ---------------------------------------*- C++ -*-===// * * The LLVM Compiler Infrastructure * From brukman at cs.uiuc.edu Mon Mar 1 17:58:14 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Mar 1 17:58:14 2004 Subject: [llvm-commits] [parallel] CVS: llvm/include/boost/config/platform/aix.hpp amigaos.hpp beos.hpp bsd.hpp cygwin.hpp hpux.hpp irix.hpp linux.hpp macos.hpp solaris.hpp win32.hpp Message-ID: <200403012357.RAA03268@zion.cs.uiuc.edu> Changes in directory llvm/include/boost/config/platform: aix.hpp (r1.1) removed amigaos.hpp (r1.1) removed beos.hpp (r1.1) removed bsd.hpp (r1.1) removed cygwin.hpp (r1.1) removed hpux.hpp (r1.1) removed irix.hpp (r1.1) removed linux.hpp (r1.1) removed macos.hpp (r1.1) removed solaris.hpp (r1.1) removed win32.hpp (r1.1) removed --- Log message: Merge from trunk --- Diffs of the changes: (+0 -0) From brukman at cs.uiuc.edu Mon Mar 1 17:58:18 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Mar 1 17:58:18 2004 Subject: [llvm-commits] [parallel] CVS: llvm/include/boost/LICENSE.TXT README.boost.llvm config.hpp type_traits.hpp Message-ID: <200403012357.RAA03237@zion.cs.uiuc.edu> Changes in directory llvm/include/boost: LICENSE.TXT (r1.1) removed README.boost.llvm (r1.1) removed config.hpp (r1.1) removed type_traits.hpp (r1.1) removed --- Log message: Merge from trunk --- Diffs of the changes: (+0 -0) From brukman at cs.uiuc.edu Mon Mar 1 17:58:23 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Mar 1 17:58:23 2004 Subject: [llvm-commits] [parallel] CVS: llvm/include/boost/config/compiler/borland.hpp comeau.hpp common_edg.hpp compaq_cxx.hpp gcc.hpp greenhills.hpp hp_acc.hpp intel.hpp kai.hpp metrowerks.hpp mpw.hpp sgi_mipspro.hpp sunpro_cc.hpp vacpp.hpp visualc.hpp Message-ID: <200403012357.RAA03258@zion.cs.uiuc.edu> Changes in directory llvm/include/boost/config/compiler: borland.hpp (r1.1) removed comeau.hpp (r1.1) removed common_edg.hpp (r1.1) removed compaq_cxx.hpp (r1.1) removed gcc.hpp (r1.4) removed greenhills.hpp (r1.1) removed hp_acc.hpp (r1.1) removed intel.hpp (r1.1) removed kai.hpp (r1.1) removed metrowerks.hpp (r1.1) removed mpw.hpp (r1.1) removed sgi_mipspro.hpp (r1.1) removed sunpro_cc.hpp (r1.1) removed vacpp.hpp (r1.1) removed visualc.hpp (r1.1) removed --- Log message: Merge from trunk --- Diffs of the changes: (+0 -0) From brukman at cs.uiuc.edu Mon Mar 1 17:58:32 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Mar 1 17:58:32 2004 Subject: [llvm-commits] [parallel] CVS: llvm/include/Support/DataTypes.h.in DenseMap.h ELF.h ThreadSupport.h.in hash_map.in hash_set.in iterator.in type_traits.h Annotation.h CommandLine.h FileUtilities.h GraphWriter.h MathExtras.h STLExtras.h Signals.h Statistic.h ilist DataTypes.h ThreadSupport.h hash_map hash_set iterator Message-ID: <200403012357.RAA03285@zion.cs.uiuc.edu> Changes in directory llvm/include/Support: DataTypes.h.in added (r1.1.2.1) DenseMap.h added (r1.3.2.1) ELF.h added (r1.4.2.1) ThreadSupport.h.in added (r1.1.2.1) hash_map.in added (r1.1.2.1) hash_set.in added (r1.1.2.1) iterator.in added (r1.1.2.1) type_traits.h added (r1.1.2.1) Annotation.h updated: 1.13 -> 1.13.4.1 CommandLine.h updated: 1.29 -> 1.29.4.1 FileUtilities.h updated: 1.14 -> 1.14.2.1 GraphWriter.h updated: 1.18 -> 1.18.4.1 MathExtras.h updated: 1.10 -> 1.10.4.1 STLExtras.h updated: 1.13 -> 1.13.4.1 Signals.h updated: 1.8 -> 1.8.2.1 Statistic.h updated: 1.9 -> 1.9.2.1 ilist updated: 1.16 -> 1.16.4.1 DataTypes.h (r1.18) removed ThreadSupport.h (r1.2) removed hash_map (r1.14) removed hash_set (r1.13) removed iterator (r1.6) removed --- Log message: Merge from trunk --- Diffs of the changes: (+876 -45) Index: llvm/include/Support/DataTypes.h.in diff -c /dev/null llvm/include/Support/DataTypes.h.in:1.1.2.1 *** /dev/null Mon Mar 1 17:57:29 2004 --- llvm/include/Support/DataTypes.h.in Mon Mar 1 17:57:18 2004 *************** *** 0 **** --- 1,45 ---- + //===-- include/Support/DataTypes.h - Define fixed size types ---*- C++ -*-===// + // + // The LLVM Compiler Infrastructure + // + // This file was developed by the LLVM research group and is distributed under + // the University of Illinois Open Source License. See LICENSE.TXT for details. + // + //===----------------------------------------------------------------------===// + // + // This file contains 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: + // + // int64_t : is a typedef for the signed 64 bit system type + // uint64_t : is a typedef for the unsigned 64 bit system type + // INT64_MAX : is a #define specifying the max value for int64_t's + // + // No library is required when using these functinons. + // + //===----------------------------------------------------------------------===// + + #ifndef SUPPORT_DATATYPES_H + #define SUPPORT_DATATYPES_H + + // 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 + + // Note that includes , if this is a C99 system. + @INCLUDE_INTTYPES_H@ + @INCLUDE_SYS_TYPES_H@ + + #if !defined(INT64_MAX) + /* We couldn't determine INT64_MAX; default it. */ + # define INT64_MAX 9223372036854775807LL + #endif + #if !defined(UINT64_MAX) + # define UINT64_MAX 0xffffffffffffffffULL + #endif + + #endif /* SUPPORT_DATATYPES_H */ Index: llvm/include/Support/DenseMap.h diff -c /dev/null llvm/include/Support/DenseMap.h:1.3.2.1 *** /dev/null Mon Mar 1 17:57:29 2004 --- llvm/include/Support/DenseMap.h Mon Mar 1 17:57:18 2004 *************** *** 0 **** --- 1,63 ---- + //===- DenseMap.h - A dense map implmentation -------------------*- C++ -*-===// + // + // The LLVM Compiler Infrastructure + // + // This file was developed by the LLVM research group and is distributed under + // the University of Illinois Open Source License. See LICENSE.TXT for details. + // + //===----------------------------------------------------------------------===// + // + // This file implements a dense map. A dense map template takes two + // types. The first is the mapped type and the second is a functor + // that maps its argument to a size_t. On instantiation a "null" value + // can be provided to be used as a "does not exist" indicator in the + // map. A member function grow() is provided that given the value of + // the maximally indexed key (the argument of the functor) makes sure + // the map has enough space for it. + // + //===----------------------------------------------------------------------===// + + #ifndef SUPPORT_DENSEMAP_H + #define SUPPORT_DENSEMAP_H + + #include + + namespace llvm { + + template + class DenseMap { + typedef typename ToIndexT::argument_type IndexT; + typedef std::vector StorageT; + StorageT storage_; + T nullVal_; + ToIndexT toIndex_; + + public: + DenseMap() : nullVal_(T()) { } + + explicit DenseMap(const T& val) : nullVal_(val) { } + + typename StorageT::reference operator[](IndexT n) { + assert(toIndex_(n) < storage_.size() && "index out of bounds!"); + return storage_[toIndex_(n)]; + } + + typename StorageT::const_reference operator[](IndexT n) const { + assert(toIndex_(n) < storage_.size() && "index out of bounds!"); + return storage_[toIndex_(n)]; + } + + void clear() { + storage_.clear(); + } + + void grow(IndexT n) { + unsigned NewSize = toIndex_(n) + 1; + if (NewSize > storage_.size()) + storage_.resize(NewSize, nullVal_); + } + }; + + } // End llvm namespace + + #endif Index: llvm/include/Support/ELF.h diff -c /dev/null llvm/include/Support/ELF.h:1.4.2.1 *** /dev/null Mon Mar 1 17:57:29 2004 --- llvm/include/Support/ELF.h Mon Mar 1 17:57:18 2004 *************** *** 0 **** --- 1,295 ---- + //===-- Support/ELF.h - ELF constants and data structures -------*- C++ -*-===// + // + // The LLVM Compiler Infrastructure + // + // This file was developed by the LLVM research group and is distributed under + // the University of Illinois Open Source License. See LICENSE.TXT for details. + // + //===----------------------------------------------------------------------===// + // + // This header contains common, non-processor-specific data structures and + // constants for the ELF file format. + // + // The details of the ELF32 bits in this file are largely based on + // the Tool Interface Standard (TIS) Executable and Linking Format + // (ELF) Specification Version 1.2, May 1995. The ELF64 stuff is not + // standardized, as far as I can tell. It was largely based on information + // I found in OpenBSD header files. + // + //===----------------------------------------------------------------------===// + + #include "Support/DataTypes.h" + #include + #include + + namespace llvm { + + namespace ELF { + + typedef uint32_t Elf32_Addr; // Program address + typedef uint16_t Elf32_Half; + typedef uint32_t Elf32_Off; // File offset + typedef int32_t Elf32_Sword; + typedef uint32_t Elf32_Word; + + typedef uint64_t Elf64_Addr; + typedef uint64_t Elf64_Off; + typedef int32_t Elf64_Shalf; + typedef int32_t Elf64_Sword; + typedef uint32_t Elf64_Word; + typedef int64_t Elf64_Sxword; + typedef uint64_t Elf64_Xword; + typedef uint32_t Elf64_Half; + typedef uint16_t Elf64_Quarter; + + // Object file magic string. + static const char ElfMagic[] = { 0x7f, 'E', 'L', 'F', '\0' }; + + struct Elf32_Ehdr { + unsigned char e_ident[16]; // ELF Identification bytes + Elf32_Half e_type; // Type of file (see ET_* below) + Elf32_Half e_machine; // Required architecture for this file (see EM_*) + Elf32_Word e_version; // Must be equal to 1 + Elf32_Addr e_entry; // Address to jump to in order to start program + Elf32_Off e_phoff; // Program header table's file offset, in bytes + Elf32_Off e_shoff; // Section header table's file offset, in bytes + Elf32_Word e_flags; // Processor-specific flags + Elf32_Half e_ehsize; // Size of ELF header, in bytes + Elf32_Half e_phentsize; // Size of an entry in the program header table + Elf32_Half e_phnum; // Number of entries in the program header table + Elf32_Half e_shentsize; // Size of an entry in the section header table + Elf32_Half e_shnum; // Number of entries in the section header table + Elf32_Half e_shstrndx; // Sect hdr table index of sect name string table + bool checkMagic () const { + return (memcmp (e_ident, ElfMagic, strlen (ElfMagic))) == 0; + } + unsigned char getFileClass () const { return e_ident[4]; } + unsigned char getDataEncoding () { return e_ident[5]; } + }; + + // 64-bit ELF header. Fields are the same as for ELF32, but with different + // types (see above). + struct Elf64_Ehdr { + unsigned char e_ident[16]; + Elf64_Quarter e_type; + Elf64_Quarter e_machine; + Elf64_Half e_version; + Elf64_Addr e_entry; + Elf64_Off e_phoff; + Elf64_Off e_shoff; + Elf64_Half e_flags; + Elf64_Quarter e_ehsize; + Elf64_Quarter e_phentsize; + Elf64_Quarter e_phnum; + Elf64_Quarter e_shentsize; + Elf64_Quarter e_shnum; + Elf64_Quarter e_shstrndx; + }; + + // File types + enum { + ET_NONE = 0, // No file type + ET_REL = 1, // Relocatable file + ET_EXEC = 2, // Executable file + ET_DYN = 3, // Shared object file + ET_CORE = 4, // Core file + ET_LOPROC = 0xff00, // Beginning of processor-specific codes + ET_HIPROC = 0xffff // Processor-specific + }; + + // Machine architectures + enum { + EM_NONE = 0, // No machine + EM_M32 = 1, // AT&T WE 32100 + EM_SPARC = 2, // SPARC + EM_386 = 3, // Intel 386 + EM_68K = 4, // Motorola 68000 + EM_88K = 5, // Motorola 88000 + EM_486 = 6, // Intel 486 (deprecated) + EM_860 = 7, // Intel 80860 + EM_MIPS = 8, // MIPS R3000 + EM_PPC = 20, // PowerPC + EM_ARM = 40, // ARM + EM_ALPHA = 41, // DEC Alpha + EM_SPARCV9 = 43 // SPARC V9 + }; + + // Object file classes. + enum { + ELFCLASS32 = 1, // 32-bit object file + ELFCLASS64 = 2 // 64-bit object file + }; + + // Object file byte orderings. + enum { + ELFDATA2LSB = 1, // Little-endian object file + ELFDATA2MSB = 2 // Big-endian object file + }; + + // Section header. + struct Elf32_Shdr { + Elf32_Word sh_name; // Section name (index into string table) + Elf32_Word sh_type; // Section type (SHT_*) + Elf32_Word sh_flags; // Section flags (SHF_*) + Elf32_Addr sh_addr; // Address where section is to be loaded + Elf32_Off sh_offset; // File offset of section data, in bytes + Elf32_Word sh_size; // Size of section, in bytes + Elf32_Word sh_link; // Section type-specific header table index link + Elf32_Word sh_info; // Section type-specific extra information + Elf32_Word sh_addralign; // Section address alignment + Elf32_Word sh_entsize; // Size of records contained within the section + }; + + // Section header for ELF64 - same fields as ELF32, different types. + struct Elf64_Shdr { + Elf64_Half sh_name; + Elf64_Half sh_type; + Elf64_Xword sh_flags; + Elf64_Addr sh_addr; + Elf64_Off sh_offset; + Elf64_Xword sh_size; + Elf64_Half sh_link; + Elf64_Half sh_info; + Elf64_Xword sh_addralign; + Elf64_Xword sh_entsize; + }; + + // Special section indices. + enum { + SHN_UNDEF = 0, // Undefined, missing, irrelevant, or meaningless + SHN_LORESERVE = 0xff00, // Lowest reserved index + SHN_LOPROC = 0xff00, // Lowest processor-specific index + SHN_HIPROC = 0xff1f, // Highest processor-specific index + SHN_ABS = 0xfff1, // Symbol has absolute value; does not need relocation + SHN_COMMON = 0xfff2, // FORTRAN COMMON or C external global variables + SHN_HIRESERVE = 0xffff // Highest reserved index + }; + + // Section types. + enum { + SHT_NULL = 0, // No associated section (inactive entry). + SHT_PROGBITS = 1, // Program-defined contents. + SHT_SYMTAB = 2, // Symbol table. + SHT_STRTAB = 3, // String table. + SHT_RELA = 4, // Relocation entries; explicit addends. + SHT_HASH = 5, // Symbol hash table. + SHT_DYNAMIC = 6, // Information for dynamic linking. + SHT_NOTE = 7, // Information about the file. + SHT_NOBITS = 8, // Data occupies no space in the file. + SHT_REL = 9, // Relocation entries; no explicit addends. + SHT_SHLIB = 10, // Reserved. + SHT_DYNSYM = 11, // Symbol table. + SHT_LOPROC = 0x70000000, // Lowest processor architecture-specific type. + SHT_HIPROC = 0x7fffffff, // Highest processor architecture-specific type. + SHT_LOUSER = 0x80000000, // Lowest type reserved for applications. + SHT_HIUSER = 0xffffffff // Highest type reserved for applications. + }; + + // Section flags. + enum { + SHF_WRITE = 0x1, // Section data should be writable during execution. + SHF_ALLOC = 0x2, // Section occupies memory during program execution. + SHF_EXECINSTR = 0x4, // Section contains executable machine instructions. + SHF_MASKPROC = 0xf0000000 // Bits indicating processor-specific flags. + }; + + // Symbol table entries. + struct Elf32_Sym { + Elf32_Word st_name; // Symbol name (index into string table) + Elf32_Addr st_value; // Value or address associated with the symbol + Elf32_Word st_size; // Size of the symbol + unsigned char st_info; // Symbol's type and binding attributes + unsigned char st_other; // Must be zero; reserved + Elf32_Half st_shndx; // Which section (header table index) it's defined in + + // These accessors and mutators correspond to the ELF32_ST_BIND, + // ELF32_ST_TYPE, and ELF32_ST_INFO macros defined in the ELF specification: + unsigned char getBinding () const { return st_info >> 4; } + unsigned char getType () const { return st_info & 0x0f; } + void setBinding (unsigned char b) { setBindingAndType (b, getType ()); } + void setType (unsigned char t) { setBindingAndType (getBinding (), t); } + void setBindingAndType (unsigned char b, unsigned char t) { + st_info = (b << 4) + (t & 0x0f); + } + }; + + // Symbol bindings. + enum { + STB_LOCAL = 0, // Local symbol, not visible outside obj file containing def + STB_GLOBAL = 1, // Global symbol, visible to all object files being combined + STB_WEAK = 2, // Weak symbol, like global but lower-precedence + STB_LOPROC = 13, // Lowest processor-specific binding type + STB_HIPROC = 15 // Highest processor-specific binding type + }; + + // Symbol types. + enum { + STT_NOTYPE = 0, // Symbol's type is not specified + STT_OBJECT = 1, // Symbol is a data object (variable, array, etc.) + STT_FUNC = 2, // Symbol is executable code (function, etc.) + STT_SECTION = 3, // Symbol refers to a section + STT_FILE = 4, // Local, absolute symbol that refers to a file + STT_LOPROC = 13, // Lowest processor-specific symbol type + STT_HIPROC = 15 // Highest processor-specific symbol type + }; + + // Relocation entry, without explicit addend. + struct Elf32_Rel { + Elf32_Addr r_offset; // Location (file byte offset, or program virtual addr) + Elf32_Word r_info; // Symbol table index and type of relocation to apply + + // These accessors and mutators correspond to the ELF32_R_SYM, ELF32_R_TYPE, + // and ELF32_R_INFO macros defined in the ELF specification: + Elf32_Word getSymbol () const { return (r_info >> 8); } + unsigned char getType () const { return (unsigned char) (r_info & 0x0ff); } + void setSymbol (Elf32_Word s) { setSymbolAndType (s, getType ()); } + void setType (unsigned char t) { setSymbolAndType (getSymbol(), t); } + void setSymbolAndType (Elf32_Word s, unsigned char t) { + r_info = (s << 8) + t; + }; + }; + + // Relocation entry with explicit addend. + struct Elf32_Rela { + Elf32_Addr r_offset; // Location (file byte offset, or program virtual addr) + Elf32_Word r_info; // Symbol table index and type of relocation to apply + Elf32_Sword r_addend; // Compute value for relocatable field by adding this + + // These accessors and mutators correspond to the ELF32_R_SYM, ELF32_R_TYPE, + // and ELF32_R_INFO macros defined in the ELF specification: + Elf32_Word getSymbol () const { return (r_info >> 8); } + unsigned char getType () const { return (unsigned char) (r_info & 0x0ff); } + void setSymbol (Elf32_Word s) { setSymbolAndType (s, getType ()); } + void setType (unsigned char t) { setSymbolAndType (getSymbol(), t); } + void setSymbolAndType (Elf32_Word s, unsigned char t) { + r_info = (s << 8) + t; + }; + }; + + // Program header. + struct Elf32_Phdr { + Elf32_Word p_type; // Type of segment + Elf32_Off p_offset; // File offset where segment is located, in bytes + Elf32_Addr p_vaddr; // Virtual address of beginning of segment + Elf32_Addr p_paddr; // Physical address of beginning of segment (OS-specific) + Elf32_Word p_filesz; // Num. of bytes in file image of segment (may be zero) + Elf32_Word p_memsz; // Num. of bytes in mem image of segment (may be zero) + Elf32_Word p_flags; // Segment flags + Elf32_Word p_align; // Segment alignment constraint + }; + + enum { + PT_NULL = 0, // Unused segment. + PT_LOAD = 1, // Loadable segment. + PT_DYNAMIC = 2, // Dynamic linking information. + PT_INTERP = 3, // Interpreter pathname. + PT_NOTE = 4, // Auxiliary information. + PT_SHLIB = 5, // Reserved. + PT_PHDR = 6, // The program header table itself. + PT_LOPROC = 0x70000000, // Lowest processor-specific program hdr entry type. + PT_HIPROC = 0x7fffffff // Highest processor-specific program hdr entry type. + }; + + } // end namespace ELF + + } // end namespace llvm Index: llvm/include/Support/ThreadSupport.h.in diff -c /dev/null llvm/include/Support/ThreadSupport.h.in:1.1.2.1 *** /dev/null Mon Mar 1 17:57:29 2004 --- llvm/include/Support/ThreadSupport.h.in Mon Mar 1 17:57:18 2004 *************** *** 0 **** --- 1,40 ---- + //===-- Support/ThreadSupport.h - Generic threading support -----*- C++ -*-===// + // + // The LLVM Compiler Infrastructure + // + // This file was developed by the LLVM research group and is distributed under + // the University of Illinois Open Source License. See LICENSE.TXT for details. + // + //===----------------------------------------------------------------------===// + // + // This file defines platform-agnostic interfaces that can be used to write + // multi-threaded programs. Autoconf is used to chose the correct + // implementation of these interfaces, or default to a non-thread-capable system + // if no matching system support is available. + // + //===----------------------------------------------------------------------===// + + #ifndef SUPPORT_THREADSUPPORT_H + #define SUPPORT_THREADSUPPORT_H + + #if @HAVE_PTHREAD_MUTEX_LOCK@ + #include "Support/ThreadSupport-PThreads.h" + #else + #include "Support/ThreadSupport-NoSupport.h" + #endif // If no system support is available + + namespace llvm { + /// MutexLocker - Instances of this class acquire a given Lock when + /// constructed and hold that lock until destruction. + /// + class MutexLocker { + Mutex &M; + MutexLocker(const MutexLocker &); // DO NOT IMPLEMENT + void operator=(const MutexLocker &); // DO NOT IMPLEMENT + public: + MutexLocker(Mutex &m) : M(m) { M.acquire(); } + ~MutexLocker() { M.release(); } + }; + } + + #endif // SUPPORT_THREADSUPPORT_H Index: llvm/include/Support/hash_map.in diff -c /dev/null llvm/include/Support/hash_map.in:1.1.2.1 *** /dev/null Mon Mar 1 17:57:29 2004 --- llvm/include/Support/hash_map.in Mon Mar 1 17:57:18 2004 *************** *** 0 **** --- 1,66 ---- + //===-- Support/hash_map - "Portable" wrapper around hash_map ---*- C++ -*-===// + // + // The LLVM Compiler Infrastructure + // + // This file was developed by the LLVM research group and is distributed under + // the University of Illinois Open Source License. See LICENSE.TXT for details. + // + //===----------------------------------------------------------------------===// + // + // This file provides a wrapper around the mysterious header file + // that seems to move around between GCC releases into and out of namespaces at + // will. #including this header will cause hash_map to be available in the + // global namespace. + // + //===----------------------------------------------------------------------===// + + #ifndef SUPPORT_HASH_MAP + #define SUPPORT_HASH_MAP + + // Compiler Support Matrix + // + // Version Namespace Header File + // 2.95.x :: hash_map + // 3.0.4 std ext/hash_map + // 3.1 __gnu_cxx ext/hash_map + // + + #if @HAVE_GNU_EXT_HASH_MAP@ + // This is for GCC-3.1+ which puts hash in ext/hash_map + # include + # ifndef HASH_NAMESPACE + # define HASH_NAMESPACE __gnu_cxx + # endif + + // GCC 3.0.x puts hash_map in and in the std namespace. + #elif @HAVE_STD_EXT_HASH_MAP@ + # include + # ifndef HASH_NAMESPACE + # define HASH_NAMESPACE std + # endif + + // Older compilers such as GCC before version 3.0 do not keep + // extensions in the `ext' directory, and ignore the `std' namespace. + #elif @HAVE_GLOBAL_HASH_MAP@ + # include + # ifndef HASH_NAMESPACE + # define HASH_NAMESPACE std + # endif + + // Give a warning if we couldn't find it, instead of (or in addition to) + // randomly doing something dumb. + #else + # warning "Autoconfiguration failed to find the hash_map header file." + #endif + + using HASH_NAMESPACE::hash_map; + using HASH_NAMESPACE::hash_multimap; + using HASH_NAMESPACE::hash; + + // Include vector because ext/hash_map includes stl_vector.h and leaves + // out specializations like stl_bvector.h, causing link conflicts. + #include + + #include + + #endif Index: llvm/include/Support/hash_set.in diff -c /dev/null llvm/include/Support/hash_set.in:1.1.2.1 *** /dev/null Mon Mar 1 17:57:29 2004 --- llvm/include/Support/hash_set.in Mon Mar 1 17:57:18 2004 *************** *** 0 **** --- 1,67 ---- + //===-- Support/hash_set - "Portable" wrapper around hash_set ---*- C++ -*-===// + // + // The LLVM Compiler Infrastructure + // + // This file was developed by the LLVM research group and is distributed under + // the University of Illinois Open Source License. See LICENSE.TXT for details. + // + //===----------------------------------------------------------------------===// + // vim:ft=cpp + // + // This file provides a wrapper around the mysterious header file + // that seems to move around between GCC releases into and out of namespaces at + // will. #including this header will cause hash_set to be available in the + // global namespace. + // + //===----------------------------------------------------------------------===// + + #ifndef SUPPORT_HASH_SET + #define SUPPORT_HASH_SET + + // Compiler Support Matrix + // + // Version Namespace Header File + // 2.95.x :: hash_set + // 3.0.4 std ext/hash_set + // 3.1 __gnu_cxx ext/hash_set + // + + // GCC versions 3.1 and later put hash_set in and in + // the __gnu_cxx namespace. + #if @HAVE_GNU_EXT_HASH_SET@ + # include + # ifndef HASH_NAMESPACE + # define HASH_NAMESPACE __gnu_cxx + # endif + + // GCC 3.0.x puts hash_set in and in the std namespace. + #elif @HAVE_STD_EXT_HASH_SET@ + # include + # ifndef HASH_NAMESPACE + # define HASH_NAMESPACE std + # endif + + // Older compilers such as GCC before version 3.0 do not keep + // extensions in the `ext' directory, and ignore the `std' namespace. + #elif @HAVE_GLOBAL_HASH_SET@ + # include + # ifndef HASH_NAMESPACE + # define HASH_NAMESPACE std + # endif + + // Give a warning if we couldn't find it, instead of (or in addition to) + // randomly doing something dumb. + #else + # warning "Autoconfiguration failed to find the hash_set header file." + #endif + + using HASH_NAMESPACE::hash_set; + using HASH_NAMESPACE::hash; + + // Include vector because ext/hash_set includes stl_vector.h and leaves + // out specializations like stl_bvector.h, causing link conflicts. + #include + + #include + + #endif Index: llvm/include/Support/iterator.in diff -c /dev/null llvm/include/Support/iterator.in:1.1.2.1 *** /dev/null Mon Mar 1 17:57:29 2004 --- llvm/include/Support/iterator.in Mon Mar 1 17:57:18 2004 *************** *** 0 **** --- 1,66 ---- + //===-- Support/iterator - "Portable" wrapper around -*- C++ -*-===// + // + // The LLVM Compiler Infrastructure + // + // This file was developed by the LLVM research group and is distributed under + // the University of Illinois Open Source License. See LICENSE.TXT for details. + // + //===----------------------------------------------------------------------===// + // + // This file provides a wrapper around the mysterious header file. + // In GCC 2.95.3, the file defines a bidirectional_iterator class (and other + // friends), instead of the standard iterator class. In GCC 3.1, the + // bidirectional_iterator class got moved out and the new, standards compliant, + // iterator<> class was added. Because there is nothing that we can do to get + // correct behavior on both compilers, we have this header with #ifdef's. Gross + // huh? + // + // By #includ'ing this file, you get the contents of plus the + // following classes in the global namespace: + // + // 1. bidirectional_iterator + // 2. forward_iterator + // + // The #if directives' expressions are filled in by Autoconf. + // + //===----------------------------------------------------------------------===// + + #ifndef SUPPORT_ITERATOR + #define SUPPORT_ITERATOR + + #include + + #if !@HAVE_BI_ITERATOR@ + # if @HAVE_STD_ITERATOR@ + /// If the bidirectional iterator is not defined, we attempt to define it in + /// terms of the C++ standard iterator. Otherwise, we import it with a "using" + /// statement. + /// + template + struct bidirectional_iterator + : public std::iterator { + }; + # else + # error "Need to have standard iterator to define bidirectional iterator!" + # endif + #else + using std::bidirectional_iterator; + #endif + + #if !@HAVE_FWD_ITERATOR@ + # if @HAVE_STD_ITERATOR@ + /// If the forward iterator is not defined, attempt to define it in terms of + /// the C++ standard iterator. Otherwise, we import it with a "using" statement. + /// + template + struct forward_iterator + : public std::iterator { + }; + # else + # error "Need to have standard iterator to define forward iterator!" + # endif + #else + using std::forward_iterator; + #endif + + #endif Index: llvm/include/Support/type_traits.h diff -c /dev/null llvm/include/Support/type_traits.h:1.1.2.1 *** /dev/null Mon Mar 1 17:57:29 2004 --- llvm/include/Support/type_traits.h Mon Mar 1 17:57:18 2004 *************** *** 0 **** --- 1,54 ---- + //===- Support/type_traits.h - Simplfied type traits ------------*- C++ -*-===// + // + // The LLVM Compiler Infrastructure + // + // This file was developed by the LLVM research group and is distributed under + // the University of Illinois Open Source License. See LICENSE.TXT for details. + // + //===----------------------------------------------------------------------===// + // + // This file provides a template class that determines if a type is a class or + // not. The basic mechanism, based on using the pointer to member function of + // a zero argument to a function was "boosted" from the boost type_traits + // library. See http://www.boost.org/ for all the gory details. + // + //===----------------------------------------------------------------------===// + + #ifndef LLVM_SUPPORT_TYPE_TRAITS_H + #define LLVM_SUPPORT_TYPE_TRAITS_H + + // This is actually the conforming implementation which works with abstract + // classes. However, enough compilers have trouble with it that most will use + // the one in boost/type_traits/object_traits.hpp. This implementation actually + // works with VC7.0, but other interactions seem to fail when we use it. + + namespace llvm { + + namespace dont_use + { + // These two functions should never be used. They are helpers to + // the is_class template below. They cannot be located inside + // is_class because doing so causes at least GCC to think that + // the value of the "value" enumerator is not constant. Placing + // them out here (for some strange reason) allows the sizeof + // operator against them to magically be constant. This is + // important to make the is_class::value idiom zero cost. it + // evaluates to a constant 1 or 0 depending on whether the + // parameter T is a class or not (respectively). + template char is_class_helper(void(T::*)(void)); + template double is_class_helper(...); + } + + template + struct is_class + { + // is_class<> metafunction due to Paul Mensonides (leavings at attbi.com). For + // more details: + // http://groups.google.com/groups?hl=en&selm=000001c1cc83%24e154d5e0%247772e50c%40c161550a&rnum=1 + public: + enum { value = sizeof(char) == sizeof(dont_use::is_class_helper(0)) }; + }; + + } + + #endif Index: llvm/include/Support/Annotation.h diff -u llvm/include/Support/Annotation.h:1.13 llvm/include/Support/Annotation.h:1.13.4.1 --- llvm/include/Support/Annotation.h:1.13 Tue Nov 11 16:41:29 2003 +++ llvm/include/Support/Annotation.h Mon Mar 1 17:57:18 2004 @@ -68,7 +68,7 @@ Annotation *Next; // The next annotation in the linked list public: inline Annotation(AnnotationID id) : ID(id), Next(0) {} - virtual ~Annotation() {} // Designed to be subclassed + virtual ~Annotation(); // Designed to be subclassed // getID - Return the unique ID# of this annotation inline AnnotationID getID() const { return ID; } @@ -95,14 +95,7 @@ void operator=(const Annotable &); // Do not implement public: Annotable() : AnnotationList(0) {} - virtual ~Annotable() { // Virtual because it's designed to be subclassed... - Annotation *A = AnnotationList; - while (A) { - Annotation *Next = A->getNext(); - delete A; - A = Next; - } - } + virtual ~Annotable(); // Virtual because it's designed to be subclassed... // getAnnotation - Search the list for annotations of the specified ID. The // pointer returned is either null (if no annotations of the specified ID Index: llvm/include/Support/CommandLine.h diff -u llvm/include/Support/CommandLine.h:1.29 llvm/include/Support/CommandLine.h:1.29.4.1 --- llvm/include/Support/CommandLine.h:1.29 Sun Nov 16 14:21:13 2003 +++ llvm/include/Support/CommandLine.h Mon Mar 1 17:57:18 2004 @@ -20,14 +20,15 @@ #ifndef SUPPORT_COMMANDLINE_H #define SUPPORT_COMMANDLINE_H +#include "Support/type_traits.h" #include #include #include #include #include -#include "boost/type_traits/object_traits.hpp" namespace llvm { + /// cl Namespace - This namespace contains all of the command line option /// processing machinery. It is intentionally a short name to make qualified /// usage concise. @@ -719,7 +720,7 @@ class ParserClass = parser > class opt : public Option, public opt_storage::value> { + is_class::value> { ParserClass Parser; virtual bool handleOccurrence(const char *ArgName, const std::string &Arg) { Index: llvm/include/Support/FileUtilities.h diff -u llvm/include/Support/FileUtilities.h:1.14 llvm/include/Support/FileUtilities.h:1.14.2.1 --- llvm/include/Support/FileUtilities.h:1.14 Wed Dec 31 00:16:02 2003 +++ llvm/include/Support/FileUtilities.h Mon Mar 1 17:57:18 2004 @@ -131,6 +131,26 @@ return Ret; } }; + + /// FileRemover - This class is a simple object meant to be stack allocated. + /// If an exception is thrown from a region, the object removes the filename + /// specified (if deleteIt is true). + /// + class FileRemover { + std::string Filename; + bool DeleteIt; + public: + FileRemover(const std::string &filename, bool deleteIt = true) + : Filename(filename), DeleteIt(deleteIt) {} + + ~FileRemover() { + if (DeleteIt) removeFile(Filename); + } + + /// releaseFile - Take ownership of the file away from the FileRemover so it + /// will not be removed when the object is destroyed. + void releaseFile() { DeleteIt = false; } + }; } // End llvm namespace #endif Index: llvm/include/Support/GraphWriter.h diff -u llvm/include/Support/GraphWriter.h:1.18 llvm/include/Support/GraphWriter.h:1.18.4.1 --- llvm/include/Support/GraphWriter.h:1.18 Sun Nov 16 14:21:13 2003 +++ llvm/include/Support/GraphWriter.h Mon Mar 1 17:57:18 2004 @@ -117,7 +117,7 @@ } if (EI != EE) - O << "|truncated..."; + O << "|truncated..."; O << "}"; } O << "}\"];\n"; // Finish printing the "node" line @@ -126,6 +126,8 @@ EI = GTraits::child_begin(Node); for (unsigned i = 0; EI != EE && i != 64; ++EI, ++i) writeEdge(Node, i, EI); + for (; EI != EE; ++EI) + writeEdge(Node, 64, EI); } void writeEdge(NodeType *Node, unsigned edgeidx, child_iterator EI) { Index: llvm/include/Support/MathExtras.h diff -u llvm/include/Support/MathExtras.h:1.10 llvm/include/Support/MathExtras.h:1.10.4.1 --- llvm/include/Support/MathExtras.h:1.10 Sun Nov 16 14:21:13 2003 +++ llvm/include/Support/MathExtras.h Mon Mar 1 17:57:18 2004 @@ -18,6 +18,10 @@ namespace llvm { +#if defined(log2) +# undef log2 +#endif + inline unsigned log2(uint64_t C) { unsigned getPow; for (getPow = 0; C > 1; ++getPow) Index: llvm/include/Support/STLExtras.h diff -u llvm/include/Support/STLExtras.h:1.13 llvm/include/Support/STLExtras.h:1.13.4.1 --- llvm/include/Support/STLExtras.h:1.13 Sat Nov 22 21:50:31 2003 +++ llvm/include/Support/STLExtras.h Mon Mar 1 17:57:18 2004 @@ -73,9 +73,6 @@ // mapped_iterator - This is a simple iterator adapter that causes a function to // be dereferenced whenever operator* is invoked on the iterator. // -// It turns out that this is disturbingly similar to boost::transform_iterator -// -#if 1 template class mapped_iterator { RootIt current; @@ -131,28 +128,6 @@ return mapped_iterator<_Iterator, Func>(X.getCurrent() - N); } -#else - -// This fails to work, because some iterators are not classes, for example -// vector iterators are commonly value_type **'s -template -class mapped_iterator : public RootIt { - UnaryFunc Fn; -public: - typedef typename UnaryFunc::result_type value_type; - typedef typename UnaryFunc::result_type *pointer; - typedef void reference; // Can't modify value returned by fn - - typedef mapped_iterator _Self; - typedef RootIt super; - inline explicit mapped_iterator(const RootIt &I) : super(I) {} - inline mapped_iterator(const super &It) : super(It) {} - - inline value_type operator*() const { // All this work to do - return Fn(super::operator*()); // this little thing - } -}; -#endif // map_iterator - Provide a convenient way to create mapped_iterators, just like // make_pair is useful for creating pairs... @@ -160,6 +135,43 @@ template inline mapped_iterator map_iterator(const ItTy &I, FuncTy F) { return mapped_iterator(I, F); +} + + +// next/prior - These functions unlike std::advance do not modify the +// passed iterator but return a copy. +// +// next(myIt) returns copy of myIt incremented once +// next(myIt, n) returns copy of myIt incremented n times +// prior(myIt) returns copy of myIt decremented once +// prior(myIt, n) returns copy of myIt decremented n times + +template +inline ItTy next(ItTy it, Dist n) +{ + std::advance(it, n); + return it; +} + +template +inline ItTy next(ItTy it) +{ + std::advance(it, 1); + return it; +} + +template +inline ItTy prior(ItTy it, Dist n) +{ + std::advance(it, -n); + return it; +} + +template +inline ItTy prior(ItTy it) +{ + std::advance(it, -1); + return it; } Index: llvm/include/Support/Signals.h diff -u llvm/include/Support/Signals.h:1.8 llvm/include/Support/Signals.h:1.8.2.1 --- llvm/include/Support/Signals.h:1.8 Tue Dec 30 22:42:00 2003 +++ llvm/include/Support/Signals.h Mon Mar 1 17:57:18 2004 @@ -24,6 +24,9 @@ /// void RemoveFileOnSignal(const std::string &Filename); + /// PrintStackTraceOnErrorSignal - When an error signal (such as SIBABRT or + /// SIGSEGV) is delivered to the process, print a stack trace and then exit. + void PrintStackTraceOnErrorSignal(); } // End llvm namespace #endif Index: llvm/include/Support/Statistic.h diff -u llvm/include/Support/Statistic.h:1.9 llvm/include/Support/Statistic.h:1.9.2.1 --- llvm/include/Support/Statistic.h:1.9 Wed Jan 14 17:37:22 2004 +++ llvm/include/Support/Statistic.h Mon Mar 1 17:57:18 2004 @@ -15,9 +15,9 @@ // This is useful for reporting information like the number of instructions // simplified, optimized or removed by various transformations, like this: // -// static Statistic<> NumInstEliminated("GCSE - Number of instructions killed"); +// static Statistic<> NumInstsKilled("gcse", "Number of instructions killed"); // -// Later, in the code: ++NumInstEliminated; +// Later, in the code: ++NumInstsKilled; // //===----------------------------------------------------------------------===// Index: llvm/include/Support/ilist diff -u llvm/include/Support/ilist:1.16 llvm/include/Support/ilist:1.16.4.1 --- llvm/include/Support/ilist:1.16 Sun Nov 16 19:07:58 2003 +++ llvm/include/Support/ilist Mon Mar 1 17:57:18 2004 @@ -152,15 +152,109 @@ return tmp; } + // Internal interface, do not use... + pointer getNodePtrUnchecked() const { return NodePtr; } +}; + +// do not implement. this is to catch errors when people try to use +// them as random access iterators +template +void operator-(int, ilist_iterator); +template +void operator-(ilist_iterator,int); + +template +void operator+(int, ilist_iterator); +template +void operator+(ilist_iterator,int); + +//===----------------------------------------------------------------------===// +// ilist_compat_iterator - Compatibility iterator for intrusive list. +// This makes an ilist act like an std::list, where you have to +// dereference stuff multiple times. This should only be used for temporary +// migration purposes. Because we don't support "changing the pointer", we only +// expose constant pointers. +// +template +class ilist_compat_iterator + : public bidirectional_iterator { + typedef ilist_traits Traits; + typedef bidirectional_iterator super; + +public: + typedef size_t size_type; + typedef typename super::pointer pointer; + typedef typename super::reference reference; +private: + NodeTy *NodePtr; +public: + + ilist_compat_iterator(NodeTy *NP) : NodePtr(NP) {} + ilist_compat_iterator() : NodePtr(0) {} + + // This is templated so that we can allow constructing a const iterator from + // a nonconst iterator... + template + ilist_compat_iterator(const ilist_compat_iterator &RHS) + : NodePtr(RHS.getNodePtrUnchecked()) {} + + // This is templated so that we can allow assigning to a const iterator from + // a nonconst iterator... + template + const ilist_compat_iterator &operator=(const + ilist_compat_iterator &RHS) { + NodePtr = RHS.getNodePtrUnchecked(); + return *this; + } - // Dummy operators to make errors apparent... - template void operator+(X Val) {} - template void operator-(X Val) {} + // Accessors... + operator pointer() const { + assert(Traits::getNext(NodePtr) != 0 && "Dereferencing end()!"); + return &NodePtr; + } + + reference operator*() const { + assert(Traits::getNext(NodePtr) != 0 && "Dereferencing end()!"); + return NodePtr; + } + pointer operator->() { return &operator*(); } + const pointer operator->() const { return &operator*(); } + + // Comparison operators + bool operator==(const ilist_compat_iterator &RHS) const { + return NodePtr == RHS.NodePtr; + } + bool operator!=(const ilist_compat_iterator &RHS) const { + return NodePtr != RHS.NodePtr; + } + + // Increment and decrement operators... + ilist_compat_iterator &operator--() { // predecrement - Back up + NodePtr = Traits::getPrev(NodePtr); + assert(NodePtr && "--'d off the beginning of an ilist!"); + return *this; + } + ilist_compat_iterator &operator++() { // preincrement - Advance + NodePtr = Traits::getNext(NodePtr); + assert(NodePtr && "++'d off the end of an ilist!"); + return *this; + } + ilist_compat_iterator operator--(int) { // postdecrement operators... + ilist_compat_iterator tmp = *this; + --*this; + return tmp; + } + ilist_compat_iterator operator++(int) { // postincrement operators... + ilist_compat_iterator tmp = *this; + ++*this; + return tmp; + } // Internal interface, do not use... pointer getNodePtrUnchecked() const { return NodePtr; } }; + // Allow ilist_iterators to convert into pointers to a node automatically when // used by the dyn_cast, cast, isa mechanisms... @@ -213,19 +307,25 @@ } ~iplist() { clear(); delete Tail; } - // Iterator creation methods... + // Iterator creation methods. iterator begin() { return iterator(Head); } const_iterator begin() const { return const_iterator(Head); } iterator end() { return iterator(Tail); } const_iterator end() const { return const_iterator(Tail); } - // reverse iterator creation methods... + // reverse iterator creation methods. reverse_iterator rbegin() { return reverse_iterator(end()); } const_reverse_iterator rbegin() const{ return const_reverse_iterator(end()); } reverse_iterator rend() { return reverse_iterator(begin()); } const_reverse_iterator rend() const {return const_reverse_iterator(begin());} - // Miscellaneous inspection routines... + + // "compatibility" iterator creation methods. + typedef ilist_compat_iterator compat_iterator; + compat_iterator compat_begin() const { return compat_iterator(Head); } + compat_iterator compat_end() const { return compat_iterator(Tail); } + + // Miscellaneous inspection routines. size_type max_size() const { return size_type(-1); } bool empty() const { return Head == Tail; } From brukman at cs.uiuc.edu Mon Mar 1 17:58:37 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Mar 1 17:58:37 2004 Subject: [llvm-commits] [parallel] CVS: llvm/include/boost/config/stdlib/dinkumware.hpp libstdcpp3.hpp modena.hpp msl.hpp roguewave.hpp sgi.hpp stlport.hpp vacpp.hpp Message-ID: <200403012357.RAA03278@zion.cs.uiuc.edu> Changes in directory llvm/include/boost/config/stdlib: dinkumware.hpp (r1.1) removed libstdcpp3.hpp (r1.1) removed modena.hpp (r1.1) removed msl.hpp (r1.1) removed roguewave.hpp (r1.1) removed sgi.hpp (r1.1) removed stlport.hpp (r1.1) removed vacpp.hpp (r1.1) removed --- Log message: Merge from trunk --- Diffs of the changes: (+0 -0) From brukman at cs.uiuc.edu Mon Mar 1 17:58:42 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Mar 1 17:58:42 2004 Subject: [llvm-commits] [parallel] CVS: llvm/include/boost/type_traits/alignment_traits.hpp arithmetic_traits.hpp array_traits.hpp composite_traits.hpp conversion_traits.hpp cv_traits.hpp function_traits.hpp fwd.hpp ice.hpp is_class.hpp object_traits.hpp reference_traits.hpp same_traits.hpp transform_traits.hpp transform_traits_spec.hpp type_traits_test.hpp utility.hpp Message-ID: <200403012357.RAA03290@zion.cs.uiuc.edu> Changes in directory llvm/include/boost/type_traits: alignment_traits.hpp (r1.1) removed arithmetic_traits.hpp (r1.1) removed array_traits.hpp (r1.1) removed composite_traits.hpp (r1.1) removed conversion_traits.hpp (r1.1) removed cv_traits.hpp (r1.1) removed function_traits.hpp (r1.1) removed fwd.hpp (r1.1) removed ice.hpp (r1.1) removed is_class.hpp (r1.1) removed object_traits.hpp (r1.1) removed reference_traits.hpp (r1.1) removed same_traits.hpp (r1.1) removed transform_traits.hpp (r1.1) removed transform_traits_spec.hpp (r1.1) removed type_traits_test.hpp (r1.1) removed utility.hpp (r1.1) removed --- Log message: Merge from trunk --- Diffs of the changes: (+0 -0) From brukman at cs.uiuc.edu Mon Mar 1 17:58:46 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Mar 1 17:58:46 2004 Subject: [llvm-commits] [parallel] CVS: llvm/include/llvm/Analysis/ProfileInfo.h ProfileInfoLoader.h AliasAnalysis.h DSGraph.h DSGraphTraits.h DSNode.h DSSupport.h LoopInfo.h PostDominators.h Message-ID: <200403012357.RAA03358@zion.cs.uiuc.edu> Changes in directory llvm/include/llvm/Analysis: ProfileInfo.h added (r1.2.2.1) ProfileInfoLoader.h added (r1.1.2.1) AliasAnalysis.h updated: 1.8 -> 1.8.4.1 DSGraph.h updated: 1.64 -> 1.64.4.1 DSGraphTraits.h updated: 1.18 -> 1.18.4.1 DSNode.h updated: 1.33 -> 1.33.4.1 DSSupport.h updated: 1.26 -> 1.26.4.1 LoopInfo.h updated: 1.30 -> 1.30.2.1 PostDominators.h updated: 1.7 -> 1.7.4.1 --- Log message: Merge from trunk --- Diffs of the changes: (+381 -89) Index: llvm/include/llvm/Analysis/ProfileInfo.h diff -c /dev/null llvm/include/llvm/Analysis/ProfileInfo.h:1.2.2.1 *** /dev/null Mon Mar 1 17:57:29 2004 --- llvm/include/llvm/Analysis/ProfileInfo.h Mon Mar 1 17:57:19 2004 *************** *** 0 **** --- 1,51 ---- + //===- llvm/Analysis/ProfileInfo.h - Profile Info Interface -----*- C++ -*-===// + // + // The LLVM Compiler Infrastructure + // + // This file was developed by the LLVM research group and is distributed under + // the University of Illinois Open Source License. See LICENSE.TXT for details. + // + //===----------------------------------------------------------------------===// + // + // This file defines the generic ProfileInfo interface, which is used as the + // common interface used by all clients of profiling information, and + // implemented either by making static guestimations, or by actually reading in + // profiling information gathered by running the program. + // + // Note that to be useful, all profile-based optimizations should preserve + // ProfileInfo, which requires that they notify it when changes to the CFG are + // made. + // + //===----------------------------------------------------------------------===// + + #ifndef LLVM_ANALYSIS_PROFILEINFO_H + #define LLVM_ANALYSIS_PROFILEINFO_H + + #include + + namespace llvm { + class BasicBlock; + class Pass; + + /// createProfileLoaderPass - This function returns a Pass that loads the + /// profiling information for the module from the specified filename, making + /// it available to the optimizers. + Pass *createProfileLoaderPass(const std::string &Filename); + + struct ProfileInfo { + virtual ~ProfileInfo(); // We want to be subclassed + + //===------------------------------------------------------------------===// + /// Profile Information Queries + /// + virtual unsigned getExecutionCount(BasicBlock *BB) = 0; + + //===------------------------------------------------------------------===// + /// Analysis Update Methods + /// + + }; + + } // End llvm namespace + + #endif Index: llvm/include/llvm/Analysis/ProfileInfoLoader.h diff -c /dev/null llvm/include/llvm/Analysis/ProfileInfoLoader.h:1.1.2.1 *** /dev/null Mon Mar 1 17:57:29 2004 --- llvm/include/llvm/Analysis/ProfileInfoLoader.h Mon Mar 1 17:57:19 2004 *************** *** 0 **** --- 1,65 ---- + //===- ProfileInfoLoader.h - Load & convert profile information -*- C++ -*-===// + // + // The LLVM Compiler Infrastructure + // + // This file was developed by the LLVM research group and is distributed under + // the University of Illinois Open Source License. See LICENSE.TXT for details. + // + //===----------------------------------------------------------------------===// + // + // The ProfileInfoLoader class is used to load and represent profiling + // information read in from the dump file. If conversions between formats are + // needed, it can also do this. + // + //===----------------------------------------------------------------------===// + + #ifndef LLVM_ANALYSIS_PROFILEINFOLOADER_H + #define LLVM_ANALYSIS_PROFILEINFOLOADER_H + + #include + #include + #include + + namespace llvm { + + class Module; + class Function; + class BasicBlock; + + class ProfileInfoLoader { + Module &M; + std::vector CommandLines; + std::vector FunctionCounts; + std::vector BlockCounts; + public: + // ProfileInfoLoader ctor - Read the specified profiling data file, exiting + // the program if the file is invalid or broken. + ProfileInfoLoader(const char *ToolName, const std::string &Filename, + Module &M); + + unsigned getNumExecutions() const { return CommandLines.size(); } + const std::string &getExecution(unsigned i) const { return CommandLines[i]; } + + // getFunctionCounts - This method is used by consumers of function counting + // information. If we do not directly have function count information, we + // compute it from other, more refined, types of profile information. + // + void getFunctionCounts(std::vector > &Counts); + + // hasAccurateBlockCounts - Return true if we can synthesize accurate block + // frequency information from whatever we have. + // + bool hasAccurateBlockCounts() const { + return !BlockCounts.empty(); + } + + // getBlockCounts - This method is used by consumers of block counting + // information. If we do not directly have block count information, we + // compute it from other, more refined, types of profile information. + // + void getBlockCounts(std::vector > &Counts); + }; + + } // End llvm namespace + + #endif Index: llvm/include/llvm/Analysis/AliasAnalysis.h diff -u llvm/include/llvm/Analysis/AliasAnalysis.h:1.8 llvm/include/llvm/Analysis/AliasAnalysis.h:1.8.4.1 --- llvm/include/llvm/Analysis/AliasAnalysis.h:1.8 Wed Dec 10 23:05:02 2003 +++ llvm/include/llvm/Analysis/AliasAnalysis.h Mon Mar 1 17:57:19 2004 @@ -31,15 +31,13 @@ #define LLVM_ANALYSIS_ALIAS_ANALYSIS_H #include "llvm/Support/CallSite.h" -#include "llvm/Pass.h" +#include "llvm/Pass.h" // Need this for IncludeFile namespace llvm { class LoadInst; class StoreInst; class TargetData; -class AnalysisUsage; -class Pass; class AliasAnalysis { const TargetData *TD; @@ -95,6 +93,11 @@ /// virtual void getMustAliases(Value *P, std::vector &RetVals) {} + /// pointsToConstantMemory - If the specified pointer is known to point into + /// constant global memory, return true. This allows disambiguation of store + /// instructions from constant pointers. + /// + virtual bool pointsToConstantMemory(const Value *P) { return false; } //===--------------------------------------------------------------------===// /// Simple mod/ref information... @@ -114,7 +117,9 @@ /// pointer. /// virtual ModRefResult getModRefInfo(CallSite CS, Value *P, unsigned Size) { - return ModRef; + // If P points to a constant memory location, the call definitely could not + // modify the memory location. + return pointsToConstantMemory(P) ? Ref : ModRef; } /// getModRefInfo - Return information about whether two call sites may refer Index: llvm/include/llvm/Analysis/DSGraph.h diff -u llvm/include/llvm/Analysis/DSGraph.h:1.64 llvm/include/llvm/Analysis/DSGraph.h:1.64.4.1 --- llvm/include/llvm/Analysis/DSGraph.h:1.64 Wed Nov 12 11:58:09 2003 +++ llvm/include/llvm/Analysis/DSGraph.h Mon Mar 1 17:57:19 2004 @@ -7,7 +7,8 @@ // //===----------------------------------------------------------------------===// // -// This header defines the data structure graph. +// This header defines the data structure graph (DSGraph) and the +// ReachabilityCloner class. // //===----------------------------------------------------------------------===// @@ -21,13 +22,86 @@ class GlobalValue; //===----------------------------------------------------------------------===// +/// DSScalarMap - An instance of this class is used to keep track of all of +/// which DSNode each scalar in a function points to. This is specialized to +/// keep track of globals with nodes in the function, and to keep track of the +/// unique DSNodeHandle being used by the scalar map. +/// +/// This class is crucial to the efficiency of DSA with some large SCC's. In +/// these cases, the cost of iterating over the scalar map dominates the cost +/// of DSA. In all of these cases, the DSA phase is really trying to identify +/// globals or unique node handles active in the function. +/// +class DSScalarMap { + typedef hash_map ValueMapTy; + ValueMapTy ValueMap; + + typedef hash_set GlobalSetTy; + GlobalSetTy GlobalSet; +public: + + // Compatibility methods: provide an interface compatible with a map of + // Value* to DSNodeHandle's. + typedef ValueMapTy::const_iterator const_iterator; + typedef ValueMapTy::iterator iterator; + iterator begin() { return ValueMap.begin(); } + iterator end() { return ValueMap.end(); } + const_iterator begin() const { return ValueMap.begin(); } + const_iterator end() const { return ValueMap.end(); } + iterator find(Value *V) { return ValueMap.find(V); } + const_iterator find(Value *V) const { return ValueMap.find(V); } + unsigned count(Value *V) const { return ValueMap.count(V); } + + void erase(Value *V) { erase(find(V)); } + + /// replaceScalar - When an instruction needs to be modified, this method can + /// be used to update the scalar map to remove the old and insert the new. + void replaceScalar(Value *Old, Value *New) { + iterator I = find(Old); + assert(I != end() && "Old value is not in the map!"); + ValueMap.insert(std::make_pair(New, I->second)); + erase(I); + } + + DSNodeHandle &operator[](Value *V) { + std::pair IP = + ValueMap.insert(std::make_pair(V, DSNodeHandle())); + if (IP.second) { // Inserted the new entry into the map. + if (GlobalValue *GV = dyn_cast(V)) + GlobalSet.insert(GV); + } + return IP.first->second; + } + + void erase(iterator I) { + assert(I != ValueMap.end() && "Cannot erase end!"); + if (GlobalValue *GV = dyn_cast(I->first)) + GlobalSet.erase(GV); + ValueMap.erase(I); + } + + void clear() { + ValueMap.clear(); + GlobalSet.clear(); + } + + // Access to the global set: the set of all globals currently in the + // scalar map. + typedef GlobalSetTy::const_iterator global_iterator; + global_iterator global_begin() const { return GlobalSet.begin(); } + global_iterator global_end() const { return GlobalSet.end(); } +}; + + +//===----------------------------------------------------------------------===// /// DSGraph - The graph that represents a function. /// struct DSGraph { // Public data-type declarations... - typedef hash_map ScalarMapTy; + typedef DSScalarMap ScalarMapTy; typedef hash_map ReturnNodesTy; - typedef hash_set GlobalSetTy; + typedef hash_set GlobalSetTy; + typedef ilist NodeListTy; /// NodeMapTy - This data type is used when cloning one graph into another to /// keep track of the correspondence between the nodes in the old and new @@ -37,7 +111,7 @@ DSGraph *GlobalsGraph; // Pointer to the common graph of global objects bool PrintAuxCalls; // Should this graph print the Aux calls vector? - std::vector Nodes; + NodeListTy Nodes; ScalarMapTy ScalarMap; // ReturnNodes - A return value for every function merged into this graph. @@ -104,10 +178,14 @@ void setPrintAuxCalls() { PrintAuxCalls = true; } bool shouldPrintAuxCalls() const { return PrintAuxCalls; } - /// getNodes - Get a vector of all the nodes in the graph - /// - const std::vector &getNodes() const { return Nodes; } - std::vector &getNodes() { return Nodes; } + /// node_iterator/begin/end - Iterate over all of the nodes in the graph. Be + /// extremely careful with these methods because any merging of nodes could + /// cause the node to be removed from this list. This means that if you are + /// iterating over nodes and doing something that could cause _any_ node to + /// merge, your node_iterators into this graph can be invalidated. + typedef NodeListTy::compat_iterator node_iterator; + node_iterator node_begin() const { return Nodes.compat_begin(); } + node_iterator node_end() const { return Nodes.compat_end(); } /// getFunctionNames - Return a space separated list of the name of the /// functions in this graph (if any) @@ -116,6 +194,7 @@ /// addNode - Add a new node to the graph. /// void addNode(DSNode *N) { Nodes.push_back(N); } + void unlinkNode(DSNode *N) { Nodes.remove(N); } /// getScalarMap - Get a map that describes what the nodes the scalars in this /// function point to... @@ -202,8 +281,8 @@ /// is useful for clearing out markers like Incomplete. /// void maskNodeTypes(unsigned Mask) { - for (unsigned i = 0, e = Nodes.size(); i != e; ++i) - Nodes[i]->maskNodeTypes(Mask); + for (node_iterator I = node_begin(), E = node_end(); I != E; ++I) + (*I)->maskNodeTypes(Mask); } void maskIncompleteMarkers() { maskNodeTypes(~DSNode::Incomplete); } @@ -240,24 +319,11 @@ DontCloneAuxCallNodes = 1 << 2, CloneAuxCallNodes = 0, StripModRefBits = 1 << 3, KeepModRefBits = 0, StripIncompleteBit = 1 << 4, KeepIncompleteBit = 0, + UpdateInlinedGlobals = 1 << 5, DontUpdateInlinedGlobals = 0, }; -private: - void cloneReachableNodes(const DSNode* Node, - unsigned BitsToClear, - NodeMapTy& OldNodeMap, - NodeMapTy& CompletedNodeMap); - -public: void updateFromGlobalGraph(); - void cloneReachableSubgraph(const DSGraph& G, - const hash_set& RootNodes, - NodeMapTy& OldNodeMap, - NodeMapTy& CompletedNodeMap, - unsigned CloneFlags = 0); - - /// computeNodeMapping - Given roots in two different DSGraphs, traverse the /// nodes reachable from the two graphs, computing the mapping of nodes from /// the first to the second graph. @@ -270,6 +336,8 @@ /// cloneInto - Clone the specified DSGraph into the current graph. The /// translated ScalarMap for the old function is filled into the OldValMap /// member, and the translated ReturnNodes map is returned into ReturnNodes. + /// OldNodeMap contains a mapping from the original nodes to the newly cloned + /// nodes. /// /// The CloneFlags member controls various aspects of the cloning process. /// @@ -294,7 +362,7 @@ // Methods for checking to make sure graphs are well formed... void AssertNodeInGraph(const DSNode *N) const { - assert((!N || find(Nodes.begin(), Nodes.end(), N) != Nodes.end()) && + assert((!N || N->getParentGraph() == this) && "AssertNodeInGraph: Node is not in graph!"); } void AssertNodeContainsGlobal(const DSNode *N, GlobalValue *GV) const { @@ -321,13 +389,6 @@ void AssertGraphOK() const; - /// mergeInGlobalsGraph - This method is useful for clients to incorporate the - /// globals graph into the DS, BU or TD graph for a function. This code - /// retains all globals, i.e., does not delete unreachable globals after they - /// are inlined. - /// - void mergeInGlobalsGraph(); - /// removeTriviallyDeadNodes - After the graph has been constructed, this /// method removes all unreachable nodes that are created because they got /// merged with other nodes in the graph. This is used as the first step of @@ -336,6 +397,49 @@ void removeTriviallyDeadNodes(); }; + + /// ReachabilityCloner - This class is used to incrementally clone and merge + /// nodes from a non-changing source graph into a potentially mutating + /// destination graph. Nodes are only cloned over on demand, either in + /// responds to a merge() or getClonedNH() call. When a node is cloned over, + /// all of the nodes reachable from it are automatically brought over as well. + class ReachabilityCloner { + DSGraph &Dest; + const DSGraph &Src; + + /// BitsToKeep - These bits are retained from the source node when the + /// source nodes are merged into the destination graph. + unsigned BitsToKeep; + unsigned CloneFlags; + + // NodeMap - A mapping from nodes in the source graph to the nodes that + // represent them in the destination graph. + DSGraph::NodeMapTy NodeMap; + public: + ReachabilityCloner(DSGraph &dest, const DSGraph &src, unsigned cloneFlags) + : Dest(dest), Src(src), CloneFlags(cloneFlags) { + assert(&Dest != &Src && "Cannot clone from graph to same graph!"); + BitsToKeep = ~DSNode::DEAD; + if (CloneFlags & DSGraph::StripAllocaBit) + BitsToKeep &= ~DSNode::AllocaNode; + if (CloneFlags & DSGraph::StripModRefBits) + BitsToKeep &= ~(DSNode::Modified | DSNode::Read); + if (CloneFlags & DSGraph::StripIncompleteBit) + BitsToKeep &= ~DSNode::Incomplete; + } + + DSNodeHandle getClonedNH(const DSNodeHandle &SrcNH); + + void merge(const DSNodeHandle &NH, const DSNodeHandle &SrcNH); + + /// mergeCallSite - Merge the nodes reachable from the specified src call + /// site into the nodes reachable from DestCS. + void mergeCallSite(const DSCallSite &DestCS, const DSCallSite &SrcCS); + + bool clonedNode() const { return !NodeMap.empty(); } + + void destroy() { NodeMap.clear(); } + }; } // End llvm namespace #endif Index: llvm/include/llvm/Analysis/DSGraphTraits.h diff -u llvm/include/llvm/Analysis/DSGraphTraits.h:1.18 llvm/include/llvm/Analysis/DSGraphTraits.h:1.18.4.1 --- llvm/include/llvm/Analysis/DSGraphTraits.h:1.18 Tue Nov 11 16:41:30 2003 +++ llvm/include/llvm/Analysis/DSGraphTraits.h Mon Mar 1 17:57:19 2004 @@ -33,10 +33,14 @@ DSNodeIterator(NodeTy *N) : Node(N), Offset(0) {} // begin iterator DSNodeIterator(NodeTy *N, bool) : Node(N) { // Create end iterator - Offset = N->getNumLinks() << DS::PointerShift; - if (Offset == 0 && Node->getForwardNode() && - Node->isDeadNode()) // Model Forward link - Offset += DS::PointerSize; + if (N != 0) { + Offset = N->getNumLinks() << DS::PointerShift; + if (Offset == 0 && Node->getForwardNode() && + Node->isDeadNode()) // Model Forward link + Offset += DS::PointerSize; + } else { + Offset = 0; + } } public: DSNodeIterator(const DSNodeHandle &NH) @@ -115,13 +119,12 @@ typedef std::pointer_to_unary_function DerefFun; // nodes_iterator/begin/end - Allow iteration over all nodes in the graph - typedef mapped_iterator::iterator, - DerefFun> nodes_iterator; + typedef mapped_iterator nodes_iterator; static nodes_iterator nodes_begin(DSGraph *G) { - return map_iterator(G->getNodes().begin(), DerefFun(dereference)); + return map_iterator(G->node_begin(), DerefFun(dereference)); } static nodes_iterator nodes_end(DSGraph *G) { - return map_iterator(G->getNodes().end(), DerefFun(dereference)); + return map_iterator(G->node_end(), DerefFun(dereference)); } static ChildIteratorType child_begin(NodeType *N) { return N->begin(); } @@ -135,13 +138,12 @@ typedef std::pointer_to_unary_function DerefFun; // nodes_iterator/begin/end - Allow iteration over all nodes in the graph - typedef mapped_iterator::const_iterator, - DerefFun> nodes_iterator; + typedef mapped_iterator nodes_iterator; static nodes_iterator nodes_begin(const DSGraph *G) { - return map_iterator(G->getNodes().begin(), DerefFun(dereferenceC)); + return map_iterator(G->node_begin(), DerefFun(dereferenceC)); } static nodes_iterator nodes_end(const DSGraph *G) { - return map_iterator(G->getNodes().end(), DerefFun(dereferenceC)); + return map_iterator(G->node_end(), DerefFun(dereferenceC)); } static ChildIteratorType child_begin(const NodeType *N) { return N->begin(); } Index: llvm/include/llvm/Analysis/DSNode.h diff -u llvm/include/llvm/Analysis/DSNode.h:1.33 llvm/include/llvm/Analysis/DSNode.h:1.33.4.1 --- llvm/include/llvm/Analysis/DSNode.h:1.33 Tue Nov 11 16:41:30 2003 +++ llvm/include/llvm/Analysis/DSNode.h Mon Mar 1 17:57:19 2004 @@ -42,6 +42,11 @@ /// null. DSNodeHandle ForwardNH; + /// Next, Prev - These instance variables are used to keep the node on a + /// doubly-linked ilist in the DSGraph. + DSNode *Next, *Prev; + friend class ilist_traits; + /// Size - The current size of the node. This should be equal to the size of /// the current type record. /// @@ -97,9 +102,16 @@ private: unsigned short NodeType; public: - + + /// DSNode ctor - Create a node of the specified type, inserting it into the + /// specified graph. DSNode(const Type *T, DSGraph *G); - DSNode(const DSNode &, DSGraph *G); + + /// DSNode "copy ctor" - Copy the specified node, inserting it into the + /// specified graph. If NullLinks is true, then null out all of the links, + /// but keep the same number of them. This can be used for efficiency if the + /// links are just going to be clobbered anyway. + DSNode(const DSNode &, DSGraph *G, bool NullLinks = false); ~DSNode() { dropAllReferences(); @@ -145,10 +157,20 @@ /// getForwardNode - This method returns the node that this node is forwarded /// to, if any. DSNode *getForwardNode() const { return ForwardNH.getNode(); } + + /// isForwarding - Return true if this node is forwarding to another. + /// + bool isForwarding() const { return !ForwardNH.isNull(); } + + /// stopForwarding - When the last reference to this forwarding node has been + /// dropped, delete the node. void stopForwarding() { - assert(!ForwardNH.isNull() && + assert(isForwarding() && "Node isn't forwarding, cannot stopForwarding!"); ForwardNH.setNode(0); + assert(ParentGraph == 0 && + "Forwarding nodes must have been removed from graph!"); + delete this; } /// hasLink - Return true if this memory object has a link in slot #LinkNo @@ -241,14 +263,24 @@ /// also marks the node with the 'G' flag if it does not already have it. /// void addGlobal(GlobalValue *GV); + void mergeGlobals(const std::vector &RHS); const std::vector &getGlobals() const { return Globals; } + typedef std::vector::const_iterator global_iterator; + global_iterator global_begin() const { return Globals.begin(); } + global_iterator global_end() const { return Globals.end(); } + + /// maskNodeTypes - Apply a mask to the node types bitfield. /// void maskNodeTypes(unsigned Mask) { NodeType &= Mask; } + void mergeNodeFlags(unsigned RHS) { + NodeType |= RHS; + } + /// getNodeFlags - Return all of the flags set on the node. If the DEAD flag /// is set, hide it from the caller. unsigned getNodeFlags() const { return NodeType & ~DEAD; } @@ -273,6 +305,7 @@ DSNode *setIncompleteMarker() { NodeType |= Incomplete; return this; } DSNode *setModifiedMarker() { NodeType |= Modified; return this; } DSNode *setReadMarker() { NodeType |= Read; return this; } + DSNode *setArrayMarker() { NodeType |= Array; return this; } void makeNodeDead() { Globals.clear(); @@ -292,7 +325,7 @@ void dropAllReferences() { Links.clear(); - if (!ForwardNH.isNull()) + if (isForwarding()) ForwardNH.setNode(0); } @@ -313,22 +346,46 @@ static void MergeNodes(DSNodeHandle& CurNodeH, DSNodeHandle& NH); }; +//===----------------------------------------------------------------------===// +// Define the ilist_traits specialization for the DSGraph ilist. +// +template<> +struct ilist_traits { + static DSNode *getPrev(const DSNode *N) { return N->Prev; } + static DSNode *getNext(const DSNode *N) { return N->Next; } + + static void setPrev(DSNode *N, DSNode *Prev) { N->Prev = Prev; } + static void setNext(DSNode *N, DSNode *Next) { N->Next = Next; } + + static DSNode *createNode() { return new DSNode(0,0); } + //static DSNode *createNode(const DSNode &V) { return new DSNode(V); } + + + void addNodeToList(DSNode *NTy) {} + void removeNodeFromList(DSNode *NTy) {} + void transferNodesFromList(iplist &L2, + ilist_iterator first, + ilist_iterator last) {} +}; + +template<> +struct ilist_traits : public ilist_traits {}; //===----------------------------------------------------------------------===// // Define inline DSNodeHandle functions that depend on the definition of DSNode // inline DSNode *DSNodeHandle::getNode() const { assert((!N || Offset < N->Size || (N->Size == 0 && Offset == 0) || - !N->ForwardNH.isNull()) && "Node handle offset out of range!"); - if (!N || N->ForwardNH.isNull()) + N->isForwarding()) && "Node handle offset out of range!"); + if (N == 0 || !N->isForwarding()) return N; return HandleForwarding(); } -inline void DSNodeHandle::setNode(DSNode *n) { - assert(!n || !n->getForwardNode() && "Cannot set node to a forwarded node!"); - if (N) N->NumReferrers--; +inline void DSNodeHandle::setNode(DSNode *n) const { + assert(!n || !n->isForwarding() && "Cannot set node to a forwarded node!"); + if (N) getNode()->NumReferrers--; N = n; if (N) { N->NumReferrers++; @@ -340,7 +397,7 @@ } assert(!N || ((N->NodeType & DSNode::DEAD) == 0)); assert((!N || Offset < N->Size || (N->Size == 0 && Offset == 0) || - !N->ForwardNH.isNull()) && "Node handle offset out of range!"); + N->isForwarding()) && "Node handle offset out of range!"); } inline bool DSNodeHandle::hasLink(unsigned Num) const { @@ -377,11 +434,14 @@ /// mergeWith - Merge the logical node pointed to by 'this' with the node /// pointed to by 'N'. /// -inline void DSNodeHandle::mergeWith(const DSNodeHandle &Node) { - if (N != 0) +inline void DSNodeHandle::mergeWith(const DSNodeHandle &Node) const { + if (!isNull()) getNode()->mergeWith(Node, Offset); - else // No node to merge with, so just point to Node - *this = Node; + else { // No node to merge with, so just point to Node + Offset = 0; + setNode(Node.getNode()); + Offset = Node.getOffset(); + } } } // End llvm namespace Index: llvm/include/llvm/Analysis/DSSupport.h diff -u llvm/include/llvm/Analysis/DSSupport.h:1.26 llvm/include/llvm/Analysis/DSSupport.h:1.26.4.1 --- llvm/include/llvm/Analysis/DSSupport.h:1.26 Tue Nov 11 16:41:31 2003 +++ llvm/include/llvm/Analysis/DSSupport.h Mon Mar 1 17:57:19 2004 @@ -28,6 +28,7 @@ class DSNode; // Each node in the graph class DSGraph; // A graph for a function +class ReachabilityCloner; namespace DS { // FIXME: After the paper, this should get cleaned up enum { PointerShift = 2, // 64bit ptrs = 3, 32 bit ptrs = 2 @@ -76,6 +77,7 @@ } bool operator>(const DSNodeHandle &H) const { return H < *this; } bool operator==(const DSNodeHandle &H) const { // Allow comparison + // getNode can change the offset, so we must call getNode() first. return getNode() == H.getNode() && Offset == H.Offset; } bool operator!=(const DSNodeHandle &H) const { return !operator==(H); } @@ -93,7 +95,7 @@ inline DSNode *getNode() const; // Defined inline in DSNode.h unsigned getOffset() const { return Offset; } - inline void setNode(DSNode *N); // Defined inline in DSNode.h + inline void setNode(DSNode *N) const; // Defined inline in DSNode.h void setOffset(unsigned O) { //assert((!N || Offset < N->Size || (N->Size == 0 && Offset == 0) || // !N->ForwardNH.isNull()) && "Node handle offset out of range!"); @@ -108,7 +110,7 @@ /// mergeWith - Merge the logical node pointed to by 'this' with the node /// pointed to by 'N'. /// - void mergeWith(const DSNodeHandle &N); + void mergeWith(const DSNodeHandle &N) const; // hasLink - Return true if there is a link at the specified offset... inline bool hasLink(unsigned Num) const; @@ -127,7 +129,8 @@ } // End llvm namespace namespace std { - inline void swap(llvm::DSNodeHandle &NH1, llvm::DSNodeHandle &NH2) { NH1.swap(NH2); } + template<> + inline void swap(llvm::DSNodeHandle &NH1, llvm::DSNodeHandle &NH2) { NH1.swap(NH2); } } namespace llvm { @@ -148,7 +151,7 @@ const hash_map &NodeMap) { if (DSNode *N = Src.getNode()) { hash_map::const_iterator I = NodeMap.find(N); - assert(I != NodeMap.end() && "Not not in mapping!"); + assert(I != NodeMap.end() && "Node not in mapping!"); NH.setOffset(Src.getOffset()); NH.setNode(I->second); @@ -159,13 +162,17 @@ const hash_map &NodeMap) { if (DSNode *N = Src.getNode()) { hash_map::const_iterator I = NodeMap.find(N); - assert(I != NodeMap.end() && "Not not in mapping!"); + assert(I != NodeMap.end() && "Node not in mapping!"); NH.setOffset(Src.getOffset()+I->second.getOffset()); NH.setNode(I->second.getNode()); } } + static void InitNH(DSNodeHandle &NH, const DSNodeHandle &Src, + ReachabilityCloner &RC); + + DSCallSite(); // DO NOT IMPLEMENT public: /// Constructor. Note - This ctor destroys the argument vector passed in. On @@ -193,7 +200,7 @@ /// This is useful when moving a call site from one graph to another. /// template - DSCallSite(const DSCallSite &FromCall, const MapTy &NodeMap) { + DSCallSite(const DSCallSite &FromCall, MapTy &NodeMap) { Site = FromCall.Site; InitNH(RetVal, FromCall.RetVal, NodeMap); InitNH(CalleeN, FromCall.CalleeN, NodeMap); @@ -234,7 +241,7 @@ assert(!CalleeN.getNode() && CalleeF); return CalleeF; } - unsigned getNumPtrArgs() const { return CallArgs.size(); } + unsigned getNumPtrArgs() const { return CallArgs.size(); } DSNodeHandle &getPtrArg(unsigned i) { assert(i < CallArgs.size() && "Argument to getPtrArgNode is out of range!"); @@ -255,7 +262,7 @@ } } - // MergeWith - Merge the return value and parameters of the these two call + // mergeWith - Merge the return value and parameters of the these two call // sites. void mergeWith(DSCallSite &CS) { getRetVal().mergeWith(CS.getRetVal()); @@ -288,14 +295,16 @@ } bool operator==(const DSCallSite &CS) const { - return RetVal == CS.RetVal && CalleeN == CS.CalleeN && - CalleeF == CS.CalleeF && CallArgs == CS.CallArgs; + return CalleeF == CS.CalleeF && CalleeN == CS.CalleeN && + RetVal == CS.RetVal && CallArgs == CS.CallArgs; } }; } // End llvm namespace namespace std { - inline void swap(llvm::DSCallSite &CS1, llvm::DSCallSite &CS2) { CS1.swap(CS2); } + template<> + inline void swap(llvm::DSCallSite &CS1, + llvm::DSCallSite &CS2) { CS1.swap(CS2); } } #endif Index: llvm/include/llvm/Analysis/LoopInfo.h diff -u llvm/include/llvm/Analysis/LoopInfo.h:1.30 llvm/include/llvm/Analysis/LoopInfo.h:1.30.2.1 --- llvm/include/llvm/Analysis/LoopInfo.h:1.30 Wed Jan 7 18:08:22 2004 +++ llvm/include/llvm/Analysis/LoopInfo.h Mon Mar 1 17:57:19 2004 @@ -54,6 +54,7 @@ Loop *getParentLoop() const { return ParentLoop; } /// contains - Return true of the specified basic block is in this loop + /// bool contains(const BasicBlock *BB) const; /// iterator/begin/end - Return the loops contained entirely within this loop. Index: llvm/include/llvm/Analysis/PostDominators.h diff -u llvm/include/llvm/Analysis/PostDominators.h:1.7 llvm/include/llvm/Analysis/PostDominators.h:1.7.4.1 --- llvm/include/llvm/Analysis/PostDominators.h:1.7 Sat Dec 6 18:35:19 2003 +++ llvm/include/llvm/Analysis/PostDominators.h Mon Mar 1 17:57:19 2004 @@ -18,7 +18,6 @@ namespace llvm { - /// PostDominatorSet Class - Concrete subclass of DominatorSetBase that is used /// to compute the post-dominator set. Because there can be multiple exit nodes /// in an LLVM function, we calculate post dominators with a special null block @@ -31,19 +30,17 @@ virtual bool runOnFunction(Function &F); - // getAnalysisUsage - This pass does not modify the function at all. - // + /// getAnalysisUsage - This pass does not modify the function at all. + /// virtual void getAnalysisUsage(AnalysisUsage &AU) const { AU.setPreservesAll(); } }; - -//===------------------------------------- -// ImmediatePostDominators Class - Concrete subclass of ImmediateDominatorsBase -// that is used to compute the immediate post-dominators. -// +/// ImmediatePostDominators Class - Concrete subclass of ImmediateDominatorsBase +/// that is used to compute the immediate post-dominators. +/// struct ImmediatePostDominators : public ImmediateDominatorsBase { ImmediatePostDominators() : ImmediateDominatorsBase(true) {} @@ -64,10 +61,9 @@ }; -//===------------------------------------- -// PostDominatorTree Class - Concrete subclass of DominatorTree that is used to -// compute the a post-dominator tree. -// +/// PostDominatorTree Class - Concrete subclass of DominatorTree that is used to +/// compute the a post-dominator tree. +/// struct PostDominatorTree : public DominatorTreeBase { PostDominatorTree() : DominatorTreeBase(true) {} @@ -88,10 +84,9 @@ }; -//===------------------------------------- -// PostDominanceFrontier Class - Concrete subclass of DominanceFrontier that is -// used to compute the a post-dominance frontier. -// +/// PostDominanceFrontier Class - Concrete subclass of DominanceFrontier that is +/// used to compute the a post-dominance frontier. +/// struct PostDominanceFrontier : public DominanceFrontierBase { PostDominanceFrontier() : DominanceFrontierBase(true) {} From brukman at cs.uiuc.edu Mon Mar 1 17:58:56 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Mar 1 17:58:56 2004 Subject: [llvm-commits] [parallel] CVS: llvm/include/llvm/Assembly/CWriter.h Message-ID: <200403012357.RAA03331@zion.cs.uiuc.edu> Changes in directory llvm/include/llvm/Assembly: CWriter.h (r1.5) removed --- Log message: Merge from trunk --- Diffs of the changes: (+0 -0) From brukman at cs.uiuc.edu Mon Mar 1 17:59:05 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Mar 1 17:59:05 2004 Subject: [llvm-commits] [parallel] CVS: llvm/include/llvm/Support/GetElementPtrTypeIterator.h Mangler.h ToolRunner.h Message-ID: <200403012357.RAA03387@zion.cs.uiuc.edu> Changes in directory llvm/include/llvm/Support: GetElementPtrTypeIterator.h updated: 1.4 -> 1.4.4.1 Mangler.h updated: 1.8 -> 1.8.4.1 ToolRunner.h updated: 1.6 -> 1.6.4.1 --- Log message: Merge from trunk --- Diffs of the changes: (+74 -42) Index: llvm/include/llvm/Support/GetElementPtrTypeIterator.h diff -u llvm/include/llvm/Support/GetElementPtrTypeIterator.h:1.4 llvm/include/llvm/Support/GetElementPtrTypeIterator.h:1.4.4.1 --- llvm/include/llvm/Support/GetElementPtrTypeIterator.h:1.4 Thu Dec 11 22:58:13 2003 +++ llvm/include/llvm/Support/GetElementPtrTypeIterator.h Mon Mar 1 17:57:19 2004 @@ -15,8 +15,7 @@ #ifndef LLVM_SUPPORT_GETELEMENTPTRTYPE_H #define LLVM_SUPPORT_GETELEMENTPTRTYPE_H -#include "Support/iterator" -#include "llvm/iMemory.h" +#include "llvm/User.h" #include "llvm/DerivedTypes.h" namespace llvm { @@ -24,30 +23,26 @@ : public forward_iterator { typedef forward_iterator super; - User *TheGEP; // Either GetElementPtrInst or ConstantExpr + User::op_iterator OpIt; const Type *CurTy; - unsigned Operand; - gep_type_iterator() {} public: - static gep_type_iterator begin(User *gep) { + static gep_type_iterator begin(const Type *Ty, User::op_iterator It) { gep_type_iterator I; - I.TheGEP = gep; - I.CurTy = gep->getOperand(0)->getType(); - I.Operand = 1; + I.CurTy = Ty; + I.OpIt = It; return I; } - static gep_type_iterator end(User *gep) { + static gep_type_iterator end(User::op_iterator It) { gep_type_iterator I; - I.TheGEP = gep; I.CurTy = 0; - I.Operand = gep->getNumOperands(); + I.OpIt = It; return I; } bool operator==(const gep_type_iterator& x) const { - return Operand == x.Operand; + return OpIt == x.OpIt; } bool operator!=(const gep_type_iterator& x) const { return !operator==(x); @@ -61,9 +56,7 @@ // current type directly. const Type *operator->() const { return operator*(); } - unsigned getOperandNum() const { return Operand; } - - Value *getOperand() const { return TheGEP->getOperand(Operand); } + Value *getOperand() const { return *OpIt; } gep_type_iterator& operator++() { // Preincrement if (const CompositeType *CT = dyn_cast(CurTy)) { @@ -71,7 +64,7 @@ } else { CurTy = 0; } - ++Operand; + ++OpIt; return *this; } @@ -81,18 +74,26 @@ }; inline gep_type_iterator gep_type_begin(User *GEP) { - return gep_type_iterator::begin(GEP); + return gep_type_iterator::begin(GEP->getOperand(0)->getType(), + GEP->op_begin()+1); } - inline gep_type_iterator gep_type_end(User *GEP) { - return gep_type_iterator::end(GEP); + return gep_type_iterator::end(GEP->op_end()); } inline gep_type_iterator gep_type_begin(User &GEP) { - return gep_type_iterator::begin(&GEP); + return gep_type_iterator::begin(GEP.getOperand(0)->getType(), + GEP.op_begin()+1); } - inline gep_type_iterator gep_type_end(User &GEP) { - return gep_type_iterator::end(&GEP); + return gep_type_iterator::end(GEP.op_end()); + } + inline gep_type_iterator gep_type_begin(const Type *Op0, User::op_iterator I, + User::op_iterator E) { + return gep_type_iterator::begin(Op0, I); + } + inline gep_type_iterator gep_type_end(const Type *Op0, User::op_iterator I, + User::op_iterator E) { + return gep_type_iterator::end(E); } } // end namespace llvm Index: llvm/include/llvm/Support/Mangler.h diff -u llvm/include/llvm/Support/Mangler.h:1.8 llvm/include/llvm/Support/Mangler.h:1.8.4.1 --- llvm/include/llvm/Support/Mangler.h:1.8 Tue Nov 11 16:41:31 2003 +++ llvm/include/llvm/Support/Mangler.h Mon Mar 1 17:57:19 2004 @@ -1,4 +1,4 @@ -//===-- Mangler.h - Self-contained c/asm llvm name mangler ------*- C++ -*-===// +//===-- Mangler.h - Self-contained llvm name mangler ------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -7,25 +7,21 @@ // //===----------------------------------------------------------------------===// // -// Unified name mangler for CWriter and assembly backends. +// Unified name mangler for various backends. // //===----------------------------------------------------------------------===// #ifndef LLVM_SUPPORT_MANGLER_H #define LLVM_SUPPORT_MANGLER_H -namespace llvm { - -class Value; -class Module; - -} // End llvm namespace - #include #include #include namespace llvm { +class Value; +class Module; +class GlobalValue; class Mangler { /// This keeps track of which global values have had their names @@ -40,6 +36,8 @@ ValueMap Memo; unsigned Count; + + void InsertName(GlobalValue *GV, std::map &Names); public: // Mangler ctor - if AddUnderscorePrefix is true, then all public global Index: llvm/include/llvm/Support/ToolRunner.h diff -u llvm/include/llvm/Support/ToolRunner.h:1.6 llvm/include/llvm/Support/ToolRunner.h:1.6.4.1 --- llvm/include/llvm/Support/ToolRunner.h:1.6 Tue Nov 11 16:41:31 2003 +++ llvm/include/llvm/Support/ToolRunner.h Mon Mar 1 17:57:19 2004 @@ -18,6 +18,7 @@ #define TOOLRUNNER_H #include "Support/SystemUtils.h" +#include #include namespace llvm { @@ -25,6 +26,20 @@ class CBE; class LLC; + +/// ToolExecutionError - An instance of this class is thrown by the +/// AbstractInterpreter instances if there is an error running a tool (e.g., LLC +/// crashes) which prevents execution of the program. +/// +class ToolExecutionError : std::exception { + std::string Message; +public: + explicit ToolExecutionError(const std::string &M) : Message(M) {} + virtual ~ToolExecutionError() throw(); + virtual const char* what() const throw() { return Message.c_str(); } +}; + + //===---------------------------------------------------------------------===// // GCC abstraction // @@ -56,9 +71,6 @@ /// int MakeSharedObject(const std::string &InputFile, FileType fileType, std::string &OutputFile); - -private: - void ProcessFailure(const char **Args); }; @@ -80,6 +92,12 @@ virtual ~AbstractInterpreter() {} + /// compileProgram - Compile the specified program from bytecode to executable + /// code. This does not produce any output, it is only used when debugging + /// the code generator. If the code generator fails, an exception should be + /// thrown, otherwise, this function will just return. + virtual void compileProgram(const std::string &Bytecode) {} + /// ExecuteProgram - Run the specified bytecode file, emitting output to the /// specified filename. This returns the exit code of the program. /// @@ -95,12 +113,18 @@ // CBE Implementation of AbstractIntepreter interface // class CBE : public AbstractInterpreter { - std::string DISPath; // The path to the `llvm-dis' executable + std::string LLCPath; // The path to the `llc' executable GCC *gcc; public: - CBE(const std::string &disPath, GCC *Gcc) : DISPath(disPath), gcc(Gcc) { } + CBE(const std::string &llcPath, GCC *Gcc) : LLCPath(llcPath), gcc(Gcc) { } ~CBE() { delete gcc; } + /// compileProgram - Compile the specified program from bytecode to executable + /// code. This does not produce any output, it is only used when debugging + /// the code generator. If the code generator fails, an exception should be + /// thrown, otherwise, this function will just return. + virtual void compileProgram(const std::string &Bytecode); + virtual int ExecuteProgram(const std::string &Bytecode, const std::vector &Args, const std::string &InputFile, @@ -108,10 +132,11 @@ const std::vector &SharedLibs = std::vector()); - // Sometimes we just want to go half-way and only generate the .c file, - // not necessarily compile it with GCC and run the program. + // Sometimes we just want to go half-way and only generate the .c file, not + // necessarily compile it with GCC and run the program. This throws an + // exception if LLC crashes. // - virtual int OutputC(const std::string &Bytecode, std::string &OutputCFile); + virtual void OutputC(const std::string &Bytecode, std::string &OutputCFile); }; @@ -126,6 +151,13 @@ : LLCPath(llcPath), gcc(Gcc) { } ~LLC() { delete gcc; } + + /// compileProgram - Compile the specified program from bytecode to executable + /// code. This does not produce any output, it is only used when debugging + /// the code generator. If the code generator fails, an exception should be + /// thrown, otherwise, this function will just return. + virtual void compileProgram(const std::string &Bytecode); + virtual int ExecuteProgram(const std::string &Bytecode, const std::vector &Args, const std::string &InputFile, @@ -134,9 +166,10 @@ std::vector()); // Sometimes we just want to go half-way and only generate the .s file, - // not necessarily compile it all the way and run the program. + // not necessarily compile it all the way and run the program. This throws + // an exception if execution of LLC fails. // - int OutputAsm(const std::string &Bytecode, std::string &OutputAsmFile); + void OutputAsm(const std::string &Bytecode, std::string &OutputAsmFile); }; } // End llvm namespace From brukman at cs.uiuc.edu Mon Mar 1 17:59:10 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Mar 1 17:59:10 2004 Subject: [llvm-commits] [parallel] CVS: llvm/include/llvm/AbstractTypeUser.h BasicBlock.h Constants.h DerivedTypes.h Function.h Instruction.h Intrinsics.h ModuleProvider.h Type.h Value.h iMemory.h iOther.h iPHINode.h iTerminators.h Message-ID: <200403012357.RAA03347@zion.cs.uiuc.edu> Changes in directory llvm/include/llvm: AbstractTypeUser.h updated: 1.18 -> 1.18.2.1 BasicBlock.h updated: 1.36 -> 1.36.2.1 Constants.h updated: 1.38 -> 1.38.2.1 DerivedTypes.h updated: 1.49.2.1 -> 1.49.2.2 Function.h updated: 1.49 -> 1.49.4.1 Instruction.h updated: 1.50 -> 1.50.2.1 Intrinsics.h updated: 1.15.2.1 -> 1.15.2.2 ModuleProvider.h updated: 1.8 -> 1.8.2.1 Type.h updated: 1.37 -> 1.37.4.1 Value.h updated: 1.49 -> 1.49.2.1 iMemory.h updated: 1.43 -> 1.43.4.1 iOther.h updated: 1.43 -> 1.43.4.1 iPHINode.h updated: 1.15 -> 1.15.4.1 iTerminators.h updated: 1.37.4.2 -> 1.37.4.3 --- Log message: Merge from trunk --- Diffs of the changes: (+403 -332) Index: llvm/include/llvm/AbstractTypeUser.h diff -u llvm/include/llvm/AbstractTypeUser.h:1.18 llvm/include/llvm/AbstractTypeUser.h:1.18.2.1 --- llvm/include/llvm/AbstractTypeUser.h:1.18 Tue Dec 23 17:25:21 2003 +++ llvm/include/llvm/AbstractTypeUser.h Mon Mar 1 17:57:19 2004 @@ -44,7 +44,7 @@ class AbstractTypeUser { protected: - virtual ~AbstractTypeUser() {} // Derive from me + virtual ~AbstractTypeUser(); // Derive from me public: /// refineAbstractType - The callback method invoked when an abstract type is Index: llvm/include/llvm/BasicBlock.h diff -u llvm/include/llvm/BasicBlock.h:1.36 llvm/include/llvm/BasicBlock.h:1.36.2.1 --- llvm/include/llvm/BasicBlock.h:1.36 Wed Jan 14 22:37:10 2004 +++ llvm/include/llvm/BasicBlock.h Mon Mar 1 17:57:19 2004 @@ -67,13 +67,14 @@ typedef std::reverse_iterator reverse_iterator; /// BasicBlock ctor - If the function parameter is specified, the basic block - /// is automatically inserted at the end of the function. + /// is automatically inserted at either the end of the function (if + /// InsertBefore is null), or before the specified basic block. /// - BasicBlock(const std::string &Name = "", Function *Parent = 0); - /// BasicBlock ctor - If the InsertBefore parameter is specified, the basic /// block is automatically inserted right before the specified block. - BasicBlock(const std::string &Name, BasicBlock *InsertBefore); + /// + BasicBlock(const std::string &Name = "", Function *Parent = 0, + BasicBlock *InsertBefore = 0); ~BasicBlock(); // Specialize setName to take care of symbol table majik @@ -131,13 +132,6 @@ static inline bool classof(const Value *V) { return V->getValueType() == Value::BasicBlockVal; } - - /// hasConstantReferences() - This predicate is true if there is a - /// reference to this basic block in the constant pool for this method. For - /// example, if a block is reached through a switch table, that table resides - /// in the constant pool, and the basic block is reference from it. - /// - bool hasConstantReferences() const; /// dropAllReferences() - This function causes all the subinstructions to "let /// go" of all references that they are maintaining. This allows one to Index: llvm/include/llvm/Constants.h diff -u llvm/include/llvm/Constants.h:1.38 llvm/include/llvm/Constants.h:1.38.2.1 --- llvm/include/llvm/Constants.h:1.38 Wed Jan 14 11:06:21 2004 +++ llvm/include/llvm/Constants.h Mon Mar 1 17:57:19 2004 @@ -258,7 +258,8 @@ /// class ConstantFP : public Constant { double Val; - friend struct ConstantCreator; + friend struct ConstantCreator; + friend struct ConstantCreator; ConstantFP(const ConstantFP &); // DO NOT IMPLEMENT protected: ConstantFP(const Type *Ty, double V); @@ -271,8 +272,34 @@ inline double getValue() const { return Val; } /// isNullValue - Return true if this is the value that would be returned by - /// getNullValue. - virtual bool isNullValue() const { return Val == 0; } + /// getNullValue. Don't depend on == for doubles to tell us it's zero, it + /// considers -0.0 to be null as well as 0.0. :( + virtual bool isNullValue() const { + union { + double V; + uint64_t I; + } T; + T.V = Val; + return T.I == 0; + } + + /// isExactlyValue - We don't rely on operator== working on double values, as + /// it returns true for things that are clearly not equal, like -0.0 and 0.0. + /// As such, this method can be used to do an exact bit-for-bit comparison of + /// two floating point values. + bool isExactlyValue(double V) const { + union { + double V; + uint64_t I; + } T1; + T1.V = Val; + union { + double V; + uint64_t I; + } T2; + T2.V = V; + return T1.I == T2.I; + } /// Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const ConstantFP *) { return true; } @@ -282,6 +309,36 @@ } }; +//===--------------------------------------------------------------------------- +/// ConstantAggregateZero - All zero aggregate value +/// +class ConstantAggregateZero : public Constant { + friend struct ConstantCreator; + ConstantAggregateZero(const ConstantAggregateZero &); // DO NOT IMPLEMENT +protected: + ConstantAggregateZero(const Type *Ty) : Constant(Ty) {} +public: + /// get() - static factory method for creating a null aggregate. It is + /// illegal to call this method with a non-aggregate type. + static Constant *get(const Type *Ty); + + /// isNullValue - Return true if this is the value that would be returned by + /// getNullValue. + virtual bool isNullValue() const { return true; } + + virtual void destroyConstant(); + virtual void replaceUsesOfWithOnConstant(Value *From, Value *To, + bool DisableChecking = false); + + /// Methods for support type inquiry through isa, cast, and dyn_cast: + /// + static inline bool classof(const ConstantAggregateZero *) { return true; } + static bool classof(const Constant *CPV); + static inline bool classof(const Value *V) { + return isa(V) && classof(cast(V)); + } +}; + //===--------------------------------------------------------------------------- /// ConstantArray - Constant Array Declarations @@ -294,8 +351,8 @@ ConstantArray(const ArrayType *T, const std::vector &Val); public: /// get() - Static factory methods - Return objects of the specified value - static ConstantArray *get(const ArrayType *T, const std::vector &); - static ConstantArray *get(const std::string &Initializer); + static Constant *get(const ArrayType *T, const std::vector &); + static Constant *get(const std::string &Initializer); /// getType - Specialize the getType() method to always return an ArrayType, /// which reduces the amount of casting needed in parts of the compiler. @@ -318,19 +375,9 @@ inline const std::vector &getValues() const { return Operands; } /// isNullValue - Return true if this is the value that would be returned by - /// getNullValue. - virtual bool isNullValue() const { - // FIXME: This should be made to be MUCH faster. Just check against well - // known null value! - if (getNumOperands()) { - const Constant *First = cast(getOperand(0)); - if (!First->isNullValue()) return false; - for (unsigned i = 1, e = getNumOperands(); i != e; ++i) - if (cast(getOperand(i)) != First) - return false; - } - return true; - } + /// getNullValue. This always returns false because zero arrays are always + /// created as ConstantAggregateZero objects. + virtual bool isNullValue() const { return false; } virtual void destroyConstant(); virtual void replaceUsesOfWithOnConstant(Value *From, Value *To, @@ -356,8 +403,7 @@ ConstantStruct(const StructType *T, const std::vector &Val); public: /// get() - Static factory methods - Return objects of the specified value - static ConstantStruct *get(const StructType *T, - const std::vector &V); + static Constant *get(const StructType *T, const std::vector &V); /// getType() specialization - Reduce amount of casting... inline const StructType *getType() const { @@ -369,14 +415,10 @@ inline const std::vector &getValues() const { return Operands; } /// isNullValue - Return true if this is the value that would be returned by - /// getNullValue. + /// getNullValue. This always returns false because zero structs are always + /// created as ConstantAggregateZero objects. virtual bool isNullValue() const { - // FIXME: This should be made to be MUCH faster. Just check against well - // known null value! - for (unsigned i = 0, e = getNumOperands(); i != e; ++i) - if (!cast(getOperand(i))->isNullValue()) - return false; - return true; + return false; } virtual void destroyConstant(); Index: llvm/include/llvm/DerivedTypes.h diff -u llvm/include/llvm/DerivedTypes.h:1.49.2.1 llvm/include/llvm/DerivedTypes.h:1.49.2.2 --- llvm/include/llvm/DerivedTypes.h:1.49.2.1 Fri Feb 6 12:40:35 2004 +++ llvm/include/llvm/DerivedTypes.h Mon Mar 1 17:57:19 2004 @@ -19,7 +19,6 @@ #define LLVM_DERIVED_TYPES_H #include "llvm/Type.h" -#include namespace llvm { @@ -30,20 +29,13 @@ class PointerValType; class DerivedType : public Type, public AbstractTypeUser { - /// RefCount - This counts the number of PATypeHolders that are pointing to - /// this type. When this number falls to zero, if the type is abstract and - /// has no AbstractTypeUsers, the type is deleted. - /// - mutable unsigned RefCount; - // AbstractTypeUsers - Implement a list of the users that need to be notified // if I am a type, and I get resolved into a more concrete type. // - ///// FIXME: kill mutable nonsense when Types are not const mutable std::vector AbstractTypeUsers; protected: - DerivedType(PrimitiveID id) : Type("", id), RefCount(0) {} + DerivedType(PrimitiveID id) : Type("", id) {} ~DerivedType() { assert(AbstractTypeUsers.empty()); } @@ -54,10 +46,17 @@ /// void notifyUsesThatTypeBecameConcrete(); - // dropAllTypeUses - When this (abstract) type is resolved to be equal to - // another (more concrete) type, we must eliminate all references to other - // types, to avoid some circular reference problems. - virtual void dropAllTypeUses() = 0; + /// dropAllTypeUses - When this (abstract) type is resolved to be equal to + /// another (more concrete) type, we must eliminate all references to other + /// types, to avoid some circular reference problems. + /// + void dropAllTypeUses(); + + void RefCountIsZero() const { + if (AbstractTypeUsers.empty()) + delete this; + } + public: @@ -66,45 +65,29 @@ // are managed by (add|remove)AbstractTypeUser. See comments in // AbstractTypeUser.h for more information. - // addAbstractTypeUser - Notify an abstract type that there is a new user of - // it. This function is called primarily by the PATypeHandle class. - // + /// addAbstractTypeUser - Notify an abstract type that there is a new user of + /// it. This function is called primarily by the PATypeHandle class. + /// void addAbstractTypeUser(AbstractTypeUser *U) const { assert(isAbstract() && "addAbstractTypeUser: Current type not abstract!"); AbstractTypeUsers.push_back(U); } - // removeAbstractTypeUser - Notify an abstract type that a user of the class - // no longer has a handle to the type. This function is called primarily by - // the PATypeHandle class. When there are no users of the abstract type, it - // is annihilated, because there is no way to get a reference to it ever - // again. - // + /// removeAbstractTypeUser - Notify an abstract type that a user of the class + /// no longer has a handle to the type. This function is called primarily by + /// the PATypeHandle class. When there are no users of the abstract type, it + /// is annihilated, because there is no way to get a reference to it ever + /// again. + /// void removeAbstractTypeUser(AbstractTypeUser *U) const; - // refineAbstractTypeTo - This function is used to when it is discovered that - // the 'this' abstract type is actually equivalent to the NewType specified. - // This causes all users of 'this' to switch to reference the more concrete - // type NewType and for 'this' to be deleted. - // + /// refineAbstractTypeTo - This function is used to when it is discovered that + /// the 'this' abstract type is actually equivalent to the NewType specified. + /// This causes all users of 'this' to switch to reference the more concrete + /// type NewType and for 'this' to be deleted. + /// void refineAbstractTypeTo(const Type *NewType); - void addRef() const { - assert(isAbstract() && "Cannot add a reference to a non-abstract type!"); - ++RefCount; - } - - void dropRef() const { - assert(isAbstract() && "Cannot drop a refernce to a non-abstract type!"); - assert(RefCount && "No objects are currently referencing this object!"); - - // If this is the last PATypeHolder using this object, and there are no - // PATypeHandles using it, the type is dead, delete it now. - if (--RefCount == 0 && AbstractTypeUsers.empty()) - delete this; - } - - void dump() const { Value::dump(); } // Methods for support type inquiry through isa, cast, and dyn_cast: @@ -118,56 +101,46 @@ }; - - -struct FunctionType : public DerivedType { - typedef std::vector ParamTypes; +/// FunctionType - Class to represent function types +/// +class FunctionType : public DerivedType { friend class TypeMap; -private: - PATypeHandle ResultType; - ParamTypes ParamTys; bool isVarArgs; FunctionType(const FunctionType &); // Do not implement const FunctionType &operator=(const FunctionType &); // Do not implement protected: - // This should really be private, but it squelches a bogus warning - // from GCC to make them protected: warning: `class FunctionType' only - // defines private constructors and has no friends - - // Private ctor - Only can be created by a static member... + /// This should really be private, but it squelches a bogus warning + /// from GCC to make them protected: warning: `class FunctionType' only + /// defines private constructors and has no friends + /// + /// Private ctor - Only can be created by a static member... + /// FunctionType(const Type *Result, const std::vector &Params, bool IsVarArgs); - // dropAllTypeUses - When this (abstract) type is resolved to be equal to - // another (more concrete) type, we must eliminate all references to other - // types, to avoid some circular reference problems. - virtual void dropAllTypeUses(); - public: /// FunctionType::get - This static method is the primary way of constructing /// a FunctionType + /// static FunctionType *get(const Type *Result, const std::vector &Params, bool isVarArg); inline bool isVarArg() const { return isVarArgs; } - inline const Type *getReturnType() const { return ResultType; } - inline const ParamTypes &getParamTypes() const { return ParamTys; } + inline const Type *getReturnType() const { return ContainedTys[0]; } - // Parameter type accessors... - const Type *getParamType(unsigned i) const { return ParamTys[i]; } - - // getNumParams - Return the number of fixed parameters this function type - // requires. This does not consider varargs. - // - unsigned getNumParams() const { return ParamTys.size(); } + typedef std::vector::const_iterator param_iterator; + param_iterator param_begin() const { return ContainedTys.begin()+1; } + param_iterator param_end() const { return ContainedTys.end(); } + // Parameter type accessors... + const Type *getParamType(unsigned i) const { return ContainedTys[i+1]; } - virtual const Type *getContainedType(unsigned i) const { - return i == 0 ? ResultType.get() : ParamTys[i-1].get(); - } - virtual unsigned getNumContainedTypes() const { return ParamTys.size()+1; } + /// getNumParams - Return the number of fixed parameters this function type + /// requires. This does not consider varargs. + /// + unsigned getNumParams() const { return ContainedTys.size()-1; } // Implement the AbstractTypeUser interface. virtual void refineAbstractType(const DerivedType *OldTy, const Type *NewTy); @@ -184,16 +157,16 @@ }; -// CompositeType - Common super class of ArrayType, StructType, and PointerType -// +/// CompositeType - Common super class of ArrayType, StructType, and PointerType +/// class CompositeType : public DerivedType { protected: inline CompositeType(PrimitiveID id) : DerivedType(id) { } public: - // getTypeAtIndex - Given an index value into the type, return the type of the - // element. - // + /// getTypeAtIndex - Given an index value into the type, return the type of + /// the element. + /// virtual const Type *getTypeAtIndex(const Value *V) const = 0; virtual bool indexValid(const Value *V) const = 0; @@ -210,44 +183,43 @@ }; -struct StructType : public CompositeType { +/// StructType - Class to represent struct types +/// +class StructType : public CompositeType { friend class TypeMap; - typedef std::vector ElementTypes; - -private: - ElementTypes ETypes; // Element types of struct - StructType(const StructType &); // Do not implement const StructType &operator=(const StructType &); // Do not implement protected: - // This should really be private, but it squelches a bogus warning - // from GCC to make them protected: warning: `class StructType' only - // defines private constructors and has no friends - - // Private ctor - Only can be created by a static member... + /// This should really be private, but it squelches a bogus warning + /// from GCC to make them protected: warning: `class StructType' only + /// defines private constructors and has no friends + /// + /// Private ctor - Only can be created by a static member... + /// StructType(const std::vector &Types); - // dropAllTypeUses - When this (abstract) type is resolved to be equal to - // another (more concrete) type, we must eliminate all references to other - // types, to avoid some circular reference problems. - virtual void dropAllTypeUses(); - public: /// StructType::get - This static method is the primary way to create a /// StructType. + /// static StructType *get(const std::vector &Params); - inline const ElementTypes &getElementTypes() const { return ETypes; } - - virtual const Type *getContainedType(unsigned i) const { - return ETypes[i].get(); + // Iterator access to the elements + typedef std::vector::const_iterator element_iterator; + element_iterator element_begin() const { return ContainedTys.begin(); } + element_iterator element_end() const { return ContainedTys.end(); } + + // Random access to the elements + unsigned getNumElements() const { return ContainedTys.size(); } + const Type *getElementType(unsigned N) const { + assert(N < ContainedTys.size() && "Element number out of range!"); + return ContainedTys[N]; } - virtual unsigned getNumContainedTypes() const { return ETypes.size(); } - // getTypeAtIndex - Given an index value into the type, return the type of the - // element. For a structure type, this must be a constant value... - // + /// getTypeAtIndex - Given an index value into the type, return the type of + /// the element. For a structure type, this must be a constant value... + /// virtual const Type *getTypeAtIndex(const Value *V) const ; virtual bool indexValid(const Value *V) const; @@ -266,35 +238,29 @@ }; -// SequentialType - This is the superclass of the array and pointer type -// classes. Both of these represent "arrays" in memory. The array type -// represents a specifically sized array, pointer types are unsized/unknown size -// arrays. SequentialType holds the common features of both, which stem from -// the fact that both lay their components out in memory identically. -// +/// SequentialType - This is the superclass of the array and pointer type +/// classes. Both of these represent "arrays" in memory. The array type +/// represents a specifically sized array, pointer types are unsized/unknown +/// size arrays. SequentialType holds the common features of both, which stem +/// from the fact that both lay their components out in memory identically. +/// class SequentialType : public CompositeType { SequentialType(const SequentialType &); // Do not implement! const SequentialType &operator=(const SequentialType &); // Do not implement! protected: - PATypeHandle ElementType; - - SequentialType(PrimitiveID TID, const Type *ElType) - : CompositeType(TID), ElementType(PATypeHandle(ElType, this)) { + SequentialType(PrimitiveID TID, const Type *ElType) : CompositeType(TID) { + ContainedTys.reserve(1); + ContainedTys.push_back(PATypeHandle(ElType, this)); } public: - inline const Type *getElementType() const { return ElementType; } + inline const Type *getElementType() const { return ContainedTys[0]; } - virtual const Type *getContainedType(unsigned i) const { - return ElementType.get(); - } - virtual unsigned getNumContainedTypes() const { return 1; } - - // getTypeAtIndex - Given an index value into the type, return the type of the - // element. For sequential types, there is only one subtype... - // + /// getTypeAtIndex - Given an index value into the type, return the type of + /// the element. For sequential types, there is only one subtype... + /// virtual const Type *getTypeAtIndex(const Value *V) const { - return ElementType.get(); + return ContainedTys[0]; } virtual bool indexValid(const Value *V) const { return V->getType()->isInteger(); @@ -312,6 +278,8 @@ }; +/// ArrayType - Class to represent array types +/// class ArrayType : public SequentialType { friend class TypeMap; unsigned NumElements; @@ -319,21 +287,18 @@ ArrayType(const ArrayType &); // Do not implement const ArrayType &operator=(const ArrayType &); // Do not implement protected: - // This should really be private, but it squelches a bogus warning - // from GCC to make them protected: warning: `class ArrayType' only - // defines private constructors and has no friends - - // Private ctor - Only can be created by a static member... + /// This should really be private, but it squelches a bogus warning + /// from GCC to make them protected: warning: `class ArrayType' only + /// defines private constructors and has no friends + /// + /// Private ctor - Only can be created by a static member... + /// ArrayType(const Type *ElType, unsigned NumEl); - // dropAllTypeUses - When this (abstract) type is resolved to be equal to - // another (more concrete) type, we must eliminate all references to other - // types, to avoid some circular reference problems. - virtual void dropAllTypeUses(); - public: /// ArrayType::get - This static method is the primary way to construct an /// ArrayType + /// static ArrayType *get(const Type *ElementType, unsigned NumElements); inline unsigned getNumElements() const { return NumElements; } @@ -353,7 +318,8 @@ }; - +/// PointerType - Class to represent pointers +/// class PointerType : public SequentialType { friend class TypeMap; PointerType(const PointerType &); // Do not implement @@ -366,10 +332,6 @@ // Private ctor - Only can be created by a static member... PointerType(const Type *ElType); - // dropAllTypeUses - When this (abstract) type is resolved to be equal to - // another (more concrete) type, we must eliminate all references to other - // types, to avoid some circular reference problems. - virtual void dropAllTypeUses(); public: /// PointerType::get - This is the only way to construct a new pointer type. static PointerType *get(const Type *ElementType); @@ -389,26 +351,22 @@ }; +/// OpaqueType - Class to represent abstract types +/// class OpaqueType : public DerivedType { OpaqueType(const OpaqueType &); // DO NOT IMPLEMENT const OpaqueType &operator=(const OpaqueType &); // DO NOT IMPLEMENT protected: - // This should really be private, but it squelches a bogus warning - // from GCC to make them protected: warning: `class OpaqueType' only - // defines private constructors and has no friends - - // Private ctor - Only can be created by a static member... + /// This should really be private, but it squelches a bogus warning + /// from GCC to make them protected: warning: `class OpaqueType' only + /// defines private constructors and has no friends + /// + /// Private ctor - Only can be created by a static member... OpaqueType(); - // dropAllTypeUses - When this (abstract) type is resolved to be equal to - // another (more concrete) type, we must eliminate all references to other - // types, to avoid some circular reference problems. - virtual void dropAllTypeUses() { - // FIXME: THIS IS NOT AN ABSTRACT TYPE USER! - } // No type uses - public: - // OpaqueType::get - Static factory method for the OpaqueType class... + /// OpaqueType::get - Static factory method for the OpaqueType class... + /// static OpaqueType *get() { return new OpaqueType(); // All opaque types are distinct } @@ -430,50 +388,6 @@ return isa(V) && classof(cast(V)); } }; - - -// Define some inline methods for the AbstractTypeUser.h:PATypeHandle class. -// These are defined here because they MUST be inlined, yet are dependent on -// the definition of the Type class. Of course Type derives from Value, which -// contains an AbstractTypeUser instance, so there is no good way to factor out -// the code. Hence this bit of uglyness. -// -inline void PATypeHandle::addUser() { - assert(Ty && "Type Handle has a null type!"); - if (Ty->isAbstract()) - cast(Ty)->addAbstractTypeUser(User); -} -inline void PATypeHandle::removeUser() { - if (Ty->isAbstract()) - cast(Ty)->removeAbstractTypeUser(User); -} - -inline void PATypeHandle::removeUserFromConcrete() { - if (!Ty->isAbstract()) - cast(Ty)->removeAbstractTypeUser(User); -} - -// Define inline methods for PATypeHolder... - -inline void PATypeHolder::addRef() { - if (Ty->isAbstract()) - cast(Ty)->addRef(); -} - -inline void PATypeHolder::dropRef() { - if (Ty->isAbstract()) - cast(Ty)->dropRef(); -} - -/// get - This implements the forwarding part of the union-find algorithm for -/// abstract types. Before every access to the Type*, we check to see if the -/// type we are pointing to is forwarding to a new type. If so, we drop our -/// reference to the type. -inline const Type* PATypeHolder::get() const { - const Type *NewTy = Ty->getForwardedType(); - if (!NewTy) return Ty; - return *const_cast(this) = NewTy; -} } // End llvm namespace Index: llvm/include/llvm/Function.h diff -u llvm/include/llvm/Function.h:1.49 llvm/include/llvm/Function.h:1.49.4.1 --- llvm/include/llvm/Function.h:1.49 Tue Nov 11 16:41:29 2003 +++ llvm/include/llvm/Function.h Mon Mar 1 17:57:19 2004 @@ -21,6 +21,7 @@ #include "llvm/GlobalValue.h" #include "llvm/BasicBlock.h" #include "llvm/Argument.h" +#include "Support/Annotation.h" namespace llvm { @@ -44,7 +45,7 @@ static iplist &getList(Function *F); }; -class Function : public GlobalValue { +class Function : public GlobalValue, public Annotable { public: typedef iplist ArgumentListType; typedef iplist BasicBlockListType; @@ -61,7 +62,6 @@ typedef std::reverse_iterator reverse_aiterator; private: - // Important things that make up a function! BasicBlockListType BasicBlocks; // The basic blocks ArgumentListType ArgumentList; // The formal arguments @@ -90,8 +90,8 @@ const Type *getReturnType() const; // Return the type of the ret val const FunctionType *getFunctionType() const; // Return the FunctionType for me - /// isExternal - Is the body of this function unknown? (the basic block list - /// is empty if so) this is true for external functions, defined as forward + /// isExternal - Is the body of this function unknown? (The basic block list + /// is empty if so.) This is true for external functions, defined as forward /// "declare"ations /// virtual bool isExternal() const { return BasicBlocks.empty(); } @@ -108,6 +108,7 @@ /// deleteBody - This method deletes the body of the function, and converts /// the linkage to external. + /// void deleteBody() { dropAllReferences(); setLinkage(ExternalLinkage); @@ -196,8 +197,8 @@ /// viewCFGOnly - This function is meant for use from the debugger. It works /// just like viewCFG, but it does not include the contents of basic blocks - /// into the nodes, just the label. If you are only interested in the CFG t - /// his can make the graph smaller. + /// into the nodes, just the label. If you are only interested in the CFG + /// this can make the graph smaller. /// void viewCFGOnly() const; @@ -211,7 +212,7 @@ /// go" of all references that they are maintaining. This allows one to /// 'delete' a whole module at a time, even though there may be circular /// references... first all references are dropped, and all use counts go to - /// zero. Then everything is delete'd for real. Note that no operations are + /// zero. Then everything is deleted for real. Note that no operations are /// valid on an object that has "dropped all references", except operator /// delete. /// Index: llvm/include/llvm/Instruction.h diff -u llvm/include/llvm/Instruction.h:1.50 llvm/include/llvm/Instruction.h:1.50.2.1 --- llvm/include/llvm/Instruction.h:1.50 Mon Jan 12 17:18:06 2004 +++ llvm/include/llvm/Instruction.h Mon Mar 1 17:57:19 2004 @@ -16,6 +16,7 @@ #define LLVM_INSTRUCTION_H #include "llvm/User.h" +#include "Support/Annotation.h" namespace llvm { @@ -25,7 +26,7 @@ template class SymbolTableListTraits; -class Instruction : public User { +class Instruction : public User, public Annotable { BasicBlock *Parent; Instruction *Prev, *Next; // Next and Prev links for our intrusive linked list Index: llvm/include/llvm/Intrinsics.h diff -u llvm/include/llvm/Intrinsics.h:1.15.2.1 llvm/include/llvm/Intrinsics.h:1.15.2.2 --- llvm/include/llvm/Intrinsics.h:1.15.2.1 Mon Feb 2 16:32:05 2004 +++ llvm/include/llvm/Intrinsics.h Mon Mar 1 17:57:19 2004 @@ -31,6 +31,15 @@ va_end, // Used to implement the va_end macro in C va_copy, // Used to implement the va_copy macro in C + // Code generator intrinsics... + returnaddress, // Yields the return address of a dynamic call frame + frameaddress, // Yields the frame address of a dynamic call frame + + // Standard libc functions... + memcpy, // Copy non-overlapping memory blocks + memmove, // Copy potentially overlapping memory blocks + memset, // Fill memory with a byte value + // Setjmp/Longjmp intrinsics... setjmp, // Used to represent a setjmp call in C longjmp, // Used to represent a longjmp call in C @@ -47,6 +56,8 @@ // Parallelism/atomicity/synchronization intrinsics... join, + // Standard libm functions... + //===------------------------------------------------------------------===// // This section defines intrinsic functions used to represent Alpha // instructions... Index: llvm/include/llvm/ModuleProvider.h diff -u llvm/include/llvm/ModuleProvider.h:1.8 llvm/include/llvm/ModuleProvider.h:1.8.2.1 --- llvm/include/llvm/ModuleProvider.h:1.8 Mon Dec 29 20:44:04 2003 +++ llvm/include/llvm/ModuleProvider.h Mon Mar 1 17:57:19 2004 @@ -35,15 +35,18 @@ /// Module* getModule() { return TheModule; } - /// materializeFunction - make sure the given function is fully read. + /// materializeFunction - make sure the given function is fully read. Note + /// that this can throw an exception if the module is corrupt! /// virtual void materializeFunction(Function *F) = 0; /// materializeModule - make sure the entire Module has been completely read. + /// Note that this can throw an exception if the module is corrupt! /// - Module* materializeModule(); + virtual Module* materializeModule() = 0; /// releaseModule - no longer delete the Module* when provider is destroyed. + /// Note that this can throw an exception if the module is corrupt! /// virtual Module* releaseModule() { // Since we're losing control of this Module, we must hand it back complete @@ -64,6 +67,7 @@ TheModule = M; } void materializeFunction(Function *F) {} + Module* materializeModule() { return TheModule; } }; } // End llvm namespace Index: llvm/include/llvm/Type.h diff -u llvm/include/llvm/Type.h:1.37 llvm/include/llvm/Type.h:1.37.4.1 --- llvm/include/llvm/Type.h:1.37 Tue Nov 11 16:41:30 2003 +++ llvm/include/llvm/Type.h Mon Mar 1 17:57:19 2004 @@ -36,6 +36,7 @@ #include "llvm/Value.h" #include "Support/GraphTraits.h" #include "Support/iterator" +#include namespace llvm { @@ -82,6 +83,13 @@ unsigned UID; // The unique ID number for this class bool Abstract; // True if type contains an OpaqueType + /// RefCount - This counts the number of PATypeHolders that are pointing to + /// this type. When this number falls to zero, if the type is abstract and + /// has no AbstractTypeUsers, the type is deleted. This is only sensical for + /// derived types. + /// + mutable unsigned RefCount; + const Type *getForwardedTypeInternal() const; protected: /// ctor is protected, so only subclasses can create Type objects... @@ -101,11 +109,22 @@ /// bool isTypeAbstract(); + unsigned getRefCount() const { return RefCount; } + /// ForwardType - This field is used to implement the union find scheme for /// abstract types. When types are refined to other types, this field is set /// to the more refined type. Only abstract types can be forwarded. mutable const Type *ForwardType; + /// ContainedTys - The list of types contained by this one. For example, this + /// includes the arguments of a function type, the elements of the structure, + /// the pointee of a pointer, etc. Note that keeping this vector in the Type + /// class wastes some space for types that do not contain anything (such as + /// primitive types). However, keeping it here allows the subtype_* members + /// to be implemented MUCH more efficiently, and dynamically very few types do + /// not contain any elements (most are derived). + std::vector ContainedTys; + public: virtual void print(std::ostream &O) const; @@ -132,7 +151,7 @@ /// isSigned - Return whether an integral numeric type is signed. This is /// true for SByteTy, ShortTy, IntTy, LongTy. Note that this is not true for /// Float and Double. - // + /// virtual bool isSigned() const { return 0; } /// isUnsigned - Return whether a numeric type is unsigned. This is not quite @@ -204,22 +223,22 @@ //===--------------------------------------------------------------------===// // Type Iteration support // - class TypeIterator; - typedef TypeIterator subtype_iterator; - inline subtype_iterator subtype_begin() const; // DEFINED BELOW - inline subtype_iterator subtype_end() const; // DEFINED BELOW + typedef std::vector::const_iterator subtype_iterator; + subtype_iterator subtype_begin() const { return ContainedTys.begin(); } + subtype_iterator subtype_end() const { return ContainedTys.end(); } /// getContainedType - This method is used to implement the type iterator /// (defined a the end of the file). For derived types, this returns the /// types 'contained' in the derived type. /// - virtual const Type *getContainedType(unsigned i) const { - assert(0 && "No contained types!"); - return 0; + const Type *getContainedType(unsigned i) const { + assert(i < ContainedTys.size() && "Index out of range!"); + return ContainedTys[i]; } - /// getNumContainedTypes - Return the number of types in the derived type - virtual unsigned getNumContainedTypes() const { return 0; } + /// getNumContainedTypes - Return the number of types in the derived type. + /// + unsigned getNumContainedTypes() const { return ContainedTys.size(); } //===--------------------------------------------------------------------===// // Static members exported by the Type class itself. Useful for getting @@ -250,49 +269,88 @@ #include "llvm/Type.def" + // Virtual methods used by callbacks below. These should only be implemented + // in the DerivedType class. + virtual void addAbstractTypeUser(AbstractTypeUser *U) const { + abort(); // Only on derived types! + } + virtual void removeAbstractTypeUser(AbstractTypeUser *U) const { + abort(); // Only on derived types! + } + + void addRef() const { + assert(isAbstract() && "Cannot add a reference to a non-abstract type!"); + ++RefCount; + } + + void dropRef() const { + assert(isAbstract() && "Cannot drop a refernce to a non-abstract type!"); + assert(RefCount && "No objects are currently referencing this object!"); + + // If this is the last PATypeHolder using this object, and there are no + // PATypeHandles using it, the type is dead, delete it now. + if (--RefCount == 0) + RefCountIsZero(); + } private: - class TypeIterator : public bidirectional_iterator { - const Type * const Ty; - unsigned Idx; - - typedef TypeIterator _Self; - public: - TypeIterator(const Type *ty, unsigned idx) : Ty(ty), Idx(idx) {} - ~TypeIterator() {} - - const _Self &operator=(const _Self &RHS) { - assert(Ty == RHS.Ty && "Cannot assign from different types!"); - Idx = RHS.Idx; - return *this; - } - - bool operator==(const _Self& x) const { return Idx == x.Idx; } - bool operator!=(const _Self& x) const { return !operator==(x); } - - pointer operator*() const { return Ty->getContainedType(Idx); } - pointer operator->() const { return operator*(); } - - _Self& operator++() { ++Idx; return *this; } // Preincrement - _Self operator++(int) { // Postincrement - _Self tmp = *this; ++*this; return tmp; - } - - _Self& operator--() { --Idx; return *this; } // Predecrement - _Self operator--(int) { // Postdecrement - _Self tmp = *this; --*this; return tmp; - } - }; + virtual void RefCountIsZero() const { + abort(); // only on derived types! + } + }; -inline Type::TypeIterator Type::subtype_begin() const { - return TypeIterator(this, 0); +//===----------------------------------------------------------------------===// +// Define some inline methods for the AbstractTypeUser.h:PATypeHandle class. +// These are defined here because they MUST be inlined, yet are dependent on +// the definition of the Type class. Of course Type derives from Value, which +// contains an AbstractTypeUser instance, so there is no good way to factor out +// the code. Hence this bit of uglyness. +// +// In the long term, Type should not derive from Value, allowing +// AbstractTypeUser.h to #include Type.h, allowing us to eliminate this +// nastyness entirely. +// +inline void PATypeHandle::addUser() { + assert(Ty && "Type Handle has a null type!"); + if (Ty->isAbstract()) + Ty->addAbstractTypeUser(User); +} +inline void PATypeHandle::removeUser() { + if (Ty->isAbstract()) + Ty->removeAbstractTypeUser(User); +} + +inline void PATypeHandle::removeUserFromConcrete() { + if (!Ty->isAbstract()) + Ty->removeAbstractTypeUser(User); } -inline Type::TypeIterator Type::subtype_end() const { - return TypeIterator(this, getNumContainedTypes()); +// Define inline methods for PATypeHolder... + +inline void PATypeHolder::addRef() { + if (Ty->isAbstract()) + Ty->addRef(); +} + +inline void PATypeHolder::dropRef() { + if (Ty->isAbstract()) + Ty->dropRef(); } +/// get - This implements the forwarding part of the union-find algorithm for +/// abstract types. Before every access to the Type*, we check to see if the +/// type we are pointing to is forwarding to a new type. If so, we drop our +/// reference to the type. +/// +inline const Type* PATypeHolder::get() const { + const Type *NewTy = Ty->getForwardedType(); + if (!NewTy) return Ty; + return *const_cast(this) = NewTy; +} + + +//===----------------------------------------------------------------------===// // Provide specializations of GraphTraits to be able to treat a type as a // graph of sub types... Index: llvm/include/llvm/Value.h diff -u llvm/include/llvm/Value.h:1.49 llvm/include/llvm/Value.h:1.49.2.1 --- llvm/include/llvm/Value.h:1.49 Sat Jan 10 15:40:29 2004 +++ llvm/include/llvm/Value.h Mon Mar 1 17:57:19 2004 @@ -19,7 +19,6 @@ #include "llvm/AbstractTypeUser.h" #include "llvm/Use.h" -#include "Support/Annotation.h" #include "Support/Casting.h" #include @@ -42,7 +41,7 @@ /// Value - The base class of all values computed by a program that may be used /// as operands to other values. /// -struct Value : public Annotable { // Values are annotable +struct Value { enum ValueTy { TypeVal, // This is an instance of Type ConstantVal, // This is an instance of Constant Index: llvm/include/llvm/iMemory.h diff -u llvm/include/llvm/iMemory.h:1.43 llvm/include/llvm/iMemory.h:1.43.4.1 --- llvm/include/llvm/iMemory.h:1.43 Sun Nov 16 14:21:15 2003 +++ llvm/include/llvm/iMemory.h Mon Mar 1 17:57:19 2004 @@ -24,35 +24,36 @@ //===----------------------------------------------------------------------===// // AllocationInst Class //===----------------------------------------------------------------------===// -// -// AllocationInst - This class is the common base class of MallocInst and -// AllocaInst. -// + +/// AllocationInst - This class is the common base class of MallocInst and +/// AllocaInst. +/// class AllocationInst : public Instruction { protected: AllocationInst(const Type *Ty, Value *ArraySize, unsigned iTy, const std::string &Name = "", Instruction *InsertBefore = 0); public: - // isArrayAllocation - Return true if there is an allocation size parameter - // to the allocation instruction that is not 1. - // + /// isArrayAllocation - Return true if there is an allocation size parameter + /// to the allocation instruction that is not 1. + /// bool isArrayAllocation() const; - // getArraySize - Get the number of element allocated, for a simple allocation - // of a single element, this will return a constant 1 value. - // + /// getArraySize - Get the number of element allocated, for a simple + /// allocation of a single element, this will return a constant 1 value. + /// inline const Value *getArraySize() const { return Operands[0]; } inline Value *getArraySize() { return Operands[0]; } - // getType - Overload to return most specific pointer type... + /// getType - Overload to return most specific pointer type + /// inline const PointerType *getType() const { return reinterpret_cast(Instruction::getType()); } - // getAllocatedType - Return the type that is being allocated by the - // instruction. - // + /// getAllocatedType - Return the type that is being allocated by the + /// instruction. + /// const Type *getAllocatedType() const; virtual Instruction *clone() const = 0; @@ -73,6 +74,8 @@ // MallocInst Class //===----------------------------------------------------------------------===// +/// MallocInst - an instruction to allocated memory on the heap +/// class MallocInst : public AllocationInst { MallocInst(const MallocInst &MI); public: @@ -99,6 +102,8 @@ // AllocaInst Class //===----------------------------------------------------------------------===// +/// AllocaInst - an instruction to allocate memory on the stack +/// class AllocaInst : public AllocationInst { AllocaInst(const AllocaInst &); public: @@ -125,6 +130,8 @@ // FreeInst Class //===----------------------------------------------------------------------===// +/// FreeInst - an instruction to deallocate memory +/// struct FreeInst : public Instruction { FreeInst(Value *Ptr, Instruction *InsertBefore = 0); @@ -147,6 +154,8 @@ // LoadInst Class //===----------------------------------------------------------------------===// +/// LoadInst - an instruction for reading from memory +/// class LoadInst : public Instruction { LoadInst(const LoadInst &LI) : Instruction(LI.getType(), Load) { Volatile = LI.isVolatile(); @@ -161,6 +170,7 @@ /// isVolatile - Return true if this is a load from a volatile memory /// location. + /// bool isVolatile() const { return Volatile; } /// setVolatile - Specify whether this is a volatile load or not. @@ -190,6 +200,8 @@ // StoreInst Class //===----------------------------------------------------------------------===// +/// StoreInst - an instruction for storing to memory +/// class StoreInst : public Instruction { StoreInst(const StoreInst &SI) : Instruction(SI.getType(), Store) { Volatile = SI.isVolatile(); @@ -206,6 +218,7 @@ /// isVolatile - Return true if this is a load from a volatile memory /// location. + /// bool isVolatile() const { return Volatile; } /// setVolatile - Specify whether this is a volatile load or not. @@ -235,6 +248,9 @@ // GetElementPtrInst Class //===----------------------------------------------------------------------===// +/// GetElementPtrInst - an instruction for type-safe pointer arithmetic to +/// access elements of arrays and structs +/// class GetElementPtrInst : public Instruction { GetElementPtrInst(const GetElementPtrInst &EPI) : Instruction(reinterpret_cast(EPI.getType()), GetElementPtr) { @@ -262,12 +278,8 @@ const std::vector &Indices, bool AllowStructLeaf = false); - inline op_iterator idx_begin() { - return op_begin()+1; - } - inline const_op_iterator idx_begin() const { - return op_begin()+1; - } + inline op_iterator idx_begin() { return op_begin()+1; } + inline const_op_iterator idx_begin() const { return op_begin()+1; } inline op_iterator idx_end() { return op_end(); } inline const_op_iterator idx_end() const { return op_end(); } Index: llvm/include/llvm/iOther.h diff -u llvm/include/llvm/iOther.h:1.43 llvm/include/llvm/iOther.h:1.43.4.1 --- llvm/include/llvm/iOther.h:1.43 Sun Dec 7 23:29:33 2003 +++ llvm/include/llvm/iOther.h Mon Mar 1 17:57:19 2004 @@ -56,6 +56,9 @@ // CallInst Class //===----------------------------------------------------------------------===// +/// CallInst - This class represents a function call, abstracting a target +/// machine's calling convention. +/// class CallInst : public Instruction { CallInst(const CallInst &CI); public: @@ -63,10 +66,10 @@ const std::string &Name = "", Instruction *InsertBefore = 0); // Alternate CallInst ctors w/ no actuals & one actual, respectively. - CallInst(Value *F, const std::string &Name = "", - Instruction *InsertBefore = 0); + CallInst(Value *F, const std::string &Name = "", + Instruction *InsertBefore = 0); CallInst(Value *F, Value *Actual, const std::string& Name = "", - Instruction* InsertBefore = 0); + Instruction *InsertBefore = 0); virtual Instruction *clone() const { return new CallInst(*this); } bool mayWriteToMemory() const { return true; } @@ -95,8 +98,8 @@ // ShiftInst Class //===----------------------------------------------------------------------===// -// ShiftInst - This class represents left and right shift instructions. -// +/// ShiftInst - This class represents left and right shift instructions. +/// class ShiftInst : public Instruction { ShiftInst(const ShiftInst &SI) : Instruction(SI.getType(), SI.getOpcode()) { Operands.reserve(2); Index: llvm/include/llvm/iPHINode.h diff -u llvm/include/llvm/iPHINode.h:1.15 llvm/include/llvm/iPHINode.h:1.15.4.1 --- llvm/include/llvm/iPHINode.h:1.15 Sun Nov 16 14:21:15 2003 +++ llvm/include/llvm/iPHINode.h Mon Mar 1 17:57:19 2004 @@ -38,11 +38,12 @@ virtual Instruction *clone() const { return new PHINode(*this); } - /// getNumIncomingValues - Return the number of incoming edges the PHI node - /// has + /// getNumIncomingValues - Return the number of incoming edges + /// unsigned getNumIncomingValues() const { return Operands.size()/2; } /// getIncomingValue - Return incoming value #x + /// Value *getIncomingValue(unsigned i) const { assert(i*2 < Operands.size() && "Invalid value number!"); return Operands[i*2]; @@ -56,6 +57,7 @@ } /// getIncomingBlock - Return incoming basic block #x + /// BasicBlock *getIncomingBlock(unsigned i) const { assert(i*2+1 < Operands.size() && "Invalid value number!"); return reinterpret_cast(Operands[i*2+1].get()); @@ -69,6 +71,7 @@ } /// addIncoming - Add an incoming value to the end of the PHI list + /// void addIncoming(Value *D, BasicBlock *BB) { assert(getType() == D->getType() && "All operands to PHI node must be the same type as the PHI node!"); Index: llvm/include/llvm/iTerminators.h diff -u llvm/include/llvm/iTerminators.h:1.37.4.2 llvm/include/llvm/iTerminators.h:1.37.4.3 --- llvm/include/llvm/iTerminators.h:1.37.4.2 Sat Feb 7 17:53:57 2004 +++ llvm/include/llvm/iTerminators.h Mon Mar 1 17:57:19 2004 @@ -21,9 +21,9 @@ namespace llvm { //===--------------------------------------------------------------------------- -// ReturnInst - Return a value (possibly void), from a function. Execution does -// not continue in this function any longer. -// +/// ReturnInst - Return a value (possibly void), from a function. Execution +/// does not continue in this function any longer. +/// class ReturnInst : public TerminatorInst { ReturnInst(const ReturnInst &RI) : TerminatorInst(Instruction::Ret) { if (RI.Operands.size()) { @@ -83,8 +83,8 @@ }; //===--------------------------------------------------------------------------- -// BranchInst - Conditional or Unconditional Branch instruction. -// +/// BranchInst - Conditional or Unconditional Branch instruction. +/// class BranchInst : public TerminatorInst { BranchInst(const BranchInst &BI); public: @@ -190,8 +190,8 @@ //===--------------------------------------------------------------------------- -// SwitchInst - Multiway switch -// +/// SwitchInst - Multiway switch +/// class SwitchInst : public TerminatorInst { // Operand[0] = Value to switch on // Operand[1] = Default basic block destination @@ -215,6 +215,36 @@ return cast(Operands[1].get()); } + /// getNumCases - return the number of 'cases' in this switch instruction. + /// Note that case #0 is always the default case. + unsigned getNumCases() const { + return Operands.size()/2; + } + + /// getCaseValue - Return the specified case value. Note that case #0, the + /// default destination, does not have a case value. + Constant *getCaseValue(unsigned i) { + assert(i && i < getNumCases() && "Illegal case value to get!"); + return getSuccessorValue(i); + } + + /// getCaseValue - Return the specified case value. Note that case #0, the + /// default destination, does not have a case value. + const Constant *getCaseValue(unsigned i) const { + assert(i && i < getNumCases() && "Illegal case value to get!"); + return getSuccessorValue(i); + } + + /// findCaseValue - Search all of the case values for the specified constant. + /// If it is explicitly handled, return the case number of it, otherwise + /// return 0 to indicate that it is handled by the default handler. + unsigned findCaseValue(const Constant *C) const { + for (unsigned i = 1, e = getNumCases(); i != e; ++i) + if (getCaseValue(i) == C) + return i; + return 0; + } + /// addCase - Add an entry to the switch instruction... /// void addCase(Constant *OnVal, BasicBlock *Dest); @@ -261,10 +291,9 @@ } }; - //===--------------------------------------------------------------------------- -// InvokeInst - Invoke instruction -// +/// InvokeInst - Invoke instruction +/// class InvokeInst : public TerminatorInst { InvokeInst(const InvokeInst &BI); public: @@ -298,10 +327,10 @@ inline BasicBlock *getNormalDest() { return cast(Operands[1].get()); } - inline const BasicBlock *getExceptionalDest() const { + inline const BasicBlock *getUnwindDest() const { return cast(Operands[2].get()); } - inline BasicBlock *getExceptionalDest() { + inline BasicBlock *getUnwindDest() { return cast(Operands[2].get()); } @@ -309,17 +338,17 @@ Operands[1] = reinterpret_cast(B); } - inline void setExceptionalDest(BasicBlock *B){ + inline void setUnwindDest(BasicBlock *B){ Operands[2] = reinterpret_cast(B); } virtual const BasicBlock *getSuccessor(unsigned i) const { assert(i < 2 && "Successor # out of range for invoke!"); - return i == 0 ? getNormalDest() : getExceptionalDest(); + return i == 0 ? getNormalDest() : getUnwindDest(); } inline BasicBlock *getSuccessor(unsigned i) { assert(i < 2 && "Successor # out of range for invoke!"); - return i == 0 ? getNormalDest() : getExceptionalDest(); + return i == 0 ? getNormalDest() : getUnwindDest(); } virtual void setSuccessor(unsigned idx, BasicBlock *NewSucc) { From brukman at cs.uiuc.edu Mon Mar 1 17:59:39 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Mar 1 17:59:39 2004 Subject: [llvm-commits] [parallel] CVS: llvm/include/llvm/CodeGen/LiveVariables.h MachineBasicBlock.h MachineCodeForInstruction.h MachineFrameInfo.h MachineFunction.h MachineInstr.h MachineInstrBuilder.h Passes.h SSARegMap.h SchedGraphCommon.h FunctionLiveVarInfo.h LiveIntervals.h MachineInstrAnnot.h Message-ID: <200403012357.RAA03406@zion.cs.uiuc.edu> Changes in directory llvm/include/llvm/CodeGen: LiveVariables.h updated: 1.11 -> 1.11.2.1 MachineBasicBlock.h updated: 1.13 -> 1.13.4.1 MachineCodeForInstruction.h updated: 1.12 -> 1.12.4.1 MachineFrameInfo.h updated: 1.9 -> 1.9.4.1 MachineFunction.h updated: 1.31 -> 1.31.2.1 MachineInstr.h updated: 1.118 -> 1.118.2.1 MachineInstrBuilder.h updated: 1.16 -> 1.16.4.1 Passes.h updated: 1.12 -> 1.12.2.1 SSARegMap.h updated: 1.8 -> 1.8.4.1 SchedGraphCommon.h updated: 1.9 -> 1.9.2.1 FunctionLiveVarInfo.h (r1.32) removed LiveIntervals.h (r1.11) removed MachineInstrAnnot.h (r1.13) removed --- Log message: Merge from trunk --- Diffs of the changes: (+287 -224) Index: llvm/include/llvm/CodeGen/LiveVariables.h diff -u llvm/include/llvm/CodeGen/LiveVariables.h:1.11 llvm/include/llvm/CodeGen/LiveVariables.h:1.11.2.1 --- llvm/include/llvm/CodeGen/LiveVariables.h:1.11 Sun Jan 11 03:18:45 2004 +++ llvm/include/llvm/CodeGen/LiveVariables.h Mon Mar 1 17:57:19 2004 @@ -103,6 +103,12 @@ /// BBMap - Maps LLVM basic blocks to their corresponding machine basic block. /// This also provides a numbering of the basic blocks in the function. std::map > BBMap; + + + /// BBIdxMap - This contains the inverse mapping of BBMap, going from block ID + /// numbers to the corresponding MachineBasicBlock. This is lazily computed + /// when the getIndexMachineBasicBlock() method is called. + std::vector BBIdxMap; const MRegisterInfo *RegInfo; @@ -126,6 +132,9 @@ return BBMap.find(BB)->second; } + /// getIndexMachineBasicBlock() - Given a block index, return the + /// MachineBasicBlock corresponding to it. + MachineBasicBlock *getIndexMachineBasicBlock(unsigned Idx); /// killed_iterator - Iterate over registers killed by a machine instruction /// @@ -158,6 +167,12 @@ //===--------------------------------------------------------------------===// // API to update live variable information + /// instructionChanged - When the address of an instruction changes, this + /// method should be called so that live variables can update its internal + /// data structures. This removes the records for OldMI, transfering them to + /// the records for NewMI. + void instructionChanged(MachineInstr *OldMI, MachineInstr *NewMI); + /// addVirtualRegisterKilled - Add information about the fact that the /// specified register is killed after being used by the specified /// instruction. @@ -243,6 +258,7 @@ RegistersKilled.clear(); RegistersDead.clear(); BBMap.clear(); + BBIdxMap.clear(); } /// getVarInfo - Return the VarInfo structure for the specified VIRTUAL Index: llvm/include/llvm/CodeGen/MachineBasicBlock.h diff -u llvm/include/llvm/CodeGen/MachineBasicBlock.h:1.13 llvm/include/llvm/CodeGen/MachineBasicBlock.h:1.13.4.1 --- llvm/include/llvm/CodeGen/MachineBasicBlock.h:1.13 Tue Nov 11 16:41:31 2003 +++ llvm/include/llvm/CodeGen/MachineBasicBlock.h Mon Mar 1 17:57:19 2004 @@ -14,40 +14,77 @@ #ifndef LLVM_CODEGEN_MACHINEBASICBLOCK_H #define LLVM_CODEGEN_MACHINEBASICBLOCK_H -#include +#include "llvm/CodeGen/MachineInstr.h" +#include "Support/ilist" +#include namespace llvm { + class MachineFunction; + +// ilist_traits +template <> +class ilist_traits { + // this is only set by the MachineBasicBlock owning the ilist + friend class MachineBasicBlock; + MachineBasicBlock* parent; + +public: + ilist_traits() : parent(0) { } + + static MachineInstr* getPrev(MachineInstr* N) { return N->prev; } + static MachineInstr* getNext(MachineInstr* N) { return N->next; } + + static const MachineInstr* + getPrev(const MachineInstr* N) { return N->prev; } + + static const MachineInstr* + getNext(const MachineInstr* N) { return N->next; } + + static void setPrev(MachineInstr* N, MachineInstr* prev) { N->prev = prev; } + static void setNext(MachineInstr* N, MachineInstr* next) { N->next = next; } + + static MachineInstr* createNode(); + void addNodeToList(MachineInstr* N); + void removeNodeFromList(MachineInstr* N); + void transferNodesFromList( + iplist >& toList, + ilist_iterator first, + ilist_iterator last); +}; class BasicBlock; -class MachineInstr; -template struct ilist_traits; class MachineBasicBlock { - std::vector Insts; +public: + typedef ilist Instructions; + Instructions Insts; MachineBasicBlock *Prev, *Next; const BasicBlock *BB; public: - MachineBasicBlock(const BasicBlock *bb = 0) : Prev(0), Next(0), BB(bb) {} + MachineBasicBlock(const BasicBlock *bb = 0) : Prev(0), Next(0), BB(bb) { + Insts.parent = this; + } ~MachineBasicBlock() {} /// getBasicBlock - Return the LLVM basic block that this instance /// corresponded to originally. /// const BasicBlock *getBasicBlock() const { return BB; } - - typedef std::vector::iterator iterator; - typedef std::vector::const_iterator const_iterator; + + /// getParent - Return the MachineFunction containing this basic block. + /// + const MachineFunction *getParent() const; + + typedef ilist::iterator iterator; + typedef ilist::const_iterator const_iterator; typedef std::reverse_iterator const_reverse_iterator; typedef std::reverse_iterator reverse_iterator; unsigned size() const { return Insts.size(); } bool empty() const { return Insts.empty(); } - MachineInstr * operator[](unsigned i) const { return Insts[i]; } - MachineInstr *&operator[](unsigned i) { return Insts[i]; } - - MachineInstr *front() const { return Insts.front(); } - MachineInstr *back() const { return Insts.back(); } + MachineInstr& front() { return Insts.front(); } + MachineInstr& back() { return Insts.back(); } iterator begin() { return Insts.begin(); } const_iterator begin() const { return Insts.begin(); } @@ -58,22 +95,26 @@ reverse_iterator rend () { return Insts.rend(); } const_reverse_iterator rend () const { return Insts.rend(); } + /// getFirstTerminator - returns an iterator to the first terminator + /// instruction of this basic block. If a terminator does not exist, + /// it returns end() + iterator getFirstTerminator(); + void push_back(MachineInstr *MI) { Insts.push_back(MI); } template void insert(iterator I, IT S, IT E) { Insts.insert(I, S, E); } iterator insert(iterator I, MachineInstr *M) { return Insts.insert(I, M); } // erase - Remove the specified element or range from the instruction list. - // These functions do not delete any instructions removed. + // These functions delete any instructions removed. // iterator erase(iterator I) { return Insts.erase(I); } iterator erase(iterator I, iterator E) { return Insts.erase(I, E); } + MachineInstr* remove(iterator &I) { return Insts.remove(I); } - MachineInstr *pop_back() { - MachineInstr *R = back(); - Insts.pop_back(); - return R; - } + // Debugging methods. + void dump() const; + void print(std::ostream &OS) const; private: // Methods used to maintain doubly linked list of blocks... friend class ilist_traits; Index: llvm/include/llvm/CodeGen/MachineCodeForInstruction.h diff -u llvm/include/llvm/CodeGen/MachineCodeForInstruction.h:1.12 llvm/include/llvm/CodeGen/MachineCodeForInstruction.h:1.12.4.1 --- llvm/include/llvm/CodeGen/MachineCodeForInstruction.h:1.12 Tue Nov 11 16:41:31 2003 +++ llvm/include/llvm/CodeGen/MachineCodeForInstruction.h Mon Mar 1 17:57:19 2004 @@ -45,14 +45,8 @@ MachineCodeForInstruction() : Annotation(MCFI_AID), callArgsDesc(NULL) {} ~MachineCodeForInstruction(); - static MachineCodeForInstruction &get(const Instruction *I) { - assert(I != NULL); - return *(MachineCodeForInstruction*) - ((Annotable*)I)->getOrCreateAnnotation(MCFI_AID); - } - static void destroy(const Instruction *I) { - ((Annotable*)I)->deleteAnnotation(MCFI_AID); - } + static MachineCodeForInstruction &get(const Instruction *I); + static void destroy(const Instruction *I); // Access to underlying machine instructions... typedef std::vector::iterator iterator; Index: llvm/include/llvm/CodeGen/MachineFrameInfo.h diff -u llvm/include/llvm/CodeGen/MachineFrameInfo.h:1.9 llvm/include/llvm/CodeGen/MachineFrameInfo.h:1.9.4.1 --- llvm/include/llvm/CodeGen/MachineFrameInfo.h:1.9 Tue Nov 11 16:41:31 2003 +++ llvm/include/llvm/CodeGen/MachineFrameInfo.h Mon Mar 1 17:57:19 2004 @@ -38,18 +38,13 @@ #ifndef LLVM_CODEGEN_MACHINEFRAMEINFO_H #define LLVM_CODEGEN_MACHINEFRAMEINFO_H -namespace llvm { +#include +namespace llvm { class TargetData; class TargetRegisterClass; class Type; class MachineFunction; - -} - -#include - -namespace llvm { class MachineFrameInfo { Index: llvm/include/llvm/CodeGen/MachineFunction.h diff -u llvm/include/llvm/CodeGen/MachineFunction.h:1.31 llvm/include/llvm/CodeGen/MachineFunction.h:1.31.2.1 --- llvm/include/llvm/CodeGen/MachineFunction.h:1.31 Sat Dec 20 04:18:58 2003 +++ llvm/include/llvm/CodeGen/MachineFunction.h Mon Mar 1 17:57:19 2004 @@ -20,7 +20,6 @@ #include "llvm/CodeGen/MachineBasicBlock.h" #include "Support/Annotation.h" -#include "Support/ilist" namespace llvm { Index: llvm/include/llvm/CodeGen/MachineInstr.h diff -u llvm/include/llvm/CodeGen/MachineInstr.h:1.118 llvm/include/llvm/CodeGen/MachineInstr.h:1.118.2.1 --- llvm/include/llvm/CodeGen/MachineInstr.h:1.118 Sun Dec 14 07:30:19 2003 +++ llvm/include/llvm/CodeGen/MachineInstr.h Mon Mar 1 17:57:19 2004 @@ -16,9 +16,9 @@ #ifndef LLVM_CODEGEN_MACHINEINSTR_H #define LLVM_CODEGEN_MACHINEINSTR_H -#include "llvm/Target/MRegisterInfo.h" -#include "Support/Annotation.h" #include "Support/iterator" +#include +#include namespace llvm { @@ -28,33 +28,10 @@ class TargetMachine; class GlobalValue; -typedef int MachineOpCode; +template class ilist_traits; +template class ilist; -//===----------------------------------------------------------------------===// -/// Special flags on instructions that modify the opcode. -/// These flags are unused for now, but having them enforces that some -/// changes will be needed if they are used. -/// -enum MachineOpCodeFlags { - AnnulFlag, /// 1 if annul bit is set on a branch - PredTakenFlag, /// 1 if branch should be predicted taken - PredNotTakenFlag /// 1 if branch should be predicted not taken -}; - -//===----------------------------------------------------------------------===// -/// MOTy - MachineOperandType - This namespace contains an enum that describes -/// how the machine operand is used by the instruction: is it read, defined, or -/// both? Note that the MachineInstr/Operator class currently uses bool -/// arguments to represent this information instead of an enum. Eventually this -/// should change over to use this _easier to read_ representation instead. -/// -namespace MOTy { - enum UseType { - Use, /// This machine operand is only read by the instruction - Def, /// This machine operand is only written by the instruction - UseAndDef /// This machine operand is read AND written - }; -} +typedef short MachineOpCode; //===----------------------------------------------------------------------===// // class MachineOperand @@ -92,6 +69,31 @@ //===----------------------------------------------------------------------===// struct MachineOperand { +private: + // Bit fields of the flags variable used for different operand properties + enum { + DEFFLAG = 0x01, // this is a def of the operand + USEFLAG = 0x02, // this is a use of the operand + HIFLAG32 = 0x04, // operand is %hi32(value_or_immedVal) + LOFLAG32 = 0x08, // operand is %lo32(value_or_immedVal) + HIFLAG64 = 0x10, // operand is %hi64(value_or_immedVal) + LOFLAG64 = 0x20, // operand is %lo64(value_or_immedVal) + PCRELATIVE = 0x40, // Operand is relative to PC, not a global address + }; + +public: + // UseType - This enum describes how the machine operand is used by + // the instruction. Note that the MachineInstr/Operator class + // currently uses bool arguments to represent this information + // instead of an enum. Eventually this should change over to use + // this _easier to read_ representation instead. + // + enum UseType { + Use = USEFLAG, /// only read + Def = DEFFLAG, /// only written + UseAndDef = Use | Def /// read AND written + }; + enum MachineOperandType { MO_VirtualRegister, // virtual register for *value MO_MachineRegister, // pre-assigned machine register `regNum' @@ -107,18 +109,6 @@ }; private: - // Bit fields of the flags variable used for different operand properties - enum { - DEFFLAG = 0x01, // this is a def of the operand - USEFLAG = 0x02, // this is a use of the operand - HIFLAG32 = 0x04, // operand is %hi32(value_or_immedVal) - LOFLAG32 = 0x08, // operand is %lo32(value_or_immedVal) - HIFLAG64 = 0x10, // operand is %hi64(value_or_immedVal) - LOFLAG64 = 0x20, // operand is %lo64(value_or_immedVal) - PCRELATIVE = 0x40, // Operand is relative to PC, not a global address - }; - -private: union { Value* value; // BasicBlockVal for a label operand. // ConstantVal for a non-address immediate. @@ -127,7 +117,7 @@ // the generated machine code. // LLVM global for MO_GlobalAddress. - int64_t immedVal; // Constant value for an explicit constant + int immedVal; // Constant value for an explicit constant MachineBasicBlock *MBB; // For MO_MachineBasicBlock type std::string *SymbolName; // For MO_ExternalSymbol type @@ -138,44 +128,25 @@ int regNum; // register number for an explicit register // will be set for a value after reg allocation private: - MachineOperand() - : immedVal(0), - flags(0), - opType(MO_VirtualRegister), - regNum(-1) {} - - MachineOperand(int64_t ImmVal, MachineOperandType OpTy) + MachineOperand(int ImmVal = 0, MachineOperandType OpTy = MO_VirtualRegister) : immedVal(ImmVal), flags(0), opType(OpTy), regNum(-1) {} - MachineOperand(int Reg, MachineOperandType OpTy, MOTy::UseType UseTy) - : immedVal(0), - opType(OpTy), - regNum(Reg) { - switch (UseTy) { - case MOTy::Use: flags = USEFLAG; break; - case MOTy::Def: flags = DEFFLAG; break; - case MOTy::UseAndDef: flags = DEFFLAG | USEFLAG; break; - default: assert(0 && "Invalid value for UseTy!"); - } - } + MachineOperand(int Reg, MachineOperandType OpTy, UseType UseTy) + : immedVal(0), flags(UseTy), opType(OpTy), regNum(Reg) { } - MachineOperand(Value *V, MachineOperandType OpTy, MOTy::UseType UseTy, + MachineOperand(Value *V, MachineOperandType OpTy, UseType UseTy, bool isPCRelative = false) - : value(V), opType(OpTy), regNum(-1) { - switch (UseTy) { - case MOTy::Use: flags = USEFLAG; break; - case MOTy::Def: flags = DEFFLAG; break; - case MOTy::UseAndDef: flags = DEFFLAG | USEFLAG; break; - default: assert(0 && "Invalid value for UseTy!"); - } - if (isPCRelative) flags |= PCRELATIVE; + : value(V), + flags(UseTy | (isPCRelative ? PCRELATIVE : 0)), + opType(OpTy), + regNum(-1) { } MachineOperand(MachineBasicBlock *mbb) - : MBB(mbb), flags(0), opType(MO_MachineBasicBlock), regNum(-1) {} + : MBB(mbb), flags(0), opType(MO_MachineBasicBlock), regNum(-1) { } MachineOperand(const std::string &SymName, bool isPCRelative) : SymbolName(new std::string(SymName)), flags(isPCRelative ? PCRELATIVE :0), @@ -207,11 +178,16 @@ return *this; } - // Accessor methods. Caller is responsible for checking the - // operand type before invoking the corresponding accessor. - // + /// getType - Returns the MachineOperandType for this operand. + /// MachineOperandType getType() const { return opType; } + /// getUseType - Returns the MachineOperandUseType of this operand. + /// + UseType getUseType() const { + return UseType(flags & (USEFLAG|DEFFLAG)); + } + /// isPCRelative - This returns the value of the PCRELATIVE flag, which /// indicates whether this operand should be emitted as a PC relative value /// instead of a global address. This is used for operands of the forms: @@ -219,22 +195,16 @@ /// bool isPCRelative() const { return (flags & PCRELATIVE) != 0; } - - // This is to finally stop caring whether we have a virtual or machine - // register -- an easier interface is to simply call both virtual and machine - // registers essentially the same, yet be able to distinguish when - // necessary. Thus the instruction selector can just add registers without - // abandon, and the register allocator won't be confused. - bool isVirtualRegister() const { - return (opType == MO_VirtualRegister || opType == MO_MachineRegister) - && regNum >= MRegisterInfo::FirstVirtualRegister; - } - bool isPhysicalRegister() const { - return (opType == MO_VirtualRegister || opType == MO_MachineRegister) - && (unsigned)regNum < MRegisterInfo::FirstVirtualRegister; + /// isRegister - Return true if this operand is a register operand. The X86 + /// backend currently can't decide whether to use MO_MR or MO_VR to represent + /// them, so we accept both. + /// + /// Note: The sparc backend should not use this method. + /// + bool isRegister() const { + return opType == MO_MachineRegister || opType == MO_VirtualRegister; } - bool isRegister() const { return isVirtualRegister() || isPhysicalRegister();} - bool isMachineRegister() const { return !isVirtualRegister(); } + bool isMachineBasicBlock() const { return opType == MO_MachineBasicBlock; } bool isPCRelativeDisp() const { return opType == MO_PCRelativeDisp; } bool isImmediate() const { @@ -258,8 +228,8 @@ assert(opType == MO_MachineRegister); return regNum; } - int64_t getImmedValue() const { assert(isImmediate()); return immedVal; } - void setImmedValue(int64_t ImmVal) { assert(isImmediate()); immedVal=ImmVal; } + int getImmedValue() const { assert(isImmediate()); return immedVal; } + void setImmedValue(int ImmVal) { assert(isImmediate()); immedVal = ImmVal; } MachineBasicBlock *getMachineBasicBlock() const { assert(isMachineBasicBlock() && "Can't get MBB in non-MBB operand!"); @@ -281,12 +251,14 @@ return *SymbolName; } - bool isUse () const { return flags & USEFLAG; } - bool isDef () const { return flags & DEFFLAG; } - bool isHiBits32 () const { return flags & HIFLAG32; } - bool isLoBits32 () const { return flags & LOFLAG32; } - bool isHiBits64 () const { return flags & HIFLAG64; } - bool isLoBits64 () const { return flags & LOFLAG64; } + bool isUse () const { return flags & USEFLAG; } + MachineOperand& setUse () { flags |= USEFLAG; return *this; } + bool isDef () const { return flags & DEFFLAG; } + MachineOperand& setDef () { flags |= DEFFLAG; return *this; } + bool isHiBits32 () const { return flags & HIFLAG32; } + bool isLoBits32 () const { return flags & LOFLAG32; } + bool isHiBits64 () const { return flags & HIFLAG64; } + bool isLoBits64 () const { return flags & LOFLAG64; } // used to check if a machine register has been allocated to this operand bool hasAllocatedReg() const { @@ -296,15 +268,12 @@ } // used to get the reg number if when one is allocated - int getAllocatedRegNum() const { + unsigned getReg() const { assert(hasAllocatedReg()); return regNum; } // ********** TODO: get rid of this duplicate code! *********** - unsigned getReg() const { - return getAllocatedRegNum(); - } void setReg(unsigned Reg) { assert(hasAllocatedReg() && "This operand cannot have a register number!"); regNum = Reg; @@ -352,45 +321,49 @@ //===----------------------------------------------------------------------===// class MachineInstr { - int opCode; // the opcode - unsigned opCodeFlags; // flags modifying instrn behavior + short Opcode; // the opcode + unsigned char numImplicitRefs; // number of implicit operands std::vector operands; // the operands - unsigned numImplicitRefs; // number of implicit operands - + MachineInstr* prev, *next; // links for our intrusive list + MachineBasicBlock* parent; // pointer to the owning basic block // OperandComplete - Return true if it's illegal to add a new operand bool OperandsComplete() const; MachineInstr(const MachineInstr &); // DO NOT IMPLEMENT void operator=(const MachineInstr&); // DO NOT IMPLEMENT + +private: + // Intrusive list support + // + friend class ilist_traits; + public: - MachineInstr(int Opcode, unsigned numOperands); + MachineInstr(short Opcode, unsigned numOperands); /// MachineInstr ctor - This constructor only does a _reserve_ of the /// operands, not a resize for them. It is expected that if you use this that /// you call add* methods below to fill up the operands, instead of the Set /// methods. Eventually, the "resizing" ctors will be phased out. /// - MachineInstr(int Opcode, unsigned numOperands, bool XX, bool YY); + MachineInstr(short Opcode, unsigned numOperands, bool XX, bool YY); /// MachineInstr ctor - Work exactly the same as the ctor above, except that /// the MachineInstr is created and added to the end of the specified basic /// block. /// - MachineInstr(MachineBasicBlock *MBB, int Opcode, unsigned numOps); + MachineInstr(MachineBasicBlock *MBB, short Opcode, unsigned numOps); + ~MachineInstr(); - // The opcode. - // - const int getOpcode() const { return opCode; } - const int getOpCode() const { return opCode; } + const MachineBasicBlock* getParent() const { return parent; } + MachineBasicBlock* getParent() { return parent; } - // Opcode flags. - // - unsigned getOpCodeFlags() const { return opCodeFlags; } + /// Accessors for opcode. + /// + const int getOpcode() const { return Opcode; } - // - // Access to explicit operands of the instruction - // + /// Access to explicit operands of the instruction. + /// unsigned getNumOperands() const { return operands.size() - numImplicitRefs; } const MachineOperand& getOperand(unsigned i) const { @@ -472,19 +445,24 @@ void addRegOperand(Value *V, bool isDef, bool isDefAndUse=false) { assert(!OperandsComplete() && "Trying to add an operand to a machine instr that is already done!"); - operands.push_back(MachineOperand(V, MachineOperand::MO_VirtualRegister, - !isDef ? MOTy::Use : (isDefAndUse ? MOTy::UseAndDef : MOTy::Def))); + operands.push_back( + MachineOperand(V, MachineOperand::MO_VirtualRegister, + !isDef ? MachineOperand::Use : + (isDefAndUse ? MachineOperand::UseAndDef : + MachineOperand::Def))); } - void addRegOperand(Value *V, MOTy::UseType UTy = MOTy::Use, - bool isPCRelative = false) { + void addRegOperand(Value *V, + MachineOperand::UseType UTy = MachineOperand::Use, + bool isPCRelative = false) { assert(!OperandsComplete() && "Trying to add an operand to a machine instr that is already done!"); operands.push_back(MachineOperand(V, MachineOperand::MO_VirtualRegister, UTy, isPCRelative)); } - void addCCRegOperand(Value *V, MOTy::UseType UTy = MOTy::Use) { + void addCCRegOperand(Value *V, + MachineOperand::UseType UTy = MachineOperand::Use) { assert(!OperandsComplete() && "Trying to add an operand to a machine instr that is already done!"); operands.push_back(MachineOperand(V, MachineOperand::MO_CCRegister, UTy, @@ -497,17 +475,19 @@ void addRegOperand(int reg, bool isDef) { assert(!OperandsComplete() && "Trying to add an operand to a machine instr that is already done!"); - operands.push_back(MachineOperand(reg, MachineOperand::MO_VirtualRegister, - isDef ? MOTy::Def : MOTy::Use)); + operands.push_back( + MachineOperand(reg, MachineOperand::MO_VirtualRegister, + isDef ? MachineOperand::Def : MachineOperand::Use)); } /// addRegOperand - Add a symbolic virtual register reference... /// - void addRegOperand(int reg, MOTy::UseType UTy = MOTy::Use) { + void addRegOperand(int reg, + MachineOperand::UseType UTy = MachineOperand::Use) { assert(!OperandsComplete() && "Trying to add an operand to a machine instr that is already done!"); - operands.push_back(MachineOperand(reg, MachineOperand::MO_VirtualRegister, - UTy)); + operands.push_back( + MachineOperand(reg, MachineOperand::MO_VirtualRegister, UTy)); } /// addPCDispOperand - Add a PC relative displacement operand to the MI @@ -515,8 +495,8 @@ void addPCDispOperand(Value *V) { assert(!OperandsComplete() && "Trying to add an operand to a machine instr that is already done!"); - operands.push_back(MachineOperand(V, MachineOperand::MO_PCRelativeDisp, - MOTy::Use)); + operands.push_back( + MachineOperand(V, MachineOperand::MO_PCRelativeDisp,MachineOperand::Use)); } /// addMachineRegOperand - Add a virtual register operand to this MachineInstr @@ -524,37 +504,39 @@ void addMachineRegOperand(int reg, bool isDef) { assert(!OperandsComplete() && "Trying to add an operand to a machine instr that is already done!"); - operands.push_back(MachineOperand(reg, MachineOperand::MO_MachineRegister, - isDef ? MOTy::Def : MOTy::Use)); + operands.push_back( + MachineOperand(reg, MachineOperand::MO_MachineRegister, + isDef ? MachineOperand::Def : MachineOperand::Use)); } /// addMachineRegOperand - Add a virtual register operand to this MachineInstr /// - void addMachineRegOperand(int reg, MOTy::UseType UTy = MOTy::Use) { + void addMachineRegOperand(int reg, + MachineOperand::UseType UTy = MachineOperand::Use) { assert(!OperandsComplete() && "Trying to add an operand to a machine instr that is already done!"); - operands.push_back(MachineOperand(reg, MachineOperand::MO_MachineRegister, - UTy)); + operands.push_back( + MachineOperand(reg, MachineOperand::MO_MachineRegister, UTy)); } /// addZeroExtImmOperand - Add a zero extended constant argument to the /// machine instruction. /// - void addZeroExtImmOperand(int64_t intValue) { + void addZeroExtImmOperand(int intValue) { assert(!OperandsComplete() && "Trying to add an operand to a machine instr that is already done!"); - operands.push_back(MachineOperand(intValue, - MachineOperand::MO_UnextendedImmed)); + operands.push_back( + MachineOperand(intValue, MachineOperand::MO_UnextendedImmed)); } /// addSignExtImmOperand - Add a zero extended constant argument to the /// machine instruction. /// - void addSignExtImmOperand(int64_t intValue) { + void addSignExtImmOperand(int intValue) { assert(!OperandsComplete() && "Trying to add an operand to a machine instr that is already done!"); - operands.push_back(MachineOperand(intValue, - MachineOperand::MO_SignExtendedImmed)); + operands.push_back( + MachineOperand(intValue, MachineOperand::MO_SignExtendedImmed)); } void addMachineBasicBlockOperand(MachineBasicBlock *MBB) { @@ -583,9 +565,9 @@ void addGlobalAddressOperand(GlobalValue *GV, bool isPCRelative) { assert(!OperandsComplete() && "Trying to add an operand to a machine instr that is already done!"); - operands.push_back(MachineOperand((Value*)GV, - MachineOperand::MO_GlobalAddress, - MOTy::Use, isPCRelative)); + operands.push_back( + MachineOperand((Value*)GV, MachineOperand::MO_GlobalAddress, + MachineOperand::Use, isPCRelative)); } /// addExternalSymbolOperand - Add an external symbol operand to this instr @@ -603,11 +585,11 @@ /// simply replace() and then set new operands with Set.*Operand methods /// below. /// - void replace(int Opcode, unsigned numOperands); + void replace(short Opcode, unsigned numOperands); /// setOpcode - Replace the opcode of the current instruction with a new one. /// - void setOpcode(unsigned Op) { opCode = Op; } + void setOpcode(unsigned Op) { Opcode = Op; } /// RemoveOperand - Erase an operand from an instruction, leaving it with one /// fewer operand than it started with. @@ -618,13 +600,13 @@ // Access to set the operands when building the machine instruction // - void SetMachineOperandVal (unsigned i, - MachineOperand::MachineOperandType operandType, - Value* V); - - void SetMachineOperandConst (unsigned i, - MachineOperand::MachineOperandType operandType, - int64_t intValue); + void SetMachineOperandVal(unsigned i, + MachineOperand::MachineOperandType operandType, + Value* V); + + void SetMachineOperandConst(unsigned i, + MachineOperand::MachineOperandType operandType, + int intValue); void SetMachineOperandReg(unsigned i, int regNum); @@ -710,7 +692,6 @@ return const_val_op_iterator::end(this); } }; - //===----------------------------------------------------------------------===// // Debugging Support Index: llvm/include/llvm/CodeGen/MachineInstrBuilder.h diff -u llvm/include/llvm/CodeGen/MachineInstrBuilder.h:1.16 llvm/include/llvm/CodeGen/MachineInstrBuilder.h:1.16.4.1 --- llvm/include/llvm/CodeGen/MachineInstrBuilder.h:1.16 Tue Nov 11 16:41:31 2003 +++ llvm/include/llvm/CodeGen/MachineInstrBuilder.h Mon Mar 1 17:57:19 2004 @@ -23,7 +23,7 @@ #ifndef LLVM_CODEGEN_MACHINEINSTRBUILDER_H #define LLVM_CODEGEN_MACHINEINSTRBUILDER_H -#include "llvm/CodeGen/MachineInstr.h" +#include "llvm/CodeGen/MachineBasicBlock.h" namespace llvm { @@ -38,33 +38,36 @@ /// addReg - Add a new virtual register operand... /// - const MachineInstrBuilder &addReg(int RegNo, - MOTy::UseType Ty = MOTy::Use) const { + const MachineInstrBuilder &addReg( + int RegNo, + MachineOperand::UseType Ty = MachineOperand::Use) const { MI->addRegOperand(RegNo, Ty); return *this; } /// addReg - Add an LLVM value that is to be used as a register... /// - const MachineInstrBuilder &addReg(Value *V, - MOTy::UseType Ty = MOTy::Use) const { + const MachineInstrBuilder &addReg( + Value *V, + MachineOperand::UseType Ty = MachineOperand::Use) const { MI->addRegOperand(V, Ty); return *this; } /// addReg - Add an LLVM value that is to be used as a register... /// - const MachineInstrBuilder &addCCReg(Value *V, - MOTy::UseType Ty = MOTy::Use) const { + const MachineInstrBuilder &addCCReg( + Value *V, + MachineOperand::UseType Ty = MachineOperand::Use) const { MI->addCCRegOperand(V, Ty); return *this; } /// addRegDef - Add an LLVM value that is to be defined as a register... this - /// is the same as addReg(V, MOTy::Def). + /// is the same as addReg(V, MachineOperand::Def). /// const MachineInstrBuilder &addRegDef(Value *V) const { - return addReg(V, MOTy::Def); + return addReg(V, MachineOperand::Def); } /// addPCDisp - Add an LLVM value to be treated as a PC relative @@ -77,22 +80,29 @@ /// addMReg - Add a machine register operand... /// - const MachineInstrBuilder &addMReg(int Reg, - MOTy::UseType Ty = MOTy::Use) const { + const MachineInstrBuilder &addMReg(int Reg, MachineOperand::UseType Ty + = MachineOperand::Use) const { MI->addMachineRegOperand(Reg, Ty); return *this; } + + /// addImm - Add a new immediate operand. + /// + const MachineInstrBuilder &addImm(int Val) const { + MI->addZeroExtImmOperand(Val); + return *this; + } /// addSImm - Add a new sign extended immediate operand... /// - const MachineInstrBuilder &addSImm(int64_t val) const { + const MachineInstrBuilder &addSImm(int val) const { MI->addSignExtImmOperand(val); return *this; } /// addZImm - Add a new zero extended immediate operand... /// - const MachineInstrBuilder &addZImm(int64_t Val) const { + const MachineInstrBuilder &addZImm(unsigned Val) const { MI->addZeroExtImmOperand(Val); return *this; } @@ -137,19 +147,42 @@ /// destination virtual register. NumOperands is the number of additional add* /// calls that are expected, it does not include the destination register. /// -inline MachineInstrBuilder BuildMI(int Opcode, unsigned NumOperands, - unsigned DestReg) { +inline MachineInstrBuilder BuildMI( + int Opcode, unsigned NumOperands, + unsigned DestReg, + MachineOperand::UseType useType = MachineOperand::Def) { return MachineInstrBuilder(new MachineInstr(Opcode, NumOperands+1, - true, true)).addReg(DestReg, MOTy::Def); + true, true)).addReg(DestReg, useType); } +/// BuildMI - Insert the instruction before a specified location in the basic +/// block. +inline MachineInstrBuilder BuildMI(MachineBasicBlock &BB, + MachineBasicBlock::iterator I, + int Opcode, unsigned NumOperands, + unsigned DestReg) { + MachineInstr *MI = new MachineInstr(Opcode, NumOperands+1, true, true); + BB.insert(I, MI); + return MachineInstrBuilder(MI).addReg(DestReg, MachineOperand::Def); +} + +/// BMI - A special BuildMI variant that takes an iterator to insert the +/// instruction at as well as a basic block. +inline MachineInstrBuilder BuildMI(MachineBasicBlock &BB, + MachineBasicBlock::iterator I, + int Opcode, unsigned NumOperands) { + MachineInstr *MI = new MachineInstr(Opcode, NumOperands, true, true); + BB.insert(I, MI); + return MachineInstrBuilder(MI); +} + /// BuildMI - This version of the builder inserts the built MachineInstr into /// the specified MachineBasicBlock. /// inline MachineInstrBuilder BuildMI(MachineBasicBlock *BB, int Opcode, unsigned NumOperands) { - return MachineInstrBuilder(new MachineInstr(BB, Opcode, NumOperands)); + return BuildMI(*BB, BB->end(), Opcode, NumOperands); } /// BuildMI - This version of the builder inserts the built MachineInstr into @@ -159,9 +192,7 @@ /// inline MachineInstrBuilder BuildMI(MachineBasicBlock *BB, int Opcode, unsigned NumOperands, unsigned DestReg) { - return MachineInstrBuilder(new MachineInstr(BB, Opcode, - NumOperands+1)).addReg(DestReg, - MOTy::Def); + return BuildMI(*BB, BB->end(), Opcode, NumOperands, DestReg); } } // End llvm namespace Index: llvm/include/llvm/CodeGen/Passes.h diff -u llvm/include/llvm/CodeGen/Passes.h:1.12 llvm/include/llvm/CodeGen/Passes.h:1.12.2.1 --- llvm/include/llvm/CodeGen/Passes.h:1.12 Sat Dec 20 04:18:58 2003 +++ llvm/include/llvm/CodeGen/Passes.h Mon Mar 1 17:57:19 2004 @@ -15,6 +15,9 @@ #ifndef LLVM_CODEGEN_PASSES_H #define LLVM_CODEGEN_PASSES_H +#include +#include + namespace llvm { class FunctionPass; @@ -23,8 +26,9 @@ /// MachineFunctionPrinter pass - This pass prints out the machine function to /// standard error, as a debugging tool. - FunctionPass *createMachineFunctionPrinterPass(); - + FunctionPass *createMachineFunctionPrinterPass(std::ostream *OS, + const std::string &Banner =""); + /// PHIElimination pass - This pass eliminates machine instruction PHI nodes /// by inserting copy instructions. This destroys SSA information, but is the /// desired input for some register allocators. This pass is "required" by Index: llvm/include/llvm/CodeGen/SSARegMap.h diff -u llvm/include/llvm/CodeGen/SSARegMap.h:1.8 llvm/include/llvm/CodeGen/SSARegMap.h:1.8.4.1 --- llvm/include/llvm/CodeGen/SSARegMap.h:1.8 Tue Nov 11 16:41:31 2003 +++ llvm/include/llvm/CodeGen/SSARegMap.h Mon Mar 1 17:57:19 2004 @@ -1,48 +1,51 @@ //===-- llvm/CodeGen/SSARegMap.h --------------------------------*- C++ -*-===// -// +// // The LLVM Compiler Infrastructure // // This file was developed by the LLVM research group and is distributed under // the University of Illinois Open Source License. See LICENSE.TXT for details. -// +// //===----------------------------------------------------------------------===// -// +// // Map register numbers to register classes that are correctly sized (typed) to // hold the information. Assists register allocation. Contained by // MachineFunction, should be deleted by register allocator when it is no // longer needed. -// +// //===----------------------------------------------------------------------===// #ifndef LLVM_CODEGEN_SSAREGMAP_H #define LLVM_CODEGEN_SSAREGMAP_H #include "llvm/Target/MRegisterInfo.h" +#include "Support/DenseMap.h" namespace llvm { class TargetRegisterClass; class SSARegMap { - std::vector RegClassMap; - - unsigned rescale(unsigned Reg) { - return Reg - MRegisterInfo::FirstVirtualRegister; - } + DenseMap RegClassMap; + unsigned NextRegNum; public: + SSARegMap() : NextRegNum(MRegisterInfo::FirstVirtualRegister) { } + const TargetRegisterClass* getRegClass(unsigned Reg) { - unsigned actualReg = rescale(Reg); - assert(actualReg < RegClassMap.size() && "Register out of bounds"); - return RegClassMap[actualReg]; + return RegClassMap[Reg]; } /// createVirtualRegister - Create and return a new virtual register in the /// function with the specified register class. /// unsigned createVirtualRegister(const TargetRegisterClass *RegClass) { - RegClassMap.push_back(RegClass); - return RegClassMap.size()+MRegisterInfo::FirstVirtualRegister-1; + RegClassMap.grow(NextRegNum); + RegClassMap[NextRegNum] = RegClass; + return NextRegNum++; + } + + unsigned getLastVirtReg() const { + return NextRegNum - 1; } }; Index: llvm/include/llvm/CodeGen/SchedGraphCommon.h diff -u llvm/include/llvm/CodeGen/SchedGraphCommon.h:1.9 llvm/include/llvm/CodeGen/SchedGraphCommon.h:1.9.2.1 --- llvm/include/llvm/CodeGen/SchedGraphCommon.h:1.9 Tue Jan 20 11:49:42 2004 +++ llvm/include/llvm/CodeGen/SchedGraphCommon.h Mon Mar 1 17:57:19 2004 @@ -72,7 +72,6 @@ virtual void print(std::ostream &os) const = 0; protected: - friend class SchedGraph; friend class SchedGraphCommon; friend class SchedGraphEdge; // give access for adding edges From brukman at cs.uiuc.edu Mon Mar 1 17:59:48 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Mar 1 17:59:48 2004 Subject: [llvm-commits] [parallel] CVS: llvm/include/llvm/ExecutionEngine/GenericValue.h Message-ID: <200403012357.RAA03368@zion.cs.uiuc.edu> Changes in directory llvm/include/llvm/ExecutionEngine: GenericValue.h updated: 1.4 -> 1.4.4.1 --- Log message: Merge from trunk --- Diffs of the changes: (+1 -0) Index: llvm/include/llvm/ExecutionEngine/GenericValue.h diff -u llvm/include/llvm/ExecutionEngine/GenericValue.h:1.4 llvm/include/llvm/ExecutionEngine/GenericValue.h:1.4.4.1 --- llvm/include/llvm/ExecutionEngine/GenericValue.h:1.4 Thu Dec 11 23:06:09 2003 +++ llvm/include/llvm/ExecutionEngine/GenericValue.h Mon Mar 1 17:57:19 2004 @@ -33,6 +33,7 @@ int64_t LongVal; double DoubleVal; float FloatVal; + struct { unsigned int first; unsigned int second; } UIntPairVal; PointerTy PointerVal; unsigned char Untyped[8]; From brukman at cs.uiuc.edu Mon Mar 1 17:59:54 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Mar 1 17:59:54 2004 Subject: [llvm-commits] [parallel] CVS: llvm/include/llvm/Transforms/IPO.h Scalar.h Message-ID: <200403012357.RAA03414@zion.cs.uiuc.edu> Changes in directory llvm/include/llvm/Transforms: IPO.h updated: 1.26 -> 1.26.2.1 Scalar.h updated: 1.31 -> 1.31.4.1 --- Log message: Merge from trunk --- Diffs of the changes: (+17 -3) Index: llvm/include/llvm/Transforms/IPO.h diff -u llvm/include/llvm/Transforms/IPO.h:1.26 llvm/include/llvm/Transforms/IPO.h:1.26.2.1 --- llvm/include/llvm/Transforms/IPO.h:1.26 Tue Dec 16 15:55:45 2003 +++ llvm/include/llvm/Transforms/IPO.h Mon Mar 1 17:57:19 2004 @@ -38,6 +38,13 @@ //===----------------------------------------------------------------------===// +// createGlobalConstifierPass - This function returns a new pass that marks +// internal globals "constant" if they are provably never written to. +// +Pass *createGlobalConstifierPass(); + + +//===----------------------------------------------------------------------===// // createRaiseAllocationsPass - Return a new pass that transforms malloc and // free function calls into malloc and free instructions. // Index: llvm/include/llvm/Transforms/Scalar.h diff -u llvm/include/llvm/Transforms/Scalar.h:1.31 llvm/include/llvm/Transforms/Scalar.h:1.31.4.1 --- llvm/include/llvm/Transforms/Scalar.h:1.31 Tue Nov 11 16:41:31 2003 +++ llvm/include/llvm/Transforms/Scalar.h Mon Mar 1 17:57:19 2004 @@ -117,7 +117,7 @@ //===----------------------------------------------------------------------===// // // InstructionCombining - Combine instructions to form fewer, simple -// instructions. This pass does not modify the CFG, and has a tendancy to +// instructions. This pass does not modify the CFG, and has a tendency to // make instructions dead, so a subsequent DCE pass is useful. // // This pass combines things like: @@ -139,6 +139,14 @@ //===----------------------------------------------------------------------===// // +// LoopExtractor - This pass moves every natural loop into its own function. +// Mostly useful in debugging via bugpoint. +// +FunctionPass *createLoopExtractorPass(); + + +//===----------------------------------------------------------------------===// +// // PiNodeInsertion - This pass inserts single entry Phi nodes into basic blocks // that are preceeded by a conditional branch, where the branch gives // information about the operands of the condition. For example, this C code: @@ -260,8 +268,7 @@ // into calls to abort(). // FunctionPass *createLowerInvokePass(); - - +extern const PassInfo *LowerInvokePassID; //===----------------------------------------------------------------------===// // From brukman at cs.uiuc.edu Mon Mar 1 18:00:00 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Mar 1 18:00:00 2004 Subject: [llvm-commits] [parallel] CVS: llvm/include/llvm/Target/MRegisterInfo.h TargetData.h TargetFrameInfo.h TargetInstrInfo.h TargetMachine.h TargetMachineImpls.h TargetRegInfo.h TargetSchedInfo.h TargetCacheInfo.h Message-ID: <200403012357.RAA03436@zion.cs.uiuc.edu> Changes in directory llvm/include/llvm/Target: MRegisterInfo.h updated: 1.26 -> 1.26.4.1 TargetData.h updated: 1.22 -> 1.22.2.1 TargetFrameInfo.h updated: 1.9 -> 1.9.4.1 TargetInstrInfo.h updated: 1.53 -> 1.53.2.1 TargetMachine.h updated: 1.42 -> 1.42.2.1 TargetMachineImpls.h updated: 1.8 -> 1.8.2.1 TargetRegInfo.h updated: 1.47 -> 1.47.4.1 TargetSchedInfo.h updated: 1.21 -> 1.21.4.1 TargetCacheInfo.h (r1.12) removed --- Log message: Merge from trunk --- Diffs of the changes: (+149 -147) Index: llvm/include/llvm/Target/MRegisterInfo.h diff -u llvm/include/llvm/Target/MRegisterInfo.h:1.26 llvm/include/llvm/Target/MRegisterInfo.h:1.26.4.1 --- llvm/include/llvm/Target/MRegisterInfo.h:1.26 Tue Nov 11 16:41:31 2003 +++ llvm/include/llvm/Target/MRegisterInfo.h Mon Mar 1 17:57:19 2004 @@ -18,11 +18,13 @@ #include "llvm/CodeGen/MachineBasicBlock.h" #include +#include namespace llvm { class Type; class MachineFunction; +class MachineInstr; /// MRegisterDesc - This record contains all of the information known about a /// particular register. The AliasSet field (if not null) contains a pointer to @@ -136,6 +138,20 @@ FirstVirtualRegister = 1024, }; + /// isPhysicalRegister - Return true if the specified register number is in + /// the physical register namespace. + static bool isPhysicalRegister(unsigned Reg) { + assert(Reg && "this is not a register!"); + return Reg < FirstVirtualRegister; + } + + /// isVirtualRegister - Return true if the specified register number is in + /// the virtual register namespace. + static bool isVirtualRegister(unsigned Reg) { + assert(Reg && "this is not a register!"); + return Reg >= FirstVirtualRegister; + } + const MRegisterDesc &operator[](unsigned RegNo) const { assert(RegNo < NumRegs && "Attempting to access record for invalid register number!"); @@ -170,6 +186,20 @@ return get(RegNo).Name; } + /// getNumRegs - Return the number of registers this target has + /// (useful for sizing arrays holding per register information) + unsigned getNumRegs() const { + return NumRegs; + } + + /// areAliases - Returns true if the two registers alias each other, + /// false otherwise + bool areAliases(unsigned regA, unsigned regB) const { + for (const unsigned *Alias = getAliasSet(regA); *Alias; ++Alias) + if (*Alias == regA) return true; + return false; + } + virtual const unsigned* getCalleeSaveRegs() const = 0; @@ -208,21 +238,32 @@ // virtual int storeRegToStackSlot(MachineBasicBlock &MBB, - MachineBasicBlock::iterator &MBBI, + MachineBasicBlock::iterator MI, unsigned SrcReg, int FrameIndex, const TargetRegisterClass *RC) const = 0; virtual int loadRegFromStackSlot(MachineBasicBlock &MBB, - MachineBasicBlock::iterator &MBBI, + MachineBasicBlock::iterator MI, unsigned DestReg, int FrameIndex, const TargetRegisterClass *RC) const = 0; virtual int copyRegToReg(MachineBasicBlock &MBB, - MachineBasicBlock::iterator &MBBI, + MachineBasicBlock::iterator MI, unsigned DestReg, unsigned SrcReg, const TargetRegisterClass *RC) const = 0; + /// foldMemoryOperand - If this target supports it, fold a load or store of + /// the specified stack slot into the specified machine instruction for the + /// specified operand. If this is possible, the target should perform the + /// folding and return true, otherwise it should return false. If it folds + /// the instruction, it is likely that the MachineInstruction the iterator + /// references has been changed. + virtual bool foldMemoryOperand(MachineBasicBlock::iterator &MI, + unsigned OpNum, int FrameIndex) const { + return false; + } + /// getCallFrameSetup/DestroyOpcode - These methods return the opcode of the /// frame setup/destroy instructions if they exist (-1 otherwise). Some /// targets use pseudo instructions in order to abstract away the difference @@ -241,14 +282,14 @@ /// setup/destroy pseudo instructions. The return value is the number of /// instructions added to (negative if removed from) the basic block. /// - virtual int eliminateCallFramePseudoInstr(MachineFunction &MF, - MachineBasicBlock &MBB, - MachineBasicBlock::iterator &I) const { + virtual void + eliminateCallFramePseudoInstr(MachineFunction &MF, + MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI) const { assert(getCallFrameSetupOpcode()== -1 && getCallFrameDestroyOpcode()== -1 && "eliminateCallFramePseudoInstr must be implemented if using" " call frame setup/destroy pseudo instructions!"); assert(0 && "Call Frame Pseudo Instructions do not exist on this target!"); - return -1; } /// processFunctionBeforeFrameFinalized - This method is called immediately @@ -258,8 +299,7 @@ /// is the number of instructions added to (negative if removed from) the /// basic block /// - virtual int processFunctionBeforeFrameFinalized(MachineFunction &MF) const { - return 0; + virtual void processFunctionBeforeFrameFinalized(MachineFunction &MF) const { } /// eliminateFrameIndex - This method must be overriden to eliminate abstract @@ -270,16 +310,23 @@ /// finished product. The return value is the number of instructions /// added to (negative if removed from) the basic block. /// - virtual int eliminateFrameIndex(MachineFunction &MF, - MachineBasicBlock::iterator &II) const = 0; + virtual void eliminateFrameIndex(MachineFunction &MF, + MachineBasicBlock::iterator MI) const = 0; /// emitProlog/emitEpilog - These methods insert prolog and epilog code into /// the function. The return value is the number of instructions /// added to (negative if removed from) the basic block (entry for prologue). /// - virtual int emitPrologue(MachineFunction &MF) const = 0; - virtual int emitEpilogue(MachineFunction &MF, - MachineBasicBlock &MBB) const = 0; + virtual void emitPrologue(MachineFunction &MF) const = 0; + virtual void emitEpilogue(MachineFunction &MF, + MachineBasicBlock &MBB) const = 0; +}; + +// This is useful when building DenseMap's keyed on virtual registers +struct VirtReg2IndexFunctor : std::unary_function { + unsigned operator()(unsigned Reg) const { + return Reg - MRegisterInfo::FirstVirtualRegister; + } }; } // End llvm namespace Index: llvm/include/llvm/Target/TargetData.h diff -u llvm/include/llvm/Target/TargetData.h:1.22 llvm/include/llvm/Target/TargetData.h:1.22.2.1 --- llvm/include/llvm/Target/TargetData.h:1.22 Sun Dec 21 23:00:45 2003 +++ llvm/include/llvm/Target/TargetData.h Mon Mar 1 17:57:19 2004 @@ -21,9 +21,9 @@ #define LLVM_TARGET_TARGETDATA_H #include "llvm/Pass.h" -#include "Support/Annotation.h" #include "Support/DataTypes.h" #include +#include namespace llvm { @@ -42,9 +42,6 @@ unsigned char DoubleAlignment; // Defaults to 8 bytes unsigned char PointerSize; // Defaults to 8 bytes unsigned char PointerAlignment; // Defaults to 8 bytes - AnnotationID AID; // AID for structure layout annotation - - static Annotation *TypeAnFactory(AnnotationID, const Annotable *, void *); public: TargetData(const std::string &TargetName = "", bool LittleEndian = false, @@ -69,7 +66,6 @@ unsigned char getDoubleAlignment() const { return DoubleAlignment; } unsigned char getPointerAlignment() const { return PointerAlignment; } unsigned char getPointerSize() const { return PointerSize; } - AnnotationID getStructLayoutAID() const { return AID; } /// getTypeSize - Return the number of bytes necessary to hold the specified /// type @@ -89,23 +85,19 @@ uint64_t getIndexedOffset(const Type *Ty, const std::vector &Indices) const; - inline const StructLayout *getStructLayout(const StructType *Ty) const { - return (const StructLayout*) - ((const Annotable*)Ty)->getOrCreateAnnotation(AID); - } + const StructLayout *getStructLayout(const StructType *Ty) const; }; -// This annotation (attached ONLY to StructType classes) is used to lazily -// calculate structure layout information for a target machine, based on the -// TargetData structure. +// This object is used to lazily calculate structure layout information for a +// target machine, based on the TargetData structure. // -struct StructLayout : public Annotation { +struct StructLayout { std::vector MemberOffsets; uint64_t StructSize; unsigned StructAlignment; private: friend class TargetData; // Only TargetData can create this class - inline StructLayout(const StructType *ST, const TargetData &TD); + StructLayout(const StructType *ST, const TargetData &TD); }; } // End llvm namespace Index: llvm/include/llvm/Target/TargetFrameInfo.h diff -u llvm/include/llvm/Target/TargetFrameInfo.h:1.9 llvm/include/llvm/Target/TargetFrameInfo.h:1.9.4.1 --- llvm/include/llvm/Target/TargetFrameInfo.h:1.9 Tue Nov 11 16:41:31 2003 +++ llvm/include/llvm/Target/TargetFrameInfo.h Mon Mar 1 17:57:19 2004 @@ -14,6 +14,8 @@ #ifndef LLVM_TARGET_TARGETFRAMEINFO_H #define LLVM_TARGET_TARGETFRAMEINFO_H +#include + namespace llvm { class MachineFunction; Index: llvm/include/llvm/Target/TargetInstrInfo.h diff -u llvm/include/llvm/Target/TargetInstrInfo.h:1.53 llvm/include/llvm/Target/TargetInstrInfo.h:1.53.2.1 --- llvm/include/llvm/Target/TargetInstrInfo.h:1.53 Sun Dec 28 11:35:08 2003 +++ llvm/include/llvm/Target/TargetInstrInfo.h Mon Mar 1 17:57:19 2004 @@ -33,12 +33,9 @@ // Data types used to define information about a single machine instruction //--------------------------------------------------------------------------- -typedef int MachineOpCode; +typedef short MachineOpCode; typedef unsigned InstrSchedClass; -const MachineOpCode INVALID_MACHINE_OPCODE = -1; - - //--------------------------------------------------------------------------- // struct TargetInstrDescriptor: // Predefined information about each machine instruction. @@ -49,14 +46,8 @@ const unsigned M_BRANCH_FLAG = 1 << 1; const unsigned M_CALL_FLAG = 1 << 2; const unsigned M_RET_FLAG = 1 << 3; -const unsigned M_ARITH_FLAG = 1 << 4; const unsigned M_CC_FLAG = 1 << 6; -const unsigned M_LOGICAL_FLAG = 1 << 6; -const unsigned M_INT_FLAG = 1 << 7; -const unsigned M_FLOAT_FLAG = 1 << 8; -const unsigned M_CONDL_FLAG = 1 << 9; const unsigned M_LOAD_FLAG = 1 << 10; -const unsigned M_PREFETCH_FLAG = 1 << 11; const unsigned M_STORE_FLAG = 1 << 12; const unsigned M_DUMMY_PHI_FLAG = 1 << 13; const unsigned M_PSEUDO_FLAG = 1 << 14; // Pseudo instruction @@ -73,7 +64,7 @@ const char * Name; // Assembly language mnemonic for the opcode. int numOperands; // Number of args; -1 if variable #args int resultPos; // Position of the result; -1 if no result - unsigned maxImmedConst; // Largest +ve constant in IMMMED field or 0. + unsigned maxImmedConst; // Largest +ve constant in IMMED field or 0. bool immedIsSignExtended; // Is IMMED field sign-extended? If so, // smallest -ve value is -(maxImmedConst+1). unsigned numDelaySlots; // Number of delay slots after instruction @@ -92,27 +83,25 @@ /// class TargetInstrInfo { const TargetInstrDescriptor* desc; // raw array to allow static init'n - unsigned descSize; // number of entries in the desc array + unsigned NumOpcodes; // number of entries in the desc array unsigned numRealOpCodes; // number of non-dummy op codes TargetInstrInfo(const TargetInstrInfo &); // DO NOT IMPLEMENT void operator=(const TargetInstrInfo &); // DO NOT IMPLEMENT public: - TargetInstrInfo(const TargetInstrDescriptor *desc, unsigned descSize, - unsigned numRealOpCodes); + TargetInstrInfo(const TargetInstrDescriptor *desc, unsigned NumOpcodes); virtual ~TargetInstrInfo(); // Invariant: All instruction sets use opcode #0 as the PHI instruction enum { PHI = 0 }; - unsigned getNumRealOpCodes() const { return numRealOpCodes; } - unsigned getNumTotalOpCodes() const { return descSize; } + unsigned getNumOpcodes() const { return NumOpcodes; } /// get - Return the machine instruction descriptor that corresponds to the /// specified instruction opcode. /// const TargetInstrDescriptor& get(MachineOpCode opCode) const { - assert(opCode >= 0 && opCode < (int)descSize); + assert((unsigned)opCode < NumOpcodes); return desc[opCode]; } @@ -123,15 +112,8 @@ int getNumOperands(MachineOpCode opCode) const { return get(opCode).numOperands; } - - int getResultPos(MachineOpCode opCode) const { - return get(opCode).resultPos; - } - - unsigned getNumDelaySlots(MachineOpCode opCode) const { - return get(opCode).numDelaySlots; - } - + + InstrSchedClass getSchedClass(MachineOpCode opCode) const { return get(opCode).schedClass; } @@ -144,66 +126,15 @@ return get(opCode).ImplicitDefs; } + // // Query instruction class flags according to the machine-independent // flags listed above. // - bool isNop(MachineOpCode opCode) const { - return get(opCode).Flags & M_NOP_FLAG; - } - bool isBranch(MachineOpCode opCode) const { - return get(opCode).Flags & M_BRANCH_FLAG; - } - bool isCall(MachineOpCode opCode) const { - return get(opCode).Flags & M_CALL_FLAG; - } bool isReturn(MachineOpCode opCode) const { return get(opCode).Flags & M_RET_FLAG; } - bool isControlFlow(MachineOpCode opCode) const { - return get(opCode).Flags & M_BRANCH_FLAG - || get(opCode).Flags & M_CALL_FLAG - || get(opCode).Flags & M_RET_FLAG; - } - bool isArith(MachineOpCode opCode) const { - return get(opCode).Flags & M_ARITH_FLAG; - } - bool isCCInstr(MachineOpCode opCode) const { - return get(opCode).Flags & M_CC_FLAG; - } - bool isLogical(MachineOpCode opCode) const { - return get(opCode).Flags & M_LOGICAL_FLAG; - } - bool isIntInstr(MachineOpCode opCode) const { - return get(opCode).Flags & M_INT_FLAG; - } - bool isFloatInstr(MachineOpCode opCode) const { - return get(opCode).Flags & M_FLOAT_FLAG; - } - bool isConditional(MachineOpCode opCode) const { - return get(opCode).Flags & M_CONDL_FLAG; - } - bool isLoad(MachineOpCode opCode) const { - return get(opCode).Flags & M_LOAD_FLAG; - } - bool isPrefetch(MachineOpCode opCode) const { - return get(opCode).Flags & M_PREFETCH_FLAG; - } - bool isLoadOrPrefetch(MachineOpCode opCode) const { - return get(opCode).Flags & M_LOAD_FLAG - || get(opCode).Flags & M_PREFETCH_FLAG; - } - bool isStore(MachineOpCode opCode) const { - return get(opCode).Flags & M_STORE_FLAG; - } - bool isMemoryAccess(MachineOpCode opCode) const { - return get(opCode).Flags & M_LOAD_FLAG - || get(opCode).Flags & M_PREFETCH_FLAG - || get(opCode).Flags & M_STORE_FLAG; - } - bool isDummyPhiInstr(MachineOpCode opCode) const { - return get(opCode).Flags & M_DUMMY_PHI_FLAG; - } + bool isPseudoInstr(MachineOpCode opCode) const { return get(opCode).Flags & M_PSEUDO_FLAG; } @@ -224,6 +155,45 @@ return false; } + + + + //------------------------------------------------------------------------- + // Code generation support for creating individual machine instructions + // + // WARNING: These methods are Sparc specific + // + // DO NOT USE ANY OF THESE METHODS THEY ARE DEPRECATED! + // + //------------------------------------------------------------------------- + + int getResultPos(MachineOpCode opCode) const { + return get(opCode).resultPos; + } + unsigned getNumDelaySlots(MachineOpCode opCode) const { + return get(opCode).numDelaySlots; + } + bool isCCInstr(MachineOpCode opCode) const { + return get(opCode).Flags & M_CC_FLAG; + } + bool isNop(MachineOpCode opCode) const { + return get(opCode).Flags & M_NOP_FLAG; + } + bool isBranch(MachineOpCode opCode) const { + return get(opCode).Flags & M_BRANCH_FLAG; + } + bool isCall(MachineOpCode opCode) const { + return get(opCode).Flags & M_CALL_FLAG; + } + bool isLoad(MachineOpCode opCode) const { + return get(opCode).Flags & M_LOAD_FLAG; + } + bool isStore(MachineOpCode opCode) const { + return get(opCode).Flags & M_STORE_FLAG; + } + bool isDummyPhiInstr(MachineOpCode opCode) const { + return get(opCode).Flags & M_DUMMY_PHI_FLAG; + } // Check if an instruction can be issued before its operands are ready, // or if a subsequent instruction that uses its result can be issued // before the results are ready. @@ -231,8 +201,7 @@ // virtual bool hasOperandInterlock(MachineOpCode opCode) const { return true; - } - + } virtual bool hasResultInterlock(MachineOpCode opCode) const { return true; } @@ -261,7 +230,7 @@ virtual bool constantFitsInImmedField(MachineOpCode opCode, int64_t intValue) const; - // Return the largest +ve constant that can be held in the IMMMED field + // Return the largest positive constant that can be held in the IMMED field // of this machine instruction. // isSignExtended is set to true if the value is sign-extended before use // (this is true for all immediate fields in SPARC instructions). @@ -291,26 +260,6 @@ const Instruction* I) const { return true; // safe but very conservative } - - - /// createNOPinstr - returns the target's implementation of NOP, which is - /// usually a pseudo-instruction, implemented by a degenerate version of - /// another instruction, e.g. X86: xchg ax, ax; SparcV9: sethi g0, 0 - /// - virtual MachineInstr* createNOPinstr() const = 0; - - /// isNOPinstr - not having a special NOP opcode, we need to know if a given - /// instruction is interpreted as an `official' NOP instr, i.e., there may be - /// more than one way to `do nothing' but only one canonical way to slack off. - /// - virtual bool isNOPinstr(const MachineInstr &MI) const = 0; - - //------------------------------------------------------------------------- - // Code generation support for creating individual machine instructions - // - // WARNING: These methods are Sparc specific - // - //------------------------------------------------------------------------- // Get certain common op codes for the current target. this and all the // Create* methods below should be moved to a machine code generation class Index: llvm/include/llvm/Target/TargetMachine.h diff -u llvm/include/llvm/Target/TargetMachine.h:1.42 llvm/include/llvm/Target/TargetMachine.h:1.42.2.1 --- llvm/include/llvm/Target/TargetMachine.h:1.42 Sun Dec 28 15:22:35 2003 +++ llvm/include/llvm/Target/TargetMachine.h Mon Mar 1 17:57:19 2004 @@ -25,7 +25,6 @@ class TargetSchedInfo; class TargetRegInfo; class TargetFrameInfo; -class TargetCacheInfo; class MachineCodeEmitter; class MRegisterInfo; class FunctionPassManager; @@ -75,7 +74,6 @@ virtual const TargetSchedInfo& getSchedInfo() const = 0; virtual const TargetRegInfo& getRegInfo() const = 0; virtual const TargetFrameInfo& getFrameInfo() const = 0; - virtual const TargetCacheInfo& getCacheInfo() const = 0; const TargetData &getTargetData() const { return DataLayout; } /// getRegisterInfo - If register information is available, return it. If Index: llvm/include/llvm/Target/TargetMachineImpls.h diff -u llvm/include/llvm/Target/TargetMachineImpls.h:1.8 llvm/include/llvm/Target/TargetMachineImpls.h:1.8.2.1 --- llvm/include/llvm/Target/TargetMachineImpls.h:1.8 Sun Dec 28 03:48:17 2003 +++ llvm/include/llvm/Target/TargetMachineImpls.h Mon Mar 1 17:57:19 2004 @@ -21,14 +21,30 @@ class Module; class IntrinsicLowering; - // allocateSparcTargetMachine - Allocate and return a subclass of - // TargetMachine that implements the Sparc backend. This takes ownership of - // the IntrinsicLowering pointer, deleting it when the target machine is + // allocateCTargetMachine - Allocate and return a subclass of TargetMachine + // that implements emits C code. This takes ownership of the + // IntrinsicLowering pointer, deleting it when the target machine is // destroyed. // - TargetMachine *allocateSparcTargetMachine(const Module &M, + TargetMachine *allocateCTargetMachine(const Module &M, + IntrinsicLowering *IL = 0); + + // allocateSparcV9TargetMachine - Allocate and return a subclass of + // TargetMachine that implements the 64-bit Sparc backend. This takes + // ownership of the IntrinsicLowering pointer, deleting it when the target + // machine is destroyed. + // + TargetMachine *allocateSparcV9TargetMachine(const Module &M, IntrinsicLowering *IL = 0); + // allocateSparcV8TargetMachine - Allocate and return a subclass of + // TargetMachine that implements the 32-bit Sparc backend. This takes + // ownership of the IntrinsicLowering pointer, deleting it when the target + // machine is destroyed. + // + TargetMachine *allocateSparcV8TargetMachine(const Module &M, + IntrinsicLowering *IL = 0); + // allocateX86TargetMachine - Allocate and return a subclass of TargetMachine // that implements the X86 backend. This takes ownership of the // IntrinsicLowering pointer, deleting it when the target machine is @@ -36,6 +52,14 @@ // TargetMachine *allocateX86TargetMachine(const Module &M, IntrinsicLowering *IL = 0); + + // allocatePowerPCTargetMachine - Allocate and return a subclass + // of TargetMachine that implements the PowerPC backend. This takes + // ownership of the IntrinsicLowering pointer, deleting it when + // the target machine is destroyed. + // + TargetMachine *allocatePowerPCTargetMachine(const Module &M, + IntrinsicLowering *IL = 0); } // End llvm namespace #endif Index: llvm/include/llvm/Target/TargetRegInfo.h diff -u llvm/include/llvm/Target/TargetRegInfo.h:1.47 llvm/include/llvm/Target/TargetRegInfo.h:1.47.4.1 --- llvm/include/llvm/Target/TargetRegInfo.h:1.47 Tue Nov 11 16:41:31 2003 +++ llvm/include/llvm/Target/TargetRegInfo.h Mon Mar 1 17:57:19 2004 @@ -149,7 +149,7 @@ // returns the register that is hardwired to zero if any (-1 if none) // - virtual int getZeroRegNum() const = 0; + virtual unsigned getZeroRegNum() const = 0; // Number of registers used for passing int args (usually 6: %o0 - %o5) // and float args (usually 32: %f0 - %f31) Index: llvm/include/llvm/Target/TargetSchedInfo.h diff -u llvm/include/llvm/Target/TargetSchedInfo.h:1.21 llvm/include/llvm/Target/TargetSchedInfo.h:1.21.4.1 --- llvm/include/llvm/Target/TargetSchedInfo.h:1.21 Tue Nov 11 16:41:31 2003 +++ llvm/include/llvm/Target/TargetSchedInfo.h Mon Mar 1 17:57:19 2004 @@ -191,16 +191,6 @@ unsigned maxNumIssueTotal; int longestIssueConflict; - int branchMispredictPenalty; // 4 for SPARC IIi - int branchTargetUnknownPenalty; // 2 for SPARC IIi - int l1DCacheMissPenalty; // 7 or 9 for SPARC IIi - int l1ICacheMissPenalty; // ? for SPARC IIi - - bool inOrderLoads; // true for SPARC IIi - bool inOrderIssue; // true for SPARC IIi - bool inOrderExec; // false for most architectures - bool inOrderRetire; // true for most architectures - protected: inline const InstrRUsage& getInstrRUsage(MachineOpCode opCode) const { assert(opCode >= 0 && opCode < (int) instrRUsages.size()); From brukman at cs.uiuc.edu Mon Mar 1 18:00:08 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Mar 1 18:00:08 2004 Subject: [llvm-commits] [parallel] CVS: llvm/include/llvm/Transforms/Utils/FunctionUtils.h Cloning.h Message-ID: <200403012357.RAA03426@zion.cs.uiuc.edu> Changes in directory llvm/include/llvm/Transforms/Utils: FunctionUtils.h added (r1.2.2.1) Cloning.h updated: 1.13 -> 1.13.4.1 --- Log message: Merge from trunk --- Diffs of the changes: (+37 -2) Index: llvm/include/llvm/Transforms/Utils/FunctionUtils.h diff -c /dev/null llvm/include/llvm/Transforms/Utils/FunctionUtils.h:1.2.2.1 *** /dev/null Mon Mar 1 17:57:29 2004 --- llvm/include/llvm/Transforms/Utils/FunctionUtils.h Mon Mar 1 17:57:19 2004 *************** *** 0 **** --- 1,32 ---- + //===-- Transform/Utils/FunctionUtils.h - Function Utils --------*- C++ -*-===// + // + // The LLVM Compiler Infrastructure + // + // This file was developed by the LLVM research group and is distributed under + // the University of Illinois Open Source License. See LICENSE.TXT for details. + // + //===----------------------------------------------------------------------===// + // + // This family of functions perform manipulations on functions. + // + //===----------------------------------------------------------------------===// + + #ifndef LLVM_TRANSFORMS_UTILS_FUNCTION_H + #define LLVM_TRANSFORMS_UTILS_FUNCTION_H + + namespace llvm { + + class Function; + class Loop; + + /// ExtractLoop - rip out a natural loop into a new function + /// + Function* ExtractLoop(Loop *L); + + /// ExtractBasicBlock - rip out a basic block into a new function + /// + Function* ExtractBasicBlock(BasicBlock *BB); + + } + + #endif Index: llvm/include/llvm/Transforms/Utils/Cloning.h diff -u llvm/include/llvm/Transforms/Utils/Cloning.h:1.13 llvm/include/llvm/Transforms/Utils/Cloning.h:1.13.4.1 --- llvm/include/llvm/Transforms/Utils/Cloning.h:1.13 Tue Nov 11 16:41:31 2003 +++ llvm/include/llvm/Transforms/Utils/Cloning.h Mon Mar 1 17:57:19 2004 @@ -55,11 +55,14 @@ /// is recorded in the ValueMap map. /// /// If you have a particular suffix you'd like to use to add to any cloned -/// names, specify it as the optional second parameter. +/// names, specify it as the optional third parameter. +/// +/// If you would like the basic block to be auto-inserted into the end of a +/// function, you can specify it as the optional fourth parameter. /// BasicBlock *CloneBasicBlock(const BasicBlock *BB, std::map &ValueMap, - const char *NameSuffix = ""); + const char *NameSuffix = "", Function *F = 0); /// CloneFunction - Return a copy of the specified function, but without From brukman at cs.uiuc.edu Mon Mar 1 18:01:01 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Mar 1 18:01:01 2004 Subject: [llvm-commits] [parallel] CVS: llvm/lib/CWriter/Makefile Writer.cpp Message-ID: <200403012358.RAA03539@zion.cs.uiuc.edu> Changes in directory llvm/lib/CWriter: Makefile (r1.2) removed Writer.cpp (r1.151) removed --- Log message: Merge from trunk --- Diffs of the changes: (+0 -0) From brukman at cs.uiuc.edu Mon Mar 1 18:01:07 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Mar 1 18:01:07 2004 Subject: [llvm-commits] [parallel] CVS: llvm/lib/Target/Sparc/RegAlloc/AllocInfo.h IGNode.cpp IGNode.h InterferenceGraph.cpp InterferenceGraph.h LiveRange.h LiveRangeInfo.cpp LiveRangeInfo.h Makefile PhyRegAlloc.cpp PhyRegAlloc.h RegAllocCommon.h RegClass.cpp RegClass.h Message-ID: <200403012358.RAA03569@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/Sparc/RegAlloc: AllocInfo.h (r1.5) removed IGNode.cpp (r1.12) removed IGNode.h (r1.20) removed InterferenceGraph.cpp (r1.19) removed InterferenceGraph.h (r1.7) removed LiveRange.h (r1.25) removed LiveRangeInfo.cpp (r1.48) removed LiveRangeInfo.h (r1.23) removed Makefile (r1.4) removed PhyRegAlloc.cpp (r1.131) removed PhyRegAlloc.h (r1.62) removed RegAllocCommon.h (r1.12) removed RegClass.cpp (r1.28) removed RegClass.h (r1.21) removed --- Log message: Merge from trunk --- Diffs of the changes: (+0 -0) From brukman at cs.uiuc.edu Mon Mar 1 18:01:13 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Mar 1 18:01:13 2004 Subject: [llvm-commits] [parallel] CVS: llvm/lib/Target/Sparc/.cvsignore EmitAssembly.cpp EmitBytecodeToAssembly.cpp Makefile MappingInfo.cpp MappingInfo.h PeepholeOpts.cpp PreSelection.cpp PrologEpilogCodeInserter.cpp Sparc.burg.in SparcFrameInfo.cpp SparcFrameInfo.h SparcInstr.def SparcInstrInfo.cpp SparcInstrInfo.h SparcInstrSelection.cpp SparcInstrSelectionSupport.h SparcInternals.h SparcJITInfo.h SparcRegClassInfo.cpp SparcRegClassInfo.h SparcRegInfo.cpp SparcRegInfo.h SparcTargetMachine.cpp SparcTargetMachine.h SparcV9.td SparcV9CodeEmitter.cpp SparcV9CodeEmitter.h SparcV9_F2.td SparcV9_F3.td SparcV9_F4.td SparcV9_Reg.td StackSlots.cpp UltraSparcSchedInfo.cpp Message-ID: <200403012358.RAA03562@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/Sparc: .cvsignore (r1.2) removed EmitAssembly.cpp (r1.101) removed EmitBytecodeToAssembly.cpp (r1.12) removed Makefile (r1.40) removed MappingInfo.cpp (r1.15) removed MappingInfo.h (r1.6) removed PeepholeOpts.cpp (r1.17) removed PreSelection.cpp (r1.27) removed PrologEpilogCodeInserter.cpp (r1.32) removed Sparc.burg.in (r1.11) removed SparcFrameInfo.cpp (r1.1) removed SparcFrameInfo.h (r1.1) removed SparcInstr.def (r1.23) removed SparcInstrInfo.cpp (r1.59) removed SparcInstrInfo.h (r1.1) removed SparcInstrSelection.cpp (r1.130) removed SparcInstrSelectionSupport.h (r1.13) removed SparcInternals.h (r1.110) removed SparcJITInfo.h (r1.3) removed SparcRegClassInfo.cpp (r1.34) removed SparcRegClassInfo.h (r1.23) removed SparcRegInfo.cpp (r1.116) removed SparcRegInfo.h (r1.8) removed SparcTargetMachine.cpp (r1.98) removed SparcTargetMachine.h (r1.4) removed SparcV9.td (r1.29) removed SparcV9CodeEmitter.cpp (r1.49) removed SparcV9CodeEmitter.h (r1.17) removed SparcV9_F2.td (r1.8) removed SparcV9_F3.td (r1.17) removed SparcV9_F4.td (r1.10) removed SparcV9_Reg.td (r1.7) removed StackSlots.cpp (r1.9) removed UltraSparcSchedInfo.cpp (r1.9) removed --- Log message: Merge from trunk --- Diffs of the changes: (+0 -0) From brukman at cs.uiuc.edu Mon Mar 1 18:01:19 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Mar 1 18:01:19 2004 Subject: [llvm-commits] [parallel] CVS: llvm/lib/Target/Sparc/LiveVar/BBLiveVar.cpp BBLiveVar.h FunctionLiveVarInfo.cpp Makefile ValueSet.cpp Message-ID: <200403012358.RAA03566@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/Sparc/LiveVar: BBLiveVar.cpp (r1.41) removed BBLiveVar.h (r1.25) removed FunctionLiveVarInfo.cpp (r1.51) removed Makefile (r1.4) removed ValueSet.cpp (r1.16) removed --- Log message: Merge from trunk --- Diffs of the changes: (+0 -0) From brukman at cs.uiuc.edu Mon Mar 1 18:01:26 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Mar 1 18:01:26 2004 Subject: [llvm-commits] [parallel] CVS: llvm/lib/Analysis/IPA/IPModRef.cpp Message-ID: <200403012358.RAA03617@zion.cs.uiuc.edu> Changes in directory llvm/lib/Analysis/IPA: IPModRef.cpp updated: 1.20 -> 1.20.4.1 --- Log message: Merge from trunk --- Diffs of the changes: (+21 -21) Index: llvm/lib/Analysis/IPA/IPModRef.cpp diff -u llvm/lib/Analysis/IPA/IPModRef.cpp:1.20 llvm/lib/Analysis/IPA/IPModRef.cpp:1.20.4.1 --- llvm/lib/Analysis/IPA/IPModRef.cpp:1.20 Tue Nov 11 16:41:32 2003 +++ llvm/lib/Analysis/IPA/IPModRef.cpp Mon Mar 1 17:58:12 2004 @@ -63,8 +63,10 @@ funcTDGraph(tdgClone), funcModRefInfo(tdgClone->getGraphSize()) { - for (unsigned i=0, N = funcTDGraph->getGraphSize(); i < N; ++i) - NodeIds[funcTDGraph->getNodes()[i]] = i; + unsigned i = 0; + for (DSGraph::node_iterator NI = funcTDGraph->node_begin(), + E = funcTDGraph->node_end(); NI != E; ++NI) + NodeIds[*NI] = i++; } @@ -95,13 +97,12 @@ { // Mark all nodes in the graph that are marked MOD as being mod // and all those marked REF as being ref. - for (unsigned i = 0, N = funcTDGraph->getGraphSize(); i < N; ++i) - { - if (funcTDGraph->getNodes()[i]->isModified()) - funcModRefInfo.setNodeIsMod(i); - if (funcTDGraph->getNodes()[i]->isRead()) - funcModRefInfo.setNodeIsRef(i); - } + unsigned i = 0; + for (DSGraph::node_iterator NI = funcTDGraph->node_begin(), + E = funcTDGraph->node_end(); NI != E; ++NI, ++i) { + if ((*NI)->isModified()) funcModRefInfo.setNodeIsMod(i); + if ((*NI)->isRead()) funcModRefInfo.setNodeIsRef(i); + } // Compute the Mod/Ref info for all call sites within the function. // The call sites are recorded in the TD graph. @@ -214,18 +215,15 @@ } // For all nodes in the graph, extract the mod/ref information - const std::vector& csgNodes = csgp->getNodes(); - const std::vector& origNodes = funcTDGraph->getNodes(); - assert(csgNodes.size() == origNodes.size()); - for (unsigned i=0, N = origNodes.size(); i < N; ++i) - { - DSNode* csgNode = NodeMap[origNodes[i]].getNode(); - assert(csgNode && "Inlined and original graphs do not correspond!"); - if (csgNode->isModified()) - callModRefInfo->setNodeIsMod(getNodeId(origNodes[i])); - if (csgNode->isRead()) - callModRefInfo->setNodeIsRef(getNodeId(origNodes[i])); - } + for (DSGraph::node_iterator NI = funcTDGraph->node_begin(), + E = funcTDGraph->node_end(); NI != E; ++NI) { + DSNode* csgNode = NodeMap[*NI].getNode(); + assert(csgNode && "Inlined and original graphs do not correspond!"); + if (csgNode->isModified()) + callModRefInfo->setNodeIsMod(getNodeId(*NI)); + if (csgNode->isRead()) + callModRefInfo->setNodeIsRef(getNodeId(*NI)); + } // Drop nodemap before we delete the graph... NodeMap.clear(); @@ -295,8 +293,10 @@ O << std::string((j < NV-1)? "; " : "\n"); } +#if 0 else tdGraph.getNodes()[i]->print(O, /*graph*/ NULL); +#endif } } }; From brukman at cs.uiuc.edu Mon Mar 1 18:01:32 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Mar 1 18:01:32 2004 Subject: [llvm-commits] [parallel] CVS: llvm/runtime/Makefile Message-ID: <200403012358.RAA04244@zion.cs.uiuc.edu> Changes in directory llvm/runtime: Makefile updated: 1.12 -> 1.12.2.1 --- Log message: Merge from trunk --- Diffs of the changes: (+3 -1) Index: llvm/runtime/Makefile diff -u llvm/runtime/Makefile:1.12 llvm/runtime/Makefile:1.12.2.1 --- llvm/runtime/Makefile:1.12 Fri Jan 16 15:13:10 2004 +++ llvm/runtime/Makefile Mon Mar 1 17:58:45 2004 @@ -12,7 +12,7 @@ include $(LEVEL)/Makefile.config ifneq ($(wildcard $(LLVMGCCDIR)),) -PARALLEL_DIRS := GCCLibraries libdummy libprofile libtrace +PARALLEL_DIRS := GCCLibraries libdummy libprofile libtrace libpng zlib else PARALLEL_DIRS := install all :: @@ -30,3 +30,5 @@ install:: clean:: + rm -f $(DESTLIBBYTECODE)/* + From brukman at cs.uiuc.edu Mon Mar 1 18:01:37 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Mar 1 18:01:37 2004 Subject: [llvm-commits] [parallel] CVS: llvm/runtime/GCCLibraries/libc/string.c Message-ID: <200403012358.RAA04260@zion.cs.uiuc.edu> Changes in directory llvm/runtime/GCCLibraries/libc: string.c updated: 1.6 -> 1.6.6.1 --- Log message: Merge from trunk --- Diffs of the changes: (+16 -3) Index: llvm/runtime/GCCLibraries/libc/string.c diff -u llvm/runtime/GCCLibraries/libc/string.c:1.6 llvm/runtime/GCCLibraries/libc/string.c:1.6.6.1 --- llvm/runtime/GCCLibraries/libc/string.c:1.6 Tue Oct 21 12:53:16 2003 +++ llvm/runtime/GCCLibraries/libc/string.c Mon Mar 1 17:58:45 2004 @@ -6,8 +6,6 @@ #include #include -void *malloc(size_t); -void free(void *); size_t strlen(const char *Str) { size_t Count = 0; @@ -16,15 +14,30 @@ } char *strdup(const char *str) { - long Len = strlen(str); + size_t Len = strlen(str); char *Result = (char*)malloc((Len+1)*sizeof(char)); memcpy(Result, str, Len+1); return Result; } +char *strndup(const char *str, size_t n) { + size_t Len = strlen(str); + if (Len > n) Len = n; + char *Result = (char*)malloc((Len+1)*sizeof(char)); + memcpy(Result, str, Len); + Result[Len] = 0; + return Result; +} + char *strcpy(char *s1, const char *s2) { char *dest = s1; while ((*s1++ = *s2++)); + return dest; +} + +char *strncpy(char *s1, const char *s2, size_t n) { + char *dest = s1; + while (n-- && (*s1++ = *s2++)); return dest; } From brukman at cs.uiuc.edu Mon Mar 1 18:01:43 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Mar 1 18:01:43 2004 Subject: [llvm-commits] [parallel] CVS: llvm/runtime/GCCLibraries/crtend/Makefile crtend.c Message-ID: <200403012358.RAA04253@zion.cs.uiuc.edu> Changes in directory llvm/runtime/GCCLibraries/crtend: Makefile updated: 1.12 -> 1.12.4.1 crtend.c updated: 1.3 -> 1.3.2.1 --- Log message: Merge from trunk --- Diffs of the changes: (+5 -4) Index: llvm/runtime/GCCLibraries/crtend/Makefile diff -u llvm/runtime/GCCLibraries/crtend/Makefile:1.12 llvm/runtime/GCCLibraries/crtend/Makefile:1.12.4.1 --- llvm/runtime/GCCLibraries/crtend/Makefile:1.12 Sun Nov 30 03:22:42 2003 +++ llvm/runtime/GCCLibraries/crtend/Makefile Mon Mar 1 17:58:45 2004 @@ -31,10 +31,10 @@ all:: $(CRTEND_A) # Installation simply requires copying the archive to it's new home. -$(LLVMGCCDIR)/bytecode-libs/libcrtend.a: $(CRTEND_A) +$(DESTDIR)$(bytecode_libdir)/libcrtend.a: $(CRTEND_A) $(DESTDIR)$(bytecode_libdir) cp $< $@ -install:: $(LLVMGCCDIR)/bytecode-libs/libcrtend.a +install:: $(DESTDIR)$(bytecode_libdir)/libcrtend.a # The four components described in the README Index: llvm/runtime/GCCLibraries/crtend/crtend.c diff -u llvm/runtime/GCCLibraries/crtend/crtend.c:1.3 llvm/runtime/GCCLibraries/crtend/crtend.c:1.3.2.1 --- llvm/runtime/GCCLibraries/crtend/crtend.c:1.3 Fri Dec 19 01:51:46 2003 +++ llvm/runtime/GCCLibraries/crtend/crtend.c Mon Mar 1 17:58:45 2004 @@ -49,8 +49,9 @@ abort(); /* Should be able to install ONE atexit handler! */ /* FIXME: This should sort the list by priority! */ - for (; R->FP; ++R) - R->FP(); + if (R->FP) + for (; R->FP; ++R) + R->FP(); } static void run_destructors(void) { From brukman at cs.uiuc.edu Mon Mar 1 18:01:49 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Mar 1 18:01:49 2004 Subject: [llvm-commits] [parallel] CVS: llvm/test/Programs/External/Makefile Message-ID: <200403012359.RAA05365@zion.cs.uiuc.edu> Changes in directory llvm/test/Programs/External: Makefile updated: 1.4 -> 1.4.2.1 --- Log message: Merge from trunk --- Diffs of the changes: (+4 -3) Index: llvm/test/Programs/External/Makefile diff -u llvm/test/Programs/External/Makefile:1.4 llvm/test/Programs/External/Makefile:1.4.2.1 --- llvm/test/Programs/External/Makefile:1.4 Thu Dec 18 10:41:58 2003 +++ llvm/test/Programs/External/Makefile Mon Mar 1 17:59:09 2004 @@ -8,9 +8,10 @@ # # Create the list of directories to compile # -DIRS := SPEC -ifndef USE_SPEC -DIRS := $(filter-out SPEC/, $(DIRS)) +DIRS := SPEC Povray + +ifndef USE_POVRAY +DIRS := $(filter-out Povray/, $(DIRS)) endif include ${LEVEL}/test/Programs/Makefile.programs From brukman at cs.uiuc.edu Mon Mar 1 18:01:55 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Mar 1 18:01:55 2004 Subject: [llvm-commits] [parallel] CVS: llvm/lib/Target/SparcV9/InstrSelection/InstrSelection.cpp InstrSelectionSupport.cpp Makefile Message-ID: <200403012358.RAA03773@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/SparcV9/InstrSelection: InstrSelection.cpp updated: 1.68 -> 1.68.2.1 InstrSelectionSupport.cpp updated: 1.61 -> 1.61.2.1 Makefile updated: 1.4 -> 1.4.2.1 --- Log message: Merge from trunk --- Diffs of the changes: (+7 -9) Index: llvm/lib/Target/SparcV9/InstrSelection/InstrSelection.cpp diff -u llvm/lib/Target/SparcV9/InstrSelection/InstrSelection.cpp:1.68 llvm/lib/Target/SparcV9/InstrSelection/InstrSelection.cpp:1.68.2.1 --- llvm/lib/Target/SparcV9/InstrSelection/InstrSelection.cpp:1.68 Sun Dec 28 15:23:38 2003 +++ llvm/lib/Target/SparcV9/InstrSelection/InstrSelection.cpp Mon Mar 1 17:58:15 2004 @@ -283,10 +283,7 @@ break; } - // find the position of first machine instruction generated by the - // terminator of this BB - MachineBasicBlock::iterator MCIt = - std::find(MBB->begin(), MBB->end(), FirstMIOfTerm); + MachineBasicBlock::iterator MCIt = FirstMIOfTerm; assert(MCIt != MBB->end() && "Start inst of terminator not found"); Index: llvm/lib/Target/SparcV9/InstrSelection/InstrSelectionSupport.cpp diff -u llvm/lib/Target/SparcV9/InstrSelection/InstrSelectionSupport.cpp:1.61 llvm/lib/Target/SparcV9/InstrSelection/InstrSelectionSupport.cpp:1.61.2.1 --- llvm/lib/Target/SparcV9/InstrSelection/InstrSelectionSupport.cpp:1.61 Fri Jan 9 00:22:34 2004 +++ llvm/lib/Target/SparcV9/InstrSelection/InstrSelectionSupport.cpp Mon Mar 1 17:58:15 2004 @@ -14,7 +14,7 @@ #include "llvm/CodeGen/InstrSelectionSupport.h" #include "llvm/CodeGen/InstrSelection.h" -#include "llvm/CodeGen/MachineInstrAnnot.h" +#include "../MachineInstrAnnot.h" #include "llvm/CodeGen/MachineCodeForInstruction.h" #include "llvm/CodeGen/InstrForest.h" #include "llvm/Target/TargetMachine.h" @@ -23,7 +23,7 @@ #include "llvm/Constants.h" #include "llvm/BasicBlock.h" #include "llvm/DerivedTypes.h" -#include "../SparcInstrSelectionSupport.h" +#include "../SparcV9InstrSelectionSupport.h" namespace llvm { @@ -71,7 +71,8 @@ opType = isSigned? MachineOperand::MO_SignExtendedImmed : MachineOperand::MO_UnextendedImmed; getImmedValue = intValue; - } else if (intValue == 0 && target.getRegInfo().getZeroRegNum() >= 0) { + } else if (intValue == 0 && + target.getRegInfo().getZeroRegNum() != (unsigned)-1) { opType = MachineOperand::MO_MachineRegister; getMachineRegNum = target.getRegInfo().getZeroRegNum(); } @@ -129,7 +130,7 @@ { std::vector MVec; - MachineOpCode opCode = minstr->getOpCode(); + MachineOpCode opCode = minstr->getOpcode(); const TargetInstrInfo& instrInfo = target.getInstrInfo(); int resultPos = instrInfo.getResultPos(opCode); int immedPos = instrInfo.getImmedConstantPos(opCode); Index: llvm/lib/Target/SparcV9/InstrSelection/Makefile diff -u llvm/lib/Target/SparcV9/InstrSelection/Makefile:1.4 llvm/lib/Target/SparcV9/InstrSelection/Makefile:1.4.2.1 --- llvm/lib/Target/SparcV9/InstrSelection/Makefile:1.4 Fri Jan 9 00:22:34 2004 +++ llvm/lib/Target/SparcV9/InstrSelection/Makefile Mon Mar 1 17:58:15 2004 @@ -9,6 +9,6 @@ LEVEL = ../../../.. DIRS = -LIBRARYNAME = select +LIBRARYNAME = sparcv9select include $(LEVEL)/Makefile.common From brukman at cs.uiuc.edu Mon Mar 1 18:02:01 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Mar 1 18:02:01 2004 Subject: [llvm-commits] [parallel] CVS: llvm/lib/Bytecode/Writer/ConstantWriter.cpp InstructionWriter.cpp Writer.cpp Message-ID: <200403012358.RAA03705@zion.cs.uiuc.edu> Changes in directory llvm/lib/Bytecode/Writer: ConstantWriter.cpp updated: 1.33 -> 1.33.2.1 InstructionWriter.cpp updated: 1.38 -> 1.38.2.1 Writer.cpp updated: 1.60 -> 1.60.2.1 --- Log message: Merge from trunk --- Diffs of the changes: (+6 -95) Index: llvm/lib/Bytecode/Writer/ConstantWriter.cpp diff -u llvm/lib/Bytecode/Writer/ConstantWriter.cpp:1.33 llvm/lib/Bytecode/Writer/ConstantWriter.cpp:1.33.2.1 --- llvm/lib/Bytecode/Writer/ConstantWriter.cpp:1.33 Sun Jan 18 15:08:52 2004 +++ llvm/lib/Bytecode/Writer/ConstantWriter.cpp Mon Mar 1 17:58:13 2004 @@ -19,21 +19,11 @@ #include "Support/Statistic.h" using namespace llvm; -static Statistic<> -TypeBytes("bytecodewriter", "Bytes of types"); -static Statistic<> -ConstantBytes("bytecodewriter", "Bytes of constants"); -static Statistic<> -NumConstants("bytecodewriter", "Number of constants"); - - void BytecodeWriter::outputType(const Type *T) { - TypeBytes -= Out.size(); output_vbr((unsigned)T->getPrimitiveID(), Out); // That's all there is to handling primitive types... if (T->isPrimitiveType()) { - TypeBytes += Out.size(); return; // We might do this if we alias a prim type: %x = type int } @@ -44,12 +34,12 @@ assert(Slot != -1 && "Type used but not available!!"); output_vbr((unsigned)Slot, Out); - // Output the number of arguments to method (+1 if varargs): - output_vbr((unsigned)MT->getParamTypes().size()+MT->isVarArg(), Out); + // Output the number of arguments to function (+1 if varargs): + output_vbr((unsigned)MT->getNumParams()+MT->isVarArg(), Out); // Output all of the arguments... - FunctionType::ParamTypes::const_iterator I = MT->getParamTypes().begin(); - for (; I != MT->getParamTypes().end(); ++I) { + FunctionType::param_iterator I = MT->param_begin(); + for (; I != MT->param_end(); ++I) { Slot = Table.getSlot(*I); assert(Slot != -1 && "Type used but not available!!"); output_vbr((unsigned)Slot, Out); @@ -76,8 +66,8 @@ const StructType *ST = cast(T); // Output all of the element types... - StructType::ElementTypes::const_iterator I = ST->getElementTypes().begin(); - for (; I != ST->getElementTypes().end(); ++I) { + for (StructType::element_iterator I = ST->element_begin(), + E = ST->element_end(); I != E; ++I) { int Slot = Table.getSlot(*I); assert(Slot != -1 && "Type used but not available!!"); output_vbr((unsigned)Slot, Out); @@ -107,16 +97,12 @@ << " Type '" << T->getDescription() << "'\n"; break; } - TypeBytes += Out.size(); } void BytecodeWriter::outputConstant(const Constant *CPV) { - ConstantBytes -= Out.size(); assert((CPV->getType()->isPrimitiveType() || !CPV->isNullValue()) && "Shouldn't output null constants!"); - ++NumConstants; - // We must check for a ConstantExpr before switching by type because // a ConstantExpr can be of any type, and has no explicit value. // @@ -133,7 +119,6 @@ Slot = Table.getSlot((*OI)->getType()); output_vbr((unsigned)Slot, Out); } - ConstantBytes += Out.size(); return; } else { output_vbr(0U, Out); // flag as not a ConstantExpr @@ -211,7 +196,6 @@ << " type '" << CPV->getType()->getName() << "'\n"; break; } - ConstantBytes += Out.size(); return; } @@ -225,8 +209,6 @@ output_vbr(unsigned(E-I), Out); output_vbr(Type::VoidTyID, Out); - ConstantBytes -= Out.size(); - // Emit all of the strings. for (I = Table.string_begin(); I != E; ++I) { const ConstantArray *Str = *I; @@ -238,8 +220,5 @@ // emit all of the characters. std::string Val = Str->getAsString(); output_data(Val.c_str(), Val.c_str()+Val.size(), Out); - - ++NumConstants; } - ConstantBytes += Out.size(); } Index: llvm/lib/Bytecode/Writer/InstructionWriter.cpp diff -u llvm/lib/Bytecode/Writer/InstructionWriter.cpp:1.38 llvm/lib/Bytecode/Writer/InstructionWriter.cpp:1.38.2.1 --- llvm/lib/Bytecode/Writer/InstructionWriter.cpp:1.38 Sun Jan 18 15:08:52 2004 +++ llvm/lib/Bytecode/Writer/InstructionWriter.cpp Mon Mar 1 17:58:13 2004 @@ -20,26 +20,6 @@ #include using namespace llvm; -static Statistic<> -NumInstrs("bytecodewriter", "Number of instructions"); -static Statistic<> -NumOversizedInstrs("bytecodewriter", "Number of oversized instructions"); -static Statistic<> -BytesOversizedInstrs("bytecodewriter", "Bytes of oversized instructions"); - -static Statistic<> -NumHugeOperandInstrs("bytecodewriter", "Number of instructions with > 3 operands"); -static Statistic<> -NumOversized1OpInstrs("bytecodewriter", "Number of oversized 1 operand instrs"); -static Statistic<> -NumOversized2OpInstrs("bytecodewriter", "Number of oversized 2 operand instrs"); -static Statistic<> -NumOversized3OpInstrs("bytecodewriter", "Number of oversized 3 operand instrs"); - -static Statistic<> -NumOversidedBecauseOfTypes("bytecodewriter", "Number of oversized instructions because of their type"); - - typedef unsigned char uchar; // outputInstructionFormat0 - Output those wierd instructions that have a large @@ -50,9 +30,6 @@ static void outputInstructionFormat0(const Instruction *I, unsigned Opcode, const SlotCalculator &Table, unsigned Type, std::deque &Out) { - NumOversizedInstrs++; - BytesOversizedInstrs -= Out.size(); - // Opcode must have top two bits clear... output_vbr(Opcode << 2, Out); // Instruction Opcode ID output_vbr(Type, Out); // Result type @@ -78,7 +55,6 @@ } align32(Out); // We must maintain correct alignment! - BytesOversizedInstrs += Out.size(); } @@ -281,8 +257,6 @@ } } - ++NumInstrs; - // Decide which instruction encoding to use. This is determined primarily by // the number of operands, and secondarily by whether or not the max operand // will fit into the instruction encoding. More operands == fewer bits per @@ -295,10 +269,6 @@ outputInstructionFormat1(&I, Opcode, Table, Slots, Type, Out); return; } - if (Type >= (1 << 12)-1) - NumOversidedBecauseOfTypes++; - - NumOversized1OpInstrs++; break; case 2: @@ -306,9 +276,6 @@ outputInstructionFormat2(&I, Opcode, Table, Slots, Type, Out); return; } - if (Type >= (1 << 8)) - NumOversidedBecauseOfTypes++; - NumOversized2OpInstrs++; break; case 3: @@ -316,12 +283,8 @@ outputInstructionFormat3(&I, Opcode, Table, Slots, Type, Out); return; } - if (Type >= (1 << 6)) - NumOversidedBecauseOfTypes++; - NumOversized3OpInstrs++; break; default: - ++NumHugeOperandInstrs; break; } Index: llvm/lib/Bytecode/Writer/Writer.cpp diff -u llvm/lib/Bytecode/Writer/Writer.cpp:1.60 llvm/lib/Bytecode/Writer/Writer.cpp:1.60.2.1 --- llvm/lib/Bytecode/Writer/Writer.cpp:1.60 Mon Jan 19 18:54:06 2004 +++ llvm/lib/Bytecode/Writer/Writer.cpp Mon Mar 1 17:58:13 2004 @@ -38,18 +38,6 @@ static Statistic<> BytesWritten("bytecodewriter", "Number of bytecode bytes written"); -static Statistic<> -ConstantTotalBytes("bytecodewriter", "Bytes of constants total"); -static Statistic<> -ConstantPlaneHeaderBytes("bytecodewriter", "Constant plane header bytes"); -static Statistic<> -InstructionBytes("bytecodewriter", "Bytes of instructions"); -static Statistic<> -SymTabBytes("bytecodewriter", "Bytes of symbol table"); -static Statistic<> -ModuleInfoBytes("bytecodewriter", "Bytes of module info"); -static Statistic<> -CompactionTableBytes("bytecodewriter", "Bytes of compaction tables"); BytecodeWriter::BytecodeWriter(std::deque &o, const Module *M) : Out(o), Table(M, true) { @@ -125,8 +113,6 @@ // FIXME: Most slabs only have 1 or 2 entries! We should encode this much // more compactly. - ConstantPlaneHeaderBytes -= Out.size(); - // Output type header: [num entries][type id number] // output_vbr(NC, Out); @@ -136,9 +122,6 @@ assert (Slot != -1 && "Type in constant pool but not in function!!"); output_vbr((unsigned)Slot, Out); - ConstantPlaneHeaderBytes += Out.size(); - - //cerr << "Emitting " << NC << " constants of type '" // << Plane.front()->getType()->getName() << "' = Slot #" << Slot << "\n"; @@ -160,7 +143,6 @@ } void BytecodeWriter::outputConstants(bool isFunction) { - ConstantTotalBytes -= Out.size(); { BytecodeBlock CPool(BytecodeFormat::ConstantPool, Out, true /* Elide block if empty */); @@ -197,7 +179,6 @@ outputConstantsInPlane(Plane, ValNo); } } - }ConstantTotalBytes += Out.size(); } static unsigned getEncodedLinkage(const GlobalValue *GV) { @@ -212,8 +193,6 @@ } void BytecodeWriter::outputModuleInfoBlock(const Module *M) { - ModuleInfoBytes -= Out.size(); - BytecodeBlock ModuleInfoBlock(BytecodeFormat::ModuleGlobalInfo, Out); // Output the types for the global variables in the module... @@ -244,17 +223,13 @@ output_vbr((unsigned)Slot, Out); } output_vbr((unsigned)Table.getSlot(Type::VoidTy), Out); - - ModuleInfoBytes += Out.size(); } void BytecodeWriter::outputInstructions(const Function *F) { BytecodeBlock ILBlock(BytecodeFormat::InstructionList, Out); - InstructionBytes -= Out.size(); 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) outputInstruction(*I); - InstructionBytes += Out.size(); } void BytecodeWriter::outputFunction(const Function *F) { @@ -316,7 +291,6 @@ } void BytecodeWriter::outputCompactionTable() { - CompactionTableBytes -= Out.size(); { BytecodeBlock CTB(BytecodeFormat::CompactionTable, Out, true/*ElideIfEmpty*/); const std::vector > &CT =Table.getCompactionTable(); @@ -328,7 +302,6 @@ for (unsigned i = 0, e = CT.size(); i != e; ++i) if (i != Type::TypeTyID) outputCompactionTablePlane(i, CT[i], 0); - } CompactionTableBytes += Out.size(); } void BytecodeWriter::outputSymbolTable(const SymbolTable &MST) { @@ -336,8 +309,6 @@ // space! if (MST.begin() == MST.end()) return; - SymTabBytes -= Out.size(); { - BytecodeBlock SymTabBlock(BytecodeFormat::SymbolTable, Out, true/* ElideIfEmpty*/); @@ -365,8 +336,6 @@ output(I->first, Out, false); // Don't force alignment... } } - - }SymTabBytes += Out.size(); } void llvm::WriteBytecodeToFile(const Module *C, std::ostream &Out) { From brukman at cs.uiuc.edu Mon Mar 1 18:02:08 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Mar 1 18:02:08 2004 Subject: [llvm-commits] [parallel] CVS: llvm/lib/Target/Sparc/InstrSelection/InstrForest.cpp InstrSelection.cpp InstrSelectionSupport.cpp Makefile Message-ID: <200403012358.RAA03624@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/Sparc/InstrSelection: InstrForest.cpp (r1.50) removed InstrSelection.cpp (r1.68) removed InstrSelectionSupport.cpp (r1.61) removed Makefile (r1.4) removed --- Log message: Merge from trunk --- Diffs of the changes: (+0 -0) From brukman at cs.uiuc.edu Mon Mar 1 18:02:14 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Mar 1 18:02:14 2004 Subject: [llvm-commits] [parallel] CVS: llvm/lib/ExecutionEngine/Interpreter/Execution.cpp Interpreter.cpp Interpreter.h Message-ID: <200403012358.RAA03687@zion.cs.uiuc.edu> Changes in directory llvm/lib/ExecutionEngine/Interpreter: Execution.cpp updated: 1.121 -> 1.121.2.1 Interpreter.cpp updated: 1.20 -> 1.20.2.1 Interpreter.h updated: 1.59 -> 1.59.2.1 --- Log message: Merge from trunk --- Diffs of the changes: (+23 -17) Index: llvm/lib/ExecutionEngine/Interpreter/Execution.cpp diff -u llvm/lib/ExecutionEngine/Interpreter/Execution.cpp:1.121 llvm/lib/ExecutionEngine/Interpreter/Execution.cpp:1.121.2.1 --- llvm/lib/ExecutionEngine/Interpreter/Execution.cpp:1.121 Wed Jan 14 00:02:53 2004 +++ llvm/lib/ExecutionEngine/Interpreter/Execution.cpp Mon Mar 1 17:58:13 2004 @@ -523,6 +523,10 @@ //===----------------------------------------------------------------------===// void Interpreter::exitCalled(GenericValue GV) { + // runAtExitHandlers() assumes there are no stack frames, but + // if exit() was called, then it had a stack frame. Blow away + // the stack before interpreting atexit handlers. + ECStack.clear (); runAtExitHandlers (); exit (GV.IntVal); } @@ -589,8 +593,7 @@ InvokingSF.Caller = CallSite (); // Go to exceptional destination BB of invoke instruction - SwitchToNewBasicBlock (cast (Inst)->getExceptionalDest (), - InvokingSF); + SwitchToNewBasicBlock(cast(Inst)->getUnwindDest(), InvokingSF); } void Interpreter::visitBranchInst(BranchInst &I) { @@ -771,9 +774,13 @@ switch (F->getIntrinsicID()) { case Intrinsic::not_intrinsic: break; - case Intrinsic::va_start: // va_start: implemented by getFirstVarArg() - SetValue(CS.getInstruction(), getFirstVarArg(), SF); + case Intrinsic::va_start: { // va_start + GenericValue ArgIndex; + ArgIndex.UIntPairVal.first = ECStack.size() - 1; + ArgIndex.UIntPairVal.second = 0; + SetValue(CS.getInstruction(), ArgIndex, SF); return; + } case Intrinsic::va_end: // va_end is a noop for the interpreter return; case Intrinsic::va_copy: // va_copy: dest = src @@ -957,14 +964,12 @@ void Interpreter::visitVANextInst(VANextInst &I) { ExecutionContext &SF = ECStack.back(); - // Get the incoming valist parameter. LLI treats the valist as a pointer - // to the next argument. + // Get the incoming valist parameter. LLI treats the valist as a + // (ec-stack-depth var-arg-index) pair. GenericValue VAList = getOperandValue(I.getOperand(0), SF); // Move the pointer to the next vararg. - GenericValue *ArgPtr = (GenericValue *) GVTOP (VAList); - ++ArgPtr; - VAList = PTOGV (ArgPtr); + ++VAList.UIntPairVal.second; SetValue(&I, VAList, SF); } @@ -974,11 +979,12 @@ void Interpreter::visitVAArgInst(VAArgInst &I) { ExecutionContext &SF = ECStack.back(); - // Get the incoming valist parameter. LLI treats the valist as a pointer - // to the next argument. + // Get the incoming valist parameter. LLI treats the valist as a + // (ec-stack-depth var-arg-index) pair. GenericValue VAList = getOperandValue(I.getOperand(0), SF); - assert (GVTOP (VAList) != 0 && "VAList was null in vaarg instruction"); - GenericValue Dest, Src = *(GenericValue *) GVTOP (VAList); + GenericValue Dest; + GenericValue Src = ECStack[VAList.UIntPairVal.first] + .VarArgs[VAList.UIntPairVal.second]; const Type *Ty = I.getType(); switch (Ty->getPrimitiveID()) { IMPLEMENT_VAARG(UByte); Index: llvm/lib/ExecutionEngine/Interpreter/Interpreter.cpp diff -u llvm/lib/ExecutionEngine/Interpreter/Interpreter.cpp:1.20 llvm/lib/ExecutionEngine/Interpreter/Interpreter.cpp:1.20.2.1 --- llvm/lib/ExecutionEngine/Interpreter/Interpreter.cpp:1.20 Sun Dec 28 03:44:37 2003 +++ llvm/lib/ExecutionEngine/Interpreter/Interpreter.cpp Mon Mar 1 17:58:13 2004 @@ -89,9 +89,9 @@ // take into account gratuitous differences in declared types, // though. std::vector ActualArgs; - const unsigned ArgCount = F->getFunctionType()->getParamTypes().size(); + const unsigned ArgCount = F->getFunctionType()->getNumParams(); for (unsigned i = 0; i < ArgCount; ++i) - ActualArgs.push_back (ArgValues[i]); + ActualArgs.push_back(ArgValues[i]); // Set up the function call. callFunction(F, ActualArgs); Index: llvm/lib/ExecutionEngine/Interpreter/Interpreter.h diff -u llvm/lib/ExecutionEngine/Interpreter/Interpreter.h:1.59 llvm/lib/ExecutionEngine/Interpreter/Interpreter.h:1.59.2.1 --- llvm/lib/ExecutionEngine/Interpreter/Interpreter.h:1.59 Sun Dec 28 03:44:37 2003 +++ llvm/lib/ExecutionEngine/Interpreter/Interpreter.h Mon Mar 1 17:58:13 2004 @@ -24,7 +24,7 @@ namespace llvm { -struct FunctionInfo; // Defined in ExecutionAnnotations.h +struct FunctionInfo; class gep_type_iterator; class ConstantExpr; @@ -159,7 +159,7 @@ } GenericValue *getFirstVarArg () { - return &(ECStack[ECStack.size () - 2].VarArgs[0]); + return &(ECStack.back ().VarArgs[0]); } //FIXME: private: From brukman at cs.uiuc.edu Mon Mar 1 18:02:21 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Mar 1 18:02:21 2004 Subject: [llvm-commits] [parallel] CVS: llvm/lib/AsmParser/Lexer.l llvmAsmParser.y Message-ID: <200403012358.RAA03674@zion.cs.uiuc.edu> Changes in directory llvm/lib/AsmParser: Lexer.l updated: 1.44.4.1 -> 1.44.4.2 llvmAsmParser.y updated: 1.148.2.1 -> 1.148.2.2 --- Log message: Merge from trunk --- Diffs of the changes: (+94 -53) Index: llvm/lib/AsmParser/Lexer.l diff -u llvm/lib/AsmParser/Lexer.l:1.44.4.1 llvm/lib/AsmParser/Lexer.l:1.44.4.2 --- llvm/lib/AsmParser/Lexer.l:1.44.4.1 Thu Jan 29 19:25:55 2004 +++ llvm/lib/AsmParser/Lexer.l Mon Mar 1 17:58:12 2004 @@ -191,7 +191,7 @@ \.\.\. { return DOTDOTDOT; } null { return NULL_TOK; } to { return TO; } -except { return EXCEPT; } +except { RET_TOK(TermOpVal, Unwind, UNWIND); } not { return NOT; } /* Deprecated, turned into XOR */ target { return TARGET; } endian { return ENDIAN; } Index: llvm/lib/AsmParser/llvmAsmParser.y diff -u llvm/lib/AsmParser/llvmAsmParser.y:1.148.2.1 llvm/lib/AsmParser/llvmAsmParser.y:1.148.2.2 --- llvm/lib/AsmParser/llvmAsmParser.y:1.148.2.1 Thu Jan 29 19:25:55 2004 +++ llvm/lib/AsmParser/llvmAsmParser.y Mon Mar 1 17:58:12 2004 @@ -20,7 +20,6 @@ #include "llvm/iOperators.h" #include "llvm/iPHINode.h" #include "Support/STLExtras.h" -#include "Support/DepthFirstIterator.h" #include #include #include @@ -58,14 +57,14 @@ // destroyed when the function is completed. // typedef std::vector ValueList; // Numbered defs -static void ResolveDefinitions(std::vector &LateResolvers, - std::vector *FutureLateResolvers = 0); +static void ResolveDefinitions(std::map &LateResolvers, + std::map *FutureLateResolvers = 0); static struct PerModuleInfo { Module *CurrentModule; - std::vector Values; // Module level numbered definitions - std::vector LateResolveValues; - std::vector Types; + std::map Values; // Module level numbered definitions + std::map LateResolveValues; + std::vector Types; std::map LateResolveTypes; // GlobalRefs - This maintains a mapping between 's and forward @@ -143,8 +142,8 @@ static struct PerFunctionInfo { Function *CurrentFunction; // Pointer to current function being created - std::vector Values; // Keep track of numbered definitions - std::vector LateResolveValues; + std::map Values; // Keep track of numbered definitions + std::map LateResolveValues; std::vector Types; std::map LateResolveTypes; SymbolTable LocalSymtab; @@ -171,11 +170,11 @@ FID = ValID::create((char*)CurrentFunction->getName().c_str()); } else { unsigned Slot = CurrentFunction->getType()->getUniqueID(); - assert(CurModule.Values.size() > Slot && "Function not inserted?"); // Figure out which slot number if is... + ValueList &List = CurModule.Values[Slot]; for (unsigned i = 0; ; ++i) { - assert(i < CurModule.Values[Slot].size() && "Function not found!"); - if (CurModule.Values[Slot][i] == CurrentFunction) { + assert(i < List.size() && "Function not found!"); + if (List[i] == CurrentFunction) { FID = ValID::create((int)i); break; } @@ -199,16 +198,15 @@ //===----------------------------------------------------------------------===// static int InsertValue(Value *D, - std::vector &ValueTab = CurFun.Values) { + std::map &ValueTab = CurFun.Values) { if (D->hasName()) return -1; // Is this a numbered definition? // Yes, insert the value into the value table... unsigned type = D->getType()->getUniqueID(); - if (ValueTab.size() <= type) - ValueTab.resize(type+1, ValueList()); //printf("Values[%d][%d] = %d\n", type, ValueTab[type].size(), D); - ValueTab[type].push_back(D); - return ValueTab[type].size()-1; + ValueList &List = ValueTab[type]; + List.push_back(D); + return List.size()-1; } // TODO: FIXME when Type are not const @@ -298,20 +296,21 @@ unsigned Num = (unsigned)D.Num; // Module constants occupy the lowest numbered slots... - if (type < CurModule.Values.size()) { - if (Num < CurModule.Values[type].size()) - return CurModule.Values[type][Num]; - - Num -= CurModule.Values[type].size(); + std::map::iterator VI = CurModule.Values.find(type); + if (VI != CurModule.Values.end()) { + if (Num < VI->second.size()) + return VI->second[Num]; + Num -= VI->second.size(); } // Make sure that our type is within bounds - if (CurFun.Values.size() <= type) return 0; + VI = CurFun.Values.find(type); + if (VI == CurFun.Values.end()) return 0; // Check that the number is within bounds... - if (CurFun.Values[type].size() <= Num) return 0; + if (VI->second.size() <= Num) return 0; - return CurFun.Values[type][Num]; + return VI->second[Num]; } case ValID::NameVal: { // Is it a named definition? @@ -416,18 +415,20 @@ // time (forward branches, phi functions for loops, etc...) resolve the // defs now... // -static void ResolveDefinitions(std::vector &LateResolvers, - std::vector *FutureLateResolvers) { +static void ResolveDefinitions(std::map &LateResolvers, + std::map *FutureLateResolvers) { // Loop over LateResolveDefs fixing up stuff that couldn't be resolved - for (unsigned ty = 0; ty < LateResolvers.size(); ty++) { - while (!LateResolvers[ty].empty()) { - Value *V = LateResolvers[ty].back(); + for (std::map::iterator LRI = LateResolvers.begin(), + E = LateResolvers.end(); LRI != E; ++LRI) { + ValueList &List = LRI->second; + while (!List.empty()) { + Value *V = List.back(); + List.pop_back(); assert(!isa(V) && "Types should be in LateResolveTypes!"); - - LateResolvers[ty].pop_back(); ValID &DID = getValIDFromPlaceHolder(V); - Value *TheRealValue = getValNonImprovising(Type::getUniqueIDType(ty),DID); + Value *TheRealValue = + getValNonImprovising(Type::getUniqueIDType(LRI->first), DID); if (TheRealValue) { V->replaceAllUsesWith(TheRealValue); delete V; @@ -586,14 +587,33 @@ // Code for handling upreferences in type names... // -// TypeContains - Returns true if Ty contains E in it. +// TypeContains - Returns true if Ty directly contains E in it. // static bool TypeContains(const Type *Ty, const Type *E) { - return find(df_begin(Ty), df_end(Ty), E) != df_end(Ty); + return find(Ty->subtype_begin(), Ty->subtype_end(), E) != Ty->subtype_end(); +} + +namespace { + struct UpRefRecord { + // NestingLevel - The number of nesting levels that need to be popped before + // this type is resolved. + unsigned NestingLevel; + + // LastContainedTy - This is the type at the current binding level for the + // type. Every time we reduce the nesting level, this gets updated. + const Type *LastContainedTy; + + // UpRefTy - This is the actual opaque type that the upreference is + // represented with. + OpaqueType *UpRefTy; + + UpRefRecord(unsigned NL, OpaqueType *URTy) + : NestingLevel(NL), LastContainedTy(URTy), UpRefTy(URTy) {} + }; } // UpRefs - A list of the outstanding upreferences that need to be resolved. -static std::vector > UpRefs; +static std::vector UpRefs; /// HandleUpRefs - Every time we finish a new layer of types, this function is /// called. It loops through the UpRefs vector, which is a list of the @@ -603,30 +623,51 @@ /// thus we can complete the cycle. /// static PATypeHolder HandleUpRefs(const Type *ty) { + if (!ty->isAbstract()) return ty; PATypeHolder Ty(ty); UR_OUT("Type '" << Ty->getDescription() << "' newly formed. Resolving upreferences.\n" << UpRefs.size() << " upreferences active!\n"); + + // If we find any resolvable upreferences (i.e., those whose NestingLevel goes + // to zero), we resolve them all together before we resolve them to Ty. At + // the end of the loop, if there is anything to resolve to Ty, it will be in + // this variable. + OpaqueType *TypeToResolve = 0; + for (unsigned i = 0; i != UpRefs.size(); ++i) { UR_OUT(" UR#" << i << " - TypeContains(" << Ty->getDescription() << ", " << UpRefs[i].second->getDescription() << ") = " << (TypeContains(Ty, UpRefs[i].second) ? "true" : "false") << "\n"); - if (TypeContains(Ty, UpRefs[i].second)) { - unsigned Level = --UpRefs[i].first; // Decrement level of upreference + if (TypeContains(Ty, UpRefs[i].LastContainedTy)) { + // Decrement level of upreference + unsigned Level = --UpRefs[i].NestingLevel; + UpRefs[i].LastContainedTy = Ty; UR_OUT(" Uplevel Ref Level = " << Level << "\n"); if (Level == 0) { // Upreference should be resolved! - UR_OUT(" * Resolving upreference for " - << UpRefs[i].second->getDescription() << "\n"; - std::string OldName = UpRefs[i].second->getDescription()); - UpRefs[i].second->refineAbstractTypeTo(Ty); - UR_OUT(" * Type '" << OldName << "' refined upreference to: " - << (const void*)Ty << ", " << Ty->getDescription() << "\n"); + if (!TypeToResolve) { + TypeToResolve = UpRefs[i].UpRefTy; + } else { + UR_OUT(" * Resolving upreference for " + << UpRefs[i].second->getDescription() << "\n"; + std::string OldName = UpRefs[i].UpRefTy->getDescription()); + UpRefs[i].UpRefTy->refineAbstractTypeTo(TypeToResolve); + UR_OUT(" * Type '" << OldName << "' refined upreference to: " + << (const void*)Ty << ", " << Ty->getDescription() << "\n"); + } UpRefs.erase(UpRefs.begin()+i); // Remove from upreference list... --i; // Do not skip the next element... } } } + if (TypeToResolve) { + UR_OUT(" * Resolving upreference for " + << UpRefs[i].second->getDescription() << "\n"; + std::string OldName = TypeToResolve->getDescription()); + TypeToResolve->refineAbstractTypeTo(Ty); + } + return Ty; } @@ -816,7 +857,7 @@ %token IMPLEMENTATION ZEROINITIALIZER TRUE FALSE BEGINTOK ENDTOK %token DECLARE GLOBAL CONSTANT VOLATILE -%token TO EXCEPT DOTDOTDOT NULL_TOK CONST INTERNAL LINKONCE WEAK APPENDING +%token TO DOTDOTDOT NULL_TOK CONST INTERNAL LINKONCE WEAK APPENDING %token OPAQUE NOT EXTERNAL TARGET ENDIAN POINTERSIZE LITTLE BIG // Basic Block Terminating Operators @@ -923,7 +964,7 @@ UpRTypes : '\\' EUINT64VAL { // Type UpReference if ($2 > (uint64_t)~0U) ThrowException("Value out of range!"); OpaqueType *OT = OpaqueType::get(); // Use temporary placeholder - UpRefs.push_back(std::make_pair((unsigned)$2, OT)); // Add to vector... + UpRefs.push_back(UpRefRecord((unsigned)$2, OT)); // Add to vector... $$ = new PATypeHolder(OT); UR_OUT("New Upreference!\n"); } @@ -1064,9 +1105,9 @@ // Check to ensure that constants are compatible with the type initializer! for (unsigned i = 0, e = $3->size(); i != e; ++i) - if ((*$3)[i]->getType() != STy->getElementTypes()[i]) + if ((*$3)[i]->getType() != STy->getElementType(i)) ThrowException("Expected type '" + - STy->getElementTypes()[i]->getDescription() + + STy->getElementType(i)->getDescription() + "' for element #" + utostr(i) + " of structure initializer!"); @@ -1615,7 +1656,7 @@ $$ = S; } | INVOKE TypesV ValueRef '(' ValueRefListE ')' TO ResolvedVal - EXCEPT ResolvedVal { + UNWIND ResolvedVal { const PointerType *PFTy; const FunctionType *Ty; @@ -1651,8 +1692,8 @@ // Loop through FunctionType's arguments and ensure they are specified // correctly! // - FunctionType::ParamTypes::const_iterator I = Ty->getParamTypes().begin(); - FunctionType::ParamTypes::const_iterator E = Ty->getParamTypes().end(); + FunctionType::param_iterator I = Ty->param_begin(); + FunctionType::param_iterator E = Ty->param_end(); std::vector::iterator ArgI = $5->begin(), ArgE = $5->end(); for (; ArgI != ArgE && I != E; ++ArgI, ++I) @@ -1852,8 +1893,8 @@ // Loop through FunctionType's arguments and ensure they are specified // correctly! // - FunctionType::ParamTypes::const_iterator I = Ty->getParamTypes().begin(); - FunctionType::ParamTypes::const_iterator E = Ty->getParamTypes().end(); + FunctionType::param_iterator I = Ty->param_begin(); + FunctionType::param_iterator E = Ty->param_end(); std::vector::iterator ArgI = $5->begin(), ArgE = $5->end(); for (; ArgI != ArgE && I != E; ++ArgI, ++I) From brukman at cs.uiuc.edu Mon Mar 1 18:02:27 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Mar 1 18:02:27 2004 Subject: [llvm-commits] [parallel] CVS: llvm/lib/ExecutionEngine/ExecutionEngine.cpp Message-ID: <200403012358.RAA03630@zion.cs.uiuc.edu> Changes in directory llvm/lib/ExecutionEngine: ExecutionEngine.cpp updated: 1.45 -> 1.45.2.1 --- Log message: Merge from trunk --- Diffs of the changes: (+17 -8) Index: llvm/lib/ExecutionEngine/ExecutionEngine.cpp diff -u llvm/lib/ExecutionEngine/ExecutionEngine.cpp:1.45 llvm/lib/ExecutionEngine/ExecutionEngine.cpp:1.45.2.1 --- llvm/lib/ExecutionEngine/ExecutionEngine.cpp:1.45 Wed Dec 31 14:21:04 2003 +++ llvm/lib/ExecutionEngine/ExecutionEngine.cpp Mon Mar 1 17:58:13 2004 @@ -130,11 +130,17 @@ EE = JIT::create(MP, IL); // If we can't make a JIT, make an interpreter instead. - try { - if (EE == 0) - EE = Interpreter::create(MP->materializeModule(), IL); - } catch (...) { - EE = 0; + if (EE == 0) { + try { + Module *M = MP->materializeModule(); + try { + EE = Interpreter::create(M, IL); + } catch (...) { + std::cerr << "Error creating the interpreter!\n"; + } + } catch (...) { + std::cerr << "Error reading the bytecode file!\n"; + } } if (EE == 0) delete IL; @@ -400,6 +406,10 @@ GenericValue Val = getConstantValue(Init); StoreValueToMemory(Val, (GenericValue*)Addr, Init->getType()); return; + } else if (isa(Init)) { + unsigned Size = getTargetData().getTypeSize(Init->getType()); + memset(Addr, 0, Size); + return; } switch (Init->getType()->getPrimitiveID()) { @@ -448,9 +458,6 @@ // Allocate some memory for it! unsigned Size = TD.getTypeSize(Ty); addGlobalMapping(I, new char[Size]); - - DEBUG(std::cerr << "Global '" << I->getName() << "' -> " - << getPointerToGlobal(I) << "\n"); } else { // External variable reference. Try to use the dynamic loader to // get a pointer to it. @@ -476,6 +483,8 @@ // already in the map. void ExecutionEngine::EmitGlobalVariable(const GlobalVariable *GV) { void *GA = getPointerToGlobalIfAvailable(GV); + DEBUG(std::cerr << "Global '" << GV->getName() << "' -> " << GA << "\n"); + const Type *ElTy = GV->getType()->getElementType(); if (GA == 0) { // If it's not already specified, allocate memory for the global. From brukman at cs.uiuc.edu Mon Mar 1 18:02:33 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Mar 1 18:02:33 2004 Subject: [llvm-commits] [parallel] CVS: llvm/lib/Makefile Message-ID: <200403012358.RAA03685@zion.cs.uiuc.edu> Changes in directory llvm/lib: Makefile updated: 1.17 -> 1.17.2.1 --- Log message: Merge from trunk --- Diffs of the changes: (+1 -1) Index: llvm/lib/Makefile diff -u llvm/lib/Makefile:1.17 llvm/lib/Makefile:1.17.2.1 --- llvm/lib/Makefile:1.17 Sun Jan 4 23:25:59 2004 +++ llvm/lib/Makefile Mon Mar 1 17:58:12 2004 @@ -8,7 +8,7 @@ ##===----------------------------------------------------------------------===## LEVEL = .. -PARALLEL_DIRS = VMCore Analysis Transforms AsmParser Bytecode CodeGen Target CWriter ExecutionEngine Debugger +PARALLEL_DIRS = VMCore Analysis Transforms AsmParser Bytecode CodeGen Target ExecutionEngine Debugger include $(LEVEL)/Makefile.common From brukman at cs.uiuc.edu Mon Mar 1 18:02:39 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Mar 1 18:02:39 2004 Subject: [llvm-commits] [parallel] CVS: llvm/lib/Target/SparcV9/LiveVar/FunctionLiveVarInfo.h BBLiveVar.cpp BBLiveVar.h FunctionLiveVarInfo.cpp Makefile Message-ID: <200403012358.RAA03833@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/SparcV9/LiveVar: FunctionLiveVarInfo.h added (r1.1.2.1) BBLiveVar.cpp updated: 1.41 -> 1.41.2.1 BBLiveVar.h updated: 1.25 -> 1.25.4.1 FunctionLiveVarInfo.cpp updated: 1.51 -> 1.51.2.1 Makefile updated: 1.4 -> 1.4.2.1 --- Log message: Merge from trunk --- Diffs of the changes: (+128 -15) Index: llvm/lib/Target/SparcV9/LiveVar/FunctionLiveVarInfo.h diff -c /dev/null llvm/lib/Target/SparcV9/LiveVar/FunctionLiveVarInfo.h:1.1.2.1 *** /dev/null Mon Mar 1 17:58:27 2004 --- llvm/lib/Target/SparcV9/LiveVar/FunctionLiveVarInfo.h Mon Mar 1 17:58:15 2004 *************** *** 0 **** --- 1,111 ---- + //===-- CodeGen/FunctionLiveVarInfo.h - LiveVar Analysis --------*- C++ -*-===// + // + // The LLVM Compiler Infrastructure + // + // This file was developed by the LLVM research group and is distributed under + // the University of Illinois Open Source License. See LICENSE.TXT for details. + // + //===----------------------------------------------------------------------===// + // + // This is the interface for live variable info of a function that is required + // by any other part of the compiler + // + // After the analysis, getInSetOfBB or getOutSetofBB can be called to get + // live var info of a BB. + // + // The live var set before an instruction can be obtained in 2 ways: + // + // 1. Use the method getLiveVarSetAfterInst(Instruction *) to get the LV Info + // just after an instruction. (also exists getLiveVarSetBeforeInst(..)) + // + // This function caluclates the LV info for a BB only once and caches that + // info. If the cache does not contain the LV info of the instruction, it + // calculates the LV info for the whole BB and caches them. + // + // Getting liveVar info this way uses more memory since, LV info should be + // cached. However, if you need LV info of nearly all the instructions of a + // BB, this is the best and simplest interfrace. + // + // 2. Use the OutSet and applyTranferFuncForInst(const Instruction *const Inst) + // declared in LiveVarSet and traverse the instructions of a basic block in + // reverse (using const_reverse_iterator in the BB class). + // + //===----------------------------------------------------------------------===// + + #ifndef FUNCTION_LIVE_VAR_INFO_H + #define FUNCTION_LIVE_VAR_INFO_H + + #include "Support/hash_map" + #include "llvm/Pass.h" + #include "llvm/CodeGen/ValueSet.h" + + namespace llvm { + + class BBLiveVar; + class MachineInstr; + + class FunctionLiveVarInfo : public FunctionPass { + // Machine Instr to LiveVarSet Map for providing LVset BEFORE each inst + // These sets are owned by this map and will be freed in releaseMemory(). + hash_map MInst2LVSetBI; + + // Machine Instr to LiveVarSet Map for providing LVset AFTER each inst. + // These sets are just pointers to sets in MInst2LVSetBI or BBLiveVar. + hash_map MInst2LVSetAI; + + hash_map BBLiveVarInfo; + + // Stored Function that the data is computed with respect to + const Function *M; + + // --------- private methods ----------------------------------------- + + // constructs BBLiveVars and init Def and In sets + void constructBBs(const Function *F); + + // do one backward pass over the CFG + bool doSingleBackwardPass(const Function *F, unsigned int iter); + + // calculates live var sets for instructions in a BB + void calcLiveVarSetsForBB(const BasicBlock *BB); + + public: + // --------- Implement the FunctionPass interface ---------------------- + + // runOnFunction - Perform analysis, update internal data structures. + virtual bool runOnFunction(Function &F); + + // releaseMemory - After LiveVariable analysis has been used, forget! + virtual void releaseMemory(); + + // getAnalysisUsage - Provide self! + virtual void getAnalysisUsage(AnalysisUsage &AU) const { + AU.setPreservesAll(); + } + + // --------- Functions to access analysis results ------------------- + + // get OutSet of a BB + const ValueSet &getOutSetOfBB(const BasicBlock *BB) const; + ValueSet &getOutSetOfBB(const BasicBlock *BB) ; + + // get InSet of a BB + const ValueSet &getInSetOfBB(const BasicBlock *BB) const; + ValueSet &getInSetOfBB(const BasicBlock *BB) ; + + // gets the Live var set BEFORE an instruction. + // if BB is specified and the live var set has not yet been computed, + // it will be computed on demand. + const ValueSet &getLiveVarSetBeforeMInst(const MachineInstr *MI, + const BasicBlock *BB = 0); + + // gets the Live var set AFTER an instruction + // if BB is specified and the live var set has not yet been computed, + // it will be computed on demand. + const ValueSet &getLiveVarSetAfterMInst(const MachineInstr *MI, + const BasicBlock *BB = 0); + }; + + } // End llvm namespace + + #endif Index: llvm/lib/Target/SparcV9/LiveVar/BBLiveVar.cpp diff -u llvm/lib/Target/SparcV9/LiveVar/BBLiveVar.cpp:1.41 llvm/lib/Target/SparcV9/LiveVar/BBLiveVar.cpp:1.41.2.1 --- llvm/lib/Target/SparcV9/LiveVar/BBLiveVar.cpp:1.41 Fri Jan 9 12:15:24 2004 +++ llvm/lib/Target/SparcV9/LiveVar/BBLiveVar.cpp Mon Mar 1 17:58:15 2004 @@ -12,16 +12,18 @@ //===----------------------------------------------------------------------===// #include "BBLiveVar.h" -#include "llvm/CodeGen/FunctionLiveVarInfo.h" +#include "FunctionLiveVarInfo.h" #include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/MachineBasicBlock.h" #include "llvm/Support/CFG.h" #include "Support/SetOperations.h" -#include "../SparcInternals.h" +#include "../SparcV9Internals.h" namespace llvm { -BBLiveVar::BBLiveVar(const BasicBlock &bb, MachineBasicBlock &mbb, unsigned id) +BBLiveVar::BBLiveVar(const BasicBlock &bb, + const MachineBasicBlock &mbb, + unsigned id) : BB(bb), MBB(mbb), POID(id) { InSetChanged = OutSetChanged = false; @@ -39,7 +41,7 @@ // iterate over all the machine instructions in BB for (MachineBasicBlock::const_reverse_iterator MII = MBB.rbegin(), MIE = MBB.rend(); MII != MIE; ++MII) { - const MachineInstr *MI = *MII; + const MachineInstr *MI = &*MII; if (DEBUG_LV >= LV_DEBUG_Verbose) { std::cerr << " *Iterating over machine instr "; @@ -76,7 +78,7 @@ // Put Phi operands in UseSet for the incoming edge, not node. // They must not "hide" later defs, and must be handled specially // during set propagation over the CFG. - if (MI->getOpCode() == V9::PHI) { // for a phi node + if (MI->getOpcode() == V9::PHI) { // for a phi node const Value *ArgVal = Op; const BasicBlock *PredBB = cast(*++OpI); // next ptr is BB @@ -95,7 +97,7 @@ // do for implicit operands as well for (unsigned i = 0; i < MI->getNumImplicitRefs(); ++i) { - assert(MI->getOpCode() != V9::PHI && "Phi cannot have implicit operands"); + assert(MI->getOpcode() != V9::PHI && "Phi cannot have implicit operands"); const Value *Op = MI->getImplicitRef(i); if (Op->getType() == Type::LabelTy) // don't process labels Index: llvm/lib/Target/SparcV9/LiveVar/BBLiveVar.h diff -u llvm/lib/Target/SparcV9/LiveVar/BBLiveVar.h:1.25 llvm/lib/Target/SparcV9/LiveVar/BBLiveVar.h:1.25.4.1 --- llvm/lib/Target/SparcV9/LiveVar/BBLiveVar.h:1.25 Tue Nov 11 16:41:32 2003 +++ llvm/lib/Target/SparcV9/LiveVar/BBLiveVar.h Mon Mar 1 17:58:15 2004 @@ -35,7 +35,7 @@ class BBLiveVar { const BasicBlock &BB; // pointer to BasicBlock - MachineBasicBlock &MBB; // Pointer to MachineBasicBlock + const MachineBasicBlock &MBB; // Pointer to MachineBasicBlock unsigned POID; // Post-Order ID ValueSet DefSet; // Def set (with no preceding uses) for LV analysis @@ -61,12 +61,12 @@ void calcDefUseSets(); // calculates the Def & Use sets for this BB public: - BBLiveVar(const BasicBlock &BB, MachineBasicBlock &MBB, unsigned POID); + BBLiveVar(const BasicBlock &BB, const MachineBasicBlock &MBB, unsigned POID); inline bool isInSetChanged() const { return InSetChanged; } inline bool isOutSetChanged() const { return OutSetChanged; } - MachineBasicBlock &getMachineBasicBlock() const { return MBB; } + const MachineBasicBlock &getMachineBasicBlock() const { return MBB; } inline unsigned getPOId() const { return POID; } Index: llvm/lib/Target/SparcV9/LiveVar/FunctionLiveVarInfo.cpp diff -u llvm/lib/Target/SparcV9/LiveVar/FunctionLiveVarInfo.cpp:1.51 llvm/lib/Target/SparcV9/LiveVar/FunctionLiveVarInfo.cpp:1.51.2.1 --- llvm/lib/Target/SparcV9/LiveVar/FunctionLiveVarInfo.cpp:1.51 Sun Dec 14 07:24:17 2003 +++ llvm/lib/Target/SparcV9/LiveVar/FunctionLiveVarInfo.cpp Mon Mar 1 17:58:15 2004 @@ -12,7 +12,7 @@ // //===----------------------------------------------------------------------===// -#include "llvm/CodeGen/FunctionLiveVarInfo.h" +#include "FunctionLiveVarInfo.h" #include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/Target/TargetMachine.h" @@ -283,7 +283,7 @@ for (MachineBasicBlock::const_reverse_iterator MII = MIVec.rbegin(), MIE = MIVec.rend(); MII != MIE; ++MII) { // MI is cur machine inst - const MachineInstr *MI = *MII; + const MachineInstr *MI = &*MII; MInst2LVSetAI[MI] = SetAI; // record in After Inst map @@ -295,12 +295,12 @@ // If the current machine instruction has delay slots, mark values // used by this instruction as live before and after each delay slot // instruction (After(MI) is the same as Before(MI+1) except for last MI). - if (unsigned DS = TM.getInstrInfo().getNumDelaySlots(MI->getOpCode())) { + if (unsigned DS = TM.getInstrInfo().getNumDelaySlots(MI->getOpcode())) { MachineBasicBlock::const_iterator fwdMII = MII.base(); // ptr to *next* MI for (unsigned i = 0; i < DS; ++i, ++fwdMII) { assert(fwdMII != MIVec.end() && "Missing instruction in delay slot?"); - MachineInstr* DelaySlotMI = *fwdMII; - if (! TM.getInstrInfo().isNop(DelaySlotMI->getOpCode())) { + const MachineInstr* DelaySlotMI = fwdMII; + if (! TM.getInstrInfo().isNop(DelaySlotMI->getOpcode())) { set_union(*MInst2LVSetBI[DelaySlotMI], *NewSet); if (i+1 == DS) set_union(*MInst2LVSetAI[DelaySlotMI], *NewSet); Index: llvm/lib/Target/SparcV9/LiveVar/Makefile diff -u llvm/lib/Target/SparcV9/LiveVar/Makefile:1.4 llvm/lib/Target/SparcV9/LiveVar/Makefile:1.4.2.1 --- llvm/lib/Target/SparcV9/LiveVar/Makefile:1.4 Fri Jan 9 12:15:24 2004 +++ llvm/lib/Target/SparcV9/LiveVar/Makefile Mon Mar 1 17:58:15 2004 @@ -8,7 +8,7 @@ ##===----------------------------------------------------------------------===## LEVEL = ../../../.. -LIBRARYNAME = livevar +LIBRARYNAME = sparcv9livevar include $(LEVEL)/Makefile.common From brukman at cs.uiuc.edu Mon Mar 1 18:02:46 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Mar 1 18:02:46 2004 Subject: [llvm-commits] [parallel] CVS: llvm/lib/Transforms/Instrumentation/BlockProfiling.cpp EmitFunctions.cpp Message-ID: <200403012358.RAA03786@zion.cs.uiuc.edu> Changes in directory llvm/lib/Transforms/Instrumentation: BlockProfiling.cpp updated: 1.5 -> 1.5.2.1 EmitFunctions.cpp updated: 1.14 -> 1.14.4.1 --- Log message: Merge from trunk --- Diffs of the changes: (+26 -19) Index: llvm/lib/Transforms/Instrumentation/BlockProfiling.cpp diff -u llvm/lib/Transforms/Instrumentation/BlockProfiling.cpp:1.5 llvm/lib/Transforms/Instrumentation/BlockProfiling.cpp:1.5.2.1 --- llvm/lib/Transforms/Instrumentation/BlockProfiling.cpp:1.5 Fri Jan 9 00:11:48 2004 +++ llvm/lib/Transforms/Instrumentation/BlockProfiling.cpp Mon Mar 1 17:58:16 2004 @@ -31,7 +31,7 @@ const Type *ArgVTy = PointerType::get(PointerType::get(Type::SByteTy)); const Type *UIntPtr = PointerType::get(Type::UIntTy); Module &M = *MainFn->getParent(); - Function *InitFn = M.getOrInsertFunction(FnName, Type::VoidTy, Type::IntTy, + Function *InitFn = M.getOrInsertFunction(FnName, Type::IntTy, Type::IntTy, ArgVTy, UIntPtr, Type::UIntTy, 0); // This could force argc and argv into programs that wouldn't otherwise have @@ -45,38 +45,45 @@ BasicBlock::iterator InsertPos = Entry->begin(); while (isa(InsertPos)) ++InsertPos; + ConstantPointerRef *ArrayCPR = ConstantPointerRef::get(Array); + std::vector GEPIndices(2, Constant::getNullValue(Type::LongTy)); + Args[2] = ConstantExpr::getGetElementPtr(ArrayCPR, GEPIndices); + + unsigned NumElements = + cast(Array->getType()->getElementType())->getNumElements(); + Args[3] = ConstantUInt::get(Type::UIntTy, NumElements); + + Instruction *InitCall = new CallInst(InitFn, Args, "newargc", InsertPos); + + // If argc or argv are not available in main, just pass null values in. Function::aiterator AI; switch (MainFn->asize()) { default: case 2: AI = MainFn->abegin(); ++AI; if (AI->getType() != ArgVTy) { - Args[1] = new CastInst(AI, ArgVTy, "argv.cast", InsertPos); + InitCall->setOperand(2, new CastInst(AI, ArgVTy, "argv.cast", InitCall)); } else { - Args[1] = AI; + InitCall->setOperand(2, AI); } case 1: AI = MainFn->abegin(); + // If the program looked at argc, have it look at the return value of the + // init call instead. if (AI->getType() != Type::IntTy) { - Args[0] = new CastInst(AI, Type::IntTy, "argc.cast", InsertPos); + if (!AI->use_empty()) + AI->replaceAllUsesWith(new CastInst(InitCall, AI->getType(), "", + InsertPos)); + InitCall->setOperand(1, new CastInst(AI, Type::IntTy, "argc.cast", + InitCall)); } else { - Args[0] = AI; + AI->replaceAllUsesWith(InitCall); + InitCall->setOperand(1, AI); } - case 0: - break; + case 0: break; } - - ConstantPointerRef *ArrayCPR = ConstantPointerRef::get(Array); - std::vector GEPIndices(2, Constant::getNullValue(Type::LongTy)); - Args[2] = ConstantExpr::getGetElementPtr(ArrayCPR, GEPIndices); - - unsigned NumElements = - cast(Array->getType()->getElementType())->getNumElements(); - Args[3] = ConstantUInt::get(Type::UIntTy, NumElements); - - new CallInst(InitFn, Args, "", InsertPos); } static void IncrementCounterInBlock(BasicBlock *BB, unsigned CounterNum, Index: llvm/lib/Transforms/Instrumentation/EmitFunctions.cpp diff -u llvm/lib/Transforms/Instrumentation/EmitFunctions.cpp:1.14 llvm/lib/Transforms/Instrumentation/EmitFunctions.cpp:1.14.4.1 --- llvm/lib/Transforms/Instrumentation/EmitFunctions.cpp:1.14 Tue Nov 11 16:41:33 2003 +++ llvm/lib/Transforms/Instrumentation/EmitFunctions.cpp Mon Mar 1 17:58:16 2004 @@ -82,14 +82,14 @@ } StructType *sttype = StructType::get(vType); - ConstantStruct *cstruct = ConstantStruct::get(sttype, vConsts); + Constant *cstruct = ConstantStruct::get(sttype, vConsts); GlobalVariable *gb = new GlobalVariable(cstruct->getType(), true, GlobalValue::ExternalLinkage, cstruct, "llvmFunctionTable"); M.getGlobalList().push_back(gb); - ConstantArray *constArray = ConstantArray::get(ArrayType::get(Type::SByteTy, + Constant *constArray = ConstantArray::get(ArrayType::get(Type::SByteTy, sBCons.size()), sBCons); From brukman at cs.uiuc.edu Mon Mar 1 18:02:53 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Mar 1 18:02:53 2004 Subject: [llvm-commits] [parallel] CVS: llvm/lib/Transforms/ExprTypeConvert.cpp LevelRaise.cpp TransformInternals.cpp Message-ID: <200403012358.RAA03861@zion.cs.uiuc.edu> Changes in directory llvm/lib/Transforms: ExprTypeConvert.cpp updated: 1.88 -> 1.88.2.1 LevelRaise.cpp updated: 1.93 -> 1.93.2.1 TransformInternals.cpp updated: 1.43 -> 1.43.2.1 --- Log message: Merge from trunk --- Diffs of the changes: (+16 -15) Index: llvm/lib/Transforms/ExprTypeConvert.cpp diff -u llvm/lib/Transforms/ExprTypeConvert.cpp:1.88 llvm/lib/Transforms/ExprTypeConvert.cpp:1.88.2.1 --- llvm/lib/Transforms/ExprTypeConvert.cpp:1.88 Mon Jan 12 12:12:44 2004 +++ llvm/lib/Transforms/ExprTypeConvert.cpp Mon Mar 1 17:58:15 2004 @@ -304,8 +304,7 @@ // const PointerType *PT = cast(I->getOperand(0)->getType()); const FunctionType *FT = cast(PT->getElementType()); - std::vector ArgTys(FT->getParamTypes().begin(), - FT->getParamTypes().end()); + std::vector ArgTys(FT->param_begin(), FT->param_end()); const FunctionType *NewTy = FunctionType::get(Ty, ArgTys, FT->isVarArg()); if (!ExpressionConvertibleToType(I->getOperand(0), @@ -513,8 +512,7 @@ // const PointerType *PT = cast(I->getOperand(0)->getType()); const FunctionType *FT = cast(PT->getElementType()); - std::vector ArgTys(FT->getParamTypes().begin(), - FT->getParamTypes().end()); + std::vector ArgTys(FT->param_begin(), FT->param_end()); const FunctionType *NewTy = FunctionType::get(Ty, ArgTys, FT->isVarArg()); const PointerType *NewPTy = PointerType::get(NewTy); @@ -862,9 +860,8 @@ // reason for this is that we prefer to have resolved functions but casted // arguments if possible. // - const FunctionType::ParamTypes &PTs = FTy->getParamTypes(); - for (unsigned i = 0, NA = PTs.size(); i < NA; ++i) - if (!PTs[i]->isLosslesslyConvertibleTo(I->getOperand(i+1)->getType())) + for (unsigned i = 0, NA = FTy->getNumParams(); i < NA; ++i) + if (!FTy->getParamType(i)->isLosslesslyConvertibleTo(I->getOperand(i+1)->getType())) return false; // Operands must have compatible types! // Okay, at this point, we know that all of the arguments can be @@ -878,7 +875,7 @@ const FunctionType *FTy = cast(MPtr->getElementType()); if (!FTy->isVarArg()) return false; - if ((OpNum-1) < FTy->getParamTypes().size()) + if ((OpNum-1) < FTy->getNumParams()) return false; // It's not in the varargs section... // If we get this far, we know the value is in the varargs section of the @@ -1175,7 +1172,6 @@ if (Meth == OldVal) { // Changing the function pointer? const PointerType *NewPTy = cast(NewVal->getType()); const FunctionType *NewTy = cast(NewPTy->getElementType()); - const FunctionType::ParamTypes &PTs = NewTy->getParamTypes(); if (NewTy->getReturnType() == Type::VoidTy) Name = ""; // Make sure not to name a void call! @@ -1191,12 +1187,13 @@ // Convert over all of the call operands to their new types... but only // convert over the part that is not in the vararg section of the call. // - for (unsigned i = 0; i < PTs.size(); ++i) - if (Params[i]->getType() != PTs[i]) { + for (unsigned i = 0; i != NewTy->getNumParams(); ++i) + if (Params[i]->getType() != NewTy->getParamType(i)) { // Create a cast to convert it to the right type, we know that this // is a lossless cast... // - Params[i] = new CastInst(Params[i], PTs[i], "callarg.cast." + + Params[i] = new CastInst(Params[i], NewTy->getParamType(i), + "callarg.cast." + Params[i]->getName(), It); } Meth = NewVal; // Update call destination to new value Index: llvm/lib/Transforms/LevelRaise.cpp diff -u llvm/lib/Transforms/LevelRaise.cpp:1.93 llvm/lib/Transforms/LevelRaise.cpp:1.93.2.1 --- llvm/lib/Transforms/LevelRaise.cpp:1.93 Mon Jan 12 12:12:44 2004 +++ llvm/lib/Transforms/LevelRaise.cpp Mon Mar 1 17:58:16 2004 @@ -375,12 +375,12 @@ const Type *IdxType; if (const StructType *CurSTy = dyn_cast(CurCTy)) { // Check for a zero element struct type... if we have one, bail. - if (CurSTy->getElementTypes().size() == 0) break; + if (CurSTy->getNumElements() == 0) break; // Grab the first element of the struct type, which must lie at // offset zero in the struct. // - ElTy = CurSTy->getElementTypes()[0]; + ElTy = CurSTy->getElementType(0); IdxType = Type::UByteTy; // FIXME when PR82 is fixed. } else { ElTy = cast(CurCTy)->getElementType(); @@ -538,6 +538,10 @@ else NewCast = new CastInst(CI->getCalledValue(), NewPFunTy, CI->getCalledValue()->getName()+"_c",CI); + + // Strip off unneeded CPR's. + if (ConstantPointerRef *CPR = dyn_cast(NewCast)) + NewCast = CPR->getValue(); // Create a new call instruction... CallInst *NewCall = new CallInst(NewCast, Index: llvm/lib/Transforms/TransformInternals.cpp diff -u llvm/lib/Transforms/TransformInternals.cpp:1.43 llvm/lib/Transforms/TransformInternals.cpp:1.43.2.1 --- llvm/lib/Transforms/TransformInternals.cpp:1.43 Thu Jan 8 23:53:38 2004 +++ llvm/lib/Transforms/TransformInternals.cpp Mon Mar 1 17:58:16 2004 @@ -62,7 +62,7 @@ uint64_t ThisOffset; const Type *NextType; if (const StructType *STy = dyn_cast(Ty)) { - if (STy->getElementTypes().empty()) { + if (STy->getNumElements()) { Offset = 0; return STy; } From brukman at cs.uiuc.edu Mon Mar 1 18:03:00 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Mar 1 18:03:00 2004 Subject: [llvm-commits] [parallel] CVS: llvm/lib/ExecutionEngine/JIT/Emitter.cpp JIT.cpp TargetSelect.cpp Message-ID: <200403012358.RAA03738@zion.cs.uiuc.edu> Changes in directory llvm/lib/ExecutionEngine/JIT: Emitter.cpp updated: 1.38 -> 1.38.2.1 JIT.cpp updated: 1.31 -> 1.31.2.1 TargetSelect.cpp updated: 1.2 -> 1.2.2.1 --- Log message: Merge from trunk --- Diffs of the changes: (+13 -9) Index: llvm/lib/ExecutionEngine/JIT/Emitter.cpp diff -u llvm/lib/ExecutionEngine/JIT/Emitter.cpp:1.38 llvm/lib/ExecutionEngine/JIT/Emitter.cpp:1.38.2.1 --- llvm/lib/ExecutionEngine/JIT/Emitter.cpp:1.38 Fri Dec 19 21:36:47 2003 +++ llvm/lib/ExecutionEngine/JIT/Emitter.cpp Mon Mar 1 17:58:13 2004 @@ -72,10 +72,9 @@ abort(); #endif + int fd = -1; #if defined(__linux__) -#define fd 0 -#else -#define fd -1 + fd = 0; #endif unsigned mmapFlags = MAP_PRIVATE|MAP_ANONYMOUS; Index: llvm/lib/ExecutionEngine/JIT/JIT.cpp diff -u llvm/lib/ExecutionEngine/JIT/JIT.cpp:1.31 llvm/lib/ExecutionEngine/JIT/JIT.cpp:1.31.2.1 --- llvm/lib/ExecutionEngine/JIT/JIT.cpp:1.31 Fri Dec 26 00:13:47 2003 +++ llvm/lib/ExecutionEngine/JIT/JIT.cpp Mon Mar 1 17:58:13 2004 @@ -110,7 +110,12 @@ return Addr; // Check if function already code gen'd // Make sure we read in the function if it exists in this Module - MP->materializeFunction(F); + try { + MP->materializeFunction(F); + } catch (...) { + std::cerr << "Error parsing bytecode file!\n"; + abort(); + } if (F->isExternal()) { void *Addr = getPointerToNamedFunction(F->getName()); Index: llvm/lib/ExecutionEngine/JIT/TargetSelect.cpp diff -u llvm/lib/ExecutionEngine/JIT/TargetSelect.cpp:1.2 llvm/lib/ExecutionEngine/JIT/TargetSelect.cpp:1.2.2.1 --- llvm/lib/ExecutionEngine/JIT/TargetSelect.cpp:1.2 Sun Dec 28 03:44:37 2003 +++ llvm/lib/ExecutionEngine/JIT/TargetSelect.cpp Mon Mar 1 17:58:13 2004 @@ -28,7 +28,7 @@ #endif namespace { - enum ArchName { x86, Sparc }; + enum ArchName { x86, SparcV9 }; #ifndef NO_JITS_ENABLED cl::opt @@ -38,13 +38,13 @@ clEnumVal(x86, " IA-32 (Pentium and above)"), #endif #ifdef ENABLE_SPARC_JIT - clEnumValN(Sparc, "sparc", " Sparc-V9"), + clEnumValN(SparcV9, "sparcv9", " Sparc-V9"), #endif 0), #if defined(ENABLE_X86_JIT) cl::init(x86) #elif defined(ENABLE_SPARC_JIT) - cl::init(Sparc) + cl::init(SparcV9) #endif ); #endif /* NO_JITS_ENABLED */ @@ -69,8 +69,8 @@ break; #endif #ifdef ENABLE_SPARC_JIT - case Sparc: - TargetMachineAllocator = allocateSparcTargetMachine; + case SparcV9: + TargetMachineAllocator = allocateSparcV9TargetMachine; break; #endif default: From brukman at cs.uiuc.edu Mon Mar 1 18:03:06 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Mar 1 18:03:06 2004 Subject: [llvm-commits] [parallel] CVS: llvm/lib/Target/Makefile Target.td TargetData.cpp TargetInstrInfo.cpp TargetMachine.cpp TargetSchedInfo.cpp Message-ID: <200403012358.RAA03836@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target: Makefile updated: 1.9 -> 1.9.6.1 Target.td updated: 1.24 -> 1.24.6.1 TargetData.cpp updated: 1.41 -> 1.41.2.1 TargetInstrInfo.cpp updated: 1.11 -> 1.11.2.1 TargetMachine.cpp updated: 1.21 -> 1.21.2.1 TargetSchedInfo.cpp updated: 1.13 -> 1.13.4.1 --- Log message: Merge from trunk --- Diffs of the changes: (+45 -52) Index: llvm/lib/Target/Makefile diff -u llvm/lib/Target/Makefile:1.9 llvm/lib/Target/Makefile:1.9.6.1 --- llvm/lib/Target/Makefile:1.9 Mon Oct 20 17:26:56 2003 +++ llvm/lib/Target/Makefile Mon Mar 1 17:58:13 2004 @@ -7,7 +7,7 @@ # ##===----------------------------------------------------------------------===## LEVEL = ../.. -DIRS = Sparc X86 +DIRS = CBackend X86 SparcV9 SparcV8 PowerPC LIBRARYNAME = target BUILD_ARCHIVE = 1 Index: llvm/lib/Target/Target.td diff -u llvm/lib/Target/Target.td:1.24 llvm/lib/Target/Target.td:1.24.6.1 --- llvm/lib/Target/Target.td:1.24 Tue Oct 21 10:17:13 2003 +++ llvm/lib/Target/Target.td Mon Mar 1 17:58:13 2004 @@ -25,6 +25,7 @@ int Value = value; } +def OtherVT: ValueType<0 , 0>; // "Other" value def i1 : ValueType<1 , 1>; // One bit boolean value def i8 : ValueType<8 , 2>; // 8-bit integer value def i16 : ValueType<16 , 3>; // 16-bit integer value Index: llvm/lib/Target/TargetData.cpp diff -u llvm/lib/Target/TargetData.cpp:1.41 llvm/lib/Target/TargetData.cpp:1.41.2.1 --- llvm/lib/Target/TargetData.cpp:1.41 Sun Dec 21 23:01:15 2003 +++ llvm/lib/Target/TargetData.cpp Mon Mar 1 17:58:13 2004 @@ -8,8 +8,7 @@ //===----------------------------------------------------------------------===// // // This file defines target properties related to datatype size/offset/alignment -// information. It uses lazy annotations to cache information about how -// structure types are laid out and used. +// information. // // This structure should be created once, filled in if the defaults are not // correct and then passed around by const&. None of the members functions @@ -33,18 +32,16 @@ uint64_t &Size, unsigned char &Alignment); //===----------------------------------------------------------------------===// -// Support for StructLayout Annotation +// Support for StructLayout //===----------------------------------------------------------------------===// -StructLayout::StructLayout(const StructType *ST, const TargetData &TD) - : Annotation(TD.getStructLayoutAID()) { +StructLayout::StructLayout(const StructType *ST, const TargetData &TD) { StructAlignment = 0; StructSize = 0; // Loop over each of the elements, placing them in memory... - for (StructType::ElementTypes::const_iterator - TI = ST->getElementTypes().begin(), - TE = ST->getElementTypes().end(); TI != TE; ++TI) { + for (StructType::element_iterator TI = ST->element_begin(), + TE = ST->element_end(); TI != TE; ++TI) { const Type *Ty = *TI; unsigned char A; unsigned TyAlign; @@ -72,16 +69,6 @@ StructSize = (StructSize/StructAlignment + 1) * StructAlignment; } -Annotation *TargetData::TypeAnFactory(AnnotationID AID, const Annotable *T, - void *D) { - const TargetData &TD = *(const TargetData*)D; - assert(AID == TD.AID && "Target data annotation ID mismatch!"); - const Type *Ty = cast((const Value *)T); - assert(isa(Ty) && - "Can only create StructLayout annotation on structs!"); - return new StructLayout(cast(Ty), TD); -} - //===----------------------------------------------------------------------===// // TargetData Class Implementation //===----------------------------------------------------------------------===// @@ -91,9 +78,7 @@ unsigned char PtrAl, unsigned char DoubleAl, unsigned char FloatAl, unsigned char LongAl, unsigned char IntAl, unsigned char ShortAl, - unsigned char ByteAl) - : AID(AnnotationManager::getID("TargetData::" + TargetName)) { - AnnotationManager::registerAnnotationFactory(AID, TypeAnFactory, this); + unsigned char ByteAl) { // If this assert triggers, a pass "required" TargetData information, but the // top level tool did not provide once for it. We do not want to default @@ -115,10 +100,7 @@ ByteAlignment = ByteAl; } -TargetData::TargetData(const std::string &ToolName, const Module *M) - : AID(AnnotationManager::getID("TargetData::" + ToolName)) { - AnnotationManager::registerAnnotationFactory(AID, TypeAnFactory, this); - +TargetData::TargetData(const std::string &ToolName, const Module *M) { LittleEndian = M->getEndianness() != Module::BigEndian; PointerSize = M->getPointerSize() != Module::Pointer64 ? 4 : 8; PointerAlignment = PointerSize; @@ -130,8 +112,38 @@ ByteAlignment = 1; } +static std::map, + StructLayout> *Layouts = 0; + + TargetData::~TargetData() { - AnnotationManager::registerAnnotationFactory(AID, 0); // Deregister factory + if (Layouts) { + // Remove any layouts for this TD. + std::map, StructLayout>::iterator + I = Layouts->lower_bound(std::make_pair(this, (const StructType*)0)); + while (I != Layouts->end() && I->first.first == this) + Layouts->erase(I++); + if (Layouts->empty()) { + delete Layouts; + Layouts = 0; + } + } +} + +const StructLayout *TargetData::getStructLayout(const StructType *Ty) const { + if (Layouts == 0) + Layouts = new std::map, + StructLayout>(); + std::map, + StructLayout>::iterator + I = Layouts->lower_bound(std::make_pair(this, Ty)); + if (I != Layouts->end() && I->first.first == this && I->first.second == Ty) + return &I->second; + else { + return &Layouts->insert(I, std::make_pair(std::make_pair(this, Ty), + StructLayout(Ty, *this)))->second; + } } static inline void getTypeInfo(const Type *Ty, const TargetData *TD, @@ -227,7 +239,7 @@ Result += Layout->MemberOffsets[FieldNo]; // Update Ty to refer to current element - Ty = STy->getElementTypes()[FieldNo]; + Ty = STy->getElementType(FieldNo); } } Index: llvm/lib/Target/TargetInstrInfo.cpp diff -u llvm/lib/Target/TargetInstrInfo.cpp:1.11 llvm/lib/Target/TargetInstrInfo.cpp:1.11.2.1 --- llvm/lib/Target/TargetInstrInfo.cpp:1.11 Thu Jan 15 12:15:58 2004 +++ llvm/lib/Target/TargetInstrInfo.cpp Mon Mar 1 17:58:13 2004 @@ -24,9 +24,8 @@ const TargetInstrDescriptor* TargetInstrDescriptors = 0; TargetInstrInfo::TargetInstrInfo(const TargetInstrDescriptor* Desc, - unsigned DescSize, - unsigned NumRealOpCodes) - : desc(Desc), descSize(DescSize), numRealOpCodes(NumRealOpCodes) { + unsigned numOpcodes) + : desc(Desc), NumOpcodes(numOpcodes) { // FIXME: TargetInstrDescriptors should not be global assert(TargetInstrDescriptors == NULL && desc != NULL && "TargetMachine data structure corrupt; maybe you tried to create another TargetMachine? (only one may exist in a program)"); Index: llvm/lib/Target/TargetMachine.cpp diff -u llvm/lib/Target/TargetMachine.cpp:1.21 llvm/lib/Target/TargetMachine.cpp:1.21.2.1 --- llvm/lib/Target/TargetMachine.cpp:1.21 Sun Dec 28 15:23:38 2003 +++ llvm/lib/Target/TargetMachine.cpp Mon Mar 1 17:58:13 2004 @@ -8,12 +8,10 @@ //===----------------------------------------------------------------------===// // // This file describes the general parts of a Target machine. -// This file also implements TargetCacheInfo. // //===----------------------------------------------------------------------===// #include "llvm/Target/TargetMachine.h" -#include "llvm/Target/TargetCacheInfo.h" #include "llvm/Type.h" #include "llvm/IntrinsicLowering.h" using namespace llvm; @@ -33,31 +31,14 @@ IL = il ? il : new DefaultIntrinsicLowering(); } - - TargetMachine::~TargetMachine() { delete IL; } - - - unsigned TargetMachine::findOptimalStorageSize(const Type *Ty) const { // All integer types smaller than ints promote to 4 byte integers. if (Ty->isIntegral() && Ty->getPrimitiveSize() < 4) return 4; return DataLayout.getTypeSize(Ty); -} - - -//--------------------------------------------------------------------------- -// TargetCacheInfo Class -// - -void TargetCacheInfo::Initialize() { - numLevels = 2; - cacheLineSizes.push_back(16); cacheLineSizes.push_back(32); - cacheSizes.push_back(1 << 15); cacheSizes.push_back(1 << 20); - cacheAssoc.push_back(1); cacheAssoc.push_back(4); } Index: llvm/lib/Target/TargetSchedInfo.cpp diff -u llvm/lib/Target/TargetSchedInfo.cpp:1.13 llvm/lib/Target/TargetSchedInfo.cpp:1.13.4.1 --- llvm/lib/Target/TargetSchedInfo.cpp:1.13 Tue Nov 11 16:41:33 2003 +++ llvm/lib/Target/TargetSchedInfo.cpp Mon Mar 1 17:58:13 2004 @@ -119,7 +119,7 @@ TargetSchedInfo::computeInstrResources(const std::vector& instrRUForClasses) { - int numOpCodes = mii->getNumRealOpCodes(); + int numOpCodes = mii->getNumOpcodes(); instrRUsages.resize(numOpCodes); // First get the resource usage information from the class resource usages. @@ -149,7 +149,7 @@ TargetSchedInfo::computeIssueGaps(const std::vector& instrRUForClasses) { - int numOpCodes = mii->getNumRealOpCodes(); + int numOpCodes = mii->getNumOpcodes(); issueGaps.resize(numOpCodes); conflictLists.resize(numOpCodes); From brukman at cs.uiuc.edu Mon Mar 1 18:03:14 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Mar 1 18:03:14 2004 Subject: [llvm-commits] [parallel] CVS: llvm/lib/Analysis/ProfileInfo.cpp ProfileInfoLoader.cpp ProfileInfoLoaderPass.cpp AliasAnalysis.cpp BasicAliasAnalysis.cpp LoadValueNumbering.cpp LoopInfo.cpp ValueNumbering.cpp Message-ID: <200403012358.RAA03881@zion.cs.uiuc.edu> Changes in directory llvm/lib/Analysis: ProfileInfo.cpp added (r1.3.2.1) ProfileInfoLoader.cpp added (r1.2.2.1) ProfileInfoLoaderPass.cpp added (r1.3.2.1) AliasAnalysis.cpp updated: 1.15 -> 1.15.4.1 BasicAliasAnalysis.cpp updated: 1.26 -> 1.26.2.1 LoadValueNumbering.cpp updated: 1.10 -> 1.10.4.1 LoopInfo.cpp updated: 1.46 -> 1.46.2.1 ValueNumbering.cpp updated: 1.9 -> 1.9.4.1 --- Log message: Merge from trunk --- Diffs of the changes: (+607 -257) Index: llvm/lib/Analysis/ProfileInfo.cpp diff -c /dev/null llvm/lib/Analysis/ProfileInfo.cpp:1.3.2.1 *** /dev/null Mon Mar 1 17:58:27 2004 --- llvm/lib/Analysis/ProfileInfo.cpp Mon Mar 1 17:58:12 2004 *************** *** 0 **** --- 1,42 ---- + //===- ProfileInfo.cpp - Profile Info Interface ---------------------------===// + // + // The LLVM Compiler Infrastructure + // + // This file was developed by the LLVM research group and is distributed under + // the University of Illinois Open Source License. See LICENSE.TXT for details. + // + //===----------------------------------------------------------------------===// + // + // This file implements the abstract ProfileInfo interface, and the default + // "no profile" implementation. + // + //===----------------------------------------------------------------------===// + + #include "llvm/Analysis/ProfileInfo.h" + #include "llvm/Pass.h" + using namespace llvm; + + // Register the ProfileInfo interface, providing a nice name to refer to. + namespace { + RegisterAnalysisGroup Z("Profile Information"); + } + + ProfileInfo::~ProfileInfo() {} + + + //===----------------------------------------------------------------------===// + // NoProfile ProfileInfo implementation + // + + namespace { + struct NoProfileInfo : public ImmutablePass, public ProfileInfo { + unsigned getExecutionCount(BasicBlock *BB) { return 0; } + }; + + // Register this pass... + RegisterOpt + X("no-profile", "No Profile Information"); + + // Declare that we implement the ProfileInfo interface + RegisterAnalysisGroup Y; + } // End of anonymous namespace Index: llvm/lib/Analysis/ProfileInfoLoader.cpp diff -c /dev/null llvm/lib/Analysis/ProfileInfoLoader.cpp:1.2.2.1 *** /dev/null Mon Mar 1 17:58:27 2004 --- llvm/lib/Analysis/ProfileInfoLoader.cpp Mon Mar 1 17:58:12 2004 *************** *** 0 **** --- 1,180 ---- + //===- ProfileInfoLoad.cpp - Load profile information from disk -----------===// + // + // The LLVM Compiler Infrastructure + // + // This file was developed by the LLVM research group and is distributed under + // the University of Illinois Open Source License. See LICENSE.TXT for details. + // + //===----------------------------------------------------------------------===// + // + // The ProfileInfoLoader class is used to load and represent profiling + // information read in from the dump file. + // + //===----------------------------------------------------------------------===// + + #include "llvm/Analysis/ProfileInfoLoader.h" + #include "llvm/Module.h" + #include + using namespace llvm; + + enum ProfilingType { + ArgumentInfo = 1, // The command line argument block + FunctionInfo = 2, // Function profiling information + BlockInfo = 3, // Block profiling information + }; + + // ByteSwap - Byteswap 'Var' if 'Really' is true. + // + static inline unsigned ByteSwap(unsigned Var, bool Really) { + if (!Really) return Var; + return ((Var & (255<< 0)) << 24) | + ((Var & (255<< 8)) << 8) | + ((Var & (255<<16)) >> 8) | + ((Var & (255<<24)) >> 24); + } + + static void ReadProfilingBlock(const char *ToolName, FILE *F, + bool ShouldByteSwap, + std::vector &Data) { + // Read the number of entries... + unsigned NumEntries; + if (fread(&NumEntries, sizeof(unsigned), 1, F) != 1) { + std::cerr << ToolName << ": data packet truncated!\n"; + perror(0); + exit(1); + } + NumEntries = ByteSwap(NumEntries, ShouldByteSwap); + + // Read the counts... + std::vector TempSpace(NumEntries); + + // Read in the block of data... + if (fread(&TempSpace[0], sizeof(unsigned)*NumEntries, 1, F) != 1) { + std::cerr << ToolName << ": data packet truncated!\n"; + perror(0); + exit(1); + } + + // Make sure we have enough space... + if (Data.size() < NumEntries) + Data.resize(NumEntries); + + // Accumulate the data we just read into the data. + if (!ShouldByteSwap) { + for (unsigned i = 0; i != NumEntries; ++i) + Data[i] += TempSpace[i]; + } else { + for (unsigned i = 0; i != NumEntries; ++i) + Data[i] += ByteSwap(TempSpace[i], true); + } + } + + // ProfileInfoLoader ctor - Read the specified profiling data file, exiting the + // program if the file is invalid or broken. + // + ProfileInfoLoader::ProfileInfoLoader(const char *ToolName, + const std::string &Filename, + Module &TheModule) : M(TheModule) { + FILE *F = fopen(Filename.c_str(), "r"); + if (F == 0) { + std::cerr << ToolName << ": Error opening '" << Filename << "': "; + perror(0); + exit(1); + } + + // Keep reading packets until we run out of them. + unsigned PacketType; + while (fread(&PacketType, sizeof(unsigned), 1, F) == 1) { + // If the low eight bits of the packet are zero, we must be dealing with an + // endianness mismatch. Byteswap all words read from the profiling + // information. + bool ShouldByteSwap = (char)PacketType == 0; + PacketType = ByteSwap(PacketType, ShouldByteSwap); + + switch (PacketType) { + case ArgumentInfo: { + unsigned ArgLength; + if (fread(&ArgLength, sizeof(unsigned), 1, F) != 1) { + std::cerr << ToolName << ": arguments packet truncated!\n"; + perror(0); + exit(1); + } + ArgLength = ByteSwap(ArgLength, ShouldByteSwap); + + // Read in the arguments... + std::vector Chars(ArgLength+4); + + if (ArgLength) + if (fread(&Chars[0], (ArgLength+3) & ~3, 1, F) != 1) { + std::cerr << ToolName << ": arguments packet truncated!\n"; + perror(0); + exit(1); + } + CommandLines.push_back(std::string(&Chars[0], &Chars[ArgLength])); + break; + } + + case FunctionInfo: + ReadProfilingBlock(ToolName, F, ShouldByteSwap, FunctionCounts); + break; + + case BlockInfo: + ReadProfilingBlock(ToolName, F, ShouldByteSwap, BlockCounts); + break; + + default: + std::cerr << ToolName << ": Unknown packet type #" << PacketType << "!\n"; + exit(1); + } + } + + fclose(F); + } + + + // getFunctionCounts - This method is used by consumers of function counting + // information. If we do not directly have function count information, we + // compute it from other, more refined, types of profile information. + // + void ProfileInfoLoader::getFunctionCounts(std::vector > &Counts) { + if (FunctionCounts.empty()) { + // Synthesize function frequency information from the number of times their + // entry blocks were executed. + std::vector > BlockCounts; + getBlockCounts(BlockCounts); + + for (unsigned i = 0, e = BlockCounts.size(); i != e; ++i) + if (&BlockCounts[i].first->getParent()->front() == BlockCounts[i].first) + Counts.push_back(std::make_pair(BlockCounts[i].first->getParent(), + BlockCounts[i].second)); + return; + } + + unsigned Counter = 0; + for (Module::iterator I = M.begin(), E = M.end(); + I != E && Counter != FunctionCounts.size(); ++I) + if (!I->isExternal()) + Counts.push_back(std::make_pair(I, FunctionCounts[Counter++])); + } + + // getBlockCounts - This method is used by consumers of block counting + // information. If we do not directly have block count information, we + // compute it from other, more refined, types of profile information. + // + void ProfileInfoLoader::getBlockCounts(std::vector > &Counts) { + if (BlockCounts.empty()) { + std::cerr << "Block counts not available, and no synthesis " + << "is implemented yet!\n"; + return; + } + + unsigned Counter = 0; + for (Module::iterator F = M.begin(), E = M.end(); F != E; ++F) + for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB) { + Counts.push_back(std::make_pair(BB, BlockCounts[Counter++])); + if (Counter == BlockCounts.size()) + return; + } + } Index: llvm/lib/Analysis/ProfileInfoLoaderPass.cpp diff -c /dev/null llvm/lib/Analysis/ProfileInfoLoaderPass.cpp:1.3.2.1 *** /dev/null Mon Mar 1 17:58:28 2004 --- llvm/lib/Analysis/ProfileInfoLoaderPass.cpp Mon Mar 1 17:58:12 2004 *************** *** 0 **** --- 1,75 ---- + //===- ProfileInfoLoaderPass.cpp - LLVM Pass to load profile info ---------===// + // + // The LLVM Compiler Infrastructure + // + // This file was developed by the LLVM research group and is distributed under + // the University of Illinois Open Source License. See LICENSE.TXT for details. + // + //===----------------------------------------------------------------------===// + // + // This file implements a concrete implementation of profiling information that + // loads the information from a profile dump file. + // + //===----------------------------------------------------------------------===// + + #include "llvm/Pass.h" + #include "llvm/Analysis/ProfileInfo.h" + #include "llvm/Analysis/ProfileInfoLoader.h" + #include "Support/CommandLine.h" + using namespace llvm; + + namespace { + cl::opt + ProfileInfoFilename("profile-info-file", cl::init("llvmprof.out"), + cl::value_desc("filename"), + cl::desc("Profile file loaded by -profile-loader")); + + class LoaderPass : public Pass, public ProfileInfo { + std::string Filename; + std::map ExecutionCounts; + public: + LoaderPass(const std::string &filename = "") + : Filename(filename) { + if (filename.empty()) Filename = ProfileInfoFilename; + } + + virtual void getAnalysisUsage(AnalysisUsage &AU) const { + AU.setPreservesAll(); + } + + virtual const char *getPassName() const { + return "Profiling information loader"; + } + + /// run - Load the profile information from the specified file. + virtual bool run(Module &M); + + virtual unsigned getExecutionCount(BasicBlock *BB) { + std::map::iterator I = ExecutionCounts.find(BB); + return I != ExecutionCounts.end() ? I->second : 0; + } + }; + + RegisterOpt + X("profile-loader", "Load profile information from llvmprof.out"); + + RegisterAnalysisGroup Y; + } // End of anonymous namespace + + + /// createProfileLoaderPass - This function returns a Pass that loads the + /// profiling information for the module from the specified filename, making it + /// available to the optimizers. + Pass *llvm::createProfileLoaderPass(const std::string &Filename) { + return new LoaderPass(Filename); + } + + bool LoaderPass::run(Module &M) { + ProfileInfoLoader PIL("opt", Filename, M); + if (PIL.hasAccurateBlockCounts()) { + std::vector > Counts; + PIL.getBlockCounts(Counts); + ExecutionCounts.insert(Counts.begin(), Counts.end()); + } + return false; + } Index: llvm/lib/Analysis/AliasAnalysis.cpp diff -u llvm/lib/Analysis/AliasAnalysis.cpp:1.15 llvm/lib/Analysis/AliasAnalysis.cpp:1.15.4.1 --- llvm/lib/Analysis/AliasAnalysis.cpp:1.15 Tue Nov 11 16:41:31 2003 +++ llvm/lib/Analysis/AliasAnalysis.cpp Mon Mar 1 17:58:12 2004 @@ -44,8 +44,15 @@ AliasAnalysis::ModRefResult AliasAnalysis::getModRefInfo(StoreInst *S, Value *P, unsigned Size) { - return alias(S->getOperand(1), TD->getTypeSize(S->getOperand(0)->getType()), - P, Size) ? Mod : NoModRef; + // If the stored address cannot alias the pointer in question, then the + // pointer cannot be modified by the store. + if (!alias(S->getOperand(1), TD->getTypeSize(S->getOperand(0)->getType()), + P, Size)) + return NoModRef; + + // If the pointer is a pointer to constant memory, then it could not have been + // modified by this store. + return pointsToConstantMemory(P) ? NoModRef : Mod; } Index: llvm/lib/Analysis/BasicAliasAnalysis.cpp diff -u llvm/lib/Analysis/BasicAliasAnalysis.cpp:1.26 llvm/lib/Analysis/BasicAliasAnalysis.cpp:1.26.2.1 --- llvm/lib/Analysis/BasicAliasAnalysis.cpp:1.26 Mon Jan 12 11:57:32 2004 +++ llvm/lib/Analysis/BasicAliasAnalysis.cpp Mon Mar 1 17:58:12 2004 @@ -14,7 +14,9 @@ // FIXME: This could be extended for a very simple form of mod/ref information. // If a pointer is locally allocated (either malloc or alloca) and never passed // into a call or stored to memory, then we know that calls will not mod/ref the -// memory. This can be important for tailcallelim. +// memory. This can be important for tailcallelim, and can support CSE of loads +// and dead store elimination across calls. This is particularly important for +// stack allocated arrays. // //===----------------------------------------------------------------------===// @@ -22,8 +24,9 @@ #include "llvm/Pass.h" #include "llvm/Argument.h" #include "llvm/iOther.h" +#include "llvm/iMemory.h" #include "llvm/Constants.h" -#include "llvm/GlobalValue.h" +#include "llvm/GlobalVariable.h" #include "llvm/DerivedTypes.h" #include "llvm/Target/TargetData.h" #include "llvm/Support/GetElementPtrTypeIterator.h" @@ -41,10 +44,13 @@ virtual void initializePass(); - // alias - This is the only method here that does anything interesting... - // AliasResult alias(const Value *V1, unsigned V1Size, const Value *V2, unsigned V2Size); + + /// pointsToConstantMemory - Chase pointers until we find a (constant + /// global) or not. + bool pointsToConstantMemory(const Value *P); + private: // CheckGEPInstructions - Check two GEP instructions with known // must-aliasing base pointers. This checks to see if the index expressions @@ -124,6 +130,14 @@ return V; } +/// pointsToConstantMemory - Chase pointers until we find a (constant +/// global) or not. +bool BasicAliasAnalysis::pointsToConstantMemory(const Value *P) { + if (const Value *V = getUnderlyingObject(P)) + if (const GlobalVariable *GV = dyn_cast(V)) + return GV->isConstant(); + return false; +} // alias - Provide a bunch of ad-hoc rules to disambiguate in common cases, such // as array references. Note that this function is heavily tail recursive. Index: llvm/lib/Analysis/LoadValueNumbering.cpp diff -u llvm/lib/Analysis/LoadValueNumbering.cpp:1.10 llvm/lib/Analysis/LoadValueNumbering.cpp:1.10.4.1 --- llvm/lib/Analysis/LoadValueNumbering.cpp:1.10 Tue Nov 11 16:41:31 2003 +++ llvm/lib/Analysis/LoadValueNumbering.cpp Mon Mar 1 17:58:12 2004 @@ -28,10 +28,8 @@ #include "llvm/iMemory.h" #include "llvm/BasicBlock.h" #include "llvm/Support/CFG.h" -#include #include - -namespace llvm { +using namespace llvm; namespace { // FIXME: This should not be a FunctionPass. @@ -52,17 +50,6 @@ /// virtual void getEqualNumberNodes(Value *V1, std::vector &RetVals) const; - private: - /// haveEqualValueNumber - Given two load instructions, determine if they - /// both produce the same value on every execution of the program, assuming - /// that their source operands always give the same value. This uses the - /// AliasAnalysis implementation to invalidate loads when stores or function - /// calls occur that could modify the value produced by the load. - /// - bool haveEqualValueNumber(LoadInst *LI, LoadInst *LI2, AliasAnalysis &AA, - DominatorSet &DomSetInfo) const; - bool haveEqualValueNumber(LoadInst *LI, StoreInst *SI, AliasAnalysis &AA, - DominatorSet &DomSetInfo) const; }; // Register this pass... @@ -72,7 +59,7 @@ RegisterAnalysisGroup Y; } -Pass *createLoadValueNumberingPass() { return new LoadVN(); } +Pass *llvm::createLoadValueNumberingPass() { return new LoadVN(); } /// getAnalysisUsage - Does not modify anything. It uses Value Numbering and @@ -86,6 +73,43 @@ AU.addRequired(); } +static bool isPathTransparentTo(BasicBlock *CurBlock, BasicBlock *Dom, + Value *Ptr, unsigned Size, AliasAnalysis &AA, + std::set &Visited, + std::map &TransparentBlocks){ + // If we have already checked out this path, or if we reached our destination, + // stop searching, returning success. + if (CurBlock == Dom || !Visited.insert(CurBlock).second) + return true; + + // Check whether this block is known transparent or not. + std::map::iterator TBI = + TransparentBlocks.lower_bound(CurBlock); + + if (TBI == TransparentBlocks.end() || TBI->first != CurBlock) { + // If this basic block can modify the memory location, then the path is not + // transparent! + if (AA.canBasicBlockModify(*CurBlock, Ptr, Size)) { + TransparentBlocks.insert(TBI, std::make_pair(CurBlock, false)); + return false; + } + TransparentBlocks.insert(TBI, std::make_pair(CurBlock, true)); + } else if (!TBI->second) + // This block is known non-transparent, so that path can't be either. + return false; + + // The current block is known to be transparent. The entire path is + // transparent if all of the predecessors paths to the parent is also + // transparent to the memory location. + for (pred_iterator PI = pred_begin(CurBlock), E = pred_end(CurBlock); + PI != E; ++PI) + if (!isPathTransparentTo(*PI, Dom, Ptr, Size, AA, Visited, + TransparentBlocks)) + return false; + return true; +} + + // getEqualNumberNodes - Return nodes with the same value number as the // specified Value. This fills in the argument vector with any equal values. // @@ -96,249 +120,260 @@ if (isa(V->getType())) getAnalysis().getMustAliases(V, RetVals); - if (LoadInst *LI = dyn_cast(V)) { - // Volatile loads cannot be replaced with the value of other loads. - if (LI->isVolatile()) - return getAnalysis().getEqualNumberNodes(V, RetVals); - - // If we have a load instruction, find all of the load and store - // instructions that use the same source operand. We implement this - // recursively, because there could be a load of a load of a load that are - // all identical. We are guaranteed that this cannot be an infinite - // recursion because load instructions would have to pass through a PHI node - // in order for there to be a cycle. The PHI node would be handled by the - // else case here, breaking the infinite recursion. - // - std::vector PointerSources; - getEqualNumberNodes(LI->getOperand(0), PointerSources); - PointerSources.push_back(LI->getOperand(0)); - - Function *F = LI->getParent()->getParent(); - - // Now that we know the set of equivalent source pointers for the load - // instruction, look to see if there are any load or store candidates that - // are identical. - // - std::vector CandidateLoads; - std::vector CandidateStores; - - while (!PointerSources.empty()) { - Value *Source = PointerSources.back(); - PointerSources.pop_back(); // Get a source pointer... - - for (Value::use_iterator UI = Source->use_begin(), UE = Source->use_end(); - UI != UE; ++UI) - if (LoadInst *Cand = dyn_cast(*UI)) {// Is a load of source? - if (Cand->getParent()->getParent() == F && // In the same function? - Cand != LI && !Cand->isVolatile()) // Not LI itself? - CandidateLoads.push_back(Cand); // Got one... - } else if (StoreInst *Cand = dyn_cast(*UI)) { - if (Cand->getParent()->getParent() == F && !Cand->isVolatile() && - Cand->getOperand(1) == Source) // It's a store THROUGH the ptr... - CandidateStores.push_back(Cand); - } - } - - // Remove duplicates from the CandidateLoads list because alias analysis - // processing may be somewhat expensive and we don't want to do more work - // than necessary. - // - unsigned OldSize = CandidateLoads.size(); - std::sort(CandidateLoads.begin(), CandidateLoads.end()); - CandidateLoads.erase(std::unique(CandidateLoads.begin(), - CandidateLoads.end()), - CandidateLoads.end()); - // FIXME: REMOVE THIS SORTING AND UNIQUING IF IT CAN'T HAPPEN - assert(CandidateLoads.size() == OldSize && "Shrunk the candloads list?"); - - // Get Alias Analysis... - AliasAnalysis &AA = getAnalysis(); - DominatorSet &DomSetInfo = getAnalysis(); - - // Loop over all of the candidate loads. If they are not invalidated by - // stores or calls between execution of them and LI, then add them to - // RetVals. - for (unsigned i = 0, e = CandidateLoads.size(); i != e; ++i) - if (haveEqualValueNumber(LI, CandidateLoads[i], AA, DomSetInfo)) - RetVals.push_back(CandidateLoads[i]); - for (unsigned i = 0, e = CandidateStores.size(); i != e; ++i) - if (haveEqualValueNumber(LI, CandidateStores[i], AA, DomSetInfo)) - RetVals.push_back(CandidateStores[i]->getOperand(0)); - - } else { + if (!isa(V)) { + // Not a load instruction? Just chain to the base value numbering + // implementation to satisfy the request... assert(&getAnalysis() != (ValueNumbering*)this && "getAnalysis() returned this!"); - // Not a load instruction? Just chain to the base value numbering - // implementation to satisfy the request... return getAnalysis().getEqualNumberNodes(V, RetVals); } -} - -// CheckForInvalidatingInst - Return true if BB or any of the predecessors of BB -// (until DestBB) contain an instruction that might invalidate Ptr. -// -static bool CheckForInvalidatingInst(BasicBlock *BB, BasicBlock *DestBB, - Value *Ptr, unsigned Size, - AliasAnalysis &AA, - std::set &VisitedSet) { - // Found the termination point! - if (BB == DestBB || VisitedSet.count(BB)) return false; - - // Avoid infinite recursion! - VisitedSet.insert(BB); - - // Can this basic block modify Ptr? - if (AA.canBasicBlockModify(*BB, Ptr, Size)) - return true; - - // Check all of our predecessor blocks... - for (pred_iterator PI = pred_begin(BB), PE = pred_end(BB); PI != PE; ++PI) - if (CheckForInvalidatingInst(*PI, DestBB, Ptr, Size, AA, VisitedSet)) - return true; - - // None of our predecessor blocks contain an invalidating instruction, and we - // don't either! - return false; -} - -/// haveEqualValueNumber - Given two load instructions, determine if they both -/// produce the same value on every execution of the program, assuming that -/// their source operands always give the same value. This uses the -/// AliasAnalysis implementation to invalidate loads when stores or function -/// calls occur that could modify the value produced by the load. -/// -bool LoadVN::haveEqualValueNumber(LoadInst *L1, LoadInst *L2, - AliasAnalysis &AA, - DominatorSet &DomSetInfo) const { - // Figure out which load dominates the other one. If neither dominates the - // other we cannot eliminate them. + // Volatile loads cannot be replaced with the value of other loads. + LoadInst *LI = cast(V); + if (LI->isVolatile()) + return getAnalysis().getEqualNumberNodes(V, RetVals); + + // If we have a load instruction, find all of the load and store instructions + // that use the same source operand. We implement this recursively, because + // there could be a load of a load of a load that are all identical. We are + // guaranteed that this cannot be an infinite recursion because load + // instructions would have to pass through a PHI node in order for there to be + // a cycle. The PHI node would be handled by the else case here, breaking the + // infinite recursion. // - // FIXME: This could be enhanced to some cases with a shared dominator! + std::vector PointerSources; + getEqualNumberNodes(LI->getOperand(0), PointerSources); + PointerSources.push_back(LI->getOperand(0)); + + BasicBlock *LoadBB = LI->getParent(); + Function *F = LoadBB->getParent(); + + // Now that we know the set of equivalent source pointers for the load + // instruction, look to see if there are any load or store candidates that are + // identical. // - if (DomSetInfo.dominates(L2, L1)) - std::swap(L1, L2); // Make L1 dominate L2 - else if (!DomSetInfo.dominates(L1, L2)) - return false; // Neither instruction dominates the other one... - - BasicBlock *BB1 = L1->getParent(), *BB2 = L2->getParent(); - Value *LoadAddress = L1->getOperand(0); - - assert(L1->getType() == L2->getType() && - "How could the same source pointer return different types?"); - + std::map > CandidateLoads; + std::map > CandidateStores; + + while (!PointerSources.empty()) { + Value *Source = PointerSources.back(); + PointerSources.pop_back(); // Get a source pointer... + + for (Value::use_iterator UI = Source->use_begin(), UE = Source->use_end(); + UI != UE; ++UI) + if (LoadInst *Cand = dyn_cast(*UI)) {// Is a load of source? + if (Cand->getParent()->getParent() == F && // In the same function? + Cand != LI && !Cand->isVolatile()) // Not LI itself? + CandidateLoads[Cand->getParent()].push_back(Cand); // Got one... + } else if (StoreInst *Cand = dyn_cast(*UI)) { + if (Cand->getParent()->getParent() == F && !Cand->isVolatile() && + Cand->getOperand(1) == Source) // It's a store THROUGH the ptr... + CandidateStores[Cand->getParent()].push_back(Cand); + } + } + + // Get alias analysis & dominators. + AliasAnalysis &AA = getAnalysis(); + DominatorSet &DomSetInfo = getAnalysis(); + Value *LoadPtr = LI->getOperand(0); // Find out how many bytes of memory are loaded by the load instruction... - unsigned LoadSize = getAnalysis().getTypeSize(L1->getType()); + unsigned LoadSize = getAnalysis().getTypeSize(LI->getType()); - // L1 now dominates L2. Check to see if the intervening instructions between - // the two loads include a store or call... - // - if (BB1 == BB2) { // In same basic block? - // In this degenerate case, no checking of global basic blocks has to occur - // just check the instructions BETWEEN L1 & L2... - // - if (AA.canInstructionRangeModify(*L1, *L2, LoadAddress, LoadSize)) - return false; // Cannot eliminate load + // Find all of the candidate loads and stores that are in the same block as + // the defining instruction. + std::set Instrs; + Instrs.insert(CandidateLoads[LoadBB].begin(), CandidateLoads[LoadBB].end()); + CandidateLoads.erase(LoadBB); + Instrs.insert(CandidateStores[LoadBB].begin(), CandidateStores[LoadBB].end()); + CandidateStores.erase(LoadBB); + + // Figure out if the load is invalidated from the entry of the block it is in + // until the actual instruction. This scans the block backwards from LI. If + // we see any candidate load or store instructions, then we know that the + // candidates have the same value # as LI. + bool LoadInvalidatedInBBBefore = false; + for (BasicBlock::iterator I = LI; I != LoadBB->begin(); ) { + --I; + // If this instruction is a candidate load before LI, we know there are no + // invalidating instructions between it and LI, so they have the same value + // number. + if (isa(I) && Instrs.count(I)) { + RetVals.push_back(I); + Instrs.erase(I); + } - // No instructions invalidate the loads, they produce the same value! - return true; - } else { - // Make sure that there are no store instructions between L1 and the end of - // its basic block... - // - if (AA.canInstructionRangeModify(*L1, *BB1->getTerminator(), LoadAddress, - LoadSize)) - return false; // Cannot eliminate load - - // Make sure that there are no store instructions between the start of BB2 - // and the second load instruction... - // - if (AA.canInstructionRangeModify(BB2->front(), *L2, LoadAddress, LoadSize)) - return false; // Cannot eliminate load - - // Do a depth first traversal of the inverse CFG starting at L2's block, - // looking for L1's block. The inverse CFG is made up of the predecessor - // nodes of a block... so all of the edges in the graph are "backward". - // - std::set VisitedSet; - for (pred_iterator PI = pred_begin(BB2), PE = pred_end(BB2); PI != PE; ++PI) - if (CheckForInvalidatingInst(*PI, BB1, LoadAddress, LoadSize, AA, - VisitedSet)) - return false; + if (AA.getModRefInfo(I, LoadPtr, LoadSize) & AliasAnalysis::Mod) { + // If the invalidating instruction is a store, and its in our candidate + // set, then we can do store-load forwarding: the load has the same value + // # as the stored value. + if (isa(I) && Instrs.count(I)) { + Instrs.erase(I); + RetVals.push_back(I->getOperand(0)); + } - // If we passed all of these checks then we are sure that the two loads - // produce the same value. - return true; + LoadInvalidatedInBBBefore = true; + break; + } } -} - -/// haveEqualValueNumber - Given a load instruction and a store instruction, -/// determine if the stored value reaches the loaded value unambiguously on -/// every execution of the program. This uses the AliasAnalysis implementation -/// to invalidate the stored value when stores or function calls occur that -/// could modify the value produced by the load. -/// -bool LoadVN::haveEqualValueNumber(LoadInst *Load, StoreInst *Store, - AliasAnalysis &AA, - DominatorSet &DomSetInfo) const { - // If the store does not dominate the load, we cannot do anything... - if (!DomSetInfo.dominates(Store, Load)) - return false; - - BasicBlock *BB1 = Store->getParent(), *BB2 = Load->getParent(); - Value *LoadAddress = Load->getOperand(0); - - assert(LoadAddress->getType() == Store->getOperand(1)->getType() && - "How could the same source pointer return different types?"); + // Figure out if the load is invalidated between the load and the exit of the + // block it is defined in. While we are scanning the current basic block, if + // we see any candidate loads, then we know they have the same value # as LI. + // + bool LoadInvalidatedInBBAfter = false; + for (BasicBlock::iterator I = LI->getNext(); I != LoadBB->end(); ++I) { + // If this instruction is a load, then this instruction returns the same + // value as LI. + if (isa(I) && Instrs.count(I)) { + RetVals.push_back(I); + Instrs.erase(I); + } - // Find out how many bytes of memory are loaded by the load instruction... - unsigned LoadSize = getAnalysis().getTypeSize(Load->getType()); + if (AA.getModRefInfo(I, LoadPtr, LoadSize) & AliasAnalysis::Mod) { + LoadInvalidatedInBBAfter = true; + break; + } + } - // Compute a basic block iterator pointing to the instruction after the store. - BasicBlock::iterator StoreIt = Store; ++StoreIt; + // If there is anything left in the Instrs set, it could not possibly equal + // LI. + Instrs.clear(); + + // TransparentBlocks - For each basic block the load/store is alive across, + // figure out if the pointer is invalidated or not. If it is invalidated, the + // boolean is set to false, if it's not it is set to true. If we don't know + // yet, the entry is not in the map. + std::map TransparentBlocks; + + // Loop over all of the basic blocks that also load the value. If the value + // is live across the CFG from the source to destination blocks, and if the + // value is not invalidated in either the source or destination blocks, add it + // to the equivalence sets. + for (std::map >::iterator + I = CandidateLoads.begin(), E = CandidateLoads.end(); I != E; ++I) { + bool CantEqual = false; + + // Right now we only can handle cases where one load dominates the other. + // FIXME: generalize this! + BasicBlock *BB1 = I->first, *BB2 = LoadBB; + if (DomSetInfo.dominates(BB1, BB2)) { + // The other load dominates LI. If the loaded value is killed entering + // the LoadBB block, we know the load is not live. + if (LoadInvalidatedInBBBefore) + CantEqual = true; + } else if (DomSetInfo.dominates(BB2, BB1)) { + std::swap(BB1, BB2); // Canonicalize + // LI dominates the other load. If the loaded value is killed exiting + // the LoadBB block, we know the load is not live. + if (LoadInvalidatedInBBAfter) + CantEqual = true; + } else { + // None of these loads can VN the same. + CantEqual = true; + } - // Check to see if the intervening instructions between the two store and load - // include a store or call... - // - if (BB1 == BB2) { // In same basic block? - // In this degenerate case, no checking of global basic blocks has to occur - // just check the instructions BETWEEN Store & Load... - // - if (AA.canInstructionRangeModify(*StoreIt, *Load, LoadAddress, LoadSize)) - return false; // Cannot eliminate load + if (!CantEqual) { + // Ok, at this point, we know that BB1 dominates BB2, and that there is + // nothing in the LI block that kills the loaded value. Check to see if + // the value is live across the CFG. + std::set Visited; + for (pred_iterator PI = pred_begin(BB2), E = pred_end(BB2); PI!=E; ++PI) + if (!isPathTransparentTo(*PI, BB1, LoadPtr, LoadSize, AA, + Visited, TransparentBlocks)) { + // None of these loads can VN the same. + CantEqual = true; + break; + } + } - // No instructions invalidate the stored value, they produce the same value! - return true; - } else { - // Make sure that there are no store instructions between the Store and the - // end of its basic block... - // - if (AA.canInstructionRangeModify(*StoreIt, *BB1->getTerminator(), - LoadAddress, LoadSize)) - return false; // Cannot eliminate load - - // Make sure that there are no store instructions between the start of BB2 - // and the second load instruction... - // - if (AA.canInstructionRangeModify(BB2->front(), *Load, LoadAddress,LoadSize)) - return false; // Cannot eliminate load - - // Do a depth first traversal of the inverse CFG starting at L2's block, - // looking for L1's block. The inverse CFG is made up of the predecessor - // nodes of a block... so all of the edges in the graph are "backward". - // - std::set VisitedSet; - for (pred_iterator PI = pred_begin(BB2), PE = pred_end(BB2); PI != PE; ++PI) - if (CheckForInvalidatingInst(*PI, BB1, LoadAddress, LoadSize, AA, - VisitedSet)) - return false; + // If the loads can equal so far, scan the basic block that contains the + // loads under consideration to see if they are invalidated in the block. + // For any loads that are not invalidated, add them to the equivalence + // set! + if (!CantEqual) { + Instrs.insert(I->second.begin(), I->second.end()); + if (BB1 == LoadBB) { + // If LI dominates the block in question, check to see if any of the + // loads in this block are invalidated before they are reached. + for (BasicBlock::iterator BBI = I->first->begin(); ; ++BBI) { + if (isa(BBI) && Instrs.count(BBI)) { + // The load is in the set! + RetVals.push_back(BBI); + Instrs.erase(BBI); + if (Instrs.empty()) break; + } else if (AA.getModRefInfo(BBI, LoadPtr, LoadSize) + & AliasAnalysis::Mod) { + // If there is a modifying instruction, nothing below it will value + // # the same. + break; + } + } + } else { + // If the block dominates LI, make sure that the loads in the block are + // not invalidated before the block ends. + BasicBlock::iterator BBI = I->first->end(); + while (1) { + --BBI; + if (isa(BBI) && Instrs.count(BBI)) { + // The load is in the set! + RetVals.push_back(BBI); + Instrs.erase(BBI); + if (Instrs.empty()) break; + } else if (AA.getModRefInfo(BBI, LoadPtr, LoadSize) + & AliasAnalysis::Mod) { + // If there is a modifying instruction, nothing above it will value + // # the same. + break; + } + } + } - // If we passed all of these checks then we are sure that the two loads - // produce the same value. - return true; + Instrs.clear(); + } } -} -} // End llvm namespace + // Handle candidate stores. If the loaded location is clobbered on entrance + // to the LoadBB, no store outside of the LoadBB can value number equal, so + // quick exit. + if (LoadInvalidatedInBBBefore) + return; + + for (std::map >::iterator + I = CandidateStores.begin(), E = CandidateStores.end(); I != E; ++I) + if (DomSetInfo.dominates(I->first, LoadBB)) { + // Check to see if the path from the store to the load is transparent + // w.r.t. the memory location. + bool CantEqual = false; + std::set Visited; + for (pred_iterator PI = pred_begin(LoadBB), E = pred_end(LoadBB); + PI != E; ++PI) + if (!isPathTransparentTo(*PI, I->first, LoadPtr, LoadSize, AA, + Visited, TransparentBlocks)) { + // None of these stores can VN the same. + CantEqual = true; + break; + } + Visited.clear(); + if (!CantEqual) { + // Okay, the path from the store block to the load block is clear, and + // we know that there are no invalidating instructions from the start + // of the load block to the load itself. Now we just scan the store + // block. + + BasicBlock::iterator BBI = I->first->end(); + while (1) { + --BBI; + if (AA.getModRefInfo(BBI, LoadPtr, LoadSize)& AliasAnalysis::Mod){ + // If the invalidating instruction is one of the candidates, + // then it provides the value the load loads. + if (StoreInst *SI = dyn_cast(BBI)) + if (std::find(I->second.begin(), I->second.end(), SI) != + I->second.end()) + RetVals.push_back(SI->getOperand(0)); + break; + } + } + } + } +} Index: llvm/lib/Analysis/LoopInfo.cpp diff -u llvm/lib/Analysis/LoopInfo.cpp:1.46 llvm/lib/Analysis/LoopInfo.cpp:1.46.2.1 --- llvm/lib/Analysis/LoopInfo.cpp:1.46 Wed Jan 7 18:09:01 2004 +++ llvm/lib/Analysis/LoopInfo.cpp Mon Mar 1 17:58:12 2004 @@ -14,10 +14,10 @@ // //===----------------------------------------------------------------------===// -#include "llvm/Analysis/LoopInfo.h" #include "llvm/Analysis/Dominators.h" -#include "llvm/Support/CFG.h" +#include "llvm/Analysis/LoopInfo.h" #include "llvm/Assembly/Writer.h" +#include "llvm/Support/CFG.h" #include "Support/DepthFirstIterator.h" #include Index: llvm/lib/Analysis/ValueNumbering.cpp diff -u llvm/lib/Analysis/ValueNumbering.cpp:1.9 llvm/lib/Analysis/ValueNumbering.cpp:1.9.4.1 --- llvm/lib/Analysis/ValueNumbering.cpp:1.9 Wed Dec 10 23:05:56 2003 +++ llvm/lib/Analysis/ValueNumbering.cpp Mon Mar 1 17:58:12 2004 @@ -15,9 +15,9 @@ #include "llvm/Analysis/ValueNumbering.h" #include "llvm/Support/InstVisitor.h" #include "llvm/BasicBlock.h" +#include "llvm/Instructions.h" #include "llvm/Pass.h" #include "llvm/Type.h" -#include "llvm/iMemory.h" namespace llvm { @@ -104,17 +104,14 @@ for (Value::use_iterator UI = Op->use_begin(), UE = Op->use_end(); UI != UE; ++UI) - if (Instruction *Other = dyn_cast(*UI)) - // Check to see if this new cast is not I, but has the same operand... - if (Other != &I && Other->getOpcode() == I.getOpcode() && - Other->getOperand(0) == Op && // Is the operand the same? + if (CastInst *Other = dyn_cast(*UI)) + // Check that the types are the same, since this code handles casts... + if (Other->getType() == I.getType() && // Is it embedded in the same function? (This could be false if LHS // is a constant or global!) Other->getParent()->getParent() == F && - - // Check that the types are the same, since this code handles casts... - Other->getType() == I.getType()) { - + // Check to see if this new cast is not I. + Other != &I) { // These instructions are identical. Add to list... RetVals.push_back(Other); } From brukman at cs.uiuc.edu Mon Mar 1 18:03:22 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Mar 1 18:03:22 2004 Subject: [llvm-commits] [parallel] CVS: llvm/lib/Target/CBackend/CTargetMachine.h Makefile Writer.cpp Message-ID: <200403012358.RAA03794@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/CBackend: CTargetMachine.h added (r1.2.2.1) Makefile updated: 1.2 -> 1.2.6.1 Writer.cpp updated: 1.151 -> 1.151.4.1 --- Log message: Merge from trunk --- Diffs of the changes: (+227 -233) Index: llvm/lib/Target/CBackend/CTargetMachine.h diff -c /dev/null llvm/lib/Target/CBackend/CTargetMachine.h:1.2.2.1 *** /dev/null Mon Mar 1 17:58:27 2004 --- llvm/lib/Target/CBackend/CTargetMachine.h Mon Mar 1 17:58:13 2004 *************** *** 0 **** --- 1,38 ---- + //===-- CTargetMachine.h - TargetMachine for the C backend ------*- C++ -*-===// + // + // The LLVM Compiler Infrastructure + // + // This file was developed by the LLVM research group and is distributed under + // the University of Illinois Open Source License. See LICENSE.TXT for details. + // + //===----------------------------------------------------------------------===// + // + // This file declares the TargetMachine that is used by the C backend. + // + //===----------------------------------------------------------------------===// + + #ifndef CTARGETMACHINE_H + #define CTARGETMACHINE_H + + #include "llvm/Target/TargetMachine.h" + + namespace llvm { + class IntrinsicLowering; + + struct CTargetMachine : public TargetMachine { + CTargetMachine(const Module &M, IntrinsicLowering *IL) : + TargetMachine("CBackend", IL) {} + + virtual const TargetInstrInfo &getInstrInfo() const { abort(); } + virtual const TargetFrameInfo &getFrameInfo() const { abort(); } + virtual const TargetSchedInfo &getSchedInfo() const { abort(); } + virtual const TargetRegInfo &getRegInfo() const { abort(); } + + // This is the only thing that actually does anything here. + virtual bool addPassesToEmitAssembly(PassManager &PM, std::ostream &Out); + }; + + } // End llvm namespace + + + #endif Index: llvm/lib/Target/CBackend/Makefile diff -u llvm/lib/Target/CBackend/Makefile:1.2 llvm/lib/Target/CBackend/Makefile:1.2.6.1 --- llvm/lib/Target/CBackend/Makefile:1.2 Mon Oct 20 17:26:56 2003 +++ llvm/lib/Target/CBackend/Makefile Mon Mar 1 17:58:13 2004 @@ -1,4 +1,4 @@ -##===- lib/CWriter/Makefile --------------------------------*- Makefile -*-===## +##===- lib/Target/CBackend/Makefile ------------------------*- Makefile -*-===## # # The LLVM Compiler Infrastructure # @@ -7,9 +7,7 @@ # ##===----------------------------------------------------------------------===## -LEVEL = ../.. - +LEVEL = ../../.. LIBRARYNAME = cwriter - include $(LEVEL)/Makefile.common Index: llvm/lib/Target/CBackend/Writer.cpp diff -u llvm/lib/Target/CBackend/Writer.cpp:1.151 llvm/lib/Target/CBackend/Writer.cpp:1.151.4.1 --- llvm/lib/Target/CBackend/Writer.cpp:1.151 Wed Dec 10 18:24:36 2003 +++ llvm/lib/Target/CBackend/Writer.cpp Mon Mar 1 17:58:13 2004 @@ -7,70 +7,70 @@ // //===----------------------------------------------------------------------===// // -// This library converts LLVM code to C code, compilable by GCC. +// This library converts LLVM code to C code, compilable by GCC and other C +// compilers. // //===----------------------------------------------------------------------===// -#include "llvm/Assembly/CWriter.h" +#include "CTargetMachine.h" +#include "llvm/Target/TargetMachineImpls.h" #include "llvm/Constants.h" #include "llvm/DerivedTypes.h" #include "llvm/Module.h" #include "llvm/Instructions.h" #include "llvm/Pass.h" +#include "llvm/PassManager.h" #include "llvm/SymbolTable.h" #include "llvm/Intrinsics.h" +#include "llvm/IntrinsicLowering.h" #include "llvm/Analysis/FindUsedTypes.h" #include "llvm/Analysis/ConstantsScanner.h" +#include "llvm/Transforms/Scalar.h" #include "llvm/Support/CallSite.h" #include "llvm/Support/GetElementPtrTypeIterator.h" #include "llvm/Support/InstVisitor.h" -#include "llvm/Support/InstIterator.h" #include "llvm/Support/Mangler.h" #include "Support/StringExtras.h" -#include "Support/STLExtras.h" #include "Config/config.h" #include #include - -namespace llvm { +using namespace llvm; namespace { class CWriter : public Pass, public InstVisitor { std::ostream &Out; + IntrinsicLowering &IL; Mangler *Mang; const Module *TheModule; FindUsedTypes *FUT; std::map TypeNames; - std::set MangledGlobals; - bool needsMalloc, emittedInvoke; std::map FPConstantMap; public: - CWriter(std::ostream &o) : Out(o) {} + CWriter(std::ostream &o, IntrinsicLowering &il) : Out(o), IL(il) {} void getAnalysisUsage(AnalysisUsage &AU) const { - AU.setPreservesAll(); AU.addRequired(); } - virtual bool run(Module &M) { - // Initialize - TheModule = &M; - FUT = &getAnalysis(); - - // Ensure that all structure types have names... - bool Changed = nameAllUsedStructureTypes(M); - Mang = new Mangler(M); + virtual const char *getPassName() const { return "C backend"; } - // Run... - printModule(&M); + bool doInitialization(Module &M); + bool run(Module &M) { + // First pass, lower all unhandled intrinsics. + lowerIntrinsics(M); + + doInitialization(M); + + for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) + if (!I->isExternal()) + printFunction(*I); // Free memory... delete Mang; TypeNames.clear(); - MangledGlobals.clear(); - return false; + return true; } std::ostream &printType(std::ostream &Out, const Type *Ty, @@ -81,6 +81,8 @@ void writeOperandInternal(Value *Operand); private : + void lowerIntrinsics(Module &M); + bool nameAllUsedStructureTypes(Module &M); void printModule(Module *M); void printFloatingPointConstants(Module &M); @@ -88,7 +90,7 @@ void printContainedStructs(const Type *Ty, std::set &); void printFunctionSignature(const Function *F, bool Prototype); - void printFunction(Function *); + void printFunction(Function &); void printConstant(Constant *CPV); void printConstantArray(ConstantArray *CPA); @@ -164,6 +166,7 @@ void printIndexingExpression(Value *Ptr, gep_type_iterator I, gep_type_iterator E); }; +} // Pass the Type* and the variable name and this prints out the variable // declaration. @@ -201,17 +204,16 @@ const FunctionType *MTy = cast(Ty); std::stringstream FunctionInnards; FunctionInnards << " (" << NameSoFar << ") ("; - for (FunctionType::ParamTypes::const_iterator - I = MTy->getParamTypes().begin(), - E = MTy->getParamTypes().end(); I != E; ++I) { - if (I != MTy->getParamTypes().begin()) + for (FunctionType::param_iterator I = MTy->param_begin(), + E = MTy->param_end(); I != E; ++I) { + if (I != MTy->param_begin()) FunctionInnards << ", "; printType(FunctionInnards, *I, ""); } if (MTy->isVarArg()) { - if (!MTy->getParamTypes().empty()) + if (MTy->getNumParams()) FunctionInnards << ", ..."; - } else if (MTy->getParamTypes().empty()) { + } else if (!MTy->getNumParams()) { FunctionInnards << "void"; } FunctionInnards << ")"; @@ -223,9 +225,8 @@ const StructType *STy = cast(Ty); Out << NameSoFar + " {\n"; unsigned Idx = 0; - for (StructType::ElementTypes::const_iterator - I = STy->getElementTypes().begin(), - E = STy->getElementTypes().end(); I != E; ++I) { + for (StructType::element_iterator I = STy->element_begin(), + E = STy->element_end(); I != E; ++I) { Out << " "; printType(Out, *I, "field" + utostr(Idx++)); Out << ";\n"; @@ -475,22 +476,50 @@ } case Type::ArrayTyID: - printConstantArray(cast(CPV)); + if (isa(CPV)) { + const ArrayType *AT = cast(CPV->getType()); + Out << "{"; + if (AT->getNumElements()) { + Out << " "; + Constant *CZ = Constant::getNullValue(AT->getElementType()); + printConstant(CZ); + for (unsigned i = 1, e = AT->getNumElements(); i != e; ++i) { + Out << ", "; + printConstant(CZ); + } + } + Out << " }"; + } else { + printConstantArray(cast(CPV)); + } break; - case Type::StructTyID: { - Out << "{"; - if (CPV->getNumOperands()) { - Out << " "; - printConstant(cast(CPV->getOperand(0))); - for (unsigned i = 1, e = CPV->getNumOperands(); i != e; ++i) { - Out << ", "; - printConstant(cast(CPV->getOperand(i))); + case Type::StructTyID: + if (isa(CPV)) { + const StructType *ST = cast(CPV->getType()); + Out << "{"; + if (ST->getNumElements()) { + Out << " "; + printConstant(Constant::getNullValue(ST->getElementType(0))); + for (unsigned i = 1, e = ST->getNumElements(); i != e; ++i) { + Out << ", "; + printConstant(Constant::getNullValue(ST->getElementType(i))); + } + } + Out << " }"; + } else { + Out << "{"; + if (CPV->getNumOperands()) { + Out << " "; + printConstant(cast(CPV->getOperand(0))); + for (unsigned i = 1, e = CPV->getNumOperands(); i != e; ++i) { + Out << ", "; + printConstant(cast(CPV->getOperand(i))); + } } + Out << " }"; } - Out << " }"; break; - } case Type::PointerTyID: if (isa(CPV)) { @@ -609,55 +638,20 @@ << "#endif\n\n"; } -// generateProcessorSpecificCode - This is where we add conditional compilation -// directives to cater to specific processors as need be. -// -static void generateProcessorSpecificCode(std::ostream& Out) { - // According to ANSI C, longjmp'ing to a setjmp could invalidate any - // non-volatile variable in the scope of the setjmp. For now, we are not - // doing analysis to determine which variables need to be marked volatile, so - // we just mark them all. - // - // HOWEVER, many targets implement setjmp by saving and restoring the register - // file, so they DON'T need variables to be marked volatile, and this is a - // HUGE pessimization for them. For this reason, on known-good processors, we - // do not emit volatile qualifiers. - Out << "#if defined(__386__) || defined(__i386__) || \\\n" - << " defined(i386) || defined(WIN32)\n" - << "/* setjmp does not require variables to be marked volatile */" - << "#define VOLATILE_FOR_SETJMP\n" - << "#else\n" - << "#define VOLATILE_FOR_SETJMP volatile\n" - << "#endif\n\n"; -} - - -void CWriter::printModule(Module *M) { - // Calculate which global values have names that will collide when we throw - // away type information. - { // Scope to delete the FoundNames set when we are done with it... - std::set FoundNames; - for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I) - if (I->hasName()) // If the global has a name... - if (FoundNames.count(I->getName())) // And the name is already used - MangledGlobals.insert(I); // Mangle the name - else - FoundNames.insert(I->getName()); // Otherwise, keep track of name - - for (Module::giterator I = M->gbegin(), E = M->gend(); I != E; ++I) - if (I->hasName()) // If the global has a name... - if (FoundNames.count(I->getName())) // And the name is already used - MangledGlobals.insert(I); // Mangle the name - else - FoundNames.insert(I->getName()); // Otherwise, keep track of name - } +bool CWriter::doInitialization(Module &M) { + // Initialize + TheModule = &M; + FUT = &getAnalysis(); + + // Ensure that all structure types have names... + bool Changed = nameAllUsedStructureTypes(M); + Mang = new Mangler(M); // get declaration for alloca Out << "/* Provide Declarations */\n"; Out << "#include \n"; // Varargs support Out << "#include \n"; // Unwind support generateCompilerSpecificCode(Out); - generateProcessorSpecificCode(Out); // Provide a definition for `bool' if not compiling with a C++ compiler. Out << "\n" @@ -667,11 +661,6 @@ << "typedef unsigned long long ConstantDoubleTy;\n" << "typedef unsigned int ConstantFloatTy;\n" - << "\n\n/* Support for the invoke instruction */\n" - << "extern struct __llvm_jmpbuf_list_t {\n" - << " jmp_buf buf; struct __llvm_jmpbuf_list_t *next;\n" - << "} *__llvm_jmpbuf_list;\n" - << "\n\n/* Global Declarations */\n"; // First output all the declarations for the program, because C requires @@ -679,12 +668,12 @@ // // Loop over the symbol table, emitting all named constants... - printSymbolTable(M->getSymbolTable()); + printSymbolTable(M.getSymbolTable()); // Global variable declarations... - if (!M->gempty()) { + if (!M.gempty()) { Out << "\n/* External Global Variable Declarations */\n"; - for (Module::giterator I = M->gbegin(), E = M->gend(); I != E; ++I) { + for (Module::giterator I = M.gbegin(), E = M.gend(); I != E; ++I) { if (I->hasExternalLinkage()) { Out << "extern "; printType(Out, I->getType()->getElementType(), Mang->getValueName(I)); @@ -694,32 +683,23 @@ } // Function declarations - if (!M->empty()) { + if (!M.empty()) { Out << "\n/* Function Declarations */\n"; - needsMalloc = true; - for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I) { - // If the function is external and the name collides don't print it. - // Sometimes the bytecode likes to have multiple "declarations" for - // external functions - if ((I->hasInternalLinkage() || !MangledGlobals.count(I)) && - !I->getIntrinsicID()) { + for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) { + // Don't print declarations for intrinsic functions. + if (!I->getIntrinsicID()) { printFunctionSignature(I, true); if (I->hasWeakLinkage()) Out << " __ATTRIBUTE_WEAK__"; + if (I->hasLinkOnceLinkage()) Out << " __ATTRIBUTE_WEAK__"; Out << ";\n"; } } } - // Print Malloc prototype if needed - if (needsMalloc) { - Out << "\n/* Malloc to make sun happy */\n"; - Out << "extern void * malloc();\n\n"; - } - // Output the global variable declarations - if (!M->gempty()) { + if (!M.gempty()) { Out << "\n\n/* Global Variable Declarations */\n"; - for (Module::giterator I = M->gbegin(), E = M->gend(); I != E; ++I) + for (Module::giterator I = M.gbegin(), E = M.gend(); I != E; ++I) if (!I->isExternal()) { Out << "extern "; printType(Out, I->getType()->getElementType(), Mang->getValueName(I)); @@ -733,9 +713,9 @@ } // Output the global variable definitions and contents... - if (!M->gempty()) { + if (!M.gempty()) { Out << "\n\n/* Global Variable Definitions and Initialization */\n"; - for (Module::giterator I = M->gbegin(), E = M->gend(); I != E; ++I) + for (Module::giterator I = M.gbegin(), E = M.gend(); I != E; ++I) if (!I->isExternal()) { if (I->hasInternalLinkage()) Out << "static "; @@ -750,38 +730,35 @@ // this, however, occurs when the variable has weak linkage. In this // case, the assembler will complain about the variable being both weak // and common, so we disable this optimization. - if (!I->getInitializer()->isNullValue() || - I->hasWeakLinkage()) { + if (!I->getInitializer()->isNullValue()) { Out << " = " ; writeOperand(I->getInitializer()); + } else if (I->hasWeakLinkage()) { + // We have to specify an initializer, but it doesn't have to be + // complete. If the value is an aggregate, print out { 0 }, and let + // the compiler figure out the rest of the zeros. + Out << " = " ; + if (isa(I->getInitializer()->getType()) || + isa(I->getInitializer()->getType())) { + Out << "{ 0 }"; + } else { + // Just print it out normally. + writeOperand(I->getInitializer()); + } } Out << ";\n"; } } // Output all floating point constants that cannot be printed accurately... - printFloatingPointConstants(*M); + printFloatingPointConstants(M); - // Output all of the functions... - emittedInvoke = false; - if (!M->empty()) { + if (!M.empty()) Out << "\n\n/* Function Bodies */\n"; - for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I) - printFunction(I); - } - - // If the program included an invoke instruction, we need to output the - // support code for it here! - if (emittedInvoke) { - Out << "\n/* More support for the invoke instruction */\n" - << "struct __llvm_jmpbuf_list_t *__llvm_jmpbuf_list " - << "__attribute__((common)) = 0;\n"; - } - - // Done with global FP constants - FPConstantMap.clear(); + return false; } + /// Output all floating point constants that cannot be printed accurately... void CWriter::printFloatingPointConstants(Module &M) { union { @@ -812,12 +789,12 @@ if (FPC->getType() == Type::DoubleTy) { DBLUnion.D = Val; - Out << "const ConstantDoubleTy FPConstant" << FPCounter++ + Out << "static const ConstantDoubleTy FPConstant" << FPCounter++ << " = 0x" << std::hex << DBLUnion.U << std::dec << "ULL; /* " << Val << " */\n"; } else if (FPC->getType() == Type::FloatTy) { FLTUnion.F = Val; - Out << "const ConstantFloatTy FPConstant" << FPCounter++ + Out << "static const ConstantFloatTy FPConstant" << FPCounter++ << " = 0x" << std::hex << FLTUnion.U << std::dec << "U; /* " << Val << " */\n"; } else @@ -889,9 +866,8 @@ //Check to see if we have already printed this struct if (StructPrinted.count(STy) == 0) { // Print all contained types first... - for (StructType::ElementTypes::const_iterator - I = STy->getElementTypes().begin(), - E = STy->getElementTypes().end(); I != E; ++I) { + for (StructType::element_iterator I = STy->element_begin(), + E = STy->element_end(); I != E; ++I) { const Type *Ty1 = I->get(); if (isa(Ty1) || isa(Ty1)) printContainedStructs(*I, StructPrinted); @@ -914,13 +890,7 @@ void CWriter::printFunctionSignature(const Function *F, bool Prototype) { - // If the program provides its own malloc prototype we don't need - // to include the general one. - if (Mang->getValueName(F) == "malloc") - needsMalloc = false; - if (F->hasInternalLinkage()) Out << "static "; - if (F->hasLinkOnceLinkage()) Out << "inline "; // Loop over the arguments, printing them... const FunctionType *FT = cast(F->getFunctionType()); @@ -948,10 +918,9 @@ } } else { // Loop over the arguments, printing them... - for (FunctionType::ParamTypes::const_iterator I = - FT->getParamTypes().begin(), - E = FT->getParamTypes().end(); I != E; ++I) { - if (I != FT->getParamTypes().begin()) FunctionInnards << ", "; + for (FunctionType::param_iterator I = FT->param_begin(), + E = FT->param_end(); I != E; ++I) { + if (I != FT->param_begin()) FunctionInnards << ", "; printType(FunctionInnards, *I); } } @@ -959,10 +928,10 @@ // Finish printing arguments... if this is a vararg function, print the ..., // unless there are no known types, in which case, we just emit (). // - if (FT->isVarArg() && !FT->getParamTypes().empty()) { - if (FT->getParamTypes().size()) FunctionInnards << ", "; + if (FT->isVarArg() && FT->getNumParams()) { + if (FT->getNumParams()) FunctionInnards << ", "; FunctionInnards << "..."; // Output varargs portion of signature! - } else if (!FT->isVarArg() && FT->getParamTypes().empty()) { + } else if (!FT->isVarArg() && FT->getNumParams() == 0) { FunctionInnards << "void"; // ret() -> ret(void) in C. } FunctionInnards << ")"; @@ -970,36 +939,23 @@ printType(Out, F->getReturnType(), FunctionInnards.str()); } -void CWriter::printFunction(Function *F) { - if (F->isExternal()) return; - - printFunctionSignature(F, false); +void CWriter::printFunction(Function &F) { + printFunctionSignature(&F, false); Out << " {\n"; - // Determine whether or not the function contains any invoke instructions. - bool HasInvoke = false; - for (Function::iterator I = F->begin(), E = F->end(); I != E; ++I) - if (isa(I->getTerminator())) { - HasInvoke = true; - break; - } - // print local variable information for the function - for (inst_iterator I = inst_begin(F), E = inst_end(F); I != E; ++I) + for (inst_iterator I = inst_begin(&F), E = inst_end(&F); I != E; ++I) if (const AllocaInst *AI = isDirectAlloca(*I)) { Out << " "; - if (HasInvoke) Out << "VOLATILE_FOR_SETJMP "; printType(Out, AI->getAllocatedType(), Mang->getValueName(AI)); Out << "; /* Address exposed local */\n"; } else if ((*I)->getType() != Type::VoidTy && !isInlinableInst(**I)) { Out << " "; - if (HasInvoke) Out << "VOLATILE_FOR_SETJMP "; printType(Out, (*I)->getType(), Mang->getValueName(*I)); Out << ";\n"; if (isa(*I)) { // Print out PHI node temporaries as well... Out << " "; - if (HasInvoke) Out << "VOLATILE_FOR_SETJMP "; printType(Out, (*I)->getType(), Mang->getValueName(*I)+"__PHI_TEMPORARY"); Out << ";\n"; @@ -1009,7 +965,7 @@ Out << "\n"; // print the basic blocks - for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB) { + for (Function::iterator BB = F.begin(), E = F.end(); BB != E; ++BB) { BasicBlock *Prev = BB->getPrev(); // Don't print the label for the basic block if there are no uses, or if the @@ -1087,43 +1043,12 @@ } void CWriter::visitInvokeInst(InvokeInst &II) { - Out << " {\n" - << " struct __llvm_jmpbuf_list_t Entry;\n" - << " Entry.next = __llvm_jmpbuf_list;\n" - << " if (setjmp(Entry.buf)) {\n" - << " __llvm_jmpbuf_list = Entry.next;\n"; - printBranchToBlock(II.getParent(), II.getExceptionalDest(), 4); - Out << " }\n" - << " __llvm_jmpbuf_list = &Entry;\n" - << " "; - - if (II.getType() != Type::VoidTy) outputLValue(&II); - visitCallSite(&II); - Out << ";\n" - << " __llvm_jmpbuf_list = Entry.next;\n" - << " }\n"; - printBranchToBlock(II.getParent(), II.getNormalDest(), 0); - emittedInvoke = true; + assert(0 && "Lowerinvoke pass didn't work!"); } void CWriter::visitUnwindInst(UnwindInst &I) { - // The unwind instructions causes a control flow transfer out of the current - // function, unwinding the stack until a caller who used the invoke - // instruction is found. In this context, we code generated the invoke - // instruction to add an entry to the top of the jmpbuf_list. Thus, here we - // just have to longjmp to the specified handler. - Out << " if (__llvm_jmpbuf_list == 0) { /* unwind */\n" - << "#ifdef _LP64\n" - << " extern signed long long write();\n" - << "#else\n" - << " extern write();\n" - << "#endif\n" - << " ((void (*)(int, void*, unsigned))write)(2,\n" - << " \"throw found with no handler!\\n\", 31); abort();\n" - << " }\n" - << " longjmp(__llvm_jmpbuf_list->buf, 1);\n"; - emittedInvoke = true; + assert(0 && "Lowerinvoke pass didn't work!"); } bool isGotoCodeNecessary(BasicBlock *From, BasicBlock *To) { @@ -1260,12 +1185,43 @@ writeOperand(I.getOperand(0)); } +void CWriter::lowerIntrinsics(Module &M) { + for (Module::iterator F = M.begin(), E = M.end(); F != E; ++F) + for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB) + for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ) + if (CallInst *CI = dyn_cast(I++)) + if (Function *F = CI->getCalledFunction()) + switch (F->getIntrinsicID()) { + case Intrinsic::not_intrinsic: + case Intrinsic::va_start: + case Intrinsic::va_copy: + case Intrinsic::va_end: + case Intrinsic::returnaddress: + case Intrinsic::frameaddress: + case Intrinsic::setjmp: + case Intrinsic::longjmp: + // We directly implement these intrinsics + break; + default: + // All other intrinsic calls we must lower. + Instruction *Before = CI->getPrev(); + IL.LowerIntrinsicCall(CI); + if (Before) { // Move iterator to instruction after call + I = Before; ++I; + } else { + I = BB->begin(); + } + } +} + + + void CWriter::visitCallInst(CallInst &I) { // Handle intrinsic function calls first... if (Function *F = I.getCalledFunction()) if (Intrinsic::ID ID = (Intrinsic::ID)F->getIntrinsicID()) { switch (ID) { - default: assert(0 && "Unknown LLVM intrinsic!"); + default: assert(0 && "Unknown LLVM intrinsic!"); case Intrinsic::va_start: Out << "0; "; @@ -1292,19 +1248,27 @@ writeOperand(I.getOperand(1)); Out << ")"; return; + case Intrinsic::returnaddress: + Out << "__builtin_return_address("; + writeOperand(I.getOperand(1)); + Out << ")"; + return; + case Intrinsic::frameaddress: + Out << "__builtin_frame_address("; + writeOperand(I.getOperand(1)); + Out << ")"; + return; case Intrinsic::setjmp: - case Intrinsic::sigsetjmp: - // This intrinsic should never exist in the program, but until we get - // setjmp/longjmp transformations going on, we should codegen it to - // something reasonable. This will allow code that never calls longjmp - // to work. - Out << "0"; + Out << "setjmp(*(jmp_buf*)"; + writeOperand(I.getOperand(1)); + Out << ")"; return; case Intrinsic::longjmp: - case Intrinsic::siglongjmp: - // Longjmp is not implemented, and never will be. It would cause an - // exception throw. - Out << "abort()"; + Out << "longjmp(*(jmp_buf*)"; + writeOperand(I.getOperand(1)); + Out << ", "; + writeOperand(I.getOperand(2)); + Out << ")"; return; } } @@ -1332,17 +1296,7 @@ } void CWriter::visitMallocInst(MallocInst &I) { - Out << "("; - printType(Out, I.getType()); - Out << ")malloc(sizeof("; - printType(Out, I.getType()->getElementType()); - Out << ")"; - - if (I.isArrayAllocation()) { - Out << " * " ; - writeOperand(I.getOperand(0)); - } - Out << ")"; + assert(0 && "lowerallocations pass didn't work!"); } void CWriter::visitAllocaInst(AllocaInst &I) { @@ -1359,9 +1313,7 @@ } void CWriter::visitFreeInst(FreeInst &I) { - Out << "free((char*)"; - writeOperand(I.getOperand(0)); - Out << ")"; + assert(0 && "lowerallocations pass didn't work!"); } void CWriter::printIndexingExpression(Value *Ptr, gep_type_iterator I, @@ -1456,12 +1408,18 @@ Out << ");\n va_end(Tmp); }"; } -} - //===----------------------------------------------------------------------===// // External Interface declaration //===----------------------------------------------------------------------===// -Pass *createWriteToCPass(std::ostream &o) { return new CWriter(o); } +bool CTargetMachine::addPassesToEmitAssembly(PassManager &PM, std::ostream &o) { + PM.add(createLowerAllocationsPass()); + PM.add(createLowerInvokePass()); + PM.add(new CWriter(o, getIntrinsicLowering())); + return false; +} -} // End llvm namespace +TargetMachine *llvm::allocateCTargetMachine(const Module &M, + IntrinsicLowering *IL) { + return new CTargetMachine(M, IL); +} From brukman at cs.uiuc.edu Mon Mar 1 18:03:30 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Mar 1 18:03:30 2004 Subject: [llvm-commits] [parallel] CVS: llvm/lib/Support/Annotation.cpp LeakDetector.cpp Mangler.cpp PluginLoader.cpp Signals.cpp ToolRunner.cpp Message-ID: <200403012358.RAA03893@zion.cs.uiuc.edu> Changes in directory llvm/lib/Support: Annotation.cpp updated: 1.13 -> 1.13.2.1 LeakDetector.cpp updated: 1.6 -> 1.6.2.1 Mangler.cpp updated: 1.8 -> 1.8.2.1 PluginLoader.cpp updated: 1.8 -> 1.8.2.1 Signals.cpp updated: 1.11 -> 1.11.2.1 ToolRunner.cpp updated: 1.13 -> 1.13.2.1 --- Log message: Merge from trunk --- Diffs of the changes: (+267 -153) Index: llvm/lib/Support/Annotation.cpp diff -u llvm/lib/Support/Annotation.cpp:1.13 llvm/lib/Support/Annotation.cpp:1.13.2.1 --- llvm/lib/Support/Annotation.cpp:1.13 Sun Dec 14 15:35:53 2003 +++ llvm/lib/Support/Annotation.cpp Mon Mar 1 17:58:13 2004 @@ -15,6 +15,18 @@ #include "Support/Annotation.h" using namespace llvm; +Annotation::~Annotation() {} // Designed to be subclassed + +Annotable::~Annotable() { // Virtual because it's designed to be subclassed... + Annotation *A = AnnotationList; + while (A) { + Annotation *Next = A->getNext(); + delete A; + A = Next; + } +} + + typedef std::map IDMapType; static unsigned IDCounter = 0; // Unique ID counter @@ -40,7 +52,6 @@ TheFactMap = 0; } } - AnnotationID AnnotationManager::getID(const std::string &Name) { // Name -> ID IDMapType::iterator I = getIDMap().find(Name); Index: llvm/lib/Support/LeakDetector.cpp diff -u llvm/lib/Support/LeakDetector.cpp:1.6 llvm/lib/Support/LeakDetector.cpp:1.6.2.1 --- llvm/lib/Support/LeakDetector.cpp:1.6 Sun Dec 14 15:35:53 2003 +++ llvm/lib/Support/LeakDetector.cpp Mon Mar 1 17:58:13 2004 @@ -16,75 +16,95 @@ #include using namespace llvm; -// Lazily allocate set so that release build doesn't have to do anything. -static std::set *Objects = 0; -static std::set *LLVMObjects = 0; - -// Because the most common usage pattern, by far, is to add a garbage object, -// then remove it immediately, we optimize this case. When an object is added, -// it is not added to the set immediately, it is added to the CachedValue Value. -// If it is immediately removed, no set search need be performed. -// -static const Value *CachedValue; +namespace { + template + struct LeakDetectorImpl { + LeakDetectorImpl(const char* const name) : Cache(0), Name(name) { } + + // Because the most common usage pattern, by far, is to add a + // garbage object, then remove it immediately, we optimize this + // case. When an object is added, it is not added to the set + // immediately, it is added to the CachedValue Value. If it is + // immediately removed, no set search need be performed. + void addGarbage(const T* o) { + if (Cache) { + assert(Ts.count(Cache) == 0 && "Object already in set!"); + Ts.insert(Cache); + } + Cache = o; + } -void LeakDetector::addGarbageObjectImpl(void *Object) { - if (Objects == 0) - Objects = new std::set(); - assert(Objects->count(Object) == 0 && "Object already in set!"); - Objects->insert(Object); + void removeGarbage(const T* o) { + if (o == Cache) + Cache = 0; // Cache hit + else + Ts.erase(o); + } + + bool hasGarbage(const std::string& Message) { + addGarbage(0); // Flush the Cache + + assert(Cache == 0 && "No value should be cached anymore!"); + + if (!Ts.empty()) { + std::cerr + << "Leaked " << Name << " objects found: " << Message << ":\n\t"; + std::copy(Ts.begin(), Ts.end(), + std::ostream_iterator(std::cerr, " ")); + std::cerr << '\n'; + + // Clear out results so we don't get duplicate warnings on + // next call... + Ts.clear(); + return true; + } + return false; + } + + private: + std::set Ts; + const T* Cache; + const char* const Name; + }; + + typedef LeakDetectorImpl Objects; + typedef LeakDetectorImpl LLVMObjects; + + Objects& getObjects() { + static Objects *o = 0; + if (o == 0) + o = new Objects("GENERIC"); + return *o; + } + + LLVMObjects& getLLVMObjects() { + static LLVMObjects *o = 0; + if (o == 0) + o = new LLVMObjects("LLVM"); + return *o; + } } -void LeakDetector::removeGarbageObjectImpl(void *Object) { - if (Objects) - Objects->erase(Object); +void LeakDetector::addGarbageObjectImpl(void *Object) { + getObjects().addGarbage(Object); } void LeakDetector::addGarbageObjectImpl(const Value *Object) { - if (CachedValue) { - if (LLVMObjects == 0) - LLVMObjects = new std::set(); - assert(LLVMObjects->count(CachedValue) == 0 && "Object already in set!"); - LLVMObjects->insert(CachedValue); - } - CachedValue = Object; + getLLVMObjects().addGarbage(Object); +} + +void LeakDetector::removeGarbageObjectImpl(void *Object) { + getObjects().removeGarbage(Object); } void LeakDetector::removeGarbageObjectImpl(const Value *Object) { - if (Object == CachedValue) - CachedValue = 0; // Cache hit! - else if (LLVMObjects) - LLVMObjects->erase(Object); + getLLVMObjects().removeGarbage(Object); } void LeakDetector::checkForGarbageImpl(const std::string &Message) { - if (CachedValue) // Flush the cache to the set... - addGarbageObjectImpl((Value*)0); - - assert(CachedValue == 0 && "No value should be cached anymore!"); - - if ((Objects && !Objects->empty()) || (LLVMObjects && !LLVMObjects->empty())){ - std::cerr << "Leaked objects found: " << Message << "\n"; - - if (Objects && !Objects->empty()) { - std::cerr << " Non-Value objects leaked:"; - for (std::set::iterator I = Objects->begin(), - E = Objects->end(); I != E; ++I) - std::cerr << " " << *I; - } - - if (LLVMObjects && !LLVMObjects->empty()) { - std::cerr << " LLVM Value subclasses leaked:"; - for (std::set::iterator I = LLVMObjects->begin(), - E = LLVMObjects->end(); I != E; ++I) - std::cerr << **I << "\n"; - } - - std::cerr << "This is probably because you removed an LLVM value " - << "(Instruction, BasicBlock, \netc), but didn't delete it. " - << "Please check your code for memory leaks.\n"; - - // Clear out results so we don't get duplicate warnings on next call... - delete Objects; delete LLVMObjects; - Objects = 0; LLVMObjects = 0; - } + // use non-short-circuit version so that both checks are performed + if (getObjects().hasGarbage(Message) | + getLLVMObjects().hasGarbage(Message)) + std::cerr << "\nThis is probably because you removed an object, but didn't " + "delete it. Please check your code for memory leaks.\n"; } Index: llvm/lib/Support/Mangler.cpp diff -u llvm/lib/Support/Mangler.cpp:1.8 llvm/lib/Support/Mangler.cpp:1.8.2.1 --- llvm/lib/Support/Mangler.cpp:1.8 Sun Dec 14 15:35:53 2003 +++ llvm/lib/Support/Mangler.cpp Mon Mar 1 17:58:13 2004 @@ -80,22 +80,37 @@ return name; } +void Mangler::InsertName(GlobalValue *GV, + std::map &Names) { + if (!GV->hasName()) { // We must mangle unnamed globals. + MangledGlobals.insert(GV); + return; + } + + // Figure out if this is already used. + GlobalValue *&ExistingValue = Names[GV->getName()]; + if (!ExistingValue) { + ExistingValue = GV; + } else { + // If GV is external but the existing one is static, mangle the existing one + if (GV->hasExternalLinkage() && !ExistingValue->hasExternalLinkage()) { + MangledGlobals.insert(ExistingValue); + ExistingValue = GV; + } else { + // Otherwise, mangle GV + MangledGlobals.insert(GV); + } + } +} + + Mangler::Mangler(Module &m, bool addUnderscorePrefix) - : M(m), AddUnderscorePrefix(addUnderscorePrefix) { + : M(m), AddUnderscorePrefix(addUnderscorePrefix), Count(0) { // Calculate which global values have names that will collide when we throw // away type information. - std::set FoundNames; + std::map Names; for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) - if (I->hasName()) // If the global has a name... - if (FoundNames.count(I->getName())) // And the name is already used - MangledGlobals.insert(I); // Mangle the name - else - FoundNames.insert(I->getName()); // Otherwise, keep track of name - + InsertName(I, Names); for (Module::giterator I = M.gbegin(), E = M.gend(); I != E; ++I) - if (I->hasName()) // If the global has a name... - if (FoundNames.count(I->getName())) // And the name is already used - MangledGlobals.insert(I); // Mangle the name - else - FoundNames.insert(I->getName()); // Otherwise, keep track of name + InsertName(I, Names); } Index: llvm/lib/Support/PluginLoader.cpp diff -u llvm/lib/Support/PluginLoader.cpp:1.8 llvm/lib/Support/PluginLoader.cpp:1.8.2.1 --- llvm/lib/Support/PluginLoader.cpp:1.8 Sun Dec 14 15:35:53 2003 +++ llvm/lib/Support/PluginLoader.cpp Mon Mar 1 17:58:13 2004 @@ -37,5 +37,5 @@ // This causes operator= above to be invoked for every -load option. static cl::opt > -LoadOpt("load", cl::ZeroOrMore, cl::value_desc("plugin.so"), +LoadOpt("load", cl::ZeroOrMore, cl::value_desc("plugin" SHLIBEXT), cl::desc("Load the specified plugin")); Index: llvm/lib/Support/Signals.cpp diff -u llvm/lib/Support/Signals.cpp:1.11 llvm/lib/Support/Signals.cpp:1.11.2.1 --- llvm/lib/Support/Signals.cpp:1.11 Sun Dec 14 15:35:53 2003 +++ llvm/lib/Support/Signals.cpp Mon Mar 1 17:58:13 2004 @@ -17,8 +17,14 @@ #include #include #include -#include #include "Config/config.h" // Get the signal handler return type +#ifdef HAVE_EXECINFO_H +# include // For backtrace(). +#endif +#include +#include +#include +#include using namespace llvm; static std::vector FilesToRemove; @@ -39,6 +45,65 @@ }; static const int *KillSigsEnd = KillSigs + sizeof(KillSigs)/sizeof(KillSigs[0]); +#ifdef HAVE_BACKTRACE +static void* StackTrace[256]; +#endif + + +// PrintStackTrace - In the case of a program crash or fault, print out a stack +// trace so that the user has an indication of why and where we died. +// +// On glibc systems we have the 'backtrace' function, which works nicely, but +// doesn't demangle symbols. In order to backtrace symbols, we fork and exec a +// 'c++filt' process to do the demangling. This seems like the simplest and +// most robust solution when we can't allocate memory (such as in a signal +// handler). If we can't find 'c++filt', we fallback to printing mangled names. +// +static void PrintStackTrace() { +#ifdef HAVE_BACKTRACE + // Use backtrace() to output a backtrace on Linux systems with glibc. + int depth = backtrace(StackTrace, sizeof(StackTrace)/sizeof(StackTrace[0])); + + // Create a one-way unix pipe. The backtracing process writes to PipeFDs[1], + // the c++filt process reads from PipeFDs[0]. + int PipeFDs[2]; + if (pipe(PipeFDs)) { + backtrace_symbols_fd(StackTrace, depth, STDERR_FILENO); + return; + } + + switch (pid_t ChildPID = fork()) { + case -1: // Error forking, print mangled stack trace + close(PipeFDs[0]); + close(PipeFDs[1]); + backtrace_symbols_fd(StackTrace, depth, STDERR_FILENO); + return; + default: // backtracing process + close(PipeFDs[0]); // Close the reader side. + + // Print the mangled backtrace into the pipe. + backtrace_symbols_fd(StackTrace, depth, PipeFDs[1]); + close(PipeFDs[1]); // We are done writing. + while (waitpid(ChildPID, 0, 0) == -1) + if (errno != EINTR) break; + return; + + case 0: // c++filt process + close(PipeFDs[1]); // Close the writer side. + dup2(PipeFDs[0], 0); // Read from standard input + close(PipeFDs[0]); // Close the old descriptor + dup2(2, 1); // Revector stdout -> stderr + + // Try to run c++filt or gc++filt. If neither is found, call back on 'cat' + // to print the mangled stack trace. If we can't find cat, just exit. + execlp("c++filt", "c++filt", 0); + execlp("gc++filt", "gc++filt", 0); + execlp("cat", "cat", 0); + execlp("/bin/cat", "cat", 0); + exit(0); + } +#endif +} // SignalHandler - The signal handler that runs... static RETSIGTYPE SignalHandler(int Sig) { @@ -50,7 +115,9 @@ if (std::find(IntSigs, IntSigsEnd, Sig) != IntSigsEnd) exit(1); // If this is an interrupt signal, exit the program - // Otherwise if it is a fault (like SEGV) reissue the signal to die... + // Otherwise if it is a fault (like SEGV) output the stacktrace to + // STDERR (if we can) and reissue the signal to die... + PrintStackTrace(); signal(Sig, SIG_DFL); } @@ -61,5 +128,11 @@ FilesToRemove.push_back(Filename); std::for_each(IntSigs, IntSigsEnd, RegisterHandler); + std::for_each(KillSigs, KillSigsEnd, RegisterHandler); +} + +/// PrintStackTraceOnErrorSignal - When an error signal (such as SIBABRT or +/// SIGSEGV) is delivered to the process, print a stack trace and then exit. +void llvm::PrintStackTraceOnErrorSignal() { std::for_each(KillSigs, KillSigsEnd, RegisterHandler); } Index: llvm/lib/Support/ToolRunner.cpp diff -u llvm/lib/Support/ToolRunner.cpp:1.13 llvm/lib/Support/ToolRunner.cpp:1.13.2.1 --- llvm/lib/Support/ToolRunner.cpp:1.13 Sun Dec 14 15:35:53 2003 +++ llvm/lib/Support/ToolRunner.cpp Mon Mar 1 17:58:13 2004 @@ -18,8 +18,36 @@ #include "Support/FileUtilities.h" #include #include +#include using namespace llvm; +ToolExecutionError::~ToolExecutionError() throw() { } + +static void ProcessFailure(std::string ProgPath, const char** Args) { + std::ostringstream OS; + OS << "\nError running tool:\n "; + for (const char **Arg = Args; *Arg; ++Arg) + OS << " " << *Arg; + OS << "\n"; + + // Rerun the compiler, capturing any error messages to print them. + std::string ErrorFilename = getUniqueFilename("error_messages"); + RunProgramWithTimeout(ProgPath, Args, "/dev/null", ErrorFilename.c_str(), + ErrorFilename.c_str()); + + // Print out the error messages generated by GCC if possible... + std::ifstream ErrorFile(ErrorFilename.c_str()); + if (ErrorFile) { + std::copy(std::istreambuf_iterator(ErrorFile), + std::istreambuf_iterator(), + std::ostreambuf_iterator(OS)); + ErrorFile.close(); + } + + removeFile(ErrorFilename); + throw ToolExecutionError(OS.str()); +} + //===---------------------------------------------------------------------===// // LLI Implementation of AbstractIntepreter interface // @@ -44,11 +72,9 @@ const std::string &InputFile, const std::string &OutputFile, const std::vector &SharedLibs) { - if (!SharedLibs.empty()) { - std::cerr << "LLI currently does not support loading shared libraries.\n" - << "Exiting.\n"; - exit(1); - } + if (!SharedLibs.empty()) + throw ToolExecutionError("LLI currently does not support " + "loading shared libraries."); std::vector LLIArgs; LLIArgs.push_back(LLIPath.c_str()); @@ -86,7 +112,7 @@ //===----------------------------------------------------------------------===// // LLC Implementation of AbstractIntepreter interface // -int LLC::OutputAsm(const std::string &Bytecode, std::string &OutputAsmFile) { +void LLC::OutputAsm(const std::string &Bytecode, std::string &OutputAsmFile) { OutputAsmFile = getUniqueFilename(Bytecode+".llc.s"); const char *LLCArgs[] = { LLCPath.c_str(), @@ -98,14 +124,14 @@ std::cout << "" << std::flush; if (RunProgramWithTimeout(LLCPath, LLCArgs, "/dev/null", "/dev/null", - "/dev/null")) { - // If LLC failed on the bytecode, print error... - std::cerr << "Error: `llc' failed!\n"; - removeFile(OutputAsmFile); - return 1; - } + "/dev/null")) + ProcessFailure(LLCPath, LLCArgs); +} - return 0; +void LLC::compileProgram(const std::string &Bytecode) { + std::string OutputAsmFile; + OutputAsm(Bytecode, OutputAsmFile); + removeFile(OutputAsmFile); } int LLC::ExecuteProgram(const std::string &Bytecode, @@ -115,16 +141,12 @@ const std::vector &SharedLibs) { std::string OutputAsmFile; - if (OutputAsm(Bytecode, OutputAsmFile)) { - std::cerr << "Could not generate asm code with `llc', exiting.\n"; - exit(1); - } + OutputAsm(Bytecode, OutputAsmFile); + FileRemover OutFileRemover(OutputAsmFile); // Assuming LLC worked, compile the result with GCC and run it. - int Result = gcc->ExecuteProgram(OutputAsmFile, Args, GCC::AsmFile, - InputFile, OutputFile, SharedLibs); - removeFile(OutputAsmFile); - return Result; + return gcc->ExecuteProgram(OutputAsmFile, Args, GCC::AsmFile, + InputFile, OutputFile, SharedLibs); } /// createLLC - Try to find the LLC executable @@ -211,27 +233,28 @@ return 0; } -int CBE::OutputC(const std::string &Bytecode, +void CBE::OutputC(const std::string &Bytecode, std::string &OutputCFile) { OutputCFile = getUniqueFilename(Bytecode+".cbe.c"); - const char *DisArgs[] = { - DISPath.c_str(), + const char *LLCArgs[] = { + LLCPath.c_str(), "-o", OutputCFile.c_str(), // Output to the C file - "-c", // Output to C + "-march=c", // Output to C "-f", // Overwrite as necessary... Bytecode.c_str(), // This is the input bytecode 0 }; std::cout << "" << std::flush; - if (RunProgramWithTimeout(DISPath, DisArgs, "/dev/null", "/dev/null", - "/dev/null")) { - // If dis failed on the bytecode, print error... - std::cerr << "Error: `llvm-dis -c' failed!\n"; - return 1; - } + if (RunProgramWithTimeout(LLCPath, LLCArgs, "/dev/null", "/dev/null", + "/dev/null")) + ProcessFailure(LLCPath, LLCArgs); +} - return 0; +void CBE::compileProgram(const std::string &Bytecode) { + std::string OutputCFile; + OutputC(Bytecode, OutputCFile); + removeFile(OutputCFile); } int CBE::ExecuteProgram(const std::string &Bytecode, @@ -240,36 +263,32 @@ const std::string &OutputFile, const std::vector &SharedLibs) { std::string OutputCFile; - if (OutputC(Bytecode, OutputCFile)) { - std::cerr << "Could not generate C code with `llvm-dis', exiting.\n"; - exit(1); - } + OutputC(Bytecode, OutputCFile); - int Result = gcc->ExecuteProgram(OutputCFile, Args, GCC::CFile, - InputFile, OutputFile, SharedLibs); - removeFile(OutputCFile); + FileRemover CFileRemove(OutputCFile); - return Result; + return gcc->ExecuteProgram(OutputCFile, Args, GCC::CFile, + InputFile, OutputFile, SharedLibs); } -/// createCBE - Try to find the 'llvm-dis' executable +/// createCBE - Try to find the 'llc' executable /// CBE *AbstractInterpreter::createCBE(const std::string &ProgramPath, std::string &Message) { - std::string DISPath = FindExecutable("llvm-dis", ProgramPath); - if (DISPath.empty()) { + std::string LLCPath = FindExecutable("llc", ProgramPath); + if (LLCPath.empty()) { Message = - "Cannot find `llvm-dis' in executable directory or PATH!\n"; + "Cannot find `llc' in executable directory or PATH!\n"; return 0; } - Message = "Found llvm-dis: " + DISPath + "\n"; + Message = "Found llc: " + LLCPath + "\n"; GCC *gcc = GCC::create(ProgramPath, Message); if (!gcc) { std::cerr << Message << "\n"; exit(1); } - return new CBE(DISPath, gcc); + return new CBE(LLCPath, gcc); } //===---------------------------------------------------------------------===// @@ -311,7 +330,7 @@ std::cout << "" << std::flush; if (RunProgramWithTimeout(GCCPath, &GCCArgs[0], "/dev/null", "/dev/null", "/dev/null")) { - ProcessFailure(&GCCArgs[0]); + ProcessFailure(GCCPath, &GCCArgs[0]); exit(1); } @@ -329,15 +348,15 @@ std::cerr << " " << ProgramArgs[i]; std::cerr << "\n"; ); - int ProgramResult = RunProgramWithTimeout(OutputBinary, &ProgramArgs[0], - InputFile, OutputFile, OutputFile); - removeFile(OutputBinary); - return ProgramResult; + + FileRemover OutputBinaryRemover(OutputBinary); + return RunProgramWithTimeout(OutputBinary, &ProgramArgs[0], + InputFile, OutputFile, OutputFile); } int GCC::MakeSharedObject(const std::string &InputFile, FileType fileType, std::string &OutputFile) { - OutputFile = getUniqueFilename(InputFile+".so"); + OutputFile = getUniqueFilename(InputFile+SHLIBEXT); // Compile the C/asm file into a shared object const char* GCCArgs[] = { GCCPath.c_str(), @@ -357,34 +376,10 @@ std::cout << "" << std::flush; if (RunProgramWithTimeout(GCCPath, GCCArgs, "/dev/null", "/dev/null", "/dev/null")) { - ProcessFailure(GCCArgs); + ProcessFailure(GCCPath, GCCArgs); return 1; } return 0; -} - -void GCC::ProcessFailure(const char** GCCArgs) { - std::cerr << "\n*** Error: invocation of the C compiler failed!\n"; - for (const char **Arg = GCCArgs; *Arg; ++Arg) - std::cerr << " " << *Arg; - std::cerr << "\n"; - - // Rerun the compiler, capturing any error messages to print them. - std::string ErrorFilename = getUniqueFilename("gcc.errors"); - RunProgramWithTimeout(GCCPath, GCCArgs, "/dev/null", ErrorFilename.c_str(), - ErrorFilename.c_str()); - - // Print out the error messages generated by GCC if possible... - std::ifstream ErrorFile(ErrorFilename.c_str()); - if (ErrorFile) { - std::copy(std::istreambuf_iterator(ErrorFile), - std::istreambuf_iterator(), - std::ostreambuf_iterator(std::cerr)); - ErrorFile.close(); - std::cerr << "\n"; - } - - removeFile(ErrorFilename); } /// create - Try to find the `gcc' executable From brukman at cs.uiuc.edu Mon Mar 1 18:03:38 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Mar 1 18:03:38 2004 Subject: [llvm-commits] [parallel] CVS: llvm/lib/Target/SparcV8/InstSelectSimple.cpp Makefile README.txt SparcV8.h SparcV8.td SparcV8CodeEmitter.cpp SparcV8InstrInfo.cpp SparcV8InstrInfo.h SparcV8InstrInfo.td SparcV8InstrInfo_F2.td SparcV8InstrInfo_F3.td SparcV8JITInfo.h SparcV8RegisterInfo.cpp SparcV8RegisterInfo.h SparcV8RegisterInfo.td SparcV8TargetMachine.cpp SparcV8TargetMachine.h Message-ID: <200403012358.RAA04026@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/SparcV8: InstSelectSimple.cpp added (r1.1.2.1) Makefile added (r1.2.2.1) README.txt added (r1.1.2.1) SparcV8.h added (r1.2.2.1) SparcV8.td added (r1.3.2.1) SparcV8CodeEmitter.cpp added (r1.1.2.1) SparcV8InstrInfo.cpp added (r1.3.2.1) SparcV8InstrInfo.h added (r1.2.2.1) SparcV8InstrInfo.td added (r1.1.2.1) SparcV8InstrInfo_F2.td added (r1.1.2.1) SparcV8InstrInfo_F3.td added (r1.1.2.1) SparcV8JITInfo.h added (r1.1.2.1) SparcV8RegisterInfo.cpp added (r1.3.2.1) SparcV8RegisterInfo.h added (r1.1.2.1) SparcV8RegisterInfo.td added (r1.3.2.1) SparcV8TargetMachine.cpp added (r1.4.2.1) SparcV8TargetMachine.h added (r1.2.2.1) --- Log message: Merge from trunk --- Diffs of the changes: (+946 -0) Index: llvm/lib/Target/SparcV8/InstSelectSimple.cpp diff -c /dev/null llvm/lib/Target/SparcV8/InstSelectSimple.cpp:1.1.2.1 *** /dev/null Mon Mar 1 17:58:28 2004 --- llvm/lib/Target/SparcV8/InstSelectSimple.cpp Mon Mar 1 17:58:14 2004 *************** *** 0 **** --- 1,152 ---- + //===-- InstSelectSimple.cpp - A simple instruction selector for SparcV8 --===// + // + // The LLVM Compiler Infrastructure + // + // This file was developed by the LLVM research group and is distributed under + // the University of Illinois Open Source License. See LICENSE.TXT for details. + // + //===----------------------------------------------------------------------===// + // + // This file defines a simple peephole instruction selector for the V8 target + // + //===----------------------------------------------------------------------===// + + #include "SparcV8.h" + #include "llvm/Instructions.h" + #include "llvm/IntrinsicLowering.h" + #include "llvm/Pass.h" + #include "llvm/CodeGen/MachineInstrBuilder.h" + #include "llvm/CodeGen/MachineFunction.h" + #include "llvm/Target/TargetMachine.h" + #include "llvm/Support/GetElementPtrTypeIterator.h" + #include "llvm/Support/InstVisitor.h" + #include "llvm/Support/CFG.h" + using namespace llvm; + + namespace { + struct V8ISel : public FunctionPass, public InstVisitor { + TargetMachine &TM; + MachineFunction *F; // The function we are compiling into + MachineBasicBlock *BB; // The current MBB we are compiling + + std::map RegMap; // Mapping between Val's and SSA Regs + + // MBBMap - Mapping between LLVM BB -> Machine BB + std::map MBBMap; + + V8ISel(TargetMachine &tm) : TM(tm), F(0), BB(0) {} + + /// runOnFunction - Top level implementation of instruction selection for + /// the entire function. + /// + bool runOnFunction(Function &Fn); + + virtual const char *getPassName() const { + return "SparcV8 Simple Instruction Selection"; + } + + /// visitBasicBlock - This method is called when we are visiting a new basic + /// block. This simply creates a new MachineBasicBlock to emit code into + /// and adds it to the current MachineFunction. Subsequent visit* for + /// instructions will be invoked for all instructions in the basic block. + /// + void visitBasicBlock(BasicBlock &LLVM_BB) { + BB = MBBMap[&LLVM_BB]; + } + + void visitReturnInst(ReturnInst &RI); + + void visitInstruction(Instruction &I) { + std::cerr << "Unhandled instruction: " << I; + abort(); + } + + /// LowerUnknownIntrinsicFunctionCalls - This performs a prepass over the + /// function, lowering any calls to unknown intrinsic functions into the + /// equivalent LLVM code. + void LowerUnknownIntrinsicFunctionCalls(Function &F); + + + void visitIntrinsicCall(Intrinsic::ID ID, CallInst &CI); + + }; + } + + FunctionPass *llvm::createSparcV8SimpleInstructionSelector(TargetMachine &TM) { + return new V8ISel(TM); + } + + + bool V8ISel::runOnFunction(Function &Fn) { + // First pass over the function, lower any unknown intrinsic functions + // with the IntrinsicLowering class. + LowerUnknownIntrinsicFunctionCalls(Fn); + + F = &MachineFunction::construct(&Fn, TM); + + // Create all of the machine basic blocks for the function... + for (Function::iterator I = Fn.begin(), E = Fn.end(); I != E; ++I) + F->getBasicBlockList().push_back(MBBMap[I] = new MachineBasicBlock(I)); + + BB = &F->front(); + + // Set up a frame object for the return address. This is used by the + // llvm.returnaddress & llvm.frameaddress intrinisics. + //ReturnAddressIndex = F->getFrameInfo()->CreateFixedObject(4, -4); + + // Copy incoming arguments off of the stack and out of fixed registers. + //LoadArgumentsToVirtualRegs(Fn); + + // Instruction select everything except PHI nodes + visit(Fn); + + // Select the PHI nodes + //SelectPHINodes(); + + RegMap.clear(); + MBBMap.clear(); + F = 0; + // We always build a machine code representation for the function + return true; + } + + + void V8ISel::visitReturnInst(ReturnInst &I) { + if (I.getNumOperands() == 0) { + // Just emit a 'ret' instruction + BuildMI(BB, V8::JMPLi, 2, V8::G0).addZImm(8).addReg(V8::I7); + return; + } + visitInstruction(I); + } + + + /// LowerUnknownIntrinsicFunctionCalls - This performs a prepass over the + /// function, lowering any calls to unknown intrinsic functions into the + /// equivalent LLVM code. + void V8ISel::LowerUnknownIntrinsicFunctionCalls(Function &F) { + for (Function::iterator BB = F.begin(), E = F.end(); BB != E; ++BB) + for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ) + if (CallInst *CI = dyn_cast(I++)) + if (Function *F = CI->getCalledFunction()) + switch (F->getIntrinsicID()) { + case Intrinsic::not_intrinsic: break; + default: + // All other intrinsic calls we must lower. + Instruction *Before = CI->getPrev(); + TM.getIntrinsicLowering().LowerIntrinsicCall(CI); + if (Before) { // Move iterator to instruction after call + I = Before; ++I; + } else { + I = BB->begin(); + } + } + } + + + void V8ISel::visitIntrinsicCall(Intrinsic::ID ID, CallInst &CI) { + unsigned TmpReg1, TmpReg2; + switch (ID) { + default: assert(0 && "Intrinsic not supported!"); + } + } Index: llvm/lib/Target/SparcV8/Makefile diff -c /dev/null llvm/lib/Target/SparcV8/Makefile:1.2.2.1 *** /dev/null Mon Mar 1 17:58:28 2004 --- llvm/lib/Target/SparcV8/Makefile Mon Mar 1 17:58:14 2004 *************** *** 0 **** --- 1,46 ---- + ##===- lib/Target/SparcV8/Makefile -------------------------*- Makefile -*-===## + # + # The LLVM Compiler Infrastructure + # + # This file was developed by the LLVM research group and is distributed under + # the University of Illinois Open Source License. See LICENSE.TXT for details. + # + ##===----------------------------------------------------------------------===## + LEVEL = ../../.. + LIBRARYNAME = sparcv8 + include $(LEVEL)/Makefile.common + + TDFILES := $(wildcard $(SourceDir)/*.td) $(SourceDir)/../Target.td + TDFILE := $(SourceDir)/SparcV8.td + + # Make sure that tblgen is run, first thing. + $(SourceDepend): SparcV8GenRegisterInfo.h.inc SparcV8GenRegisterNames.inc \ + SparcV8GenRegisterInfo.inc SparcV8GenInstrNames.inc \ + SparcV8GenInstrInfo.inc SparcV8GenInstrSelector.inc + + SparcV8GenRegisterNames.inc:: $(TDFILES) $(TBLGEN) + @echo "Building SparcV8.td register names with tblgen" + $(VERB) $(TBLGEN) -I $(BUILD_SRC_DIR) $(TDFILE) -gen-register-enums -o $@ + + SparcV8GenRegisterInfo.h.inc:: $(TDFILES) $(TBLGEN) + @echo "Building SparcV8.td register information header with tblgen" + $(VERB) $(TBLGEN) -I $(BUILD_SRC_DIR) $(TDFILE) -gen-register-desc-header -o $@ + + SparcV8GenRegisterInfo.inc:: $(TDFILES) $(TBLGEN) + @echo "Building SparcV8.td register information implementation with tblgen" + $(VERB) $(TBLGEN) -I $(BUILD_SRC_DIR) $(TDFILE) -gen-register-desc -o $@ + + SparcV8GenInstrNames.inc:: $(TDFILES) $(TBLGEN) + @echo "Building SparcV8.td instruction names with tblgen" + $(VERB) $(TBLGEN) -I $(BUILD_SRC_DIR) $(TDFILE) -gen-instr-enums -o $@ + + SparcV8GenInstrInfo.inc:: $(TDFILES) $(TBLGEN) + @echo "Building SparcV8.td instruction information with tblgen" + $(VERB) $(TBLGEN) -I $(BUILD_SRC_DIR) $(TDFILE) -gen-instr-desc -o $@ + + SparcV8GenInstrSelector.inc:: $(TDFILES) $(TBLGEN) + @echo "Building SparcV8.td instruction selector with tblgen" + $(VERB) $(TBLGEN) -I $(BUILD_SRC_DIR) $(TDFILE) -gen-instr-selector -o $@ + + clean:: + $(VERB) rm -f *.inc Index: llvm/lib/Target/SparcV8/README.txt diff -c /dev/null llvm/lib/Target/SparcV8/README.txt:1.1.2.1 *** /dev/null Mon Mar 1 17:58:28 2004 --- llvm/lib/Target/SparcV8/README.txt Mon Mar 1 17:58:14 2004 *************** *** 0 **** --- 1,9 ---- + + SparcV8 backend skeleton + ------------------------ + + This directory will house a 32-bit SPARC V8 backend employing a expander-based + instruction selector. Watch this space for more news coming soon! + + $Date: 2004/03/01 23:58:14 $ + Index: llvm/lib/Target/SparcV8/SparcV8.h diff -c /dev/null llvm/lib/Target/SparcV8/SparcV8.h:1.2.2.1 *** /dev/null Mon Mar 1 17:58:28 2004 --- llvm/lib/Target/SparcV8/SparcV8.h Mon Mar 1 17:58:14 2004 *************** *** 0 **** --- 1,40 ---- + //===-- SparcV8.h - Top-level interface for SparcV8 representation -*- C++ -*-// + // + // The LLVM Compiler Infrastructure + // + // This file was developed by the LLVM research group and is distributed under + // the University of Illinois Open Source License. See LICENSE.TXT for details. + // + //===----------------------------------------------------------------------===// + // + // This file contains the entry points for global functions defined in the LLVM + // SparcV8 back-end. + // + //===----------------------------------------------------------------------===// + + #ifndef TARGET_SPARCV8_H + #define TARGET_SPARCV8_H + + #include + + namespace llvm { + + class FunctionPass; + class TargetMachine; + + FunctionPass *createSparcV8SimpleInstructionSelector(TargetMachine &TM); + // FunctionPass *createSparcV8CodePrinterPass(std::ostream &OS, + // TargetMachine &TM); + + } // end namespace llvm; + + // Defines symbolic names for SparcV8 registers. This defines a mapping from + // register name to register number. + // + #include "SparcV8GenRegisterNames.inc" + + // Defines symbolic names for the SparcV8 instructions. + // + #include "SparcV8GenInstrNames.inc" + + #endif Index: llvm/lib/Target/SparcV8/SparcV8.td diff -c /dev/null llvm/lib/Target/SparcV8/SparcV8.td:1.3.2.1 *** /dev/null Mon Mar 1 17:58:28 2004 --- llvm/lib/Target/SparcV8/SparcV8.td Mon Mar 1 17:58:14 2004 *************** *** 0 **** --- 1,38 ---- + //===- SparcV8.td - Describe the SparcV8 Target Machine ---------*- C++ -*-===// + // + // The LLVM Compiler Infrastructure + // + // This file was developed by the LLVM research group and is distributed under + // the University of Illinois Open Source License. See LICENSE.TXT for details. + // + //===----------------------------------------------------------------------===// + // + // + //===----------------------------------------------------------------------===// + + // Get the target-independent interfaces which we are implementing... + // + include "../Target.td" + + //===----------------------------------------------------------------------===// + // Register File Description + //===----------------------------------------------------------------------===// + + include "SparcV8RegisterInfo.td" + include "SparcV8InstrInfo.td" + + def SparcV8InstrInfo : InstrInfo { + let PHIInst = PHI; + } + + def SparcV8 : Target { + // Pointers are 32-bits in size. + let PointerType = i32; + + // According to the Mach-O Runtime ABI, these regs are nonvolatile across + // calls: + let CalleeSavedRegisters = []; + + // Pull in Instruction Info: + let InstructionSet = SparcV8InstrInfo; + } Index: llvm/lib/Target/SparcV8/SparcV8CodeEmitter.cpp diff -c /dev/null llvm/lib/Target/SparcV8/SparcV8CodeEmitter.cpp:1.1.2.1 *** /dev/null Mon Mar 1 17:58:28 2004 --- llvm/lib/Target/SparcV8/SparcV8CodeEmitter.cpp Mon Mar 1 17:58:14 2004 *************** *** 0 **** --- 1,43 ---- + //===-- SparcV8CodeEmitter.cpp - JIT Code Emitter for SparcV8 -----*- C++ -*-=// + // + // The LLVM Compiler Infrastructure + // + // This file was developed by the LLVM research group and is distributed under + // the University of Illinois Open Source License. See LICENSE.TXT for details. + // + //===----------------------------------------------------------------------===// + // + // + //===----------------------------------------------------------------------===// + + #include "SparcV8TargetMachine.h" + + namespace llvm { + + /// addPassesToEmitMachineCode - Add passes to the specified pass manager to get + /// machine code emitted. This uses a MachineCodeEmitter object to handle + /// actually outputting the machine code and resolving things like the address + /// of functions. This method should returns true if machine code emission is + /// not supported. + /// + bool SparcV8TargetMachine::addPassesToEmitMachineCode(FunctionPassManager &PM, + MachineCodeEmitter &MCE) { + return true; + // It should go something like this: + // PM.add(new Emitter(MCE)); // Machine code emitter pass for SparcV8 + // Delete machine code for this function after emitting it: + // PM.add(createMachineCodeDeleter()); + } + + void *SparcV8JITInfo::getJITStubForFunction(Function *F, + MachineCodeEmitter &MCE) { + assert (0 && "SparcV8JITInfo::getJITStubForFunction not implemented"); + return 0; + } + + void SparcV8JITInfo::replaceMachineCodeForFunction (void *Old, void *New) { + assert (0 && "SparcV8JITInfo::replaceMachineCodeForFunction not implemented"); + } + + } // end llvm namespace + Index: llvm/lib/Target/SparcV8/SparcV8InstrInfo.cpp diff -c /dev/null llvm/lib/Target/SparcV8/SparcV8InstrInfo.cpp:1.3.2.1 *** /dev/null Mon Mar 1 17:58:28 2004 --- llvm/lib/Target/SparcV8/SparcV8InstrInfo.cpp Mon Mar 1 17:58:14 2004 *************** *** 0 **** --- 1,22 ---- + //===- SparcV8InstrInfo.cpp - SparcV8 Instruction Information ---*- C++ -*-===// + // + // The LLVM Compiler Infrastructure + // + // This file was developed by the LLVM research group and is distributed under + // the University of Illinois Open Source License. See LICENSE.TXT for details. + // + //===----------------------------------------------------------------------===// + // + // This file contains the SparcV8 implementation of the TargetInstrInfo class. + // + //===----------------------------------------------------------------------===// + + #include "SparcV8InstrInfo.h" + #include "llvm/CodeGen/MachineInstrBuilder.h" + #include "SparcV8GenInstrInfo.inc" + using namespace llvm; + + SparcV8InstrInfo::SparcV8InstrInfo() + : TargetInstrInfo(SparcV8Insts, sizeof(SparcV8Insts)/sizeof(SparcV8Insts[0])){ + } + Index: llvm/lib/Target/SparcV8/SparcV8InstrInfo.h diff -c /dev/null llvm/lib/Target/SparcV8/SparcV8InstrInfo.h:1.2.2.1 *** /dev/null Mon Mar 1 17:58:28 2004 --- llvm/lib/Target/SparcV8/SparcV8InstrInfo.h Mon Mar 1 17:58:14 2004 *************** *** 0 **** --- 1,36 ---- + //===- SparcV8InstrInfo.h - SparcV8 Instruction Information -----*- C++ -*-===// + // + // The LLVM Compiler Infrastructure + // + // This file was developed by the LLVM research group and is distributed under + // the University of Illinois Open Source License. See LICENSE.TXT for details. + // + //===----------------------------------------------------------------------===// + // + // This file contains the SparcV8 implementation of the TargetInstrInfo class. + // + //===----------------------------------------------------------------------===// + + #ifndef SPARCV8INSTRUCTIONINFO_H + #define SPARCV8INSTRUCTIONINFO_H + + #include "llvm/Target/TargetInstrInfo.h" + #include "SparcV8RegisterInfo.h" + + namespace llvm { + + class SparcV8InstrInfo : public TargetInstrInfo { + const SparcV8RegisterInfo RI; + public: + SparcV8InstrInfo(); + + /// getRegisterInfo - TargetInstrInfo is a superset of MRegister info. As + /// such, whenever a client has an instance of instruction info, it should + /// always be able to get register info as well (through this method). + /// + virtual const MRegisterInfo &getRegisterInfo() const { return RI; } + }; + + } + + #endif Index: llvm/lib/Target/SparcV8/SparcV8InstrInfo.td diff -c /dev/null llvm/lib/Target/SparcV8/SparcV8InstrInfo.td:1.1.2.1 *** /dev/null Mon Mar 1 17:58:28 2004 --- llvm/lib/Target/SparcV8/SparcV8InstrInfo.td Mon Mar 1 17:58:14 2004 *************** *** 0 **** --- 1,68 ---- + //===- SparcV8Instrs.td - Target Description for SparcV8 Target -----------===// + // + // The LLVM Compiler Infrastructure + // + // This file was developed by the LLVM research group and is distributed under + // the University of Illinois Open Source License. See LICENSE.TXT for details. + // + //===----------------------------------------------------------------------===// + // + // This file describes the SparcV8 instructions in TableGen format. + // + //===----------------------------------------------------------------------===// + + //===----------------------------------------------------------------------===// + // Instruction format superclass + //===----------------------------------------------------------------------===// + + class InstV8 : Instruction { // SparcV8 instruction baseline + field bits<32> Inst; + + let Namespace = "V8"; + + bits<2> op; + let Inst{31-30} = op; // Top two bits are the 'op' field + + // Bit attributes specific to SparcV8 instructions + bit isPasi = 0; // Does this instruction affect an alternate addr space? + bit isPrivileged = 0; // Is this a privileged instruction? + } + + include "SparcV8InstrInfo_F2.td" + include "SparcV8InstrInfo_F3.td" + + //===----------------------------------------------------------------------===// + // Instructions + //===----------------------------------------------------------------------===// + + // Pseudo instructions. + def PHI : InstV8 { + let Name = "PHI"; + } + def ADJCALLSTACKDOWN : InstV8 { + let Name = "ADJCALLSTACKDOWN"; + } + def ADJCALLSTACKUP : InstV8 { + let Name = "ADJCALLSTACKUP"; + } + + // Section B.20: SAVE and RESTORE - p117 + def SAVEr : F3_1<2, 0b111100, "save">; // save r, r, r + def SAVEi : F3_2<2, 0b111100, "save">; // save r, i, r + def RESTOREr : F3_1<2, 0b111101, "restore">; // restore r, r, r + def RESTOREi : F3_2<2, 0b111101, "restore">; // restore r, i, r + + // Section B.24: Call and Link - p125 + // This is the only Format 1 instruction + def CALL : InstV8 { + bits<30> disp; + + let op = 1; + let Inst{29-0} = disp; + let Name = "call"; + } + + // Section B.25: Jump and Link - p126 + def JMPLr : F3_1<2, 0b111000, "jmpl">; // jmpl [rs1+rs2], rd + def JMPLi : F3_2<2, 0b111000, "jmpl">; // jmpl [rs1+imm], rd + Index: llvm/lib/Target/SparcV8/SparcV8InstrInfo_F2.td diff -c /dev/null llvm/lib/Target/SparcV8/SparcV8InstrInfo_F2.td:1.1.2.1 *** /dev/null Mon Mar 1 17:58:28 2004 --- llvm/lib/Target/SparcV8/SparcV8InstrInfo_F2.td Mon Mar 1 17:58:14 2004 *************** *** 0 **** --- 1,44 ---- + //===- SparcV8Instrs_F2.td - Format 2 instructions: SparcV8 Target --------===// + // + // The LLVM Compiler Infrastructure + // + // This file was developed by the LLVM research group and is distributed under + // the University of Illinois Open Source License. See LICENSE.TXT for details. + // + //===----------------------------------------------------------------------===// + // + // Format #2 instruction classes in the SparcV8 + // + //===----------------------------------------------------------------------===// + + class F2 : InstV8 { // Format 2 instructions + bits<3> op2; + bits<22> imm22; + let op = 0; // op = 0 + let Inst{24-22} = op2; + let Inst{21-0} = imm22; + } + + // Specific F2 classes: SparcV8 manual, page 44 + // + class F2_1 op2Val, string name> : F2 { + bits<5> rd; + bits<22> imm; + + let op2 = op2Val; + let Name = name; + + let Inst{29-25} = rd; + } + + class F2_2 condVal, bits<3> op2Val, string name> : F2 { + bits<4> cond; + bit annul = 0; // currently unused + + let cond = condVal; + let op2 = op2Val; + let Name = name; + + let Inst{29} = annul; + let Inst{28-25} = cond; + } Index: llvm/lib/Target/SparcV8/SparcV8InstrInfo_F3.td diff -c /dev/null llvm/lib/Target/SparcV8/SparcV8InstrInfo_F3.td:1.1.2.1 *** /dev/null Mon Mar 1 17:58:28 2004 --- llvm/lib/Target/SparcV8/SparcV8InstrInfo_F3.td Mon Mar 1 17:58:14 2004 *************** *** 0 **** --- 1,62 ---- + //===- SparcV8Instrs_F3.td - Format 3 Instructions: SparcV8 Target --------===// + // + // The LLVM Compiler Infrastructure + // + // This file was developed by the LLVM research group and is distributed under + // the University of Illinois Open Source License. See LICENSE.TXT for details. + // + //===----------------------------------------------------------------------===// + // + // Format #3 instruction classes in the SparcV8 + // + //===----------------------------------------------------------------------===// + + class F3 : InstV8 { + bits<5> rd; + bits<6> op3; + bits<5> rs1; + let op{1} = 1; // Op = 2 or 3 + let Inst{29-25} = rd; + let Inst{24-19} = op3; + let Inst{18-14} = rs1; + } + + // Specific F3 classes: SparcV8 manual, page 44 + // + class F3_1 opVal, bits<6> op3val, string name> : F3 { + bits<8> asi; + bits<5> rs2; + + let op = opVal; + let op3 = op3val; + let Name = name; + + let Inst{13} = 0; // i field = 0 + let Inst{12-5} = asi; // address space identifier + let Inst{4-0} = rs2; + } + + class F3_2 opVal, bits<6> op3val, string name> : F3 { + bits<13> simm13; + + let op = opVal; + let op3 = op3val; + let Name = name; + + let Inst{13} = 1; // i field = 1 + let Inst{12-0} = simm13; + } + + /* + class F3_3 opVal, bits<6> op3val, bits<9> opfVal, string name> + : F3_rs1rs2 { + bits<5> rs2; + + let op = opVal; + let op3 = op3val; + let Name = name; + + let Inst{13-5} = opfVal; + let Inst{4-0} = rs2; + } + */ \ No newline at end of file Index: llvm/lib/Target/SparcV8/SparcV8JITInfo.h diff -c /dev/null llvm/lib/Target/SparcV8/SparcV8JITInfo.h:1.1.2.1 *** /dev/null Mon Mar 1 17:58:28 2004 --- llvm/lib/Target/SparcV8/SparcV8JITInfo.h Mon Mar 1 17:58:14 2004 *************** *** 0 **** --- 1,49 ---- + //===- SparcV8JITInfo.h - SparcV8 impl. of the JIT interface ----*- C++ -*-===// + // + // The LLVM Compiler Infrastructure + // + // This file was developed by the LLVM research group and is distributed under + // the University of Illinois Open Source License. See LICENSE.TXT for details. + // + //===----------------------------------------------------------------------===// + // + // This file contains the SparcV8 implementation of the TargetJITInfo class. + // + //===----------------------------------------------------------------------===// + + #ifndef SPARCV8JITINFO_H + #define SPARCV8JITINFO_H + + #include "llvm/Target/TargetJITInfo.h" + + namespace llvm { + class TargetMachine; + class IntrinsicLowering; + + class SparcV8JITInfo : public TargetJITInfo { + TargetMachine &TM; + public: + SparcV8JITInfo(TargetMachine &tm) : TM(tm) {} + + /// addPassesToJITCompile - Add passes to the specified pass manager to + /// implement a fast dynamic compiler for this target. Return true if this + /// is not supported for this target. + /// + virtual void addPassesToJITCompile(FunctionPassManager &PM); + + /// replaceMachineCodeForFunction - Make it so that calling the function + /// whose machine code is at OLD turns into a call to NEW, perhaps by + /// overwriting OLD with a branch to NEW. This is used for self-modifying + /// code. + /// + virtual void replaceMachineCodeForFunction(void *Old, void *New); + + /// getJITStubForFunction - Create or return a stub for the specified + /// function. This stub acts just like the specified function, except that + /// it allows the "address" of the function to be taken without having to + /// generate code for it. + virtual void *getJITStubForFunction(Function *F, MachineCodeEmitter &MCE); + }; + } + + #endif Index: llvm/lib/Target/SparcV8/SparcV8RegisterInfo.cpp diff -c /dev/null llvm/lib/Target/SparcV8/SparcV8RegisterInfo.cpp:1.3.2.1 *** /dev/null Mon Mar 1 17:58:28 2004 --- llvm/lib/Target/SparcV8/SparcV8RegisterInfo.cpp Mon Mar 1 17:58:14 2004 *************** *** 0 **** --- 1,107 ---- + //===- SparcV8RegisterInfo.cpp - SparcV8 Register Information ---*- C++ -*-===// + // + // The LLVM Compiler Infrastructure + // + // This file was developed by the LLVM research group and is distributed under + // the University of Illinois Open Source License. See LICENSE.TXT for details. + // + //===----------------------------------------------------------------------===// + // + // This file contains the SparcV8 implementation of the MRegisterInfo class. + // + //===----------------------------------------------------------------------===// + + #include "SparcV8.h" + #include "SparcV8RegisterInfo.h" + #include "llvm/CodeGen/MachineInstrBuilder.h" + #include "llvm/CodeGen/MachineFunction.h" + #include "llvm/Type.h" + #include "Support/STLExtras.h" + using namespace llvm; + + SparcV8RegisterInfo::SparcV8RegisterInfo() + : SparcV8GenRegisterInfo(V8::ADJCALLSTACKDOWN, + V8::ADJCALLSTACKUP) {} + + int SparcV8RegisterInfo::storeRegToStackSlot( + MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + unsigned SrcReg, int FrameIdx, + const TargetRegisterClass *RC) const + { + abort(); + return -1; + } + + int SparcV8RegisterInfo::loadRegFromStackSlot( + MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + unsigned DestReg, int FrameIdx, + const TargetRegisterClass *RC) const + { + abort(); + return -1; + } + + int SparcV8RegisterInfo::copyRegToReg(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + unsigned DestReg, unsigned SrcReg, + const TargetRegisterClass *RC) const { + abort(); + return -1; + } + + void SparcV8RegisterInfo:: + eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) const { + abort(); + } + + void + SparcV8RegisterInfo::eliminateFrameIndex(MachineFunction &MF, + MachineBasicBlock::iterator II) const { + abort(); + } + + void SparcV8RegisterInfo:: + processFunctionBeforeFrameFinalized(MachineFunction &MF) const {} + + void SparcV8RegisterInfo::emitPrologue(MachineFunction &MF) const { + MachineBasicBlock &MBB = MF.front(); + + // Eventually this should emit the correct save instruction based on the + // number of bytes in the frame. For now we just hardcode it. + BuildMI(MBB, MBB.begin(), V8::SAVEi, 2, V8::SP).addImm(-122).addReg(V8::SP); + } + + void SparcV8RegisterInfo::emitEpilogue(MachineFunction &MF, + MachineBasicBlock &MBB) const { + MachineBasicBlock::iterator MBBI = prior(MBB.end()); + assert(MBBI->getOpcode() == V8::JMPLi && + "Can only put epilog before return instruction!"); + BuildMI(MBB, MBBI, V8::RESTOREi, 2, V8::O0).addImm(0).addReg(V8::L7); + } + + + #include "SparcV8GenRegisterInfo.inc" + + const TargetRegisterClass* + SparcV8RegisterInfo::getRegClassForType(const Type* Ty) const { + switch (Ty->getPrimitiveID()) { + case Type::FloatTyID: + case Type::DoubleTyID: + assert(0 && "Floating point registers not supported yet!"); + case Type::LongTyID: + case Type::ULongTyID: assert(0 && "Long values can't fit in registers!"); + default: assert(0 && "Invalid type to getClass!"); + case Type::BoolTyID: + case Type::SByteTyID: + case Type::UByteTyID: + case Type::ShortTyID: + case Type::UShortTyID: + case Type::IntTyID: + case Type::UIntTyID: + case Type::PointerTyID: return &IntRegsInstance; + } + } + Index: llvm/lib/Target/SparcV8/SparcV8RegisterInfo.h diff -c /dev/null llvm/lib/Target/SparcV8/SparcV8RegisterInfo.h:1.1.2.1 *** /dev/null Mon Mar 1 17:58:28 2004 --- llvm/lib/Target/SparcV8/SparcV8RegisterInfo.h Mon Mar 1 17:58:14 2004 *************** *** 0 **** --- 1,58 ---- + //===- SparcV8RegisterInfo.h - SparcV8 Register Information Impl -*- C++ -*-==// + // + // The LLVM Compiler Infrastructure + // + // This file was developed by the LLVM research group and is distributed under + // the University of Illinois Open Source License. See LICENSE.TXT for details. + // + //===----------------------------------------------------------------------===// + // + // This file contains the SparcV8 implementation of the MRegisterInfo class. + // + //===----------------------------------------------------------------------===// + + #ifndef SPARCV8REGISTERINFO_H + #define SPARCV8REGISTERINFO_H + + #include "llvm/Target/MRegisterInfo.h" + #include "SparcV8GenRegisterInfo.h.inc" + + namespace llvm { + + class Type; + + struct SparcV8RegisterInfo : public SparcV8GenRegisterInfo { + SparcV8RegisterInfo(); + const TargetRegisterClass* getRegClassForType(const Type* Ty) const; + + /// Code Generation virtual methods... + int storeRegToStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + unsigned SrcReg, int FrameIndex, + const TargetRegisterClass *RC) const; + + int loadRegFromStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + unsigned DestReg, int FrameIndex, + const TargetRegisterClass *RC) const; + + int copyRegToReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, + unsigned DestReg, unsigned SrcReg, + const TargetRegisterClass *RC) const; + + void eliminateCallFramePseudoInstr(MachineFunction &MF, + MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) const; + + void eliminateFrameIndex(MachineFunction &MF, + MachineBasicBlock::iterator II) const; + + void processFunctionBeforeFrameFinalized(MachineFunction &MF) const; + + void emitPrologue(MachineFunction &MF) const; + void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const; + }; + + } // end namespace llvm + + #endif Index: llvm/lib/Target/SparcV8/SparcV8RegisterInfo.td diff -c /dev/null llvm/lib/Target/SparcV8/SparcV8RegisterInfo.td:1.3.2.1 *** /dev/null Mon Mar 1 17:58:28 2004 --- llvm/lib/Target/SparcV8/SparcV8RegisterInfo.td Mon Mar 1 17:58:14 2004 *************** *** 0 **** --- 1,45 ---- + //===- SparcV8Reg.td - Describe the SparcV8 Register File -------*- C++ -*-===// + // + // The LLVM Compiler Infrastructure + // + // This file was developed by the LLVM research group and is distributed under + // the University of Illinois Open Source License. See LICENSE.TXT for details. + // + //===----------------------------------------------------------------------===// + // + // Declarations that describe the SparcV8 register file + // + //===----------------------------------------------------------------------===// + + // Ri - 32-bit integer registers + class Ri num> : Register { + field bits<5> Num = num; // Numbers are identified with a 5 bit ID + } + + let Namespace = "V8" in { + def G0 : Ri< 0>; def G1 : Ri< 1>; def G2 : Ri< 2>; def G3 : Ri< 3>; + def G4 : Ri< 4>; def G5 : Ri< 5>; def G6 : Ri< 6>; def G7 : Ri< 7>; + def O0 : Ri< 8>; def O1 : Ri< 9>; def O2 : Ri<10>; def O3 : Ri<11>; + def O4 : Ri<12>; def O5 : Ri<13>; def O6 : Ri<14>; def O7 : Ri<15>; + def L0 : Ri<16>; def L1 : Ri<17>; def L2 : Ri<18>; def L3 : Ri<19>; + def L4 : Ri<20>; def L5 : Ri<21>; def L6 : Ri<22>; def L7 : Ri<23>; + def I0 : Ri<24>; def I1 : Ri<25>; def I2 : Ri<26>; def I3 : Ri<27>; + def I4 : Ri<28>; def I5 : Ri<29>; def I6 : Ri<30>; def I7 : Ri<31>; + + // Standard register aliases. + def SP : Ri<14>; def FP : Ri<30>; + + // Floating-point registers? + // ... + } + + + // For fun, specify a register class. + // + // FIXME: the register order should be defined in terms of the preferred + // allocation order... + // + def IntRegs : RegisterClass; Index: llvm/lib/Target/SparcV8/SparcV8TargetMachine.cpp diff -c /dev/null llvm/lib/Target/SparcV8/SparcV8TargetMachine.cpp:1.4.2.1 *** /dev/null Mon Mar 1 17:58:29 2004 --- llvm/lib/Target/SparcV8/SparcV8TargetMachine.cpp Mon Mar 1 17:58:14 2004 *************** *** 0 **** --- 1,67 ---- + //===-- SparcV8TargetMachine.cpp - Define TargetMachine for SparcV8 -------===// + // + // The LLVM Compiler Infrastructure + // + // This file was developed by the LLVM research group and is distributed under + // the University of Illinois Open Source License. See LICENSE.TXT for details. + // + //===----------------------------------------------------------------------===// + // + // + //===----------------------------------------------------------------------===// + + #include "SparcV8TargetMachine.h" + #include "SparcV8.h" + #include "llvm/Module.h" + #include "llvm/PassManager.h" + #include "llvm/Target/TargetMachineImpls.h" + #include "llvm/CodeGen/MachineFunction.h" + #include "llvm/CodeGen/Passes.h" + using namespace llvm; + + // allocateSparcV8TargetMachine - Allocate and return a subclass of + // TargetMachine that implements the SparcV8 backend. + // + TargetMachine *llvm::allocateSparcV8TargetMachine(const Module &M, + IntrinsicLowering *IL) { + return new SparcV8TargetMachine(M, IL); + } + + /// SparcV8TargetMachine ctor - Create an ILP32 architecture model + /// + SparcV8TargetMachine::SparcV8TargetMachine(const Module &M, + IntrinsicLowering *IL) + : TargetMachine("SparcV8", IL, true, 4, 4, 4, 4, 4), + FrameInfo(TargetFrameInfo::StackGrowsDown, 8, 4), JITInfo(*this) { + } + + /// addPassesToEmitAssembly - Add passes to the specified pass manager + /// to implement a static compiler for this target. + /// + bool SparcV8TargetMachine::addPassesToEmitAssembly(PassManager &PM, + std::ostream &Out) { + PM.add(createSparcV8SimpleInstructionSelector(*this)); + + // Print machine instructions as they are created. + PM.add(createMachineFunctionPrinterPass(&std::cerr)); + + PM.add(createRegisterAllocator()); + PM.add(createPrologEpilogCodeInserter()); + // + + // This is not a correct asm writer by any means, but at least we see what we + // are producing. + PM.add(createMachineFunctionPrinterPass(&Out)); + + PM.add(createMachineCodeDeleter()); + return false; + } + + /// addPassesToJITCompile - Add passes to the specified pass manager to + /// implement a fast dynamic compiler for this target. + /// + void SparcV8JITInfo::addPassesToJITCompile(FunctionPassManager &PM) { + // + PM.add(createRegisterAllocator()); + PM.add(createPrologEpilogCodeInserter()); + } Index: llvm/lib/Target/SparcV8/SparcV8TargetMachine.h diff -c /dev/null llvm/lib/Target/SparcV8/SparcV8TargetMachine.h:1.2.2.1 *** /dev/null Mon Mar 1 17:58:29 2004 --- llvm/lib/Target/SparcV8/SparcV8TargetMachine.h Mon Mar 1 17:58:14 2004 *************** *** 0 **** --- 1,60 ---- + //===-- SparcV8TargetMachine.h - Define TargetMachine for SparcV8 -*- C++ -*-=// + // + // The LLVM Compiler Infrastructure + // + // This file was developed by the LLVM research group and is distributed under + // the University of Illinois Open Source License. See LICENSE.TXT for details. + // + //===----------------------------------------------------------------------===// + // + // This file declares the SparcV8 specific subclass of TargetMachine. + // + //===----------------------------------------------------------------------===// + + #ifndef SPARCV8TARGETMACHINE_H + #define SPARCV8TARGETMACHINE_H + + #include "llvm/Target/TargetMachine.h" + #include "llvm/Target/TargetFrameInfo.h" + #include "llvm/PassManager.h" + #include "SparcV8InstrInfo.h" + #include "SparcV8JITInfo.h" + + namespace llvm { + + class IntrinsicLowering; + + class SparcV8TargetMachine : public TargetMachine { + SparcV8InstrInfo InstrInfo; + TargetFrameInfo FrameInfo; + SparcV8JITInfo JITInfo; + public: + SparcV8TargetMachine(const Module &M, IntrinsicLowering *IL); + + virtual const SparcV8InstrInfo &getInstrInfo() const { return InstrInfo; } + virtual const TargetFrameInfo &getFrameInfo() const { return FrameInfo; } + virtual const MRegisterInfo *getRegisterInfo() const { + return &InstrInfo.getRegisterInfo(); + } + virtual TargetJITInfo *getJITInfo() { + return &JITInfo; + } + + virtual const TargetSchedInfo &getSchedInfo() const { abort(); } + virtual const TargetRegInfo &getRegInfo() const { abort(); } + + /// addPassesToEmitMachineCode - Add passes to the specified pass manager to + /// get machine code emitted. This uses a MachineCodeEmitter object to handle + /// actually outputting the machine code and resolving things like the address + /// of functions. This method should returns true if machine code emission is + /// not supported. + /// + virtual bool addPassesToEmitMachineCode(FunctionPassManager &PM, + MachineCodeEmitter &MCE); + + virtual bool addPassesToEmitAssembly(PassManager &PM, std::ostream &Out); + }; + + } // end namespace llvm + + #endif From brukman at cs.uiuc.edu Mon Mar 1 18:03:47 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Mar 1 18:03:47 2004 Subject: [llvm-commits] [parallel] CVS: llvm/lib/Target/SparcV9/RegAlloc/AllocInfo.h LiveRangeInfo.cpp Makefile PhyRegAlloc.cpp Message-ID: <200403012358.RAA03868@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/SparcV9/RegAlloc: AllocInfo.h updated: 1.5 -> 1.5.4.1 LiveRangeInfo.cpp updated: 1.48 -> 1.48.2.1 Makefile updated: 1.4 -> 1.4.2.1 PhyRegAlloc.cpp updated: 1.131 -> 1.131.2.1 --- Log message: Merge from trunk --- Diffs of the changes: (+66 -78) Index: llvm/lib/Target/SparcV9/RegAlloc/AllocInfo.h diff -u llvm/lib/Target/SparcV9/RegAlloc/AllocInfo.h:1.5 llvm/lib/Target/SparcV9/RegAlloc/AllocInfo.h:1.5.4.1 --- llvm/lib/Target/SparcV9/RegAlloc/AllocInfo.h:1.5 Tue Nov 11 16:41:33 2003 +++ llvm/lib/Target/SparcV9/RegAlloc/AllocInfo.h Mon Mar 1 17:58:15 2004 @@ -79,6 +79,13 @@ } }; +static inline std::ostream &operator << (std::ostream &OS, AllocInfo &S) { + OS << "(Instruction " << S.Instruction << " Operand " << S.Operand + << " AllocState " << S.allocStateToString () << " Placement " + << S.Placement << ")"; + return OS; +} + } // End llvm namespace #endif // ALLOCINFO_H Index: llvm/lib/Target/SparcV9/RegAlloc/LiveRangeInfo.cpp diff -u llvm/lib/Target/SparcV9/RegAlloc/LiveRangeInfo.cpp:1.48 llvm/lib/Target/SparcV9/RegAlloc/LiveRangeInfo.cpp:1.48.2.1 --- llvm/lib/Target/SparcV9/RegAlloc/LiveRangeInfo.cpp:1.48 Sun Dec 14 07:24:15 2003 +++ llvm/lib/Target/SparcV9/RegAlloc/LiveRangeInfo.cpp Mon Mar 1 17:58:15 2004 @@ -171,13 +171,13 @@ // iterate over all the machine instructions in BB for(MachineBasicBlock::iterator MInstIterator = MBB.begin(); MInstIterator != MBB.end(); ++MInstIterator) { - MachineInstr *MInst = *MInstIterator; + MachineInstr *MInst = MInstIterator; // If the machine instruction is a call/return instruction, add it to // CallRetInstrList for processing its args, ret value, and ret addr. // - if(TM.getInstrInfo().isReturn(MInst->getOpCode()) || - TM.getInstrInfo().isCall(MInst->getOpCode())) + if(TM.getInstrInfo().isReturn(MInst->getOpcode()) || + TM.getInstrInfo().isCall(MInst->getOpcode())) CallRetInstrList.push_back(MInst); // iterate over explicit MI operands and create a new LR @@ -194,9 +194,8 @@ // set it directly in the LiveRange if (OpI.getMachineOperand().hasAllocatedReg()) { unsigned getClassId; - LR->setColor(MRI.getClassRegNum( - OpI.getMachineOperand().getAllocatedRegNum(), - getClassId)); + LR->setColor(MRI.getClassRegNum(OpI.getMachineOperand().getReg(), + getClassId)); } } @@ -212,7 +211,7 @@ if (MInst->getImplicitOp(i).hasAllocatedReg()) { unsigned getClassId; LR->setColor(MRI.getClassRegNum( - MInst->getImplicitOp(i).getAllocatedRegNum(), + MInst->getImplicitOp(i).getReg(), getClassId)); } } @@ -243,7 +242,7 @@ std::vector::iterator It = CallRetInstrList.begin(); for( ; It != CallRetInstrList.end(); ++It) { MachineInstr *MInst = *It; - MachineOpCode OpCode = MInst->getOpCode(); + MachineOpCode OpCode = MInst->getOpcode(); if ((TM.getInstrInfo()).isReturn(OpCode)) MRI.suggestReg4RetValue(MInst, *this); @@ -330,7 +329,7 @@ // iterate over all the machine instructions in BB for(MachineBasicBlock::iterator MII = MBB.begin(); MII != MBB.end(); ++MII){ - const MachineInstr *MI = *MII; + const MachineInstr *MI = MII; if( DEBUG_RA >= RA_DEBUG_LiveRanges) { std::cerr << " *Iterating over machine instr "; Index: llvm/lib/Target/SparcV9/RegAlloc/Makefile diff -u llvm/lib/Target/SparcV9/RegAlloc/Makefile:1.4 llvm/lib/Target/SparcV9/RegAlloc/Makefile:1.4.2.1 --- llvm/lib/Target/SparcV9/RegAlloc/Makefile:1.4 Fri Jan 9 00:16:12 2004 +++ llvm/lib/Target/SparcV9/RegAlloc/Makefile Mon Mar 1 17:58:15 2004 @@ -10,7 +10,7 @@ DIRS = -LIBRARYNAME = regalloc +LIBRARYNAME = sparcv9regalloc BUILD_ARCHIVE = 1 Index: llvm/lib/Target/SparcV9/RegAlloc/PhyRegAlloc.cpp diff -u llvm/lib/Target/SparcV9/RegAlloc/PhyRegAlloc.cpp:1.131 llvm/lib/Target/SparcV9/RegAlloc/PhyRegAlloc.cpp:1.131.2.1 --- llvm/lib/Target/SparcV9/RegAlloc/PhyRegAlloc.cpp:1.131 Sun Dec 14 07:24:15 2003 +++ llvm/lib/Target/SparcV9/RegAlloc/PhyRegAlloc.cpp Mon Mar 1 17:58:15 2004 @@ -25,20 +25,20 @@ #include "PhyRegAlloc.h" #include "RegAllocCommon.h" #include "RegClass.h" +#include "../LiveVar/FunctionLiveVarInfo.h" #include "llvm/Constants.h" #include "llvm/DerivedTypes.h" #include "llvm/iOther.h" #include "llvm/Module.h" #include "llvm/Type.h" #include "llvm/Analysis/LoopInfo.h" -#include "llvm/CodeGen/FunctionLiveVarInfo.h" #include "llvm/CodeGen/InstrSelection.h" #include "llvm/CodeGen/MachineCodeForInstruction.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineFunctionInfo.h" #include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/MachineInstrBuilder.h" -#include "llvm/CodeGen/MachineInstrAnnot.h" +#include "../MachineInstrAnnot.h" #include "llvm/CodeGen/Passes.h" #include "llvm/Support/InstIterator.h" #include "llvm/Target/TargetInstrInfo.h" @@ -233,11 +233,11 @@ // iterate over all the machine instructions in BB for ( ; MII != MBB.end(); ++MII) { - const MachineInstr *MInst = *MII; + const MachineInstr *MInst = MII; // get the LV set after the instruction const ValueSet &LVSetAI = LVI->getLiveVarSetAfterMInst(MInst, BB); - bool isCallInst = TM.getInstrInfo().isCall(MInst->getOpCode()); + bool isCallInst = TM.getInstrInfo().isCall(MInst->getOpcode()); if (isCallInst) { // set the isCallInterference flag of each live range which extends @@ -262,7 +262,7 @@ // another. This must be done because pseudo-instructions may be // expanded to multiple instructions by the assembler, so all the // operands must get distinct registers. - if (TM.getInstrInfo().isPseudoInstr(MInst->getOpCode())) + if (TM.getInstrInfo().isPseudoInstr(MInst->getOpcode())) addInterf4PseudoInstr(MInst); // Also add interference for any implicit definitions in a machine @@ -355,25 +355,13 @@ MII = MBB.insert(MII, newMI); } -// used by: updateMachineCode (1 time) -inline void DeleteInstruction(MachineBasicBlock& MBB, - MachineBasicBlock::iterator& MII) { - MII = MBB.erase(MII); -} - -// used by: updateMachineCode (1 time) -inline void SubstituteInPlace(MachineInstr* newMI, MachineBasicBlock& MBB, - MachineBasicBlock::iterator MII) { - *MII = newMI; -} - // used by: updateMachineCode (2 times) inline void PrependInstructions(std::vector &IBef, MachineBasicBlock& MBB, MachineBasicBlock::iterator& MII, const std::string& msg) { if (!IBef.empty()) { - MachineInstr* OrigMI = *MII; + MachineInstr* OrigMI = MII; std::vector::iterator AdIt; for (AdIt = IBef.begin(); AdIt != IBef.end() ; ++AdIt) { if (DEBUG_RA) { @@ -391,7 +379,7 @@ MachineBasicBlock::iterator& MII, const std::string& msg) { if (!IAft.empty()) { - MachineInstr* OrigMI = *MII; + MachineInstr* OrigMI = MII; std::vector::iterator AdIt; for ( AdIt = IAft.begin(); AdIt != IAft.end() ; ++AdIt ) { if (DEBUG_RA) { @@ -442,14 +430,14 @@ /// void PhyRegAlloc::updateInstruction(MachineBasicBlock::iterator& MII, MachineBasicBlock &MBB) { - MachineInstr* MInst = *MII; - unsigned Opcode = MInst->getOpCode(); + MachineInstr* MInst = MII; + unsigned Opcode = MInst->getOpcode(); // Reset tmp stack positions so they can be reused for each machine instr. MF->getInfo()->popAllTempValues(); // Mark the operands for which regs have been allocated. - bool instrNeedsSpills = markAllocatedRegs(*MII); + bool instrNeedsSpills = markAllocatedRegs(MII); #ifndef NDEBUG // Mark that the operands have been updated. Later, @@ -506,7 +494,7 @@ // their assigned registers or insert spill code, as appropriate. // Also, fix operands of call/return instructions. for (MachineBasicBlock::iterator MII = MBB.begin(); MII != MBB.end(); ++MII) - if (! TM.getInstrInfo().isDummyPhiInstr((*MII)->getOpCode())) + if (! TM.getInstrInfo().isDummyPhiInstr(MII->getOpcode())) updateInstruction(MII, MBB); // Now, move code out of delay slots of branches and returns if needed. @@ -523,59 +511,58 @@ // // If the annul bit of the branch is set, neither of these is legal! // If so, we need to handle spill differently but annulling is not yet used. - for (MachineBasicBlock::iterator MII = MBB.begin(); - MII != MBB.end(); ++MII) + for (MachineBasicBlock::iterator MII = MBB.begin(); MII != MBB.end(); ++MII) if (unsigned delaySlots = - TM.getInstrInfo().getNumDelaySlots((*MII)->getOpCode())) { - MachineInstr *MInst = *MII, *DelaySlotMI = *(MII+1); + TM.getInstrInfo().getNumDelaySlots(MII->getOpcode())) { + MachineBasicBlock::iterator DelaySlotMI = next(MII); + assert(DelaySlotMI != MBB.end() && "no instruction for delay slot"); // Check the 2 conditions above: // (1) Does a branch need instructions added after it? // (2) O/w does delay slot instr. need instrns before or after? - bool isBranch = (TM.getInstrInfo().isBranch(MInst->getOpCode()) || - TM.getInstrInfo().isReturn(MInst->getOpCode())); + bool isBranch = (TM.getInstrInfo().isBranch(MII->getOpcode()) || + TM.getInstrInfo().isReturn(MII->getOpcode())); bool cond1 = (isBranch && - AddedInstrMap.count(MInst) && - AddedInstrMap[MInst].InstrnsAfter.size() > 0); + AddedInstrMap.count(MII) && + AddedInstrMap[MII].InstrnsAfter.size() > 0); bool cond2 = (AddedInstrMap.count(DelaySlotMI) && (AddedInstrMap[DelaySlotMI].InstrnsBefore.size() > 0 || AddedInstrMap[DelaySlotMI].InstrnsAfter.size() > 0)); if (cond1 || cond2) { - assert((MInst->getOpCodeFlags() & AnnulFlag) == 0 && - "FIXME: Moving an annulled delay slot instruction!"); assert(delaySlots==1 && "InsertBefore does not yet handle >1 delay slots!"); - InsertBefore(DelaySlotMI, MBB, MII); // MII pts back to branch - - // In case (1), delete it and don't replace with anything! - // Otherwise (i.e., case (2) only) replace it with a NOP. - if (cond1) { - DeleteInstruction(MBB, ++MII); // MII now points to next inst. - --MII; // reset MII for ++MII of loop - } - else - SubstituteInPlace(BuildMI(TM.getInstrInfo().getNOPOpCode(),1), - MBB, MII+1); // replace with NOP if (DEBUG_RA) { std::cerr << "\nRegAlloc: Moved instr. with added code: " << *DelaySlotMI - << " out of delay slots of instr: " << *MInst; + << " out of delay slots of instr: " << *MII; + } + + // move instruction before branch + MBB.insert(MII, MBB.remove(DelaySlotMI)); + + // On cond1 we are done (we already moved the + // instruction out of the delay slot). On cond2 we need + // to insert a nop in place of the moved instruction + if (cond2) { + MBB.insert(MII, BuildMI(TM.getInstrInfo().getNOPOpCode(),1)); } } - else + else { // For non-branch instr with delay slots (probably a call), move // InstrAfter to the instr. in the last delay slot. - move2DelayedInstr(*MII, *(MII+delaySlots)); - } + MachineBasicBlock::iterator tmp = next(MII, delaySlots); + move2DelayedInstr(MII, tmp); + } + } // Finally iterate over all instructions in BB and insert before/after for (MachineBasicBlock::iterator MII=MBB.begin(); MII != MBB.end(); ++MII) { - MachineInstr *MInst = *MII; + MachineInstr *MInst = MII; // do not process Phis - if (TM.getInstrInfo().isDummyPhiInstr(MInst->getOpCode())) + if (TM.getInstrInfo().isDummyPhiInstr(MInst->getOpcode())) continue; // if there are any added instructions... @@ -583,11 +570,11 @@ AddedInstrns &CallAI = AddedInstrMap[MInst]; #ifndef NDEBUG - bool isBranch = (TM.getInstrInfo().isBranch(MInst->getOpCode()) || - TM.getInstrInfo().isReturn(MInst->getOpCode())); + bool isBranch = (TM.getInstrInfo().isBranch(MInst->getOpcode()) || + TM.getInstrInfo().isReturn(MInst->getOpcode())); assert((!isBranch || AddedInstrMap[MInst].InstrnsAfter.size() <= - TM.getInstrInfo().getNumDelaySlots(MInst->getOpCode())) && + TM.getInstrInfo().getNumDelaySlots(MInst->getOpcode())) && "Cannot put more than #delaySlots instrns after " "branch or return! Need to handle temps differently."); #endif @@ -635,12 +622,12 @@ MachineBasicBlock::iterator& MII, MachineBasicBlock &MBB, const unsigned OpNum) { - MachineInstr *MInst = *MII; + MachineInstr *MInst = MII; const BasicBlock *BB = MBB.getBasicBlock(); - assert((! TM.getInstrInfo().isCall(MInst->getOpCode()) || OpNum == 0) && + assert((! TM.getInstrInfo().isCall(MInst->getOpcode()) || OpNum == 0) && "Outgoing arg of a call must be handled elsewhere (func arg ok)"); - assert(! TM.getInstrInfo().isReturn(MInst->getOpCode()) && + assert(! TM.getInstrInfo().isReturn(MInst->getOpcode()) && "Return value of a ret must be handled elsewhere"); MachineOperand& Op = MInst->getOperand(OpNum); @@ -658,8 +645,8 @@ // include all live variables before that branch or return -- we don't want to // trample those! Verify that the set is included in the LV set before MInst. if (MII != MBB.begin()) { - MachineInstr *PredMI = *(MII-1); - if (unsigned DS = TM.getInstrInfo().getNumDelaySlots(PredMI->getOpCode())) + MachineBasicBlock::iterator PredMI = prior(MII); + if (unsigned DS = TM.getInstrInfo().getNumDelaySlots(PredMI->getOpcode())) assert(set_difference(LVI->getLiveVarSetBeforeMInst(PredMI), LVSetBef) .empty() && "Live-var set before branch should be included in " "live-var set of each delay slot instruction!"); @@ -745,7 +732,7 @@ std::vector &instrnsAfter, MachineInstr *CallMI, const BasicBlock *BB) { - assert(TM.getInstrInfo().isCall(CallMI->getOpCode())); + assert(TM.getInstrInfo().isCall(CallMI->getOpcode())); // hash set to record which registers were saved/restored hash_set PushedRegSet; @@ -1030,12 +1017,11 @@ // explicit and implicit operands are set. for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) if (MI->getOperand(i).hasAllocatedReg()) - markRegisterUsed(MI->getOperand(i).getAllocatedRegNum(), RC, RegType,MRI); + markRegisterUsed(MI->getOperand(i).getReg(), RC, RegType,MRI); for (unsigned i = 0, e = MI->getNumImplicitRefs(); i != e; ++i) if (MI->getImplicitOp(i).hasAllocatedReg()) - markRegisterUsed(MI->getImplicitOp(i).getAllocatedRegNum(), RC, - RegType,MRI); + markRegisterUsed(MI->getImplicitOp(i).getReg(), RC, RegType,MRI); // Add all of the scratch registers that are used to save values across the // instruction (e.g., for saving state register values). @@ -1201,12 +1187,8 @@ std::cerr << "FnAllocState:\n"; for (unsigned i = 0; i < state.size (); ++i) { AllocInfo &S = state[i]; - if (Insn == S.Instruction) { - std::cerr << " (Instruction " << S.Instruction - << ", Operand " << S.Operand - << ", AllocState " << S.allocStateToString () - << ", Placement " << S.Placement << ")\n"; - } + if (Insn == S.Instruction) + std::cerr << " " << S << "\n"; } std::cerr << "----------\n"; ++Insn; From brukman at cs.uiuc.edu Mon Mar 1 18:03:55 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Mar 1 18:03:55 2004 Subject: [llvm-commits] [parallel] CVS: llvm/lib/Target/PowerPC/Makefile PowerPC.h PowerPC.td PowerPCCodeEmitter.cpp PowerPCInstrInfo.cpp PowerPCInstrInfo.h PowerPCInstrs.td PowerPCJITInfo.h PowerPCReg.td PowerPCRegisterInfo.cpp PowerPCRegisterInfo.h PowerPCTargetMachine.cpp PowerPCTargetMachine.h README.txt Message-ID: <200403012358.RAA04018@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/PowerPC: Makefile added (r1.1.2.1) PowerPC.h added (r1.2.2.1) PowerPC.td added (r1.1.2.1) PowerPCCodeEmitter.cpp added (r1.1.2.1) PowerPCInstrInfo.cpp added (r1.3.2.1) PowerPCInstrInfo.h added (r1.2.2.1) PowerPCInstrs.td added (r1.1.2.1) PowerPCJITInfo.h added (r1.1.2.1) PowerPCReg.td added (r1.1.2.1) PowerPCRegisterInfo.cpp added (r1.4.2.1) PowerPCRegisterInfo.h added (r1.4.2.1) PowerPCTargetMachine.cpp added (r1.7.2.1) PowerPCTargetMachine.h added (r1.4.2.1) README.txt added (r1.2.2.1) --- Log message: Merge from trunk --- Diffs of the changes: (+717 -0) Index: llvm/lib/Target/PowerPC/Makefile diff -c /dev/null llvm/lib/Target/PowerPC/Makefile:1.1.2.1 *** /dev/null Mon Mar 1 17:58:27 2004 --- llvm/lib/Target/PowerPC/Makefile Mon Mar 1 17:58:13 2004 *************** *** 0 **** --- 1,55 ---- + ##===- lib/Target/PowerPC/Makefile -------------------------*- Makefile -*-===## + # + # The LLVM Compiler Infrastructure + # + # This file was developed by the LLVM research group and is distributed under + # the University of Illinois Open Source License. See LICENSE.TXT for details. + # + ##===----------------------------------------------------------------------===## + LEVEL = ../../.. + LIBRARYNAME = powerpc + include $(LEVEL)/Makefile.common + + # Make sure that tblgen is run, first thing. + $(SourceDepend): PowerPCGenRegisterInfo.h.inc PowerPCGenRegisterNames.inc \ + PowerPCGenRegisterInfo.inc PowerPCGenInstrNames.inc \ + PowerPCGenInstrInfo.inc PowerPCGenInstrSelector.inc + + PowerPCGenRegisterNames.inc:: $(SourceDir)/PowerPC.td \ + $(SourceDir)/PowerPCReg.td \ + $(SourceDir)/../Target.td $(TBLGEN) + @echo "Building PowerPC.td register names with tblgen" + $(VERB) $(TBLGEN) -I $(BUILD_SRC_DIR) $< -gen-register-enums -o $@ + + PowerPCGenRegisterInfo.h.inc:: $(SourceDir)/PowerPC.td \ + $(SourceDir)/PowerPCReg.td \ + $(SourceDir)/../Target.td $(TBLGEN) + @echo "Building PowerPC.td register information header with tblgen" + $(VERB) $(TBLGEN) -I $(BUILD_SRC_DIR) $< -gen-register-desc-header -o $@ + + PowerPCGenRegisterInfo.inc:: $(SourceDir)/PowerPC.td \ + $(SourceDir)/PowerPCReg.td \ + $(SourceDir)/../Target.td $(TBLGEN) + @echo "Building PowerPC.td register information implementation with tblgen" + $(VERB) $(TBLGEN) -I $(BUILD_SRC_DIR) $< -gen-register-desc -o $@ + + PowerPCGenInstrNames.inc:: $(SourceDir)/PowerPC.td \ + $(SourceDir)/PowerPCInstrs.td \ + $(SourceDir)/../Target.td $(TBLGEN) + @echo "Building PowerPC.td instruction names with tblgen" + $(VERB) $(TBLGEN) -I $(BUILD_SRC_DIR) $< -gen-instr-enums -o $@ + + PowerPCGenInstrInfo.inc:: $(SourceDir)/PowerPC.td \ + $(SourceDir)/PowerPCInstrs.td \ + $(SourceDir)/../Target.td $(TBLGEN) + @echo "Building PowerPC.td instruction information with tblgen" + $(VERB) $(TBLGEN) -I $(BUILD_SRC_DIR) $< -gen-instr-desc -o $@ + + PowerPCGenInstrSelector.inc:: $(SourceDir)/PowerPC.td \ + $(SourceDir)/PowerPCInstrs.td \ + $(SourceDir)/../Target.td $(TBLGEN) + @echo "Building PowerPC.td instruction selector with tblgen" + $(VERB) $(TBLGEN) -I $(BUILD_SRC_DIR) $< -gen-instr-selector -o $@ + + clean:: + $(VERB) rm -f *.inc Index: llvm/lib/Target/PowerPC/PowerPC.h diff -c /dev/null llvm/lib/Target/PowerPC/PowerPC.h:1.2.2.1 *** /dev/null Mon Mar 1 17:58:28 2004 --- llvm/lib/Target/PowerPC/PowerPC.h Mon Mar 1 17:58:13 2004 *************** *** 0 **** --- 1,42 ---- + //===-- PowerPC.h - Top-level interface for PowerPC representation -*- C++ -*-// + // + // The LLVM Compiler Infrastructure + // + // This file was developed by the LLVM research group and is distributed under + // the University of Illinois Open Source License. See LICENSE.TXT for details. + // + //===----------------------------------------------------------------------===// + // + // This file contains the entry points for global functions defined in the LLVM + // PowerPC back-end. + // + //===----------------------------------------------------------------------===// + + #ifndef TARGET_POWERPC_H + #define TARGET_POWERPC_H + + #include + + namespace llvm { + + class FunctionPass; + class TargetMachine; + + // Here is where you would define factory methods for powerpc-specific + // passes. For example: + // FunctionPass *createPowerPCSimpleInstructionSelector (TargetMachine &TM); + // FunctionPass *createPowerPCCodePrinterPass(std::ostream &OS, + // TargetMachine &TM); + + } // end namespace llvm; + + // Defines symbolic names for PowerPC registers. This defines a mapping from + // register name to register number. + // + #include "PowerPCGenRegisterNames.inc" + + // Defines symbolic names for the PowerPC instructions. + // + #include "PowerPCGenInstrNames.inc" + + #endif Index: llvm/lib/Target/PowerPC/PowerPC.td diff -c /dev/null llvm/lib/Target/PowerPC/PowerPC.td:1.1.2.1 *** /dev/null Mon Mar 1 17:58:28 2004 --- llvm/lib/Target/PowerPC/PowerPC.td Mon Mar 1 17:58:13 2004 *************** *** 0 **** --- 1,41 ---- + //===- PowerPC.td - Describe the PowerPC Target Machine ---------*- C++ -*-===// + // + // The LLVM Compiler Infrastructure + // + // This file was developed by the LLVM research group and is distributed under + // the University of Illinois Open Source License. See LICENSE.TXT for details. + // + //===----------------------------------------------------------------------===// + // + // + //===----------------------------------------------------------------------===// + + // Get the target-independent interfaces which we are implementing... + // + include "../Target.td" + + //===----------------------------------------------------------------------===// + // Register File Description + //===----------------------------------------------------------------------===// + + include "PowerPCReg.td" + include "PowerPCInstrs.td" + + def PowerPCInstrInfo : InstrInfo { + let PHIInst = PHI; + } + + def PowerPC : Target { + // Pointers are 32-bits in size. + let PointerType = i32; + + // According to the Mach-O Runtime ABI, these regs are nonvolatile across + // calls: + let CalleeSavedRegisters = [R1, R13, R14, R15, R16, R17, R18, R19, + R20, R21, R22, R23, R24, R25, R26, R27, R28, R29, R30, R31, F14, F15, + F16, F17, F18, F19, F20, F21, F22, F23, F24, F25, F26, F27, F28, F29, + F30, F31, CR2, CR3, CR4]; + + // Pull in Instruction Info: + let InstructionSet = PowerPCInstrInfo; + } Index: llvm/lib/Target/PowerPC/PowerPCCodeEmitter.cpp diff -c /dev/null llvm/lib/Target/PowerPC/PowerPCCodeEmitter.cpp:1.1.2.1 *** /dev/null Mon Mar 1 17:58:28 2004 --- llvm/lib/Target/PowerPC/PowerPCCodeEmitter.cpp Mon Mar 1 17:58:13 2004 *************** *** 0 **** --- 1,43 ---- + //===-- PowerPCCodeEmitter.cpp - JIT Code Emitter for PowerPC -----*- C++ -*-=// + // + // The LLVM Compiler Infrastructure + // + // This file was developed by the LLVM research group and is distributed under + // the University of Illinois Open Source License. See LICENSE.TXT for details. + // + //===----------------------------------------------------------------------===// + // + // + //===----------------------------------------------------------------------===// + + #include "PowerPCTargetMachine.h" + + namespace llvm { + + /// addPassesToEmitMachineCode - Add passes to the specified pass manager to get + /// machine code emitted. This uses a MachineCodeEmitter object to handle + /// actually outputting the machine code and resolving things like the address + /// of functions. This method should returns true if machine code emission is + /// not supported. + /// + bool PowerPCTargetMachine::addPassesToEmitMachineCode(FunctionPassManager &PM, + MachineCodeEmitter &MCE) { + return true; + // It should go something like this: + // PM.add(new Emitter(MCE)); // Machine code emitter pass for PowerPC + // Delete machine code for this function after emitting it: + // PM.add(createMachineCodeDeleter()); + } + + void *PowerPCJITInfo::getJITStubForFunction(Function *F, + MachineCodeEmitter &MCE) { + assert (0 && "PowerPCJITInfo::getJITStubForFunction not implemented"); + return 0; + } + + void PowerPCJITInfo::replaceMachineCodeForFunction (void *Old, void *New) { + assert (0 && "PowerPCJITInfo::replaceMachineCodeForFunction not implemented"); + } + + } // end llvm namespace + Index: llvm/lib/Target/PowerPC/PowerPCInstrInfo.cpp diff -c /dev/null llvm/lib/Target/PowerPC/PowerPCInstrInfo.cpp:1.3.2.1 *** /dev/null Mon Mar 1 17:58:28 2004 --- llvm/lib/Target/PowerPC/PowerPCInstrInfo.cpp Mon Mar 1 17:58:13 2004 *************** *** 0 **** --- 1,21 ---- + //===- PowerPCInstrInfo.cpp - PowerPC Instruction Information ---*- C++ -*-===// + // + // The LLVM Compiler Infrastructure + // + // This file was developed by the LLVM research group and is distributed under + // the University of Illinois Open Source License. See LICENSE.TXT for details. + // + //===----------------------------------------------------------------------===// + // + // This file contains the PowerPC implementation of the TargetInstrInfo class. + // + //===----------------------------------------------------------------------===// + + #include "PowerPCInstrInfo.h" + #include "llvm/CodeGen/MachineInstrBuilder.h" + #include "PowerPCGenInstrInfo.inc" + using namespace llvm; + + PowerPCInstrInfo::PowerPCInstrInfo() + : TargetInstrInfo(PowerPCInsts, sizeof(PowerPCInsts)/sizeof(PowerPCInsts[0])){ + } Index: llvm/lib/Target/PowerPC/PowerPCInstrInfo.h diff -c /dev/null llvm/lib/Target/PowerPC/PowerPCInstrInfo.h:1.2.2.1 *** /dev/null Mon Mar 1 17:58:28 2004 --- llvm/lib/Target/PowerPC/PowerPCInstrInfo.h Mon Mar 1 17:58:13 2004 *************** *** 0 **** --- 1,36 ---- + //===- PowerPCInstrInfo.h - PowerPC Instruction Information -----*- C++ -*-===// + // + // The LLVM Compiler Infrastructure + // + // This file was developed by the LLVM research group and is distributed under + // the University of Illinois Open Source License. See LICENSE.TXT for details. + // + //===----------------------------------------------------------------------===// + // + // This file contains the PowerPC implementation of the TargetInstrInfo class. + // + //===----------------------------------------------------------------------===// + + #ifndef POWERPCINSTRUCTIONINFO_H + #define POWERPCINSTRUCTIONINFO_H + + #include "llvm/Target/TargetInstrInfo.h" + #include "PowerPCRegisterInfo.h" + + namespace llvm { + + class PowerPCInstrInfo : public TargetInstrInfo { + const PowerPCRegisterInfo RI; + public: + PowerPCInstrInfo(); + + /// getRegisterInfo - TargetInstrInfo is a superset of MRegister info. As + /// such, whenever a client has an instance of instruction info, it should + /// always be able to get register info as well (through this method). + /// + virtual const MRegisterInfo &getRegisterInfo() const { return RI; } + }; + + } + + #endif Index: llvm/lib/Target/PowerPC/PowerPCInstrs.td diff -c /dev/null llvm/lib/Target/PowerPC/PowerPCInstrs.td:1.1.2.1 *** /dev/null Mon Mar 1 17:58:28 2004 --- llvm/lib/Target/PowerPC/PowerPCInstrs.td Mon Mar 1 17:58:13 2004 *************** *** 0 **** --- 1,46 ---- + //===- PowerPCInstrInfo.td - Describe the PowerPC Instruction Set -*- C++ -*-=// + // + // The LLVM Compiler Infrastructure + // + // This file was developed by the LLVM research group and is distributed under + // the University of Illinois Open Source License. See LICENSE.TXT for details. + // + //===----------------------------------------------------------------------===// + // + // + //===----------------------------------------------------------------------===// + + class Format val> { + bits<4> Value = val; + } + + // All of the PowerPC instruction formats, plus a pseudo-instruction format: + def Pseudo : Format<0>; + def IForm : Format<1>; + def BForm : Format<2>; + def SCForm : Format<3>; + def DForm : Format<4>; + def XForm : Format<5>; + def XLForm : Format<6>; + def XFXForm : Format<7>; + def XFLForm : Format<8>; + def XOForm : Format<9>; + def AForm : Format<10>; + def MForm : Format<11>; + + class PPCInst opcd, Format f> : Instruction { + let Namespace = "PowerPC"; + + let Name = nm; + bits<6> Opcode = opcd; + Format Form = f; + bits<4> FormBits = Form.Value; + } + + // Pseudo-instructions: + def PHI : PPCInst<"PHI", 0, Pseudo>; // PHI node... + def NOP : PPCInst<"NOP", 0, Pseudo>; // No-op + def ADJCALLSTACKDOWN : PPCInst<"ADJCALLSTACKDOWN", 0, Pseudo>; + def ADJCALLSTACKUP : PPCInst<"ADJCALLSTACKUP", 0, Pseudo>; + + Index: llvm/lib/Target/PowerPC/PowerPCJITInfo.h diff -c /dev/null llvm/lib/Target/PowerPC/PowerPCJITInfo.h:1.1.2.1 *** /dev/null Mon Mar 1 17:58:28 2004 --- llvm/lib/Target/PowerPC/PowerPCJITInfo.h Mon Mar 1 17:58:13 2004 *************** *** 0 **** --- 1,49 ---- + //===- PowerPCJITInfo.h - PowerPC impl. of the JIT interface ----*- C++ -*-===// + // + // The LLVM Compiler Infrastructure + // + // This file was developed by the LLVM research group and is distributed under + // the University of Illinois Open Source License. See LICENSE.TXT for details. + // + //===----------------------------------------------------------------------===// + // + // This file contains the PowerPC implementation of the TargetJITInfo class. + // + //===----------------------------------------------------------------------===// + + #ifndef POWERPCJITINFO_H + #define POWERPCJITINFO_H + + #include "llvm/Target/TargetJITInfo.h" + + namespace llvm { + class TargetMachine; + class IntrinsicLowering; + + class PowerPCJITInfo : public TargetJITInfo { + TargetMachine &TM; + public: + PowerPCJITInfo(TargetMachine &tm) : TM(tm) {} + + /// addPassesToJITCompile - Add passes to the specified pass manager to + /// implement a fast dynamic compiler for this target. Return true if this + /// is not supported for this target. + /// + virtual void addPassesToJITCompile(FunctionPassManager &PM); + + /// replaceMachineCodeForFunction - Make it so that calling the function + /// whose machine code is at OLD turns into a call to NEW, perhaps by + /// overwriting OLD with a branch to NEW. This is used for self-modifying + /// code. + /// + virtual void replaceMachineCodeForFunction(void *Old, void *New); + + /// getJITStubForFunction - Create or return a stub for the specified + /// function. This stub acts just like the specified function, except that + /// it allows the "address" of the function to be taken without having to + /// generate code for it. + virtual void *getJITStubForFunction(Function *F, MachineCodeEmitter &MCE); + }; + } + + #endif Index: llvm/lib/Target/PowerPC/PowerPCReg.td diff -c /dev/null llvm/lib/Target/PowerPC/PowerPCReg.td:1.1.2.1 *** /dev/null Mon Mar 1 17:58:28 2004 --- llvm/lib/Target/PowerPC/PowerPCReg.td Mon Mar 1 17:58:13 2004 *************** *** 0 **** --- 1,82 ---- + //===- PowerPCReg.td - Describe the PowerPC Register File -------*- C++ -*-===// + // + // The LLVM Compiler Infrastructure + // + // This file was developed by the LLVM research group and is distributed under + // the University of Illinois Open Source License. See LICENSE.TXT for details. + // + //===----------------------------------------------------------------------===// + // + // + //===----------------------------------------------------------------------===// + + class PPCReg : Register { + let Namespace = "PowerPC"; + } + + // We identify all our registers with a 5-bit ID, for consistency's sake. + + // GPR - One of the 32 32-bit general-purpose registers + class GPR num> : PPCReg { + field bits<5> Num = num; + } + + // SPR - One of the 32-bit special-purpose registers + class SPR num> : PPCReg { + field bits<5> Num = num; + } + + // FPR - One of the 32 64-bit floating-point registers + class FPR num> : PPCReg { + field bits<5> Num = num; + } + + // CR - One of the 8 4-bit condition registers + class CR num> : PPCReg { + field bits<5> Num = num; + } + + // General-purpose registers + def R0 : GPR< 0>; def R1 : GPR< 1>; def R2 : GPR< 2>; def R3 : GPR< 3>; + def R4 : GPR< 4>; def R5 : GPR< 5>; def R6 : GPR< 6>; def R7 : GPR< 7>; + def R8 : GPR< 8>; def R9 : GPR< 9>; def R10 : GPR<10>; def R11 : GPR<11>; + def R12 : GPR<12>; def R13 : GPR<13>; def R14 : GPR<14>; def R15 : GPR<15>; + def R16 : GPR<16>; def R17 : GPR<17>; def R18 : GPR<18>; def R19 : GPR<19>; + def R20 : GPR<20>; def R21 : GPR<21>; def R22 : GPR<22>; def R23 : GPR<23>; + def R24 : GPR<24>; def R25 : GPR<25>; def R26 : GPR<26>; def R27 : GPR<27>; + def R28 : GPR<28>; def R29 : GPR<29>; def R30 : GPR<30>; def R31 : GPR<31>; + + // Floating-point registers + def F0 : FPR< 0>; def F1 : FPR< 1>; def F2 : FPR< 2>; def F3 : FPR< 3>; + def F4 : FPR< 4>; def F5 : FPR< 5>; def F6 : FPR< 6>; def F7 : FPR< 7>; + def F8 : FPR< 8>; def F9 : FPR< 9>; def F10 : FPR<10>; def F11 : FPR<11>; + def F12 : FPR<12>; def F13 : FPR<13>; def F14 : FPR<14>; def F15 : FPR<15>; + def F16 : FPR<16>; def F17 : FPR<17>; def F18 : FPR<18>; def F19 : FPR<19>; + def F20 : FPR<20>; def F21 : FPR<21>; def F22 : FPR<22>; def F23 : FPR<23>; + def F24 : FPR<24>; def F25 : FPR<25>; def F26 : FPR<26>; def F27 : FPR<27>; + def F28 : FPR<28>; def F29 : FPR<29>; def F30 : FPR<30>; def F31 : FPR<31>; + + // Condition registers + def CR0 : CR<0>; def CR1 : CR<1>; def CR2 : CR<2>; def CR3 : CR<3>; + def CR4 : CR<4>; def CR5 : CR<5>; def CR6 : CR<6>; def CR7 : CR<7>; + + // Floating-point status and control register + def FPSCR : SPR<0>; + // fiXed-point Exception Register? :-) + def XER : SPR<1>; + // Link register + def LR : SPR<2>; + // Count register + def CTR : SPR<3>; + // These are the "time base" registers which are read-only in user mode. + def TBL : SPR<4>; + def TBU : SPR<5>; + + /// Register classes: one for floats and another for non-floats. + def GPRC : RegisterClass; + def FPRC : RegisterClass; + Index: llvm/lib/Target/PowerPC/PowerPCRegisterInfo.cpp diff -c /dev/null llvm/lib/Target/PowerPC/PowerPCRegisterInfo.cpp:1.4.2.1 *** /dev/null Mon Mar 1 17:58:28 2004 --- llvm/lib/Target/PowerPC/PowerPCRegisterInfo.cpp Mon Mar 1 17:58:13 2004 *************** *** 0 **** --- 1,99 ---- + //===- PowerPCRegisterInfo.cpp - PowerPC Register Information ---*- C++ -*-===// + // + // The LLVM Compiler Infrastructure + // + // This file was developed by the LLVM research group and is distributed under + // the University of Illinois Open Source License. See LICENSE.TXT for details. + // + //===----------------------------------------------------------------------===// + // + // This file contains the PowerPC implementation of the MRegisterInfo class. + // + //===----------------------------------------------------------------------===// + + #include "PowerPC.h" + #include "PowerPCRegisterInfo.h" + #include "llvm/Type.h" + using namespace llvm; + + PowerPCRegisterInfo::PowerPCRegisterInfo() + : PowerPCGenRegisterInfo(PowerPC::ADJCALLSTACKDOWN, + PowerPC::ADJCALLSTACKUP) {} + + int PowerPCRegisterInfo::storeRegToStackSlot( + MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + unsigned SrcReg, int FrameIdx, + const TargetRegisterClass *RC) const + { + abort(); + return -1; + } + + int PowerPCRegisterInfo::loadRegFromStackSlot( + MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + unsigned DestReg, int FrameIdx, + const TargetRegisterClass *RC) const + { + abort(); + return -1; + } + + int PowerPCRegisterInfo::copyRegToReg(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + unsigned DestReg, unsigned SrcReg, + const TargetRegisterClass *RC) const { + abort(); + return -1; + } + + void PowerPCRegisterInfo:: + eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) const { + abort(); + } + + void + PowerPCRegisterInfo::eliminateFrameIndex(MachineFunction &MF, + MachineBasicBlock::iterator II) const { + abort(); + } + + void PowerPCRegisterInfo::processFunctionBeforeFrameFinalized( + MachineFunction &MF) const { + abort(); + } + + void PowerPCRegisterInfo::emitPrologue(MachineFunction &MF) const { + abort(); + } + + void PowerPCRegisterInfo::emitEpilogue(MachineFunction &MF, + MachineBasicBlock &MBB) const { + abort(); + } + + + #include "PowerPCGenRegisterInfo.inc" + + const TargetRegisterClass* + PowerPCRegisterInfo::getRegClassForType(const Type* Ty) const { + switch (Ty->getPrimitiveID()) { + case Type::LongTyID: + case Type::ULongTyID: assert(0 && "Long values can't fit in registers!"); + default: assert(0 && "Invalid type to getClass!"); + case Type::BoolTyID: + case Type::SByteTyID: + case Type::UByteTyID: + case Type::ShortTyID: + case Type::UShortTyID: + case Type::IntTyID: + case Type::UIntTyID: + case Type::PointerTyID: return &GPRCInstance; + + case Type::FloatTyID: + case Type::DoubleTyID: return &FPRCInstance; + } + } + Index: llvm/lib/Target/PowerPC/PowerPCRegisterInfo.h diff -c /dev/null llvm/lib/Target/PowerPC/PowerPCRegisterInfo.h:1.4.2.1 *** /dev/null Mon Mar 1 17:58:28 2004 --- llvm/lib/Target/PowerPC/PowerPCRegisterInfo.h Mon Mar 1 17:58:13 2004 *************** *** 0 **** --- 1,58 ---- + //===- PowerPCRegisterInfo.h - PowerPC Register Information Impl -*- C++ -*-==// + // + // The LLVM Compiler Infrastructure + // + // This file was developed by the LLVM research group and is distributed under + // the University of Illinois Open Source License. See LICENSE.TXT for details. + // + //===----------------------------------------------------------------------===// + // + // This file contains the PowerPC implementation of the MRegisterInfo class. + // + //===----------------------------------------------------------------------===// + + #ifndef POWERPCREGISTERINFO_H + #define POWERPCREGISTERINFO_H + + #include "llvm/Target/MRegisterInfo.h" + #include "PowerPCGenRegisterInfo.h.inc" + + namespace llvm { + + class Type; + + struct PowerPCRegisterInfo : public PowerPCGenRegisterInfo { + PowerPCRegisterInfo(); + const TargetRegisterClass* getRegClassForType(const Type* Ty) const; + + /// Code Generation virtual methods... + int storeRegToStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + unsigned SrcReg, int FrameIndex, + const TargetRegisterClass *RC) const; + + int loadRegFromStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + unsigned DestReg, int FrameIndex, + const TargetRegisterClass *RC) const; + + int copyRegToReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, + unsigned DestReg, unsigned SrcReg, + const TargetRegisterClass *RC) const; + + void eliminateCallFramePseudoInstr(MachineFunction &MF, + MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) const; + + void eliminateFrameIndex(MachineFunction &MF, + MachineBasicBlock::iterator II) const; + + void processFunctionBeforeFrameFinalized(MachineFunction &MF) const; + + void emitPrologue(MachineFunction &MF) const; + void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const; + }; + + } // end namespace llvm + + #endif Index: llvm/lib/Target/PowerPC/PowerPCTargetMachine.cpp diff -c /dev/null llvm/lib/Target/PowerPC/PowerPCTargetMachine.cpp:1.7.2.1 *** /dev/null Mon Mar 1 17:58:28 2004 --- llvm/lib/Target/PowerPC/PowerPCTargetMachine.cpp Mon Mar 1 17:58:13 2004 *************** *** 0 **** --- 1,59 ---- + //===-- PowerPCTargetMachine.cpp - Define TargetMachine for PowerPC -------===// + // + // The LLVM Compiler Infrastructure + // + // This file was developed by the LLVM research group and is distributed under + // the University of Illinois Open Source License. See LICENSE.TXT for details. + // + //===----------------------------------------------------------------------===// + // + // + //===----------------------------------------------------------------------===// + + #include "PowerPCTargetMachine.h" + #include "PowerPC.h" + #include "llvm/Module.h" + #include "llvm/PassManager.h" + #include "llvm/Target/TargetMachineImpls.h" + #include "llvm/CodeGen/MachineFunction.h" + #include "llvm/CodeGen/Passes.h" + using namespace llvm; + + // allocatePowerPCTargetMachine - Allocate and return a subclass of + // TargetMachine that implements the PowerPC backend. + // + TargetMachine *llvm::allocatePowerPCTargetMachine(const Module &M, + IntrinsicLowering *IL) { + return new PowerPCTargetMachine(M, IL); + } + + /// PowerPCTargetMachine ctor - Create an ILP32 architecture model + /// + PowerPCTargetMachine::PowerPCTargetMachine(const Module &M, + IntrinsicLowering *IL) + : TargetMachine("PowerPC", IL, true, 4, 4, 4, 4, 4), + FrameInfo(TargetFrameInfo::StackGrowsDown, 8, 4), JITInfo(*this) { + } + + /// addPassesToEmitAssembly - Add passes to the specified pass manager + /// to implement a static compiler for this target. + /// + bool PowerPCTargetMachine::addPassesToEmitAssembly(PassManager &PM, + std::ostream &Out) { + // + PM.add(createRegisterAllocator()); + PM.add(createPrologEpilogCodeInserter()); + // + PM.add(createMachineCodeDeleter()); + return true; // change to `return false' when this actually works. + } + + /// addPassesToJITCompile - Add passes to the specified pass manager to + /// implement a fast dynamic compiler for this target. + /// + void PowerPCJITInfo::addPassesToJITCompile(FunctionPassManager &PM) { + // + PM.add(createRegisterAllocator()); + PM.add(createPrologEpilogCodeInserter()); + } + Index: llvm/lib/Target/PowerPC/PowerPCTargetMachine.h diff -c /dev/null llvm/lib/Target/PowerPC/PowerPCTargetMachine.h:1.4.2.1 *** /dev/null Mon Mar 1 17:58:28 2004 --- llvm/lib/Target/PowerPC/PowerPCTargetMachine.h Mon Mar 1 17:58:13 2004 *************** *** 0 **** --- 1,60 ---- + //===-- PowerPCTargetMachine.h - Define TargetMachine for PowerPC -*- C++ -*-=// + // + // The LLVM Compiler Infrastructure + // + // This file was developed by the LLVM research group and is distributed under + // the University of Illinois Open Source License. See LICENSE.TXT for details. + // + //===----------------------------------------------------------------------===// + // + // This file declares the PowerPC specific subclass of TargetMachine. + // + //===----------------------------------------------------------------------===// + + #ifndef POWERPCTARGETMACHINE_H + #define POWERPCTARGETMACHINE_H + + #include "llvm/Target/TargetMachine.h" + #include "llvm/Target/TargetFrameInfo.h" + #include "llvm/PassManager.h" + #include "PowerPCInstrInfo.h" + #include "PowerPCJITInfo.h" + + namespace llvm { + + class IntrinsicLowering; + + class PowerPCTargetMachine : public TargetMachine { + PowerPCInstrInfo InstrInfo; + TargetFrameInfo FrameInfo; + PowerPCJITInfo JITInfo; + public: + PowerPCTargetMachine(const Module &M, IntrinsicLowering *IL); + + virtual const PowerPCInstrInfo &getInstrInfo() const { return InstrInfo; } + virtual const TargetFrameInfo &getFrameInfo() const { return FrameInfo; } + virtual const MRegisterInfo *getRegisterInfo() const { + return &InstrInfo.getRegisterInfo(); + } + virtual TargetJITInfo *getJITInfo() { + return &JITInfo; + } + + virtual const TargetSchedInfo &getSchedInfo() const { abort(); } + virtual const TargetRegInfo &getRegInfo() const { abort(); } + + /// addPassesToEmitMachineCode - Add passes to the specified pass manager to + /// get machine code emitted. This uses a MachineCodeEmitter object to handle + /// actually outputting the machine code and resolving things like the address + /// of functions. This method should returns true if machine code emission is + /// not supported. + /// + virtual bool addPassesToEmitMachineCode(FunctionPassManager &PM, + MachineCodeEmitter &MCE); + + virtual bool addPassesToEmitAssembly(PassManager &PM, std::ostream &Out); + }; + + } // end namespace llvm + + #endif Index: llvm/lib/Target/PowerPC/README.txt diff -c /dev/null llvm/lib/Target/PowerPC/README.txt:1.2.2.1 *** /dev/null Mon Mar 1 17:58:29 2004 --- llvm/lib/Target/PowerPC/README.txt Mon Mar 1 17:58:13 2004 *************** *** 0 **** --- 1,26 ---- + + PowerPC backend skeleton + ------------------------ + + Someday we'd like to have a PowerPC backend. Unfortunately, this + is not yet that day. + + This directory contains mainly stubs and placeholders; there is no + binary machine code emitter, no assembly writer, and no instruction + selector here. Most of the functions in these files call abort() + or fail assertions on purpose, just to reinforce the fact that they + don't work. + + If you want to use LLVM on the PowerPC *today*, use the C Backend + (llc -march=c). It generates C code that you can compile with the + native GCC compiler and run. A distant second choice would be the + Interpreter (lli --force-interpreter=true). + + A few things *are* really here, including: + * PowerPC register file definition in TableGen format + * PowerPC definitions of TargetMachine and other target-specific classes + + "Patches," as they say, "are accepted." + + $Date: 2004/03/01 23:58:13 $ + From brukman at cs.uiuc.edu Mon Mar 1 18:04:04 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Mar 1 18:04:04 2004 Subject: [llvm-commits] [parallel] CVS: llvm/lib/Transforms/IPO/GlobalConstifier.cpp DeadArgumentElimination.cpp DeadTypeElimination.cpp FunctionResolution.cpp LowerSetJmp.cpp MutateStructTypes.cpp Parallelize.cpp PruneEH.cpp SimpleStructMutation.cpp Message-ID: <200403012358.RAA04021@zion.cs.uiuc.edu> Changes in directory llvm/lib/Transforms/IPO: GlobalConstifier.cpp added (r1.2.2.1) DeadArgumentElimination.cpp updated: 1.14 -> 1.14.4.1 DeadTypeElimination.cpp updated: 1.48 -> 1.48.4.1 FunctionResolution.cpp updated: 1.45 -> 1.45.4.1 LowerSetJmp.cpp updated: 1.14 -> 1.14.4.1 MutateStructTypes.cpp updated: 1.44 -> 1.44.2.1 Parallelize.cpp updated: 1.12 -> 1.12.4.1 PruneEH.cpp updated: 1.9 -> 1.9.4.1 SimpleStructMutation.cpp updated: 1.24 -> 1.24.4.1 --- Log message: Merge from trunk --- Diffs of the changes: (+270 -219) Index: llvm/lib/Transforms/IPO/GlobalConstifier.cpp diff -c /dev/null llvm/lib/Transforms/IPO/GlobalConstifier.cpp:1.2.2.1 *** /dev/null Mon Mar 1 17:58:28 2004 --- llvm/lib/Transforms/IPO/GlobalConstifier.cpp Mon Mar 1 17:58:16 2004 *************** *** 0 **** --- 1,82 ---- + //===- GlobalConstifier.cpp - Mark read-only globals constant -------------===// + // + // The LLVM Compiler Infrastructure + // + // This file was developed by the LLVM research group and is distributed under + // the University of Illinois Open Source License. See LICENSE.TXT for details. + // + //===----------------------------------------------------------------------===// + // + // This pass loops over the non-constant internal global variables in the + // program. If it can prove that they are never written to, it marks them + // constant. + // + // NOTE: this should eventually use the alias analysis interfaces to do the + // transformation, but for now we just stick with a simple solution. DSA in + // particular could give a much more accurate answer to the mod/ref query, but + // it's not quite ready for this. + // + //===----------------------------------------------------------------------===// + + #include "llvm/Transforms/IPO.h" + #include "llvm/Constants.h" + #include "llvm/Instructions.h" + #include "llvm/Module.h" + #include "llvm/Pass.h" + #include "Support/Debug.h" + #include "Support/Statistic.h" + using namespace llvm; + + namespace { + Statistic<> NumMarked("constify", "Number of globals marked constant"); + + struct Constifier : public Pass { + bool run(Module &M); + }; + + RegisterOpt X("constify", "Global Constifier"); + } + + Pass *llvm::createGlobalConstifierPass() { return new Constifier(); } + + /// isStoredThrough - Return false if the specified pointer is provably never + /// stored through. If we can't tell, we must conservatively assume it might. + /// + static bool isStoredThrough(Value *V) { + for (Value::use_iterator UI = V->use_begin(), E = V->use_end(); UI != E; ++UI) + if (Constant *C = dyn_cast(*UI)) { + if (ConstantExpr *CE = dyn_cast(C)) { + if (isStoredThrough(CE)) + return true; + } else if (ConstantPointerRef *CPR = dyn_cast(C)) { + if (isStoredThrough(CPR)) return true; + } else { + // Must be an element of a constant array or something. + return true; + } + } else if (Instruction *I = dyn_cast(*UI)) { + if (I->getOpcode() == Instruction::GetElementPtr) { + if (isStoredThrough(I)) return true; + } else if (!isa(*UI) && !isa(*UI)) + return true; // Any other non-load instruction might store! + } else { + // Otherwise must be a global or some other user. + return true; + } + + return false; + } + + bool Constifier::run(Module &M) { + bool Changed = false; + for (Module::giterator GV = M.gbegin(), E = M.gend(); GV != E; ++GV) + if (!GV->isConstant() && GV->hasInternalLinkage() && GV->hasInitializer()) { + if (!isStoredThrough(GV)) { + DEBUG(std::cerr << "MARKING CONSTANT: " << *GV << "\n"); + GV->setConstant(true); + ++NumMarked; + Changed = true; + } + } + return Changed; + } Index: llvm/lib/Transforms/IPO/DeadArgumentElimination.cpp diff -u llvm/lib/Transforms/IPO/DeadArgumentElimination.cpp:1.14 llvm/lib/Transforms/IPO/DeadArgumentElimination.cpp:1.14.4.1 --- llvm/lib/Transforms/IPO/DeadArgumentElimination.cpp:1.14 Fri Nov 21 15:54:21 2003 +++ llvm/lib/Transforms/IPO/DeadArgumentElimination.cpp Mon Mar 1 17:58:16 2004 @@ -101,7 +101,7 @@ virtual bool ShouldHackArguments() const { return true; } }; RegisterPass Y("deadarghaX0r", - "Dead Argument Hacking (bugpoint usage only)"); + "Dead Argument Hacking (BUGPOINT USE ONLY; DO NOT USE)"); } /// createDeadArgEliminationPass - This pass removes arguments from functions @@ -424,7 +424,7 @@ Instruction *New; if (InvokeInst *II = dyn_cast(Call)) { - New = new InvokeInst(NF, II->getNormalDest(), II->getExceptionalDest(), + New = new InvokeInst(NF, II->getNormalDest(), II->getUnwindDest(), Args, "", Call); } else { New = new CallInst(NF, Args, "", Call); Index: llvm/lib/Transforms/IPO/DeadTypeElimination.cpp diff -u llvm/lib/Transforms/IPO/DeadTypeElimination.cpp:1.48 llvm/lib/Transforms/IPO/DeadTypeElimination.cpp:1.48.4.1 --- llvm/lib/Transforms/IPO/DeadTypeElimination.cpp:1.48 Fri Nov 21 15:54:21 2003 +++ llvm/lib/Transforms/IPO/DeadTypeElimination.cpp Mon Mar 1 17:58:16 2004 @@ -49,12 +49,12 @@ // ShouldNukeSymtabEntry - Return true if this module level symbol table entry // should be eliminated. // -static inline bool ShouldNukeSymtabEntry(const std::pair&E){ +static inline bool ShouldNukeSymtabEntry(const Type *Ty){ // Nuke all names for primitive types! - if (cast(E.second)->isPrimitiveType()) return true; + if (Ty->isPrimitiveType()) return true; // Nuke all pointers to primitive types as well... - if (const PointerType *PT = dyn_cast(E.second)) + if (const PointerType *PT = dyn_cast(Ty)) if (PT->getElementType()->isPrimitiveType()) return true; return false; @@ -69,8 +69,7 @@ bool Changed = false; SymbolTable &ST = M.getSymbolTable(); - const std::set &UsedTypes = - getAnalysis().getTypes(); + std::set UsedTypes = getAnalysis().getTypes(); // Check the symbol table for superfluous type entries... // @@ -79,18 +78,20 @@ if (STI != ST.end()) { // Loop over all entries in the type plane... SymbolTable::VarMap &Plane = STI->second; - for (SymbolTable::VarMap::iterator PI = Plane.begin(); PI != Plane.end();) + for (SymbolTable::VarMap::iterator PI = Plane.begin(); PI != Plane.end();) { // If this entry should be unconditionally removed, or if we detect that // the type is not used, remove it. - if (ShouldNukeSymtabEntry(*PI) || - !UsedTypes.count(cast(PI->second))) { - SymbolTable::VarMap::iterator PJ = PI++; - Plane.erase(PJ); + const Type *RHS = cast(PI->second); + if (ShouldNukeSymtabEntry(RHS) || !UsedTypes.count(RHS)) { + Plane.erase(PI++); ++NumKilled; Changed = true; } else { ++PI; + // We only need to leave one name for each type. + UsedTypes.erase(RHS); } + } } return Changed; Index: llvm/lib/Transforms/IPO/FunctionResolution.cpp diff -u llvm/lib/Transforms/IPO/FunctionResolution.cpp:1.45 llvm/lib/Transforms/IPO/FunctionResolution.cpp:1.45.4.1 --- llvm/lib/Transforms/IPO/FunctionResolution.cpp:1.45 Thu Nov 20 15:21:31 2003 +++ llvm/lib/Transforms/IPO/FunctionResolution.cpp Mon Mar 1 17:58:16 2004 @@ -58,7 +58,7 @@ const FunctionType *OldMT = Old->getFunctionType(); const FunctionType *ConcreteMT = Concrete->getFunctionType(); - if (OldMT->getParamTypes().size() > ConcreteMT->getParamTypes().size() && + if (OldMT->getNumParams() > ConcreteMT->getNumParams() && !ConcreteMT->isVarArg()) if (!Old->use_empty()) { std::cerr << "WARNING: Linking function '" << Old->getName() @@ -73,14 +73,14 @@ // Check to make sure that if there are specified types, that they // match... // - unsigned NumArguments = std::min(OldMT->getParamTypes().size(), - ConcreteMT->getParamTypes().size()); + unsigned NumArguments = std::min(OldMT->getNumParams(), + ConcreteMT->getNumParams()); if (!Old->use_empty() && !Concrete->use_empty()) for (unsigned i = 0; i < NumArguments; ++i) - if (OldMT->getParamTypes()[i] != ConcreteMT->getParamTypes()[i]) - if (OldMT->getParamTypes()[i]->getPrimitiveID() != - ConcreteMT->getParamTypes()[i]->getPrimitiveID()) { + if (OldMT->getParamType(i) != ConcreteMT->getParamType(i)) + if (OldMT->getParamType(i)->getPrimitiveID() != + ConcreteMT->getParamType(i)->getPrimitiveID()) { std::cerr << "WARNING: Function [" << Old->getName() << "]: Parameter types conflict for: '"; WriteTypeSymbolic(std::cerr, OldMT, &M); @@ -231,7 +231,7 @@ if ((ConcreteF->getReturnType() == OtherF->getReturnType() || CallersAllIgnoreReturnValue(*OtherF)) && OtherF->getFunctionType()->isVarArg() && - OtherF->getFunctionType()->getParamTypes().empty()) + OtherF->getFunctionType()->getNumParams() == 0) DontPrintWarning = true; // Otherwise, if the non-concrete global is a global array variable with a Index: llvm/lib/Transforms/IPO/LowerSetJmp.cpp diff -u llvm/lib/Transforms/IPO/LowerSetJmp.cpp:1.14 llvm/lib/Transforms/IPO/LowerSetJmp.cpp:1.14.4.1 --- llvm/lib/Transforms/IPO/LowerSetJmp.cpp:1.14 Fri Nov 21 15:54:22 2003 +++ llvm/lib/Transforms/IPO/LowerSetJmp.cpp Mon Mar 1 17:58:16 2004 @@ -413,11 +413,6 @@ SetJmpContBlock->setName("SetJmpContBlock"); - // Reposition the split BB in the BB list to make things tidier. - Func->getBasicBlockList().remove(SetJmpContBlock); - Func->getBasicBlockList().insert(++Function::iterator(ABlock), - SetJmpContBlock); - // This PHI node will be in the new block created from the // splitBasicBlock call. PHINode* PHI = new PHINode(Type::IntTy, "SetJmpReturn", Inst); @@ -460,10 +455,7 @@ assert(NewBB && "Couldn't split BB of \"call\" instruction!!"); NewBB->setName("Call2Invoke"); - // Reposition the split BB in the BB list to make things tidier. Function* Func = OldBB->getParent(); - Func->getBasicBlockList().remove(NewBB); - Func->getBasicBlockList().insert(++Function::iterator(OldBB), NewBB); // Construct the new "invoke" instruction. TerminatorInst* Term = OldBB->getTerminator(); @@ -497,7 +489,7 @@ if (!DFSBlocks.count(BB)) return; BasicBlock* NormalBB = II.getNormalDest(); - BasicBlock* ExceptBB = II.getExceptionalDest(); + BasicBlock* ExceptBB = II.getUnwindDest(); Function* Func = BB->getParent(); BasicBlock* NewExceptBB = new BasicBlock("InvokeExcept", Func); @@ -511,7 +503,7 @@ new BranchInst(PrelimBBMap[Func], ExceptBB, IsLJExcept, NewExceptBB); - II.setExceptionalDest(NewExceptBB); + II.setUnwindDest(NewExceptBB); ++InvokesTransformed; } Index: llvm/lib/Transforms/IPO/MutateStructTypes.cpp diff -u llvm/lib/Transforms/IPO/MutateStructTypes.cpp:1.44 llvm/lib/Transforms/IPO/MutateStructTypes.cpp:1.44.2.1 --- llvm/lib/Transforms/IPO/MutateStructTypes.cpp:1.44 Fri Jan 9 00:02:51 2004 +++ llvm/lib/Transforms/IPO/MutateStructTypes.cpp Mon Mar 1 17:58:16 2004 @@ -60,8 +60,8 @@ const Type *RetTy = ConvertType(FT->getReturnType()); std::vector ArgTypes; - for (FunctionType::ParamTypes::const_iterator I = FT->getParamTypes().begin(), - E = FT->getParamTypes().end(); I != E; ++I) + for (FunctionType::param_iterator I = FT->param_begin(), + E = FT->param_end(); I != E; ++I) ArgTypes.push_back(ConvertType(*I)); DestTy = FunctionType::get(RetTy, ArgTypes, FT->isVarArg()); @@ -69,11 +69,10 @@ } case Type::StructTyID: { const StructType *ST = cast(Ty); - const StructType::ElementTypes &El = ST->getElementTypes(); std::vector Types; - for (StructType::ElementTypes::const_iterator I = El.begin(), E = El.end(); - I != E; ++I) + for (StructType::element_iterator I = ST->element_begin(), + E = ST->element_end(); I != E; ++I) Types.push_back(ConvertType(*I)); DestTy = StructType::get(Types); break; @@ -115,7 +114,7 @@ if (const StructType *OldST = dyn_cast(OldTy)) { // Figure out what the current index is... unsigned ElNum = cast(Idx[i])->getValue(); - assert(ElNum < OldST->getElementTypes().size()); + assert(ElNum < OldST->getNumElements()); std::map::iterator I = Transforms.find(OldST); @@ -198,7 +197,7 @@ const StructType *OldTy = I->first; const std::vector &InVec = I->second; - assert(OldTy->getElementTypes().size() == InVec.size() && + assert(OldTy->getNumElements() == InVec.size() && "Action not specified for every element of structure type!"); std::vector NewType; Index: llvm/lib/Transforms/IPO/Parallelize.cpp diff -u llvm/lib/Transforms/IPO/Parallelize.cpp:1.12 llvm/lib/Transforms/IPO/Parallelize.cpp:1.12.4.1 --- llvm/lib/Transforms/IPO/Parallelize.cpp:1.12 Fri Nov 21 15:54:22 2003 +++ llvm/lib/Transforms/IPO/Parallelize.cpp Mon Mar 1 17:58:16 2004 @@ -91,10 +91,7 @@ // Code generation pass that transforms code to identify where Cilk keywords // should be inserted. This relies on `llvm-dis -c' to print out the keywords. //---------------------------------------------------------------------------- - - -class Cilkifier: public InstVisitor -{ +class Cilkifier: public InstVisitor { Function* DummySyncFunc; // Data used when transforming each function. @@ -124,16 +121,14 @@ }; -Cilkifier::Cilkifier(Module& M) -{ +Cilkifier::Cilkifier(Module& M) { // create the dummy Sync function and add it to the Module DummySyncFunc = M.getOrInsertFunction(DummySyncFuncName, Type::VoidTy, 0); } void Cilkifier::TransformFunc(Function* F, const hash_set& _cilkFunctions, - PgmDependenceGraph& _depGraph) -{ + PgmDependenceGraph& _depGraph) { // Memoize the information for this function cilkFunctions = &_cilkFunctions; depGraph = &_depGraph; @@ -159,37 +154,35 @@ stmtsVisited.insert(I); // If there is a dependence from root to I, insert Sync and return - if (depsOfRoot.find(I) != depsOfRoot.end()) - { // Insert a sync before I and stop searching along this path. - // If I is a Phi instruction, the dependence can only be an SSA dep. - // and we need to insert the sync in the predecessor on the appropriate - // incoming edge! - CallInst* syncI = 0; - if (PHINode* phiI = dyn_cast(I)) - { // check all operands of the Phi and insert before each one - for (unsigned i = 0, N = phiI->getNumIncomingValues(); i < N; ++i) - if (phiI->getIncomingValue(i) == root) - syncI = new CallInst(DummySyncFunc, std::vector(), "", - phiI->getIncomingBlock(i)->getTerminator()); - } - else - syncI = new CallInst(DummySyncFunc, std::vector(), "", I); + if (depsOfRoot.find(I) != depsOfRoot.end()) { + // Insert a sync before I and stop searching along this path. + // If I is a Phi instruction, the dependence can only be an SSA dep. + // and we need to insert the sync in the predecessor on the appropriate + // incoming edge! + CallInst* syncI = 0; + if (PHINode* phiI = dyn_cast(I)) { + // check all operands of the Phi and insert before each one + for (unsigned i = 0, N = phiI->getNumIncomingValues(); i < N; ++i) + if (phiI->getIncomingValue(i) == root) + syncI = new CallInst(DummySyncFunc, std::vector(), "", + phiI->getIncomingBlock(i)->getTerminator()); + } else + syncI = new CallInst(DummySyncFunc, std::vector(), "", I); - // Remember the sync for each spawn to eliminate redundant ones later - spawnToSyncsMap[cast(root)].insert(syncI); + // Remember the sync for each spawn to eliminate redundant ones later + spawnToSyncsMap[cast(root)].insert(syncI); - return; - } + return; + } // else visit unvisited successors - if (BranchInst* brI = dyn_cast(I)) - { // visit first instruction in each successor BB - for (unsigned i = 0, N = brI->getNumSuccessors(); i < N; ++i) - if (stmtsVisited.find(&brI->getSuccessor(i)->front()) - == stmtsVisited.end()) - DFSVisitInstr(&brI->getSuccessor(i)->front(), root, depsOfRoot); - } - else + if (BranchInst* brI = dyn_cast(I)) { + // visit first instruction in each successor BB + for (unsigned i = 0, N = brI->getNumSuccessors(); i < N; ++i) + if (stmtsVisited.find(&brI->getSuccessor(i)->front()) + == stmtsVisited.end()) + DFSVisitInstr(&brI->getSuccessor(i)->front(), root, depsOfRoot); + } else if (Instruction* nextI = I->getNext()) if (stmtsVisited.find(nextI) == stmtsVisited.end()) DFSVisitInstr(nextI, root, depsOfRoot); @@ -214,44 +207,37 @@ std::vector phiUsers; hash_set phisSeen; // ensures we don't visit a phi twice for (Value::use_iterator UI=CI.use_begin(), UE=CI.use_end(); UI != UE; ++UI) - if (const PHINode* phiUser = dyn_cast(*UI)) - { - if (phisSeen.find(phiUser) == phisSeen.end()) - { - phiUsers.push_back(phiUser); - phisSeen.insert(phiUser); - } + if (const PHINode* phiUser = dyn_cast(*UI)) { + if (phisSeen.find(phiUser) == phisSeen.end()) { + phiUsers.push_back(phiUser); + phisSeen.insert(phiUser); } + } else depsOfRoot.insert(cast(*UI)); // Now we've found the non-Phi users and immediate phi users. // Recursively walk the phi users and add their non-phi users. - for (const PHINode* phiUser; !phiUsers.empty(); phiUsers.pop_back()) - { - phiUser = phiUsers.back(); - for (Value::use_const_iterator UI=phiUser->use_begin(), - UE=phiUser->use_end(); UI != UE; ++UI) - if (const PHINode* pn = dyn_cast(*UI)) - { - if (phisSeen.find(pn) == phisSeen.end()) - { - phiUsers.push_back(pn); - phisSeen.insert(pn); - } - } - else - depsOfRoot.insert(cast(*UI)); - } + for (const PHINode* phiUser; !phiUsers.empty(); phiUsers.pop_back()) { + phiUser = phiUsers.back(); + for (Value::use_const_iterator UI=phiUser->use_begin(), + UE=phiUser->use_end(); UI != UE; ++UI) + if (const PHINode* pn = dyn_cast(*UI)) { + if (phisSeen.find(pn) == phisSeen.end()) { + phiUsers.push_back(pn); + phisSeen.insert(pn); + } + } else + depsOfRoot.insert(cast(*UI)); + } // Walk paths of the CFG starting at the call instruction and insert // one sync before the first dependence on each path, if any. - if (! depsOfRoot.empty()) - { - stmtsVisited.clear(); // start a new DFS for this CallInst - assert(CI.getNext() && "Call instruction cannot be a terminator!"); - DFSVisitInstr(CI.getNext(), &CI, depsOfRoot); - } + if (! depsOfRoot.empty()) { + stmtsVisited.clear(); // start a new DFS for this CallInst + assert(CI.getNext() && "Call instruction cannot be a terminator!"); + DFSVisitInstr(CI.getNext(), &CI, depsOfRoot); + } // Now, eliminate all users of the SSA value of the CallInst, i.e., // if the call instruction returns a value, delete the return value @@ -304,31 +290,28 @@ // Now we've found all CallInsts reachable from each CallInst. // Find those CallInsts that are parallel with at least one other CallInst // by counting total inEdges and outEdges. - // unsigned long totalNumCalls = completed.size(); - if (totalNumCalls == 1) - { // Check first for the special case of a single call instruction not - // in any loop. It is not parallel, even if it has no dependences - // (this is why it is a special case). - // - // FIXME: - // THIS CASE IS NOT HANDLED RIGHT NOW, I.E., THERE IS NO - // PARALLELISM FOR CALLS IN DIFFERENT ITERATIONS OF A LOOP. - // - return; - } + if (totalNumCalls == 1) { + // Check first for the special case of a single call instruction not + // in any loop. It is not parallel, even if it has no dependences + // (this is why it is a special case). + // + // FIXME: + // THIS CASE IS NOT HANDLED RIGHT NOW, I.E., THERE IS NO + // PARALLELISM FOR CALLS IN DIFFERENT ITERATIONS OF A LOOP. + return; + } hash_map numDeps; for (hash_map::iterator II = dependents.begin(), - IE = dependents.end(); II != IE; ++II) - { - CallInst* fromCI = II->first; - numDeps[fromCI] += II->second.size(); - for (Dependents_iterator DI = II->second.begin(), DE = II->second.end(); - DI != DE; ++DI) - numDeps[*DI]++; // *DI can be reached from II->first - } + IE = dependents.end(); II != IE; ++II) { + CallInst* fromCI = II->first; + numDeps[fromCI] += II->second.size(); + for (Dependents_iterator DI = II->second.begin(), DE = II->second.end(); + DI != DE; ++DI) + numDeps[*DI]++; // *DI can be reached from II->first + } for (hash_map::iterator II = dependents.begin(), IE = dependents.end(); II != IE; ++II) @@ -347,36 +330,31 @@ stmtsVisited.insert(I); if (CallInst* CI = dyn_cast(I)) - // FIXME: Ignoring parallelism in a loop. Here we're actually *ignoring* // a self-dependence in order to get the count comparison right above. // When we include loop parallelism, self-dependences should be included. - // - if (CI != root) - - { // CallInst root has a path to CallInst I and any calls reachable from I - depsOfRoot.insert(CI); - if (completed[CI]) - { // We have already visited I so we know all nodes it can reach! - DependentsSet& depsOfI = dependents[CI]; - depsOfRoot.insert(depsOfI.begin(), depsOfI.end()); - return; - } + if (CI != root) { + // CallInst root has a path to CallInst I and any calls reachable from I + depsOfRoot.insert(CI); + if (completed[CI]) { + // We have already visited I so we know all nodes it can reach! + DependentsSet& depsOfI = dependents[CI]; + depsOfRoot.insert(depsOfI.begin(), depsOfI.end()); + return; } + } // If we reach here, we need to visit all children of I for (PgmDependenceGraph::iterator DI = depGraph.outDepBegin(*I); - ! DI.fini(); ++DI) - { - Instruction* sink = &DI->getSink()->getInstr(); - if (stmtsVisited.find(sink) == stmtsVisited.end()) - VisitOutEdges(sink, root, depsOfRoot); - } + ! DI.fini(); ++DI) { + Instruction* sink = &DI->getSink()->getInstr(); + if (stmtsVisited.find(sink) == stmtsVisited.end()) + VisitOutEdges(sink, root, depsOfRoot); + } } -void FindParallelCalls::visitCallInst(CallInst& CI) -{ +void FindParallelCalls::visitCallInst(CallInst& CI) { if (completed[&CI]) return; stmtsVisited.clear(); // clear flags to do a fresh DFS @@ -384,12 +362,11 @@ // Visit all children of CI using a recursive walk through dep graph DependentsSet& depsOfRoot = dependents[&CI]; for (PgmDependenceGraph::iterator DI = depGraph.outDepBegin(CI); - ! DI.fini(); ++DI) - { - Instruction* sink = &DI->getSink()->getInstr(); - if (stmtsVisited.find(sink) == stmtsVisited.end()) - VisitOutEdges(sink, &CI, depsOfRoot); - } + ! DI.fini(); ++DI) { + Instruction* sink = &DI->getSink()->getInstr(); + if (stmtsVisited.find(sink) == stmtsVisited.end()) + VisitOutEdges(sink, &CI, depsOfRoot); + } completed[&CI] = true; } @@ -411,8 +388,7 @@ //---------------------------------------------------------------------------- namespace { - class Parallelize: public Pass - { + class Parallelize: public Pass { public: /// Driver functions to transform a program /// @@ -433,68 +409,50 @@ } -static Function* FindMain(Module& M) -{ - for (Module::iterator FI = M.begin(), FE = M.end(); FI != FE; ++FI) - if (FI->getName() == std::string("main")) - return FI; - return NULL; -} - - -bool Parallelize::run(Module& M) -{ +bool Parallelize::run(Module& M) { hash_set parallelFunctions; hash_set safeParallelFunctions; hash_set indirectlyCalled; // If there is no main (i.e., for an incomplete program), we can do nothing. // If there is a main, mark main as a parallel function. - // - Function* mainFunc = FindMain(M); + Function* mainFunc = M.getMainFunction(); if (!mainFunc) return false; // (1) Find candidate parallel functions and mark them as Cilk functions - // for (Module::iterator FI = M.begin(), FE = M.end(); FI != FE; ++FI) - if (! FI->isExternal()) - { - Function* F = FI; - DSGraph& tdg = getAnalysis().getDSGraph(*F); - - // All the hard analysis work gets done here! - // - FindParallelCalls finder(*F, - getAnalysis().getGraph(*F)); - /* getAnalysis().getGraph(*F)); */ - - // Now we know which call instructions are useful to parallelize. - // Remember those callee functions. - // - for (std::vector::iterator - CII = finder.parallelCalls.begin(), - CIE = finder.parallelCalls.end(); CII != CIE; ++CII) - { - // Check if this is a direct call... - if ((*CII)->getCalledFunction() != NULL) - { // direct call: if this is to a non-external function, - // mark it as a parallelizable function - if (! (*CII)->getCalledFunction()->isExternal()) - parallelFunctions.insert((*CII)->getCalledFunction()); - } - else - { // Indirect call: mark all potential callees as bad - std::vector callees = - tdg.getNodeForValue((*CII)->getCalledValue()) - .getNode()->getGlobals(); - indirectlyCalled.insert(callees.begin(), callees.end()); - } - } + if (! FI->isExternal()) { + Function* F = FI; + DSGraph& tdg = getAnalysis().getDSGraph(*F); + + // All the hard analysis work gets done here! + FindParallelCalls finder(*F, + getAnalysis().getGraph(*F)); + /* getAnalysis().getGraph(*F)); */ + + // Now we know which call instructions are useful to parallelize. + // Remember those callee functions. + for (std::vector::iterator + CII = finder.parallelCalls.begin(), + CIE = finder.parallelCalls.end(); CII != CIE; ++CII) { + // Check if this is a direct call... + if ((*CII)->getCalledFunction() != NULL) { + // direct call: if this is to a non-external function, + // mark it as a parallelizable function + if (! (*CII)->getCalledFunction()->isExternal()) + parallelFunctions.insert((*CII)->getCalledFunction()); + } else { + // Indirect call: mark all potential callees as bad + std::vector callees = + tdg.getNodeForValue((*CII)->getCalledValue()) + .getNode()->getGlobals(); + indirectlyCalled.insert(callees.begin(), callees.end()); + } } + } // Remove all indirectly called functions from the list of Cilk functions. - // for (hash_set::iterator PFI = parallelFunctions.begin(), PFE = parallelFunctions.end(); PFI != PFE; ++PFI) if (indirectlyCalled.count(*PFI) == 0) @@ -524,15 +482,13 @@ // This should identify both functions and calls to such functions // to the code generator. // (4) Also, insert calls to sync at appropriate points. - // Cilkifier cilkifier(M); for (hash_set::iterator CFI = safeParallelFunctions.begin(), - CFE = safeParallelFunctions.end(); CFI != CFE; ++CFI) - { - cilkifier.TransformFunc(*CFI, safeParallelFunctions, - getAnalysis().getGraph(**CFI)); - /* getAnalysis().getGraph(**CFI)); */ - } + CFE = safeParallelFunctions.end(); CFI != CFE; ++CFI) { + cilkifier.TransformFunc(*CFI, safeParallelFunctions, + getAnalysis().getGraph(**CFI)); + /* getAnalysis().getGraph(**CFI)); */ + } return true; } Index: llvm/lib/Transforms/IPO/PruneEH.cpp diff -u llvm/lib/Transforms/IPO/PruneEH.cpp:1.9 llvm/lib/Transforms/IPO/PruneEH.cpp:1.9.4.1 --- llvm/lib/Transforms/IPO/PruneEH.cpp:1.9 Fri Nov 21 20:26:17 2003 +++ llvm/lib/Transforms/IPO/PruneEH.cpp Mon Mar 1 17:58:16 2004 @@ -51,19 +51,41 @@ // obviously the SCC might throw. // bool SCCMightThrow = false; - for (unsigned i = 0, e = SCC.size(); i != e; ++i) - if (!DoesNotThrow.count(SCC[i]) && // Calls maybe throwing fn - // Make sure this is not one of the fn's in the SCC. - std::find(SCC.begin(), SCC.end(), SCC[i]) == SCC.end()) { - SCCMightThrow = true; break; - } else if (Function *F = SCC[i]->getFunction()) - if (F->isExternal()) { - SCCMightThrow = true; break; + for (unsigned i = 0, e = SCC.size(); !SCCMightThrow && i != e; ++i) + if (Function *F = SCC[i]->getFunction()) + if (F->isExternal() && !F->getIntrinsicID()) { + SCCMightThrow = true; } else { - for (Function::iterator I = F->begin(), E = F->end(); I != E; ++I) - if (isa(I->getTerminator())) { // Uses unwind! - SCCMightThrow = true; break; + // Check to see if this function performs an unwind or calls an + // unwinding function. + for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB) { + if (isa(BB->getTerminator())) { // Uses unwind! + SCCMightThrow = true; + break; } + + // Invoke instructions don't allow unwinding to continue, so we are + // only interested in call instructions. + for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ++I) + if (CallInst *CI = dyn_cast(I)) { + if (Function *Callee = CI->getCalledFunction()) { + CallGraphNode *CalleeNode = CG[Callee]; + // If the callee is outside our current SCC, or if it is not + // known to throw, then we might throw also. + if (std::find(SCC.begin(), SCC.end(), CalleeNode) == SCC.end()&& + !DoesNotThrow.count(CalleeNode)) { + SCCMightThrow = true; + break; + } + + } else { + // Indirect call, it might throw. + SCCMightThrow = true; + break; + } + } + if (SCCMightThrow) break; + } } bool MadeChange = false; @@ -91,7 +113,7 @@ // Anything that used the value produced by the invoke instruction // now uses the value produced by the call instruction. II->replaceAllUsesWith(Call); - II->getExceptionalDest()->removePredecessor(II->getParent()); + II->getUnwindDest()->removePredecessor(II->getParent()); // Insert a branch to the normal destination right before the // invoke. Index: llvm/lib/Transforms/IPO/SimpleStructMutation.cpp diff -u llvm/lib/Transforms/IPO/SimpleStructMutation.cpp:1.24 llvm/lib/Transforms/IPO/SimpleStructMutation.cpp:1.24.4.1 --- llvm/lib/Transforms/IPO/SimpleStructMutation.cpp:1.24 Fri Nov 21 15:52:10 2003 +++ llvm/lib/Transforms/IPO/SimpleStructMutation.cpp Mon Mar 1 17:58:16 2004 @@ -90,7 +90,7 @@ // for (Type::subtype_iterator I = Ty->subtype_begin(), E = Ty->subtype_end(); I != E; ++I) { - if (!isa(*I)) + if (!isa(I->get())) PruneTypes(*I, TypesToModify, ProcessedTypes); } } @@ -109,7 +109,7 @@ static inline void GetTransformation(const TargetData &TD, const StructType *ST, std::vector &Transform, enum SimpleStructMutation::Transform XForm) { - unsigned NumElements = ST->getElementTypes().size(); + unsigned NumElements = ST->getNumElements(); Transform.reserve(NumElements); switch (XForm) { @@ -124,8 +124,7 @@ // Build mapping from index to size for (unsigned i = 0; i < NumElements; ++i) - ElList.push_back( - std::make_pair(i, TD.getTypeSize(ST->getElementTypes()[i]))); + ElList.push_back(std::make_pair(i,TD.getTypeSize(ST->getElementType(i)))); sort(ElList.begin(), ElList.end(), ptr_fun(FirstLess)); From brukman at cs.uiuc.edu Mon Mar 1 18:04:14 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Mar 1 18:04:14 2004 Subject: [llvm-commits] [parallel] CVS: llvm/lib/CodeGen/InstrSched/InstrScheduling.cpp SchedGraph.cpp SchedGraph.h SchedPriorities.cpp Message-ID: <200403012358.RAA03848@zion.cs.uiuc.edu> Changes in directory llvm/lib/CodeGen/InstrSched: InstrScheduling.cpp updated: 1.62 -> 1.62.4.1 SchedGraph.cpp updated: 1.54 -> 1.54.2.1 SchedGraph.h updated: 1.38 -> 1.38.2.1 SchedPriorities.cpp updated: 1.29 -> 1.29.4.1 --- Log message: Merge from trunk --- Diffs of the changes: (+113 -140) Index: llvm/lib/CodeGen/InstrSched/InstrScheduling.cpp diff -u llvm/lib/CodeGen/InstrSched/InstrScheduling.cpp:1.62 llvm/lib/CodeGen/InstrSched/InstrScheduling.cpp:1.62.4.1 --- llvm/lib/CodeGen/InstrSched/InstrScheduling.cpp:1.62 Tue Nov 11 16:41:32 2003 +++ llvm/lib/CodeGen/InstrSched/InstrScheduling.cpp Mon Mar 1 17:58:13 2004 @@ -16,7 +16,7 @@ #include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/MachineCodeForInstruction.h" #include "llvm/CodeGen/MachineFunction.h" -#include "llvm/CodeGen/FunctionLiveVarInfo.h" +#include "../../Target/SparcV9/LiveVar/FunctionLiveVarInfo.h" #include "llvm/Target/TargetMachine.h" #include "llvm/BasicBlock.h" #include "Support/CommandLine.h" @@ -149,10 +149,10 @@ typedef ScheduleIterator iterator; typedef ScheduleIterator const_iterator; - iterator begin(); - const_iterator begin() const; - iterator end(); - const_iterator end() const; + iterator begin() { return iterator::begin(*this); } + const_iterator begin() const { return const_iterator::begin(*this); } + iterator end() { return iterator::end(*this); } + const_iterator end() const { return const_iterator::end(*this); } public: // constructors and destructor /*ctor*/ InstrSchedule (unsigned int _nslots, @@ -280,30 +280,6 @@ return _Self(_schedule, _schedule.groups.size(), 0); } -InstrSchedule::iterator -InstrSchedule::begin() -{ - return iterator::begin(*this); -} - -InstrSchedule::const_iterator -InstrSchedule::begin() const -{ - return const_iterator::begin(*this); -} - -InstrSchedule::iterator -InstrSchedule::end() -{ - return iterator::end(*this); -} - -InstrSchedule::const_iterator -InstrSchedule::end() const -{ - return const_iterator::end( *this); -} - //---------------------------------------------------------------------- // class DelaySlotInfo: @@ -448,7 +424,7 @@ // Append the instruction to the vector of choices for current cycle. // Increment numInClass[c] for the sched class to which the instr belongs. choiceVec.push_back(node); - const InstrSchedClass& sc = schedInfo.getSchedClass(node->getOpCode()); + const InstrSchedClass& sc = schedInfo.getSchedClass(node->getOpcode()); assert(sc < numInClass.size()); numInClass[sc]++; } @@ -502,7 +478,7 @@ choicesForSlot[s].erase(node); // and decrement the instr count for the sched class to which it belongs - const InstrSchedClass& sc = schedInfo.getSchedClass(node->getOpCode()); + const InstrSchedClass& sc = schedInfo.getSchedClass(node->getOpcode()); assert(sc < numInClass.size()); numInClass[sc]--; } @@ -522,7 +498,7 @@ if (!createIfMissing) return 0; DelaySlotInfo *dinfo = - new DelaySlotInfo(bn, getInstrInfo().getNumDelaySlots(bn->getOpCode())); + new DelaySlotInfo(bn, getInstrInfo().getNumDelaySlots(bn->getOpcode())); return delaySlotInfoForBranches[bn] = dinfo; } @@ -544,7 +520,7 @@ nextEarliestIssueTime(0), choicesForSlot(nslots), numInClass(target.getSchedInfo().getNumSchedClasses(), 0), // set all to 0 - nextEarliestStartTime(target.getInstrInfo().getNumRealOpCodes(), + nextEarliestStartTime(target.getInstrInfo().getNumOpcodes(), (cycles_t) 0) // set all to 0 { updateTime(0); @@ -561,19 +537,19 @@ SchedulingManager::updateEarliestStartTimes(const SchedGraphNode* node, cycles_t schedTime) { - if (schedInfo.numBubblesAfter(node->getOpCode()) > 0) + if (schedInfo.numBubblesAfter(node->getOpcode()) > 0) { // Update next earliest time before which *nothing* can issue. nextEarliestIssueTime = std::max(nextEarliestIssueTime, - curTime + 1 + schedInfo.numBubblesAfter(node->getOpCode())); + curTime + 1 + schedInfo.numBubblesAfter(node->getOpcode())); } const std::vector& - conflictVec = schedInfo.getConflictList(node->getOpCode()); + conflictVec = schedInfo.getConflictList(node->getOpcode()); for (unsigned i=0; i < conflictVec.size(); i++) { MachineOpCode toOp = conflictVec[i]; - cycles_t est=schedTime + schedInfo.getMinIssueGap(node->getOpCode(),toOp); + cycles_t est=schedTime + schedInfo.getMinIssueGap(node->getOpcode(),toOp); assert(toOp < (int) nextEarliestStartTime.size()); if (nextEarliestStartTime[toOp] < est) nextEarliestStartTime[toOp] = est; @@ -654,8 +630,8 @@ // some NOPs from delay slots. Also, PHIs are not included in the schedule. unsigned numInstr = 0; for (MachineBasicBlock::iterator I=MBB.begin(); I != MBB.end(); ++I) - if (! mii.isNop((*I)->getOpCode()) && - ! mii.isDummyPhiInstr((*I)->getOpCode())) + if (! mii.isNop(I->getOpcode()) && + ! mii.isDummyPhiInstr(I->getOpcode())) ++numInstr; assert(S.isched.getNumInstructions() >= numInstr && "Lost some non-NOP instructions during scheduling!"); @@ -667,12 +643,12 @@ // First find the dummy instructions at the start of the basic block MachineBasicBlock::iterator I = MBB.begin(); for ( ; I != MBB.end(); ++I) - if (! mii.isDummyPhiInstr((*I)->getOpCode())) + if (! mii.isDummyPhiInstr(I->getOpcode())) break; - // Erase all except the dummy PHI instructions from MBB, and + // Remove all except the dummy PHI instructions from MBB, and // pre-allocate create space for the ones we will put back in. - MBB.erase(I, MBB.end()); + while (I != MBB.end()) MBB.remove(I); InstrSchedule::const_iterator NIend = S.isched.end(); for (InstrSchedule::const_iterator NI = S.isched.begin(); NI != NIend; ++NI) @@ -750,7 +726,7 @@ if (nextNode == NULL) break; // no more instructions for this cycle - if (S.getInstrInfo().getNumDelaySlots(nextNode->getOpCode()) > 0) { + if (S.getInstrInfo().getNumDelaySlots(nextNode->getOpcode()) > 0) { delaySlotInfo = S.getDelaySlotInfoForInstr(nextNode); if (delaySlotInfo != NULL) { if (indexForBreakingNode < S.nslots) @@ -760,7 +736,7 @@ else indexForDelayedInstr = S.getNumChoices(); } - } else if (S.schedInfo.breaksIssueGroup(nextNode->getOpCode())) { + } else if (S.schedInfo.breaksIssueGroup(nextNode->getOpcode())) { if (indexForBreakingNode < S.nslots) // have a breaking instruction already so throw this one away nextNode = NULL; @@ -771,7 +747,7 @@ if (nextNode != NULL) { S.addChoice(nextNode); - if (S.schedInfo.isSingleIssue(nextNode->getOpCode())) { + if (S.schedInfo.isSingleIssue(nextNode->getOpcode())) { assert(S.getNumChoices() == 1 && "Prioritizer returned invalid instr for this cycle!"); break; @@ -796,7 +772,7 @@ // This is the common case, so handle it separately for efficiency. if (S.getNumChoices() == 1) { - MachineOpCode opCode = S.getChoice(0)->getOpCode(); + MachineOpCode opCode = S.getChoice(0)->getOpcode(); unsigned int s; for (s=startSlot; s < S.nslots; s++) if (S.schedInfo.instrCanUseSlot(opCode, s)) @@ -805,7 +781,7 @@ S.addChoiceToSlot(s, S.getChoice(0)); } else { for (unsigned i=0; i < S.getNumChoices(); i++) { - MachineOpCode opCode = S.getChoice(i)->getOpCode(); + MachineOpCode opCode = S.getChoice(i)->getOpcode(); for (unsigned int s=startSlot; s < S.nslots; s++) if (S.schedInfo.instrCanUseSlot(opCode, s)) S.addChoiceToSlot(s, S.getChoice(i)); @@ -823,7 +799,7 @@ assert(delaySlotInfo != NULL && "No delay slot info for instr?"); const SchedGraphNode* delayedNode = S.getChoice(indexForDelayedInstr); - MachineOpCode delayOpCode = delayedNode->getOpCode(); + MachineOpCode delayOpCode = delayedNode->getOpcode(); unsigned ndelays= S.getInstrInfo().getNumDelaySlots(delayOpCode); unsigned delayedNodeSlot = S.nslots; @@ -841,7 +817,7 @@ for (unsigned i=0; i < S.getNumChoices() - 1; i++) { // Try to assign every other instruction to a lower numbered // slot than delayedNodeSlot. - MachineOpCode opCode =S.getChoice(i)->getOpCode(); + MachineOpCode opCode =S.getChoice(i)->getOpcode(); bool noSlotFound = true; unsigned int s; for (s=startSlot; s < delayedNodeSlot; s++) @@ -891,7 +867,7 @@ // Find the last possible slot for this instruction. for (int s = S.nslots-1; s >= (int) startSlot; s--) - if (S.schedInfo.instrCanUseSlot(breakingNode->getOpCode(), s)) { + if (S.schedInfo.instrCanUseSlot(breakingNode->getOpcode(), s)) { breakingSlot = s; break; } @@ -904,7 +880,7 @@ for (unsigned i=0; i < S.getNumChoices() && i < indexForBreakingNode; i++) { - MachineOpCode opCode =S.getChoice(i)->getOpCode(); + MachineOpCode opCode =S.getChoice(i)->getOpcode(); // If a higher priority instruction cannot be assigned to // any earlier slots, don't schedule the breaking instruction. @@ -938,7 +914,7 @@ // group, only assign them to slots lower than the breaking slot. // Otherwise, just ignore the instruction. for (unsigned i=indexForBreakingNode+1; i < S.getNumChoices(); i++) { - MachineOpCode opCode = S.getChoice(i)->getOpCode(); + MachineOpCode opCode = S.getChoice(i)->getOpcode(); for (unsigned int s=startSlot; s < nslotsToUse; s++) if (S.schedInfo.instrCanUseSlot(opCode, s)) S.addChoiceToSlot(s, S.getChoice(i)); @@ -1050,11 +1026,11 @@ assert(! node->isDummyNode()); // don't put a branch in the delay slot of another branch - if (S.getInstrInfo().isBranch(node->getOpCode())) + if (S.getInstrInfo().isBranch(node->getOpcode())) return false; // don't put a single-issue instruction in the delay slot of a branch - if (S.schedInfo.isSingleIssue(node->getOpCode())) + if (S.schedInfo.isSingleIssue(node->getOpcode())) return false; // don't put a load-use dependence in the delay slot of a branch @@ -1063,13 +1039,13 @@ for (SchedGraphNode::const_iterator EI = node->beginInEdges(); EI != node->endInEdges(); ++EI) if (! ((SchedGraphNode*)(*EI)->getSrc())->isDummyNode() - && mii.isLoad(((SchedGraphNode*)(*EI)->getSrc())->getOpCode()) + && mii.isLoad(((SchedGraphNode*)(*EI)->getSrc())->getOpcode()) && (*EI)->getDepType() == SchedGraphEdge::CtrlDep) return false; // for now, don't put an instruction that does not have operand // interlocks in the delay slot of a branch - if (! S.getInstrInfo().hasOperandInterlock(node->getOpCode())) + if (! S.getInstrInfo().hasOperandInterlock(node->getOpcode())) return false; // Finally, if the instruction precedes the branch, we make sure the @@ -1126,7 +1102,7 @@ { const TargetInstrInfo& mii = S.getInstrInfo(); unsigned ndelays = - mii.getNumDelaySlots(brNode->getOpCode()); + mii.getNumDelaySlots(brNode->getOpcode()); if (ndelays == 0) return; @@ -1141,10 +1117,10 @@ for (sg_pred_iterator P = pred_begin(brNode); P != pred_end(brNode) && sdelayNodeVec.size() < ndelays; ++P) if (! (*P)->isDummyNode() && - ! mii.isNop((*P)->getOpCode()) && + ! mii.isNop((*P)->getOpcode()) && NodeCanFillDelaySlot(S, *P, brNode, /*pred*/ true)) { - if (mii.maxLatency((*P)->getOpCode()) > 1) + if (mii.maxLatency((*P)->getOpcode()) > 1) mdelayNodeVec.push_back(*P); else sdelayNodeVec.push_back(*P); @@ -1157,12 +1133,12 @@ // while (sdelayNodeVec.size() < ndelays && mdelayNodeVec.size() > 0) { unsigned lmin = - mii.maxLatency(mdelayNodeVec[0]->getOpCode()); + mii.maxLatency(mdelayNodeVec[0]->getOpcode()); unsigned minIndex = 0; for (unsigned i=1; i < mdelayNodeVec.size(); i++) { unsigned li = - mii.maxLatency(mdelayNodeVec[i]->getOpCode()); + mii.maxLatency(mdelayNodeVec[i]->getOpcode()); if (lmin >= li) { lmin = li; @@ -1190,7 +1166,7 @@ std::vector nopNodeVec; // this will hold unused NOPs const TargetInstrInfo& mii = S.getInstrInfo(); const MachineInstr* brInstr = node->getMachineInstr(); - unsigned ndelays= mii.getNumDelaySlots(brInstr->getOpCode()); + unsigned ndelays= mii.getNumDelaySlots(brInstr->getOpcode()); assert(ndelays > 0 && "Unnecessary call to replace NOPs"); // Remove the NOPs currently in delay slots from the graph. @@ -1199,25 +1175,29 @@ // unsigned int firstDelaySlotIdx = node->getOrigIndexInBB() + 1; MachineBasicBlock& MBB = node->getMachineBasicBlock(); - assert(MBB[firstDelaySlotIdx - 1] == brInstr && + MachineBasicBlock::iterator MBBI = MBB.begin(); + std::advance(MBBI, firstDelaySlotIdx - 1); + assert(&*MBBI++ == brInstr && "Incorrect instr. index in basic block for brInstr"); // First find all useful instructions already in the delay slots // and USE THEM. We'll throw away the unused alternatives below // - for (unsigned i=firstDelaySlotIdx; i < firstDelaySlotIdx + ndelays; ++i) - if (! mii.isNop(MBB[i]->getOpCode())) + MachineBasicBlock::iterator Tmp = MBBI; + for (unsigned i = 0; i != ndelays; ++i, ++MBBI) + if (!mii.isNop(MBBI->getOpcode())) sdelayNodeVec.insert(sdelayNodeVec.begin(), - graph->getGraphNodeForInstr(MBB[i])); - + graph->getGraphNodeForInstr(MBBI)); + MBBI = Tmp; + // Then find the NOPs and keep only as many as are needed. // Put the rest in nopNodeVec to be deleted. - for (unsigned i=firstDelaySlotIdx; i < firstDelaySlotIdx + ndelays; ++i) - if (mii.isNop(MBB[i]->getOpCode())) + for (unsigned i=firstDelaySlotIdx; i < firstDelaySlotIdx+ndelays; ++i, ++MBBI) + if (mii.isNop(MBBI->getOpcode())) if (sdelayNodeVec.size() < ndelays) - sdelayNodeVec.push_back(graph->getGraphNodeForInstr(MBB[i])); + sdelayNodeVec.push_back(graph->getGraphNodeForInstr(MBBI)); else { - nopNodeVec.push_back(graph->getGraphNodeForInstr(MBB[i])); + nopNodeVec.push_back(graph->getGraphNodeForInstr(MBBI)); //remove the MI from the Machine Code For Instruction const TerminatorInst *TI = MBB.getBasicBlock()->getTerminator(); @@ -1226,7 +1206,7 @@ for(MachineCodeForInstruction::iterator mciI=llvmMvec.begin(), mciE=llvmMvec.end(); mciI!=mciE; ++mciI){ - if (*mciI==MBB[i]) + if (*mciI == MBBI) llvmMvec.erase(mciI); } } @@ -1280,7 +1260,7 @@ // unsigned first = 0; while (first < termMvec.size() && - ! mii.isBranch(termMvec[first]->getOpCode())) + ! mii.isBranch(termMvec[first]->getOpcode())) { ++first; } @@ -1305,11 +1285,9 @@ // brInstr will be NULL so this will handle the branch instrs. as well. // delayNodeVec.clear(); - for (unsigned i=0; i < MBB.size(); ++i) - if (MBB[i] != brInstr && - mii.getNumDelaySlots(MBB[i]->getOpCode()) > 0) - { - SchedGraphNode* node = graph->getGraphNodeForInstr(MBB[i]); + for (MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end(); I != E; ++I) + if (I != brInstr && mii.getNumDelaySlots(I->getOpcode()) > 0) { + SchedGraphNode* node = graph->getGraphNodeForInstr(I); ReplaceNopsWithUsefulInstr(S, node, delayNodeVec, graph); } } @@ -1345,10 +1323,10 @@ for (unsigned i=0; i < delayNodeVec.size(); i++) { const SchedGraphNode* dnode = delayNodeVec[i]; if ( ! S.isScheduled(dnode) - && S.schedInfo.instrCanUseSlot(dnode->getOpCode(), nextSlot) - && instrIsFeasible(S, dnode->getOpCode())) + && S.schedInfo.instrCanUseSlot(dnode->getOpcode(), nextSlot) + && instrIsFeasible(S, dnode->getOpcode())) { - assert(S.getInstrInfo().hasOperandInterlock(dnode->getOpCode()) + assert(S.getInstrInfo().hasOperandInterlock(dnode->getOpcode()) && "Instructions without interlocks not yet supported " "when filling branch delay slots"); S.scheduleInstr(dnode, nextSlot, nextTime); Index: llvm/lib/CodeGen/InstrSched/SchedGraph.cpp diff -u llvm/lib/CodeGen/InstrSched/SchedGraph.cpp:1.54 llvm/lib/CodeGen/InstrSched/SchedGraph.cpp:1.54.2.1 --- llvm/lib/CodeGen/InstrSched/SchedGraph.cpp:1.54 Sun Dec 14 07:24:16 2003 +++ llvm/lib/CodeGen/InstrSched/SchedGraph.cpp Mon Mar 1 17:58:13 2004 @@ -53,9 +53,13 @@ SchedGraphNode::SchedGraphNode(unsigned NID, MachineBasicBlock *mbb, int indexInBB, const TargetMachine& Target) - : SchedGraphNodeCommon(NID,indexInBB), MBB(mbb), MI(mbb ? (*mbb)[indexInBB] : 0) { - if (MI) { - MachineOpCode mopCode = MI->getOpCode(); + : SchedGraphNodeCommon(NID,indexInBB), MBB(mbb), MI(0) { + if (mbb) { + MachineBasicBlock::iterator I = MBB->begin(); + std::advance(I, indexInBB); + MI = I; + + MachineOpCode mopCode = MI->getOpcode(); latency = Target.getInstrInfo().hasResultInterlock(mopCode) ? Target.getInstrInfo().minLatency(mopCode) : Target.getInstrInfo().maxLatency(mopCode); @@ -100,26 +104,24 @@ } void SchedGraph::dump() const { - std::cerr << " Sched Graph for Basic Block: "; - std::cerr << MBB.getBasicBlock()->getName() - << " (" << MBB.getBasicBlock() << ")"; - - std::cerr << "\n\n Actual Root nodes : "; - for (unsigned i=0, N=graphRoot->outEdges.size(); i < N; i++) - std::cerr << graphRoot->outEdges[i]->getSink()->getNodeId() - << ((i == N-1)? "" : ", "); - + std::cerr << " Sched Graph for Basic Block: " + << MBB.getBasicBlock()->getName() + << " (" << MBB.getBasicBlock() << ")" + << "\n\n Actual Root nodes: "; + for (SchedGraphNodeCommon::const_iterator I = graphRoot->beginOutEdges(), + E = graphRoot->endOutEdges(); + I != E; ++I) { + std::cerr << (*I)->getSink ()->getNodeId (); + if (I + 1 != E) { std::cerr << ", "; } + } std::cerr << "\n Graph Nodes:\n"; - for (const_iterator I=begin(); I != end(); ++I) + for (const_iterator I = begin(), E = end(); I != E; ++I) std::cerr << "\n" << *I->second; - std::cerr << "\n"; } - - void SchedGraph::addDummyEdges() { - assert(graphRoot->outEdges.size() == 0); + assert(graphRoot->getNumOutEdges() == 0); for (const_iterator I=begin(); I != end(); ++I) { SchedGraphNode* node = (*I).second; @@ -142,8 +144,8 @@ // Find the first branch instr in the sequence of machine instrs for term // unsigned first = 0; - while (! mii.isBranch(termMvec[first]->getOpCode()) && - ! mii.isReturn(termMvec[first]->getOpCode())) + while (! mii.isBranch(termMvec[first]->getOpcode()) && + ! mii.isReturn(termMvec[first]->getOpcode())) ++first; assert(first < termMvec.size() && "No branch instructions for terminator? Ok, but weird!"); @@ -161,8 +163,8 @@ assert(toNode && "No node for instr generated for branch/ret?"); for (unsigned j = i-1; j != 0; --j) - if (mii.isBranch(termMvec[j-1]->getOpCode()) || - mii.isReturn(termMvec[j-1]->getOpCode())) { + if (mii.isBranch(termMvec[j-1]->getOpcode()) || + mii.isReturn(termMvec[j-1]->getOpcode())) { SchedGraphNode* brNode = getGraphNodeForInstr(termMvec[j-1]); assert(brNode && "No node for instr generated for branch/ret?"); (void) new SchedGraphEdge(brNode, toNode, SchedGraphEdge::CtrlDep, @@ -184,11 +186,11 @@ // Now add CD edges to the first branch instruction in the sequence from // all preceding instructions in the basic block. Use 0 latency again. // - for (unsigned i=0, N=MBB.size(); i < N; i++) { - if (MBB[i] == termMvec[first]) // reached the first branch + for (MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end(); I != E; ++I){ + if (&*I == termMvec[first]) // reached the first branch break; - SchedGraphNode* fromNode = this->getGraphNodeForInstr(MBB[i]); + SchedGraphNode* fromNode = getGraphNodeForInstr(I); if (fromNode == NULL) continue; // dummy instruction, e.g., PHI @@ -200,11 +202,11 @@ // the terminator) that also have delay slots, add an outgoing edge // from the instruction to the instructions in the delay slots. // - unsigned d = mii.getNumDelaySlots(MBB[i]->getOpCode()); - assert(i+d < N && "Insufficient delay slots for instruction?"); - - for (unsigned j=1; j <= d; j++) { - SchedGraphNode* toNode = this->getGraphNodeForInstr(MBB[i+j]); + unsigned d = mii.getNumDelaySlots(I->getOpcode()); + + MachineBasicBlock::iterator J = I; ++J; + for (unsigned j=1; j <= d; j++, ++J) { + SchedGraphNode* toNode = this->getGraphNodeForInstr(J); assert(toNode && "No node for machine instr in delay slot?"); (void) new SchedGraphEdge(fromNode, toNode, SchedGraphEdge::CtrlDep, @@ -244,12 +246,12 @@ // so simply look at all pairs i]>. // for (unsigned im=0, NM=memNodeVec.size(); im < NM; im++) { - MachineOpCode fromOpCode = memNodeVec[im]->getOpCode(); + MachineOpCode fromOpCode = memNodeVec[im]->getOpcode(); int fromType = (mii.isCall(fromOpCode)? SG_CALL_REF : (mii.isLoad(fromOpCode)? SG_LOAD_REF : SG_STORE_REF)); for (unsigned jm=im+1; jm < NM; jm++) { - MachineOpCode toOpCode = memNodeVec[jm]->getOpCode(); + MachineOpCode toOpCode = memNodeVec[jm]->getOpcode(); int toType = (mii.isCall(toOpCode)? SG_CALL_REF : (mii.isLoad(toOpCode)? SG_LOAD_REF : SG_STORE_REF)); @@ -276,7 +278,7 @@ // so simply look at all pairs i]>. // for (unsigned ic=0, NC=callDepNodeVec.size(); ic < NC; ic++) - if (mii.isCall(callDepNodeVec[ic]->getOpCode())) { + if (mii.isCall(callDepNodeVec[ic]->getOpcode())) { // Add SG_CALL_REF edges from all preds to this instruction. for (unsigned jc=0; jc < ic; jc++) (void) new SchedGraphEdge(callDepNodeVec[jc], callDepNodeVec[ic], @@ -294,7 +296,7 @@ // Find the call instruction nodes and put them in a vector. std::vector callNodeVec; for (unsigned im=0, NM=memNodeVec.size(); im < NM; im++) - if (mii.isCall(memNodeVec[im]->getOpCode())) + if (mii.isCall(memNodeVec[im]->getOpcode())) callNodeVec.push_back(memNodeVec[im]); // Now walk the entire basic block, looking for CC instructions *and* @@ -304,14 +306,14 @@ // int lastCallNodeIdx = -1; for (unsigned i=0, N=bbMvec.size(); i < N; i++) - if (mii.isCall(bbMvec[i]->getOpCode())) { + if (mii.isCall(bbMvec[i]->getOpcode())) { ++lastCallNodeIdx; for ( ; lastCallNodeIdx < (int)callNodeVec.size(); ++lastCallNodeIdx) if (callNodeVec[lastCallNodeIdx]->getMachineInstr() == bbMvec[i]) break; assert(lastCallNodeIdx < (int)callNodeVec.size() && "Missed Call?"); } - else if (mii.isCCInstr(bbMvec[i]->getOpCode())) { + else if (mii.isCCInstr(bbMvec[i]->getOpcode())) { // Add incoming/outgoing edges from/to preceding/later calls SchedGraphNode* ccNode = this->getGraphNodeForInstr(bbMvec[i]); int j=0; @@ -471,7 +473,7 @@ ValueToDefVecMap& valueToDefVecMap) { const TargetInstrInfo& mii = target.getInstrInfo(); - MachineOpCode opCode = node->getOpCode(); + MachineOpCode opCode = node->getOpcode(); if (mii.isCall(opCode) || mii.isCCInstr(opCode)) callDepNodeVec.push_back(node); @@ -488,11 +490,11 @@ // if this references a register other than the hardwired // "zero" register, record the reference. if (mop.hasAllocatedReg()) { - int regNum = mop.getAllocatedRegNum(); + unsigned regNum = mop.getReg(); // If this is not a dummy zero register, record the reference in order if (regNum != target.getRegInfo().getZeroRegNum()) - regToRefVecMap[mop.getAllocatedRegNum()] + regToRefVecMap[mop.getReg()] .push_back(std::make_pair(node, i)); // If this is a volatile register, add the instruction to callDepVec @@ -529,9 +531,9 @@ for (unsigned i=0, N = MI.getNumImplicitRefs(); i != N; ++i) { const MachineOperand& mop = MI.getImplicitOp(i); if (mop.hasAllocatedReg()) { - int regNum = mop.getAllocatedRegNum(); + unsigned regNum = mop.getReg(); if (regNum != target.getRegInfo().getZeroRegNum()) - regToRefVecMap[mop.getAllocatedRegNum()] + regToRefVecMap[mop.getReg()] .push_back(std::make_pair(node, i + MI.getNumOperands())); continue; // nothing more to do } @@ -555,10 +557,12 @@ // Build graph nodes for each VM instruction and gather def/use info. // Do both those together in a single pass over all machine instructions. - for (unsigned i=0; i < MBB.size(); i++) - if (!mii.isDummyPhiInstr(MBB[i]->getOpCode())) { + unsigned i = 0; + for (MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end(); I != E; + ++I, ++i) + if (!mii.isDummyPhiInstr(I->getOpcode())) { SchedGraphNode* node = new SchedGraphNode(getNumNodes(), &MBB, i, target); - noteGraphNodeForInstr(MBB[i], node); + noteGraphNodeForInstr(I, node); // Remember all register references and value defs findDefUseInfoAtInstr(target, node, memNodeVec, callDepNodeVec, @@ -633,21 +637,12 @@ this->addCallDepEdges(callDepNodeVec, target); // Then add incoming def-use (SSA) edges for each machine instruction. - for (unsigned i=0, N=MBB.size(); i < N; i++) - addEdgesForInstruction(*MBB[i], valueToDefVecMap, target); - -#ifdef NEED_SEPARATE_NONSSA_EDGES_CODE - // Then add non-SSA edges for all VM instructions in the block. - // We assume that all machine instructions that define a value are - // generated from the VM instruction corresponding to that value. - // TODO: This could probably be done much more efficiently. - for (BasicBlock::const_iterator II = bb->begin(); II != bb->end(); ++II) - this->addNonSSAEdgesForValue(*II, target); -#endif //NEED_SEPARATE_NONSSA_EDGES_CODE - + for (MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end(); I != E; ++I) + addEdgesForInstruction(*I, valueToDefVecMap, target); + // Then add edges for dependences on machine registers this->addMachineRegEdges(regToRefVecMap, target); - + // Finally, add edges from the dummy root and to dummy leaf this->addDummyEdges(); } Index: llvm/lib/CodeGen/InstrSched/SchedGraph.h diff -u llvm/lib/CodeGen/InstrSched/SchedGraph.h:1.38 llvm/lib/CodeGen/InstrSched/SchedGraph.h:1.38.2.1 --- llvm/lib/CodeGen/InstrSched/SchedGraph.h:1.38 Tue Jan 20 11:49:30 2004 +++ llvm/lib/CodeGen/InstrSched/SchedGraph.h Mon Mar 1 17:58:13 2004 @@ -48,7 +48,7 @@ // Accessor methods const MachineInstr* getMachineInstr() const { return MI; } - const MachineOpCode getOpCode() const { return MI->getOpCode(); } + const MachineOpCode getOpcode() const { return MI->getOpcode(); } bool isDummyNode() const { return (MI == NULL); } MachineBasicBlock &getMachineBasicBlock() const { return *MBB; } Index: llvm/lib/CodeGen/InstrSched/SchedPriorities.cpp diff -u llvm/lib/CodeGen/InstrSched/SchedPriorities.cpp:1.29 llvm/lib/CodeGen/InstrSched/SchedPriorities.cpp:1.29.4.1 --- llvm/lib/CodeGen/InstrSched/SchedPriorities.cpp:1.29 Tue Nov 11 16:41:33 2003 +++ llvm/lib/CodeGen/InstrSched/SchedPriorities.cpp Mon Mar 1 17:58:13 2004 @@ -18,7 +18,7 @@ //===----------------------------------------------------------------------===// #include "SchedPriorities.h" -#include "llvm/CodeGen/FunctionLiveVarInfo.h" +#include "../../Target/SparcV9/LiveVar/FunctionLiveVarInfo.h" #include "llvm/CodeGen/MachineBasicBlock.h" #include "llvm/Support/CFG.h" #include "Support/PostOrderIterator.h" @@ -211,7 +211,7 @@ // it becomes empty. nextChoice = candsAsHeap.getNode(mcands[nextIdx]); if (getEarliestReadyTimeForNode(nextChoice) > curTime - || ! instrIsFeasible(S, nextChoice->getMachineInstr()->getOpCode())) + || ! instrIsFeasible(S, nextChoice->getMachineInstr()->getOpcode())) { mcands.erase(mcands.begin() + nextIdx); nextIdx = -1; From brukman at cs.uiuc.edu Mon Mar 1 18:04:24 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Mar 1 18:04:24 2004 Subject: [llvm-commits] [parallel] CVS: llvm/lib/Bytecode/Reader/ConstantReader.cpp InstructionReader.cpp Reader.cpp ReaderInternals.h Message-ID: <200403012358.RAA03825@zion.cs.uiuc.edu> Changes in directory llvm/lib/Bytecode/Reader: ConstantReader.cpp updated: 1.72 -> 1.72.2.1 InstructionReader.cpp updated: 1.66.2.1 -> 1.66.2.2 Reader.cpp updated: 1.102 -> 1.102.2.1 ReaderInternals.h updated: 1.76 -> 1.76.2.1 --- Log message: Merge from trunk --- Diffs of the changes: (+33 -28) Index: llvm/lib/Bytecode/Reader/ConstantReader.cpp diff -u llvm/lib/Bytecode/Reader/ConstantReader.cpp:1.72 llvm/lib/Bytecode/Reader/ConstantReader.cpp:1.72.2.1 --- llvm/lib/Bytecode/Reader/ConstantReader.cpp:1.72 Sun Jan 18 15:08:15 2004 +++ llvm/lib/Bytecode/Reader/ConstantReader.cpp Mon Mar 1 17:58:13 2004 @@ -89,7 +89,6 @@ // something and when we reread the type later, we can replace the opaque type // with a new resolved concrete type. // -namespace llvm { void debug_type_tables(); } void BytecodeParser::parseTypeConstants(const unsigned char *&Buf, const unsigned char *EndBuf, TypeValuesListTy &Tab, @@ -129,7 +128,6 @@ for (unsigned i = 0; i < NumEntries; ++i) { BCR_TRACE(5, (void*)Tab[i].get() << " - " << Tab[i].get() << "\n"); } - debug_type_tables(); } @@ -233,12 +231,12 @@ case Type::StructTyID: { const StructType *ST = cast(Ty); - const StructType::ElementTypes &ET = ST->getElementTypes(); std::vector Elements; - Elements.reserve(ET.size()); - for (unsigned i = 0; i != ET.size(); ++i) - Elements.push_back(getConstantValue(ET[i], read_vbr_uint(Buf, EndBuf))); + Elements.reserve(ST->getNumElements()); + for (unsigned i = 0; i != ST->getNumElements(); ++i) + Elements.push_back(getConstantValue(ST->getElementType(i), + read_vbr_uint(Buf, EndBuf))); return ConstantStruct::get(ST, Elements); } Index: llvm/lib/Bytecode/Reader/InstructionReader.cpp diff -u llvm/lib/Bytecode/Reader/InstructionReader.cpp:1.66.2.1 llvm/lib/Bytecode/Reader/InstructionReader.cpp:1.66.2.2 --- llvm/lib/Bytecode/Reader/InstructionReader.cpp:1.66.2.1 Thu Jan 29 19:27:45 2004 +++ llvm/lib/Bytecode/Reader/InstructionReader.cpp Mon Mar 1 17:58:13 2004 @@ -230,16 +230,16 @@ if (FTy == 0) throw std::string("Call to non function pointer value!"); std::vector Params; - const FunctionType::ParamTypes &PL = FTy->getParamTypes(); - if (!FTy->isVarArg()) { - FunctionType::ParamTypes::const_iterator It = PL.begin(); + FunctionType::param_iterator It = FTy->param_begin(); for (unsigned i = 1, e = Args.size(); i != e; ++i) { - if (It == PL.end()) throw std::string("Invalid call instruction!"); + if (It == FTy->param_end()) + throw std::string("Invalid call instruction!"); Params.push_back(getValue(getTypeSlot(*It++), Args[i])); } - if (It != PL.end()) throw std::string("Invalid call instruction!"); + if (It != FTy->param_end()) + throw std::string("Invalid call instruction!"); } else { Args.erase(Args.begin(), Args.begin()+1+hasVarArgCallPadding); @@ -280,18 +280,18 @@ std::vector Params; BasicBlock *Normal, *Except; - const FunctionType::ParamTypes &PL = FTy->getParamTypes(); - if (!FTy->isVarArg()) { Normal = getBasicBlock(Args[1]); Except = getBasicBlock(Args[2]); - FunctionType::ParamTypes::const_iterator It = PL.begin(); + FunctionType::param_iterator It = FTy->param_begin(); for (unsigned i = 3, e = Args.size(); i != e; ++i) { - if (It == PL.end()) throw std::string("Invalid invoke instruction!"); + if (It == FTy->param_end()) + throw std::string("Invalid invoke instruction!"); Params.push_back(getValue(getTypeSlot(*It++), Args[i])); } - if (It != PL.end()) throw std::string("Invalid invoke instruction!"); + if (It != FTy->param_end()) + throw std::string("Invalid invoke instruction!"); } else { Args.erase(Args.begin(), Args.begin()+1+hasVarArgCallPadding); Index: llvm/lib/Bytecode/Reader/Reader.cpp diff -u llvm/lib/Bytecode/Reader/Reader.cpp:1.102 llvm/lib/Bytecode/Reader/Reader.cpp:1.102.2.1 --- llvm/lib/Bytecode/Reader/Reader.cpp:1.102 Tue Jan 20 11:06:29 2004 +++ llvm/lib/Bytecode/Reader/Reader.cpp Mon Mar 1 17:58:13 2004 @@ -381,11 +381,10 @@ // Insert arguments into the value table before we parse the first basic // block in the function, but after we potentially read in the // compaction table. - const FunctionType::ParamTypes &Params = - F->getFunctionType()->getParamTypes(); + const FunctionType *FT = F->getFunctionType(); Function::aiterator AI = F->abegin(); - for (FunctionType::ParamTypes::const_iterator It = Params.begin(); - It != Params.end(); ++It, ++AI) + for (FunctionType::param_iterator It = FT->param_begin(); + It != FT->param_end(); ++It, ++AI) insertValue(AI, getTypeSlot(AI->getType()), Values); InsertedArguments = true; } @@ -404,11 +403,10 @@ // Insert arguments into the value table before we parse the first basic // block in the function, but after we potentially read in the // compaction table. - const FunctionType::ParamTypes &Params = - F->getFunctionType()->getParamTypes(); + const FunctionType *FT = F->getFunctionType(); Function::aiterator AI = F->abegin(); - for (FunctionType::ParamTypes::const_iterator It = Params.begin(); - It != Params.end(); ++It, ++AI) + for (FunctionType::param_iterator It = FT->param_begin(); + It != FT->param_end(); ++It, ++AI) insertValue(AI, getTypeSlot(AI->getType()), Values); InsertedArguments = true; } @@ -424,11 +422,10 @@ // list for the function, but after we potentially read in the compaction // table. if (!InsertedArguments) { - const FunctionType::ParamTypes &Params = - F->getFunctionType()->getParamTypes(); + const FunctionType *FT = F->getFunctionType(); Function::aiterator AI = F->abegin(); - for (FunctionType::ParamTypes::const_iterator It = Params.begin(); - It != Params.end(); ++It, ++AI) + for (FunctionType::param_iterator It = FT->param_begin(); + It != FT->param_end(); ++It, ++AI) insertValue(AI, getTypeSlot(AI->getType()), Values); InsertedArguments = true; } Index: llvm/lib/Bytecode/Reader/ReaderInternals.h diff -u llvm/lib/Bytecode/Reader/ReaderInternals.h:1.76 llvm/lib/Bytecode/Reader/ReaderInternals.h:1.76.2.1 --- llvm/lib/Bytecode/Reader/ReaderInternals.h:1.76 Sun Jan 18 15:08:15 2004 +++ llvm/lib/Bytecode/Reader/ReaderInternals.h Mon Mar 1 17:58:13 2004 @@ -55,6 +55,16 @@ freeTable(ModuleValues); } + Module* materializeModule() { + while (! LazyFunctionLoadMap.empty()) { + std::map::iterator i = + LazyFunctionLoadMap.begin(); + materializeFunction((*i).first); + } + + return TheModule; + } + Module* releaseModule() { // Since we're losing control of this Module, we must hand it back complete Module *M = ModuleProvider::releaseModule(); From brukman at cs.uiuc.edu Mon Mar 1 18:04:33 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Mar 1 18:04:33 2004 Subject: [llvm-commits] [parallel] CVS: llvm/lib/CodeGen/ModuloScheduling/MSchedGraph.cpp MSchedGraph.h ModuloScheduling.h ModuloScheduling.cpp ModuloSchedGraph.cpp ModuloSchedGraph.h Message-ID: <200403012358.RAA03900@zion.cs.uiuc.edu> Changes in directory llvm/lib/CodeGen/ModuloScheduling: MSchedGraph.cpp added (r1.1.2.1) MSchedGraph.h added (r1.1.2.1) ModuloScheduling.h added (r1.11.2.1) ModuloScheduling.cpp updated: 1.15 -> 1.15.4.1 ModuloSchedGraph.cpp (r1.14) removed ModuloSchedGraph.h (r1.12) removed --- Log message: Merge from trunk --- Diffs of the changes: (+1451 -24) Index: llvm/lib/CodeGen/ModuloScheduling/MSchedGraph.cpp diff -c /dev/null llvm/lib/CodeGen/ModuloScheduling/MSchedGraph.cpp:1.1.2.1 *** /dev/null Mon Mar 1 17:58:27 2004 --- llvm/lib/CodeGen/ModuloScheduling/MSchedGraph.cpp Mon Mar 1 17:58:13 2004 *************** *** 0 **** --- 1,391 ---- + //===-- MSchedGraph.h - Scheduling Graph ------------------------*- C++ -*-===// + // + // The LLVM Compiler Infrastructure + // + // This file was developed by the LLVM research group and is distributed under + // the University of Illinois Open Source License. See LICENSE.TXT for details. + // + //===----------------------------------------------------------------------===// + // + // A graph class for dependencies + // + //===----------------------------------------------------------------------===// + #define DEBUG_TYPE "ModuloSched" + + #include "MSchedGraph.h" + #include "llvm/CodeGen/MachineBasicBlock.h" + #include "llvm/Target/TargetInstrInfo.h" + #include "Support/Debug.h" + #include + using namespace llvm; + + MSchedGraphNode::MSchedGraphNode(const MachineInstr* inst, + MSchedGraph *graph, + unsigned late) + : Inst(inst), Parent(graph), latency(late) { + + //Add to the graph + graph->addNode(inst, this); + } + + void MSchedGraphNode::print(std::ostream &os) const { + os << "MSehedGraphNode: Inst=" << *Inst << ", latency= " << latency << "\n"; + } + + MSchedGraphEdge MSchedGraphNode::getInEdge(MSchedGraphNode *pred) { + //Loop over all the successors of our predecessor + //return the edge the corresponds to this in edge + for(MSchedGraphNode::succ_iterator I = pred->succ_begin(), E = pred->succ_end(); + I != E; ++I) { + if(*I == this) + return I.getEdge(); + } + assert(0 && "Should have found edge between this node and its predecessor!"); + + } + + void MSchedGraph::addNode(const MachineInstr *MI, + MSchedGraphNode *node) { + + //Make sure node does not already exist + assert(GraphMap.find(MI) == GraphMap.end() + && "New MSchedGraphNode already exists for this instruction"); + + GraphMap[MI] = node; + } + + MSchedGraph::MSchedGraph(const MachineBasicBlock *bb, const TargetMachine &targ) + : BB(bb), Target(targ) { + + //Make sure BB is not null, + assert(BB != NULL && "Basic Block is null"); + + DEBUG(std::cerr << "Constructing graph for " << bb << "\n"); + + //Create nodes and edges for this BB + buildNodesAndEdges(); + } + + MSchedGraph::~MSchedGraph () { + for(MSchedGraph::iterator I = GraphMap.begin(), E = GraphMap.end(); I != E; ++I) + delete I->second; + } + + void MSchedGraph::buildNodesAndEdges() { + + //Get Machine target information for calculating latency + const TargetInstrInfo &MTI = Target.getInstrInfo(); + + std::vector memInstructions; + std::map > regNumtoNodeMap; + std::map > valuetoNodeMap; + + //Save PHI instructions to deal with later + std::vector phiInstrs; + + //Loop over instructions in MBB and add nodes and edges + for (MachineBasicBlock::const_iterator MI = BB->begin(), e = BB->end(); MI != e; ++MI) { + //Get each instruction of machine basic block, get the delay + //using the op code, create a new node for it, and add to the + //graph. + + MachineOpCode MIopCode = MI->getOpcode(); + int delay; + + //Check if subsequent instructions can be issued before + //the result is ready, if so use min delay. + if(MTI.hasResultInterlock(MIopCode)) + delay = MTI.minLatency(MIopCode); + else + delay = MTI.maxLatency(MIopCode); + + //Create new node for this machine instruction and add to the graph. + //Create only if not a nop + if(MTI.isNop(MIopCode)) + continue; + + //Add PHI to phi instruction list to be processed later + if (MIopCode == TargetInstrInfo::PHI) + phiInstrs.push_back(MI); + + //Node is created and added to the graph automatically + MSchedGraphNode *node = new MSchedGraphNode(MI, this, delay); + + DEBUG(std::cerr << "Created Node: " << *node << "\n"); + + //Check OpCode to keep track of memory operations to add memory dependencies later. + MachineOpCode opCode = MI->getOpcode(); + + if(MTI.isLoad(opCode) || MTI.isStore(opCode)) + memInstructions.push_back(node); + + //Loop over all operands, and put them into the register number to + //graph node map for determining dependencies + //If an operands is a use/def, we have an anti dependence to itself + for(unsigned i=0; i < MI->getNumOperands(); ++i) { + //Get Operand + const MachineOperand &mOp = MI->getOperand(i); + + //Check if it has an allocated register (Note: this means it + //is greater then zero because zero is a special register for + //Sparc that holds the constant zero + if(mOp.hasAllocatedReg()) { + int regNum = mOp.getReg(); + + //Put into our map + regNumtoNodeMap[regNum].push_back(std::make_pair(i, node)); + continue; + } + + + //Add virtual registers dependencies + //Check if any exist in the value map already and create dependencies + //between them. + if(mOp.getType() == MachineOperand::MO_VirtualRegister || mOp.getType() == MachineOperand::MO_CCRegister) { + + //Make sure virtual register value is not null + assert((mOp.getVRegValue() != NULL) && "Null value is defined"); + + //Check if this is a read operation in a phi node, if so DO NOT PROCESS + if(mOp.isUse() && (MIopCode == TargetInstrInfo::PHI)) + continue; + + + if (const Value* srcI = mOp.getVRegValue()) { + + //Find value in the map + std::map >::iterator V + = valuetoNodeMap.find(srcI); + + //If there is something in the map already, add edges from + //those instructions + //to this one we are processing + if(V != valuetoNodeMap.end()) { + addValueEdges(V->second, node, mOp.isUse(), mOp.isDef()); + + //Add to value map + V->second.push_back(std::make_pair(i,node)); + } + //Otherwise put it in the map + else + //Put into value map + valuetoNodeMap[mOp.getVRegValue()].push_back(std::make_pair(i, node)); + } + } + } + } + addMemEdges(memInstructions); + addMachRegEdges(regNumtoNodeMap); + + //Finally deal with PHI Nodes and Value* + for(std::vector::iterator I = phiInstrs.begin(), E = phiInstrs.end(); I != E; ++I) { + //Get Node for this instruction + MSchedGraphNode *node = find(*I)->second; + + //Loop over operands for this instruction and add value edges + for(unsigned i=0; i < (*I)->getNumOperands(); ++i) { + //Get Operand + const MachineOperand &mOp = (*I)->getOperand(i); + if((mOp.getType() == MachineOperand::MO_VirtualRegister || mOp.getType() == MachineOperand::MO_CCRegister) && mOp.isUse()) { + //find the value in the map + if (const Value* srcI = mOp.getVRegValue()) { + + //Find value in the map + std::map >::iterator V + = valuetoNodeMap.find(srcI); + + //If there is something in the map already, add edges from + //those instructions + //to this one we are processing + if(V != valuetoNodeMap.end()) { + addValueEdges(V->second, node, mOp.isUse(), mOp.isDef(), 1); + } + } + } + } + } + } + + void MSchedGraph::addValueEdges(std::vector &NodesInMap, + MSchedGraphNode *destNode, bool nodeIsUse, + bool nodeIsDef, int diff) { + + for(std::vector::iterator I = NodesInMap.begin(), + E = NodesInMap.end(); I != E; ++I) { + + //Get node in vectors machine operand that is the same value as node + MSchedGraphNode *srcNode = I->second; + MachineOperand mOp = srcNode->getInst()->getOperand(I->first); + + //Node is a Def, so add output dep. + if(nodeIsDef) { + if(mOp.isUse()) + srcNode->addOutEdge(destNode, MSchedGraphEdge::ValueDep, + MSchedGraphEdge::AntiDep, diff); + if(mOp.isDef()) + srcNode->addOutEdge(destNode, MSchedGraphEdge::ValueDep, + MSchedGraphEdge::OutputDep, diff); + + } + if(nodeIsUse) { + if(mOp.isDef()) + srcNode->addOutEdge(destNode, MSchedGraphEdge::ValueDep, + MSchedGraphEdge::TrueDep, diff); + } + } + } + + + void MSchedGraph::addMachRegEdges(std::map >& regNumtoNodeMap) { + //Loop over all machine registers in the map, and add dependencies + //between the instructions that use it + typedef std::map > regNodeMap; + for(regNodeMap::iterator I = regNumtoNodeMap.begin(); I != regNumtoNodeMap.end(); ++I) { + //Get the register number + int regNum = (*I).first; + + //Get Vector of nodes that use this register + std::vector Nodes = (*I).second; + + //Loop over nodes and determine the dependence between the other + //nodes in the vector + for(unsigned i =0; i < Nodes.size(); ++i) { + + //Get src node operator index that uses this machine register + int srcOpIndex = Nodes[i].first; + + //Get the actual src Node + MSchedGraphNode *srcNode = Nodes[i].second; + + //Get Operand + const MachineOperand &srcMOp = srcNode->getInst()->getOperand(srcOpIndex); + + bool srcIsUseandDef = srcMOp.isDef() && srcMOp.isUse(); + bool srcIsUse = srcMOp.isUse() && !srcMOp.isDef(); + + + //Look at all instructions after this in execution order + for(unsigned j=i+1; j < Nodes.size(); ++j) { + + //Sink node is a write + if(Nodes[j].second->getInst()->getOperand(Nodes[j].first).isDef()) { + //Src only uses the register (read) + if(srcIsUse) + srcNode->addOutEdge(Nodes[j].second, MSchedGraphEdge::MachineRegister, + MSchedGraphEdge::AntiDep); + + else if(srcIsUseandDef) { + srcNode->addOutEdge(Nodes[j].second, MSchedGraphEdge::MachineRegister, + MSchedGraphEdge::AntiDep); + + srcNode->addOutEdge(Nodes[j].second, MSchedGraphEdge::MachineRegister, + MSchedGraphEdge::OutputDep); + } + else + srcNode->addOutEdge(Nodes[j].second, MSchedGraphEdge::MachineRegister, + MSchedGraphEdge::OutputDep); + } + //Dest node is a read + else { + if(!srcIsUse || srcIsUseandDef) + srcNode->addOutEdge(Nodes[j].second, MSchedGraphEdge::MachineRegister, + MSchedGraphEdge::TrueDep); + } + + } + + //Look at all the instructions before this one since machine registers + //could live across iterations. + for(unsigned j = 0; j < i; ++j) { + //Sink node is a write + if(Nodes[j].second->getInst()->getOperand(Nodes[j].first).isDef()) { + //Src only uses the register (read) + if(srcIsUse) + srcNode->addOutEdge(Nodes[j].second, MSchedGraphEdge::MachineRegister, + MSchedGraphEdge::AntiDep, 1); + + else if(srcIsUseandDef) { + srcNode->addOutEdge(Nodes[j].second, MSchedGraphEdge::MachineRegister, + MSchedGraphEdge::AntiDep, 1); + + srcNode->addOutEdge(Nodes[j].second, MSchedGraphEdge::MachineRegister, + MSchedGraphEdge::OutputDep, 1); + } + else + srcNode->addOutEdge(Nodes[j].second, MSchedGraphEdge::MachineRegister, + MSchedGraphEdge::OutputDep, 1); + } + //Dest node is a read + else { + if(!srcIsUse || srcIsUseandDef) + srcNode->addOutEdge(Nodes[j].second, MSchedGraphEdge::MachineRegister, + MSchedGraphEdge::TrueDep,1 ); + } + + + } + + } + + } + + } + + void MSchedGraph::addMemEdges(const std::vector& memInst) { + + //Get Target machine instruction info + const TargetInstrInfo& TMI = Target.getInstrInfo(); + + //Loop over all memory instructions in the vector + //Knowing that they are in execution, add true, anti, and output dependencies + for (unsigned srcIndex = 0; srcIndex < memInst.size(); ++srcIndex) { + + //Get the machine opCode to determine type of memory instruction + MachineOpCode srcNodeOpCode = memInst[srcIndex]->getInst()->getOpcode(); + + //All instructions after this one in execution order have an iteration delay of 0 + for(unsigned destIndex = srcIndex + 1; destIndex < memInst.size(); ++destIndex) { + + //source is a Load, so add anti-dependencies (store after load) + if(TMI.isLoad(srcNodeOpCode)) + if(TMI.isStore(memInst[destIndex]->getInst()->getOpcode())) + memInst[srcIndex]->addOutEdge(memInst[destIndex], + MSchedGraphEdge::MemoryDep, + MSchedGraphEdge::AntiDep); + + //If source is a store, add output and true dependencies + if(TMI.isStore(srcNodeOpCode)) { + if(TMI.isStore(memInst[destIndex]->getInst()->getOpcode())) + memInst[srcIndex]->addOutEdge(memInst[destIndex], + MSchedGraphEdge::MemoryDep, + MSchedGraphEdge::OutputDep); + else + memInst[srcIndex]->addOutEdge(memInst[destIndex], + MSchedGraphEdge::MemoryDep, + MSchedGraphEdge::TrueDep); + } + } + + //All instructions before the src in execution order have an iteration delay of 1 + for(unsigned destIndex = 0; destIndex < srcIndex; ++destIndex) { + //source is a Load, so add anti-dependencies (store after load) + if(TMI.isLoad(srcNodeOpCode)) + if(TMI.isStore(memInst[destIndex]->getInst()->getOpcode())) + memInst[srcIndex]->addOutEdge(memInst[destIndex], + MSchedGraphEdge::MemoryDep, + MSchedGraphEdge::AntiDep, 1); + if(TMI.isStore(srcNodeOpCode)) { + if(TMI.isStore(memInst[destIndex]->getInst()->getOpcode())) + memInst[srcIndex]->addOutEdge(memInst[destIndex], + MSchedGraphEdge::MemoryDep, + MSchedGraphEdge::OutputDep, 1); + else + memInst[srcIndex]->addOutEdge(memInst[destIndex], + MSchedGraphEdge::MemoryDep, + MSchedGraphEdge::TrueDep, 1); + } + + } + + } + } Index: llvm/lib/CodeGen/ModuloScheduling/MSchedGraph.h diff -c /dev/null llvm/lib/CodeGen/ModuloScheduling/MSchedGraph.h:1.1.2.1 *** /dev/null Mon Mar 1 17:58:28 2004 --- llvm/lib/CodeGen/ModuloScheduling/MSchedGraph.h Mon Mar 1 17:58:13 2004 *************** *** 0 **** --- 1,310 ---- + //===-- MSchedGraph.h - Scheduling Graph ------------------------*- C++ -*-===// + // + // The LLVM Compiler Infrastructure + // + // This file was developed by the LLVM research group and is distributed under + // the University of Illinois Open Source License. See LICENSE.TXT for details. + // + //===----------------------------------------------------------------------===// + // + // A graph class for dependencies + // + //===----------------------------------------------------------------------===// + + #ifndef LLVM_MSCHEDGRAPH_H + #define LLVM_MSCHEDGRAPH_H + + #include "llvm/CodeGen/MachineInstr.h" + #include "llvm/Target/TargetMachine.h" + #include "Support/GraphTraits.h" + #include "Support/STLExtras.h" + #include "Support/iterator" + #include + + namespace llvm { + class MSchedGraph; + class MSchedGraphNode; + template + class MSchedGraphNodeIterator; + + + struct MSchedGraphEdge { + enum DataDepOrderType { + TrueDep, AntiDep, OutputDep, NonDataDep + }; + + enum MSchedGraphEdgeType { + MemoryDep, ValueDep, MachineRegister + }; + + MSchedGraphNode *getDest() const { return dest; } + unsigned getIteDiff() { return iteDiff; } + unsigned getDepOrderType() { return depOrderType; } + + private: + friend class MSchedGraphNode; + MSchedGraphEdge(MSchedGraphNode *destination, MSchedGraphEdgeType type, + unsigned deptype, unsigned diff) + : dest(destination), depType(type), depOrderType(deptype), iteDiff(diff) {} + + MSchedGraphNode *dest; + MSchedGraphEdgeType depType; + unsigned depOrderType; + unsigned iteDiff; + }; + + class MSchedGraphNode { + + const MachineInstr* Inst; //Machine Instruction + MSchedGraph* Parent; //Graph this node belongs to + unsigned latency; //Latency of Instruction + + std::vector Predecessors; //Predecessor Nodes + std::vector Successors; + + public: + MSchedGraphNode(const MachineInstr *inst, MSchedGraph *graph, + unsigned late=0); + + //Iterators + typedef std::vector::iterator pred_iterator; + pred_iterator pred_begin() { return Predecessors.begin(); } + pred_iterator pred_end() { return Predecessors.end(); } + + typedef std::vector::const_iterator pred_const_iterator; + pred_const_iterator pred_begin() const { return Predecessors.begin(); } + pred_const_iterator pred_end() const { return Predecessors.end(); } + + // Successor iterators. + typedef MSchedGraphNodeIterator::const_iterator, + const MSchedGraphNode> succ_const_iterator; + succ_const_iterator succ_begin() const; + succ_const_iterator succ_end() const; + + typedef MSchedGraphNodeIterator::iterator, + MSchedGraphNode> succ_iterator; + succ_iterator succ_begin(); + succ_iterator succ_end(); + + + void addOutEdge(MSchedGraphNode *destination, + MSchedGraphEdge::MSchedGraphEdgeType type, + unsigned deptype, unsigned diff=0) { + Successors.push_back(MSchedGraphEdge(destination, type, deptype,diff)); + destination->Predecessors.push_back(this); + } + const MachineInstr* getInst() { return Inst; } + MSchedGraph* getParent() { return Parent; } + bool hasPredecessors() { return (Predecessors.size() > 0); } + bool hasSuccessors() { return (Successors.size() > 0); } + int getLatency() { return latency; } + MSchedGraphEdge getInEdge(MSchedGraphNode *pred); + + //Debug support + void print(std::ostream &os) const; + + }; + + template + class MSchedGraphNodeIterator : public forward_iterator { + IteratorType I; // std::vector::iterator or const_iterator + public: + MSchedGraphNodeIterator(IteratorType i) : I(i) {} + + bool operator==(const MSchedGraphNodeIterator RHS) const { return I == RHS.I; } + bool operator!=(const MSchedGraphNodeIterator RHS) const { return I != RHS.I; } + + const MSchedGraphNodeIterator &operator=(const MSchedGraphNodeIterator &RHS) { + I = RHS.I; + return *this; + } + + NodeType* operator*() const { + return I->getDest(); + } + NodeType* operator->() const { return operator*(); } + + MSchedGraphNodeIterator& operator++() { // Preincrement + ++I; + return *this; + } + MSchedGraphNodeIterator operator++(int) { // Postincrement + MSchedGraphNodeIterator tmp = *this; ++*this; return tmp; + } + + MSchedGraphEdge &getEdge() { + return *I; + } + const MSchedGraphEdge &getEdge() const { + return *I; + } + }; + + inline MSchedGraphNode::succ_const_iterator MSchedGraphNode::succ_begin() const { + return succ_const_iterator(Successors.begin()); + } + inline MSchedGraphNode::succ_const_iterator MSchedGraphNode::succ_end() const { + return succ_const_iterator(Successors.end()); + } + inline MSchedGraphNode::succ_iterator MSchedGraphNode::succ_begin() { + return succ_iterator(Successors.begin()); + } + inline MSchedGraphNode::succ_iterator MSchedGraphNode::succ_end() { + return succ_iterator(Successors.end()); + } + + // ostream << operator for MSGraphNode class + inline std::ostream &operator<<(std::ostream &os, + const MSchedGraphNode &node) { + node.print(os); + return os; + } + + + + class MSchedGraph { + + const MachineBasicBlock *BB; //Machine basic block + const TargetMachine &Target; //Target Machine + + //Nodes + std::map GraphMap; + + //Add Nodes and Edges to this graph for our BB + typedef std::pair OpIndexNodePair; + void buildNodesAndEdges(); + void addValueEdges(std::vector &NodesInMap, + MSchedGraphNode *node, + bool nodeIsUse, bool nodeIsDef, int diff=0); + void addMachRegEdges(std::map >& regNumtoNodeMap); + void addMemEdges(const std::vector& memInst); + + public: + MSchedGraph(const MachineBasicBlock *bb, const TargetMachine &targ); + ~MSchedGraph(); + + //Add Nodes to the Graph + void addNode(const MachineInstr* MI, MSchedGraphNode *node); + + //iterators + typedef std::map::iterator iterator; + typedef std::map::const_iterator const_iterator; + typedef std::map::reverse_iterator reverse_iterator; + iterator find(const MachineInstr* I) { return GraphMap.find(I); } + iterator end() { return GraphMap.end(); } + iterator begin() { return GraphMap.begin(); } + reverse_iterator rbegin() { return GraphMap.rbegin(); } + reverse_iterator rend() { return GraphMap.rend(); } + + }; + + + static MSchedGraphNode& getSecond(std::pair &Pair) { + return *Pair.second; + } + + + + // Provide specializations of GraphTraits to be able to use graph + // iterators on the scheduling graph! + // + template <> struct GraphTraits { + typedef MSchedGraphNode NodeType; + typedef MSchedGraphNode::succ_iterator ChildIteratorType; + + static inline ChildIteratorType child_begin(NodeType *N) { + return N->succ_begin(); + } + static inline ChildIteratorType child_end(NodeType *N) { + return N->succ_end(); + } + + typedef std::pointer_to_unary_function&, MSchedGraphNode&> DerefFun; + + typedef mapped_iterator nodes_iterator; + static nodes_iterator nodes_begin(MSchedGraph *G) { + return map_iterator(((MSchedGraph*)G)->begin(), DerefFun(getSecond)); + } + static nodes_iterator nodes_end(MSchedGraph *G) { + return map_iterator(((MSchedGraph*)G)->end(), DerefFun(getSecond)); + } + + + }; + + template <> struct GraphTraits { + typedef const MSchedGraphNode NodeType; + typedef MSchedGraphNode::succ_const_iterator ChildIteratorType; + + static inline ChildIteratorType child_begin(NodeType *N) { + return N->succ_begin(); + } + static inline ChildIteratorType child_end(NodeType *N) { + return N->succ_end(); + } + typedef std::pointer_to_unary_function&, MSchedGraphNode&> DerefFun; + + typedef mapped_iterator nodes_iterator; + static nodes_iterator nodes_begin(MSchedGraph *G) { + return map_iterator(((MSchedGraph*)G)->begin(), DerefFun(getSecond)); + } + static nodes_iterator nodes_end(MSchedGraph *G) { + return map_iterator(((MSchedGraph*)G)->end(), DerefFun(getSecond)); + } + }; + + template <> struct GraphTraits > { + typedef MSchedGraphNode NodeType; + typedef MSchedGraphNode::pred_iterator ChildIteratorType; + + static inline ChildIteratorType child_begin(NodeType *N) { + return N->pred_begin(); + } + static inline ChildIteratorType child_end(NodeType *N) { + return N->pred_end(); + } + typedef std::pointer_to_unary_function&, MSchedGraphNode&> DerefFun; + + typedef mapped_iterator nodes_iterator; + static nodes_iterator nodes_begin(MSchedGraph *G) { + return map_iterator(((MSchedGraph*)G)->begin(), DerefFun(getSecond)); + } + static nodes_iterator nodes_end(MSchedGraph *G) { + return map_iterator(((MSchedGraph*)G)->end(), DerefFun(getSecond)); + } + }; + + template <> struct GraphTraits > { + typedef const MSchedGraphNode NodeType; + typedef MSchedGraphNode::pred_const_iterator ChildIteratorType; + + static inline ChildIteratorType child_begin(NodeType *N) { + return N->pred_begin(); + } + static inline ChildIteratorType child_end(NodeType *N) { + return N->pred_end(); + } + + typedef std::pointer_to_unary_function&, MSchedGraphNode&> DerefFun; + + typedef mapped_iterator nodes_iterator; + static nodes_iterator nodes_begin(MSchedGraph *G) { + return map_iterator(((MSchedGraph*)G)->begin(), DerefFun(getSecond)); + } + static nodes_iterator nodes_end(MSchedGraph *G) { + return map_iterator(((MSchedGraph*)G)->end(), DerefFun(getSecond)); + } + }; + + + + + } + + #endif Index: llvm/lib/CodeGen/ModuloScheduling/ModuloScheduling.h diff -c /dev/null llvm/lib/CodeGen/ModuloScheduling/ModuloScheduling.h:1.11.2.1 *** /dev/null Mon Mar 1 17:58:28 2004 --- llvm/lib/CodeGen/ModuloScheduling/ModuloScheduling.h Mon Mar 1 17:58:13 2004 *************** *** 0 **** --- 1,68 ---- + //===-- ModuloScheduling.h - Swing Modulo Scheduling------------*- C++ -*-===// + // + // The LLVM Compiler Infrastructure + // + // This file was developed by the LLVM research group and is distributed under + // the University of Illinois Open Source License. See LICENSE.TXT for details. + // + //===----------------------------------------------------------------------===// + // + // + //===----------------------------------------------------------------------===// + + #ifndef LLVM_MODULOSCHEDULING_H + #define LLVM_MODULOSCHEDULING_H + + #include "MSchedGraph.h" + #include "llvm/Function.h" + #include "llvm/Pass.h" + #include + + namespace llvm { + + + //Struct to contain ModuloScheduling Specific Information for each node + struct MSNodeAttributes { + int ASAP; //Earliest time at which the opreation can be scheduled + int ALAP; //Latest time at which the operation can be scheduled. + int MOB; + int depth; + int height; + MSNodeAttributes(int asap=-1, int alap=-1, int mob=-1, + int d=-1, int h=-1) : ASAP(asap), ALAP(alap), + MOB(mob), depth(d), + height(h) {} + }; + + + class ModuloSchedulingPass : public FunctionPass { + const TargetMachine ⌖ + + //Map that holds node to node attribute information + std::map nodeToAttributesMap; + + //Internal functions + bool MachineBBisValid(const MachineBasicBlock *BI); + int calculateResMII(const MachineBasicBlock *BI); + void calculateNodeAttributes(MSchedGraph *graph, int MII); + void calculateASAP(MSchedGraphNode *node, MSNodeAttributes &attributes, + int MII,std::set &visitedNodes); + void calculateALAP(MSchedGraphNode *node, MSNodeAttributes &attributes, int MII, + int maxASAP, std::set &visitedNodes); + void calculateHeight(MSchedGraphNode *node, + MSNodeAttributes &attributes, std::set &visitedNodes); + void calculateDepth(MSchedGraphNode *node, MSNodeAttributes &attributes, + std::set &visitedNodes); + + int findMaxASAP(); + void ModuloSchedulingPass::orderNodes(); + void findAllReccurrences(MSchedGraphNode *node, std::vector &visitedNodes); + public: + ModuloSchedulingPass(TargetMachine &targ) : target(targ) {} + virtual bool runOnFunction(Function &F); + }; + + } + + + #endif Index: llvm/lib/CodeGen/ModuloScheduling/ModuloScheduling.cpp diff -u llvm/lib/CodeGen/ModuloScheduling/ModuloScheduling.cpp:1.15 llvm/lib/CodeGen/ModuloScheduling/ModuloScheduling.cpp:1.15.4.1 --- llvm/lib/CodeGen/ModuloScheduling/ModuloScheduling.cpp:1.15 Tue Nov 11 16:41:33 2003 +++ llvm/lib/CodeGen/ModuloScheduling/ModuloScheduling.cpp Mon Mar 1 17:58:13 2004 @@ -1,46 +1,704 @@ -//===-- ModuloScheduling.cpp - Software Pipeling Approach - SMS -----------===// -// +//===-- ModuloScheduling.cpp - ModuloScheduling ----------------*- C++ -*-===// +// // The LLVM Compiler Infrastructure // // This file was developed by the LLVM research group and is distributed under // the University of Illinois Open Source License. See LICENSE.TXT for details. -// +// //===----------------------------------------------------------------------===// // -// The is a software pipelining pass based on the Swing Modulo Scheduling -// algorithm (SMS). +// // //===----------------------------------------------------------------------===// -#include "ModuloSchedGraph.h" -#include "llvm/Function.h" -#include "llvm/Pass.h" +#define DEBUG_TYPE "ModuloSched" -namespace llvm { +#include "ModuloScheduling.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/Passes.h" +#include "llvm/Support/CFG.h" +#include "llvm/Target/TargetSchedInfo.h" +#include "Support/Debug.h" +#include "Support/GraphWriter.h" +#include +#include +#include +#include +#include + +using namespace llvm; + +/// Create ModuloSchedulingPass +/// +FunctionPass *llvm::createModuloSchedulingPass(TargetMachine & targ) { + DEBUG(std::cerr << "Created ModuloSchedulingPass\n"); + return new ModuloSchedulingPass(targ); +} -namespace { +template +static void WriteGraphToFile(std::ostream &O, const std::string &GraphName, + const GraphType >) { + std::string Filename = GraphName + ".dot"; + O << "Writing '" << Filename << "'..."; + std::ofstream F(Filename.c_str()); - class ModuloScheduling : public FunctionPass { + if (F.good()) + WriteGraph(F, GT); + else + O << " error opening file for writing!"; + O << "\n"; +}; + +namespace llvm { + + template<> + struct DOTGraphTraits : public DefaultDOTGraphTraits { + static std::string getGraphName(MSchedGraph *F) { + return "Dependence Graph"; + } - public: - virtual bool runOnFunction(Function &F); - }; + static std::string getNodeLabel(MSchedGraphNode *Node, MSchedGraph *Graph) { + if (Node->getInst()) { + std::stringstream ss; + ss << *(Node->getInst()); + return ss.str(); //((MachineInstr*)Node->getInst()); + } + else + return "No Inst"; + } + static std::string getEdgeSourceLabel(MSchedGraphNode *Node, + MSchedGraphNode::succ_iterator I) { + //Label each edge with the type of dependence + std::string edgelabel = ""; + switch (I.getEdge().getDepOrderType()) { + + case MSchedGraphEdge::TrueDep: + edgelabel = "True"; + break; + + case MSchedGraphEdge::AntiDep: + edgelabel = "Anti"; + break; + + case MSchedGraphEdge::OutputDep: + edgelabel = "Output"; + break; + + default: + edgelabel = "Unknown"; + break; + } + if(I.getEdge().getIteDiff() > 0) + edgelabel += I.getEdge().getIteDiff(); + + return edgelabel; + } - RegisterOpt X("modulo-sched", - "Modulo Scheduling/Software Pipelining"); -} -/// Create Modulo Scheduling Pass -/// -Pass *createModuloSchedPass() { - return new ModuloScheduling(); + + }; } /// ModuloScheduling::runOnFunction - main transformation entry point -/// -bool ModuloScheduling::runOnFunction(Function &F) { +bool ModuloSchedulingPass::runOnFunction(Function &F) { bool Changed = false; + + DEBUG(std::cerr << "Creating ModuloSchedGraph for each BasicBlock in" + F.getName() + "\n"); + + //Get MachineFunction + MachineFunction &MF = MachineFunction::get(&F); + + //Iterate over BasicBlocks and do ModuloScheduling if they are valid + for (MachineFunction::const_iterator BI = MF.begin(); BI != MF.end(); ++BI) { + if(MachineBBisValid(BI)) { + MSchedGraph *MSG = new MSchedGraph(BI, target); + + //Write Graph out to file + DEBUG(WriteGraphToFile(std::cerr, "dependgraph", MSG)); + + //Print out BB for debugging + DEBUG(BI->print(std::cerr)); + + //Calculate Resource II + int ResMII = calculateResMII(BI); + + calculateNodeAttributes(MSG, ResMII); + + } + } + + return Changed; } -} // End llvm namespace + +bool ModuloSchedulingPass::MachineBBisValid(const MachineBasicBlock *BI) { + + //Valid basic blocks must be loops and can not have if/else statements or calls. + bool isLoop = false; + + //Check first if its a valid loop + for(succ_const_iterator I = succ_begin(BI->getBasicBlock()), + E = succ_end(BI->getBasicBlock()); I != E; ++I) { + if (*I == BI->getBasicBlock()) // has single block loop + isLoop = true; + } + + if(!isLoop) { + DEBUG(std::cerr << "Basic Block is not a loop\n"); + return false; + } + else + DEBUG(std::cerr << "Basic Block is a loop\n"); + + //Get Target machine instruction info + /*const TargetInstrInfo& TMI = targ.getInstrInfo(); + + //Check each instruction and look for calls or if/else statements + unsigned count = 0; + for(MachineBasicBlock::const_iterator I = BI->begin(), E = BI->end(); I != E; ++I) { + //Get opcode to check instruction type + MachineOpCode OC = I->getOpcode(); + if(TMI.isControlFlow(OC) && (count+1 < BI->size())) + return false; + count++; + }*/ + return true; + +} + +//ResMII is calculated by determining the usage count for each resource +//and using the maximum. +//FIXME: In future there should be a way to get alternative resources +//for each instruction +int ModuloSchedulingPass::calculateResMII(const MachineBasicBlock *BI) { + + const TargetInstrInfo & mii = target.getInstrInfo(); + const TargetSchedInfo & msi = target.getSchedInfo(); + + int ResMII = 0; + + //Map to keep track of usage count of each resource + std::map resourceUsageCount; + + for(MachineBasicBlock::const_iterator I = BI->begin(), E = BI->end(); I != E; ++I) { + + //Get resource usage for this instruction + InstrRUsage rUsage = msi.getInstrRUsage(I->getOpcode()); + std::vector > resources = rUsage.resourcesByCycle; + + //Loop over resources in each cycle and increments their usage count + for(unsigned i=0; i < resources.size(); ++i) + for(unsigned j=0; j < resources[i].size(); ++j) { + if( resourceUsageCount.find(resources[i][j]) == resourceUsageCount.end()) { + resourceUsageCount[resources[i][j]] = 1; + } + else { + resourceUsageCount[resources[i][j]] = resourceUsageCount[resources[i][j]] + 1; + } + } + } + + //Find maximum usage count + + //Get max number of instructions that can be issued at once. + int issueSlots = msi.maxNumIssueTotal; + + for(std::map::iterator RB = resourceUsageCount.begin(), RE = resourceUsageCount.end(); RB != RE; ++RB) { + //Get the total number of the resources in our cpu + //int resourceNum = msi.getCPUResourceNum(RB->first); + + //Get total usage count for this resources + unsigned usageCount = RB->second; + + //Divide the usage count by either the max number we can issue or the number of + //resources (whichever is its upper bound) + double finalUsageCount; + //if( resourceNum <= issueSlots) + //finalUsageCount = ceil(1.0 * usageCount / resourceNum); + //else + finalUsageCount = ceil(1.0 * usageCount / issueSlots); + + + DEBUG(std::cerr << "Resource ID: " << RB->first << " (usage=" << usageCount << ", resourceNum=X" << ", issueSlots=" << issueSlots << ", finalUsage=" << finalUsageCount << ")\n"); + + //Only keep track of the max + ResMII = std::max( (int) finalUsageCount, ResMII); + + } + + DEBUG(std::cerr << "Final Resource MII: " << ResMII << "\n"); + return ResMII; + +} + +void ModuloSchedulingPass::calculateNodeAttributes(MSchedGraph *graph, int MII) { + + //Loop over the nodes and add them to the map + for(MSchedGraph::iterator I = graph->begin(), E = graph->end(); I != E; ++I) { + //Assert if its already in the map + assert(nodeToAttributesMap.find(I->second) == nodeToAttributesMap.end() && "Node attributes are already in the map"); + + //Put into the map with default attribute values + nodeToAttributesMap[I->second] = MSNodeAttributes(); + } + + //Create set to deal with reccurrences + std::set visitedNodes; + std::vector vNodes; + //Now Loop over map and calculate the node attributes + for(std::map::iterator I = nodeToAttributesMap.begin(), E = nodeToAttributesMap.end(); I != E; ++I) { + // calculateASAP(I->first, (I->second), MII, visitedNodes); + findAllReccurrences(I->first, vNodes); + vNodes.clear(); + visitedNodes.clear(); + } + + //Calculate ALAP which depends on ASAP being totally calculated + /*for(std::map::iterator I = nodeToAttributesMap.begin(), E = nodeToAttributesMap.end(); I != E; ++I) { + calculateALAP(I->first, (I->second), MII, MII, visitedNodes); + visitedNodes.clear(); + }*/ + + //Calculate MOB which depends on ASAP being totally calculated, also do depth and height + /*for(std::map::iterator I = nodeToAttributesMap.begin(), E = nodeToAttributesMap.end(); I != E; ++I) { + (I->second).MOB = (I->second).ALAP - (I->second).ASAP; + DEBUG(std::cerr << "MOB: " << (I->second).MOB << " (" << *(I->first) << ")\n"); + calculateDepth(I->first, (I->second), visitedNodes); + visitedNodes.clear(); + calculateHeight(I->first, (I->second), visitedNodes); + visitedNodes.clear(); + }*/ + + +} + +void ModuloSchedulingPass::calculateASAP(MSchedGraphNode *node, MSNodeAttributes &attributes, + int MII, std::set &visitedNodes) { + + DEBUG(std::cerr << "Calculating ASAP for " << *node << "\n"); + + if(attributes.ASAP != -1 || (visitedNodes.find(node) != visitedNodes.end())) { + visitedNodes.erase(node); + return; + } + if(node->hasPredecessors()) { + int maxPredValue = 0; + + //Iterate over all of the predecessors and fine max + for(MSchedGraphNode::pred_iterator P = node->pred_begin(), E = node->pred_end(); P != E; ++P) { + + //Get that nodes ASAP + MSNodeAttributes predAttributes = nodeToAttributesMap.find(*P)->second; + if(predAttributes.ASAP == -1) { + //Put into set before you recurse + visitedNodes.insert(node); + calculateASAP(*P, predAttributes, MII, visitedNodes); + predAttributes = nodeToAttributesMap.find(*P)->second; + } + int iteDiff = node->getInEdge(*P).getIteDiff(); + + int currentPredValue = predAttributes.ASAP + node->getLatency() - iteDiff * MII; + DEBUG(std::cerr << "Current ASAP pred: " << currentPredValue << "\n"); + maxPredValue = std::max(maxPredValue, currentPredValue); + } + visitedNodes.erase(node); + attributes.ASAP = maxPredValue; + } + else { + visitedNodes.erase(node); + attributes.ASAP = 0; + } + + DEBUG(std::cerr << "ASAP: " << attributes.ASAP << " (" << *node << ")\n"); +} + + +void ModuloSchedulingPass::calculateALAP(MSchedGraphNode *node, MSNodeAttributes &attributes, + int MII, int maxASAP, + std::set &visitedNodes) { + + DEBUG(std::cerr << "Calculating AlAP for " << *node << "\n"); + + if(attributes.ALAP != -1|| (visitedNodes.find(node) != visitedNodes.end())) { + visitedNodes.erase(node); + return; + } + if(node->hasSuccessors()) { + int minSuccValue = 0; + + //Iterate over all of the predecessors and fine max + for(MSchedGraphNode::succ_iterator P = node->succ_begin(), + E = node->succ_end(); P != E; ++P) { + + MSNodeAttributes succAttributes = nodeToAttributesMap.find(*P)->second; + if(succAttributes.ASAP == -1) { + + //Put into set before recursing + visitedNodes.insert(node); + + calculateALAP(*P, succAttributes, MII, maxASAP, visitedNodes); + succAttributes = nodeToAttributesMap.find(*P)->second; + assert(succAttributes.ASAP == -1 && "Successors ALAP should have been caclulated"); + } + int iteDiff = P.getEdge().getIteDiff(); + int currentSuccValue = succAttributes.ALAP + node->getLatency() + iteDiff * MII; + minSuccValue = std::min(minSuccValue, currentSuccValue); + } + visitedNodes.erase(node); + attributes.ALAP = minSuccValue; + } + else { + visitedNodes.erase(node); + attributes.ALAP = maxASAP; + } + DEBUG(std::cerr << "ALAP: " << attributes.ALAP << " (" << *node << ")\n"); +} + +int ModuloSchedulingPass::findMaxASAP() { + int maxASAP = 0; + + for(std::map::iterator I = nodeToAttributesMap.begin(), + E = nodeToAttributesMap.end(); I != E; ++I) + maxASAP = std::max(maxASAP, I->second.ASAP); + return maxASAP; +} + + +void ModuloSchedulingPass::calculateHeight(MSchedGraphNode *node, + MSNodeAttributes &attributes, + std::set &visitedNodes) { + + if(attributes.depth != -1 || (visitedNodes.find(node) != visitedNodes.end())) { + //Remove from map before returning + visitedNodes.erase(node); + return; + } + + if(node->hasSuccessors()) { + int maxHeight = 0; + + //Iterate over all of the predecessors and fine max + for(MSchedGraphNode::succ_iterator P = node->succ_begin(), + E = node->succ_end(); P != E; ++P) { + + MSNodeAttributes succAttributes = nodeToAttributesMap.find(*P)->second; + if(succAttributes.height == -1) { + + //Put into map before recursing + visitedNodes.insert(node); + + calculateHeight(*P, succAttributes, visitedNodes); + succAttributes = nodeToAttributesMap.find(*P)->second; + assert(succAttributes.height == -1 && "Successors Height should have been caclulated"); + } + int currentHeight = succAttributes.height + node->getLatency(); + maxHeight = std::max(maxHeight, currentHeight); + } + visitedNodes.erase(node); + attributes.height = maxHeight; + } + else { + visitedNodes.erase(node); + attributes.height = 0; + } + + DEBUG(std::cerr << "Height: " << attributes.height << " (" << *node << ")\n"); +} + + +void ModuloSchedulingPass::calculateDepth(MSchedGraphNode *node, + MSNodeAttributes &attributes, + std::set &visitedNodes) { + + if(attributes.depth != -1 || (visitedNodes.find(node) != visitedNodes.end())) { + //Remove from map before returning + visitedNodes.erase(node); + return; + } + + if(node->hasPredecessors()) { + int maxDepth = 0; + + //Iterate over all of the predecessors and fine max + for(MSchedGraphNode::pred_iterator P = node->pred_begin(), E = node->pred_end(); P != E; ++P) { + + //Get that nodes depth + MSNodeAttributes predAttributes = nodeToAttributesMap.find(*P)->second; + if(predAttributes.depth == -1) { + + //Put into set before recursing + visitedNodes.insert(node); + + calculateDepth(*P, predAttributes, visitedNodes); + predAttributes = nodeToAttributesMap.find(*P)->second; + assert(predAttributes.depth == -1 && "Predecessors ASAP should have been caclulated"); + } + int currentDepth = predAttributes.depth + node->getLatency(); + maxDepth = std::max(maxDepth, currentDepth); + } + + //Remove from map before returning + visitedNodes.erase(node); + + attributes.height = maxDepth; + } + else { + //Remove from map before returning + visitedNodes.erase(node); + attributes.depth = 0; + } + + DEBUG(std::cerr << "Depth: " << attributes.depth << " (" << *node << "*)\n"); + +} + + +void ModuloSchedulingPass::findAllReccurrences(MSchedGraphNode *node, + std::vector &visitedNodes) { + + if(find(visitedNodes.begin(), visitedNodes.end(), node) != visitedNodes.end()) { + //DUMP out recurrence + DEBUG(std::cerr << "Reccurrence:\n"); + bool first = true; + for(std::vector::iterator I = visitedNodes.begin(), E = visitedNodes.end(); + I !=E; ++I) { + if(*I == node) + first = false; + if(first) + continue; + DEBUG(std::cerr << **I << "\n"); + } + DEBUG(std::cerr << "End Reccurrence:\n"); + return; + } + + for(MSchedGraphNode::succ_iterator I = node->succ_begin(), E = node->succ_end(); I != E; ++I) { + visitedNodes.push_back(node); + findAllReccurrences(*I, visitedNodes); + visitedNodes.pop_back(); + } + +} + + + + + + + + + +void ModuloSchedulingPass::orderNodes() { + + int BOTTOM_UP = 0; + int TOP_DOWN = 1; + + //FIXME: Group nodes into sets and order all the sets based on RecMII + typedef std::vector NodeVector; + typedef std::pair NodeSet; + + std::vector NodeSetsToOrder; + + //Order the resulting sets + NodeVector FinalNodeOrder; + + //Loop over all the sets and place them in the final node order + for(unsigned i=0; i < NodeSetsToOrder.size(); ++i) { + + //Set default order + int order = BOTTOM_UP; + + //Get Nodes in Current set + NodeVector CurrentSet = NodeSetsToOrder[i].second; + + //Loop through the predecessors for each node in the final order + //and only keeps nodes both in the pred_set and currentset + NodeVector IntersectCurrent; + + //Sort CurrentSet so we can use lowerbound + sort(CurrentSet.begin(), CurrentSet.end()); + + for(unsigned j=0; j < FinalNodeOrder.size(); ++j) { + for(MSchedGraphNode::pred_iterator P = FinalNodeOrder[j]->pred_begin(), + E = FinalNodeOrder[j]->pred_end(); P != E; ++P) { + if(lower_bound(CurrentSet.begin(), + CurrentSet.end(), *P) != CurrentSet.end()) + IntersectCurrent.push_back(*P); + } + } + + //If the intersection of predecessor and current set is not empty + //sort nodes bottom up + if(IntersectCurrent.size() != 0) + order = BOTTOM_UP; + + //If empty, use successors + else { + + for(unsigned j=0; j < FinalNodeOrder.size(); ++j) { + for(MSchedGraphNode::succ_iterator P = FinalNodeOrder[j]->succ_begin(), + E = FinalNodeOrder[j]->succ_end(); P != E; ++P) { + if(lower_bound(CurrentSet.begin(), + CurrentSet.end(), *P) != CurrentSet.end()) + IntersectCurrent.push_back(*P); + } + } + + //sort top-down + if(IntersectCurrent.size() != 0) + order = TOP_DOWN; + + else { + //Find node with max ASAP in current Set + MSchedGraphNode *node; + int maxASAP = 0; + for(unsigned j=0; j < CurrentSet.size(); ++j) { + //Get node attributes + MSNodeAttributes nodeAttr= nodeToAttributesMap.find(CurrentSet[j])->second; + //assert(nodeAttr != nodeToAttributesMap.end() && "Node not in attributes map!"); + + if(maxASAP < nodeAttr.ASAP) { + maxASAP = nodeAttr.ASAP; + node = CurrentSet[j]; + } + } + order = BOTTOM_UP; + } + } + + //Repeat until all nodes are put into the final order from current set + /*while(IntersectCurrent.size() > 0) { + + if(order == TOP_DOWN) { + while(IntersectCurrent.size() > 0) { + + //FIXME + //Get node attributes + MSNodeAttributes nodeAttr= nodeToAttributesMap.find(IntersectCurrent[0])->second; + assert(nodeAttr != nodeToAttributesMap.end() && "Node not in attributes map!"); + + //Get node with highest height, if a tie, use one with lowest + //MOB + int MOB = nodeAttr.MBO; + int height = nodeAttr.height; + ModuloSchedGraphNode *V = IntersectCurrent[0]; + + for(unsigned j=0; j < IntersectCurrent.size(); ++j) { + int temp = IntersectCurrent[j]->getHeight(); + if(height < temp) { + V = IntersectCurrent[j]; + height = temp; + MOB = V->getMobility(); + } + else if(height == temp) { + if(MOB > IntersectCurrent[j]->getMobility()) { + V = IntersectCurrent[j]; + height = temp; + MOB = V->getMobility(); + } + } + } + + //Append V to the NodeOrder + NodeOrder.push_back(V); + + //Remove V from IntersectOrder + IntersectCurrent.erase(find(IntersectCurrent.begin(), + IntersectCurrent.end(), V)); + + //Intersect V's successors with CurrentSet + for(mod_succ_iterator P = succ_begin(V), + E = succ_end(V); P != E; ++P) { + if(lower_bound(CurrentSet.begin(), + CurrentSet.end(), *P) != CurrentSet.end()) { + //If not already in Intersect, add + if(find(IntersectCurrent.begin(), IntersectCurrent.end(), *P) == IntersectCurrent.end()) + IntersectCurrent.push_back(*P); + } + } + } //End while loop over Intersect Size + + //Change direction + order = BOTTOM_UP; + + //Reset Intersect to reflect changes in OrderNodes + IntersectCurrent.clear(); + for(unsigned j=0; j < NodeOrder.size(); ++j) { + for(mod_pred_iterator P = pred_begin(NodeOrder[j]), + E = pred_end(NodeOrder[j]); P != E; ++P) { + if(lower_bound(CurrentSet.begin(), + CurrentSet.end(), *P) != CurrentSet.end()) + IntersectCurrent.push_back(*P); + } + } + } //End If TOP_DOWN + + //Begin if BOTTOM_UP + else { + while(IntersectCurrent.size() > 0) { + //Get node with highest depth, if a tie, use one with lowest + //MOB + int MOB = IntersectCurrent[0]->getMobility(); + int depth = IntersectCurrent[0]->getDepth(); + ModuloSchedGraphNode *V = IntersectCurrent[0]; + + for(unsigned j=0; j < IntersectCurrent.size(); ++j) { + int temp = IntersectCurrent[j]->getDepth(); + if(depth < temp) { + V = IntersectCurrent[j]; + depth = temp; + MOB = V->getMobility(); + } + else if(depth == temp) { + if(MOB > IntersectCurrent[j]->getMobility()) { + V = IntersectCurrent[j]; + depth = temp; + MOB = V->getMobility(); + } + } + } + + //Append V to the NodeOrder + NodeOrder.push_back(V); + + //Remove V from IntersectOrder + IntersectCurrent.erase(find(IntersectCurrent.begin(), + IntersectCurrent.end(),V)); + + //Intersect V's pred with CurrentSet + for(mod_pred_iterator P = pred_begin(V), + E = pred_end(V); P != E; ++P) { + if(lower_bound(CurrentSet.begin(), + CurrentSet.end(), *P) != CurrentSet.end()) { + //If not already in Intersect, add + if(find(IntersectCurrent.begin(), IntersectCurrent.end(), *P) == IntersectCurrent.end()) + IntersectCurrent.push_back(*P); + } + } + } //End while loop over Intersect Size + + //Change order + order = TOP_DOWN; + + //Reset IntersectCurrent to reflect changes in OrderNodes + IntersectCurrent.clear(); + for(unsigned j=0; j < NodeOrder.size(); ++j) { + for(mod_succ_iterator P = succ_begin(NodeOrder[j]), + E = succ_end(NodeOrder[j]); P != E; ++P) { + if(lower_bound(CurrentSet.begin(), + CurrentSet.end(), *P) != CurrentSet.end()) + IntersectCurrent.push_back(*P); + } + + } + } //End if BOTTOM_DOWN + + }*/ +//End Wrapping while loop + + }//End for over all sets of nodes + + //Return final Order + //return FinalNodeOrder; +} From brukman at cs.uiuc.edu Mon Mar 1 18:04:44 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Mar 1 18:04:44 2004 Subject: [llvm-commits] [parallel] CVS: llvm/lib/VMCore/AsmWriter.cpp BasicBlock.cpp ConstantFolding.cpp Constants.cpp Function.cpp Instruction.cpp IntrinsicLowering.cpp ModuleProvider.cpp Pass.cpp PassManagerT.h SlotCalculator.cpp Type.cpp Verifier.cpp iCall.cpp iOperators.cpp Message-ID: <200403012358.RAA04086@zion.cs.uiuc.edu> Changes in directory llvm/lib/VMCore: AsmWriter.cpp updated: 1.116 -> 1.116.2.1 BasicBlock.cpp updated: 1.38 -> 1.38.4.1 ConstantFolding.cpp updated: 1.50 -> 1.50.2.1 Constants.cpp updated: 1.71 -> 1.71.2.1 Function.cpp updated: 1.62.2.1 -> 1.62.2.2 Instruction.cpp updated: 1.33.2.1 -> 1.33.2.2 IntrinsicLowering.cpp updated: 1.5.2.1 -> 1.5.2.2 ModuleProvider.cpp updated: 1.8 -> 1.8.4.1 Pass.cpp updated: 1.54 -> 1.54.4.1 PassManagerT.h updated: 1.46 -> 1.46.4.1 SlotCalculator.cpp updated: 1.50 -> 1.50.2.1 Type.cpp updated: 1.87 -> 1.87.2.1 Verifier.cpp updated: 1.78.2.2 -> 1.78.2.3 iCall.cpp updated: 1.22 -> 1.22.4.1 iOperators.cpp updated: 1.25 -> 1.25.4.1 --- Log message: Merge from trunk --- Diffs of the changes: (+583 -446) Index: llvm/lib/VMCore/AsmWriter.cpp diff -u llvm/lib/VMCore/AsmWriter.cpp:1.116 llvm/lib/VMCore/AsmWriter.cpp:1.116.2.1 --- llvm/lib/VMCore/AsmWriter.cpp:1.116 Tue Jan 20 13:50:22 2004 +++ llvm/lib/VMCore/AsmWriter.cpp Mon Mar 1 17:58:16 2004 @@ -142,7 +142,6 @@ // This is another base case for the recursion. In this case, we know // that we have looped back to a type that we have previously visited. // Generate the appropriate upreference to handle this. - // if (Slot < CurSize) return "\\" + utostr(CurSize-Slot); // Here's the upreference @@ -153,15 +152,14 @@ case Type::FunctionTyID: { const FunctionType *FTy = cast(Ty); Result = calcTypeName(FTy->getReturnType(), TypeStack, TypeNames) + " ("; - for (FunctionType::ParamTypes::const_iterator - I = FTy->getParamTypes().begin(), - E = FTy->getParamTypes().end(); I != E; ++I) { - if (I != FTy->getParamTypes().begin()) + for (FunctionType::param_iterator I = FTy->param_begin(), + E = FTy->param_end(); I != E; ++I) { + if (I != FTy->param_begin()) Result += ", "; Result += calcTypeName(*I, TypeStack, TypeNames); } if (FTy->isVarArg()) { - if (!FTy->getParamTypes().empty()) Result += ", "; + if (FTy->getNumParams()) Result += ", "; Result += "..."; } Result += ")"; @@ -170,10 +168,9 @@ case Type::StructTyID: { const StructType *STy = cast(Ty); Result = "{ "; - for (StructType::ElementTypes::const_iterator - I = STy->getElementTypes().begin(), - E = STy->getElementTypes().end(); I != E; ++I) { - if (I != STy->getElementTypes().begin()) + for (StructType::element_iterator I = STy->element_begin(), + E = STy->element_end(); I != E; ++I) { + if (I != STy->element_begin()) Result += ", "; Result += calcTypeName(*I, TypeStack, TypeNames); } @@ -202,9 +199,9 @@ } -// printTypeInt - The internal guts of printing out a type that has a -// potentially named portion. -// +/// printTypeInt - The internal guts of printing out a type that has a +/// potentially named portion. +/// static std::ostream &printTypeInt(std::ostream &Out, const Type *Ty, std::map &TypeNames) { // Primitive types always print out their description, regardless of whether @@ -228,10 +225,10 @@ } -// WriteTypeSymbolic - This attempts to write the specified type as a symbolic -// type, iff there is an entry in the modules symbol table for the specified -// type or one of it's component types. This is slower than a simple x << Type; -// +/// WriteTypeSymbolic - This attempts to write the specified type as a symbolic +/// type, iff there is an entry in the modules symbol table for the specified +/// type or one of it's component types. This is slower than a simple x << Type +/// std::ostream &llvm::WriteTypeSymbolic(std::ostream &Out, const Type *Ty, const Module *M) { Out << " "; @@ -290,12 +287,9 @@ "assuming that double is 64 bits!"); Out << "0x" << utohexstr(*(uint64_t*)Ptr); + } else if (isa(CV)) { + Out << "zeroinitializer"; } else if (const ConstantArray *CA = dyn_cast(CV)) { - if (CA->getNumOperands() > 5 && CA->isNullValue()) { - Out << "zeroinitializer"; - return; - } - // As a special case, print the array as a string if it is an array of // ubytes or an array of sbytes with positive values. // @@ -341,11 +335,6 @@ Out << " ]"; } } else if (const ConstantStruct *CS = dyn_cast(CV)) { - if (CS->getNumOperands() > 5 && CS->isNullValue()) { - Out << "zeroinitializer"; - return; - } - Out << "{"; if (CS->getNumOperands()) { Out << " "; @@ -424,20 +413,23 @@ } if (Slot >= 0) Out << "%" << Slot; else if (PrintName) - Out << ""; // Not embedded into a location? + if (V->hasName()) + Out << "getName()) << ">"; + else + Out << ""; // Not embedded into a location? } } } -// WriteAsOperand - Write the name of the specified value out to the specified -// ostream. This can be useful when you just want to print int %reg126, not the -// whole instruction that generated it. -// +/// WriteAsOperand - Write the name of the specified value out to the specified +/// ostream. This can be useful when you just want to print int %reg126, not +/// the whole instruction that generated it. +/// std::ostream &llvm::WriteAsOperand(std::ostream &Out, const Value *V, - bool PrintType, - bool PrintName, const Module *Context) { + bool PrintType, bool PrintName, + const Module *Context) { std::map TypeNames; if (Context == 0) Context = getModuleFromVal(V); @@ -517,24 +509,22 @@ std::ostream &AssemblyWriter::printTypeAtLeastOneLevel(const Type *Ty) { if (const FunctionType *FTy = dyn_cast(Ty)) { printType(FTy->getReturnType()) << " ("; - for (FunctionType::ParamTypes::const_iterator - I = FTy->getParamTypes().begin(), - E = FTy->getParamTypes().end(); I != E; ++I) { - if (I != FTy->getParamTypes().begin()) + for (FunctionType::param_iterator I = FTy->param_begin(), + E = FTy->param_end(); I != E; ++I) { + if (I != FTy->param_begin()) Out << ", "; printType(*I); } if (FTy->isVarArg()) { - if (!FTy->getParamTypes().empty()) Out << ", "; + if (FTy->getNumParams()) Out << ", "; Out << "..."; } Out << ")"; } else if (const StructType *STy = dyn_cast(Ty)) { Out << "{ "; - for (StructType::ElementTypes::const_iterator - I = STy->getElementTypes().begin(), - E = STy->getElementTypes().end(); I != E; ++I) { - if (I != STy->getElementTypes().begin()) + for (StructType::element_iterator I = STy->element_begin(), + E = STy->element_end(); I != E; ++I) { + if (I != STy->element_begin()) Out << ", "; printType(*I); } @@ -689,7 +679,7 @@ // Finish printing arguments... if (FT->isVarArg()) { - if (FT->getParamTypes().size()) Out << ", "; + if (FT->getNumParams()) Out << ", "; Out << "..."; // Output varargs portion of signature! } Out << ")"; @@ -894,8 +884,8 @@ Out << " )\n\t\t\tto"; writeOperand(II->getNormalDest(), true); - Out << " except"; - writeOperand(II->getExceptionalDest(), true); + Out << " unwind"; + writeOperand(II->getUnwindDest(), true); } else if (const AllocationInst *AI = dyn_cast(&I)) { Out << " "; Index: llvm/lib/VMCore/BasicBlock.cpp diff -u llvm/lib/VMCore/BasicBlock.cpp:1.38 llvm/lib/VMCore/BasicBlock.cpp:1.38.4.1 --- llvm/lib/VMCore/BasicBlock.cpp:1.38 Fri Nov 21 10:52:05 2003 +++ llvm/lib/VMCore/BasicBlock.cpp Mon Mar 1 17:58:16 2004 @@ -61,25 +61,8 @@ template class SymbolTableListTraits; -// BasicBlock ctor - If the function parameter is specified, the basic block is -// automatically inserted at the end of the function. -// -BasicBlock::BasicBlock(const std::string &name, Function *Parent) - : Value(Type::LabelTy, Value::BasicBlockVal, name) { - // Initialize the instlist... - InstList.setItemParent(this); - - // Make sure that we get added to a function - LeakDetector::addGarbageObject(this); - - if (Parent) - Parent->getBasicBlockList().push_back(this); -} - -/// BasicBlock ctor - If the InsertBefore parameter is specified, the basic -/// block is automatically inserted right before the specified block. -/// -BasicBlock::BasicBlock(const std::string &Name, BasicBlock *InsertBefore) +BasicBlock::BasicBlock(const std::string &Name, Function *Parent, + BasicBlock *InsertBefore) : Value(Type::LabelTy, Value::BasicBlockVal, Name) { // Initialize the instlist... InstList.setItemParent(this); @@ -88,10 +71,11 @@ LeakDetector::addGarbageObject(this); if (InsertBefore) { - assert(InsertBefore->getParent() && - "Cannot insert block before another block that is not embedded into" - " a function yet!"); - InsertBefore->getParent()->getBasicBlockList().insert(InsertBefore, this); + assert(Parent && + "Cannot insert block before another block with no function!"); + Parent->getBasicBlockList().insert(InsertBefore, this); + } else if (Parent) { + Parent->getBasicBlockList().push_back(this); } } @@ -136,19 +120,6 @@ I->dropAllReferences(); } -// hasConstantReferences() - This predicate is true if there is a -// reference to this basic block in the constant pool for this method. For -// example, if a block is reached through a switch table, that table resides -// in the constant pool, and the basic block is reference from it. -// -bool BasicBlock::hasConstantReferences() const { - for (use_const_iterator I = use_begin(), E = use_end(); I != E; ++I) - if (isa((Value*)*I)) - return true; - - return false; -} - // removePredecessor - This method is used to notify a BasicBlock that the // specified Predecessor of the block is no longer able to reach it. This is // actually not used to update the Predecessor list, but is actually used to @@ -231,16 +202,11 @@ assert(I != InstList.end() && "Trying to get me to create degenerate basic block!"); - BasicBlock *New = new BasicBlock(BBName, getParent()); + BasicBlock *New = new BasicBlock(BBName, getParent(), getNext()); - // Go from the end of the basic block through to the iterator pointer, moving - // to the new basic block... - Instruction *Inst = 0; - do { - iterator EndIt = end(); - Inst = InstList.remove(--EndIt); // Remove from end - New->InstList.push_front(Inst); // Add to front - } while (Inst != &*I); // Loop until we move the specified instruction. + // Move all of the specified instructions from the original basic block into + // the new basic block. + New->getInstList().splice(New->end(), this->getInstList(), I, end()); // Add a branch instruction to the newly formed basic block. new BranchInst(New, this); Index: llvm/lib/VMCore/ConstantFolding.cpp diff -u llvm/lib/VMCore/ConstantFolding.cpp:1.50 llvm/lib/VMCore/ConstantFolding.cpp:1.50.2.1 --- llvm/lib/VMCore/ConstantFolding.cpp:1.50 Mon Jan 12 23:51:55 2004 +++ llvm/lib/VMCore/ConstantFolding.cpp Mon Mar 1 17:58:16 2004 @@ -20,9 +20,7 @@ #include "ConstantFolding.h" #include "llvm/Constants.h" -#include "llvm/iPHINode.h" -#include "llvm/iOperators.h" -#include "llvm/InstrTypes.h" +#include "llvm/Instructions.h" #include "llvm/DerivedTypes.h" #include "llvm/Support/GetElementPtrTypeIterator.h" #include @@ -625,11 +623,18 @@ // If the first operand is simple, swap operands. assert((isa(V2) || isa(V2)) && "Simple cases should have been handled by caller!"); - return SetCondInst::getSwappedCondition(evaluateRelation(V2, V1)); + Instruction::BinaryOps SwappedRelation = evaluateRelation(V2, V1); + if (SwappedRelation != Instruction::BinaryOpsEnd) + return SetCondInst::getSwappedCondition(SwappedRelation); } else if (const ConstantPointerRef *CPR1 = dyn_cast(V1)){ - if (isa(V2)) // Swap as necessary. - return SetCondInst::getSwappedCondition(evaluateRelation(V2, V1)); + if (isa(V2)) { // Swap as necessary. + Instruction::BinaryOps SwappedRelation = evaluateRelation(V2, V1); + if (SwappedRelation != Instruction::BinaryOpsEnd) + return SetCondInst::getSwappedCondition(SwappedRelation); + else + return Instruction::BinaryOpsEnd; + } // Now we know that the RHS is a ConstantPointerRef or simple constant, // which (since the types must match) means that it's a ConstantPointerNull. @@ -920,8 +925,21 @@ (IdxList.size() == 1 && IdxList[0]->isNullValue())) return const_cast(C); - // TODO If C is null and all idx's are null, return null of the right type. - + if (C->isNullValue()) { + bool isNull = true; + for (unsigned i = 0, e = IdxList.size(); i != e; ++i) + if (!IdxList[i]->isNullValue()) { + isNull = false; + break; + } + if (isNull) { + std::vector VIdxList(IdxList.begin(), IdxList.end()); + const Type *Ty = GetElementPtrInst::getIndexedType(C->getType(), VIdxList, + true); + assert(Ty != 0 && "Invalid indices for GEP!"); + return ConstantPointerNull::get(PointerType::get(Ty)); + } + } if (ConstantExpr *CE = dyn_cast(const_cast(C))) { // Combine Indices - If the source pointer to this getelementptr instruction Index: llvm/lib/VMCore/Constants.cpp diff -u llvm/lib/VMCore/Constants.cpp:1.71 llvm/lib/VMCore/Constants.cpp:1.71.2.1 --- llvm/lib/VMCore/Constants.cpp:1.71 Wed Jan 14 11:51:53 2004 +++ llvm/lib/VMCore/Constants.cpp Mon Mar 1 17:58:16 2004 @@ -116,21 +116,9 @@ case Type::PointerTyID: return ConstantPointerNull::get(cast(Ty)); - case Type::StructTyID: { - const StructType *ST = cast(Ty); - const StructType::ElementTypes &ETs = ST->getElementTypes(); - std::vector Elements; - Elements.resize(ETs.size()); - for (unsigned i = 0, e = ETs.size(); i != e; ++i) - Elements[i] = Constant::getNullValue(ETs[i]); - return ConstantStruct::get(ST, Elements); - } - case Type::ArrayTyID: { - const ArrayType *AT = cast(Ty); - Constant *El = Constant::getNullValue(AT->getElementType()); - unsigned NumElements = AT->getNumElements(); - return ConstantArray::get(AT, std::vector(NumElements, El)); - } + case Type::StructTyID: + case Type::ArrayTyID: + return ConstantAggregateZero::get(Ty); default: // Function, Type, Label, or Opaque type? assert(0 && "Cannot create a null constant of that type!"); @@ -263,14 +251,15 @@ ConstantStruct::ConstantStruct(const StructType *T, const std::vector &V) : Constant(T) { - const StructType::ElementTypes &ETypes = T->getElementTypes(); - assert(V.size() == ETypes.size() && + assert(V.size() == T->getNumElements() && "Invalid initializer vector for constant structure"); Operands.reserve(V.size()); for (unsigned i = 0, e = V.size(); i != e; ++i) { - assert((V[i]->getType() == ETypes[i] || - ((ETypes[i]->isAbstract() || V[i]->getType()->isAbstract()) && - ETypes[i]->getPrimitiveID()==V[i]->getType()->getPrimitiveID())) && + assert((V[i]->getType() == T->getElementType(i) || + ((T->getElementType(i)->isAbstract() || + V[i]->getType()->isAbstract()) && + T->getElementType(i)->getPrimitiveID() == + V[i]->getType()->getPrimitiveID())) && "Initializer for struct element doesn't match struct element type!"); Operands.push_back(Use(V[i], this)); } @@ -330,11 +319,15 @@ return ((Ty == Type::FloatTy || Ty == Type::DoubleTy) && !isa(CPV)); } +bool ConstantAggregateZero::classof(const Constant *CPV) { + return (isa(CPV->getType()) || isa(CPV->getType())) && + CPV->isNullValue(); +} bool ConstantArray::classof(const Constant *CPV) { - return isa(CPV->getType()) && !isa(CPV); + return isa(CPV->getType()) && !CPV->isNullValue(); } bool ConstantStruct::classof(const Constant *CPV) { - return isa(CPV->getType()) && !isa(CPV); + return isa(CPV->getType()) && !CPV->isNullValue(); } bool ConstantPointerNull::classof(const Constant *CPV) { @@ -417,7 +410,7 @@ Values.push_back(Val); } - ConstantArray *Replacement = ConstantArray::get(getType(), Values); + Constant *Replacement = ConstantArray::get(getType(), Values); assert(Replacement != this && "I didn't contain From!"); // Everyone using this now uses the replacement... @@ -442,7 +435,7 @@ Values.push_back(Val); } - ConstantStruct *Replacement = ConstantStruct::get(getType(), Values); + Constant *Replacement = ConstantStruct::get(getType(), Values); assert(Replacement != this && "I didn't contain From!"); // Everyone using this now uses the replacement... @@ -698,12 +691,100 @@ //---- ConstantFP::get() implementation... // -static ValueMap FPConstants; +namespace llvm { + template<> + struct ConstantCreator { + static ConstantFP *create(const Type *Ty, uint64_t V) { + assert(Ty == Type::DoubleTy); + union { + double F; + uint64_t I; + } T; + T.I = V; + return new ConstantFP(Ty, T.F); + } + }; + template<> + struct ConstantCreator { + static ConstantFP *create(const Type *Ty, uint32_t V) { + assert(Ty == Type::FloatTy); + union { + float F; + uint32_t I; + } T; + T.I = V; + return new ConstantFP(Ty, T.F); + } + }; +} + +static ValueMap DoubleConstants; +static ValueMap FloatConstants; ConstantFP *ConstantFP::get(const Type *Ty, double V) { - return FPConstants.getOrCreate(Ty, V); + if (Ty == Type::FloatTy) { + // Force the value through memory to normalize it. + union { + float F; + uint32_t I; + } T; + T.F = (float)V; + return FloatConstants.getOrCreate(Ty, T.I); + } else { + assert(Ty == Type::DoubleTy); + union { + double F; + uint64_t I; + } T; + T.F = V; + return DoubleConstants.getOrCreate(Ty, T.I); + } +} + +//---- ConstantAggregateZero::get() implementation... +// +namespace llvm { + // ConstantAggregateZero does not take extra "value" argument... + template + struct ConstantCreator { + static ConstantAggregateZero *create(const Type *Ty, const ValType &V){ + return new ConstantAggregateZero(Ty); + } + }; + + template<> + struct ConvertConstantType { + static void convert(ConstantAggregateZero *OldC, const Type *NewTy) { + // Make everyone now use a constant of the new type... + Constant *New = ConstantAggregateZero::get(NewTy); + assert(New != OldC && "Didn't replace constant??"); + OldC->uncheckedReplaceAllUsesWith(New); + OldC->destroyConstant(); // This constant is now dead, destroy it. + } + }; +} + +static ValueMap AggZeroConstants; + +Constant *ConstantAggregateZero::get(const Type *Ty) { + return AggZeroConstants.getOrCreate(Ty, 0); +} + +// destroyConstant - Remove the constant from the constant table... +// +void ConstantAggregateZero::destroyConstant() { + AggZeroConstants.remove(this); + destroyConstantImpl(); +} + +void ConstantAggregateZero::replaceUsesOfWithOnConstant(Value *From, Value *To, + bool DisableChecking) { + assert(0 && "No uses!"); + abort(); } + + //---- ConstantArray::get() implementation... // namespace llvm { @@ -725,9 +806,18 @@ static ValueMap, ArrayType, ConstantArray> ArrayConstants; -ConstantArray *ConstantArray::get(const ArrayType *Ty, - const std::vector &V) { - return ArrayConstants.getOrCreate(Ty, V); +Constant *ConstantArray::get(const ArrayType *Ty, + const std::vector &V) { + // If this is an all-zero array, return a ConstantAggregateZero object + if (!V.empty()) { + Constant *C = V[0]; + if (!C->isNullValue()) + return ArrayConstants.getOrCreate(Ty, V); + for (unsigned i = 1, e = V.size(); i != e; ++i) + if (V[i] != C) + return ArrayConstants.getOrCreate(Ty, V); + } + return ConstantAggregateZero::get(Ty); } // destroyConstant - Remove the constant from the constant table... @@ -741,7 +831,7 @@ // contain the specified string. A null terminator is added to the specified // string so that it may be used in a natural way... // -ConstantArray *ConstantArray::get(const std::string &Str) { +Constant *ConstantArray::get(const std::string &Str) { std::vector ElementVals; for (unsigned i = 0; i < Str.length(); ++i) @@ -805,9 +895,14 @@ static ValueMap, StructType, ConstantStruct> StructConstants; -ConstantStruct *ConstantStruct::get(const StructType *Ty, - const std::vector &V) { - return StructConstants.getOrCreate(Ty, V); +Constant *ConstantStruct::get(const StructType *Ty, + const std::vector &V) { + // Create a ConstantAggregateZero value if all elements are zeros... + for (unsigned i = 0, e = V.size(); i != e; ++i) + if (!V[i]->isNullValue()) + return StructConstants.getOrCreate(Ty, V); + + return ConstantAggregateZero::get(Ty); } // destroyConstant - Remove the constant from the constant table... @@ -986,11 +1081,15 @@ Constant *ConstantExpr::getGetElementPtrTy(const Type *ReqTy, Constant *C, const std::vector &IdxList) { + assert(GetElementPtrInst::getIndexedType(C->getType(), + std::vector(IdxList.begin(), IdxList.end()), true) && + "GEP indices invalid!"); + if (Constant *FC = ConstantFoldGetElementPtr(C, IdxList)) return FC; // Fold a few common cases... + assert(isa(C->getType()) && "Non-pointer type for constant GetElementPtr expression"); - // Look up the constant in the table first to ensure uniqueness std::vector argVec(1, C); argVec.insert(argVec.end(), IdxList.begin(), IdxList.end()); @@ -1006,17 +1105,6 @@ const Type *Ty = GetElementPtrInst::getIndexedType(C->getType(), VIdxList, true); assert(Ty && "GEP indices invalid!"); - - if (C->isNullValue()) { - bool isNull = true; - for (unsigned i = 0, e = IdxList.size(); i != e; ++i) - if (!IdxList[i]->isNullValue()) { - isNull = false; - break; - } - if (isNull) return ConstantPointerNull::get(PointerType::get(Ty)); - } - return getGetElementPtrTy(PointerType::get(Ty), C, IdxList); } Index: llvm/lib/VMCore/Function.cpp diff -u llvm/lib/VMCore/Function.cpp:1.62.2.1 llvm/lib/VMCore/Function.cpp:1.62.2.2 --- llvm/lib/VMCore/Function.cpp:1.62.2.1 Mon Feb 2 16:33:06 2004 +++ llvm/lib/VMCore/Function.cpp Mon Mar 1 17:58:16 2004 @@ -214,11 +214,22 @@ if (getName() == "llvm.dbg.func.start") return Intrinsic::dbg_func_start; if (getName() == "llvm.dbg.declare") return Intrinsic::dbg_declare; break; + case 'f': + if (getName() == "llvm.frameaddress") return Intrinsic::frameaddress; + break; case 'j': if (getName() == "llvm.join") return Intrinsic::join; break; case 'l': if (getName() == "llvm.longjmp") return Intrinsic::longjmp; + break; + case 'm': + if (getName() == "llvm.memcpy") return Intrinsic::memcpy; + if (getName() == "llvm.memmove") return Intrinsic::memmove; + if (getName() == "llvm.memset") return Intrinsic::memset; + break; + case 'r': + if (getName() == "llvm.returnaddress") return Intrinsic::returnaddress; break; case 's': if (getName() == "llvm.setjmp") return Intrinsic::setjmp; Index: llvm/lib/VMCore/Instruction.cpp diff -u llvm/lib/VMCore/Instruction.cpp:1.33.2.1 llvm/lib/VMCore/Instruction.cpp:1.33.2.2 --- llvm/lib/VMCore/Instruction.cpp:1.33.2.1 Thu Jan 29 19:28:20 2004 +++ llvm/lib/VMCore/Instruction.cpp Mon Mar 1 17:58:16 2004 @@ -35,13 +35,13 @@ } void Instruction::setParent(BasicBlock *P) { - if (getParent()) - LeakDetector::addGarbageObject(this); + if (getParent()) { + if (!P) LeakDetector::addGarbageObject(this); + } else { + if (P) LeakDetector::removeGarbageObject(this); + } Parent = P; - - if (getParent()) - LeakDetector::removeGarbageObject(this); } // Specialize setName to take care of symbol table majik Index: llvm/lib/VMCore/IntrinsicLowering.cpp diff -u llvm/lib/VMCore/IntrinsicLowering.cpp:1.5.2.1 llvm/lib/VMCore/IntrinsicLowering.cpp:1.5.2.2 --- llvm/lib/VMCore/IntrinsicLowering.cpp:1.5.2.1 Mon Feb 2 16:33:06 2004 +++ llvm/lib/VMCore/IntrinsicLowering.cpp Mon Mar 1 17:58:16 2004 @@ -12,12 +12,55 @@ //===----------------------------------------------------------------------===// #include "llvm/IntrinsicLowering.h" -#include "llvm/Constant.h" +#include "llvm/Constants.h" +#include "llvm/DerivedTypes.h" #include "llvm/Module.h" -#include "llvm/Type.h" #include "llvm/iOther.h" using namespace llvm; +/// ReplaceCallWith - This function is used when we want to lower an intrinsic +/// call to a call of an external function. This handles hard cases such as +/// when there was already a prototype for the external function, and if that +/// prototype doesn't match the arguments we expect to pass in. +template +static CallInst *ReplaceCallWith(const char *NewFn, CallInst *CI, + ArgIt ArgBegin, ArgIt ArgEnd, + const Type *RetTy, Function *&FCache) { + if (!FCache) { + // If we haven't already looked up this function, check to see if the + // program already contains a function with this name. + Module *M = CI->getParent()->getParent()->getParent(); + FCache = M->getNamedFunction(NewFn); + if (!FCache) { + // It doesn't already exist in the program, insert a new definition now. + std::vector ParamTys; + for (ArgIt I = ArgBegin; I != ArgEnd; ++I) + ParamTys.push_back((*I)->getType()); + FCache = M->getOrInsertFunction(NewFn, + FunctionType::get(RetTy, ParamTys, false)); + } + } + + const FunctionType *FT = FCache->getFunctionType(); + std::vector Operands; + unsigned ArgNo = 0; + for (ArgIt I = ArgBegin; I != ArgEnd && ArgNo != FT->getNumParams(); + ++I, ++ArgNo) { + Value *Arg = *I; + if (Arg->getType() != FT->getParamType(ArgNo)) + Arg = new CastInst(Arg, FT->getParamType(ArgNo), Arg->getName(), CI); + Operands.push_back(Arg); + } + // Pass nulls into any additional arguments... + for (; ArgNo != FT->getNumParams(); ++ArgNo) + Operands.push_back(Constant::getNullValue(FT->getParamType(ArgNo))); + + std::string Name = CI->getName(); CI->setName(""); + if (FT->getReturnType() == Type::VoidTy) Name.clear(); + return new CallInst(FCache, Operands, Name, CI); +} + + void DefaultIntrinsicLowering::LowerIntrinsicCall(CallInst *CI) { Function *Callee = CI->getCalledFunction(); assert(Callee && "Cannot lower an indirect call!"); @@ -34,19 +77,43 @@ << Callee->getName() << "'!\n"; abort(); - // The default implementation of setjmp/longjmp transforms setjmp into a - // noop that always returns zero and longjmp into a call to abort. This - // allows code that never longjmps to work correctly. - case Intrinsic::setjmp: - case Intrinsic::sigsetjmp: + // The setjmp/longjmp intrinsics should only exist in the code if it was + // never optimized (ie, right out of the CFE), or if it has been hacked on + // by the lowerinvoke pass. In both cases, the right thing to do is to + // convert the call to an explicit setjmp or longjmp call. + case Intrinsic::setjmp: { + static Function *SetjmpFCache = 0; + Value *V = ReplaceCallWith("setjmp", CI, CI->op_begin()+1, CI->op_end(), + Type::IntTy, SetjmpFCache); if (CI->getType() != Type::VoidTy) - CI->replaceAllUsesWith(Constant::getNullValue(CI->getType())); + CI->replaceAllUsesWith(V); break; + } + case Intrinsic::sigsetjmp: + if (CI->getType() != Type::VoidTy) + CI->replaceAllUsesWith(Constant::getNullValue(CI->getType())); + break; case Intrinsic::longjmp: + static Function *LongjmpFCache = 0; + ReplaceCallWith("longjmp", CI, CI->op_begin()+1, CI->op_end(), + Type::VoidTy, LongjmpFCache); + break; + case Intrinsic::siglongjmp: // Insert the call to abort - new CallInst(M->getOrInsertFunction("abort", Type::VoidTy, 0), "", CI); + static Function *AbortFCache = 0; + ReplaceCallWith("abort", CI, CI->op_end(), CI->op_end(), Type::VoidTy, + AbortFCache); + break; + + case Intrinsic::returnaddress: + case Intrinsic::frameaddress: + std::cerr << "WARNING: this target does not support the llvm." + << (Callee->getIntrinsicID() == Intrinsic::returnaddress ? + "return" : "frame") << "address intrinsic.\n"; + CI->replaceAllUsesWith(ConstantPointerNull::get( + cast(CI->getType()))); break; case Intrinsic::dbg_stoppoint: @@ -62,8 +129,30 @@ // Insert the call to abort new CallInst(M->getOrInsertFunction("abort", Type::VoidTy, 0), "", CI); break; - } + case Intrinsic::memcpy: + // The memcpy intrinsic take an extra alignment argument that the memcpy + // libc function does not. + static Function *MemcpyFCache = 0; + ReplaceCallWith("memcpy", CI, CI->op_begin()+1, CI->op_end()-1, + (*(CI->op_begin()+1))->getType(), MemcpyFCache); + break; + case Intrinsic::memmove: + // The memmove intrinsic take an extra alignment argument that the memmove + // libc function does not. + static Function *MemmoveFCache = 0; + ReplaceCallWith("memmove", CI, CI->op_begin()+1, CI->op_end()-1, + (*(CI->op_begin()+1))->getType(), MemmoveFCache); + break; + case Intrinsic::memset: + // The memset intrinsic take an extra alignment argument that the memset + // libc function does not. + static Function *MemsetFCache = 0; + ReplaceCallWith("memset", CI, CI->op_begin()+1, CI->op_end()-1, + (*(CI->op_begin()+1))->getType(), MemsetFCache); + break; + } + assert(CI->use_empty() && "Lowering should have eliminated any uses of the intrinsic call!"); CI->getParent()->getInstList().erase(CI); Index: llvm/lib/VMCore/ModuleProvider.cpp diff -u llvm/lib/VMCore/ModuleProvider.cpp:1.8 llvm/lib/VMCore/ModuleProvider.cpp:1.8.4.1 --- llvm/lib/VMCore/ModuleProvider.cpp:1.8 Fri Nov 21 14:23:48 2003 +++ llvm/lib/VMCore/ModuleProvider.cpp Mon Mar 1 17:58:16 2004 @@ -24,15 +24,3 @@ ModuleProvider::~ModuleProvider() { delete TheModule; } - -/// materializeFunction - make sure the given function is fully read. -/// -Module* ModuleProvider::materializeModule() { - assert(TheModule && "Attempting to materialize an invalid module!"); - - for (Module::iterator i = TheModule->begin(), e = TheModule->end(); - i != e; ++i) - materializeFunction(i); - - return TheModule; -} Index: llvm/lib/VMCore/Pass.cpp diff -u llvm/lib/VMCore/Pass.cpp:1.54 llvm/lib/VMCore/Pass.cpp:1.54.4.1 --- llvm/lib/VMCore/Pass.cpp:1.54 Fri Nov 21 14:23:48 2003 +++ llvm/lib/VMCore/Pass.cpp Mon Mar 1 17:58:16 2004 @@ -91,8 +91,6 @@ void FunctionPassManager::add(FunctionPass *P) { PM->add(P); } void FunctionPassManager::add(ImmutablePass *IP) { PM->add(IP); } bool FunctionPassManager::run(Function &F) { - Function *mF = MP->getModule()->getNamedFunction(F.getName()); - assert((&F == mF) && "ModuleProvider does not contain this function!"); MP->materializeFunction(&F); return PM->run(F); } @@ -135,22 +133,31 @@ } void PMDebug::PrintPassInformation(unsigned Depth, const char *Action, - Pass *P, Annotable *V) { + Pass *P, Module *M) { if (PassDebugging >= Executions) { std::cerr << (void*)P << std::string(Depth*2+1, ' ') << Action << " '" << P->getPassName(); - if (V) { - std::cerr << "' on "; + if (M) std::cerr << "' on Module '" << M->getModuleIdentifier() << "'\n"; + std::cerr << "'...\n"; + } +} - if (dynamic_cast(V)) { - std::cerr << "Module\n"; return; - } else if (Function *F = dynamic_cast(V)) - std::cerr << "Function '" << F->getName(); - else if (BasicBlock *BB = dynamic_cast(V)) - std::cerr << "BasicBlock '" << BB->getName(); - else if (Value *Val = dynamic_cast(V)) - std::cerr << typeid(*Val).name() << " '" << Val->getName(); - } +void PMDebug::PrintPassInformation(unsigned Depth, const char *Action, + Pass *P, Function *F) { + if (PassDebugging >= Executions) { + std::cerr << (void*)P << std::string(Depth*2+1, ' ') << Action << " '" + << P->getPassName(); + if (F) std::cerr << "' on Function '" << F->getName(); + std::cerr << "'...\n"; + } +} + +void PMDebug::PrintPassInformation(unsigned Depth, const char *Action, + Pass *P, BasicBlock *BB) { + if (PassDebugging >= Executions) { + std::cerr << (void*)P << std::string(Depth*2+1, ' ') << Action << " '" + << P->getPassName(); + if (BB) std::cerr << "' on BasicBlock '" << BB->getName(); std::cerr << "'...\n"; } } @@ -184,7 +191,7 @@ std::cerr << std::string(Offset*2, ' ') << getPassName() << "\n"; } -// getPassName - Use C++ RTTI to get a SOMEWHAT intelligable name for the pass. +// getPassName - Use C++ RTTI to get a SOMEWHAT intelligible name for the pass. // const char *Pass::getPassName() const { if (const PassInfo *PI = getPassInfo()) Index: llvm/lib/VMCore/PassManagerT.h diff -u llvm/lib/VMCore/PassManagerT.h:1.46 llvm/lib/VMCore/PassManagerT.h:1.46.4.1 --- llvm/lib/VMCore/PassManagerT.h:1.46 Tue Nov 11 16:41:34 2003 +++ llvm/lib/VMCore/PassManagerT.h Mon Mar 1 17:58:16 2004 @@ -31,8 +31,6 @@ namespace llvm { -class Annotable; - //===----------------------------------------------------------------------===// // Pass debugging information. Often it is useful to find out what pass is // running when a crash occurs in a utility. When this library is compiled with @@ -75,7 +73,9 @@ } static void PrintArgumentInformation(const Pass *P); - static void PrintPassInformation(unsigned,const char*,Pass *, Annotable *); + static void PrintPassInformation(unsigned,const char*,Pass *, Module *); + static void PrintPassInformation(unsigned,const char*,Pass *, Function *); + static void PrintPassInformation(unsigned,const char*,Pass *, BasicBlock *); static void PrintAnalysisSetInfo(unsigned,const char*,Pass *P, const std::vector &); }; @@ -216,8 +216,7 @@ for (unsigned i = 0, e = Passes.size(); i < e; ++i) { PassClass *P = Passes[i]; - PMDebug::PrintPassInformation(getDepth(), "Executing Pass", P, - (Annotable*)M); + PMDebug::PrintPassInformation(getDepth(), "Executing Pass", P, M); // Get information about what analyses the pass uses... AnalysisUsage AnUsage; @@ -259,8 +258,7 @@ P->getPassName() + "'"); if (Changed) - PMDebug::PrintPassInformation(getDepth()+1, "Made Modification", P, - (Annotable*)M); + PMDebug::PrintPassInformation(getDepth()+1, "Made Modification", P, M); PMDebug::PrintAnalysisSetInfo(getDepth(), "Preserved", P, AnUsage.getPreservedSet()); @@ -301,8 +299,7 @@ std::vector &DeadPass = LastUserOf[P]; for (std::vector::iterator I = DeadPass.begin(),E = DeadPass.end(); I != E; ++I) { - PMDebug::PrintPassInformation(getDepth()+1, "Freeing Pass", *I, - (Annotable*)M); + PMDebug::PrintPassInformation(getDepth()+1, "Freeing Pass", *I, M); (*I)->releaseMemory(); } Index: llvm/lib/VMCore/SlotCalculator.cpp diff -u llvm/lib/VMCore/SlotCalculator.cpp:1.50 llvm/lib/VMCore/SlotCalculator.cpp:1.50.2.1 --- llvm/lib/VMCore/SlotCalculator.cpp:1.50 Tue Jan 20 13:50:23 2004 +++ llvm/lib/VMCore/SlotCalculator.cpp Mon Mar 1 17:58:16 2004 @@ -146,7 +146,8 @@ TypePlane &Plane = Table[plane]; unsigned FirstNonStringID = 0; for (unsigned i = 0, e = Plane.size(); i != e; ++i) - if (cast(Plane[i])->isString()) { + if (isa(Plane[i]) || + cast(Plane[i])->isString()) { // Check to see if we have to shuffle this string around. If not, // don't do anything. if (i != FirstNonStringID) { @@ -381,6 +382,8 @@ /// getOrCreateCompactionTableSlot - This method is used to build up the initial /// approximation of the compaction table. unsigned SlotCalculator::getOrCreateCompactionTableSlot(const Value *V) { + if (const ConstantPointerRef *CPR = dyn_cast(V)) + V = CPR->getValue(); std::map::iterator I = CompactionNodeMap.lower_bound(V); if (I != CompactionNodeMap.end() && I->first == V) Index: llvm/lib/VMCore/Type.cpp diff -u llvm/lib/VMCore/Type.cpp:1.87 llvm/lib/VMCore/Type.cpp:1.87.2.1 --- llvm/lib/VMCore/Type.cpp:1.87 Tue Dec 30 21:19:37 2003 +++ llvm/lib/VMCore/Type.cpp Mon Mar 1 17:58:16 2004 @@ -18,7 +18,6 @@ #include "Support/StringExtras.h" #include "Support/STLExtras.h" #include - using namespace llvm; // DEBUG_MERGE_TYPES - Enable this #define to see how and when derived types are @@ -27,6 +26,7 @@ // //#define DEBUG_MERGE_TYPES 1 +AbstractTypeUser::~AbstractTypeUser() {} //===----------------------------------------------------------------------===// // Type Class Implementation @@ -43,7 +43,7 @@ static std::map AbstractTypeDescriptions; Type::Type(const std::string &name, PrimitiveID id) - : Value(Type::TypeTy, Value::TypeVal), ForwardType(0) { + : Value(Type::TypeTy, Value::TypeVal), RefCount(0), ForwardType(0) { if (!name.empty()) ConcreteTypeDescriptions[this] = name; ID = id; @@ -190,15 +190,14 @@ case Type::FunctionTyID: { const FunctionType *FTy = cast(Ty); Result = getTypeDescription(FTy->getReturnType(), TypeStack) + " ("; - for (FunctionType::ParamTypes::const_iterator - I = FTy->getParamTypes().begin(), - E = FTy->getParamTypes().end(); I != E; ++I) { - if (I != FTy->getParamTypes().begin()) + for (FunctionType::param_iterator I = FTy->param_begin(), + E = FTy->param_end(); I != E; ++I) { + if (I != FTy->param_begin()) Result += ", "; Result += getTypeDescription(*I, TypeStack); } if (FTy->isVarArg()) { - if (!FTy->getParamTypes().empty()) Result += ", "; + if (FTy->getNumParams()) Result += ", "; Result += "..."; } Result += ")"; @@ -207,10 +206,9 @@ case Type::StructTyID: { const StructType *STy = cast(Ty); Result = "{ "; - for (StructType::ElementTypes::const_iterator - I = STy->getElementTypes().begin(), - E = STy->getElementTypes().end(); I != E; ++I) { - if (I != STy->getElementTypes().begin()) + for (StructType::element_iterator I = STy->element_begin(), + E = STy->element_end(); I != E; ++I) { + if (I != STy->element_begin()) Result += ", "; Result += getTypeDescription(*I, TypeStack); } @@ -263,7 +261,7 @@ bool StructType::indexValid(const Value *V) const { // Structure indexes require unsigned integer constants. if (const ConstantUInt *CU = dyn_cast(V)) - return CU->getValue() < ETypes.size(); + return CU->getValue() < ContainedTys.size(); return false; } @@ -273,9 +271,9 @@ const Type *StructType::getTypeAtIndex(const Value *V) const { assert(isa(V) && "Structure index must be a constant!!"); unsigned Idx = cast(V)->getValue(); - assert(Idx < ETypes.size() && "Structure index out of range!"); + assert(Idx < ContainedTys.size() && "Structure index out of range!"); assert(indexValid(V) && "Invalid structure index!"); // Duplicate check - return ETypes[Idx]; + return ContainedTys[Idx]; } @@ -360,12 +358,13 @@ FunctionType::FunctionType(const Type *Result, const std::vector &Params, bool IsVarArgs) : DerivedType(FunctionTyID), - ResultType(PATypeHandle(Result, this)), - isVarArgs(IsVarArgs) { + isVarArgs(IsVarArgs) { bool isAbstract = Result->isAbstract(); - ParamTys.reserve(Params.size()); - for (unsigned i = 0; i < Params.size(); ++i) { - ParamTys.push_back(PATypeHandle(Params[i], this)); + ContainedTys.reserve(Params.size()+1); + ContainedTys.push_back(PATypeHandle(Result, this)); + + for (unsigned i = 0; i != Params.size(); ++i) { + ContainedTys.push_back(PATypeHandle(Params[i], this)); isAbstract |= Params[i]->isAbstract(); } @@ -375,11 +374,11 @@ StructType::StructType(const std::vector &Types) : CompositeType(StructTyID) { - ETypes.reserve(Types.size()); + ContainedTys.reserve(Types.size()); bool isAbstract = false; for (unsigned i = 0; i < Types.size(); ++i) { assert(Types[i] != Type::VoidTy && "Void type in method prototype!!"); - ETypes.push_back(PATypeHandle(Types[i], this)); + ContainedTys.push_back(PATypeHandle(Types[i], this)); isAbstract |= Types[i]->isAbstract(); } @@ -407,44 +406,22 @@ #endif } - -// getAlwaysOpaqueTy - This function returns an opaque type. It doesn't matter -// _which_ opaque type it is, but the opaque type must never get resolved. -// -static Type *getAlwaysOpaqueTy() { - static Type *AlwaysOpaqueTy = OpaqueType::get(); - static PATypeHolder Holder(AlwaysOpaqueTy); - return AlwaysOpaqueTy; -} - - -//===----------------------------------------------------------------------===// -// dropAllTypeUses methods - These methods eliminate any possibly recursive type -// references from a derived type. The type must remain abstract, so we make -// sure to use an always opaque type as an argument. -// - -void FunctionType::dropAllTypeUses() { - ResultType = getAlwaysOpaqueTy(); - ParamTys.clear(); -} - -void ArrayType::dropAllTypeUses() { - ElementType = getAlwaysOpaqueTy(); -} - -void StructType::dropAllTypeUses() { - ETypes.clear(); - ETypes.push_back(PATypeHandle(getAlwaysOpaqueTy(), this)); -} - -void PointerType::dropAllTypeUses() { - ElementType = getAlwaysOpaqueTy(); +// dropAllTypeUses - When this (abstract) type is resolved to be equal to +// another (more concrete) type, we must eliminate all references to other +// types, to avoid some circular reference problems. +void DerivedType::dropAllTypeUses() { + if (!ContainedTys.empty()) { + while (ContainedTys.size() > 1) + ContainedTys.pop_back(); + + // The type must stay abstract. To do this, we insert a pointer to a type + // that will never get resolved, thus will always be abstract. + static Type *AlwaysOpaqueTy = OpaqueType::get(); + static PATypeHolder Holder(AlwaysOpaqueTy); + ContainedTys[0] = AlwaysOpaqueTy; + } } - - - // isTypeAbstract - This is a recursive function that walks a type hierarchy // calculating whether or not a type is abstract. Worst case it will have to do // a lot of traversing if you have some whacko opaque types, but in most cases, @@ -467,7 +444,7 @@ // one! for (Type::subtype_iterator I = subtype_begin(), E = subtype_end(); I != E; ++I) - if (const_cast(*I)->isTypeAbstract()) { + if (const_cast(I->get())->isTypeAbstract()) { setAbstract(true); // Restore the abstract bit. return true; // This type is abstract if subtype is abstract! } @@ -513,12 +490,10 @@ return TypesEqual(PTy->getElementType(), cast(Ty2)->getElementType(), EqTypes); } else if (const StructType *STy = dyn_cast(Ty)) { - const StructType::ElementTypes &STyE = STy->getElementTypes(); - const StructType::ElementTypes &STyE2 = - cast(Ty2)->getElementTypes(); - if (STyE.size() != STyE2.size()) return false; - for (unsigned i = 0, e = STyE.size(); i != e; ++i) - if (!TypesEqual(STyE[i], STyE2[i], EqTypes)) + const StructType *STy2 = cast(Ty2); + if (STy->getNumElements() != STy2->getNumElements()) return false; + for (unsigned i = 0, e = STy2->getNumElements(); i != e; ++i) + if (!TypesEqual(STy->getElementType(i), STy2->getElementType(i), EqTypes)) return false; return true; } else if (const ArrayType *ATy = dyn_cast(Ty)) { @@ -528,13 +503,11 @@ } else if (const FunctionType *FTy = dyn_cast(Ty)) { const FunctionType *FTy2 = cast(Ty2); if (FTy->isVarArg() != FTy2->isVarArg() || - FTy->getParamTypes().size() != FTy2->getParamTypes().size() || + FTy->getNumParams() != FTy2->getNumParams() || !TypesEqual(FTy->getReturnType(), FTy2->getReturnType(), EqTypes)) return false; - const FunctionType::ParamTypes &FTyP = FTy->getParamTypes(); - const FunctionType::ParamTypes &FTy2P = FTy2->getParamTypes(); - for (unsigned i = 0, e = FTyP.size(); i != e; ++i) - if (!TypesEqual(FTyP[i], FTy2P[i], EqTypes)) + for (unsigned i = 0, e = FTy2->getNumParams(); i != e; ++i) + if (!TypesEqual(FTy->getParamType(i), FTy2->getParamType(i), EqTypes)) return false; return true; } else { @@ -548,6 +521,38 @@ return TypesEqual(Ty, Ty2, EqTypes); } +// TypeHasCycleThrough - Return true there is a path from CurTy to TargetTy in +// the type graph. We know that Ty is an abstract type, so if we ever reach a +// non-abstract type, we know that we don't need to search the subgraph. +static bool TypeHasCycleThrough(const Type *TargetTy, const Type *CurTy, + std::set &VisitedTypes) { + if (TargetTy == CurTy) return true; + if (!CurTy->isAbstract()) return false; + + std::set::iterator VTI = VisitedTypes.lower_bound(CurTy); + if (VTI != VisitedTypes.end() && *VTI == CurTy) + return false; + VisitedTypes.insert(VTI, CurTy); + + for (Type::subtype_iterator I = CurTy->subtype_begin(), + E = CurTy->subtype_end(); I != E; ++I) + if (TypeHasCycleThrough(TargetTy, *I, VisitedTypes)) + return true; + return false; +} + + +/// TypeHasCycleThroughItself - Return true if the specified type has a cycle +/// back to itself. +static bool TypeHasCycleThroughItself(const Type *Ty) { + assert(Ty->isAbstract() && "This code assumes that Ty was abstract!"); + std::set VisitedTypes; + for (Type::subtype_iterator I = Ty->subtype_begin(), E = Ty->subtype_end(); + I != E; ++I) + if (TypeHasCycleThrough(Ty, *I, VisitedTypes)) + return true; + return false; +} //===----------------------------------------------------------------------===// @@ -556,15 +561,18 @@ // TypeMap - Make sure that only one instance of a particular type may be // created on any given run of the compiler... note that this involves updating -// our map if an abstract type gets refined somehow... +// our map if an abstract type gets refined somehow. // namespace llvm { template class TypeMap { - typedef std::map MapTy; - MapTy Map; + std::map Map; + + /// TypesByHash - Keep track of each type by its structure hash value. + /// + std::multimap TypesByHash; public: - typedef typename MapTy::iterator iterator; + typedef typename std::map::iterator iterator; ~TypeMap() { print("ON EXIT"); } inline TypeClass *get(const ValType &V) { @@ -572,58 +580,65 @@ return I != Map.end() ? cast((Type*)I->second.get()) : 0; } - inline void add(const ValType &V, TypeClass *T) { - Map.insert(std::make_pair(V, T)); + inline void add(const ValType &V, TypeClass *Ty) { + Map.insert(std::make_pair(V, Ty)); + + // If this type has a cycle, remember it. + TypesByHash.insert(std::make_pair(ValType::hashTypeStructure(Ty), Ty)); print("add"); } - iterator getEntryForType(TypeClass *Ty) { - iterator I = Map.find(ValType::get(Ty)); - if (I == Map.end()) print("ERROR!"); - assert(I != Map.end() && "Didn't find type entry!"); - assert(I->second.get() == (const Type*)Ty && "Type entry wrong?"); - return I; + void RemoveFromTypesByHash(unsigned Hash, const Type *Ty) { + std::multimap::iterator I = + TypesByHash.lower_bound(Hash); + while (I->second != Ty) { + ++I; + assert(I != TypesByHash.end() && I->first == Hash); + } + TypesByHash.erase(I); } /// finishRefinement - This method is called after we have updated an existing /// type with its new components. We must now either merge the type away with /// some other type or reinstall it in the map with it's new configuration. /// The specified iterator tells us what the type USED to look like. - void finishRefinement(iterator TyIt) { + void finishRefinement(TypeClass *Ty, const DerivedType *OldType, + const Type *NewType) { + assert((Ty->isAbstract() || !OldType->isAbstract()) && + "Refining a non-abstract type!"); +#ifdef DEBUG_MERGE_TYPES + std::cerr << "refineAbstractTy(" << (void*)OldType << "[" << *OldType + << "], " << (void*)NewType << " [" << *NewType << "])\n"; +#endif + // Make a temporary type holder for the type so that it doesn't disappear on // us when we erase the entry from the map. - PATypeHolder TyHolder = TyIt->second; - TypeClass *Ty = cast((Type*)TyHolder.get()); + PATypeHolder TyHolder = Ty; // The old record is now out-of-date, because one of the children has been // updated. Remove the obsolete entry from the map. - Map.erase(TyIt); + Map.erase(ValType::get(Ty)); - // Determine whether there is a cycle through the type graph which passes - // back through this type. Other cycles are ok though. - bool HasTypeCycle = false; - { - std::set VisitedTypes; - for (Type::subtype_iterator I = Ty->subtype_begin(), - E = Ty->subtype_end(); I != E; ++I) { - for (df_ext_iterator > - DFI = df_ext_begin(*I, VisitedTypes), - E = df_ext_end(*I, VisitedTypes); DFI != E; ++DFI) - if (*DFI == Ty) { - HasTypeCycle = true; - goto FoundCycle; - } + // Remember the structural hash for the type before we start hacking on it, + // in case we need it later. Also, check to see if the type HAD a cycle + // through it, if so, we know it will when we hack on it. + unsigned OldTypeHash = ValType::hashTypeStructure(Ty); + + // Find the type element we are refining... and change it now! + for (unsigned i = 0, e = Ty->ContainedTys.size(); i != e; ++i) + if (Ty->ContainedTys[i] == OldType) { + Ty->ContainedTys[i].removeUserFromConcrete(); + Ty->ContainedTys[i] = NewType; } - } - FoundCycle: - - ValType Key = ValType::get(Ty); + unsigned TypeHash = ValType::hashTypeStructure(Ty); + // If there are no cycles going through this node, we can do a simple, // efficient lookup in the map, instead of an inefficient nasty linear // lookup. - if (!HasTypeCycle) { - iterator I = Map.find(Key); + bool TypeHasCycle = Ty->isAbstract() && TypeHasCycleThroughItself(Ty); + if (!TypeHasCycle) { + iterator I = Map.find(ValType::get(Ty)); if (I != Map.end()) { // We already have this type in the table. Get rid of the newly refined // type. @@ -631,6 +646,7 @@ TypeClass *NewTy = cast((Type*)I->second.get()); // Refined to a different type altogether? + RemoveFromTypesByHash(TypeHash, Ty); Ty->refineAbstractTypeTo(NewTy); return; } @@ -640,20 +656,46 @@ // structurally identical to the newly refined type. If so, this type // gets refined to the pre-existing type. // - for (iterator I = Map.begin(), E = Map.end(); I != E; ++I) - if (TypesEqual(Ty, I->second)) { - assert(Ty->isAbstract() && "Replacing a non-abstract type?"); - TypeClass *NewTy = cast((Type*)I->second.get()); - - // Refined to a different type altogether? - Ty->refineAbstractTypeTo(NewTy); - return; + std::multimap::iterator I,E, Entry; + tie(I, E) = TypesByHash.equal_range(TypeHash); + Entry = E; + for (; I != E; ++I) { + if (I->second != Ty) { + if (TypesEqual(Ty, I->second)) { + assert(Ty->isAbstract() && "Replacing a non-abstract type?"); + TypeClass *NewTy = cast((Type*)I->second.get()); + + if (Entry == E) { + // Find the location of Ty in the TypesByHash structure. + while (I->second != Ty) { + ++I; + assert(I != E && "Structure doesn't contain type??"); + } + Entry = I; + } + + TypesByHash.erase(Entry); + Ty->refineAbstractTypeTo(NewTy); + return; + } + } else { + // Remember the position of + Entry = I; } + } + } + + // If we succeeded, we need to insert the type into the cycletypes table. + // There are several cases here, depending on whether the original type + // had the same hash code and was itself cyclic. + if (TypeHash != OldTypeHash) { + RemoveFromTypesByHash(OldTypeHash, Ty); + TypesByHash.insert(std::make_pair(TypeHash, Ty)); } // If there is no existing type of the same structure, we reinsert an // updated record into the map. - Map.insert(std::make_pair(Key, Ty)); + Map.insert(std::make_pair(ValType::get(Ty), Ty)); // If the type is currently thought to be abstract, rescan all of our // subtypes to see if the type has just become concrete! @@ -666,23 +708,12 @@ } } - void remove(const ValType &OldVal) { - iterator I = Map.find(OldVal); - assert(I != Map.end() && "TypeMap::remove, element not found!"); - Map.erase(I); - } - - void remove(iterator I) { - assert(I != Map.end() && "Cannot remove invalid iterator pointer!"); - Map.erase(I); - } - void print(const char *Arg) const { #ifdef DEBUG_MERGE_TYPES std::cerr << "TypeMap<>::" << Arg << " table contents:\n"; unsigned i = 0; - for (typename MapTy::const_iterator I = Map.begin(), E = Map.end(); - I != E; ++I) + for (typename std::map::const_iterator I + = Map.begin(), E = Map.end(); I != E; ++I) std::cerr << " " << (++i) << ". " << (void*)I->second.get() << " " << *I->second.get() << "\n"; #endif @@ -713,6 +744,10 @@ static FunctionValType get(const FunctionType *FT); + static unsigned hashTypeStructure(const FunctionType *FT) { + return FT->getNumParams()*2+FT->isVarArg(); + } + // Subclass should override this... to update self as usual void doRefinement(const DerivedType *OldType, const Type *NewType) { if (RetTy == OldType) RetTy = NewType; @@ -736,8 +771,8 @@ FunctionValType FunctionValType::get(const FunctionType *FT) { // Build up a FunctionValType std::vector ParamTypes; - ParamTypes.reserve(FT->getParamTypes().size()); - for (unsigned i = 0, e = FT->getParamTypes().size(); i != e; ++i) + ParamTypes.reserve(FT->getNumParams()); + for (unsigned i = 0, e = FT->getNumParams(); i != e; ++i) ParamTypes.push_back(FT->getParamType(i)); return FunctionValType(FT->getReturnType(), ParamTypes, FT->isVarArg()); } @@ -773,6 +808,10 @@ return ArrayValType(AT->getElementType(), AT->getNumElements()); } + static unsigned hashTypeStructure(const ArrayType *AT) { + return AT->getNumElements(); + } + // Subclass should override this... to update self as usual void doRefinement(const DerivedType *OldType, const Type *NewType) { assert(ValTy == OldType); @@ -818,13 +857,17 @@ static StructValType get(const StructType *ST) { std::vector ElTypes; - ElTypes.reserve(ST->getElementTypes().size()); - for (unsigned i = 0, e = ST->getElementTypes().size(); i != e; ++i) - ElTypes.push_back(ST->getElementTypes()[i]); + ElTypes.reserve(ST->getNumElements()); + for (unsigned i = 0, e = ST->getNumElements(); i != e; ++i) + ElTypes.push_back(ST->getElementType(i)); return StructValType(ElTypes); } + static unsigned hashTypeStructure(const StructType *ST) { + return ST->getNumElements(); + } + // Subclass should override this... to update self as usual void doRefinement(const DerivedType *OldType, const Type *NewType) { for (unsigned i = 0; i < ElTypes.size(); ++i) @@ -871,6 +914,10 @@ return PointerValType(PT->getElementType()); } + static unsigned hashTypeStructure(const PointerType *PT) { + return 0; + } + // Subclass should override this... to update self as usual void doRefinement(const DerivedType *OldType, const Type *NewType) { assert(ValTy == OldType); @@ -901,14 +948,6 @@ return PT; } -namespace llvm { -void debug_type_tables() { - FunctionTypes.dump(); - ArrayTypes.dump(); - StructTypes.dump(); - PointerTypes.dump(); -} -} //===----------------------------------------------------------------------===// // Derived Type Refinement Functions @@ -938,7 +977,7 @@ << *this << "][" << i << "] User = " << U << "\n"; #endif - if (AbstractTypeUsers.empty() && RefCount == 0 && isAbstract()) { + if (AbstractTypeUsers.empty() && getRefCount() == 0 && isAbstract()) { #ifdef DEBUG_MERGE_TYPES std::cerr << "DELETEing unused abstract type: <" << *this << ">[" << (void*)this << "]" << "\n"; @@ -1044,30 +1083,7 @@ // void FunctionType::refineAbstractType(const DerivedType *OldType, const Type *NewType) { - assert((isAbstract() || !OldType->isAbstract()) && - "Refining a non-abstract type!"); -#ifdef DEBUG_MERGE_TYPES - std::cerr << "FunctionTy::refineAbstractTy(" << (void*)OldType << "[" - << *OldType << "], " << (void*)NewType << " [" - << *NewType << "])\n"; -#endif - - // Look up our current type map entry.. - TypeMap::iterator TMI = - FunctionTypes.getEntryForType(this); - - // Find the type element we are refining... - if (ResultType == OldType) { - ResultType.removeUserFromConcrete(); - ResultType = NewType; - } - for (unsigned i = 0, e = ParamTys.size(); i != e; ++i) - if (ParamTys[i] == OldType) { - ParamTys[i].removeUserFromConcrete(); - ParamTys[i] = NewType; - } - - FunctionTypes.finishRefinement(TMI); + FunctionTypes.finishRefinement(this, OldType, NewType); } void FunctionType::typeBecameConcrete(const DerivedType *AbsTy) { @@ -1081,23 +1097,7 @@ // void ArrayType::refineAbstractType(const DerivedType *OldType, const Type *NewType) { - assert((isAbstract() || !OldType->isAbstract()) && - "Refining a non-abstract type!"); -#ifdef DEBUG_MERGE_TYPES - std::cerr << "ArrayTy::refineAbstractTy(" << (void*)OldType << "[" - << *OldType << "], " << (void*)NewType << " [" - << *NewType << "])\n"; -#endif - - // Look up our current type map entry.. - TypeMap::iterator TMI = - ArrayTypes.getEntryForType(this); - - assert(getElementType() == OldType); - ElementType.removeUserFromConcrete(); - ElementType = NewType; - - ArrayTypes.finishRefinement(TMI); + ArrayTypes.finishRefinement(this, OldType, NewType); } void ArrayType::typeBecameConcrete(const DerivedType *AbsTy) { @@ -1111,27 +1111,7 @@ // void StructType::refineAbstractType(const DerivedType *OldType, const Type *NewType) { - assert((isAbstract() || !OldType->isAbstract()) && - "Refining a non-abstract type!"); -#ifdef DEBUG_MERGE_TYPES - std::cerr << "StructTy::refineAbstractTy(" << (void*)OldType << "[" - << *OldType << "], " << (void*)NewType << " [" - << *NewType << "])\n"; -#endif - - // Look up our current type map entry.. - TypeMap::iterator TMI = - StructTypes.getEntryForType(this); - - for (int i = ETypes.size()-1; i >= 0; --i) - if (ETypes[i] == OldType) { - ETypes[i].removeUserFromConcrete(); - - // Update old type to new type in the array... - ETypes[i] = NewType; - } - - StructTypes.finishRefinement(TMI); + StructTypes.finishRefinement(this, OldType, NewType); } void StructType::typeBecameConcrete(const DerivedType *AbsTy) { @@ -1144,23 +1124,7 @@ // void PointerType::refineAbstractType(const DerivedType *OldType, const Type *NewType) { - assert((isAbstract() || !OldType->isAbstract()) && - "Refining a non-abstract type!"); -#ifdef DEBUG_MERGE_TYPES - std::cerr << "PointerTy::refineAbstractTy(" << (void*)OldType << "[" - << *OldType << "], " << (void*)NewType << " [" - << *NewType << "])\n"; -#endif - - // Look up our current type map entry.. - TypeMap::iterator TMI = - PointerTypes.getEntryForType(this); - - assert(ElementType == OldType); - ElementType.removeUserFromConcrete(); - ElementType = NewType; - - PointerTypes.finishRefinement(TMI); + PointerTypes.finishRefinement(this, OldType, NewType); } void PointerType::typeBecameConcrete(const DerivedType *AbsTy) { Index: llvm/lib/VMCore/Verifier.cpp diff -u llvm/lib/VMCore/Verifier.cpp:1.78.2.2 llvm/lib/VMCore/Verifier.cpp:1.78.2.3 --- llvm/lib/VMCore/Verifier.cpp:1.78.2.2 Sat Feb 7 17:55:02 2004 +++ llvm/lib/VMCore/Verifier.cpp Mon Mar 1 17:58:16 2004 @@ -41,17 +41,14 @@ #include "llvm/Analysis/Verifier.h" #include "llvm/Assembly/Writer.h" +#include "llvm/Constants.h" #include "llvm/Pass.h" #include "llvm/Module.h" #include "llvm/DerivedTypes.h" -#include "llvm/iPHINode.h" -#include "llvm/iTerminators.h" -#include "llvm/iOther.h" -#include "llvm/iOperators.h" -#include "llvm/iMemory.h" -#include "llvm/SymbolTable.h" -#include "llvm/PassManager.h" +#include "llvm/Instructions.h" #include "llvm/Intrinsics.h" +#include "llvm/PassManager.h" +#include "llvm/SymbolTable.h" #include "llvm/Analysis/Dominators.h" #include "llvm/Support/CFG.h" #include "llvm/Support/InstVisitor.h" @@ -389,9 +386,9 @@ // Verify that all arguments to the call match the function type... for (unsigned i = 0, e = FTy->getNumParams(); i != e; ++i) - Assert2(CI.getOperand(i+1)->getType() == FTy->getParamType(i), + Assert3(CI.getOperand(i+1)->getType() == FTy->getParamType(i), "Call parameter type does not match function signature!", - CI.getOperand(i+1), FTy->getParamType(i)); + CI.getOperand(i+1), FTy->getParamType(i), &CI); if (Function *F = CI.getCalledFunction()) if (Intrinsic::ID ID = (Intrinsic::ID)F->getIntrinsicID()) @@ -477,7 +474,8 @@ if (!isa(I)) { // Check that non-phi nodes are not self referential for (Value::use_iterator UI = I.use_begin(), UE = I.use_end(); UI != UE; ++UI) - Assert1(*UI != (User*)&I, + Assert1(*UI != (User*)&I || + !DS->dominates(&BB->getParent()->getEntryBlock(), BB), "Only PHI nodes may reference their own value!", &I); } @@ -551,6 +549,16 @@ case Intrinsic::va_end: NumArgs = 1; break; case Intrinsic::va_copy: NumArgs = 1; break; + case Intrinsic::returnaddress: + case Intrinsic::frameaddress: + Assert1(isa(FT->getReturnType()), + "llvm.(frame|return)address must return pointers", IF); + Assert1(FT->getNumParams() == 1 && isa(CI.getOperand(1)), + "llvm.(frame|return)address require a single constant integer argument", + &CI); + NumArgs = 1; + break; + case Intrinsic::setjmp: NumArgs = 1; break; case Intrinsic::longjmp: NumArgs = 2; break; case Intrinsic::sigsetjmp: NumArgs = 2; break; @@ -564,6 +572,10 @@ // Join takes a single parameter which is returned by pbr case Intrinsic::join: NumArgs = 1; break; + + case Intrinsic::memcpy: NumArgs = 4; break; + case Intrinsic::memmove: NumArgs = 4; break; + case Intrinsic::memset: NumArgs = 4; break; case Intrinsic::alpha_ctlz: NumArgs = 1; break; case Intrinsic::alpha_cttz: NumArgs = 1; break; Index: llvm/lib/VMCore/iCall.cpp diff -u llvm/lib/VMCore/iCall.cpp:1.22 llvm/lib/VMCore/iCall.cpp:1.22.4.1 --- llvm/lib/VMCore/iCall.cpp:1.22 Thu Nov 20 11:45:12 2003 +++ llvm/lib/VMCore/iCall.cpp Mon Mar 1 17:58:16 2004 @@ -31,14 +31,13 @@ Operands.reserve(1+params.size()); Operands.push_back(Use(Func, this)); - const FunctionType *MTy = + const FunctionType *FTy = cast(cast(Func->getType())->getElementType()); - const FunctionType::ParamTypes &PL = MTy->getParamTypes(); - assert(params.size() == PL.size() || - (MTy->isVarArg() && params.size() > PL.size()) && + assert((params.size() == FTy->getNumParams() || + (FTy->isVarArg() && params.size() > FTy->getNumParams())) && "Calling a function with bad signature"); - for (unsigned i = 0; i < params.size(); i++) + for (unsigned i = 0; i != params.size(); i++) Operands.push_back(Use(params[i], this)); } @@ -53,8 +52,7 @@ const FunctionType *MTy = cast(cast(Func->getType())->getElementType()); - const FunctionType::ParamTypes &PL = MTy->getParamTypes(); - assert(PL.empty() && "Calling a function with bad signature"); + assert(MTy->getNumParams() == 0 && "Calling a function with bad signature"); } CallInst::CallInst(Value *Func, Value* A, const std::string &Name, @@ -68,8 +66,8 @@ const FunctionType *MTy = cast(cast(Func->getType())->getElementType()); - const FunctionType::ParamTypes &PL = MTy->getParamTypes(); - assert(PL.size() == 1 || (MTy->isVarArg() && PL.empty()) && + assert((MTy->getNumParams() == 1 || + (MTy->isVarArg() && MTy->getNumParams() == 0)) && "Calling a function with bad signature"); Operands.push_back(Use(A, this)); } @@ -115,9 +113,8 @@ const FunctionType *MTy = cast(cast(Func->getType())->getElementType()); - const FunctionType::ParamTypes &PL = MTy->getParamTypes(); - assert((params.size() == PL.size()) || - (MTy->isVarArg() && params.size() > PL.size()) && + assert((params.size() == MTy->getNumParams()) || + (MTy->isVarArg() && params.size() > MTy->getNumParams()) && "Calling a function with bad signature"); for (unsigned i = 0; i < params.size(); i++) @@ -138,9 +135,8 @@ const FunctionType *MTy = cast(cast(Func->getType())->getElementType()); - const FunctionType::ParamTypes &PL = MTy->getParamTypes(); - assert((params.size() == PL.size()) || - (MTy->isVarArg() && params.size() > PL.size()) && + assert((params.size() == MTy->getNumParams()) || + (MTy->isVarArg() && params.size() > MTy->getNumParams()) && "Calling a function with bad signature"); for (unsigned i = 0; i < params.size(); i++) Index: llvm/lib/VMCore/iOperators.cpp diff -u llvm/lib/VMCore/iOperators.cpp:1.25 llvm/lib/VMCore/iOperators.cpp:1.25.4.1 --- llvm/lib/VMCore/iOperators.cpp:1.25 Thu Nov 20 11:45:12 2003 +++ llvm/lib/VMCore/iOperators.cpp Mon Mar 1 17:58:16 2004 @@ -78,9 +78,14 @@ BinaryOperator *BinaryOperator::createNeg(Value *Op, const std::string &Name, Instruction *InsertBefore) { - return new BinaryOperator(Instruction::Sub, - Constant::getNullValue(Op->getType()), Op, - Op->getType(), Name, InsertBefore); + if (!Op->getType()->isFloatingPoint()) + return new BinaryOperator(Instruction::Sub, + Constant::getNullValue(Op->getType()), Op, + Op->getType(), Name, InsertBefore); + else + return new BinaryOperator(Instruction::Sub, + ConstantFP::get(Op->getType(), -0.0), Op, + Op->getType(), Name, InsertBefore); } BinaryOperator *BinaryOperator::createNot(Value *Op, const std::string &Name, @@ -98,8 +103,11 @@ bool BinaryOperator::isNeg(const Value *V) { if (const BinaryOperator *Bop = dyn_cast(V)) - return Bop->getOpcode() == Instruction::Sub && - Bop->getOperand(0) == Constant::getNullValue(Bop->getType()); + if (Bop->getOpcode() == Instruction::Sub) + if (!V->getType()->isFloatingPoint()) + return Bop->getOperand(0) == Constant::getNullValue(Bop->getType()); + else + return Bop->getOperand(0) == ConstantFP::get(Bop->getType(), -0.0); return false; } From brukman at cs.uiuc.edu Mon Mar 1 18:04:57 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Mar 1 18:04:57 2004 Subject: [llvm-commits] [parallel] CVS: llvm/lib/Analysis/DataStructure/BottomUpClosure.cpp CompleteBottomUp.cpp DataStructure.cpp DataStructureAA.cpp GraphChecker.cpp Local.cpp Printer.cpp Steensgaard.cpp TopDownClosure.cpp Message-ID: <200403012358.RAA03933@zion.cs.uiuc.edu> Changes in directory llvm/lib/Analysis/DataStructure: BottomUpClosure.cpp updated: 1.70 -> 1.70.4.1 CompleteBottomUp.cpp updated: 1.3 -> 1.3.4.1 DataStructure.cpp updated: 1.131 -> 1.131.4.1 DataStructureAA.cpp updated: 1.13 -> 1.13.4.1 GraphChecker.cpp updated: 1.10 -> 1.10.4.1 Local.cpp updated: 1.74 -> 1.74.4.1 Printer.cpp updated: 1.62 -> 1.62.4.1 Steensgaard.cpp updated: 1.35 -> 1.35.4.1 TopDownClosure.cpp updated: 1.60 -> 1.60.4.1 --- Log message: Merge from trunk --- Diffs of the changes: (+1053 -544) Index: llvm/lib/Analysis/DataStructure/BottomUpClosure.cpp diff -u llvm/lib/Analysis/DataStructure/BottomUpClosure.cpp:1.70 llvm/lib/Analysis/DataStructure/BottomUpClosure.cpp:1.70.4.1 --- llvm/lib/Analysis/DataStructure/BottomUpClosure.cpp:1.70 Wed Nov 12 23:04:19 2003 +++ llvm/lib/Analysis/DataStructure/BottomUpClosure.cpp Mon Mar 1 17:58:12 2004 @@ -63,6 +63,7 @@ // nodes at the end of the BU phase should make things that they point to // incomplete in the globals graph. // + GlobalsGraph->removeTriviallyDeadNodes(); GlobalsGraph->maskIncompleteMarkers(); return false; } @@ -152,7 +153,7 @@ } else { // SCCFunctions - Keep track of the functions in the current SCC // - hash_set SCCFunctions; + hash_set SCCGraphs; Function *NF; std::vector::iterator FirstInSCC = Stack.end(); @@ -160,42 +161,44 @@ do { NF = *--FirstInSCC; ValMap[NF] = ~0U; - SCCFunctions.insert(NF); // Figure out which graph is the largest one, in order to speed things up // a bit in situations where functions in the SCC have widely different // graph sizes. DSGraph &NFGraph = getDSGraph(*NF); + SCCGraphs.insert(&NFGraph); if (!SCCGraph || SCCGraph->getGraphSize() < NFGraph.getGraphSize()) SCCGraph = &NFGraph; } while (NF != F); std::cerr << "Calculating graph for SCC #: " << MyID << " of size: " - << SCCFunctions.size() << "\n"; + << SCCGraphs.size() << "\n"; // Compute the Max SCC Size... - if (MaxSCC < SCCFunctions.size()) - MaxSCC = SCCFunctions.size(); + if (MaxSCC < SCCGraphs.size()) + MaxSCC = SCCGraphs.size(); // First thing first, collapse all of the DSGraphs into a single graph for // the entire SCC. We computed the largest graph, so clone all of the other // (smaller) graphs into it. Discard all of the old graphs. // - for (hash_set::iterator I = SCCFunctions.begin(), - E = SCCFunctions.end(); I != E; ++I) { - DSGraph &G = getDSGraph(**I); + for (hash_set::iterator I = SCCGraphs.begin(), + E = SCCGraphs.end(); I != E; ++I) { + DSGraph &G = **I; if (&G != SCCGraph) { DSGraph::NodeMapTy NodeMap; SCCGraph->cloneInto(G, SCCGraph->getScalarMap(), - SCCGraph->getReturnNodes(), NodeMap, 0); + SCCGraph->getReturnNodes(), NodeMap); // Update the DSInfo map and delete the old graph... - DSInfo[*I] = SCCGraph; + for (DSGraph::ReturnNodesTy::iterator I = G.getReturnNodes().begin(), + E = G.getReturnNodes().end(); I != E; ++I) + DSInfo[I->first] = SCCGraph; delete &G; } } // Clean up the graph before we start inlining a bunch again... - SCCGraph->removeTriviallyDeadNodes(); + SCCGraph->removeDeadNodes(DSGraph::RemoveUnreachableGlobals); // Now that we have one big happy family, resolve all of the call sites in // the graph... @@ -276,13 +279,15 @@ // DSGraph &GI = getDSGraph(*Callee); // Graph to inline + if (Callee->getName() == "bc_raise") + std::cerr << "HERE!\n"; + DEBUG(std::cerr << " Inlining graph for " << Callee->getName() << "[" << GI.getGraphSize() << "+" << GI.getAuxFunctionCalls().size() << "] into '" << Graph.getFunctionNames() << "' [" << Graph.getGraphSize() << "+" << Graph.getAuxFunctionCalls().size() << "]\n"); - // Handle self recursion by resolving the arguments and return value Graph.mergeInGraph(CS, *Callee, GI, DSGraph::KeepModRefBits | DSGraph::StripAllocaBit | DSGraph::DontCloneCallNodes); @@ -301,18 +306,25 @@ TempFCs.clear(); - // Re-materialize nodes from the globals graph. - // Do not ignore globals inlined from callees -- they are not up-to-date! - Graph.getInlinedGlobals().clear(); - Graph.updateFromGlobalGraph(); - // Recompute the Incomplete markers + assert(Graph.getInlinedGlobals().empty()); Graph.maskIncompleteMarkers(); Graph.markIncompleteNodes(DSGraph::MarkFormalArgs); // Delete dead nodes. Treat globals that are unreachable but that can // reach live nodes as live. Graph.removeDeadNodes(DSGraph::KeepUnreachableGlobals); + + // When this graph is finalized, clone the globals in the graph into the + // globals graph to make sure it has everything, from all graphs. + DSScalarMap &MainSM = Graph.getScalarMap(); + ReachabilityCloner RC(*GlobalsGraph, Graph, DSGraph::StripAllocaBit); + + // Clone everything reachable from globals in the "main" graph into the + // globals graph. + for (DSScalarMap::global_iterator I = MainSM.global_begin(), + E = MainSM.global_end(); I != E; ++I) + RC.getClonedNH(MainSM[*I]); //Graph.writeGraphToFile(std::cerr, "bu_" + F.getName()); } Index: llvm/lib/Analysis/DataStructure/CompleteBottomUp.cpp diff -u llvm/lib/Analysis/DataStructure/CompleteBottomUp.cpp:1.3 llvm/lib/Analysis/DataStructure/CompleteBottomUp.cpp:1.3.4.1 --- llvm/lib/Analysis/DataStructure/CompleteBottomUp.cpp:1.3 Thu Nov 13 12:48:11 2003 +++ llvm/lib/Analysis/DataStructure/CompleteBottomUp.cpp Mon Mar 1 17:58:12 2004 @@ -77,6 +77,7 @@ if (!I->isExternal() && !DSInfo.count(I)) calculateSCCGraphs(getOrCreateGraph(*I), Stack, NextID, ValMap); + GlobalsGraph->removeTriviallyDeadNodes(); return false; } @@ -141,7 +142,7 @@ ValMap[NG] = ~0U; DSGraph::NodeMapTy NodeMap; - FG.cloneInto(*NG, FG.getScalarMap(), FG.getReturnNodes(), NodeMap, 0); + FG.cloneInto(*NG, FG.getScalarMap(), FG.getReturnNodes(), NodeMap); // Update the DSInfo map and delete the old graph... for (DSGraph::ReturnNodesTy::iterator I = NG->getReturnNodes().begin(); @@ -167,6 +168,7 @@ /// processGraph - Process the BU graphs for the program in bottom-up order on /// the SCC of the __ACTUAL__ call graph. This builds "complete" BU graphs. void CompleteBUDataStructures::processGraph(DSGraph &G) { + // The edges out of the current node are the call site targets... for (unsigned i = 0, e = G.getFunctionCalls().size(); i != e; ++i) { const DSCallSite &CS = G.getFunctionCalls()[i]; @@ -191,12 +193,8 @@ } } - // Re-materialize nodes from the globals graph. - // Do not ignore globals inlined from callees -- they are not up-to-date! - G.getInlinedGlobals().clear(); - G.updateFromGlobalGraph(); - // Recompute the Incomplete markers + assert(G.getInlinedGlobals().empty()); G.maskIncompleteMarkers(); G.markIncompleteNodes(DSGraph::MarkFormalArgs); Index: llvm/lib/Analysis/DataStructure/DataStructure.cpp diff -u llvm/lib/Analysis/DataStructure/DataStructure.cpp:1.131 llvm/lib/Analysis/DataStructure/DataStructure.cpp:1.131.4.1 --- llvm/lib/Analysis/DataStructure/DataStructure.cpp:1.131 Wed Nov 12 17:11:14 2003 +++ llvm/lib/Analysis/DataStructure/DataStructure.cpp Mon Mar 1 17:58:12 2004 @@ -13,10 +13,12 @@ #include "llvm/Analysis/DSGraph.h" #include "llvm/Function.h" +#include "llvm/GlobalVariable.h" #include "llvm/iOther.h" #include "llvm/DerivedTypes.h" #include "llvm/Target/TargetData.h" #include "llvm/Assembly/Writer.h" +#include "Support/CommandLine.h" #include "Support/Debug.h" #include "Support/STLExtras.h" #include "Support/Statistic.h" @@ -25,14 +27,25 @@ using namespace llvm; namespace { - Statistic<> NumFolds ("dsnode", "Number of nodes completely folded"); - Statistic<> NumCallNodesMerged("dsnode", "Number of call nodes merged"); + Statistic<> NumFolds ("dsa", "Number of nodes completely folded"); + Statistic<> NumCallNodesMerged("dsa", "Number of call nodes merged"); + Statistic<> NumNodeAllocated ("dsa", "Number of nodes allocated"); + Statistic<> NumDNE ("dsa", "Number of nodes removed by reachability"); + Statistic<> NumTrivialDNE ("dsa", "Number of nodes trivially removed"); + Statistic<> NumTrivialGlobalDNE("dsa", "Number of globals trivially removed"); }; +#if 1 +#define TIME_REGION(VARNAME, DESC) \ + NamedRegionTimer VARNAME(DESC) +#else +#define TIME_REGION(VARNAME, DESC) +#endif + using namespace DS; DSNode *DSNodeHandle::HandleForwarding() const { - assert(!N->ForwardNH.isNull() && "Can only be invoked if forwarding!"); + assert(N->isForwarding() && "Can only be invoked if forwarding!"); // Handle node forwarding here! DSNode *Next = N->ForwardNH.getNode(); // Cause recursive shrinkage @@ -60,14 +73,20 @@ : NumReferrers(0), Size(0), ParentGraph(G), Ty(Type::VoidTy), NodeType(0) { // Add the type entry if it is specified... if (T) mergeTypeInfo(T, 0); - G->getNodes().push_back(this); + if (G) G->addNode(this); + ++NumNodeAllocated; } // DSNode copy constructor... do not copy over the referrers list! -DSNode::DSNode(const DSNode &N, DSGraph *G) +DSNode::DSNode(const DSNode &N, DSGraph *G, bool NullLinks) : NumReferrers(0), Size(N.Size), ParentGraph(G), - Ty(N.Ty), Links(N.Links), Globals(N.Globals), NodeType(N.NodeType) { - G->getNodes().push_back(this); + Ty(N.Ty), Globals(N.Globals), NodeType(N.NodeType) { + if (!NullLinks) + Links = N.Links; + else + Links.resize(N.Links.size()); // Create the appropriate number of null links + G->addNode(this); + ++NumNodeAllocated; } /// getTargetData - Get the target data object used to construct this node. @@ -83,9 +102,9 @@ "Node not OK!"); assert(ParentGraph && "Node has no parent?"); - const DSGraph::ScalarMapTy &SM = ParentGraph->getScalarMap(); + const DSScalarMap &SM = ParentGraph->getScalarMap(); for (unsigned i = 0, e = Globals.size(); i != e; ++i) { - assert(SM.find(Globals[i]) != SM.end()); + assert(SM.count(Globals[i])); assert(SM.find(Globals[i])->second.getNode() == this); } } @@ -104,6 +123,10 @@ NodeType = DEAD; Size = 0; Ty = Type::VoidTy; + + // Remove this node from the parent graph's Nodes list. + ParentGraph->unlinkNode(this); + ParentGraph = 0; } // addGlobal - Add an entry for a global value to the Globals list. This also @@ -131,26 +154,40 @@ ++NumFolds; - // Create the node we are going to forward to... - DSNode *DestNode = new DSNode(0, ParentGraph); - DestNode->NodeType = NodeType|DSNode::Array; - DestNode->Ty = Type::VoidTy; - DestNode->Size = 1; - DestNode->Globals.swap(Globals); - - // Start forwarding to the destination node... - forwardNode(DestNode, 0); - - if (Links.size()) { - DestNode->Links.push_back(Links[0]); - DSNodeHandle NH(DestNode); - - // If we have links, merge all of our outgoing links together... - for (unsigned i = Links.size()-1; i != 0; --i) - NH.getNode()->Links[0].mergeWith(Links[i]); - Links.clear(); + // If this node has a size that is <= 1, we don't need to create a forwarding + // node. + if (getSize() <= 1) { + NodeType |= DSNode::Array; + Ty = Type::VoidTy; + Size = 1; + assert(Links.size() <= 1 && "Size is 1, but has more links?"); + Links.resize(1); } else { - DestNode->Links.resize(1); + // Create the node we are going to forward to. This is required because + // some referrers may have an offset that is > 0. By forcing them to + // forward, the forwarder has the opportunity to correct the offset. + DSNode *DestNode = new DSNode(0, ParentGraph); + DestNode->NodeType = NodeType|DSNode::Array; + DestNode->Ty = Type::VoidTy; + DestNode->Size = 1; + DestNode->Globals.swap(Globals); + + // Start forwarding to the destination node... + forwardNode(DestNode, 0); + + if (!Links.empty()) { + DestNode->Links.reserve(1); + + DSNodeHandle NH(DestNode); + DestNode->Links.push_back(Links[0]); + + // If we have links, merge all of our outgoing links together... + for (unsigned i = Links.size()-1; i != 0; --i) + NH.getNode()->Links[0].mergeWith(Links[i]); + Links.clear(); + } else { + DestNode->Links.resize(1); + } } } @@ -201,7 +238,7 @@ StackState &SS = Stack.back(); if (const StructType *ST = dyn_cast(SS.Ty)) { ++SS.Idx; - if (SS.Idx != ST->getElementTypes().size()) { + if (SS.Idx != ST->getNumElements()) { const StructLayout *SL = TD.getStructLayout(ST); SS.Offset += SL->MemberOffsets[SS.Idx]-SL->MemberOffsets[SS.Idx-1]; return; @@ -226,14 +263,14 @@ while (!Stack.empty() && !Stack.back().Ty->isFirstClassType()) { StackState &SS = Stack.back(); if (const StructType *ST = dyn_cast(SS.Ty)) { - if (ST->getElementTypes().empty()) { + if (ST->getNumElements() == 0) { assert(SS.Idx == 0); PopStackAndAdvance(); } else { // Step into the structure... - assert(SS.Idx < ST->getElementTypes().size()); + assert(SS.Idx < ST->getNumElements()); const StructLayout *SL = TD.getStructLayout(ST); - Stack.push_back(StackState(ST->getElementTypes()[SS.Idx], + Stack.push_back(StackState(ST->getElementType(SS.Idx), SS.Offset+SL->MemberOffsets[SS.Idx])); } } else { @@ -403,7 +440,7 @@ /* empty */; // The offset we are looking for must be in the i'th element... - SubType = STy->getElementTypes()[i]; + SubType = STy->getElementType(i); O += SL.MemberOffsets[i]; break; } @@ -425,6 +462,10 @@ // If we found our type exactly, early exit if (SubType == NewTy) return false; + // Differing function types don't require us to merge. They are not values anyway. + if (isa(SubType) && + isa(NewTy)) return false; + unsigned SubTypeSize = SubType->isSized() ? TD.getTypeSize(SubType) : 0; // Ok, we are getting desperate now. Check for physical subtyping, where we @@ -452,7 +493,7 @@ NextPadSize = SL.MemberOffsets[1]; else NextPadSize = SubTypeSize; - NextSubType = STy->getElementTypes()[0]; + NextSubType = STy->getElementType(0); NextSubTypeSize = TD.getTypeSize(NextSubType); break; } @@ -516,10 +557,10 @@ // can cause merging of nodes in the graph. // void DSNode::addEdgeTo(unsigned Offset, const DSNodeHandle &NH) { - if (NH.getNode() == 0) return; // Nothing to do + if (NH.isNull()) return; // Nothing to do DSNodeHandle &ExistingEdge = getLink(Offset); - if (ExistingEdge.getNode()) { + if (!ExistingEdge.isNull()) { // Merge the two nodes... ExistingEdge.mergeWith(NH); } else { // No merging to perform... @@ -571,8 +612,11 @@ } } +void DSNode::mergeGlobals(const std::vector &RHS) { + MergeSortedVectors(Globals, RHS); +} -// MergeNodes() - Helper function for DSNode::mergeWith(). +// MergeNodes - Helper function for DSNode::mergeWith(). // This function does the hard work of merging two nodes, CurNodeH // and NH after filtering out trivial cases and making sure that // CurNodeH.offset >= NH.offset. @@ -635,7 +679,7 @@ if (CurNodeH.getNode() == N || N == 0) return; assert(!CurNodeH.getNode()->isDeadNode()); - // Merge the NodeType information... + // Merge the NodeType information. CurNodeH.getNode()->NodeType |= N->NodeType; // Start forwarding to the new node! @@ -666,7 +710,7 @@ // Merge the globals list... if (!N->Globals.empty()) { - MergeSortedVectors(CurNodeH.getNode()->Globals, N->Globals); + CurNodeH.getNode()->mergeGlobals(N->Globals); // Delete the globals from the old node... std::vector().swap(N->Globals); @@ -679,13 +723,20 @@ // Offset indicates what offset the specified node is to be merged into the // current node. // -// The specified node may be a null pointer (in which case, nothing happens). +// The specified node may be a null pointer (in which case, we update it to +// point to this node). // void DSNode::mergeWith(const DSNodeHandle &NH, unsigned Offset) { DSNode *N = NH.getNode(); - if (N == 0 || (N == this && NH.getOffset() == Offset)) + if (N == this && NH.getOffset() == Offset) return; // Noop + // If the RHS is a null node, make it point to this node! + if (N == 0) { + NH.mergeWith(DSNodeHandle(this, Offset)); + return; + } + assert(!N->isDeadNode() && !isDeadNode()); assert(!hasNoReferrers() && "Should not try to fold a useless node!"); @@ -717,6 +768,232 @@ DSNode::MergeNodes(CurNodeH, NHCopy); } + +//===----------------------------------------------------------------------===// +// ReachabilityCloner Implementation +//===----------------------------------------------------------------------===// + +DSNodeHandle ReachabilityCloner::getClonedNH(const DSNodeHandle &SrcNH) { + if (SrcNH.isNull()) return DSNodeHandle(); + const DSNode *SN = SrcNH.getNode(); + + DSNodeHandle &NH = NodeMap[SN]; + if (!NH.isNull()) // Node already mapped? + return DSNodeHandle(NH.getNode(), NH.getOffset()+SrcNH.getOffset()); + + DSNode *DN = new DSNode(*SN, &Dest, true /* Null out all links */); + DN->maskNodeTypes(BitsToKeep); + NH = DN; + + // Next, recursively clone all outgoing links as necessary. Note that + // adding these links can cause the node to collapse itself at any time, and + // the current node may be merged with arbitrary other nodes. For this + // reason, we must always go through NH. + DN = 0; + for (unsigned i = 0, e = SN->getNumLinks(); i != e; ++i) { + const DSNodeHandle &SrcEdge = SN->getLink(i << DS::PointerShift); + if (!SrcEdge.isNull()) { + const DSNodeHandle &DestEdge = getClonedNH(SrcEdge); + // Compute the offset into the current node at which to + // merge this link. In the common case, this is a linear + // relation to the offset in the original node (with + // wrapping), but if the current node gets collapsed due to + // recursive merging, we must make sure to merge in all remaining + // links at offset zero. + unsigned MergeOffset = 0; + DSNode *CN = NH.getNode(); + if (CN->getSize() != 1) + MergeOffset = ((i << DS::PointerShift)+NH.getOffset() + - SrcNH.getOffset()) %CN->getSize(); + CN->addEdgeTo(MergeOffset, DestEdge); + } + } + + // If this node contains any globals, make sure they end up in the scalar + // map with the correct offset. + for (DSNode::global_iterator I = SN->global_begin(), E = SN->global_end(); + I != E; ++I) { + GlobalValue *GV = *I; + const DSNodeHandle &SrcGNH = Src.getNodeForValue(GV); + DSNodeHandle &DestGNH = NodeMap[SrcGNH.getNode()]; + assert(DestGNH.getNode() == NH.getNode() &&"Global mapping inconsistent"); + Dest.getNodeForValue(GV).mergeWith(DSNodeHandle(DestGNH.getNode(), + DestGNH.getOffset()+SrcGNH.getOffset())); + + if (CloneFlags & DSGraph::UpdateInlinedGlobals) + Dest.getInlinedGlobals().insert(GV); + } + + return DSNodeHandle(NH.getNode(), NH.getOffset()+SrcNH.getOffset()); +} + +void ReachabilityCloner::merge(const DSNodeHandle &NH, + const DSNodeHandle &SrcNH) { + if (SrcNH.isNull()) return; // Noop + if (NH.isNull()) { + // If there is no destination node, just clone the source and assign the + // destination node to be it. + NH.mergeWith(getClonedNH(SrcNH)); + return; + } + + // Okay, at this point, we know that we have both a destination and a source + // node that need to be merged. Check to see if the source node has already + // been cloned. + const DSNode *SN = SrcNH.getNode(); + DSNodeHandle &SCNH = NodeMap[SN]; // SourceClonedNodeHandle + if (!SCNH.isNull()) { // Node already cloned? + NH.mergeWith(DSNodeHandle(SCNH.getNode(), + SCNH.getOffset()+SrcNH.getOffset())); + + return; // Nothing to do! + } + + // Okay, so the source node has not already been cloned. Instead of creating + // a new DSNode, only to merge it into the one we already have, try to perform + // the merge in-place. The only case we cannot handle here is when the offset + // into the existing node is less than the offset into the virtual node we are + // merging in. In this case, we have to extend the existing node, which + // requires an allocation anyway. + DSNode *DN = NH.getNode(); // Make sure the Offset is up-to-date + if (NH.getOffset() >= SrcNH.getOffset()) { + if (!DN->isNodeCompletelyFolded()) { + // Make sure the destination node is folded if the source node is folded. + if (SN->isNodeCompletelyFolded()) { + DN->foldNodeCompletely(); + DN = NH.getNode(); + } else if (SN->getSize() != DN->getSize()) { + // If the two nodes are of different size, and the smaller node has the + // array bit set, collapse! + if (SN->getSize() < DN->getSize()) { + if (SN->isArray()) { + DN->foldNodeCompletely(); + DN = NH.getNode(); + } + } else if (DN->isArray()) { + DN->foldNodeCompletely(); + DN = NH.getNode(); + } + } + + // Merge the type entries of the two nodes together... + if (SN->getType() != Type::VoidTy && !DN->isNodeCompletelyFolded()) { + DN->mergeTypeInfo(SN->getType(), NH.getOffset()-SrcNH.getOffset()); + DN = NH.getNode(); + } + } + + assert(!DN->isDeadNode()); + + // Merge the NodeType information. + DN->mergeNodeFlags(SN->getNodeFlags() & BitsToKeep); + + // Before we start merging outgoing links and updating the scalar map, make + // sure it is known that this is the representative node for the src node. + SCNH = DSNodeHandle(DN, NH.getOffset()-SrcNH.getOffset()); + + // If the source node contains any globals, make sure they end up in the + // scalar map with the correct offset. + if (SN->global_begin() != SN->global_end()) { + // Update the globals in the destination node itself. + DN->mergeGlobals(SN->getGlobals()); + + // Update the scalar map for the graph we are merging the source node + // into. + for (DSNode::global_iterator I = SN->global_begin(), E = SN->global_end(); + I != E; ++I) { + GlobalValue *GV = *I; + const DSNodeHandle &SrcGNH = Src.getNodeForValue(GV); + DSNodeHandle &DestGNH = NodeMap[SrcGNH.getNode()]; + assert(DestGNH.getNode()==NH.getNode() &&"Global mapping inconsistent"); + Dest.getNodeForValue(GV).mergeWith(DSNodeHandle(DestGNH.getNode(), + DestGNH.getOffset()+SrcGNH.getOffset())); + + if (CloneFlags & DSGraph::UpdateInlinedGlobals) + Dest.getInlinedGlobals().insert(GV); + } + } + } else { + // We cannot handle this case without allocating a temporary node. Fall + // back on being simple. + DSNode *NewDN = new DSNode(*SN, &Dest, true /* Null out all links */); + NewDN->maskNodeTypes(BitsToKeep); + + unsigned NHOffset = NH.getOffset(); + NH.mergeWith(DSNodeHandle(NewDN, SrcNH.getOffset())); + + assert(NH.getNode() && + (NH.getOffset() > NHOffset || + (NH.getOffset() == 0 && NH.getNode()->isNodeCompletelyFolded())) && + "Merging did not adjust the offset!"); + + // Before we start merging outgoing links and updating the scalar map, make + // sure it is known that this is the representative node for the src node. + SCNH = DSNodeHandle(NH.getNode(), NH.getOffset()-SrcNH.getOffset()); + + // If the source node contained any globals, make sure to create entries + // in the scalar map for them! + for (DSNode::global_iterator I = SN->global_begin(), E = SN->global_end(); + I != E; ++I) { + GlobalValue *GV = *I; + const DSNodeHandle &SrcGNH = Src.getNodeForValue(GV); + DSNodeHandle &DestGNH = NodeMap[SrcGNH.getNode()]; + assert(DestGNH.getNode()==NH.getNode() &&"Global mapping inconsistent"); + assert(SrcGNH.getNode() == SN && "Global mapping inconsistent"); + Dest.getNodeForValue(GV).mergeWith(DSNodeHandle(DestGNH.getNode(), + DestGNH.getOffset()+SrcGNH.getOffset())); + + if (CloneFlags & DSGraph::UpdateInlinedGlobals) + Dest.getInlinedGlobals().insert(GV); + } + } + + + // Next, recursively merge all outgoing links as necessary. Note that + // adding these links can cause the destination node to collapse itself at + // any time, and the current node may be merged with arbitrary other nodes. + // For this reason, we must always go through NH. + DN = 0; + for (unsigned i = 0, e = SN->getNumLinks(); i != e; ++i) { + const DSNodeHandle &SrcEdge = SN->getLink(i << DS::PointerShift); + if (!SrcEdge.isNull()) { + // Compute the offset into the current node at which to + // merge this link. In the common case, this is a linear + // relation to the offset in the original node (with + // wrapping), but if the current node gets collapsed due to + // recursive merging, we must make sure to merge in all remaining + // links at offset zero. + unsigned MergeOffset = 0; + DSNode *CN = SCNH.getNode(); + if (CN->getSize() != 1) + MergeOffset = ((i << DS::PointerShift)+SCNH.getOffset()) %CN->getSize(); + + DSNodeHandle &Link = CN->getLink(MergeOffset); + if (!Link.isNull()) { + // Perform the recursive merging. Make sure to create a temporary NH, + // because the Link can disappear in the process of recursive merging. + DSNodeHandle Tmp = Link; + merge(Tmp, SrcEdge); + } else { + merge(Link, SrcEdge); + } + } + } +} + +/// mergeCallSite - Merge the nodes reachable from the specified src call +/// site into the nodes reachable from DestCS. +void ReachabilityCloner::mergeCallSite(const DSCallSite &DestCS, + const DSCallSite &SrcCS) { + merge(DestCS.getRetVal(), SrcCS.getRetVal()); + unsigned MinArgs = DestCS.getNumPtrArgs(); + if (SrcCS.getNumPtrArgs() < MinArgs) MinArgs = SrcCS.getNumPtrArgs(); + + for (unsigned a = 0; a != MinArgs; ++a) + merge(DestCS.getPtrArg(a), SrcCS.getPtrArg(a)); +} + + //===----------------------------------------------------------------------===// // DSCallSite Implementation //===----------------------------------------------------------------------===// @@ -726,6 +1003,10 @@ return *Site.getInstruction()->getParent()->getParent(); } +void DSCallSite::InitNH(DSNodeHandle &NH, const DSNodeHandle &Src, + ReachabilityCloner &RC) { + NH = RC.getClonedNH(Src); +} //===----------------------------------------------------------------------===// // DSGraph Implementation @@ -752,14 +1033,12 @@ PrintAuxCalls = false; NodeMapTy NodeMap; cloneInto(G, ScalarMap, ReturnNodes, NodeMap); - InlinedGlobals.clear(); // clear set of "up-to-date" globals } DSGraph::DSGraph(const DSGraph &G, NodeMapTy &NodeMap) : GlobalsGraph(0), TD(G.TD) { PrintAuxCalls = false; cloneInto(G, ScalarMap, ReturnNodes, NodeMap); - InlinedGlobals.clear(); // clear set of "up-to-date" globals } DSGraph::~DSGraph() { @@ -770,11 +1049,11 @@ ReturnNodes.clear(); // Drop all intra-node references, so that assertions don't fail... - std::for_each(Nodes.begin(), Nodes.end(), - std::mem_fun(&DSNode::dropAllReferences)); + for (node_iterator NI = node_begin(), E = node_end(); NI != E; ++NI) + (*NI)->dropAllReferences(); - // Delete all of the nodes themselves... - std::for_each(Nodes.begin(), Nodes.end(), deleter); + // Free all of the nodes. + Nodes.clear(); } // dump - Allow inspection of graph in a debugger. @@ -785,132 +1064,36 @@ /// specified mapping. /// void DSNode::remapLinks(DSGraph::NodeMapTy &OldNodeMap) { - for (unsigned i = 0, e = Links.size(); i != e; ++i) { - DSNodeHandle &H = OldNodeMap[Links[i].getNode()]; - Links[i].setNode(H.getNode()); - Links[i].setOffset(Links[i].getOffset()+H.getOffset()); - } -} - - -/// cloneReachableNodes - Clone all reachable nodes from *Node into the -/// current graph. This is a recursive function. The map OldNodeMap is a -/// map from the original nodes to their clones. -/// -void DSGraph::cloneReachableNodes(const DSNode* Node, - unsigned BitsToClear, - NodeMapTy& OldNodeMap, - NodeMapTy& CompletedNodeMap) { - if (CompletedNodeMap.find(Node) != CompletedNodeMap.end()) - return; - - DSNodeHandle& NH = OldNodeMap[Node]; - if (NH.getNode() != NULL) - return; - - // else Node has not yet been cloned: clone it and clear the specified bits - NH = new DSNode(*Node, this); // enters in OldNodeMap - NH.getNode()->maskNodeTypes(~BitsToClear); - - // now recursively clone nodes pointed to by this node - for (unsigned i = 0, e = Node->getNumLinks(); i != e; ++i) { - const DSNodeHandle &Link = Node->getLink(i << DS::PointerShift); - if (const DSNode* nextNode = Link.getNode()) - cloneReachableNodes(nextNode, BitsToClear, OldNodeMap, CompletedNodeMap); - } -} - -void DSGraph::cloneReachableSubgraph(const DSGraph& G, - const hash_set& RootNodes, - NodeMapTy& OldNodeMap, - NodeMapTy& CompletedNodeMap, - unsigned CloneFlags) { - if (RootNodes.empty()) - return; - - assert(OldNodeMap.empty() && "Returned OldNodeMap should be empty!"); - assert(&G != this && "Cannot clone graph into itself!"); - assert((*RootNodes.begin())->getParentGraph() == &G && - "Root nodes do not belong to this graph!"); - - // Remove alloca or mod/ref bits as specified... - unsigned BitsToClear = ((CloneFlags & StripAllocaBit)? DSNode::AllocaNode : 0) - | ((CloneFlags & StripModRefBits)? (DSNode::Modified | DSNode::Read) : 0) - | ((CloneFlags & StripIncompleteBit)? DSNode::Incomplete : 0); - BitsToClear |= DSNode::DEAD; // Clear dead flag... - - // Clone all nodes reachable from each root node, using a recursive helper - for (hash_set::const_iterator I = RootNodes.begin(), - E = RootNodes.end(); I != E; ++I) - cloneReachableNodes(*I, BitsToClear, OldNodeMap, CompletedNodeMap); - - // Merge the map entries in OldNodeMap and CompletedNodeMap to remap links - NodeMapTy MergedMap(OldNodeMap); - MergedMap.insert(CompletedNodeMap.begin(), CompletedNodeMap.end()); - - // Rewrite the links in the newly created nodes (the nodes in OldNodeMap) - // to point into the current graph. MergedMap gives the full mapping. - for (NodeMapTy::iterator I=OldNodeMap.begin(), E=OldNodeMap.end(); I!= E; ++I) - I->second.getNode()->remapLinks(MergedMap); - - // Now merge cloned global nodes with their copies in the current graph - // Just look through OldNodeMap to find such nodes! - for (NodeMapTy::iterator I=OldNodeMap.begin(), E=OldNodeMap.end(); I!= E; ++I) - if (I->first->isGlobalNode()) { - DSNodeHandle &GClone = I->second; - assert(GClone.getNode() != NULL && "NULL node in OldNodeMap?"); - const std::vector &Globals = I->first->getGlobals(); - for (unsigned gi = 0, ge = Globals.size(); gi != ge; ++gi) { - DSNodeHandle &GH = ScalarMap[Globals[gi]]; - GH.mergeWith(GClone); + for (unsigned i = 0, e = Links.size(); i != e; ++i) + if (DSNode *N = Links[i].getNode()) { + DSGraph::NodeMapTy::const_iterator ONMI = OldNodeMap.find(N); + if (ONMI != OldNodeMap.end()) { + Links[i].setNode(ONMI->second.getNode()); + Links[i].setOffset(Links[i].getOffset()+ONMI->second.getOffset()); } } } - /// updateFromGlobalGraph - This function rematerializes global nodes and /// nodes reachable from them from the globals graph into the current graph. -/// It invokes cloneReachableSubgraph, using the globals in the current graph -/// as the roots. It also uses the vector InlinedGlobals to avoid cloning and -/// merging globals that are already up-to-date in the current graph. In -/// practice, in the TD pass, this is likely to be a large fraction of the -/// live global nodes in each function (since most live nodes are likely to -/// have been brought up-to-date in at _some_ caller or callee). +/// It uses the vector InlinedGlobals to avoid cloning and merging globals that +/// are already up-to-date in the current graph. In practice, in the TD pass, +/// this is likely to be a large fraction of the live global nodes in each +/// function (since most live nodes are likely to have been brought up-to-date +/// in at _some_ caller or callee). /// void DSGraph::updateFromGlobalGraph() { + TIME_REGION(X, "updateFromGlobalGraph"); + ReachabilityCloner RC(*this, *GlobalsGraph, 0); - // Use a map to keep track of the mapping between nodes in the globals graph - // and this graph for up-to-date global nodes, which do not need to be cloned. - NodeMapTy CompletedMap; - - // Put the live, non-up-to-date global nodes into a set and the up-to-date - // ones in the map above, mapping node in GlobalsGraph to the up-to-date node. - hash_set GlobalNodeSet; - for (ScalarMapTy::const_iterator I = getScalarMap().begin(), - E = getScalarMap().end(); I != E; ++I) - if (GlobalValue* GV = dyn_cast(I->first)) { - DSNode* GNode = I->second.getNode(); - assert(GNode && "No node for live global in current Graph?"); - if (const DSNode* GGNode = GlobalsGraph->ScalarMap[GV].getNode()) - if (InlinedGlobals.count(GV) == 0) // GNode is not up-to-date - GlobalNodeSet.insert(GGNode); - else { // GNode is up-to-date - CompletedMap[GGNode] = I->second; - assert(GGNode->getNumLinks() == GNode->getNumLinks() && - "Links dont match in a node that is supposed to be up-to-date?" - "\nremapLinks() will not work if the links don't match!"); - } + // Clone the non-up-to-date global nodes into this graph. + for (DSScalarMap::global_iterator I = getScalarMap().global_begin(), + E = getScalarMap().global_end(); I != E; ++I) + if (InlinedGlobals.count(*I) == 0) { // GNode is not up-to-date + DSScalarMap::iterator It = GlobalsGraph->ScalarMap.find(*I); + if (It != GlobalsGraph->ScalarMap.end()) + RC.merge(getNodeForValue(*I), It->second); } - - // Clone the subgraph reachable from the vector of nodes in GlobalNodes - // and merge the cloned global nodes with the corresponding ones, if any. - NodeMapTy OldNodeMap; - cloneReachableSubgraph(*GlobalsGraph, GlobalNodeSet, OldNodeMap,CompletedMap); - - // Merging global nodes leaves behind unused nodes: get rid of them now. - OldNodeMap.clear(); // remove references before dead node cleanup - CompletedMap.clear(); // remove references before dead node cleanup - removeTriviallyDeadNodes(); } /// cloneInto - Clone the specified DSGraph into the current graph. The @@ -919,39 +1102,44 @@ /// /// The CloneFlags member controls various aspects of the cloning process. /// -void DSGraph::cloneInto(const DSGraph &G, ScalarMapTy &OldValMap, +void DSGraph::cloneInto(const DSGraph &G, DSScalarMap &OldValMap, ReturnNodesTy &OldReturnNodes, NodeMapTy &OldNodeMap, unsigned CloneFlags) { + TIME_REGION(X, "cloneInto"); assert(OldNodeMap.empty() && "Returned OldNodeMap should be empty!"); assert(&G != this && "Cannot clone graph into itself!"); - unsigned FN = Nodes.size(); // First new node... - - // Duplicate all of the nodes, populating the node map... - Nodes.reserve(FN+G.Nodes.size()); - // Remove alloca or mod/ref bits as specified... unsigned BitsToClear = ((CloneFlags & StripAllocaBit)? DSNode::AllocaNode : 0) | ((CloneFlags & StripModRefBits)? (DSNode::Modified | DSNode::Read) : 0) | ((CloneFlags & StripIncompleteBit)? DSNode::Incomplete : 0); BitsToClear |= DSNode::DEAD; // Clear dead flag... - for (unsigned i = 0, e = G.Nodes.size(); i != e; ++i) { - DSNode *Old = G.Nodes[i]; - DSNode *New = new DSNode(*Old, this); + + for (node_iterator I = G.node_begin(), E = G.node_end(); I != E; ++I) { + assert(!(*I)->isForwarding() && + "Forward nodes shouldn't be in node list!"); + DSNode *New = new DSNode(**I, this); New->maskNodeTypes(~BitsToClear); - OldNodeMap[Old] = New; + OldNodeMap[*I] = New; } - + #ifndef NDEBUG Timer::addPeakMemoryMeasurement(); #endif - + // Rewrite the links in the new nodes to point into the current graph now. - for (unsigned i = FN, e = Nodes.size(); i != e; ++i) - Nodes[i]->remapLinks(OldNodeMap); + // Note that we don't loop over the node's list to do this. The problem is + // that remaping links can cause recursive merging to happen, which means + // that node_iterator's can get easily invalidated! Because of this, we + // loop over the OldNodeMap, which contains all of the new nodes as the + // .second element of the map elements. Also note that if we remap a node + // more than once, we won't break anything. + for (NodeMapTy::iterator I = OldNodeMap.begin(), E = OldNodeMap.end(); + I != E; ++I) + I->second.getNode()->remapLinks(OldNodeMap); // Copy the scalar map... merging all of the global nodes... - for (ScalarMapTy::const_iterator I = G.ScalarMap.begin(), + for (DSScalarMap::const_iterator I = G.ScalarMap.begin(), E = G.ScalarMap.end(); I != E; ++I) { DSNodeHandle &MappedNode = OldNodeMap[I->second.getNode()]; DSNodeHandle &H = OldValMap[I->first]; @@ -961,7 +1149,8 @@ // If this is a global, add the global to this fn or merge if already exists if (GlobalValue* GV = dyn_cast(I->first)) { ScalarMap[GV].mergeWith(H); - InlinedGlobals.insert(GV); + if (CloneFlags & DSGraph::UpdateInlinedGlobals) + InlinedGlobals.insert(GV); } } @@ -992,6 +1181,7 @@ } } + /// mergeInGraph - The method is used for merging graphs together. If the /// argument graph is not *this, it makes a clone of the specified graph, then /// merges the nodes specified in the call site with the formal arguments in the @@ -999,52 +1189,83 @@ /// void DSGraph::mergeInGraph(const DSCallSite &CS, Function &F, const DSGraph &Graph, unsigned CloneFlags) { - ScalarMapTy OldValMap, *ScalarMap; - DSNodeHandle RetVal; + TIME_REGION(X, "mergeInGraph"); // If this is not a recursive call, clone the graph into this graph... if (&Graph != this) { - // Clone the callee's graph into the current graph, keeping - // track of where scalars in the old graph _used_ to point, - // and of the new nodes matching nodes of the old graph. - NodeMapTy OldNodeMap; + // Clone the callee's graph into the current graph, keeping track of where + // scalars in the old graph _used_ to point, and of the new nodes matching + // nodes of the old graph. + ReachabilityCloner RC(*this, Graph, CloneFlags); + + // Set up argument bindings + Function::aiterator AI = F.abegin(); + for (unsigned i = 0, e = CS.getNumPtrArgs(); i != e; ++i, ++AI) { + // Advance the argument iterator to the first pointer argument... + while (AI != F.aend() && !isPointerType(AI->getType())) { + ++AI; +#ifndef NDEBUG // FIXME: We should merge vararg arguments! + if (AI == F.aend() && !F.getFunctionType()->isVarArg()) + std::cerr << "Bad call to Function: " << F.getName() << "\n"; +#endif + } + if (AI == F.aend()) break; + + // Add the link from the argument scalar to the provided value. + RC.merge(CS.getPtrArg(i), Graph.getNodeForValue(AI)); + } + + // Map the return node pointer over. + if (!CS.getRetVal().isNull()) + RC.merge(CS.getRetVal(), Graph.getReturnNodeFor(F)); + + // If requested, copy the calls or aux-calls lists. + if (!(CloneFlags & DontCloneCallNodes)) { + // Copy the function calls list... + FunctionCalls.reserve(FunctionCalls.size()+Graph.FunctionCalls.size()); + for (unsigned i = 0, ei = Graph.FunctionCalls.size(); i != ei; ++i) + FunctionCalls.push_back(DSCallSite(Graph.FunctionCalls[i], RC)); + } + + if (!(CloneFlags & DontCloneAuxCallNodes)) { + // Copy the auxiliary function calls list... + AuxFunctionCalls.reserve(AuxFunctionCalls.size()+ + Graph.AuxFunctionCalls.size()); + for (unsigned i = 0, ei = Graph.AuxFunctionCalls.size(); i != ei; ++i) + AuxFunctionCalls.push_back(DSCallSite(Graph.AuxFunctionCalls[i], RC)); + } - // The clone call may invalidate any of the vectors in the data - // structure graph. Strip locals and don't copy the list of callers - ReturnNodesTy OldRetNodes; - cloneInto(Graph, OldValMap, OldRetNodes, OldNodeMap, CloneFlags); - - // We need to map the arguments for the function to the cloned nodes old - // argument values. Do this now. - RetVal = OldRetNodes[&F]; - ScalarMap = &OldValMap; + // Clone over all globals that appear in the caller and callee graphs. + for (DSScalarMap::global_iterator GI = Graph.getScalarMap().global_begin(), + E = Graph.getScalarMap().global_end(); GI != E; ++GI) + if (GlobalVariable *GV = dyn_cast(*GI)) + if (ScalarMap.count(GV)) + RC.merge(ScalarMap[GV], Graph.getNodeForValue(GV)); } else { - RetVal = getReturnNodeFor(F); - ScalarMap = &getScalarMap(); - } - - // Merge the return value with the return value of the context... - RetVal.mergeWith(CS.getRetVal()); + DSNodeHandle RetVal = getReturnNodeFor(F); - // Resolve all of the function arguments... - Function::aiterator AI = F.abegin(); - - for (unsigned i = 0, e = CS.getNumPtrArgs(); i != e; ++i, ++AI) { - // Advance the argument iterator to the first pointer argument... - while (AI != F.aend() && !isPointerType(AI->getType())) { - ++AI; -#ifndef NDEBUG - if (AI == F.aend()) - std::cerr << "Bad call to Function: " << F.getName() << "\n"; + // Merge the return value with the return value of the context... + RetVal.mergeWith(CS.getRetVal()); + + // Resolve all of the function arguments... + Function::aiterator AI = F.abegin(); + + for (unsigned i = 0, e = CS.getNumPtrArgs(); i != e; ++i, ++AI) { + // Advance the argument iterator to the first pointer argument... + while (AI != F.aend() && !isPointerType(AI->getType())) { + ++AI; +#ifndef NDEBUG // FIXME: We should merge varargs arguments!! + if (AI == F.aend() && !F.getFunctionType()->isVarArg()) + std::cerr << "Bad call to Function: " << F.getName() << "\n"; #endif + } + if (AI == F.aend()) break; + + // Add the link from the argument scalar to the provided value + DSNodeHandle &NH = getNodeForValue(AI); + assert(NH.getNode() && "Pointer argument without scalarmap entry?"); + NH.mergeWith(CS.getPtrArg(i)); } - if (AI == F.aend()) break; - - // Add the link from the argument scalar to the provided value - assert(ScalarMap->count(AI) && "Argument not in scalar map?"); - DSNodeHandle &NH = (*ScalarMap)[AI]; - assert(NH.getNode() && "Pointer argument without scalarmap entry?"); - NH.mergeWith(CS.getPtrArg(i)); } } @@ -1056,7 +1277,7 @@ for (Function::aiterator I = F.abegin(), E = F.aend(); I != E; ++I) if (isPointerType(I->getType())) - Args.push_back(getScalarMap().find(I)->second); + Args.push_back(getNodeForValue(I)); return DSCallSite(CallSite(), getReturnNodeFor(F), &F, Args); } @@ -1109,9 +1330,8 @@ Function &F = *FI->first; if (F.getName() != "main") for (Function::aiterator I = F.abegin(), E = F.aend(); I != E; ++I) - if (isPointerType(I->getType()) && - ScalarMap.find(I) != ScalarMap.end()) - markIncompleteNode(ScalarMap[I].getNode()); + if (isPointerType(I->getType())) + markIncompleteNode(getNodeForValue(I).getNode()); } // Mark stuff passed into functions calls as being incomplete... @@ -1125,9 +1345,11 @@ // Mark all global nodes as incomplete... if ((Flags & DSGraph::IgnoreGlobals) == 0) - for (unsigned i = 0, e = Nodes.size(); i != e; ++i) - if (Nodes[i]->isGlobalNode() && Nodes[i]->getNumLinks()) - markIncompleteNode(Nodes[i]); + for (DSScalarMap::global_iterator I = ScalarMap.global_begin(), + E = ScalarMap.global_end(); I != E; ++I) + if (GlobalVariable *GV = dyn_cast(*I)) + if (!GV->isConstant()) + markIncompleteNode(ScalarMap[GV].getNode()); } static inline void killIfUselessEdge(DSNodeHandle &Edge) { @@ -1148,11 +1370,11 @@ } static void removeIdenticalCalls(std::vector &Calls) { - // Remove trivially identical function calls unsigned NumFns = Calls.size(); std::sort(Calls.begin(), Calls.end()); // Sort by callee as primary key! +#if 1 // Scan the call list cleaning it up as necessary... DSNode *LastCalleeNode = 0; Function *LastCalleeFunc = 0; @@ -1164,8 +1386,11 @@ // If the Callee is a useless edge, this must be an unreachable call site, // eliminate it. if (CS.isIndirectCall() && CS.getCalleeNode()->getNumReferrers() == 1 && - CS.getCalleeNode()->getNodeFlags() == 0) { // No useful info? - std::cerr << "WARNING: Useless call site found??\n"; + CS.getCalleeNode()->isComplete() && + CS.getCalleeNode()->getGlobals().empty()) { // No useful info? +#ifndef NDEBUG + std::cerr << "WARNING: Useless call site found.\n"; +#endif CS.swap(Calls.back()); Calls.pop_back(); --i; @@ -1193,12 +1418,21 @@ else LastCalleeContainsExternalFunction = LastCalleeFunc->isExternal(); } - + + // It is not clear why, but enabling this code makes DSA really + // sensitive to node forwarding. Basically, with this enabled, DSA + // performs different number of inlinings based on which nodes are + // forwarding or not. This is clearly a problem, so this code is + // disabled until this can be resolved. #if 1 - if (LastCalleeContainsExternalFunction || + if (LastCalleeContainsExternalFunction +#if 0 + || // This should be more than enough context sensitivity! // FIXME: Evaluate how many times this is tripped! - NumDuplicateCalls > 20) { + NumDuplicateCalls > 20 +#endif + ) { DSCallSite &OCS = Calls[i-1]; OCS.mergeWith(CS); @@ -1221,9 +1455,8 @@ } } } - - Calls.erase(std::unique(Calls.begin(), Calls.end()), - Calls.end()); +#endif + Calls.erase(std::unique(Calls.begin(), Calls.end()), Calls.end()); // Track the number of call nodes merged away... NumCallNodesMerged += NumFns-Calls.size(); @@ -1239,92 +1472,82 @@ // we don't have to perform any non-trivial analysis here. // void DSGraph::removeTriviallyDeadNodes() { - removeIdenticalCalls(FunctionCalls); - removeIdenticalCalls(AuxFunctionCalls); + TIME_REGION(X, "removeTriviallyDeadNodes"); // Loop over all of the nodes in the graph, calling getNode on each field. // This will cause all nodes to update their forwarding edges, causing // forwarded nodes to be delete-able. - for (unsigned i = 0, e = Nodes.size(); i != e; ++i) { - DSNode *N = Nodes[i]; + for (node_iterator NI = node_begin(), E = node_end(); NI != E; ++NI) { + DSNode *N = *NI; for (unsigned l = 0, e = N->getNumLinks(); l != e; ++l) N->getLink(l*N->getPointerSize()).getNode(); } - // Likewise, forward any edges from the scalar nodes... - for (ScalarMapTy::iterator I = ScalarMap.begin(), E = ScalarMap.end(); - I != E; ++I) + // NOTE: This code is disabled. Though it should, in theory, allow us to + // remove more nodes down below, the scan of the scalar map is incredibly + // expensive for certain programs (with large SCCs). In the future, if we can + // make the scalar map scan more efficient, then we can reenable this. +#if 0 + { TIME_REGION(X, "removeTriviallyDeadNodes:scalarmap"); + + // Likewise, forward any edges from the scalar nodes. While we are at it, + // clean house a bit. + for (DSScalarMap::iterator I = ScalarMap.begin(),E = ScalarMap.end();I != E;){ I->second.getNode(); - + ++I; + } + } +#endif bool isGlobalsGraph = !GlobalsGraph; - for (unsigned i = 0; i != Nodes.size(); ++i) { - DSNode *Node = Nodes[i]; + for (NodeListTy::iterator NI = Nodes.begin(), E = Nodes.end(); NI != E; ) { + DSNode &Node = *NI; // Do not remove *any* global nodes in the globals graph. // This is a special case because such nodes may not have I, M, R flags set. - if (Node->isGlobalNode() && isGlobalsGraph) + if (Node.isGlobalNode() && isGlobalsGraph) { + ++NI; continue; + } - if (Node->isComplete() && !Node->isModified() && !Node->isRead()) { + if (Node.isComplete() && !Node.isModified() && !Node.isRead()) { // This is a useless node if it has no mod/ref info (checked above), // outgoing edges (which it cannot, as it is not modified in this // context), and it has no incoming edges. If it is a global node it may // have all of these properties and still have incoming edges, due to the // scalar map, so we check those now. // - if (Node->getNumReferrers() == Node->getGlobals().size()) { - const std::vector &Globals = Node->getGlobals(); + if (Node.getNumReferrers() == Node.getGlobals().size()) { + const std::vector &Globals = Node.getGlobals(); // Loop through and make sure all of the globals are referring directly // to the node... for (unsigned j = 0, e = Globals.size(); j != e; ++j) { - DSNode *N = ScalarMap.find(Globals[j])->second.getNode(); - assert(N == Node && "ScalarMap doesn't match globals list!"); + DSNode *N = getNodeForValue(Globals[j]).getNode(); + assert(N == &Node && "ScalarMap doesn't match globals list!"); } // Make sure NumReferrers still agrees, if so, the node is truly dead. - if (Node->getNumReferrers() == Globals.size()) { + if (Node.getNumReferrers() == Globals.size()) { for (unsigned j = 0, e = Globals.size(); j != e; ++j) ScalarMap.erase(Globals[j]); - Node->makeNodeDead(); + Node.makeNodeDead(); + ++NumTrivialGlobalDNE; } } - -#ifdef SANER_CODE_FOR_CHECKING_IF_ALL_REFERRERS_ARE_FROM_SCALARMAP - // - // *** It seems to me that we should be able to simply check if - // *** there are fewer or equal #referrers as #globals and make - // *** sure that all those referrers are in the scalar map? - // - if (Node->getNumReferrers() <= Node->getGlobals().size()) { - const std::vector &Globals = Node->getGlobals(); - -#ifndef NDEBUG - // Loop through and make sure all of the globals are referring directly - // to the node... - for (unsigned j = 0, e = Globals.size(); j != e; ++j) { - DSNode *N = ScalarMap.find(Globals[j])->second.getNode(); - assert(N == Node && "ScalarMap doesn't match globals list!"); - } -#endif - - // Make sure NumReferrers still agrees. The node is truly dead. - assert(Node->getNumReferrers() == Globals.size()); - for (unsigned j = 0, e = Globals.size(); j != e; ++j) - ScalarMap.erase(Globals[j]); - Node->makeNodeDead(); - } -#endif } - if (Node->getNodeFlags() == 0 && Node->hasNoReferrers()) { + if (Node.getNodeFlags() == 0 && Node.hasNoReferrers()) { // This node is dead! - delete Node; // Free memory... - Nodes[i--] = Nodes.back(); - Nodes.pop_back(); // Remove from node list... + NI = Nodes.erase(NI); // Erase & remove from node list. + ++NumTrivialDNE; + } else { + ++NI; } } + + removeIdenticalCalls(FunctionCalls); + removeIdenticalCalls(AuxFunctionCalls); } @@ -1335,11 +1558,9 @@ void DSNode::markReachableNodes(hash_set &ReachableNodes) { if (this == 0) return; assert(getForwardNode() == 0 && "Cannot mark a forwarded node!"); - if (ReachableNodes.count(this)) return; // Already marked reachable - ReachableNodes.insert(this); // Is reachable now - - for (unsigned i = 0, e = getSize(); i < e; i += DS::PointerSize) - getLink(i).getNode()->markReachableNodes(ReachableNodes); + if (ReachableNodes.insert(this).second) // Is newly reachable? + for (unsigned i = 0, e = getSize(); i < e; i += DS::PointerSize) + getLink(i).getNode()->markReachableNodes(ReachableNodes); } void DSCallSite::markReachableNodes(hash_set &Nodes) { @@ -1414,20 +1635,45 @@ // merging... removeTriviallyDeadNodes(); + TIME_REGION(X, "removeDeadNodes"); + // FIXME: Merge non-trivially identical call nodes... // Alive - a set that holds all nodes found to be reachable/alive. hash_set Alive; std::vector > GlobalNodes; + // Copy and merge all information about globals to the GlobalsGraph if this is + // not a final pass (where unreachable globals are removed). + // + // Strip all alloca bits since the current function is only for the BU pass. + // Strip all incomplete bits since they are short-lived properties and they + // will be correctly computed when rematerializing nodes into the functions. + // + ReachabilityCloner GGCloner(*GlobalsGraph, *this, DSGraph::StripAllocaBit | + DSGraph::StripIncompleteBit); + // Mark all nodes reachable by (non-global) scalar nodes as alive... - for (ScalarMapTy::iterator I = ScalarMap.begin(), E = ScalarMap.end(); I !=E;) + { TIME_REGION(Y, "removeDeadNodes:scalarscan"); + for (DSScalarMap::iterator I = ScalarMap.begin(), E = ScalarMap.end(); I !=E;) if (isa(I->first)) { // Keep track of global nodes assert(I->second.getNode() && "Null global node?"); assert(I->second.getNode()->isGlobalNode() && "Should be a global node!"); GlobalNodes.push_back(std::make_pair(I->first, I->second.getNode())); + + // Make sure that all globals are cloned over as roots. + if (!(Flags & DSGraph::RemoveUnreachableGlobals)) { + DSGraph::ScalarMapTy::iterator SMI = + GlobalsGraph->getScalarMap().find(I->first); + if (SMI != GlobalsGraph->getScalarMap().end()) + GGCloner.merge(SMI->second, I->second); + else + GGCloner.getClonedNH(I->second); + } ++I; } else { + DSNode *N = I->second.getNode(); +#if 0 // Check to see if this is a worthless node generated for non-pointer // values, such as integers. Consider an addition of long types: A+B. // Assuming we can track all uses of the value in this context, and it is @@ -1438,16 +1684,17 @@ // uninteresting for data structure analysis. If we run across one of // these, prune the scalar pointing to it. // - DSNode *N = I->second.getNode(); - if (N->getNodeFlags() == DSNode::UnknownNode && !isa(I->first)){ + if (N->getNodeFlags() == DSNode::UnknownNode && !isa(I->first)) ScalarMap.erase(I++); - } else { - I->second.getNode()->markReachableNodes(Alive); + else { +#endif + N->markReachableNodes(Alive); ++I; - } + //} } + } - // The return value is alive as well... + // The return values are alive as well. for (ReturnNodesTy::iterator I = ReturnNodes.begin(), E = ReturnNodes.end(); I != E; ++I) I->second.getNode()->markReachableNodes(Alive); @@ -1456,14 +1703,6 @@ for (unsigned i = 0, e = FunctionCalls.size(); i != e; ++i) FunctionCalls[i].markReachableNodes(Alive); - // Copy and merge all information about globals to the GlobalsGraph - // if this is not a final pass (where unreachable globals are removed) - NodeMapTy GlobalNodeMap; - hash_set GlobalNodeSet; - - for (std::vector >::const_iterator - I = GlobalNodes.begin(), E = GlobalNodes.end(); I != E; ++I) - GlobalNodeSet.insert(I->second); // put global nodes into a set // Now find globals and aux call nodes that are already live or reach a live // value (which makes them live in turn), and continue till no more are found. @@ -1479,13 +1718,13 @@ // Iterate = false; if (!(Flags & DSGraph::RemoveUnreachableGlobals)) - for (unsigned i = 0; i != GlobalNodes.size(); ++i) - if (CanReachAliveNodes(GlobalNodes[i].second, Alive, Visited, - Flags & DSGraph::RemoveUnreachableGlobals)) { - std::swap(GlobalNodes[i--], GlobalNodes.back()); // Move to end to... - GlobalNodes.pop_back(); // erase efficiently - Iterate = true; - } + for (unsigned i = 0; i != GlobalNodes.size(); ++i) + if (CanReachAliveNodes(GlobalNodes[i].second, Alive, Visited, + Flags & DSGraph::RemoveUnreachableGlobals)) { + std::swap(GlobalNodes[i--], GlobalNodes.back()); // Move to end to... + GlobalNodes.pop_back(); // erase efficiently + Iterate = true; + } // Mark only unresolvable call nodes for moving to the GlobalsGraph since // call nodes that get resolved will be difficult to remove from that graph. @@ -1512,51 +1751,18 @@ // GlobalsGraph, and all nodes reachable from those nodes // if (!(Flags & DSGraph::RemoveUnreachableGlobals)) { - - // First, add the dead aux call nodes to the set of root nodes for cloning - // -- return value at this call site, if any - // -- actual arguments passed at this call site - // -- callee node at this call site, if this is an indirect call - for (unsigned i = CurIdx, e = AuxFunctionCalls.size(); i != e; ++i) { - if (const DSNode* RetNode = AuxFunctionCalls[i].getRetVal().getNode()) - GlobalNodeSet.insert(RetNode); - for (unsigned j=0, N=AuxFunctionCalls[i].getNumPtrArgs(); j < N; ++j) - if (const DSNode* ArgTarget=AuxFunctionCalls[i].getPtrArg(j).getNode()) - GlobalNodeSet.insert(ArgTarget); - if (AuxFunctionCalls[i].isIndirectCall()) - GlobalNodeSet.insert(AuxFunctionCalls[i].getCalleeNode()); - } - - // There are no "pre-completed" nodes so use any empty map for those. - // Strip all alloca bits since the current function is only for the BU pass. - // Strip all incomplete bits since they are short-lived properties and they - // will be correctly computed when rematerializing nodes into the functions. - // - NodeMapTy CompletedMap; - GlobalsGraph->cloneReachableSubgraph(*this, GlobalNodeSet, - GlobalNodeMap, CompletedMap, - (DSGraph::StripAllocaBit | - DSGraph::StripIncompleteBit)); - } - - // Remove all dead aux function calls... - if (!(Flags & DSGraph::RemoveUnreachableGlobals)) { - assert(GlobalsGraph && "No globals graph available??"); - - // Copy the unreachable call nodes to the globals graph, updating - // their target pointers using the GlobalNodeMap + // Copy the unreachable call nodes to the globals graph, updating their + // target pointers using the GGCloner for (unsigned i = CurIdx, e = AuxFunctionCalls.size(); i != e; ++i) GlobalsGraph->AuxFunctionCalls.push_back(DSCallSite(AuxFunctionCalls[i], - GlobalNodeMap)); + GGCloner)); } // Crop all the useless ones out... AuxFunctionCalls.erase(AuxFunctionCalls.begin()+CurIdx, AuxFunctionCalls.end()); - // We are finally done with the GlobalNodeMap so we can clear it and - // then get rid of unused nodes in the GlobalsGraph produced by merging. - GlobalNodeMap.clear(); - GlobalsGraph->removeTriviallyDeadNodes(); + // We are finally done with the GGCloner so we can destroy it. + GGCloner.destroy(); // At this point, any nodes which are visited, but not alive, are nodes // which can be removed. Loop over all nodes, eliminating completely @@ -1564,26 +1770,27 @@ // std::vector DeadNodes; DeadNodes.reserve(Nodes.size()); - for (unsigned i = 0; i != Nodes.size(); ++i) - if (!Alive.count(Nodes[i])) { - DSNode *N = Nodes[i]; - Nodes[i--] = Nodes.back(); // move node to end of vector - Nodes.pop_back(); // Erase node from alive list. + for (NodeListTy::iterator NI = Nodes.begin(), E = Nodes.end(); NI != E;) { + DSNode *N = NI++; + assert(!N->isForwarding() && "Forwarded node in nodes list?"); + + if (!Alive.count(N)) { + Nodes.remove(N); + assert(!N->isForwarding() && "Cannot remove a forwarding node!"); DeadNodes.push_back(N); N->dropAllReferences(); - } else { - assert(Nodes[i]->getForwardNode() == 0 && "Alive forwarded node?"); + ++NumDNE; } + } // Remove all unreachable globals from the ScalarMap. // If flag RemoveUnreachableGlobals is set, GlobalNodes has only dead nodes. // In either case, the dead nodes will not be in the set Alive. - for (unsigned i = 0, e = GlobalNodes.size(); i != e; ++i) { - assert(((Flags & DSGraph::RemoveUnreachableGlobals) || - !Alive.count(GlobalNodes[i].second)) && "huh? non-dead global"); + for (unsigned i = 0, e = GlobalNodes.size(); i != e; ++i) if (!Alive.count(GlobalNodes[i].second)) ScalarMap.erase(GlobalNodes[i].first); - } + else + assert((Flags & DSGraph::RemoveUnreachableGlobals) && "non-dead global"); // Delete all dead nodes now since their referrer counts are zero. for (unsigned i = 0, e = DeadNodes.size(); i != e; ++i) @@ -1593,8 +1800,8 @@ } void DSGraph::AssertGraphOK() const { - for (unsigned i = 0, e = Nodes.size(); i != e; ++i) - Nodes[i]->assertOK(); + for (node_iterator NI = node_begin(), E = node_end(); NI != E; ++NI) + (*NI)->assertOK(); for (ScalarMapTy::const_iterator I = ScalarMap.begin(), E = ScalarMap.end(); I != E; ++I) { @@ -1609,36 +1816,6 @@ AssertCallNodesInGraph(); AssertAuxCallNodesInGraph(); } - -/// mergeInGlobalsGraph - This method is useful for clients to incorporate the -/// globals graph into the DS, BU or TD graph for a function. This code retains -/// all globals, i.e., does not delete unreachable globals after they are -/// inlined. -/// -void DSGraph::mergeInGlobalsGraph() { - NodeMapTy GlobalNodeMap; - ScalarMapTy OldValMap; - ReturnNodesTy OldRetNodes; - cloneInto(*GlobalsGraph, OldValMap, OldRetNodes, GlobalNodeMap, - DSGraph::KeepAllocaBit | DSGraph::DontCloneCallNodes | - DSGraph::DontCloneAuxCallNodes); - - // Now merge existing global nodes in the GlobalsGraph with their copies - for (ScalarMapTy::iterator I = ScalarMap.begin(), E = ScalarMap.end(); - I != E; ++I) - if (isa(I->first)) { // Found a global node - DSNodeHandle &GH = I->second; - DSNodeHandle &GGNodeH = GlobalsGraph->getScalarMap()[I->first]; - GH.mergeWith(GlobalNodeMap[GGNodeH.getNode()]); - } - - // Merging leaves behind unused nodes: get rid of them now. - GlobalNodeMap.clear(); - OldValMap.clear(); - OldRetNodes.clear(); - removeTriviallyDeadNodes(); -} - /// computeNodeMapping - Given roots in two different DSGraphs, traverse the /// nodes reachable from the two graphs, computing the mapping of nodes from Index: llvm/lib/Analysis/DataStructure/DataStructureAA.cpp diff -u llvm/lib/Analysis/DataStructure/DataStructureAA.cpp:1.13 llvm/lib/Analysis/DataStructure/DataStructureAA.cpp:1.13.4.1 --- llvm/lib/Analysis/DataStructure/DataStructureAA.cpp:1.13 Wed Nov 12 17:11:14 2003 +++ llvm/lib/Analysis/DataStructure/DataStructureAA.cpp Mon Mar 1 17:58:12 2004 @@ -53,6 +53,10 @@ void getMustAliases(Value *P, std::vector &RetVals); + bool pointsToConstantMemory(const Value *P) { + return getAnalysis().pointsToConstantMemory(P); + } + private: DSGraph *getGraphForValue(const Value *V); }; @@ -166,9 +170,8 @@ // The only must alias information we can currently determine occurs when // the node for P is a global node with only one entry. - const DSGraph::ScalarMapTy &GSM = G->getScalarMap(); - DSGraph::ScalarMapTy::const_iterator I = GSM.find(P); - if (I != GSM.end()) { + DSGraph::ScalarMapTy::const_iterator I = G->getScalarMap().find(P); + if (I != G->getScalarMap().end()) { DSNode *N = I->second.getNode(); if (N->isComplete() && isSinglePhysicalObject(N)) RetVals.push_back(N->getGlobals()[0]); Index: llvm/lib/Analysis/DataStructure/GraphChecker.cpp diff -u llvm/lib/Analysis/DataStructure/GraphChecker.cpp:1.10 llvm/lib/Analysis/DataStructure/GraphChecker.cpp:1.10.4.1 --- llvm/lib/Analysis/DataStructure/GraphChecker.cpp:1.10 Wed Nov 12 17:11:14 2003 +++ llvm/lib/Analysis/DataStructure/GraphChecker.cpp Mon Mar 1 17:58:12 2004 @@ -12,7 +12,7 @@ // or not a node is collapsed, etc. These are the command line arguments that // it supports: // -// --dsgc-dsapass={local,bu,td} - Specify what flavor of graph to check +// --dsgc-dspass={local,bu,td} - Specify what flavor of graph to check // --dsgc-abort-if-any-collapsed - Abort if any collapsed nodes are found // --dsgc-abort-if-collapsed= - Abort if a node pointed to by an SSA // value with name in is collapsed @@ -114,11 +114,10 @@ void DSGC::verify(const DSGraph &G) { // Loop over all of the nodes, checking to see if any are collapsed... if (AbortIfAnyCollapsed) { - const std::vector &Nodes = G.getNodes(); - for (unsigned i = 0, e = Nodes.size(); i != e; ++i) - if (Nodes[i]->isNodeCompletelyFolded()) { + for (DSGraph::node_iterator I = G.node_begin(), E = G.node_end(); I!=E; ++I) + if ((*I)->isNodeCompletelyFolded()) { std::cerr << "Node is collapsed: "; - Nodes[i]->print(std::cerr, &G); + (*I)->print(std::cerr, &G); abort(); } } Index: llvm/lib/Analysis/DataStructure/Local.cpp diff -u llvm/lib/Analysis/DataStructure/Local.cpp:1.74 llvm/lib/Analysis/DataStructure/Local.cpp:1.74.4.1 --- llvm/lib/Analysis/DataStructure/Local.cpp:1.74 Tue Nov 25 14:19:55 2003 +++ llvm/lib/Analysis/DataStructure/Local.cpp Mon Mar 1 17:58:12 2004 @@ -17,6 +17,7 @@ #include "llvm/Constants.h" #include "llvm/DerivedTypes.h" #include "llvm/Instructions.h" +#include "llvm/Intrinsics.h" #include "llvm/Support/GetElementPtrTypeIterator.h" #include "llvm/Support/InstVisitor.h" #include "llvm/Target/TargetData.h" @@ -37,7 +38,6 @@ static cl::opt TrackIntegersAsPointers("dsa-track-integers", cl::desc("If this is set, track integers as potential pointers")); - namespace llvm { namespace DS { @@ -72,7 +72,7 @@ class GraphBuilder : InstVisitor { DSGraph &G; DSNodeHandle *RetNode; // Node that gets returned... - DSGraph::ScalarMapTy &ScalarMap; + DSScalarMap &ScalarMap; std::vector *FunctionCalls; public: @@ -171,13 +171,24 @@ #endif // Remove all integral constants from the scalarmap! - for (ScalarMapTy::iterator I = ScalarMap.begin(); I != ScalarMap.end();) - if (isa(I->first)) { - ScalarMapTy::iterator J = I++; - ScalarMap.erase(J); - } else + for (DSScalarMap::iterator I = ScalarMap.begin(); I != ScalarMap.end();) + if (isa(I->first)) + ScalarMap.erase(I++); + else ++I; + // If there are any constant globals referenced in this function, merge their + // initializers into the local graph from the globals graph. + if (ScalarMap.global_begin() != ScalarMap.global_end()) { + ReachabilityCloner RC(*this, *GG, 0); + + for (DSScalarMap::global_iterator I = ScalarMap.global_begin(); + I != ScalarMap.global_end(); ++I) + if (GlobalVariable *GV = dyn_cast(*I)) + if (GV->isConstant()) + RC.merge(ScalarMap[GV], GG->ScalarMap[GV]); + } + markIncompleteNodes(DSGraph::MarkFormalArgs); // Remove any nodes made dead due to merging... @@ -211,7 +222,7 @@ NH = getValueDest(*CE->getOperand(0)); else if (CE->getOpcode() == Instruction::GetElementPtr) { visitGetElementPtrInst(*CE); - DSGraph::ScalarMapTy::iterator I = ScalarMap.find(CE); + DSScalarMap::iterator I = ScalarMap.find(CE); assert(I != ScalarMap.end() && "GEP didn't get processed right?"); NH = I->second; } else { @@ -372,6 +383,10 @@ if (const StructType *STy = dyn_cast(*I)) { unsigned FieldNo = cast(I.getOperand())->getValue(); Offset += TD.getStructLayout(STy)->MemberOffsets[FieldNo]; + } else if (const PointerType *PTy = dyn_cast(*I)) { + if (!isa(I.getOperand()) || + !cast(I.getOperand())->isNullValue()) + Value.getNode()->setArrayMarker(); } @@ -454,42 +469,351 @@ } void GraphBuilder::visitCallSite(CallSite CS) { + Value *Callee = CS.getCalledValue(); + if (ConstantPointerRef *CPR = dyn_cast(Callee)) + Callee = CPR->getValue(); + // Special case handling of certain libc allocation functions here. - if (Function *F = CS.getCalledFunction()) + if (Function *F = dyn_cast(Callee)) if (F->isExternal()) - if (F->getName() == "calloc") { - setDestTo(*CS.getInstruction(), - createNode()->setHeapNodeMarker()->setModifiedMarker()); - return; - } else if (F->getName() == "realloc") { - DSNodeHandle RetNH = getValueDest(*CS.getInstruction()); - RetNH.mergeWith(getValueDest(**CS.arg_begin())); - if (DSNode *N = RetNH.getNode()) - N->setHeapNodeMarker()->setModifiedMarker()->setReadMarker(); - return; - } else if (F->getName() == "memset") { - // Merge the first argument with the return value, and mark the memory + switch (F->getIntrinsicID()) { + case Intrinsic::memmove: + case Intrinsic::memcpy: { + // Merge the first & second arguments, and mark the memory read and // modified. - DSNodeHandle RetNH = getValueDest(*CS.getInstruction()); - RetNH.mergeWith(getValueDest(**CS.arg_begin())); - if (DSNode *N = RetNH.getNode()) - N->setModifiedMarker(); - return; - } else if (F->getName() == "memmove") { - // Merge the first & second arguments with the result, and mark the - // memory read and modified. - DSNodeHandle RetNH = getValueDest(*CS.getInstruction()); - RetNH.mergeWith(getValueDest(**CS.arg_begin())); + DSNodeHandle RetNH = getValueDest(**CS.arg_begin()); RetNH.mergeWith(getValueDest(**(CS.arg_begin()+1))); if (DSNode *N = RetNH.getNode()) N->setModifiedMarker()->setReadMarker(); return; - } else if (F->getName() == "bzero") { + } + case Intrinsic::memset: // Mark the memory modified. - DSNodeHandle H = getValueDest(**CS.arg_begin()); - if (DSNode *N = H.getNode()) + if (DSNode *N = getValueDest(**CS.arg_begin()).getNode()) N->setModifiedMarker(); return; + default: + if (F->getName() == "calloc") { + setDestTo(*CS.getInstruction(), + createNode()->setHeapNodeMarker()->setModifiedMarker()); + return; + } else if (F->getName() == "realloc") { + DSNodeHandle RetNH = getValueDest(*CS.getInstruction()); + RetNH.mergeWith(getValueDest(**CS.arg_begin())); + if (DSNode *N = RetNH.getNode()) + N->setHeapNodeMarker()->setModifiedMarker()->setReadMarker(); + return; + } else if (F->getName() == "memmove") { + // Merge the first & second arguments, and mark the memory read and + // modified. + DSNodeHandle RetNH = getValueDest(**CS.arg_begin()); + RetNH.mergeWith(getValueDest(**(CS.arg_begin()+1))); + if (DSNode *N = RetNH.getNode()) + N->setModifiedMarker()->setReadMarker(); + return; + + } else if (F->getName() == "atoi" || F->getName() == "atof" || + F->getName() == "atol" || F->getName() == "atoll" || + F->getName() == "remove" || F->getName() == "unlink" || + F->getName() == "rename" || F->getName() == "memcmp" || + F->getName() == "strcmp" || F->getName() == "strncmp" || + F->getName() == "execl" || F->getName() == "execlp" || + F->getName() == "execle" || F->getName() == "execv" || + F->getName() == "execvp" || F->getName() == "chmod" || + F->getName() == "puts" || F->getName() == "write" || + F->getName() == "open" || F->getName() == "create" || + F->getName() == "truncate" || F->getName() == "chdir" || + F->getName() == "mkdir" || F->getName() == "rmdir") { + // These functions read all of their pointer operands. + for (CallSite::arg_iterator AI = CS.arg_begin(), E = CS.arg_end(); + AI != E; ++AI) { + if (isPointerType((*AI)->getType())) + if (DSNode *N = getValueDest(**AI).getNode()) + N->setReadMarker(); + } + return; + } else if (F->getName() == "read" || F->getName() == "pipe" || + F->getName() == "wait" || F->getName() == "time") { + // These functions write all of their pointer operands. + for (CallSite::arg_iterator AI = CS.arg_begin(), E = CS.arg_end(); + AI != E; ++AI) { + if (isPointerType((*AI)->getType())) + if (DSNode *N = getValueDest(**AI).getNode()) + N->setModifiedMarker(); + } + return; + } else if (F->getName() == "stat" || F->getName() == "fstat" || + F->getName() == "lstat") { + // These functions read their first operand if its a pointer. + CallSite::arg_iterator AI = CS.arg_begin(); + if (isPointerType((*AI)->getType())) { + DSNodeHandle Path = getValueDest(**AI); + if (DSNode *N = Path.getNode()) N->setReadMarker(); + } + + // Then they write into the stat buffer. + DSNodeHandle StatBuf = getValueDest(**++AI); + if (DSNode *N = StatBuf.getNode()) { + N->setModifiedMarker(); + const Type *StatTy = F->getFunctionType()->getParamType(1); + if (const PointerType *PTy = dyn_cast(StatTy)) + N->mergeTypeInfo(PTy->getElementType(), StatBuf.getOffset()); + } + return; + } else if (F->getName() == "fopen" || F->getName() == "fdopen" || + F->getName() == "freopen") { + // These functions read all of their pointer operands. + for (CallSite::arg_iterator AI = CS.arg_begin(), E = CS.arg_end(); + AI != E; ++AI) + if (isPointerType((*AI)->getType())) + if (DSNode *N = getValueDest(**AI).getNode()) + N->setReadMarker(); + + // fopen allocates in an unknown way and writes to the file + // descriptor. Also, merge the allocated type into the node. + DSNodeHandle Result = getValueDest(*CS.getInstruction()); + if (DSNode *N = Result.getNode()) { + N->setModifiedMarker()->setUnknownNodeMarker(); + const Type *RetTy = F->getFunctionType()->getReturnType(); + if (const PointerType *PTy = dyn_cast(RetTy)) + N->mergeTypeInfo(PTy->getElementType(), Result.getOffset()); + } + + // If this is freopen, merge the file descriptor passed in with the + // result. + Result.mergeWith(getValueDest(**--CS.arg_end())); + + return; + } else if (F->getName() == "fclose" && CS.arg_end()-CS.arg_begin() ==1){ + // fclose reads and deallocates the memory in an unknown way for the + // file descriptor. It merges the FILE type into the descriptor. + DSNodeHandle H = getValueDest(**CS.arg_begin()); + if (DSNode *N = H.getNode()) { + N->setReadMarker()->setUnknownNodeMarker(); + const Type *ArgTy = F->getFunctionType()->getParamType(0); + if (const PointerType *PTy = dyn_cast(ArgTy)) + N->mergeTypeInfo(PTy->getElementType(), H.getOffset()); + } + return; + } else if (CS.arg_end()-CS.arg_begin() == 1 && + (F->getName() == "fflush" || F->getName() == "feof" || + F->getName() == "fileno" || F->getName() == "clearerr" || + F->getName() == "rewind" || F->getName() == "ftell" || + F->getName() == "ferror" || F->getName() == "fgetc" || + F->getName() == "fgetc" || F->getName() == "_IO_getc")) { + // fflush reads and writes the memory for the file descriptor. It + // merges the FILE type into the descriptor. + DSNodeHandle H = getValueDest(**CS.arg_begin()); + if (DSNode *N = H.getNode()) { + N->setReadMarker()->setModifiedMarker(); + + const Type *ArgTy = F->getFunctionType()->getParamType(0); + if (const PointerType *PTy = dyn_cast(ArgTy)) + N->mergeTypeInfo(PTy->getElementType(), H.getOffset()); + } + return; + } else if (CS.arg_end()-CS.arg_begin() == 4 && + (F->getName() == "fwrite" || F->getName() == "fread")) { + // fread writes the first operand, fwrite reads it. They both + // read/write the FILE descriptor, and merges the FILE type. + DSNodeHandle H = getValueDest(**--CS.arg_end()); + if (DSNode *N = H.getNode()) { + N->setReadMarker()->setModifiedMarker(); + const Type *ArgTy = F->getFunctionType()->getParamType(3); + if (const PointerType *PTy = dyn_cast(ArgTy)) + N->mergeTypeInfo(PTy->getElementType(), H.getOffset()); + } + + H = getValueDest(**CS.arg_begin()); + if (DSNode *N = H.getNode()) + if (F->getName() == "fwrite") + N->setReadMarker(); + else + N->setModifiedMarker(); + return; + } else if (F->getName() == "fgets" && CS.arg_end()-CS.arg_begin() == 3){ + // fgets reads and writes the memory for the file descriptor. It + // merges the FILE type into the descriptor, and writes to the + // argument. It returns the argument as well. + CallSite::arg_iterator AI = CS.arg_begin(); + DSNodeHandle H = getValueDest(**AI); + if (DSNode *N = H.getNode()) + N->setModifiedMarker(); // Writes buffer + H.mergeWith(getValueDest(*CS.getInstruction())); // Returns buffer + ++AI; ++AI; + + // Reads and writes file descriptor, merge in FILE type. + H = getValueDest(**AI); + if (DSNode *N = H.getNode()) { + N->setReadMarker()->setModifiedMarker(); + const Type *ArgTy = F->getFunctionType()->getParamType(2); + if (const PointerType *PTy = dyn_cast(ArgTy)) + N->mergeTypeInfo(PTy->getElementType(), H.getOffset()); + } + return; + } else if (F->getName() == "ungetc" || F->getName() == "fputc" || + F->getName() == "fputs" || F->getName() == "putc" || + F->getName() == "ftell" || F->getName() == "rewind" || + F->getName() == "_IO_putc") { + // These functions read and write the memory for the file descriptor, + // which is passes as the last argument. + DSNodeHandle H = getValueDest(**--CS.arg_end()); + if (DSNode *N = H.getNode()) { + N->setReadMarker()->setModifiedMarker(); + const Type *ArgTy = *--F->getFunctionType()->param_end(); + if (const PointerType *PTy = dyn_cast(ArgTy)) + N->mergeTypeInfo(PTy->getElementType(), H.getOffset()); + } + + // Any pointer arguments are read. + for (CallSite::arg_iterator AI = CS.arg_begin(), E = CS.arg_end(); + AI != E; ++AI) + if (isPointerType((*AI)->getType())) + if (DSNode *N = getValueDest(**AI).getNode()) + N->setReadMarker(); + return; + } else if (F->getName() == "fseek" || F->getName() == "fgetpos" || + F->getName() == "fsetpos") { + // These functions read and write the memory for the file descriptor, + // and read/write all other arguments. + DSNodeHandle H = getValueDest(**CS.arg_begin()); + if (DSNode *N = H.getNode()) { + const Type *ArgTy = *--F->getFunctionType()->param_end(); + if (const PointerType *PTy = dyn_cast(ArgTy)) + N->mergeTypeInfo(PTy->getElementType(), H.getOffset()); + } + + // Any pointer arguments are read. + for (CallSite::arg_iterator AI = CS.arg_begin(), E = CS.arg_end(); + AI != E; ++AI) + if (isPointerType((*AI)->getType())) + if (DSNode *N = getValueDest(**AI).getNode()) + N->setReadMarker()->setModifiedMarker(); + return; + } else if (F->getName() == "printf" || F->getName() == "fprintf" || + F->getName() == "sprintf") { + CallSite::arg_iterator AI = CS.arg_begin(), E = CS.arg_end(); + + if (F->getName() == "fprintf") { + // fprintf reads and writes the FILE argument, and applies the type + // to it. + DSNodeHandle H = getValueDest(**AI); + if (DSNode *N = H.getNode()) { + N->setModifiedMarker(); + const Type *ArgTy = (*AI)->getType(); + if (const PointerType *PTy = dyn_cast(ArgTy)) + N->mergeTypeInfo(PTy->getElementType(), H.getOffset()); + } + } else if (F->getName() == "sprintf") { + // sprintf writes the first string argument. + DSNodeHandle H = getValueDest(**AI++); + if (DSNode *N = H.getNode()) { + N->setModifiedMarker(); + const Type *ArgTy = (*AI)->getType(); + if (const PointerType *PTy = dyn_cast(ArgTy)) + N->mergeTypeInfo(PTy->getElementType(), H.getOffset()); + } + } + + for (; AI != E; ++AI) { + // printf reads all pointer arguments. + if (isPointerType((*AI)->getType())) + if (DSNode *N = getValueDest(**AI).getNode()) + N->setReadMarker(); + } + return; + } else if (F->getName() == "scanf" || F->getName() == "fscanf" || + F->getName() == "sscanf") { + CallSite::arg_iterator AI = CS.arg_begin(), E = CS.arg_end(); + + if (F->getName() == "fscanf") { + // fscanf reads and writes the FILE argument, and applies the type + // to it. + DSNodeHandle H = getValueDest(**AI); + if (DSNode *N = H.getNode()) { + N->setReadMarker(); + const Type *ArgTy = (*AI)->getType(); + if (const PointerType *PTy = dyn_cast(ArgTy)) + N->mergeTypeInfo(PTy->getElementType(), H.getOffset()); + } + } else if (F->getName() == "sscanf") { + // sscanf reads the first string argument. + DSNodeHandle H = getValueDest(**AI++); + if (DSNode *N = H.getNode()) { + N->setReadMarker(); + const Type *ArgTy = (*AI)->getType(); + if (const PointerType *PTy = dyn_cast(ArgTy)) + N->mergeTypeInfo(PTy->getElementType(), H.getOffset()); + } + } + + for (; AI != E; ++AI) { + // scanf writes all pointer arguments. + if (isPointerType((*AI)->getType())) + if (DSNode *N = getValueDest(**AI).getNode()) + N->setModifiedMarker(); + } + return; + } else if (F->getName() == "strtok") { + // strtok reads and writes the first argument, returning it. It reads + // its second arg. FIXME: strtok also modifies some hidden static + // data. Someday this might matter. + CallSite::arg_iterator AI = CS.arg_begin(); + DSNodeHandle H = getValueDest(**AI++); + if (DSNode *N = H.getNode()) { + N->setReadMarker()->setModifiedMarker(); // Reads/Writes buffer + const Type *ArgTy = F->getFunctionType()->getParamType(0); + if (const PointerType *PTy = dyn_cast(ArgTy)) + N->mergeTypeInfo(PTy->getElementType(), H.getOffset()); + } + H.mergeWith(getValueDest(*CS.getInstruction())); // Returns buffer + + H = getValueDest(**AI); // Reads delimiter + if (DSNode *N = H.getNode()) { + N->setReadMarker(); + const Type *ArgTy = F->getFunctionType()->getParamType(1); + if (const PointerType *PTy = dyn_cast(ArgTy)) + N->mergeTypeInfo(PTy->getElementType(), H.getOffset()); + } + return; + } else if (F->getName() == "strchr" || F->getName() == "strrchr" || + F->getName() == "strstr") { + // These read their arguments, and return the first one + DSNodeHandle H = getValueDest(**CS.arg_begin()); + H.mergeWith(getValueDest(*CS.getInstruction())); // Returns buffer + + for (CallSite::arg_iterator AI = CS.arg_begin(), E = CS.arg_end(); + AI != E; ++AI) + if (isPointerType((*AI)->getType())) + if (DSNode *N = getValueDest(**AI).getNode()) + N->setReadMarker(); + + if (DSNode *N = H.getNode()) + N->setReadMarker(); + return; + } else if (F->getName() == "modf" && CS.arg_end()-CS.arg_begin() == 2) { + // This writes its second argument, and forces it to double. + DSNodeHandle H = getValueDest(**--CS.arg_end()); + if (DSNode *N = H.getNode()) { + N->setModifiedMarker(); + N->mergeTypeInfo(Type::DoubleTy, H.getOffset()); + } + return; + } else { + // Unknown function, warn if it returns a pointer type or takes a + // pointer argument. + bool Warn = isPointerType(CS.getInstruction()->getType()); + if (!Warn) + for (CallSite::arg_iterator I = CS.arg_begin(), E = CS.arg_end(); + I != E; ++I) + if (isPointerType((*I)->getType())) { + Warn = true; + break; + } + if (Warn) + std::cerr << "WARNING: Call to unknown external function '" + << F->getName() << "' will cause pessimistic results!\n"; + } } @@ -499,12 +823,11 @@ if (isPointerType(I->getType())) RetVal = getValueDest(*I); - DSNode *Callee = 0; - if (DisableDirectCallOpt || !isa(CS.getCalledValue())) { - Callee = getValueDest(*CS.getCalledValue()).getNode(); - if (Callee == 0) { - std::cerr << "WARNING: Program is calling through a null pointer?\n" - << *I; + DSNode *CalleeNode = 0; + if (DisableDirectCallOpt || !isa(Callee)) { + CalleeNode = getValueDest(*Callee).getNode(); + if (CalleeNode == 0) { + std::cerr << "WARNING: Program is calling through a null pointer?\n"<< *I; return; // Calling a null pointer? } } @@ -518,18 +841,17 @@ Args.push_back(getValueDest(**I)); // Add a new function call entry... - if (Callee) - FunctionCalls->push_back(DSCallSite(CS, RetVal, Callee, Args)); + if (CalleeNode) + FunctionCalls->push_back(DSCallSite(CS, RetVal, CalleeNode, Args)); else - FunctionCalls->push_back(DSCallSite(CS, RetVal, CS.getCalledFunction(), + FunctionCalls->push_back(DSCallSite(CS, RetVal, cast(Callee), Args)); } void GraphBuilder::visitFreeInst(FreeInst &FI) { // Mark that the node is written to... - DSNode *N = getValueDest(*FI.getOperand(0)).getNode(); - N->setModifiedMarker(); - N->setHeapNodeMarker(); + if (DSNode *N = getValueDest(*FI.getOperand(0)).getNode()) + N->setModifiedMarker()->setHeapNodeMarker(); } /// Handle casts... @@ -594,6 +916,8 @@ DSNodeHandle NewNH(NH.getNode(), NH.getOffset()+SL->MemberOffsets[i]); MergeConstantInitIntoNode(NewNH, cast(CS->getOperand(i))); } + } else if (ConstantAggregateZero *CAZ = dyn_cast(C)) { + // Noop } else { assert(0 && "Unknown constant type!"); } @@ -612,20 +936,22 @@ const TargetData &TD = getAnalysis(); + { + GraphBuilder GGB(*GlobalsGraph); + + // Add initializers for all of the globals to the globals graph... + for (Module::giterator I = M.gbegin(), E = M.gend(); I != E; ++I) + if (!I->isExternal()) + GGB.mergeInGlobalInitializer(I); + } + // Calculate all of the graphs... for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) if (!I->isExternal()) DSInfo.insert(std::make_pair(I, new DSGraph(TD, *I, GlobalsGraph))); - GraphBuilder GGB(*GlobalsGraph); - - // Add initializers for all of the globals to the globals graph... - for (Module::giterator I = M.gbegin(), E = M.gend(); I != E; ++I) - if (!I->isExternal()) - GGB.mergeInGlobalInitializer(I); - - GlobalsGraph->markIncompleteNodes(DSGraph::MarkFormalArgs); GlobalsGraph->removeTriviallyDeadNodes(); + GlobalsGraph->markIncompleteNodes(DSGraph::MarkFormalArgs); return false; } Index: llvm/lib/Analysis/DataStructure/Printer.cpp diff -u llvm/lib/Analysis/DataStructure/Printer.cpp:1.62 llvm/lib/Analysis/DataStructure/Printer.cpp:1.62.4.1 --- llvm/lib/Analysis/DataStructure/Printer.cpp:1.62 Wed Nov 12 23:05:41 2003 +++ llvm/lib/Analysis/DataStructure/Printer.cpp Mon Mar 1 17:58:12 2004 @@ -29,8 +29,9 @@ // namespace { cl::opt OnlyPrintMain("only-print-main-ds", cl::ReallyHidden); - Statistic<> MaxGraphSize ("dsnode", "Maximum graph size"); - Statistic<> NumFoldedNodes ("dsnode", "Number of folded nodes (in final graph)"); + cl::opt DontPrintAnything("dont-print-ds", cl::ReallyHidden); + Statistic<> MaxGraphSize ("dsa", "Maximum graph size"); + Statistic<> NumFoldedNodes ("dsa", "Number of folded nodes (in final graph)"); } void DSNode::dump() const { print(std::cerr, 0); } @@ -38,6 +39,9 @@ static std::string getCaption(const DSNode *N, const DSGraph *G) { std::stringstream OS; Module *M = 0; + + if (G) G = N->getParentGraph(); + // Get the module from ONE of the functions in the graph it is available. if (G && !G->getReturnNodes().empty()) M = G->getReturnNodes().begin()->first->getParent(); @@ -248,10 +252,12 @@ << Gr.getGraphSize() << "+" << NumCalls << "]\n"; } - if (MaxGraphSize < Gr.getNodes().size()) - MaxGraphSize = Gr.getNodes().size(); - for (unsigned i = 0, e = Gr.getNodes().size(); i != e; ++i) - if (Gr.getNodes()[i]->isNodeCompletelyFolded()) + unsigned GraphSize = Gr.getGraphSize(); + if (MaxGraphSize < GraphSize) MaxGraphSize = GraphSize; + + for (DSGraph::node_iterator NI = Gr.node_begin(), E = Gr.node_end(); + NI != E; ++NI) + if ((*NI)->isNodeCompletelyFolded()) ++NumFoldedNodes; } @@ -272,18 +278,22 @@ // print - Print out the analysis results... void LocalDataStructures::print(std::ostream &O, const Module *M) const { + if (DontPrintAnything) return; printCollection(*this, O, M, "ds."); } void BUDataStructures::print(std::ostream &O, const Module *M) const { + if (DontPrintAnything) return; printCollection(*this, O, M, "bu."); } void TDDataStructures::print(std::ostream &O, const Module *M) const { + if (DontPrintAnything) return; printCollection(*this, O, M, "td."); } void CompleteBUDataStructures::print(std::ostream &O, const Module *M) const { + if (DontPrintAnything) return; printCollection(*this, O, M, "cbu."); } Index: llvm/lib/Analysis/DataStructure/Steensgaard.cpp diff -u llvm/lib/Analysis/DataStructure/Steensgaard.cpp:1.35 llvm/lib/Analysis/DataStructure/Steensgaard.cpp:1.35.4.1 --- llvm/lib/Analysis/DataStructure/Steensgaard.cpp:1.35 Wed Nov 12 17:11:14 2003 +++ llvm/lib/Analysis/DataStructure/Steensgaard.cpp Mon Mar 1 17:58:12 2004 @@ -63,6 +63,10 @@ // alias - This is the only method here that does anything interesting... AliasResult alias(const Value *V1, unsigned V1Size, const Value *V2, unsigned V2Size); + + bool pointsToConstantMemory(const Value *P) { + return getAnalysis().pointsToConstantMemory(P); + } private: void ResolveFunctionCall(Function *F, const DSCallSite &Call, @@ -130,7 +134,8 @@ { // Scope to free NodeMap memory ASAP DSGraph::NodeMapTy NodeMap; const DSGraph &FDSG = LDS.getDSGraph(*I); - ResultGraph->cloneInto(FDSG, ValMap, RetValMap, NodeMap); + ResultGraph->cloneInto(FDSG, ValMap, RetValMap, NodeMap, + DSGraph::UpdateInlinedGlobals); } // Incorporate the inlined Function's ScalarMap into the global Index: llvm/lib/Analysis/DataStructure/TopDownClosure.cpp diff -u llvm/lib/Analysis/DataStructure/TopDownClosure.cpp:1.60 llvm/lib/Analysis/DataStructure/TopDownClosure.cpp:1.60.4.1 --- llvm/lib/Analysis/DataStructure/TopDownClosure.cpp:1.60 Wed Nov 12 17:11:14 2003 +++ llvm/lib/Analysis/DataStructure/TopDownClosure.cpp Mon Mar 1 17:58:12 2004 @@ -60,15 +60,14 @@ // they are accessible outside this compilation unit. Currently, these // arguments are functions which are reachable by global variables in the // globals graph. - const DSGraph::ScalarMapTy &GGSM = GlobalsGraph->getScalarMap(); + const DSScalarMap &GGSM = GlobalsGraph->getScalarMap(); hash_set Visited; - for (DSGraph::ScalarMapTy::const_iterator I = GGSM.begin(), E = GGSM.end(); + for (DSScalarMap::global_iterator I = GGSM.global_begin(), E = GGSM.global_end(); I != E; ++I) - if (isa(I->first)) - markReachableFunctionsExternallyAccessible(I->second.getNode(), Visited); + markReachableFunctionsExternallyAccessible(GGSM.find(*I)->second.getNode(), Visited); // Loop over unresolved call nodes. Any functions passed into (but not - // returned!?) from unresolvable call nodes may be invoked outside of the + // returned!) from unresolvable call nodes may be invoked outside of the // current module. const std::vector &Calls = GlobalsGraph->getAuxFunctionCalls(); for (unsigned i = 0, e = Calls.size(); i != e; ++i) { @@ -108,6 +107,8 @@ } ArgsRemainIncomplete.clear(); + GlobalsGraph->removeTriviallyDeadNodes(); + return false; } @@ -176,7 +177,6 @@ void TDDataStructures::inlineGraphIntoCallees(DSGraph &Graph) { // Recompute the Incomplete markers and eliminate unreachable nodes. - Graph.removeTriviallyDeadNodes(); Graph.maskIncompleteMarkers(); // If any of the functions has incomplete incoming arguments, don't mark any @@ -228,80 +228,59 @@ const BUDataStructures::ActualCalleesTy &ActualCallees = getAnalysis().getActualCallees(); - // Loop over all the call sites and all the callees at each call site. - // Clone and merge the reachable subgraph from the call into callee's graph. - // + // Loop over all the call sites and all the callees at each call site. Build + // a mapping from called DSGraph's to the call sites in this function that + // invoke them. This is useful because we can be more efficient if there are + // multiple call sites to the callees in the graph from this caller. + std::multimap > CallSites; + for (unsigned i = 0, e = FunctionCalls.size(); i != e; ++i) { Instruction *CallI = FunctionCalls[i].getCallSite().getInstruction(); // For each function in the invoked function list at this call site... std::pair IP = ActualCallees.equal_range(CallI); - - // Multiple callees may have the same graph, so try to inline and merge - // only once for each pair, not once for each - // pair; the latter will be correct but slower. - hash_set GraphsSeen; - // Loop over each actual callee at this call site for (BUDataStructures::ActualCalleesTy::const_iterator I = IP.first; I != IP.second; ++I) { DSGraph& CalleeGraph = getDSGraph(*I->second); assert(&CalleeGraph != &Graph && "TD need not inline graph into self!"); - // if this callee graph is already done at this site, skip this callee - if (GraphsSeen.find(&CalleeGraph) != GraphsSeen.end()) - continue; - GraphsSeen.insert(&CalleeGraph); - - // Get the root nodes for cloning the reachable subgraph into each callee: - // -- all global nodes that appear in both the caller and the callee - // -- return value at this call site, if any - // -- actual arguments passed at this call site - // -- callee node at this call site, if this is an indirect call (this may - // not be needed for merging, but allows us to create CS and therefore - // simplify the merging below). - hash_set RootNodeSet; - for (DSGraph::ScalarMapTy::const_iterator - SI = CalleeGraph.getScalarMap().begin(), - SE = CalleeGraph.getScalarMap().end(); SI != SE; ++SI) - if (GlobalValue* GV = dyn_cast(SI->first)) { - DSGraph::ScalarMapTy::const_iterator GI=Graph.getScalarMap().find(GV); - if (GI != Graph.getScalarMap().end()) - RootNodeSet.insert(GI->second.getNode()); - } - - if (const DSNode* RetNode = FunctionCalls[i].getRetVal().getNode()) - RootNodeSet.insert(RetNode); - - for (unsigned j=0, N=FunctionCalls[i].getNumPtrArgs(); j < N; ++j) - if (const DSNode* ArgTarget = FunctionCalls[i].getPtrArg(j).getNode()) - RootNodeSet.insert(ArgTarget); + CallSites.insert(std::make_pair(&CalleeGraph, + std::make_pair(I->second, &FunctionCalls[i]))); + } + } - if (FunctionCalls[i].isIndirectCall()) - RootNodeSet.insert(FunctionCalls[i].getCalleeNode()); + // Now that we built the mapping, actually perform the inlining a callee graph + // at a time. + std::multimap >::iterator CSI; + for (CSI = CallSites.begin(); CSI != CallSites.end(); ) { + DSGraph &CalleeGraph = *CSI->first; + // Iterate through all of the call sites of this graph, cloning and merging + // any nodes required by the call. + ReachabilityCloner RC(CalleeGraph, Graph, DSGraph::StripModRefBits); + + // Clone over any global nodes that appear in both graphs. + for (DSScalarMap::global_iterator + SI = CalleeGraph.getScalarMap().global_begin(), + SE = CalleeGraph.getScalarMap().global_end(); SI != SE; ++SI) { + DSScalarMap::const_iterator GI = Graph.getScalarMap().find(*SI); + if (GI != Graph.getScalarMap().end()) + RC.merge(CalleeGraph.getNodeForValue(*SI), GI->second); + } + // Loop over all of the distinct call sites in the caller of the callee. + for (; CSI != CallSites.end() && CSI->first == &CalleeGraph; ++CSI) { + Function &CF = *CSI->second.first; + const DSCallSite &CS = *CSI->second.second; DEBUG(std::cerr << " [TD] Resolving arguments for callee graph '" << CalleeGraph.getFunctionNames() - << "': " << I->second->getFunctionType()->getNumParams() - << " args\n at call site (DSCallSite*) 0x" - << &FunctionCalls[i] << "\n"); + << "': " << CF.getFunctionType()->getNumParams() + << " args\n at call site (DSCallSite*) 0x" << &CS << "\n"); - DSGraph::NodeMapTy NodeMapInCallee; // map from nodes to clones in callee - DSGraph::NodeMapTy CompletedMap; // unused map for nodes not to do - CalleeGraph.cloneReachableSubgraph(Graph, RootNodeSet, - NodeMapInCallee, CompletedMap, - DSGraph::StripModRefBits | - DSGraph::KeepAllocaBit); - - // Transform our call site info into the cloned version for CalleeGraph - DSCallSite CS(FunctionCalls[i], NodeMapInCallee); - - // Get the formal argument and return nodes for the called function - // and merge them with the cloned subgraph. Global nodes were merged - // already by cloneReachableSubgraph() above. - CalleeGraph.getCallSiteForArguments(*I->second).mergeWith(CS); - + // Get the formal argument and return nodes for the called function and + // merge them with the cloned subgraph. + RC.mergeCallSite(CalleeGraph.getCallSiteForArguments(CF), CS); ++NumTDInlines; } } From brukman at cs.uiuc.edu Mon Mar 1 18:05:10 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Mar 1 18:05:10 2004 Subject: [llvm-commits] [parallel] CVS: llvm/lib/Transforms/Utils/CodeExtractor.cpp LoopExtractor.cpp BreakCriticalEdges.cpp CloneFunction.cpp CloneTrace.cpp InlineFunction.cpp Linker.cpp PromoteMemoryToRegister.cpp SimplifyCFG.cpp ValueMapper.cpp Message-ID: <200403012358.RAA04027@zion.cs.uiuc.edu> Changes in directory llvm/lib/Transforms/Utils: CodeExtractor.cpp added (r1.2.2.1) LoopExtractor.cpp added (r1.2.2.1) BreakCriticalEdges.cpp updated: 1.18 -> 1.18.2.1 CloneFunction.cpp updated: 1.19 -> 1.19.2.1 CloneTrace.cpp updated: 1.5 -> 1.5.2.1 InlineFunction.cpp updated: 1.18 -> 1.18.2.1 Linker.cpp updated: 1.66 -> 1.66.2.1 PromoteMemoryToRegister.cpp updated: 1.59 -> 1.59.2.1 SimplifyCFG.cpp updated: 1.19 -> 1.19.2.1 ValueMapper.cpp updated: 1.10 -> 1.10.2.1 --- Log message: Merge from trunk --- Diffs of the changes: (+1723 -308) Index: llvm/lib/Transforms/Utils/CodeExtractor.cpp diff -c /dev/null llvm/lib/Transforms/Utils/CodeExtractor.cpp:1.2.2.1 *** /dev/null Mon Mar 1 17:58:28 2004 --- llvm/lib/Transforms/Utils/CodeExtractor.cpp Mon Mar 1 17:58:16 2004 *************** *** 0 **** --- 1,583 ---- + //===- CodeExtractor.cpp - Pull code region into a new function -----------===// + // + // The LLVM Compiler Infrastructure + // + // This file was developed by the LLVM research group and is distributed under + // the University of Illinois Open Source License. See LICENSE.TXT for details. + // + //===----------------------------------------------------------------------===// + // + // This file implements the interface to tear out a code region, such as an + // individual loop or a parallel section, into a new function, replacing it with + // a call to the new function. + // + //===----------------------------------------------------------------------===// + + #include "llvm/BasicBlock.h" + #include "llvm/Constants.h" + #include "llvm/DerivedTypes.h" + #include "llvm/Instructions.h" + #include "llvm/Module.h" + #include "llvm/Pass.h" + #include "llvm/Analysis/LoopInfo.h" + #include "llvm/Transforms/Utils/BasicBlockUtils.h" + #include "llvm/Transforms/Utils/FunctionUtils.h" + #include "Support/Debug.h" + #include "Support/StringExtras.h" + #include + #include + #include + using namespace llvm; + + namespace { + + inline bool contains(const std::vector &V, const BasicBlock *BB){ + return std::find(V.begin(), V.end(), BB) != V.end(); + } + + /// getFunctionArg - Return a pointer to F's ARGNOth argument. + /// + Argument *getFunctionArg(Function *F, unsigned argno) { + Function::aiterator ai = F->abegin(); + while (argno) { ++ai; --argno; } + return &*ai; + } + + struct CodeExtractor { + typedef std::vector Values; + typedef std::vector > PhiValChangesTy; + typedef std::map PhiVal2ArgTy; + PhiVal2ArgTy PhiVal2Arg; + + public: + Function *ExtractCodeRegion(const std::vector &code); + + private: + void findInputsOutputs(const std::vector &code, + Values &inputs, + Values &outputs, + BasicBlock *newHeader, + BasicBlock *newRootNode); + + void processPhiNodeInputs(PHINode *Phi, + const std::vector &code, + Values &inputs, + BasicBlock *newHeader, + BasicBlock *newRootNode); + + void rewritePhiNodes(Function *F, BasicBlock *newFuncRoot); + + Function *constructFunction(const Values &inputs, + const Values &outputs, + BasicBlock *newRootNode, BasicBlock *newHeader, + const std::vector &code, + Function *oldFunction, Module *M); + + void moveCodeToFunction(const std::vector &code, + Function *newFunction); + + void emitCallAndSwitchStatement(Function *newFunction, + BasicBlock *newHeader, + const std::vector &code, + Values &inputs, + Values &outputs); + + }; + } + + void CodeExtractor::processPhiNodeInputs(PHINode *Phi, + const std::vector &code, + Values &inputs, + BasicBlock *codeReplacer, + BasicBlock *newFuncRoot) + { + // Separate incoming values and BasicBlocks as internal/external. We ignore + // the case where both the value and BasicBlock are internal, because we don't + // need to do a thing. + std::vector EValEBB; + std::vector EValIBB; + std::vector IValEBB; + + for (unsigned i = 0, e = Phi->getNumIncomingValues(); i != e; ++i) { + Value *phiVal = Phi->getIncomingValue(i); + if (Instruction *Inst = dyn_cast(phiVal)) { + if (contains(code, Inst->getParent())) { + if (!contains(code, Phi->getIncomingBlock(i))) + IValEBB.push_back(i); + } else { + if (contains(code, Phi->getIncomingBlock(i))) + EValIBB.push_back(i); + else + EValEBB.push_back(i); + } + } else if (Constant *Const = dyn_cast(phiVal)) { + // Constants are internal, but considered `external' if they are coming + // from an external block. + if (!contains(code, Phi->getIncomingBlock(i))) + EValEBB.push_back(i); + } else if (Argument *Arg = dyn_cast(phiVal)) { + // arguments are external + if (contains(code, Phi->getIncomingBlock(i))) + EValIBB.push_back(i); + else + EValEBB.push_back(i); + } else { + phiVal->dump(); + assert(0 && "Unhandled input in a Phi node"); + } + } + + // Both value and block are external. Need to group all of + // these, have an external phi, pass the result as an + // argument, and have THIS phi use that result. + if (EValEBB.size() > 0) { + if (EValEBB.size() == 1) { + // Now if it's coming from the newFuncRoot, it's that funky input + unsigned phiIdx = EValEBB[0]; + if (!dyn_cast(Phi->getIncomingValue(phiIdx))) + { + PhiVal2Arg[Phi].push_back(std::make_pair(phiIdx, inputs.size())); + // We can just pass this value in as argument + inputs.push_back(Phi->getIncomingValue(phiIdx)); + } + Phi->setIncomingBlock(phiIdx, newFuncRoot); + } else { + PHINode *externalPhi = new PHINode(Phi->getType(), "extPhi"); + codeReplacer->getInstList().insert(codeReplacer->begin(), externalPhi); + for (std::vector::iterator i = EValEBB.begin(), + e = EValEBB.end(); i != e; ++i) + { + externalPhi->addIncoming(Phi->getIncomingValue(*i), + Phi->getIncomingBlock(*i)); + + // We make these values invalid instead of deleting them because that + // would shift the indices of other values... The fixPhiNodes should + // clean these phi nodes up later. + Phi->setIncomingValue(*i, 0); + Phi->setIncomingBlock(*i, 0); + } + PhiVal2Arg[Phi].push_back(std::make_pair(Phi->getNumIncomingValues(), + inputs.size())); + // We can just pass this value in as argument + inputs.push_back(externalPhi); + } + } + + // When the value is external, but block internal... + // just pass it in as argument, no change to phi node + for (std::vector::iterator i = EValIBB.begin(), + e = EValIBB.end(); i != e; ++i) + { + // rewrite the phi input node to be an argument + PhiVal2Arg[Phi].push_back(std::make_pair(*i, inputs.size())); + inputs.push_back(Phi->getIncomingValue(*i)); + } + + // Value internal, block external + // this can happen if we are extracting a part of a loop + for (std::vector::iterator i = IValEBB.begin(), + e = IValEBB.end(); i != e; ++i) + { + assert(0 && "Cannot (YET) handle internal values via external blocks"); + } + } + + + void CodeExtractor::findInputsOutputs(const std::vector &code, + Values &inputs, + Values &outputs, + BasicBlock *newHeader, + BasicBlock *newRootNode) + { + for (std::vector::const_iterator ci = code.begin(), + ce = code.end(); ci != ce; ++ci) { + BasicBlock *BB = *ci; + for (BasicBlock::iterator BBi = BB->begin(), BBe = BB->end(); + BBi != BBe; ++BBi) { + // If a use is defined outside the region, it's an input. + // If a def is used outside the region, it's an output. + if (Instruction *I = dyn_cast(&*BBi)) { + // If it's a phi node + if (PHINode *Phi = dyn_cast(I)) { + processPhiNodeInputs(Phi, code, inputs, newHeader, newRootNode); + } else { + // All other instructions go through the generic input finder + // Loop over the operands of each instruction (inputs) + for (User::op_iterator op = I->op_begin(), opE = I->op_end(); + op != opE; ++op) { + if (Instruction *opI = dyn_cast(op->get())) { + // Check if definition of this operand is within the loop + if (!contains(code, opI->getParent())) { + // add this operand to the inputs + inputs.push_back(opI); + } + } + } + } + + // Consider uses of this instruction (outputs) + for (Value::use_iterator use = I->use_begin(), useE = I->use_end(); + use != useE; ++use) { + if (Instruction* inst = dyn_cast(*use)) { + if (!contains(code, inst->getParent())) { + // add this op to the outputs + outputs.push_back(I); + } + } + } + } /* if */ + } /* for: insts */ + } /* for: basic blocks */ + } + + void CodeExtractor::rewritePhiNodes(Function *F, + BasicBlock *newFuncRoot) { + // Write any changes that were saved before: use function arguments as inputs + for (PhiVal2ArgTy::iterator i = PhiVal2Arg.begin(), e = PhiVal2Arg.end(); + i != e; ++i) + { + PHINode *phi = (*i).first; + PhiValChangesTy &values = (*i).second; + for (unsigned cIdx = 0, ce = values.size(); cIdx != ce; ++cIdx) + { + unsigned phiValueIdx = values[cIdx].first, argNum = values[cIdx].second; + if (phiValueIdx < phi->getNumIncomingValues()) + phi->setIncomingValue(phiValueIdx, getFunctionArg(F, argNum)); + else + phi->addIncoming(getFunctionArg(F, argNum), newFuncRoot); + } + } + + // Delete any invalid Phi node inputs that were marked as NULL previously + for (PhiVal2ArgTy::iterator i = PhiVal2Arg.begin(), e = PhiVal2Arg.end(); + i != e; ++i) + { + PHINode *phi = (*i).first; + for (unsigned idx = 0, end = phi->getNumIncomingValues(); idx != end; ++idx) + { + if (phi->getIncomingValue(idx) == 0 && phi->getIncomingBlock(idx) == 0) { + phi->removeIncomingValue(idx); + --idx; + --end; + } + } + } + + // We are done with the saved values + PhiVal2Arg.clear(); + } + + + /// constructFunction - make a function based on inputs and outputs, as follows: + /// f(in0, ..., inN, out0, ..., outN) + /// + Function *CodeExtractor::constructFunction(const Values &inputs, + const Values &outputs, + BasicBlock *newRootNode, + BasicBlock *newHeader, + const std::vector &code, + Function *oldFunction, Module *M) { + DEBUG(std::cerr << "inputs: " << inputs.size() << "\n"); + DEBUG(std::cerr << "outputs: " << outputs.size() << "\n"); + BasicBlock *header = code[0]; + + // This function returns unsigned, outputs will go back by reference. + Type *retTy = Type::UShortTy; + std::vector paramTy; + + // Add the types of the input values to the function's argument list + for (Values::const_iterator i = inputs.begin(), + e = inputs.end(); i != e; ++i) { + const Value *value = *i; + DEBUG(std::cerr << "value used in func: " << value << "\n"); + paramTy.push_back(value->getType()); + } + + // Add the types of the output values to the function's argument list, but + // make them pointer types for scalars + for (Values::const_iterator i = outputs.begin(), + e = outputs.end(); i != e; ++i) { + const Value *value = *i; + DEBUG(std::cerr << "instr used in func: " << value << "\n"); + const Type *valueType = value->getType(); + // Convert scalar types into a pointer of that type + if (valueType->isPrimitiveType()) { + valueType = PointerType::get(valueType); + } + paramTy.push_back(valueType); + } + + DEBUG(std::cerr << "Function type: " << retTy << " f("); + for (std::vector::iterator i = paramTy.begin(), + e = paramTy.end(); i != e; ++i) + DEBUG(std::cerr << (*i) << ", "); + DEBUG(std::cerr << ")\n"); + + const FunctionType *funcType = FunctionType::get(retTy, paramTy, false); + + // Create the new function + Function *newFunction = new Function(funcType, + GlobalValue::InternalLinkage, + oldFunction->getName() + "_code", M); + newFunction->getBasicBlockList().push_back(newRootNode); + + for (unsigned i = 0, e = inputs.size(); i != e; ++i) { + std::vector Users(inputs[i]->use_begin(), inputs[i]->use_end()); + for (std::vector::iterator use = Users.begin(), useE = Users.end(); + use != useE; ++use) { + if (Instruction* inst = dyn_cast(*use)) { + if (contains(code, inst->getParent())) { + inst->replaceUsesOfWith(inputs[i], getFunctionArg(newFunction, i)); + } + } + } + } + + // Rewrite branches to basic blocks outside of the loop to new dummy blocks + // within the new function. This must be done before we lose track of which + // blocks were originally in the code region. + std::vector Users(header->use_begin(), header->use_end()); + for (std::vector::iterator i = Users.begin(), e = Users.end(); + i != e; ++i) { + if (BranchInst *inst = dyn_cast(*i)) { + BasicBlock *BB = inst->getParent(); + if (!contains(code, BB) && BB->getParent() == oldFunction) { + // The BasicBlock which contains the branch is not in the region + // modify the branch target to a new block + inst->replaceUsesOfWith(header, newHeader); + } + } + } + + return newFunction; + } + + void CodeExtractor::moveCodeToFunction(const std::vector &code, + Function *newFunction) + { + for (std::vector::const_iterator i = code.begin(), e =code.end(); + i != e; ++i) { + BasicBlock *BB = *i; + Function *oldFunc = BB->getParent(); + Function::BasicBlockListType &oldBlocks = oldFunc->getBasicBlockList(); + + // Delete the basic block from the old function, and the list of blocks + oldBlocks.remove(BB); + + // Insert this basic block into the new function + Function::BasicBlockListType &newBlocks = newFunction->getBasicBlockList(); + newBlocks.push_back(BB); + } + } + + void + CodeExtractor::emitCallAndSwitchStatement(Function *newFunction, + BasicBlock *codeReplacer, + const std::vector &code, + Values &inputs, + Values &outputs) + { + // Emit a call to the new function, passing allocated memory for outputs and + // just plain inputs for non-scalars + std::vector params; + BasicBlock *codeReplacerTail = new BasicBlock("codeReplTail", + codeReplacer->getParent()); + for (Values::const_iterator i = inputs.begin(), + e = inputs.end(); i != e; ++i) + params.push_back(*i); + for (Values::const_iterator i = outputs.begin(), + e = outputs.end(); i != e; ++i) { + // Create allocas for scalar outputs + if ((*i)->getType()->isPrimitiveType()) { + Constant *one = ConstantUInt::get(Type::UIntTy, 1); + AllocaInst *alloca = new AllocaInst((*i)->getType(), one); + codeReplacer->getInstList().push_back(alloca); + params.push_back(alloca); + + LoadInst *load = new LoadInst(alloca, "alloca"); + codeReplacerTail->getInstList().push_back(load); + std::vector Users((*i)->use_begin(), (*i)->use_end()); + for (std::vector::iterator use = Users.begin(), useE =Users.end(); + use != useE; ++use) { + if (Instruction* inst = dyn_cast(*use)) { + if (!contains(code, inst->getParent())) { + inst->replaceUsesOfWith(*i, load); + } + } + } + } else { + params.push_back(*i); + } + } + CallInst *call = new CallInst(newFunction, params, "targetBlock"); + codeReplacer->getInstList().push_back(call); + codeReplacer->getInstList().push_back(new BranchInst(codeReplacerTail)); + + // Now we can emit a switch statement using the call as a value. + // FIXME: perhaps instead of default being self BB, it should be a second + // dummy block which asserts that the value is not within the range...? + //BasicBlock *defaultBlock = new BasicBlock("defaultBlock", oldF); + //insert abort() ? + //defaultBlock->getInstList().push_back(new BranchInst(codeReplacer)); + + SwitchInst *switchInst = new SwitchInst(call, codeReplacerTail, + codeReplacerTail); + + // Since there may be multiple exits from the original region, make the new + // function return an unsigned, switch on that number + unsigned switchVal = 0; + for (std::vector::const_iterator i =code.begin(), e = code.end(); + i != e; ++i) { + BasicBlock *BB = *i; + + // rewrite the terminator of the original BasicBlock + Instruction *term = BB->getTerminator(); + if (BranchInst *brInst = dyn_cast(term)) { + + // Restore values just before we exit + // FIXME: Use a GetElementPtr to bunch the outputs in a struct + for (unsigned outIdx = 0, outE = outputs.size(); outIdx != outE; ++outIdx) + { + new StoreInst(outputs[outIdx], + getFunctionArg(newFunction, outIdx), + brInst); + } + + // Rewrite branches into exists which return a value based on which + // exit we take from this function + if (brInst->isUnconditional()) { + if (!contains(code, brInst->getSuccessor(0))) { + ConstantUInt *brVal = ConstantUInt::get(Type::UShortTy, switchVal); + ReturnInst *newRet = new ReturnInst(brVal); + // add a new target to the switch + switchInst->addCase(brVal, brInst->getSuccessor(0)); + ++switchVal; + // rewrite the branch with a return + BasicBlock::iterator ii(brInst); + ReplaceInstWithInst(BB->getInstList(), ii, newRet); + delete brInst; + } + } else { + // Replace the conditional branch to branch + // to two new blocks, each of which returns a different code. + for (unsigned idx = 0; idx < 2; ++idx) { + BasicBlock *oldTarget = brInst->getSuccessor(idx); + if (!contains(code, oldTarget)) { + // add a new basic block which returns the appropriate value + BasicBlock *newTarget = new BasicBlock("newTarget", newFunction); + ConstantUInt *brVal = ConstantUInt::get(Type::UShortTy, switchVal); + ReturnInst *newRet = new ReturnInst(brVal); + newTarget->getInstList().push_back(newRet); + // rewrite the original branch instruction with this new target + brInst->setSuccessor(idx, newTarget); + // the switch statement knows what to do with this value + switchInst->addCase(brVal, oldTarget); + ++switchVal; + } + } + } + } else if (ReturnInst *retTerm = dyn_cast(term)) { + assert(0 && "Cannot handle return instructions just yet."); + // FIXME: what if the terminator is a return!??! + // Need to rewrite: add new basic block, move the return there + // treat the original as an unconditional branch to that basicblock + } else if (SwitchInst *swTerm = dyn_cast(term)) { + assert(0 && "Cannot handle switch instructions just yet."); + } else if (InvokeInst *invInst = dyn_cast(term)) { + assert(0 && "Cannot handle invoke instructions just yet."); + } else { + assert(0 && "Unrecognized terminator, or badly-formed BasicBlock."); + } + } + } + + + /// ExtractRegion - Removes a loop from a function, replaces it with a call to + /// new function. Returns pointer to the new function. + /// + /// algorithm: + /// + /// find inputs and outputs for the region + /// + /// for inputs: add to function as args, map input instr* to arg# + /// for outputs: add allocas for scalars, + /// add to func as args, map output instr* to arg# + /// + /// rewrite func to use argument #s instead of instr* + /// + /// for each scalar output in the function: at every exit, store intermediate + /// computed result back into memory. + /// + Function *CodeExtractor::ExtractCodeRegion(const std::vector &code) + { + // 1) Find inputs, outputs + // 2) Construct new function + // * Add allocas for defs, pass as args by reference + // * Pass in uses as args + // 3) Move code region, add call instr to func + // + + Values inputs, outputs; + + // Assumption: this is a single-entry code region, and the header is the first + // block in the region. FIXME: is this true for a list of blocks from a + // natural function? + BasicBlock *header = code[0]; + Function *oldFunction = header->getParent(); + Module *module = oldFunction->getParent(); + + // This takes place of the original loop + BasicBlock *codeReplacer = new BasicBlock("codeRepl", oldFunction); + + // The new function needs a root node because other nodes can branch to the + // head of the loop, and the root cannot have predecessors + BasicBlock *newFuncRoot = new BasicBlock("newFuncRoot"); + newFuncRoot->getInstList().push_back(new BranchInst(header)); + + // Find inputs to, outputs from the code region + // + // If one of the inputs is coming from a different basic block and it's in a + // phi node, we need to rewrite the phi node: + // + // * All the inputs which involve basic blocks OUTSIDE of this region go into + // a NEW phi node that takes care of finding which value really came in. + // The result of this phi is passed to the function as an argument. + // + // * All the other phi values stay. + // + // FIXME: PHI nodes' incoming blocks aren't being rewritten to accomodate for + // blocks moving to a new function. + // SOLUTION: move Phi nodes out of the loop header into the codeReplacer, pass + // the values as parameters to the function + findInputsOutputs(code, inputs, outputs, codeReplacer, newFuncRoot); + + // Step 2: Construct new function based on inputs/outputs, + // Add allocas for all defs + Function *newFunction = constructFunction(inputs, outputs, newFuncRoot, + codeReplacer, code, + oldFunction, module); + + rewritePhiNodes(newFunction, newFuncRoot); + + emitCallAndSwitchStatement(newFunction, codeReplacer, code, inputs, outputs); + + moveCodeToFunction(code, newFunction); + + return newFunction; + } + + /// ExtractBasicBlock - slurp a natural loop into a brand new function + /// + Function* llvm::ExtractLoop(Loop *L) { + CodeExtractor CE; + return CE.ExtractCodeRegion(L->getBlocks()); + } + + /// ExtractBasicBlock - slurp a basic block into a brand new function + /// + Function* llvm::ExtractBasicBlock(BasicBlock *BB) { + CodeExtractor CE; + std::vector Blocks; + Blocks.push_back(BB); + return CE.ExtractCodeRegion(Blocks); + } Index: llvm/lib/Transforms/Utils/LoopExtractor.cpp diff -c /dev/null llvm/lib/Transforms/Utils/LoopExtractor.cpp:1.2.2.1 *** /dev/null Mon Mar 1 17:58:28 2004 --- llvm/lib/Transforms/Utils/LoopExtractor.cpp Mon Mar 1 17:58:16 2004 *************** *** 0 **** --- 1,69 ---- + //===- LoopExtractor.cpp - Extract each loop into a new function ----------===// + // + // A pass wrapper around the ExtractLoop() scalar transformation to extract each + // top-level loop into its own new function. If the loop is the ONLY loop in a + // given function, it is not touched. + // + //===----------------------------------------------------------------------===// + + #include "llvm/Module.h" + #include "llvm/Pass.h" + #include "llvm/Analysis/LoopInfo.h" + #include "llvm/Transforms/Scalar.h" + #include "llvm/Transforms/Utils/FunctionUtils.h" + #include + using namespace llvm; + + namespace { + + // FIXME: PassManager should allow Module passes to require FunctionPasses + struct LoopExtractor : public FunctionPass { + + public: + LoopExtractor() {} + virtual bool run(Module &M); + virtual bool runOnFunction(Function &F); + + virtual void getAnalysisUsage(AnalysisUsage &AU) const { + AU.addRequired(); + } + + }; + + RegisterOpt + X("loop-extract", "Extract loops into new functions"); + + bool LoopExtractor::run(Module &M) { + bool Changed = false; + for (Module::iterator i = M.begin(), e = M.end(); i != e; ++i) + Changed |= runOnFunction(*i); + return Changed; + } + + bool LoopExtractor::runOnFunction(Function &F) { + std::cerr << F.getName() << "\n"; + + LoopInfo &LI = getAnalysis(); + + // We don't want to keep extracting the only loop of a function into a new one + if (LI.begin() == LI.end() || LI.begin() + 1 == LI.end()) + return false; + + bool Changed = false; + + // Try to move each loop out of the code into separate function + for (LoopInfo::iterator i = LI.begin(), e = LI.end(); i != e; ++i) + Changed |= (ExtractLoop(*i) != 0); + + return Changed; + } + + + + } // End anonymous namespace + + /// createLoopExtractorPass + /// + FunctionPass* llvm::createLoopExtractorPass() { + return new LoopExtractor(); + } Index: llvm/lib/Transforms/Utils/BreakCriticalEdges.cpp diff -u llvm/lib/Transforms/Utils/BreakCriticalEdges.cpp:1.18 llvm/lib/Transforms/Utils/BreakCriticalEdges.cpp:1.18.2.1 --- llvm/lib/Transforms/Utils/BreakCriticalEdges.cpp:1.18 Fri Jan 9 00:12:10 2004 +++ llvm/lib/Transforms/Utils/BreakCriticalEdges.cpp Mon Mar 1 17:58:16 2004 @@ -119,8 +119,11 @@ // for (BasicBlock::iterator I = DestBB->begin(); PHINode *PN = dyn_cast(I); ++I) { - // We no longer enter through TIBB, now we come in through NewBB. - PN->replaceUsesOfWith(TIBB, NewBB); + // We no longer enter through TIBB, now we come in through NewBB. Revector + // exactly one entry in the PHI node that used to come from TIBB to come + // from NewBB. + Value *InVal = PN->removeIncomingValue(TIBB, false); + PN->addIncoming(InVal, NewBB); } // If we don't have a pass object, we can't update anything... Index: llvm/lib/Transforms/Utils/CloneFunction.cpp diff -u llvm/lib/Transforms/Utils/CloneFunction.cpp:1.19 llvm/lib/Transforms/Utils/CloneFunction.cpp:1.19.2.1 --- llvm/lib/Transforms/Utils/CloneFunction.cpp:1.19 Fri Jan 9 00:12:12 2004 +++ llvm/lib/Transforms/Utils/CloneFunction.cpp Mon Mar 1 17:58:16 2004 @@ -42,8 +42,8 @@ // CloneBasicBlock - See comments in Cloning.h BasicBlock *llvm::CloneBasicBlock(const BasicBlock *BB, std::map &ValueMap, - const char *NameSuffix) { - BasicBlock *NewBB = new BasicBlock(""); + const char *NameSuffix, Function *F) { + BasicBlock *NewBB = new BasicBlock("", F); if (BB->hasName()) NewBB->setName(BB->getName()+NameSuffix); // Loop over all instructions copying them over... @@ -82,8 +82,7 @@ const BasicBlock &BB = *BI; // Create a new basic block and copy instructions into it! - BasicBlock *CBB = CloneBasicBlock(&BB, ValueMap, NameSuffix); - NewFunc->getBasicBlockList().push_back(CBB); + BasicBlock *CBB = CloneBasicBlock(&BB, ValueMap, NameSuffix, NewFunc); ValueMap[&BB] = CBB; // Add basic block mapping. if (ReturnInst *RI = dyn_cast(CBB->getTerminator())) @@ -93,14 +92,11 @@ // Loop over all of the instructions in the function, fixing up operand // references as we go. This uses ValueMap to do all the hard work. // - for (Function::const_iterator BB = OldFunc->begin(), BE = OldFunc->end(); - BB != BE; ++BB) { - BasicBlock *NBB = cast(ValueMap[BB]); - + for (Function::iterator BB = cast(ValueMap[OldFunc->begin()]), + BE = NewFunc->end(); BB != BE; ++BB) // Loop over all instructions, fixing each one as we find it... - for (BasicBlock::iterator II = NBB->begin(); II != NBB->end(); ++II) + for (BasicBlock::iterator II = BB->begin(); II != BB->end(); ++II) RemapInstruction(II, ValueMap); - } } /// CloneFunction - Return a copy of the specified function, but without Index: llvm/lib/Transforms/Utils/CloneTrace.cpp diff -u llvm/lib/Transforms/Utils/CloneTrace.cpp:1.5 llvm/lib/Transforms/Utils/CloneTrace.cpp:1.5.2.1 --- llvm/lib/Transforms/Utils/CloneTrace.cpp:1.5 Fri Jan 9 00:12:15 2004 +++ llvm/lib/Transforms/Utils/CloneTrace.cpp Mon Mar 1 17:58:16 2004 @@ -7,11 +7,11 @@ // //===----------------------------------------------------------------------===// // -// This file implements the CloneTrace interface, which is used -// when writing runtime optimizations. It takes a vector of basic blocks -// clones the basic blocks, removes internal phi nodes, adds it to the -// same function as the original (although there is no jump to it) and -// returns the new vector of basic blocks. +// This file implements the CloneTrace interface, which is used when writing +// runtime optimizations. It takes a vector of basic blocks clones the basic +// blocks, removes internal phi nodes, adds it to the same function as the +// original (although there is no jump to it) and returns the new vector of +// basic blocks. // //===----------------------------------------------------------------------===// @@ -34,16 +34,14 @@ End = origTrace.end(); T != End; ++T) { //Clone Basic Block - BasicBlock *clonedBlock = CloneBasicBlock(*T, ValueMap); + BasicBlock *clonedBlock = + CloneBasicBlock(*T, ValueMap, ".tr", (*T)->getParent()); //Add it to our new trace clonedTrace.push_back(clonedBlock); //Add this new mapping to our Value Map ValueMap[*T] = clonedBlock; - - //Add this cloned BB to the old BB's function - (*T)->getParent()->getBasicBlockList().push_back(clonedBlock); //Loop over the phi instructions and delete operands //that are from blocks not in the trace Index: llvm/lib/Transforms/Utils/InlineFunction.cpp diff -u llvm/lib/Transforms/Utils/InlineFunction.cpp:1.18 llvm/lib/Transforms/Utils/InlineFunction.cpp:1.18.2.1 --- llvm/lib/Transforms/Utils/InlineFunction.cpp:1.18 Fri Jan 9 00:12:20 2004 +++ llvm/lib/Transforms/Utils/InlineFunction.cpp Mon Mar 1 17:58:16 2004 @@ -11,7 +11,7 @@ // parameters and the return value as appropriate. // // FIXME: This pass should transform alloca instructions in the called function -// into malloc/free pairs! Or perhaps it should refuse to inline them! +// into alloca/dealloca pairs! Or perhaps it should refuse to inline them! // //===----------------------------------------------------------------------===// @@ -50,183 +50,112 @@ BasicBlock *OrigBB = TheCall->getParent(); Function *Caller = OrigBB->getParent(); - // We want to clone the entire callee function into the whole between the - // "starter" and "ender" blocks. How we accomplish this depends on whether - // this is an invoke instruction or a call instruction. - - BasicBlock *InvokeDest = 0; // Exception handling destination - std::vector InvokeDestPHIValues; // Values for PHI nodes in InvokeDest - BasicBlock *AfterCallBB; - - if (InvokeInst *II = dyn_cast(TheCall)) { - InvokeDest = II->getExceptionalDest(); - - // If there are PHI nodes in the exceptional destination block, we need to - // keep track of which values came into them from this invoke, then remove - // the entry for this block. - for (BasicBlock::iterator I = InvokeDest->begin(); - PHINode *PN = dyn_cast(I); ++I) { - // Save the value to use for this edge... - InvokeDestPHIValues.push_back(PN->getIncomingValueForBlock(OrigBB)); - } - - // Add an unconditional branch to make this look like the CallInst case... - BranchInst *NewBr = new BranchInst(II->getNormalDest(), TheCall); - - // Split the basic block. This guarantees that no PHI nodes will have to be - // updated due to new incoming edges, and make the invoke case more - // symmetric to the call case. - AfterCallBB = OrigBB->splitBasicBlock(NewBr, - CalledFunc->getName()+".entry"); - - // Remove (unlink) the InvokeInst from the function... - OrigBB->getInstList().remove(TheCall); - - } else { // It's a call - // If this is a call instruction, we need to split the basic block that the - // call lives in. - // - AfterCallBB = OrigBB->splitBasicBlock(TheCall, - CalledFunc->getName()+".entry"); - // Remove (unlink) the CallInst from the function... - AfterCallBB->getInstList().remove(TheCall); - } - - // If we have a return value generated by this call, convert it into a PHI - // node that gets values from each of the old RET instructions in the original - // function. - // - PHINode *PHI = 0; - if (!TheCall->use_empty()) { - // The PHI node should go at the front of the new basic block to merge all - // possible incoming values. - // - PHI = new PHINode(CalledFunc->getReturnType(), TheCall->getName(), - AfterCallBB->begin()); - - // Anything that used the result of the function call should now use the PHI - // node as their operand. - // - TheCall->replaceAllUsesWith(PHI); - } - // Get an iterator to the last basic block in the function, which will have // the new function inlined after it. // Function::iterator LastBlock = &Caller->back(); - // Calculate the vector of arguments to pass into the function cloner... - std::map ValueMap; - assert(std::distance(CalledFunc->abegin(), CalledFunc->aend()) == - std::distance(CS.arg_begin(), CS.arg_end()) && - "No varargs calls can be inlined!"); - - CallSite::arg_iterator AI = CS.arg_begin(); - for (Function::const_aiterator I = CalledFunc->abegin(), E=CalledFunc->aend(); - I != E; ++I, ++AI) - ValueMap[I] = *AI; - - // Since we are now done with the Call/Invoke, we can delete it. - delete TheCall; - - // Make a vector to capture the return instructions in the cloned function... + // Make sure to capture all of the return instructions from the cloned + // function. std::vector Returns; + { // Scope to destroy ValueMap after cloning. + // Calculate the vector of arguments to pass into the function cloner... + std::map ValueMap; + assert(std::distance(CalledFunc->abegin(), CalledFunc->aend()) == + std::distance(CS.arg_begin(), CS.arg_end()) && + "No varargs calls can be inlined!"); + + CallSite::arg_iterator AI = CS.arg_begin(); + for (Function::const_aiterator I = CalledFunc->abegin(), + E = CalledFunc->aend(); I != E; ++I, ++AI) + ValueMap[I] = *AI; + + // Clone the entire body of the callee into the caller. + CloneFunctionInto(Caller, CalledFunc, ValueMap, Returns, ".i"); + } - // Do all of the hard part of cloning the callee into the caller... - CloneFunctionInto(Caller, CalledFunc, ValueMap, Returns, ".i"); - - // Loop over all of the return instructions, turning them into unconditional - // branches to the merge point now... - for (unsigned i = 0, e = Returns.size(); i != e; ++i) { - ReturnInst *RI = Returns[i]; - BasicBlock *BB = RI->getParent(); - - // Add a branch to the merge point where the PHI node lives if it exists. - new BranchInst(AfterCallBB, RI); - - if (PHI) { // The PHI node should include this value! - assert(RI->getReturnValue() && "Ret should have value!"); - assert(RI->getReturnValue()->getType() == PHI->getType() && - "Ret value not consistent in function!"); - PHI->addIncoming(RI->getReturnValue(), BB); - } - - // Delete the return instruction now - BB->getInstList().erase(RI); - } - - // Check to see if the PHI node only has one argument. This is a common - // case resulting from there only being a single return instruction in the - // function call. Because this is so common, eliminate the PHI node. - // - if (PHI && PHI->getNumIncomingValues() == 1) { - PHI->replaceAllUsesWith(PHI->getIncomingValue(0)); - PHI->getParent()->getInstList().erase(PHI); - } - - // Change the branch that used to go to AfterCallBB to branch to the first - // basic block of the inlined function. - // - TerminatorInst *Br = OrigBB->getTerminator(); - assert(Br && Br->getOpcode() == Instruction::Br && - "splitBasicBlock broken!"); - Br->setOperand(0, ++LastBlock); + // Remember the first block that is newly cloned over. + Function::iterator FirstNewBlock = LastBlock; ++FirstNewBlock; // If there are any alloca instructions in the block that used to be the entry // block for the callee, move them to the entry block of the caller. First // calculate which instruction they should be inserted before. We insert the // instructions at the end of the current alloca list. // - if (isa(LastBlock->begin())) { + if (isa(FirstNewBlock->begin())) { BasicBlock::iterator InsertPoint = Caller->begin()->begin(); - while (isa(InsertPoint)) ++InsertPoint; - - for (BasicBlock::iterator I = LastBlock->begin(), E = LastBlock->end(); - I != E; ) + for (BasicBlock::iterator I = FirstNewBlock->begin(), + E = FirstNewBlock->end(); I != E; ) if (AllocaInst *AI = dyn_cast(I++)) if (isa(AI->getArraySize())) { - LastBlock->getInstList().remove(AI); - Caller->front().getInstList().insert(InsertPoint, AI); + // Scan for the block of allocas that we can move over. + while (isa(I) && + isa(cast(I)->getArraySize())) + ++I; + + // Transfer all of the allocas over in a block. Using splice means + // that they instructions aren't removed from the symbol table, then + // reinserted. + Caller->front().getInstList().splice(InsertPoint, + FirstNewBlock->getInstList(), + AI, I); } } - // If we just inlined a call due to an invoke instruction, scan the inlined - // function checking for function calls that should now be made into invoke - // instructions, and for unwind's which should be turned into branches. - if (InvokeDest) { - for (Function::iterator BB = LastBlock, E = Caller->end(); BB != E; ++BB) { + // If we are inlining for an invoke instruction, we must make sure to rewrite + // any inlined 'unwind' instructions into branches to the invoke exception + // destination, and call instructions into invoke instructions. + if (InvokeInst *II = dyn_cast(TheCall)) { + BasicBlock *InvokeDest = II->getUnwindDest(); + std::vector InvokeDestPHIValues; + + // If there are PHI nodes in the exceptional destination block, we need to + // keep track of which values came into them from this invoke, then remove + // the entry for this block. + for (BasicBlock::iterator I = InvokeDest->begin(); + PHINode *PN = dyn_cast(I); ++I) + // Save the value to use for this edge... + InvokeDestPHIValues.push_back(PN->getIncomingValueForBlock(OrigBB)); + + for (Function::iterator BB = FirstNewBlock, E = Caller->end(); + BB != E; ++BB) { for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ) { // We only need to check for function calls: inlined invoke instructions // require no special handling... if (CallInst *CI = dyn_cast(I)) { - // Convert this function call into an invoke instruction... - - // First, split the basic block... - BasicBlock *Split = BB->splitBasicBlock(CI, CI->getName()+".noexc"); - - // Next, create the new invoke instruction, inserting it at the end - // of the old basic block. - InvokeInst *II = - new InvokeInst(CI->getCalledValue(), Split, InvokeDest, - std::vector(CI->op_begin()+1, CI->op_end()), - CI->getName(), BB->getTerminator()); - - // Make sure that anything using the call now uses the invoke! - CI->replaceAllUsesWith(II); - - // Delete the unconditional branch inserted by splitBasicBlock - BB->getInstList().pop_back(); - Split->getInstList().pop_front(); // Delete the original call - - // Update any PHI nodes in the exceptional block to indicate that - // there is now a new entry in them. - unsigned i = 0; - for (BasicBlock::iterator I = InvokeDest->begin(); - PHINode *PN = dyn_cast(I); ++I, ++i) - PN->addIncoming(InvokeDestPHIValues[i], BB); - - // This basic block is now complete, start scanning the next one. - break; + // Convert this function call into an invoke instruction... if it's + // not an intrinsic function call (which are known to not throw). + if (CI->getCalledFunction() && + CI->getCalledFunction()->getIntrinsicID()) { + ++I; + } else { + // First, split the basic block... + BasicBlock *Split = BB->splitBasicBlock(CI, CI->getName()+".noexc"); + + // Next, create the new invoke instruction, inserting it at the end + // of the old basic block. + InvokeInst *II = + new InvokeInst(CI->getCalledValue(), Split, InvokeDest, + std::vector(CI->op_begin()+1, CI->op_end()), + CI->getName(), BB->getTerminator()); + + // Make sure that anything using the call now uses the invoke! + CI->replaceAllUsesWith(II); + + // Delete the unconditional branch inserted by splitBasicBlock + BB->getInstList().pop_back(); + Split->getInstList().pop_front(); // Delete the original call + + // Update any PHI nodes in the exceptional block to indicate that + // there is now a new entry in them. + unsigned i = 0; + for (BasicBlock::iterator I = InvokeDest->begin(); + PHINode *PN = dyn_cast(I); ++I, ++i) + PN->addIncoming(InvokeDestPHIValues[i], BB); + + // This basic block is now complete, start scanning the next one. + break; + } } else { ++I; } @@ -255,27 +184,145 @@ // the exception destination block still have entries due to the original // invoke instruction. Eliminate these entries (which might even delete the // PHI node) now. - for (BasicBlock::iterator I = InvokeDest->begin(); - PHINode *PN = dyn_cast(I); ++I) - PN->removeIncomingValue(AfterCallBB); + InvokeDest->removePredecessor(II->getParent()); + } + + // If we cloned in _exactly one_ basic block, and if that block ends in a + // return instruction, we splice the body of the inlined callee directly into + // the calling basic block. + if (Returns.size() == 1 && std::distance(FirstNewBlock, Caller->end()) == 1) { + // Move all of the instructions right before the call. + OrigBB->getInstList().splice(TheCall, FirstNewBlock->getInstList(), + FirstNewBlock->begin(), FirstNewBlock->end()); + // Remove the cloned basic block. + Caller->getBasicBlockList().pop_back(); + + // If the call site was an invoke instruction, add a branch to the normal + // destination. + if (InvokeInst *II = dyn_cast(TheCall)) + new BranchInst(II->getNormalDest(), TheCall); + + // If the return instruction returned a value, replace uses of the call with + // uses of the returned value. + if (!TheCall->use_empty()) + TheCall->replaceAllUsesWith(Returns[0]->getReturnValue()); + + // Since we are now done with the Call/Invoke, we can delete it. + TheCall->getParent()->getInstList().erase(TheCall); + + // Since we are now done with the return instruction, delete it also. + Returns[0]->getParent()->getInstList().erase(Returns[0]); + + // We are now done with the inlining. + return true; + } + + // Otherwise, we have the normal case, of more than one block to inline or + // multiple return sites. + + // We want to clone the entire callee function into the hole between the + // "starter" and "ender" blocks. How we accomplish this depends on whether + // this is an invoke instruction or a call instruction. + BasicBlock *AfterCallBB; + if (InvokeInst *II = dyn_cast(TheCall)) { + + // Add an unconditional branch to make this look like the CallInst case... + BranchInst *NewBr = new BranchInst(II->getNormalDest(), TheCall); + + // Split the basic block. This guarantees that no PHI nodes will have to be + // updated due to new incoming edges, and make the invoke case more + // symmetric to the call case. + AfterCallBB = OrigBB->splitBasicBlock(NewBr, + CalledFunc->getName()+".entry"); + + } else { // It's a call + // If this is a call instruction, we need to split the basic block that + // the call lives in. + // + AfterCallBB = OrigBB->splitBasicBlock(TheCall, + CalledFunc->getName()+".entry"); } + + // Change the branch that used to go to AfterCallBB to branch to the first + // basic block of the inlined function. + // + TerminatorInst *Br = OrigBB->getTerminator(); + assert(Br && Br->getOpcode() == Instruction::Br && + "splitBasicBlock broken!"); + Br->setOperand(0, FirstNewBlock); + + // Now that the function is correct, make it a little bit nicer. In // particular, move the basic blocks inserted from the end of the function // into the space made by splitting the source basic block. // - Caller->getBasicBlockList().splice(AfterCallBB, Caller->getBasicBlockList(), - LastBlock, Caller->end()); + Caller->getBasicBlockList().splice(AfterCallBB, Caller->getBasicBlockList(), + FirstNewBlock, Caller->end()); + + // Handle all of the return instructions that we just cloned in, and eliminate + // any users of the original call/invoke instruction. + if (Returns.size() > 1) { + // The PHI node should go at the front of the new basic block to merge all + // possible incoming values. + // + PHINode *PHI = 0; + if (!TheCall->use_empty()) { + PHI = new PHINode(CalledFunc->getReturnType(), + TheCall->getName(), AfterCallBB->begin()); + + // Anything that used the result of the function call should now use the + // PHI node as their operand. + // + TheCall->replaceAllUsesWith(PHI); + } + + // Loop over all of the return instructions, turning them into unconditional + // branches to the merge point now, and adding entries to the PHI node as + // appropriate. + for (unsigned i = 0, e = Returns.size(); i != e; ++i) { + ReturnInst *RI = Returns[i]; + + if (PHI) { + assert(RI->getReturnValue() && "Ret should have value!"); + assert(RI->getReturnValue()->getType() == PHI->getType() && + "Ret value not consistent in function!"); + PHI->addIncoming(RI->getReturnValue(), RI->getParent()); + } + + // Add a branch to the merge point where the PHI node lives if it exists. + new BranchInst(AfterCallBB, RI); + + // Delete the return instruction now + RI->getParent()->getInstList().erase(RI); + } + + } else if (!Returns.empty()) { + // Otherwise, if there is exactly one return value, just replace anything + // using the return value of the call with the computed value. + if (!TheCall->use_empty()) + TheCall->replaceAllUsesWith(Returns[0]->getReturnValue()); + + // Add a branch to the merge point where the PHI node lives if it exists. + new BranchInst(AfterCallBB, Returns[0]); + + // Delete the return instruction now + Returns[0]->getParent()->getInstList().erase(Returns[0]); + } + + // Since we are now done with the Call/Invoke, we can delete it. + TheCall->getParent()->getInstList().erase(TheCall); // We should always be able to fold the entry block of the function into the // single predecessor of the block... - assert(cast(Br)->isUnconditional() && "splitBasicBlock broken!"); + assert(cast(Br)->isUnconditional() &&"splitBasicBlock broken!"); BasicBlock *CalleeEntry = cast(Br)->getSuccessor(0); SimplifyCFG(CalleeEntry); - + // Okay, continue the CFG cleanup. It's often the case that there is only a // single return instruction in the callee function. If this is the case, // then we have an unconditional branch from the return block to the // 'AfterCallBB'. Check for this case, and eliminate the branch is possible. SimplifyCFG(AfterCallBB); + return true; } Index: llvm/lib/Transforms/Utils/Linker.cpp diff -u llvm/lib/Transforms/Utils/Linker.cpp:1.66 llvm/lib/Transforms/Utils/Linker.cpp:1.66.2.1 --- llvm/lib/Transforms/Utils/Linker.cpp:1.66 Mon Jan 12 13:10:58 2004 +++ llvm/lib/Transforms/Utils/Linker.cpp Mon Mar 1 17:58:16 2004 @@ -284,7 +284,8 @@ // Check to see if it's a constant that we are interesting in transforming... if (const Constant *CPV = dyn_cast(In)) { - if (!isa(CPV->getType()) && !isa(CPV)) + if ((!isa(CPV->getType()) && !isa(CPV)) || + isa(CPV)) return const_cast(CPV); // Simple constants stay identical... Constant *Result = 0; @@ -565,7 +566,6 @@ GlobalVariable *DGV = cast(ValueMap[SGV]); if (DGV->hasInitializer()) { - assert(SGV->getLinkage() == DGV->getLinkage()); if (SGV->hasExternalLinkage()) { if (DGV->getInitializer() != SInit) return Error(Err, "Global Variable Collision on '" + @@ -574,6 +574,9 @@ } else if (DGV->hasLinkOnceLinkage() || DGV->hasWeakLinkage()) { // Nothing is required, mapped values will take the new global // automatically. + } else if (SGV->hasLinkOnceLinkage() || SGV->hasWeakLinkage()) { + // Nothing is required, mapped values will take the new global + // automatically. } else if (DGV->hasAppendingLinkage()) { assert(0 && "Appending linkage unimplemented!"); } else { @@ -796,12 +799,24 @@ // Merge the initializer... Inits.reserve(NewSize); - ConstantArray *I = cast(G1->getInitializer()); - for (unsigned i = 0, e = T1->getNumElements(); i != e; ++i) - Inits.push_back(cast(I->getValues()[i])); - I = cast(G2->getInitializer()); - for (unsigned i = 0, e = T2->getNumElements(); i != e; ++i) - Inits.push_back(cast(I->getValues()[i])); + if (ConstantArray *I = dyn_cast(G1->getInitializer())) { + for (unsigned i = 0, e = T1->getNumElements(); i != e; ++i) + Inits.push_back(cast(I->getValues()[i])); + } else { + assert(isa(G1->getInitializer())); + Constant *CV = Constant::getNullValue(T1->getElementType()); + for (unsigned i = 0, e = T1->getNumElements(); i != e; ++i) + Inits.push_back(CV); + } + if (ConstantArray *I = dyn_cast(G2->getInitializer())) { + for (unsigned i = 0, e = T2->getNumElements(); i != e; ++i) + Inits.push_back(cast(I->getValues()[i])); + } else { + assert(isa(G2->getInitializer())); + Constant *CV = Constant::getNullValue(T2->getElementType()); + for (unsigned i = 0, e = T2->getNumElements(); i != e; ++i) + Inits.push_back(CV); + } NG->setInitializer(ConstantArray::get(NewType, Inits)); Inits.clear(); Index: llvm/lib/Transforms/Utils/PromoteMemoryToRegister.cpp diff -u llvm/lib/Transforms/Utils/PromoteMemoryToRegister.cpp:1.59 llvm/lib/Transforms/Utils/PromoteMemoryToRegister.cpp:1.59.2.1 --- llvm/lib/Transforms/Utils/PromoteMemoryToRegister.cpp:1.59 Sun Jan 11 19:18:32 2004 +++ llvm/lib/Transforms/Utils/PromoteMemoryToRegister.cpp Mon Mar 1 17:58:16 2004 @@ -110,7 +110,9 @@ private: void MarkDominatingPHILive(BasicBlock *BB, unsigned AllocaNum, std::set &DeadPHINodes); - void PromoteLocallyUsedAlloca(AllocaInst *AI); + void PromoteLocallyUsedAlloca(BasicBlock *BB, AllocaInst *AI); + void PromoteLocallyUsedAllocas(BasicBlock *BB, + const std::vector &AIs); void RenamePass(BasicBlock *BB, BasicBlock *Pred, std::vector &IncVals); @@ -122,6 +124,13 @@ void PromoteMem2Reg::run() { Function &F = *DF.getRoot()->getParent(); + // LocallyUsedAllocas - Keep track of all of the alloca instructions which are + // only used in a single basic block. These instructions can be efficiently + // promoted by performing a single linear scan over that one block. Since + // individual basic blocks are sometimes large, we group together all allocas + // that are live in a single basic block by the basic block they are live in. + std::map > LocallyUsedAllocas; + for (unsigned AllocaNum = 0; AllocaNum != Allocas.size(); ++AllocaNum) { AllocaInst *AI = Allocas[AllocaNum]; @@ -207,9 +216,9 @@ // If the alloca is only read and written in one basic block, just perform a // linear sweep over the block to eliminate it. if (OnlyUsedInOneBlock) { - PromoteLocallyUsedAlloca(AI); + LocallyUsedAllocas[OnlyBlock].push_back(AI); - // Remove the alloca from the Allocas list, since it has been processed + // Remove the alloca from the Allocas list, since it will be processed. Allocas[AllocaNum] = Allocas.back(); Allocas.pop_back(); --AllocaNum; @@ -272,6 +281,20 @@ AllocaLookup[Allocas[AllocaNum]] = AllocaNum; } + // Process all allocas which are only used in a single basic block. + for (std::map >::iterator I = + LocallyUsedAllocas.begin(), E = LocallyUsedAllocas.end(); I != E; ++I){ + const std::vector &Allocas = I->second; + assert(!Allocas.empty() && "empty alloca list??"); + + // It's common for there to only be one alloca in the list. Handle it + // efficiently. + if (Allocas.size() == 1) + PromoteLocallyUsedAlloca(I->first, Allocas[0]); + else + PromoteLocallyUsedAllocas(I->first, Allocas); + } + if (Allocas.empty()) return; // All of the allocas must have been trivial! @@ -393,41 +416,92 @@ } } -// PromoteLocallyUsedAlloca - Many allocas are only used within a single basic -// block. If this is the case, avoid traversing the CFG and inserting a lot of -// potentially useless PHI nodes by just performing a single linear pass over -// the basic block using the Alloca. -// -void PromoteMem2Reg::PromoteLocallyUsedAlloca(AllocaInst *AI) { +/// PromoteLocallyUsedAlloca - Many allocas are only used within a single basic +/// block. If this is the case, avoid traversing the CFG and inserting a lot of +/// potentially useless PHI nodes by just performing a single linear pass over +/// the basic block using the Alloca. +/// +void PromoteMem2Reg::PromoteLocallyUsedAlloca(BasicBlock *BB, AllocaInst *AI) { assert(!AI->use_empty() && "There are no uses of the alloca!"); - // Uses of the uninitialized memory location shall get zero... - Value *CurVal = Constant::getNullValue(AI->getAllocatedType()); + // Handle degenerate cases quickly. + if (AI->hasOneUse()) { + Instruction *U = cast(AI->use_back()); + if (LoadInst *LI = dyn_cast(U)) { + // Must be a load of uninitialized value. + LI->replaceAllUsesWith(Constant::getNullValue(AI->getAllocatedType())); + } else { + // Otherwise it must be a store which is never read. + assert(isa(U)); + } + BB->getInstList().erase(U); + } else { + // Uses of the uninitialized memory location shall get zero... + Value *CurVal = Constant::getNullValue(AI->getAllocatedType()); - BasicBlock *BB = cast(AI->use_back())->getParent(); + for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ) { + Instruction *Inst = I++; + if (LoadInst *LI = dyn_cast(Inst)) { + if (LI->getOperand(0) == AI) { + // Loads just returns the "current value"... + LI->replaceAllUsesWith(CurVal); + BB->getInstList().erase(LI); + } + } else if (StoreInst *SI = dyn_cast(Inst)) { + if (SI->getOperand(1) == AI) { + // Store updates the "current value"... + CurVal = SI->getOperand(0); + BB->getInstList().erase(SI); + } + } + } + } + + // After traversing the basic block, there should be no more uses of the + // alloca, remove it now. + assert(AI->use_empty() && "Uses of alloca from more than one BB??"); + AI->getParent()->getInstList().erase(AI); +} + +/// PromoteLocallyUsedAllocas - This method is just like +/// PromoteLocallyUsedAlloca, except that it processes multiple alloca +/// instructions in parallel. This is important in cases where we have large +/// basic blocks, as we don't want to rescan the entire basic block for each +/// alloca which is locally used in it (which might be a lot). +void PromoteMem2Reg:: +PromoteLocallyUsedAllocas(BasicBlock *BB, const std::vector &AIs) { + std::map CurValues; + for (unsigned i = 0, e = AIs.size(); i != e; ++i) + CurValues[AIs[i]] = 0; // Insert with null value for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ) { Instruction *Inst = I++; if (LoadInst *LI = dyn_cast(Inst)) { - if (LI->getOperand(0) == AI) { - // Loads just return the "current value"... - LI->replaceAllUsesWith(CurVal); - BB->getInstList().erase(LI); + // Is this a load of an alloca we are tracking? + if (AllocaInst *AI = dyn_cast(LI->getOperand(0))) { + std::map::iterator AIt = CurValues.find(AI); + if (AIt != CurValues.end()) { + // Loads just returns the "current value"... + if (AIt->second == 0) // Uninitialized value?? + AIt->second =Constant::getNullValue(AIt->first->getAllocatedType()); + LI->replaceAllUsesWith(AIt->second); + BB->getInstList().erase(LI); + } } } else if (StoreInst *SI = dyn_cast(Inst)) { - if (SI->getOperand(1) == AI) { - // Loads just update the "current value"... - CurVal = SI->getOperand(0); - BB->getInstList().erase(SI); + if (AllocaInst *AI = dyn_cast(SI->getOperand(1))) { + std::map::iterator AIt = CurValues.find(AI); + if (AIt != CurValues.end()) { + // Store updates the "current value"... + AIt->second = SI->getOperand(0); + BB->getInstList().erase(SI); + } } } } - - // After traversing the basic block, there should be no more uses of the - // alloca, remove it now. - assert(AI->use_empty() && "Uses of alloca from more than one BB??"); - AI->getParent()->getInstList().erase(AI); } + + // QueuePhiNode - queues a phi-node to be added to a basic-block for a specific // Alloca returns true if there wasn't already a phi-node for that variable Index: llvm/lib/Transforms/Utils/SimplifyCFG.cpp diff -u llvm/lib/Transforms/Utils/SimplifyCFG.cpp:1.19 llvm/lib/Transforms/Utils/SimplifyCFG.cpp:1.19.2.1 --- llvm/lib/Transforms/Utils/SimplifyCFG.cpp:1.19 Fri Jan 9 00:12:25 2004 +++ llvm/lib/Transforms/Utils/SimplifyCFG.cpp Mon Mar 1 17:58:16 2004 @@ -12,22 +12,21 @@ //===----------------------------------------------------------------------===// #include "llvm/Transforms/Utils/Local.h" -#include "llvm/Constant.h" -#include "llvm/Intrinsics.h" -#include "llvm/iPHINode.h" -#include "llvm/iTerminators.h" -#include "llvm/iOther.h" +#include "llvm/Constants.h" +#include "llvm/Instructions.h" +#include "llvm/Type.h" #include "llvm/Support/CFG.h" #include #include +#include using namespace llvm; -// PropagatePredecessors - This gets "Succ" ready to have the predecessors from -// "BB". This is a little tricky because "Succ" has PHI nodes, which need to -// have extra slots added to them to hold the merge edges from BB's -// predecessors, and BB itself might have had PHI nodes in it. This function -// returns true (failure) if the Succ BB already has a predecessor that is a -// predecessor of BB and incoming PHI arguments would not be discernible. +// PropagatePredecessorsForPHIs - This gets "Succ" ready to have the +// predecessors from "BB". This is a little tricky because "Succ" has PHI +// nodes, which need to have extra slots added to them to hold the merge edges +// from BB's predecessors, and BB itself might have had PHI nodes in it. This +// function returns true (failure) if the Succ BB already has a predecessor that +// is a predecessor of BB and incoming PHI arguments would not be discernible. // // Assumption: Succ is the single successor for BB. // @@ -89,6 +88,408 @@ return false; } +/// GetIfCondition - Given a basic block (BB) with two predecessors (and +/// presumably PHI nodes in it), check to see if the merge at this block is due +/// to an "if condition". If so, return the boolean condition that determines +/// which entry into BB will be taken. Also, return by references the block +/// that will be entered from if the condition is true, and the block that will +/// be entered if the condition is false. +/// +/// +static Value *GetIfCondition(BasicBlock *BB, + BasicBlock *&IfTrue, BasicBlock *&IfFalse) { + assert(std::distance(pred_begin(BB), pred_end(BB)) == 2 && + "Function can only handle blocks with 2 predecessors!"); + BasicBlock *Pred1 = *pred_begin(BB); + BasicBlock *Pred2 = *++pred_begin(BB); + + // We can only handle branches. Other control flow will be lowered to + // branches if possible anyway. + if (!isa(Pred1->getTerminator()) || + !isa(Pred2->getTerminator())) + return 0; + BranchInst *Pred1Br = cast(Pred1->getTerminator()); + BranchInst *Pred2Br = cast(Pred2->getTerminator()); + + // Eliminate code duplication by ensuring that Pred1Br is conditional if + // either are. + if (Pred2Br->isConditional()) { + // If both branches are conditional, we don't have an "if statement". In + // reality, we could transform this case, but since the condition will be + // required anyway, we stand no chance of eliminating it, so the xform is + // probably not profitable. + if (Pred1Br->isConditional()) + return 0; + + std::swap(Pred1, Pred2); + std::swap(Pred1Br, Pred2Br); + } + + if (Pred1Br->isConditional()) { + // If we found a conditional branch predecessor, make sure that it branches + // to BB and Pred2Br. If it doesn't, this isn't an "if statement". + if (Pred1Br->getSuccessor(0) == BB && + Pred1Br->getSuccessor(1) == Pred2) { + IfTrue = Pred1; + IfFalse = Pred2; + } else if (Pred1Br->getSuccessor(0) == Pred2 && + Pred1Br->getSuccessor(1) == BB) { + IfTrue = Pred2; + IfFalse = Pred1; + } else { + // We know that one arm of the conditional goes to BB, so the other must + // go somewhere unrelated, and this must not be an "if statement". + return 0; + } + + // The only thing we have to watch out for here is to make sure that Pred2 + // doesn't have incoming edges from other blocks. If it does, the condition + // doesn't dominate BB. + if (++pred_begin(Pred2) != pred_end(Pred2)) + return 0; + + return Pred1Br->getCondition(); + } + + // Ok, if we got here, both predecessors end with an unconditional branch to + // BB. Don't panic! If both blocks only have a single (identical) + // predecessor, and THAT is a conditional branch, then we're all ok! + if (pred_begin(Pred1) == pred_end(Pred1) || + ++pred_begin(Pred1) != pred_end(Pred1) || + pred_begin(Pred2) == pred_end(Pred2) || + ++pred_begin(Pred2) != pred_end(Pred2) || + *pred_begin(Pred1) != *pred_begin(Pred2)) + return 0; + + // Otherwise, if this is a conditional branch, then we can use it! + BasicBlock *CommonPred = *pred_begin(Pred1); + if (BranchInst *BI = dyn_cast(CommonPred->getTerminator())) { + assert(BI->isConditional() && "Two successors but not conditional?"); + if (BI->getSuccessor(0) == Pred1) { + IfTrue = Pred1; + IfFalse = Pred2; + } else { + IfTrue = Pred2; + IfFalse = Pred1; + } + return BI->getCondition(); + } + return 0; +} + + +// If we have a merge point of an "if condition" as accepted above, return true +// if the specified value dominates the block. We don't handle the true +// generality of domination here, just a special case which works well enough +// for us. +static bool DominatesMergePoint(Value *V, BasicBlock *BB) { + if (Instruction *I = dyn_cast(V)) { + BasicBlock *PBB = I->getParent(); + // If this instruction is defined in a block that contains an unconditional + // branch to BB, then it must be in the 'conditional' part of the "if + // statement". + if (isa(PBB->getTerminator()) && + cast(PBB->getTerminator())->isUnconditional() && + cast(PBB->getTerminator())->getSuccessor(0) == BB) + return false; + + // We also don't want to allow wierd loops that might have the "if + // condition" in the bottom of this block. + if (PBB == BB) return false; + } + + // Non-instructions all dominate instructions. + return true; +} + +// GatherConstantSetEQs - Given a potentially 'or'd together collection of seteq +// instructions that compare a value against a constant, return the value being +// compared, and stick the constant into the Values vector. +static Value *GatherConstantSetEQs(Value *V, std::vector &Values) { + if (Instruction *Inst = dyn_cast(V)) + if (Inst->getOpcode() == Instruction::SetEQ) { + if (Constant *C = dyn_cast(Inst->getOperand(1))) { + Values.push_back(C); + return Inst->getOperand(0); + } else if (Constant *C = dyn_cast(Inst->getOperand(0))) { + Values.push_back(C); + return Inst->getOperand(1); + } + } else if (Inst->getOpcode() == Instruction::Or) { + if (Value *LHS = GatherConstantSetEQs(Inst->getOperand(0), Values)) + if (Value *RHS = GatherConstantSetEQs(Inst->getOperand(1), Values)) + if (LHS == RHS) + return LHS; + } + return 0; +} + +// GatherConstantSetNEs - Given a potentially 'and'd together collection of +// setne instructions that compare a value against a constant, return the value +// being compared, and stick the constant into the Values vector. +static Value *GatherConstantSetNEs(Value *V, std::vector &Values) { + if (Instruction *Inst = dyn_cast(V)) + if (Inst->getOpcode() == Instruction::SetNE) { + if (Constant *C = dyn_cast(Inst->getOperand(1))) { + Values.push_back(C); + return Inst->getOperand(0); + } else if (Constant *C = dyn_cast(Inst->getOperand(0))) { + Values.push_back(C); + return Inst->getOperand(1); + } + } else if (Inst->getOpcode() == Instruction::Cast) { + // Cast of X to bool is really a comparison against zero. + assert(Inst->getType() == Type::BoolTy && "Can only handle bool values!"); + Values.push_back(Constant::getNullValue(Inst->getOperand(0)->getType())); + return Inst->getOperand(0); + } else if (Inst->getOpcode() == Instruction::And) { + if (Value *LHS = GatherConstantSetNEs(Inst->getOperand(0), Values)) + if (Value *RHS = GatherConstantSetNEs(Inst->getOperand(1), Values)) + if (LHS == RHS) + return LHS; + } + return 0; +} + + + +/// GatherValueComparisons - If the specified Cond is an 'and' or 'or' of a +/// bunch of comparisons of one value against constants, return the value and +/// the constants being compared. +static bool GatherValueComparisons(Instruction *Cond, Value *&CompVal, + std::vector &Values) { + if (Cond->getOpcode() == Instruction::Or) { + CompVal = GatherConstantSetEQs(Cond, Values); + + // Return true to indicate that the condition is true if the CompVal is + // equal to one of the constants. + return true; + } else if (Cond->getOpcode() == Instruction::And) { + CompVal = GatherConstantSetNEs(Cond, Values); + + // Return false to indicate that the condition is false if the CompVal is + // equal to one of the constants. + return false; + } + return false; +} + +/// ErasePossiblyDeadInstructionTree - If the specified instruction is dead and +/// has no side effects, nuke it. If it uses any instructions that become dead +/// because the instruction is now gone, nuke them too. +static void ErasePossiblyDeadInstructionTree(Instruction *I) { + if (isInstructionTriviallyDead(I)) { + std::vector Operands(I->op_begin(), I->op_end()); + I->getParent()->getInstList().erase(I); + for (unsigned i = 0, e = Operands.size(); i != e; ++i) + if (Instruction *OpI = dyn_cast(Operands[i])) + ErasePossiblyDeadInstructionTree(OpI); + } +} + +/// SafeToMergeTerminators - Return true if it is safe to merge these two +/// terminator instructions together. +/// +static bool SafeToMergeTerminators(TerminatorInst *SI1, TerminatorInst *SI2) { + if (SI1 == SI2) return false; // Can't merge with self! + + // It is not safe to merge these two switch instructions if they have a common + // successor, and if that successor has a PHI node, and if that PHI node has + // conflicting incoming values from the two switch blocks. + BasicBlock *SI1BB = SI1->getParent(); + BasicBlock *SI2BB = SI2->getParent(); + std::set SI1Succs(succ_begin(SI1BB), succ_end(SI1BB)); + + for (succ_iterator I = succ_begin(SI2BB), E = succ_end(SI2BB); I != E; ++I) + if (SI1Succs.count(*I)) + for (BasicBlock::iterator BBI = (*I)->begin(); + PHINode *PN = dyn_cast(BBI); ++BBI) + if (PN->getIncomingValueForBlock(SI1BB) != + PN->getIncomingValueForBlock(SI2BB)) + return false; + + return true; +} + +/// AddPredecessorToBlock - Update PHI nodes in Succ to indicate that there will +/// now be entries in it from the 'NewPred' block. The values that will be +/// flowing into the PHI nodes will be the same as those coming in from +/// ExistPred, and existing predecessor of Succ. +static void AddPredecessorToBlock(BasicBlock *Succ, BasicBlock *NewPred, + BasicBlock *ExistPred) { + assert(std::find(succ_begin(ExistPred), succ_end(ExistPred), Succ) != + succ_end(ExistPred) && "ExistPred is not a predecessor of Succ!"); + if (!isa(Succ->begin())) return; // Quick exit if nothing to do + + for (BasicBlock::iterator I = Succ->begin(); + PHINode *PN = dyn_cast(I); ++I) { + Value *V = PN->getIncomingValueForBlock(ExistPred); + PN->addIncoming(V, NewPred); + } +} + +// isValueEqualityComparison - Return true if the specified terminator checks to +// see if a value is equal to constant integer value. +static Value *isValueEqualityComparison(TerminatorInst *TI) { + if (SwitchInst *SI = dyn_cast(TI)) + return SI->getCondition(); + if (BranchInst *BI = dyn_cast(TI)) + if (BI->isConditional() && BI->getCondition()->hasOneUse()) + if (SetCondInst *SCI = dyn_cast(BI->getCondition())) + if ((SCI->getOpcode() == Instruction::SetEQ || + SCI->getOpcode() == Instruction::SetNE) && + isa(SCI->getOperand(1))) + return SCI->getOperand(0); + return 0; +} + +// Given a value comparison instruction, decode all of the 'cases' that it +// represents and return the 'default' block. +static BasicBlock * +GetValueEqualityComparisonCases(TerminatorInst *TI, + std::vector > &Cases) { + if (SwitchInst *SI = dyn_cast(TI)) { + Cases.reserve(SI->getNumCases()); + for (unsigned i = 1, e = SI->getNumCases(); i != e; ++i) + Cases.push_back(std::make_pair(cast(SI->getCaseValue(i)), + SI->getSuccessor(i))); + return SI->getDefaultDest(); + } + + BranchInst *BI = cast(TI); + SetCondInst *SCI = cast(BI->getCondition()); + Cases.push_back(std::make_pair(cast(SCI->getOperand(1)), + BI->getSuccessor(SCI->getOpcode() == + Instruction::SetNE))); + return BI->getSuccessor(SCI->getOpcode() == Instruction::SetEQ); +} + + +// FoldValueComparisonIntoPredecessors - The specified terminator is a value +// equality comparison instruction (either a switch or a branch on "X == c"). +// See if any of the predecessors of the terminator block are value comparisons +// on the same value. If so, and if safe to do so, fold them together. +static bool FoldValueComparisonIntoPredecessors(TerminatorInst *TI) { + BasicBlock *BB = TI->getParent(); + Value *CV = isValueEqualityComparison(TI); // CondVal + assert(CV && "Not a comparison?"); + bool Changed = false; + + std::vector Preds(pred_begin(BB), pred_end(BB)); + while (!Preds.empty()) { + BasicBlock *Pred = Preds.back(); + Preds.pop_back(); + + // See if the predecessor is a comparison with the same value. + TerminatorInst *PTI = Pred->getTerminator(); + Value *PCV = isValueEqualityComparison(PTI); // PredCondVal + + if (PCV == CV && SafeToMergeTerminators(TI, PTI)) { + // Figure out which 'cases' to copy from SI to PSI. + std::vector > BBCases; + BasicBlock *BBDefault = GetValueEqualityComparisonCases(TI, BBCases); + + std::vector > PredCases; + BasicBlock *PredDefault = GetValueEqualityComparisonCases(PTI, PredCases); + + // Based on whether the default edge from PTI goes to BB or not, fill in + // PredCases and PredDefault with the new switch cases we would like to + // build. + std::vector NewSuccessors; + + if (PredDefault == BB) { + // If this is the default destination from PTI, only the edges in TI + // that don't occur in PTI, or that branch to BB will be activated. + std::set PTIHandled; + for (unsigned i = 0, e = PredCases.size(); i != e; ++i) + if (PredCases[i].second != BB) + PTIHandled.insert(PredCases[i].first); + else { + // The default destination is BB, we don't need explicit targets. + std::swap(PredCases[i], PredCases.back()); + PredCases.pop_back(); + --i; --e; + } + + // Reconstruct the new switch statement we will be building. + if (PredDefault != BBDefault) { + PredDefault->removePredecessor(Pred); + PredDefault = BBDefault; + NewSuccessors.push_back(BBDefault); + } + for (unsigned i = 0, e = BBCases.size(); i != e; ++i) + if (!PTIHandled.count(BBCases[i].first) && + BBCases[i].second != BBDefault) { + PredCases.push_back(BBCases[i]); + NewSuccessors.push_back(BBCases[i].second); + } + + } else { + // If this is not the default destination from PSI, only the edges + // in SI that occur in PSI with a destination of BB will be + // activated. + std::set PTIHandled; + for (unsigned i = 0, e = PredCases.size(); i != e; ++i) + if (PredCases[i].second == BB) { + PTIHandled.insert(PredCases[i].first); + std::swap(PredCases[i], PredCases.back()); + PredCases.pop_back(); + --i; --e; + } + + // Okay, now we know which constants were sent to BB from the + // predecessor. Figure out where they will all go now. + for (unsigned i = 0, e = BBCases.size(); i != e; ++i) + if (PTIHandled.count(BBCases[i].first)) { + // If this is one we are capable of getting... + PredCases.push_back(BBCases[i]); + NewSuccessors.push_back(BBCases[i].second); + PTIHandled.erase(BBCases[i].first);// This constant is taken care of + } + + // If there are any constants vectored to BB that TI doesn't handle, + // they must go to the default destination of TI. + for (std::set::iterator I = PTIHandled.begin(), + E = PTIHandled.end(); I != E; ++I) { + PredCases.push_back(std::make_pair(*I, BBDefault)); + NewSuccessors.push_back(BBDefault); + } + } + + // Okay, at this point, we know which new successor Pred will get. Make + // sure we update the number of entries in the PHI nodes for these + // successors. + for (unsigned i = 0, e = NewSuccessors.size(); i != e; ++i) + AddPredecessorToBlock(NewSuccessors[i], Pred, BB); + + // Now that the successors are updated, create the new Switch instruction. + SwitchInst *NewSI = new SwitchInst(CV, PredDefault, PTI); + for (unsigned i = 0, e = PredCases.size(); i != e; ++i) + NewSI->addCase(PredCases[i].first, PredCases[i].second); + Pred->getInstList().erase(PTI); + + // Okay, last check. If BB is still a successor of PSI, then we must + // have an infinite loop case. If so, add an infinitely looping block + // to handle the case to preserve the behavior of the code. + BasicBlock *InfLoopBlock = 0; + for (unsigned i = 0, e = NewSI->getNumSuccessors(); i != e; ++i) + if (NewSI->getSuccessor(i) == BB) { + if (InfLoopBlock == 0) { + // Insert it at the end of the loop, because it's either code, + // or it won't matter if it's hot. :) + InfLoopBlock = new BasicBlock("infloop", BB->getParent()); + new BranchInst(InfLoopBlock, InfLoopBlock); + } + NewSI->setSuccessor(i, InfLoopBlock); + } + + Changed = true; + } + } + return Changed; +} + // SimplifyCFG - This function is used to do simplification of a CFG. For // example, it adjusts branches to branches to eliminate the extra hop, it @@ -105,39 +506,9 @@ assert(BB->getTerminator() && "Degenerate basic block encountered!"); assert(&BB->getParent()->front() != BB && "Can't Simplify entry block!"); - // Check to see if the first instruction in this block is just an - // 'llvm.unwind'. If so, replace any invoke instructions which use this as an - // exception destination with call instructions. - // - if (UnwindInst *UI = dyn_cast(BB->getTerminator())) - if (BB->begin() == BasicBlock::iterator(UI)) { // Empty block? - std::vector Preds(pred_begin(BB), pred_end(BB)); - while (!Preds.empty()) { - BasicBlock *Pred = Preds.back(); - if (InvokeInst *II = dyn_cast(Pred->getTerminator())) - if (II->getExceptionalDest() == BB) { - // Insert a new branch instruction before the invoke, because this - // is now a fall through... - BranchInst *BI = new BranchInst(II->getNormalDest(), II); - Pred->getInstList().remove(II); // Take out of symbol table - - // Insert the call now... - std::vector Args(II->op_begin()+3, II->op_end()); - CallInst *CI = new CallInst(II->getCalledValue(), Args, - II->getName(), BI); - // If the invoke produced a value, the Call now does instead - II->replaceAllUsesWith(CI); - delete II; - Changed = true; - } - - Preds.pop_back(); - } - } - // Remove basic blocks that have no predecessors... which are unreachable. - if (pred_begin(BB) == pred_end(BB) && - !BB->hasConstantReferences()) { + if (pred_begin(BB) == pred_end(BB) || + *pred_begin(BB) == BB && ++pred_begin(BB) == pred_end(BB)) { //cerr << "Removing BB: \n" << BB; // Loop through all of our successors and make sure they know that one @@ -233,69 +604,328 @@ } } + // If this is a returning block with only PHI nodes in it, fold the return + // instruction into any unconditional branch predecessors. + if (ReturnInst *RI = dyn_cast(BB->getTerminator())) { + BasicBlock::iterator BBI = BB->getTerminator(); + if (BBI == BB->begin() || isa(--BBI)) { + // Find predecessors that end with unconditional branches. + std::vector UncondBranchPreds; + for (pred_iterator PI = pred_begin(BB), E = pred_end(BB); PI != E; ++PI) { + TerminatorInst *PTI = (*PI)->getTerminator(); + if (BranchInst *BI = dyn_cast(PTI)) + if (BI->isUnconditional()) + UncondBranchPreds.push_back(*PI); + } + + // If we found some, do the transformation! + if (!UncondBranchPreds.empty()) { + while (!UncondBranchPreds.empty()) { + BasicBlock *Pred = UncondBranchPreds.back(); + UncondBranchPreds.pop_back(); + Instruction *UncondBranch = Pred->getTerminator(); + // Clone the return and add it to the end of the predecessor. + Instruction *NewRet = RI->clone(); + Pred->getInstList().push_back(NewRet); + + // If the return instruction returns a value, and if the value was a + // PHI node in "BB", propagate the right value into the return. + if (NewRet->getNumOperands() == 1) + if (PHINode *PN = dyn_cast(NewRet->getOperand(0))) + if (PN->getParent() == BB) + NewRet->setOperand(0, PN->getIncomingValueForBlock(Pred)); + // Update any PHI nodes in the returning block to realize that we no + // longer branch to them. + BB->removePredecessor(Pred); + Pred->getInstList().erase(UncondBranch); + } + + // If we eliminated all predecessors of the block, delete the block now. + if (pred_begin(BB) == pred_end(BB)) + // We know there are no successors, so just nuke the block. + M->getBasicBlockList().erase(BB); + + return true; + } + } + } else if (UnwindInst *UI = dyn_cast(BB->begin())) { + // Check to see if the first instruction in this block is just an unwind. + // If so, replace any invoke instructions which use this as an exception + // destination with call instructions. + // + std::vector Preds(pred_begin(BB), pred_end(BB)); + while (!Preds.empty()) { + BasicBlock *Pred = Preds.back(); + if (InvokeInst *II = dyn_cast(Pred->getTerminator())) + if (II->getUnwindDest() == BB) { + // Insert a new branch instruction before the invoke, because this + // is now a fall through... + BranchInst *BI = new BranchInst(II->getNormalDest(), II); + Pred->getInstList().remove(II); // Take out of symbol table + + // Insert the call now... + std::vector Args(II->op_begin()+3, II->op_end()); + CallInst *CI = new CallInst(II->getCalledValue(), Args, + II->getName(), BI); + // If the invoke produced a value, the Call now does instead + II->replaceAllUsesWith(CI); + delete II; + Changed = true; + } + + Preds.pop_back(); + } + + // If this block is now dead, remove it. + if (pred_begin(BB) == pred_end(BB)) { + // We know there are no successors, so just nuke the block. + M->getBasicBlockList().erase(BB); + return true; + } + + } else if (SwitchInst *SI = dyn_cast(BB->begin())) { + if (FoldValueComparisonIntoPredecessors(SI)) + return SimplifyCFG(BB) || 1; + } else if (BranchInst *BI = dyn_cast(BB->getTerminator())) { + if (Value *CompVal = isValueEqualityComparison(BB->getTerminator())) { + // This block must be empty, except for the setcond inst, if it exists. + BasicBlock::iterator I = BB->begin(); + if (&*I == BI || + (&*I == cast(BI->getCondition()) && + &*++I == BI)) + if (FoldValueComparisonIntoPredecessors(BI)) + return SimplifyCFG(BB) || 1; + } + } + // Merge basic blocks into their predecessor if there is only one distinct // pred, and if there is only one distinct successor of the predecessor, and // if there are no PHI nodes. // - if (!BB->hasConstantReferences()) { - pred_iterator PI(pred_begin(BB)), PE(pred_end(BB)); - BasicBlock *OnlyPred = *PI++; - for (; PI != PE; ++PI) // Search all predecessors, see if they are all same - if (*PI != OnlyPred) { - OnlyPred = 0; // There are multiple different predecessors... + pred_iterator PI(pred_begin(BB)), PE(pred_end(BB)); + BasicBlock *OnlyPred = *PI++; + for (; PI != PE; ++PI) // Search all predecessors, see if they are all same + if (*PI != OnlyPred) { + OnlyPred = 0; // There are multiple different predecessors... + break; + } + + BasicBlock *OnlySucc = 0; + if (OnlyPred && OnlyPred != BB && // Don't break self loops + OnlyPred->getTerminator()->getOpcode() != Instruction::Invoke) { + // Check to see if there is only one distinct successor... + succ_iterator SI(succ_begin(OnlyPred)), SE(succ_end(OnlyPred)); + OnlySucc = BB; + for (; SI != SE; ++SI) + if (*SI != OnlySucc) { + OnlySucc = 0; // There are multiple distinct successors! break; } - - BasicBlock *OnlySucc = 0; - if (OnlyPred && OnlyPred != BB && // Don't break self loops - OnlyPred->getTerminator()->getOpcode() != Instruction::Invoke) { - // Check to see if there is only one distinct successor... - succ_iterator SI(succ_begin(OnlyPred)), SE(succ_end(OnlyPred)); - OnlySucc = BB; - for (; SI != SE; ++SI) - if (*SI != OnlySucc) { - OnlySucc = 0; // There are multiple distinct successors! - break; - } - } + } - if (OnlySucc) { - //cerr << "Merging: " << BB << "into: " << OnlyPred; - TerminatorInst *Term = OnlyPred->getTerminator(); - - // Resolve any PHI nodes at the start of the block. They are all - // guaranteed to have exactly one entry if they exist, unless there are - // multiple duplicate (but guaranteed to be equal) entries for the - // incoming edges. This occurs when there are multiple edges from - // OnlyPred to OnlySucc. - // - while (PHINode *PN = dyn_cast(&BB->front())) { - PN->replaceAllUsesWith(PN->getIncomingValue(0)); - BB->getInstList().pop_front(); // Delete the phi node... - } + if (OnlySucc) { + //cerr << "Merging: " << BB << "into: " << OnlyPred; + TerminatorInst *Term = OnlyPred->getTerminator(); + + // Resolve any PHI nodes at the start of the block. They are all + // guaranteed to have exactly one entry if they exist, unless there are + // multiple duplicate (but guaranteed to be equal) entries for the + // incoming edges. This occurs when there are multiple edges from + // OnlyPred to OnlySucc. + // + while (PHINode *PN = dyn_cast(&BB->front())) { + PN->replaceAllUsesWith(PN->getIncomingValue(0)); + BB->getInstList().pop_front(); // Delete the phi node... + } - // Delete the unconditional branch from the predecessor... - OnlyPred->getInstList().pop_back(); + // Delete the unconditional branch from the predecessor... + OnlyPred->getInstList().pop_back(); - // Move all definitions in the successor to the predecessor... - OnlyPred->getInstList().splice(OnlyPred->end(), BB->getInstList()); + // Move all definitions in the successor to the predecessor... + OnlyPred->getInstList().splice(OnlyPred->end(), BB->getInstList()); - // Make all PHI nodes that referred to BB now refer to Pred as their - // source... - BB->replaceAllUsesWith(OnlyPred); + // Make all PHI nodes that referred to BB now refer to Pred as their + // source... + BB->replaceAllUsesWith(OnlyPred); - std::string OldName = BB->getName(); + std::string OldName = BB->getName(); - // Erase basic block from the function... - M->getBasicBlockList().erase(BB); + // Erase basic block from the function... + M->getBasicBlockList().erase(BB); - // Inherit predecessors name if it exists... - if (!OldName.empty() && !OnlyPred->hasName()) - OnlyPred->setName(OldName); + // Inherit predecessors name if it exists... + if (!OldName.empty() && !OnlyPred->hasName()) + OnlyPred->setName(OldName); - return true; - } + return true; } + + for (pred_iterator PI = pred_begin(BB), E = pred_end(BB); PI != E; ++PI) + if (BranchInst *BI = dyn_cast((*PI)->getTerminator())) + // Change br (X == 0 | X == 1), T, F into a switch instruction. + if (BI->isConditional() && isa(BI->getCondition())) { + Instruction *Cond = cast(BI->getCondition()); + // If this is a bunch of seteq's or'd together, or if it's a bunch of + // 'setne's and'ed together, collect them. + Value *CompVal = 0; + std::vector Values; + bool TrueWhenEqual = GatherValueComparisons(Cond, CompVal, Values); + if (CompVal && CompVal->getType()->isInteger()) { + // There might be duplicate constants in the list, which the switch + // instruction can't handle, remove them now. + std::sort(Values.begin(), Values.end()); + Values.erase(std::unique(Values.begin(), Values.end()), Values.end()); + + // Figure out which block is which destination. + BasicBlock *DefaultBB = BI->getSuccessor(1); + BasicBlock *EdgeBB = BI->getSuccessor(0); + if (!TrueWhenEqual) std::swap(DefaultBB, EdgeBB); + + // Create the new switch instruction now. + SwitchInst *New = new SwitchInst(CompVal, DefaultBB, BI); + + // Add all of the 'cases' to the switch instruction. + for (unsigned i = 0, e = Values.size(); i != e; ++i) + New->addCase(Values[i], EdgeBB); + + // We added edges from PI to the EdgeBB. As such, if there were any + // PHI nodes in EdgeBB, they need entries to be added corresponding to + // the number of edges added. + for (BasicBlock::iterator BBI = EdgeBB->begin(); + PHINode *PN = dyn_cast(BBI); ++BBI) { + Value *InVal = PN->getIncomingValueForBlock(*PI); + for (unsigned i = 0, e = Values.size()-1; i != e; ++i) + PN->addIncoming(InVal, *PI); + } + + // Erase the old branch instruction. + (*PI)->getInstList().erase(BI); + + // Erase the potentially condition tree that was used to computed the + // branch condition. + ErasePossiblyDeadInstructionTree(Cond); + return true; + } + } + + // If there is a trivial two-entry PHI node in this basic block, and we can + // eliminate it, do so now. + if (PHINode *PN = dyn_cast(BB->begin())) + if (PN->getNumIncomingValues() == 2) { + // Ok, this is a two entry PHI node. Check to see if this is a simple "if + // statement", which has a very simple dominance structure. Basically, we + // are trying to find the condition that is being branched on, which + // subsequently causes this merge to happen. We really want control + // dependence information for this check, but simplifycfg can't keep it up + // to date, and this catches most of the cases we care about anyway. + // + BasicBlock *IfTrue, *IfFalse; + if (Value *IfCond = GetIfCondition(BB, IfTrue, IfFalse)) { + //std::cerr << "FOUND IF CONDITION! " << *IfCond << " T: " + // << IfTrue->getName() << " F: " << IfFalse->getName() << "\n"; + + // Figure out where to insert instructions as necessary. + BasicBlock::iterator AfterPHIIt = BB->begin(); + while (isa(AfterPHIIt)) ++AfterPHIIt; + + BasicBlock::iterator I = BB->begin(); + while (PHINode *PN = dyn_cast(I)) { + ++I; + + // If we can eliminate this PHI by directly computing it based on the + // condition, do so now. We can't eliminate PHI nodes where the + // incoming values are defined in the conditional parts of the branch, + // so check for this. + // + if (DominatesMergePoint(PN->getIncomingValue(0), BB) && + DominatesMergePoint(PN->getIncomingValue(1), BB)) { + Value *TrueVal = + PN->getIncomingValue(PN->getIncomingBlock(0) == IfFalse); + Value *FalseVal = + PN->getIncomingValue(PN->getIncomingBlock(0) == IfTrue); + + // FIXME: when we have a 'select' statement, we can be completely + // generic and clean here and let the instcombine pass clean up + // after us, by folding the select instructions away when possible. + // + if (TrueVal == FalseVal) { + // Degenerate case... + PN->replaceAllUsesWith(TrueVal); + BB->getInstList().erase(PN); + Changed = true; + } else if (isa(TrueVal) && + isa(FalseVal)) { + if (TrueVal == ConstantBool::True) { + // The PHI node produces the same thing as the condition. + PN->replaceAllUsesWith(IfCond); + } else { + // The PHI node produces the inverse of the condition. Insert a + // "NOT" instruction, which is really a XOR. + Value *InverseCond = + BinaryOperator::createNot(IfCond, IfCond->getName()+".inv", + AfterPHIIt); + PN->replaceAllUsesWith(InverseCond); + } + BB->getInstList().erase(PN); + Changed = true; + } else if (isa(TrueVal) && isa(FalseVal)){ + // If this is a PHI of two constant integers, we insert a cast of + // the boolean to the integer type in question, giving us 0 or 1. + // Then we multiply this by the difference of the two constants, + // giving us 0 if false, and the difference if true. We add this + // result to the base constant, giving us our final value. We + // rely on the instruction combiner to eliminate many special + // cases, like turning multiplies into shifts when possible. + std::string Name = PN->getName(); PN->setName(""); + Value *TheCast = new CastInst(IfCond, TrueVal->getType(), + Name, AfterPHIIt); + Constant *TheDiff = ConstantExpr::get(Instruction::Sub, + cast(TrueVal), + cast(FalseVal)); + Value *V = TheCast; + if (TheDiff != ConstantInt::get(TrueVal->getType(), 1)) + V = BinaryOperator::create(Instruction::Mul, TheCast, + TheDiff, TheCast->getName()+".scale", + AfterPHIIt); + if (!cast(FalseVal)->isNullValue()) + V = BinaryOperator::create(Instruction::Add, V, FalseVal, + V->getName()+".offs", AfterPHIIt); + PN->replaceAllUsesWith(V); + BB->getInstList().erase(PN); + Changed = true; + } else if (isa(FalseVal) && + cast(FalseVal)->isNullValue()) { + // If the false condition is an integral zero value, we can + // compute the PHI by multiplying the condition by the other + // value. + std::string Name = PN->getName(); PN->setName(""); + Value *TheCast = new CastInst(IfCond, TrueVal->getType(), + Name+".c", AfterPHIIt); + Value *V = BinaryOperator::create(Instruction::Mul, TrueVal, + TheCast, Name, AfterPHIIt); + PN->replaceAllUsesWith(V); + BB->getInstList().erase(PN); + Changed = true; + } else if (isa(TrueVal) && + cast(TrueVal)->isNullValue()) { + // If the true condition is an integral zero value, we can compute + // the PHI by multiplying the inverse condition by the other + // value. + std::string Name = PN->getName(); PN->setName(""); + Value *NotCond = BinaryOperator::createNot(IfCond, Name+".inv", + AfterPHIIt); + Value *TheCast = new CastInst(NotCond, TrueVal->getType(), + Name+".inv", AfterPHIIt); + Value *V = BinaryOperator::create(Instruction::Mul, FalseVal, + TheCast, Name, AfterPHIIt); + PN->replaceAllUsesWith(V); + BB->getInstList().erase(PN); + Changed = true; + } + } + } + } + } return Changed; } Index: llvm/lib/Transforms/Utils/ValueMapper.cpp diff -u llvm/lib/Transforms/Utils/ValueMapper.cpp:1.10 llvm/lib/Transforms/Utils/ValueMapper.cpp:1.10.2.1 --- llvm/lib/Transforms/Utils/ValueMapper.cpp:1.10 Mon Jan 12 13:10:58 2004 +++ llvm/lib/Transforms/Utils/ValueMapper.cpp Mon Mar 1 17:58:16 2004 @@ -28,7 +28,7 @@ if (Constant *C = const_cast(dyn_cast(V))) { if (isa(C) || isa(C) || - isa(C)) + isa(C) || isa(C)) return VMSlot = C; // Primitive constants map directly else if (ConstantPointerRef *CPR = dyn_cast(C)) { GlobalValue *MV = cast(MapValue((Value*)CPR->getValue(),VM)); From brukman at cs.uiuc.edu Mon Mar 1 18:05:23 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Mar 1 18:05:23 2004 Subject: [llvm-commits] [parallel] CVS: llvm/lib/Transforms/Scalar/BasicBlockPlacement.cpp ADCE.cpp GCSE.cpp InstructionCombining.cpp LICM.cpp LoopSimplify.cpp LowerAllocations.cpp LowerInvoke.cpp LowerSwitch.cpp SCCP.cpp TailDuplication.cpp TailRecursionElimination.cpp Message-ID: <200403012358.RAA04036@zion.cs.uiuc.edu> Changes in directory llvm/lib/Transforms/Scalar: BasicBlockPlacement.cpp added (r1.2.2.1) ADCE.cpp updated: 1.70 -> 1.70.2.1 GCSE.cpp updated: 1.33 -> 1.33.2.1 InstructionCombining.cpp updated: 1.149 -> 1.149.2.1 LICM.cpp updated: 1.55 -> 1.55.2.1 LoopSimplify.cpp updated: 1.30 -> 1.30.2.1 LowerAllocations.cpp updated: 1.43 -> 1.43.2.1 LowerInvoke.cpp updated: 1.4 -> 1.4.4.1 LowerSwitch.cpp updated: 1.10 -> 1.10.2.1 SCCP.cpp updated: 1.88 -> 1.88.2.1 TailDuplication.cpp updated: 1.11 -> 1.11.2.1 TailRecursionElimination.cpp updated: 1.12 -> 1.12.2.1 --- Log message: Merge from trunk --- Diffs of the changes: (+992 -116) Index: llvm/lib/Transforms/Scalar/BasicBlockPlacement.cpp diff -c /dev/null llvm/lib/Transforms/Scalar/BasicBlockPlacement.cpp:1.2.2.1 *** /dev/null Mon Mar 1 17:58:28 2004 --- llvm/lib/Transforms/Scalar/BasicBlockPlacement.cpp Mon Mar 1 17:58:16 2004 *************** *** 0 **** --- 1,139 ---- + //===-- BasicBlockPlacement.cpp - Basic Block Code Layout optimization ----===// + // + // The LLVM Compiler Infrastructure + // + // This file was developed by the LLVM research group and is distributed under + // the University of Illinois Open Source License. See LICENSE.TXT for details. + // + //===----------------------------------------------------------------------===// + // + // This file implements a very simple profile guided basic block placement + // algorithm. The idea is to put frequently executed blocks together at the + // start of the function, and hopefully increase the number of fall-through + // conditional branches. If there is no profile information for a particular + // function, this pass basically orders blocks in depth-first order + // + // The algorithm implemented here is basically "Algo1" from "Profile Guided Code + // Positioning" by Pettis and Hansen, except that it uses basic block counts + // instead of edge counts. This should be improved in many ways, but is very + // simple for now. + // + // Basically we "place" the entry block, then loop over all successors in a DFO, + // placing the most frequently executed successor until we run out of blocks. I + // told you this was _extremely_ simplistic. :) This is also much slower than it + // could be. When it becomes important, this pass will be rewritten to use a + // better algorithm, and then we can worry about efficiency. + // + //===----------------------------------------------------------------------===// + + #include "llvm/Analysis/ProfileInfo.h" + #include "llvm/Function.h" + #include "llvm/Pass.h" + #include "llvm/Support/CFG.h" + #include "Support/Statistic.h" + #include + using namespace llvm; + + namespace { + Statistic<> NumMoved("block-placement", "Number of basic blocks moved"); + + struct BlockPlacement : public FunctionPass { + virtual bool runOnFunction(Function &F); + + virtual void getAnalysisUsage(AnalysisUsage &AU) const { + AU.setPreservesCFG(); + AU.addRequired(); + //AU.addPreserved(); // Does this work? + } + private: + /// PI - The profile information that is guiding us. + /// + ProfileInfo *PI; + + /// NumMovedBlocks - Every time we move a block, increment this counter. + /// + unsigned NumMovedBlocks; + + /// PlacedBlocks - Every time we place a block, remember it so we don't get + /// into infinite loops. + std::set PlacedBlocks; + + /// InsertPos - This an iterator to the next place we want to insert a + /// block. + Function::iterator InsertPos; + + /// PlaceBlocks - Recursively place the specified blocks and any unplaced + /// successors. + void PlaceBlocks(BasicBlock *BB); + }; + + RegisterOpt X("block-placement", + "Profile Guided Basic Block Placement"); + } + + bool BlockPlacement::runOnFunction(Function &F) { + PI = &getAnalysis(); + + NumMovedBlocks = 0; + InsertPos = F.begin(); + + // Recursively place all blocks. + PlaceBlocks(F.begin()); + + PlacedBlocks.clear(); + NumMoved += NumMovedBlocks; + return NumMovedBlocks != 0; + } + + + /// PlaceBlocks - Recursively place the specified blocks and any unplaced + /// successors. + void BlockPlacement::PlaceBlocks(BasicBlock *BB) { + assert(!PlacedBlocks.count(BB) && "Already placed this block!"); + PlacedBlocks.insert(BB); + + // Place the specified block. + if (&*InsertPos != BB) { + // Use splice to move the block into the right place. This avoids having to + // remove the block from the function then readd it, which causes a bunch of + // symbol table traffic that is entirely pointless. + Function::BasicBlockListType &Blocks = BB->getParent()->getBasicBlockList(); + Blocks.splice(InsertPos, Blocks, BB); + + ++NumMovedBlocks; + } else { + // This block is already in the right place, we don't have to do anything. + ++InsertPos; + } + + // Keep placing successors until we run out of ones to place. Note that this + // loop is very inefficient (N^2) for blocks with many successors, like switch + // statements. FIXME! + while (1) { + // Okay, now place any unplaced successors. + succ_iterator SI = succ_begin(BB), E = succ_end(BB); + + // Scan for the first unplaced successor. + for (; SI != E && PlacedBlocks.count(*SI); ++SI) + /*empty*/; + if (SI == E) return; // No more successors to place. + + unsigned MaxExecutionCount = PI->getExecutionCount(*SI); + BasicBlock *MaxSuccessor = *SI; + + // Scan for more frequently executed successors + for (; SI != E; ++SI) + if (!PlacedBlocks.count(*SI)) { + unsigned Count = PI->getExecutionCount(*SI); + if (Count > MaxExecutionCount || + // Prefer to not disturb the code. + (Count == MaxExecutionCount && *SI == &*InsertPos)) { + MaxExecutionCount = Count; + MaxSuccessor = *SI; + } + } + + // Now that we picked the maximally executed successor, place it. + PlaceBlocks(MaxSuccessor); + } + } Index: llvm/lib/Transforms/Scalar/ADCE.cpp diff -u llvm/lib/Transforms/Scalar/ADCE.cpp:1.70 llvm/lib/Transforms/Scalar/ADCE.cpp:1.70.2.1 --- llvm/lib/Transforms/Scalar/ADCE.cpp:1.70 Fri Dec 19 03:08:34 2003 +++ llvm/lib/Transforms/Scalar/ADCE.cpp Mon Mar 1 17:58:16 2004 @@ -144,6 +144,7 @@ // Delete the instruction... I = BB->getInstList().erase(I); Changed = true; + ++NumInstRemoved; } else { ++I; } Index: llvm/lib/Transforms/Scalar/GCSE.cpp diff -u llvm/lib/Transforms/Scalar/GCSE.cpp:1.33 llvm/lib/Transforms/Scalar/GCSE.cpp:1.33.2.1 --- llvm/lib/Transforms/Scalar/GCSE.cpp:1.33 Fri Jan 9 00:02:20 2004 +++ llvm/lib/Transforms/Scalar/GCSE.cpp Mon Mar 1 17:58:16 2004 @@ -21,6 +21,7 @@ #include "llvm/Analysis/ValueNumbering.h" #include "llvm/Support/InstIterator.h" #include "Support/Statistic.h" +#include "Support/Debug.h" #include using namespace llvm; @@ -165,6 +166,9 @@ // void GCSE::ReplaceInstWithInst(Instruction *First, BasicBlock::iterator SI) { Instruction &Second = *SI; + + DEBUG(std::cerr << "GCSE: Substituting %" << First->getName() << " for: " + << Second); //cerr << "DEL " << (void*)Second << Second; Index: llvm/lib/Transforms/Scalar/InstructionCombining.cpp diff -u llvm/lib/Transforms/Scalar/InstructionCombining.cpp:1.149 llvm/lib/Transforms/Scalar/InstructionCombining.cpp:1.149.2.1 --- llvm/lib/Transforms/Scalar/InstructionCombining.cpp:1.149 Wed Jan 14 00:06:08 2004 +++ llvm/lib/Transforms/Scalar/InstructionCombining.cpp Mon Mar 1 17:58:16 2004 @@ -35,6 +35,7 @@ #include "llvm/Transforms/Scalar.h" #include "llvm/Instructions.h" +#include "llvm/Intrinsics.h" #include "llvm/Pass.h" #include "llvm/Constants.h" #include "llvm/DerivedTypes.h" @@ -60,15 +61,25 @@ std::vector WorkList; TargetData *TD; - void AddUsesToWorkList(Instruction &I) { - // The instruction was simplified, add all users of the instruction to - // the work lists because they might get more simplified now... - // + /// AddUsersToWorkList - When an instruction is simplified, add all users of + /// the instruction to the work lists because they might get more simplified + /// now. + /// + void AddUsersToWorkList(Instruction &I) { for (Value::use_iterator UI = I.use_begin(), UE = I.use_end(); UI != UE; ++UI) WorkList.push_back(cast(*UI)); } + /// AddUsesToWorkList - When an instruction is simplified, add operands to + /// the work lists because they might get more simplified now. + /// + void AddUsesToWorkList(Instruction &I) { + for (unsigned i = 0, e = I.getNumOperands(); i != e; ++i) + if (Instruction *Op = dyn_cast(I.getOperand(i))) + WorkList.push_back(Op); + } + // removeFromWorkList - remove all instances of I from the worklist. void removeFromWorkList(Instruction *I); public: @@ -116,12 +127,13 @@ // InsertNewInstBefore - insert an instruction New before instruction Old // in the program. Add the new instruction to the worklist. // - void InsertNewInstBefore(Instruction *New, Instruction &Old) { + Value *InsertNewInstBefore(Instruction *New, Instruction &Old) { assert(New && New->getParent() == 0 && "New instruction already inserted into a basic block!"); BasicBlock *BB = Old.getParent(); BB->getInstList().insert(&Old, New); // Insert inst WorkList.push_back(New); // Add to worklist + return New; } public: @@ -132,10 +144,24 @@ // modified. // Instruction *ReplaceInstUsesWith(Instruction &I, Value *V) { - AddUsesToWorkList(I); // Add all modified instrs to worklist + AddUsersToWorkList(I); // Add all modified instrs to worklist I.replaceAllUsesWith(V); return &I; } + + // EraseInstFromFunction - When dealing with an instruction that has side + // effects or produces a void value, we can't rely on DCE to delete the + // instruction. Instead, visit methods should return the value returned by + // this function. + Instruction *EraseInstFromFunction(Instruction &I) { + assert(I.use_empty() && "Cannot erase instruction that is used!"); + AddUsesToWorkList(I); + removeFromWorkList(&I); + I.getParent()->getInstList().erase(&I); + return 0; // Don't do anything with FI + } + + private: /// InsertOperandCastBefore - This inserts a cast of V to DestTy before the /// InsertBefore instruction. This is specialized a bit to avoid inserting @@ -173,6 +199,31 @@ return V->hasOneUse() || isa(V); } +// getSignedIntegralType - Given an unsigned integral type, return the signed +// version of it that has the same size. +static const Type *getSignedIntegralType(const Type *Ty) { + switch (Ty->getPrimitiveID()) { + default: assert(0 && "Invalid unsigned integer type!"); abort(); + case Type::UByteTyID: return Type::SByteTy; + case Type::UShortTyID: return Type::ShortTy; + case Type::UIntTyID: return Type::IntTy; + case Type::ULongTyID: return Type::LongTy; + } +} + +// getPromotedType - Return the specified type promoted as it would be to pass +// though a va_arg area... +static const Type *getPromotedType(const Type *Ty) { + switch (Ty->getPrimitiveID()) { + case Type::SByteTyID: + case Type::ShortTyID: return Type::IntTy; + case Type::UByteTyID: + case Type::UShortTyID: return Type::UIntTy; + case Type::FloatTyID: return Type::DoubleTy; + default: return Ty; + } +} + // SimplifyCommutative - This performs a few simplifications for commutative // operators: // @@ -415,7 +466,8 @@ Value *LHS = I.getOperand(0), *RHS = I.getOperand(1); // X + 0 --> X - if (RHS == Constant::getNullValue(I.getType())) + if (!I.getType()->isFloatingPoint() && // -0 + +0 = +0, so it's not a noop + RHS == Constant::getNullValue(I.getType())) return ReplaceInstUsesWith(I, LHS); // X + X --> X << 1 @@ -512,7 +564,8 @@ // Replace (x - (y - z)) with (x + (z - y)) if the (y - z) subexpression // is not used by anyone else... // - if (Op1I->getOpcode() == Instruction::Sub) { + if (Op1I->getOpcode() == Instruction::Sub && + !Op1I->getType()->isFloatingPoint()) { // Swap the two operands of the subexpr... Value *IIOp0 = Op1I->getOperand(0), *IIOp1 = Op1I->getOperand(1); Op1I->setOperand(0, IIOp1); @@ -556,6 +609,26 @@ return 0; } +/// isSignBitCheck - Given an exploded setcc instruction, return true if it is +/// really just returns true if the most significant (sign) bit is set. +static bool isSignBitCheck(unsigned Opcode, Value *LHS, ConstantInt *RHS) { + if (RHS->getType()->isSigned()) { + // True if source is LHS < 0 or LHS <= -1 + return Opcode == Instruction::SetLT && RHS->isNullValue() || + Opcode == Instruction::SetLE && RHS->isAllOnesValue(); + } else { + ConstantUInt *RHSC = cast(RHS); + // True if source is LHS > 127 or LHS >= 128, where the constants depend on + // the size of the integer type. + if (Opcode == Instruction::SetGE) + return RHSC->getValue() == 1ULL<<(RHS->getType()->getPrimitiveSize()*8-1); + if (Opcode == Instruction::SetGT) + return RHSC->getValue() == + (1ULL << (RHS->getType()->getPrimitiveSize()*8-1))-1; + } + return false; +} + Instruction *InstCombiner::visitMul(BinaryOperator &I) { bool Changed = SimplifyCommutative(I); Value *Op0 = I.getOperand(0); @@ -598,6 +671,52 @@ if (Value *Op1v = dyn_castNegVal(I.getOperand(1))) return BinaryOperator::create(Instruction::Mul, Op0v, Op1v); + // If one of the operands of the multiply is a cast from a boolean value, then + // we know the bool is either zero or one, so this is a 'masking' multiply. + // See if we can simplify things based on how the boolean was originally + // formed. + CastInst *BoolCast = 0; + if (CastInst *CI = dyn_cast(I.getOperand(0))) + if (CI->getOperand(0)->getType() == Type::BoolTy) + BoolCast = CI; + if (!BoolCast) + if (CastInst *CI = dyn_cast(I.getOperand(1))) + if (CI->getOperand(0)->getType() == Type::BoolTy) + BoolCast = CI; + if (BoolCast) { + if (SetCondInst *SCI = dyn_cast(BoolCast->getOperand(0))) { + Value *SCIOp0 = SCI->getOperand(0), *SCIOp1 = SCI->getOperand(1); + const Type *SCOpTy = SCIOp0->getType(); + + // If the setcc is true iff the sign bit of X is set, then convert this + // multiply into a shift/and combination. + if (isa(SCIOp1) && + isSignBitCheck(SCI->getOpcode(), SCIOp0, cast(SCIOp1))) { + // Shift the X value right to turn it into "all signbits". + Constant *Amt = ConstantUInt::get(Type::UByteTy, + SCOpTy->getPrimitiveSize()*8-1); + if (SCIOp0->getType()->isUnsigned()) { + const Type *NewTy = getSignedIntegralType(SCIOp0->getType()); + SCIOp0 = InsertNewInstBefore(new CastInst(SCIOp0, NewTy, + SCIOp0->getName()), I); + } + + Value *V = + InsertNewInstBefore(new ShiftInst(Instruction::Shr, SCIOp0, Amt, + BoolCast->getOperand(0)->getName()+ + ".mask"), I); + + // If the multiply type is not the same as the source type, sign extend + // or truncate to the multiply type. + if (I.getType() != V->getType()) + V = InsertNewInstBefore(new CastInst(V, I.getType(), V->getName()),I); + + Value *OtherOp = Op0 == BoolCast ? I.getOperand(1) : Op0; + return BinaryOperator::create(Instruction::And, V, OtherOp); + } + } + } + return Changed ? &I : 0; } @@ -1001,15 +1120,26 @@ return Changed ? &I : 0; } +// XorSelf - Implements: X ^ X --> 0 +struct XorSelf { + Value *RHS; + XorSelf(Value *rhs) : RHS(rhs) {} + bool shouldApply(Value *LHS) const { return LHS == RHS; } + Instruction *apply(BinaryOperator &Xor) const { + return &Xor; + } +}; Instruction *InstCombiner::visitXor(BinaryOperator &I) { bool Changed = SimplifyCommutative(I); Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1); - // xor X, X = 0 - if (Op0 == Op1) + // xor X, X = 0, even if X is nested in a sequence of Xor's. + if (Instruction *Result = AssociativeOpt(I, XorSelf(Op1))) { + assert(Result == &I && "AssociativeOpt didn't work?"); return ReplaceInstUsesWith(I, Constant::getNullValue(I.getType())); + } if (ConstantIntegral *RHS = dyn_cast(Op1)) { // xor X, 0 == X @@ -1074,7 +1204,7 @@ ConstantIntegral::getAllOnesValue(I.getType())); if (Instruction *Op1I = dyn_cast(Op1)) - if (Op1I->getOpcode() == Instruction::Or) + if (Op1I->getOpcode() == Instruction::Or) { if (Op1I->getOperand(0) == Op0) { // B^(B|A) == (A|B)^B cast(Op1I)->swapOperands(); I.swapOperands(); @@ -1082,7 +1212,13 @@ } else if (Op1I->getOperand(1) == Op0) { // B^(A|B) == (A|B)^B I.swapOperands(); std::swap(Op0, Op1); - } + } + } else if (Op1I->getOpcode() == Instruction::Xor) { + if (Op0 == Op1I->getOperand(0)) // A^(A^B) == B + return ReplaceInstUsesWith(I, Op1I->getOperand(1)); + else if (Op0 == Op1I->getOperand(1)) // A^(B^A) == B + return ReplaceInstUsesWith(I, Op1I->getOperand(0)); + } if (Instruction *Op0I = dyn_cast(Op0)) if (Op0I->getOpcode() == Instruction::Or && Op0I->hasOneUse()) { @@ -1094,6 +1230,11 @@ return BinaryOperator::create(Instruction::And, Op0I->getOperand(0), NotB); } + } else if (Op0I->getOpcode() == Instruction::Xor) { + if (Op1 == Op0I->getOperand(0)) // (A^B)^A == B + return ReplaceInstUsesWith(I, Op0I->getOperand(1)); + else if (Op1 == Op0I->getOperand(1)) // (B^A)^A == B + return ReplaceInstUsesWith(I, Op0I->getOperand(0)); } // (A & C1)^(B & C2) -> (A & C1)|(B & C2) iff C1^C2 == 0 @@ -1250,14 +1391,7 @@ Value *X = BO->getOperand(0); // If 'X' is not signed, insert a cast now... if (!BOC->getType()->isSigned()) { - const Type *DestTy; - switch (BOC->getType()->getPrimitiveID()) { - case Type::UByteTyID: DestTy = Type::SByteTy; break; - case Type::UShortTyID: DestTy = Type::ShortTy; break; - case Type::UIntTyID: DestTy = Type::IntTy; break; - case Type::ULongTyID: DestTy = Type::LongTy; break; - default: assert(0 && "Invalid unsigned integer type!"); abort(); - } + const Type *DestTy = getSignedIntegralType(BOC->getType()); CastInst *NewCI = new CastInst(X,DestTy,X->getName()+".signed"); InsertNewInstBefore(NewCI, I); X = NewCI; @@ -1270,6 +1404,43 @@ default: break; } } + } else { // Not a SetEQ/SetNE + // If the LHS is a cast from an integral value of the same size, + if (CastInst *Cast = dyn_cast(Op0)) { + Value *CastOp = Cast->getOperand(0); + const Type *SrcTy = CastOp->getType(); + unsigned SrcTySize = SrcTy->getPrimitiveSize(); + if (SrcTy != Cast->getType() && SrcTy->isInteger() && + SrcTySize == Cast->getType()->getPrimitiveSize()) { + assert((SrcTy->isSigned() ^ Cast->getType()->isSigned()) && + "Source and destination signednesses should differ!"); + if (Cast->getType()->isSigned()) { + // If this is a signed comparison, check for comparisons in the + // vicinity of zero. + if (I.getOpcode() == Instruction::SetLT && CI->isNullValue()) + // X < 0 => x > 127 + return BinaryOperator::create(Instruction::SetGT, CastOp, + ConstantUInt::get(SrcTy, (1ULL << (SrcTySize*8-1))-1)); + else if (I.getOpcode() == Instruction::SetGT && + cast(CI)->getValue() == -1) + // X > -1 => x < 128 + return BinaryOperator::create(Instruction::SetLT, CastOp, + ConstantUInt::get(SrcTy, 1ULL << (SrcTySize*8-1))); + } else { + ConstantUInt *CUI = cast(CI); + if (I.getOpcode() == Instruction::SetLT && + CUI->getValue() == 1ULL << (SrcTySize*8-1)) + // X < 128 => X > -1 + return BinaryOperator::create(Instruction::SetGT, CastOp, + ConstantSInt::get(SrcTy, -1)); + else if (I.getOpcode() == Instruction::SetGT && + CUI->getValue() == (1ULL << (SrcTySize*8-1))-1) + // X > 127 => X < 0 + return BinaryOperator::create(Instruction::SetLT, CastOp, + Constant::getNullValue(SrcTy)); + } + } + } } // Check to see if we are comparing against the minimum or maximum value... @@ -1306,6 +1477,15 @@ if (I.getOpcode() == Instruction::SetLE) // A <= MAX-1 -> A != MAX return BinaryOperator::create(Instruction::SetNE, Op0, AddOne(CI)); } + + // If we still have a setle or setge instruction, turn it into the + // appropriate setlt or setgt instruction. Since the border cases have + // already been handled above, this requires little checking. + // + if (I.getOpcode() == Instruction::SetLE) + return BinaryOperator::create(Instruction::SetLT, Op0, AddOne(CI)); + if (I.getOpcode() == Instruction::SetGE) + return BinaryOperator::create(Instruction::SetGT, Op0, SubOne(CI)); } // Test to see if the operands of the setcc are casted versions of other @@ -1416,9 +1596,14 @@ // of a signed value. // unsigned TypeBits = Op0->getType()->getPrimitiveSize()*8; - if (CUI->getValue() >= TypeBits && - (!Op0->getType()->isSigned() || isLeftShift)) - return ReplaceInstUsesWith(I, Constant::getNullValue(Op0->getType())); + if (CUI->getValue() >= TypeBits) { + if (!Op0->getType()->isSigned() || isLeftShift) + return ReplaceInstUsesWith(I, Constant::getNullValue(Op0->getType())); + else { + I.setOperand(1, ConstantUInt::get(Type::UByteTy, TypeBits-1)); + return &I; + } + } // ((X*C1) << C2) == (X * (C1 << C2)) if (BinaryOperator *BO = dyn_cast(Op0)) @@ -1482,6 +1667,8 @@ // Check for (A << c1) << c2 and (A >> c1) >> c2 if (I.getOpcode() == Op0SI->getOpcode()) { unsigned Amt = ShiftAmt1+ShiftAmt2; // Fold into one big shift... + if (Op0->getType()->getPrimitiveSize()*8 < Amt) + Amt = Op0->getType()->getPrimitiveSize()*8; return new ShiftInst(I.getOpcode(), Op0SI->getOperand(0), ConstantUInt::get(Type::UByteTy, Amt)); } @@ -1747,6 +1934,23 @@ // CallInst simplification // Instruction *InstCombiner::visitCallInst(CallInst &CI) { + // Intrinsics cannot occur in an invoke, so handle them here instead of in + // visitCallSite. + if (Function *F = CI.getCalledFunction()) + switch (F->getIntrinsicID()) { + case Intrinsic::memmove: + case Intrinsic::memcpy: + case Intrinsic::memset: + // memmove/cpy/set of zero bytes is a noop. + if (Constant *NumBytes = dyn_cast(CI.getOperand(3))) { + if (NumBytes->isNullValue()) + return EraseInstFromFunction(CI); + } + break; + default: + break; + } + return visitCallSite(&CI); } @@ -1756,19 +1960,6 @@ return visitCallSite(&II); } -// getPromotedType - Return the specified type promoted as it would be to pass -// though a va_arg area... -static const Type *getPromotedType(const Type *Ty) { - switch (Ty->getPrimitiveID()) { - case Type::SByteTyID: - case Type::ShortTyID: return Type::IntTy; - case Type::UByteTyID: - case Type::UShortTyID: return Type::UIntTy; - case Type::FloatTyID: return Type::DoubleTy; - default: return Ty; - } -} - // visitCallSite - Improvements for call and invoke instructions. // Instruction *InstCombiner::visitCallSite(CallSite CS) { @@ -1838,7 +2029,7 @@ UI != E; ++UI) if (PHINode *PN = dyn_cast(*UI)) if (PN->getParent() == II->getNormalDest() || - PN->getParent() == II->getExceptionalDest()) + PN->getParent() == II->getUnwindDest()) return false; } @@ -1903,7 +2094,7 @@ Instruction *NC; if (InvokeInst *II = dyn_cast(Caller)) { - NC = new InvokeInst(Callee, II->getNormalDest(), II->getExceptionalDest(), + NC = new InvokeInst(Callee, II->getNormalDest(), II->getUnwindDest(), Args, Caller->getName(), Caller); } else { NC = new CallInst(Callee, Args, Caller->getName(), Caller); @@ -1925,7 +2116,7 @@ // Otherwise, it's a call, just insert cast right after the call instr InsertNewInstBefore(NC, *Caller); } - AddUsesToWorkList(*Caller); + AddUsersToWorkList(*Caller); } else { NV = Constant::getNullValue(Caller->getType()); } @@ -1945,6 +2136,35 @@ Instruction *InstCombiner::visitPHINode(PHINode &PN) { if (Value *V = hasConstantValue(&PN)) return ReplaceInstUsesWith(PN, V); + + // If the only user of this instruction is a cast instruction, and all of the + // incoming values are constants, change this PHI to merge together the casted + // constants. + if (PN.hasOneUse()) + if (CastInst *CI = dyn_cast(PN.use_back())) + if (CI->getType() != PN.getType()) { // noop casts will be folded + bool AllConstant = true; + for (unsigned i = 0, e = PN.getNumIncomingValues(); i != e; ++i) + if (!isa(PN.getIncomingValue(i))) { + AllConstant = false; + break; + } + if (AllConstant) { + // Make a new PHI with all casted values. + PHINode *New = new PHINode(CI->getType(), PN.getName(), &PN); + for (unsigned i = 0, e = PN.getNumIncomingValues(); i != e; ++i) { + Constant *OldArg = cast(PN.getIncomingValue(i)); + New->addIncoming(ConstantExpr::getCast(OldArg, New->getType()), + PN.getIncomingBlock(i)); + } + + // Update the cast instruction. + CI->setOperand(0, New); + WorkList.push_back(CI); // revisit the cast instruction to fold. + WorkList.push_back(New); // Make sure to revisit the new Phi + return &PN; // PN is now dead! + } + } return 0; } @@ -1952,9 +2172,14 @@ Instruction *InstCombiner::visitGetElementPtrInst(GetElementPtrInst &GEP) { // Is it 'getelementptr %P, long 0' or 'getelementptr %P' // If so, eliminate the noop. - if ((GEP.getNumOperands() == 2 && - GEP.getOperand(1) == Constant::getNullValue(Type::LongTy)) || - GEP.getNumOperands() == 1) + if (GEP.getNumOperands() == 1) + return ReplaceInstUsesWith(GEP, GEP.getOperand(0)); + + bool HasZeroPointerIndex = false; + if (Constant *C = dyn_cast(GEP.getOperand(1))) + HasZeroPointerIndex = C->isNullValue(); + + if (GEP.getNumOperands() == 2 && HasZeroPointerIndex) return ReplaceInstUsesWith(GEP, GEP.getOperand(0)); // Combine Indices - If the source pointer to this getelementptr instruction @@ -1975,12 +2200,20 @@ assert(Sum && "Constant folding of longs failed!?"); GEP.setOperand(0, Src->getOperand(0)); GEP.setOperand(1, Sum); - AddUsesToWorkList(*Src); // Reduce use count of Src + AddUsersToWorkList(*Src); // Reduce use count of Src return &GEP; } else if (Src->getNumOperands() == 2) { // Replace: gep (gep %P, long B), long A, ... // With: T = long A+B; gep %P, T, ... // + // Note that if our source is a gep chain itself that we wait for that + // chain to be resolved before we perform this transformation. This + // avoids us creating a TON of code in some cases. + // + if (isa(Src->getOperand(0)) && + cast(Src->getOperand(0))->getNumOperands() == 2) + return 0; // Wait until our source is folded to completion. + Value *Sum = BinaryOperator::create(Instruction::Add, Src->getOperand(1), GEP.getOperand(1), Src->getName()+".sum", &GEP); @@ -2021,6 +2254,31 @@ // Replace all uses of the GEP with the new constexpr... return ReplaceInstUsesWith(GEP, CE); } + } else if (ConstantExpr *CE = dyn_cast(GEP.getOperand(0))) { + if (CE->getOpcode() == Instruction::Cast) { + if (HasZeroPointerIndex) { + // transform: GEP (cast [10 x ubyte]* X to [0 x ubyte]*), long 0, ... + // into : GEP [10 x ubyte]* X, long 0, ... + // + // This occurs when the program declares an array extern like "int X[];" + // + Constant *X = CE->getOperand(0); + const PointerType *CPTy = cast(CE->getType()); + if (const PointerType *XTy = dyn_cast(X->getType())) + if (const ArrayType *XATy = + dyn_cast(XTy->getElementType())) + if (const ArrayType *CATy = + dyn_cast(CPTy->getElementType())) + if (CATy->getElementType() == XATy->getElementType()) { + // At this point, we know that the cast source type is a pointer + // to an array of the same type as the destination pointer + // array. Because the array type is never stepped over (there + // is a leading zero) we can fold the cast into this GEP. + GEP.setOperand(0, X); + return &GEP; + } + } + } } return 0; @@ -2071,6 +2329,11 @@ return &FI; } + // If we have 'free null' delete the instruction. This can happen in stl code + // when lots of inlining happens. + if (isa(Op)) + return EraseInstFromFunction(FI); + return 0; } @@ -2087,11 +2350,13 @@ // addressing... for (unsigned i = 2, e = CE->getNumOperands(); i != e; ++i) if (ConstantUInt *CU = dyn_cast(CE->getOperand(i))) { - ConstantStruct *CS = cast(C); + ConstantStruct *CS = dyn_cast(C); + if (CS == 0) return 0; if (CU->getValue() >= CS->getValues().size()) return 0; C = cast(CS->getValues()[CU->getValue()]); } else if (ConstantSInt *CS = dyn_cast(CE->getOperand(i))) { - ConstantArray *CA = cast(C); + ConstantArray *CA = dyn_cast(C); + if (CA == 0) return 0; if ((uint64_t)CS->getValue() >= CA->getValues().size()) return 0; C = cast(CA->getValues()[CS->getValue()]); } else @@ -2125,7 +2390,7 @@ Instruction *InstCombiner::visitBranchInst(BranchInst &BI) { // Change br (not X), label True, label False to: br X, label False, True - if (BI.isConditional() && !isa(BI.getCondition())) + if (BI.isConditional() && !isa(BI.getCondition())) { if (Value *V = dyn_castNotVal(BI.getCondition())) { BasicBlock *TrueDest = BI.getSuccessor(0); BasicBlock *FalseDest = BI.getSuccessor(1); @@ -2134,7 +2399,29 @@ BI.setSuccessor(0, FalseDest); BI.setSuccessor(1, TrueDest); return &BI; + } else if (SetCondInst *I = dyn_cast(BI.getCondition())) { + // Cannonicalize setne -> seteq + if ((I->getOpcode() == Instruction::SetNE || + I->getOpcode() == Instruction::SetLE || + I->getOpcode() == Instruction::SetGE) && I->hasOneUse()) { + std::string Name = I->getName(); I->setName(""); + Instruction::BinaryOps NewOpcode = + SetCondInst::getInverseCondition(I->getOpcode()); + Value *NewSCC = BinaryOperator::create(NewOpcode, I->getOperand(0), + I->getOperand(1), Name, I); + BasicBlock *TrueDest = BI.getSuccessor(0); + BasicBlock *FalseDest = BI.getSuccessor(1); + // Swap Destinations and condition... + BI.setCondition(NewSCC); + BI.setSuccessor(0, FalseDest); + BI.setSuccessor(1, TrueDest); + removeFromWorkList(I); + I->getParent()->getInstList().erase(I); + WorkList.push_back(cast(NewSCC)); + return &BI; + } } + } return 0; } @@ -2159,9 +2446,7 @@ if (isInstructionTriviallyDead(I)) { // Add operands to the worklist... if (I->getNumOperands() < 4) - for (unsigned i = 0, e = I->getNumOperands(); i != e; ++i) - if (Instruction *Op = dyn_cast(I->getOperand(i))) - WorkList.push_back(Op); + AddUsesToWorkList(*I); ++NumDeadInst; I->getParent()->getInstList().erase(I); @@ -2172,9 +2457,7 @@ // Instruction isn't dead, see if we can constant propagate it... if (Constant *C = ConstantFoldInstruction(I)) { // Add operands to the worklist... - for (unsigned i = 0, e = I->getNumOperands(); i != e; ++i) - if (Instruction *Op = dyn_cast(I->getOperand(i))) - WorkList.push_back(Op); + AddUsesToWorkList(*I); ReplaceInstUsesWith(*I, C); ++NumConstProp; @@ -2220,7 +2503,7 @@ if (Result) { WorkList.push_back(Result); - AddUsesToWorkList(*Result); + AddUsersToWorkList(*Result); } Changed = true; } Index: llvm/lib/Transforms/Scalar/LICM.cpp diff -u llvm/lib/Transforms/Scalar/LICM.cpp:1.55 llvm/lib/Transforms/Scalar/LICM.cpp:1.55.2.1 --- llvm/lib/Transforms/Scalar/LICM.cpp:1.55 Wed Jan 7 18:09:44 2004 +++ llvm/lib/Transforms/Scalar/LICM.cpp Mon Mar 1 17:58:16 2004 @@ -679,7 +679,7 @@ I != E; ++I) { AliasSet &AS = *I; // We can promote this alias set if it has a store, if it is a "Must" alias - // set, and if the pointer is loop invariant. + // set, if the pointer is loop invariant, if if we are not eliminating any volatile loads or stores. if (!AS.isForwardingAliasSet() && AS.isMod() && AS.isMustAlias() && !AS.isVolatile() && isLoopInvariant(AS.begin()->first)) { assert(AS.begin() != AS.end() && Index: llvm/lib/Transforms/Scalar/LoopSimplify.cpp diff -u llvm/lib/Transforms/Scalar/LoopSimplify.cpp:1.30 llvm/lib/Transforms/Scalar/LoopSimplify.cpp:1.30.2.1 --- llvm/lib/Transforms/Scalar/LoopSimplify.cpp:1.30 Wed Jan 7 18:09:44 2004 +++ llvm/lib/Transforms/Scalar/LoopSimplify.cpp Mon Mar 1 17:58:16 2004 @@ -151,7 +151,7 @@ const std::vector &Preds) { // Create new basic block, insert right before the original block... - BasicBlock *NewBB = new BasicBlock(BB->getName()+Suffix, BB); + BasicBlock *NewBB = new BasicBlock(BB->getName()+Suffix, BB->getParent(), BB); // The preheader first gets an unconditional branch to the loop header... BranchInst *BI = new BranchInst(BB, NewBB); @@ -484,20 +484,44 @@ /// dominators, dominator trees, and dominance frontiers) after a new block has /// been added to the CFG. /// -/// This only supports the case when an existing block (known as "Exit"), had -/// some of its predecessors factored into a new basic block. This +/// This only supports the case when an existing block (known as "NewBBSucc"), +/// had some of its predecessors factored into a new basic block. This /// transformation inserts a new basic block ("NewBB"), with a single -/// unconditional branch to Exit, and moves some predecessors of "Exit" to now -/// branch to NewBB. These predecessors are listed in PredBlocks, even though -/// they are the same as pred_begin(NewBB)/pred_end(NewBB). +/// unconditional branch to NewBBSucc, and moves some predecessors of +/// "NewBBSucc" to now branch to NewBB. These predecessors are listed in +/// PredBlocks, even though they are the same as +/// pred_begin(NewBB)/pred_end(NewBB). /// void LoopSimplify::UpdateDomInfoForRevectoredPreds(BasicBlock *NewBB, std::vector &PredBlocks) { + assert(!PredBlocks.empty() && "No predblocks??"); assert(succ_begin(NewBB) != succ_end(NewBB) && ++succ_begin(NewBB) == succ_end(NewBB) && "NewBB should have a single successor!"); + BasicBlock *NewBBSucc = *succ_begin(NewBB); DominatorSet &DS = getAnalysis(); + // The newly inserted basic block will dominate existing basic blocks iff the + // PredBlocks dominate all of the non-pred blocks. If all predblocks dominate + // the non-pred blocks, then they all must be the same block! + bool NewBBDominatesNewBBSucc = true; + { + BasicBlock *OnePred = PredBlocks[0]; + for (unsigned i = 1, e = PredBlocks.size(); i != e; ++i) + if (PredBlocks[i] != OnePred) { + NewBBDominatesNewBBSucc = false; + break; + } + + if (NewBBDominatesNewBBSucc) + for (pred_iterator PI = pred_begin(NewBBSucc), E = pred_end(NewBBSucc); + PI != E; ++PI) + if (*PI != NewBB && !DS.dominates(NewBBSucc, *PI)) { + NewBBDominatesNewBBSucc = false; + break; + } + } + // Update dominator information... The blocks that dominate NewBB are the // intersection of the dominators of predecessors, plus the block itself. // The newly created basic block does not dominate anything except itself. @@ -508,13 +532,22 @@ NewBBDomSet.insert(NewBB); // All blocks dominate themselves... DS.addBasicBlock(NewBB, NewBBDomSet); + // If NewBB dominates some blocks, then it will dominate all blocks that + // NewBBSucc does. + if (NewBBDominatesNewBBSucc) { + BasicBlock *PredBlock = PredBlocks[0]; + Function *F = NewBB->getParent(); + for (Function::iterator I = F->begin(), E = F->end(); I != E; ++I) + if (DS.dominates(NewBBSucc, I)) + DS.addDominator(I, NewBB); + } + // Update immediate dominator information if we have it... BasicBlock *NewBBIDom = 0; if (ImmediateDominators *ID = getAnalysisToUpdate()) { - // This block does not strictly dominate anything, so it is not an immediate - // dominator. To find the immediate dominator of the new exit node, we - // trace up the immediate dominators of a predecessor until we find a basic - // block that dominates the exit block. + // To find the immediate dominator of the new exit node, we trace up the + // immediate dominators of a predecessor until we find a basic block that + // dominates the exit block. // BasicBlock *Dom = PredBlocks[0]; // Some random predecessor... while (!NewBBDomSet.count(Dom)) { // Loop until we find a dominator... @@ -525,13 +558,21 @@ // Set the immediate dominator now... ID->addNewBlock(NewBB, Dom); NewBBIDom = Dom; // Reuse this if calculating DominatorTree info... + + // If NewBB strictly dominates other blocks, we need to update their idom's + // now. The only block that need adjustment is the NewBBSucc block, whose + // idom should currently be set to PredBlocks[0]. + if (NewBBDominatesNewBBSucc) { + assert(ID->get(NewBBSucc) == PredBlocks[0] && + "Immediate dominator update code broken!"); + ID->setImmediateDominator(NewBBSucc, NewBB); + } } // Update DominatorTree information if it is active. if (DominatorTree *DT = getAnalysisToUpdate()) { - // NewBB doesn't dominate anything, so just create a node and link it into - // its immediate dominator. If we don't have ImmediateDominator info - // around, calculate the idom as above. + // If we don't have ImmediateDominator info around, calculate the idom as + // above. DominatorTree::Node *NewBBIDomNode; if (NewBBIDom) { NewBBIDomNode = DT->getNode(NewBBIDom); @@ -543,27 +584,58 @@ } } - // Create the new dominator tree node... - DT->createNewNode(NewBB, NewBBIDomNode); + // Create the new dominator tree node... and set the idom of NewBB. + DominatorTree::Node *NewBBNode = DT->createNewNode(NewBB, NewBBIDomNode); + + // If NewBB strictly dominates other blocks, then it is now the immediate + // dominator of NewBBSucc. Update the dominator tree as appropriate. + if (NewBBDominatesNewBBSucc) { + DominatorTree::Node *NewBBSuccNode = DT->getNode(NewBBSucc); + assert(NewBBSuccNode->getIDom()->getBlock() == PredBlocks[0] && + "Immediate tree update code broken!"); + DT->changeImmediateDominator(NewBBSuccNode, NewBBNode); + } } // Update dominance frontier information... if (DominanceFrontier *DF = getAnalysisToUpdate()) { - // DF(NewBB) is {Exit} because NewBB does not strictly dominate Exit, but it - // does dominate itself (and there is an edge (NewBB -> Exit)). Exit is the - // single successor of NewBB. - DominanceFrontier::DomSetType NewDFSet; - BasicBlock *Exit = *succ_begin(NewBB); - NewDFSet.insert(Exit); - DF->addBasicBlock(NewBB, NewDFSet); + // If NewBB dominates NewBBSucc, then the global dominance frontiers are not + // changed. DF(NewBB) is now going to be the DF(PredBlocks[0]) without the + // stuff that the new block does not dominate a predecessor of. + if (NewBBDominatesNewBBSucc) { + DominanceFrontier::iterator DFI = DF->find(PredBlocks[0]); + if (DFI != DF->end()) { + DominanceFrontier::DomSetType Set = DFI->second; + // Filter out stuff in Set that we do not dominate a predecessor of. + for (DominanceFrontier::DomSetType::iterator SetI = Set.begin(), + E = Set.end(); SetI != E;) { + bool DominatesPred = false; + for (pred_iterator PI = pred_begin(*SetI), E = pred_end(*SetI); + PI != E; ++PI) + if (DS.dominates(NewBB, *PI)) + DominatesPred = true; + if (!DominatesPred) + Set.erase(SetI++); + else + ++SetI; + } - // Now we must loop over all of the dominance frontiers in the function, - // replacing occurrences of Exit with NewBB in some cases. All blocks that - // dominate a block in PredBlocks and contained Exit in their dominance - // frontier must be updated to contain NewBB instead. This only occurs if - // there is more than one block in PredBlocks. - // - if (PredBlocks.size() > 1) { + DF->addBasicBlock(NewBB, Set); + } + + } else { + // DF(NewBB) is {NewBBSucc} because NewBB does not strictly dominate + // NewBBSucc, but it does dominate itself (and there is an edge (NewBB -> + // NewBBSucc)). NewBBSucc is the single successor of NewBB. + DominanceFrontier::DomSetType NewDFSet; + NewDFSet.insert(NewBBSucc); + DF->addBasicBlock(NewBB, NewDFSet); + + // Now we must loop over all of the dominance frontiers in the function, + // replacing occurrences of NewBBSucc with NewBB in some cases. All + // blocks that dominate a block in PredBlocks and contained NewBBSucc in + // their dominance frontier must be updated to contain NewBB instead. + // for (unsigned i = 0, e = PredBlocks.size(); i != e; ++i) { BasicBlock *Pred = PredBlocks[i]; // Get all of the dominators of the predecessor... @@ -572,13 +644,13 @@ PDE = PredDoms.end(); PDI != PDE; ++PDI) { BasicBlock *PredDom = *PDI; - // If the Exit node is in DF(PredDom), then PredDom didn't dominate - // Exit but did dominate a predecessor of it. Now we change this - // entry to include NewBB in the DF instead of Exit. + // If the NewBBSucc node is in DF(PredDom), then PredDom didn't + // dominate NewBBSucc but did dominate a predecessor of it. Now we + // change this entry to include NewBB in the DF instead of NewBBSucc. DominanceFrontier::iterator DFI = DF->find(PredDom); assert(DFI != DF->end() && "No dominance frontier for node?"); - if (DFI->second.count(Exit)) { - DF->removeFromFrontier(DFI, Exit); + if (DFI->second.count(NewBBSucc)) { + DF->removeFromFrontier(DFI, NewBBSucc); DF->addToFrontier(DFI, NewBB); } } Index: llvm/lib/Transforms/Scalar/LowerAllocations.cpp diff -u llvm/lib/Transforms/Scalar/LowerAllocations.cpp:1.43 llvm/lib/Transforms/Scalar/LowerAllocations.cpp:1.43.2.1 --- llvm/lib/Transforms/Scalar/LowerAllocations.cpp:1.43 Fri Jan 9 00:02:20 2004 +++ llvm/lib/Transforms/Scalar/LowerAllocations.cpp Mon Mar 1 17:58:16 2004 @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// // -// The LowerAllocations transformation is a target dependent tranformation +// The LowerAllocations transformation is a target-dependent tranformation // because it depends on the size of data types and alignment constraints. // //===----------------------------------------------------------------------===// @@ -67,8 +67,13 @@ // bool LowerAllocations::doInitialization(Module &M) { const Type *SBPTy = PointerType::get(Type::SByteTy); - MallocFunc = M.getOrInsertFunction("malloc", SBPTy, Type::UIntTy, 0); - FreeFunc = M.getOrInsertFunction("free" , Type::VoidTy, SBPTy, 0); + MallocFunc = M.getNamedFunction("malloc"); + FreeFunc = M.getNamedFunction("free"); + + if (MallocFunc == 0) + MallocFunc = M.getOrInsertFunction("malloc", SBPTy, Type::UIntTy, 0); + if (FreeFunc == 0) + FreeFunc = M.getOrInsertFunction("free" , Type::VoidTy, SBPTy, 0); return true; } @@ -101,13 +106,30 @@ MallocArg = BinaryOperator::create(Instruction::Mul, MI->getOperand(0), MallocArg, "", I); } + + const FunctionType *MallocFTy = MallocFunc->getFunctionType(); + std::vector MallocArgs; + if (MallocFTy->getNumParams() > 0 || MallocFTy->isVarArg()) { + if (MallocFTy->getNumParams() > 0 && + MallocFTy->getParamType(0) != Type::UIntTy) + MallocArg = new CastInst(MallocArg, MallocFTy->getParamType(0), "",I); + MallocArgs.push_back(MallocArg); + } + + // If malloc is prototyped to take extra arguments, pass nulls. + for (unsigned i = 1; i < MallocFTy->getNumParams(); ++i) + MallocArgs.push_back(Constant::getNullValue(MallocFTy->getParamType(i))); + // Create the call to Malloc... - CallInst *MCall = new CallInst(MallocFunc, - std::vector(1, MallocArg), "", I); + CallInst *MCall = new CallInst(MallocFunc, MallocArgs, "", I); // Create a cast instruction to convert to the right type... - CastInst *MCast = new CastInst(MCall, MI->getType(), "", I); + Value *MCast; + if (MCall->getType() != Type::VoidTy) + MCast = new CastInst(MCall, MI->getType(), "", I); + else + MCast = Constant::getNullValue(MI->getType()); // Replace all uses of the old malloc inst with the cast inst MI->replaceAllUsesWith(MCast); @@ -115,13 +137,23 @@ Changed = true; ++NumLowered; } else if (FreeInst *FI = dyn_cast(I)) { - // Cast the argument to free into a ubyte*... - CastInst *MCast = new CastInst(FI->getOperand(0), - PointerType::get(Type::SByteTy), "", I); + const FunctionType *FreeFTy = FreeFunc->getFunctionType(); + std::vector FreeArgs; + + if (FreeFTy->getNumParams() > 0 || FreeFTy->isVarArg()) { + Value *MCast = FI->getOperand(0); + if (FreeFTy->getNumParams() > 0 && + FreeFTy->getParamType(0) != MCast->getType()) + MCast = new CastInst(MCast, FreeFTy->getParamType(0), "", I); + FreeArgs.push_back(MCast); + } + + // If malloc is prototyped to take extra arguments, pass nulls. + for (unsigned i = 1; i < FreeFTy->getNumParams(); ++i) + FreeArgs.push_back(Constant::getNullValue(FreeFTy->getParamType(i))); // Insert a call to the free function... - CallInst *FCall = new CallInst(FreeFunc, std::vector(1, MCast), - "", I); + new CallInst(FreeFunc, FreeArgs, "", I); // Delete the old free instruction I = --BBIL.erase(I); Index: llvm/lib/Transforms/Scalar/LowerInvoke.cpp diff -u llvm/lib/Transforms/Scalar/LowerInvoke.cpp:1.4 llvm/lib/Transforms/Scalar/LowerInvoke.cpp:1.4.4.1 --- llvm/lib/Transforms/Scalar/LowerInvoke.cpp:1.4 Wed Dec 10 14:22:42 2003 +++ llvm/lib/Transforms/Scalar/LowerInvoke.cpp Mon Mar 1 17:58:16 2004 @@ -8,47 +8,205 @@ //===----------------------------------------------------------------------===// // // This transformation is designed for use by code generators which do not yet -// support stack unwinding. This pass gives them the ability to execute any -// program which does not throw an exception, by turning 'invoke' instructions -// into calls and by turning 'unwind' instructions into calls to abort(). +// support stack unwinding. This pass supports two models of exception handling +// lowering, the 'cheap' support and the 'expensive' support. +// +// 'Cheap' exception handling support gives the program the ability to execute +// any program which does not "throw an exception", by turning 'invoke' +// instructions into calls and by turning 'unwind' instructions into calls to +// abort(). If the program does dynamically use the unwind instruction, the +// program will print a message then abort. +// +// 'Expensive' exception handling support gives the full exception handling +// support to the program at making the 'invoke' instruction really expensive. +// It basically inserts setjmp/longjmp calls to emulate the exception handling +// as necessary. +// +// Because the 'expensive' support slows down programs a lot, and EH is only +// used for a subset of the programs, it must be specifically enabled by an +// option. // //===----------------------------------------------------------------------===// #include "llvm/Transforms/Scalar.h" -#include "llvm/Pass.h" -#include "llvm/iTerminators.h" -#include "llvm/iOther.h" +#include "llvm/Constants.h" +#include "llvm/DerivedTypes.h" +#include "llvm/Instructions.h" #include "llvm/Module.h" -#include "llvm/Type.h" -#include "llvm/Constant.h" +#include "llvm/Pass.h" +#include "llvm/Transforms/Utils/BasicBlockUtils.h" #include "Support/Statistic.h" +#include "Support/CommandLine.h" +#include using namespace llvm; namespace { Statistic<> NumLowered("lowerinvoke", "Number of invoke & unwinds replaced"); + cl::opt ExpensiveEHSupport("enable-correct-eh-support", + cl::desc("Make the -lowerinvoke pass insert expensive, but correct, EH code")); class LowerInvoke : public FunctionPass { + // Used for both models. + Function *WriteFn; Function *AbortFn; + Constant *AbortMessageInit; + Value *AbortMessage; + unsigned AbortMessageLength; + + // Used for expensive EH support. + const Type *JBLinkTy; + GlobalVariable *JBListHead; + Function *SetJmpFn, *LongJmpFn; public: bool doInitialization(Module &M); bool runOnFunction(Function &F); + private: + void writeAbortMessage(Instruction *IB); + bool insertCheapEHSupport(Function &F); + bool insertExpensiveEHSupport(Function &F); }; RegisterOpt X("lowerinvoke", "Lower invoke and unwind, for unwindless code generators"); } +const PassInfo *llvm::LowerInvokePassID = X.getPassInfo(); + // Public Interface To the LowerInvoke pass. FunctionPass *llvm::createLowerInvokePass() { return new LowerInvoke(); } // doInitialization - Make sure that there is a prototype for abort in the // current module. bool LowerInvoke::doInitialization(Module &M) { + const Type *VoidPtrTy = PointerType::get(Type::SByteTy); + AbortMessage = 0; + if (ExpensiveEHSupport) { + // Insert a type for the linked list of jump buffers. Unfortunately, we + // don't know the size of the target's setjmp buffer, so we make a guess. + // If this guess turns out to be too small, bad stuff could happen. + unsigned JmpBufSize = 200; // PPC has 192 words + assert(sizeof(jmp_buf) <= JmpBufSize*sizeof(void*) && + "LowerInvoke doesn't know about targets with jmp_buf size > 200 words!"); + const Type *JmpBufTy = ArrayType::get(VoidPtrTy, JmpBufSize); + + { // The type is recursive, so use a type holder. + std::vector Elements; + OpaqueType *OT = OpaqueType::get(); + Elements.push_back(PointerType::get(OT)); + Elements.push_back(JmpBufTy); + PATypeHolder JBLType(StructType::get(Elements)); + OT->refineAbstractTypeTo(JBLType.get()); // Complete the cycle. + JBLinkTy = JBLType.get(); + } + + const Type *PtrJBList = PointerType::get(JBLinkTy); + + // Now that we've done that, insert the jmpbuf list head global, unless it + // already exists. + if (!(JBListHead = M.getGlobalVariable("llvm.sjljeh.jblist", PtrJBList))) + JBListHead = new GlobalVariable(PtrJBList, false, + GlobalValue::LinkOnceLinkage, + Constant::getNullValue(PtrJBList), + "llvm.sjljeh.jblist", &M); + SetJmpFn = M.getOrInsertFunction("llvm.setjmp", Type::IntTy, + PointerType::get(JmpBufTy), 0); + LongJmpFn = M.getOrInsertFunction("llvm.longjmp", Type::VoidTy, + PointerType::get(JmpBufTy), + Type::IntTy, 0); + + // The abort message for expensive EH support tells the user that the + // program 'unwound' without an 'invoke' instruction. + Constant *Msg = + ConstantArray::get("ERROR: Exception thrown, but not caught!\n"); + AbortMessageLength = Msg->getNumOperands()-1; // don't include \0 + AbortMessageInit = Msg; + + GlobalVariable *MsgGV = M.getGlobalVariable("abort.msg", Msg->getType()); + if (MsgGV && (!MsgGV->hasInitializer() || MsgGV->getInitializer() != Msg)) + MsgGV = 0; + + if (MsgGV) { + std::vector GEPIdx(2, Constant::getNullValue(Type::LongTy)); + AbortMessage = + ConstantExpr::getGetElementPtr(ConstantPointerRef::get(MsgGV), GEPIdx); + } + + } else { + // The abort message for cheap EH support tells the user that EH is not + // enabled. + Constant *Msg = + ConstantArray::get("Exception handler needed, but not enabled. Recompile" + " program with -enable-correct-eh-support.\n"); + AbortMessageLength = Msg->getNumOperands()-1; // don't include \0 + AbortMessageInit = Msg; + + GlobalVariable *MsgGV = M.getGlobalVariable("abort.msg", Msg->getType()); + if (MsgGV && (!MsgGV->hasInitializer() || MsgGV->getInitializer() != Msg)) + MsgGV = 0; + + if (MsgGV) { + std::vector GEPIdx(2, Constant::getNullValue(Type::LongTy)); + AbortMessage = + ConstantExpr::getGetElementPtr(ConstantPointerRef::get(MsgGV), GEPIdx); + } + } + + // We need the 'write' and 'abort' functions for both models. AbortFn = M.getOrInsertFunction("abort", Type::VoidTy, 0); + + // Unfortunately, 'write' can end up being prototyped in several different + // ways. If the user defines a three (or more) operand function named 'write' + // we will use their prototype. We _do not_ want to insert another instance + // of a write prototype, because we don't know that the funcresolve pass will + // run after us. If there is a definition of a write function, but it's not + // suitable for our uses, we just don't emit write calls. If there is no + // write prototype at all, we just add one. + if (Function *WF = M.getNamedFunction("write")) { + if (WF->getFunctionType()->getNumParams() > 3 || + WF->getFunctionType()->isVarArg()) + WriteFn = WF; + else + WriteFn = 0; + } else { + WriteFn = M.getOrInsertFunction("write", Type::VoidTy, Type::IntTy, + VoidPtrTy, Type::IntTy, 0); + } return true; } -bool LowerInvoke::runOnFunction(Function &F) { +void LowerInvoke::writeAbortMessage(Instruction *IB) { + if (WriteFn) { + if (!AbortMessage) { + GlobalVariable *MsgGV = new GlobalVariable(AbortMessageInit->getType(), + true, + GlobalValue::InternalLinkage, + AbortMessageInit, "abort.msg", + WriteFn->getParent()); + std::vector GEPIdx(2, Constant::getNullValue(Type::LongTy)); + AbortMessage = + ConstantExpr::getGetElementPtr(ConstantPointerRef::get(MsgGV), GEPIdx); + } + + // These are the arguments we WANT... + std::vector Args; + Args.push_back(ConstantInt::get(Type::IntTy, 2)); + Args.push_back(AbortMessage); + Args.push_back(ConstantInt::get(Type::IntTy, AbortMessageLength)); + + // If the actual declaration of write disagrees, insert casts as + // appropriate. + const FunctionType *FT = WriteFn->getFunctionType(); + unsigned NumArgs = FT->getNumParams(); + for (unsigned i = 0; i != 3; ++i) + if (i < NumArgs && FT->getParamType(i) != Args[i]->getType()) + Args[i] = ConstantExpr::getCast(cast(Args[i]), + FT->getParamType(i)); + + new CallInst(WriteFn, Args, "", IB); + } +} + +bool LowerInvoke::insertCheapEHSupport(Function &F) { bool Changed = false; for (Function::iterator BB = F.begin(), E = F.end(); BB != E; ++BB) if (InvokeInst *II = dyn_cast(BB->getTerminator())) { @@ -63,17 +221,21 @@ new BranchInst(II->getNormalDest(), II); // Remove any PHI node entries from the exception destination. - II->getExceptionalDest()->removePredecessor(BB); + II->getUnwindDest()->removePredecessor(BB); // Remove the invoke instruction now. BB->getInstList().erase(II); ++NumLowered; Changed = true; } else if (UnwindInst *UI = dyn_cast(BB->getTerminator())) { + // Insert a new call to write(2, AbortMessage, AbortMessageLength); + writeAbortMessage(UI); + // Insert a call to abort() new CallInst(AbortFn, std::vector(), "", UI); - // Insert a return instruction. + // Insert a return instruction. This really should be a "barrier", as it + // is unreachable. new ReturnInst(F.getReturnType() == Type::VoidTy ? 0 : Constant::getNullValue(F.getReturnType()), UI); @@ -83,4 +245,152 @@ ++NumLowered; Changed = true; } return Changed; +} + +bool LowerInvoke::insertExpensiveEHSupport(Function &F) { + bool Changed = false; + + // If a function uses invoke, we have an alloca for the jump buffer. + AllocaInst *JmpBuf = 0; + + // If this function contains an unwind instruction, two blocks get added: one + // to actually perform the longjmp, and one to terminate the program if there + // is no handler. + BasicBlock *UnwindBlock = 0, *TermBlock = 0; + std::vector JBPtrs; + + for (Function::iterator BB = F.begin(), E = F.end(); BB != E; ++BB) + if (InvokeInst *II = dyn_cast(BB->getTerminator())) { + if (JmpBuf == 0) + JmpBuf = new AllocaInst(JBLinkTy, 0, "jblink", F.begin()->begin()); + + // On the entry to the invoke, we must install our JmpBuf as the top of + // the stack. + LoadInst *OldEntry = new LoadInst(JBListHead, "oldehlist", II); + + // Store this old value as our 'next' field, and store our alloca as the + // current jblist. + std::vector Idx; + Idx.push_back(Constant::getNullValue(Type::LongTy)); + Idx.push_back(ConstantUInt::get(Type::UByteTy, 0)); + Value *NextFieldPtr = new GetElementPtrInst(JmpBuf, Idx, "NextField", II); + new StoreInst(OldEntry, NextFieldPtr, II); + new StoreInst(JmpBuf, JBListHead, II); + + // Call setjmp, passing in the address of the jmpbuffer. + Idx[1] = ConstantUInt::get(Type::UByteTy, 1); + Value *JmpBufPtr = new GetElementPtrInst(JmpBuf, Idx, "TheJmpBuf", II); + Value *SJRet = new CallInst(SetJmpFn, JmpBufPtr, "sjret", II); + + // Compare the return value to zero. + Value *IsNormal = BinaryOperator::create(Instruction::SetEQ, SJRet, + Constant::getNullValue(SJRet->getType()), + "notunwind", II); + // Create the receiver block if there is a critical edge to the normal + // destination. + SplitCriticalEdge(II, 0, this); + Instruction *InsertLoc = II->getNormalDest()->begin(); + + // Insert a normal call instruction on the normal execution path. + std::string Name = II->getName(); II->setName(""); + Value *NewCall = new CallInst(II->getCalledValue(), + std::vector(II->op_begin()+3, + II->op_end()), Name, + InsertLoc); + II->replaceAllUsesWith(NewCall); + + // If we got this far, then no exception was thrown and we can pop our + // jmpbuf entry off. + new StoreInst(OldEntry, JBListHead, InsertLoc); + + // Now we change the invoke into a branch instruction. + new BranchInst(II->getNormalDest(), II->getUnwindDest(), IsNormal, II); + + // Remove the InvokeInst now. + BB->getInstList().erase(II); + ++NumLowered; Changed = true; + + } else if (UnwindInst *UI = dyn_cast(BB->getTerminator())) { + if (UnwindBlock == 0) { + // Create two new blocks, the unwind block and the terminate block. Add + // them at the end of the function because they are not hot. + UnwindBlock = new BasicBlock("unwind", &F); + TermBlock = new BasicBlock("unwinderror", &F); + + // Insert return instructions. These really should be "barrier"s, as + // they are unreachable. + new ReturnInst(F.getReturnType() == Type::VoidTy ? 0 : + Constant::getNullValue(F.getReturnType()), UnwindBlock); + new ReturnInst(F.getReturnType() == Type::VoidTy ? 0 : + Constant::getNullValue(F.getReturnType()), TermBlock); + } + + // Load the JBList, if it's null, then there was no catch! + LoadInst *Ptr = new LoadInst(JBListHead, "ehlist", UI); + Value *NotNull = BinaryOperator::create(Instruction::SetNE, Ptr, + Constant::getNullValue(Ptr->getType()), + "notnull", UI); + new BranchInst(UnwindBlock, TermBlock, NotNull, UI); + + // Remember the loaded value so we can insert the PHI node as needed. + JBPtrs.push_back(Ptr); + + // Remove the UnwindInst now. + BB->getInstList().erase(UI); + ++NumLowered; Changed = true; + } + + // If an unwind instruction was inserted, we need to set up the Unwind and + // term blocks. + if (UnwindBlock) { + // In the unwind block, we know that the pointer coming in on the JBPtrs + // list are non-null. + Instruction *RI = UnwindBlock->getTerminator(); + + Value *RecPtr; + if (JBPtrs.size() == 1) + RecPtr = JBPtrs[0]; + else { + // If there is more than one unwind in this function, make a PHI node to + // merge in all of the loaded values. + PHINode *PN = new PHINode(JBPtrs[0]->getType(), "jbptrs", RI); + for (unsigned i = 0, e = JBPtrs.size(); i != e; ++i) + PN->addIncoming(JBPtrs[i], JBPtrs[i]->getParent()); + RecPtr = PN; + } + + // Now that we have a pointer to the whole record, remove the entry from the + // JBList. + std::vector Idx; + Idx.push_back(Constant::getNullValue(Type::LongTy)); + Idx.push_back(ConstantUInt::get(Type::UByteTy, 0)); + Value *NextFieldPtr = new GetElementPtrInst(RecPtr, Idx, "NextField", RI); + Value *NextRec = new LoadInst(NextFieldPtr, "NextRecord", RI); + new StoreInst(NextRec, JBListHead, RI); + + // Now that we popped the top of the JBList, get a pointer to the jmpbuf and + // longjmp. + Idx[1] = ConstantUInt::get(Type::UByteTy, 1); + Idx[0] = new GetElementPtrInst(RecPtr, Idx, "JmpBuf", RI); + Idx[1] = ConstantInt::get(Type::IntTy, 1); + new CallInst(LongJmpFn, Idx, "", RI); + + // Now we set up the terminate block. + RI = TermBlock->getTerminator(); + + // Insert a new call to write(2, AbortMessage, AbortMessageLength); + writeAbortMessage(RI); + + // Insert a call to abort() + new CallInst(AbortFn, std::vector(), "", RI); + } + + return Changed; +} + +bool LowerInvoke::runOnFunction(Function &F) { + if (ExpensiveEHSupport) + return insertExpensiveEHSupport(F); + else + return insertCheapEHSupport(F); } Index: llvm/lib/Transforms/Scalar/LowerSwitch.cpp diff -u llvm/lib/Transforms/Scalar/LowerSwitch.cpp:1.10 llvm/lib/Transforms/Scalar/LowerSwitch.cpp:1.10.2.1 --- llvm/lib/Transforms/Scalar/LowerSwitch.cpp:1.10 Fri Jan 9 00:02:20 2004 +++ llvm/lib/Transforms/Scalar/LowerSwitch.cpp Mon Mar 1 17:58:16 2004 @@ -115,7 +115,8 @@ Case& Pivot = *(Begin + Mid); DEBUG(std::cerr << "Pivot ==> " - << cast(Pivot.first)->getValue() << "\n"); + << (int64_t)cast(Pivot.first)->getRawValue() + << "\n"); BasicBlock* LBranch = switchConvert(LHS.begin(), LHS.end(), Val, OrigBlock, Default); Index: llvm/lib/Transforms/Scalar/SCCP.cpp diff -u llvm/lib/Transforms/Scalar/SCCP.cpp:1.88 llvm/lib/Transforms/Scalar/SCCP.cpp:1.88.2.1 --- llvm/lib/Transforms/Scalar/SCCP.cpp:1.88 Mon Jan 12 13:08:43 2004 +++ llvm/lib/Transforms/Scalar/SCCP.cpp Mon Mar 1 17:58:16 2004 @@ -689,14 +689,16 @@ // addressing... for (unsigned i = 2, e = CE->getNumOperands(); i != e; ++i) if (ConstantUInt *CU = dyn_cast(CE->getOperand(i))) { - ConstantStruct *CS = cast(C); + ConstantStruct *CS = dyn_cast(C); + if (CS == 0) return 0; if (CU->getValue() >= CS->getValues().size()) return 0; C = cast(CS->getValues()[CU->getValue()]); } else if (ConstantSInt *CS = dyn_cast(CE->getOperand(i))) { - ConstantArray *CA = cast(C); + ConstantArray *CA = dyn_cast(C); + if (CA == 0) return 0; if ((uint64_t)CS->getValue() >= CA->getValues().size()) return 0; C = cast(CA->getValues()[CS->getValue()]); - } else + } else return 0; return C; } Index: llvm/lib/Transforms/Scalar/TailDuplication.cpp diff -u llvm/lib/Transforms/Scalar/TailDuplication.cpp:1.11 llvm/lib/Transforms/Scalar/TailDuplication.cpp:1.11.2.1 --- llvm/lib/Transforms/Scalar/TailDuplication.cpp:1.11 Fri Jan 9 00:02:20 2004 +++ llvm/lib/Transforms/Scalar/TailDuplication.cpp Mon Mar 1 17:58:16 2004 @@ -41,6 +41,7 @@ bool runOnFunction(Function &F); private: inline bool shouldEliminateUnconditionalBranch(TerminatorInst *TI); + inline bool canEliminateUnconditionalBranch(TerminatorInst *TI); inline void eliminateUnconditionalBranch(BranchInst *BI); inline void InsertPHINodesIfNecessary(Instruction *OrigInst, Value *NewInst, BasicBlock *NewBlock); @@ -63,7 +64,8 @@ bool TailDup::runOnFunction(Function &F) { bool Changed = false; for (Function::iterator I = F.begin(), E = F.end(); I != E; ) - if (shouldEliminateUnconditionalBranch(I->getTerminator())) { + if (shouldEliminateUnconditionalBranch(I->getTerminator()) && + canEliminateUnconditionalBranch(I->getTerminator())) { eliminateUnconditionalBranch(cast(I->getTerminator())); Changed = true; } else { @@ -109,6 +111,36 @@ for (unsigned Size = 0; I != Dest->end(); ++Size, ++I) if (Size == 6) return false; // The block is too large... return true; +} + +/// canEliminateUnconditionalBranch - Unfortunately, the general form of tail +/// duplication can do very bad things to SSA form, by destroying arbitrary +/// relationships between dominators and dominator frontiers as it processes the +/// program. The right solution for this is to have an incrementally updating +/// dominator data structure, which can gracefully react to arbitrary +/// "addEdge/removeEdge" changes to the CFG. Implementing this is nontrivial, +/// however, so we just disable the transformation in cases where it is not +/// currently safe. +/// +bool TailDup::canEliminateUnconditionalBranch(TerminatorInst *TI) { + // Basically, we refuse to make the transformation if any of the values + // computed in the 'tail' are used in any other basic blocks. + BasicBlock *BB = TI->getParent(); + BasicBlock *Tail = TI->getSuccessor(0); + assert(isa(TI) && cast(TI)->isUnconditional()); + + for (BasicBlock::iterator I = Tail->begin(), E = Tail->end(); I != E; ++I) + for (Value::use_iterator UI = I->use_begin(), E = I->use_end(); UI != E; + ++UI) { + Instruction *User = cast(*UI); + if (User->getParent() != Tail && User->getParent() != BB) + return false; + + // The 'swap' problem foils the tail duplication rewriting code. + if (isa(User) && User->getParent() == Tail) + return false; + } + return true; } Index: llvm/lib/Transforms/Scalar/TailRecursionElimination.cpp diff -u llvm/lib/Transforms/Scalar/TailRecursionElimination.cpp:1.12 llvm/lib/Transforms/Scalar/TailRecursionElimination.cpp:1.12.2.1 --- llvm/lib/Transforms/Scalar/TailRecursionElimination.cpp:1.12 Sun Dec 14 17:57:39 2003 +++ llvm/lib/Transforms/Scalar/TailRecursionElimination.cpp Mon Mar 1 17:58:16 2004 @@ -290,7 +290,7 @@ if (OldEntry == 0) { OldEntry = &F->getEntryBlock(); std::string OldName = OldEntry->getName(); OldEntry->setName("tailrecurse"); - BasicBlock *NewEntry = new BasicBlock(OldName, OldEntry); + BasicBlock *NewEntry = new BasicBlock(OldName, F, OldEntry); new BranchInst(OldEntry, NewEntry); // Now that we have created a new block, which jumps to the entry From brukman at cs.uiuc.edu Mon Mar 1 18:05:38 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Mar 1 18:05:38 2004 Subject: [llvm-commits] [parallel] CVS: llvm/lib/Target/SparcV9/EmitBytecodeToAssembly.cpp Makefile MappingInfo.cpp MappingInfo.h SparcV9.burg.in SparcV9.td SparcV9AsmPrinter.cpp SparcV9CodeEmitter.cpp SparcV9FrameInfo.cpp SparcV9FrameInfo.h SparcV9Instr.def SparcV9InstrInfo.cpp SparcV9InstrInfo.h SparcV9InstrSelection.cpp SparcV9InstrSelectionSupport.h SparcV9Internals.h SparcV9JITInfo.h SparcV9PeepholeOpts.cpp SparcV9PreSelection.cpp SparcV9PrologEpilogInserter.cpp SparcV9RegClassInfo.cpp SparcV9RegClassInfo.h SparcV9RegInfo.cpp SparcV9RegInfo.h SparcV9SchedInfo.cpp SparcV9StackSlots.cpp SparcV9TargetMachine.cpp SparcV9TargetMachine.h SparcV9_F2.td SparcV9_F3.td SparcV9_F4.td SparcV9_Reg.td Message-ID: <200403012358.RAA04134@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/SparcV9: EmitBytecodeToAssembly.cpp updated: 1.12 -> 1.12.4.1 Makefile updated: 1.40 -> 1.40.2.1 MappingInfo.cpp updated: 1.15 -> 1.15.4.1 MappingInfo.h updated: 1.6 -> 1.6.4.1 SparcV9.burg.in updated: 1.11 -> 1.11.4.1 SparcV9.td updated: 1.29 -> 1.29.6.1 SparcV9AsmPrinter.cpp updated: 1.101 -> 1.101.2.1 SparcV9CodeEmitter.cpp updated: 1.49 -> 1.49.2.1 SparcV9FrameInfo.cpp updated: 1.1 -> 1.1.2.1 SparcV9FrameInfo.h updated: 1.1 -> 1.1.2.1 SparcV9Instr.def updated: 1.23 -> 1.23.6.1 SparcV9InstrInfo.cpp updated: 1.59 -> 1.59.2.1 SparcV9InstrInfo.h updated: 1.1 -> 1.1.2.1 SparcV9InstrSelection.cpp updated: 1.130 -> 1.130.2.1 SparcV9InstrSelectionSupport.h updated: 1.13 -> 1.13.4.1 SparcV9Internals.h updated: 1.110 -> 1.110.2.1 SparcV9JITInfo.h updated: 1.3 -> 1.3.2.1 SparcV9PeepholeOpts.cpp updated: 1.17 -> 1.17.2.1 SparcV9PreSelection.cpp updated: 1.27 -> 1.27.2.1 SparcV9PrologEpilogInserter.cpp updated: 1.32 -> 1.32.4.1 SparcV9RegClassInfo.cpp updated: 1.34 -> 1.34.2.1 SparcV9RegClassInfo.h updated: 1.23 -> 1.23.4.1 SparcV9RegInfo.cpp updated: 1.116 -> 1.116.2.1 SparcV9RegInfo.h updated: 1.8 -> 1.8.2.1 SparcV9SchedInfo.cpp updated: 1.9 -> 1.9.2.1 SparcV9StackSlots.cpp updated: 1.9 -> 1.9.4.1 SparcV9TargetMachine.cpp updated: 1.98 -> 1.98.2.1 SparcV9TargetMachine.h updated: 1.4 -> 1.4.2.1 SparcV9_F2.td updated: 1.8 -> 1.8.6.1 SparcV9_F3.td updated: 1.17 -> 1.17.6.1 SparcV9_F4.td updated: 1.10 -> 1.10.6.1 SparcV9_Reg.td updated: 1.7 -> 1.7.4.1 --- Log message: Merge from trunk --- Diffs of the changes: (+861 -924) Index: llvm/lib/Target/SparcV9/EmitBytecodeToAssembly.cpp diff -u llvm/lib/Target/SparcV9/EmitBytecodeToAssembly.cpp:1.12 llvm/lib/Target/SparcV9/EmitBytecodeToAssembly.cpp:1.12.4.1 --- llvm/lib/Target/SparcV9/EmitBytecodeToAssembly.cpp:1.12 Wed Nov 12 18:19:02 2003 +++ llvm/lib/Target/SparcV9/EmitBytecodeToAssembly.cpp Mon Mar 1 17:58:14 2004 @@ -1,4 +1,4 @@ -//===-- EmitBytecodeToAssembly.cpp - Emit bytecode to Sparc .s File --------==// +//===-- EmitBytecodeToAssembly.cpp - Emit bytecode to SparcV9 .s File --------==// // // The LLVM Compiler Infrastructure // @@ -13,7 +13,7 @@ // //===----------------------------------------------------------------------===// -#include "SparcInternals.h" +#include "SparcV9Internals.h" #include "llvm/Pass.h" #include "llvm/Bytecode/Writer.h" #include @@ -86,13 +86,13 @@ << "\n"; } - // SparcBytecodeWriter - Write bytecode out to a stream that is sparc'ified - class SparcBytecodeWriter : public Pass { + // SparcV9BytecodeWriter - Write bytecode out to a stream that is sparc'ified + class SparcV9BytecodeWriter : public Pass { std::ostream &Out; public: - SparcBytecodeWriter(std::ostream &out) : Out(out) {} + SparcV9BytecodeWriter(std::ostream &out) : Out(out) {} - const char *getPassName() const { return "Emit Bytecode to Sparc Assembly";} + const char *getPassName() const { return "Emit Bytecode to SparcV9 Assembly";} virtual bool run(Module &M) { // Write an object containing the bytecode to the SPARC assembly stream @@ -113,7 +113,7 @@ } // end anonymous namespace Pass *createBytecodeAsmPrinterPass(std::ostream &Out) { - return new SparcBytecodeWriter(Out); + return new SparcV9BytecodeWriter(Out); } } // End llvm namespace Index: llvm/lib/Target/SparcV9/Makefile diff -u llvm/lib/Target/SparcV9/Makefile:1.40 llvm/lib/Target/SparcV9/Makefile:1.40.2.1 --- llvm/lib/Target/SparcV9/Makefile:1.40 Fri Jan 9 12:15:22 2004 +++ llvm/lib/Target/SparcV9/Makefile Mon Mar 1 17:58:14 2004 @@ -1,4 +1,4 @@ -##===- lib/Target/Sparc/Makefile ---------------------------*- Makefile -*-===## +##===- lib/Target/SparcV9/Makefile ---------------------------*- Makefile -*-===## # # The LLVM Compiler Infrastructure # @@ -7,10 +7,10 @@ # ##===----------------------------------------------------------------------===## LEVEL = ../../.. -LIBRARYNAME = sparc +LIBRARYNAME = sparcv9 DIRS = InstrSelection RegAlloc LiveVar -ExtraSource = Sparc.burm.cpp +ExtraSource = SparcV9.burm.cpp include $(LEVEL)/Makefile.common @@ -20,26 +20,26 @@ DEBUG_FLAG = -D_DEBUG endif -Sparc.burg.in1 : $(SourceDir)/Sparc.burg.in +SparcV9.burg.in1 : $(SourceDir)/SparcV9.burg.in $(CXX) -E -I$(LLVM_SRC_ROOT)/include $(DEBUG_FLAG) -x c++ $< | $(SED) '/^#/d' | $(SED) 's/Ydefine/#define/' > $@ -Sparc.burm : Sparc.burg.in1 +SparcV9.burm : SparcV9.burg.in1 $(CXX) -E -I$(LLVM_SRC_ROOT)/include $(DEBUG_FLAG) -x c++ $< | $(SED) '/^#/d' | $(SED) 's/^Xinclude/#include/' | $(SED) 's/^Xdefine/#define/' > $@ -Sparc.burm.cpp: Sparc.burm +SparcV9.burm.cpp: SparcV9.burm @echo "Burging `basename $<`" $(RunBurg) $< -o $@ -$(BUILD_OBJ_DIR)/Debug/Sparc.burm.lo: Sparc.burm.cpp +$(BUILD_OBJ_DIR)/Debug/SparcV9.burm.lo: SparcV9.burm.cpp $(CompileG) $< -o $@ -$(BUILD_OBJ_DIR)/Release/Sparc.burm.lo: Sparc.burm.cpp +$(BUILD_OBJ_DIR)/Release/SparcV9.burm.lo: SparcV9.burm.cpp $(CompileO) $< -o $@ -$(BUILD_OBJ_DIR)/Profile/Sparc.burm.lo: Sparc.burm.cpp +$(BUILD_OBJ_DIR)/Profile/SparcV9.burm.lo: SparcV9.burm.cpp $(CompileP) $< -o $@ -$(BUILD_OBJ_DIR)/Depend/Sparc.burm.d: $(BUILD_OBJ_DIR)/Depend/.dir +$(BUILD_OBJ_DIR)/Depend/SparcV9.burm.d: $(BUILD_OBJ_DIR)/Depend/.dir touch $@ TARGET_NAME := SparcV9 @@ -56,5 +56,5 @@ $(TBLGEN) -I $(SourceDir) $< -gen-emitter -o $@ clean:: - $(RM) -f $(TARGET_NAME)CodeEmitter.inc Sparc.burg.in1 Sparc.burm Sparc.burm.cpp + $(RM) -f $(TARGET_NAME)CodeEmitter.inc SparcV9.burg.in1 SparcV9.burm SparcV9.burm.cpp Index: llvm/lib/Target/SparcV9/MappingInfo.cpp diff -u llvm/lib/Target/SparcV9/MappingInfo.cpp:1.15 llvm/lib/Target/SparcV9/MappingInfo.cpp:1.15.4.1 --- llvm/lib/Target/SparcV9/MappingInfo.cpp:1.15 Tue Nov 11 16:41:33 2003 +++ llvm/lib/Target/SparcV9/MappingInfo.cpp Mon Mar 1 17:58:14 2004 @@ -153,7 +153,7 @@ for (MachineFunction::iterator BI = MF.begin(), BE = MF.end(); BI != BE; ++BI) { MachineBasicBlock &miBB = *BI; - key[miBB[0]] = i; + key[&miBB.front()] = i; i = i+(miBB.size()); } } @@ -174,7 +174,7 @@ unsigned j = 0; for(MachineBasicBlock::iterator miI = miBB.begin(), miE = miBB.end(); miI != miE; ++miI, ++j) { - key[*miI] = j; + key[miI] = j; } } } @@ -195,7 +195,7 @@ BI != BE; ++BI, ++bb) { MachineBasicBlock &miBB = *BI; writeNumber(bb); - writeNumber(BBkey[miBB[0]]); + writeNumber(BBkey[&miBB.front()]); writeNumber(miBB.size()); } } Index: llvm/lib/Target/SparcV9/MappingInfo.h diff -u llvm/lib/Target/SparcV9/MappingInfo.h:1.6 llvm/lib/Target/SparcV9/MappingInfo.h:1.6.4.1 --- llvm/lib/Target/SparcV9/MappingInfo.h:1.6 Tue Nov 11 16:41:33 2003 +++ llvm/lib/Target/SparcV9/MappingInfo.h Mon Mar 1 17:58:14 2004 @@ -1,4 +1,4 @@ -//===- lib/Target/Sparc/MappingInfo.h ---------------------------*- C++ -*-===// +//===- lib/Target/SparcV9/MappingInfo.h ---------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // Index: llvm/lib/Target/SparcV9/SparcV9.burg.in diff -u llvm/lib/Target/SparcV9/SparcV9.burg.in:1.11 llvm/lib/Target/SparcV9/SparcV9.burg.in:1.11.4.1 --- llvm/lib/Target/SparcV9/SparcV9.burg.in:1.11 Tue Nov 11 16:41:33 2003 +++ llvm/lib/Target/SparcV9/SparcV9.burg.in Mon Mar 1 17:58:14 2004 @@ -46,7 +46,7 @@ %term Or=OrOPCODE %term Xor=XorOPCODE /* Use the next 4 to distinguish bitwise operators from - * logical operators. This is no longer used for Sparc, + * logical operators. This is no longer used for SparcV9, * but may be useful for other target machines. * The last one is the bitwise Not(val) == XOR val, 11..1. * Note that it is also a binary operator, not unary. Index: llvm/lib/Target/SparcV9/SparcV9.td diff -u llvm/lib/Target/SparcV9/SparcV9.td:1.29 llvm/lib/Target/SparcV9/SparcV9.td:1.29.6.1 --- llvm/lib/Target/SparcV9/SparcV9.td:1.29 Tue Oct 21 10:17:13 2003 +++ llvm/lib/Target/SparcV9/SparcV9.td Mon Mar 1 17:58:14 2004 @@ -1,4 +1,4 @@ -//===- SparcV9.td - Target Description for Sparc V9 Target ----------------===// +//===- SparcV9.td - Target Description for SparcV9 V9 Target ----------------===// // // The LLVM Compiler Infrastructure // @@ -19,7 +19,7 @@ // Instructions //===----------------------------------------------------------------------===// -class InstV9 : Instruction { // Sparc instruction baseline +class InstV9 : Instruction { // SparcV9 instruction baseline field bits<32> Inst; let Namespace = "V9"; @@ -27,7 +27,7 @@ bits<2> op; let Inst{31-30} = op; // Top two bits are the 'op' field - // Bit attributes specific to Sparc instructions + // Bit attributes specific to SparcV9 instructions bit isPasi = 0; // Does this instruction affect an alternate addr space? bit isDeprecated = 0; // Is this instruction deprecated? bit isPrivileged = 0; // Is this a privileged instruction? @@ -62,7 +62,7 @@ } // Section A.4: Branch on Floating-Point Condition Codes (FBfcc) p140 -// The following deprecated instructions don't seem to play nice on Sparc +// The following deprecated instructions don't seem to play nice on SparcV9 /* let isDeprecated = 1 in { let op2 = 0b110 in { @@ -107,7 +107,7 @@ } // Section A.5: Branch on FP condition codes with prediction - p143 -// Not used in the Sparc backend (directly) +// Not used in the SparcV9 backend (directly) /* let op2 = 0b101 in { def FBPA : F2_3<0b1000, "fba">; // Branch always @@ -176,7 +176,7 @@ } // Section A.7: Branch on integer condition codes with prediction - p148 -// Not used in the Sparc backend +// Not used in the SparcV9 backend /* let op2 = 0b001 in { def BPA : F2_3<0b1000, "bpa">; // Branch always @@ -212,7 +212,7 @@ // Section A.10: Divide (64-bit / 32-bit) - p178 -// Not used in the Sparc backend +// Not used in the SparcV9 backend /* let isDeprecated = 1 in { def UDIVr : F3_1<2, 0b001110, "udiv">; // udiv r, r, r @@ -227,7 +227,7 @@ */ // Section A.11: DONE and RETRY - p181 -// Not used in the Sparc backend +// Not used in the SparcV9 backend /* let isPrivileged = 1 in { def DONE : F3_18<0, "done">; // done @@ -247,7 +247,7 @@ def FCMPS : F3_15<2, 0b110101, 0b001010001, "fcmps">; // fcmps %fcc, r1, r2 def FCMPD : F3_15<2, 0b110101, 0b001010010, "fcmpd">; // fcmpd %fcc, r1, r2 def FCMPQ : F3_15<2, 0b110101, 0b001010011, "fcmpq">; // fcmpq %fcc, r1, r2 -// Currently unused in the Sparc backend +// Currently unused in the SparcV9 backend /* def FCMPES : F3_15<2, 0b110101, 0b001010101, "fcmpes">; // fcmpes %fcc, r1, r2 def FCMPED : F3_15<2, 0b110101, 0b001010110, "fcmped">; // fcmped %fcc, r1, r2 @@ -317,7 +317,7 @@ // Not currently used // Section A.24: Jump and Link - p172 -// Mimicking the Sparc's instr def... +// Mimicking the SparcV9's instr def... def JMPLCALLr : F3_1<2, 0b111000, "jmpl">; // jmpl [rs1+rs2], rd def JMPLCALLi : F3_2<2, 0b111000, "jmpl">; // jmpl [rs1+imm], rd def JMPLRETr : F3_1<2, 0b111000, "jmpl">; // jmpl [rs1+rs2], rd @@ -393,7 +393,7 @@ def XNORcci : F3_2<2, 0b010111, "xnorcc">; // xnorcc rs1, imm, rd // Section A.32: Memory Barrier - p186 -// Not currently used in the Sparc backend +// Not currently used in the SparcV9 backend // Section A.33: Move Floating-Point Register on Condition (FMOVcc) // ======================= Single Floating Point ====================== @@ -622,7 +622,7 @@ def UDIVXi : F3_2<2, 0b001101, "udivx">; // udivx r, i, r // Section A.38: Multiply (32-bit) - p200 -// Not used in the Sparc backend +// Not used in the SparcV9 backend /* let Inst{13} = 0 in { def UMULr : F3_1<2, 0b001010, "umul">; // umul r, r, r @@ -639,7 +639,7 @@ */ // Section A.39: Multiply Step - p202 -// Not currently used in the Sparc backend +// Not currently used in the SparcV9 backend // Section A.40: No operation - p204 // NOP is really a pseudo-instruction (special case of SETHI) @@ -652,13 +652,13 @@ } // Section A.41: Population Count - p205 -// Not currently used in the Sparc backend +// Not currently used in the SparcV9 backend // Section A.42: Prefetch Data - p206 -// Not currently used in the Sparc backend +// Not currently used in the SparcV9 backend // Section A.43: Read Privileged Register - p211 -// Not currently used in the Sparc backend +// Not currently used in the SparcV9 backend // Section A.44: Read State Register // The only instr from this section currently used is RDCCR @@ -679,7 +679,7 @@ def RESTOREi : F3_2<2, 0b111101, "restore">; // restore r, i, r // Section A.47: SAVED and RESTORED - p219 -// Not currently used in Sparc backend +// Not currently used in SparcV9 backend // Section A.48: SETHI - p220 let op2 = 0b100 in { @@ -687,7 +687,7 @@ } // Section A.49: Shift - p221 -// Not currently used in the Sparc backend +// Not currently used in the SparcV9 backend /* uses 5 least significant bits of rs2 let x = 0 in { @@ -720,10 +720,10 @@ def SRAXi6 : F3_13<2, 0b100111, "srax">; // srax r, shcnt64, r // Section A.50: Sofware-Initiated Reset - p223 -// Not currently used in the Sparc backend +// Not currently used in the SparcV9 backend // Section A.51: Store Barrier - p224 -// Not currently used in the Sparc backend +// Not currently used in the SparcV9 backend // Section A.52: Store Floating-point - p225 // Store instructions all want their rd register first @@ -732,7 +732,7 @@ def STDFr : F3_1rd<3, 0b100111, "std">; // std r, [r+r] def STDFi : F3_2rd<3, 0b100111, "std">; // std r, [r+i] -// Not currently used in the Sparc backend +// Not currently used in the SparcV9 backend /* def STQFr : F3_1rd<3, 0b100110, "stq">; // stq r, [r+r] def STQFi : F3_2rd<3, 0b100110, "stq">; // stq r, [r+i] @@ -740,7 +740,7 @@ // FIXME: An encoding needs to be chosen here, because STFSRx expect rd=0, // while STXFSRx expect rd=1, but assembly syntax dictates %fsr as first arg. -// These are being disabled because they aren't used in the Sparc backend. +// These are being disabled because they aren't used in the SparcV9 backend. /* let isDeprecated = 1 in { def STFSRr : F3_1<3, 0b100101, "st">; // st %fsr, [r+r] @@ -751,7 +751,7 @@ def STXFSRi : F3_2<3, 0b100101, "stx">; // stx %fsr, [r+i] // Section A.53: Store Floating-Point into Alternate Space - p227 -// Not currently used in the Sparc backend +// Not currently used in the SparcV9 backend // Section A.54: Store Integer - p229 // Store instructions all want their rd register first @@ -765,7 +765,7 @@ def STXi : F3_2rd<3, 0b001110, "stx">; // stx r, [r+i] // Section A.55: Store Integer into Alternate Space - p231 -// Not currently used in the Sparc backend +// Not currently used in the SparcV9 backend // Section A.56: Subtract - p233 def SUBr : F3_1<2, 0b000100, "sub">; // sub r, r, r Index: llvm/lib/Target/SparcV9/SparcV9AsmPrinter.cpp diff -u llvm/lib/Target/SparcV9/SparcV9AsmPrinter.cpp:1.101 llvm/lib/Target/SparcV9/SparcV9AsmPrinter.cpp:1.101.2.1 --- llvm/lib/Target/SparcV9/SparcV9AsmPrinter.cpp:1.101 Thu Jan 15 16:44:19 2004 +++ llvm/lib/Target/SparcV9/SparcV9AsmPrinter.cpp Mon Mar 1 17:58:14 2004 @@ -1,4 +1,4 @@ -//===-- EmitAssembly.cpp - Emit Sparc Specific .s File ---------------------==// +//===-- EmitAssembly.cpp - Emit SparcV9 Specific .s File ---------------------==// // // The LLVM Compiler Infrastructure // @@ -30,7 +30,7 @@ #include "llvm/Support/Mangler.h" #include "Support/StringExtras.h" #include "Support/Statistic.h" -#include "SparcInternals.h" +#include "SparcV9Internals.h" #include using namespace llvm; @@ -119,7 +119,7 @@ /// inline unsigned int SizeToAlignment(unsigned int size, const TargetMachine& target) { - unsigned short cacheLineSize = target.getCacheInfo().getCacheLineSize(1); + const unsigned short cacheLineSize = 16; if (size > (unsigned) cacheLineSize / 2) return cacheLineSize; else @@ -184,14 +184,11 @@ } void PrintZeroBytesToPad(int numBytes) { - for (/* no init */; numBytes >= 8; numBytes -= 8) - printSingleConstantValue(Constant::getNullValue(Type::ULongTy)); - - if (numBytes >= 4) { - printSingleConstantValue(Constant::getNullValue(Type::UIntTy)); - numBytes -= 4; - } - + // + // Always use single unsigned bytes for padding. We don't know upon + // what data size the beginning address is aligned, so using anything + // other than a byte may cause alignment errors in the assembler. + // while (numBytes--) printSingleConstantValue(Constant::getNullValue(Type::UByteTy)); } @@ -254,7 +251,7 @@ } // getID Wrappers - Ensure consistent usage - // Symbol names in Sparc assembly language have these rules: + // Symbol names in SparcV9 assembly language have these rules: // (a) Must match { letter | _ | . | $ } { letter | _ | . | $ | digit }* // (b) A name beginning in "." is treated as a local name. std::string getID(const Function *F) { @@ -343,6 +340,8 @@ toAsm << "\t! " << CV->getType()->getDescription() << " value: " << Val << "\n"; + } else if (const ConstantBool *CB = dyn_cast(CV)) { + toAsm << (int)CB->getValue() << "\n"; } else { WriteAsOperand(toAsm, CV, false, false) << "\n"; } @@ -388,8 +387,9 @@ } assert(sizeSoFar == cvsLayout->StructSize && "Layout of constant struct may be incorrect!"); - } - else + } else if (isa(CV)) { + PrintZeroBytesToPad(Target.getTargetData().getTypeSize(CV->getType())); + } else printSingleConstantValue(CV); if (numPadBytesAfter) @@ -504,19 +504,19 @@ //===----------------------------------------------------------------------===// -// SparcAsmPrinter Code +// SparcV9AsmPrinter Code //===----------------------------------------------------------------------===// namespace { - struct SparcAsmPrinter : public FunctionPass, public AsmPrinter { - inline SparcAsmPrinter(std::ostream &os, const TargetMachine &t) + struct SparcV9AsmPrinter : public FunctionPass, public AsmPrinter { + inline SparcV9AsmPrinter(std::ostream &os, const TargetMachine &t) : AsmPrinter(os, t) {} const Function *currFunction; const char *getPassName() const { - return "Output Sparc Assembly for Functions"; + return "Output SparcV9 Assembly for Functions"; } virtual bool doInitialization(Module &M) { @@ -565,9 +565,9 @@ } // End anonymous namespace inline bool -SparcAsmPrinter::OpIsBranchTargetLabel(const MachineInstr *MI, +SparcV9AsmPrinter::OpIsBranchTargetLabel(const MachineInstr *MI, unsigned int opNum) { - switch (MI->getOpCode()) { + switch (MI->getOpcode()) { case V9::JMPLCALLr: case V9::JMPLCALLi: case V9::JMPLRETr: @@ -579,11 +579,11 @@ } inline bool -SparcAsmPrinter::OpIsMemoryAddressBase(const MachineInstr *MI, +SparcV9AsmPrinter::OpIsMemoryAddressBase(const MachineInstr *MI, unsigned int opNum) { - if (Target.getInstrInfo().isLoad(MI->getOpCode())) + if (Target.getInstrInfo().isLoad(MI->getOpcode())) return (opNum == 0); - else if (Target.getInstrInfo().isStore(MI->getOpCode())) + else if (Target.getInstrInfo().isStore(MI->getOpcode())) return (opNum == 1); else return false; @@ -596,27 +596,27 @@ printOneOperand(mop2, opCode); unsigned int -SparcAsmPrinter::printOperands(const MachineInstr *MI, +SparcV9AsmPrinter::printOperands(const MachineInstr *MI, unsigned int opNum) { const MachineOperand& mop = MI->getOperand(opNum); if (OpIsBranchTargetLabel(MI, opNum)) { - PrintOp1PlusOp2(mop, MI->getOperand(opNum+1), MI->getOpCode()); + PrintOp1PlusOp2(mop, MI->getOperand(opNum+1), MI->getOpcode()); return 2; } else if (OpIsMemoryAddressBase(MI, opNum)) { toAsm << "["; - PrintOp1PlusOp2(mop, MI->getOperand(opNum+1), MI->getOpCode()); + PrintOp1PlusOp2(mop, MI->getOperand(opNum+1), MI->getOpcode()); toAsm << "]"; return 2; } else { - printOneOperand(mop, MI->getOpCode()); + printOneOperand(mop, MI->getOpcode()); return 1; } } void -SparcAsmPrinter::printOneOperand(const MachineOperand &mop, +SparcV9AsmPrinter::printOneOperand(const MachineOperand &mop, MachineOpCode opCode) { bool needBitsFlag = true; @@ -638,7 +638,7 @@ case MachineOperand::MO_CCRegister: case MachineOperand::MO_MachineRegister: { - int regNum = (int)mop.getAllocatedRegNum(); + int regNum = (int)mop.getReg(); if (regNum == Target.getRegInfo().getInvalidRegNum()) { // better to print code with NULL registers than to die @@ -659,7 +659,7 @@ case MachineOperand::MO_PCRelativeDisp: { const Value *Val = mop.getVRegValue(); - assert(Val && "\tNULL Value in SparcAsmPrinter"); + assert(Val && "\tNULL Value in SparcV9AsmPrinter"); if (const BasicBlock *BB = dyn_cast(Val)) toAsm << getID(BB); @@ -670,7 +670,7 @@ else if (const Constant *CV = dyn_cast(Val)) toAsm << getID(CV); else - assert(0 && "Unrecognized value in SparcAsmPrinter"); + assert(0 && "Unrecognized value in SparcV9AsmPrinter"); break; } @@ -691,8 +691,8 @@ toAsm << ")"; } -void SparcAsmPrinter::emitMachineInst(const MachineInstr *MI) { - unsigned Opcode = MI->getOpCode(); +void SparcV9AsmPrinter::emitMachineInst(const MachineInstr *MI) { + unsigned Opcode = MI->getOpcode(); if (Target.getInstrInfo().isDummyPhiInstr(Opcode)) return; // IGNORE PHI NODES @@ -715,18 +715,18 @@ ++EmittedInsts; } -void SparcAsmPrinter::emitBasicBlock(const MachineBasicBlock &MBB) { +void SparcV9AsmPrinter::emitBasicBlock(const MachineBasicBlock &MBB) { // Emit a label for the basic block toAsm << getID(MBB.getBasicBlock()) << ":\n"; // Loop over all of the instructions in the basic block... for (MachineBasicBlock::const_iterator MII = MBB.begin(), MIE = MBB.end(); MII != MIE; ++MII) - emitMachineInst(*MII); + emitMachineInst(MII); toAsm << "\n"; // Separate BB's with newlines } -void SparcAsmPrinter::emitFunction(const Function &F) { +void SparcV9AsmPrinter::emitFunction(const Function &F) { std::string methName = getID(&F); toAsm << "!****** Outputing Function: " << methName << " ******\n"; @@ -760,7 +760,7 @@ toAsm << "\n\n"; } -void SparcAsmPrinter::printGlobalVariable(const GlobalVariable* GV) { +void SparcV9AsmPrinter::printGlobalVariable(const GlobalVariable* GV) { if (GV->hasExternalLinkage()) toAsm << "\t.global\t" << getID(GV) << "\n"; @@ -776,7 +776,7 @@ } } -void SparcAsmPrinter::emitGlobals(const Module &M) { +void SparcV9AsmPrinter::emitGlobals(const Module &M) { // Output global variables... for (Module::const_giterator GI = M.gbegin(), GE = M.gend(); GI != GE; ++GI) if (! GI->isExternal()) { @@ -796,5 +796,5 @@ FunctionPass *llvm::createAsmPrinterPass(std::ostream &Out, const TargetMachine &TM) { - return new SparcAsmPrinter(Out, TM); + return new SparcV9AsmPrinter(Out, TM); } Index: llvm/lib/Target/SparcV9/SparcV9CodeEmitter.cpp diff -u llvm/lib/Target/SparcV9/SparcV9CodeEmitter.cpp:1.49 llvm/lib/Target/SparcV9/SparcV9CodeEmitter.cpp:1.49.2.1 --- llvm/lib/Target/SparcV9/SparcV9CodeEmitter.cpp:1.49 Sat Dec 20 03:17:40 2003 +++ llvm/lib/Target/SparcV9/SparcV9CodeEmitter.cpp Mon Mar 1 17:58:14 2004 @@ -34,9 +34,9 @@ #include "Support/Debug.h" #include "Support/hash_set" #include "Support/Statistic.h" -#include "SparcInternals.h" -#include "SparcTargetMachine.h" -#include "SparcRegInfo.h" +#include "SparcV9Internals.h" +#include "SparcV9TargetMachine.h" +#include "SparcV9RegInfo.h" #include "SparcV9CodeEmitter.h" #include "Config/alloca.h" @@ -48,12 +48,12 @@ Statistic<> CallbackCalls("callback", "Number CompilationCallback() calls"); } -bool SparcTargetMachine::addPassesToEmitMachineCode(FunctionPassManager &PM, +bool SparcV9TargetMachine::addPassesToEmitMachineCode(FunctionPassManager &PM, MachineCodeEmitter &MCE) { MachineCodeEmitter *M = &MCE; DEBUG(M = MachineCodeEmitter::createFilePrinterEmitter(MCE)); PM.add(new SparcV9CodeEmitter(*this, *M)); - PM.add(createSparcMachineCodeDestructionPass()); //Free stuff no longer needed + PM.add(createSparcV9MachineCodeDestructionPass()); //Free stuff no longer needed return false; } @@ -179,8 +179,8 @@ void JITResolver::insertFarJumpAtAddr(int64_t Target, uint64_t Addr) { static const unsigned - o6 = SparcIntRegClass::o6, g0 = SparcIntRegClass::g0, - g1 = SparcIntRegClass::g1, g5 = SparcIntRegClass::g5; + o6 = SparcV9IntRegClass::o6, g0 = SparcV9IntRegClass::g0, + g1 = SparcV9IntRegClass::g1, g5 = SparcV9IntRegClass::g5; MachineInstr* BinaryCode[] = { // @@ -362,7 +362,7 @@ // Rewrite the call target so that we don't fault every time we execute it. // - static const unsigned o6 = SparcIntRegClass::o6; + static const unsigned o6 = SparcV9IntRegClass::o6; // Subtract enough to overwrite up to the 'save' instruction // This depends on whether we made a short call (1 instruction) or the @@ -418,11 +418,11 @@ DEBUG(std::cerr << "Emitting stub at addr: 0x" << std::hex << MCE.getCurrentPCValue() << "\n"); - unsigned o6 = SparcIntRegClass::o6, g0 = SparcIntRegClass::g0; + unsigned o6 = SparcV9IntRegClass::o6, g0 = SparcV9IntRegClass::g0; // restore %g0, 0, %g0 MachineInstr *R = BuildMI(V9::RESTOREi, 3).addMReg(g0).addSImm(0) - .addMReg(g0, MOTy::Def); + .addMReg(g0, MachineOperand::Def); SparcV9.emitWord(SparcV9.getBinaryCodeForInstr(*R)); delete R; @@ -485,8 +485,8 @@ fakeReg = RI.getClassRegNum(fakeReg, regClass); switch (regClass) { - case SparcRegInfo::IntRegClassID: { - // Sparc manual, p31 + case SparcV9RegInfo::IntRegClassID: { + // SparcV9 manual, p31 static const unsigned IntRegMap[] = { // "o0", "o1", "o2", "o3", "o4", "o5", "o7", 8, 9, 10, 11, 12, 13, 15, @@ -503,14 +503,14 @@ return IntRegMap[fakeReg]; break; } - case SparcRegInfo::FloatRegClassID: { + case SparcV9RegInfo::FloatRegClassID: { DEBUG(std::cerr << "FP reg: " << fakeReg << "\n"); - if (regType == SparcRegInfo::FPSingleRegType) { + if (regType == SparcV9RegInfo::FPSingleRegType) { // only numbered 0-31, hence can already fit into 5 bits (and 6) DEBUG(std::cerr << "FP single reg, returning: " << fakeReg << "\n"); - } else if (regType == SparcRegInfo::FPDoubleRegType) { + } else if (regType == SparcV9RegInfo::FPDoubleRegType) { // FIXME: This assumes that we only have 5-bit register fields! - // From Sparc Manual, page 40. + // From SparcV9 Manual, page 40. // The bit layout becomes: b[4], b[3], b[2], b[1], b[5] fakeReg |= (fakeReg >> 5) & 1; fakeReg &= 0x1f; @@ -518,7 +518,7 @@ } return fakeReg; } - case SparcRegInfo::IntCCRegClassID: { + case SparcV9RegInfo::IntCCRegClassID: { /* xcc, icc, ccr */ static const unsigned IntCCReg[] = { 6, 4, 2 }; @@ -527,7 +527,7 @@ DEBUG(std::cerr << "IntCC reg: " << IntCCReg[fakeReg] << "\n"); return IntCCReg[fakeReg]; } - case SparcRegInfo::FloatCCRegClassID: { + case SparcV9RegInfo::FloatCCRegClassID: { /* These are laid out %fcc0 - %fcc3 => 0 - 3, so are correct */ DEBUG(std::cerr << "FP CC reg: " << fakeReg << "\n"); return fakeReg; @@ -542,9 +542,9 @@ // WARNING: if the call used the delay slot to do meaningful work, that's not // being accounted for, and the behavior will be incorrect!! inline void SparcV9CodeEmitter::emitFarCall(uint64_t Target, Function *F) { - static const unsigned o6 = SparcIntRegClass::o6, - o7 = SparcIntRegClass::o7, g0 = SparcIntRegClass::g0, - g1 = SparcIntRegClass::g1, g5 = SparcIntRegClass::g5; + static const unsigned o6 = SparcV9IntRegClass::o6, + o7 = SparcV9IntRegClass::o7, g0 = SparcV9IntRegClass::g0, + g1 = SparcV9IntRegClass::g1, g5 = SparcV9IntRegClass::g5; MachineInstr* BinaryCode[] = { // @@ -582,7 +582,7 @@ } } -void SparcJITInfo::replaceMachineCodeForFunction (void *Old, void *New) { +void SparcV9JITInfo::replaceMachineCodeForFunction (void *Old, void *New) { assert (TheJITResolver && "Can only call replaceMachineCodeForFunction from within JIT"); uint64_t Target = (uint64_t)(intptr_t)New; @@ -594,11 +594,7 @@ MachineOperand &MO) { int64_t rv = 0; // Return value; defaults to 0 for unhandled cases // or things that get fixed up later by the JIT. - - if (MO.isVirtualRegister()) { - std::cerr << "ERROR: virtual register found in machine code.\n"; - abort(); - } else if (MO.isPCRelativeDisp()) { + if (MO.isPCRelativeDisp()) { DEBUG(std::cerr << "PCRelativeDisp: "); Value *V = MO.getVRegValue(); if (BasicBlock *BB = dyn_cast(V)) { @@ -660,13 +656,12 @@ std::cerr << "ERROR: PC relative disp unhandled:" << MO << "\n"; abort(); } - } else if (MO.isPhysicalRegister() || - MO.getType() == MachineOperand::MO_CCRegister) + } else if (MO.isRegister() || MO.getType() == MachineOperand::MO_CCRegister) { - // This is necessary because the Sparc backend doesn't actually lay out + // This is necessary because the SparcV9 backend doesn't actually lay out // registers in the real fashion -- it skips those that it chooses not to // allocate, i.e. those that are the FP, SP, etc. - unsigned fakeReg = MO.getAllocatedRegNum(); + unsigned fakeReg = MO.getReg(); unsigned realRegByClass = getRealRegNum(fakeReg, MI); DEBUG(std::cerr << MO << ": Reg[" << std::dec << fakeReg << "] => " << realRegByClass << " (LLC: " @@ -682,17 +677,17 @@ MI, MO.isPCRelative()); } else if (MO.isMachineBasicBlock()) { // Duplicate code of the above case for VirtualRegister, BasicBlock... - // It should really hit this case, but Sparc backend uses VRegs instead + // It should really hit this case, but SparcV9 backend uses VRegs instead DEBUG(std::cerr << "Saving reference to MBB\n"); const BasicBlock *BB = MO.getMachineBasicBlock()->getBasicBlock(); unsigned* CurrPC = (unsigned*)(intptr_t)MCE.getCurrentPCValue(); BBRefs.push_back(std::make_pair(BB, std::make_pair(CurrPC, &MI))); } else if (MO.isExternalSymbol()) { - // Sparc backend doesn't generate this (yet...) + // SparcV9 backend doesn't generate this (yet...) std::cerr << "ERROR: External symbol unhandled: " << MO << "\n"; abort(); } else if (MO.isFrameIndex()) { - // Sparc backend doesn't generate this (yet...) + // SparcV9 backend doesn't generate this (yet...) int FrameIndex = MO.getFrameIndex(); std::cerr << "ERROR: Frame index unhandled.\n"; abort(); @@ -708,13 +703,13 @@ // are used in SPARC assembly. (Some of these make no sense in combination // with some of the above; we'll trust that the instruction selector // will not produce nonsense, and not check for valid combinations here.) - if (MO.isLoBits32()) { // %lo(val) == %lo() in Sparc ABI doc + if (MO.isLoBits32()) { // %lo(val) == %lo() in SparcV9 ABI doc return rv & 0x03ff; - } else if (MO.isHiBits32()) { // %lm(val) == %hi() in Sparc ABI doc + } else if (MO.isHiBits32()) { // %lm(val) == %hi() in SparcV9 ABI doc return (rv >> 10) & 0x03fffff; - } else if (MO.isLoBits64()) { // %hm(val) == %ulo() in Sparc ABI doc + } else if (MO.isLoBits64()) { // %hm(val) == %ulo() in SparcV9 ABI doc return (rv >> 32) & 0x03ff; - } else if (MO.isHiBits64()) { // %hh(val) == %uhi() in Sparc ABI doc + } else if (MO.isHiBits64()) { // %hh(val) == %uhi() in SparcV9 ABI doc return rv >> 42; } else { // (unadorned) val return rv; @@ -783,7 +778,7 @@ currBB = MBB.getBasicBlock(); BBLocations[currBB] = MCE.getCurrentPCValue(); for (MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end(); I != E; ++I){ - unsigned binCode = getBinaryCodeForInstr(**I); + unsigned binCode = getBinaryCodeForInstr(*I); if (binCode == (1 << 30)) { // this is an invalid call: the addr is out of bounds. that means a code // sequence has already been emitted, and this is a no-op Index: llvm/lib/Target/SparcV9/SparcV9FrameInfo.cpp diff -u llvm/lib/Target/SparcV9/SparcV9FrameInfo.cpp:1.1 llvm/lib/Target/SparcV9/SparcV9FrameInfo.cpp:1.1.2.1 --- llvm/lib/Target/SparcV9/SparcV9FrameInfo.cpp:1.1 Wed Dec 17 16:04:00 2003 +++ llvm/lib/Target/SparcV9/SparcV9FrameInfo.cpp Mon Mar 1 17:58:14 2004 @@ -1,4 +1,4 @@ -//===-- Sparc.cpp - General implementation file for the Sparc Target ------===// +//===-- SparcV9.cpp - General implementation file for the SparcV9 Target ------===// // // The LLVM Compiler Infrastructure // @@ -16,18 +16,18 @@ #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineFunctionInfo.h" #include "llvm/Target/TargetFrameInfo.h" -#include "SparcFrameInfo.h" +#include "SparcV9FrameInfo.h" using namespace llvm; int -SparcFrameInfo::getFirstAutomaticVarOffset(MachineFunction&, bool& pos) const { +SparcV9FrameInfo::getFirstAutomaticVarOffset(MachineFunction&, bool& pos) const { pos = false; // static stack area grows downwards return StaticAreaOffsetFromFP; } int -SparcFrameInfo::getRegSpillAreaOffset(MachineFunction& mcInfo, bool& pos) const +SparcV9FrameInfo::getRegSpillAreaOffset(MachineFunction& mcInfo, bool& pos) const { // ensure no more auto vars are added mcInfo.getInfo()->freezeAutomaticVarsArea(); @@ -37,7 +37,7 @@ return StaticAreaOffsetFromFP - autoVarsSize; } -int SparcFrameInfo::getTmpAreaOffset(MachineFunction& mcInfo, bool& pos) const { +int SparcV9FrameInfo::getTmpAreaOffset(MachineFunction& mcInfo, bool& pos) const { MachineFunctionInfo *MFI = mcInfo.getInfo(); MFI->freezeAutomaticVarsArea(); // ensure no more auto vars are added MFI->freezeSpillsArea(); // ensure no more spill slots are added @@ -50,7 +50,7 @@ } int -SparcFrameInfo::getDynamicAreaOffset(MachineFunction& mcInfo, bool& pos) const { +SparcV9FrameInfo::getDynamicAreaOffset(MachineFunction& mcInfo, bool& pos) const { // Dynamic stack area grows downwards starting at top of opt-args area. // The opt-args, required-args, and register-save areas are empty except // during calls and traps, so they are shifted downwards on each Index: llvm/lib/Target/SparcV9/SparcV9FrameInfo.h diff -u llvm/lib/Target/SparcV9/SparcV9FrameInfo.h:1.1 llvm/lib/Target/SparcV9/SparcV9FrameInfo.h:1.1.2.1 --- llvm/lib/Target/SparcV9/SparcV9FrameInfo.h:1.1 Wed Dec 17 16:04:00 2003 +++ llvm/lib/Target/SparcV9/SparcV9FrameInfo.h Mon Mar 1 17:58:14 2004 @@ -1,4 +1,4 @@ -//===-- SparcFrameInfo.h - Define TargetFrameInfo for Sparc -----*- C++ -*-===// +//===-- SparcV9FrameInfo.h - Define TargetFrameInfo for SparcV9 -----*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -22,10 +22,10 @@ namespace llvm { -class SparcFrameInfo: public TargetFrameInfo { +class SparcV9FrameInfo: public TargetFrameInfo { const TargetMachine ⌖ public: - SparcFrameInfo(const TargetMachine &TM) + SparcV9FrameInfo(const TargetMachine &TM) : TargetFrameInfo(StackGrowsDown, StackFrameSizeAlignment, 0), target(TM) {} public: @@ -114,10 +114,10 @@ private: /*---------------------------------------------------------------------- - This diagram shows the stack frame layout used by llc on Sparc V9. + This diagram shows the stack frame layout used by llc on SparcV9 V9. Note that only the location of automatic variables, spill area, temporary storage, and dynamically allocated stack area are chosen - by us. The rest conform to the Sparc V9 ABI. + by us. The rest conform to the SparcV9 V9 ABI. All stack addresses are offset by OFFSET = 0x7ff (2047). Alignment assumptions and other invariants: @@ -156,7 +156,7 @@ *----------------------------------------------------------------------*/ - // All stack addresses must be offset by 0x7ff (2047) on Sparc V9. + // All stack addresses must be offset by 0x7ff (2047) on SparcV9 V9. static const int OFFSET = (int) 0x7ff; static const int StackFrameSizeAlignment = 16; static const int MinStackFrameSize = 176; Index: llvm/lib/Target/SparcV9/SparcV9Instr.def diff -u llvm/lib/Target/SparcV9/SparcV9Instr.def:1.23 llvm/lib/Target/SparcV9/SparcV9Instr.def:1.23.6.1 --- llvm/lib/Target/SparcV9/SparcV9Instr.def:1.23 Tue Oct 21 10:17:13 2003 +++ llvm/lib/Target/SparcV9/SparcV9Instr.def Mon Mar 1 17:58:14 2004 @@ -51,155 +51,155 @@ // Synthetic SPARC assembly opcodes for setting a register to a constant. // Max immediate constant should be ignored for both these instructions. // Use a latency > 1 since this may generate as many as 3 instructions. -I(SETSW, "setsw", 2, 1, 0, true , 0, 2, SPARC_IEUN, M_INT_FLAG | M_ARITH_FLAG | M_PSEUDO_FLAG ) -I(SETUW, "setuw", 2, 1, 0, false, 0, 2, SPARC_IEUN, M_INT_FLAG | M_LOGICAL_FLAG | M_ARITH_FLAG | M_PSEUDO_FLAG ) -I(SETX, "setx", 3, 2, 0, true, 0, 2, SPARC_IEUN, M_INT_FLAG | M_LOGICAL_FLAG | M_ARITH_FLAG | M_PSEUDO_FLAG ) +I(SETSW, "setsw", 2, 1, 0, true , 0, 2, SPARC_IEUN, M_PSEUDO_FLAG ) +I(SETUW, "setuw", 2, 1, 0, false, 0, 2, SPARC_IEUN, M_PSEUDO_FLAG ) +I(SETX, "setx", 3, 2, 0, true, 0, 2, SPARC_IEUN, M_PSEUDO_FLAG ) // Set high-order bits of register and clear low-order bits -I(SETHI, "sethi", 2, 1, B22, false, 0, 1, SPARC_IEUN, M_INT_FLAG | M_LOGICAL_FLAG | M_ARITH_FLAG) +I(SETHI, "sethi", 2, 1, B22, false, 0, 1, SPARC_IEUN, 0) // Add or add with carry. -I(ADDr , "add", 3, 2, B12, true , 0, 1, SPARC_IEUN, M_INT_FLAG | M_ARITH_FLAG) -I(ADDi , "add", 3, 2, B12, true , 0, 1, SPARC_IEUN, M_INT_FLAG | M_ARITH_FLAG) -I(ADDccr, "addcc", 4, 2, B12, true , 0, 1, SPARC_IEU1, M_INT_FLAG | M_ARITH_FLAG | M_CC_FLAG ) -I(ADDcci, "addcc", 4, 2, B12, true , 0, 1, SPARC_IEU1, M_INT_FLAG | M_ARITH_FLAG | M_CC_FLAG ) -I(ADDCr , "addc", 3, 2, B12, true , 0, 1, SPARC_IEUN, M_INT_FLAG | M_ARITH_FLAG) -I(ADDCi , "addc", 3, 2, B12, true , 0, 1, SPARC_IEUN, M_INT_FLAG | M_ARITH_FLAG) -I(ADDCccr, "addccc", 4, 2, B12, true , 0, 1, SPARC_IEU1, M_INT_FLAG | M_ARITH_FLAG | M_CC_FLAG ) -I(ADDCcci, "addccc", 4, 2, B12, true , 0, 1, SPARC_IEU1, M_INT_FLAG | M_ARITH_FLAG | M_CC_FLAG ) +I(ADDr , "add", 3, 2, B12, true , 0, 1, SPARC_IEUN, 0) +I(ADDi , "add", 3, 2, B12, true , 0, 1, SPARC_IEUN, 0) +I(ADDccr, "addcc", 4, 2, B12, true , 0, 1, SPARC_IEU1, M_CC_FLAG ) +I(ADDcci, "addcc", 4, 2, B12, true , 0, 1, SPARC_IEU1, M_CC_FLAG ) +I(ADDCr , "addc", 3, 2, B12, true , 0, 1, SPARC_IEUN, 0) +I(ADDCi , "addc", 3, 2, B12, true , 0, 1, SPARC_IEUN, 0) +I(ADDCccr, "addccc", 4, 2, B12, true , 0, 1, SPARC_IEU1, M_CC_FLAG ) +I(ADDCcci, "addccc", 4, 2, B12, true , 0, 1, SPARC_IEU1, M_CC_FLAG ) // Subtract or subtract with carry. -I(SUBr , "sub", 3, 2, B12, true , 0, 1, SPARC_IEUN, M_INT_FLAG | M_ARITH_FLAG) -I(SUBi , "sub", 3, 2, B12, true , 0, 1, SPARC_IEUN, M_INT_FLAG | M_ARITH_FLAG) -I(SUBccr , "subcc", 4, 2, B12, true , 0, 1, SPARC_IEU1, M_INT_FLAG | M_ARITH_FLAG | M_CC_FLAG ) -I(SUBcci , "subcc", 4, 2, B12, true , 0, 1, SPARC_IEU1, M_INT_FLAG | M_ARITH_FLAG | M_CC_FLAG ) -I(SUBCr , "subc", 3, 2, B12, true , 0, 1, SPARC_IEUN, M_INT_FLAG | M_ARITH_FLAG) -I(SUBCi , "subc", 3, 2, B12, true , 0, 1, SPARC_IEUN, M_INT_FLAG | M_ARITH_FLAG) -I(SUBCccr, "subccc", 4, 2, B12, true , 0, 1, SPARC_IEU1, M_INT_FLAG | M_ARITH_FLAG | M_CC_FLAG ) -I(SUBCcci, "subccc", 4, 2, B12, true , 0, 1, SPARC_IEU1, M_INT_FLAG | M_ARITH_FLAG | M_CC_FLAG ) +I(SUBr , "sub", 3, 2, B12, true , 0, 1, SPARC_IEUN, 0) +I(SUBi , "sub", 3, 2, B12, true , 0, 1, SPARC_IEUN, 0) +I(SUBccr , "subcc", 4, 2, B12, true , 0, 1, SPARC_IEU1, M_CC_FLAG ) +I(SUBcci , "subcc", 4, 2, B12, true , 0, 1, SPARC_IEU1, M_CC_FLAG ) +I(SUBCr , "subc", 3, 2, B12, true , 0, 1, SPARC_IEUN, 0) +I(SUBCi , "subc", 3, 2, B12, true , 0, 1, SPARC_IEUN, 0) +I(SUBCccr, "subccc", 4, 2, B12, true , 0, 1, SPARC_IEU1, M_CC_FLAG ) +I(SUBCcci, "subccc", 4, 2, B12, true , 0, 1, SPARC_IEU1, M_CC_FLAG ) // Integer multiply, signed divide, unsigned divide. // Note that the deprecated 32-bit multiply and multiply-step are not used. -I(MULXr , "mulx", 3, 2, B12, true , 0, 3, SPARC_IEUN, M_INT_FLAG | M_ARITH_FLAG) -I(MULXi , "mulx", 3, 2, B12, true , 0, 3, SPARC_IEUN, M_INT_FLAG | M_ARITH_FLAG) -I(SDIVXr, "sdivx", 3, 2, B12, true , 0, 6, SPARC_IEUN, M_INT_FLAG | M_ARITH_FLAG) -I(SDIVXi, "sdivx", 3, 2, B12, true , 0, 6, SPARC_IEUN, M_INT_FLAG | M_ARITH_FLAG) -I(UDIVXr, "udivx", 3, 2, B12, true , 0, 6, SPARC_IEUN, M_INT_FLAG | M_ARITH_FLAG) -I(UDIVXi, "udivx", 3, 2, B12, true , 0, 6, SPARC_IEUN, M_INT_FLAG | M_ARITH_FLAG) +I(MULXr , "mulx", 3, 2, B12, true , 0, 3, SPARC_IEUN, 0) +I(MULXi , "mulx", 3, 2, B12, true , 0, 3, SPARC_IEUN, 0) +I(SDIVXr, "sdivx", 3, 2, B12, true , 0, 6, SPARC_IEUN, 0) +I(SDIVXi, "sdivx", 3, 2, B12, true , 0, 6, SPARC_IEUN, 0) +I(UDIVXr, "udivx", 3, 2, B12, true , 0, 6, SPARC_IEUN, 0) +I(UDIVXi, "udivx", 3, 2, B12, true , 0, 6, SPARC_IEUN, 0) // Floating point add, subtract, compare. // Note that destination of FCMP* instructions is operand 0, not operand 2. -I(FADDS, "fadds", 3, 2, 0, false, 0, 3, SPARC_FPA, M_FLOAT_FLAG | M_ARITH_FLAG) -I(FADDD, "faddd", 3, 2, 0, false, 0, 3, SPARC_FPA, M_FLOAT_FLAG | M_ARITH_FLAG) -I(FADDQ, "faddq", 3, 2, 0, false, 0, 3, SPARC_FPA, M_FLOAT_FLAG | M_ARITH_FLAG) -I(FSUBS, "fsubs", 3, 2, 0, false, 0, 3, SPARC_FPA, M_FLOAT_FLAG | M_ARITH_FLAG) -I(FSUBD, "fsubd", 3, 2, 0, false, 0, 3, SPARC_FPA, M_FLOAT_FLAG | M_ARITH_FLAG) -I(FSUBQ, "fsubq", 3, 2, 0, false, 0, 3, SPARC_FPA, M_FLOAT_FLAG | M_ARITH_FLAG) -I(FCMPS, "fcmps", 3, 0, 0, false, 0, 3, SPARC_FPA, M_FLOAT_FLAG | M_ARITH_FLAG | M_CC_FLAG ) -I(FCMPD, "fcmpd", 3, 0, 0, false, 0, 3, SPARC_FPA, M_FLOAT_FLAG | M_ARITH_FLAG | M_CC_FLAG ) -I(FCMPQ, "fcmpq", 3, 0, 0, false, 0, 3, SPARC_FPA, M_FLOAT_FLAG | M_ARITH_FLAG | M_CC_FLAG ) +I(FADDS, "fadds", 3, 2, 0, false, 0, 3, SPARC_FPA, 0) +I(FADDD, "faddd", 3, 2, 0, false, 0, 3, SPARC_FPA, 0) +I(FADDQ, "faddq", 3, 2, 0, false, 0, 3, SPARC_FPA, 0) +I(FSUBS, "fsubs", 3, 2, 0, false, 0, 3, SPARC_FPA, 0) +I(FSUBD, "fsubd", 3, 2, 0, false, 0, 3, SPARC_FPA, 0) +I(FSUBQ, "fsubq", 3, 2, 0, false, 0, 3, SPARC_FPA, 0) +I(FCMPS, "fcmps", 3, 0, 0, false, 0, 3, SPARC_FPA, M_CC_FLAG ) +I(FCMPD, "fcmpd", 3, 0, 0, false, 0, 3, SPARC_FPA, M_CC_FLAG ) +I(FCMPQ, "fcmpq", 3, 0, 0, false, 0, 3, SPARC_FPA, M_CC_FLAG ) // NOTE: FCMPE{S,D,Q}: FP Compare With Exception are currently unused! // Floating point multiply or divide. -I(FMULS , "fmuls", 3, 2, 0, false, 0, 3, SPARC_FPM, M_FLOAT_FLAG | M_ARITH_FLAG) -I(FMULD , "fmuld", 3, 2, 0, false, 0, 3, SPARC_FPM, M_FLOAT_FLAG | M_ARITH_FLAG) -I(FMULQ , "fmulq", 3, 2, 0, false, 0, 0, SPARC_FPM, M_FLOAT_FLAG | M_ARITH_FLAG) -I(FSMULD, "fsmuld", 3, 2, 0, false, 0, 3, SPARC_FPM, M_FLOAT_FLAG | M_ARITH_FLAG) -I(FDMULQ, "fdmulq", 3, 2, 0, false, 0, 0, SPARC_FPM, M_FLOAT_FLAG | M_ARITH_FLAG) -I(FDIVS , "fdivs", 3, 2, 0, false, 0, 12, SPARC_FPM, M_FLOAT_FLAG | M_ARITH_FLAG) -I(FDIVD , "fdivd", 3, 2, 0, false, 0, 22, SPARC_FPM, M_FLOAT_FLAG | M_ARITH_FLAG) -I(FDIVQ , "fdivq", 3, 2, 0, false, 0, 0, SPARC_FPM, M_FLOAT_FLAG | M_ARITH_FLAG) -I(FSQRTS, "fsqrts", 3, 2, 0, false, 0, 12, SPARC_FPM, M_FLOAT_FLAG | M_ARITH_FLAG) -I(FSQRTD, "fsqrtd", 3, 2, 0, false, 0, 22, SPARC_FPM, M_FLOAT_FLAG | M_ARITH_FLAG) -I(FSQRTQ, "fsqrtq", 3, 2, 0, false, 0, 0, SPARC_FPM, M_FLOAT_FLAG | M_ARITH_FLAG) +I(FMULS , "fmuls", 3, 2, 0, false, 0, 3, SPARC_FPM, 0) +I(FMULD , "fmuld", 3, 2, 0, false, 0, 3, SPARC_FPM, 0) +I(FMULQ , "fmulq", 3, 2, 0, false, 0, 0, SPARC_FPM, 0) +I(FSMULD, "fsmuld", 3, 2, 0, false, 0, 3, SPARC_FPM, 0) +I(FDMULQ, "fdmulq", 3, 2, 0, false, 0, 0, SPARC_FPM, 0) +I(FDIVS , "fdivs", 3, 2, 0, false, 0, 12, SPARC_FPM, 0) +I(FDIVD , "fdivd", 3, 2, 0, false, 0, 22, SPARC_FPM, 0) +I(FDIVQ , "fdivq", 3, 2, 0, false, 0, 0, SPARC_FPM, 0) +I(FSQRTS, "fsqrts", 3, 2, 0, false, 0, 12, SPARC_FPM, 0) +I(FSQRTD, "fsqrtd", 3, 2, 0, false, 0, 22, SPARC_FPM, 0) +I(FSQRTQ, "fsqrtq", 3, 2, 0, false, 0, 0, SPARC_FPM, 0) // Logical operations -I(ANDr , "and", 3, 2, B12, true , 0, 1, SPARC_IEUN, M_INT_FLAG | M_LOGICAL_FLAG) -I(ANDi , "and", 3, 2, B12, true , 0, 1, SPARC_IEUN, M_INT_FLAG | M_LOGICAL_FLAG) -I(ANDccr , "andcc", 4, 2, B12, true , 0, 1, SPARC_IEU1, M_INT_FLAG | M_LOGICAL_FLAG) -I(ANDcci , "andcc", 4, 2, B12, true , 0, 1, SPARC_IEU1, M_INT_FLAG | M_LOGICAL_FLAG) -I(ANDNr , "andn", 3, 2, B12, true , 0, 1, SPARC_IEUN, M_INT_FLAG | M_LOGICAL_FLAG) -I(ANDNi , "andn", 3, 2, B12, true , 0, 1, SPARC_IEUN, M_INT_FLAG | M_LOGICAL_FLAG) -I(ANDNccr, "andncc", 4, 2, B12, true , 0, 1, SPARC_IEU1, M_INT_FLAG | M_LOGICAL_FLAG) -I(ANDNcci, "andncc", 4, 2, B12, true , 0, 1, SPARC_IEU1, M_INT_FLAG | M_LOGICAL_FLAG) - -I(ORr , "or", 3, 2, B12, true , 0, 1, SPARC_IEUN, M_INT_FLAG | M_LOGICAL_FLAG) -I(ORi , "or", 3, 2, B12, true , 0, 1, SPARC_IEUN, M_INT_FLAG | M_LOGICAL_FLAG) -I(ORccr , "orcc", 4, 2, B12, true , 0, 1, SPARC_IEU1, M_INT_FLAG | M_LOGICAL_FLAG) -I(ORcci , "orcc", 4, 2, B12, true , 0, 1, SPARC_IEU1, M_INT_FLAG | M_LOGICAL_FLAG) -I(ORNr , "orn", 3, 2, B12, true , 0, 1, SPARC_IEUN, M_INT_FLAG | M_LOGICAL_FLAG) -I(ORNi , "orn", 3, 2, B12, true , 0, 1, SPARC_IEUN, M_INT_FLAG | M_LOGICAL_FLAG) -I(ORNccr, "orncc", 4, 2, B12, true , 0, 1, SPARC_IEU1, M_INT_FLAG | M_LOGICAL_FLAG) -I(ORNcci, "orncc", 4, 2, B12, true , 0, 1, SPARC_IEU1, M_INT_FLAG | M_LOGICAL_FLAG) - -I(XORr , "xor", 3, 2, B12, true , 0, 1, SPARC_IEUN, M_INT_FLAG | M_LOGICAL_FLAG) -I(XORi , "xor", 3, 2, B12, true , 0, 1, SPARC_IEUN, M_INT_FLAG | M_LOGICAL_FLAG) -I(XORccr , "xorcc", 4, 2, B12, true , 0, 1, SPARC_IEU1, M_INT_FLAG | M_LOGICAL_FLAG) -I(XORcci , "xorcc", 4, 2, B12, true , 0, 1, SPARC_IEU1, M_INT_FLAG | M_LOGICAL_FLAG) -I(XNORr , "xnor", 3, 2, B12, true , 0, 1, SPARC_IEUN, M_INT_FLAG | M_LOGICAL_FLAG) -I(XNORi , "xnor", 3, 2, B12, true , 0, 1, SPARC_IEUN, M_INT_FLAG | M_LOGICAL_FLAG) -I(XNORccr, "xnorcc", 4, 2, B12, true , 0, 1, SPARC_IEU1, M_INT_FLAG | M_LOGICAL_FLAG) -I(XNORcci, "xnorcc", 4, 2, B12, true , 0, 1, SPARC_IEU1, M_INT_FLAG | M_LOGICAL_FLAG) +I(ANDr , "and", 3, 2, B12, true , 0, 1, SPARC_IEUN, 0) +I(ANDi , "and", 3, 2, B12, true , 0, 1, SPARC_IEUN, 0) +I(ANDccr , "andcc", 4, 2, B12, true , 0, 1, SPARC_IEU1, 0) +I(ANDcci , "andcc", 4, 2, B12, true , 0, 1, SPARC_IEU1, 0) +I(ANDNr , "andn", 3, 2, B12, true , 0, 1, SPARC_IEUN, 0) +I(ANDNi , "andn", 3, 2, B12, true , 0, 1, SPARC_IEUN, 0) +I(ANDNccr, "andncc", 4, 2, B12, true , 0, 1, SPARC_IEU1, 0) +I(ANDNcci, "andncc", 4, 2, B12, true , 0, 1, SPARC_IEU1, 0) + +I(ORr , "or", 3, 2, B12, true , 0, 1, SPARC_IEUN, 0) +I(ORi , "or", 3, 2, B12, true , 0, 1, SPARC_IEUN, 0) +I(ORccr , "orcc", 4, 2, B12, true , 0, 1, SPARC_IEU1, 0) +I(ORcci , "orcc", 4, 2, B12, true , 0, 1, SPARC_IEU1, 0) +I(ORNr , "orn", 3, 2, B12, true , 0, 1, SPARC_IEUN, 0) +I(ORNi , "orn", 3, 2, B12, true , 0, 1, SPARC_IEUN, 0) +I(ORNccr, "orncc", 4, 2, B12, true , 0, 1, SPARC_IEU1, 0) +I(ORNcci, "orncc", 4, 2, B12, true , 0, 1, SPARC_IEU1, 0) + +I(XORr , "xor", 3, 2, B12, true , 0, 1, SPARC_IEUN, 0) +I(XORi , "xor", 3, 2, B12, true , 0, 1, SPARC_IEUN, 0) +I(XORccr , "xorcc", 4, 2, B12, true , 0, 1, SPARC_IEU1, 0) +I(XORcci , "xorcc", 4, 2, B12, true , 0, 1, SPARC_IEU1, 0) +I(XNORr , "xnor", 3, 2, B12, true , 0, 1, SPARC_IEUN, 0) +I(XNORi , "xnor", 3, 2, B12, true , 0, 1, SPARC_IEUN, 0) +I(XNORccr, "xnorcc", 4, 2, B12, true , 0, 1, SPARC_IEU1, 0) +I(XNORcci, "xnorcc", 4, 2, B12, true , 0, 1, SPARC_IEU1, 0) // Shift operations -I(SLLr5 , "sll", 3, 2, B5, true , 0, 1, SPARC_IEU0, M_INT_FLAG | M_LOGICAL_FLAG) -I(SLLi5 , "sll", 3, 2, B5, true , 0, 1, SPARC_IEU0, M_INT_FLAG | M_LOGICAL_FLAG) -I(SRLr5 , "srl", 3, 2, B5, true , 0, 1, SPARC_IEU0, M_INT_FLAG | M_LOGICAL_FLAG) -I(SRLi5 , "srl", 3, 2, B5, true , 0, 1, SPARC_IEU0, M_INT_FLAG | M_LOGICAL_FLAG) -I(SRAr5 , "sra", 3, 2, B5, true , 0, 1, SPARC_IEU0, M_INT_FLAG | M_ARITH_FLAG) -I(SRAi5 , "sra", 3, 2, B5, true , 0, 1, SPARC_IEU0, M_INT_FLAG | M_ARITH_FLAG) -I(SLLXr6, "sllx", 3, 2, B6, true , 0, 1, SPARC_IEU0, M_INT_FLAG | M_LOGICAL_FLAG) -I(SLLXi6, "sllx", 3, 2, B6, true , 0, 1, SPARC_IEU0, M_INT_FLAG | M_LOGICAL_FLAG) -I(SRLXr6, "srlx", 3, 2, B6, true , 0, 1, SPARC_IEU0, M_INT_FLAG | M_LOGICAL_FLAG) -I(SRLXi6, "srlx", 3, 2, B6, true , 0, 1, SPARC_IEU0, M_INT_FLAG | M_LOGICAL_FLAG) -I(SRAXr6, "srax", 3, 2, B6, true , 0, 1, SPARC_IEU0, M_INT_FLAG | M_ARITH_FLAG) -I(SRAXi6, "srax", 3, 2, B6, true , 0, 1, SPARC_IEU0, M_INT_FLAG | M_ARITH_FLAG) +I(SLLr5 , "sll", 3, 2, B5, true , 0, 1, SPARC_IEU0, 0) +I(SLLi5 , "sll", 3, 2, B5, true , 0, 1, SPARC_IEU0, 0) +I(SRLr5 , "srl", 3, 2, B5, true , 0, 1, SPARC_IEU0, 0) +I(SRLi5 , "srl", 3, 2, B5, true , 0, 1, SPARC_IEU0, 0) +I(SRAr5 , "sra", 3, 2, B5, true , 0, 1, SPARC_IEU0, 0) +I(SRAi5 , "sra", 3, 2, B5, true , 0, 1, SPARC_IEU0, 0) +I(SLLXr6, "sllx", 3, 2, B6, true , 0, 1, SPARC_IEU0, 0) +I(SLLXi6, "sllx", 3, 2, B6, true , 0, 1, SPARC_IEU0, 0) +I(SRLXr6, "srlx", 3, 2, B6, true , 0, 1, SPARC_IEU0, 0) +I(SRLXi6, "srlx", 3, 2, B6, true , 0, 1, SPARC_IEU0, 0) +I(SRAXr6, "srax", 3, 2, B6, true , 0, 1, SPARC_IEU0, 0) +I(SRAXi6, "srax", 3, 2, B6, true , 0, 1, SPARC_IEU0, 0) // Floating point move, negate, and abs instructions -I(FMOVS, "fmovs", 2, 1, 0, false, 0, 1, SPARC_FPA, M_FLOAT_FLAG) -I(FMOVD, "fmovd", 2, 1, 0, false, 0, 1, SPARC_FPA, M_FLOAT_FLAG) -//I(FMOVQ, "fmovq", 2, 1, 0, false, 0, ?, SPARC_FPA, M_FLOAT_FLAG) -I(FNEGS, "fnegs", 2, 1, 0, false, 0, 1, SPARC_FPA, M_FLOAT_FLAG) -I(FNEGD, "fnegd", 2, 1, 0, false, 0, 1, SPARC_FPA, M_FLOAT_FLAG) -//I(FNEGQ, "fnegq", 2, 1, 0, false, 0, ?, SPARC_FPA, M_FLOAT_FLAG) -I(FABSS, "fabss", 2, 1, 0, false, 0, 1, SPARC_FPA, M_FLOAT_FLAG) -I(FABSD, "fabsd", 2, 1, 0, false, 0, 1, SPARC_FPA, M_FLOAT_FLAG) -//I(FABSQ, "fabsq", 2, 1, 0, false, 0, ?, SPARC_FPA, M_FLOAT_FLAG) +I(FMOVS, "fmovs", 2, 1, 0, false, 0, 1, SPARC_FPA, 0) +I(FMOVD, "fmovd", 2, 1, 0, false, 0, 1, SPARC_FPA, 0) +//I(FMOVQ, "fmovq", 2, 1, 0, false, 0, ?, SPARC_FPA, 0) +I(FNEGS, "fnegs", 2, 1, 0, false, 0, 1, SPARC_FPA, 0) +I(FNEGD, "fnegd", 2, 1, 0, false, 0, 1, SPARC_FPA, 0) +//I(FNEGQ, "fnegq", 2, 1, 0, false, 0, ?, SPARC_FPA, 0) +I(FABSS, "fabss", 2, 1, 0, false, 0, 1, SPARC_FPA, 0) +I(FABSD, "fabsd", 2, 1, 0, false, 0, 1, SPARC_FPA, 0) +//I(FABSQ, "fabsq", 2, 1, 0, false, 0, ?, SPARC_FPA, 0) // Convert from floating point to floating point formats -I(FSTOD, "fstod", 2, 1, 0, false, 0, 3, SPARC_FPA, M_FLOAT_FLAG | M_ARITH_FLAG) -I(FSTOQ, "fstoq", 2, 1, 0, false, 0, 0, SPARC_FPA, M_FLOAT_FLAG | M_ARITH_FLAG) -I(FDTOS, "fdtos", 2, 1, 0, false, 0, 3, SPARC_FPA, M_FLOAT_FLAG | M_ARITH_FLAG) -I(FDTOQ, "fdtoq", 2, 1, 0, false, 0, 0, SPARC_FPA, M_FLOAT_FLAG | M_ARITH_FLAG) -I(FQTOS, "fqtos", 2, 1, 0, false, 0, 0, SPARC_FPA, M_FLOAT_FLAG | M_ARITH_FLAG) -I(FQTOD, "fqtod", 2, 1, 0, false, 0, 0, SPARC_FPA, M_FLOAT_FLAG | M_ARITH_FLAG) +I(FSTOD, "fstod", 2, 1, 0, false, 0, 3, SPARC_FPA, 0) +I(FSTOQ, "fstoq", 2, 1, 0, false, 0, 0, SPARC_FPA, 0) +I(FDTOS, "fdtos", 2, 1, 0, false, 0, 3, SPARC_FPA, 0) +I(FDTOQ, "fdtoq", 2, 1, 0, false, 0, 0, SPARC_FPA, 0) +I(FQTOS, "fqtos", 2, 1, 0, false, 0, 0, SPARC_FPA, 0) +I(FQTOD, "fqtod", 2, 1, 0, false, 0, 0, SPARC_FPA, 0) // Convert from floating point to integer formats. // Note that this accesses both integer and floating point registers. -I(FSTOX, "fstox", 2, 1, 0, false, 0, 3, SPARC_FPA, M_FLOAT_FLAG | M_INT_FLAG | M_ARITH_FLAG) -I(FDTOX, "fdtox", 2, 1, 0, false, 0, 0, SPARC_FPA, M_FLOAT_FLAG | M_INT_FLAG | M_ARITH_FLAG) -I(FQTOX, "fqtox", 2, 1, 0, false, 0, 2, SPARC_FPA, M_FLOAT_FLAG | M_INT_FLAG | M_ARITH_FLAG) -I(FSTOI, "fstoi", 2, 1, 0, false, 0, 3, SPARC_FPA, M_FLOAT_FLAG | M_INT_FLAG | M_ARITH_FLAG) -I(FDTOI, "fdtoi", 2, 1, 0, false, 0, 3, SPARC_FPA, M_FLOAT_FLAG | M_INT_FLAG | M_ARITH_FLAG) -I(FQTOI, "fqtoi", 2, 1, 0, false, 0, 0, SPARC_FPA, M_FLOAT_FLAG | M_INT_FLAG | M_ARITH_FLAG) +I(FSTOX, "fstox", 2, 1, 0, false, 0, 3, SPARC_FPA, 0) +I(FDTOX, "fdtox", 2, 1, 0, false, 0, 0, SPARC_FPA, 0) +I(FQTOX, "fqtox", 2, 1, 0, false, 0, 2, SPARC_FPA, 0) +I(FSTOI, "fstoi", 2, 1, 0, false, 0, 3, SPARC_FPA, 0) +I(FDTOI, "fdtoi", 2, 1, 0, false, 0, 3, SPARC_FPA, 0) +I(FQTOI, "fqtoi", 2, 1, 0, false, 0, 0, SPARC_FPA, 0) // Convert from integer to floating point formats // Note that this accesses both integer and floating point registers. -I(FXTOS, "fxtos", 2, 1, 0, false, 0, 3, SPARC_FPA, M_FLOAT_FLAG | M_INT_FLAG | M_ARITH_FLAG) -I(FXTOD, "fxtod", 2, 1, 0, false, 0, 3, SPARC_FPA, M_FLOAT_FLAG | M_INT_FLAG | M_ARITH_FLAG) -I(FXTOQ, "fxtoq", 2, 1, 0, false, 0, 0, SPARC_FPA, M_FLOAT_FLAG | M_INT_FLAG | M_ARITH_FLAG) -I(FITOS, "fitos", 2, 1, 0, false, 0, 3, SPARC_FPA, M_FLOAT_FLAG | M_INT_FLAG | M_ARITH_FLAG) -I(FITOD, "fitod", 2, 1, 0, false, 0, 3, SPARC_FPA, M_FLOAT_FLAG | M_INT_FLAG | M_ARITH_FLAG) -I(FITOQ, "fitoq", 2, 1, 0, false, 0, 0, SPARC_FPA, M_FLOAT_FLAG | M_INT_FLAG | M_ARITH_FLAG) +I(FXTOS, "fxtos", 2, 1, 0, false, 0, 3, SPARC_FPA, 0) +I(FXTOD, "fxtod", 2, 1, 0, false, 0, 3, SPARC_FPA, 0) +I(FXTOQ, "fxtoq", 2, 1, 0, false, 0, 0, SPARC_FPA, 0) +I(FITOS, "fitos", 2, 1, 0, false, 0, 3, SPARC_FPA, 0) +I(FITOD, "fitod", 2, 1, 0, false, 0, 3, SPARC_FPA, 0) +I(FITOQ, "fitoq", 2, 1, 0, false, 0, 0, SPARC_FPA, 0) // Branch on integer comparison with zero. // Latency excludes the delay slot since it can be issued in same cycle. -I(BRZ , "brz", 2, -1, B15, true , 1, 1, SPARC_CTI, M_INT_FLAG | M_BRANCH_FLAG) -I(BRLEZ, "brlez", 2, -1, B15, true , 1, 1, SPARC_CTI, M_INT_FLAG | M_BRANCH_FLAG) -I(BRLZ , "brlz", 2, -1, B15, true , 1, 1, SPARC_CTI, M_INT_FLAG | M_BRANCH_FLAG) -I(BRNZ , "brnz", 2, -1, B15, true , 1, 1, SPARC_CTI, M_INT_FLAG | M_BRANCH_FLAG) -I(BRGZ , "brgz", 2, -1, B15, true , 1, 1, SPARC_CTI, M_INT_FLAG | M_BRANCH_FLAG) -I(BRGEZ, "brgez", 2, -1, B15, true , 1, 1, SPARC_CTI, M_INT_FLAG | M_BRANCH_FLAG) +I(BRZ , "brz", 2, -1, B15, true , 1, 1, SPARC_CTI, M_BRANCH_FLAG) +I(BRLEZ, "brlez", 2, -1, B15, true , 1, 1, SPARC_CTI, M_BRANCH_FLAG) +I(BRLZ , "brlz", 2, -1, B15, true , 1, 1, SPARC_CTI, M_BRANCH_FLAG) +I(BRNZ , "brnz", 2, -1, B15, true , 1, 1, SPARC_CTI, M_BRANCH_FLAG) +I(BRGZ , "brgz", 2, -1, B15, true , 1, 1, SPARC_CTI, M_BRANCH_FLAG) +I(BRGEZ, "brgez", 2, -1, B15, true , 1, 1, SPARC_CTI, M_BRANCH_FLAG) // Branch on integer condition code. // The first argument specifies the ICC register: %icc or %xcc @@ -242,219 +242,219 @@ I(FBO , "fbo", 2, -1, B18, true , 1, 2, SPARC_CTI, M_CC_FLAG | M_BRANCH_FLAG) // Conditional move on integer comparison with zero. -I(MOVRZr , "movrz", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CONDL_FLAG | M_INT_FLAG) -I(MOVRZi , "movrz", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CONDL_FLAG | M_INT_FLAG) -I(MOVRLEZr, "movrlez", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CONDL_FLAG | M_INT_FLAG) -I(MOVRLEZi, "movrlez", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CONDL_FLAG | M_INT_FLAG) -I(MOVRLZr , "movrlz", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CONDL_FLAG | M_INT_FLAG) -I(MOVRLZi , "movrlz", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CONDL_FLAG | M_INT_FLAG) -I(MOVRNZr , "movrnz", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CONDL_FLAG | M_INT_FLAG) -I(MOVRNZi , "movrnz", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CONDL_FLAG | M_INT_FLAG) -I(MOVRGZr , "movrgz", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CONDL_FLAG | M_INT_FLAG) -I(MOVRGZi , "movrgz", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CONDL_FLAG | M_INT_FLAG) -I(MOVRGEZr, "movrgez", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CONDL_FLAG | M_INT_FLAG) -I(MOVRGEZi, "movrgez", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CONDL_FLAG | M_INT_FLAG) +I(MOVRZr , "movrz", 3, 2, B12, true , 0, 2, SPARC_SINGLE, 0) +I(MOVRZi , "movrz", 3, 2, B12, true , 0, 2, SPARC_SINGLE, 0) +I(MOVRLEZr, "movrlez", 3, 2, B12, true , 0, 2, SPARC_SINGLE, 0) +I(MOVRLEZi, "movrlez", 3, 2, B12, true , 0, 2, SPARC_SINGLE, 0) +I(MOVRLZr , "movrlz", 3, 2, B12, true , 0, 2, SPARC_SINGLE, 0) +I(MOVRLZi , "movrlz", 3, 2, B12, true , 0, 2, SPARC_SINGLE, 0) +I(MOVRNZr , "movrnz", 3, 2, B12, true , 0, 2, SPARC_SINGLE, 0) +I(MOVRNZi , "movrnz", 3, 2, B12, true , 0, 2, SPARC_SINGLE, 0) +I(MOVRGZr , "movrgz", 3, 2, B12, true , 0, 2, SPARC_SINGLE, 0) +I(MOVRGZi , "movrgz", 3, 2, B12, true , 0, 2, SPARC_SINGLE, 0) +I(MOVRGEZr, "movrgez", 3, 2, B12, true , 0, 2, SPARC_SINGLE, 0) +I(MOVRGEZi, "movrgez", 3, 2, B12, true , 0, 2, SPARC_SINGLE, 0) // Conditional move on integer condition code. // The first argument specifies the ICC register: %icc or %xcc -I(MOVAr , "mova", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVAi , "mova", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVNr , "movn", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVNi , "movn", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVNEr , "movne", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVNEi , "movne", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVEr , "move", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVEi , "move", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVGr , "movg", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVGi , "movg", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVLEr , "movle", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVLEi , "movle", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVGEr , "movge", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVGEi , "movge", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVLr , "movl", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVLi , "movl", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVGUr , "movgu", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVGUi , "movgu", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVLEUr, "movleu", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVLEUi, "movleu", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVCCr , "movcc", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVCCi , "movcc", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVCSr , "movcs", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVCSi , "movcs", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVPOSr, "movpos", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVPOSi, "movpos", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVNEGr, "movneg", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVNEGi, "movneg", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVVCr , "movvc", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVVCi , "movvc", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVVSr , "movvs", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVVSi , "movvs", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) +I(MOVAr , "mova", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(MOVAi , "mova", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(MOVNr , "movn", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(MOVNi , "movn", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(MOVNEr , "movne", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(MOVNEi , "movne", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(MOVEr , "move", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(MOVEi , "move", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(MOVGr , "movg", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(MOVGi , "movg", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(MOVLEr , "movle", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(MOVLEi , "movle", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(MOVGEr , "movge", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(MOVGEi , "movge", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(MOVLr , "movl", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(MOVLi , "movl", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(MOVGUr , "movgu", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(MOVGUi , "movgu", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(MOVLEUr, "movleu", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(MOVLEUi, "movleu", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(MOVCCr , "movcc", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(MOVCCi , "movcc", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(MOVCSr , "movcs", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(MOVCSi , "movcs", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(MOVPOSr, "movpos", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(MOVPOSi, "movpos", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(MOVNEGr, "movneg", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(MOVNEGi, "movneg", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(MOVVCr , "movvc", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(MOVVCi , "movvc", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(MOVVSr , "movvs", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(MOVVSi , "movvs", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) // Conditional move (of integer register) on floating point condition code. // The first argument is the FCCn register (0 <= n <= 3). // Note that the enum name above is not the same as the assembly mnemonic // because some of the assembly mnemonics are the same as the move on // integer CC (e.g., MOVG), and we cannot have the same enum entry twice. -I(MOVFAr , "mova", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVFAi , "mova", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVFNr , "movn", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVFNi , "movn", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVFUr , "movu", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVFUi , "movu", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVFGr , "movg", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVFGi , "movg", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVFUGr , "movug", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVFUGi , "movug", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVFLr , "movl", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVFLi , "movl", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVFULr , "movul", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVFULi , "movul", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVFLGr , "movlg", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVFLGi , "movlg", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVFNEr , "movne", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVFNEi , "movne", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVFEr , "move", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVFEi , "move", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVFUEr , "movue", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVFUEi , "movue", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVFGEr , "movge", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVFGEi , "movge", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVFUGEr, "movuge", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVFUGEi, "movuge", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVFLEr , "movle", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVFLEi , "movle", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVFULEr, "movule", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVFULEi, "movule", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVFOr , "movo", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVFOi , "movo", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) +I(MOVFAr , "mova", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(MOVFAi , "mova", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(MOVFNr , "movn", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(MOVFNi , "movn", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(MOVFUr , "movu", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(MOVFUi , "movu", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(MOVFGr , "movg", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(MOVFGi , "movg", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(MOVFUGr , "movug", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(MOVFUGi , "movug", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(MOVFLr , "movl", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(MOVFLi , "movl", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(MOVFULr , "movul", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(MOVFULi , "movul", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(MOVFLGr , "movlg", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(MOVFLGi , "movlg", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(MOVFNEr , "movne", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(MOVFNEi , "movne", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(MOVFEr , "move", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(MOVFEi , "move", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(MOVFUEr , "movue", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(MOVFUEi , "movue", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(MOVFGEr , "movge", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(MOVFGEi , "movge", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(MOVFUGEr, "movuge", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(MOVFUGEi, "movuge", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(MOVFLEr , "movle", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(MOVFLEi , "movle", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(MOVFULEr, "movule", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(MOVFULEi, "movule", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(MOVFOr , "movo", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(MOVFOi , "movo", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) // Conditional move of floating point register on each of the above: // i. on integer comparison with zero. // ii. on integer condition code // iii. on floating point condition code // Note that the same set is repeated for S,D,Q register classes. -I(FMOVRSZ ,"fmovrsz", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CONDL_FLAG | M_FLOAT_FLAG | M_INT_FLAG) -I(FMOVRSLEZ,"fmovrslez",3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CONDL_FLAG | M_FLOAT_FLAG | M_INT_FLAG) -I(FMOVRSLZ ,"fmovrslz", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CONDL_FLAG | M_FLOAT_FLAG | M_INT_FLAG) -I(FMOVRSNZ ,"fmovrsnz", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CONDL_FLAG | M_FLOAT_FLAG | M_INT_FLAG) -I(FMOVRSGZ ,"fmovrsgz", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CONDL_FLAG | M_FLOAT_FLAG | M_INT_FLAG) -I(FMOVRSGEZ,"fmovrsgez",3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CONDL_FLAG | M_FLOAT_FLAG | M_INT_FLAG) - -I(FMOVSA , "fmovsa", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVSN , "fmovsn", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVSNE , "fmovsne", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVSE , "fmovse", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVSG , "fmovsg", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVSLE , "fmovsle", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVSGE , "fmovsge", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVSL , "fmovsl", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVSGU , "fmovsgu", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVSLEU, "fmovsleu", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVSCC , "fmovscc", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVSCS , "fmovscs", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVSPOS, "fmovspos", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVSNEG, "fmovsneg", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVSVC , "fmovsvc", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVSVS , "fmovsvs", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) - -I(FMOVSFA , "fmovsa", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVSFN , "fmovsn", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVSFU , "fmovsu", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVSFG , "fmovsg", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVSFUG , "fmovsug", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVSFL , "fmovsl", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVSFUL , "fmovsul", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVSFLG , "fmovslg", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVSFNE , "fmovsne", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVSFE , "fmovse", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVSFUE , "fmovsue", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVSFGE , "fmovsge", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVSFUGE, "fmovsuge",3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVSFLE , "fmovsle", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVSFULE, "fmovslue",3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVSFO , "fmovso", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) - -I(FMOVRDZ , "fmovrdz", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CONDL_FLAG | M_FLOAT_FLAG | M_INT_FLAG) -I(FMOVRDLEZ, "fmovrdlez",3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CONDL_FLAG | M_FLOAT_FLAG | M_INT_FLAG) -I(FMOVRDLZ , "fmovrdlz",3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CONDL_FLAG | M_FLOAT_FLAG | M_INT_FLAG) -I(FMOVRDNZ , "fmovrdnz",3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CONDL_FLAG | M_FLOAT_FLAG | M_INT_FLAG) -I(FMOVRDGZ , "fmovrdgz",3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CONDL_FLAG | M_FLOAT_FLAG | M_INT_FLAG) -I(FMOVRDGEZ, "fmovrdgez",3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CONDL_FLAG | M_FLOAT_FLAG | M_INT_FLAG) - -I(FMOVDA , "fmovda", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVDN , "fmovdn", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVDNE , "fmovdne", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVDE , "fmovde", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVDG , "fmovdg", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVDLE , "fmovdle", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVDGE , "fmovdge", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVDL , "fmovdl", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVDGU , "fmovdgu", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVDLEU, "fmovdleu", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVDCC , "fmovdcc", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVDCS , "fmovdcs", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVDPOS, "fmovdpos", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVDNEG, "fmovdneg", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVDVC , "fmovdvc", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVDVS , "fmovdvs", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) - -I(FMOVDFA , "fmovda", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVDFN , "fmovdn", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVDFU , "fmovdu", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVDFG , "fmovdg", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVDFUG , "fmovdug", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVDFL , "fmovdl", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVDFUL , "fmovdul", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVDFLG , "fmovdlg", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVDFNE , "fmovdne", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVDFE , "fmovde", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVDFUE , "fmovdue", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVDFGE , "fmovdge", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVDFUGE, "fmovduge",3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVDFLE , "fmovdle", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVDFULE, "fmovdule",3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVDFO , "fmovdo", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) - -I(FMOVRQZ , "fmovrqz", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CONDL_FLAG | M_FLOAT_FLAG | M_INT_FLAG) -I(FMOVRQLEZ, "fmovrqlez",3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CONDL_FLAG | M_FLOAT_FLAG | M_INT_FLAG) -I(FMOVRQLZ , "fmovrqlz",3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CONDL_FLAG | M_FLOAT_FLAG | M_INT_FLAG) -I(FMOVRQNZ , "fmovrqnz",3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CONDL_FLAG | M_FLOAT_FLAG | M_INT_FLAG) -I(FMOVRQGZ , "fmovrqgz",3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CONDL_FLAG | M_FLOAT_FLAG | M_INT_FLAG) -I(FMOVRQGEZ, "fmovrqgez",3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CONDL_FLAG | M_FLOAT_FLAG | M_INT_FLAG) - -I(FMOVQA , "fmovqa", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVQN , "fmovqn", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVQNE , "fmovqne", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVQE , "fmovqe", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVQG , "fmovqg", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVQLE , "fmovqle", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVQGE , "fmovqge", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVQL , "fmovql", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVQGU , "fmovqgu", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVQLEU, "fmovqleu", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVQCC , "fmovqcc", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVQCS , "fmovqcs", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVQPOS, "fmovqpos", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVQNEG, "fmovqneg", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVQVC , "fmovqvc", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVQVS , "fmovqvs", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) - -I(FMOVQFA , "fmovqa", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVQFN , "fmovqn", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVQFU , "fmovqu", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVQFG , "fmovqg", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVQFUG , "fmovqug", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVQFL , "fmovql", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVQFUL , "fmovqul", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVQFLG , "fmovqlg", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVQFNE , "fmovqne", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVQFE , "fmovqe", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVQFUE , "fmovque", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVQFGE , "fmovqge", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVQFUGE, "fmovquge",3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVQFLE , "fmovqle", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVQFULE, "fmovqule",3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVQFO , "fmovqo", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) +I(FMOVRSZ ,"fmovrsz", 3, 2, 0, false, 0, 2, SPARC_SINGLE, 0) +I(FMOVRSLEZ,"fmovrslez",3, 2, 0, false, 0, 2, SPARC_SINGLE, 0) +I(FMOVRSLZ ,"fmovrslz", 3, 2, 0, false, 0, 2, SPARC_SINGLE, 0) +I(FMOVRSNZ ,"fmovrsnz", 3, 2, 0, false, 0, 2, SPARC_SINGLE, 0) +I(FMOVRSGZ ,"fmovrsgz", 3, 2, 0, false, 0, 2, SPARC_SINGLE, 0) +I(FMOVRSGEZ,"fmovrsgez",3, 2, 0, false, 0, 2, SPARC_SINGLE, 0) + +I(FMOVSA , "fmovsa", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVSN , "fmovsn", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVSNE , "fmovsne", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVSE , "fmovse", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVSG , "fmovsg", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVSLE , "fmovsle", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVSGE , "fmovsge", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVSL , "fmovsl", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVSGU , "fmovsgu", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVSLEU, "fmovsleu", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVSCC , "fmovscc", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVSCS , "fmovscs", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVSPOS, "fmovspos", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVSNEG, "fmovsneg", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVSVC , "fmovsvc", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVSVS , "fmovsvs", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) + +I(FMOVSFA , "fmovsa", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVSFN , "fmovsn", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVSFU , "fmovsu", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVSFG , "fmovsg", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVSFUG , "fmovsug", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVSFL , "fmovsl", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVSFUL , "fmovsul", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVSFLG , "fmovslg", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVSFNE , "fmovsne", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVSFE , "fmovse", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVSFUE , "fmovsue", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVSFGE , "fmovsge", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVSFUGE, "fmovsuge",3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVSFLE , "fmovsle", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVSFULE, "fmovslue",3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVSFO , "fmovso", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) + +I(FMOVRDZ , "fmovrdz", 3, 2, 0, false, 0, 2, SPARC_SINGLE, 0) +I(FMOVRDLEZ, "fmovrdlez",3, 2, 0, false, 0, 2, SPARC_SINGLE, 0) +I(FMOVRDLZ , "fmovrdlz",3, 2, 0, false, 0, 2, SPARC_SINGLE, 0) +I(FMOVRDNZ , "fmovrdnz",3, 2, 0, false, 0, 2, SPARC_SINGLE, 0) +I(FMOVRDGZ , "fmovrdgz",3, 2, 0, false, 0, 2, SPARC_SINGLE, 0) +I(FMOVRDGEZ, "fmovrdgez",3, 2, 0, false, 0, 2, SPARC_SINGLE, 0) + +I(FMOVDA , "fmovda", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVDN , "fmovdn", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVDNE , "fmovdne", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVDE , "fmovde", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVDG , "fmovdg", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVDLE , "fmovdle", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVDGE , "fmovdge", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVDL , "fmovdl", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVDGU , "fmovdgu", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVDLEU, "fmovdleu", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVDCC , "fmovdcc", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVDCS , "fmovdcs", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVDPOS, "fmovdpos", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVDNEG, "fmovdneg", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVDVC , "fmovdvc", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVDVS , "fmovdvs", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) + +I(FMOVDFA , "fmovda", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVDFN , "fmovdn", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVDFU , "fmovdu", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVDFG , "fmovdg", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVDFUG , "fmovdug", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVDFL , "fmovdl", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVDFUL , "fmovdul", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVDFLG , "fmovdlg", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVDFNE , "fmovdne", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVDFE , "fmovde", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVDFUE , "fmovdue", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVDFGE , "fmovdge", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVDFUGE, "fmovduge",3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVDFLE , "fmovdle", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVDFULE, "fmovdule",3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVDFO , "fmovdo", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) + +I(FMOVRQZ , "fmovrqz", 3, 2, 0, false, 0, 2, SPARC_SINGLE, 0) +I(FMOVRQLEZ, "fmovrqlez",3, 2, 0, false, 0, 2, SPARC_SINGLE, 0) +I(FMOVRQLZ , "fmovrqlz",3, 2, 0, false, 0, 2, SPARC_SINGLE, 0) +I(FMOVRQNZ , "fmovrqnz",3, 2, 0, false, 0, 2, SPARC_SINGLE, 0) +I(FMOVRQGZ , "fmovrqgz",3, 2, 0, false, 0, 2, SPARC_SINGLE, 0) +I(FMOVRQGEZ, "fmovrqgez",3, 2, 0, false, 0, 2, SPARC_SINGLE, 0) + +I(FMOVQA , "fmovqa", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVQN , "fmovqn", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVQNE , "fmovqne", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVQE , "fmovqe", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVQG , "fmovqg", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVQLE , "fmovqle", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVQGE , "fmovqge", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVQL , "fmovql", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVQGU , "fmovqgu", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVQLEU, "fmovqleu", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVQCC , "fmovqcc", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVQCS , "fmovqcs", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVQPOS, "fmovqpos", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVQNEG, "fmovqneg", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVQVC , "fmovqvc", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVQVS , "fmovqvs", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) + +I(FMOVQFA , "fmovqa", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVQFN , "fmovqn", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVQFU , "fmovqu", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVQFG , "fmovqg", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVQFUG , "fmovqug", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVQFL , "fmovql", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVQFUL , "fmovqul", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVQFLG , "fmovqlg", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVQFNE , "fmovqne", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVQFE , "fmovqe", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVQFUE , "fmovque", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVQFGE , "fmovqge", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVQFUGE, "fmovquge",3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVQFLE , "fmovqle", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVQFULE, "fmovqule",3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) +I(FMOVQFO , "fmovqo", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG) // Load integer instructions // Latency includes 1 cycle for address generation (Sparc IIi), @@ -464,55 +464,55 @@ // Not reflected here: After a 3-cycle loads, all subsequent consecutive // loads also require 3 cycles to avoid contention for the load return // stage. Latency returns to 2 cycles after the first cycle with no load. -I(LDSBr, "ldsb", 3, 2, B12, true , 0, 6, SPARC_LD, M_INT_FLAG | M_LOAD_FLAG) -I(LDSBi, "ldsb", 3, 2, B12, true , 0, 6, SPARC_LD, M_INT_FLAG | M_LOAD_FLAG) -I(LDSHr, "ldsh", 3, 2, B12, true , 0, 6, SPARC_LD, M_INT_FLAG | M_LOAD_FLAG) -I(LDSHi, "ldsh", 3, 2, B12, true , 0, 6, SPARC_LD, M_INT_FLAG | M_LOAD_FLAG) -I(LDSWr, "ldsw", 3, 2, B12, true , 0, 6, SPARC_LD, M_INT_FLAG | M_LOAD_FLAG) -I(LDSWi, "ldsw", 3, 2, B12, true , 0, 6, SPARC_LD, M_INT_FLAG | M_LOAD_FLAG) -I(LDUBr, "ldub", 3, 2, B12, true , 0, 5, SPARC_LD, M_INT_FLAG | M_LOAD_FLAG) -I(LDUBi, "ldub", 3, 2, B12, true , 0, 5, SPARC_LD, M_INT_FLAG | M_LOAD_FLAG) -I(LDUHr, "lduh", 3, 2, B12, true , 0, 5, SPARC_LD, M_INT_FLAG | M_LOAD_FLAG) -I(LDUHi, "lduh", 3, 2, B12, true , 0, 5, SPARC_LD, M_INT_FLAG | M_LOAD_FLAG) -I(LDUWr, "lduw", 3, 2, B12, true , 0, 5, SPARC_LD, M_INT_FLAG | M_LOAD_FLAG) -I(LDUWi, "lduw", 3, 2, B12, true , 0, 5, SPARC_LD, M_INT_FLAG | M_LOAD_FLAG) -I(LDXr , "ldx" , 3, 2, B12, true , 0, 5, SPARC_LD, M_INT_FLAG | M_LOAD_FLAG) -I(LDXi , "ldx" , 3, 2, B12, true , 0, 5, SPARC_LD, M_INT_FLAG | M_LOAD_FLAG) +I(LDSBr, "ldsb", 3, 2, B12, true , 0, 6, SPARC_LD, M_LOAD_FLAG) +I(LDSBi, "ldsb", 3, 2, B12, true , 0, 6, SPARC_LD, M_LOAD_FLAG) +I(LDSHr, "ldsh", 3, 2, B12, true , 0, 6, SPARC_LD, M_LOAD_FLAG) +I(LDSHi, "ldsh", 3, 2, B12, true , 0, 6, SPARC_LD, M_LOAD_FLAG) +I(LDSWr, "ldsw", 3, 2, B12, true , 0, 6, SPARC_LD, M_LOAD_FLAG) +I(LDSWi, "ldsw", 3, 2, B12, true , 0, 6, SPARC_LD, M_LOAD_FLAG) +I(LDUBr, "ldub", 3, 2, B12, true , 0, 5, SPARC_LD, M_LOAD_FLAG) +I(LDUBi, "ldub", 3, 2, B12, true , 0, 5, SPARC_LD, M_LOAD_FLAG) +I(LDUHr, "lduh", 3, 2, B12, true , 0, 5, SPARC_LD, M_LOAD_FLAG) +I(LDUHi, "lduh", 3, 2, B12, true , 0, 5, SPARC_LD, M_LOAD_FLAG) +I(LDUWr, "lduw", 3, 2, B12, true , 0, 5, SPARC_LD, M_LOAD_FLAG) +I(LDUWi, "lduw", 3, 2, B12, true , 0, 5, SPARC_LD, M_LOAD_FLAG) +I(LDXr , "ldx" , 3, 2, B12, true , 0, 5, SPARC_LD, M_LOAD_FLAG) +I(LDXi , "ldx" , 3, 2, B12, true , 0, 5, SPARC_LD, M_LOAD_FLAG) // Load floating-point instructions // Latency includes 1 cycle for address generation (Sparc IIi) -I(LDFr , "ld", 3, 2, B12, true , 0, 5, SPARC_LD, M_FLOAT_FLAG | M_LOAD_FLAG) -I(LDFi , "ld", 3, 2, B12, true , 0, 5, SPARC_LD, M_FLOAT_FLAG | M_LOAD_FLAG) -I(LDDFr, "ldd", 3, 2, B12, true , 0, 5, SPARC_LD, M_FLOAT_FLAG | M_LOAD_FLAG) -I(LDDFi, "ldd", 3, 2, B12, true , 0, 5, SPARC_LD, M_FLOAT_FLAG | M_LOAD_FLAG) -I(LDQFr, "ldq", 3, 2, B12, true , 0, 5, SPARC_LD, M_FLOAT_FLAG | M_LOAD_FLAG) -I(LDQFi, "ldq", 3, 2, B12, true , 0, 5, SPARC_LD, M_FLOAT_FLAG | M_LOAD_FLAG) -I(LDFSRr, "ld", 3, 2, B12, true , 0, 5, SPARC_LD, M_FLOAT_FLAG | M_LOAD_FLAG) -I(LDFSRi, "ld", 3, 2, B12, true , 0, 5, SPARC_LD, M_FLOAT_FLAG | M_LOAD_FLAG) -I(LDXFSRr, "ldx", 3, 2, B12, true , 0, 5, SPARC_LD, M_FLOAT_FLAG | M_LOAD_FLAG) -I(LDXFSRi, "ldx", 3, 2, B12, true , 0, 5, SPARC_LD, M_FLOAT_FLAG | M_LOAD_FLAG) +I(LDFr , "ld", 3, 2, B12, true , 0, 5, SPARC_LD, M_LOAD_FLAG) +I(LDFi , "ld", 3, 2, B12, true , 0, 5, SPARC_LD, M_LOAD_FLAG) +I(LDDFr, "ldd", 3, 2, B12, true , 0, 5, SPARC_LD, M_LOAD_FLAG) +I(LDDFi, "ldd", 3, 2, B12, true , 0, 5, SPARC_LD, M_LOAD_FLAG) +I(LDQFr, "ldq", 3, 2, B12, true , 0, 5, SPARC_LD, M_LOAD_FLAG) +I(LDQFi, "ldq", 3, 2, B12, true , 0, 5, SPARC_LD, M_LOAD_FLAG) +I(LDFSRr, "ld", 3, 2, B12, true , 0, 5, SPARC_LD, M_LOAD_FLAG) +I(LDFSRi, "ld", 3, 2, B12, true , 0, 5, SPARC_LD, M_LOAD_FLAG) +I(LDXFSRr, "ldx", 3, 2, B12, true , 0, 5, SPARC_LD, M_LOAD_FLAG) +I(LDXFSRi, "ldx", 3, 2, B12, true , 0, 5, SPARC_LD, M_LOAD_FLAG) // Store integer instructions. // Requires 1 cycle for address generation (Sparc IIi). // Default latency is 0 because value is not explicitly used. -I(STBr, "stb", 3, -1, B12, true , 0, 0, SPARC_ST, M_INT_FLAG | M_STORE_FLAG) -I(STBi, "stb", 3, -1, B12, true , 0, 0, SPARC_ST, M_INT_FLAG | M_STORE_FLAG) -I(STHr, "sth", 3, -1, B12, true , 0, 0, SPARC_ST, M_INT_FLAG | M_STORE_FLAG) -I(STHi, "sth", 3, -1, B12, true , 0, 0, SPARC_ST, M_INT_FLAG | M_STORE_FLAG) -I(STWr, "stw", 3, -1, B12, true , 0, 0, SPARC_ST, M_INT_FLAG | M_STORE_FLAG) -I(STWi, "stw", 3, -1, B12, true , 0, 0, SPARC_ST, M_INT_FLAG | M_STORE_FLAG) -I(STXr, "stx", 3, -1, B12, true , 0, 0, SPARC_ST, M_INT_FLAG | M_STORE_FLAG) -I(STXi, "stx", 3, -1, B12, true , 0, 0, SPARC_ST, M_INT_FLAG | M_STORE_FLAG) +I(STBr, "stb", 3, -1, B12, true , 0, 0, SPARC_ST, M_STORE_FLAG) +I(STBi, "stb", 3, -1, B12, true , 0, 0, SPARC_ST, M_STORE_FLAG) +I(STHr, "sth", 3, -1, B12, true , 0, 0, SPARC_ST, M_STORE_FLAG) +I(STHi, "sth", 3, -1, B12, true , 0, 0, SPARC_ST, M_STORE_FLAG) +I(STWr, "stw", 3, -1, B12, true , 0, 0, SPARC_ST, M_STORE_FLAG) +I(STWi, "stw", 3, -1, B12, true , 0, 0, SPARC_ST, M_STORE_FLAG) +I(STXr, "stx", 3, -1, B12, true , 0, 0, SPARC_ST, M_STORE_FLAG) +I(STXi, "stx", 3, -1, B12, true , 0, 0, SPARC_ST, M_STORE_FLAG) // Store floating-point instructions (Sparc IIi) -I(STFr, "st", 3, -1, B12, true , 0, 0, SPARC_ST, M_FLOAT_FLAG | M_STORE_FLAG) -I(STFi, "st", 3, -1, B12, true , 0, 0, SPARC_ST, M_FLOAT_FLAG | M_STORE_FLAG) -I(STDFr, "std", 3, -1, B12, true , 0, 0, SPARC_ST, M_FLOAT_FLAG | M_STORE_FLAG) -I(STDFi, "std", 3, -1, B12, true , 0, 0, SPARC_ST, M_FLOAT_FLAG | M_STORE_FLAG) -I(STFSRr, "st", 3, -1, B12, true , 0, 0, SPARC_ST, M_FLOAT_FLAG | M_STORE_FLAG) -I(STFSRi, "st", 3, -1, B12, true , 0, 0, SPARC_ST, M_FLOAT_FLAG | M_STORE_FLAG) -I(STXFSRr, "stx", 3, -1, B12, true , 0, 0, SPARC_ST, M_FLOAT_FLAG | M_STORE_FLAG) -I(STXFSRi, "stx", 3, -1, B12, true , 0, 0, SPARC_ST, M_FLOAT_FLAG | M_STORE_FLAG) +I(STFr, "st", 3, -1, B12, true , 0, 0, SPARC_ST, M_STORE_FLAG) +I(STFi, "st", 3, -1, B12, true , 0, 0, SPARC_ST, M_STORE_FLAG) +I(STDFr, "std", 3, -1, B12, true , 0, 0, SPARC_ST, M_STORE_FLAG) +I(STDFi, "std", 3, -1, B12, true , 0, 0, SPARC_ST, M_STORE_FLAG) +I(STFSRr, "st", 3, -1, B12, true , 0, 0, SPARC_ST, M_STORE_FLAG) +I(STFSRi, "st", 3, -1, B12, true , 0, 0, SPARC_ST, M_STORE_FLAG) +I(STXFSRr, "stx", 3, -1, B12, true , 0, 0, SPARC_ST, M_STORE_FLAG) +I(STXFSRi, "stx", 3, -1, B12, true , 0, 0, SPARC_ST, M_STORE_FLAG) // Call, Return and "Jump and link". Operand (2) for JMPL is marked as // a "result" because JMPL stores the return address for the call in it. @@ -526,19 +526,19 @@ I(RETURNi, "return", 2, -1, 0, false, 1, 2, SPARC_CTI, M_RET_FLAG) // SAVE and restore instructions -I(SAVEr, "save", 3, 2, B12, true , 0, 1, SPARC_SINGLE, M_INT_FLAG | M_ARITH_FLAG) -I(SAVEi, "save", 3, 2, B12, true , 0, 1, SPARC_SINGLE, M_INT_FLAG | M_ARITH_FLAG) -I(RESTOREr, "restore", 3, 2, B12, true , 0, 1, SPARC_SINGLE, M_INT_FLAG | M_ARITH_FLAG) -I(RESTOREi, "restore", 3, 2, B12, true , 0, 1, SPARC_SINGLE, M_INT_FLAG | M_ARITH_FLAG) +I(SAVEr, "save", 3, 2, B12, true , 0, 1, SPARC_SINGLE, 0) +I(SAVEi, "save", 3, 2, B12, true , 0, 1, SPARC_SINGLE, 0) +I(RESTOREr, "restore", 3, 2, B12, true , 0, 1, SPARC_SINGLE, 0) +I(RESTOREi, "restore", 3, 2, B12, true , 0, 1, SPARC_SINGLE, 0) // Read and Write CCR register from/to an int reg -I(RDCCR, "rd", 2, 1, 0, false, 0, 1, SPARC_SINGLE, M_INT_FLAG | M_CC_FLAG) -I(WRCCRr, "wr", 3, 2, 0, false, 0, 1, SPARC_SINGLE, M_INT_FLAG | M_CC_FLAG) -I(WRCCRi, "wr", 3, 2, 0, false, 0, 1, SPARC_SINGLE, M_INT_FLAG | M_CC_FLAG) +I(RDCCR, "rd", 2, 1, 0, false, 0, 1, SPARC_SINGLE, M_CC_FLAG) +I(WRCCRr, "wr", 3, 2, 0, false, 0, 1, SPARC_SINGLE, M_CC_FLAG) +I(WRCCRi, "wr", 3, 2, 0, false, 0, 1, SPARC_SINGLE, M_CC_FLAG) // Synthetic phi operation for near-SSA form of machine code // Number of operands is variable, indicated by -1. Result is the first op. -I(PHI, "", -1, 0, 0, false, 0, 0, SPARC_INV, M_DUMMY_PHI_FLAG) +I(PHI, "", -1, 0, 0, false, 0, 0, SPARC_NONE, M_DUMMY_PHI_FLAG) #undef B5 Index: llvm/lib/Target/SparcV9/SparcV9InstrInfo.cpp diff -u llvm/lib/Target/SparcV9/SparcV9InstrInfo.cpp:1.59 llvm/lib/Target/SparcV9/SparcV9InstrInfo.cpp:1.59.2.1 --- llvm/lib/Target/SparcV9/SparcV9InstrInfo.cpp:1.59 Wed Dec 17 16:04:00 2003 +++ llvm/lib/Target/SparcV9/SparcV9InstrInfo.cpp Mon Mar 1 17:58:15 2004 @@ -1,4 +1,4 @@ -//===-- SparcInstrInfo.cpp ------------------------------------------------===// +//===-- SparcV9InstrInfo.cpp ------------------------------------------------===// // // The LLVM Compiler Infrastructure // @@ -20,9 +20,9 @@ #include "llvm/CodeGen/MachineFunctionInfo.h" #include "llvm/CodeGen/MachineCodeForInstruction.h" #include "llvm/CodeGen/MachineInstrBuilder.h" -#include "SparcInternals.h" -#include "SparcInstrSelectionSupport.h" -#include "SparcInstrInfo.h" +#include "SparcV9Internals.h" +#include "SparcV9InstrSelectionSupport.h" +#include "SparcV9InstrInfo.h" namespace llvm { @@ -42,7 +42,7 @@ //--------------------------------------------------------------------------- uint64_t -SparcInstrInfo::ConvertConstantToIntType(const TargetMachine &target, +SparcV9InstrInfo::ConvertConstantToIntType(const TargetMachine &target, const Value *V, const Type *destType, bool &isValidConstant) const @@ -386,7 +386,7 @@ default: break; }; - return (modelOpCode < 0)? 0: SparcMachineInstrDesc[modelOpCode].maxImmedConst; + return (modelOpCode < 0)? 0: SparcV9MachineInstrDesc[modelOpCode].maxImmedConst; } static void @@ -407,26 +407,22 @@ //--------------------------------------------------------------------------- -// class SparcInstrInfo +// class SparcV9InstrInfo // // Purpose: // Information about individual instructions. -// Most information is stored in the SparcMachineInstrDesc array above. +// Most information is stored in the SparcV9MachineInstrDesc array above. // Other information is computed on demand, and most such functions // default to member functions in base class TargetInstrInfo. //--------------------------------------------------------------------------- -/*ctor*/ -SparcInstrInfo::SparcInstrInfo() - : TargetInstrInfo(SparcMachineInstrDesc, - /*descSize = */ V9::NUM_TOTAL_OPCODES, - /*numRealOpCodes = */ V9::NUM_REAL_OPCODES) -{ +SparcV9InstrInfo::SparcV9InstrInfo() + : TargetInstrInfo(SparcV9MachineInstrDesc, V9::NUM_TOTAL_OPCODES) { InitializeMaxConstantsTable(); } bool -SparcInstrInfo::ConstantMayNotFitInImmedField(const Constant* CV, +SparcV9InstrInfo::ConstantMayNotFitInImmedField(const Constant* CV, const Instruction* I) const { if (I->getOpcode() >= MaxConstantsTable.size()) // user-defined op (or bug!) @@ -456,7 +452,7 @@ // Any stack space required is allocated via MachineFunction. // void -SparcInstrInfo::CreateCodeToLoadConst(const TargetMachine& target, +SparcV9InstrInfo::CreateCodeToLoadConst(const TargetMachine& target, Function* F, Value* val, Instruction* dest, @@ -553,7 +549,7 @@ // Any stack space required is allocated via MachineFunction. // void -SparcInstrInfo::CreateCodeToCopyIntToFloat(const TargetMachine& target, +SparcV9InstrInfo::CreateCodeToCopyIntToFloat(const TargetMachine& target, Function* F, Value* val, Instruction* dest, @@ -614,7 +610,7 @@ // Temporary stack space required is allocated via MachineFunction. // void -SparcInstrInfo::CreateCodeToCopyFloatToInt(const TargetMachine& target, +SparcV9InstrInfo::CreateCodeToCopyFloatToInt(const TargetMachine& target, Function* F, Value* val, Instruction* dest, @@ -665,7 +661,7 @@ // Any stack space required is allocated via MachineFunction. // void -SparcInstrInfo::CreateCopyInstructionsByType(const TargetMachine& target, +SparcV9InstrInfo::CreateCopyInstructionsByType(const TargetMachine& target, Function *F, Value* src, Instruction* dest, @@ -761,7 +757,7 @@ // Any stack space required is allocated via MachineFunction. // void -SparcInstrInfo::CreateSignExtensionInstructions( +SparcV9InstrInfo::CreateSignExtensionInstructions( const TargetMachine& target, Function* F, Value* srcVal, @@ -783,7 +779,7 @@ // Any stack space required is allocated via MachineFunction. // void -SparcInstrInfo::CreateZeroExtensionInstructions( +SparcV9InstrInfo::CreateZeroExtensionInstructions( const TargetMachine& target, Function* F, Value* srcVal, Index: llvm/lib/Target/SparcV9/SparcV9InstrInfo.h diff -u llvm/lib/Target/SparcV9/SparcV9InstrInfo.h:1.1 llvm/lib/Target/SparcV9/SparcV9InstrInfo.h:1.1.2.1 --- llvm/lib/Target/SparcV9/SparcV9InstrInfo.h:1.1 Wed Dec 17 16:04:00 2003 +++ llvm/lib/Target/SparcV9/SparcV9InstrInfo.h Mon Mar 1 17:58:15 2004 @@ -1,4 +1,4 @@ -//===-- SparcInstrInfo.h - Define TargetInstrInfo for Sparc -----*- C++ -*-===// +//===-- SparcV9InstrInfo.h - Define TargetInstrInfo for SparcV9 -----*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -8,7 +8,7 @@ //===----------------------------------------------------------------------===// // // This class contains information about individual instructions. -// Most information is stored in the SparcMachineInstrDesc array above. +// Most information is stored in the SparcV9MachineInstrDesc array above. // Other information is computed on demand, and most such functions // default to member functions in base class TargetInstrInfo. // @@ -19,12 +19,12 @@ #include "llvm/Target/TargetInstrInfo.h" #include "llvm/CodeGen/MachineInstr.h" -#include "SparcInternals.h" +#include "SparcV9Internals.h" namespace llvm { -struct SparcInstrInfo : public TargetInstrInfo { - SparcInstrInfo(); +struct SparcV9InstrInfo : public TargetInstrInfo { + SparcV9InstrInfo(); // All immediate constants are in position 1 except the // store instructions and SETxx. @@ -48,32 +48,6 @@ return -1; } - /// createNOPinstr - returns the target's implementation of NOP, which is - /// usually a pseudo-instruction, implemented by a degenerate version of - /// another instruction, e.g. X86: xchg ax, ax; SparcV9: sethi 0, g0 - /// - MachineInstr* createNOPinstr() const { - return BuildMI(V9::SETHI, 2).addZImm(0).addReg(SparcIntRegClass::g0); - } - - /// isNOPinstr - not having a special NOP opcode, we need to know if a given - /// instruction is interpreted as an `official' NOP instr, i.e., there may be - /// more than one way to `do nothing' but only one canonical way to slack off. - /// - bool isNOPinstr(const MachineInstr &MI) const { - // Make sure the instruction is EXACTLY `sethi g0, 0' - if (MI.getOpcode() == V9::SETHI && MI.getNumOperands() == 2) { - const MachineOperand &op0 = MI.getOperand(0), &op1 = MI.getOperand(1); - if (op0.isImmediate() && op0.getImmedValue() == 0 && - op1.isMachineRegister() && - op1.getMachineRegNum() == SparcIntRegClass::g0) - { - return true; - } - } - return false; - } - virtual bool hasResultInterlock(MachineOpCode opCode) const { // All UltraSPARC instructions have interlocks (note that delay slots Index: llvm/lib/Target/SparcV9/SparcV9InstrSelection.cpp diff -u llvm/lib/Target/SparcV9/SparcV9InstrSelection.cpp:1.130 llvm/lib/Target/SparcV9/SparcV9InstrSelection.cpp:1.130.2.1 --- llvm/lib/Target/SparcV9/SparcV9InstrSelection.cpp:1.130 Mon Jan 12 12:08:18 2004 +++ llvm/lib/Target/SparcV9/SparcV9InstrSelection.cpp Mon Mar 1 17:58:15 2004 @@ -1,4 +1,4 @@ -//===-- SparcInstrSelection.cpp -------------------------------------------===// +//===-- SparcV9InstrSelection.cpp -------------------------------------------===// // // The LLVM Compiler Infrastructure // @@ -23,11 +23,11 @@ #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineFunctionInfo.h" #include "llvm/CodeGen/MachineInstrBuilder.h" -#include "llvm/CodeGen/MachineInstrAnnot.h" -#include "SparcInstrSelectionSupport.h" -#include "SparcInternals.h" -#include "SparcRegClassInfo.h" -#include "SparcRegInfo.h" +#include "MachineInstrAnnot.h" +#include "SparcV9InstrSelectionSupport.h" +#include "SparcV9Internals.h" +#include "SparcV9RegClassInfo.h" +#include "SparcV9RegInfo.h" #include "Support/MathExtras.h" #include #include @@ -786,9 +786,9 @@ MachineInstr* M = (optArgVal2 != NULL) ? BuildMI(shiftOpCode, 3).addReg(argVal1).addReg(optArgVal2) - .addReg(shiftDest, MOTy::Def) + .addReg(shiftDest, MachineOperand::Def) : BuildMI(shiftOpCode, 3).addReg(argVal1).addZImm(optShiftNum) - .addReg(shiftDest, MOTy::Def); + .addReg(shiftDest, MachineOperand::Def); mvec.push_back(M); if (shiftDest != destVal) { @@ -874,7 +874,7 @@ if (firstNewInstr < mvec.size()) { cost = 0; for (unsigned i=firstNewInstr; i < mvec.size(); ++i) - cost += target.getInstrInfo().minLatency(mvec[i]->getOpCode()); + cost += target.getInstrInfo().minLatency(mvec[i]->getOpcode()); } return cost; @@ -915,7 +915,7 @@ Value* lval, Value* rval, Instruction* destVal, std::vector& mvec, MachineCodeForInstruction& mcfi, - MachineOpCode forceMulOp = INVALID_MACHINE_OPCODE) + MachineOpCode forceMulOp = -1) { unsigned L = mvec.size(); CreateCheapestMulConstInstruction(target,F, lval, rval, destVal, mvec, mcfi); @@ -923,7 +923,7 @@ // no instructions were added so create MUL reg, reg, reg. // Use FSMULD if both operands are actually floats cast to doubles. // Otherwise, use the default opcode for the appropriate type. - MachineOpCode mulOp = ((forceMulOp != INVALID_MACHINE_OPCODE) + MachineOpCode mulOp = ((forceMulOp != -1) ? forceMulOp : ChooseMulInstructionByType(destVal->getType())); mvec.push_back(BuildMI(mulOp, 3).addReg(lval).addReg(rval) @@ -1115,15 +1115,15 @@ // Instruction 1: mul numElements, typeSize -> tmpProd // This will optimize the MUL as far as possible. CreateMulInstruction(target, F, numElementsVal, tsizeVal, tmpProd, getMvec, - mcfi, INVALID_MACHINE_OPCODE); + mcfi, -1); // Instruction 2: andn tmpProd, 0x0f -> tmpAndn getMvec.push_back(BuildMI(V9::ADDi, 3).addReg(tmpProd).addSImm(15) - .addReg(tmpAdd15, MOTy::Def)); + .addReg(tmpAdd15, MachineOperand::Def)); // Instruction 3: add tmpAndn, 0x10 -> tmpAdd16 getMvec.push_back(BuildMI(V9::ANDi, 3).addReg(tmpAdd15).addSImm(-16) - .addReg(tmpAndf0, MOTy::Def)); + .addReg(tmpAndf0, MachineOperand::Def)); totalSizeVal = tmpAndf0; } @@ -1141,7 +1141,7 @@ // Instruction 2: sub %sp, totalSizeVal -> %sp getMvec.push_back(BuildMI(V9::SUBr, 3).addMReg(SPReg).addReg(totalSizeVal) - .addMReg(SPReg,MOTy::Def)); + .addMReg(SPReg,MachineOperand::Def)); // Instruction 3: add %sp, frameSizeBelowDynamicArea -> result getMvec.push_back(BuildMI(V9::ADDr,3).addMReg(SPReg).addReg(dynamicAreaOffset) @@ -1278,7 +1278,7 @@ eltSizeVal, /* rval, likely to be constant */ addr, /* result */ mulVec, MachineCodeForInstruction::get(memInst), - INVALID_MACHINE_OPCODE); + -1); assert(mulVec.size() > 0 && "No multiply code created?"); mvec.insert(mvec.end(), mulVec.begin(), mulVec.end()); @@ -1413,7 +1413,7 @@ } case Intrinsic::va_end: - return true; // no-op on Sparc + return true; // no-op on SparcV9 case Intrinsic::va_copy: // Simple copy of current va_list (arg1) to new va_list (result) @@ -1534,7 +1534,7 @@ MachineInstr* retMI = BuildMI(V9::JMPLRETi, 3).addReg(returnAddrTmp).addSImm(8) - .addMReg(target.getRegInfo().getZeroRegNum(), MOTy::Def); + .addMReg(target.getRegInfo().getZeroRegNum(), MachineOperand::Def); // If there is a value to return, we need to: // (a) Sign-extend the value if it is smaller than 8 bytes (reg size) @@ -1543,13 +1543,13 @@ // -- For non-FP values, create an add-with-0 instruction // if (retVal != NULL) { - const SparcRegInfo& regInfo = - (SparcRegInfo&) target.getRegInfo(); + const SparcV9RegInfo& regInfo = + (SparcV9RegInfo&) target.getRegInfo(); const Type* retType = retVal->getType(); unsigned regClassID = regInfo.getRegClassIDOfType(retType); unsigned retRegNum = (retType->isFloatingPoint() - ? (unsigned) SparcFloatRegClass::f0 - : (unsigned) SparcIntRegClass::i0); + ? (unsigned) SparcV9FloatRegClass::f0 + : (unsigned) SparcV9IntRegClass::i0); retRegNum = regInfo.getUnifiedRegNum(regClassID, retRegNum); // () Insert sign-extension instructions for small signed values. @@ -1581,11 +1581,11 @@ if (retType->isFloatingPoint()) M = (BuildMI(retType==Type::FloatTy? V9::FMOVS : V9::FMOVD, 2) - .addReg(retValToUse).addReg(retVReg, MOTy::Def)); + .addReg(retValToUse).addReg(retVReg, MachineOperand::Def)); else M = (BuildMI(ChooseAddInstructionByType(retType), 3) .addReg(retValToUse).addSImm((int64_t) 0) - .addReg(retVReg, MOTy::Def)); + .addReg(retVReg, MachineOperand::Def)); // Mark the operand with the register it should be assigned M->SetRegForOperand(M->getNumOperands()-1, retRegNum); @@ -1751,7 +1751,7 @@ // Mark the register as a use (as well as a def) because the old // value will be retained if the condition is false. mvec.push_back(BuildMI(V9::MOVRZi, 3).addReg(notArg).addZImm(1) - .addReg(notI, MOTy::UseAndDef)); + .addReg(notI, MachineOperand::UseAndDef)); break; } @@ -1786,7 +1786,7 @@ // value will be retained if the condition is false. MachineOpCode opCode = foldCase? V9::MOVRZi : V9::MOVRNZi; mvec.push_back(BuildMI(opCode, 3).addReg(opVal).addZImm(1) - .addReg(castI, MOTy::UseAndDef)); + .addReg(castI, MachineOperand::UseAndDef)); break; } @@ -1918,7 +1918,7 @@ const MachineCodeForInstruction& mcfi = MachineCodeForInstruction::get( cast(subtreeRoot->parent())->getInstruction()); - if (mcfi.size() == 0 || mcfi.front()->getOpCode() == V9::FSMULD) + if (mcfi.size() == 0 || mcfi.front()->getOpcode() == V9::FSMULD) forwardOperandNum = 0; // forward first operand to user } @@ -2006,8 +2006,8 @@ { maskUnsignedResult = true; MachineOpCode forceOp = ((checkCast && BothFloatToDouble(subtreeRoot)) - ? V9::FSMULD - : INVALID_MACHINE_OPCODE); + ? (MachineOpCode)V9::FSMULD + : -1); Instruction* mulInstr = subtreeRoot->getInstruction(); CreateMulInstruction(target, mulInstr->getParent()->getParent(), subtreeRoot->leftChild()->getValue(), @@ -2024,8 +2024,8 @@ { maskUnsignedResult = true; MachineOpCode forceOp = ((checkCast && BothFloatToDouble(subtreeRoot)) - ? V9::FSMULD - : INVALID_MACHINE_OPCODE); + ? (MachineOpCode)V9::FSMULD + : -1); Instruction* mulInstr = subtreeRoot->getInstruction(); CreateMulInstruction(target, mulInstr->getParent()->getParent(), subtreeRoot->leftChild()->getValue(), @@ -2149,12 +2149,12 @@ Value *lhs = subtreeRoot->leftChild()->getValue(); Value *dest = subtreeRoot->getValue(); mvec.push_back(BuildMI(V9::ANDNr, 3).addReg(lhs).addReg(notArg) - .addReg(dest, MOTy::Def)); + .addReg(dest, MachineOperand::Def)); if (notArg->getType() == Type::BoolTy) { // set 1 in result register if result of above is non-zero mvec.push_back(BuildMI(V9::MOVRNZi, 3).addReg(dest).addZImm(1) - .addReg(dest, MOTy::UseAndDef)); + .addReg(dest, MachineOperand::UseAndDef)); } break; @@ -2180,12 +2180,12 @@ Value *dest = subtreeRoot->getValue(); mvec.push_back(BuildMI(V9::ORNr, 3).addReg(lhs).addReg(notArg) - .addReg(dest, MOTy::Def)); + .addReg(dest, MachineOperand::Def)); if (notArg->getType() == Type::BoolTy) { // set 1 in result register if result of above is non-zero mvec.push_back(BuildMI(V9::MOVRNZi, 3).addReg(dest).addZImm(1) - .addReg(dest, MOTy::UseAndDef)); + .addReg(dest, MachineOperand::UseAndDef)); } break; @@ -2210,12 +2210,12 @@ Value *lhs = subtreeRoot->leftChild()->getValue(); Value *dest = subtreeRoot->getValue(); mvec.push_back(BuildMI(V9::XNORr, 3).addReg(lhs).addReg(notArg) - .addReg(dest, MOTy::Def)); + .addReg(dest, MachineOperand::Def)); if (notArg->getType() == Type::BoolTy) { // set 1 in result register if result of above is non-zero mvec.push_back(BuildMI(V9::MOVRNZi, 3).addReg(dest).addZImm(1) - .addReg(dest, MOTy::UseAndDef)); + .addReg(dest, MachineOperand::UseAndDef)); } break; } @@ -2262,7 +2262,8 @@ MachineOpCode movOpCode = ChooseMovpregiForSetCC(subtreeRoot); mvec.push_back(BuildMI(movOpCode, 3) .addReg(subtreeRoot->leftChild()->getValue()) - .addZImm(1).addReg(setCCInstr, MOTy::UseAndDef)); + .addZImm(1) + .addReg(setCCInstr, MachineOperand::UseAndDef)); break; } @@ -2336,12 +2337,13 @@ mvec.push_back(BuildMI(V9::SUBccr, 4) .addReg(leftOpToUse) .addReg(rightOpToUse) - .addMReg(target.getRegInfo().getZeroRegNum(),MOTy::Def) - .addCCReg(tmpForCC, MOTy::Def)); + .addMReg(target.getRegInfo() + .getZeroRegNum(), MachineOperand::Def) + .addCCReg(tmpForCC, MachineOperand::Def)); } else { // FP condition: dest of FCMP should be some FCCn register mvec.push_back(BuildMI(ChooseFcmpInstruction(subtreeRoot), 3) - .addCCReg(tmpForCC, MOTy::Def) + .addCCReg(tmpForCC, MachineOperand::Def) .addReg(leftOpToUse) .addReg(rightOpToUse)); } @@ -2359,7 +2361,7 @@ // Mark the register as a use (as well as a def) because the old // value will be retained if the condition is false. M = (BuildMI(movOpCode, 3).addCCReg(tmpForCC).addZImm(1) - .addReg(setCCInstr, MOTy::UseAndDef)); + .addReg(setCCInstr, MachineOperand::UseAndDef)); mvec.push_back(M); } break; @@ -2448,8 +2450,8 @@ MachineFunction& MF = MachineFunction::get(currentFunc); MachineCodeForInstruction& mcfi = MachineCodeForInstruction::get(callInstr); - const SparcRegInfo& regInfo = - (SparcRegInfo&) target.getRegInfo(); + const SparcV9RegInfo& regInfo = + (SparcV9RegInfo&) target.getRegInfo(); const TargetFrameInfo& frameInfo = target.getFrameInfo(); // Create hidden virtual register for return address with type void* @@ -2589,7 +2591,7 @@ unsigned LoadOpcode = ChooseLoadInstruction(loadTy); M = BuildMI(convertOpcodeFromRegToImm(LoadOpcode), 3) .addMReg(regInfo.getFramePointer()).addSImm(tmpOffset) - .addReg(argVReg, MOTy::Def); + .addReg(argVReg, MachineOperand::Def); // Mark operand with register it should be assigned // both for copy and for the callMI @@ -2668,11 +2670,11 @@ // -- For non-FP values, create an add-with-0 instruction if (argType->isFloatingPoint()) M=(BuildMI(argType==Type::FloatTy? V9::FMOVS :V9::FMOVD,2) - .addReg(argVal).addReg(argVReg, MOTy::Def)); + .addReg(argVal).addReg(argVReg, MachineOperand::Def)); else M = (BuildMI(ChooseAddInstructionByType(argType), 3) .addReg(argVal).addSImm((int64_t) 0) - .addReg(argVReg, MOTy::Def)); + .addReg(argVReg, MachineOperand::Def)); // Mark the operand with the register it should be assigned M->SetRegForOperand(M->getNumOperands()-1, regNumForArg); @@ -2699,8 +2701,8 @@ const Type* retType = callInstr->getType(); int regNum = (retType->isFloatingPoint() - ? (unsigned) SparcFloatRegClass::f0 - : (unsigned) SparcIntRegClass::o0); + ? (unsigned) SparcV9FloatRegClass::f0 + : (unsigned) SparcV9IntRegClass::o0); unsigned regClassID = regInfo.getRegClassIDOfType(retType); regNum = regInfo.getUnifiedRegNum(regClassID, regNum); @@ -2716,11 +2718,11 @@ // -- For non-FP values, create an add-with-0 instruction if (retType->isFloatingPoint()) M = (BuildMI(retType==Type::FloatTy? V9::FMOVS : V9::FMOVD, 2) - .addReg(retVReg).addReg(callInstr, MOTy::Def)); + .addReg(retVReg).addReg(callInstr, MachineOperand::Def)); else M = (BuildMI(ChooseAddInstructionByType(retType), 3) .addReg(retVReg).addSImm((int64_t) 0) - .addReg(callInstr, MOTy::Def)); + .addReg(callInstr, MachineOperand::Def)); // Mark the operand with the register it should be assigned // Also mark the implicit ref of the call defining this operand @@ -2878,12 +2880,13 @@ tmpI, NULL, "maskHi2"); mvec.push_back(BuildMI(V9::SLLXi6, 3).addReg(tmpI) .addZImm(8*(4-destSize)) - .addReg(srlArgToUse, MOTy::Def)); + .addReg(srlArgToUse, MachineOperand::Def)); } // Logical right shift 32-N to get zero extension in top 64-N bits. mvec.push_back(BuildMI(V9::SRLi5, 3).addReg(srlArgToUse) - .addZImm(8*(4-destSize)).addReg(dest, MOTy::Def)); + .addZImm(8*(4-destSize)) + .addReg(dest, MachineOperand::Def)); } else if (destSize < 8) { assert(0 && "Unsupported type size: 32 < size < 64 bits"); Index: llvm/lib/Target/SparcV9/SparcV9InstrSelectionSupport.h diff -u llvm/lib/Target/SparcV9/SparcV9InstrSelectionSupport.h:1.13 llvm/lib/Target/SparcV9/SparcV9InstrSelectionSupport.h:1.13.4.1 --- llvm/lib/Target/SparcV9/SparcV9InstrSelectionSupport.h:1.13 Tue Nov 11 16:41:33 2003 +++ llvm/lib/Target/SparcV9/SparcV9InstrSelectionSupport.h Mon Mar 1 17:58:15 2004 @@ -1,4 +1,4 @@ -//===-- llvm/CodeGen/SparcInstrSelectionSupport.h ---------------*- C++ -*-===// +//===-- llvm/CodeGen/SparcV9InstrSelectionSupport.h ---------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -15,7 +15,7 @@ #define SPARC_INSTR_SELECTION_SUPPORT_h #include "llvm/DerivedTypes.h" -#include "SparcInternals.h" +#include "SparcV9Internals.h" namespace llvm { @@ -90,7 +90,7 @@ } -// Because the Sparc instruction selector likes to re-write operands to +// Because the SparcV9 instruction selector likes to re-write operands to // instructions, making them change from a Value* (virtual register) to a // Constant* (making an immediate field), we need to change the opcode from a // register-based instruction to an immediate-based instruction, hence this Index: llvm/lib/Target/SparcV9/SparcV9Internals.h diff -u llvm/lib/Target/SparcV9/SparcV9Internals.h:1.110 llvm/lib/Target/SparcV9/SparcV9Internals.h:1.110.2.1 --- llvm/lib/Target/SparcV9/SparcV9Internals.h:1.110 Sat Dec 20 03:17:40 2003 +++ llvm/lib/Target/SparcV9/SparcV9Internals.h Mon Mar 1 17:58:15 2004 @@ -1,4 +1,4 @@ -//===-- SparcInternals.h ----------------------------------------*- C++ -*-===// +//===-- SparcV9Internals.h ----------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// // -// This file defines stuff that is to be private to the Sparc backend, but is +// This file defines stuff that is to be private to the SparcV9 backend, but is // shared among different portions of the backend. // //===----------------------------------------------------------------------===// @@ -19,19 +19,18 @@ #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetSchedInfo.h" #include "llvm/Target/TargetFrameInfo.h" -#include "llvm/Target/TargetCacheInfo.h" #include "llvm/Target/TargetRegInfo.h" #include "llvm/Type.h" -#include "SparcRegClassInfo.h" +#include "SparcV9RegClassInfo.h" #include "Config/sys/types.h" namespace llvm { class LiveRange; -class SparcTargetMachine; +class SparcV9TargetMachine; class Pass; -enum SparcInstrSchedClass { +enum SparcV9InstrSchedClass { SPARC_NONE, /* Instructions with no scheduling restrictions */ SPARC_IEUN, /* Integer class that can use IEU0 or IEU1 */ SPARC_IEU0, /* Integer class IEU0 */ @@ -49,20 +48,20 @@ //--------------------------------------------------------------------------- -// enum SparcMachineOpCode. -// const TargetInstrDescriptor SparcMachineInstrDesc[] +// enum SparcV9MachineOpCode. +// const TargetInstrDescriptor SparcV9MachineInstrDesc[] // // Purpose: -// Description of UltraSparc machine instructions. +// Description of UltraSparcV9 machine instructions. // //--------------------------------------------------------------------------- namespace V9 { - enum SparcMachineOpCode { + enum SparcV9MachineOpCode { #define I(ENUM, OPCODESTRING, NUMOPERANDS, RESULTPOS, MAXIMM, IMMSE, \ NUMDELAYSLOTS, LATENCY, SCHEDCLASS, INSTFLAGS) \ ENUM, -#include "SparcInstr.def" +#include "SparcV9Instr.def" // End-of-array marker INVALID_OPCODE, @@ -72,36 +71,23 @@ } // Array of machine instruction descriptions... -extern const TargetInstrDescriptor SparcMachineInstrDesc[]; +extern const TargetInstrDescriptor SparcV9MachineInstrDesc[]; //--------------------------------------------------------------------------- -// class SparcSchedInfo +// class SparcV9SchedInfo // // Purpose: // Interface to instruction scheduling information for UltraSPARC. // The parameter values above are based on UltraSPARC IIi. //--------------------------------------------------------------------------- -class SparcSchedInfo: public TargetSchedInfo { +class SparcV9SchedInfo: public TargetSchedInfo { public: - SparcSchedInfo(const TargetMachine &tgt); + SparcV9SchedInfo(const TargetMachine &tgt); protected: virtual void initializeResources(); }; -//--------------------------------------------------------------------------- -// class SparcCacheInfo -// -// Purpose: -// Interface to cache parameters for the UltraSPARC. -// Just use defaults for now. -//--------------------------------------------------------------------------- - -struct SparcCacheInfo: public TargetCacheInfo { - SparcCacheInfo(const TargetMachine &T) : TargetCacheInfo(T) {} -}; - - /// createStackSlotsPass - External interface to stack-slots pass that enters 2 /// empty slots at the top of each function stack /// @@ -127,7 +113,7 @@ /// Pass* createBytecodeAsmPrinterPass(std::ostream &Out); -FunctionPass *createSparcMachineCodeDestructionPass(); +FunctionPass *createSparcV9MachineCodeDestructionPass(); } // End llvm namespace Index: llvm/lib/Target/SparcV9/SparcV9JITInfo.h diff -u llvm/lib/Target/SparcV9/SparcV9JITInfo.h:1.3 llvm/lib/Target/SparcV9/SparcV9JITInfo.h:1.3.2.1 --- llvm/lib/Target/SparcV9/SparcV9JITInfo.h:1.3 Sun Dec 28 15:23:38 2003 +++ llvm/lib/Target/SparcV9/SparcV9JITInfo.h Mon Mar 1 17:58:15 2004 @@ -1,4 +1,4 @@ -//===- SparcJITInfo.h - Sparc implementation of the JIT interface -*-C++-*-===// +//===- SparcV9JITInfo.h - SparcV9 implementation of the JIT interface -*-C++-*-===// // // The LLVM Compiler Infrastructure // @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// // -// This file contains the Sparc implementation of the TargetJITInfo class. +// This file contains the SparcV9 implementation of the TargetJITInfo class. // //===----------------------------------------------------------------------===// @@ -19,10 +19,10 @@ namespace llvm { class TargetMachine; - class SparcJITInfo : public TargetJITInfo { + class SparcV9JITInfo : public TargetJITInfo { TargetMachine &TM; public: - SparcJITInfo(TargetMachine &tm) : TM(tm) {} + SparcV9JITInfo(TargetMachine &tm) : TM(tm) {} /// addPassesToJITCompile - Add passes to the specified pass manager to /// implement a fast dynamic compiler for this target. Return true if this Index: llvm/lib/Target/SparcV9/SparcV9PeepholeOpts.cpp diff -u llvm/lib/Target/SparcV9/SparcV9PeepholeOpts.cpp:1.17 llvm/lib/Target/SparcV9/SparcV9PeepholeOpts.cpp:1.17.2.1 --- llvm/lib/Target/SparcV9/SparcV9PeepholeOpts.cpp:1.17 Wed Dec 17 16:08:20 2003 +++ llvm/lib/Target/SparcV9/SparcV9PeepholeOpts.cpp Mon Mar 1 17:58:15 2004 @@ -12,13 +12,14 @@ // //===----------------------------------------------------------------------===// -#include "SparcInternals.h" +#include "SparcV9Internals.h" #include "llvm/BasicBlock.h" #include "llvm/Pass.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineInstr.h" #include "llvm/Target/TargetInstrInfo.h" #include "llvm/Target/TargetMachine.h" +#include "Support/STLExtras.h" namespace llvm { @@ -31,14 +32,14 @@ // Check if this instruction is in a delay slot of its predecessor. if (BBI != mvec.begin()) { const TargetInstrInfo& mii = target.getInstrInfo(); - MachineInstr* predMI = *(BBI-1); - if (unsigned ndelay = mii.getNumDelaySlots(predMI->getOpCode())) { + MachineBasicBlock::iterator predMI = prior(BBI); + if (unsigned ndelay = mii.getNumDelaySlots(predMI->getOpcode())) { // This instruction is in a delay slot of its predecessor, so // replace it with a nop. By replacing in place, we save having // to update the I-I maps. // assert(ndelay == 1 && "Not yet handling multiple-delay-slot targets"); - (*BBI)->replace(mii.getNOPOpCode(), 0); + BBI->replace(mii.getNOPOpCode(), 0); return; } } @@ -61,18 +62,17 @@ //---------------------------------------------------------------------------- static bool IsUselessCopy(const TargetMachine &target, const MachineInstr* MI) { - if (MI->getOpCode() == V9::FMOVS || MI->getOpCode() == V9::FMOVD) { + if (MI->getOpcode() == V9::FMOVS || MI->getOpcode() == V9::FMOVD) { return (// both operands are allocated to the same register - MI->getOperand(0).getAllocatedRegNum() == - MI->getOperand(1).getAllocatedRegNum()); - } else if (MI->getOpCode() == V9::ADDr || MI->getOpCode() == V9::ORr || - MI->getOpCode() == V9::ADDi || MI->getOpCode() == V9::ORi) { + MI->getOperand(0).getReg() == MI->getOperand(1).getReg()); + } else if (MI->getOpcode() == V9::ADDr || MI->getOpcode() == V9::ORr || + MI->getOpcode() == V9::ADDi || MI->getOpcode() == V9::ORi) { unsigned srcWithDestReg; for (srcWithDestReg = 0; srcWithDestReg < 2; ++srcWithDestReg) if (MI->getOperand(srcWithDestReg).hasAllocatedReg() && - MI->getOperand(srcWithDestReg).getAllocatedRegNum() - == MI->getOperand(2).getAllocatedRegNum()) + MI->getOperand(srcWithDestReg).getReg() + == MI->getOperand(2).getReg()) break; if (srcWithDestReg == 2) @@ -82,7 +82,7 @@ unsigned otherOp = 1 - srcWithDestReg; return (// either operand otherOp is register %g0 (MI->getOperand(otherOp).hasAllocatedReg() && - MI->getOperand(otherOp).getAllocatedRegNum() == + MI->getOperand(otherOp).getReg() == target.getRegInfo().getZeroRegNum()) || // or operand otherOp == 0 @@ -99,7 +99,7 @@ RemoveUselessCopies(MachineBasicBlock& mvec, MachineBasicBlock::iterator& BBI, const TargetMachine& target) { - if (IsUselessCopy(target, *BBI)) { + if (IsUselessCopy(target, BBI)) { DeleteInstruction(mvec, BBI, target); return true; } @@ -148,16 +148,8 @@ assert(MBB && "MachineBasicBlock object not found for specified block!"); MachineBasicBlock &mvec = *MBB; - // Iterate over all machine instructions in the BB - // Use a reverse iterator to allow deletion of MI or any instruction after it. - // Insertions or deletions *before* MI are not safe. - // - for (MachineBasicBlock::reverse_iterator RI=mvec.rbegin(), - RE=mvec.rend(); RI != RE; ) { - MachineBasicBlock::iterator BBI = RI.base()-1; // save before incr - ++RI; // pre-increment to delete MI or after it - visit(mvec, BBI); - } + for (MachineBasicBlock::iterator I = mvec.begin(), E = mvec.end(); I != E; ) + visit(mvec, I++); return true; } Index: llvm/lib/Target/SparcV9/SparcV9PreSelection.cpp diff -u llvm/lib/Target/SparcV9/SparcV9PreSelection.cpp:1.27 llvm/lib/Target/SparcV9/SparcV9PreSelection.cpp:1.27.2.1 --- llvm/lib/Target/SparcV9/SparcV9PreSelection.cpp:1.27 Wed Dec 17 16:06:08 2003 +++ llvm/lib/Target/SparcV9/SparcV9PreSelection.cpp Mon Mar 1 17:58:15 2004 @@ -15,7 +15,7 @@ // //===----------------------------------------------------------------------===// -#include "SparcInternals.h" +#include "SparcV9Internals.h" #include "llvm/Constants.h" #include "llvm/DerivedTypes.h" #include "llvm/iMemory.h" Index: llvm/lib/Target/SparcV9/SparcV9PrologEpilogInserter.cpp diff -u llvm/lib/Target/SparcV9/SparcV9PrologEpilogInserter.cpp:1.32 llvm/lib/Target/SparcV9/SparcV9PrologEpilogInserter.cpp:1.32.4.1 --- llvm/lib/Target/SparcV9/SparcV9PrologEpilogInserter.cpp:1.32 Wed Nov 12 18:18:04 2003 +++ llvm/lib/Target/SparcV9/SparcV9PrologEpilogInserter.cpp Mon Mar 1 17:58:15 2004 @@ -16,8 +16,8 @@ // //===----------------------------------------------------------------------===// -#include "SparcInternals.h" -#include "SparcRegClassInfo.h" +#include "SparcV9Internals.h" +#include "SparcV9RegClassInfo.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineFunctionInfo.h" #include "llvm/CodeGen/MachineCodeForInstruction.h" @@ -31,7 +31,7 @@ namespace { struct InsertPrologEpilogCode : public MachineFunctionPass { - const char *getPassName() const { return "Sparc Prolog/Epilog Inserter"; } + const char *getPassName() const { return "SparcV9 Prolog/Epilog Inserter"; } bool runOnMachineFunction(MachineFunction &F) { if (!F.getInfo()->isCompiledAsLeafMethod()) { @@ -74,7 +74,7 @@ int SP = TM.getRegInfo().getStackPointer(); if (TM.getInstrInfo().constantFitsInImmedField(V9::SAVEi,staticStackSize)) { mvec.push_back(BuildMI(V9::SAVEi, 3).addMReg(SP).addSImm(C) - .addMReg(SP, MOTy::Def)); + .addMReg(SP, MachineOperand::Def)); } else { // We have to put the stack size value into a register before SAVE. // Use register %g1 since it is volatile across calls. Note that the @@ -83,24 +83,25 @@ // SETSW -(stackSize), %g1 int uregNum = TM.getRegInfo().getUnifiedRegNum( TM.getRegInfo().getRegClassIDOfType(Type::IntTy), - SparcIntRegClass::g1); + SparcV9IntRegClass::g1); MachineInstr* M = BuildMI(V9::SETHI, 2).addSImm(C) - .addMReg(uregNum, MOTy::Def); + .addMReg(uregNum, MachineOperand::Def); M->setOperandHi32(0); mvec.push_back(M); M = BuildMI(V9::ORi, 3).addMReg(uregNum).addSImm(C) - .addMReg(uregNum, MOTy::Def); + .addMReg(uregNum, MachineOperand::Def); M->setOperandLo32(1); mvec.push_back(M); M = BuildMI(V9::SRAi5, 3).addMReg(uregNum).addZImm(0) - .addMReg(uregNum, MOTy::Def); + .addMReg(uregNum, MachineOperand::Def); mvec.push_back(M); // Now generate the SAVE using the value in register %g1 - M = BuildMI(V9::SAVEr,3).addMReg(SP).addMReg(uregNum).addMReg(SP,MOTy::Def); + M = BuildMI(V9::SAVEr,3).addMReg(SP).addMReg(uregNum) + .addMReg(SP,MachineOperand::Def); mvec.push_back(M); } @@ -118,7 +119,7 @@ bool ignore; int firstArgReg = TM.getRegInfo().getUnifiedRegNum( TM.getRegInfo().getRegClassIDOfType(Type::IntTy), - SparcIntRegClass::i0); + SparcV9IntRegClass::i0); int fpReg = TM.getFrameInfo().getIncomingArgBaseRegNum(); int argSize = TM.getFrameInfo().getSizeOfEachArgOnStack(); int firstArgOffset=TM.getFrameInfo().getFirstIncomingArgOffset(MF,ignore); @@ -148,25 +149,26 @@ { int ZR = TM.getRegInfo().getZeroRegNum(); MachineInstr *Restore = - BuildMI(V9::RESTOREi, 3).addMReg(ZR).addSImm(0).addMReg(ZR, MOTy::Def); + BuildMI(V9::RESTOREi, 3).addMReg(ZR).addSImm(0) + .addMReg(ZR, MachineOperand::Def); MachineCodeForInstruction &termMvec = MachineCodeForInstruction::get(TermInst); // Remove the NOPs in the delay slots of the return instruction unsigned numNOPs = 0; - while (termMvec.back()->getOpCode() == V9::NOP) + while (termMvec.back()->getOpcode() == V9::NOP) { - assert( termMvec.back() == MBB.back()); - delete MBB.pop_back(); + assert( termMvec.back() == &MBB.back()); termMvec.pop_back(); + MBB.erase(&MBB.back()); ++numNOPs; } - assert(termMvec.back() == MBB.back()); + assert(termMvec.back() == &MBB.back()); // Check that we found the right number of NOPs and have the right // number of instructions to replace them. - unsigned ndelays = MII.getNumDelaySlots(termMvec.back()->getOpCode()); + unsigned ndelays = MII.getNumDelaySlots(termMvec.back()->getOpcode()); assert(numNOPs == ndelays && "Missing NOPs in delay slots?"); assert(ndelays == 1 && "Cannot use epilog code for delay slots?"); Index: llvm/lib/Target/SparcV9/SparcV9RegClassInfo.cpp diff -u llvm/lib/Target/SparcV9/SparcV9RegClassInfo.cpp:1.34 llvm/lib/Target/SparcV9/SparcV9RegClassInfo.cpp:1.34.2.1 --- llvm/lib/Target/SparcV9/SparcV9RegClassInfo.cpp:1.34 Fri Jan 9 10:17:09 2004 +++ llvm/lib/Target/SparcV9/SparcV9RegClassInfo.cpp Mon Mar 1 17:58:15 2004 @@ -1,4 +1,4 @@ -//===-- SparcRegClassInfo.cpp - Register class def'ns for Sparc -----------===// +//===-- SparcV9RegClassInfo.cpp - Register class def'ns for SparcV9 -----------===// // // The LLVM Compiler Infrastructure // @@ -7,14 +7,14 @@ // //===----------------------------------------------------------------------===// // -// This file defines the register classes used by the Sparc target description. +// This file defines the register classes used by the SparcV9 target description. // //===----------------------------------------------------------------------===// #include "llvm/Type.h" -#include "SparcRegClassInfo.h" -#include "SparcInternals.h" -#include "SparcRegInfo.h" +#include "SparcV9RegClassInfo.h" +#include "SparcV9Internals.h" +#include "SparcV9RegInfo.h" #include "RegAlloc/RegAllocCommon.h" #include "RegAlloc/IGNode.h" @@ -33,7 +33,7 @@ // If both above fail, spill. // //----------------------------------------------------------------------------- -void SparcIntRegClass::colorIGNode(IGNode * Node, +void SparcV9IntRegClass::colorIGNode(IGNode * Node, const std::vector &IsColorUsedArr) const { LiveRange *LR = Node->getParentLR(); @@ -69,16 +69,16 @@ //if this Node is between calls if (! LR->isCallInterference()) { // start with volatiles (we can allocate volatiles safely) - SearchStart = SparcIntRegClass::StartOfAllRegs; + SearchStart = SparcV9IntRegClass::StartOfAllRegs; } else { // start with non volatiles (no non-volatiles) - SearchStart = SparcIntRegClass::StartOfNonVolatileRegs; + SearchStart = SparcV9IntRegClass::StartOfNonVolatileRegs; } unsigned c=0; // color // find first unused color - for (c=SearchStart; c < SparcIntRegClass::NumOfAvailRegs; c++) { + for (c=SearchStart; c < SparcV9IntRegClass::NumOfAvailRegs; c++) { if (!IsColorUsedArr[c]) { ColorFound = true; break; @@ -95,10 +95,10 @@ // else if (LR->isCallInterference()) { // start from 0 - try to find even a volatile this time - SearchStart = SparcIntRegClass::StartOfAllRegs; + SearchStart = SparcV9IntRegClass::StartOfAllRegs; // find first unused volatile color - for(c=SearchStart; c < SparcIntRegClass::StartOfNonVolatileRegs; c++) { + for(c=SearchStart; c < SparcV9IntRegClass::StartOfNonVolatileRegs; c++) { if (! IsColorUsedArr[c]) { ColorFound = true; break; @@ -140,7 +140,7 @@ // Note: The third name (%ccr) is essentially an assembly mnemonic and // depends solely on the opcode, so the name can be chosen in EmitAssembly. //----------------------------------------------------------------------------- -void SparcIntCCRegClass::colorIGNode(IGNode *Node, +void SparcV9IntCCRegClass::colorIGNode(IGNode *Node, const std::vector &IsColorUsedArr) const { if (Node->getNumOfNeighbors() > 0) @@ -173,7 +173,7 @@ } -void SparcFloatCCRegClass::colorIGNode(IGNode *Node, +void SparcV9FloatCCRegClass::colorIGNode(IGNode *Node, const std::vector &IsColorUsedArr) const { for(unsigned c = 0; c != 4; ++c) if (!IsColorUsedArr[c]) { // find unused color @@ -201,7 +201,7 @@ // If a color is still not fond, mark for spilling // //---------------------------------------------------------------------------- -void SparcFloatRegClass::colorIGNode(IGNode * Node, +void SparcV9FloatRegClass::colorIGNode(IGNode * Node, const std::vector &IsColorUsedArr) const { LiveRange *LR = Node->getParentLR(); @@ -211,11 +211,11 @@ // // FIXME: This is old code that is no longer needed. Temporarily converting // it into a big assertion just to check that the replacement logic - // (invoking SparcFloatRegClass::markColorsUsed() directly from + // (invoking SparcV9FloatRegClass::markColorsUsed() directly from // RegClass::colorIGNode) works correctly. // // In fact, this entire function should be identical to - // SparcIntRegClass::colorIGNode(), and perhaps can be + // SparcV9IntRegClass::colorIGNode(), and perhaps can be // made into a general case in CodeGen/RegAlloc/RegClass.cpp. // unsigned NumNeighbors = Node->getNumOfNeighbors(); // total # of neighbors @@ -242,7 +242,7 @@ // **NOTE: We don't check for call interferences in allocating suggested // color in this class since ALL registers are volatile. If this fact // changes, we should change the following part - //- see SparcIntRegClass::colorIGNode() + //- see SparcV9IntRegClass::colorIGNode() // if( LR->hasSuggestedColor() ) { if( ! IsColorUsedArr[ LR->getSuggestedColor() ] ) { @@ -280,10 +280,10 @@ //if this Node is between calls (i.e., no call interferences ) if (! isCallInterf) { // start with volatiles (we can allocate volatiles safely) - SearchStart = SparcFloatRegClass::StartOfAllRegs; + SearchStart = SparcV9FloatRegClass::StartOfAllRegs; } else { // start with non volatiles (no non-volatiles) - SearchStart = SparcFloatRegClass::StartOfNonVolatileRegs; + SearchStart = SparcV9FloatRegClass::StartOfNonVolatileRegs; } ColorFound = findFloatColor(LR, SearchStart, 32, IsColorUsedArr); @@ -296,8 +296,8 @@ // We are here because there is a call interference and no non-volatile // color could be found. // Now try to allocate even a volatile color - ColorFound = findFloatColor(LR, SparcFloatRegClass::StartOfAllRegs, - SparcFloatRegClass::StartOfNonVolatileRegs, + ColorFound = findFloatColor(LR, SparcV9FloatRegClass::StartOfAllRegs, + SparcV9FloatRegClass::StartOfNonVolatileRegs, IsColorUsedArr); } @@ -316,13 +316,13 @@ // for double-precision registers. //----------------------------------------------------------------------------- -void SparcFloatRegClass::markColorsUsed(unsigned RegInClass, +void SparcV9FloatRegClass::markColorsUsed(unsigned RegInClass, int UserRegType, int RegTypeWanted, std::vector &IsColorUsedArr) const { - if (UserRegType == SparcRegInfo::FPDoubleRegType || - RegTypeWanted == SparcRegInfo::FPDoubleRegType) { + if (UserRegType == SparcV9RegInfo::FPDoubleRegType || + RegTypeWanted == SparcV9RegInfo::FPDoubleRegType) { // This register is used as or is needed as a double-precision reg. // We need to mark the [even,odd] pair corresponding to this reg. // Get the even numbered register corresponding to this reg. @@ -346,10 +346,10 @@ // for double-precision registers // It returns -1 if no unused color is found. // -int SparcFloatRegClass::findUnusedColor(int RegTypeWanted, +int SparcV9FloatRegClass::findUnusedColor(int RegTypeWanted, const std::vector &IsColorUsedArr) const { - if (RegTypeWanted == SparcRegInfo::FPDoubleRegType) { + if (RegTypeWanted == SparcV9RegInfo::FPDoubleRegType) { unsigned NC = 2 * this->getNumOfAvailRegs(); assert(IsColorUsedArr.size() == NC && "Invalid colors-used array"); for (unsigned c = 0; c < NC; c+=2) @@ -369,7 +369,7 @@ // type of the Node (i.e., float/double) //----------------------------------------------------------------------------- -int SparcFloatRegClass::findFloatColor(const LiveRange *LR, +int SparcV9FloatRegClass::findFloatColor(const LiveRange *LR, unsigned Start, unsigned End, const std::vector &IsColorUsedArr) const @@ -380,7 +380,7 @@ for (unsigned c=Start; c < End ; c+= 2) if (!IsColorUsedArr[c]) { assert(!IsColorUsedArr[c+1] && - "Incorrect marking of used regs for Sparc FP double!"); + "Incorrect marking of used regs for SparcV9 FP double!"); return c; } } else { Index: llvm/lib/Target/SparcV9/SparcV9RegClassInfo.h diff -u llvm/lib/Target/SparcV9/SparcV9RegClassInfo.h:1.23 llvm/lib/Target/SparcV9/SparcV9RegClassInfo.h:1.23.4.1 --- llvm/lib/Target/SparcV9/SparcV9RegClassInfo.h:1.23 Tue Nov 11 16:41:33 2003 +++ llvm/lib/Target/SparcV9/SparcV9RegClassInfo.h Mon Mar 1 17:58:15 2004 @@ -1,4 +1,4 @@ -//===-- SparcRegClassInfo.h - Register class def'ns for Sparc ---*- C++ -*-===// +//===-- SparcV9RegClassInfo.h - Register class def'ns for SparcV9 ---*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// // -// This file defines the register classes used by the Sparc target description. +// This file defines the register classes used by the SparcV9 target description. // //===----------------------------------------------------------------------===// @@ -22,8 +22,8 @@ // Integer Register Class //----------------------------------------------------------------------------- -struct SparcIntRegClass : public TargetRegClassInfo { - SparcIntRegClass(unsigned ID) +struct SparcV9IntRegClass : public TargetRegClassInfo { + SparcV9IntRegClass(unsigned ID) : TargetRegClassInfo(ID, NumOfAvailRegs, NumOfAllRegs) { } void colorIGNode(IGNode *Node, @@ -87,12 +87,12 @@ // Float Register Class //----------------------------------------------------------------------------- -class SparcFloatRegClass : public TargetRegClassInfo { +class SparcV9FloatRegClass : public TargetRegClassInfo { int findFloatColor(const LiveRange *LR, unsigned Start, unsigned End, const std::vector &IsColorUsedArr) const; public: - SparcFloatRegClass(unsigned ID) + SparcV9FloatRegClass(unsigned ID) : TargetRegClassInfo(ID, NumOfAvailRegs, NumOfAllRegs) {} // This method marks the registers used for a given register number. @@ -116,7 +116,7 @@ void colorIGNode(IGNode *Node, const std::vector &IsColorUsedArr) const; - // according to Sparc 64 ABI, all %fp regs are volatile + // according to SparcV9 64 ABI, all %fp regs are volatile inline bool isRegVolatile(int Reg) const { return true; } enum { @@ -153,14 +153,14 @@ // allocated for the three names. //----------------------------------------------------------------------------- -struct SparcIntCCRegClass : public TargetRegClassInfo { - SparcIntCCRegClass(unsigned ID) +struct SparcV9IntCCRegClass : public TargetRegClassInfo { + SparcV9IntCCRegClass(unsigned ID) : TargetRegClassInfo(ID, 1, 3) { } void colorIGNode(IGNode *Node, const std::vector &IsColorUsedArr) const; - // according to Sparc 64 ABI, %ccr is volatile + // according to SparcV9 64 ABI, %ccr is volatile // inline bool isRegVolatile(int Reg) const { return true; } @@ -177,14 +177,14 @@ // Only 4 Float CC registers are available for allocation. //----------------------------------------------------------------------------- -struct SparcFloatCCRegClass : public TargetRegClassInfo { - SparcFloatCCRegClass(unsigned ID) +struct SparcV9FloatCCRegClass : public TargetRegClassInfo { + SparcV9FloatCCRegClass(unsigned ID) : TargetRegClassInfo(ID, 4, 5) { } void colorIGNode(IGNode *Node, const std::vector &IsColorUsedArr) const; - // according to Sparc 64 ABI, all %fp CC regs are volatile + // according to SparcV9 64 ABI, all %fp CC regs are volatile // inline bool isRegVolatile(int Reg) const { return true; } @@ -196,17 +196,17 @@ }; //----------------------------------------------------------------------------- -// Sparc special register class. These registers are not used for allocation +// SparcV9 special register class. These registers are not used for allocation // but are used as arguments of some instructions. //----------------------------------------------------------------------------- -struct SparcSpecialRegClass : public TargetRegClassInfo { - SparcSpecialRegClass(unsigned ID) +struct SparcV9SpecialRegClass : public TargetRegClassInfo { + SparcV9SpecialRegClass(unsigned ID) : TargetRegClassInfo(ID, 0, 1) { } void colorIGNode(IGNode *Node, const std::vector &IsColorUsedArr) const { - assert(0 && "SparcSpecialRegClass should never be used for allocation"); + assert(0 && "SparcV9SpecialRegClass should never be used for allocation"); } // all currently included special regs are volatile Index: llvm/lib/Target/SparcV9/SparcV9RegInfo.cpp diff -u llvm/lib/Target/SparcV9/SparcV9RegInfo.cpp:1.116 llvm/lib/Target/SparcV9/SparcV9RegInfo.cpp:1.116.2.1 --- llvm/lib/Target/SparcV9/SparcV9RegInfo.cpp:1.116 Fri Jan 9 10:17:09 2004 +++ llvm/lib/Target/SparcV9/SparcV9RegInfo.cpp Mon Mar 1 17:58:15 2004 @@ -1,4 +1,4 @@ -//===-- SparcRegInfo.cpp - Sparc Target Register Information --------------===// +//===-- SparcV9RegInfo.cpp - SparcV9 Target Register Information --------------===// // // The LLVM Compiler Infrastructure // @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// // -// This file contains implementation of Sparc specific helper methods +// This file contains implementation of SparcV9 specific helper methods // used for register allocation. // //===----------------------------------------------------------------------===// @@ -17,17 +17,17 @@ #include "llvm/CodeGen/InstrSelection.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineCodeForInstruction.h" -#include "llvm/CodeGen/MachineInstrAnnot.h" +#include "MachineInstrAnnot.h" #include "RegAlloc/LiveRangeInfo.h" #include "RegAlloc/LiveRange.h" #include "llvm/DerivedTypes.h" #include "llvm/Function.h" #include "llvm/iTerminators.h" #include "llvm/iOther.h" -#include "SparcInternals.h" -#include "SparcRegClassInfo.h" -#include "SparcRegInfo.h" -#include "SparcTargetMachine.h" +#include "SparcV9Internals.h" +#include "SparcV9RegClassInfo.h" +#include "SparcV9RegInfo.h" +#include "SparcV9TargetMachine.h" namespace llvm { @@ -35,16 +35,16 @@ BadRegClass = ~0 }; -SparcRegInfo::SparcRegInfo(const SparcTargetMachine &tgt) +SparcV9RegInfo::SparcV9RegInfo(const SparcV9TargetMachine &tgt) : TargetRegInfo(tgt), NumOfIntArgRegs(6), NumOfFloatArgRegs(32) { - MachineRegClassArr.push_back(new SparcIntRegClass(IntRegClassID)); - MachineRegClassArr.push_back(new SparcFloatRegClass(FloatRegClassID)); - MachineRegClassArr.push_back(new SparcIntCCRegClass(IntCCRegClassID)); - MachineRegClassArr.push_back(new SparcFloatCCRegClass(FloatCCRegClassID)); - MachineRegClassArr.push_back(new SparcSpecialRegClass(SpecialRegClassID)); + MachineRegClassArr.push_back(new SparcV9IntRegClass(IntRegClassID)); + MachineRegClassArr.push_back(new SparcV9FloatRegClass(FloatRegClassID)); + MachineRegClassArr.push_back(new SparcV9IntCCRegClass(IntCCRegClassID)); + MachineRegClassArr.push_back(new SparcV9FloatCCRegClass(FloatCCRegClassID)); + MachineRegClassArr.push_back(new SparcV9SpecialRegClass(SpecialRegClassID)); - assert(SparcFloatRegClass::StartOfNonVolatileRegs == 32 && + assert(SparcV9FloatRegClass::StartOfNonVolatileRegs == 32 && "32 Float regs are used for float arg passing"); } @@ -52,31 +52,31 @@ // getZeroRegNum - returns the register that contains always zero. // this is the unified register number // -int SparcRegInfo::getZeroRegNum() const { - return getUnifiedRegNum(SparcRegInfo::IntRegClassID, - SparcIntRegClass::g0); +unsigned SparcV9RegInfo::getZeroRegNum() const { + return getUnifiedRegNum(SparcV9RegInfo::IntRegClassID, + SparcV9IntRegClass::g0); } // getCallAddressReg - returns the reg used for pushing the address when a // method is called. This can be used for other purposes between calls // -unsigned SparcRegInfo::getCallAddressReg() const { - return getUnifiedRegNum(SparcRegInfo::IntRegClassID, - SparcIntRegClass::o7); +unsigned SparcV9RegInfo::getCallAddressReg() const { + return getUnifiedRegNum(SparcV9RegInfo::IntRegClassID, + SparcV9IntRegClass::o7); } // Returns the register containing the return address. // It should be made sure that this register contains the return // value when a return instruction is reached. // -unsigned SparcRegInfo::getReturnAddressReg() const { - return getUnifiedRegNum(SparcRegInfo::IntRegClassID, - SparcIntRegClass::i7); +unsigned SparcV9RegInfo::getReturnAddressReg() const { + return getUnifiedRegNum(SparcV9RegInfo::IntRegClassID, + SparcV9IntRegClass::i7); } // Register get name implementations... -// Int register names in same order as enum in class SparcIntRegClass +// Int register names in same order as enum in class SparcV9IntRegClass static const char * const IntRegNames[] = { "o0", "o1", "o2", "o3", "o4", "o5", "o7", "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7", @@ -86,7 +86,7 @@ "o6" }; -const char * const SparcIntRegClass::getRegName(unsigned reg) const { +const char * const SparcV9IntRegClass::getRegName(unsigned reg) const { assert(reg < NumOfAllRegs); return IntRegNames[reg]; } @@ -101,7 +101,7 @@ "f60", "f61", "f62", "f63" }; -const char * const SparcFloatRegClass::getRegName(unsigned reg) const { +const char * const SparcV9FloatRegClass::getRegName(unsigned reg) const { assert (reg < NumOfAllRegs); return FloatRegNames[reg]; } @@ -111,7 +111,7 @@ "xcc", "icc", "ccr" }; -const char * const SparcIntCCRegClass::getRegName(unsigned reg) const { +const char * const SparcV9IntCCRegClass::getRegName(unsigned reg) const { assert(reg < 3); return IntCCRegNames[reg]; } @@ -120,7 +120,7 @@ "fcc0", "fcc1", "fcc2", "fcc3" }; -const char * const SparcFloatCCRegClass::getRegName(unsigned reg) const { +const char * const SparcV9FloatCCRegClass::getRegName(unsigned reg) const { assert (reg < 5); return FloatCCRegNames[reg]; } @@ -129,21 +129,21 @@ "fsr" }; -const char * const SparcSpecialRegClass::getRegName(unsigned reg) const { +const char * const SparcV9SpecialRegClass::getRegName(unsigned reg) const { assert (reg < 1); return SpecialRegNames[reg]; } // Get unified reg number for frame pointer -unsigned SparcRegInfo::getFramePointer() const { - return getUnifiedRegNum(SparcRegInfo::IntRegClassID, - SparcIntRegClass::i6); +unsigned SparcV9RegInfo::getFramePointer() const { + return getUnifiedRegNum(SparcV9RegInfo::IntRegClassID, + SparcV9IntRegClass::i6); } // Get unified reg number for stack pointer -unsigned SparcRegInfo::getStackPointer() const { - return getUnifiedRegNum(SparcRegInfo::IntRegClassID, - SparcIntRegClass::o6); +unsigned SparcV9RegInfo::getStackPointer() const { + return getUnifiedRegNum(SparcV9RegInfo::IntRegClassID, + SparcV9IntRegClass::o6); } @@ -175,14 +175,14 @@ // regClassId is set to the register class ID. // int -SparcRegInfo::regNumForIntArg(bool inCallee, bool isVarArgsCall, +SparcV9RegInfo::regNumForIntArg(bool inCallee, bool isVarArgsCall, unsigned argNo, unsigned& regClassId) const { regClassId = IntRegClassID; if (argNo >= NumOfIntArgRegs) return getInvalidRegNum(); else - return argNo + (inCallee? SparcIntRegClass::i0 : SparcIntRegClass::o0); + return argNo + (inCallee? SparcV9IntRegClass::i0 : SparcV9IntRegClass::o0); } // Get the register number for the specified FP argument #argNo, @@ -194,7 +194,7 @@ // regClassId is set to the register class ID. // int -SparcRegInfo::regNumForFPArg(unsigned regType, +SparcV9RegInfo::regNumForFPArg(unsigned regType, bool inCallee, bool isVarArgsCall, unsigned argNo, unsigned& regClassId) const { @@ -205,10 +205,10 @@ regClassId = FloatRegClassID; if (regType == FPSingleRegType) return (argNo*2+1 >= NumOfFloatArgRegs)? - getInvalidRegNum() : SparcFloatRegClass::f0 + (argNo * 2 + 1); + getInvalidRegNum() : SparcV9FloatRegClass::f0 + (argNo * 2 + 1); else if (regType == FPDoubleRegType) return (argNo*2 >= NumOfFloatArgRegs)? - getInvalidRegNum() : SparcFloatRegClass::f0 + (argNo * 2); + getInvalidRegNum() : SparcV9FloatRegClass::f0 + (argNo * 2); else assert(0 && "Illegal FP register type"); return 0; @@ -220,10 +220,10 @@ // Finds the return address of a call sparc specific call instruction //--------------------------------------------------------------------------- -// The following 4 methods are used to find the RegType (SparcInternals.h) +// The following 4 methods are used to find the RegType (SparcV9Internals.h) // of a LiveRange, a Value, and for a given register unified reg number. // -int SparcRegInfo::getRegTypeForClassAndType(unsigned regClassID, +int SparcV9RegInfo::getRegTypeForClassAndType(unsigned regClassID, const Type* type) const { switch (regClassID) { @@ -239,17 +239,17 @@ } } -int SparcRegInfo::getRegTypeForDataType(const Type* type) const +int SparcV9RegInfo::getRegTypeForDataType(const Type* type) const { return getRegTypeForClassAndType(getRegClassIDOfType(type), type); } -int SparcRegInfo::getRegTypeForLR(const LiveRange *LR) const +int SparcV9RegInfo::getRegTypeForLR(const LiveRange *LR) const { return getRegTypeForClassAndType(LR->getRegClassID(), LR->getType()); } -int SparcRegInfo::getRegType(int unifiedRegNum) const +int SparcV9RegInfo::getRegType(int unifiedRegNum) const { if (unifiedRegNum < 32) return IntRegType; @@ -269,7 +269,7 @@ // To find the register class used for a specified Type // -unsigned SparcRegInfo::getRegClassIDOfType(const Type *type, +unsigned SparcV9RegInfo::getRegClassIDOfType(const Type *type, bool isCCReg) const { Type::PrimitiveID ty = type->getPrimitiveID(); unsigned res; @@ -292,7 +292,7 @@ return res; } -unsigned SparcRegInfo::getRegClassIDOfRegType(int regType) const { +unsigned SparcV9RegInfo::getRegClassIDOfRegType(int regType) const { switch(regType) { case IntRegType: return IntRegClassID; case FPSingleRegType: @@ -309,14 +309,14 @@ // Suggests a register for the ret address in the RET machine instruction. // We always suggest %i7 by convention. //--------------------------------------------------------------------------- -void SparcRegInfo::suggestReg4RetAddr(MachineInstr *RetMI, +void SparcV9RegInfo::suggestReg4RetAddr(MachineInstr *RetMI, LiveRangeInfo& LRI) const { - assert(target.getInstrInfo().isReturn(RetMI->getOpCode())); + assert(target.getInstrInfo().isReturn(RetMI->getOpcode())); // return address is always mapped to i7 so set it immediately RetMI->SetRegForOperand(0, getUnifiedRegNum(IntRegClassID, - SparcIntRegClass::i7)); + SparcV9IntRegClass::i7)); // Possible Optimization: // Instead of setting the color, we can suggest one. In that case, @@ -329,16 +329,16 @@ // assert( RetAddrVal && "LR for ret address must be created at start"); // LiveRange * RetAddrLR = LRI.getLiveRangeForValue( RetAddrVal); // RetAddrLR->setSuggestedColor(getUnifiedRegNum( IntRegClassID, - // SparcIntRegOrdr::i7) ); + // SparcV9IntRegOrdr::i7) ); } //--------------------------------------------------------------------------- // Suggests a register for the ret address in the JMPL/CALL machine instr. -// Sparc ABI dictates that %o7 be used for this purpose. +// SparcV9 ABI dictates that %o7 be used for this purpose. //--------------------------------------------------------------------------- void -SparcRegInfo::suggestReg4CallAddr(MachineInstr * CallMI, +SparcV9RegInfo::suggestReg4CallAddr(MachineInstr * CallMI, LiveRangeInfo& LRI) const { CallArgsDescriptor* argDesc = CallArgsDescriptor::get(CallMI); @@ -350,19 +350,19 @@ assert(RetAddrLR && "INTERNAL ERROR: No LR for return address of call!"); unsigned RegClassID = RetAddrLR->getRegClassID(); - RetAddrLR->setColor(getUnifiedRegNum(IntRegClassID, SparcIntRegClass::o7)); + RetAddrLR->setColor(getUnifiedRegNum(IntRegClassID, SparcV9IntRegClass::o7)); } //--------------------------------------------------------------------------- // This method will suggest colors to incoming args to a method. -// According to the Sparc ABI, the first 6 incoming args are in +// According to the SparcV9 ABI, the first 6 incoming args are in // %i0 - %i5 (if they are integer) OR in %f0 - %f31 (if they are float). // If the arg is passed on stack due to the lack of regs, NOTHING will be // done - it will be colored (or spilled) as a normal live range. //--------------------------------------------------------------------------- -void SparcRegInfo::suggestRegs4MethodArgs(const Function *Meth, +void SparcV9RegInfo::suggestRegs4MethodArgs(const Function *Meth, LiveRangeInfo& LRI) const { // Check if this is a varArgs function. needed for choosing regs. @@ -395,7 +395,7 @@ // the correct hardware registers if they did not receive the correct // (suggested) color through graph coloring. //--------------------------------------------------------------------------- -void SparcRegInfo::colorMethodArgs(const Function *Meth, +void SparcV9RegInfo::colorMethodArgs(const Function *Meth, LiveRangeInfo &LRI, std::vector& InstrnsBefore, std::vector& InstrnsAfter) const { @@ -568,9 +568,9 @@ // This method is called before graph coloring to suggest colors to the // outgoing call args and the return value of the call. //--------------------------------------------------------------------------- -void SparcRegInfo::suggestRegs4CallArgs(MachineInstr *CallMI, +void SparcV9RegInfo::suggestRegs4CallArgs(MachineInstr *CallMI, LiveRangeInfo& LRI) const { - assert ( (target.getInstrInfo()).isCall(CallMI->getOpCode()) ); + assert ( (target.getInstrInfo()).isCall(CallMI->getOpcode()) ); CallArgsDescriptor* argDesc = CallArgsDescriptor::get(CallMI); @@ -588,9 +588,9 @@ // now suggest a register depending on the register class of ret arg if( RegClassID == IntRegClassID ) - RetValLR->setSuggestedColor(SparcIntRegClass::o0); + RetValLR->setSuggestedColor(SparcV9IntRegClass::o0); else if (RegClassID == FloatRegClassID ) - RetValLR->setSuggestedColor(SparcFloatRegClass::f0 ); + RetValLR->setSuggestedColor(SparcV9FloatRegClass::f0 ); else assert( 0 && "Unknown reg class for return value of call\n"); } @@ -636,10 +636,10 @@ // this method is called for an LLVM return instruction to identify which // values will be returned from this method and to suggest colors. //--------------------------------------------------------------------------- -void SparcRegInfo::suggestReg4RetValue(MachineInstr *RetMI, +void SparcV9RegInfo::suggestReg4RetValue(MachineInstr *RetMI, LiveRangeInfo& LRI) const { - assert( (target.getInstrInfo()).isReturn( RetMI->getOpCode() ) ); + assert( (target.getInstrInfo()).isReturn( RetMI->getOpcode() ) ); suggestReg4RetAddr(RetMI, LRI); @@ -650,8 +650,8 @@ if (const Value *RetVal = retI->getReturnValue()) if (LiveRange *const LR = LRI.getLiveRangeForValue(RetVal)) LR->setSuggestedColor(LR->getRegClassID() == IntRegClassID - ? (unsigned) SparcIntRegClass::i0 - : (unsigned) SparcFloatRegClass::f0); + ? (unsigned) SparcV9IntRegClass::i0 + : (unsigned) SparcV9FloatRegClass::f0); } //--------------------------------------------------------------------------- @@ -664,7 +664,7 @@ //--------------------------------------------------------------------------- bool -SparcRegInfo::regTypeNeedsScratchReg(int RegType, +SparcV9RegInfo::regTypeNeedsScratchReg(int RegType, int& scratchRegType) const { if (RegType == IntCCRegType) @@ -681,7 +681,7 @@ //--------------------------------------------------------------------------- void -SparcRegInfo::cpReg2RegMI(std::vector& mvec, +SparcV9RegInfo::cpReg2RegMI(std::vector& mvec, unsigned SrcReg, unsigned DestReg, int RegType) const { @@ -697,18 +697,19 @@ if (getRegType(DestReg) == IntRegType) { // copy intCC reg to int reg MI = (BuildMI(V9::RDCCR, 2) - .addMReg(getUnifiedRegNum(SparcRegInfo::IntCCRegClassID, - SparcIntCCRegClass::ccr)) - .addMReg(DestReg,MOTy::Def)); + .addMReg(getUnifiedRegNum(SparcV9RegInfo::IntCCRegClassID, + SparcV9IntCCRegClass::ccr)) + .addMReg(DestReg,MachineOperand::Def)); } else { // copy int reg to intCC reg assert(getRegType(SrcReg) == IntRegType && "Can only copy CC reg to/from integer reg"); MI = (BuildMI(V9::WRCCRr, 3) .addMReg(SrcReg) - .addMReg(SparcIntRegClass::g0) - .addMReg(getUnifiedRegNum(SparcRegInfo::IntCCRegClassID, - SparcIntCCRegClass::ccr), MOTy::Def)); + .addMReg(SparcV9IntRegClass::g0) + .addMReg(getUnifiedRegNum(SparcV9RegInfo::IntCCRegClassID, + SparcV9IntCCRegClass::ccr), + MachineOperand::Def)); } break; @@ -718,15 +719,17 @@ case IntRegType: MI = BuildMI(V9::ADDr, 3).addMReg(SrcReg).addMReg(getZeroRegNum()) - .addMReg(DestReg, MOTy::Def); + .addMReg(DestReg, MachineOperand::Def); break; case FPSingleRegType: - MI = BuildMI(V9::FMOVS, 2).addMReg(SrcReg).addMReg(DestReg, MOTy::Def); + MI = BuildMI(V9::FMOVS, 2).addMReg(SrcReg) + .addMReg(DestReg, MachineOperand::Def); break; case FPDoubleRegType: - MI = BuildMI(V9::FMOVD, 2).addMReg(SrcReg).addMReg(DestReg, MOTy::Def); + MI = BuildMI(V9::FMOVD, 2).addMReg(SrcReg) + .addMReg(DestReg, MachineOperand::Def); break; default: @@ -745,7 +748,7 @@ void -SparcRegInfo::cpReg2MemMI(std::vector& mvec, +SparcV9RegInfo::cpReg2MemMI(std::vector& mvec, unsigned SrcReg, unsigned PtrReg, int Offset, int RegType, @@ -765,8 +768,8 @@ OffReg = PRA.getUnusedUniRegAtMI(RC, RegType, MInst, LVSetBef); #else // Default to using register g4 for holding large offsets - OffReg = getUnifiedRegNum(SparcRegInfo::IntRegClassID, - SparcIntRegClass::g4); + OffReg = getUnifiedRegNum(SparcV9RegInfo::IntRegClassID, + SparcV9IntRegClass::g4); #endif assert(OffReg >= 0 && "FIXME: cpReg2MemMI cannot find an unused reg."); mvec.push_back(BuildMI(V9::SETSW, 2).addZImm(Offset).addReg(OffReg)); @@ -798,17 +801,17 @@ assert(scratchReg >= 0 && "Need scratch reg to store %ccr to memory"); assert(getRegType(scratchReg) ==IntRegType && "Invalid scratch reg"); MI = (BuildMI(V9::RDCCR, 2) - .addMReg(getUnifiedRegNum(SparcRegInfo::IntCCRegClassID, - SparcIntCCRegClass::ccr)) - .addMReg(scratchReg, MOTy::Def)); + .addMReg(getUnifiedRegNum(SparcV9RegInfo::IntCCRegClassID, + SparcV9IntCCRegClass::ccr)) + .addMReg(scratchReg, MachineOperand::Def)); mvec.push_back(MI); cpReg2MemMI(mvec, scratchReg, PtrReg, Offset, IntRegType); return; case FloatCCRegType: { - unsigned fsrReg = getUnifiedRegNum(SparcRegInfo::SpecialRegClassID, - SparcSpecialRegClass::fsr); + unsigned fsrReg = getUnifiedRegNum(SparcV9RegInfo::SpecialRegClassID, + SparcV9SpecialRegClass::fsr); if (target.getInstrInfo().constantFitsInImmedField(V9::STXFSRi, Offset)) MI=BuildMI(V9::STXFSRi,3).addMReg(fsrReg).addMReg(PtrReg).addSImm(Offset); else @@ -829,7 +832,7 @@ void -SparcRegInfo::cpMem2RegMI(std::vector& mvec, +SparcV9RegInfo::cpMem2RegMI(std::vector& mvec, unsigned PtrReg, int Offset, unsigned DestReg, @@ -850,8 +853,8 @@ OffReg = PRA.getUnusedUniRegAtMI(RC, RegType, MInst, LVSetBef); #else // Default to using register g4 for holding large offsets - OffReg = getUnifiedRegNum(SparcRegInfo::IntRegClassID, - SparcIntRegClass::g4); + OffReg = getUnifiedRegNum(SparcV9RegInfo::IntRegClassID, + SparcV9IntRegClass::g4); #endif assert(OffReg >= 0 && "FIXME: cpReg2MemMI cannot find an unused reg."); mvec.push_back(BuildMI(V9::SETSW, 2).addZImm(Offset).addReg(OffReg)); @@ -860,29 +863,29 @@ switch (RegType) { case IntRegType: if (target.getInstrInfo().constantFitsInImmedField(V9::LDXi, Offset)) - MI = BuildMI(V9::LDXi, 3).addMReg(PtrReg).addSImm(Offset).addMReg(DestReg, - MOTy::Def); + MI = BuildMI(V9::LDXi, 3).addMReg(PtrReg).addSImm(Offset) + .addMReg(DestReg, MachineOperand::Def); else - MI = BuildMI(V9::LDXr, 3).addMReg(PtrReg).addMReg(OffReg).addMReg(DestReg, - MOTy::Def); + MI = BuildMI(V9::LDXr, 3).addMReg(PtrReg).addMReg(OffReg) + .addMReg(DestReg, MachineOperand::Def); break; case FPSingleRegType: if (target.getInstrInfo().constantFitsInImmedField(V9::LDFi, Offset)) - MI = BuildMI(V9::LDFi, 3).addMReg(PtrReg).addSImm(Offset).addMReg(DestReg, - MOTy::Def); + MI = BuildMI(V9::LDFi, 3).addMReg(PtrReg).addSImm(Offset) + .addMReg(DestReg, MachineOperand::Def); else - MI = BuildMI(V9::LDFr, 3).addMReg(PtrReg).addMReg(OffReg).addMReg(DestReg, - MOTy::Def); + MI = BuildMI(V9::LDFr, 3).addMReg(PtrReg).addMReg(OffReg) + .addMReg(DestReg, MachineOperand::Def); break; case FPDoubleRegType: if (target.getInstrInfo().constantFitsInImmedField(V9::LDDFi, Offset)) - MI= BuildMI(V9::LDDFi, 3).addMReg(PtrReg).addSImm(Offset).addMReg(DestReg, - MOTy::Def); + MI= BuildMI(V9::LDDFi, 3).addMReg(PtrReg).addSImm(Offset) + .addMReg(DestReg, MachineOperand::Def); else - MI= BuildMI(V9::LDDFr, 3).addMReg(PtrReg).addMReg(OffReg).addMReg(DestReg, - MOTy::Def); + MI= BuildMI(V9::LDDFr, 3).addMReg(PtrReg).addMReg(OffReg) + .addMReg(DestReg, MachineOperand::Def); break; case IntCCRegType: @@ -891,20 +894,20 @@ cpMem2RegMI(mvec, PtrReg, Offset, scratchReg, IntRegType); MI = (BuildMI(V9::WRCCRr, 3) .addMReg(scratchReg) - .addMReg(SparcIntRegClass::g0) - .addMReg(getUnifiedRegNum(SparcRegInfo::IntCCRegClassID, - SparcIntCCRegClass::ccr), MOTy::Def)); + .addMReg(SparcV9IntRegClass::g0) + .addMReg(getUnifiedRegNum(SparcV9RegInfo::IntCCRegClassID, + SparcV9IntCCRegClass::ccr), MachineOperand::Def)); break; case FloatCCRegType: { - unsigned fsrRegNum = getUnifiedRegNum(SparcRegInfo::SpecialRegClassID, - SparcSpecialRegClass::fsr); + unsigned fsrRegNum = getUnifiedRegNum(SparcV9RegInfo::SpecialRegClassID, + SparcV9SpecialRegClass::fsr); if (target.getInstrInfo().constantFitsInImmedField(V9::LDXFSRi, Offset)) MI = BuildMI(V9::LDXFSRi, 3).addMReg(PtrReg).addSImm(Offset) - .addMReg(fsrRegNum, MOTy::UseAndDef); + .addMReg(fsrRegNum, MachineOperand::UseAndDef); else MI = BuildMI(V9::LDXFSRr, 3).addMReg(PtrReg).addMReg(OffReg) - .addMReg(fsrRegNum, MOTy::UseAndDef); + .addMReg(fsrRegNum, MachineOperand::UseAndDef); break; } default: @@ -921,7 +924,7 @@ void -SparcRegInfo::cpValue2Value(Value *Src, Value *Dest, +SparcV9RegInfo::cpValue2Value(Value *Src, Value *Dest, std::vector& mvec) const { int RegType = getRegTypeForDataType(Src->getType()); MachineInstr * MI = NULL; @@ -950,7 +953,7 @@ // Print the register assigned to a LR //--------------------------------------------------------------------------- -void SparcRegInfo::printReg(const LiveRange *LR) const { +void SparcV9RegInfo::printReg(const LiveRange *LR) const { unsigned RegClassID = LR->getRegClassID(); std::cerr << " Node "; Index: llvm/lib/Target/SparcV9/SparcV9RegInfo.h diff -u llvm/lib/Target/SparcV9/SparcV9RegInfo.h:1.8 llvm/lib/Target/SparcV9/SparcV9RegInfo.h:1.8.2.1 --- llvm/lib/Target/SparcV9/SparcV9RegInfo.h:1.8 Thu Jan 15 12:17:07 2004 +++ llvm/lib/Target/SparcV9/SparcV9RegInfo.h Mon Mar 1 17:58:15 2004 @@ -1,4 +1,4 @@ -//===-- SparcRegInfo.h - Define TargetRegInfo for Sparc ---------*- C++ -*-===// +//===-- SparcV9RegInfo.h - Define TargetRegInfo for SparcV9 ---------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// // -// This class implements the virtual class TargetRegInfo for Sparc. +// This class implements the virtual class TargetRegInfo for SparcV9. // //---------------------------------------------------------------------------- @@ -18,9 +18,9 @@ namespace llvm { -class SparcTargetMachine; +class SparcV9TargetMachine; -class SparcRegInfo : public TargetRegInfo { +class SparcV9RegInfo : public TargetRegInfo { private: @@ -34,7 +34,7 @@ // The following methods are used to color special live ranges (e.g. // function args and return values etc.) with specific hardware registers - // as required. See SparcRegInfo.cpp for the implementation. + // as required. See SparcV9RegInfo.cpp for the implementation. // void suggestReg4RetAddr(MachineInstr *RetMI, LiveRangeInfo &LRI) const; @@ -45,7 +45,7 @@ int getRegTypeForClassAndType(unsigned regClassID, const Type* type) const; public: - // Type of registers available in Sparc. There can be several reg types + // Type of registers available in SparcV9. There can be several reg types // in the same class. For instace, the float reg class has Single/Double // types // @@ -58,7 +58,7 @@ SpecialRegType }; - // The actual register classes in the Sparc + // The actual register classes in the SparcV9 // // **** WARNING: If this enum order is changed, also modify // getRegisterClassOfValue method below since it assumes this particular @@ -72,7 +72,7 @@ SpecialRegClassID // Special (unallocated) registers }; - SparcRegInfo(const SparcTargetMachine &tgt); + SparcV9RegInfo(const SparcV9TargetMachine &tgt); // To find the register class used for a specified Type // @@ -86,7 +86,7 @@ // getZeroRegNum - returns the register that contains always zero this is the // unified register number // - virtual int getZeroRegNum() const; + virtual unsigned getZeroRegNum() const; // getCallAddressReg - returns the reg used for pushing the address when a // function is called. This can be used for other purposes between calls @@ -115,7 +115,7 @@ // The following methods are used to color special live ranges (e.g. // function args and return values etc.) with specific hardware registers - // as required. See SparcRegInfo.cpp for the implementation for Sparc. + // as required. See SparcV9RegInfo.cpp for the implementation for SparcV9. // void suggestRegs4MethodArgs(const Function *Meth, LiveRangeInfo& LRI) const; @@ -135,7 +135,7 @@ void printReg(const LiveRange *LR) const; // returns the # of bytes of stack space allocated for each register - // type. For Sparc, currently we allocate 8 bytes on stack for all + // type. For SparcV9, currently we allocate 8 bytes on stack for all // register types. We can optimize this later if necessary to save stack // space (However, should make sure that stack alignment is correct) // Index: llvm/lib/Target/SparcV9/SparcV9SchedInfo.cpp diff -u llvm/lib/Target/SparcV9/SparcV9SchedInfo.cpp:1.9 llvm/lib/Target/SparcV9/SparcV9SchedInfo.cpp:1.9.2.1 --- llvm/lib/Target/SparcV9/SparcV9SchedInfo.cpp:1.9 Wed Dec 17 16:04:00 2003 +++ llvm/lib/Target/SparcV9/SparcV9SchedInfo.cpp Mon Mar 1 17:58:15 2004 @@ -1,4 +1,4 @@ -//===-- UltraSparcSchedInfo.cpp -------------------------------------------===// +//===-- UltraSparcV9SchedInfo.cpp -------------------------------------------===// // // The LLVM Compiler Infrastructure // @@ -7,11 +7,11 @@ // //===----------------------------------------------------------------------===// // -// Describe the scheduling characteristics of the UltraSparc +// Describe the scheduling characteristics of the UltraSparcV9 // //===----------------------------------------------------------------------===// -#include "SparcInternals.h" +#include "SparcV9Internals.h" using namespace llvm; @@ -129,7 +129,7 @@ //--------------------------------------------------------------------------- -// const InstrClassRUsage SparcRUsageDesc[] +// const InstrClassRUsage SparcV9RUsageDesc[] // // Purpose: // Resource usage information for instruction in each scheduling class. @@ -396,7 +396,7 @@ }; -static const InstrClassRUsage SparcRUsageDesc[] = { +static const InstrClassRUsage SparcV9RUsageDesc[] = { NoneClassRUsage, IEUNClassRUsage, IEU0ClassRUsage, @@ -412,14 +412,14 @@ //--------------------------------------------------------------------------- -// const InstrIssueDelta SparcInstrIssueDeltas[] +// const InstrIssueDelta SparcV9InstrIssueDeltas[] // // Purpose: // Changes to issue restrictions information in InstrClassRUsage for // instructions that differ from other instructions in their class. //--------------------------------------------------------------------------- -static const InstrIssueDelta SparcInstrIssueDeltas[] = { +static const InstrIssueDelta SparcV9InstrIssueDeltas[] = { // opCode, isSingleIssue, breaksGroup, numBubbles @@ -504,14 +504,14 @@ //--------------------------------------------------------------------------- -// const InstrRUsageDelta SparcInstrUsageDeltas[] +// const InstrRUsageDelta SparcV9InstrUsageDeltas[] // // Purpose: // Changes to resource usage information in InstrClassRUsage for // instructions that differ from other instructions in their class. //--------------------------------------------------------------------------- -static const InstrRUsageDelta SparcInstrUsageDeltas[] = { +static const InstrRUsageDelta SparcV9InstrUsageDeltas[] = { // MachineOpCode, Resource, Start cycle, Num cycles @@ -601,7 +601,7 @@ #ifdef EXPLICIT_BUBBLES_NEEDED // // MULScc inserts one bubble. - // This means it breaks the current group (captured in UltraSparcSchedInfo) + // This means it breaks the current group (captured in UltraSparcV9SchedInfo) // *and occupies all issue slots for the next cycle // //{ V9::MULScc, AllIssueSlots.rid, 2, 2-1 }, @@ -728,7 +728,7 @@ //--------------------------------------------------------------------------- -// class SparcSchedInfo +// class SparcV9SchedInfo // // Purpose: // Scheduling information for the UltraSPARC. @@ -737,34 +737,24 @@ //--------------------------------------------------------------------------- /*ctor*/ -SparcSchedInfo::SparcSchedInfo(const TargetMachine& tgt) +SparcV9SchedInfo::SparcV9SchedInfo(const TargetMachine& tgt) : TargetSchedInfo(tgt, (unsigned int) SPARC_NUM_SCHED_CLASSES, - SparcRUsageDesc, - SparcInstrUsageDeltas, - SparcInstrIssueDeltas, - sizeof(SparcInstrUsageDeltas)/sizeof(InstrRUsageDelta), - sizeof(SparcInstrIssueDeltas)/sizeof(InstrIssueDelta)) + SparcV9RUsageDesc, + SparcV9InstrUsageDeltas, + SparcV9InstrIssueDeltas, + sizeof(SparcV9InstrUsageDeltas)/sizeof(InstrRUsageDelta), + sizeof(SparcV9InstrIssueDeltas)/sizeof(InstrIssueDelta)) { maxNumIssueTotal = 4; longestIssueConflict = 0; // computed from issuesGaps[] - branchMispredictPenalty = 4; // 4 for SPARC IIi - branchTargetUnknownPenalty = 2; // 2 for SPARC IIi - l1DCacheMissPenalty = 8; // 7 or 9 for SPARC IIi - l1ICacheMissPenalty = 8; // ? for SPARC IIi - - inOrderLoads = true; // true for SPARC IIi - inOrderIssue = true; // true for SPARC IIi - inOrderExec = false; // false for most architectures - inOrderRetire= true; // true for most architectures - // must be called after above parameters are initialized. initializeResources(); } void -SparcSchedInfo::initializeResources() +SparcV9SchedInfo::initializeResources() { // Compute TargetSchedInfo::instrRUsages and TargetSchedInfo::issueGaps TargetSchedInfo::initializeResources(); Index: llvm/lib/Target/SparcV9/SparcV9StackSlots.cpp diff -u llvm/lib/Target/SparcV9/SparcV9StackSlots.cpp:1.9 llvm/lib/Target/SparcV9/SparcV9StackSlots.cpp:1.9.4.1 --- llvm/lib/Target/SparcV9/SparcV9StackSlots.cpp:1.9 Tue Nov 11 16:41:33 2003 +++ llvm/lib/Target/SparcV9/SparcV9StackSlots.cpp Mon Mar 1 17:58:15 2004 @@ -13,7 +13,7 @@ // //===----------------------------------------------------------------------===// -#include "SparcInternals.h" +#include "SparcV9Internals.h" #include "llvm/Constant.h" #include "llvm/DerivedTypes.h" #include "llvm/Function.h" Index: llvm/lib/Target/SparcV9/SparcV9TargetMachine.cpp diff -u llvm/lib/Target/SparcV9/SparcV9TargetMachine.cpp:1.98 llvm/lib/Target/SparcV9/SparcV9TargetMachine.cpp:1.98.2.1 --- llvm/lib/Target/SparcV9/SparcV9TargetMachine.cpp:1.98 Tue Jan 13 13:26:21 2004 +++ llvm/lib/Target/SparcV9/SparcV9TargetMachine.cpp Mon Mar 1 17:58:15 2004 @@ -1,4 +1,4 @@ -//===-- Sparc.cpp - General implementation file for the Sparc Target ------===// +//===-- SparcV9.cpp - General implementation file for the SparcV9 Target ------===// // // The LLVM Compiler Infrastructure // @@ -26,21 +26,21 @@ #include "llvm/Target/TargetMachineImpls.h" #include "llvm/Transforms/Scalar.h" #include "MappingInfo.h" -#include "SparcInternals.h" -#include "SparcTargetMachine.h" +#include "SparcV9Internals.h" +#include "SparcV9TargetMachine.h" #include "Support/CommandLine.h" using namespace llvm; static const unsigned ImplicitRegUseList[] = { 0 }; /* not used yet */ // Build the MachineInstruction Description Array... -const TargetInstrDescriptor llvm::SparcMachineInstrDesc[] = { +const TargetInstrDescriptor llvm::SparcV9MachineInstrDesc[] = { #define I(ENUM, OPCODESTRING, NUMOPERANDS, RESULTPOS, MAXIMM, IMMSE, \ NUMDELAYSLOTS, LATENCY, SCHEDCLASS, INSTFLAGS) \ { OPCODESTRING, NUMOPERANDS, RESULTPOS, MAXIMM, IMMSE, \ NUMDELAYSLOTS, LATENCY, SCHEDCLASS, INSTFLAGS, 0, \ ImplicitRegUseList, ImplicitRegUseList }, -#include "SparcInstr.def" +#include "SparcV9Instr.def" }; //--------------------------------------------------------------------------- @@ -82,7 +82,7 @@ }; struct DestroyMachineFunction : public FunctionPass { - const char *getPassName() const { return "FreeMachineFunction"; } + const char *getPassName() const { return "DestroyMachineFunction"; } static void freeMachineCode(Instruction &I) { MachineCodeForInstruction::destroy(&I); @@ -106,25 +106,24 @@ } } -FunctionPass *llvm::createSparcMachineCodeDestructionPass() { +FunctionPass *llvm::createSparcV9MachineCodeDestructionPass() { return new DestroyMachineFunction(); } -SparcTargetMachine::SparcTargetMachine(IntrinsicLowering *il) - : TargetMachine("UltraSparc-Native", il, false), +SparcV9TargetMachine::SparcV9TargetMachine(IntrinsicLowering *il) + : TargetMachine("UltraSparcV9-Native", il, false), schedInfo(*this), regInfo(*this), frameInfo(*this), - cacheInfo(*this), jitInfo(*this) { } -// addPassesToEmitAssembly - This method controls the entire code generation -// process for the ultra sparc. -// +/// addPassesToEmitAssembly - This method controls the entire code generation +/// process for the ultra sparc. +/// bool -SparcTargetMachine::addPassesToEmitAssembly(PassManager &PM, std::ostream &Out) +SparcV9TargetMachine::addPassesToEmitAssembly(PassManager &PM, std::ostream &Out) { // The following 3 passes used to be inserted specially by llc. // Replace malloc and free instructions with library calls. @@ -176,9 +175,10 @@ // function output is pipelined with all of the rest of code generation stuff, // allowing machine code representations for functions to be free'd after the // function has been emitted. - // PM.add(createAsmPrinterPass(Out, *this)); - PM.add(createSparcMachineCodeDestructionPass()); // Free mem no longer needed + + // Free machine-code IR which is no longer needed: + PM.add(createSparcV9MachineCodeDestructionPass()); // Emit bytecode to the assembly file into its special section next if (EmitMappingInfo) @@ -187,10 +187,10 @@ return false; } -// addPassesToJITCompile - This method controls the JIT method of code -// generation for the UltraSparc. -// -void SparcJITInfo::addPassesToJITCompile(FunctionPassManager &PM) { +/// addPassesToJITCompile - This method controls the JIT method of code +/// generation for the UltraSparcV9. +/// +void SparcV9JITInfo::addPassesToJITCompile(FunctionPassManager &PM) { const TargetData &TD = TM.getTargetData(); PM.add(new TargetData("lli", TD.isLittleEndian(), TD.getPointerSize(), @@ -230,12 +230,10 @@ PM.add(createPeepholeOptsPass(TM)); } -//---------------------------------------------------------------------------- -// allocateSparcTargetMachine - Allocate and return a subclass of TargetMachine -// that implements the Sparc backend. (the llvm/CodeGen/Sparc.h interface) -//---------------------------------------------------------------------------- - -TargetMachine *llvm::allocateSparcTargetMachine(const Module &M, +/// allocateSparcV9TargetMachine - Allocate and return a subclass of TargetMachine +/// that implements the SparcV9 backend. (the llvm/CodeGen/SparcV9.h interface) +/// +TargetMachine *llvm::allocateSparcV9TargetMachine(const Module &M, IntrinsicLowering *IL) { - return new SparcTargetMachine(IL); + return new SparcV9TargetMachine(IL); } Index: llvm/lib/Target/SparcV9/SparcV9TargetMachine.h diff -u llvm/lib/Target/SparcV9/SparcV9TargetMachine.h:1.4 llvm/lib/Target/SparcV9/SparcV9TargetMachine.h:1.4.2.1 --- llvm/lib/Target/SparcV9/SparcV9TargetMachine.h:1.4 Sun Dec 28 15:23:38 2003 +++ llvm/lib/Target/SparcV9/SparcV9TargetMachine.h Mon Mar 1 17:58:15 2004 @@ -1,4 +1,4 @@ -//===-- SparcTargetMachine.h - Define TargetMachine for Sparc ---*- C++ -*-===// +//===-- SparcV9TargetMachine.h - Define TargetMachine for SparcV9 ---*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -16,30 +16,28 @@ #include "llvm/Target/TargetFrameInfo.h" #include "llvm/Target/TargetMachine.h" -#include "SparcInstrInfo.h" -#include "SparcInternals.h" -#include "SparcRegInfo.h" -#include "SparcFrameInfo.h" -#include "SparcJITInfo.h" +#include "SparcV9InstrInfo.h" +#include "SparcV9Internals.h" +#include "SparcV9RegInfo.h" +#include "SparcV9FrameInfo.h" +#include "SparcV9JITInfo.h" namespace llvm { class PassManager; -class SparcTargetMachine : public TargetMachine { - SparcInstrInfo instrInfo; - SparcSchedInfo schedInfo; - SparcRegInfo regInfo; - SparcFrameInfo frameInfo; - SparcCacheInfo cacheInfo; - SparcJITInfo jitInfo; +class SparcV9TargetMachine : public TargetMachine { + SparcV9InstrInfo instrInfo; + SparcV9SchedInfo schedInfo; + SparcV9RegInfo regInfo; + SparcV9FrameInfo frameInfo; + SparcV9JITInfo jitInfo; public: - SparcTargetMachine(IntrinsicLowering *IL); + SparcV9TargetMachine(IntrinsicLowering *IL); virtual const TargetInstrInfo &getInstrInfo() const { return instrInfo; } virtual const TargetSchedInfo &getSchedInfo() const { return schedInfo; } virtual const TargetRegInfo &getRegInfo() const { return regInfo; } virtual const TargetFrameInfo &getFrameInfo() const { return frameInfo; } - virtual const TargetCacheInfo &getCacheInfo() const { return cacheInfo; } virtual TargetJITInfo *getJITInfo() { return &jitInfo; } virtual bool addPassesToEmitAssembly(PassManager &PM, std::ostream &Out); Index: llvm/lib/Target/SparcV9/SparcV9_F2.td diff -u llvm/lib/Target/SparcV9/SparcV9_F2.td:1.8 llvm/lib/Target/SparcV9/SparcV9_F2.td:1.8.6.1 --- llvm/lib/Target/SparcV9/SparcV9_F2.td:1.8 Tue Oct 21 10:17:13 2003 +++ llvm/lib/Target/SparcV9/SparcV9_F2.td Mon Mar 1 17:58:15 2004 @@ -1,4 +1,4 @@ -//===- SparcV9_F2.td - Format 2 instructions: Sparc V9 Target -------------===// +//===- SparcV9_F2.td - Format 2 instructions: SparcV9 V9 Target -------------===// // // The LLVM Compiler Infrastructure // @@ -32,7 +32,7 @@ class F2_2 cond, string name> : F2_br { // Format 2.2 instructions bits<22> disp; - bit annul = 0; // currently unused by Sparc backend + bit annul = 0; // currently unused by SparcV9 backend let Name = name; let Inst{29} = annul; @@ -44,7 +44,7 @@ bits<2> cc; bits<19> disp; bit predict = 1; - bit annul = 0; // currently unused by Sparc backend + bit annul = 0; // currently unused by SparcV9 backend let Name = name; let Inst{29} = annul; @@ -58,7 +58,7 @@ bits<5> rs1; bits<16> disp; bit predict = 1; - bit annul = 0; // currently unused by Sparc backend + bit annul = 0; // currently unused by SparcV9 backend let Name = name; let Inst{29} = annul; Index: llvm/lib/Target/SparcV9/SparcV9_F3.td diff -u llvm/lib/Target/SparcV9/SparcV9_F3.td:1.17 llvm/lib/Target/SparcV9/SparcV9_F3.td:1.17.6.1 --- llvm/lib/Target/SparcV9/SparcV9_F3.td:1.17 Tue Oct 21 10:17:13 2003 +++ llvm/lib/Target/SparcV9/SparcV9_F3.td Mon Mar 1 17:58:15 2004 @@ -1,4 +1,4 @@ -//===- SparcV9_F3.td - Format 3 Instructions: Sparc V9 Target -------------===// +//===- SparcV9_F3.td - Format 3 Instructions: SparcV9 V9 Target -------------===// // // The LLVM Compiler Infrastructure // Index: llvm/lib/Target/SparcV9/SparcV9_F4.td diff -u llvm/lib/Target/SparcV9/SparcV9_F4.td:1.10 llvm/lib/Target/SparcV9/SparcV9_F4.td:1.10.6.1 --- llvm/lib/Target/SparcV9/SparcV9_F4.td:1.10 Tue Oct 21 10:17:13 2003 +++ llvm/lib/Target/SparcV9/SparcV9_F4.td Mon Mar 1 17:58:15 2004 @@ -1,4 +1,4 @@ -//===- SparcV9_F4.td - Format 4 instructions: Sparc V9 Target -------------===// +//===- SparcV9_F4.td - Format 4 instructions: SparcV9 V9 Target -------------===// // // The LLVM Compiler Infrastructure // Index: llvm/lib/Target/SparcV9/SparcV9_Reg.td diff -u llvm/lib/Target/SparcV9/SparcV9_Reg.td:1.7 llvm/lib/Target/SparcV9/SparcV9_Reg.td:1.7.4.1 --- llvm/lib/Target/SparcV9/SparcV9_Reg.td:1.7 Sat Nov 8 12:12:24 2003 +++ llvm/lib/Target/SparcV9/SparcV9_Reg.td Mon Mar 1 17:58:15 2004 @@ -1,4 +1,4 @@ -//===- SparcV9_Reg.td - Sparc V9 Register definitions ---------------------===// +//===- SparcV9_Reg.td - SparcV9 V9 Register definitions ---------------------===// // // The LLVM Compiler Infrastructure // @@ -8,7 +8,7 @@ //===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===// -// Declarations that describe the Sparc register file +// Declarations that describe the SparcV9 register file //===----------------------------------------------------------------------===// // Ri - One of the 32 64 bit integer registers From brukman at cs.uiuc.edu Mon Mar 1 18:05:56 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Mar 1 18:05:56 2004 Subject: [llvm-commits] [parallel] CVS: llvm/lib/Target/X86/FloatingPoint.cpp InstSelectSimple.cpp PeepholeOptimizer.cpp Printer.cpp README.txt X86.td X86CodeEmitter.cpp X86InstrBuilder.h X86InstrInfo.cpp X86InstrInfo.h X86InstrInfo.td X86RegisterInfo.cpp X86RegisterInfo.h X86RegisterInfo.td X86TargetMachine.cpp X86TargetMachine.h Message-ID: <200403012358.RAA04106@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/X86: FloatingPoint.cpp updated: 1.16 -> 1.16.2.1 InstSelectSimple.cpp updated: 1.149 -> 1.149.2.1 PeepholeOptimizer.cpp updated: 1.9 -> 1.9.2.1 Printer.cpp updated: 1.76 -> 1.76.2.1 README.txt updated: 1.10 -> 1.10.6.1 X86.td updated: 1.7 -> 1.7.6.1 X86CodeEmitter.cpp updated: 1.46 -> 1.46.2.1 X86InstrBuilder.h updated: 1.9 -> 1.9.4.1 X86InstrInfo.cpp updated: 1.18 -> 1.18.2.1 X86InstrInfo.h updated: 1.30 -> 1.30.2.1 X86InstrInfo.td updated: 1.15 -> 1.15.2.1 X86RegisterInfo.cpp updated: 1.40 -> 1.40.4.1 X86RegisterInfo.h updated: 1.18 -> 1.18.4.1 X86RegisterInfo.td updated: 1.8 -> 1.8.6.1 X86TargetMachine.cpp updated: 1.44 -> 1.44.2.1 X86TargetMachine.h updated: 1.21 -> 1.21.2.1 --- Log message: Merge from trunk --- Diffs of the changes: (+2300 -1128) Index: llvm/lib/Target/X86/FloatingPoint.cpp diff -u llvm/lib/Target/X86/FloatingPoint.cpp:1.16 llvm/lib/Target/X86/FloatingPoint.cpp:1.16.2.1 --- llvm/lib/Target/X86/FloatingPoint.cpp:1.16 Sat Dec 20 10:22:59 2003 +++ llvm/lib/Target/X86/FloatingPoint.cpp Mon Mar 1 17:58:15 2004 @@ -8,7 +8,23 @@ //===----------------------------------------------------------------------===// // // This file defines the pass which converts floating point instructions from -// virtual registers into register stack instructions. +// virtual registers into register stack instructions. This pass uses live +// variable information to indicate where the FPn registers are used and their +// lifetimes. +// +// This pass is hampered by the lack of decent CFG manipulation routines for +// machine code. In particular, this wants to be able to split critical edges +// as necessary, traverse the machine basic block CFG in depth-first order, and +// allow there to be multiple machine basic blocks for each LLVM basicblock +// (needed for critical edge splitting). +// +// In particular, this pass currently barfs on critical edges. Because of this, +// it requires the instruction selector to insert FP_REG_KILL instructions on +// the exits of any basic block that has critical edges going from it, or which +// branch to a critical basic block. +// +// FIXME: this is not implemented yet. The stackifier pass only works on local +// basic blocks. // //===----------------------------------------------------------------------===// @@ -21,10 +37,14 @@ #include "llvm/CodeGen/Passes.h" #include "llvm/Target/TargetInstrInfo.h" #include "llvm/Target/TargetMachine.h" +#include "llvm/Function.h" // FIXME: remove when using MBB CFG! +#include "llvm/Support/CFG.h" // FIXME: remove when using MBB CFG! #include "Support/Debug.h" +#include "Support/DepthFirstIterator.h" #include "Support/Statistic.h" +#include "Support/STLExtras.h" #include -#include +#include using namespace llvm; namespace { @@ -75,7 +95,7 @@ return StackTop - 1 - getSlot(RegNo) + llvm::X86::ST0; } - // pushReg - Push the specifiex FP register onto the stack + // pushReg - Push the specified FP register onto the stack void pushReg(unsigned Reg) { assert(Reg < 8 && "Register number out of range!"); assert(StackTop < 8 && "Stack overflow!"); @@ -99,7 +119,7 @@ // Emit an fxch to update the runtime processors version of the state MachineInstr *MI = BuildMI(X86::FXCH, 1).addReg(STReg); - I = 1+MBB->insert(I, MI); + MBB->insert(I, MI); NumFXCH++; } } @@ -110,7 +130,7 @@ pushReg(AsReg); // New register on top of stack MachineInstr *MI = BuildMI(X86::FLDrr, 1).addReg(STReg); - I = 1+MBB->insert(I, MI); + MBB->insert(I, MI); } // popStackAfter - Pop the current value off of the top of the FP stack @@ -121,6 +141,7 @@ void handleZeroArgFP(MachineBasicBlock::iterator &I); void handleOneArgFP(MachineBasicBlock::iterator &I); + void handleOneArgFPRW(MachineBasicBlock::iterator &I); void handleTwoArgFP(MachineBasicBlock::iterator &I); void handleSpecialFP(MachineBasicBlock::iterator &I); }; @@ -135,9 +156,32 @@ LV = &getAnalysis(); StackTop = 0; - bool Changed = false; + // Figure out the mapping of MBB's to BB's. + // + // FIXME: Eventually we should be able to traverse the MBB CFG directly, and + // we will need to extend this when one llvm basic block can codegen to + // multiple MBBs. + // + // FIXME again: Just use the mapping established by LiveVariables! + // + std::map MBBMap; for (MachineFunction::iterator I = MF.begin(), E = MF.end(); I != E; ++I) - Changed |= processBasicBlock(MF, *I); + MBBMap[I->getBasicBlock()] = I; + + // Process the function in depth first order so that we process at least one + // of the predecessors for every reachable block in the function. + std::set Processed; + const BasicBlock *Entry = MF.getFunction()->begin(); + + bool Changed = false; + for (df_ext_iterator > + I = df_ext_begin(Entry, Processed), E = df_ext_end(Entry, Processed); + I != E; ++I) + Changed |= processBasicBlock(MF, *MBBMap[*I]); + + assert(MBBMap.size() == Processed.size() && + "Doesn't handle unreachable code yet!"); + return Changed; } @@ -150,11 +194,14 @@ MBB = &BB; for (MachineBasicBlock::iterator I = BB.begin(); I != BB.end(); ++I) { - MachineInstr *MI = *I; - MachineInstr *PrevMI = I == BB.begin() ? 0 : *(I-1); + MachineInstr *MI = I; unsigned Flags = TII.get(MI->getOpcode()).TSFlags; + if ((Flags & X86II::FPTypeMask) == X86II::NotFP) + continue; // Efficiently ignore non-fp insts! - if ((Flags & X86II::FPTypeMask) == 0) continue; // Ignore non-fp insts! + MachineInstr *PrevMI = 0; + if (I != BB.begin()) + PrevMI = prior(I); ++NumFP; // Keep track of # of pseudo instrs DEBUG(std::cerr << "\nFPInst:\t"; @@ -176,14 +223,11 @@ }); switch (Flags & X86II::FPTypeMask) { - case X86II::ZeroArgFP: handleZeroArgFP(I); break; - case X86II::OneArgFP: handleOneArgFP(I); break; - - case X86II::OneArgFPRW: // ST(0) = fsqrt(ST(0)) - assert(0 && "FP instr type not handled yet!"); - - case X86II::TwoArgFP: handleTwoArgFP(I); break; - case X86II::SpecialFP: handleSpecialFP(I); break; + case X86II::ZeroArgFP: handleZeroArgFP(I); break; + case X86II::OneArgFP: handleOneArgFP(I); break; // fstp ST(0) + case X86II::OneArgFPRW: handleOneArgFPRW(I); break; // ST(0) = fsqrt(ST(0)) + case X86II::TwoArgFP: handleTwoArgFP(I); break; + case X86II::SpecialFP: handleSpecialFP(I); break; default: assert(0 && "Unknown FP Type!"); } @@ -201,18 +245,20 @@ } // Print out all of the instructions expanded to if -debug - DEBUG(if (*I == PrevMI) { - std::cerr<< "Just deleted pseudo instruction\n"; - } else { - MachineBasicBlock::iterator Start = I; - // Rewind to first instruction newly inserted. - while (Start != BB.begin() && *(Start-1) != PrevMI) --Start; - std::cerr << "Inserted instructions:\n\t"; - (*Start)->print(std::cerr, MF.getTarget()); - while (++Start != I+1); - } - dumpStack(); - ); + DEBUG( + MachineBasicBlock::iterator PrevI(PrevMI); + if (I == PrevI) { + std::cerr<< "Just deleted pseudo instruction\n"; + } else { + MachineBasicBlock::iterator Start = I; + // Rewind to first instruction newly inserted. + while (Start != BB.begin() && prior(Start) != PrevI) --Start; + std::cerr << "Inserted instructions:\n\t"; + Start->print(std::cerr, MF.getTarget()); + while (++Start != next(I)); + } + dumpStack(); + ); Changed = true; } @@ -275,13 +321,13 @@ { X86::FDIVRrST0, X86::FDIVRPrST0 }, { X86::FDIVrST0 , X86::FDIVPrST0 }, - { X86::FISTr16 , X86::FISTPr16 }, - { X86::FISTr32 , X86::FISTPr32 }, + { X86::FIST16m , X86::FISTP16m }, + { X86::FIST32m , X86::FISTP32m }, { X86::FMULrST0 , X86::FMULPrST0 }, - { X86::FSTr32 , X86::FSTPr32 }, - { X86::FSTr64 , X86::FSTPr64 }, + { X86::FST32m , X86::FSTP32m }, + { X86::FST64m , X86::FSTP64m }, { X86::FSTrr , X86::FSTPrr }, { X86::FSUBRrST0, X86::FSUBRPrST0 }, @@ -303,20 +349,20 @@ RegMap[Stack[--StackTop]] = ~0; // Update state // Check to see if there is a popping version of this instruction... - int Opcode = Lookup(PopTable, ARRAY_SIZE(PopTable), (*I)->getOpcode()); + int Opcode = Lookup(PopTable, ARRAY_SIZE(PopTable), I->getOpcode()); if (Opcode != -1) { - (*I)->setOpcode(Opcode); + I->setOpcode(Opcode); if (Opcode == X86::FUCOMPPr) - (*I)->RemoveOperand(0); + I->RemoveOperand(0); } else { // Insert an explicit pop MachineInstr *MI = BuildMI(X86::FSTPrr, 1).addReg(X86::ST0); - I = MBB->insert(I+1, MI); + I = MBB->insert(++I, MI); } } static unsigned getFPReg(const MachineOperand &MO) { - assert(MO.isPhysicalRegister() && "Expected an FP register!"); + assert(MO.isRegister() && "Expected an FP register!"); unsigned Reg = MO.getReg(); assert(Reg >= X86::FP0 && Reg <= X86::FP6 && "Expected FP register!"); return Reg - X86::FP0; @@ -328,9 +374,9 @@ //===----------------------------------------------------------------------===// /// handleZeroArgFP - ST(0) = fld0 ST(0) = flds -// +/// void FPS::handleZeroArgFP(MachineBasicBlock::iterator &I) { - MachineInstr *MI = *I; + MachineInstr *MI = I; unsigned DestReg = getFPReg(MI->getOperand(0)); MI->RemoveOperand(0); // Remove the explicit ST(0) operand @@ -338,32 +384,34 @@ pushReg(DestReg); } -/// handleOneArgFP - fst ST(0), -// +/// handleOneArgFP - fst , ST(0) +/// void FPS::handleOneArgFP(MachineBasicBlock::iterator &I) { - MachineInstr *MI = *I; - assert(MI->getNumOperands() == 5 && "Can only handle fst* instructions!"); + MachineInstr *MI = I; + assert((MI->getNumOperands() == 5 || MI->getNumOperands() == 1) && + "Can only handle fst* & ftst instructions!"); - unsigned Reg = getFPReg(MI->getOperand(4)); + // Is this the last use of the source register? + unsigned Reg = getFPReg(MI->getOperand(MI->getNumOperands()-1)); bool KillsSrc = false; for (LiveVariables::killed_iterator KI = LV->killed_begin(MI), E = LV->killed_end(MI); KI != E; ++KI) KillsSrc |= KI->second == X86::FP0+Reg; - // FSTPr80 and FISTPr64 are strange because there are no non-popping versions. + // FSTP80r and FISTP64r are strange because there are no non-popping versions. // If we have one _and_ we don't want to pop the operand, duplicate the value // on the stack instead of moving it. This ensure that popping the value is // always ok. // - if ((MI->getOpcode() == X86::FSTPr80 || - MI->getOpcode() == X86::FISTPr64) && !KillsSrc) { + if ((MI->getOpcode() == X86::FSTP80m || + MI->getOpcode() == X86::FISTP64m) && !KillsSrc) { duplicateToTop(Reg, 7 /*temp register*/, I); } else { moveToTop(Reg, I); // Move to the top of the stack... } - MI->RemoveOperand(4); // Remove explicit ST(0) operand + MI->RemoveOperand(MI->getNumOperands()-1); // Remove explicit ST(0) operand - if (MI->getOpcode() == X86::FSTPr80 || MI->getOpcode() == X86::FISTPr64) { + if (MI->getOpcode() == X86::FSTP80m || MI->getOpcode() == X86::FISTP64m) { assert(StackTop > 0 && "Stack empty??"); --StackTop; } else if (KillsSrc) { // Last use of operand? @@ -371,6 +419,38 @@ } } + +/// handleOneArgFPRW - fchs - ST(0) = -ST(0) +/// +void FPS::handleOneArgFPRW(MachineBasicBlock::iterator &I) { + MachineInstr *MI = I; + assert(MI->getNumOperands() == 2 && "Can only handle fst* instructions!"); + + // Is this the last use of the source register? + unsigned Reg = getFPReg(MI->getOperand(1)); + bool KillsSrc = false; + for (LiveVariables::killed_iterator KI = LV->killed_begin(MI), + E = LV->killed_end(MI); KI != E; ++KI) + KillsSrc |= KI->second == X86::FP0+Reg; + + if (KillsSrc) { + // If this is the last use of the source register, just make sure it's on + // the top of the stack. + moveToTop(Reg, I); + assert(StackTop > 0 && "Stack cannot be empty!"); + --StackTop; + pushReg(getFPReg(MI->getOperand(0))); + } else { + // If this is not the last use of the source register, _copy_ it to the top + // of the stack. + duplicateToTop(Reg, getFPReg(MI->getOperand(0)), I); + } + + MI->RemoveOperand(1); // Drop the source operand. + MI->RemoveOperand(0); // Drop the destination operand. +} + + //===----------------------------------------------------------------------===// // Define tables of various ways to map pseudo instructions // @@ -428,7 +508,7 @@ void FPS::handleTwoArgFP(MachineBasicBlock::iterator &I) { ASSERT_SORTED(ForwardST0Table); ASSERT_SORTED(ReverseST0Table); ASSERT_SORTED(ForwardSTiTable); ASSERT_SORTED(ReverseSTiTable); - MachineInstr *MI = *I; + MachineInstr *MI = I; unsigned NumOperands = MI->getNumOperands(); assert(NumOperands == 3 || @@ -513,7 +593,8 @@ unsigned NotTOS = (TOS == Op0) ? Op1 : Op0; // Replace the old instruction with a new instruction - *I = BuildMI(Opcode, 1).addReg(getSTReg(NotTOS)); + MBB->remove(I); + I = MBB->insert(I, BuildMI(Opcode, 1).addReg(getSTReg(NotTOS))); // If both operands are killed, pop one off of the stack in addition to // overwriting the other one. @@ -542,7 +623,7 @@ Stack[--StackTop] = ~0; MachineInstr *MI = BuildMI(X86::FSTPrr, 1).addReg(STReg); - I = MBB->insert(I+1, MI); + I = MBB->insert(++I, MI); } } } @@ -564,7 +645,7 @@ /// instructions. /// void FPS::handleSpecialFP(MachineBasicBlock::iterator &I) { - MachineInstr *MI = *I; + MachineInstr *MI = I; switch (MI->getOpcode()) { default: assert(0 && "Unknown SpecialFP instruction!"); case X86::FpGETRESULT: // Appears immediately after a call returning FP type! @@ -600,6 +681,6 @@ } } - I = MBB->erase(I)-1; // Remove the pseudo instruction - delete MI; + I = MBB->erase(I); // Remove the pseudo instruction + --I; } Index: llvm/lib/Target/X86/InstSelectSimple.cpp diff -u llvm/lib/Target/X86/InstSelectSimple.cpp:1.149 llvm/lib/Target/X86/InstSelectSimple.cpp:1.149.2.1 --- llvm/lib/Target/X86/InstSelectSimple.cpp:1.149 Mon Jan 12 01:22:45 2004 +++ llvm/lib/Target/X86/InstSelectSimple.cpp Mon Mar 1 17:58:15 2004 @@ -23,44 +23,27 @@ #include "llvm/CodeGen/MachineConstantPool.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineFunction.h" -#include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/SSARegMap.h" #include "llvm/Target/MRegisterInfo.h" #include "llvm/Target/TargetMachine.h" +#include "llvm/Support/GetElementPtrTypeIterator.h" #include "llvm/Support/InstVisitor.h" +#include "llvm/Support/CFG.h" +#include "Support/Statistic.h" using namespace llvm; -/// BMI - A special BuildMI variant that takes an iterator to insert the -/// instruction at as well as a basic block. This is the version for when you -/// have a destination register in mind. -inline static MachineInstrBuilder BMI(MachineBasicBlock *MBB, - MachineBasicBlock::iterator &I, - int Opcode, unsigned NumOperands, - unsigned DestReg) { - assert(I >= MBB->begin() && I <= MBB->end() && "Bad iterator!"); - MachineInstr *MI = new MachineInstr(Opcode, NumOperands+1, true, true); - I = MBB->insert(I, MI)+1; - return MachineInstrBuilder(MI).addReg(DestReg, MOTy::Def); -} - -/// BMI - A special BuildMI variant that takes an iterator to insert the -/// instruction at as well as a basic block. -inline static MachineInstrBuilder BMI(MachineBasicBlock *MBB, - MachineBasicBlock::iterator &I, - int Opcode, unsigned NumOperands) { - assert(I >= MBB->begin() && I <= MBB->end() && "Bad iterator!"); - MachineInstr *MI = new MachineInstr(Opcode, NumOperands, true, true); - I = MBB->insert(I, MI)+1; - return MachineInstrBuilder(MI); +namespace { + Statistic<> + NumFPKill("x86-codegen", "Number of FP_REG_KILL instructions added"); } - namespace { struct ISel : public FunctionPass, InstVisitor { TargetMachine &TM; MachineFunction *F; // The function we are compiling into MachineBasicBlock *BB; // The current MBB we are compiling int VarArgsFrameIndex; // FrameIndex for start of varargs area + int ReturnAddressIndex; // FrameIndex for the return address std::map RegMap; // Mapping between Val's and SSA Regs @@ -85,6 +68,10 @@ BB = &F->front(); + // Set up a frame object for the return address. This is used by the + // llvm.returnaddress & llvm.frameaddress intrinisics. + ReturnAddressIndex = F->getFrameInfo()->CreateFixedObject(4, -4); + // Copy incoming arguments off of the stack... LoadArgumentsToVirtualRegs(Fn); @@ -94,6 +81,9 @@ // Select the PHI nodes SelectPHINodes(); + // Insert the FP_REG_KILL instructions into blocks that need them. + InsertFPRegKills(); + RegMap.clear(); MBBMap.clear(); F = 0; @@ -130,6 +120,12 @@ /// void SelectPHINodes(); + /// InsertFPRegKills - Insert FP_REG_KILL instructions into basic blocks + /// that need them. This only occurs due to the floating point stackifier + /// not being aggressive enough to handle arbitrary global stackification. + /// + void InsertFPRegKills(); + // Visitation methods for various instructions. These methods simply emit // fixed X86 code for each instruction. // @@ -154,11 +150,11 @@ void visitSimpleBinary(BinaryOperator &B, unsigned OpcodeClass); void visitAdd(BinaryOperator &B) { visitSimpleBinary(B, 0); } void visitSub(BinaryOperator &B) { visitSimpleBinary(B, 1); } - void doMultiply(MachineBasicBlock *MBB, MachineBasicBlock::iterator &MBBI, + void doMultiply(MachineBasicBlock *MBB, MachineBasicBlock::iterator MBBI, unsigned DestReg, const Type *DestTy, unsigned Op0Reg, unsigned Op1Reg); void doMultiplyConst(MachineBasicBlock *MBB, - MachineBasicBlock::iterator &MBBI, + MachineBasicBlock::iterator MBBI, unsigned DestReg, const Type *DestTy, unsigned Op0Reg, unsigned Op1Val); void visitMul(BinaryOperator &B); @@ -176,7 +172,7 @@ void visitSetCondInst(SetCondInst &I); unsigned EmitComparison(unsigned OpNum, Value *Op0, Value *Op1, MachineBasicBlock *MBB, - MachineBasicBlock::iterator &MBBI); + MachineBasicBlock::iterator MBBI); // Memory Instructions void visitLoadInst(LoadInst &I); @@ -202,41 +198,55 @@ /// void promote32(unsigned targetReg, const ValueRecord &VR); + // getGEPIndex - This is used to fold GEP instructions into X86 addressing + // expressions. + void getGEPIndex(MachineBasicBlock *MBB, MachineBasicBlock::iterator IP, + std::vector &GEPOps, + std::vector &GEPTypes, unsigned &BaseReg, + unsigned &Scale, unsigned &IndexReg, unsigned &Disp); + + /// isGEPFoldable - Return true if the specified GEP can be completely + /// folded into the addressing mode of a load/store or lea instruction. + bool isGEPFoldable(MachineBasicBlock *MBB, + Value *Src, User::op_iterator IdxBegin, + User::op_iterator IdxEnd, unsigned &BaseReg, + unsigned &Scale, unsigned &IndexReg, unsigned &Disp); + /// emitGEPOperation - Common code shared between visitGetElementPtrInst and /// constant expression GEP support. /// - void emitGEPOperation(MachineBasicBlock *BB, MachineBasicBlock::iterator&IP, + void emitGEPOperation(MachineBasicBlock *BB, MachineBasicBlock::iterator IP, Value *Src, User::op_iterator IdxBegin, User::op_iterator IdxEnd, unsigned TargetReg); /// emitCastOperation - Common code shared between visitCastInst and /// constant expression cast support. - void emitCastOperation(MachineBasicBlock *BB,MachineBasicBlock::iterator&IP, + void emitCastOperation(MachineBasicBlock *BB,MachineBasicBlock::iterator IP, Value *Src, const Type *DestTy, unsigned TargetReg); /// emitSimpleBinaryOperation - Common code shared between visitSimpleBinary /// and constant expression support. void emitSimpleBinaryOperation(MachineBasicBlock *BB, - MachineBasicBlock::iterator &IP, + MachineBasicBlock::iterator IP, Value *Op0, Value *Op1, unsigned OperatorClass, unsigned TargetReg); void emitDivRemOperation(MachineBasicBlock *BB, - MachineBasicBlock::iterator &IP, + MachineBasicBlock::iterator IP, unsigned Op0Reg, unsigned Op1Reg, bool isDiv, const Type *Ty, unsigned TargetReg); /// emitSetCCOperation - Common code shared between visitSetCondInst and /// constant expression support. void emitSetCCOperation(MachineBasicBlock *BB, - MachineBasicBlock::iterator &IP, + MachineBasicBlock::iterator IP, Value *Op0, Value *Op1, unsigned Opcode, unsigned TargetReg); /// emitShiftOperation - Common code shared between visitShiftInst and /// constant expression support. void emitShiftOperation(MachineBasicBlock *MBB, - MachineBasicBlock::iterator &IP, + MachineBasicBlock::iterator IP, Value *Op, Value *ShiftAmount, bool isLeftShift, const Type *ResultTy, unsigned DestReg); @@ -245,7 +255,7 @@ /// specified constant into the specified register. /// void copyConstantToRegister(MachineBasicBlock *MBB, - MachineBasicBlock::iterator &MBBI, + MachineBasicBlock::iterator MBBI, Constant *C, unsigned Reg); /// makeAnotherReg - This method returns the next register number we haven't @@ -285,7 +295,7 @@ return getReg(V, BB, It); } unsigned getReg(Value *V, MachineBasicBlock *MBB, - MachineBasicBlock::iterator &IPt) { + MachineBasicBlock::iterator IPt) { unsigned &Reg = RegMap[V]; if (Reg == 0) { Reg = makeAnotherReg(V->getType()); @@ -300,7 +310,7 @@ RegMap.erase(V); // Assign a new name to this constant if ref'd again } else if (GlobalValue *GV = dyn_cast(V)) { // Move the address of the global into the register - BMI(MBB, IPt, X86::MOVir32, 1, Reg).addGlobalAddress(GV); + BuildMI(*MBB, IPt, X86::MOV32ri, 1, Reg).addGlobalAddress(GV); RegMap.erase(V); // Assign a new name to this address if ref'd again } @@ -351,7 +361,7 @@ /// specified constant into the specified register. /// void ISel::copyConstantToRegister(MachineBasicBlock *MBB, - MachineBasicBlock::iterator &IP, + MachineBasicBlock::iterator IP, Constant *C, unsigned R) { if (ConstantExpr *CE = dyn_cast(C)) { unsigned Class = 0; @@ -417,29 +427,28 @@ if (Class == cLong) { // Copy the value into the register pair. uint64_t Val = cast(C)->getRawValue(); - BMI(MBB, IP, X86::MOVir32, 1, R).addZImm(Val & 0xFFFFFFFF); - BMI(MBB, IP, X86::MOVir32, 1, R+1).addZImm(Val >> 32); + BuildMI(*MBB, IP, X86::MOV32ri, 1, R).addImm(Val & 0xFFFFFFFF); + BuildMI(*MBB, IP, X86::MOV32ri, 1, R+1).addImm(Val >> 32); return; } assert(Class <= cInt && "Type not handled yet!"); static const unsigned IntegralOpcodeTab[] = { - X86::MOVir8, X86::MOVir16, X86::MOVir32 + X86::MOV8ri, X86::MOV16ri, X86::MOV32ri }; if (C->getType() == Type::BoolTy) { - BMI(MBB, IP, X86::MOVir8, 1, R).addZImm(C == ConstantBool::True); + BuildMI(*MBB, IP, X86::MOV8ri, 1, R).addImm(C == ConstantBool::True); } else { ConstantInt *CI = cast(C); - BMI(MBB, IP, IntegralOpcodeTab[Class], 1, R).addZImm(CI->getRawValue()); + BuildMI(*MBB, IP, IntegralOpcodeTab[Class],1,R).addImm(CI->getRawValue()); } } else if (ConstantFP *CFP = dyn_cast(C)) { - double Value = CFP->getValue(); - if (Value == +0.0) - BMI(MBB, IP, X86::FLD0, 0, R); - else if (Value == +1.0) - BMI(MBB, IP, X86::FLD1, 0, R); + if (CFP->isExactlyValue(+0.0)) + BuildMI(*MBB, IP, X86::FLD0, 0, R); + else if (CFP->isExactlyValue(+1.0)) + BuildMI(*MBB, IP, X86::FLD1, 0, R); else { // Otherwise we need to spill the constant to memory... MachineConstantPool *CP = F->getConstantPool(); @@ -447,16 +456,15 @@ const Type *Ty = CFP->getType(); assert(Ty == Type::FloatTy || Ty == Type::DoubleTy && "Unknown FP type!"); - unsigned LoadOpcode = Ty == Type::FloatTy ? X86::FLDr32 : X86::FLDr64; - addConstantPoolReference(BMI(MBB, IP, LoadOpcode, 4, R), CPI); + unsigned LoadOpcode = Ty == Type::FloatTy ? X86::FLD32m : X86::FLD64m; + addConstantPoolReference(BuildMI(*MBB, IP, LoadOpcode, 4, R), CPI); } } else if (isa(C)) { // Copy zero (null pointer) to the register. - BMI(MBB, IP, X86::MOVir32, 1, R).addZImm(0); + BuildMI(*MBB, IP, X86::MOV32ri, 1, R).addImm(0); } else if (ConstantPointerRef *CPR = dyn_cast(C)) { - unsigned SrcReg = getReg(CPR->getValue(), MBB, IP); - BMI(MBB, IP, X86::MOVrr32, 1, R).addReg(SrcReg); + BuildMI(*MBB, IP, X86::MOV32ri, 1, R).addGlobalAddress(CPR->getValue()); } else { std::cerr << "Offending constant: " << C << "\n"; assert(0 && "Type not handled yet!"); @@ -485,29 +493,29 @@ switch (getClassB(I->getType())) { case cByte: FI = MFI->CreateFixedObject(1, ArgOffset); - addFrameReference(BuildMI(BB, X86::MOVmr8, 4, Reg), FI); + addFrameReference(BuildMI(BB, X86::MOV8rm, 4, Reg), FI); break; case cShort: FI = MFI->CreateFixedObject(2, ArgOffset); - addFrameReference(BuildMI(BB, X86::MOVmr16, 4, Reg), FI); + addFrameReference(BuildMI(BB, X86::MOV16rm, 4, Reg), FI); break; case cInt: FI = MFI->CreateFixedObject(4, ArgOffset); - addFrameReference(BuildMI(BB, X86::MOVmr32, 4, Reg), FI); + addFrameReference(BuildMI(BB, X86::MOV32rm, 4, Reg), FI); break; case cLong: FI = MFI->CreateFixedObject(8, ArgOffset); - addFrameReference(BuildMI(BB, X86::MOVmr32, 4, Reg), FI); - addFrameReference(BuildMI(BB, X86::MOVmr32, 4, Reg+1), FI, 4); + addFrameReference(BuildMI(BB, X86::MOV32rm, 4, Reg), FI); + addFrameReference(BuildMI(BB, X86::MOV32rm, 4, Reg+1), FI, 4); ArgOffset += 4; // longs require 4 additional bytes break; case cFP: unsigned Opcode; if (I->getType() == Type::FloatTy) { - Opcode = X86::FLDr32; + Opcode = X86::FLD32m; FI = MFI->CreateFixedObject(4, ArgOffset); } else { - Opcode = X86::FLDr64; + Opcode = X86::FLD64m; FI = MFI->CreateFixedObject(8, ArgOffset); ArgOffset += 4; // doubles require 4 additional bytes } @@ -536,23 +544,22 @@ const Function &LF = *F->getFunction(); // The LLVM function... for (Function::const_iterator I = LF.begin(), E = LF.end(); I != E; ++I) { const BasicBlock *BB = I; - MachineBasicBlock *MBB = MBBMap[I]; + MachineBasicBlock &MBB = *MBBMap[I]; // Loop over all of the PHI nodes in the LLVM basic block... - unsigned NumPHIs = 0; + MachineBasicBlock::iterator PHIInsertPoint = MBB.begin(); for (BasicBlock::const_iterator I = BB->begin(); PHINode *PN = const_cast(dyn_cast(I)); ++I) { // Create a new machine instr PHI node, and insert it. unsigned PHIReg = getReg(*PN); - MachineInstr *PhiMI = BuildMI(X86::PHI, PN->getNumOperands(), PHIReg); - MBB->insert(MBB->begin()+NumPHIs++, PhiMI); + MachineInstr *PhiMI = BuildMI(MBB, PHIInsertPoint, + X86::PHI, PN->getNumOperands(), PHIReg); MachineInstr *LongPhiMI = 0; - if (PN->getType() == Type::LongTy || PN->getType() == Type::ULongTy) { - LongPhiMI = BuildMI(X86::PHI, PN->getNumOperands(), PHIReg+1); - MBB->insert(MBB->begin()+NumPHIs++, LongPhiMI); - } + if (PN->getType() == Type::LongTy || PN->getType() == Type::ULongTy) + LongPhiMI = BuildMI(MBB, PHIInsertPoint, + X86::PHI, PN->getNumOperands(), PHIReg+1); // PHIValues - Map of blocks to incoming virtual registers. We use this // so that we only initialize one incoming value for a particular block, @@ -586,7 +593,7 @@ MachineBasicBlock::iterator PI = PredMBB->begin(); // Skip over any PHI nodes though! - while (PI != PredMBB->end() && (*PI)->getOpcode() == X86::PHI) + while (PI != PredMBB->end() && PI->getOpcode() == X86::PHI) ++PI; ValReg = getReg(Val, PredMBB, PI); @@ -605,10 +612,106 @@ LongPhiMI->addMachineBasicBlockOperand(PredMBB); } } + + // Now that we emitted all of the incoming values for the PHI node, make + // sure to reposition the InsertPoint after the PHI that we just added. + // This is needed because we might have inserted a constant into this + // block, right after the PHI's which is before the old insert point! + PHIInsertPoint = LongPhiMI ? LongPhiMI : PhiMI; + ++PHIInsertPoint; } } } +/// RequiresFPRegKill - The floating point stackifier pass cannot insert +/// compensation code on critical edges. As such, it requires that we kill all +/// FP registers on the exit from any blocks that either ARE critical edges, or +/// branch to a block that has incoming critical edges. +/// +/// Note that this kill instruction will eventually be eliminated when +/// restrictions in the stackifier are relaxed. +/// +static bool RequiresFPRegKill(const BasicBlock *BB) { +#if 0 + for (succ_const_iterator SI = succ_begin(BB), E = succ_end(BB); SI!=E; ++SI) { + const BasicBlock *Succ = *SI; + pred_const_iterator PI = pred_begin(Succ), PE = pred_end(Succ); + ++PI; // Block have at least one predecessory + if (PI != PE) { // If it has exactly one, this isn't crit edge + // If this block has more than one predecessor, check all of the + // predecessors to see if they have multiple successors. If so, then the + // block we are analyzing needs an FPRegKill. + for (PI = pred_begin(Succ); PI != PE; ++PI) { + const BasicBlock *Pred = *PI; + succ_const_iterator SI2 = succ_begin(Pred); + ++SI2; // There must be at least one successor of this block. + if (SI2 != succ_end(Pred)) + return true; // Yes, we must insert the kill on this edge. + } + } + } + // If we got this far, there is no need to insert the kill instruction. + return false; +#else + return true; +#endif +} + +// InsertFPRegKills - Insert FP_REG_KILL instructions into basic blocks that +// need them. This only occurs due to the floating point stackifier not being +// aggressive enough to handle arbitrary global stackification. +// +// Currently we insert an FP_REG_KILL instruction into each block that uses or +// defines a floating point virtual register. +// +// When the global register allocators (like linear scan) finally update live +// variable analysis, we can keep floating point values in registers across +// portions of the CFG that do not involve critical edges. This will be a big +// win, but we are waiting on the global allocators before we can do this. +// +// With a bit of work, the floating point stackifier pass can be enhanced to +// break critical edges as needed (to make a place to put compensation code), +// but this will require some infrastructure improvements as well. +// +void ISel::InsertFPRegKills() { + SSARegMap &RegMap = *F->getSSARegMap(); + + for (MachineFunction::iterator BB = F->begin(), E = F->end(); BB != E; ++BB) { + for (MachineBasicBlock::iterator I = BB->begin(), E = BB->end(); I!=E; ++I) + for (unsigned i = 0, e = I->getNumOperands(); i != e; ++i) { + MachineOperand& MO = I->getOperand(i); + if (MO.isRegister() && MO.getReg()) { + unsigned Reg = MO.getReg(); + if (MRegisterInfo::isVirtualRegister(Reg)) + if (RegMap.getRegClass(Reg)->getSize() == 10) + goto UsesFPReg; + } + } + // If we haven't found an FP register use or def in this basic block, check + // to see if any of our successors has an FP PHI node, which will cause a + // copy to be inserted into this block. + for (succ_const_iterator SI = succ_begin(BB->getBasicBlock()), + E = succ_end(BB->getBasicBlock()); SI != E; ++SI) { + MachineBasicBlock *SBB = MBBMap[*SI]; + for (MachineBasicBlock::iterator I = SBB->begin(); + I != SBB->end() && I->getOpcode() == X86::PHI; ++I) { + if (RegMap.getRegClass(I->getOperand(0).getReg())->getSize() == 10) + goto UsesFPReg; + } + } + continue; + UsesFPReg: + // Okay, this block uses an FP register. If the block has successors (ie, + // it's not an unwind/return), insert the FP_REG_KILL instruction. + if (BB->getBasicBlock()->getTerminator()->getNumSuccessors() && + RequiresFPRegKill(BB->getBasicBlock())) { + BuildMI(*BB, BB->getFirstTerminator(), X86::FP_REG_KILL, 0); + ++NumFPKill; + } + } +} + + // canFoldSetCCIntoBranch - Return the setcc instruction if we can fold it into // the conditional branch instruction which is the only user of the cc // instruction. This is the case if the conditional branch is the only user of @@ -664,7 +767,7 @@ // returning the extended setcc code to use. unsigned ISel::EmitComparison(unsigned OpNum, Value *Op0, Value *Op1, MachineBasicBlock *MBB, - MachineBasicBlock::iterator &IP) { + MachineBasicBlock::iterator IP) { // The arguments are already supposed to be of the same type. const Type *CompTy = Op0->getType(); unsigned Class = getClassB(CompTy); @@ -683,9 +786,9 @@ // !=. These should have been strength reduced already anyway. if (Op1v == 0 && (CompTy->isSigned() || OpNum < 2)) { static const unsigned TESTTab[] = { - X86::TESTrr8, X86::TESTrr16, X86::TESTrr32 + X86::TEST8rr, X86::TEST16rr, X86::TEST32rr }; - BMI(MBB, IP, TESTTab[Class], 2).addReg(Op0r).addReg(Op0r); + BuildMI(*MBB, IP, TESTTab[Class], 2).addReg(Op0r).addReg(Op0r); if (OpNum == 2) return 6; // Map jl -> js if (OpNum == 3) return 7; // Map jg -> jns @@ -693,10 +796,19 @@ } static const unsigned CMPTab[] = { - X86::CMPri8, X86::CMPri16, X86::CMPri32 + X86::CMP8ri, X86::CMP16ri, X86::CMP32ri }; - BMI(MBB, IP, CMPTab[Class], 2).addReg(Op0r).addZImm(Op1v); + BuildMI(*MBB, IP, CMPTab[Class], 2).addReg(Op0r).addImm(Op1v); + return OpNum; + } + + // Special case handling of comparison against +/- 0.0 + if (ConstantFP *CFP = dyn_cast(Op1)) + if (CFP->isExactlyValue(+0.0) || CFP->isExactlyValue(-0.0)) { + BuildMI(*MBB, IP, X86::FTST, 1).addReg(Op0r); + BuildMI(*MBB, IP, X86::FNSTSW8r, 0); + BuildMI(*MBB, IP, X86::SAHF, 1); return OpNum; } @@ -707,18 +819,18 @@ // compare 8-bit with 8-bit, 16-bit with 16-bit, 32-bit with // 32-bit. case cByte: - BMI(MBB, IP, X86::CMPrr8, 2).addReg(Op0r).addReg(Op1r); + BuildMI(*MBB, IP, X86::CMP8rr, 2).addReg(Op0r).addReg(Op1r); break; case cShort: - BMI(MBB, IP, X86::CMPrr16, 2).addReg(Op0r).addReg(Op1r); + BuildMI(*MBB, IP, X86::CMP16rr, 2).addReg(Op0r).addReg(Op1r); break; case cInt: - BMI(MBB, IP, X86::CMPrr32, 2).addReg(Op0r).addReg(Op1r); + BuildMI(*MBB, IP, X86::CMP32rr, 2).addReg(Op0r).addReg(Op1r); break; case cFP: - BMI(MBB, IP, X86::FpUCOM, 2).addReg(Op0r).addReg(Op1r); - BMI(MBB, IP, X86::FNSTSWr8, 0); - BMI(MBB, IP, X86::SAHF, 1); + BuildMI(*MBB, IP, X86::FpUCOM, 2).addReg(Op0r).addReg(Op1r); + BuildMI(*MBB, IP, X86::FNSTSW8r, 0); + BuildMI(*MBB, IP, X86::SAHF, 1); break; case cLong: @@ -726,9 +838,9 @@ unsigned LoTmp = makeAnotherReg(Type::IntTy); unsigned HiTmp = makeAnotherReg(Type::IntTy); unsigned FinalTmp = makeAnotherReg(Type::IntTy); - BMI(MBB, IP, X86::XORrr32, 2, LoTmp).addReg(Op0r).addReg(Op1r); - BMI(MBB, IP, X86::XORrr32, 2, HiTmp).addReg(Op0r+1).addReg(Op1r+1); - BMI(MBB, IP, X86::ORrr32, 2, FinalTmp).addReg(LoTmp).addReg(HiTmp); + BuildMI(*MBB, IP, X86::XOR32rr, 2, LoTmp).addReg(Op0r).addReg(Op1r); + BuildMI(*MBB, IP, X86::XOR32rr, 2, HiTmp).addReg(Op0r+1).addReg(Op1r+1); + BuildMI(*MBB, IP, X86::OR32rr, 2, FinalTmp).addReg(LoTmp).addReg(HiTmp); break; // Allow the sete or setne to be generated from flags set by OR } else { // Emit a sequence of code which compares the high and low parts once @@ -744,13 +856,14 @@ // classes! Until then, hardcode registers so that we can deal with their // aliases (because we don't have conditional byte moves). // - BMI(MBB, IP, X86::CMPrr32, 2).addReg(Op0r).addReg(Op1r); - BMI(MBB, IP, SetCCOpcodeTab[0][OpNum], 0, X86::AL); - BMI(MBB, IP, X86::CMPrr32, 2).addReg(Op0r+1).addReg(Op1r+1); - BMI(MBB, IP, SetCCOpcodeTab[CompTy->isSigned()][OpNum], 0, X86::BL); - BMI(MBB, IP, X86::IMPLICIT_DEF, 0, X86::BH); - BMI(MBB, IP, X86::IMPLICIT_DEF, 0, X86::AH); - BMI(MBB, IP, X86::CMOVErr16, 2, X86::BX).addReg(X86::BX).addReg(X86::AX); + BuildMI(*MBB, IP, X86::CMP32rr, 2).addReg(Op0r).addReg(Op1r); + BuildMI(*MBB, IP, SetCCOpcodeTab[0][OpNum], 0, X86::AL); + BuildMI(*MBB, IP, X86::CMP32rr, 2).addReg(Op0r+1).addReg(Op1r+1); + BuildMI(*MBB, IP, SetCCOpcodeTab[CompTy->isSigned()][OpNum], 0, X86::BL); + BuildMI(*MBB, IP, X86::IMPLICIT_DEF, 0, X86::BH); + BuildMI(*MBB, IP, X86::IMPLICIT_DEF, 0, X86::AH); + BuildMI(*MBB, IP, X86::CMOVE16rr, 2, X86::BX).addReg(X86::BX) + .addReg(X86::AX); // NOTE: visitSetCondInst knows that the value is dumped into the BL // register at this point for long values... return OpNum; @@ -775,7 +888,7 @@ /// emitSetCCOperation - Common code shared between visitSetCondInst and /// constant expression support. void ISel::emitSetCCOperation(MachineBasicBlock *MBB, - MachineBasicBlock::iterator &IP, + MachineBasicBlock::iterator IP, Value *Op0, Value *Op1, unsigned Opcode, unsigned TargetReg) { unsigned OpNum = getSetCCNumber(Opcode); @@ -787,11 +900,11 @@ if (CompClass != cLong || OpNum < 2) { // Handle normal comparisons with a setcc instruction... - BMI(MBB, IP, SetCCOpcodeTab[isSigned][OpNum], 0, TargetReg); + BuildMI(*MBB, IP, SetCCOpcodeTab[isSigned][OpNum], 0, TargetReg); } else { // Handle long comparisons by copying the value which is already in BL into // the register we want... - BMI(MBB, IP, X86::MOVrr8, 1, TargetReg).addReg(X86::BL); + BuildMI(*MBB, IP, X86::MOV8rr, 1, TargetReg).addReg(X86::BL); } } @@ -810,20 +923,20 @@ case cByte: // Extend value into target register (8->32) if (isUnsigned) - BuildMI(BB, X86::MOVZXr32r8, 1, targetReg).addReg(Reg); + BuildMI(BB, X86::MOVZX32rr8, 1, targetReg).addReg(Reg); else - BuildMI(BB, X86::MOVSXr32r8, 1, targetReg).addReg(Reg); + BuildMI(BB, X86::MOVSX32rr8, 1, targetReg).addReg(Reg); break; case cShort: // Extend value into target register (16->32) if (isUnsigned) - BuildMI(BB, X86::MOVZXr32r16, 1, targetReg).addReg(Reg); + BuildMI(BB, X86::MOVZX32rr16, 1, targetReg).addReg(Reg); else - BuildMI(BB, X86::MOVSXr32r16, 1, targetReg).addReg(Reg); + BuildMI(BB, X86::MOVSX32rr16, 1, targetReg).addReg(Reg); break; case cInt: // Move value into target register (32->32) - BuildMI(BB, X86::MOVrr32, 1, targetReg).addReg(Reg); + BuildMI(BB, X86::MOV32rr, 1, targetReg).addReg(Reg); break; default: assert(0 && "Unpromotable operand class in promote32"); @@ -843,7 +956,6 @@ /// void ISel::visitReturnInst(ReturnInst &I) { if (I.getNumOperands() == 0) { - BuildMI(BB, X86::FP_REG_KILL, 0); BuildMI(BB, X86::RET, 0); // Just emit a 'ret' instruction return; } @@ -864,8 +976,8 @@ BuildMI(BB, X86::IMPLICIT_USE, 2).addReg(X86::ST0).addReg(X86::ESP); break; case cLong: - BuildMI(BB, X86::MOVrr32, 1, X86::EAX).addReg(RetReg); - BuildMI(BB, X86::MOVrr32, 1, X86::EDX).addReg(RetReg+1); + BuildMI(BB, X86::MOV32rr, 1, X86::EAX).addReg(RetReg); + BuildMI(BB, X86::MOV32rr, 1, X86::EDX).addReg(RetReg+1); // Declare that EAX & EDX are live on exit BuildMI(BB, X86::IMPLICIT_USE, 3).addReg(X86::EAX).addReg(X86::EDX) .addReg(X86::ESP); @@ -874,7 +986,6 @@ visitInstruction(I); } // Emit a 'ret' instruction - BuildMI(BB, X86::FP_REG_KILL, 0); BuildMI(BB, X86::RET, 0); } @@ -894,10 +1005,8 @@ BasicBlock *NextBB = getBlockAfter(BI.getParent()); // BB after current one if (!BI.isConditional()) { // Unconditional branch? - if (BI.getSuccessor(0) != NextBB) { - BuildMI(BB, X86::FP_REG_KILL, 0); + if (BI.getSuccessor(0) != NextBB) BuildMI(BB, X86::JMP, 1).addPCDisp(BI.getSuccessor(0)); - } return; } @@ -907,8 +1016,7 @@ // Nope, cannot fold setcc into this branch. Emit a branch on a condition // computed some other way... unsigned condReg = getReg(BI.getCondition()); - BuildMI(BB, X86::CMPri8, 2).addReg(condReg).addZImm(0); - BuildMI(BB, X86::FP_REG_KILL, 0); + BuildMI(BB, X86::CMP8ri, 2).addReg(condReg).addImm(0); if (BI.getSuccessor(1) == NextBB) { if (BI.getSuccessor(0) != NextBB) BuildMI(BB, X86::JNE, 1).addPCDisp(BI.getSuccessor(0)); @@ -947,7 +1055,6 @@ X86::JS, X86::JNS }, }; - BuildMI(BB, X86::FP_REG_KILL, 0); if (BI.getSuccessor(0) != NextBB) { BuildMI(BB, OpcodeTab[isSigned][OpNum], 1).addPCDisp(BI.getSuccessor(0)); if (BI.getSuccessor(1) != NextBB) @@ -986,41 +1093,57 @@ } // Adjust the stack pointer for the new arguments... - BuildMI(BB, X86::ADJCALLSTACKDOWN, 1).addZImm(NumBytes); + BuildMI(BB, X86::ADJCALLSTACKDOWN, 1).addImm(NumBytes); // Arguments go on the stack in reverse order, as specified by the ABI. unsigned ArgOffset = 0; for (unsigned i = 0, e = Args.size(); i != e; ++i) { - unsigned ArgReg = Args[i].Val ? getReg(Args[i].Val) : Args[i].Reg; + unsigned ArgReg; switch (getClassB(Args[i].Ty)) { case cByte: - case cShort: { - // Promote arg to 32 bits wide into a temporary register... - unsigned R = makeAnotherReg(Type::UIntTy); - promote32(R, Args[i]); - addRegOffset(BuildMI(BB, X86::MOVrm32, 5), - X86::ESP, ArgOffset).addReg(R); + case cShort: + if (Args[i].Val && isa(Args[i].Val)) { + // Zero/Sign extend constant, then stuff into memory. + ConstantInt *Val = cast(Args[i].Val); + Val = cast(ConstantExpr::getCast(Val, Type::IntTy)); + addRegOffset(BuildMI(BB, X86::MOV32mi, 5), X86::ESP, ArgOffset) + .addImm(Val->getRawValue() & 0xFFFFFFFF); + } else { + // Promote arg to 32 bits wide into a temporary register... + ArgReg = makeAnotherReg(Type::UIntTy); + promote32(ArgReg, Args[i]); + addRegOffset(BuildMI(BB, X86::MOV32mr, 5), + X86::ESP, ArgOffset).addReg(ArgReg); + } break; - } case cInt: - addRegOffset(BuildMI(BB, X86::MOVrm32, 5), - X86::ESP, ArgOffset).addReg(ArgReg); + if (Args[i].Val && isa(Args[i].Val)) { + unsigned Val = cast(Args[i].Val)->getRawValue(); + addRegOffset(BuildMI(BB, X86::MOV32mi, 5), + X86::ESP, ArgOffset).addImm(Val); + } else { + ArgReg = Args[i].Val ? getReg(Args[i].Val) : Args[i].Reg; + addRegOffset(BuildMI(BB, X86::MOV32mr, 5), + X86::ESP, ArgOffset).addReg(ArgReg); + } break; case cLong: - addRegOffset(BuildMI(BB, X86::MOVrm32, 5), + ArgReg = Args[i].Val ? getReg(Args[i].Val) : Args[i].Reg; + addRegOffset(BuildMI(BB, X86::MOV32mr, 5), X86::ESP, ArgOffset).addReg(ArgReg); - addRegOffset(BuildMI(BB, X86::MOVrm32, 5), + addRegOffset(BuildMI(BB, X86::MOV32mr, 5), X86::ESP, ArgOffset+4).addReg(ArgReg+1); ArgOffset += 4; // 8 byte entry, not 4. break; case cFP: + ArgReg = Args[i].Val ? getReg(Args[i].Val) : Args[i].Reg; if (Args[i].Ty == Type::FloatTy) { - addRegOffset(BuildMI(BB, X86::FSTr32, 5), + addRegOffset(BuildMI(BB, X86::FST32m, 5), X86::ESP, ArgOffset).addReg(ArgReg); } else { assert(Args[i].Ty == Type::DoubleTy && "Unknown FP type!"); - addRegOffset(BuildMI(BB, X86::FSTr64, 5), + addRegOffset(BuildMI(BB, X86::FST64m, 5), X86::ESP, ArgOffset).addReg(ArgReg); ArgOffset += 4; // 8 byte entry, not 4. } @@ -1031,12 +1154,12 @@ ArgOffset += 4; } } else { - BuildMI(BB, X86::ADJCALLSTACKDOWN, 1).addZImm(0); + BuildMI(BB, X86::ADJCALLSTACKDOWN, 1).addImm(0); } BB->push_back(CallMI); - BuildMI(BB, X86::ADJCALLSTACKUP, 1).addZImm(NumBytes); + BuildMI(BB, X86::ADJCALLSTACKUP, 1).addImm(NumBytes); // If there is a return value, scavenge the result from the location the call // leaves it in... @@ -1050,7 +1173,7 @@ // Integral results are in %eax, or the appropriate portion // thereof. static const unsigned regRegMove[] = { - X86::MOVrr8, X86::MOVrr16, X86::MOVrr32 + X86::MOV8rr, X86::MOV16rr, X86::MOV32rr }; static const unsigned AReg[] = { X86::AL, X86::AX, X86::EAX }; BuildMI(BB, regRegMove[DestClass], 1, Ret.Reg).addReg(AReg[DestClass]); @@ -1060,8 +1183,8 @@ BuildMI(BB, X86::FpGETRESULT, 1, Ret.Reg); break; case cLong: // Long values are left in EDX:EAX - BuildMI(BB, X86::MOVrr32, 1, Ret.Reg).addReg(X86::EAX); - BuildMI(BB, X86::MOVrr32, 1, Ret.Reg+1).addReg(X86::EDX); + BuildMI(BB, X86::MOV32rr, 1, Ret.Reg).addReg(X86::EAX); + BuildMI(BB, X86::MOV32rr, 1, Ret.Reg+1).addReg(X86::EDX); break; default: assert(0 && "Unknown class!"); } @@ -1083,7 +1206,7 @@ TheCall = BuildMI(X86::CALLpcrel32, 1).addGlobalAddress(F, true); } else { // Emit an indirect call... unsigned Reg = getReg(CI.getCalledValue()); - TheCall = BuildMI(X86::CALLr32, 1).addReg(Reg); + TheCall = BuildMI(X86::CALL32r, 1).addReg(Reg); } std::vector Args; @@ -1108,6 +1231,10 @@ case Intrinsic::va_start: case Intrinsic::va_copy: case Intrinsic::va_end: + case Intrinsic::returnaddress: + case Intrinsic::frameaddress: + case Intrinsic::memcpy: + case Intrinsic::memset: // We directly implement these intrinsics break; default: @@ -1129,16 +1256,146 @@ case Intrinsic::va_start: // Get the address of the first vararg value... TmpReg1 = getReg(CI); - addFrameReference(BuildMI(BB, X86::LEAr32, 5, TmpReg1), VarArgsFrameIndex); + addFrameReference(BuildMI(BB, X86::LEA32r, 5, TmpReg1), VarArgsFrameIndex); return; case Intrinsic::va_copy: TmpReg1 = getReg(CI); TmpReg2 = getReg(CI.getOperand(1)); - BuildMI(BB, X86::MOVrr32, 1, TmpReg1).addReg(TmpReg2); + BuildMI(BB, X86::MOV32rr, 1, TmpReg1).addReg(TmpReg2); return; case Intrinsic::va_end: return; // Noop on X86 + case Intrinsic::returnaddress: + case Intrinsic::frameaddress: + TmpReg1 = getReg(CI); + if (cast(CI.getOperand(1))->isNullValue()) { + if (ID == Intrinsic::returnaddress) { + // Just load the return address + addFrameReference(BuildMI(BB, X86::MOV32rm, 4, TmpReg1), + ReturnAddressIndex); + } else { + addFrameReference(BuildMI(BB, X86::LEA32r, 4, TmpReg1), + ReturnAddressIndex, -4); + } + } else { + // Values other than zero are not implemented yet. + BuildMI(BB, X86::MOV32ri, 1, TmpReg1).addImm(0); + } + return; + + case Intrinsic::memcpy: { + assert(CI.getNumOperands() == 5 && "Illegal llvm.memcpy call!"); + unsigned Align = 1; + if (ConstantInt *AlignC = dyn_cast(CI.getOperand(4))) { + Align = AlignC->getRawValue(); + if (Align == 0) Align = 1; + } + + // Turn the byte code into # iterations + unsigned CountReg; + unsigned Opcode; + switch (Align & 3) { + case 2: // WORD aligned + if (ConstantInt *I = dyn_cast(CI.getOperand(3))) { + CountReg = getReg(ConstantUInt::get(Type::UIntTy, I->getRawValue()/2)); + } else { + CountReg = makeAnotherReg(Type::IntTy); + unsigned ByteReg = getReg(CI.getOperand(3)); + BuildMI(BB, X86::SHR32ri, 2, CountReg).addReg(ByteReg).addImm(1); + } + Opcode = X86::REP_MOVSW; + break; + case 0: // DWORD aligned + if (ConstantInt *I = dyn_cast(CI.getOperand(3))) { + CountReg = getReg(ConstantUInt::get(Type::UIntTy, I->getRawValue()/4)); + } else { + CountReg = makeAnotherReg(Type::IntTy); + unsigned ByteReg = getReg(CI.getOperand(3)); + BuildMI(BB, X86::SHR32ri, 2, CountReg).addReg(ByteReg).addImm(2); + } + Opcode = X86::REP_MOVSD; + break; + default: // BYTE aligned + CountReg = getReg(CI.getOperand(3)); + Opcode = X86::REP_MOVSB; + break; + } + + // No matter what the alignment is, we put the source in ESI, the + // destination in EDI, and the count in ECX. + TmpReg1 = getReg(CI.getOperand(1)); + TmpReg2 = getReg(CI.getOperand(2)); + BuildMI(BB, X86::MOV32rr, 1, X86::ECX).addReg(CountReg); + BuildMI(BB, X86::MOV32rr, 1, X86::EDI).addReg(TmpReg1); + BuildMI(BB, X86::MOV32rr, 1, X86::ESI).addReg(TmpReg2); + BuildMI(BB, Opcode, 0); + return; + } + case Intrinsic::memset: { + assert(CI.getNumOperands() == 5 && "Illegal llvm.memset call!"); + unsigned Align = 1; + if (ConstantInt *AlignC = dyn_cast(CI.getOperand(4))) { + Align = AlignC->getRawValue(); + if (Align == 0) Align = 1; + } + + // Turn the byte code into # iterations + unsigned CountReg; + unsigned Opcode; + if (ConstantInt *ValC = dyn_cast(CI.getOperand(2))) { + unsigned Val = ValC->getRawValue() & 255; + + // If the value is a constant, then we can potentially use larger copies. + switch (Align & 3) { + case 2: // WORD aligned + if (ConstantInt *I = dyn_cast(CI.getOperand(3))) { + CountReg =getReg(ConstantUInt::get(Type::UIntTy, I->getRawValue()/2)); + } else { + CountReg = makeAnotherReg(Type::IntTy); + unsigned ByteReg = getReg(CI.getOperand(3)); + BuildMI(BB, X86::SHR32ri, 2, CountReg).addReg(ByteReg).addImm(1); + } + BuildMI(BB, X86::MOV16ri, 1, X86::AX).addImm((Val << 8) | Val); + Opcode = X86::REP_STOSW; + break; + case 0: // DWORD aligned + if (ConstantInt *I = dyn_cast(CI.getOperand(3))) { + CountReg =getReg(ConstantUInt::get(Type::UIntTy, I->getRawValue()/4)); + } else { + CountReg = makeAnotherReg(Type::IntTy); + unsigned ByteReg = getReg(CI.getOperand(3)); + BuildMI(BB, X86::SHR32ri, 2, CountReg).addReg(ByteReg).addImm(2); + } + Val = (Val << 8) | Val; + BuildMI(BB, X86::MOV32ri, 1, X86::EAX).addImm((Val << 16) | Val); + Opcode = X86::REP_STOSD; + break; + default: // BYTE aligned + CountReg = getReg(CI.getOperand(3)); + BuildMI(BB, X86::MOV8ri, 1, X86::AL).addImm(Val); + Opcode = X86::REP_STOSB; + break; + } + } else { + // If it's not a constant value we are storing, just fall back. We could + // try to be clever to form 16 bit and 32 bit values, but we don't yet. + unsigned ValReg = getReg(CI.getOperand(2)); + BuildMI(BB, X86::MOV8rr, 1, X86::AL).addReg(ValReg); + CountReg = getReg(CI.getOperand(3)); + Opcode = X86::REP_STOSB; + } + + // No matter what the alignment is, we put the source in ESI, the + // destination in EDI, and the count in ECX. + TmpReg1 = getReg(CI.getOperand(1)); + //TmpReg2 = getReg(CI.getOperand(2)); + BuildMI(BB, X86::MOV32rr, 1, X86::ECX).addReg(CountReg); + BuildMI(BB, X86::MOV32rr, 1, X86::EDI).addReg(TmpReg1); + BuildMI(BB, Opcode, 0); + return; + } + default: assert(0 && "Error: unknown intrinsics should have been lowered!"); } } @@ -1162,40 +1419,47 @@ /// and constant expression support. /// void ISel::emitSimpleBinaryOperation(MachineBasicBlock *MBB, - MachineBasicBlock::iterator &IP, + MachineBasicBlock::iterator IP, Value *Op0, Value *Op1, unsigned OperatorClass, unsigned DestReg) { unsigned Class = getClassB(Op0->getType()); // sub 0, X -> neg X if (OperatorClass == 1 && Class != cLong) - if (ConstantInt *CI = dyn_cast(Op0)) + if (ConstantInt *CI = dyn_cast(Op0)) { if (CI->isNullValue()) { unsigned op1Reg = getReg(Op1, MBB, IP); switch (Class) { default: assert(0 && "Unknown class for this function!"); case cByte: - BMI(MBB, IP, X86::NEGr8, 1, DestReg).addReg(op1Reg); + BuildMI(*MBB, IP, X86::NEG8r, 1, DestReg).addReg(op1Reg); return; case cShort: - BMI(MBB, IP, X86::NEGr16, 1, DestReg).addReg(op1Reg); + BuildMI(*MBB, IP, X86::NEG16r, 1, DestReg).addReg(op1Reg); return; case cInt: - BMI(MBB, IP, X86::NEGr32, 1, DestReg).addReg(op1Reg); + BuildMI(*MBB, IP, X86::NEG32r, 1, DestReg).addReg(op1Reg); return; } } + } else if (ConstantFP *CFP = dyn_cast(Op0)) + if (CFP->isExactlyValue(-0.0)) { + // -0.0 - X === -X + unsigned op1Reg = getReg(Op1, MBB, IP); + BuildMI(*MBB, IP, X86::FCHS, 1, DestReg).addReg(op1Reg); + return; + } if (!isa(Op1) || Class == cLong) { static const unsigned OpcodeTab[][4] = { // Arithmetic operators - { X86::ADDrr8, X86::ADDrr16, X86::ADDrr32, X86::FpADD }, // ADD - { X86::SUBrr8, X86::SUBrr16, X86::SUBrr32, X86::FpSUB }, // SUB + { X86::ADD8rr, X86::ADD16rr, X86::ADD32rr, X86::FpADD }, // ADD + { X86::SUB8rr, X86::SUB16rr, X86::SUB32rr, X86::FpSUB }, // SUB // Bitwise operators - { X86::ANDrr8, X86::ANDrr16, X86::ANDrr32, 0 }, // AND - { X86:: ORrr8, X86:: ORrr16, X86:: ORrr32, 0 }, // OR - { X86::XORrr8, X86::XORrr16, X86::XORrr32, 0 }, // XOR + { X86::AND8rr, X86::AND16rr, X86::AND32rr, 0 }, // AND + { X86:: OR8rr, X86:: OR16rr, X86:: OR32rr, 0 }, // OR + { X86::XOR8rr, X86::XOR16rr, X86::XOR32rr, 0 }, // XOR }; bool isLong = false; @@ -1208,13 +1472,13 @@ assert(Opcode && "Floating point arguments to logical inst?"); unsigned Op0r = getReg(Op0, MBB, IP); unsigned Op1r = getReg(Op1, MBB, IP); - BMI(MBB, IP, Opcode, 2, DestReg).addReg(Op0r).addReg(Op1r); + BuildMI(*MBB, IP, Opcode, 2, DestReg).addReg(Op0r).addReg(Op1r); if (isLong) { // Handle the upper 32 bits of long values... static const unsigned TopTab[] = { - X86::ADCrr32, X86::SBBrr32, X86::ANDrr32, X86::ORrr32, X86::XORrr32 + X86::ADC32rr, X86::SBB32rr, X86::AND32rr, X86::OR32rr, X86::XOR32rr }; - BMI(MBB, IP, TopTab[OperatorClass], 2, + BuildMI(*MBB, IP, TopTab[OperatorClass], 2, DestReg+1).addReg(Op0r+1).addReg(Op1r+1); } return; @@ -1226,34 +1490,34 @@ // xor X, -1 -> not X if (OperatorClass == 4 && Op1C->isAllOnesValue()) { - static unsigned const NOTTab[] = { X86::NOTr8, X86::NOTr16, X86::NOTr32 }; - BMI(MBB, IP, NOTTab[Class], 1, DestReg).addReg(Op0r); + static unsigned const NOTTab[] = { X86::NOT8r, X86::NOT16r, X86::NOT32r }; + BuildMI(*MBB, IP, NOTTab[Class], 1, DestReg).addReg(Op0r); return; } // add X, -1 -> dec X if (OperatorClass == 0 && Op1C->isAllOnesValue()) { - static unsigned const DECTab[] = { X86::DECr8, X86::DECr16, X86::DECr32 }; - BMI(MBB, IP, DECTab[Class], 1, DestReg).addReg(Op0r); + static unsigned const DECTab[] = { X86::DEC8r, X86::DEC16r, X86::DEC32r }; + BuildMI(*MBB, IP, DECTab[Class], 1, DestReg).addReg(Op0r); return; } // add X, 1 -> inc X if (OperatorClass == 0 && Op1C->equalsInt(1)) { - static unsigned const DECTab[] = { X86::INCr8, X86::INCr16, X86::INCr32 }; - BMI(MBB, IP, DECTab[Class], 1, DestReg).addReg(Op0r); + static unsigned const DECTab[] = { X86::INC8r, X86::INC16r, X86::INC32r }; + BuildMI(*MBB, IP, DECTab[Class], 1, DestReg).addReg(Op0r); return; } static const unsigned OpcodeTab[][3] = { // Arithmetic operators - { X86::ADDri8, X86::ADDri16, X86::ADDri32 }, // ADD - { X86::SUBri8, X86::SUBri16, X86::SUBri32 }, // SUB + { X86::ADD8ri, X86::ADD16ri, X86::ADD32ri }, // ADD + { X86::SUB8ri, X86::SUB16ri, X86::SUB32ri }, // SUB // Bitwise operators - { X86::ANDri8, X86::ANDri16, X86::ANDri32 }, // AND - { X86:: ORri8, X86:: ORri16, X86:: ORri32 }, // OR - { X86::XORri8, X86::XORri16, X86::XORri32 }, // XOR + { X86::AND8ri, X86::AND16ri, X86::AND32ri }, // AND + { X86:: OR8ri, X86:: OR16ri, X86:: OR32ri }, // OR + { X86::XOR8ri, X86::XOR16ri, X86::XOR32ri }, // XOR }; assert(Class < 3 && "General code handles 64-bit integer types!"); @@ -1262,31 +1526,31 @@ // Mask off any upper bits of the constant, if there are any... Op1v &= (1ULL << (8 << Class)) - 1; - BMI(MBB, IP, Opcode, 2, DestReg).addReg(Op0r).addZImm(Op1v); + BuildMI(*MBB, IP, Opcode, 2, DestReg).addReg(Op0r).addImm(Op1v); } /// doMultiply - Emit appropriate instructions to multiply together the /// registers op0Reg and op1Reg, and put the result in DestReg. The type of the /// result should be given as DestTy. /// -void ISel::doMultiply(MachineBasicBlock *MBB, MachineBasicBlock::iterator &MBBI, +void ISel::doMultiply(MachineBasicBlock *MBB, MachineBasicBlock::iterator MBBI, unsigned DestReg, const Type *DestTy, unsigned op0Reg, unsigned op1Reg) { unsigned Class = getClass(DestTy); switch (Class) { case cFP: // Floating point multiply - BMI(BB, MBBI, X86::FpMUL, 2, DestReg).addReg(op0Reg).addReg(op1Reg); + BuildMI(*MBB, MBBI, X86::FpMUL, 2, DestReg).addReg(op0Reg).addReg(op1Reg); return; case cInt: case cShort: - BMI(BB, MBBI, Class == cInt ? X86::IMULrr32 : X86::IMULrr16, 2, DestReg) + BuildMI(*MBB, MBBI, Class == cInt ? X86::IMUL32rr:X86::IMUL16rr, 2, DestReg) .addReg(op0Reg).addReg(op1Reg); return; case cByte: // Must use the MUL instruction, which forces use of AL... - BMI(MBB, MBBI, X86::MOVrr8, 1, X86::AL).addReg(op0Reg); - BMI(MBB, MBBI, X86::MULr8, 1).addReg(op1Reg); - BMI(MBB, MBBI, X86::MOVrr8, 1, DestReg).addReg(X86::AL); + BuildMI(*MBB, MBBI, X86::MOV8rr, 1, X86::AL).addReg(op0Reg); + BuildMI(*MBB, MBBI, X86::MUL8r, 1).addReg(op1Reg); + BuildMI(*MBB, MBBI, X86::MOV8rr, 1, DestReg).addReg(X86::AL); return; default: case cLong: assert(0 && "doMultiply cannot operate on LONG values!"); @@ -1307,7 +1571,7 @@ } void ISel::doMultiplyConst(MachineBasicBlock *MBB, - MachineBasicBlock::iterator &IP, + MachineBasicBlock::iterator IP, unsigned DestReg, const Type *DestTy, unsigned op0Reg, unsigned ConstRHS) { unsigned Class = getClass(DestTy); @@ -1317,32 +1581,32 @@ switch (Class) { default: assert(0 && "Unknown class for this function!"); case cByte: - BMI(MBB, IP, X86::SHLir32, 2, DestReg).addReg(op0Reg).addZImm(Shift-1); + BuildMI(*MBB, IP, X86::SHL32ri,2, DestReg).addReg(op0Reg).addImm(Shift-1); return; case cShort: - BMI(MBB, IP, X86::SHLir32, 2, DestReg).addReg(op0Reg).addZImm(Shift-1); + BuildMI(*MBB, IP, X86::SHL32ri,2, DestReg).addReg(op0Reg).addImm(Shift-1); return; case cInt: - BMI(MBB, IP, X86::SHLir32, 2, DestReg).addReg(op0Reg).addZImm(Shift-1); + BuildMI(*MBB, IP, X86::SHL32ri,2, DestReg).addReg(op0Reg).addImm(Shift-1); return; } } if (Class == cShort) { - BMI(MBB, IP, X86::IMULri16, 2, DestReg).addReg(op0Reg).addZImm(ConstRHS); + BuildMI(*MBB, IP, X86::IMUL16rri,2,DestReg).addReg(op0Reg).addImm(ConstRHS); return; } else if (Class == cInt) { - BMI(MBB, IP, X86::IMULri32, 2, DestReg).addReg(op0Reg).addZImm(ConstRHS); + BuildMI(*MBB, IP, X86::IMUL32rri,2,DestReg).addReg(op0Reg).addImm(ConstRHS); return; } // Most general case, emit a normal multiply... - static const unsigned MOVirTab[] = { - X86::MOVir8, X86::MOVir16, X86::MOVir32 + static const unsigned MOVriTab[] = { + X86::MOV8ri, X86::MOV16ri, X86::MOV32ri }; unsigned TmpReg = makeAnotherReg(DestTy); - BMI(MBB, IP, MOVirTab[Class], 1, TmpReg).addZImm(ConstRHS); + BuildMI(*MBB, IP, MOVriTab[Class], 1, TmpReg).addImm(ConstRHS); // Emit a MUL to multiply the register holding the index by // elementSize, putting the result in OffsetReg. @@ -1372,26 +1636,26 @@ // Long value. We have to do things the hard way... // Multiply the two low parts... capturing carry into EDX - BuildMI(BB, X86::MOVrr32, 1, X86::EAX).addReg(Op0Reg); - BuildMI(BB, X86::MULr32, 1).addReg(Op1Reg); // AL*BL + BuildMI(BB, X86::MOV32rr, 1, X86::EAX).addReg(Op0Reg); + BuildMI(BB, X86::MUL32r, 1).addReg(Op1Reg); // AL*BL unsigned OverflowReg = makeAnotherReg(Type::UIntTy); - BuildMI(BB, X86::MOVrr32, 1, DestReg).addReg(X86::EAX); // AL*BL - BuildMI(BB, X86::MOVrr32, 1, OverflowReg).addReg(X86::EDX); // AL*BL >> 32 + BuildMI(BB, X86::MOV32rr, 1, DestReg).addReg(X86::EAX); // AL*BL + BuildMI(BB, X86::MOV32rr, 1, OverflowReg).addReg(X86::EDX); // AL*BL >> 32 MachineBasicBlock::iterator MBBI = BB->end(); unsigned AHBLReg = makeAnotherReg(Type::UIntTy); // AH*BL - BMI(BB, MBBI, X86::IMULrr32, 2, AHBLReg).addReg(Op0Reg+1).addReg(Op1Reg); + BuildMI(*BB, MBBI, X86::IMUL32rr,2,AHBLReg).addReg(Op0Reg+1).addReg(Op1Reg); unsigned AHBLplusOverflowReg = makeAnotherReg(Type::UIntTy); - BuildMI(BB, X86::ADDrr32, 2, // AH*BL+(AL*BL >> 32) + BuildMI(*BB, MBBI, X86::ADD32rr, 2, // AH*BL+(AL*BL >> 32) AHBLplusOverflowReg).addReg(AHBLReg).addReg(OverflowReg); MBBI = BB->end(); unsigned ALBHReg = makeAnotherReg(Type::UIntTy); // AL*BH - BMI(BB, MBBI, X86::IMULrr32, 2, ALBHReg).addReg(Op0Reg).addReg(Op1Reg+1); + BuildMI(*BB, MBBI, X86::IMUL32rr,2,ALBHReg).addReg(Op0Reg).addReg(Op1Reg+1); - BuildMI(BB, X86::ADDrr32, 2, // AL*BH + AH*BL + (AL*BL >> 32) + BuildMI(*BB, MBBI, X86::ADD32rr, 2, // AL*BH + AH*BL + (AL*BL >> 32) DestReg+1).addReg(AHBLplusOverflowReg).addReg(ALBHReg); } } @@ -1413,14 +1677,14 @@ } void ISel::emitDivRemOperation(MachineBasicBlock *BB, - MachineBasicBlock::iterator &IP, + MachineBasicBlock::iterator IP, unsigned Op0Reg, unsigned Op1Reg, bool isDiv, const Type *Ty, unsigned ResultReg) { unsigned Class = getClass(Ty); switch (Class) { case cFP: // Floating point divide if (isDiv) { - BMI(BB, IP, X86::FpDIV, 2, ResultReg).addReg(Op0Reg).addReg(Op1Reg); + BuildMI(*BB, IP, X86::FpDIV, 2, ResultReg).addReg(Op0Reg).addReg(Op1Reg); } else { // Floating point remainder... MachineInstr *TheCall = BuildMI(X86::CALLpcrel32, 1).addExternalSymbol("fmod", true); @@ -1450,14 +1714,14 @@ } static const unsigned Regs[] ={ X86::AL , X86::AX , X86::EAX }; - static const unsigned MovOpcode[]={ X86::MOVrr8, X86::MOVrr16, X86::MOVrr32 }; - static const unsigned SarOpcode[]={ X86::SARir8, X86::SARir16, X86::SARir32 }; - static const unsigned ClrOpcode[]={ X86::MOVir8, X86::MOVir16, X86::MOVir32 }; + static const unsigned MovOpcode[]={ X86::MOV8rr, X86::MOV16rr, X86::MOV32rr }; + static const unsigned SarOpcode[]={ X86::SAR8ri, X86::SAR16ri, X86::SAR32ri }; + static const unsigned ClrOpcode[]={ X86::MOV8ri, X86::MOV16ri, X86::MOV32ri }; static const unsigned ExtRegs[] ={ X86::AH , X86::DX , X86::EDX }; static const unsigned DivOpcode[][4] = { - { X86::DIVr8 , X86::DIVr16 , X86::DIVr32 , 0 }, // Unsigned division - { X86::IDIVr8, X86::IDIVr16, X86::IDIVr32, 0 }, // Signed division + { X86::DIV8r , X86::DIV16r , X86::DIV32r , 0 }, // Unsigned division + { X86::IDIV8r, X86::IDIV16r, X86::IDIV32r, 0 }, // Signed division }; bool isSigned = Ty->isSigned(); @@ -1465,26 +1729,26 @@ unsigned ExtReg = ExtRegs[Class]; // Put the first operand into one of the A registers... - BMI(BB, IP, MovOpcode[Class], 1, Reg).addReg(Op0Reg); + BuildMI(*BB, IP, MovOpcode[Class], 1, Reg).addReg(Op0Reg); if (isSigned) { // Emit a sign extension instruction... unsigned ShiftResult = makeAnotherReg(Ty); - BMI(BB, IP, SarOpcode[Class], 2, ShiftResult).addReg(Op0Reg).addZImm(31); - BMI(BB, IP, MovOpcode[Class], 1, ExtReg).addReg(ShiftResult); + BuildMI(*BB, IP, SarOpcode[Class], 2,ShiftResult).addReg(Op0Reg).addImm(31); + BuildMI(*BB, IP, MovOpcode[Class], 1, ExtReg).addReg(ShiftResult); } else { // If unsigned, emit a zeroing instruction... (reg = 0) - BMI(BB, IP, ClrOpcode[Class], 2, ExtReg).addZImm(0); + BuildMI(*BB, IP, ClrOpcode[Class], 2, ExtReg).addImm(0); } // Emit the appropriate divide or remainder instruction... - BMI(BB, IP, DivOpcode[isSigned][Class], 1).addReg(Op1Reg); + BuildMI(*BB, IP, DivOpcode[isSigned][Class], 1).addReg(Op1Reg); // Figure out which register we want to pick the result out of... unsigned DestReg = isDiv ? Reg : ExtReg; // Put the result into the destination register... - BMI(BB, IP, MovOpcode[Class], 1, ResultReg).addReg(DestReg); + BuildMI(*BB, IP, MovOpcode[Class], 1, ResultReg).addReg(DestReg); } @@ -1503,7 +1767,7 @@ /// emitShiftOperation - Common code shared between visitShiftInst and /// constant expression support. void ISel::emitShiftOperation(MachineBasicBlock *MBB, - MachineBasicBlock::iterator &IP, + MachineBasicBlock::iterator IP, Value *Op, Value *ShiftAmount, bool isLeftShift, const Type *ResultTy, unsigned DestReg) { unsigned SrcReg = getReg (Op, MBB, IP); @@ -1511,17 +1775,17 @@ unsigned Class = getClass (ResultTy); static const unsigned ConstantOperand[][4] = { - { X86::SHRir8, X86::SHRir16, X86::SHRir32, X86::SHRDir32 }, // SHR - { X86::SARir8, X86::SARir16, X86::SARir32, X86::SHRDir32 }, // SAR - { X86::SHLir8, X86::SHLir16, X86::SHLir32, X86::SHLDir32 }, // SHL - { X86::SHLir8, X86::SHLir16, X86::SHLir32, X86::SHLDir32 }, // SAL = SHL + { X86::SHR8ri, X86::SHR16ri, X86::SHR32ri, X86::SHRD32rri8 }, // SHR + { X86::SAR8ri, X86::SAR16ri, X86::SAR32ri, X86::SHRD32rri8 }, // SAR + { X86::SHL8ri, X86::SHL16ri, X86::SHL32ri, X86::SHLD32rri8 }, // SHL + { X86::SHL8ri, X86::SHL16ri, X86::SHL32ri, X86::SHLD32rri8 }, // SAL = SHL }; static const unsigned NonConstantOperand[][4] = { - { X86::SHRrr8, X86::SHRrr16, X86::SHRrr32 }, // SHR - { X86::SARrr8, X86::SARrr16, X86::SARrr32 }, // SAR - { X86::SHLrr8, X86::SHLrr16, X86::SHLrr32 }, // SHL - { X86::SHLrr8, X86::SHLrr16, X86::SHLrr32 }, // SAL = SHL + { X86::SHR8rCL, X86::SHR16rCL, X86::SHR32rCL }, // SHR + { X86::SAR8rCL, X86::SAR16rCL, X86::SAR32rCL }, // SAR + { X86::SHL8rCL, X86::SHL16rCL, X86::SHL32rCL }, // SHL + { X86::SHL8rCL, X86::SHL16rCL, X86::SHL32rCL }, // SAL = SHL }; // Longs, as usual, are handled specially... @@ -1534,25 +1798,25 @@ if (Amount < 32) { const unsigned *Opc = ConstantOperand[isLeftShift*2+isSigned]; if (isLeftShift) { - BMI(MBB, IP, Opc[3], 3, - DestReg+1).addReg(SrcReg+1).addReg(SrcReg).addZImm(Amount); - BMI(MBB, IP, Opc[2], 2, DestReg).addReg(SrcReg).addZImm(Amount); + BuildMI(*MBB, IP, Opc[3], 3, + DestReg+1).addReg(SrcReg+1).addReg(SrcReg).addImm(Amount); + BuildMI(*MBB, IP, Opc[2], 2, DestReg).addReg(SrcReg).addImm(Amount); } else { - BMI(MBB, IP, Opc[3], 3, - DestReg).addReg(SrcReg ).addReg(SrcReg+1).addZImm(Amount); - BMI(MBB, IP, Opc[2], 2, DestReg+1).addReg(SrcReg+1).addZImm(Amount); + BuildMI(*MBB, IP, Opc[3], 3, + DestReg).addReg(SrcReg ).addReg(SrcReg+1).addImm(Amount); + BuildMI(*MBB, IP, Opc[2],2,DestReg+1).addReg(SrcReg+1).addImm(Amount); } } else { // Shifting more than 32 bits Amount -= 32; if (isLeftShift) { - BMI(MBB, IP, X86::SHLir32, 2, - DestReg + 1).addReg(SrcReg).addZImm(Amount); - BMI(MBB, IP, X86::MOVir32, 1, - DestReg).addZImm(0); + BuildMI(*MBB, IP, X86::SHL32ri, 2, + DestReg + 1).addReg(SrcReg).addImm(Amount); + BuildMI(*MBB, IP, X86::MOV32ri, 1, + DestReg).addImm(0); } else { - unsigned Opcode = isSigned ? X86::SARir32 : X86::SHRir32; - BMI(MBB, IP, Opcode, 2, DestReg).addReg(SrcReg+1).addZImm(Amount); - BMI(MBB, IP, X86::MOVir32, 1, DestReg+1).addZImm(0); + unsigned Opcode = isSigned ? X86::SAR32ri : X86::SHR32ri; + BuildMI(*MBB, IP, Opcode, 2, DestReg).addReg(SrcReg+1).addImm(Amount); + BuildMI(*MBB, IP, X86::MOV32ri, 1, DestReg+1).addImm(0); } } } else { @@ -1562,50 +1826,52 @@ // If this is a SHR of a Long, then we need to do funny sign extension // stuff. TmpReg gets the value to use as the high-part if we are // shifting more than 32 bits. - BMI(MBB, IP, X86::SARir32, 2, TmpReg).addReg(SrcReg).addZImm(31); + BuildMI(*MBB, IP, X86::SAR32ri, 2, TmpReg).addReg(SrcReg).addImm(31); } else { // Other shifts use a fixed zero value if the shift is more than 32 // bits. - BMI(MBB, IP, X86::MOVir32, 1, TmpReg).addZImm(0); + BuildMI(*MBB, IP, X86::MOV32ri, 1, TmpReg).addImm(0); } // Initialize CL with the shift amount... unsigned ShiftAmountReg = getReg(ShiftAmount, MBB, IP); - BMI(MBB, IP, X86::MOVrr8, 1, X86::CL).addReg(ShiftAmountReg); + BuildMI(*MBB, IP, X86::MOV8rr, 1, X86::CL).addReg(ShiftAmountReg); unsigned TmpReg2 = makeAnotherReg(Type::IntTy); unsigned TmpReg3 = makeAnotherReg(Type::IntTy); if (isLeftShift) { // TmpReg2 = shld inHi, inLo - BMI(MBB, IP, X86::SHLDrr32, 2, TmpReg2).addReg(SrcReg+1).addReg(SrcReg); + BuildMI(*MBB, IP, X86::SHLD32rrCL,2,TmpReg2).addReg(SrcReg+1) + .addReg(SrcReg); // TmpReg3 = shl inLo, CL - BMI(MBB, IP, X86::SHLrr32, 1, TmpReg3).addReg(SrcReg); + BuildMI(*MBB, IP, X86::SHL32rCL, 1, TmpReg3).addReg(SrcReg); // Set the flags to indicate whether the shift was by more than 32 bits. - BMI(MBB, IP, X86::TESTri8, 2).addReg(X86::CL).addZImm(32); + BuildMI(*MBB, IP, X86::TEST8ri, 2).addReg(X86::CL).addImm(32); // DestHi = (>32) ? TmpReg3 : TmpReg2; - BMI(MBB, IP, X86::CMOVNErr32, 2, + BuildMI(*MBB, IP, X86::CMOVNE32rr, 2, DestReg+1).addReg(TmpReg2).addReg(TmpReg3); // DestLo = (>32) ? TmpReg : TmpReg3; - BMI(MBB, IP, X86::CMOVNErr32, 2, + BuildMI(*MBB, IP, X86::CMOVNE32rr, 2, DestReg).addReg(TmpReg3).addReg(TmpReg); } else { // TmpReg2 = shrd inLo, inHi - BMI(MBB, IP, X86::SHRDrr32, 2, TmpReg2).addReg(SrcReg).addReg(SrcReg+1); + BuildMI(*MBB, IP, X86::SHRD32rrCL,2,TmpReg2).addReg(SrcReg) + .addReg(SrcReg+1); // TmpReg3 = s[ah]r inHi, CL - BMI(MBB, IP, isSigned ? X86::SARrr32 : X86::SHRrr32, 1, TmpReg3) + BuildMI(*MBB, IP, isSigned ? X86::SAR32rCL : X86::SHR32rCL, 1, TmpReg3) .addReg(SrcReg+1); // Set the flags to indicate whether the shift was by more than 32 bits. - BMI(MBB, IP, X86::TESTri8, 2).addReg(X86::CL).addZImm(32); + BuildMI(*MBB, IP, X86::TEST8ri, 2).addReg(X86::CL).addImm(32); // DestLo = (>32) ? TmpReg3 : TmpReg2; - BMI(MBB, IP, X86::CMOVNErr32, 2, + BuildMI(*MBB, IP, X86::CMOVNE32rr, 2, DestReg).addReg(TmpReg2).addReg(TmpReg3); // DestHi = (>32) ? TmpReg : TmpReg3; - BMI(MBB, IP, X86::CMOVNErr32, 2, + BuildMI(*MBB, IP, X86::CMOVNE32rr, 2, DestReg+1).addReg(TmpReg3).addReg(TmpReg); } } @@ -1617,14 +1883,14 @@ assert(CUI->getType() == Type::UByteTy && "Shift amount not a ubyte?"); const unsigned *Opc = ConstantOperand[isLeftShift*2+isSigned]; - BMI(MBB, IP, Opc[Class], 2, - DestReg).addReg(SrcReg).addZImm(CUI->getValue()); + BuildMI(*MBB, IP, Opc[Class], 2, + DestReg).addReg(SrcReg).addImm(CUI->getValue()); } else { // The shift amount is non-constant. unsigned ShiftAmountReg = getReg (ShiftAmount, MBB, IP); - BMI(MBB, IP, X86::MOVrr8, 1, X86::CL).addReg(ShiftAmountReg); + BuildMI(*MBB, IP, X86::MOV8rr, 1, X86::CL).addReg(ShiftAmountReg); const unsigned *Opc = NonConstantOperand[isLeftShift*2+isSigned]; - BMI(MBB, IP, Opc[Class], 1, DestReg).addReg(SrcReg); + BuildMI(*MBB, IP, Opc[Class], 1, DestReg).addReg(SrcReg); } } @@ -1634,47 +1900,106 @@ /// need to worry about the memory layout of the target machine. /// void ISel::visitLoadInst(LoadInst &I) { - unsigned SrcAddrReg = getReg(I.getOperand(0)); unsigned DestReg = getReg(I); + unsigned BaseReg = 0, Scale = 1, IndexReg = 0, Disp = 0; + Value *Addr = I.getOperand(0); + if (GetElementPtrInst *GEP = dyn_cast(Addr)) { + if (isGEPFoldable(BB, GEP->getOperand(0), GEP->op_begin()+1, GEP->op_end(), + BaseReg, Scale, IndexReg, Disp)) + Addr = 0; // Address is consumed! + } else if (ConstantExpr *CE = dyn_cast(Addr)) { + if (CE->getOpcode() == Instruction::GetElementPtr) + if (isGEPFoldable(BB, CE->getOperand(0), CE->op_begin()+1, CE->op_end(), + BaseReg, Scale, IndexReg, Disp)) + Addr = 0; + } + + if (Addr) { + // If it's not foldable, reset addr mode. + BaseReg = getReg(Addr); + Scale = 1; IndexReg = 0; Disp = 0; + } unsigned Class = getClassB(I.getType()); - if (Class == cLong) { - addDirectMem(BuildMI(BB, X86::MOVmr32, 4, DestReg), SrcAddrReg); - addRegOffset(BuildMI(BB, X86::MOVmr32, 4, DestReg+1), SrcAddrReg, 4); + addFullAddress(BuildMI(BB, X86::MOV32rm, 4, DestReg), + BaseReg, Scale, IndexReg, Disp); + addFullAddress(BuildMI(BB, X86::MOV32rm, 4, DestReg+1), + BaseReg, Scale, IndexReg, Disp+4); return; } static const unsigned Opcodes[] = { - X86::MOVmr8, X86::MOVmr16, X86::MOVmr32, X86::FLDr32 + X86::MOV8rm, X86::MOV16rm, X86::MOV32rm, X86::FLD32m }; unsigned Opcode = Opcodes[Class]; - if (I.getType() == Type::DoubleTy) Opcode = X86::FLDr64; - addDirectMem(BuildMI(BB, Opcode, 4, DestReg), SrcAddrReg); + if (I.getType() == Type::DoubleTy) Opcode = X86::FLD64m; + addFullAddress(BuildMI(BB, Opcode, 4, DestReg), + BaseReg, Scale, IndexReg, Disp); } /// visitStoreInst - Implement LLVM store instructions in terms of the x86 'mov' /// instruction. /// void ISel::visitStoreInst(StoreInst &I) { - unsigned ValReg = getReg(I.getOperand(0)); - unsigned AddressReg = getReg(I.getOperand(1)); - + unsigned BaseReg = 0, Scale = 1, IndexReg = 0, Disp = 0; + Value *Addr = I.getOperand(1); + if (GetElementPtrInst *GEP = dyn_cast(Addr)) { + if (isGEPFoldable(BB, GEP->getOperand(0), GEP->op_begin()+1, GEP->op_end(), + BaseReg, Scale, IndexReg, Disp)) + Addr = 0; // Address is consumed! + } else if (ConstantExpr *CE = dyn_cast(Addr)) { + if (CE->getOpcode() == Instruction::GetElementPtr) + if (isGEPFoldable(BB, CE->getOperand(0), CE->op_begin()+1, CE->op_end(), + BaseReg, Scale, IndexReg, Disp)) + Addr = 0; + } + + if (Addr) { + // If it's not foldable, reset addr mode. + BaseReg = getReg(Addr); + Scale = 1; IndexReg = 0; Disp = 0; + } + const Type *ValTy = I.getOperand(0)->getType(); unsigned Class = getClassB(ValTy); - if (Class == cLong) { - addDirectMem(BuildMI(BB, X86::MOVrm32, 1+4), AddressReg).addReg(ValReg); - addRegOffset(BuildMI(BB, X86::MOVrm32, 1+4), AddressReg,4).addReg(ValReg+1); - return; + if (ConstantInt *CI = dyn_cast(I.getOperand(0))) { + uint64_t Val = CI->getRawValue(); + if (Class == cLong) { + addFullAddress(BuildMI(BB, X86::MOV32mi, 5), + BaseReg, Scale, IndexReg, Disp).addImm(Val & ~0U); + addFullAddress(BuildMI(BB, X86::MOV32mi, 5), + BaseReg, Scale, IndexReg, Disp+4).addImm(Val>>32); + } else { + static const unsigned Opcodes[] = { + X86::MOV8mi, X86::MOV16mi, X86::MOV32mi + }; + unsigned Opcode = Opcodes[Class]; + addFullAddress(BuildMI(BB, Opcode, 5), + BaseReg, Scale, IndexReg, Disp).addImm(Val); + } + } else if (ConstantBool *CB = dyn_cast(I.getOperand(0))) { + addFullAddress(BuildMI(BB, X86::MOV8mi, 5), + BaseReg, Scale, IndexReg, Disp).addImm(CB->getValue()); + } else { + if (Class == cLong) { + unsigned ValReg = getReg(I.getOperand(0)); + addFullAddress(BuildMI(BB, X86::MOV32mr, 5), + BaseReg, Scale, IndexReg, Disp).addReg(ValReg); + addFullAddress(BuildMI(BB, X86::MOV32mr, 5), + BaseReg, Scale, IndexReg, Disp+4).addReg(ValReg+1); + } else { + unsigned ValReg = getReg(I.getOperand(0)); + static const unsigned Opcodes[] = { + X86::MOV8mr, X86::MOV16mr, X86::MOV32mr, X86::FST32m + }; + unsigned Opcode = Opcodes[Class]; + if (ValTy == Type::DoubleTy) Opcode = X86::FST64m; + addFullAddress(BuildMI(BB, Opcode, 1+4), + BaseReg, Scale, IndexReg, Disp).addReg(ValReg); + } } - - static const unsigned Opcodes[] = { - X86::MOVrm8, X86::MOVrm16, X86::MOVrm32, X86::FSTr32 - }; - unsigned Opcode = Opcodes[Class]; - if (ValTy == Type::DoubleTy) Opcode = X86::FSTr64; - addDirectMem(BuildMI(BB, Opcode, 1+4), AddressReg).addReg(ValReg); } @@ -1706,7 +2031,7 @@ /// emitCastOperation - Common code shared between visitCastInst and /// constant expression cast support. void ISel::emitCastOperation(MachineBasicBlock *BB, - MachineBasicBlock::iterator &IP, + MachineBasicBlock::iterator IP, Value *Src, const Type *DestTy, unsigned DestReg) { unsigned SrcReg = getReg(Src, BB, IP); @@ -1719,43 +2044,45 @@ if (DestTy == Type::BoolTy) { switch (SrcClass) { case cByte: - BMI(BB, IP, X86::TESTrr8, 2).addReg(SrcReg).addReg(SrcReg); + BuildMI(*BB, IP, X86::TEST8rr, 2).addReg(SrcReg).addReg(SrcReg); break; case cShort: - BMI(BB, IP, X86::TESTrr16, 2).addReg(SrcReg).addReg(SrcReg); + BuildMI(*BB, IP, X86::TEST16rr, 2).addReg(SrcReg).addReg(SrcReg); break; case cInt: - BMI(BB, IP, X86::TESTrr32, 2).addReg(SrcReg).addReg(SrcReg); + BuildMI(*BB, IP, X86::TEST32rr, 2).addReg(SrcReg).addReg(SrcReg); break; case cLong: { unsigned TmpReg = makeAnotherReg(Type::IntTy); - BMI(BB, IP, X86::ORrr32, 2, TmpReg).addReg(SrcReg).addReg(SrcReg+1); + BuildMI(*BB, IP, X86::OR32rr, 2, TmpReg).addReg(SrcReg).addReg(SrcReg+1); break; } case cFP: - assert(0 && "FIXME: implement cast FP to bool"); - abort(); + BuildMI(*BB, IP, X86::FTST, 1).addReg(SrcReg); + BuildMI(*BB, IP, X86::FNSTSW8r, 0); + BuildMI(*BB, IP, X86::SAHF, 1); + break; } // If the zero flag is not set, then the value is true, set the byte to // true. - BMI(BB, IP, X86::SETNEr, 1, DestReg); + BuildMI(*BB, IP, X86::SETNEr, 1, DestReg); return; } static const unsigned RegRegMove[] = { - X86::MOVrr8, X86::MOVrr16, X86::MOVrr32, X86::FpMOV, X86::MOVrr32 + X86::MOV8rr, X86::MOV16rr, X86::MOV32rr, X86::FpMOV, X86::MOV32rr }; // Implement casts between values of the same type class (as determined by // getClass) by using a register-to-register move. if (SrcClass == DestClass) { if (SrcClass <= cInt || (SrcClass == cFP && SrcTy == DestTy)) { - BMI(BB, IP, RegRegMove[SrcClass], 1, DestReg).addReg(SrcReg); + BuildMI(*BB, IP, RegRegMove[SrcClass], 1, DestReg).addReg(SrcReg); } else if (SrcClass == cFP) { if (SrcTy == Type::FloatTy) { // double -> float assert(DestTy == Type::DoubleTy && "Unknown cFP member!"); - BMI(BB, IP, X86::FpMOV, 1, DestReg).addReg(SrcReg); + BuildMI(*BB, IP, X86::FpMOV, 1, DestReg).addReg(SrcReg); } else { // float -> double assert(SrcTy == Type::DoubleTy && DestTy == Type::FloatTy && "Unknown cFP member!"); @@ -1763,12 +2090,12 @@ // reading it back. unsigned FltAlign = TM.getTargetData().getFloatAlignment(); int FrameIdx = F->getFrameInfo()->CreateStackObject(4, FltAlign); - addFrameReference(BMI(BB, IP, X86::FSTr32, 5), FrameIdx).addReg(SrcReg); - addFrameReference(BMI(BB, IP, X86::FLDr32, 5, DestReg), FrameIdx); + addFrameReference(BuildMI(*BB, IP, X86::FST32m, 5), FrameIdx).addReg(SrcReg); + addFrameReference(BuildMI(*BB, IP, X86::FLD32m, 5, DestReg), FrameIdx); } } else if (SrcClass == cLong) { - BMI(BB, IP, X86::MOVrr32, 1, DestReg).addReg(SrcReg); - BMI(BB, IP, X86::MOVrr32, 1, DestReg+1).addReg(SrcReg+1); + BuildMI(*BB, IP, X86::MOV32rr, 1, DestReg).addReg(SrcReg); + BuildMI(*BB, IP, X86::MOV32rr, 1, DestReg+1).addReg(SrcReg+1); } else { assert(0 && "Cannot handle this type of cast instruction!"); abort(); @@ -1784,26 +2111,26 @@ if (isLong) DestClass = cInt; static const unsigned Opc[][4] = { - { X86::MOVSXr16r8, X86::MOVSXr32r8, X86::MOVSXr32r16, X86::MOVrr32 }, // s - { X86::MOVZXr16r8, X86::MOVZXr32r8, X86::MOVZXr32r16, X86::MOVrr32 } // u + { X86::MOVSX16rr8, X86::MOVSX32rr8, X86::MOVSX32rr16, X86::MOV32rr }, // s + { X86::MOVZX16rr8, X86::MOVZX32rr8, X86::MOVZX32rr16, X86::MOV32rr } // u }; bool isUnsigned = SrcTy->isUnsigned(); - BMI(BB, IP, Opc[isUnsigned][SrcClass + DestClass - 1], 1, + BuildMI(*BB, IP, Opc[isUnsigned][SrcClass + DestClass - 1], 1, DestReg).addReg(SrcReg); if (isLong) { // Handle upper 32 bits as appropriate... if (isUnsigned) // Zero out top bits... - BMI(BB, IP, X86::MOVir32, 1, DestReg+1).addZImm(0); + BuildMI(*BB, IP, X86::MOV32ri, 1, DestReg+1).addImm(0); else // Sign extend bottom half... - BMI(BB, IP, X86::SARir32, 2, DestReg+1).addReg(DestReg).addZImm(31); + BuildMI(*BB, IP, X86::SAR32ri, 2, DestReg+1).addReg(DestReg).addImm(31); } return; } // Special case long -> int ... if (SrcClass == cLong && DestClass == cInt) { - BMI(BB, IP, X86::MOVrr32, 1, DestReg).addReg(SrcReg); + BuildMI(*BB, IP, X86::MOV32rr, 1, DestReg).addReg(SrcReg); return; } @@ -1812,8 +2139,8 @@ if ((SrcClass <= cInt || SrcClass == cLong) && DestClass <= cInt && SrcClass > DestClass) { static const unsigned AReg[] = { X86::AL, X86::AX, X86::EAX, 0, X86::EAX }; - BMI(BB, IP, RegRegMove[SrcClass], 1, AReg[SrcClass]).addReg(SrcReg); - BMI(BB, IP, RegRegMove[DestClass], 1, DestReg).addReg(AReg[DestClass]); + BuildMI(*BB, IP, RegRegMove[SrcClass], 1, AReg[SrcClass]).addReg(SrcReg); + BuildMI(*BB, IP, RegRegMove[DestClass], 1, DestReg).addReg(AReg[DestClass]); return; } @@ -1825,42 +2152,45 @@ // const Type *PromoteType = 0; unsigned PromoteOpcode; + unsigned RealDestReg = DestReg; switch (SrcTy->getPrimitiveID()) { case Type::BoolTyID: case Type::SByteTyID: // We don't have the facilities for directly loading byte sized data from // memory (even signed). Promote it to 16 bits. PromoteType = Type::ShortTy; - PromoteOpcode = X86::MOVSXr16r8; + PromoteOpcode = X86::MOVSX16rr8; break; case Type::UByteTyID: PromoteType = Type::ShortTy; - PromoteOpcode = X86::MOVZXr16r8; + PromoteOpcode = X86::MOVZX16rr8; break; case Type::UShortTyID: PromoteType = Type::IntTy; - PromoteOpcode = X86::MOVZXr32r16; + PromoteOpcode = X86::MOVZX32rr16; break; case Type::UIntTyID: { // Make a 64 bit temporary... and zero out the top of it... unsigned TmpReg = makeAnotherReg(Type::LongTy); - BMI(BB, IP, X86::MOVrr32, 1, TmpReg).addReg(SrcReg); - BMI(BB, IP, X86::MOVir32, 1, TmpReg+1).addZImm(0); + BuildMI(*BB, IP, X86::MOV32rr, 1, TmpReg).addReg(SrcReg); + BuildMI(*BB, IP, X86::MOV32ri, 1, TmpReg+1).addImm(0); SrcTy = Type::LongTy; SrcClass = cLong; SrcReg = TmpReg; break; } case Type::ULongTyID: - assert("FIXME: not implemented: cast ulong X to fp type!"); + // Don't fild into the read destination. + DestReg = makeAnotherReg(Type::DoubleTy); + break; default: // No promotion needed... break; } if (PromoteType) { unsigned TmpReg = makeAnotherReg(PromoteType); - BMI(BB, IP, SrcTy->isSigned() ? X86::MOVSXr16r8 : X86::MOVZXr16r8, - 1, TmpReg).addReg(SrcReg); + unsigned Opc = SrcTy->isSigned() ? X86::MOVSX16rr8 : X86::MOVZX16rr8; + BuildMI(*BB, IP, Opc, 1, TmpReg).addReg(SrcReg); SrcTy = PromoteType; SrcClass = getClass(PromoteType); SrcReg = TmpReg; @@ -1871,17 +2201,51 @@ F->getFrameInfo()->CreateStackObject(SrcTy, TM.getTargetData()); if (SrcClass == cLong) { - addFrameReference(BMI(BB, IP, X86::MOVrm32, 5), FrameIdx).addReg(SrcReg); - addFrameReference(BMI(BB, IP, X86::MOVrm32, 5), + addFrameReference(BuildMI(*BB, IP, X86::MOV32mr, 5), + FrameIdx).addReg(SrcReg); + addFrameReference(BuildMI(*BB, IP, X86::MOV32mr, 5), FrameIdx, 4).addReg(SrcReg+1); } else { - static const unsigned Op1[] = { X86::MOVrm8, X86::MOVrm16, X86::MOVrm32 }; - addFrameReference(BMI(BB, IP, Op1[SrcClass], 5), FrameIdx).addReg(SrcReg); + static const unsigned Op1[] = { X86::MOV8mr, X86::MOV16mr, X86::MOV32mr }; + addFrameReference(BuildMI(*BB, IP, Op1[SrcClass], 5), + FrameIdx).addReg(SrcReg); } static const unsigned Op2[] = - { 0/*byte*/, X86::FILDr16, X86::FILDr32, 0/*FP*/, X86::FILDr64 }; - addFrameReference(BMI(BB, IP, Op2[SrcClass], 5, DestReg), FrameIdx); + { 0/*byte*/, X86::FILD16m, X86::FILD32m, 0/*FP*/, X86::FILD64m }; + addFrameReference(BuildMI(*BB, IP, Op2[SrcClass], 5, DestReg), FrameIdx); + + // We need special handling for unsigned 64-bit integer sources. If the + // input number has the "sign bit" set, then we loaded it incorrectly as a + // negative 64-bit number. In this case, add an offset value. + if (SrcTy == Type::ULongTy) { + // Emit a test instruction to see if the dynamic input value was signed. + BuildMI(*BB, IP, X86::TEST32rr, 2).addReg(SrcReg+1).addReg(SrcReg+1); + + // If the sign bit is set, get a pointer to an offset, otherwise get a + // pointer to a zero. + MachineConstantPool *CP = F->getConstantPool(); + unsigned Zero = makeAnotherReg(Type::IntTy); + Constant *Null = Constant::getNullValue(Type::UIntTy); + addConstantPoolReference(BuildMI(*BB, IP, X86::LEA32r, 5, Zero), + CP->getConstantPoolIndex(Null)); + unsigned Offset = makeAnotherReg(Type::IntTy); + Constant *OffsetCst = ConstantUInt::get(Type::UIntTy, 0x5f800000); + + addConstantPoolReference(BuildMI(*BB, IP, X86::LEA32r, 5, Offset), + CP->getConstantPoolIndex(OffsetCst)); + unsigned Addr = makeAnotherReg(Type::IntTy); + BuildMI(*BB, IP, X86::CMOVS32rr, 2, Addr).addReg(Zero).addReg(Offset); + + // Load the constant for an add. FIXME: this could make an 'fadd' that + // reads directly from memory, but we don't support these yet. + unsigned ConstReg = makeAnotherReg(Type::DoubleTy); + addDirectMem(BuildMI(*BB, IP, X86::FLD32m, 4, ConstReg), Addr); + + BuildMI(*BB, IP, X86::FpADD, 2, RealDestReg) + .addReg(ConstReg).addReg(DestReg); + } + return; } @@ -1891,20 +2255,22 @@ // mode when truncating to an integer value. // int CWFrameIdx = F->getFrameInfo()->CreateStackObject(2, 2); - addFrameReference(BMI(BB, IP, X86::FNSTCWm16, 4), CWFrameIdx); + addFrameReference(BuildMI(*BB, IP, X86::FNSTCW16m, 4), CWFrameIdx); // Load the old value of the high byte of the control word... unsigned HighPartOfCW = makeAnotherReg(Type::UByteTy); - addFrameReference(BMI(BB, IP, X86::MOVmr8, 4, HighPartOfCW), CWFrameIdx, 1); + addFrameReference(BuildMI(*BB, IP, X86::MOV8rm, 4, HighPartOfCW), + CWFrameIdx, 1); // Set the high part to be round to zero... - addFrameReference(BMI(BB, IP, X86::MOVim8, 5), CWFrameIdx, 1).addZImm(12); + addFrameReference(BuildMI(*BB, IP, X86::MOV8mi, 5), + CWFrameIdx, 1).addImm(12); // Reload the modified control word now... - addFrameReference(BMI(BB, IP, X86::FLDCWm16, 4), CWFrameIdx); + addFrameReference(BuildMI(*BB, IP, X86::FLDCW16m, 4), CWFrameIdx); // Restore the memory image of control word to original value - addFrameReference(BMI(BB, IP, X86::MOVrm8, 5), + addFrameReference(BuildMI(*BB, IP, X86::MOV8mr, 5), CWFrameIdx, 1).addReg(HighPartOfCW); // We don't have the facilities for directly storing byte sized data to @@ -1929,19 +2295,21 @@ F->getFrameInfo()->CreateStackObject(StoreTy, TM.getTargetData()); static const unsigned Op1[] = - { 0, X86::FISTr16, X86::FISTr32, 0, X86::FISTPr64 }; - addFrameReference(BMI(BB, IP, Op1[StoreClass], 5), FrameIdx).addReg(SrcReg); + { 0, X86::FIST16m, X86::FIST32m, 0, X86::FISTP64m }; + addFrameReference(BuildMI(*BB, IP, Op1[StoreClass], 5), + FrameIdx).addReg(SrcReg); if (DestClass == cLong) { - addFrameReference(BMI(BB, IP, X86::MOVmr32, 4, DestReg), FrameIdx); - addFrameReference(BMI(BB, IP, X86::MOVmr32, 4, DestReg+1), FrameIdx, 4); + addFrameReference(BuildMI(*BB, IP, X86::MOV32rm, 4, DestReg), FrameIdx); + addFrameReference(BuildMI(*BB, IP, X86::MOV32rm, 4, DestReg+1), + FrameIdx, 4); } else { - static const unsigned Op2[] = { X86::MOVmr8, X86::MOVmr16, X86::MOVmr32 }; - addFrameReference(BMI(BB, IP, Op2[DestClass], 4, DestReg), FrameIdx); + static const unsigned Op2[] = { X86::MOV8rm, X86::MOV16rm, X86::MOV32rm }; + addFrameReference(BuildMI(*BB, IP, Op2[DestClass], 4, DestReg), FrameIdx); } // Reload the original control word now... - addFrameReference(BMI(BB, IP, X86::FLDCWm16, 4), CWFrameIdx); + addFrameReference(BuildMI(*BB, IP, X86::FLDCW16m, 4), CWFrameIdx); return; } @@ -1975,7 +2343,7 @@ } // Increment the VAList pointer... - BuildMI(BB, X86::ADDri32, 2, DestReg).addReg(VAList).addZImm(Size); + BuildMI(BB, X86::ADD32ri, 2, DestReg).addReg(VAList).addImm(Size); } void ISel::visitVAArgInst(VAArgInst &I) { @@ -1990,64 +2358,220 @@ case Type::PointerTyID: case Type::UIntTyID: case Type::IntTyID: - addDirectMem(BuildMI(BB, X86::MOVmr32, 4, DestReg), VAList); + addDirectMem(BuildMI(BB, X86::MOV32rm, 4, DestReg), VAList); break; case Type::ULongTyID: case Type::LongTyID: - addDirectMem(BuildMI(BB, X86::MOVmr32, 4, DestReg), VAList); - addRegOffset(BuildMI(BB, X86::MOVmr32, 4, DestReg+1), VAList, 4); + addDirectMem(BuildMI(BB, X86::MOV32rm, 4, DestReg), VAList); + addRegOffset(BuildMI(BB, X86::MOV32rm, 4, DestReg+1), VAList, 4); break; case Type::DoubleTyID: - addDirectMem(BuildMI(BB, X86::FLDr64, 4, DestReg), VAList); + addDirectMem(BuildMI(BB, X86::FLD64m, 4, DestReg), VAList); break; } } void ISel::visitGetElementPtrInst(GetElementPtrInst &I) { + // If this GEP instruction will be folded into all of its users, we don't need + // to explicitly calculate it! + unsigned A, B, C, D; + if (isGEPFoldable(0, I.getOperand(0), I.op_begin()+1, I.op_end(), A,B,C,D)) { + // Check all of the users of the instruction to see if they are loads and + // stores. + bool AllWillFold = true; + for (Value::use_iterator UI = I.use_begin(), E = I.use_end(); UI != E; ++UI) + if (cast(*UI)->getOpcode() != Instruction::Load) + if (cast(*UI)->getOpcode() != Instruction::Store || + cast(*UI)->getOperand(0) == &I) { + AllWillFold = false; + break; + } + + // If the instruction is foldable, and will be folded into all users, don't + // emit it! + if (AllWillFold) return; + } + unsigned outputReg = getReg(I); - MachineBasicBlock::iterator MI = BB->end(); - emitGEPOperation(BB, MI, I.getOperand(0), + emitGEPOperation(BB, BB->end(), I.getOperand(0), I.op_begin()+1, I.op_end(), outputReg); } +/// getGEPIndex - Inspect the getelementptr operands specified with GEPOps and +/// GEPTypes (the derived types being stepped through at each level). On return +/// from this function, if some indexes of the instruction are representable as +/// an X86 lea instruction, the machine operands are put into the Ops +/// instruction and the consumed indexes are poped from the GEPOps/GEPTypes +/// lists. Otherwise, GEPOps.size() is returned. If this returns a an +/// addressing mode that only partially consumes the input, the BaseReg input of +/// the addressing mode must be left free. +/// +/// Note that there is one fewer entry in GEPTypes than there is in GEPOps. +/// +void ISel::getGEPIndex(MachineBasicBlock *MBB, MachineBasicBlock::iterator IP, + std::vector &GEPOps, + std::vector &GEPTypes, unsigned &BaseReg, + unsigned &Scale, unsigned &IndexReg, unsigned &Disp) { + const TargetData &TD = TM.getTargetData(); + + // Clear out the state we are working with... + BaseReg = 0; // No base register + Scale = 1; // Unit scale + IndexReg = 0; // No index register + Disp = 0; // No displacement + + // While there are GEP indexes that can be folded into the current address, + // keep processing them. + while (!GEPTypes.empty()) { + if (const StructType *StTy = dyn_cast(GEPTypes.back())) { + // It's a struct access. CUI is the index into the structure, + // which names the field. This index must have unsigned type. + const ConstantUInt *CUI = cast(GEPOps.back()); + + // Use the TargetData structure to pick out what the layout of the + // structure is in memory. Since the structure index must be constant, we + // can get its value and use it to find the right byte offset from the + // StructLayout class's list of structure member offsets. + Disp += TD.getStructLayout(StTy)->MemberOffsets[CUI->getValue()]; + GEPOps.pop_back(); // Consume a GEP operand + GEPTypes.pop_back(); + } else { + // It's an array or pointer access: [ArraySize x ElementType]. + const SequentialType *SqTy = cast(GEPTypes.back()); + Value *idx = GEPOps.back(); + + // idx is the index into the array. Unlike with structure + // indices, we may not know its actual value at code-generation + // time. + assert(idx->getType() == Type::LongTy && "Bad GEP array index!"); + + // If idx is a constant, fold it into the offset. + unsigned TypeSize = TD.getTypeSize(SqTy->getElementType()); + if (ConstantSInt *CSI = dyn_cast(idx)) { + Disp += TypeSize*CSI->getValue(); + } else { + // If the index reg is already taken, we can't handle this index. + if (IndexReg) return; + + // If this is a size that we can handle, then add the index as + switch (TypeSize) { + case 1: case 2: case 4: case 8: + // These are all acceptable scales on X86. + Scale = TypeSize; + break; + default: + // Otherwise, we can't handle this scale + return; + } + + if (CastInst *CI = dyn_cast(idx)) + if (CI->getOperand(0)->getType() == Type::IntTy || + CI->getOperand(0)->getType() == Type::UIntTy) + idx = CI->getOperand(0); + + IndexReg = MBB ? getReg(idx, MBB, IP) : 1; + } + + GEPOps.pop_back(); // Consume a GEP operand + GEPTypes.pop_back(); + } + } + + // GEPTypes is empty, which means we have a single operand left. See if we + // can set it as the base register. + // + // FIXME: When addressing modes are more powerful/correct, we could load + // global addresses directly as 32-bit immediates. + assert(BaseReg == 0); + BaseReg = MBB ? getReg(GEPOps[0], MBB, IP) : 1; + GEPOps.pop_back(); // Consume the last GEP operand +} + + +/// isGEPFoldable - Return true if the specified GEP can be completely +/// folded into the addressing mode of a load/store or lea instruction. +bool ISel::isGEPFoldable(MachineBasicBlock *MBB, + Value *Src, User::op_iterator IdxBegin, + User::op_iterator IdxEnd, unsigned &BaseReg, + unsigned &Scale, unsigned &IndexReg, unsigned &Disp) { + if (ConstantPointerRef *CPR = dyn_cast(Src)) + Src = CPR->getValue(); + + std::vector GEPOps; + GEPOps.resize(IdxEnd-IdxBegin+1); + GEPOps[0] = Src; + std::copy(IdxBegin, IdxEnd, GEPOps.begin()+1); + + std::vector GEPTypes; + GEPTypes.assign(gep_type_begin(Src->getType(), IdxBegin, IdxEnd), + gep_type_end(Src->getType(), IdxBegin, IdxEnd)); + + MachineBasicBlock::iterator IP; + if (MBB) IP = MBB->end(); + getGEPIndex(MBB, IP, GEPOps, GEPTypes, BaseReg, Scale, IndexReg, Disp); + + // We can fold it away iff the getGEPIndex call eliminated all operands. + return GEPOps.empty(); +} + void ISel::emitGEPOperation(MachineBasicBlock *MBB, - MachineBasicBlock::iterator &IP, + MachineBasicBlock::iterator IP, Value *Src, User::op_iterator IdxBegin, User::op_iterator IdxEnd, unsigned TargetReg) { const TargetData &TD = TM.getTargetData(); - const Type *Ty = Src->getType(); - unsigned BaseReg = getReg(Src, MBB, IP); + if (ConstantPointerRef *CPR = dyn_cast(Src)) + Src = CPR->getValue(); + + std::vector GEPOps; + GEPOps.resize(IdxEnd-IdxBegin+1); + GEPOps[0] = Src; + std::copy(IdxBegin, IdxEnd, GEPOps.begin()+1); + + std::vector GEPTypes; + GEPTypes.assign(gep_type_begin(Src->getType(), IdxBegin, IdxEnd), + gep_type_end(Src->getType(), IdxBegin, IdxEnd)); + + // Keep emitting instructions until we consume the entire GEP instruction. + while (!GEPOps.empty()) { + unsigned OldSize = GEPOps.size(); + unsigned BaseReg, Scale, IndexReg, Disp; + getGEPIndex(MBB, IP, GEPOps, GEPTypes, BaseReg, Scale, IndexReg, Disp); + + if (GEPOps.size() != OldSize) { + // getGEPIndex consumed some of the input. Build an LEA instruction here. + unsigned NextTarget = 0; + if (!GEPOps.empty()) { + assert(BaseReg == 0 && + "getGEPIndex should have left the base register open for chaining!"); + NextTarget = BaseReg = makeAnotherReg(Type::UIntTy); + } - // GEPs have zero or more indices; we must perform a struct access - // or array access for each one. - for (GetElementPtrInst::op_iterator oi = IdxBegin, - oe = IdxEnd; oi != oe; ++oi) { - Value *idx = *oi; - unsigned NextReg = BaseReg; - if (const StructType *StTy = dyn_cast(Ty)) { - // It's a struct access. idx is the index into the structure, - // which names the field. This index must have ubyte type. - const ConstantUInt *CUI = cast(idx); - assert(CUI->getType() == Type::UByteTy - && "Funny-looking structure index in GEP"); - // Use the TargetData structure to pick out what the layout of - // the structure is in memory. Since the structure index must - // be constant, we can get its value and use it to find the - // right byte offset from the StructLayout class's list of - // structure member offsets. - unsigned idxValue = CUI->getValue(); - unsigned FieldOff = TD.getStructLayout(StTy)->MemberOffsets[idxValue]; - if (FieldOff) { - NextReg = makeAnotherReg(Type::UIntTy); - // Emit an ADD to add FieldOff to the basePtr. - BMI(MBB, IP, X86::ADDri32, 2,NextReg).addReg(BaseReg).addZImm(FieldOff); - } - // The next type is the member of the structure selected by the - // index. - Ty = StTy->getElementTypes()[idxValue]; - } else if (const SequentialType *SqTy = cast(Ty)) { + if (IndexReg == 0 && Disp == 0) + BuildMI(*MBB, IP, X86::MOV32rr, 1, TargetReg).addReg(BaseReg); + else + addFullAddress(BuildMI(*MBB, IP, X86::LEA32r, 5, TargetReg), + BaseReg, Scale, IndexReg, Disp); + --IP; + TargetReg = NextTarget; + } else if (GEPTypes.empty()) { + // The getGEPIndex operation didn't want to build an LEA. Check to see if + // all operands are consumed but the base pointer. If so, just load it + // into the register. + if (GlobalValue *GV = dyn_cast(GEPOps[0])) { + BuildMI(*MBB, IP, X86::MOV32ri, 1, TargetReg).addGlobalAddress(GV); + } else { + unsigned BaseReg = getReg(GEPOps[0], MBB, IP); + BuildMI(*MBB, IP, X86::MOV32rr, 1, TargetReg).addReg(BaseReg); + } + break; // we are now done + + } else { // It's an array or pointer access: [ArraySize x ElementType]. + const SequentialType *SqTy = cast(GEPTypes.back()); + Value *idx = GEPOps.back(); + GEPOps.pop_back(); // Consume a GEP operand + GEPTypes.pop_back(); // idx is the index into the array. Unlike with structure // indices, we may not know its actual value at code-generation @@ -2064,41 +2588,54 @@ // We want to add BaseReg to(idxReg * sizeof ElementType). First, we // must find the size of the pointed-to type (Not coincidentally, the next // type is the type of the elements in the array). - Ty = SqTy->getElementType(); - unsigned elementSize = TD.getTypeSize(Ty); + const Type *ElTy = SqTy->getElementType(); + unsigned elementSize = TD.getTypeSize(ElTy); // If idxReg is a constant, we don't need to perform the multiply! if (ConstantSInt *CSI = dyn_cast(idx)) { if (!CSI->isNullValue()) { unsigned Offset = elementSize*CSI->getValue(); - NextReg = makeAnotherReg(Type::UIntTy); - BMI(MBB, IP, X86::ADDri32, 2,NextReg).addReg(BaseReg).addZImm(Offset); + unsigned Reg = makeAnotherReg(Type::UIntTy); + BuildMI(*MBB, IP, X86::ADD32ri, 2, TargetReg) + .addReg(Reg).addImm(Offset); + --IP; // Insert the next instruction before this one. + TargetReg = Reg; // Codegen the rest of the GEP into this } } else if (elementSize == 1) { // If the element size is 1, we don't have to multiply, just add unsigned idxReg = getReg(idx, MBB, IP); - NextReg = makeAnotherReg(Type::UIntTy); - BMI(MBB, IP, X86::ADDrr32, 2, NextReg).addReg(BaseReg).addReg(idxReg); + unsigned Reg = makeAnotherReg(Type::UIntTy); + BuildMI(*MBB, IP, X86::ADD32rr, 2,TargetReg).addReg(Reg).addReg(idxReg); + --IP; // Insert the next instruction before this one. + TargetReg = Reg; // Codegen the rest of the GEP into this } else { unsigned idxReg = getReg(idx, MBB, IP); unsigned OffsetReg = makeAnotherReg(Type::UIntTy); + // Make sure we can back the iterator up to point to the first + // instruction emitted. + MachineBasicBlock::iterator BeforeIt = IP; + if (IP == MBB->begin()) + BeforeIt = MBB->end(); + else + --BeforeIt; doMultiplyConst(MBB, IP, OffsetReg, Type::IntTy, idxReg, elementSize); // Emit an ADD to add OffsetReg to the basePtr. - NextReg = makeAnotherReg(Type::UIntTy); - BMI(MBB, IP, X86::ADDrr32, 2,NextReg).addReg(BaseReg).addReg(OffsetReg); + unsigned Reg = makeAnotherReg(Type::UIntTy); + BuildMI(*MBB, IP, X86::ADD32rr, 2, TargetReg) + .addReg(Reg).addReg(OffsetReg); + + // Step to the first instruction of the multiply. + if (BeforeIt == MBB->end()) + IP = MBB->begin(); + else + IP = ++BeforeIt; + + TargetReg = Reg; // Codegen the rest of the GEP into this } } - // Now that we are here, further indices refer to subtypes of this - // one, so we don't need to worry about BaseReg itself, anymore. - BaseReg = NextReg; - } - // After we have processed all the indices, the result is left in - // BaseReg. Move it to the register where we were expected to - // put the answer. A 32-bit move should do it, because we are in - // ILP32 land. - BMI(MBB, IP, X86::MOVrr32, 1, TargetReg).addReg(BaseReg); + } } @@ -2120,7 +2657,7 @@ // Create a new stack object using the frame manager... int FrameIdx = F->getFrameInfo()->CreateStackObject(TySize, Alignment); - addFrameReference(BuildMI(BB, X86::LEAr32, 5, getReg(I)), FrameIdx); + addFrameReference(BuildMI(BB, X86::LEA32r, 5, getReg(I)), FrameIdx); return; } } @@ -2136,18 +2673,18 @@ // AddedSize = add , 15 unsigned AddedSizeReg = makeAnotherReg(Type::UIntTy); - BuildMI(BB, X86::ADDri32, 2, AddedSizeReg).addReg(TotalSizeReg).addZImm(15); + BuildMI(BB, X86::ADD32ri, 2, AddedSizeReg).addReg(TotalSizeReg).addImm(15); // AlignedSize = and , ~15 unsigned AlignedSize = makeAnotherReg(Type::UIntTy); - BuildMI(BB, X86::ANDri32, 2, AlignedSize).addReg(AddedSizeReg).addZImm(~15); + BuildMI(BB, X86::AND32ri, 2, AlignedSize).addReg(AddedSizeReg).addImm(~15); // Subtract size from stack pointer, thereby allocating some space. - BuildMI(BB, X86::SUBrr32, 2, X86::ESP).addReg(X86::ESP).addReg(AlignedSize); + BuildMI(BB, X86::SUB32rr, 2, X86::ESP).addReg(X86::ESP).addReg(AlignedSize); // Put a pointer to the space into the result register, by copying // the stack pointer. - BuildMI(BB, X86::MOVrr32, 1, getReg(I)).addReg(X86::ESP); + BuildMI(BB, X86::MOV32rr, 1, getReg(I)).addReg(X86::ESP); // Inform the Frame Information that we have just allocated a variable-sized // object. Index: llvm/lib/Target/X86/PeepholeOptimizer.cpp diff -u llvm/lib/Target/X86/PeepholeOptimizer.cpp:1.9 llvm/lib/Target/X86/PeepholeOptimizer.cpp:1.9.2.1 --- llvm/lib/Target/X86/PeepholeOptimizer.cpp:1.9 Sun Dec 14 07:24:15 2003 +++ llvm/lib/Target/X86/PeepholeOptimizer.cpp Mon Mar 1 17:58:15 2004 @@ -14,12 +14,18 @@ #include "X86.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/Target/MRegisterInfo.h" +#include "llvm/Target/TargetInstrInfo.h" +#include "llvm/Target/TargetMachine.h" #include "Support/Statistic.h" +#include "Support/STLExtras.h" + using namespace llvm; namespace { Statistic<> NumPHOpts("x86-peephole", "Number of peephole optimization performed"); + Statistic<> NumPHMoves("x86-peephole", "Number of peephole moves folded"); struct PH : public MachineFunctionPass { virtual bool runOnMachineFunction(MachineFunction &MF); @@ -49,16 +55,18 @@ bool PH::PeepholeOptimize(MachineBasicBlock &MBB, MachineBasicBlock::iterator &I) { - MachineInstr *MI = *I; - MachineInstr *Next = (I+1 != MBB.end()) ? *(I+1) : 0; + assert(I != MBB.end()); + MachineBasicBlock::iterator NextI = next(I); + + MachineInstr *MI = I; + MachineInstr *Next = (NextI != MBB.end()) ? &*NextI : (MachineInstr*)0; unsigned Size = 0; switch (MI->getOpcode()) { - case X86::MOVrr8: - case X86::MOVrr16: - case X86::MOVrr32: // Destroy X = X copies... + case X86::MOV8rr: + case X86::MOV16rr: + case X86::MOV32rr: // Destroy X = X copies... if (MI->getOperand(0).getReg() == MI->getOperand(1).getReg()) { I = MBB.erase(I); - delete MI; return true; } return false; @@ -67,12 +75,7 @@ // immediate despite the fact that the operands are 16 or 32 bits. Because // this can save three bytes of code size (and icache space), we want to // shrink them if possible. - case X86::ADDri16: case X86::ADDri32: - case X86::SUBri16: case X86::SUBri32: - case X86::IMULri16: case X86::IMULri32: - case X86::ANDri16: case X86::ANDri32: - case X86::ORri16: case X86::ORri32: - case X86::XORri16: case X86::XORri32: + case X86::IMUL16rri: case X86::IMUL32rri: assert(MI->getNumOperands() == 3 && "These should all have 3 operands!"); if (MI->getOperand(2).isImmediate()) { int Val = MI->getOperand(2).getImmedValue(); @@ -81,41 +84,127 @@ unsigned Opcode; switch (MI->getOpcode()) { default: assert(0 && "Unknown opcode value!"); - case X86::ADDri16: Opcode = X86::ADDri16b; break; - case X86::ADDri32: Opcode = X86::ADDri32b; break; - case X86::SUBri16: Opcode = X86::SUBri16b; break; - case X86::SUBri32: Opcode = X86::SUBri32b; break; - case X86::IMULri16: Opcode = X86::IMULri16b; break; - case X86::IMULri32: Opcode = X86::IMULri32b; break; - case X86::ANDri16: Opcode = X86::ANDri16b; break; - case X86::ANDri32: Opcode = X86::ANDri32b; break; - case X86::ORri16: Opcode = X86::ORri16b; break; - case X86::ORri32: Opcode = X86::ORri32b; break; - case X86::XORri16: Opcode = X86::XORri16b; break; - case X86::XORri32: Opcode = X86::XORri32b; break; + case X86::IMUL16rri: Opcode = X86::IMUL16rri8; break; + case X86::IMUL32rri: Opcode = X86::IMUL32rri8; break; } unsigned R0 = MI->getOperand(0).getReg(); unsigned R1 = MI->getOperand(1).getReg(); - *I = BuildMI(Opcode, 2, R0).addReg(R1).addZImm((char)Val); - delete MI; + I = MBB.insert(MBB.erase(I), + BuildMI(Opcode, 2, R0).addReg(R1).addZImm((char)Val)); + return true; + } + } + return false; + +#if 0 + case X86::IMUL16rmi: case X86::IMUL32rmi: + assert(MI->getNumOperands() == 6 && "These should all have 6 operands!"); + if (MI->getOperand(5).isImmediate()) { + int Val = MI->getOperand(5).getImmedValue(); + // If the value is the same when signed extended from 8 bits... + if (Val == (signed int)(signed char)Val) { + unsigned Opcode; + switch (MI->getOpcode()) { + default: assert(0 && "Unknown opcode value!"); + case X86::IMUL16rmi: Opcode = X86::IMUL16rmi8; break; + case X86::IMUL32rmi: Opcode = X86::IMUL32rmi8; break; + } + unsigned R0 = MI->getOperand(0).getReg(); + unsigned R1 = MI->getOperand(1).getReg(); + unsigned Scale = MI->getOperand(2).getImmedValue(); + unsigned R2 = MI->getOperand(3).getReg(); + unsigned Offset = MI->getOperand(4).getImmedValue(); + I = MBB.insert(MBB.erase(I), + BuildMI(Opcode, 5, R0).addReg(R1).addZImm(Scale). + addReg(R2).addSImm(Offset).addZImm((char)Val)); + return true; + } + } + return false; +#endif + + case X86::ADD16ri: case X86::ADD32ri: + case X86::SUB16ri: case X86::SUB32ri: + case X86::AND16ri: case X86::AND32ri: + case X86::OR16ri: case X86::OR32ri: + case X86::XOR16ri: case X86::XOR32ri: + assert(MI->getNumOperands() == 2 && "These should all have 2 operands!"); + if (MI->getOperand(1).isImmediate()) { + int Val = MI->getOperand(1).getImmedValue(); + // If the value is the same when signed extended from 8 bits... + if (Val == (signed int)(signed char)Val) { + unsigned Opcode; + switch (MI->getOpcode()) { + default: assert(0 && "Unknown opcode value!"); + case X86::ADD16ri: Opcode = X86::ADD16ri8; break; + case X86::ADD32ri: Opcode = X86::ADD32ri8; break; + case X86::SUB16ri: Opcode = X86::SUB16ri8; break; + case X86::SUB32ri: Opcode = X86::SUB32ri8; break; + case X86::AND16ri: Opcode = X86::AND16ri8; break; + case X86::AND32ri: Opcode = X86::AND32ri8; break; + case X86::OR16ri: Opcode = X86::OR16ri8; break; + case X86::OR32ri: Opcode = X86::OR32ri8; break; + case X86::XOR16ri: Opcode = X86::XOR16ri8; break; + case X86::XOR32ri: Opcode = X86::XOR32ri8; break; + } + unsigned R0 = MI->getOperand(0).getReg(); + I = MBB.insert(MBB.erase(I), + BuildMI(Opcode, 1, R0, MachineOperand::UseAndDef) + .addZImm((char)Val)); + return true; + } + } + return false; + + case X86::ADD16mi: case X86::ADD32mi: + case X86::SUB16mi: case X86::SUB32mi: + case X86::AND16mi: case X86::AND32mi: + case X86::OR16mi: case X86::OR32mi: + case X86::XOR16mi: case X86::XOR32mi: + assert(MI->getNumOperands() == 5 && "These should all have 5 operands!"); + if (MI->getOperand(4).isImmediate()) { + int Val = MI->getOperand(4).getImmedValue(); + // If the value is the same when signed extended from 8 bits... + if (Val == (signed int)(signed char)Val) { + unsigned Opcode; + switch (MI->getOpcode()) { + default: assert(0 && "Unknown opcode value!"); + case X86::ADD16mi: Opcode = X86::ADD16mi8; break; + case X86::ADD32mi: Opcode = X86::ADD32mi8; break; + case X86::SUB16mi: Opcode = X86::SUB16mi8; break; + case X86::SUB32mi: Opcode = X86::SUB32mi8; break; + case X86::AND16mi: Opcode = X86::AND16mi8; break; + case X86::AND32mi: Opcode = X86::AND32mi8; break; + case X86::OR16mi: Opcode = X86::OR16mi8; break; + case X86::OR32mi: Opcode = X86::OR32mi8; break; + case X86::XOR16mi: Opcode = X86::XOR16mi8; break; + case X86::XOR32mi: Opcode = X86::XOR32mi8; break; + } + unsigned R0 = MI->getOperand(0).getReg(); + unsigned Scale = MI->getOperand(1).getImmedValue(); + unsigned R1 = MI->getOperand(2).getReg(); + unsigned Offset = MI->getOperand(3).getImmedValue(); + I = MBB.insert(MBB.erase(I), + BuildMI(Opcode, 5).addReg(R0).addZImm(Scale). + addReg(R1).addSImm(Offset).addZImm((char)Val)); return true; } } return false; #if 0 - case X86::MOVir32: Size++; - case X86::MOVir16: Size++; - case X86::MOVir8: + case X86::MOV32ri: Size++; + case X86::MOV16ri: Size++; + case X86::MOV8ri: // FIXME: We can only do this transformation if we know that flags are not // used here, because XOR clobbers the flags! if (MI->getOperand(1).isImmediate()) { // avoid mov EAX, int Val = MI->getOperand(1).getImmedValue(); if (Val == 0) { // mov EAX, 0 -> xor EAX, EAX - static const unsigned Opcode[] ={X86::XORrr8,X86::XORrr16,X86::XORrr32}; + static const unsigned Opcode[] ={X86::XOR8rr,X86::XOR16rr,X86::XOR32rr}; unsigned Reg = MI->getOperand(0).getReg(); - *I = BuildMI(Opcode[Size], 2, Reg).addReg(Reg).addReg(Reg); - delete MI; + I = MBB.insert(MBB.erase(I), + BuildMI(Opcode[Size], 2, Reg).addReg(Reg).addReg(Reg)); return true; } else if (Val == -1) { // mov EAX, -1 -> or EAX, -1 // TODO: 'or Reg, -1' has a smaller encoding than 'mov Reg, -1' @@ -123,12 +212,10 @@ } return false; #endif - case X86::BSWAPr32: // Change bswap EAX, bswap EAX into nothing - if (Next->getOpcode() == X86::BSWAPr32 && + case X86::BSWAP32r: // Change bswap EAX, bswap EAX into nothing + if (Next->getOpcode() == X86::BSWAP32r && MI->getOperand(0).getReg() == Next->getOperand(0).getReg()) { I = MBB.erase(MBB.erase(I)); - delete MI; - delete Next; return true; } return false; @@ -144,7 +231,7 @@ // getDefinition - Return the machine instruction that defines the specified // SSA virtual register. MachineInstr *getDefinition(unsigned Reg) { - assert(Reg >= MRegisterInfo::FirstVirtualRegister && + assert(MRegisterInfo::isVirtualRegister(Reg) && "use-def chains only exist for SSA registers!"); assert(Reg - MRegisterInfo::FirstVirtualRegister < DefiningInst.size() && "Unknown register number!"); @@ -171,11 +258,11 @@ virtual bool runOnMachineFunction(MachineFunction &MF) { for (MachineFunction::iterator BI = MF.begin(), E = MF.end(); BI!=E; ++BI) for (MachineBasicBlock::iterator I = BI->begin(); I != BI->end(); ++I) { - MachineInstr *MI = *I; - for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { - MachineOperand &MO = MI->getOperand(i); - if (MO.isVirtualRegister() && MO.isDef() && !MO.isUse()) - setDefinition(MO.getReg(), MI); + for (unsigned i = 0, e = I->getNumOperands(); i != e; ++i) { + MachineOperand &MO = I->getOperand(i); + if (MO.isRegister() && MO.isDef() && !MO.isUse() && + MRegisterInfo::isVirtualRegister(MO.getReg())) + setDefinition(MO.getReg(), I); } } return false; @@ -233,7 +320,8 @@ /// register, return the machine instruction defining it, otherwise, return /// null. MachineInstr *getDefiningInst(MachineOperand &MO) { - if (MO.isDef() || !MO.isVirtualRegister()) return 0; + if (MO.isDef() || !MO.isRegister() || + !MRegisterInfo::isVirtualRegister(MO.getReg())) return 0; return UDC->getDefinition(MO.getReg()); } @@ -299,7 +387,7 @@ // Attempt to fold instructions used by the base register into the instruction if (MachineInstr *DefInst = getDefiningInst(BaseRegOp)) { switch (DefInst->getOpcode()) { - case X86::MOVir32: + case X86::MOV32ri: // If there is no displacement set for this instruction set one now. // FIXME: If we can fold two immediates together, we should do so! if (DisplacementOp.isImmediate() && !DisplacementOp.getImmedValue()) { @@ -310,7 +398,7 @@ } break; - case X86::ADDrr32: + case X86::ADD32rr: // If the source is a register-register add, and we do not yet have an // index register, fold the add into the memory address. if (IndexReg == 0) { @@ -321,7 +409,7 @@ } break; - case X86::SHLir32: + case X86::SHL32ri: // If this shift could be folded into the index portion of the address if // it were the index register, move it to the index register operand now, // so it will be folded in below. @@ -339,7 +427,7 @@ // Attempt to fold instructions used by the index into the instruction if (MachineInstr *DefInst = getDefiningInst(IndexRegOp)) { switch (DefInst->getOpcode()) { - case X86::SHLir32: { + case X86::SHL32ri: { // Figure out what the resulting scale would be if we folded this shift. unsigned ResScale = Scale * (1 << DefInst->getOperand(2).getImmedValue()); if (isValidScaleAmount(ResScale)) { @@ -357,41 +445,48 @@ bool SSAPH::PeepholeOptimize(MachineBasicBlock &MBB, MachineBasicBlock::iterator &I) { - MachineInstr *MI = *I; - MachineInstr *Next = (I+1 != MBB.end()) ? *(I+1) : 0; + MachineBasicBlock::iterator NextI = next(I); + + MachineInstr *MI = I; + MachineInstr *Next = (NextI != MBB.end()) ? &*NextI : (MachineInstr*)0; bool Changed = false; + const TargetInstrInfo &TII = MBB.getParent()->getTarget().getInstrInfo(); + // Scan the operands of this instruction. If any operands are // register-register copies, replace the operand with the source. for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) // Is this an SSA register use? - if (MachineInstr *DefInst = getDefiningInst(MI->getOperand(i))) + if (MachineInstr *DefInst = getDefiningInst(MI->getOperand(i))) { // If the operand is a vreg-vreg copy, it is always safe to replace the // source value with the input operand. - if (DefInst->getOpcode() == X86::MOVrr8 || - DefInst->getOpcode() == X86::MOVrr16 || - DefInst->getOpcode() == X86::MOVrr32) { - // Don't propagate physical registers into PHI nodes... - if (MI->getOpcode() != X86::PHI || - DefInst->getOperand(1).isVirtualRegister()) - Changed = Propagate(MI, i, DefInst, 1); + unsigned Source, Dest; + if (TII.isMoveInstr(*DefInst, Source, Dest)) { + // Don't propagate physical registers into any instructions. + if (DefInst->getOperand(1).isRegister() && + MRegisterInfo::isVirtualRegister(Source)) { + MI->getOperand(i).setReg(Source); + Changed = true; + ++NumPHMoves; + } } + } // Perform instruction specific optimizations. switch (MI->getOpcode()) { // Register to memory stores. Format: , srcreg - case X86::MOVrm32: case X86::MOVrm16: case X86::MOVrm8: - case X86::MOVim32: case X86::MOVim16: case X86::MOVim8: + case X86::MOV32mr: case X86::MOV16mr: case X86::MOV8mr: + case X86::MOV32mi: case X86::MOV16mi: case X86::MOV8mi: // Check to see if we can fold the source instruction into this one... if (MachineInstr *SrcInst = getDefiningInst(MI->getOperand(4))) { switch (SrcInst->getOpcode()) { // Fold the immediate value into the store, if possible. - case X86::MOVir8: return Propagate(MI, 4, SrcInst, 1, X86::MOVim8); - case X86::MOVir16: return Propagate(MI, 4, SrcInst, 1, X86::MOVim16); - case X86::MOVir32: return Propagate(MI, 4, SrcInst, 1, X86::MOVim32); + case X86::MOV8ri: return Propagate(MI, 4, SrcInst, 1, X86::MOV8mi); + case X86::MOV16ri: return Propagate(MI, 4, SrcInst, 1, X86::MOV16mi); + case X86::MOV32ri: return Propagate(MI, 4, SrcInst, 1, X86::MOV32mi); default: break; } } @@ -401,9 +496,9 @@ return true; break; - case X86::MOVmr32: - case X86::MOVmr16: - case X86::MOVmr8: + case X86::MOV32rm: + case X86::MOV16rm: + case X86::MOV8rm: // If we can optimize the addressing expression, do so now. if (OptimizeAddress(MI, 1)) return true; Index: llvm/lib/Target/X86/Printer.cpp diff -u llvm/lib/Target/X86/Printer.cpp:1.76 llvm/lib/Target/X86/Printer.cpp:1.76.2.1 --- llvm/lib/Target/X86/Printer.cpp:1.76 Wed Jan 14 11:14:42 2004 +++ llvm/lib/Target/X86/Printer.cpp Mon Mar 1 17:58:15 2004 @@ -28,8 +28,7 @@ #include "Support/Statistic.h" #include "Support/StringExtras.h" #include "Support/CommandLine.h" - -namespace llvm { +using namespace llvm; namespace { Statistic<> EmittedInsts("asm-printer", "Number of machine instrs printed"); @@ -91,7 +90,7 @@ /// using the given target machine description. This should work /// regardless of whether the function is in SSA form. /// -FunctionPass *createX86CodePrinterPass(std::ostream &o,TargetMachine &tm){ +FunctionPass *llvm::createX86CodePrinterPass(std::ostream &o,TargetMachine &tm){ return new Printer(o, tm); } @@ -145,7 +144,10 @@ assert(CB == ConstantBool::True); O << "1"; } else if (const ConstantSInt *CI = dyn_cast(CV)) - O << CI->getValue(); + if (((CI->getValue() << 32) >> 32) == CI->getValue()) + O << CI->getValue(); + else + O << (unsigned long long)CI->getValue(); else if (const ConstantUInt *CI = dyn_cast(CV)) O << CI->getValue(); else if (const ConstantPointerRef *CPR = dyn_cast(CV)) @@ -365,7 +367,7 @@ II != E; ++II) { // Print the assembly for the instruction. O << "\t"; - printMachineInstruction(*II); + printMachineInstruction(II); } } @@ -400,7 +402,7 @@ } // FALLTHROUGH case MachineOperand::MO_MachineRegister: - if (MO.getReg() < MRegisterInfo::FirstVirtualRegister) + if (MRegisterInfo::isPhysicalRegister(MO.getReg())) // Bug Workaround: See note in Printer::doInitialization about %. O << "%" << RI.get(MO.getReg()).Name; else @@ -431,16 +433,14 @@ } } -static const std::string sizePtr(const TargetInstrDescriptor &Desc) { - switch (Desc.TSFlags & X86II::ArgMask) { +static const char* const sizePtr(const TargetInstrDescriptor &Desc) { + switch (Desc.TSFlags & X86II::MemMask) { default: assert(0 && "Unknown arg size!"); - case X86II::Arg8: return "BYTE PTR"; - case X86II::Arg16: return "WORD PTR"; - case X86II::Arg32: return "DWORD PTR"; - case X86II::Arg64: return "QWORD PTR"; - case X86II::ArgF32: return "DWORD PTR"; - case X86II::ArgF64: return "QWORD PTR"; - case X86II::ArgF80: return "XWORD PTR"; + case X86II::Mem8: return "BYTE PTR"; + case X86II::Mem16: return "WORD PTR"; + case X86II::Mem32: return "DWORD PTR"; + case X86II::Mem64: return "QWORD PTR"; + case X86II::Mem80: return "XWORD PTR"; } } @@ -594,7 +594,7 @@ unsigned Reg = MI->getOperand(0).getReg(); - O << TII.getName(MI->getOpCode()) << " "; + O << TII.getName(MI->getOpcode()) << " "; printOp(MI->getOperand(0)); if (MI->getNumOperands() == 2 && (!MI->getOperand(1).isRegister() || @@ -609,35 +609,31 @@ return; } case X86II::MRMDestReg: { - // There are two acceptable forms of MRMDestReg instructions, those with 2, - // 3 and 4 operands: + // There are three forms of MRMDestReg instructions, those with 2 + // or 3 operands: // - // 2 Operands: this is for things like mov that do not read a second input + // 2 Operands: this is for things like mov that do not read a + // second input. // - // 3 Operands: in this form, the first two registers (the destination, and - // the first operand) should be the same, post register allocation. The 3rd - // operand is an additional input. This should be for things like add - // instructions. + // 2 Operands: two address instructions which def&use the first + // argument and use the second as input. // - // 4 Operands: This form is for instructions which are 3 operands forms, but - // have a constant argument as well. + // 3 Operands: in this form, two address instructions are the same + // as in 2 but have a constant argument as well. // bool isTwoAddr = TII.isTwoAddrInstr(Opcode); assert(MI->getOperand(0).isRegister() && (MI->getNumOperands() == 2 || - (isTwoAddr && MI->getOperand(1).isRegister() && - MI->getOperand(0).getReg() == MI->getOperand(1).getReg() && - (MI->getNumOperands() == 3 || - (MI->getNumOperands() == 4 && MI->getOperand(3).isImmediate())))) + (MI->getNumOperands() == 3 && MI->getOperand(2).isImmediate())) && "Bad format for MRMDestReg!"); - O << TII.getName(MI->getOpCode()) << " "; + O << TII.getName(MI->getOpcode()) << " "; printOp(MI->getOperand(0)); O << ", "; - printOp(MI->getOperand(1+isTwoAddr)); - if (MI->getNumOperands() == 4) { + printOp(MI->getOperand(1)); + if (MI->getNumOperands() == 3) { O << ", "; - printOp(MI->getOperand(3)); + printOp(MI->getOperand(2)); } O << "\n"; return; @@ -647,52 +643,53 @@ // These instructions are the same as MRMDestReg, but instead of having a // register reference for the mod/rm field, it's a memory reference. // - assert(isMem(MI, 0) && MI->getNumOperands() == 4+1 && - MI->getOperand(4).isRegister() && "Bad format for MRMDestMem!"); + assert(isMem(MI, 0) && + (MI->getNumOperands() == 4+1 || + (MI->getNumOperands() == 4+2 && MI->getOperand(5).isImmediate())) + && "Bad format for MRMDestMem!"); - O << TII.getName(MI->getOpCode()) << " " << sizePtr(Desc) << " "; + O << TII.getName(MI->getOpcode()) << " " << sizePtr(Desc) << " "; printMemReference(MI, 0); O << ", "; printOp(MI->getOperand(4)); + if (MI->getNumOperands() == 4+2) { + O << ", "; + printOp(MI->getOperand(5)); + } O << "\n"; return; } case X86II::MRMSrcReg: { - // There are three forms that are acceptable for MRMSrcReg instructions, - // those with 3 and 2 operands: + // There are three forms that are acceptable for MRMSrcReg + // instructions, those with 2 or 3 operands: // - // 3 Operands: in this form, the last register (the second input) is the - // ModR/M input. The first two operands should be the same, post register - // allocation. This is for things like: add r32, r/m32 + // 2 Operands: this is for things like mov that do not read a + // second input. // - // 3 Operands: in this form, we can have 'INST R, R, imm', which is used for - // instructions like the IMULri instructions. + // 2 Operands: in this form, the last register is the ModR/M + // input. The first operand is a def&use. This is for things + // like: add r32, r/m32 + // + // 3 Operands: in this form, we can have 'INST R1, R2, imm', which is used + // for instructions like the IMULrri instructions. // - // 2 Operands: this is for things like mov that do not read a second input // assert(MI->getOperand(0).isRegister() && MI->getOperand(1).isRegister() && - (MI->getNumOperands() == 2 || - (MI->getNumOperands() == 3 && - (MI->getOperand(2).isRegister() || - MI->getOperand(2).isImmediate()))) + (MI->getNumOperands() == 2 || + (MI->getNumOperands() == 3 && + (MI->getOperand(2).isImmediate()))) && "Bad format for MRMSrcReg!"); - if (MI->getNumOperands() == 3 && - MI->getOperand(0).getReg() != MI->getOperand(1).getReg()) - O << "**"; - O << TII.getName(MI->getOpCode()) << " "; + O << TII.getName(MI->getOpcode()) << " "; printOp(MI->getOperand(0)); - - // If this is IMULri* instructions, print the non-two-address operand. - if (MI->getNumOperands() == 3 && MI->getOperand(2).isImmediate()) { - O << ", "; - printOp(MI->getOperand(1)); - } - O << ", "; - printOp(MI->getOperand(MI->getNumOperands()-1)); + printOp(MI->getOperand(1)); + if (MI->getNumOperands() == 3) { + O << ", "; + printOp(MI->getOperand(2)); + } O << "\n"; return; } @@ -703,25 +700,24 @@ // assert(MI->getOperand(0).isRegister() && (MI->getNumOperands() == 1+4 && isMem(MI, 1)) || - (MI->getNumOperands() == 2+4 && MI->getOperand(1).isRegister() && - isMem(MI, 2)) - && "Bad format for MRMDestReg!"); - if (MI->getNumOperands() == 2+4 && - MI->getOperand(0).getReg() != MI->getOperand(1).getReg()) - O << "**"; - - O << TII.getName(MI->getOpCode()) << " "; +(MI->getNumOperands() == 2+4 && MI->getOperand(5).isImmediate() && isMem(MI, 1)) + && "Bad format for MRMSrcMem!"); + O << TII.getName(MI->getOpcode()) << " "; printOp(MI->getOperand(0)); O << ", " << sizePtr(Desc) << " "; - printMemReference(MI, MI->getNumOperands()-4); + printMemReference(MI, 1); + if (MI->getNumOperands() == 2+4) { + O << ", "; + printOp(MI->getOperand(5)); + } O << "\n"; return; } - case X86II::MRMS0r: case X86II::MRMS1r: - case X86II::MRMS2r: case X86II::MRMS3r: - case X86II::MRMS4r: case X86II::MRMS5r: - case X86II::MRMS6r: case X86II::MRMS7r: { + case X86II::MRM0r: case X86II::MRM1r: + case X86II::MRM2r: case X86II::MRM3r: + case X86II::MRM4r: case X86II::MRM5r: + case X86II::MRM6r: case X86II::MRM7r: { // In this form, the following are valid formats: // 1. sete r // 2. cmp reg, immediate @@ -741,7 +737,7 @@ MI->getOperand(0).getReg() != MI->getOperand(1).getReg()) O << "**"; - O << TII.getName(MI->getOpCode()) << " "; + O << TII.getName(MI->getOpcode()) << " "; printOp(MI->getOperand(0)); if (MI->getOperand(MI->getNumOperands()-1).isImmediate()) { O << ", "; @@ -753,10 +749,10 @@ return; } - case X86II::MRMS0m: case X86II::MRMS1m: - case X86II::MRMS2m: case X86II::MRMS3m: - case X86II::MRMS4m: case X86II::MRMS5m: - case X86II::MRMS6m: case X86II::MRMS7m: { + case X86II::MRM0m: case X86II::MRM1m: + case X86II::MRM2m: case X86II::MRM3m: + case X86II::MRM4m: case X86II::MRM5m: + case X86II::MRM6m: case X86II::MRM7m: { // In this form, the following are valid formats: // 1. sete [m] // 2. cmp [m], immediate @@ -776,7 +772,7 @@ // is misassembled by gas in intel_syntax mode as its 32-bit // equivalent "fstp DWORD PTR [...]". Workaround: Output the raw // opcode bytes instead of the instruction. - if (MI->getOpCode() == X86::FSTPr80) { + if (MI->getOpcode() == X86::FSTP80m) { if ((MI->getOperand(0).getReg() == X86::ESP) && (MI->getOperand(1).getImmedValue() == 1)) { if (Op3.isImmediate() && @@ -797,7 +793,7 @@ // misassembled by gas in intel_syntax mode as its 32-bit // equivalent "fld DWORD PTR [...]". Workaround: Output the raw // opcode bytes instead of the instruction. - if (MI->getOpCode() == X86::FLDr80 && + if (MI->getOpcode() == X86::FLD80m && MI->getOperand(0).getReg() == X86::ESP && MI->getOperand(1).getImmedValue() == 1) { if (Op3.isImmediate() && Op3.getImmedValue() >= -128 && @@ -817,7 +813,7 @@ // 64 bit modes." libopcodes disassembles it as "fild DWORD PTR // [...]", which is wrong. Workaround: Output the raw opcode bytes // instead of the instruction. - if (MI->getOpCode() == X86::FILDr64 && + if (MI->getOpcode() == X86::FILD64m && MI->getOperand(0).getReg() == X86::ESP && MI->getOperand(1).getImmedValue() == 1) { if (Op3.isImmediate() && Op3.getImmedValue() >= -128 && @@ -838,7 +834,7 @@ // "fistpll DWORD PTR [...]", which is wrong. Workaround: Output // "fistpll DWORD PTR " instead, which is what libopcodes is // expecting to see. - if (MI->getOpCode() == X86::FISTPr64) { + if (MI->getOpcode() == X86::FISTP64m) { O << "fistpll DWORD PTR "; printMemReference(MI, 0); if (MI->getNumOperands() == 5) { @@ -848,7 +844,7 @@ O << "\t# "; } - O << TII.getName(MI->getOpCode()) << " "; + O << TII.getName(MI->getOpcode()) << " "; O << sizePtr(Desc) << " "; printMemReference(MI, 0); if (MI->getNumOperands() == 5) { @@ -955,5 +951,3 @@ delete Mang; return false; // success } - -} // End llvm namespace Index: llvm/lib/Target/X86/README.txt diff -u llvm/lib/Target/X86/README.txt:1.10 llvm/lib/Target/X86/README.txt:1.10.6.1 --- llvm/lib/Target/X86/README.txt:1.10 Wed Aug 13 14:02:09 2003 +++ llvm/lib/Target/X86/README.txt Mon Mar 1 17:58:15 2004 @@ -8,14 +8,14 @@ I. Overview =========== -This directory contains a machine description for the X86 processor. Currently -this machine description is used for a high performance code generator used by a -LLVM JIT. One of the main objectives that we would like to support with this -project is to build a nice clean code generator that may be extended in the -future in a variety of ways: new targets, new optimizations, new -transformations, etc. +This directory contains a machine description for the X86 processor family. +Currently this machine description is used for a high performance code generator +used by the LLVM JIT and static code generators. One of the main objectives +that we would like to support with this project is to build a nice clean code +generator that may be extended in the future in a variety of ways: new targets, +new optimizations, new transformations, etc. -This document describes the current state of the LLVM JIT, along with +This document describes the current state of the X86 code generator, along with implementation notes, design decisions, and other stuff. @@ -33,10 +33,9 @@ At the high-level, LLVM code is translated to a machine specific representation formed out of MachineFunction, MachineBasicBlock, and MachineInstr instances (defined in include/llvm/CodeGen). This representation is completely target -agnostic, representing instructions in their most abstract form: an opcode, a -destination, and a series of operands. This representation is designed to -support both SSA representation for machine code, as well as a register -allocated, non-SSA form. +agnostic, representing instructions in their most abstract form: an opcode and a +series of operands. This representation is designed to support both SSA +representation for machine code, as well as a register allocated, non-SSA form. Because the Machine* representation must work regardless of the target machine, it contains very little semantic information about the program. To get semantic @@ -52,22 +51,22 @@ ------------------------------ Target machine instructions are represented as instances of MachineInstr, and all specific machine instruction types should have an entry in the -InstructionInfo table defined through X86InstrInfo.def. In the X86 backend, -there are two particularly interesting forms of machine instruction: those that -produce a value (such as add), and those that do not (such as a store). +X86InstrInfo.td file. In the X86 backend, there are two particularly +interesting forms of machine instruction: those that produce a value (such as +add), and those that do not (such as a store). Instructions that produce a value use Operand #0 as the "destination" register. When printing the assembly code with the built-in machine instruction printer, these destination registers will be printed to the left side of an '=' sign, as -in: %reg1027 = addl %reg1026, %reg1025 +in: %reg1027 = add %reg1026, %reg1025 -This 'addl' MachineInstruction contains three "operands": the first is the +This `add' MachineInstruction contains three "operands": the first is the destination register (#1027), the second is the first source register (#1026) and the third is the second source register (#1025). Never forget the destination register will show up in the MachineInstr operands vector. The code to generate this instruction looks like this: - BuildMI(BB, X86::ADDrr32, 2, 1027).addReg(1026).addReg(1025); + BuildMI(BB, X86::ADD32rr, 2, 1027).addReg(1026).addReg(1025); The first argument to BuildMI is the basic block to append the machine instruction to, the second is the opcode, the third is the number of operands, @@ -83,7 +82,8 @@ IV. Source Code Layout ====================== -The LLVM-JIT is composed of source files primarily in the following locations: +The LLVM code generator is composed of source files primarily in the following +locations: include/llvm/CodeGen -------------------- @@ -113,16 +113,15 @@ rest of the compiler working. It contains any code that is truly specific to the X86 backend, for example the instruction selector and machine code emitter. -tools/lli/JIT -------------- +lib/ExecutionEngine/JIT +----------------------- This directory contains the top-level code for the JIT compiler. This code -basically boils down to a call to TargetMachine::addPassesToJITCompile. As we -progress with the project, this will also contain the compile-dispatch-recompile -loop. - -test/Regression/Jello ---------------------- -This directory contains regression tests for the JIT. +basically boils down to a call to TargetMachine::addPassesToJITCompile, and +handles the compile-dispatch-recompile cycle. + +test/Regression/CodeGen/X86 +--------------------------- +This directory contains regression tests for the X86 code generator. ================================================== @@ -150,30 +149,37 @@ way, in the same order. -========================== -VI. TODO / Future Projects -========================== +====================== +VI. Instruction naming +====================== -There are a large number of things remaining to do. Here is a partial list: +An instruction name consists of the base name, a default operand size +followed by a character per operand with an optional special size. For +example: -Next Phase: ------------ -1. Implement linear time optimal instruction selector -2. Implement smarter (linear scan?) register allocator +ADD8rr -> add, 8-bit register, 8-bit register -After this project: -------------------- -1. Implement lots of nifty runtime optimizations -2. Implement new targets: IA64? X86-64? M68k? MMIX? Who knows... +IMUL16rmi -> imul, 16-bit register, 16-bit memory, 16-bit immediate + +IMUL16rmi8 -> imul, 16-bit register, 16-bit memory, 8-bit immediate + +MOVSX32rm16 -> movsx, 32-bit register, 16-bit memory + + +========================== +VII. TODO / Future Projects +========================== + +Ideas for Improvements: +----------------------- +1. Implement an *optimal* linear time instruction selector +2. Implement lots of nifty runtime optimizations +3. Implement new targets: IA64? X86-64? M68k? MMIX? Who knows... Infrastructure Improvements: ---------------------------- -1. Bytecode is designed to be able to read particular functions from the - bytecode without having to read the whole program. Bytecode reader should be - extended to allow on-demand loading of functions. - -2. X86/Printer.cpp and Sparc/EmitAssembly.cpp both have copies of what is +1. X86/Printer.cpp and Sparc/EmitAssembly.cpp both have copies of what is roughly the same code, used to output constants in a form the assembler can understand. These functions should be shared at some point. They should be rewritten to pass around iostreams instead of strings. The Index: llvm/lib/Target/X86/X86.td diff -u llvm/lib/Target/X86/X86.td:1.7 llvm/lib/Target/X86/X86.td:1.7.6.1 --- llvm/lib/Target/X86/X86.td:1.7 Tue Oct 21 10:17:13 2003 +++ llvm/lib/Target/X86/X86.td Mon Mar 1 17:58:15 2004 @@ -33,10 +33,10 @@ // Define how we want to layout our TargetSpecific information field... This // should be kept up-to-date with the fields in the X86InstrInfo.h file. - let TSFlagsFields = ["FormBits" , "hasOpSizePrefix" , "Prefix", "TypeBits", - "FPFormBits", "printImplicitUses", "Opcode"]; - let TSFlagsShifts = [ 0, 5, 6, 10, - 13, 16, 17]; + let TSFlagsFields = ["FormBits" , "hasOpSizePrefix" , "Prefix", "MemTypeBits", + "ImmTypeBits", "FPFormBits", "printImplicitUses", "Opcode"]; + let TSFlagsShifts = [0, 5, 6, 10, 13, + 15, 18, 19]; } def X86 : Target { Index: llvm/lib/Target/X86/X86CodeEmitter.cpp diff -u llvm/lib/Target/X86/X86CodeEmitter.cpp:1.46 llvm/lib/Target/X86/X86CodeEmitter.cpp:1.46.2.1 --- llvm/lib/Target/X86/X86CodeEmitter.cpp:1.46 Sat Dec 20 10:22:59 2003 +++ llvm/lib/Target/X86/X86CodeEmitter.cpp Mon Mar 1 17:58:15 2004 @@ -242,7 +242,7 @@ BasicBlockAddrs[MBB.getBasicBlock()] = Addr; for (MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end(); I != E; ++I) - emitInstruction(**I); + emitInstruction(*I); } @@ -329,7 +329,7 @@ case X86::ST4: case X86::ST5: case X86::ST6: case X86::ST7: return RegNo-X86::ST0; default: - assert(RegNo >= MRegisterInfo::FirstVirtualRegister && + assert(MRegisterInfo::isVirtualRegister(RegNo) && "Unknown physical register!"); assert(0 && "Register allocator hasn't allocated reg correctly yet!"); return 0; @@ -453,14 +453,24 @@ } } +static unsigned sizeOfImm(const TargetInstrDescriptor &Desc) { + switch (Desc.TSFlags & X86II::ImmMask) { + case X86II::Imm8: return 1; + case X86II::Imm16: return 2; + case X86II::Imm32: return 4; + default: assert(0 && "Immediate size not set!"); + return 0; + } +} + static unsigned sizeOfPtr(const TargetInstrDescriptor &Desc) { - switch (Desc.TSFlags & X86II::ArgMask) { - case X86II::Arg8: return 1; - case X86II::Arg16: return 2; - case X86II::Arg32: return 4; - case X86II::ArgF32: return 4; - case X86II::ArgF64: return 8; - case X86II::ArgF80: return 10; + switch (Desc.TSFlags & X86II::MemMask) { + case X86II::Mem8: return 1; + case X86II::Mem16: return 2; + case X86II::Mem32: return 4; + case X86II::Mem64: return 8; + case X86II::Mem80: return 10; + case X86II::Mem128: return 16; default: assert(0 && "Memory size not set!"); return 0; } @@ -472,6 +482,9 @@ unsigned Opcode = MI.getOpcode(); const TargetInstrDescriptor &Desc = II->get(Opcode); + // Emit the repeat opcode prefix as needed. + if ((Desc.TSFlags & X86II::Op0Mask) == X86II::REP) MCE.emitByte(0xF3); + // Emit instruction prefixes if necessary if (Desc.TSFlags & X86II::OpSize) MCE.emitByte(0x66);// Operand size... @@ -479,6 +492,7 @@ case X86II::TB: MCE.emitByte(0x0F); // Two-byte opcode prefix break; + case X86II::REP: break; // already handled. case X86II::D8: case X86II::D9: case X86II::DA: case X86II::DB: case X86II::DC: case X86II::DD: case X86II::DE: case X86II::DF: MCE.emitByte(0xD8+ @@ -523,35 +537,31 @@ MCE.emitByte(BaseOpcode + getX86RegNum(MI.getOperand(0).getReg())); if (MI.getNumOperands() == 2) { MachineOperand &MO1 = MI.getOperand(1); - if (MO1.isImmediate() || MO1.getVRegValueOrNull() || - MO1.isGlobalAddress() || MO1.isExternalSymbol()) { - unsigned Size = sizeOfPtr(Desc); - if (Value *V = MO1.getVRegValueOrNull()) { - assert(Size == 4 && "Don't know how to emit non-pointer values!"); - emitGlobalAddressForPtr(cast(V)); - } else if (MO1.isGlobalAddress()) { - assert(Size == 4 && "Don't know how to emit non-pointer values!"); - assert(!MO1.isPCRelative() && "Function pointer ref is PC relative?"); - emitGlobalAddressForPtr(MO1.getGlobal()); - } else if (MO1.isExternalSymbol()) { - assert(Size == 4 && "Don't know how to emit non-pointer values!"); - - unsigned Address = MCE.getGlobalValueAddress(MO1.getSymbolName()); - assert(Address && "Unknown external symbol!"); - emitMaybePCRelativeValue(Address, MO1.isPCRelative()); - } else { - emitConstant(MO1.getImmedValue(), Size); - } + if (Value *V = MO1.getVRegValueOrNull()) { + assert(sizeOfImm(Desc) == 4 && "Don't know how to emit non-pointer values!"); + emitGlobalAddressForPtr(cast(V)); + } else if (MO1.isGlobalAddress()) { + assert(sizeOfImm(Desc) == 4 && "Don't know how to emit non-pointer values!"); + assert(!MO1.isPCRelative() && "Function pointer ref is PC relative?"); + emitGlobalAddressForPtr(MO1.getGlobal()); + } else if (MO1.isExternalSymbol()) { + assert(sizeOfImm(Desc) == 4 && "Don't know how to emit non-pointer values!"); + + unsigned Address = MCE.getGlobalValueAddress(MO1.getSymbolName()); + assert(Address && "Unknown external symbol!"); + emitMaybePCRelativeValue(Address, MO1.isPCRelative()); + } else { + emitConstant(MO1.getImmedValue(), sizeOfImm(Desc)); } } break; case X86II::MRMDestReg: { MCE.emitByte(BaseOpcode); - MachineOperand &SrcOp = MI.getOperand(1+II->isTwoAddrInstr(Opcode)); - emitRegModRMByte(MI.getOperand(0).getReg(), getX86RegNum(SrcOp.getReg())); - if (MI.getNumOperands() == 4) - emitConstant(MI.getOperand(3).getImmedValue(), sizeOfPtr(Desc)); + emitRegModRMByte(MI.getOperand(0).getReg(), + getX86RegNum(MI.getOperand(1).getReg())); + if (MI.getNumOperands() == 3) + emitConstant(MI.getOperand(2).getImmedValue(), sizeOfImm(Desc)); break; } case X86II::MRMDestMem: @@ -562,50 +572,46 @@ case X86II::MRMSrcReg: MCE.emitByte(BaseOpcode); - if (MI.getNumOperands() == 2) { - emitRegModRMByte(MI.getOperand(MI.getNumOperands()-1).getReg(), - getX86RegNum(MI.getOperand(0).getReg())); - } else if (MI.getOperand(2).isImmediate()) { - emitRegModRMByte(MI.getOperand(1).getReg(), - getX86RegNum(MI.getOperand(0).getReg())); - - emitConstant(MI.getOperand(2).getImmedValue(), sizeOfPtr(Desc)); - } else { - emitRegModRMByte(MI.getOperand(2).getReg(), - getX86RegNum(MI.getOperand(0).getReg())); - } + emitRegModRMByte(MI.getOperand(1).getReg(), + getX86RegNum(MI.getOperand(0).getReg())); + if (MI.getNumOperands() == 3) + emitConstant(MI.getOperand(2).getImmedValue(), sizeOfImm(Desc)); break; case X86II::MRMSrcMem: MCE.emitByte(BaseOpcode); - emitMemModRMByte(MI, MI.getNumOperands()-4, - getX86RegNum(MI.getOperand(0).getReg())); + emitMemModRMByte(MI, 1, getX86RegNum(MI.getOperand(0).getReg())); + if (MI.getNumOperands() == 2+4) + emitConstant(MI.getOperand(5).getImmedValue(), sizeOfImm(Desc)); break; - case X86II::MRMS0r: case X86II::MRMS1r: - case X86II::MRMS2r: case X86II::MRMS3r: - case X86II::MRMS4r: case X86II::MRMS5r: - case X86II::MRMS6r: case X86II::MRMS7r: + case X86II::MRM0r: case X86II::MRM1r: + case X86II::MRM2r: case X86II::MRM3r: + case X86II::MRM4r: case X86II::MRM5r: + case X86II::MRM6r: case X86II::MRM7r: MCE.emitByte(BaseOpcode); emitRegModRMByte(MI.getOperand(0).getReg(), - (Desc.TSFlags & X86II::FormMask)-X86II::MRMS0r); + (Desc.TSFlags & X86II::FormMask)-X86II::MRM0r); if (MI.getOperand(MI.getNumOperands()-1).isImmediate()) { - unsigned Size = sizeOfPtr(Desc); - emitConstant(MI.getOperand(MI.getNumOperands()-1).getImmedValue(), Size); + emitConstant(MI.getOperand(MI.getNumOperands()-1).getImmedValue(), sizeOfImm(Desc)); } break; - case X86II::MRMS0m: case X86II::MRMS1m: - case X86II::MRMS2m: case X86II::MRMS3m: - case X86II::MRMS4m: case X86II::MRMS5m: - case X86II::MRMS6m: case X86II::MRMS7m: + case X86II::MRM0m: case X86II::MRM1m: + case X86II::MRM2m: case X86II::MRM3m: + case X86II::MRM4m: case X86II::MRM5m: + case X86II::MRM6m: case X86II::MRM7m: MCE.emitByte(BaseOpcode); - emitMemModRMByte(MI, 0, (Desc.TSFlags & X86II::FormMask)-X86II::MRMS0m); + emitMemModRMByte(MI, 0, (Desc.TSFlags & X86II::FormMask)-X86II::MRM0m); if (MI.getNumOperands() == 5) { - unsigned Size = sizeOfPtr(Desc); - emitConstant(MI.getOperand(4).getImmedValue(), Size); + if (MI.getOperand(4).isImmediate()) + emitConstant(MI.getOperand(4).getImmedValue(), sizeOfImm(Desc)); + else if (MI.getOperand(4).isGlobalAddress()) + emitGlobalAddressForPtr(MI.getOperand(4).getGlobal()); + else + assert(0 && "Unknown operand!"); } break; } Index: llvm/lib/Target/X86/X86InstrBuilder.h diff -u llvm/lib/Target/X86/X86InstrBuilder.h:1.9 llvm/lib/Target/X86/X86InstrBuilder.h:1.9.4.1 --- llvm/lib/Target/X86/X86InstrBuilder.h:1.9 Tue Nov 11 16:41:33 2003 +++ llvm/lib/Target/X86/X86InstrBuilder.h Mon Mar 1 17:58:15 2004 @@ -49,6 +49,14 @@ return MIB.addReg(Reg).addZImm(1).addReg(0).addSImm(Offset); } +inline const MachineInstrBuilder &addFullAddress(const MachineInstrBuilder &MIB, + unsigned BaseReg, + unsigned Scale, + unsigned IndexReg, + unsigned Disp) { + return MIB.addReg(BaseReg).addZImm(Scale).addReg(IndexReg).addSImm(Disp); +} + /// addFrameReference - This function is used to add a reference to the base of /// an abstract object on the stack frame of the current function. This /// reference has base register as the FrameIndex offset until it is resolved. Index: llvm/lib/Target/X86/X86InstrInfo.cpp diff -u llvm/lib/Target/X86/X86InstrInfo.cpp:1.18 llvm/lib/Target/X86/X86InstrInfo.cpp:1.18.2.1 --- llvm/lib/Target/X86/X86InstrInfo.cpp:1.18 Sun Dec 28 11:35:07 2003 +++ llvm/lib/Target/X86/X86InstrInfo.cpp Mon Mar 1 17:58:15 2004 @@ -14,54 +14,26 @@ #include "X86InstrInfo.h" #include "X86.h" #include "llvm/CodeGen/MachineInstrBuilder.h" - #include "X86GenInstrInfo.inc" - using namespace llvm; X86InstrInfo::X86InstrInfo() - : TargetInstrInfo(X86Insts, sizeof(X86Insts)/sizeof(X86Insts[0]), 0) { + : TargetInstrInfo(X86Insts, sizeof(X86Insts)/sizeof(X86Insts[0])) { } -// createNOPinstr - returns the target's implementation of NOP, which is -// usually a pseudo-instruction, implemented by a degenerate version of -// another instruction, e.g. X86: `xchg ax, ax'; SparcV9: `sethi r0, r0, r0' -// -MachineInstr* X86InstrInfo::createNOPinstr() const { - return BuildMI(X86::XCHGrr16, 2).addReg(X86::AX, MOTy::UseAndDef) - .addReg(X86::AX, MOTy::UseAndDef); -} - - -/// isNOPinstr - not having a special NOP opcode, we need to know if a given -/// instruction is interpreted as an `official' NOP instr, i.e., there may be -/// more than one way to `do nothing' but only one canonical way to slack off. -// -bool X86InstrInfo::isNOPinstr(const MachineInstr &MI) const { - // Make sure the instruction is EXACTLY `xchg ax, ax' - if (MI.getOpcode() == X86::XCHGrr16) { - const MachineOperand &op0 = MI.getOperand(0), &op1 = MI.getOperand(1); - if (op0.isMachineRegister() && op0.getMachineRegNum() == X86::AX && - op1.isMachineRegister() && op1.getMachineRegNum() == X86::AX) { - return true; - } - } - // FIXME: there are several NOOP instructions, we should check for them here. - return false; -} - bool X86InstrInfo::isMoveInstr(const MachineInstr& MI, unsigned& sourceReg, unsigned& destReg) const { MachineOpCode oc = MI.getOpcode(); - if (oc == X86::MOVrr8 || oc == X86::MOVrr16 || oc == X86::MOVrr32) { + if (oc == X86::MOV8rr || oc == X86::MOV16rr || oc == X86::MOV32rr || + oc == X86::FpMOV) { assert(MI.getNumOperands() == 2 && MI.getOperand(0).isRegister() && MI.getOperand(1).isRegister() && "invalid register-register move instruction"); - sourceReg = MI.getOperand(1).getAllocatedRegNum(); - destReg = MI.getOperand(0).getAllocatedRegNum(); + sourceReg = MI.getOperand(1).getReg(); + destReg = MI.getOperand(0).getReg(); return true; } return false; Index: llvm/lib/Target/X86/X86InstrInfo.h diff -u llvm/lib/Target/X86/X86InstrInfo.h:1.30 llvm/lib/Target/X86/X86InstrInfo.h:1.30.2.1 --- llvm/lib/Target/X86/X86InstrInfo.h:1.30 Sun Dec 28 11:35:07 2003 +++ llvm/lib/Target/X86/X86InstrInfo.h Mon Mar 1 17:58:15 2004 @@ -62,18 +62,18 @@ /// MRMSrcMem = 6, - /// MRMS[0-7][rm] - These forms are used to represent instructions that use + /// MRM[0-7][rm] - These forms are used to represent instructions that use /// a Mod/RM byte, and use the middle field to hold extended opcode /// information. In the intel manual these are represented as /0, /1, ... /// // First, instructions that operate on a register r/m operand... - MRMS0r = 16, MRMS1r = 17, MRMS2r = 18, MRMS3r = 19, // Format /0 /1 /2 /3 - MRMS4r = 20, MRMS5r = 21, MRMS6r = 22, MRMS7r = 23, // Format /4 /5 /6 /7 + MRM0r = 16, MRM1r = 17, MRM2r = 18, MRM3r = 19, // Format /0 /1 /2 /3 + MRM4r = 20, MRM5r = 21, MRM6r = 22, MRM7r = 23, // Format /4 /5 /6 /7 // Next, instructions that operate on a memory r/m operand... - MRMS0m = 24, MRMS1m = 25, MRMS2m = 26, MRMS3m = 27, // Format /0 /1 /2 /3 - MRMS4m = 28, MRMS5m = 29, MRMS6m = 30, MRMS7m = 31, // Format /4 /5 /6 /7 + MRM0m = 24, MRM1m = 25, MRM2m = 26, MRM3m = 27, // Format /0 /1 /2 /3 + MRM4m = 28, MRM5m = 29, MRM6m = 30, MRM7m = 31, // Format /4 /5 /6 /7 FormMask = 31, @@ -86,9 +86,9 @@ OpSize = 1 << 5, // Op0Mask - There are several prefix bytes that are used to form two byte - // opcodes. These are currently 0x0F, and 0xD8-0xDF. This mask is used to - // obtain the setting of this field. If no bits in this field is set, there - // is no prefix byte for obtaining a multibyte opcode. + // opcodes. These are currently 0x0F, 0xF3, and 0xD8-0xDF. This mask is + // used to obtain the setting of this field. If no bits in this field is + // set, there is no prefix byte for obtaining a multibyte opcode. // Op0Shift = 6, Op0Mask = 0xF << Op0Shift, @@ -97,33 +97,48 @@ // starts with a 0x0F byte before the real opcode. TB = 1 << Op0Shift, + // REP - The 0xF3 prefix byte indicating repetition of the following + // instruction. + REP = 2 << Op0Shift, + // D8-DF - These escape opcodes are used by the floating point unit. These // values must remain sequential. - D8 = 2 << Op0Shift, D9 = 3 << Op0Shift, - DA = 4 << Op0Shift, DB = 5 << Op0Shift, - DC = 6 << Op0Shift, DD = 7 << Op0Shift, - DE = 8 << Op0Shift, DF = 9 << Op0Shift, + D8 = 3 << Op0Shift, D9 = 4 << Op0Shift, + DA = 5 << Op0Shift, DB = 6 << Op0Shift, + DC = 7 << Op0Shift, DD = 8 << Op0Shift, + DE = 9 << Op0Shift, DF = 10 << Op0Shift, //===------------------------------------------------------------------===// // This three-bit field describes the size of a memory operand. Zero is // unused so that we can tell if we forgot to set a value. - ArgShift = 10, - ArgMask = 7 << ArgShift, - Arg8 = 1 << ArgShift, - Arg16 = 2 << ArgShift, - Arg32 = 3 << ArgShift, - Arg64 = 4 << ArgShift, // 64 bit int argument for FILD64 - ArgF32 = 5 << ArgShift, - ArgF64 = 6 << ArgShift, - ArgF80 = 7 << ArgShift, + MemShift = 10, + MemMask = 7 << MemShift, + Mem8 = 1 << MemShift, + Mem16 = 2 << MemShift, + Mem32 = 3 << MemShift, + Mem64 = 4 << MemShift, + Mem80 = 5 << MemShift, + Mem128 = 6 << MemShift, + + //===------------------------------------------------------------------===// + // This tow-bit field describes the size of an immediate operand. Zero is + // unused so that we can tell if we forgot to set a value. + ImmShift = 13, + ImmMask = 7 << ImmShift, + Imm8 = 1 << ImmShift, + Imm16 = 2 << ImmShift, + Imm32 = 3 << ImmShift, //===------------------------------------------------------------------===// // FP Instruction Classification... Zero is non-fp instruction. // FPTypeMask - Mask for all of the FP types... - FPTypeShift = 13, + FPTypeShift = 15, FPTypeMask = 7 << FPTypeShift, + // NotFP - The default, set for instructions that do not use FP registers. + NotFP = 0 << FPTypeShift, + // ZeroArgFP - 0 arg FP instruction which implicitly pushes ST(0), f.e. fld0 ZeroArgFP = 1 << FPTypeShift, @@ -144,9 +159,9 @@ SpecialFP = 5 << FPTypeShift, // PrintImplUses - Print out implicit uses in the assembly output. - PrintImplUses = 1 << 16, + PrintImplUses = 1 << 18, - OpcodeShift = 17, + OpcodeShift = 19, OpcodeMask = 0xFF << OpcodeShift, // Bits 25 -> 31 are unused }; @@ -163,12 +178,6 @@ /// virtual const MRegisterInfo &getRegisterInfo() const { return RI; } - /// createNOPinstr - returns the target's implementation of NOP, which is - /// usually a pseudo-instruction, implemented by a degenerate version of - /// another instruction, e.g. X86: `xchg ax, ax'; SparcV9: `sethi r0, r0, r0' - /// - MachineInstr* createNOPinstr() const; - // // Return true if the instruction is a register to register move and // leave the source and dest operands in the passed parameters. @@ -176,12 +185,6 @@ virtual bool isMoveInstr(const MachineInstr& MI, unsigned& sourceReg, unsigned& destReg) const; - - /// isNOPinstr - not having a special NOP opcode, we need to know if a given - /// instruction is interpreted as an `official' NOP instr, i.e., there may be - /// more than one way to `do nothing' but only one canonical way to slack off. - /// - bool isNOPinstr(const MachineInstr &MI) const; // getBaseOpcodeFor - This function returns the "base" X86 opcode for the // specified opcode number. Index: llvm/lib/Target/X86/X86InstrInfo.td diff -u llvm/lib/Target/X86/X86InstrInfo.td:1.15 llvm/lib/Target/X86/X86InstrInfo.td:1.15.2.1 --- llvm/lib/Target/X86/X86InstrInfo.td:1.15 Sat Dec 20 10:22:59 2003 +++ llvm/lib/Target/X86/X86InstrInfo.td Mon Mar 1 17:58:15 2004 @@ -24,27 +24,37 @@ def AddRegFrm : Format<2>; def MRMDestReg : Format<3>; def MRMDestMem : Format<4>; def MRMSrcReg : Format<5>; def MRMSrcMem : Format<6>; -def MRMS0r : Format<16>; def MRMS1r : Format<17>; def MRMS2r : Format<18>; -def MRMS3r : Format<19>; def MRMS4r : Format<20>; def MRMS5r : Format<21>; -def MRMS6r : Format<22>; def MRMS7r : Format<23>; -def MRMS0m : Format<24>; def MRMS1m : Format<25>; def MRMS2m : Format<26>; -def MRMS3m : Format<27>; def MRMS4m : Format<28>; def MRMS5m : Format<29>; -def MRMS6m : Format<30>; def MRMS7m : Format<31>; +def MRM0r : Format<16>; def MRM1r : Format<17>; def MRM2r : Format<18>; +def MRM3r : Format<19>; def MRM4r : Format<20>; def MRM5r : Format<21>; +def MRM6r : Format<22>; def MRM7r : Format<23>; +def MRM0m : Format<24>; def MRM1m : Format<25>; def MRM2m : Format<26>; +def MRM3m : Format<27>; def MRM4m : Format<28>; def MRM5m : Format<29>; +def MRM6m : Format<30>; def MRM7m : Format<31>; -// ArgType - This specifies the argument type used by an instruction. This is +// ImmType - This specifies the immediate type used by an instruction. This is // part of the ad-hoc solution used to emit machine instruction encodings by our // machine code emitter. -class ArgType val> { +class ImmType val> { + bits<2> Value = val; +} +def NoImm : ImmType<0>; +def Imm8 : ImmType<1>; +def Imm16 : ImmType<2>; +def Imm32 : ImmType<3>; + +// MemType - This specifies the immediate type used by an instruction. This is +// part of the ad-hoc solution used to emit machine instruction encodings by our +// machine code emitter. +class MemType val> { bits<3> Value = val; } -def NoArg : ArgType<0>; -def Arg8 : ArgType<1>; -def Arg16 : ArgType<2>; -def Arg32 : ArgType<3>; -def Arg64 : ArgType<4>; // 64 bit int argument for FILD64 -def ArgF32 : ArgType<5>; -def ArgF64 : ArgType<6>; -def ArgF80 : ArgType<6>; +def NoMem : MemType<0>; +def Mem8 : MemType<1>; +def Mem16 : MemType<2>; +def Mem32 : MemType<3>; +def Mem64 : MemType<4>; +def Mem80 : MemType<4>; +def Mem128 : MemType<6>; // FPFormat - This specifies what form this FP instruction has. This is used by // the Floating-Point stackifier pass. @@ -59,15 +69,17 @@ def SpecialFP : FPFormat<5>; -class X86Inst opcod, Format f, ArgType a> : Instruction { +class X86Inst opcod, Format f, MemType m, ImmType i> : Instruction { let Namespace = "X86"; let Name = nam; bits<8> Opcode = opcod; Format Form = f; bits<5> FormBits = Form.Value; - ArgType Type = a; - bits<3> TypeBits = Type.Value; + MemType MemT = m; + bits<3> MemTypeBits = MemT.Value; + ImmType ImmT = i; + bits<2> ImmTypeBits = ImmT.Value; // Attributes specific to X86 instructions... bit hasOpSizePrefix = 0; // Does this inst have a 0x66 prefix? @@ -92,43 +104,68 @@ // emitter that various prefix bytes are required. class OpSize { bit hasOpSizePrefix = 1; } class TB { bits<4> Prefix = 1; } -class D8 { bits<4> Prefix = 2; } -class D9 { bits<4> Prefix = 3; } -class DA { bits<4> Prefix = 4; } -class DB { bits<4> Prefix = 5; } -class DC { bits<4> Prefix = 6; } -class DD { bits<4> Prefix = 7; } -class DE { bits<4> Prefix = 8; } -class DF { bits<4> Prefix = 9; } +class REP { bits<4> Prefix = 2; } +class D8 { bits<4> Prefix = 3; } +class D9 { bits<4> Prefix = 4; } +class DA { bits<4> Prefix = 5; } +class DB { bits<4> Prefix = 6; } +class DC { bits<4> Prefix = 7; } +class DD { bits<4> Prefix = 8; } +class DE { bits<4> Prefix = 9; } +class DF { bits<4> Prefix = 10; } + + +//===----------------------------------------------------------------------===// +// Instruction templates... + +class I o, Format f> : X86Inst; + +class Im o, Format f, MemType m> : X86Inst; +class Im8 o, Format f> : Im; +class Im16 o, Format f> : Im; +class Im32 o, Format f> : Im; +class Ii o, Format f, ImmType i> : X86Inst; +class Ii8 o, Format f> : Ii; +class Ii16 o, Format f> : Ii; +class Ii32 o, Format f> : Ii; +class Im8i8 o, Format f> : X86Inst; +class Im16i16 o, Format f> : X86Inst; +class Im32i32 o, Format f> : X86Inst; + +class Im16i8 o, Format f> : X86Inst; +class Im32i8 o, Format f> : X86Inst; + +// Helper for shift instructions +class UsesCL { list Uses = [CL]; bit printImplicitUses = 1; } //===----------------------------------------------------------------------===// // Instruction list... // -def PHI : X86Inst<"PHI", 0, Pseudo, NoArg>; // PHI node... +def PHI : I<"PHI", 0, Pseudo>; // PHI node... -def NOOP : X86Inst<"nop", 0x90, RawFrm, NoArg>; // nop +def NOOP : I<"nop", 0x90, RawFrm>; // nop -def ADJCALLSTACKDOWN : X86Inst<"ADJCALLSTACKDOWN", 0, Pseudo, NoArg>; -def ADJCALLSTACKUP : X86Inst<"ADJCALLSTACKUP", 0, Pseudo, NoArg>; -def IMPLICIT_USE : X86Inst<"IMPLICIT_USE", 0, Pseudo, NoArg>; -def IMPLICIT_DEF : X86Inst<"IMPLICIT_DEF", 0, Pseudo, NoArg>; +def ADJCALLSTACKDOWN : I<"ADJCALLSTACKDOWN", 0, Pseudo>; +def ADJCALLSTACKUP : I<"ADJCALLSTACKUP", 0, Pseudo>; +def IMPLICIT_USE : I<"IMPLICIT_USE", 0, Pseudo>; +def IMPLICIT_DEF : I<"IMPLICIT_DEF", 0, Pseudo>; let isTerminator = 1 in let Defs = [FP0, FP1, FP2, FP3, FP4, FP5, FP6] in - def FP_REG_KILL : X86Inst<"FP_REG_KILL", 0, Pseudo, NoArg>; + def FP_REG_KILL : I<"FP_REG_KILL", 0, Pseudo>; //===----------------------------------------------------------------------===// // Control Flow Instructions... // // Return instruction... let isTerminator = 1, isReturn = 1 in - def RET : X86Inst<"ret", 0xC3, RawFrm, NoArg>, Pattern<(retvoid)>; + def RET : I<"ret", 0xC3, RawFrm>, Pattern<(retvoid)>; // All branches are RawFrm, Void, Branch, and Terminators let isBranch = 1, isTerminator = 1 in - class IBr opcode> : X86Inst; + class IBr opcode> : I; def JMP : IBr<"jmp", 0xE9>, Pattern<(br basicblock)>; def JB : IBr<"jb" , 0x82>, TB; @@ -151,231 +188,420 @@ let isCall = 1 in // All calls clobber the non-callee saved registers... let Defs = [EAX, ECX, EDX, FP0, FP1, FP2, FP3, FP4, FP5, FP6] in { - def CALLpcrel32 : X86Inst<"call", 0xE8, RawFrm, NoArg>; - def CALLr32 : X86Inst<"call", 0xFF, MRMS2r, Arg32>; - def CALLm32 : X86Inst<"call", 0xFF, MRMS2m, Arg32>; + def CALLpcrel32 : I <"call", 0xE8, RawFrm>; + def CALL32r : I <"call", 0xFF, MRM2r>; + def CALL32m : Im32<"call", 0xFF, MRM2m>; } //===----------------------------------------------------------------------===// // Miscellaneous Instructions... // -def LEAVE : X86Inst<"leave", 0xC9, RawFrm, NoArg>, Imp<[EBP], [EBP]>; - -let isTwoAddress = 1 in // R32 = bswap R32 - def BSWAPr32 : X86Inst<"bswap", 0xC8, AddRegFrm, Arg32>, TB; +def LEAVE : I<"leave", 0xC9, RawFrm>, Imp<[EBP,ESP],[EBP,ESP]>; +def POP32r : I<"pop", 0x58, AddRegFrm>, Imp<[ESP],[ESP]>; -def XCHGrr8 : X86Inst<"xchg", 0x86, MRMDestReg, Arg8>; // xchg R8, R8 -def XCHGrr16 : X86Inst<"xchg", 0x87, MRMDestReg, Arg16>, OpSize;// xchg R16, R16 -def XCHGrr32 : X86Inst<"xchg", 0x87, MRMDestReg, Arg32>; // xchg R32, R32 +let isTwoAddress = 1 in // R32 = bswap R32 + def BSWAP32r : I<"bswap", 0xC8, AddRegFrm>, TB; -def LEAr16 : X86Inst<"lea", 0x8D, MRMSrcMem, Arg16>, OpSize; // R16 = lea [mem] -def LEAr32 : X86Inst<"lea", 0x8D, MRMSrcMem, Arg32>; // R32 = lea [mem] +def XCHG8rr : I <"xchg", 0x86, MRMDestReg>; // xchg R8, R8 +def XCHG16rr : I <"xchg", 0x87, MRMDestReg>, OpSize; // xchg R16, R16 +def XCHG32rr : I <"xchg", 0x87, MRMDestReg>; // xchg R32, R32 +def XCHG8mr : Im8 <"xchg", 0x86, MRMDestMem>; // xchg [mem8], R8 +def XCHG16mr : Im16<"xchg", 0x87, MRMDestMem>, OpSize; // xchg [mem16], R16 +def XCHG32mr : Im32<"xchg", 0x87, MRMDestMem>; // xchg [mem32], R32 +def XCHG8rm : Im8 <"xchg", 0x86, MRMSrcMem >; // xchg R8, [mem8] +def XCHG16rm : Im16<"xchg", 0x87, MRMSrcMem >, OpSize; // xchg R16, [mem16] +def XCHG32rm : Im32<"xchg", 0x87, MRMSrcMem >; // xchg R32, [mem32] + +def LEA16r : Im32<"lea", 0x8D, MRMSrcMem>, OpSize; // R16 = lea [mem] +def LEA32r : Im32<"lea", 0x8D, MRMSrcMem>; // R32 = lea [mem] + + +def REP_MOVSB : I<"rep movsb", 0xA4, RawFrm>, REP, + Imp<[ECX,EDI,ESI], [ECX,EDI,ESI]>; +def REP_MOVSW : I<"rep movsw", 0xA5, RawFrm>, REP, OpSize, + Imp<[ECX,EDI,ESI], [ECX,EDI,ESI]>; +def REP_MOVSD : I<"rep movsd", 0xA5, RawFrm>, REP, + Imp<[ECX,EDI,ESI], [ECX,EDI,ESI]>; + +def REP_STOSB : I<"rep stosb", 0xAA, RawFrm>, REP, + Imp<[AL,ECX,EDI], [ECX,EDI]>; +def REP_STOSW : I<"rep stosw", 0xAB, RawFrm>, REP, OpSize, + Imp<[AX,ECX,EDI], [ECX,EDI]>; +def REP_STOSD : I<"rep stosd", 0xAB, RawFrm>, REP, + Imp<[EAX,ECX,EDI], [ECX,EDI]>; //===----------------------------------------------------------------------===// // Move Instructions... // -def MOVrr8 : X86Inst<"mov", 0x88, MRMDestReg, Arg8>, Pattern<(set R8 , R8 )>; -def MOVrr16 : X86Inst<"mov", 0x89, MRMDestReg, Arg16>, OpSize, Pattern<(set R16, R16)>; -def MOVrr32 : X86Inst<"mov", 0x89, MRMDestReg, Arg32>, Pattern<(set R32, R32)>; -def MOVir8 : X86Inst<"mov", 0xB0, AddRegFrm , Arg8>, Pattern<(set R8 , imm )>; -def MOVir16 : X86Inst<"mov", 0xB8, AddRegFrm , Arg16>, OpSize, Pattern<(set R16, imm)>; -def MOVir32 : X86Inst<"mov", 0xB8, AddRegFrm , Arg32>, Pattern<(set R32, imm)>; -def MOVim8 : X86Inst<"mov", 0xC6, MRMS0m , Arg8>; // [mem] = imm8 -def MOVim16 : X86Inst<"mov", 0xC7, MRMS0m , Arg16>, OpSize; // [mem] = imm16 -def MOVim32 : X86Inst<"mov", 0xC7, MRMS0m , Arg32>; // [mem] = imm32 +def MOV8rr : I <"mov", 0x88, MRMDestReg>, Pattern<(set R8 , R8 )>; +def MOV16rr : I <"mov", 0x89, MRMDestReg>, OpSize, Pattern<(set R16, R16)>; +def MOV32rr : I <"mov", 0x89, MRMDestReg>, Pattern<(set R32, R32)>; +def MOV8ri : Ii8 <"mov", 0xB0, AddRegFrm >, Pattern<(set R8 , imm )>; +def MOV16ri : Ii16 <"mov", 0xB8, AddRegFrm >, OpSize, Pattern<(set R16, imm)>; +def MOV32ri : Ii32 <"mov", 0xB8, AddRegFrm >, Pattern<(set R32, imm)>; +def MOV8mi : Im8i8 <"mov", 0xC6, MRM0m >; // [mem8] = imm8 +def MOV16mi : Im16i16<"mov", 0xC7, MRM0m >, OpSize; // [mem16] = imm16 +def MOV32mi : Im32i32<"mov", 0xC7, MRM0m >; // [mem32] = imm32 -def MOVmr8 : X86Inst<"mov", 0x8A, MRMSrcMem , Arg8>; // R8 = [mem] -def MOVmr16 : X86Inst<"mov", 0x8B, MRMSrcMem , Arg16>, OpSize, // R16 = [mem] +def MOV8rm : Im8 <"mov", 0x8A, MRMSrcMem>; // R8 = [mem8] +def MOV16rm : Im16 <"mov", 0x8B, MRMSrcMem>, OpSize, // R16 = [mem16] Pattern<(set R16, (load (plus R32, (plus (times imm, R32), imm))))>; -def MOVmr32 : X86Inst<"mov", 0x8B, MRMSrcMem , Arg32>, // R32 = [mem] +def MOV32rm : Im32 <"mov", 0x8B, MRMSrcMem>, // R32 = [mem32] Pattern<(set R32, (load (plus R32, (plus (times imm, R32), imm))))>; -def MOVrm8 : X86Inst<"mov", 0x88, MRMDestMem, Arg8>; // [mem] = R8 -def MOVrm16 : X86Inst<"mov", 0x89, MRMDestMem, Arg16>, OpSize; // [mem] = R16 -def MOVrm32 : X86Inst<"mov", 0x89, MRMDestMem, Arg32>; // [mem] = R32 +def MOV8mr : Im8 <"mov", 0x88, MRMDestMem>; // [mem8] = R8 +def MOV16mr : Im16 <"mov", 0x89, MRMDestMem>, OpSize; // [mem16] = R16 +def MOV32mr : Im32 <"mov", 0x89, MRMDestMem>; // [mem32] = R32 //===----------------------------------------------------------------------===// // Fixed-Register Multiplication and Division Instructions... // // Extra precision multiplication -def MULr8 : X86Inst<"mul", 0xF6, MRMS4r, Arg8 >, Imp<[AL],[AX]>; // AL,AH = AL*R8 -def MULr16 : X86Inst<"mul", 0xF7, MRMS4r, Arg16>, Imp<[AX],[AX,DX]>, OpSize; // AX,DX = AX*R16 -def MULr32 : X86Inst<"mul", 0xF7, MRMS4r, Arg32>, Imp<[EAX],[EAX,EDX]>; // EAX,EDX = EAX*R32 +def MUL8r : I <"mul", 0xF6, MRM4r>, Imp<[AL],[AX]>; // AL,AH = AL*R8 +def MUL16r : I <"mul", 0xF7, MRM4r>, Imp<[AX],[AX,DX]>, OpSize; // AX,DX = AX*R16 +def MUL32r : I <"mul", 0xF7, MRM4r>, Imp<[EAX],[EAX,EDX]>; // EAX,EDX = EAX*R32 +def MUL8m : Im8 <"mul", 0xF6, MRM4m>, Imp<[AL],[AX]>; // AL,AH = AL*[mem8] +def MUL16m : Im16<"mul", 0xF7, MRM4m>, Imp<[AX],[AX,DX]>, OpSize; // AX,DX = AX*[mem16] +def MUL32m : Im32<"mul", 0xF7, MRM4m>, Imp<[EAX],[EAX,EDX]>; // EAX,EDX = EAX*[mem32] // unsigned division/remainder -def DIVr8 : X86Inst<"div", 0xF6, MRMS6r, Arg8 >, Imp<[AX],[AX]>; // AX/r8 = AL,AH -def DIVr16 : X86Inst<"div", 0xF7, MRMS6r, Arg16>, Imp<[AX,DX],[AX,DX]>, OpSize; // DX:AX/r16 = AX,DX -def DIVr32 : X86Inst<"div", 0xF7, MRMS6r, Arg32>, Imp<[EAX,EDX],[EAX,EDX]>; // EDX:EAX/r32 = EAX,EDX +def DIV8r : I <"div", 0xF6, MRM6r>, Imp<[AX],[AX]>; // AX/r8 = AL,AH +def DIV16r : I <"div", 0xF7, MRM6r>, Imp<[AX,DX],[AX,DX]>, OpSize; // DX:AX/r16 = AX,DX +def DIV32r : I <"div", 0xF7, MRM6r>, Imp<[EAX,EDX],[EAX,EDX]>; // EDX:EAX/r32 = EAX,EDX +def DIV8m : Im8 <"div", 0xF6, MRM6m>, Imp<[AX],[AX]>; // AX/[mem8] = AL,AH +def DIV16m : Im16<"div", 0xF7, MRM6m>, Imp<[AX,DX],[AX,DX]>, OpSize; // DX:AX/[mem16] = AX,DX +def DIV32m : Im32<"div", 0xF7, MRM6m>, Imp<[EAX,EDX],[EAX,EDX]>; // EDX:EAX/[mem32] = EAX,EDX // signed division/remainder -def IDIVr8 : X86Inst<"idiv",0xF6, MRMS7r, Arg8 >, Imp<[AX],[AX]>; // AX/r8 = AL,AH -def IDIVr16: X86Inst<"idiv",0xF7, MRMS7r, Arg16>, Imp<[AX,DX],[AX,DX]>, OpSize; // DX:AX/r16 = AX,DX -def IDIVr32: X86Inst<"idiv",0xF7, MRMS7r, Arg32>, Imp<[EAX,EDX],[EAX,EDX]>; // EDX:EAX/r32 = EAX,EDX +def IDIV8r : I <"idiv",0xF6, MRM7r>, Imp<[AX],[AX]>; // AX/r8 = AL,AH +def IDIV16r: I <"idiv",0xF7, MRM7r>, Imp<[AX,DX],[AX,DX]>, OpSize; // DX:AX/r16 = AX,DX +def IDIV32r: I <"idiv",0xF7, MRM7r>, Imp<[EAX,EDX],[EAX,EDX]>; // EDX:EAX/r32 = EAX,EDX +def IDIV8m : Im8 <"idiv",0xF6, MRM7m>, Imp<[AX],[AX]>; // AX/[mem8] = AL,AH +def IDIV16m: Im16<"idiv",0xF7, MRM7m>, Imp<[AX,DX],[AX,DX]>, OpSize; // DX:AX/[mem16] = AX,DX +def IDIV32m: Im32<"idiv",0xF7, MRM7m>, Imp<[EAX,EDX],[EAX,EDX]>; // EDX:EAX/[mem32] = EAX,EDX // Sign-extenders for division -def CBW : X86Inst<"cbw", 0x98, RawFrm, Arg8 >, Imp<[AL],[AH]>; // AX = signext(AL) -def CWD : X86Inst<"cwd", 0x99, RawFrm, Arg8 >, Imp<[AX],[DX]>; // DX:AX = signext(AX) -def CDQ : X86Inst<"cdq", 0x99, RawFrm, Arg8 >, Imp<[EAX],[EDX]>; // EDX:EAX = signext(EAX) +def CBW : I<"cbw", 0x98, RawFrm >, Imp<[AL],[AH]>; // AX = signext(AL) +def CWD : I<"cwd", 0x99, RawFrm >, Imp<[AX],[DX]>; // DX:AX = signext(AX) +def CDQ : I<"cdq", 0x99, RawFrm >, Imp<[EAX],[EDX]>; // EDX:EAX = signext(EAX) //===----------------------------------------------------------------------===// // Two address Instructions... // -let isTwoAddress = 1 in { // Define some helper classes to make defs shorter. - class I2A8 o, Format F> : X86Inst; - class I2A16 o, Format F> : X86Inst; - class I2A32 o, Format F> : X86Inst; -} +let isTwoAddress = 1 in { -// unary instructions -def NEGr8 : I2A8 <"neg", 0xF6, MRMS3r>; // R8 = -R8 = 0-R8 -def NEGr16 : I2A16<"neg", 0xF7, MRMS3r>, OpSize; // R16 = -R16 = 0-R16 -def NEGr32 : I2A32<"neg", 0xF7, MRMS3r>; // R32 = -R32 = 0-R32 -def NOTr8 : I2A8 <"not", 0xF6, MRMS2r>; // R8 = ~R8 = R8^-1 -def NOTr16 : I2A16<"not", 0xF7, MRMS2r>, OpSize; // R16 = ~R16 = R16^-1 -def NOTr32 : I2A32<"not", 0xF7, MRMS2r>; // R32 = ~R32 = R32^-1 - -def INCr8 : I2A8 <"inc", 0xFE, MRMS0r>; // R8 = R8 +1 -def INCr16 : I2A16<"inc", 0xFF, MRMS0r>, OpSize; // R16 = R16+1 -def INCr32 : I2A32<"inc", 0xFF, MRMS0r>; // R32 = R32+1 -def DECr8 : I2A8 <"dec", 0xFE, MRMS1r>; // R8 = R8 -1 -def DECr16 : I2A16<"dec", 0xFF, MRMS1r>, OpSize; // R16 = R16-1 -def DECr32 : I2A32<"dec", 0xFF, MRMS1r>; // R32 = R32-1 +// Conditional moves. These are modelled as X = cmovXX Y, Z. Eventually +// register allocated to cmovXX XY, Z +def CMOVE16rr : I<"cmove", 0x44, MRMSrcReg>, TB, OpSize; // if ==, R16 = R16 +def CMOVNE32rr: I<"cmovne",0x45, MRMSrcReg>, TB; // if !=, R32 = R32 +def CMOVS32rr : I<"cmovs", 0x48, MRMSrcReg>, TB; // if signed, R32 = R32 +// unary instructions +def NEG8r : I <"neg", 0xF6, MRM3r>; // R8 = -R8 = 0-R8 +def NEG16r : I <"neg", 0xF7, MRM3r>, OpSize; // R16 = -R16 = 0-R16 +def NEG32r : I <"neg", 0xF7, MRM3r>; // R32 = -R32 = 0-R32 +def NEG8m : Im8 <"neg", 0xF6, MRM3m>; // [mem8] = -[mem8] = 0-[mem8] +def NEG16m : Im16<"neg", 0xF7, MRM3m>, OpSize; // [mem16] = -[mem16] = 0-[mem16] +def NEG32m : Im32<"neg", 0xF7, MRM3m>; // [mem32] = -[mem32] = 0-[mem32] + +def NOT8r : I <"not", 0xF6, MRM2r>; // R8 = ~R8 = R8^-1 +def NOT16r : I <"not", 0xF7, MRM2r>, OpSize; // R16 = ~R16 = R16^-1 +def NOT32r : I <"not", 0xF7, MRM2r>; // R32 = ~R32 = R32^-1 +def NOT8m : Im8 <"not", 0xF6, MRM2m>; // [mem8] = ~[mem8] = [mem8^-1] +def NOT16m : Im16<"not", 0xF7, MRM2m>, OpSize; // [mem16] = ~[mem16] = [mem16^-1] +def NOT32m : Im32<"not", 0xF7, MRM2m>; // [mem32] = ~[mem32] = [mem32^-1] + +def INC8r : I <"inc", 0xFE, MRM0r>; // ++R8 +def INC16r : I <"inc", 0xFF, MRM0r>, OpSize; // ++R16 +def INC32r : I <"inc", 0xFF, MRM0r>; // ++R32 +def INC8m : Im8 <"inc", 0xFE, MRM0m>; // ++R8 +def INC16m : Im16<"inc", 0xFF, MRM0m>, OpSize; // ++R16 +def INC32m : Im32<"inc", 0xFF, MRM0m>; // ++R32 + +def DEC8r : I <"dec", 0xFE, MRM1r>; // --R8 +def DEC16r : I <"dec", 0xFF, MRM1r>, OpSize; // --R16 +def DEC32r : I <"dec", 0xFF, MRM1r>; // --R32 +def DEC8m : Im8 <"dec", 0xFE, MRM1m>; // --[mem8] +def DEC16m : Im16<"dec", 0xFF, MRM1m>, OpSize; // --[mem16] +def DEC32m : Im32<"dec", 0xFF, MRM1m>; // --[mem32] +// Logical operators... +def AND8rr : I <"and", 0x20, MRMDestReg>, Pattern<(set R8 , (and R8 , R8 ))>; +def AND16rr : I <"and", 0x21, MRMDestReg>, OpSize, Pattern<(set R16, (and R16, R16))>; +def AND32rr : I <"and", 0x21, MRMDestReg>, Pattern<(set R32, (and R32, R32))>; +def AND8mr : Im8 <"and", 0x20, MRMDestMem>; // [mem8] &= R8 +def AND16mr : Im16 <"and", 0x21, MRMDestMem>, OpSize; // [mem16] &= R16 +def AND32mr : Im32 <"and", 0x21, MRMDestMem>; // [mem32] &= R32 +def AND8rm : Im8 <"and", 0x22, MRMSrcMem >; // R8 &= [mem8] +def AND16rm : Im16 <"and", 0x23, MRMSrcMem >, OpSize; // R16 &= [mem16] +def AND32rm : Im32 <"and", 0x23, MRMSrcMem >; // R32 &= [mem32] + +def AND8ri : Ii8 <"and", 0x80, MRM4r >, Pattern<(set R8 , (and R8 , imm))>; +def AND16ri : Ii16 <"and", 0x81, MRM4r >, OpSize, Pattern<(set R16, (and R16, imm))>; +def AND32ri : Ii32 <"and", 0x81, MRM4r >, Pattern<(set R32, (and R32, imm))>; +def AND8mi : Im8i8 <"and", 0x80, MRM4m >; // [mem8] &= imm8 +def AND16mi : Im16i16 <"and", 0x81, MRM4m >, OpSize; // [mem16] &= imm16 +def AND32mi : Im32i32 <"and", 0x81, MRM4m >; // [mem32] &= imm32 + +def AND16ri8 : Ii8 <"and", 0x83, MRM4r >, OpSize; // R16 &= imm8 +def AND32ri8 : Ii8 <"and", 0x83, MRM4r >; // R32 &= imm8 +def AND16mi8 : Im16i8<"and", 0x83, MRM4m >, OpSize; // [mem16] &= imm8 +def AND32mi8 : Im32i8<"and", 0x83, MRM4m >; // [mem32] &= imm8 + + +def OR8rr : I <"or" , 0x08, MRMDestReg>, Pattern<(set R8 , (or R8 , R8 ))>; +def OR16rr : I <"or" , 0x09, MRMDestReg>, OpSize, Pattern<(set R16, (or R16, R16))>; +def OR32rr : I <"or" , 0x09, MRMDestReg>, Pattern<(set R32, (or R32, R32))>; +def OR8mr : Im8 <"or" , 0x08, MRMDestMem>; // [mem8] |= R8 +def OR16mr : Im16 <"or" , 0x09, MRMDestMem>, OpSize; // [mem16] |= R16 +def OR32mr : Im32 <"or" , 0x09, MRMDestMem>; // [mem32] |= R32 +def OR8rm : Im8 <"or" , 0x0A, MRMSrcMem >; // R8 |= [mem8] +def OR16rm : Im16 <"or" , 0x0B, MRMSrcMem >, OpSize; // R16 |= [mem16] +def OR32rm : Im32 <"or" , 0x0B, MRMSrcMem >; // R32 |= [mem32] + +def OR8ri : Ii8 <"or" , 0x80, MRM1r >, Pattern<(set R8 , (or R8 , imm))>; +def OR16ri : Ii16 <"or" , 0x81, MRM1r >, OpSize, Pattern<(set R16, (or R16, imm))>; +def OR32ri : Ii32 <"or" , 0x81, MRM1r >, Pattern<(set R32, (or R32, imm))>; +def OR8mi : Im8i8 <"or" , 0x80, MRM1m >; // [mem8] |= imm8 +def OR16mi : Im16i16 <"or" , 0x81, MRM1m >, OpSize; // [mem16] |= imm16 +def OR32mi : Im32i32 <"or" , 0x81, MRM1m >; // [mem32] |= imm32 + +def OR16ri8 : Ii8 <"or" , 0x83, MRM1r >, OpSize; // R16 |= imm8 +def OR32ri8 : Ii8 <"or" , 0x83, MRM1r >; // R32 |= imm8 +def OR16mi8 : Im16i8<"or" , 0x83, MRM1m >, OpSize; // [mem16] |= imm8 +def OR32mi8 : Im32i8<"or" , 0x83, MRM1m >; // [mem32] |= imm8 + + +def XOR8rr : I <"xor", 0x30, MRMDestReg>, Pattern<(set R8 , (xor R8 , R8 ))>; +def XOR16rr : I <"xor", 0x31, MRMDestReg>, OpSize, Pattern<(set R16, (xor R16, R16))>; +def XOR32rr : I <"xor", 0x31, MRMDestReg>, Pattern<(set R32, (xor R32, R32))>; +def XOR8mr : Im8 <"xor", 0x30, MRMDestMem>; // [mem8] ^= R8 +def XOR16mr : Im16 <"xor", 0x31, MRMDestMem>, OpSize; // [mem16] ^= R16 +def XOR32mr : Im32 <"xor", 0x31, MRMDestMem>; // [mem32] ^= R32 +def XOR8rm : Im8 <"xor", 0x32, MRMSrcMem >; // R8 ^= [mem8] +def XOR16rm : Im16 <"xor", 0x33, MRMSrcMem >, OpSize; // R16 ^= [mem16] +def XOR32rm : Im32 <"xor", 0x33, MRMSrcMem >; // R32 ^= [mem32] + +def XOR8ri : Ii8 <"xor", 0x80, MRM6r >, Pattern<(set R8 , (xor R8 , imm))>; +def XOR16ri : Ii16 <"xor", 0x81, MRM6r >, OpSize, Pattern<(set R16, (xor R16, imm))>; +def XOR32ri : Ii32 <"xor", 0x81, MRM6r >, Pattern<(set R32, (xor R32, imm))>; +def XOR8mi : Im8i8 <"xor", 0x80, MRM6m >; // [mem8] ^= R8 +def XOR16mi : Im16i16 <"xor", 0x81, MRM6m >, OpSize; // [mem16] ^= R16 +def XOR32mi : Im32i32 <"xor", 0x81, MRM6m >; // [mem32] ^= R32 + +def XOR16ri8 : Ii8 <"xor", 0x83, MRM6r >, OpSize; // R16 ^= imm8 +def XOR32ri8 : Ii8 <"xor", 0x83, MRM6r >; // R32 ^= imm8 +def XOR16mi8 : Im16i8<"xor", 0x83, MRM6m >, OpSize; // [mem16] ^= imm8 +def XOR32mi8 : Im32i8<"xor", 0x83, MRM6m >; // [mem32] ^= imm8 -// Arithmetic... -def ADDrr8 : I2A8 <"add", 0x00, MRMDestReg>, Pattern<(set R8 , (plus R8 , R8 ))>; -def ADDrr16 : I2A16<"add", 0x01, MRMDestReg>, OpSize, Pattern<(set R16, (plus R16, R16))>; -def ADDrr32 : I2A32<"add", 0x01, MRMDestReg>, Pattern<(set R32, (plus R32, R32))>; -def ADDri8 : I2A8 <"add", 0x80, MRMS0r >, Pattern<(set R8 , (plus R8 , imm))>; -def ADDri16 : I2A16<"add", 0x81, MRMS0r >, OpSize, Pattern<(set R16, (plus R16, imm))>; -def ADDri32 : I2A32<"add", 0x81, MRMS0r >, Pattern<(set R32, (plus R32, imm))>; -def ADDri16b : I2A8 <"add", 0x83, MRMS0r >, OpSize; // ADDri with sign extended 8 bit imm -def ADDri32b : I2A8 <"add", 0x83, MRMS0r >; - -def ADCrr32 : I2A32<"adc", 0x11, MRMDestReg>; // R32 += imm32+Carry - -def SUBrr8 : I2A8 <"sub", 0x28, MRMDestReg>, Pattern<(set R8 , (minus R8 , R8 ))>; -def SUBrr16 : I2A16<"sub", 0x29, MRMDestReg>, OpSize, Pattern<(set R16, (minus R16, R16))>; -def SUBrr32 : I2A32<"sub", 0x29, MRMDestReg>, Pattern<(set R32, (minus R32, R32))>; -def SUBri8 : I2A8 <"sub", 0x80, MRMS5r >, Pattern<(set R8 , (minus R8 , imm))>; -def SUBri16 : I2A16<"sub", 0x81, MRMS5r >, OpSize, Pattern<(set R16, (minus R16, imm))>; -def SUBri32 : I2A32<"sub", 0x81, MRMS5r >, Pattern<(set R32, (minus R32, imm))>; -def SUBri16b : I2A8 <"sub", 0x83, MRMS5r >, OpSize; -def SUBri32b : I2A8 <"sub", 0x83, MRMS5r >; - -def SBBrr32 : I2A32<"sbb", 0x19, MRMDestReg>; // R32 -= R32+Carry - -def IMULrr16 : I2A16<"imul", 0xAF, MRMSrcReg>, TB, OpSize, Pattern<(set R16, (times R16, R16))>; -def IMULrr32 : I2A32<"imul", 0xAF, MRMSrcReg>, TB , Pattern<(set R32, (times R32, R32))>; -def IMULri16 : I2A16<"imul", 0x69, MRMSrcReg>, OpSize; -def IMULri32 : I2A32<"imul", 0x69, MRMSrcReg>; -def IMULri16b : I2A8<"imul", 0x6B, MRMSrcReg>, OpSize; -def IMULri32b : I2A8<"imul", 0x6B, MRMSrcReg>; +// Shift instructions +def SHL8rCL : I <"shl", 0xD2, MRM4r > , UsesCL; // R8 <<= cl +def SHL16rCL : I <"shl", 0xD3, MRM4r >, OpSize, UsesCL; // R16 <<= cl +def SHL32rCL : I <"shl", 0xD3, MRM4r > , UsesCL; // R32 <<= cl +def SHL8mCL : Im8 <"shl", 0xD2, MRM4m > , UsesCL; // [mem8] <<= cl +def SHL16mCL : Im16 <"shl", 0xD3, MRM4m >, OpSize, UsesCL; // [mem16] <<= cl +def SHL32mCL : Im32 <"shl", 0xD3, MRM4m > , UsesCL; // [mem32] <<= cl + +def SHL8ri : Ii8 <"shl", 0xC0, MRM4r >; // R8 <<= imm8 +def SHL16ri : Ii8 <"shl", 0xC1, MRM4r >, OpSize; // R16 <<= imm8 +def SHL32ri : Ii8 <"shl", 0xC1, MRM4r >; // R32 <<= imm8 +def SHL8mi : Im8i8 <"shl", 0xC0, MRM4m >; // [mem8] <<= imm8 +def SHL16mi : Im16i8<"shl", 0xC1, MRM4m >, OpSize; // [mem16] <<= imm8 +def SHL32mi : Im32i8<"shl", 0xC1, MRM4m >; // [mem32] <<= imm8 + +def SHR8rCL : I <"shr", 0xD2, MRM5r > , UsesCL; // R8 >>= cl +def SHR16rCL : I <"shr", 0xD3, MRM5r >, OpSize, UsesCL; // R16 >>= cl +def SHR32rCL : I <"shr", 0xD3, MRM5r > , UsesCL; // R32 >>= cl +def SHR8mCL : Im8 <"shr", 0xD2, MRM5m > , UsesCL; // [mem8] >>= cl +def SHR16mCL : Im16 <"shr", 0xD3, MRM5m >, OpSize, UsesCL; // [mem16] >>= cl +def SHR32mCL : Im32 <"shr", 0xD3, MRM5m > , UsesCL; // [mem32] >>= cl + +def SHR8ri : Ii8 <"shr", 0xC0, MRM5r >; // R8 >>= imm8 +def SHR16ri : Ii8 <"shr", 0xC1, MRM5r >, OpSize; // R16 >>= imm8 +def SHR32ri : Ii8 <"shr", 0xC1, MRM5r >; // R32 >>= imm8 +def SHR8mi : Im8i8 <"shr", 0xC0, MRM5m >; // [mem8] >>= imm8 +def SHR16mi : Im16i8<"shr", 0xC1, MRM5m >, OpSize; // [mem16] >>= imm8 +def SHR32mi : Im32i8<"shr", 0xC1, MRM5m >; // [mem32] >>= imm8 + +def SAR8rCL : I <"sar", 0xD2, MRM7r > , UsesCL; // R8 >>>= cl +def SAR16rCL : I <"sar", 0xD3, MRM7r >, OpSize, UsesCL; // R16 >>>= cl +def SAR32rCL : I <"sar", 0xD3, MRM7r > , UsesCL; // R32 >>>= cl +def SAR8mCL : Im8 <"sar", 0xD2, MRM7m > , UsesCL; // [mem8] >>>= cl +def SAR16mCL : Im16 <"sar", 0xD3, MRM7m >, OpSize, UsesCL; // [mem16] >>>= cl +def SAR32mCL : Im32 <"sar", 0xD3, MRM7m > , UsesCL; // [mem32] >>>= cl + +def SAR8ri : Ii8 <"sar", 0xC0, MRM7r >; // R8 >>>= imm8 +def SAR16ri : Ii8 <"sar", 0xC1, MRM7r >, OpSize; // R16 >>>= imm8 +def SAR32ri : Ii8 <"sar", 0xC1, MRM7r >; // R32 >>>= imm8 +def SAR8mi : Im8i8 <"sar", 0xC0, MRM7m >; // [mem8] >>>= imm8 +def SAR16mi : Im16i8<"sar", 0xC1, MRM7m >, OpSize; // [mem16] >>>= imm8 +def SAR32mi : Im32i8<"sar", 0xC1, MRM7m >; // [mem32] >>>= imm8 + +def SHLD32rrCL : I <"shld", 0xA5, MRMDestReg>, TB, UsesCL; // R32 <<= R32,R32 cl +def SHLD32mrCL : Im32 <"shld", 0xA5, MRMDestMem>, TB, UsesCL; // [mem32] <<= [mem32],R32 cl +def SHLD32rri8 : Ii8 <"shld", 0xA4, MRMDestReg>, TB; // R32 <<= R32,R32 imm8 +def SHLD32mri8 : Im32i8<"shld", 0xA4, MRMDestMem>, TB; // [mem32] <<= [mem32],R32 imm8 + +def SHRD32rrCL : I <"shrd", 0xAD, MRMDestReg>, TB, UsesCL; // R32 >>= R32,R32 cl +def SHRD32mrCL : Im32 <"shrd", 0xAD, MRMDestMem>, TB, UsesCL; // [mem32] >>= [mem32],R32 cl +def SHRD32rri8 : Ii8 <"shrd", 0xAC, MRMDestReg>, TB; // R32 >>= R32,R32 imm8 +def SHRD32mri8 : Im32i8<"shrd", 0xAC, MRMDestMem>, TB; // [mem32] >>= [mem32],R32 imm8 -// Logical operators... -def ANDrr8 : I2A8 <"and", 0x20, MRMDestReg>, Pattern<(set R8 , (and R8 , R8 ))>; -def ANDrr16 : I2A16<"and", 0x21, MRMDestReg>, OpSize, Pattern<(set R16, (and R16, R16))>; -def ANDrr32 : I2A32<"and", 0x21, MRMDestReg>, Pattern<(set R32, (and R32, R32))>; -def ANDri8 : I2A8 <"and", 0x80, MRMS4r >, Pattern<(set R8 , (and R8 , imm))>; -def ANDri16 : I2A16<"and", 0x81, MRMS4r >, OpSize, Pattern<(set R16, (and R16, imm))>; -def ANDri32 : I2A32<"and", 0x81, MRMS4r >, Pattern<(set R32, (and R32, imm))>; -def ANDri16b : I2A8 <"and", 0x83, MRMS4r >, OpSize; -def ANDri32b : I2A8 <"and", 0x83, MRMS4r >; - -def ORrr8 : I2A8 <"or" , 0x08, MRMDestReg>, Pattern<(set R8 , (or R8 , R8 ))>; -def ORrr16 : I2A16<"or" , 0x09, MRMDestReg>, OpSize, Pattern<(set R16, (or R16, R16))>; -def ORrr32 : I2A32<"or" , 0x09, MRMDestReg>, Pattern<(set R32, (or R32, R32))>; -def ORri8 : I2A8 <"or" , 0x80, MRMS1r >, Pattern<(set R8 , (or R8 , imm))>; -def ORri16 : I2A16<"or" , 0x81, MRMS1r >, OpSize, Pattern<(set R16, (or R16, imm))>; -def ORri32 : I2A32<"or" , 0x81, MRMS1r >, Pattern<(set R32, (or R32, imm))>; -def ORri16b : I2A8 <"or" , 0x83, MRMS1r >, OpSize; -def ORri32b : I2A8 <"or" , 0x83, MRMS1r >; - - -def XORrr8 : I2A8 <"xor", 0x30, MRMDestReg>, Pattern<(set R8 , (xor R8 , R8 ))>; -def XORrr16 : I2A16<"xor", 0x31, MRMDestReg>, OpSize, Pattern<(set R16, (xor R16, R16))>; -def XORrr32 : I2A32<"xor", 0x31, MRMDestReg>, Pattern<(set R32, (xor R32, R32))>; -def XORri8 : I2A8 <"xor", 0x80, MRMS6r >, Pattern<(set R8 , (xor R8 , imm))>; -def XORri16 : I2A16<"xor", 0x81, MRMS6r >, OpSize, Pattern<(set R16, (xor R16, imm))>; -def XORri32 : I2A32<"xor", 0x81, MRMS6r >, Pattern<(set R32, (xor R32, imm))>; -def XORri16b : I2A8 <"xor", 0x83, MRMS6r >, OpSize; -def XORri32b : I2A8 <"xor", 0x83, MRMS6r >; +// Arithmetic... +def ADD8rr : I <"add", 0x00, MRMDestReg>, Pattern<(set R8 , (plus R8 , R8 ))>; +def ADD16rr : I <"add", 0x01, MRMDestReg>, OpSize, Pattern<(set R16, (plus R16, R16))>; +def ADD32rr : I <"add", 0x01, MRMDestReg>, Pattern<(set R32, (plus R32, R32))>; +def ADD8mr : Im8 <"add", 0x00, MRMDestMem>; // [mem8] += R8 +def ADD16mr : Im16 <"add", 0x01, MRMDestMem>, OpSize; // [mem16] += R16 +def ADD32mr : Im32 <"add", 0x01, MRMDestMem>; // [mem32] += R32 +def ADD8rm : Im8 <"add", 0x02, MRMSrcMem >; // R8 += [mem8] +def ADD16rm : Im16 <"add", 0x03, MRMSrcMem >, OpSize; // R16 += [mem16] +def ADD32rm : Im32 <"add", 0x03, MRMSrcMem >; // R32 += [mem32] + +def ADD8ri : Ii8 <"add", 0x80, MRM0r >, Pattern<(set R8 , (plus R8 , imm))>; +def ADD16ri : Ii16 <"add", 0x81, MRM0r >, OpSize, Pattern<(set R16, (plus R16, imm))>; +def ADD32ri : Ii32 <"add", 0x81, MRM0r >, Pattern<(set R32, (plus R32, imm))>; +def ADD8mi : Im8i8 <"add", 0x80, MRM0m >; // [mem8] += I8 +def ADD16mi : Im16i16 <"add", 0x81, MRM0m >, OpSize; // [mem16] += I16 +def ADD32mi : Im32i32 <"add", 0x81, MRM0m >; // [mem32] += I32 + +def ADD16ri8 : Ii8 <"add", 0x83, MRM0r >, OpSize; // ADDri with sign extended 8 bit imm +def ADD32ri8 : Ii8 <"add", 0x83, MRM0r >; +def ADD16mi8 : Im16i8<"add", 0x83, MRM0m >, OpSize; // [mem16] += I8 +def ADD32mi8 : Im32i8<"add", 0x83, MRM0m >; // [mem32] += I8 + +def ADC32rr : I <"adc", 0x11, MRMDestReg>; // R32 += R32+Carry +def ADC32rm : Im32 <"adc", 0x11, MRMSrcMem >; // R32 += [mem32]+Carry +def ADC32mr : Im32 <"adc", 0x13, MRMDestMem>; // [mem32] += R32+Carry + + +def SUB8rr : I <"sub", 0x28, MRMDestReg>, Pattern<(set R8 , (minus R8 , R8 ))>; +def SUB16rr : I <"sub", 0x29, MRMDestReg>, OpSize, Pattern<(set R16, (minus R16, R16))>; +def SUB32rr : I <"sub", 0x29, MRMDestReg>, Pattern<(set R32, (minus R32, R32))>; +def SUB8mr : Im8 <"sub", 0x28, MRMDestMem>; // [mem8] -= R8 +def SUB16mr : Im16 <"sub", 0x29, MRMDestMem>, OpSize; // [mem16] -= R16 +def SUB32mr : Im32 <"sub", 0x29, MRMDestMem>; // [mem32] -= R32 +def SUB8rm : Im8 <"sub", 0x2A, MRMSrcMem >; // R8 -= [mem8] +def SUB16rm : Im16 <"sub", 0x2B, MRMSrcMem >, OpSize; // R16 -= [mem16] +def SUB32rm : Im32 <"sub", 0x2B, MRMSrcMem >; // R32 -= [mem32] + +def SUB8ri : Ii8 <"sub", 0x80, MRM5r >, Pattern<(set R8 , (minus R8 , imm))>; +def SUB16ri : Ii16 <"sub", 0x81, MRM5r >, OpSize, Pattern<(set R16, (minus R16, imm))>; +def SUB32ri : Ii32 <"sub", 0x81, MRM5r >, Pattern<(set R32, (minus R32, imm))>; +def SUB8mi : Im8i8 <"sub", 0x80, MRM5m >; // [mem8] -= I8 +def SUB16mi : Im16i16 <"sub", 0x81, MRM5m >, OpSize; // [mem16] -= I16 +def SUB32mi : Im32i32 <"sub", 0x81, MRM5m >; // [mem32] -= I32 + +def SUB16ri8 : Ii8 <"sub", 0x83, MRM5r >, OpSize; +def SUB32ri8 : Ii8 <"sub", 0x83, MRM5r >; +def SUB16mi8 : Im16i8<"sub", 0x83, MRM5m >, OpSize; // [mem16] -= I8 +def SUB32mi8 : Im32i8<"sub", 0x83, MRM5m >; // [mem32] -= I8 + +def SBB32rr : I <"sbb", 0x19, MRMDestReg>; // R32 -= R32+Borrow +def SBB32rm : Im32 <"sbb", 0x19, MRMSrcMem >; // R32 -= [mem32]+Borrow +def SBB32mr : Im32 <"sbb", 0x1B, MRMDestMem>; // [mem32] -= R32+Borrow + +def IMUL16rr : I <"imul", 0xAF, MRMSrcReg>, TB, OpSize, Pattern<(set R16, (times R16, R16))>; +def IMUL32rr : I <"imul", 0xAF, MRMSrcReg>, TB , Pattern<(set R32, (times R32, R32))>; +def IMUL16rm : Im16 <"imul", 0xAF, MRMSrcMem>, TB, OpSize; +def IMUL32rm : Im32 <"imul", 0xAF, MRMSrcMem>, TB ; + +} // end Two Address instructions + +// These are suprisingly enough not two address instructions! +def IMUL16rri : Ii16 <"imul", 0x69, MRMSrcReg>, OpSize; // R16 = R16*I16 +def IMUL32rri : Ii32 <"imul", 0x69, MRMSrcReg>; // R32 = R32*I32 +def IMUL16rri8 : Ii8 <"imul", 0x6B, MRMSrcReg>, OpSize; // R16 = R16*I8 +def IMUL32rri8 : Ii8 <"imul", 0x6B, MRMSrcReg>; // R32 = R32*I8 +def IMUL16rmi : Im16i16 <"imul", 0x69, MRMSrcMem>, OpSize; // R16 = [mem16]*I16 +def IMUL32rmi : Im32i32 <"imul", 0x69, MRMSrcMem>; // R32 = [mem32]*I32 +def IMUL16rmi8 : Im16i8<"imul", 0x6B, MRMSrcMem>, OpSize; // R16 = [mem16]*I8 +def IMUL32rmi8 : Im32i8<"imul", 0x6B, MRMSrcMem>; // R32 = [mem32]*I8 +//===----------------------------------------------------------------------===// // Test instructions are just like AND, except they don't generate a result. -def TESTrr8 : X86Inst<"test", 0x84, MRMDestReg, Arg8 >; // flags = R8 & R8 -def TESTrr16 : X86Inst<"test", 0x85, MRMDestReg, Arg16>, OpSize; // flags = R16 & R16 -def TESTrr32 : X86Inst<"test", 0x85, MRMDestReg, Arg32>; // flags = R32 & R32 -def TESTri8 : X86Inst<"test", 0xF6, MRMS0r , Arg8 >; // flags = R8 & imm8 -def TESTri16 : X86Inst<"test", 0xF7, MRMS0r , Arg16>, OpSize; // flags = R16 & imm16 -def TESTri32 : X86Inst<"test", 0xF7, MRMS0r , Arg32>; // flags = R32 & imm32 +def TEST8rr : I <"test", 0x84, MRMDestReg>; // flags = R8 & R8 +def TEST16rr : I <"test", 0x85, MRMDestReg>, OpSize; // flags = R16 & R16 +def TEST32rr : I <"test", 0x85, MRMDestReg>; // flags = R32 & R32 +def TEST8mr : Im8 <"test", 0x84, MRMDestMem>; // flags = [mem8] & R8 +def TEST16mr : Im16 <"test", 0x85, MRMDestMem>, OpSize; // flags = [mem16] & R16 +def TEST32mr : Im32 <"test", 0x85, MRMDestMem>; // flags = [mem32] & R32 +def TEST8rm : Im8 <"test", 0x84, MRMSrcMem >; // flags = R8 & [mem8] +def TEST16rm : Im16 <"test", 0x85, MRMSrcMem >, OpSize; // flags = R16 & [mem16] +def TEST32rm : Im32 <"test", 0x85, MRMSrcMem >; // flags = R32 & [mem32] + +def TEST8ri : Ii8 <"test", 0xF6, MRM0r >; // flags = R8 & imm8 +def TEST16ri : Ii16 <"test", 0xF7, MRM0r >, OpSize; // flags = R16 & imm16 +def TEST32ri : Ii32 <"test", 0xF7, MRM0r >; // flags = R32 & imm32 +def TEST8mi : Im8i8 <"test", 0xF6, MRM0m >; // flags = [mem8] & imm8 +def TEST16mi : Im16i16<"test", 0xF7, MRM0m >, OpSize; // flags = [mem16] & imm16 +def TEST32mi : Im32i32<"test", 0xF7, MRM0m >; // flags = [mem32] & imm32 -// Shift instructions -class UsesCL { list Uses = [CL]; bit printImplicitUses = 1; } -def SHLrr8 : I2A8 <"shl", 0xD2, MRMS4r > , UsesCL; // R8 <<= cl -def SHLrr16 : I2A8 <"shl", 0xD3, MRMS4r >, OpSize, UsesCL; // R16 <<= cl -def SHLrr32 : I2A8 <"shl", 0xD3, MRMS4r > , UsesCL; // R32 <<= cl -def SHLir8 : I2A8 <"shl", 0xC0, MRMS4r >; // R8 <<= imm8 -def SHLir16 : I2A8 <"shl", 0xC1, MRMS4r >, OpSize; // R16 <<= imm16 -def SHLir32 : I2A8 <"shl", 0xC1, MRMS4r >; // R32 <<= imm32 -def SHRrr8 : I2A8 <"shr", 0xD2, MRMS5r > , UsesCL; // R8 >>= cl -def SHRrr16 : I2A8 <"shr", 0xD3, MRMS5r >, OpSize, UsesCL; // R16 >>= cl -def SHRrr32 : I2A8 <"shr", 0xD3, MRMS5r > , UsesCL; // R32 >>= cl -def SHRir8 : I2A8 <"shr", 0xC0, MRMS5r >; // R8 >>= imm8 -def SHRir16 : I2A8 <"shr", 0xC1, MRMS5r >, OpSize; // R16 >>= imm16 -def SHRir32 : I2A8 <"shr", 0xC1, MRMS5r >; // R32 >>= imm32 -def SARrr8 : I2A8 <"sar", 0xD2, MRMS7r > , UsesCL; // R8 >>>= cl -def SARrr16 : I2A8 <"sar", 0xD3, MRMS7r >, OpSize, UsesCL; // R16 >>>= cl -def SARrr32 : I2A8 <"sar", 0xD3, MRMS7r > , UsesCL; // R32 >>>= cl -def SARir8 : I2A8 <"sar", 0xC0, MRMS7r >; // R8 >>>= imm8 -def SARir16 : I2A8 <"sar", 0xC1, MRMS7r >, OpSize; // R16 >>>= imm16 -def SARir32 : I2A8 <"sar", 0xC1, MRMS7r >; // R32 >>>= imm32 - -def SHLDrr32 : I2A8 <"shld", 0xA5, MRMDestReg>, TB, UsesCL; // R32 <<= R32,R32 cl -def SHLDir32 : I2A8 <"shld", 0xA4, MRMDestReg>, TB; // R32 <<= R32,R32 imm8 -def SHRDrr32 : I2A8 <"shrd", 0xAD, MRMDestReg>, TB, UsesCL; // R32 >>= R32,R32 cl -def SHRDir32 : I2A8 <"shrd", 0xAC, MRMDestReg>, TB; // R32 >>= R32,R32 imm8 // Condition code ops, incl. set if equal/not equal/... -def SAHF : X86Inst<"sahf" , 0x9E, RawFrm, Arg8>, Imp<[AH],[]>; // flags = AH -def SETBr : X86Inst<"setb" , 0x92, MRMS0r, Arg8>, TB; // R8 = < unsign -def SETAEr : X86Inst<"setae", 0x93, MRMS0r, Arg8>, TB; // R8 = >= unsign -def SETEr : X86Inst<"sete" , 0x94, MRMS0r, Arg8>, TB; // R8 = == -def SETNEr : X86Inst<"setne", 0x95, MRMS0r, Arg8>, TB; // R8 = != -def SETBEr : X86Inst<"setbe", 0x96, MRMS0r, Arg8>, TB; // R8 = <= unsign -def SETAr : X86Inst<"seta" , 0x97, MRMS0r, Arg8>, TB; // R8 = > signed -def SETSr : X86Inst<"sets" , 0x98, MRMS0r, Arg8>, TB; // R8 = -def SETNSr : X86Inst<"setns", 0x99, MRMS0r, Arg8>, TB; // R8 = ! -def SETLr : X86Inst<"setl" , 0x9C, MRMS0r, Arg8>, TB; // R8 = < signed -def SETGEr : X86Inst<"setge", 0x9D, MRMS0r, Arg8>, TB; // R8 = >= signed -def SETLEr : X86Inst<"setle", 0x9E, MRMS0r, Arg8>, TB; // R8 = <= signed -def SETGr : X86Inst<"setg" , 0x9F, MRMS0r, Arg8>, TB; // R8 = < signed +def SAHF : I <"sahf" , 0x9E, RawFrm>, Imp<[AH],[]>; // flags = AH -// Conditional moves. These are modelled as X = cmovXX Y, Z. Eventually -// register allocated to cmovXX XY, Z -def CMOVErr16 : I2A16<"cmove", 0x44, MRMSrcReg>, TB, OpSize; // if ==, R16 = R16 -def CMOVNErr32: I2A32<"cmovne",0x45, MRMSrcReg>, TB; // if !=, R32 = R32 +def SETBr : I <"setb" , 0x92, MRM0r>, TB; // R8 = < unsign +def SETBm : Im8<"setb" , 0x92, MRM0m>, TB; // [mem8] = < unsign +def SETAEr : I <"setae", 0x93, MRM0r>, TB; // R8 = >= unsign +def SETAEm : Im8<"setae", 0x93, MRM0m>, TB; // [mem8] = >= unsign +def SETEr : I <"sete" , 0x94, MRM0r>, TB; // R8 = == +def SETEm : Im8<"sete" , 0x94, MRM0m>, TB; // [mem8] = == +def SETNEr : I <"setne", 0x95, MRM0r>, TB; // R8 = != +def SETNEm : Im8<"setne", 0x95, MRM0m>, TB; // [mem8] = != +def SETBEr : I <"setbe", 0x96, MRM0r>, TB; // R8 = <= unsign +def SETBEm : Im8<"setbe", 0x96, MRM0m>, TB; // [mem8] = <= unsign +def SETAr : I <"seta" , 0x97, MRM0r>, TB; // R8 = > signed +def SETAm : Im8<"seta" , 0x97, MRM0m>, TB; // [mem8] = > signed +def SETSr : I <"sets" , 0x98, MRM0r>, TB; // R8 = +def SETSm : Im8<"sets" , 0x98, MRM0m>, TB; // [mem8] = +def SETNSr : I <"setns", 0x99, MRM0r>, TB; // R8 = ! +def SETNSm : Im8<"setns", 0x99, MRM0m>, TB; // [mem8] = ! +def SETLr : I <"setl" , 0x9C, MRM0r>, TB; // R8 = < signed +def SETLm : Im8<"setl" , 0x9C, MRM0m>, TB; // [mem8] = < signed +def SETGEr : I <"setge", 0x9D, MRM0r>, TB; // R8 = >= signed +def SETGEm : Im8<"setge", 0x9D, MRM0m>, TB; // [mem8] = >= signed +def SETLEr : I <"setle", 0x9E, MRM0r>, TB; // R8 = <= signed +def SETLEm : Im8<"setle", 0x9E, MRM0m>, TB; // [mem8] = <= signed +def SETGr : I <"setg" , 0x9F, MRM0r>, TB; // R8 = < signed +def SETGm : Im8<"setg" , 0x9F, MRM0m>, TB; // [mem8] = < signed // Integer comparisons -def CMPrr8 : X86Inst<"cmp", 0x38, MRMDestReg, Arg8 >; // compare R8, R8 -def CMPrr16 : X86Inst<"cmp", 0x39, MRMDestReg, Arg16>, OpSize; // compare R16, R16 -def CMPrr32 : X86Inst<"cmp", 0x39, MRMDestReg, Arg32>, // compare R32, R32 +def CMP8rr : I <"cmp", 0x38, MRMDestReg>; // compare R8, R8 +def CMP16rr : I <"cmp", 0x39, MRMDestReg>, OpSize; // compare R16, R16 +def CMP32rr : I <"cmp", 0x39, MRMDestReg>, // compare R32, R32 Pattern<(isVoid (unspec2 R32, R32))>; -def CMPri8 : X86Inst<"cmp", 0x80, MRMS7r , Arg8 >; // compare R8, imm8 -def CMPri16 : X86Inst<"cmp", 0x81, MRMS7r , Arg16>, OpSize; // compare R16, imm16 -def CMPri32 : X86Inst<"cmp", 0x81, MRMS7r , Arg32>; // compare R32, imm32 +def CMP8mr : Im8 <"cmp", 0x38, MRMDestMem>; // compare [mem8], R8 +def CMP16mr : Im16 <"cmp", 0x39, MRMDestMem>, OpSize; // compare [mem16], R16 +def CMP32mr : Im32 <"cmp", 0x39, MRMDestMem>; // compare [mem32], R32 +def CMP8rm : Im8 <"cmp", 0x3A, MRMSrcMem >; // compare R8, [mem8] +def CMP16rm : Im16 <"cmp", 0x3B, MRMSrcMem >, OpSize; // compare R16, [mem16] +def CMP32rm : Im32 <"cmp", 0x3B, MRMSrcMem >; // compare R32, [mem32] +def CMP8ri : Ii8 <"cmp", 0x80, MRM7r >; // compare R8, imm8 +def CMP16ri : Ii16 <"cmp", 0x81, MRM7r >, OpSize; // compare R16, imm16 +def CMP32ri : Ii32 <"cmp", 0x81, MRM7r >; // compare R32, imm32 +def CMP8mi : Im8i8 <"cmp", 0x80, MRM7m >; // compare [mem8], imm8 +def CMP16mi : Im16i16<"cmp", 0x81, MRM7m >, OpSize; // compare [mem16], imm16 +def CMP32mi : Im32i32<"cmp", 0x81, MRM7m >; // compare [mem32], imm32 // Sign/Zero extenders -def MOVSXr16r8 : X86Inst<"movsx", 0xBE, MRMSrcReg, Arg8>, TB, OpSize; // R16 = signext(R8) -def MOVSXr32r8 : X86Inst<"movsx", 0xBE, MRMSrcReg, Arg8>, TB; // R32 = signext(R8) -def MOVSXr32r16: X86Inst<"movsx", 0xBF, MRMSrcReg, Arg8>, TB; // R32 = signext(R16) -def MOVZXr16r8 : X86Inst<"movzx", 0xB6, MRMSrcReg, Arg8>, TB, OpSize; // R16 = zeroext(R8) -def MOVZXr32r8 : X86Inst<"movzx", 0xB6, MRMSrcReg, Arg8>, TB; // R32 = zeroext(R8) -def MOVZXr32r16: X86Inst<"movzx", 0xB7, MRMSrcReg, Arg8>, TB; // R32 = zeroext(R16) +def MOVSX16rr8 : I <"movsx", 0xBE, MRMSrcReg>, TB, OpSize; // R16 = signext(R8) +def MOVSX32rr8 : I <"movsx", 0xBE, MRMSrcReg>, TB; // R32 = signext(R8) +def MOVSX32rr16: I <"movsx", 0xBF, MRMSrcReg>, TB; // R32 = signext(R16) +def MOVSX16rm8 : Im8 <"movsx", 0xBE, MRMSrcMem>, TB, OpSize; // R16 = signext([mem8]) +def MOVSX32rm8 : Im8 <"movsx", 0xBE, MRMSrcMem>, TB; // R32 = signext([mem8]) +def MOVSX32rm16: Im16<"movsx", 0xBF, MRMSrcMem>, TB; // R32 = signext([mem16]) + +def MOVZX16rr8 : I <"movzx", 0xB6, MRMSrcReg>, TB, OpSize; // R16 = zeroext(R8) +def MOVZX32rr8 : I <"movzx", 0xB6, MRMSrcReg>, TB; // R32 = zeroext(R8) +def MOVZX32rr16: I <"movzx", 0xB7, MRMSrcReg>, TB; // R32 = zeroext(R16) +def MOVZX16rm8 : Im8 <"movzx", 0xB6, MRMSrcMem>, TB, OpSize; // R16 = zeroext([mem8]) +def MOVZX32rm8 : Im8 <"movzx", 0xB6, MRMSrcMem>, TB; // R32 = zeroext([mem8]) +def MOVZX32rm16: Im16<"movzx", 0xB7, MRMSrcMem>, TB; // R32 = zeroext([mem16]) //===----------------------------------------------------------------------===// @@ -384,64 +610,78 @@ // FIXME: These need to indicate mod/ref sets for FP regs... & FP 'TOP' -// Floating point pseudo instructions... -class FPInst o, Format F, ArgType t, FPFormat fp> - : X86Inst { let FPForm = fp; let FPFormBits = FPForm.Value; } - -def FpMOV : FPInst<"FMOV", 0, Pseudo, ArgF80, SpecialFP>; // f1 = fmov f2 -def FpADD : FPInst<"FADD", 0, Pseudo, ArgF80, TwoArgFP>; // f1 = fadd f2, f3 -def FpSUB : FPInst<"FSUB", 0, Pseudo, ArgF80, TwoArgFP>; // f1 = fsub f2, f3 -def FpMUL : FPInst<"FMUL", 0, Pseudo, ArgF80, TwoArgFP>; // f1 = fmul f2, f3 -def FpDIV : FPInst<"FDIV", 0, Pseudo, ArgF80, TwoArgFP>; // f1 = fdiv f2, f3 +// Floating point instruction templates +class FPInst o, Format F, FPFormat fp, MemType m, ImmType i> + : X86Inst { let FPForm = fp; let FPFormBits = FPForm.Value; } + +class FPI o, Format F, FPFormat fp> : FPInst; + +class FPIM o, Format F, FPFormat fp, MemType m> : FPInst; + +class FPI16m o, Format F, FPFormat fp> : FPIM; +class FPI32m o, Format F, FPFormat fp> : FPIM; +class FPI64m o, Format F, FPFormat fp> : FPIM; +class FPI80m o, Format F, FPFormat fp> : FPIM; + +// Pseudo instructions for floating point. We use these pseudo instructions +// because they can be expanded by the fp spackifier into one of many different +// forms of instructions for doing these operations. Until the stackifier runs, +// we prefer to be abstract. +def FpMOV : FPI<"FMOV", 0, Pseudo, SpecialFP>; // f1 = fmov f2 +def FpADD : FPI<"FADD", 0, Pseudo, TwoArgFP>; // f1 = fadd f2, f3 +def FpSUB : FPI<"FSUB", 0, Pseudo, TwoArgFP>; // f1 = fsub f2, f3 +def FpMUL : FPI<"FMUL", 0, Pseudo, TwoArgFP>; // f1 = fmul f2, f3 +def FpDIV : FPI<"FDIV", 0, Pseudo, TwoArgFP>; // f1 = fdiv f2, f3 + +def FpUCOM : FPI<"FUCOM", 0, Pseudo, TwoArgFP>; // FPSW = fucom f1, f2 +def FpGETRESULT : FPI<"FGETRESULT",0, Pseudo, SpecialFP>; // FPR = ST(0) +def FpSETRESULT : FPI<"FSETRESULT",0, Pseudo, SpecialFP>; // ST(0) = FPR -def FpUCOM : FPInst<"FUCOM", 0, Pseudo, ArgF80, TwoArgFP>; // FPSW = fucom f1, f2 +// Floating point loads & stores... +def FLDrr : FPI <"fld" , 0xC0, AddRegFrm, NotFP>, D9; // push(ST(i)) +def FLD32m : FPI32m <"fld" , 0xD9, MRM0m , ZeroArgFP>; // load float +def FLD64m : FPI64m <"fld" , 0xDD, MRM0m , ZeroArgFP>; // load double +def FLD80m : FPI80m <"fld" , 0xDB, MRM5m , ZeroArgFP>; // load extended +def FILD16m : FPI16m <"fild" , 0xDF, MRM0m , ZeroArgFP>; // load signed short +def FILD32m : FPI32m <"fild" , 0xDB, MRM0m , ZeroArgFP>; // load signed int +def FILD64m : FPI64m <"fild" , 0xDF, MRM5m , ZeroArgFP>; // load signed long + +def FSTrr : FPI <"fst" , 0xD0, AddRegFrm, NotFP >, DD; // ST(i) = ST(0) +def FSTPrr : FPI <"fstp", 0xD8, AddRegFrm, NotFP >, DD; // ST(i) = ST(0), pop +def FST32m : FPI32m <"fst" , 0xD9, MRM2m , OneArgFP>; // store float +def FST64m : FPI64m <"fst" , 0xDD, MRM2m , OneArgFP>; // store double +def FSTP32m : FPI32m <"fstp", 0xD9, MRM3m , OneArgFP>; // store float, pop +def FSTP64m : FPI64m <"fstp", 0xDD, MRM3m , OneArgFP>; // store double, pop +def FSTP80m : FPI80m <"fstp", 0xDB, MRM7m , OneArgFP>; // store extended, pop + +def FIST16m : FPI16m <"fist", 0xDF, MRM2m , OneArgFP>; // store signed short +def FIST32m : FPI32m <"fist", 0xDB, MRM2m , OneArgFP>; // store signed int +def FISTP16m : FPI16m <"fistp", 0xDF, MRM3m , NotFP >; // store signed short, pop +def FISTP32m : FPI32m <"fistp", 0xDB, MRM3m , NotFP >; // store signed int, pop +def FISTP64m : FPI64m <"fistpll", 0xDF, MRM7m , OneArgFP>; // store signed long, pop -def FpGETRESULT : FPInst<"FGETRESULT",0, Pseudo, ArgF80, SpecialFP>; // FPR = ST(0) +def FXCH : FPI <"fxch", 0xC8, AddRegFrm, NotFP>, D9; // fxch ST(i), ST(0) -def FpSETRESULT : FPInst<"FSETRESULT",0, Pseudo, ArgF80, SpecialFP>; // ST(0) = FPR +// Floating point constant loads... +def FLD0 : FPI<"fldz", 0xEE, RawFrm, ZeroArgFP>, D9; +def FLD1 : FPI<"fld1", 0xE8, RawFrm, ZeroArgFP>, D9; -// Floating point loads & stores... -def FLDrr : FPInst<"fld" , 0xC0, AddRegFrm, ArgF80, NotFP>, D9; // push(ST(i)) -def FLDr32 : FPInst<"fld" , 0xD9, MRMS0m , ArgF32, ZeroArgFP>; // load float -def FLDr64 : FPInst<"fld" , 0xDD, MRMS0m , ArgF64, ZeroArgFP>; // load double -def FLDr80 : FPInst<"fld" , 0xDB, MRMS5m , ArgF80, ZeroArgFP>; // load extended -def FILDr16 : FPInst<"fild" , 0xDF, MRMS0m , Arg16 , ZeroArgFP>; // load signed short -def FILDr32 : FPInst<"fild" , 0xDB, MRMS0m , Arg32 , ZeroArgFP>; // load signed int -def FILDr64 : FPInst<"fild" , 0xDF, MRMS5m , Arg64 , ZeroArgFP>; // load signed long - -def FSTr32 : FPInst<"fst" , 0xD9, MRMS2m , ArgF32, OneArgFP>; // store float -def FSTr64 : FPInst<"fst" , 0xDD, MRMS2m , ArgF64, OneArgFP>; // store double -def FSTPr32 : FPInst<"fstp", 0xD9, MRMS3m , ArgF32, OneArgFP>; // store float, pop -def FSTPr64 : FPInst<"fstp", 0xDD, MRMS3m , ArgF64, OneArgFP>; // store double, pop -def FSTPr80 : FPInst<"fstp", 0xDB, MRMS7m , ArgF80, OneArgFP>; // store extended, pop -def FSTrr : FPInst<"fst" , 0xD0, AddRegFrm, ArgF80, NotFP >, DD; // ST(i) = ST(0) -def FSTPrr : FPInst<"fstp", 0xD8, AddRegFrm, ArgF80, NotFP >, DD; // ST(i) = ST(0), pop - -def FISTr16 : FPInst<"fist", 0xDF, MRMS2m, Arg16 , OneArgFP>; // store signed short -def FISTr32 : FPInst<"fist", 0xDB, MRMS2m, Arg32 , OneArgFP>; // store signed int -def FISTPr16 : FPInst<"fistp", 0xDF, MRMS3m, Arg16 , NotFP >; // store signed short, pop -def FISTPr32 : FPInst<"fistp", 0xDB, MRMS3m, Arg32 , NotFP >; // store signed int, pop -def FISTPr64 : FPInst<"fistpll", 0xDF, MRMS7m, Arg64 , OneArgFP>; // store signed long, pop -def FXCH : FPInst<"fxch", 0xC8, AddRegFrm, ArgF80, NotFP>, D9; // fxch ST(i), ST(0) +// Unary operations... +def FCHS : FPI<"fchs", 0xE0, RawFrm, OneArgFPRW>, D9; // f1 = fchs f2 -// Floating point constant loads... -def FLD0 : FPInst<"fldz", 0xEE, RawFrm, ArgF80, ZeroArgFP>, D9; -def FLD1 : FPInst<"fld1", 0xE8, RawFrm, ArgF80, ZeroArgFP>, D9; +def FTST : FPI<"ftst", 0xE4, RawFrm, OneArgFP>, D9; // ftst ST(0) // Binary arithmetic operations... -class FPST0rInst o> - : X86Inst, D8 { +class FPST0rInst o> : I, D8 { list Uses = [ST0]; list Defs = [ST0]; } -class FPrST0Inst o> - : X86Inst, DC { +class FPrST0Inst o> : I, DC { bit printImplicitUses = 1; list Uses = [ST0]; } -class FPrST0PInst o> - : X86Inst, DE { +class FPrST0PInst o> : I, DE { list Uses = [ST0]; } @@ -470,14 +710,14 @@ def FDIVRPrST0 : FPrST0PInst<"fdivrp", 0xF0>; // ST(i) = ST(0) / ST(i), pop // Floating point compares -def FUCOMr : X86Inst<"fucom" , 0xE0, AddRegFrm, ArgF80>, DD, Imp<[ST0],[]>; // FPSW = compare ST(0) with ST(i) -def FUCOMPr : X86Inst<"fucomp" , 0xE8, AddRegFrm, ArgF80>, DD, Imp<[ST0],[]>; // FPSW = compare ST(0) with ST(i), pop -def FUCOMPPr : X86Inst<"fucompp", 0xE9, RawFrm , ArgF80>, DA, Imp<[ST0],[]>; // compare ST(0) with ST(1), pop, pop +def FUCOMr : I<"fucom" , 0xE0, AddRegFrm>, DD, Imp<[ST0],[]>; // FPSW = compare ST(0) with ST(i) +def FUCOMPr : I<"fucomp" , 0xE8, AddRegFrm>, DD, Imp<[ST0],[]>; // FPSW = compare ST(0) with ST(i), pop +def FUCOMPPr : I<"fucompp", 0xE9, RawFrm >, DA, Imp<[ST0],[]>; // compare ST(0) with ST(1), pop, pop // Floating point flag ops -def FNSTSWr8 : X86Inst<"fnstsw" , 0xE0, RawFrm , ArgF80>, DF, Imp<[],[AX]>; // AX = fp flags -def FNSTCWm16 : X86Inst<"fnstcw" , 0xD9, MRMS7m , Arg16 >; // [mem16] = X87 control world -def FLDCWm16 : X86Inst<"fldcw" , 0xD9, MRMS5m , Arg16 >; // X87 control world = [mem16] +def FNSTSW8r : I <"fnstsw" , 0xE0, RawFrm>, DF, Imp<[],[AX]>; // AX = fp flags +def FNSTCW16m : Im16<"fnstcw" , 0xD9, MRM7m >; // [mem16] = X87 control world +def FLDCW16m : Im16<"fldcw" , 0xD9, MRM5m >; // X87 control world = [mem16] //===----------------------------------------------------------------------===// @@ -485,26 +725,26 @@ // def RET_R32 : Expander<(ret R32:$reg), - [(MOVrr32 EAX, R32:$reg), + [(MOV32rr EAX, R32:$reg), (RET)]>; // FIXME: This should eventually just be implemented by defining a frameidx as a // value address for a load. def LOAD_FI16 : Expander<(set R16:$dest, (load frameidx:$fi)), - [(MOVmr16 R16:$dest, frameidx:$fi, 1, 0/*NoReg*/, 0)]>; + [(MOV16rm R16:$dest, frameidx:$fi, 1, 0/*NoReg*/, 0)]>; def LOAD_FI32 : Expander<(set R32:$dest, (load frameidx:$fi)), - [(MOVmr32 R32:$dest, frameidx:$fi, 1, 0/*NoReg*/, 0)]>; + [(MOV32rm R32:$dest, frameidx:$fi, 1, 0/*NoReg*/, 0)]>; def LOAD_R16 : Expander<(set R16:$dest, (load R32:$src)), - [(MOVmr16 R16:$dest, R32:$src, 1, 0/*NoReg*/, 0)]>; + [(MOV16rm R16:$dest, R32:$src, 1, 0/*NoReg*/, 0)]>; def LOAD_R32 : Expander<(set R32:$dest, (load R32:$src)), - [(MOVmr32 R32:$dest, R32:$src, 1, 0/*NoReg*/, 0)]>; + [(MOV32rm R32:$dest, R32:$src, 1, 0/*NoReg*/, 0)]>; def BR_EQ : Expander<(brcond (seteq R32:$a1, R32:$a2), basicblock:$d1, basicblock:$d2), - [(CMPrr32 R32:$a1, R32:$a2), + [(CMP32rr R32:$a1, R32:$a2), (JE basicblock:$d1), (JMP basicblock:$d2)]>; Index: llvm/lib/Target/X86/X86RegisterInfo.cpp diff -u llvm/lib/Target/X86/X86RegisterInfo.cpp:1.40 llvm/lib/Target/X86/X86RegisterInfo.cpp:1.40.4.1 --- llvm/lib/Target/X86/X86RegisterInfo.cpp:1.40 Tue Nov 11 16:41:33 2003 +++ llvm/lib/Target/X86/X86RegisterInfo.cpp Mon Mar 1 17:58:15 2004 @@ -24,13 +24,21 @@ #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetFrameInfo.h" #include "Support/CommandLine.h" - -namespace llvm { +#include "Support/STLExtras.h" +using namespace llvm; namespace { cl::opt NoFPElim("disable-fp-elim", cl::desc("Disable frame pointer elimination optimization")); + cl::opt + NoFusing("disable-spill-fusing", + cl::desc("Disable fusing of spill code into instructions")); + cl::opt + PrintFailedFusing("print-failed-fuse-candidates", + cl::desc("Print instructions that the allocator wants to" + " fuse, but the X86 backend currently can't"), + cl::Hidden); } X86RegisterInfo::X86RegisterInfo() @@ -47,40 +55,257 @@ } int X86RegisterInfo::storeRegToStackSlot(MachineBasicBlock &MBB, - MachineBasicBlock::iterator &MBBI, + MachineBasicBlock::iterator MI, unsigned SrcReg, int FrameIdx, const TargetRegisterClass *RC) const { static const unsigned Opcode[] = - { X86::MOVrm8, X86::MOVrm16, X86::MOVrm32, X86::FSTPr80 }; - MachineInstr *MI = addFrameReference(BuildMI(Opcode[getIdx(RC)], 5), + { X86::MOV8mr, X86::MOV16mr, X86::MOV32mr, X86::FSTP80m }; + MachineInstr *I = addFrameReference(BuildMI(Opcode[getIdx(RC)], 5), FrameIdx).addReg(SrcReg); - MBBI = MBB.insert(MBBI, MI)+1; + MBB.insert(MI, I); return 1; } int X86RegisterInfo::loadRegFromStackSlot(MachineBasicBlock &MBB, - MachineBasicBlock::iterator &MBBI, + MachineBasicBlock::iterator MI, unsigned DestReg, int FrameIdx, const TargetRegisterClass *RC) const{ static const unsigned Opcode[] = - { X86::MOVmr8, X86::MOVmr16, X86::MOVmr32, X86::FLDr80 }; - MachineInstr *MI = addFrameReference(BuildMI(Opcode[getIdx(RC)], 4, DestReg), - FrameIdx); - MBBI = MBB.insert(MBBI, MI)+1; + { X86::MOV8rm, X86::MOV16rm, X86::MOV32rm, X86::FLD80m }; + unsigned OC = Opcode[getIdx(RC)]; + MBB.insert(MI, addFrameReference(BuildMI(OC, 4, DestReg), FrameIdx)); return 1; } int X86RegisterInfo::copyRegToReg(MachineBasicBlock &MBB, - MachineBasicBlock::iterator &MBBI, + MachineBasicBlock::iterator MI, unsigned DestReg, unsigned SrcReg, const TargetRegisterClass *RC) const { static const unsigned Opcode[] = - { X86::MOVrr8, X86::MOVrr16, X86::MOVrr32, X86::FpMOV }; - MachineInstr *MI = BuildMI(Opcode[getIdx(RC)],1,DestReg).addReg(SrcReg); - MBBI = MBB.insert(MBBI, MI)+1; + { X86::MOV8rr, X86::MOV16rr, X86::MOV32rr, X86::FpMOV }; + MBB.insert(MI, BuildMI(Opcode[getIdx(RC)],1,DestReg).addReg(SrcReg)); return 1; } +static MachineInstr *MakeMInst(unsigned Opcode, unsigned FrameIndex, + MachineInstr *MI) { + return addFrameReference(BuildMI(Opcode, 4), FrameIndex); +} + +static MachineInstr *MakeMRInst(unsigned Opcode, unsigned FrameIndex, + MachineInstr *MI) { + return addFrameReference(BuildMI(Opcode, 5), FrameIndex) + .addReg(MI->getOperand(1).getReg()); +} + +static MachineInstr *MakeMRIInst(unsigned Opcode, unsigned FrameIndex, + MachineInstr *MI) { + return addFrameReference(BuildMI(Opcode, 5), FrameIndex) + .addReg(MI->getOperand(1).getReg()) + .addZImm(MI->getOperand(2).getImmedValue()); +} + +static MachineInstr *MakeMIInst(unsigned Opcode, unsigned FrameIndex, + MachineInstr *MI) { + if (MI->getOperand(1).isImmediate()) + return addFrameReference(BuildMI(Opcode, 5), FrameIndex) + .addZImm(MI->getOperand(1).getImmedValue()); + else if (MI->getOperand(1).isGlobalAddress()) + return addFrameReference(BuildMI(Opcode, 5), FrameIndex) + .addGlobalAddress(MI->getOperand(1).getGlobal()); + assert(0 && "Unknown operand for MakeMI!"); + return 0; +} + +static MachineInstr *MakeRMInst(unsigned Opcode, unsigned FrameIndex, + MachineInstr *MI) { + const MachineOperand& op = MI->getOperand(0); + return addFrameReference(BuildMI(Opcode, 5, op.getReg(), op.getUseType()), + FrameIndex); +} + +static MachineInstr *MakeRMIInst(unsigned Opcode, unsigned FrameIndex, + MachineInstr *MI) { + const MachineOperand& op = MI->getOperand(0); + return addFrameReference(BuildMI(Opcode, 5, op.getReg(), op.getUseType()), + FrameIndex).addZImm(MI->getOperand(2).getImmedValue()); +} + + +bool X86RegisterInfo::foldMemoryOperand(MachineBasicBlock::iterator &MI, + unsigned i, int FrameIndex) const { + if (NoFusing) return false; + + /// FIXME: This should obviously be autogenerated by tablegen when patterns + /// are available! + MachineBasicBlock& MBB = *MI->getParent(); + MachineInstr* NI = 0; + if (i == 0) { + switch(MI->getOpcode()) { + case X86::XCHG8rr: NI = MakeMRInst(X86::XCHG8mr ,FrameIndex, MI); break; + case X86::XCHG16rr:NI = MakeMRInst(X86::XCHG16mr,FrameIndex, MI); break; + case X86::XCHG32rr:NI = MakeMRInst(X86::XCHG32mr,FrameIndex, MI); break; + case X86::MOV8rr: NI = MakeMRInst(X86::MOV8mr , FrameIndex, MI); break; + case X86::MOV16rr: NI = MakeMRInst(X86::MOV16mr, FrameIndex, MI); break; + case X86::MOV32rr: NI = MakeMRInst(X86::MOV32mr, FrameIndex, MI); break; + case X86::MOV8ri: NI = MakeMIInst(X86::MOV8mi , FrameIndex, MI); break; + case X86::MOV16ri: NI = MakeMIInst(X86::MOV16mi, FrameIndex, MI); break; + case X86::MOV32ri: NI = MakeMIInst(X86::MOV32mi, FrameIndex, MI); break; + case X86::MUL8r: NI = MakeMInst( X86::MUL8m , FrameIndex, MI); break; + case X86::MUL16r: NI = MakeMInst( X86::MUL16m, FrameIndex, MI); break; + case X86::MUL32r: NI = MakeMInst( X86::MUL32m, FrameIndex, MI); break; + case X86::DIV8r: NI = MakeMInst( X86::DIV8m , FrameIndex, MI); break; + case X86::DIV16r: NI = MakeMInst( X86::DIV16m, FrameIndex, MI); break; + case X86::DIV32r: NI = MakeMInst( X86::DIV32m, FrameIndex, MI); break; + case X86::IDIV8r: NI = MakeMInst( X86::IDIV8m , FrameIndex, MI); break; + case X86::IDIV16r: NI = MakeMInst( X86::IDIV16m, FrameIndex, MI); break; + case X86::IDIV32r: NI = MakeMInst( X86::IDIV32m, FrameIndex, MI); break; + case X86::NEG8r: NI = MakeMInst( X86::NEG8m , FrameIndex, MI); break; + case X86::NEG16r: NI = MakeMInst( X86::NEG16m, FrameIndex, MI); break; + case X86::NEG32r: NI = MakeMInst( X86::NEG32m, FrameIndex, MI); break; + case X86::NOT8r: NI = MakeMInst( X86::NOT8m , FrameIndex, MI); break; + case X86::NOT16r: NI = MakeMInst( X86::NOT16m, FrameIndex, MI); break; + case X86::NOT32r: NI = MakeMInst( X86::NOT32m, FrameIndex, MI); break; + case X86::INC8r: NI = MakeMInst( X86::INC8m , FrameIndex, MI); break; + case X86::INC16r: NI = MakeMInst( X86::INC16m, FrameIndex, MI); break; + case X86::INC32r: NI = MakeMInst( X86::INC32m, FrameIndex, MI); break; + case X86::DEC8r: NI = MakeMInst( X86::DEC8m , FrameIndex, MI); break; + case X86::DEC16r: NI = MakeMInst( X86::DEC16m, FrameIndex, MI); break; + case X86::DEC32r: NI = MakeMInst( X86::DEC32m, FrameIndex, MI); break; + case X86::ADD8rr: NI = MakeMRInst(X86::ADD8mr , FrameIndex, MI); break; + case X86::ADD16rr: NI = MakeMRInst(X86::ADD16mr, FrameIndex, MI); break; + case X86::ADD32rr: NI = MakeMRInst(X86::ADD32mr, FrameIndex, MI); break; + case X86::ADC32rr: NI = MakeMRInst(X86::ADC32mr, FrameIndex, MI); break; + case X86::ADD8ri: NI = MakeMIInst(X86::ADD8mi , FrameIndex, MI); break; + case X86::ADD16ri: NI = MakeMIInst(X86::ADD16mi, FrameIndex, MI); break; + case X86::ADD32ri: NI = MakeMIInst(X86::ADD32mi, FrameIndex, MI); break; + case X86::SUB8rr: NI = MakeMRInst(X86::SUB8mr , FrameIndex, MI); break; + case X86::SUB16rr: NI = MakeMRInst(X86::SUB16mr, FrameIndex, MI); break; + case X86::SUB32rr: NI = MakeMRInst(X86::SUB32mr, FrameIndex, MI); break; + case X86::SBB32rr: NI = MakeMRInst(X86::SBB32mr, FrameIndex, MI); break; + case X86::SUB8ri: NI = MakeMIInst(X86::SUB8mi , FrameIndex, MI); break; + case X86::SUB16ri: NI = MakeMIInst(X86::SUB16mi, FrameIndex, MI); break; + case X86::SUB32ri: NI = MakeMIInst(X86::SUB32mi, FrameIndex, MI); break; + case X86::AND8rr: NI = MakeMRInst(X86::AND8mr , FrameIndex, MI); break; + case X86::AND16rr: NI = MakeMRInst(X86::AND16mr, FrameIndex, MI); break; + case X86::AND32rr: NI = MakeMRInst(X86::AND32mr, FrameIndex, MI); break; + case X86::AND8ri: NI = MakeMIInst(X86::AND8mi , FrameIndex, MI); break; + case X86::AND16ri: NI = MakeMIInst(X86::AND16mi, FrameIndex, MI); break; + case X86::AND32ri: NI = MakeMIInst(X86::AND32mi, FrameIndex, MI); break; + case X86::OR8rr: NI = MakeMRInst(X86::OR8mr , FrameIndex, MI); break; + case X86::OR16rr: NI = MakeMRInst(X86::OR16mr, FrameIndex, MI); break; + case X86::OR32rr: NI = MakeMRInst(X86::OR32mr, FrameIndex, MI); break; + case X86::OR8ri: NI = MakeMIInst(X86::OR8mi , FrameIndex, MI); break; + case X86::OR16ri: NI = MakeMIInst(X86::OR16mi, FrameIndex, MI); break; + case X86::OR32ri: NI = MakeMIInst(X86::OR32mi, FrameIndex, MI); break; + case X86::XOR8rr: NI = MakeMRInst(X86::XOR8mr , FrameIndex, MI); break; + case X86::XOR16rr: NI = MakeMRInst(X86::XOR16mr, FrameIndex, MI); break; + case X86::XOR32rr: NI = MakeMRInst(X86::XOR32mr, FrameIndex, MI); break; + case X86::XOR8ri: NI = MakeMIInst(X86::XOR8mi , FrameIndex, MI); break; + case X86::XOR16ri: NI = MakeMIInst(X86::XOR16mi, FrameIndex, MI); break; + case X86::XOR32ri: NI = MakeMIInst(X86::XOR32mi, FrameIndex, MI); break; + case X86::SHL8rCL: NI = MakeMInst( X86::SHL8mCL ,FrameIndex, MI); break; + case X86::SHL16rCL:NI = MakeMInst( X86::SHL16mCL,FrameIndex, MI); break; + case X86::SHL32rCL:NI = MakeMInst( X86::SHL32mCL,FrameIndex, MI); break; + case X86::SHL8ri: NI = MakeMIInst(X86::SHL8mi , FrameIndex, MI); break; + case X86::SHL16ri: NI = MakeMIInst(X86::SHL16mi, FrameIndex, MI); break; + case X86::SHL32ri: NI = MakeMIInst(X86::SHL32mi, FrameIndex, MI); break; + case X86::SHR8rCL: NI = MakeMInst( X86::SHR8mCL ,FrameIndex, MI); break; + case X86::SHR16rCL:NI = MakeMInst( X86::SHR16mCL,FrameIndex, MI); break; + case X86::SHR32rCL:NI = MakeMInst( X86::SHR32mCL,FrameIndex, MI); break; + case X86::SHR8ri: NI = MakeMIInst(X86::SHR8mi , FrameIndex, MI); break; + case X86::SHR16ri: NI = MakeMIInst(X86::SHR16mi, FrameIndex, MI); break; + case X86::SHR32ri: NI = MakeMIInst(X86::SHR32mi, FrameIndex, MI); break; + case X86::SAR8rCL: NI = MakeMInst( X86::SAR8mCL ,FrameIndex, MI); break; + case X86::SAR16rCL:NI = MakeMInst( X86::SAR16mCL,FrameIndex, MI); break; + case X86::SAR32rCL:NI = MakeMInst( X86::SAR32mCL,FrameIndex, MI); break; + case X86::SAR8ri: NI = MakeMIInst(X86::SAR8mi , FrameIndex, MI); break; + case X86::SAR16ri: NI = MakeMIInst(X86::SAR16mi, FrameIndex, MI); break; + case X86::SAR32ri: NI = MakeMIInst(X86::SAR32mi, FrameIndex, MI); break; + case X86::SHLD32rrCL:NI = MakeMRInst( X86::SHLD32mrCL,FrameIndex, MI);break; + case X86::SHLD32rri8:NI = MakeMRIInst(X86::SHLD32mri8,FrameIndex, MI);break; + case X86::SHRD32rrCL:NI = MakeMRInst( X86::SHRD32mrCL,FrameIndex, MI);break; + case X86::SHRD32rri8:NI = MakeMRIInst(X86::SHRD32mri8,FrameIndex, MI);break; + case X86::SETBr: NI = MakeMInst( X86::SETBm, FrameIndex, MI); break; + case X86::SETAEr: NI = MakeMInst( X86::SETAEm, FrameIndex, MI); break; + case X86::SETEr: NI = MakeMInst( X86::SETEm, FrameIndex, MI); break; + case X86::SETNEr: NI = MakeMInst( X86::SETNEm, FrameIndex, MI); break; + case X86::SETBEr: NI = MakeMInst( X86::SETBEm, FrameIndex, MI); break; + case X86::SETAr: NI = MakeMInst( X86::SETAm, FrameIndex, MI); break; + case X86::SETSr: NI = MakeMInst( X86::SETSm, FrameIndex, MI); break; + case X86::SETNSr: NI = MakeMInst( X86::SETNSm, FrameIndex, MI); break; + case X86::SETLr: NI = MakeMInst( X86::SETLm, FrameIndex, MI); break; + case X86::SETGEr: NI = MakeMInst( X86::SETGEm, FrameIndex, MI); break; + case X86::SETLEr: NI = MakeMInst( X86::SETLEm, FrameIndex, MI); break; + case X86::SETGr: NI = MakeMInst( X86::SETGm, FrameIndex, MI); break; + case X86::TEST8rr: NI = MakeMRInst(X86::TEST8mr ,FrameIndex, MI); break; + case X86::TEST16rr:NI = MakeMRInst(X86::TEST16mr,FrameIndex, MI); break; + case X86::TEST32rr:NI = MakeMRInst(X86::TEST32mr,FrameIndex, MI); break; + case X86::TEST8ri: NI = MakeMIInst(X86::TEST8mi ,FrameIndex, MI); break; + case X86::TEST16ri:NI = MakeMIInst(X86::TEST16mi,FrameIndex, MI); break; + case X86::TEST32ri:NI = MakeMIInst(X86::TEST32mi,FrameIndex, MI); break; + case X86::CMP8rr: NI = MakeMRInst(X86::CMP8mr , FrameIndex, MI); break; + case X86::CMP16rr: NI = MakeMRInst(X86::CMP16mr, FrameIndex, MI); break; + case X86::CMP32rr: NI = MakeMRInst(X86::CMP32mr, FrameIndex, MI); break; + case X86::CMP8ri: NI = MakeMIInst(X86::CMP8mi , FrameIndex, MI); break; + case X86::CMP16ri: NI = MakeMIInst(X86::CMP16mi, FrameIndex, MI); break; + case X86::CMP32ri: NI = MakeMIInst(X86::CMP32mi, FrameIndex, MI); break; + default: break; // Cannot fold + } + } else if (i == 1) { + switch(MI->getOpcode()) { + case X86::XCHG8rr: NI = MakeRMInst(X86::XCHG8rm ,FrameIndex, MI); break; + case X86::XCHG16rr:NI = MakeRMInst(X86::XCHG16rm,FrameIndex, MI); break; + case X86::XCHG32rr:NI = MakeRMInst(X86::XCHG32rm,FrameIndex, MI); break; + case X86::MOV8rr: NI = MakeRMInst(X86::MOV8rm , FrameIndex, MI); break; + case X86::MOV16rr: NI = MakeRMInst(X86::MOV16rm, FrameIndex, MI); break; + case X86::MOV32rr: NI = MakeRMInst(X86::MOV32rm, FrameIndex, MI); break; + case X86::ADD8rr: NI = MakeRMInst(X86::ADD8rm , FrameIndex, MI); break; + case X86::ADD16rr: NI = MakeRMInst(X86::ADD16rm, FrameIndex, MI); break; + case X86::ADD32rr: NI = MakeRMInst(X86::ADD32rm, FrameIndex, MI); break; + case X86::ADC32rr: NI = MakeRMInst(X86::ADC32rm, FrameIndex, MI); break; + case X86::SUB8rr: NI = MakeRMInst(X86::SUB8rm , FrameIndex, MI); break; + case X86::SUB16rr: NI = MakeRMInst(X86::SUB16rm, FrameIndex, MI); break; + case X86::SUB32rr: NI = MakeRMInst(X86::SUB32rm, FrameIndex, MI); break; + case X86::SBB32rr: NI = MakeRMInst(X86::SBB32rm, FrameIndex, MI); break; + case X86::AND8rr: NI = MakeRMInst(X86::AND8rm , FrameIndex, MI); break; + case X86::AND16rr: NI = MakeRMInst(X86::AND16rm, FrameIndex, MI); break; + case X86::AND32rr: NI = MakeRMInst(X86::AND32rm, FrameIndex, MI); break; + case X86::OR8rr: NI = MakeRMInst(X86::OR8rm , FrameIndex, MI); break; + case X86::OR16rr: NI = MakeRMInst(X86::OR16rm, FrameIndex, MI); break; + case X86::OR32rr: NI = MakeRMInst(X86::OR32rm, FrameIndex, MI); break; + case X86::XOR8rr: NI = MakeRMInst(X86::XOR8rm , FrameIndex, MI); break; + case X86::XOR16rr: NI = MakeRMInst(X86::XOR16rm, FrameIndex, MI); break; + case X86::XOR32rr: NI = MakeRMInst(X86::XOR32rm, FrameIndex, MI); break; + case X86::TEST8rr: NI = MakeRMInst(X86::TEST8rm ,FrameIndex, MI); break; + case X86::TEST16rr:NI = MakeRMInst(X86::TEST16rm,FrameIndex, MI); break; + case X86::TEST32rr:NI = MakeRMInst(X86::TEST32rm,FrameIndex, MI); break; + case X86::IMUL16rr:NI = MakeRMInst(X86::IMUL16rm,FrameIndex, MI); break; + case X86::IMUL32rr:NI = MakeRMInst(X86::IMUL32rm,FrameIndex, MI); break; + case X86::IMUL16rri: NI = MakeRMIInst(X86::IMUL16rmi, FrameIndex, MI);break; + case X86::IMUL32rri: NI = MakeRMIInst(X86::IMUL32rmi, FrameIndex, MI);break; + case X86::CMP8rr: NI = MakeRMInst(X86::CMP8rm , FrameIndex, MI); break; + case X86::CMP16rr: NI = MakeRMInst(X86::CMP16rm, FrameIndex, MI); break; + case X86::CMP32rr: NI = MakeRMInst(X86::CMP32rm, FrameIndex, MI); break; + case X86::MOVSX16rr8: NI = MakeRMInst(X86::MOVSX16rm8 , FrameIndex, MI); break; + case X86::MOVSX32rr8: NI = MakeRMInst(X86::MOVSX32rm8, FrameIndex, MI); break; + case X86::MOVSX32rr16:NI = MakeRMInst(X86::MOVSX32rm16, FrameIndex, MI); break; + case X86::MOVZX16rr8: NI = MakeRMInst(X86::MOVZX16rm8 , FrameIndex, MI); break; + case X86::MOVZX32rr8: NI = MakeRMInst(X86::MOVZX32rm8, FrameIndex, MI); break; + case X86::MOVZX32rr16:NI = MakeRMInst(X86::MOVZX32rm16, FrameIndex, MI); break; + default: break; + } + } + if (NI) { + MI = MBB.insert(MBB.erase(MI), NI); + return true; + } else { + if (PrintFailedFusing) + std::cerr << "We failed to fuse: " << *MI; + return false; + } +} + //===----------------------------------------------------------------------===// // Stack Frame Processing methods //===----------------------------------------------------------------------===// @@ -93,14 +318,14 @@ return NoFPElim || MF.getFrameInfo()->hasVarSizedObjects(); } -int X86RegisterInfo::eliminateCallFramePseudoInstr(MachineFunction &MF, - MachineBasicBlock &MBB, - MachineBasicBlock::iterator &I) const { - MachineInstr *New = 0, *Old = *I;; +void X86RegisterInfo:: +eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) const { if (hasFP(MF)) { // If we have a frame pointer, turn the adjcallstackup instruction into a // 'sub ESP, ' and the adjcallstackdown instruction into 'add ESP, // ' + MachineInstr *Old = I; unsigned Amount = Old->getOperand(0).getImmedValue(); if (Amount != 0) { // We need to keep the stack aligned properly. To do this, we round the @@ -109,30 +334,28 @@ unsigned Align = MF.getTarget().getFrameInfo().getStackAlignment(); Amount = (Amount+Align-1)/Align*Align; + MachineInstr *New; if (Old->getOpcode() == X86::ADJCALLSTACKDOWN) { - New=BuildMI(X86::SUBri32, 2, X86::ESP).addReg(X86::ESP).addZImm(Amount); + New=BuildMI(X86::SUB32ri, 1, X86::ESP, MachineOperand::UseAndDef) + .addZImm(Amount); } else { assert(Old->getOpcode() == X86::ADJCALLSTACKUP); - New=BuildMI(X86::ADDri32, 2, X86::ESP).addReg(X86::ESP).addZImm(Amount); + New=BuildMI(X86::ADD32ri, 1, X86::ESP, MachineOperand::UseAndDef) + .addZImm(Amount); } + + // Replace the pseudo instruction with a new instruction... + MBB.insert(I, New); } } - if (New) { - *I = New; // Replace the pseudo instruction with a new instruction... - delete Old; - return 0; - } else { - I = MBB.erase(I);// Just delete the pseudo instruction... - delete Old; - return -1; - } + MBB.erase(I); } -int X86RegisterInfo::eliminateFrameIndex(MachineFunction &MF, - MachineBasicBlock::iterator &II) const { +void X86RegisterInfo::eliminateFrameIndex(MachineFunction &MF, + MachineBasicBlock::iterator II) const { unsigned i = 0; - MachineInstr &MI = **II; + MachineInstr &MI = *II; while (!MI.getOperand(i).isFrameIndex()) { ++i; assert(i < MI.getNumOperands() && "Instr doesn't have FrameIndex operand!"); @@ -150,85 +373,86 @@ if (!hasFP(MF)) Offset += MF.getFrameInfo()->getStackSize(); + else + Offset += 4; // Skip the saved EBP MI.SetMachineOperandConst(i+3, MachineOperand::MO_SignExtendedImmed, Offset); - return 0; } -int X86RegisterInfo::processFunctionBeforeFrameFinalized(MachineFunction &MF) - const { +void +X86RegisterInfo::processFunctionBeforeFrameFinalized(MachineFunction &MF) const{ if (hasFP(MF)) { // Create a frame entry for the EBP register that must be saved. - int FrameIdx = MF.getFrameInfo()->CreateStackObject(4, 4); - assert(FrameIdx == MF.getFrameInfo()->getObjectIndexEnd()-1 && - "Slot for EBP register must be last in order to be found!"); + int FrameIdx = MF.getFrameInfo()->CreateFixedObject(4, -8); + assert(FrameIdx == MF.getFrameInfo()->getObjectIndexBegin() && + "Slot for EBP register must be last in order to be found!"); } - return 0; } -int X86RegisterInfo::emitPrologue(MachineFunction &MF) const { +void X86RegisterInfo::emitPrologue(MachineFunction &MF) const { MachineBasicBlock &MBB = MF.front(); // Prolog goes in entry BB MachineBasicBlock::iterator MBBI = MBB.begin(); MachineFrameInfo *MFI = MF.getFrameInfo(); MachineInstr *MI; - unsigned oldSize = MBB.size(); // Get the number of bytes to allocate from the FrameInfo unsigned NumBytes = MFI->getStackSize(); if (hasFP(MF)) { // Get the offset of the stack slot for the EBP register... which is // guaranteed to be the last slot by processFunctionBeforeFrameFinalized. - int EBPOffset = MFI->getObjectOffset(MFI->getObjectIndexEnd()-1)+4; + int EBPOffset = MFI->getObjectOffset(MFI->getObjectIndexBegin())+4; if (NumBytes) { // adjust stack pointer: ESP -= numbytes - MI= BuildMI(X86::SUBri32, 2, X86::ESP).addReg(X86::ESP).addZImm(NumBytes); - MBBI = MBB.insert(MBBI, MI)+1; + MI= BuildMI(X86::SUB32ri, 1, X86::ESP, MachineOperand::UseAndDef) + .addZImm(NumBytes); + MBB.insert(MBBI, MI); } // Save EBP into the appropriate stack slot... - MI = addRegOffset(BuildMI(X86::MOVrm32, 5), // mov [ESP-], EBP + MI = addRegOffset(BuildMI(X86::MOV32mr, 5), // mov [ESP-], EBP X86::ESP, EBPOffset+NumBytes).addReg(X86::EBP); - MBBI = MBB.insert(MBBI, MI)+1; + MBB.insert(MBBI, MI); // Update EBP with the new base value... - if (NumBytes == 0) // mov EBP, ESP - MI = BuildMI(X86::MOVrr32, 2, X86::EBP).addReg(X86::ESP); + if (NumBytes == 4) // mov EBP, ESP + MI = BuildMI(X86::MOV32rr, 2, X86::EBP).addReg(X86::ESP); else // lea EBP, [ESP+StackSize] - MI = addRegOffset(BuildMI(X86::LEAr32, 5, X86::EBP), X86::ESP, NumBytes); + MI = addRegOffset(BuildMI(X86::LEA32r, 5, X86::EBP), X86::ESP,NumBytes-4); - MBBI = MBB.insert(MBBI, MI)+1; + MBB.insert(MBBI, MI); } else { - // When we have no frame pointer, we reserve argument space for call sites - // in the function immediately on entry to the current function. This - // eliminates the need for add/sub ESP brackets around call sites. - // - NumBytes += MFI->getMaxCallFrameSize(); - - // Round the size to a multiple of the alignment (don't forget the 4 byte - // offset though). - unsigned Align = MF.getTarget().getFrameInfo().getStackAlignment(); - NumBytes = ((NumBytes+4)+Align-1)/Align*Align - 4; + if (MFI->hasCalls()) { + // When we have no frame pointer, we reserve argument space for call sites + // in the function immediately on entry to the current function. This + // eliminates the need for add/sub ESP brackets around call sites. + // + NumBytes += MFI->getMaxCallFrameSize(); + + // Round the size to a multiple of the alignment (don't forget the 4 byte + // offset though). + unsigned Align = MF.getTarget().getFrameInfo().getStackAlignment(); + NumBytes = ((NumBytes+4)+Align-1)/Align*Align - 4; + } // Update frame info to pretend that this is part of the stack... MFI->setStackSize(NumBytes); if (NumBytes) { // adjust stack pointer: ESP -= numbytes - MI= BuildMI(X86::SUBri32, 2, X86::ESP).addReg(X86::ESP).addZImm(NumBytes); + MI= BuildMI(X86::SUB32ri, 1, X86::ESP, MachineOperand::UseAndDef) + .addZImm(NumBytes); MBB.insert(MBBI, MI); } } - return MBB.size() - oldSize; } -int X86RegisterInfo::emitEpilogue(MachineFunction &MF, - MachineBasicBlock &MBB) const { - unsigned oldSize = MBB.size(); +void X86RegisterInfo::emitEpilogue(MachineFunction &MF, + MachineBasicBlock &MBB) const { const MachineFrameInfo *MFI = MF.getFrameInfo(); - MachineBasicBlock::iterator MBBI = MBB.end()-1; + MachineBasicBlock::iterator MBBI = prior(MBB.end()); MachineInstr *MI; - assert((*MBBI)->getOpcode() == X86::RET && + assert(MBBI->getOpcode() == X86::RET && "Can only insert epilog into returning blocks"); if (hasFP(MF)) { @@ -237,30 +461,26 @@ int EBPOffset = MFI->getObjectOffset(MFI->getObjectIndexEnd()-1)+4; // mov ESP, EBP - MI = BuildMI(X86::MOVrr32, 1,X86::ESP).addReg(X86::EBP); - MBBI = 1+MBB.insert(MBBI, MI); + MI = BuildMI(X86::MOV32rr, 1,X86::ESP).addReg(X86::EBP); + MBB.insert(MBBI, MI); - // mov EBP, [ESP-] - MI = addRegOffset(BuildMI(X86::MOVmr32, 5, X86::EBP), X86::ESP, EBPOffset); - MBBI = 1+MBB.insert(MBBI, MI); + // pop EBP + MI = BuildMI(X86::POP32r, 0, X86::EBP); + MBB.insert(MBBI, MI); } else { // Get the number of bytes allocated from the FrameInfo... unsigned NumBytes = MFI->getStackSize(); if (NumBytes) { // adjust stack pointer back: ESP += numbytes - MI =BuildMI(X86::ADDri32, 2, X86::ESP).addReg(X86::ESP).addZImm(NumBytes); - MBBI = 1+MBB.insert(MBBI, MI); + MI =BuildMI(X86::ADD32ri, 1, X86::ESP, MachineOperand::UseAndDef) + .addZImm(NumBytes); + MBB.insert(MBBI, MI); } } - return MBB.size() - oldSize; } -} // End llvm namespace - #include "X86GenRegisterInfo.inc" -namespace llvm { - const TargetRegisterClass* X86RegisterInfo::getRegClassForType(const Type* Ty) const { switch (Ty->getPrimitiveID()) { @@ -280,5 +500,3 @@ case Type::DoubleTyID: return &RFPInstance; } } - -} // End llvm namespace Index: llvm/lib/Target/X86/X86RegisterInfo.h diff -u llvm/lib/Target/X86/X86RegisterInfo.h:1.18 llvm/lib/Target/X86/X86RegisterInfo.h:1.18.4.1 --- llvm/lib/Target/X86/X86RegisterInfo.h:1.18 Tue Nov 11 16:41:33 2003 +++ llvm/lib/Target/X86/X86RegisterInfo.h Mon Mar 1 17:58:15 2004 @@ -28,30 +28,41 @@ /// Code Generation virtual methods... int storeRegToStackSlot(MachineBasicBlock &MBB, - MachineBasicBlock::iterator &MBBI, + MachineBasicBlock::iterator MI, unsigned SrcReg, int FrameIndex, const TargetRegisterClass *RC) const; int loadRegFromStackSlot(MachineBasicBlock &MBB, - MachineBasicBlock::iterator &MBBI, + MachineBasicBlock::iterator MI, unsigned DestReg, int FrameIndex, const TargetRegisterClass *RC) const; - int copyRegToReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator &MBBI, + int copyRegToReg(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, unsigned DestReg, unsigned SrcReg, const TargetRegisterClass *RC) const; - int eliminateCallFramePseudoInstr(MachineFunction &MF, - MachineBasicBlock &MBB, - MachineBasicBlock::iterator &I) const; + /// foldMemoryOperand - If this target supports it, fold a load or store of + /// the specified stack slot into the specified machine instruction for the + /// specified operand. If this is possible, the target should perform the + /// folding and return true, otherwise it should return false. If it folds + /// the instruction, it is likely that the MachineInstruction the iterator + /// references has been changed. + virtual bool foldMemoryOperand(MachineBasicBlock::iterator &MI,unsigned OpNum, + int FrameIndex) const; - int eliminateFrameIndex(MachineFunction &MF, - MachineBasicBlock::iterator &II) const; - int processFunctionBeforeFrameFinalized(MachineFunction &MF) const; + void eliminateCallFramePseudoInstr(MachineFunction &MF, + MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI) const; - int emitPrologue(MachineFunction &MF) const; - int emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const; + void eliminateFrameIndex(MachineFunction &MF, + MachineBasicBlock::iterator MI) const; + + void processFunctionBeforeFrameFinalized(MachineFunction &MF) const; + + void emitPrologue(MachineFunction &MF) const; + void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const; }; } // End llvm namespace Index: llvm/lib/Target/X86/X86RegisterInfo.td diff -u llvm/lib/Target/X86/X86RegisterInfo.td:1.8 llvm/lib/Target/X86/X86RegisterInfo.td:1.8.6.1 --- llvm/lib/Target/X86/X86RegisterInfo.td:1.8 Tue Oct 21 10:17:13 2003 +++ llvm/lib/Target/X86/X86RegisterInfo.td Mon Mar 1 17:58:15 2004 @@ -76,8 +76,8 @@ // top-level register classes. The order specified in the register list is // implicitly defined to be the register allocation order. // -def R8 : RegisterClass; -def R16 : RegisterClass { +def R8 : RegisterClass; +def R16 : RegisterClass { let Methods = [{ iterator allocation_order_end(MachineFunction &MF) const { if (hasFP(MF)) // Does the function dedicate EBP to being a frame ptr? @@ -88,7 +88,7 @@ }]; } -def R32 : RegisterClass { +def R32 : RegisterClass { let Methods = [{ iterator allocation_order_end(MachineFunction &MF) const { if (hasFP(MF)) // Does the function dedicate EBP to being a frame ptr? Index: llvm/lib/Target/X86/X86TargetMachine.cpp diff -u llvm/lib/Target/X86/X86TargetMachine.cpp:1.44 llvm/lib/Target/X86/X86TargetMachine.cpp:1.44.2.1 --- llvm/lib/Target/X86/X86TargetMachine.cpp:1.44 Sun Dec 28 15:23:38 2003 +++ llvm/lib/Target/X86/X86TargetMachine.cpp Mon Mar 1 17:58:15 2004 @@ -32,6 +32,9 @@ cl::opt NoSSAPeephole("disable-ssa-peephole", cl::init(true), cl::desc("Disable the ssa-based peephole optimizer " "(defaults to disabled)")); + cl::opt DisableOutput("disable-x86-llc-output", cl::Hidden, + cl::desc("Disable the X86 asm printer, for use " + "when profiling the code generator.")); } // allocateX86TargetMachine - Allocate and return a subclass of TargetMachine @@ -56,9 +59,6 @@ // does to emit statically compiled machine code. bool X86TargetMachine::addPassesToEmitAssembly(PassManager &PM, std::ostream &Out) { - // FIXME: Implement the switch instruction in the instruction selector! - PM.add(createLowerSwitchPass()); - // FIXME: Implement the invoke/unwind instructions! PM.add(createLowerInvokePass()); @@ -66,6 +66,9 @@ // unreachable basic blocks. PM.add(createCFGSimplificationPass()); + // FIXME: Implement the switch instruction in the instruction selector! + PM.add(createLowerSwitchPass()); + if (NoPatternISel) PM.add(createX86SimpleInstructionSelector(*this)); else @@ -77,18 +80,18 @@ // Print the instruction selected machine code... if (PrintCode) - PM.add(createMachineFunctionPrinterPass()); + PM.add(createMachineFunctionPrinterPass(&std::cerr)); // Perform register allocation to convert to a concrete x86 representation PM.add(createRegisterAllocator()); if (PrintCode) - PM.add(createMachineFunctionPrinterPass()); + PM.add(createMachineFunctionPrinterPass(&std::cerr)); PM.add(createX86FloatingPointStackifierPass()); if (PrintCode) - PM.add(createMachineFunctionPrinterPass()); + PM.add(createMachineFunctionPrinterPass(&std::cerr)); // Insert prolog/epilog code. Eliminate abstract frame index references... PM.add(createPrologEpilogCodeInserter()); @@ -98,7 +101,8 @@ if (PrintCode) // Print the register-allocated code PM.add(createX86CodePrinterPass(std::cerr, *this)); - PM.add(createX86CodePrinterPass(Out, *this)); + if (!DisableOutput) + PM.add(createX86CodePrinterPass(Out, *this)); // Delete machine code for this function PM.add(createMachineCodeDeleter()); @@ -111,8 +115,6 @@ /// not supported for this target. /// void X86JITInfo::addPassesToJITCompile(FunctionPassManager &PM) { - // FIXME: Implement the switch instruction in the instruction selector! - PM.add(createLowerSwitchPass()); // FIXME: Implement the invoke/unwind instructions! PM.add(createLowerInvokePass()); @@ -121,6 +123,9 @@ // unreachable basic blocks. PM.add(createCFGSimplificationPass()); + // FIXME: Implement the switch instruction in the instruction selector! + PM.add(createLowerSwitchPass()); + if (NoPatternISel) PM.add(createX86SimpleInstructionSelector(TM)); else @@ -134,18 +139,18 @@ // Print the instruction selected machine code... if (PrintCode) - PM.add(createMachineFunctionPrinterPass()); + PM.add(createMachineFunctionPrinterPass(&std::cerr)); // Perform register allocation to convert to a concrete x86 representation PM.add(createRegisterAllocator()); if (PrintCode) - PM.add(createMachineFunctionPrinterPass()); + PM.add(createMachineFunctionPrinterPass(&std::cerr)); PM.add(createX86FloatingPointStackifierPass()); if (PrintCode) - PM.add(createMachineFunctionPrinterPass()); + PM.add(createMachineFunctionPrinterPass(&std::cerr)); // Insert prolog/epilog code. Eliminate abstract frame index references... PM.add(createPrologEpilogCodeInserter()); Index: llvm/lib/Target/X86/X86TargetMachine.h diff -u llvm/lib/Target/X86/X86TargetMachine.h:1.21 llvm/lib/Target/X86/X86TargetMachine.h:1.21.2.1 --- llvm/lib/Target/X86/X86TargetMachine.h:1.21 Sun Dec 28 15:23:38 2003 +++ llvm/lib/Target/X86/X86TargetMachine.h Mon Mar 1 17:58:15 2004 @@ -32,18 +32,14 @@ virtual const X86InstrInfo &getInstrInfo() const { return InstrInfo; } virtual const TargetFrameInfo &getFrameInfo() const { return FrameInfo; } - virtual const MRegisterInfo *getRegisterInfo() const { + virtual TargetJITInfo *getJITInfo() { return &JITInfo; } + virtual const MRegisterInfo *getRegisterInfo() const { return &InstrInfo.getRegisterInfo(); } - virtual TargetJITInfo *getJITInfo() { - return &JITInfo; - } - - - virtual const TargetSchedInfo &getSchedInfo() const { abort(); } - virtual const TargetRegInfo &getRegInfo() const { abort(); } - virtual const TargetCacheInfo &getCacheInfo() const { abort(); } + // deprecated interfaces + virtual const TargetSchedInfo &getSchedInfo() const { abort(); } + virtual const TargetRegInfo &getRegInfo() const { abort(); } /// addPassesToEmitMachineCode - Add passes to the specified pass manager to /// get machine code emitted. This uses a MachineCodeEmitter object to handle From brukman at cs.uiuc.edu Mon Mar 1 18:06:18 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Mar 1 18:06:18 2004 Subject: [llvm-commits] [parallel] CVS: llvm/projects/Stacker/lib/compiler/StackerCompiler.cpp Message-ID: <200403012358.RAA04148@zion.cs.uiuc.edu> Changes in directory llvm/projects/Stacker/lib/compiler: StackerCompiler.cpp updated: 1.3 -> 1.3.4.1 --- Log message: Merge from trunk --- Diffs of the changes: (+7 -7) Index: llvm/projects/Stacker/lib/compiler/StackerCompiler.cpp diff -u llvm/projects/Stacker/lib/compiler/StackerCompiler.cpp:1.3 llvm/projects/Stacker/lib/compiler/StackerCompiler.cpp:1.3.4.1 --- llvm/projects/Stacker/lib/compiler/StackerCompiler.cpp:1.3 Sun Nov 23 20:57:25 2003 +++ llvm/projects/Stacker/lib/compiler/StackerCompiler.cpp Mon Mar 1 17:58:28 2004 @@ -173,7 +173,7 @@ TheExit = new Function( exit_type, GlobalValue::ExternalLinkage, "exit", TheModule); - ConstantArray* str_format = ConstantArray::get("%s"); + Constant* str_format = ConstantArray::get("%s"); StrFormat = new GlobalVariable( /*type=*/ArrayType::get( Type::SByteTy, 3 ), /*isConstant=*/true, @@ -183,7 +183,7 @@ /*parent=*/TheModule ); - ConstantArray* in_str_format = ConstantArray::get(" %as"); + Constant* in_str_format = ConstantArray::get(" %as"); InStrFormat = new GlobalVariable( /*type=*/ArrayType::get( Type::SByteTy, 5 ), /*isConstant=*/true, @@ -193,7 +193,7 @@ /*parent=*/TheModule ); - ConstantArray* num_format = ConstantArray::get("%d"); + Constant* num_format = ConstantArray::get("%d"); NumFormat = new GlobalVariable( /*type=*/ArrayType::get( Type::SByteTy, 3 ), /*isConstant=*/true, @@ -203,7 +203,7 @@ /*parent=*/TheModule ); - ConstantArray* in_num_format = ConstantArray::get(" %d"); + Constant* in_num_format = ConstantArray::get(" %d"); InNumFormat = new GlobalVariable( /*type=*/ArrayType::get( Type::SByteTy, 4 ), /*isConstant=*/true, @@ -213,7 +213,7 @@ /*parent=*/TheModule ); - ConstantArray* chr_format = ConstantArray::get("%c"); + Constant* chr_format = ConstantArray::get("%c"); ChrFormat = new GlobalVariable( /*type=*/ArrayType::get( Type::SByteTy, 3 ), /*isConstant=*/true, @@ -223,7 +223,7 @@ /*parent=*/TheModule ); - ConstantArray* in_chr_format = ConstantArray::get(" %c"); + Constant* in_chr_format = ConstantArray::get(" %c"); InChrFormat = new GlobalVariable( /*type=*/ArrayType::get( Type::SByteTy, 4 ), /*isConstant=*/true, @@ -413,7 +413,7 @@ ArrayType* char_array = ArrayType::get( Type::SByteTy, len + 1 ); // Create an initializer for the value - ConstantArray* initVal = ConstantArray::get( value ); + Constant* initVal = ConstantArray::get( value ); // Create an internal linkage global variable to hold the constant. GlobalVariable* strconst = new GlobalVariable( From brukman at cs.uiuc.edu Mon Mar 1 18:06:33 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Mar 1 18:06:33 2004 Subject: [llvm-commits] [parallel] CVS: llvm/lib/CodeGen/MachineBasicBlock.cpp PhysRegTracker.h VirtRegMap.cpp VirtRegMap.h LiveIntervals.cpp LiveIntervals.h LiveVariables.cpp MachineCodeEmitter.cpp MachineCodeForInstruction.cpp MachineFunction.cpp MachineInstr.cpp MachineInstrAnnot.cpp PHIElimination.cpp Passes.cpp PrologEpilogInserter.cpp RegAllocLinearScan.cpp RegAllocLocal.cpp RegAllocSimple.cpp TwoAddressInstructionPass.cpp Message-ID: <200403012358.RAA04103@zion.cs.uiuc.edu> Changes in directory llvm/lib/CodeGen: MachineBasicBlock.cpp added (r1.9.2.1) PhysRegTracker.h added (r1.4.2.1) VirtRegMap.cpp added (r1.8.2.1) VirtRegMap.h added (r1.9.2.1) LiveIntervals.cpp updated: 1.28 -> 1.28.2.1 LiveIntervals.h updated: 1.11 -> 1.11.2.1 LiveVariables.cpp updated: 1.15 -> 1.15.2.1 MachineCodeEmitter.cpp updated: 1.14 -> 1.14.4.1 MachineCodeForInstruction.cpp updated: 1.11 -> 1.11.2.1 MachineFunction.cpp updated: 1.46 -> 1.46.2.1 MachineInstr.cpp updated: 1.82 -> 1.82.2.1 MachineInstrAnnot.cpp updated: 1.10 -> 1.10.4.1 PHIElimination.cpp updated: 1.14 -> 1.14.2.1 Passes.cpp updated: 1.5 -> 1.5.2.1 PrologEpilogInserter.cpp updated: 1.16 -> 1.16.2.1 RegAllocLinearScan.cpp updated: 1.31 -> 1.31.2.1 RegAllocLocal.cpp updated: 1.37 -> 1.37.2.1 RegAllocSimple.cpp updated: 1.47 -> 1.47.2.1 TwoAddressInstructionPass.cpp updated: 1.6 -> 1.6.2.1 --- Log message: Merge from trunk --- Diffs of the changes: (+2022 -1250) Index: llvm/lib/CodeGen/MachineBasicBlock.cpp diff -c /dev/null llvm/lib/CodeGen/MachineBasicBlock.cpp:1.9.2.1 *** /dev/null Mon Mar 1 17:58:27 2004 --- llvm/lib/CodeGen/MachineBasicBlock.cpp Mon Mar 1 17:58:13 2004 *************** *** 0 **** --- 1,83 ---- + //===-- llvm/CodeGen/MachineBasicBlock.cpp ----------------------*- C++ -*-===// + // + // The LLVM Compiler Infrastructure + // + // This file was developed by the LLVM research group and is distributed under + // the University of Illinois Open Source License. See LICENSE.TXT for details. + // + //===----------------------------------------------------------------------===// + // + // Collect the sequence of machine instructions for a basic block. + // + //===----------------------------------------------------------------------===// + + #include "llvm/CodeGen/MachineBasicBlock.h" + #include "llvm/BasicBlock.h" + #include "llvm/CodeGen/MachineFunction.h" + #include "llvm/CodeGen/MachineInstr.h" + #include "llvm/Target/TargetInstrInfo.h" + #include "llvm/Target/TargetMachine.h" + #include "Support/LeakDetector.h" + using namespace llvm; + + const MachineFunction *MachineBasicBlock::getParent() const { + // Get the parent by getting the Function parent of the basic block, and + // getting the MachineFunction from it. + return &MachineFunction::get(getBasicBlock()->getParent()); + } + + + MachineInstr* ilist_traits::createNode() + { + MachineInstr* dummy = new MachineInstr(0, 0); + LeakDetector::removeGarbageObject(dummy); + return dummy; + } + + void ilist_traits::addNodeToList(MachineInstr* N) + { + assert(N->parent == 0 && "machine instruction already in a basic block"); + N->parent = parent; + LeakDetector::removeGarbageObject(N); + } + + void ilist_traits::removeNodeFromList(MachineInstr* N) + { + assert(N->parent != 0 && "machine instruction not in a basic block"); + N->parent = 0; + LeakDetector::addGarbageObject(N); + } + + void ilist_traits::transferNodesFromList( + iplist >& toList, + ilist_iterator first, + ilist_iterator last) + { + if (parent != toList.parent) + for (; first != last; ++first) + first->parent = toList.parent; + } + + MachineBasicBlock::iterator MachineBasicBlock::getFirstTerminator() + { + const TargetInstrInfo& TII = getParent()->getTarget().getInstrInfo(); + iterator I = end(); + while (I != begin() && TII.isTerminatorInstr((--I)->getOpcode())); + if (I != end() && !TII.isTerminatorInstr(I->getOpcode())) ++I; + return I; + } + + void MachineBasicBlock::dump() const + { + print(std::cerr); + } + + void MachineBasicBlock::print(std::ostream &OS) const + { + const BasicBlock *LBB = getBasicBlock(); + OS << "\n" << LBB->getName() << " (" << (const void*)LBB << "):\n"; + for (const_iterator I = begin(); I != end(); ++I) { + OS << "\t"; + I->print(OS, MachineFunction::get(LBB->getParent()).getTarget()); + } + } Index: llvm/lib/CodeGen/PhysRegTracker.h diff -c /dev/null llvm/lib/CodeGen/PhysRegTracker.h:1.4.2.1 *** /dev/null Mon Mar 1 17:58:27 2004 --- llvm/lib/CodeGen/PhysRegTracker.h Mon Mar 1 17:58:13 2004 *************** *** 0 **** --- 1,73 ---- + //===-- llvm/CodeGen/PhysRegTracker.h - Physical Register Tracker -*- C++ -*-=// + // + // The LLVM Compiler Infrastructure + // + // This file was developed by the LLVM research group and is distributed under + // the University of Illinois Open Source License. See LICENSE.TXT for details. + // + //===----------------------------------------------------------------------===// + // + // This file implements a physical register tracker. The tracker + // tracks physical register usage through addRegUse and + // delRegUse. isRegAvail checks if a physical register is available or + // not taking into consideration register aliases. + // + //===----------------------------------------------------------------------===// + + #ifndef LLVM_CODEGEN_PHYSREGTRACKER_H + #define LLVM_CODEGEN_PHYSREGTRACKER_H + + #include "llvm/Target/MRegisterInfo.h" + + namespace llvm { + + class PhysRegTracker { + const MRegisterInfo* mri_; + std::vector regUse_; + + public: + PhysRegTracker(const MRegisterInfo& mri) + : mri_(&mri), + regUse_(mri_->getNumRegs(), 0) { + } + + PhysRegTracker(const PhysRegTracker& rhs) + : mri_(rhs.mri_), + regUse_(rhs.regUse_) { + } + + const PhysRegTracker& operator=(const PhysRegTracker& rhs) { + mri_ = rhs.mri_; + regUse_ = rhs.regUse_; + return *this; + } + + void addRegUse(unsigned physReg) { + assert(MRegisterInfo::isPhysicalRegister(physReg) && + "should be physical register!"); + ++regUse_[physReg]; + for (const unsigned* as = mri_->getAliasSet(physReg); *as; ++as) + ++regUse_[*as]; + } + + void delRegUse(unsigned physReg) { + assert(MRegisterInfo::isPhysicalRegister(physReg) && + "should be physical register!"); + assert(regUse_[physReg] != 0); + --regUse_[physReg]; + for (const unsigned* as = mri_->getAliasSet(physReg); *as; ++as) { + assert(regUse_[*as] != 0); + --regUse_[*as]; + } + } + + bool isRegAvail(unsigned physReg) const { + assert(MRegisterInfo::isPhysicalRegister(physReg) && + "should be physical register!"); + return regUse_[physReg] == 0; + } + }; + + } // End llvm namespace + + #endif Index: llvm/lib/CodeGen/VirtRegMap.cpp diff -c /dev/null llvm/lib/CodeGen/VirtRegMap.cpp:1.8.2.1 *** /dev/null Mon Mar 1 17:58:28 2004 --- llvm/lib/CodeGen/VirtRegMap.cpp Mon Mar 1 17:58:13 2004 *************** *** 0 **** --- 1,285 ---- + //===-- llvm/CodeGen/VirtRegMap.cpp - Virtual Register Map ----------------===// + // + // The LLVM Compiler Infrastructure + // + // This file was developed by the LLVM research group and is distributed under + // the University of Illinois Open Source License. See LICENSE.TXT for details. + // + //===----------------------------------------------------------------------===// + // + // This file implements the virtual register map. It also implements + // the eliminateVirtRegs() function that given a virtual register map + // and a machine function it eliminates all virtual references by + // replacing them with physical register references and adds spill + // code as necessary. + // + //===----------------------------------------------------------------------===// + + #define DEBUG_TYPE "regalloc" + #include "VirtRegMap.h" + #include "llvm/Function.h" + #include "llvm/CodeGen/MachineFrameInfo.h" + #include "llvm/CodeGen/MachineInstr.h" + #include "llvm/Target/TargetMachine.h" + #include "llvm/Target/TargetInstrInfo.h" + #include "Support/CommandLine.h" + #include "Support/Debug.h" + #include "Support/DenseMap.h" + #include "Support/Statistic.h" + #include "Support/STLExtras.h" + #include + + using namespace llvm; + + namespace { + Statistic<> numSpills("spiller", "Number of register spills"); + Statistic<> numStores("spiller", "Number of stores added"); + Statistic<> numLoads ("spiller", "Number of loads added"); + + enum SpillerName { local }; + + cl::opt + SpillerOpt("spiller", + cl::desc("Spiller to use: (default: local)"), + cl::Prefix, + cl::values(clEnumVal(local, " local spiller"), + 0), + cl::init(local)); + } + + int VirtRegMap::assignVirt2StackSlot(unsigned virtReg) + { + assert(MRegisterInfo::isVirtualRegister(virtReg)); + assert(v2ssMap_[virtReg] == NO_STACK_SLOT && + "attempt to assign stack slot to already spilled register"); + const TargetRegisterClass* rc = + mf_->getSSARegMap()->getRegClass(virtReg); + int frameIndex = mf_->getFrameInfo()->CreateStackObject(rc); + v2ssMap_[virtReg] = frameIndex; + ++numSpills; + return frameIndex; + } + + void VirtRegMap::virtFolded(unsigned virtReg, + MachineInstr* oldMI, + MachineInstr* newMI) + { + // move previous memory references folded to new instruction + MI2VirtMap::iterator i, e; + std::vector regs; + for (tie(i, e) = mi2vMap_.equal_range(oldMI); i != e; ) { + regs.push_back(i->second); + mi2vMap_.erase(i++); + } + for (unsigned i = 0, e = regs.size(); i != e; ++i) + mi2vMap_.insert(std::make_pair(newMI, i)); + + // add new memory reference + mi2vMap_.insert(std::make_pair(newMI, virtReg)); + } + + std::ostream& llvm::operator<<(std::ostream& os, const VirtRegMap& vrm) + { + const MRegisterInfo* mri = vrm.mf_->getTarget().getRegisterInfo(); + + std::cerr << "********** REGISTER MAP **********\n"; + for (unsigned i = MRegisterInfo::FirstVirtualRegister, + e = vrm.mf_->getSSARegMap()->getLastVirtReg(); i <= e; ++i) { + if (vrm.v2pMap_[i] != VirtRegMap::NO_PHYS_REG) + std::cerr << "[reg" << i << " -> " + << mri->getName(vrm.v2pMap_[i]) << "]\n"; + } + for (unsigned i = MRegisterInfo::FirstVirtualRegister, + e = vrm.mf_->getSSARegMap()->getLastVirtReg(); i <= e; ++i) { + if (vrm.v2ssMap_[i] != VirtRegMap::NO_STACK_SLOT) + std::cerr << "[reg" << i << " -> fi#" + << vrm.v2ssMap_[i] << "]\n"; + } + return std::cerr << '\n'; + } + + Spiller::~Spiller() + { + + } + + namespace { + + class LocalSpiller : public Spiller { + typedef std::vector Phys2VirtMap; + typedef std::vector PhysFlag; + typedef DenseMap Virt2MI; + + MachineFunction* mf_; + const TargetMachine* tm_; + const TargetInstrInfo* tii_; + const MRegisterInfo* mri_; + const VirtRegMap* vrm_; + Phys2VirtMap p2vMap_; + PhysFlag dirty_; + Virt2MI lastDef_; + + public: + bool runOnMachineFunction(MachineFunction& mf, const VirtRegMap& vrm) { + mf_ = &mf; + tm_ = &mf_->getTarget(); + tii_ = &tm_->getInstrInfo(); + mri_ = tm_->getRegisterInfo(); + vrm_ = &vrm; + p2vMap_.assign(mri_->getNumRegs(), 0); + dirty_.assign(mri_->getNumRegs(), false); + + DEBUG(std::cerr << "********** REWRITE MACHINE CODE **********\n"); + DEBUG(std::cerr << "********** Function: " + << mf_->getFunction()->getName() << '\n'); + + for (MachineFunction::iterator mbbi = mf_->begin(), + mbbe = mf_->end(); mbbi != mbbe; ++mbbi) { + lastDef_.grow(mf_->getSSARegMap()->getLastVirtReg()); + DEBUG(std::cerr << mbbi->getBasicBlock()->getName() << ":\n"); + eliminateVirtRegsInMbb(*mbbi); + // clear map, dirty flag and last ref + p2vMap_.assign(p2vMap_.size(), 0); + dirty_.assign(dirty_.size(), false); + lastDef_.clear(); + } + return true; + } + + private: + void vacateJustPhysReg(MachineBasicBlock& mbb, + MachineBasicBlock::iterator mii, + unsigned physReg) { + unsigned virtReg = p2vMap_[physReg]; + if (dirty_[physReg] && vrm_->hasStackSlot(virtReg)) { + assert(lastDef_[virtReg] && "virtual register is mapped " + "to a register and but was not defined!"); + MachineBasicBlock::iterator lastDef = lastDef_[virtReg]; + MachineBasicBlock::iterator nextLastRef = next(lastDef); + mri_->storeRegToStackSlot(*lastDef->getParent(), + nextLastRef, + physReg, + vrm_->getStackSlot(virtReg), + mri_->getRegClass(physReg)); + ++numStores; + DEBUG(std::cerr << "added: "; + prior(nextLastRef)->print(std::cerr, *tm_); + std::cerr << "after: "; + lastDef->print(std::cerr, *tm_)); + lastDef_[virtReg] = 0; + } + p2vMap_[physReg] = 0; + dirty_[physReg] = false; + } + + void vacatePhysReg(MachineBasicBlock& mbb, + MachineBasicBlock::iterator mii, + unsigned physReg) { + vacateJustPhysReg(mbb, mii, physReg); + for (const unsigned* as = mri_->getAliasSet(physReg); *as; ++as) + vacateJustPhysReg(mbb, mii, *as); + } + + void handleUse(MachineBasicBlock& mbb, + MachineBasicBlock::iterator mii, + unsigned virtReg, + unsigned physReg) { + // check if we are replacing a previous mapping + if (p2vMap_[physReg] != virtReg) { + vacatePhysReg(mbb, mii, physReg); + p2vMap_[physReg] = virtReg; + // load if necessary + if (vrm_->hasStackSlot(virtReg)) { + mri_->loadRegFromStackSlot(mbb, mii, physReg, + vrm_->getStackSlot(virtReg), + mri_->getRegClass(physReg)); + ++numLoads; + DEBUG(std::cerr << "added: "; + prior(mii)->print(std::cerr, *tm_)); + lastDef_[virtReg] = mii; + } + } + } + + void handleDef(MachineBasicBlock& mbb, + MachineBasicBlock::iterator mii, + unsigned virtReg, + unsigned physReg) { + // check if we are replacing a previous mapping + if (p2vMap_[physReg] != virtReg) + vacatePhysReg(mbb, mii, physReg); + + p2vMap_[physReg] = virtReg; + dirty_[physReg] = true; + lastDef_[virtReg] = mii; + } + + void eliminateVirtRegsInMbb(MachineBasicBlock& mbb) { + for (MachineBasicBlock::iterator mii = mbb.begin(), + mie = mbb.end(); mii != mie; ++mii) { + + // if we have references to memory operands make sure + // we clear all physical registers that may contain + // the value of the spilled virtual register + VirtRegMap::MI2VirtMap::const_iterator i, e; + for (tie(i, e) = vrm_->getFoldedVirts(mii); i != e; ++i) { + unsigned physReg = vrm_->getPhys(i->second); + if (physReg) vacateJustPhysReg(mbb, mii, physReg); + } + + // rewrite all used operands + for (unsigned i = 0, e = mii->getNumOperands(); i != e; ++i) { + MachineOperand& op = mii->getOperand(i); + if (op.isRegister() && op.getReg() && op.isUse() && + MRegisterInfo::isVirtualRegister(op.getReg())) { + unsigned virtReg = op.getReg(); + unsigned physReg = vrm_->getPhys(virtReg); + handleUse(mbb, mii, virtReg, physReg); + mii->SetMachineOperandReg(i, physReg); + // mark as dirty if this is def&use + if (op.isDef()) { + dirty_[physReg] = true; + lastDef_[virtReg] = mii; + } + } + } + + // spill implicit defs + const TargetInstrDescriptor& tid = tii_->get(mii->getOpcode()); + for (const unsigned* id = tid.ImplicitDefs; *id; ++id) + vacatePhysReg(mbb, mii, *id); + + // rewrite def operands (def&use was handled with the + // uses so don't check for those here) + for (unsigned i = 0, e = mii->getNumOperands(); i != e; ++i) { + MachineOperand& op = mii->getOperand(i); + if (op.isRegister() && op.getReg() && !op.isUse()) + if (MRegisterInfo::isPhysicalRegister(op.getReg())) + vacatePhysReg(mbb, mii, op.getReg()); + else { + unsigned physReg = vrm_->getPhys(op.getReg()); + handleDef(mbb, mii, op.getReg(), physReg); + mii->SetMachineOperandReg(i, physReg); + } + } + + DEBUG(std::cerr << '\t'; mii->print(std::cerr, *tm_)); + } + + for (unsigned i = 1, e = p2vMap_.size(); i != e; ++i) + vacateJustPhysReg(mbb, mbb.getFirstTerminator(), i); + + } + }; + } + + llvm::Spiller* llvm::createSpiller() + { + switch (SpillerOpt) { + default: + std::cerr << "no spiller selected"; + abort(); + case local: + return new LocalSpiller(); + } + } Index: llvm/lib/CodeGen/VirtRegMap.h diff -c /dev/null llvm/lib/CodeGen/VirtRegMap.h:1.9.2.1 *** /dev/null Mon Mar 1 17:58:28 2004 --- llvm/lib/CodeGen/VirtRegMap.h Mon Mar 1 17:58:13 2004 *************** *** 0 **** --- 1,122 ---- + //===-- llvm/CodeGen/VirtRegMap.h - Virtual Register Map -*- C++ -*--------===// + // + // The LLVM Compiler Infrastructure + // + // This file was developed by the LLVM research group and is distributed under + // the University of Illinois Open Source License. See LICENSE.TXT for details. + // + //===----------------------------------------------------------------------===// + // + // This file implements a virtual register map. This maps virtual + // registers to physical registers and virtual registers to stack + // slots. It is created and updated by a register allocator and then + // used by a machine code rewriter that adds spill code and rewrites + // virtual into physical register references. + // + //===----------------------------------------------------------------------===// + + #ifndef LLVM_CODEGEN_VIRTREGMAP_H + #define LLVM_CODEGEN_VIRTREGMAP_H + + #include "llvm/CodeGen/MachineFunction.h" + #include "llvm/CodeGen/SSARegMap.h" + #include "Support/DenseMap.h" + #include + #include + + namespace llvm { + + class MachineInstr; + + class VirtRegMap { + public: + typedef DenseMap Virt2PhysMap; + typedef DenseMap Virt2StackSlotMap; + typedef std::multimap MI2VirtMap; + + private: + MachineFunction* mf_; + Virt2PhysMap v2pMap_; + Virt2StackSlotMap v2ssMap_; + MI2VirtMap mi2vMap_; + + // do not implement + VirtRegMap(const VirtRegMap& rhs); + const VirtRegMap& operator=(const VirtRegMap& rhs); + + enum { + NO_PHYS_REG = 0, + NO_STACK_SLOT = INT_MAX + }; + + public: + VirtRegMap(MachineFunction& mf) + : mf_(&mf), + v2pMap_(NO_PHYS_REG), + v2ssMap_(NO_STACK_SLOT) { + v2pMap_.grow(mf.getSSARegMap()->getLastVirtReg()); + v2ssMap_.grow(mf.getSSARegMap()->getLastVirtReg()); + } + + bool hasPhys(unsigned virtReg) const { + return getPhys(virtReg) != NO_PHYS_REG; + } + + unsigned getPhys(unsigned virtReg) const { + assert(MRegisterInfo::isVirtualRegister(virtReg)); + return v2pMap_[virtReg]; + } + + void assignVirt2Phys(unsigned virtReg, unsigned physReg) { + assert(MRegisterInfo::isVirtualRegister(virtReg) && + MRegisterInfo::isPhysicalRegister(physReg)); + assert(v2pMap_[virtReg] == NO_PHYS_REG && + "attempt to assign physical register to already mapped " + "virtual register"); + v2pMap_[virtReg] = physReg; + } + + void clearVirt(unsigned virtReg) { + assert(MRegisterInfo::isVirtualRegister(virtReg)); + assert(v2pMap_[virtReg] != NO_PHYS_REG && + "attempt to clear a not assigned virtual register"); + v2pMap_[virtReg] = NO_PHYS_REG; + } + + bool hasStackSlot(unsigned virtReg) const { + return getStackSlot(virtReg) != NO_STACK_SLOT; + } + + int getStackSlot(unsigned virtReg) const { + assert(MRegisterInfo::isVirtualRegister(virtReg)); + return v2ssMap_[virtReg]; + } + + int assignVirt2StackSlot(unsigned virtReg); + + void virtFolded(unsigned virtReg, + MachineInstr* oldMI, + MachineInstr* newMI); + + std::pair + getFoldedVirts(MachineInstr* MI) const { + return mi2vMap_.equal_range(MI); + } + + friend std::ostream& operator<<(std::ostream& os, const VirtRegMap& li); + }; + + std::ostream& operator<<(std::ostream& os, const VirtRegMap& li); + + struct Spiller { + virtual ~Spiller(); + + virtual bool runOnMachineFunction(MachineFunction& mf, const VirtRegMap& vrm) = 0; + + }; + + Spiller* createSpiller(); + + } // End llvm namespace + + #endif Index: llvm/lib/CodeGen/LiveIntervals.cpp diff -u llvm/lib/CodeGen/LiveIntervals.cpp:1.28 llvm/lib/CodeGen/LiveIntervals.cpp:1.28.2.1 --- llvm/lib/CodeGen/LiveIntervals.cpp:1.28 Fri Jan 16 10:23:23 2004 +++ llvm/lib/CodeGen/LiveIntervals.cpp Mon Mar 1 17:58:13 2004 @@ -16,23 +16,22 @@ //===----------------------------------------------------------------------===// #define DEBUG_TYPE "liveintervals" -#include "llvm/CodeGen/LiveIntervals.h" -#include "llvm/Function.h" +#include "LiveIntervals.h" #include "llvm/Analysis/LoopInfo.h" #include "llvm/CodeGen/LiveVariables.h" #include "llvm/CodeGen/MachineFrameInfo.h" -#include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/Passes.h" #include "llvm/CodeGen/SSARegMap.h" #include "llvm/Target/MRegisterInfo.h" #include "llvm/Target/TargetInstrInfo.h" #include "llvm/Target/TargetMachine.h" -#include "llvm/Target/TargetRegInfo.h" #include "llvm/Support/CFG.h" +#include "Support/CommandLine.h" #include "Support/Debug.h" -#include "Support/DepthFirstIterator.h" #include "Support/Statistic.h" +#include "Support/STLExtras.h" +#include "VirtRegMap.h" #include #include #include @@ -43,7 +42,25 @@ RegisterAnalysis X("liveintervals", "Live Interval Analysis"); - Statistic<> numIntervals("liveintervals", "Number of intervals"); + Statistic<> numIntervals + ("liveintervals", "Number of original intervals"); + + Statistic<> numIntervalsAfter + ("liveintervals", "Number of intervals after coalescing"); + + Statistic<> numJoins + ("liveintervals", "Number of interval joins performed"); + + Statistic<> numPeep + ("liveintervals", "Number of identity moves eliminated after coalescing"); + + Statistic<> numFolded + ("liveintervals", "Number of loads/stores folded into instructions"); + + cl::opt + join("join-liveintervals", + cl::desc("Join compatible live intervals"), + cl::init(true)); }; void LiveIntervals::getAnalysisUsage(AnalysisUsage &AU) const @@ -57,128 +74,241 @@ MachineFunctionPass::getAnalysisUsage(AU); } +void LiveIntervals::releaseMemory() +{ + mbbi2mbbMap_.clear(); + mi2iMap_.clear(); + i2miMap_.clear(); + r2iMap_.clear(); + r2rMap_.clear(); + intervals_.clear(); +} + + /// runOnMachineFunction - Register allocate the whole function /// bool LiveIntervals::runOnMachineFunction(MachineFunction &fn) { - DEBUG(std::cerr << "Machine Function\n"); mf_ = &fn; tm_ = &fn.getTarget(); mri_ = tm_->getRegisterInfo(); lv_ = &getAnalysis(); - mbbi2mbbMap_.clear(); - mi2iMap_.clear(); - r2iMap_.clear(); - r2iMap_.clear(); - intervals_.clear(); // number MachineInstrs unsigned miIndex = 0; for (MachineFunction::iterator mbb = mf_->begin(), mbbEnd = mf_->end(); mbb != mbbEnd; ++mbb) { const std::pair& entry = - lv_->getMachineBasicBlockInfo(&*mbb); + lv_->getMachineBasicBlockInfo(mbb); bool inserted = mbbi2mbbMap_.insert(std::make_pair(entry.second, entry.first)).second; assert(inserted && "multiple index -> MachineBasicBlock"); for (MachineBasicBlock::iterator mi = mbb->begin(), miEnd = mbb->end(); mi != miEnd; ++mi) { - inserted = mi2iMap_.insert(std::make_pair(*mi, miIndex)).second; + inserted = mi2iMap_.insert(std::make_pair(mi, miIndex)).second; assert(inserted && "multiple MachineInstr -> index mappings"); - ++miIndex; + i2miMap_.push_back(mi); + miIndex += InstrSlots::NUM; } } computeIntervals(); - // compute spill weights + numIntervals += intervals_.size(); + + // join intervals if requested + if (join) joinIntervals(); + + numIntervalsAfter += intervals_.size(); + + // perform a final pass over the instructions and compute spill + // weights, coalesce virtual registers and remove identity moves const LoopInfo& loopInfo = getAnalysis(); const TargetInstrInfo& tii = tm_->getInstrInfo(); - for (MbbIndex2MbbMap::iterator - it = mbbi2mbbMap_.begin(), itEnd = mbbi2mbbMap_.end(); - it != itEnd; ++it) { - MachineBasicBlock* mbb = it->second; - + for (MachineFunction::iterator mbbi = mf_->begin(), mbbe = mf_->end(); + mbbi != mbbe; ++mbbi) { + MachineBasicBlock* mbb = mbbi; unsigned loopDepth = loopInfo.getLoopDepth(mbb->getBasicBlock()); - for (MachineBasicBlock::iterator mi = mbb->begin(), miEnd = mbb->end(); - mi != miEnd; ++mi) { - MachineInstr* instr = *mi; - for (int i = instr->getNumOperands() - 1; i >= 0; --i) { - MachineOperand& mop = instr->getOperand(i); - - if (!mop.isVirtualRegister()) - continue; + for (MachineBasicBlock::iterator mii = mbb->begin(), mie = mbb->end(); + mii != mie; ) { + for (unsigned i = 0; i < mii->getNumOperands(); ++i) { + const MachineOperand& mop = mii->getOperand(i); + if (mop.isRegister() && mop.getReg()) { + // replace register with representative register + unsigned reg = rep(mop.getReg()); + mii->SetMachineOperandReg(i, reg); + + if (MRegisterInfo::isVirtualRegister(reg)) { + Reg2IntervalMap::iterator r2iit = r2iMap_.find(reg); + assert(r2iit != r2iMap_.end()); + r2iit->second->weight += pow(10.0F, loopDepth); + } + } + } - unsigned reg = mop.getAllocatedRegNum(); - Reg2IntervalMap::iterator r2iit = r2iMap_.find(reg); - assert(r2iit != r2iMap_.end()); - r2iit->second->weight += pow(10.0F, loopDepth); + // if the move is now an identity move delete it + unsigned srcReg, dstReg; + if (tii.isMoveInstr(*mii, srcReg, dstReg) && srcReg == dstReg) { + // remove index -> MachineInstr and + // MachineInstr -> index mappings + Mi2IndexMap::iterator mi2i = mi2iMap_.find(mii); + if (mi2i != mi2iMap_.end()) { + i2miMap_[mi2i->second/InstrSlots::NUM] = 0; + mi2iMap_.erase(mi2i); + } + mii = mbbi->erase(mii); + ++numPeep; } + else + ++mii; } } - numIntervals += intervals_.size(); + intervals_.sort(StartPointComp()); + DEBUG(std::cerr << "********** INTERVALS **********\n"); + DEBUG(std::copy(intervals_.begin(), intervals_.end(), + std::ostream_iterator(std::cerr, "\n"))); + DEBUG(std::cerr << "********** MACHINEINSTRS **********\n"); + DEBUG( + for (MachineFunction::iterator mbbi = mf_->begin(), mbbe = mf_->end(); + mbbi != mbbe; ++mbbi) { + std::cerr << mbbi->getBasicBlock()->getName() << ":\n"; + for (MachineBasicBlock::iterator mii = mbbi->begin(), + mie = mbbi->end(); mii != mie; ++mii) { + std::cerr << getInstructionIndex(mii) << '\t'; + mii->print(std::cerr, *tm_); + } + }); return true; } +void LiveIntervals::updateSpilledInterval(Interval& li, + VirtRegMap& vrm, + int slot) +{ + assert(li.weight != std::numeric_limits::infinity() && + "attempt to spill already spilled interval!"); + Interval::Ranges oldRanges; + swap(oldRanges, li.ranges); + + DEBUG(std::cerr << "\t\t\t\tupdating interval: " << li); + + for (Interval::Ranges::iterator i = oldRanges.begin(), e = oldRanges.end(); + i != e; ++i) { + unsigned index = getBaseIndex(i->first); + unsigned end = getBaseIndex(i->second-1) + InstrSlots::NUM; + for (; index < end; index += InstrSlots::NUM) { + // skip deleted instructions + while (!getInstructionFromIndex(index)) index += InstrSlots::NUM; + MachineBasicBlock::iterator mi = getInstructionFromIndex(index); + + for_operand: + for (unsigned i = 0; i < mi->getNumOperands(); ++i) { + MachineOperand& mop = mi->getOperand(i); + if (mop.isRegister() && mop.getReg() == li.reg) { + MachineInstr* old = mi; + if (mri_->foldMemoryOperand(mi, i, slot)) { + lv_->instructionChanged(old, mi); + vrm.virtFolded(li.reg, old, mi); + mi2iMap_.erase(old); + i2miMap_[index/InstrSlots::NUM] = mi; + mi2iMap_[mi] = index; + ++numFolded; + goto for_operand; + } + else { + // This is tricky. We need to add information in + // the interval about the spill code so we have to + // use our extra load/store slots. + // + // If we have a use we are going to have a load so + // we start the interval from the load slot + // onwards. Otherwise we start from the def slot. + unsigned start = (mop.isUse() ? + getLoadIndex(index) : + getDefIndex(index)); + // If we have a def we are going to have a store + // right after it so we end the interval after the + // use of the next instruction. Otherwise we end + // after the use of this instruction. + unsigned end = 1 + (mop.isDef() ? + getUseIndex(index+InstrSlots::NUM) : + getUseIndex(index)); + li.addRange(start, end); + } + } + } + } + } + // the new spill weight is now infinity as it cannot be spilled again + li.weight = std::numeric_limits::infinity(); + DEBUG(std::cerr << '\n'); + DEBUG(std::cerr << "\t\t\t\tupdated interval: " << li << '\n'); +} + void LiveIntervals::printRegName(unsigned reg) const { - if (reg < MRegisterInfo::FirstVirtualRegister) + if (MRegisterInfo::isPhysicalRegister(reg)) std::cerr << mri_->getName(reg); else - std::cerr << '%' << reg; + std::cerr << "%reg" << reg; } void LiveIntervals::handleVirtualRegisterDef(MachineBasicBlock* mbb, MachineBasicBlock::iterator mi, unsigned reg) { - DEBUG(std::cerr << "\t\tregister: ";printRegName(reg); std::cerr << '\n'); - - unsigned instrIndex = getInstructionIndex(*mi); - + DEBUG(std::cerr << "\t\tregister: "; printRegName(reg)); LiveVariables::VarInfo& vi = lv_->getVarInfo(reg); Interval* interval = 0; - Reg2IntervalMap::iterator r2iit = r2iMap_.find(reg); - if (r2iit == r2iMap_.end()) { + Reg2IntervalMap::iterator r2iit = r2iMap_.lower_bound(reg); + if (r2iit == r2iMap_.end() || r2iit->first != reg) { // add new interval intervals_.push_back(Interval(reg)); // update interval index for this register - bool inserted = - r2iMap_.insert(std::make_pair(reg, --intervals_.end())).second; - assert(inserted); + r2iMap_.insert(r2iit, std::make_pair(reg, --intervals_.end())); interval = &intervals_.back(); + + // iterate over all of the blocks that the variable is + // completely live in, adding them to the live + // interval. obviously we only need to do this once. + for (unsigned i = 0, e = vi.AliveBlocks.size(); i != e; ++i) { + if (vi.AliveBlocks[i]) { + MachineBasicBlock* mbb = lv_->getIndexMachineBasicBlock(i); + if (!mbb->empty()) { + interval->addRange( + getInstructionIndex(&mbb->front()), + getInstructionIndex(&mbb->back()) + InstrSlots::NUM); + } + } + } } else { interval = &*r2iit->second; } - for (MbbIndex2MbbMap::iterator - it = mbbi2mbbMap_.begin(), itEnd = mbbi2mbbMap_.end(); - it != itEnd; ++it) { - unsigned liveBlockIndex = it->first; - MachineBasicBlock* liveBlock = it->second; - if (liveBlockIndex < vi.AliveBlocks.size() && - vi.AliveBlocks[liveBlockIndex] && - !liveBlock->empty()) { - unsigned start = getInstructionIndex(liveBlock->front()); - unsigned end = getInstructionIndex(liveBlock->back()) + 1; - interval->addRange(start, end); - } - } + unsigned baseIndex = getInstructionIndex(mi); bool killedInDefiningBasicBlock = false; for (int i = 0, e = vi.Kills.size(); i != e; ++i) { MachineBasicBlock* killerBlock = vi.Kills[i].first; MachineInstr* killerInstr = vi.Kills[i].second; unsigned start = (mbb == killerBlock ? - instrIndex : - getInstructionIndex(killerBlock->front())); - unsigned end = getInstructionIndex(killerInstr) + 1; + getDefIndex(baseIndex) : + getInstructionIndex(&killerBlock->front())); + unsigned end = (killerInstr == mi ? + // dead + start + 1 : + // killed + getUseIndex(getInstructionIndex(killerInstr))+1); + // we do not want to add invalid ranges. these can happen when + // a variable has its latest use and is redefined later on in + // the same basic block (common with variables introduced by + // PHI elimination) if (start < end) { killedInDefiningBasicBlock |= mbb == killerBlock; interval->addRange(start, end); @@ -186,9 +316,10 @@ } if (!killedInDefiningBasicBlock) { - unsigned end = getInstructionIndex(mbb->back()) + 1; - interval->addRange(instrIndex, end); + unsigned end = getInstructionIndex(&mbb->back()) + InstrSlots::NUM; + interval->addRange(getDefIndex(baseIndex), end); } + DEBUG(std::cerr << '\n'); } void LiveIntervals::handlePhysicalRegisterDef(MachineBasicBlock* mbb, @@ -196,72 +327,58 @@ unsigned reg) { DEBUG(std::cerr << "\t\tregister: "; printRegName(reg)); + typedef LiveVariables::killed_iterator KillIter; - unsigned start = getInstructionIndex(*mi); + MachineBasicBlock::iterator e = mbb->end(); + unsigned baseIndex = getInstructionIndex(mi); + unsigned start = getDefIndex(baseIndex); unsigned end = start; - // register can be dead by the instruction defining it but it can - // only be killed by subsequent instructions - - for (LiveVariables::killed_iterator - ki = lv_->dead_begin(*mi), - ke = lv_->dead_end(*mi); + // a variable can be dead by the instruction defining it + for (KillIter ki = lv_->dead_begin(mi), ke = lv_->dead_end(mi); ki != ke; ++ki) { if (reg == ki->second) { - end = getInstructionIndex(ki->first) + 1; - DEBUG(std::cerr << " dead\n"); + DEBUG(std::cerr << " dead"); + end = getDefIndex(start) + 1; goto exit; } } - ++mi; - for (MachineBasicBlock::iterator e = mbb->end(); mi != e; ++mi) { - for (LiveVariables::killed_iterator - ki = lv_->dead_begin(*mi), - ke = lv_->dead_end(*mi); + // a variable can only be killed by subsequent instructions + do { + ++mi; + baseIndex += InstrSlots::NUM; + for (KillIter ki = lv_->killed_begin(mi), ke = lv_->killed_end(mi); ki != ke; ++ki) { if (reg == ki->second) { - end = getInstructionIndex(ki->first) + 1; - DEBUG(std::cerr << " dead\n"); + DEBUG(std::cerr << " killed"); + end = getUseIndex(baseIndex) + 1; goto exit; } } + } while (mi != e); - for (LiveVariables::killed_iterator - ki = lv_->killed_begin(*mi), - ke = lv_->killed_end(*mi); - ki != ke; ++ki) { - if (reg == ki->second) { - end = getInstructionIndex(ki->first) + 1; - DEBUG(std::cerr << " killed\n"); - goto exit; - } - } - } exit: assert(start < end && "did not find end of interval?"); - Reg2IntervalMap::iterator r2iit = r2iMap_.find(reg); - if (r2iit != r2iMap_.end()) { - Interval& interval = *r2iit->second; - interval.addRange(start, end); + Reg2IntervalMap::iterator r2iit = r2iMap_.lower_bound(reg); + if (r2iit != r2iMap_.end() && r2iit->first == reg) { + r2iit->second->addRange(start, end); } else { intervals_.push_back(Interval(reg)); - Interval& interval = intervals_.back(); // update interval index for this register - bool inserted = - r2iMap_.insert(std::make_pair(reg, --intervals_.end())).second; - assert(inserted); - interval.addRange(start, end); + r2iMap_.insert(r2iit, std::make_pair(reg, --intervals_.end())); + intervals_.back().addRange(start, end); } + DEBUG(std::cerr << '\n'); } void LiveIntervals::handleRegisterDef(MachineBasicBlock* mbb, MachineBasicBlock::iterator mi, unsigned reg) { - if (reg < MRegisterInfo::FirstVirtualRegister) { + if (MRegisterInfo::isPhysicalRegister(reg)) { if (lv_->getAllocatablePhysicalRegisters()[reg]) { handlePhysicalRegisterDef(mbb, mi, reg); for (const unsigned* as = mri_->getAliasSet(reg); *as; ++as) @@ -275,144 +392,318 @@ unsigned LiveIntervals::getInstructionIndex(MachineInstr* instr) const { - assert(mi2iMap_.find(instr) != mi2iMap_.end() && - "instruction not assigned a number"); - return mi2iMap_.find(instr)->second; + Mi2IndexMap::const_iterator it = mi2iMap_.find(instr); + return (it == mi2iMap_.end() ? + std::numeric_limits::max() : + it->second); +} + +MachineInstr* LiveIntervals::getInstructionFromIndex(unsigned index) const +{ + index /= InstrSlots::NUM; // convert index to vector index + assert(index < i2miMap_.size() && + "index does not correspond to an instruction"); + return i2miMap_[index]; } /// computeIntervals - computes the live intervals for virtual /// registers. for some ordering of the machine instructions [1,N] a -/// live interval is an interval [i, j] where 1 <= i <= j <= N for +/// live interval is an interval [i, j) where 1 <= i <= j < N for /// which a variable is live void LiveIntervals::computeIntervals() { - DEBUG(std::cerr << "computing live intervals:\n"); + DEBUG(std::cerr << "********** COMPUTING LIVE INTERVALS **********\n"); + DEBUG(std::cerr << "********** Function: " + << mf_->getFunction()->getName() << '\n'); for (MbbIndex2MbbMap::iterator it = mbbi2mbbMap_.begin(), itEnd = mbbi2mbbMap_.end(); it != itEnd; ++it) { MachineBasicBlock* mbb = it->second; - DEBUG(std::cerr << "machine basic block: " - << mbb->getBasicBlock()->getName() << "\n"); + DEBUG(std::cerr << mbb->getBasicBlock()->getName() << ":\n"); for (MachineBasicBlock::iterator mi = mbb->begin(), miEnd = mbb->end(); mi != miEnd; ++mi) { - MachineInstr* instr = *mi; const TargetInstrDescriptor& tid = - tm_->getInstrInfo().get(instr->getOpcode()); - DEBUG(std::cerr << "\t[" << getInstructionIndex(instr) << "] "; - instr->print(std::cerr, *tm_);); + tm_->getInstrInfo().get(mi->getOpcode()); + DEBUG(std::cerr << getInstructionIndex(mi) << "\t"; + mi->print(std::cerr, *tm_)); // handle implicit defs for (const unsigned* id = tid.ImplicitDefs; *id; ++id) handleRegisterDef(mbb, mi, *id); // handle explicit defs - for (int i = instr->getNumOperands() - 1; i >= 0; --i) { - MachineOperand& mop = instr->getOperand(i); + for (int i = mi->getNumOperands() - 1; i >= 0; --i) { + MachineOperand& mop = mi->getOperand(i); + // handle register defs - build intervals + if (mop.isRegister() && mop.getReg() && mop.isDef()) + handleRegisterDef(mbb, mi, mop.getReg()); + } + } + } +} + +unsigned LiveIntervals::rep(unsigned reg) +{ + Reg2RegMap::iterator it = r2rMap_.find(reg); + if (it != r2rMap_.end()) + return it->second = rep(it->second); + return reg; +} + +void LiveIntervals::joinIntervals() +{ + DEBUG(std::cerr << "********** JOINING INTERVALS ***********\n"); + + const TargetInstrInfo& tii = tm_->getInstrInfo(); - if (!mop.isRegister()) + for (MachineFunction::iterator mbbi = mf_->begin(), mbbe = mf_->end(); + mbbi != mbbe; ++mbbi) { + MachineBasicBlock* mbb = mbbi; + DEBUG(std::cerr << mbb->getBasicBlock()->getName() << ":\n"); + + for (MachineBasicBlock::iterator mi = mbb->begin(), mie = mbb->end(); + mi != mie; ++mi) { + const TargetInstrDescriptor& tid = + tm_->getInstrInfo().get(mi->getOpcode()); + DEBUG(std::cerr << getInstructionIndex(mi) << '\t'; + mi->print(std::cerr, *tm_);); + + // we only join virtual registers with allocatable + // physical registers since we do not have liveness information + // on not allocatable physical registers + unsigned regA, regB; + if (tii.isMoveInstr(*mi, regA, regB) && + (MRegisterInfo::isVirtualRegister(regA) || + lv_->getAllocatablePhysicalRegisters()[regA]) && + (MRegisterInfo::isVirtualRegister(regB) || + lv_->getAllocatablePhysicalRegisters()[regB])) { + + // get representative registers + regA = rep(regA); + regB = rep(regB); + + // if they are already joined we continue + if (regA == regB) continue; - // handle defs - build intervals - if (mop.isDef()) - handleRegisterDef(mbb, mi, mop.getAllocatedRegNum()); + Reg2IntervalMap::iterator r2iA = r2iMap_.find(regA); + assert(r2iA != r2iMap_.end()); + Reg2IntervalMap::iterator r2iB = r2iMap_.find(regB); + assert(r2iB != r2iMap_.end()); + + Intervals::iterator intA = r2iA->second; + Intervals::iterator intB = r2iB->second; + + // both A and B are virtual registers + if (MRegisterInfo::isVirtualRegister(intA->reg) && + MRegisterInfo::isVirtualRegister(intB->reg)) { + + const TargetRegisterClass *rcA, *rcB; + rcA = mf_->getSSARegMap()->getRegClass(intA->reg); + rcB = mf_->getSSARegMap()->getRegClass(intB->reg); + assert(rcA == rcB && "registers must be of the same class"); + + // if their intervals do not overlap we join them + if (!intB->overlaps(*intA)) { + intA->join(*intB); + r2iB->second = r2iA->second; + r2rMap_.insert(std::make_pair(intB->reg, intA->reg)); + intervals_.erase(intB); + } + } + else if (MRegisterInfo::isPhysicalRegister(intA->reg) ^ + MRegisterInfo::isPhysicalRegister(intB->reg)) { + if (MRegisterInfo::isPhysicalRegister(intB->reg)) { + std::swap(regA, regB); + std::swap(intA, intB); + std::swap(r2iA, r2iB); + } + + assert(MRegisterInfo::isPhysicalRegister(intA->reg) && + MRegisterInfo::isVirtualRegister(intB->reg) && + "A must be physical and B must be virtual"); + + if (!intA->overlaps(*intB) && + !overlapsAliases(*intA, *intB)) { + intA->join(*intB); + r2iB->second = r2iA->second; + r2rMap_.insert(std::make_pair(intB->reg, intA->reg)); + intervals_.erase(intB); + } + } } } } +} + +bool LiveIntervals::overlapsAliases(const Interval& lhs, + const Interval& rhs) const +{ + assert(MRegisterInfo::isPhysicalRegister(lhs.reg) && + "first interval must describe a physical register"); + + for (const unsigned* as = mri_->getAliasSet(lhs.reg); *as; ++as) { + Reg2IntervalMap::const_iterator r2i = r2iMap_.find(*as); + assert(r2i != r2iMap_.end() && "alias does not have interval?"); + if (rhs.overlaps(*r2i->second)) + return true; + } - intervals_.sort(StartPointComp()); - DEBUG(std::copy(intervals_.begin(), intervals_.end(), - std::ostream_iterator(std::cerr, "\n"))); + return false; } LiveIntervals::Interval::Interval(unsigned r) - : reg(r), hint(0), - weight((r < MRegisterInfo::FirstVirtualRegister ? - std::numeric_limits::max() : 0.0F)) + : reg(r), + weight((MRegisterInfo::isPhysicalRegister(r) ? + std::numeric_limits::infinity() : 0.0F)) { } +bool LiveIntervals::Interval::spilled() const +{ + return (weight == std::numeric_limits::infinity() && + MRegisterInfo::isVirtualRegister(reg)); +} + +// An example for liveAt(): +// +// this = [1,4), liveAt(0) will return false. The instruction defining +// this spans slots [0,3]. The interval belongs to an spilled +// definition of the variable it represents. This is because slot 1 is +// used (def slot) and spans up to slot 3 (store slot). +// +bool LiveIntervals::Interval::liveAt(unsigned index) const +{ + Range dummy(index, index+1); + Ranges::const_iterator r = std::upper_bound(ranges.begin(), + ranges.end(), + dummy); + if (r == ranges.begin()) + return false; + + --r; + return index >= r->first && index < r->second; +} + +// An example for overlaps(): +// +// 0: A = ... +// 4: B = ... +// 8: C = A + B ;; last use of A +// +// The live intervals should look like: +// +// A = [3, 11) +// B = [7, x) +// C = [11, y) +// +// A->overlaps(C) should return false since we want to be able to join +// A and C. +bool LiveIntervals::Interval::overlaps(const Interval& other) const +{ + Ranges::const_iterator i = ranges.begin(); + Ranges::const_iterator ie = ranges.end(); + Ranges::const_iterator j = other.ranges.begin(); + Ranges::const_iterator je = other.ranges.end(); + if (i->first < j->first) { + i = std::upper_bound(i, ie, *j); + if (i != ranges.begin()) --i; + } + else if (j->first < i->first) { + j = std::upper_bound(j, je, *i); + if (j != other.ranges.begin()) --j; + } + + while (i != ie && j != je) { + if (i->first == j->first) { + return true; + } + else { + if (i->first > j->first) { + swap(i, j); + swap(ie, je); + } + assert(i->first < j->first); + + if (i->second > j->first) { + return true; + } + else { + ++i; + } + } + } + + return false; +} + void LiveIntervals::Interval::addRange(unsigned start, unsigned end) { - DEBUG(std::cerr << "\t\t\tadding range: [" << start <<','<< end << ") -> "); + assert(start < end && "Invalid range to add!"); + DEBUG(std::cerr << " +[" << start << ',' << end << ")"); //assert(start < end && "invalid range?"); Range range = std::make_pair(start, end); Ranges::iterator it = ranges.insert(std::upper_bound(ranges.begin(), ranges.end(), range), range); - mergeRangesForward(it); - mergeRangesBackward(it); - DEBUG(std::cerr << *this << '\n'); + it = mergeRangesForward(it); + it = mergeRangesBackward(it); } -void LiveIntervals::Interval::mergeRangesForward(Ranges::iterator it) +void LiveIntervals::Interval::join(const LiveIntervals::Interval& other) { - for (Ranges::iterator next = it + 1; - next != ranges.end() && it->second >= next->first; ) { - it->second = std::max(it->second, next->second); - next = ranges.erase(next); - } -} + DEBUG(std::cerr << "\t\tjoining " << *this << " with " << other << '\n'); + Ranges::iterator cur = ranges.begin(); -void LiveIntervals::Interval::mergeRangesBackward(Ranges::iterator it) -{ - for (Ranges::iterator prev = it - 1; - it != ranges.begin() && it->first <= prev->second; ) { - it->first = std::min(it->first, prev->first); - it->second = std::max(it->second, prev->second); - it = ranges.erase(prev); - prev = it - 1; + for (Ranges::const_iterator i = other.ranges.begin(), + e = other.ranges.end(); i != e; ++i) { + cur = ranges.insert(std::upper_bound(cur, ranges.end(), *i), *i); + cur = mergeRangesForward(cur); + cur = mergeRangesBackward(cur); } + weight += other.weight; + ++numJoins; } -bool LiveIntervals::Interval::liveAt(unsigned index) const +LiveIntervals::Interval::Ranges::iterator +LiveIntervals::Interval::mergeRangesForward(Ranges::iterator it) { - Ranges::const_iterator r = ranges.begin(); - while (r != ranges.end() && index < (r->second - 1)) { - if (index >= r->first) - return true; - ++r; + Ranges::iterator n; + while ((n = next(it)) != ranges.end()) { + if (n->first > it->second) + break; + it->second = std::max(it->second, n->second); + n = ranges.erase(n); } - return false; + return it; } -bool LiveIntervals::Interval::overlaps(const Interval& other) const +LiveIntervals::Interval::Ranges::iterator +LiveIntervals::Interval::mergeRangesBackward(Ranges::iterator it) { - Ranges::const_iterator i = ranges.begin(); - Ranges::const_iterator j = other.ranges.begin(); + while (it != ranges.begin()) { + Ranges::iterator p = prior(it); + if (it->first > p->second) + break; - while (i != ranges.end() && j != other.ranges.end()) { - if (i->first < j->first) { - if ((i->second - 1) > j->first) { - return true; - } - else { - ++i; - } - } - else if (j->first < i->first) { - if ((j->second - 1) > i->first) { - return true; - } - else { - ++j; - } - } - else { - return true; - } + it->first = std::min(it->first, p->first); + it->second = std::max(it->second, p->second); + it = ranges.erase(p); } - return false; + return it; } std::ostream& llvm::operator<<(std::ostream& os, const LiveIntervals::Interval& li) { os << "%reg" << li.reg << ',' << li.weight << " = "; + if (li.empty()) + return os << "EMPTY"; for (LiveIntervals::Interval::Ranges::const_iterator i = li.ranges.begin(), e = li.ranges.end(); i != e; ++i) { os << "[" << i->first << "," << i->second << ")"; Index: llvm/lib/CodeGen/LiveIntervals.h diff -u llvm/lib/CodeGen/LiveIntervals.h:1.11 llvm/lib/CodeGen/LiveIntervals.h:1.11.2.1 --- llvm/lib/CodeGen/LiveIntervals.h:1.11 Fri Jan 16 14:17:05 2004 +++ llvm/lib/CodeGen/LiveIntervals.h Mon Mar 1 17:58:13 2004 @@ -9,12 +9,12 @@ // // This file implements the LiveInterval analysis pass. Given some // numbering of each the machine instructions (in this implemention -// depth-first order) an interval [i, j] is said to be a live interval +// depth-first order) an interval [i, j) is said to be a live interval // for register v if there is no instruction with number j' > j such // that v is live at j' abd there is no instruction with number i' < i // such that v is live at i'. In this implementation intervals can -// have holes, i.e. an interval might look like [1,20], [50,65], -// [1000,1001] +// have holes, i.e. an interval might look like [1,20), [50,65), +// [1000,1001) // //===----------------------------------------------------------------------===// @@ -22,15 +22,13 @@ #define LLVM_CODEGEN_LIVEINTERVALS_H #include "llvm/CodeGen/MachineFunctionPass.h" -#include "llvm/CodeGen/MachineBasicBlock.h" -#include #include -#include namespace llvm { class LiveVariables; class MRegisterInfo; + class VirtRegMap; class LiveIntervals : public MachineFunctionPass { @@ -39,20 +37,23 @@ typedef std::pair Range; typedef std::vector Ranges; unsigned reg; // the register of this interval - unsigned hint; float weight; // weight of this interval (number of uses // * 10^loopDepth) - Ranges ranges; // the ranges this register is valid + Ranges ranges; // the ranges in which this register is live Interval(unsigned r); + bool empty() const { return ranges.empty(); } + + bool spilled() const; + unsigned start() const { - assert(!ranges.empty() && "empty interval for register"); + assert(!empty() && "empty interval for register"); return ranges.front().first; } unsigned end() const { - assert(!ranges.empty() && "empty interval for register"); + assert(!empty() && "empty interval for register"); return ranges.back().second; } @@ -66,10 +67,12 @@ void addRange(unsigned start, unsigned end); + void join(const Interval& other); + private: - void mergeRangesForward(Ranges::iterator it); + Ranges::iterator mergeRangesForward(Ranges::iterator it); - void mergeRangesBackward(Ranges::iterator it); + Ranges::iterator mergeRangesBackward(Ranges::iterator it); }; struct StartPointComp { @@ -85,7 +88,6 @@ }; typedef std::list Intervals; - typedef std::vector MachineBasicBlockPtrs; private: MachineFunction* mf_; @@ -101,31 +103,76 @@ typedef std::map Mi2IndexMap; Mi2IndexMap mi2iMap_; + typedef std::vector Index2MiMap; + Index2MiMap i2miMap_; + typedef std::map Reg2IntervalMap; Reg2IntervalMap r2iMap_; + typedef std::map Reg2RegMap; + Reg2RegMap r2rMap_; + Intervals intervals_; public: - virtual void getAnalysisUsage(AnalysisUsage &AU) const; - Intervals& getIntervals() { return intervals_; } - MachineBasicBlockPtrs getOrderedMachineBasicBlockPtrs() const { - MachineBasicBlockPtrs result; - for (MbbIndex2MbbMap::const_iterator - it = mbbi2mbbMap_.begin(), itEnd = mbbi2mbbMap_.end(); - it != itEnd; ++it) { - result.push_back(it->second); - } - return result; + struct InstrSlots + { + enum { + LOAD = 0, + USE = 1, + DEF = 2, + STORE = 3, + NUM = 4, + }; + }; + + static unsigned getBaseIndex(unsigned index) { + return index - (index % InstrSlots::NUM); + } + static unsigned getBoundaryIndex(unsigned index) { + return getBaseIndex(index + InstrSlots::NUM - 1); + } + static unsigned getLoadIndex(unsigned index) { + return getBaseIndex(index) + InstrSlots::LOAD; + } + static unsigned getUseIndex(unsigned index) { + return getBaseIndex(index) + InstrSlots::USE; + } + static unsigned getDefIndex(unsigned index) { + return getBaseIndex(index) + InstrSlots::DEF; + } + static unsigned getStoreIndex(unsigned index) { + return getBaseIndex(index) + InstrSlots::STORE; } - private: + virtual void getAnalysisUsage(AnalysisUsage &AU) const; + virtual void releaseMemory(); + /// runOnMachineFunction - pass entry point - bool runOnMachineFunction(MachineFunction&); + virtual bool runOnMachineFunction(MachineFunction&); + + Interval& getInterval(unsigned reg) { + assert(r2iMap_.count(reg)&& "Interval does not exist for register"); + return *r2iMap_.find(reg)->second; + } + + /// getInstructionIndex - returns the base index of instr + unsigned getInstructionIndex(MachineInstr* instr) const; + /// getInstructionFromIndex - given an index in any slot of an + /// instruction return a pointer the instruction + MachineInstr* getInstructionFromIndex(unsigned index) const; + + Intervals& getIntervals() { return intervals_; } + + void updateSpilledInterval(Interval& i, VirtRegMap& vrm, int slot); + + private: /// computeIntervals - compute live intervals void computeIntervals(); + /// joinIntervals - join compatible live intervals + void joinIntervals(); /// handleRegisterDef - update intervals for a register def /// (calls handlePhysicalRegisterDef and @@ -146,7 +193,10 @@ MachineBasicBlock::iterator mi, unsigned reg); - unsigned getInstructionIndex(MachineInstr* instr) const; + bool overlapsAliases(const Interval& lhs, const Interval& rhs) const; + + /// rep - returns the representative of this register + unsigned rep(unsigned reg); void printRegName(unsigned reg) const; }; Index: llvm/lib/CodeGen/LiveVariables.cpp diff -u llvm/lib/CodeGen/LiveVariables.cpp:1.15 llvm/lib/CodeGen/LiveVariables.cpp:1.15.2.1 --- llvm/lib/CodeGen/LiveVariables.cpp:1.15 Tue Jan 13 15:16:25 2004 +++ llvm/lib/CodeGen/LiveVariables.cpp Mon Mar 1 17:58:13 2004 @@ -28,12 +28,13 @@ #include "llvm/CodeGen/LiveVariables.h" #include "llvm/CodeGen/MachineInstr.h" +#include "llvm/Target/MRegisterInfo.h" #include "llvm/Target/TargetInstrInfo.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Support/CFG.h" #include "Support/DepthFirstIterator.h" - -namespace llvm { +#include "Support/STLExtras.h" +using namespace llvm; static RegisterAnalysis X("livevars", "Live Variable Analysis"); @@ -41,9 +42,25 @@ LiveVariables::getMachineBasicBlockInfo(MachineBasicBlock *MBB) const{ return BBMap.find(MBB->getBasicBlock())->second; } + +/// getIndexMachineBasicBlock() - Given a block index, return the +/// MachineBasicBlock corresponding to it. +MachineBasicBlock *LiveVariables::getIndexMachineBasicBlock(unsigned Idx) { + if (BBIdxMap.empty()) { + BBIdxMap.resize(BBMap.size()); + for (std::map > + ::iterator I = BBMap.begin(), E = BBMap.end(); I != E; ++I) { + assert(BBIdxMap.size() > I->second.second &&"Indices are not sequential"); + assert(BBIdxMap[I->second.second] == 0 && "Multiple idx collision!"); + BBIdxMap[I->second.second] = I->second.first; + } + } + assert(Idx < BBIdxMap.size() && "BB Index out of range!"); + return BBIdxMap[Idx]; +} LiveVariables::VarInfo &LiveVariables::getVarInfo(unsigned RegIdx) { - assert(RegIdx >= MRegisterInfo::FirstVirtualRegister && + assert(MRegisterInfo::isVirtualRegister(RegIdx) && "getVarInfo: not a virtual register!"); RegIdx -= MRegisterInfo::FirstVirtualRegister; if (RegIdx >= VirtRegInfo.size()) { @@ -131,29 +148,31 @@ for (const unsigned *AliasSet = RegInfo->getAliasSet(Reg); *AliasSet; ++AliasSet) { - if (MachineInstr *LastUse = PhysRegInfo[*AliasSet]) { - if (PhysRegUsed[*AliasSet]) - RegistersKilled.insert(std::make_pair(LastUse, *AliasSet)); + unsigned Alias = *AliasSet; + if (MachineInstr *LastUse = PhysRegInfo[Alias]) { + if (PhysRegUsed[Alias]) + RegistersKilled.insert(std::make_pair(LastUse, Alias)); else - RegistersDead.insert(std::make_pair(LastUse, *AliasSet)); + RegistersDead.insert(std::make_pair(LastUse, Alias)); } - PhysRegInfo[*AliasSet] = MI; - PhysRegUsed[*AliasSet] = false; + PhysRegInfo[Alias] = MI; + PhysRegUsed[Alias] = false; } } bool LiveVariables::runOnMachineFunction(MachineFunction &MF) { + const TargetInstrInfo &TII = MF.getTarget().getInstrInfo(); + RegInfo = MF.getTarget().getRegisterInfo(); + assert(RegInfo && "Target doesn't have register information?"); + // First time though, initialize AllocatablePhysicalRegisters for the target if (AllocatablePhysicalRegisters.empty()) { - const MRegisterInfo &MRI = *MF.getTarget().getRegisterInfo(); - assert(&MRI && "Target doesn't have register information?"); - // Make space, initializing to false... - AllocatablePhysicalRegisters.resize(MRegisterInfo::FirstVirtualRegister); + AllocatablePhysicalRegisters.resize(RegInfo->getNumRegs()); // Loop over all of the register classes... - for (MRegisterInfo::regclass_iterator RCI = MRI.regclass_begin(), - E = MRI.regclass_end(); RCI != E; ++RCI) + for (MRegisterInfo::regclass_iterator RCI = RegInfo->regclass_begin(), + E = RegInfo->regclass_end(); RCI != E; ++RCI) // Loop over all of the allocatable registers in the function... for (TargetRegisterClass::iterator I = (*RCI)->allocation_order_begin(MF), E = (*RCI)->allocation_order_end(MF); I != E; ++I) @@ -169,16 +188,12 @@ // physical register. This is a purely local property, because all physical // register references as presumed dead across basic blocks. // - MachineInstr *PhysRegInfoA[MRegisterInfo::FirstVirtualRegister]; - bool PhysRegUsedA[MRegisterInfo::FirstVirtualRegister]; - std::fill(PhysRegInfoA, PhysRegInfoA+MRegisterInfo::FirstVirtualRegister, - (MachineInstr*)0); + MachineInstr *PhysRegInfoA[RegInfo->getNumRegs()]; + bool PhysRegUsedA[RegInfo->getNumRegs()]; + std::fill(PhysRegInfoA, PhysRegInfoA+RegInfo->getNumRegs(), (MachineInstr*)0); PhysRegInfo = PhysRegInfoA; PhysRegUsed = PhysRegUsedA; - const TargetInstrInfo &TII = MF.getTarget().getInstrInfo(); - RegInfo = MF.getTarget().getRegisterInfo(); - /// Get some space for a respectable number of registers... VirtRegInfo.resize(64); @@ -198,7 +213,7 @@ // Loop over all of the instructions, processing them. for (MachineBasicBlock::iterator I = MBB->begin(), E = MBB->end(); I != E; ++I) { - MachineInstr *MI = *I; + MachineInstr *MI = I; const TargetInstrDescriptor &MID = TII.get(MI->getOpcode()); // Process all of the operands of the instruction... @@ -217,10 +232,10 @@ // Process all explicit uses... for (unsigned i = 0; i != NumOperandsToProcess; ++i) { MachineOperand &MO = MI->getOperand(i); - if (MO.isUse()) { - if (MO.isVirtualRegister() && !MO.getVRegValueOrNull()) { + if (MO.isUse() && MO.isRegister() && MO.getReg()) { + if (MRegisterInfo::isVirtualRegister(MO.getReg())){ HandleVirtRegUse(getVarInfo(MO.getReg()), MBB, MI); - } else if (MO.isPhysicalRegister() && + } else if (MRegisterInfo::isPhysicalRegister(MO.getReg()) && AllocatablePhysicalRegisters[MO.getReg()]) { HandlePhysRegUse(MO.getReg(), MI); } @@ -235,15 +250,15 @@ // Process all explicit defs... for (unsigned i = 0; i != NumOperandsToProcess; ++i) { MachineOperand &MO = MI->getOperand(i); - if (MO.isDef()) { - if (MO.isVirtualRegister()) { + if (MO.isDef() && MO.isRegister() && MO.getReg()) { + if (MRegisterInfo::isVirtualRegister(MO.getReg())) { VarInfo &VRInfo = getVarInfo(MO.getReg()); assert(VRInfo.DefBlock == 0 && "Variable multiply defined!"); VRInfo.DefBlock = MBB; // Created here... VRInfo.DefInst = MI; VRInfo.Kills.push_back(std::make_pair(MBB, MI)); // Defaults to dead - } else if (MO.isPhysicalRegister() && + } else if (MRegisterInfo::isPhysicalRegister(MO.getReg()) && AllocatablePhysicalRegisters[MO.getReg()]) { HandlePhysRegDef(MO.getReg(), MI); } @@ -260,10 +275,11 @@ MachineBasicBlock *Succ = BBMap.find(*SI)->second.first; // PHI nodes are guaranteed to be at the top of the block... - for (MachineBasicBlock::iterator I = Succ->begin(), E = Succ->end(); - I != E && (*I)->getOpcode() == TargetInstrInfo::PHI; ++I) { - MachineInstr *MI = *I; - for (unsigned i = 1; ; i += 2) + for (MachineBasicBlock::iterator MI = Succ->begin(), ME = Succ->end(); + MI != ME && MI->getOpcode() == TargetInstrInfo::PHI; ++MI) { + for (unsigned i = 1; ; i += 2) { + assert(MI->getNumOperands() > i+1 && + "Didn't find an entry for our predecessor??"); if (MI->getOperand(i+1).getMachineBasicBlock() == MBB) { MachineOperand &MO = MI->getOperand(i); if (!MO.getVRegValueOrNull()) { @@ -274,12 +290,13 @@ break; // Found the PHI entry for this block... } } + } } } // Loop over PhysRegInfo, killing any registers that are available at the // end of the basic block. This also resets the PhysRegInfo map. - for (unsigned i = 0, e = MRegisterInfo::FirstVirtualRegister; i != e; ++i) + for (unsigned i = 0, e = RegInfo->getNumRegs(); i != e; ++i) if (PhysRegInfo[i]) HandlePhysRegDef(i, 0); } @@ -301,4 +318,44 @@ return false; } -} // End llvm namespace +/// instructionChanged - When the address of an instruction changes, this +/// method should be called so that live variables can update its internal +/// data structures. This removes the records for OldMI, transfering them to +/// the records for NewMI. +void LiveVariables::instructionChanged(MachineInstr *OldMI, + MachineInstr *NewMI) { + // If the instruction defines any virtual registers, update the VarInfo for + // the instruction. + for (unsigned i = 0, e = NewMI->getNumOperands(); i != e; ++i) { + MachineOperand &MO = NewMI->getOperand(i); + if (MO.isRegister() && MO.isDef() && MO.getReg() && + MRegisterInfo::isVirtualRegister(MO.getReg())) { + unsigned Reg = MO.getReg(); + VarInfo &VI = getVarInfo(Reg); + if (VI.DefInst == OldMI) + VI.DefInst = NewMI; + } + } + + // Move the killed information over... + killed_iterator I, E; + tie(I, E) = killed_range(OldMI); + std::vector Regs; + for (killed_iterator A = I; A != E; ++A) + Regs.push_back(A->second); + RegistersKilled.erase(I, E); + + for (unsigned i = 0, e = Regs.size(); i != e; ++i) + RegistersKilled.insert(std::make_pair(NewMI, Regs[i])); + Regs.clear(); + + + // Move the dead information over... + tie(I, E) = dead_range(OldMI); + for (killed_iterator A = I; A != E; ++A) + Regs.push_back(A->second); + RegistersDead.erase(I, E); + + for (unsigned i = 0, e = Regs.size(); i != e; ++i) + RegistersDead.insert(std::make_pair(NewMI, Regs[i])); +} Index: llvm/lib/CodeGen/MachineCodeEmitter.cpp diff -u llvm/lib/CodeGen/MachineCodeEmitter.cpp:1.14 llvm/lib/CodeGen/MachineCodeEmitter.cpp:1.14.4.1 --- llvm/lib/CodeGen/MachineCodeEmitter.cpp:1.14 Tue Nov 11 16:41:32 2003 +++ llvm/lib/CodeGen/MachineCodeEmitter.cpp Mon Mar 1 17:58:13 2004 @@ -15,8 +15,7 @@ #include "llvm/CodeGen/MachineFunction.h" #include "llvm/Function.h" #include - -namespace llvm { +using namespace llvm; namespace { struct DebugMachineCodeEmitter : public MachineCodeEmitter { @@ -173,5 +172,3 @@ MachineCodeEmitter::createFilePrinterEmitter(MachineCodeEmitter &MCE) { return new FilePrinterEmitter(MCE, std::cerr); } - -} // End llvm namespace Index: llvm/lib/CodeGen/MachineCodeForInstruction.cpp diff -u llvm/lib/CodeGen/MachineCodeForInstruction.cpp:1.11 llvm/lib/CodeGen/MachineCodeForInstruction.cpp:1.11.2.1 --- llvm/lib/CodeGen/MachineCodeForInstruction.cpp:1.11 Sat Jan 10 13:16:26 2004 +++ llvm/lib/CodeGen/MachineCodeForInstruction.cpp Mon Mar 1 17:58:13 2004 @@ -24,10 +24,19 @@ #include "llvm/CodeGen/MachineCodeForInstruction.h" #include "llvm/CodeGen/MachineInstr.h" -#include "llvm/CodeGen/MachineInstrAnnot.h" +#include "../Target/SparcV9/MachineInstrAnnot.h" #include "llvm/Instruction.h" using namespace llvm; +MachineCodeForInstruction &MachineCodeForInstruction::get(const Instruction *I){ + return *(MachineCodeForInstruction*)I->getOrCreateAnnotation(MCFI_AID); +} +void MachineCodeForInstruction::destroy(const Instruction *I) { + I->deleteAnnotation(MCFI_AID); +} + + + AnnotationID llvm::MCFI_AID( AnnotationManager::getID("CodeGen::MachineCodeForInstruction")); @@ -60,9 +69,8 @@ for (unsigned i=0, N=tempVec.size(); i < N; i++) delete tempVec[i]; - // Free the MachineInstr objects allocated, if any. - for (unsigned i=0, N = size(); i < N; i++) - delete (*this)[i]; + // do not free the MachineInstr objects allocated. they are managed + // by the ilist in MachineBasicBlock // Free the CallArgsDescriptor if it exists. delete callArgsDesc; Index: llvm/lib/CodeGen/MachineFunction.cpp diff -u llvm/lib/CodeGen/MachineFunction.cpp:1.46 llvm/lib/CodeGen/MachineFunction.cpp:1.46.2.1 --- llvm/lib/CodeGen/MachineFunction.cpp:1.46 Sat Dec 20 04:20:58 2003 +++ llvm/lib/CodeGen/MachineFunction.cpp Mon Mar 1 17:58:13 2004 @@ -15,7 +15,6 @@ #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineInstr.h" -#include "llvm/CodeGen/MachineCodeForInstruction.h" #include "llvm/CodeGen/SSARegMap.h" #include "llvm/CodeGen/MachineFunctionInfo.h" #include "llvm/CodeGen/MachineFrameInfo.h" @@ -23,7 +22,6 @@ #include "llvm/CodeGen/Passes.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetFrameInfo.h" -#include "llvm/Target/TargetCacheInfo.h" #include "llvm/Function.h" #include "llvm/iOther.h" using namespace llvm; @@ -34,6 +32,12 @@ namespace { struct Printer : public MachineFunctionPass { + std::ostream *OS; + const std::string Banner; + + Printer (std::ostream *_OS, const std::string &_Banner) : + OS (_OS), Banner (_Banner) { } + const char *getPassName() const { return "MachineFunction Printer"; } virtual void getAnalysisUsage(AnalysisUsage &AU) const { @@ -41,14 +45,19 @@ } bool runOnMachineFunction(MachineFunction &MF) { - MF.dump(); + (*OS) << Banner; + MF.print (*OS); return false; } }; } -FunctionPass *llvm::createMachineFunctionPrinterPass() { - return new Printer(); +/// Returns a newly-created MachineFunction Printer pass. The default output +/// stream is std::cerr; the default banner is empty. +/// +FunctionPass *llvm::createMachineFunctionPrinterPass(std::ostream *OS, + const std::string &Banner) { + return new Printer(OS, Banner); } namespace { @@ -56,14 +65,6 @@ const char *getPassName() const { return "Machine Code Deleter"; } bool runOnMachineFunction(MachineFunction &MF) { - // Delete all of the MachineInstrs out of the function. When the sparc - // backend gets fixed, this can be dramatically simpler, but actually - // putting this stuff into the MachineBasicBlock destructor! - for (MachineFunction::iterator BB = MF.begin(), E = MF.end(); BB != E; - ++BB) - while (!BB->empty()) - delete BB->pop_back(); - // Delete the annotation from the function now. MachineFunction::destruct(MF.getFunction()); return true; @@ -79,6 +80,7 @@ } + //===---------------------------------------------------------------------===// // MachineFunction implementation //===---------------------------------------------------------------------===// @@ -111,18 +113,11 @@ // Print Constant Pool getConstantPool()->print(OS); - for (const_iterator BB = begin(); BB != end(); ++BB) { - const BasicBlock *LBB = BB->getBasicBlock(); - OS << "\n" << LBB->getName() << " (" << (const void*)LBB << "):\n"; - for (MachineBasicBlock::const_iterator I = BB->begin(); I != BB->end();++I){ - OS << "\t"; - (*I)->print(OS, Target); - } - } + for (const_iterator BB = begin(); BB != end(); ++BB) + BB->print(OS); OS << "\nEnd function \"" << Fn->getName() << "\"\n\n"; } - // The next two methods are used to construct and to retrieve // the MachineCodeForFunction object for the given function. // construct() -- Allocates and initializes for a given function and target @@ -277,7 +272,7 @@ inline unsigned SizeToAlignment(unsigned size, const TargetMachine& target) { - unsigned short cacheLineSize = target.getCacheInfo().getCacheLineSize(1); + const unsigned short cacheLineSize = 16; if (size > (unsigned) cacheLineSize / 2) return cacheLineSize; else Index: llvm/lib/CodeGen/MachineInstr.cpp diff -u llvm/lib/CodeGen/MachineInstr.cpp:1.82 llvm/lib/CodeGen/MachineInstr.cpp:1.82.2.1 --- llvm/lib/CodeGen/MachineInstr.cpp:1.82 Sun Dec 14 07:24:17 2003 +++ llvm/lib/CodeGen/MachineInstr.cpp Mon Mar 1 17:58:13 2004 @@ -6,17 +6,22 @@ // the University of Illinois Open Source License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// -// +// +// Methods common to all machine instructions. +// +// FIXME: Now that MachineInstrs have parent pointers, they should always +// print themselves using their MachineFunction's TargetMachine. +// //===----------------------------------------------------------------------===// #include "llvm/CodeGen/MachineInstr.h" -#include "llvm/CodeGen/MachineBasicBlock.h" +#include "llvm/CodeGen/MachineFunction.h" #include "llvm/Value.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetInstrInfo.h" #include "llvm/Target/MRegisterInfo.h" - -namespace llvm { +#include "Support/LeakDetector.h" +using namespace llvm; // Global variable holding an array of descriptors for machine instructions. // The actual object needs to be created separately for each target machine. @@ -25,15 +30,18 @@ // FIXME: This should be a property of the target so that more than one target // at a time can be active... // -extern const TargetInstrDescriptor *TargetInstrDescriptors; +namespace llvm { + extern const TargetInstrDescriptor *TargetInstrDescriptors; +} // Constructor for instructions with variable #operands -MachineInstr::MachineInstr(MachineOpCode OpCode, unsigned numOperands) - : opCode(OpCode), - opCodeFlags(0), +MachineInstr::MachineInstr(short opcode, unsigned numOperands) + : Opcode(opcode), + numImplicitRefs(0), operands(numOperands, MachineOperand()), - numImplicitRefs(0) -{ + parent(0) { + // Make sure that we get added to a machine basicblock + LeakDetector::addGarbageObject(this); } /// MachineInstr ctor - This constructor only does a _reserve_ of the operands, @@ -41,50 +49,48 @@ /// add* methods below to fill up the operands, instead of the Set methods. /// Eventually, the "resizing" ctors will be phased out. /// -MachineInstr::MachineInstr(MachineOpCode Opcode, unsigned numOperands, - bool XX, bool YY) - : opCode(Opcode), - opCodeFlags(0), - numImplicitRefs(0) -{ +MachineInstr::MachineInstr(short opcode, unsigned numOperands, bool XX, bool YY) + : Opcode(opcode), numImplicitRefs(0), parent(0) { operands.reserve(numOperands); + // Make sure that we get added to a machine basicblock + LeakDetector::addGarbageObject(this); } /// MachineInstr ctor - Work exactly the same as the ctor above, except that the /// MachineInstr is created and added to the end of the specified basic block. /// -MachineInstr::MachineInstr(MachineBasicBlock *MBB, MachineOpCode Opcode, +MachineInstr::MachineInstr(MachineBasicBlock *MBB, short opcode, unsigned numOperands) - : opCode(Opcode), - opCodeFlags(0), - numImplicitRefs(0) -{ + : Opcode(opcode), numImplicitRefs(0), parent(0) { assert(MBB && "Cannot use inserting ctor with null basic block!"); operands.reserve(numOperands); + // Make sure that we get added to a machine basicblock + LeakDetector::addGarbageObject(this); MBB->push_back(this); // Add instruction to end of basic block! } - -// OperandComplete - Return true if it's illegal to add a new operand -bool MachineInstr::OperandsComplete() const +MachineInstr::~MachineInstr() { - int NumOperands = TargetInstrDescriptors[opCode].numOperands; + LeakDetector::removeGarbageObject(this); +} + +/// OperandComplete - Return true if it's illegal to add a new operand +/// +bool MachineInstr::OperandsComplete() const { + int NumOperands = TargetInstrDescriptors[Opcode].numOperands; if (NumOperands >= 0 && getNumOperands() >= (unsigned)NumOperands) return true; // Broken: we have all the operands of this instruction! return false; } - -// -// Support for replacing opcode and operands of a MachineInstr in place. -// This only resets the size of the operand vector and initializes it. -// The new operands must be set explicitly later. -// -void MachineInstr::replace(MachineOpCode Opcode, unsigned numOperands) -{ +/// replace - Support for replacing opcode and operands of a MachineInstr in +/// place. This only resets the size of the operand vector and initializes it. +/// The new operands must be set explicitly later. +/// +void MachineInstr::replace(short opcode, unsigned numOperands) { assert(getNumImplicitRefs() == 0 && "This is probably broken because implicit refs are going to be lost."); - opCode = Opcode; + Opcode = opcode; operands.clear(); operands.resize(numOperands, MachineOperand()); } @@ -100,14 +106,13 @@ void MachineInstr::SetMachineOperandConst(unsigned i, - MachineOperand::MachineOperandType operandType, - int64_t intValue) -{ + MachineOperand::MachineOperandType opTy, + int intValue) { assert(i < getNumOperands()); // must be explicit op - assert(TargetInstrDescriptors[opCode].resultPos != (int) i && + assert(TargetInstrDescriptors[Opcode].resultPos != (int) i && "immed. constant cannot be defined"); - operands[i].opType = operandType; + operands[i].opType = opTy; operands[i].value = NULL; operands[i].immedVal = intValue; operands[i].regNum = -1; @@ -122,23 +127,24 @@ operands[i].regNum = regNum; } -void -MachineInstr::SetRegForOperand(unsigned i, int regNum) -{ +// Used only by the SPARC back-end. +void MachineInstr::SetRegForOperand(unsigned i, int regNum) { assert(i < getNumOperands()); // must be explicit op operands[i].setRegForValue(regNum); } -void -MachineInstr::SetRegForImplicitRef(unsigned i, int regNum) -{ +// Used only by the SPARC back-end. +void MachineInstr::SetRegForImplicitRef(unsigned i, int regNum) { getImplicitOp(i).setRegForValue(regNum); } - -// Substitute all occurrences of Value* oldVal with newVal in all operands -// and all implicit refs. -// If defsOnly == true, substitute defs only. +/// substituteValue - Substitute all occurrences of Value* oldVal with newVal +/// in all operands and all implicit refs. If defsOnly == true, substitute defs +/// only. +/// +/// FIXME: Fold this into its single caller, at SparcInstrSelection.cpp:2865, +/// or make it a static function in that file. +/// unsigned MachineInstr::substituteValue(const Value* oldVal, Value* newVal, bool defsOnly, bool notDefsAndUses, @@ -178,32 +184,28 @@ return numSubst; } - -void -MachineInstr::dump() const -{ +void MachineInstr::dump() const { std::cerr << " " << *this; } -static inline std::ostream& -OutputValue(std::ostream &os, const Value* val) -{ +static inline std::ostream& OutputValue(std::ostream &os, const Value* val) { os << "(val "; os << (void*) val; // print address always if (val && val->hasName()) - os << " " << val->getName() << ")"; // print name also, if available + os << " " << val->getName(); // print name also, if available + os << ")"; return os; } static inline void OutputReg(std::ostream &os, unsigned RegNo, const MRegisterInfo *MRI = 0) { - if (MRI) { - if (RegNo < MRegisterInfo::FirstVirtualRegister) + if (!RegNo || MRegisterInfo::isPhysicalRegister(RegNo)) { + if (MRI) os << "%" << MRI->get(RegNo).Name; else - os << "%reg" << RegNo; + os << "%mreg(" << RegNo << ")"; } else - os << "%mreg(" << RegNo << ")"; + os << "%reg" << RegNo; } static void print(const MachineOperand &MO, std::ostream &OS, @@ -230,14 +232,14 @@ OS << "=="; } if (MO.hasAllocatedReg()) - OutputReg(OS, MO.getAllocatedRegNum(), MRI); + OutputReg(OS, MO.getReg(), MRI); break; case MachineOperand::MO_CCRegister: OS << "%ccreg"; OutputValue(OS, MO.getVRegValue()); if (MO.hasAllocatedReg()) { OS << "=="; - OutputReg(OS, MO.getAllocatedRegNum(), MRI); + OutputReg(OS, MO.getReg(), MRI); } break; case MachineOperand::MO_MachineRegister: @@ -290,7 +292,7 @@ // Specialize printing if op#0 is definition if (getNumOperands() && getOperand(0).isDef() && !getOperand(0).isUse()) { - llvm::print(getOperand(0), OS, TM); + ::print(getOperand(0), OS, TM); OS << " = "; ++StartOp; // Don't print this operand again! } @@ -301,7 +303,7 @@ if (i != StartOp) OS << ","; OS << " "; - llvm::print(mop, OS, TM); + ::print(mop, OS, TM); if (mop.isDef()) if (mop.isUse()) @@ -327,10 +329,19 @@ OS << "\n"; } +namespace llvm { +std::ostream &operator<<(std::ostream &os, const MachineInstr &MI) { + // If the instruction is embedded into a basic block, we can find the target + // info for the instruction. + if (const MachineBasicBlock *MBB = MI.getParent()) { + const MachineFunction *MF = MBB->getParent(); + MI.print(os, MF->getTarget()); + return os; + } -std::ostream &operator<<(std::ostream& os, const MachineInstr& MI) -{ - os << TargetInstrDescriptors[MI.opCode].Name; + // Otherwise, print it out in the "raw" format without symbolic register names + // and such. + os << TargetInstrDescriptors[MI.getOpcode()].Name; for (unsigned i=0, N=MI.getNumOperands(); i < N; i++) { os << "\t" << MI.getOperand(i); @@ -359,8 +370,7 @@ return os << "\n"; } -std::ostream &operator<<(std::ostream &OS, const MachineOperand &MO) -{ +std::ostream &operator<<(std::ostream &OS, const MachineOperand &MO) { if (MO.isHiBits32()) OS << "%lm("; else if (MO.isLoBits32()) @@ -374,7 +384,7 @@ { case MachineOperand::MO_VirtualRegister: if (MO.hasAllocatedReg()) - OutputReg(OS, MO.getAllocatedRegNum()); + OutputReg(OS, MO.getReg()); if (MO.getVRegValue()) { if (MO.hasAllocatedReg()) OS << "=="; @@ -387,7 +397,7 @@ OutputValue(OS, MO.getVRegValue()); if (MO.hasAllocatedReg()) { OS << "=="; - OutputReg(OS, MO.getAllocatedRegNum()); + OutputReg(OS, MO.getReg()); } break; case MachineOperand::MO_MachineRegister: @@ -433,12 +443,10 @@ break; } - if (MO.flags & - (MachineOperand::HIFLAG32 | MachineOperand::LOFLAG32 | - MachineOperand::HIFLAG64 | MachineOperand::LOFLAG64)) + if (MO.isHiBits32() || MO.isLoBits32() || MO.isHiBits64() || MO.isLoBits64()) OS << ")"; return OS; } -} // End llvm namespace +} Index: llvm/lib/CodeGen/MachineInstrAnnot.cpp diff -u llvm/lib/CodeGen/MachineInstrAnnot.cpp:1.10 llvm/lib/CodeGen/MachineInstrAnnot.cpp:1.10.4.1 --- llvm/lib/CodeGen/MachineInstrAnnot.cpp:1.10 Tue Nov 11 16:41:32 2003 +++ llvm/lib/CodeGen/MachineInstrAnnot.cpp Mon Mar 1 17:58:13 2004 @@ -12,13 +12,12 @@ // //===----------------------------------------------------------------------===// -#include "llvm/CodeGen/MachineInstrAnnot.h" +#include "../Target/SparcV9/MachineInstrAnnot.h" #include "llvm/CodeGen/InstrSelection.h" #include "llvm/CodeGen/MachineCodeForInstruction.h" #include "llvm/iOther.h" #include "llvm/Type.h" - -namespace llvm { +using namespace llvm; CallArgsDescriptor::CallArgsDescriptor(CallInst* _callInstr, TmpInstruction* _retAddrReg, @@ -77,5 +76,3 @@ assert(desc->getCallInst()==callInstr && "Incorrect call args descriptor?"); return desc; } - -} // End llvm namespace Index: llvm/lib/CodeGen/PHIElimination.cpp diff -u llvm/lib/CodeGen/PHIElimination.cpp:1.14 llvm/lib/CodeGen/PHIElimination.cpp:1.14.2.1 --- llvm/lib/CodeGen/PHIElimination.cpp:1.14 Sun Dec 14 07:24:17 2003 +++ llvm/lib/CodeGen/PHIElimination.cpp Mon Mar 1 17:58:13 2004 @@ -13,6 +13,7 @@ // //===----------------------------------------------------------------------===// +#include "llvm/CodeGen/Passes.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/SSARegMap.h" @@ -20,8 +21,8 @@ #include "llvm/Target/TargetInstrInfo.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Support/CFG.h" - -namespace llvm { +#include "Support/STLExtras.h" +using namespace llvm; namespace { struct PNE : public MachineFunctionPass { @@ -55,28 +56,28 @@ } -const PassInfo *PHIEliminationID = X.getPassInfo(); +const PassInfo *llvm::PHIEliminationID = X.getPassInfo(); /// EliminatePHINodes - Eliminate phi nodes by inserting copy instructions in /// predecessor basic blocks. /// bool PNE::EliminatePHINodes(MachineFunction &MF, MachineBasicBlock &MBB) { - if (MBB.empty() || MBB.front()->getOpcode() != TargetInstrInfo::PHI) + if (MBB.empty() || MBB.front().getOpcode() != TargetInstrInfo::PHI) return false; // Quick exit for normal case... LiveVariables *LV = getAnalysisToUpdate(); const TargetInstrInfo &MII = MF.getTarget().getInstrInfo(); const MRegisterInfo *RegInfo = MF.getTarget().getRegisterInfo(); - while (MBB.front()->getOpcode() == TargetInstrInfo::PHI) { - MachineInstr *MI = MBB.front(); + while (MBB.front().getOpcode() == TargetInstrInfo::PHI) { // Unlink the PHI node from the basic block... but don't delete the PHI yet - MBB.erase(MBB.begin()); - - assert(MI->getOperand(0).isVirtualRegister() && + MachineBasicBlock::iterator begin = MBB.begin(); + MachineInstr *MI = MBB.remove(begin); + + assert(MRegisterInfo::isVirtualRegister(MI->getOperand(0).getReg()) && "PHI node doesn't write virt reg?"); - unsigned DestReg = MI->getOperand(0).getAllocatedRegNum(); + unsigned DestReg = MI->getOperand(0).getReg(); // Create a new register for the incoming PHI arguments const TargetRegisterClass *RC = MF.getSSARegMap()->getRegClass(DestReg); @@ -88,13 +89,13 @@ // MachineBasicBlock::iterator AfterPHIsIt = MBB.begin(); while (AfterPHIsIt != MBB.end() && - (*AfterPHIsIt)->getOpcode() == TargetInstrInfo::PHI) + AfterPHIsIt->getOpcode() == TargetInstrInfo::PHI) ++AfterPHIsIt; // Skip over all of the PHI nodes... RegInfo->copyRegToReg(MBB, AfterPHIsIt, DestReg, IncomingReg, RC); // Update live variable information if there is any... if (LV) { - MachineInstr *PHICopy = *(AfterPHIsIt-1); + MachineInstr *PHICopy = --AfterPHIsIt; // Add information to LiveVariables to know that the incoming value is // killed. Note that because the value is defined in several places (once @@ -142,22 +143,7 @@ // source path the PHI. MachineBasicBlock &opBlock = *MI->getOperand(i).getMachineBasicBlock(); - // Figure out where to insert the copy, which is at the end of the - // predecessor basic block, but before any terminator/branch - // instructions... - MachineBasicBlock::iterator I = opBlock.end(); - if (I != opBlock.begin()) { // Handle empty blocks - --I; - // must backtrack over ALL the branches in the previous block - while (MII.isTerminatorInstr((*I)->getOpcode()) && - I != opBlock.begin()) - --I; - - // move back to the first branch instruction so new instructions - // are inserted right in front of it and not in front of a non-branch - if (!MII.isTerminatorInstr((*I)->getOpcode())) - ++I; - } + MachineBasicBlock::iterator I = opBlock.getFirstTerminator(); // Check to make sure we haven't already emitted the copy for this block. // This can happen because PHI nodes may have multiple entries for the @@ -171,10 +157,10 @@ bool HaveNotEmitted = true; if (I != opBlock.begin()) { - MachineInstr *PrevInst = *(I-1); + MachineBasicBlock::iterator PrevInst = prior(I); for (unsigned i = 0, e = PrevInst->getNumOperands(); i != e; ++i) { MachineOperand &MO = PrevInst->getOperand(i); - if (MO.isVirtualRegister() && MO.getReg() == IncomingReg) + if (MO.isRegister() && MO.getReg() == IncomingReg) if (MO.isDef()) { HaveNotEmitted = false; break; @@ -183,7 +169,7 @@ } if (HaveNotEmitted) { // If the copy has not already been emitted, do it. - assert(opVal.isVirtualRegister() && + assert(MRegisterInfo::isVirtualRegister(opVal.getReg()) && "Machine PHI Operands must all be virtual registers!"); unsigned SrcReg = opVal.getReg(); RegInfo->copyRegToReg(opBlock, I, IncomingReg, SrcReg, RC); @@ -238,10 +224,10 @@ // Loop over all of the PHIs in this successor, checking to see if // the register is being used... for (MachineBasicBlock::iterator BBI = MBB->begin(), E=MBB->end(); - BBI != E && (*BBI)->getOpcode() == TargetInstrInfo::PHI; + BBI != E && BBI->getOpcode() == TargetInstrInfo::PHI; ++BBI) - for (unsigned i = 1, e = (*BBI)->getNumOperands(); i < e; i += 2) - if ((*BBI)->getOperand(i).getReg() == SrcReg) { + for (unsigned i = 1, e = BBI->getNumOperands(); i < e; i += 2) + if (BBI->getOperand(i).getReg() == SrcReg) { ValueIsLive = true; break; } @@ -251,8 +237,10 @@ // we can add a kill marker to the copy we inserted saying that it // kills the incoming value! // - if (!ValueIsLive) - LV->addVirtualRegisterKilled(SrcReg, &opBlock, *(I-1)); + if (!ValueIsLive) { + MachineBasicBlock::iterator Prev = prior(I); + LV->addVirtualRegisterKilled(SrcReg, &opBlock, Prev); + } } } } @@ -260,8 +248,5 @@ // really delete the PHI instruction now! delete MI; } - return true; } - -} // End llvm namespace Index: llvm/lib/CodeGen/Passes.cpp diff -u llvm/lib/CodeGen/Passes.cpp:1.5 llvm/lib/CodeGen/Passes.cpp:1.5.2.1 --- llvm/lib/CodeGen/Passes.cpp:1.5 Sun Dec 28 01:59:53 2003 +++ llvm/lib/CodeGen/Passes.cpp Mon Mar 1 17:58:13 2004 @@ -26,7 +26,7 @@ cl::Prefix, cl::values(clEnumVal(simple, " simple register allocator"), clEnumVal(local, " local register allocator"), - clEnumVal(linearscan, " linear-scan global register allocator"), + clEnumVal(linearscan, " linear scan register allocator (experimental)"), 0), cl::init(local)); } Index: llvm/lib/CodeGen/PrologEpilogInserter.cpp diff -u llvm/lib/CodeGen/PrologEpilogInserter.cpp:1.16 llvm/lib/CodeGen/PrologEpilogInserter.cpp:1.16.2.1 --- llvm/lib/CodeGen/PrologEpilogInserter.cpp:1.16 Sun Dec 14 07:24:16 2003 +++ llvm/lib/CodeGen/PrologEpilogInserter.cpp Mon Mar 1 17:58:13 2004 @@ -24,8 +24,7 @@ #include "llvm/Target/MRegisterInfo.h" #include "llvm/Target/TargetFrameInfo.h" #include "llvm/Target/TargetInstrInfo.h" - -namespace llvm { +using namespace llvm; namespace { struct PEI : public MachineFunctionPass { @@ -72,7 +71,7 @@ /// createPrologEpilogCodeInserter - This function returns a pass that inserts /// prolog and epilog code, and eliminates abstract frame references. /// -FunctionPass *createPrologEpilogCodeInserter() { return new PEI(); } +FunctionPass *llvm::createPrologEpilogCodeInserter() { return new PEI(); } /// saveCallerSavedRegisters - Scan the function for modified caller saved @@ -99,28 +98,29 @@ return; // This bitset contains an entry for each physical register for the target... - std::vector ModifiedRegs(MRegisterInfo::FirstVirtualRegister); + std::vector ModifiedRegs(RegInfo->getNumRegs()); unsigned MaxCallFrameSize = 0; bool HasCalls = false; for (MachineFunction::iterator BB = Fn.begin(), E = Fn.end(); BB != E; ++BB) for (MachineBasicBlock::iterator I = BB->begin(); I != BB->end(); ) - if ((*I)->getOpcode() == FrameSetupOpcode || - (*I)->getOpcode() == FrameDestroyOpcode) { - assert((*I)->getNumOperands() == 1 && "Call Frame Setup/Destroy Pseudo" + if (I->getOpcode() == FrameSetupOpcode || + I->getOpcode() == FrameDestroyOpcode) { + assert(I->getNumOperands() == 1 && "Call Frame Setup/Destroy Pseudo" " instructions should have a single immediate argument!"); - unsigned Size = (*I)->getOperand(0).getImmedValue(); + unsigned Size = I->getOperand(0).getImmedValue(); if (Size > MaxCallFrameSize) MaxCallFrameSize = Size; HasCalls = true; - RegInfo->eliminateCallFramePseudoInstr(Fn, *BB, I); + RegInfo->eliminateCallFramePseudoInstr(Fn, *BB, I++); } else { - for (unsigned i = 0, e = (*I)->getNumOperands(); i != e; ++i) { - MachineOperand &MO = (*I)->getOperand(i); - assert(!MO.isVirtualRegister() && - "Register allocation must be performed!"); - if (MO.isPhysicalRegister() && MO.isDef()) + for (unsigned i = 0, e = I->getNumOperands(); i != e; ++i) { + MachineOperand &MO = I->getOperand(i); + if (MO.isRegister() && MO.isDef()) { + assert(MRegisterInfo::isPhysicalRegister(MO.getReg()) && + "Register allocation must be performed!"); ModifiedRegs[MO.getReg()] = true; // Register is modified - } + } + } ++I; } @@ -173,8 +173,9 @@ const TargetInstrInfo &TII = Fn.getTarget().getInstrInfo(); for (MachineFunction::iterator FI = Fn.begin(), E = Fn.end(); FI != E; ++FI) { // If last instruction is a return instruction, add an epilogue - if (!FI->empty() && TII.isReturn(FI->back()->getOpcode())) { - MBB = FI; I = MBB->end()-1; + if (!FI->empty() && TII.isReturn(FI->back().getOpcode())) { + MBB = FI; + I = MBB->end(); --I; for (unsigned i = 0, e = RegsToSave.size(); i != e; ++i) { const TargetRegisterClass *RC = RegInfo->getRegClass(RegsToSave[i]); @@ -201,8 +202,18 @@ unsigned StackAlignment = TFI.getStackAlignment(); - // Start at the beginning of the local area... + // Start at the beginning of the local area. int Offset = TFI.getOffsetOfLocalArea(); + + // Check to see if there are any fixed sized objects that are preallocated in + // the local area. We currently don't support filling in holes in between + // fixed sized objects, so we just skip to the end of the last fixed sized + // preallocated object. + for (int i = FFI->getObjectIndexBegin(); i != 0; ++i) { + int FixedOff = -FFI->getObjectOffset(i); + if (FixedOff > Offset) Offset = FixedOff; + } + for (unsigned i = 0, e = FFI->getObjectIndexEnd(); i != e; ++i) { Offset += FFI->getObjectSize(i); // Allocate Size bytes... @@ -214,8 +225,11 @@ FFI->setObjectOffset(i, -Offset); // Set the computed offset } - // Align the final stack pointer offset... - Offset = (Offset+StackAlignment-1)/StackAlignment*StackAlignment; + // Align the final stack pointer offset, but only if there are calls in the + // function. This ensures that any calls to subroutines have their stack + // frames suitable aligned. + if (FFI->hasCalls()) + Offset = (Offset+StackAlignment-1)/StackAlignment*StackAlignment; // Set the final value of the stack pointer... FFI->setStackSize(Offset-TFI.getOffsetOfLocalArea()); @@ -234,7 +248,7 @@ const TargetInstrInfo &TII = Fn.getTarget().getInstrInfo(); for (MachineFunction::iterator I = Fn.begin(), E = Fn.end(); I != E; ++I) { // If last instruction is a return instruction, add an epilogue - if (!I->empty() && TII.isReturn(I->back()->getOpcode())) + if (!I->empty() && TII.isReturn(I->back().getOpcode())) Fn.getTarget().getRegisterInfo()->emitEpilogue(Fn, *I); } } @@ -252,13 +266,11 @@ for (MachineFunction::iterator BB = Fn.begin(), E = Fn.end(); BB != E; ++BB) for (MachineBasicBlock::iterator I = BB->begin(); I != BB->end(); ++I) - for (unsigned i = 0, e = (*I)->getNumOperands(); i != e; ++i) - if ((*I)->getOperand(i).isFrameIndex()) { + for (unsigned i = 0, e = I->getNumOperands(); i != e; ++i) + if (I->getOperand(i).isFrameIndex()) { // If this instruction has a FrameIndex operand, we need to use that // target machine register info object to eliminate it. MRI.eliminateFrameIndex(Fn, I); break; } } - -} // End llvm namespace Index: llvm/lib/CodeGen/RegAllocLinearScan.cpp diff -u llvm/lib/CodeGen/RegAllocLinearScan.cpp:1.31 llvm/lib/CodeGen/RegAllocLinearScan.cpp:1.31.2.1 --- llvm/lib/CodeGen/RegAllocLinearScan.cpp:1.31 Fri Jan 16 14:33:13 2004 +++ llvm/lib/CodeGen/RegAllocLinearScan.cpp Mon Mar 1 17:58:13 2004 @@ -10,56 +10,41 @@ // This file implements a linear scan register allocator. // //===----------------------------------------------------------------------===// + #define DEBUG_TYPE "regalloc" #include "llvm/Function.h" -#include "llvm/CodeGen/LiveIntervals.h" #include "llvm/CodeGen/LiveVariables.h" -#include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/Passes.h" #include "llvm/CodeGen/SSARegMap.h" #include "llvm/Target/MRegisterInfo.h" -#include "llvm/Target/TargetInstrInfo.h" #include "llvm/Target/TargetMachine.h" -#include "llvm/Support/CFG.h" #include "Support/Debug.h" -#include "Support/DepthFirstIterator.h" -#include "Support/Statistic.h" -#include "Support/STLExtras.h" +#include "LiveIntervals.h" +#include "PhysRegTracker.h" +#include "VirtRegMap.h" +#include +#include + using namespace llvm; namespace { - Statistic<> numSpilled ("ra-linearscan", "Number of registers spilled"); - Statistic<> numReloaded("ra-linearscan", "Number of registers reloaded"); - class RA : public MachineFunctionPass { private: MachineFunction* mf_; const TargetMachine* tm_; const MRegisterInfo* mri_; - MachineFunction::iterator currentMbb_; - MachineBasicBlock::iterator currentInstr_; - typedef std::vector IntervalPtrs; - IntervalPtrs unhandled_, fixed_, active_, inactive_; - - typedef std::vector Regs; - Regs tempUseOperands_; - Regs tempDefOperands_; - - typedef std::vector RegMask; - RegMask reserved_; - - unsigned regUse_[MRegisterInfo::FirstVirtualRegister]; - unsigned regUseBackup_[MRegisterInfo::FirstVirtualRegister]; + LiveIntervals* li_; + typedef std::list IntervalPtrs; + IntervalPtrs unhandled_, fixed_, active_, inactive_, handled_; + + std::auto_ptr prt_; + std::auto_ptr vrm_; + std::auto_ptr spiller_; - typedef std::map Virt2PhysMap; - Virt2PhysMap v2pMap_; - - typedef std::map Virt2StackSlotMap; - Virt2StackSlotMap v2ssMap_; - - int instrAdded_; + typedef std::vector SpillWeights; + SpillWeights spillWeights_; public: virtual const char* getPassName() const { @@ -72,13 +57,18 @@ MachineFunctionPass::getAnalysisUsage(AU); } - private: /// runOnMachineFunction - register allocate the whole function bool runOnMachineFunction(MachineFunction&); + void releaseMemory(); + + private: + /// linearScan - the linear scan algorithm + void linearScan(); + /// initIntervalSets - initializa the four interval sets: /// unhandled, fixed, active and inactive - void initIntervalSets(const LiveIntervals::Intervals& li); + void initIntervalSets(LiveIntervals::Intervals& li); /// processActiveIntervals - expire old intervals and move /// non-overlapping ones to the incative list @@ -88,11 +78,13 @@ /// overlapping ones to the active list void processInactiveIntervals(IntervalPtrs::value_type cur); - /// assignStackSlotAtInterval - choose and spill - /// interval. Currently we spill the interval with the last - /// end point in the active and inactive lists and the current - /// interval - void assignStackSlotAtInterval(IntervalPtrs::value_type cur); + /// updateSpillWeights - updates the spill weights of the + /// specifed physical register and its weight + void updateSpillWeights(unsigned reg, SpillWeights::value_type weight); + + /// assignRegOrStackSlotAtInterval - assign a register if one + /// is available, or spill. + void assignRegOrStackSlotAtInterval(IntervalPtrs::value_type cur); /// /// register handling helpers @@ -103,321 +95,146 @@ /// 0 unsigned getFreePhysReg(IntervalPtrs::value_type cur); - /// physRegAvailable - returns true if the specifed physical - /// register is available - bool physRegAvailable(unsigned physReg); - - /// tempPhysRegAvailable - returns true if the specifed - /// temporary physical register is available - bool tempPhysRegAvailable(unsigned physReg); - - /// getFreeTempPhysReg - return a free temprorary physical - /// register for this virtual register if we have one (should - /// never return 0) - unsigned getFreeTempPhysReg(unsigned virtReg); - - /// assignVirt2PhysReg - assigns the free physical register to - /// the virtual register passed as arguments - void assignVirt2PhysReg(unsigned virtReg, unsigned physReg); - - /// clearVirtReg - free the physical register associated with this - /// virtual register and disassociate virtual->physical and - /// physical->virtual mappings - void clearVirtReg(unsigned virtReg); - /// assignVirt2StackSlot - assigns this virtual register to a - /// stack slot - void assignVirt2StackSlot(unsigned virtReg); - - /// getStackSlot - returns the offset of the specified - /// register on the stack - int getStackSlot(unsigned virtReg); - - /// spillVirtReg - spills the virtual register - void spillVirtReg(unsigned virtReg); - - /// loadPhysReg - loads to the physical register the value of - /// the virtual register specifed. Virtual register must have - /// an assigned stack slot - void loadVirt2PhysReg(unsigned virtReg, unsigned physReg); - - void markPhysRegFree(unsigned physReg); - void markPhysRegNotFree(unsigned physReg); - - void backupRegUse() { - memcpy(regUseBackup_, regUse_, sizeof(regUseBackup_)); - } - - void restoreRegUse() { - memcpy(regUse_, regUseBackup_, sizeof(regUseBackup_)); - } - - void printVirt2PhysMap() const { - std::cerr << "allocated registers:\n"; - for (Virt2PhysMap::const_iterator - i = v2pMap_.begin(), e = v2pMap_.end(); i != e; ++i) { - std::cerr << '[' << i->first << ',' - << mri_->getName(i->second) << "]\n"; - } - std::cerr << '\n'; - } + /// stack slot. returns the stack slot + int assignVirt2StackSlot(unsigned virtReg); void printIntervals(const char* const str, RA::IntervalPtrs::const_iterator i, RA::IntervalPtrs::const_iterator e) const { if (str) std::cerr << str << " intervals:\n"; for (; i != e; ++i) { - std::cerr << "\t\t" << **i << " -> "; + std::cerr << "\t" << **i << " -> "; unsigned reg = (*i)->reg; - if (reg >= MRegisterInfo::FirstVirtualRegister) { - Virt2PhysMap::const_iterator it = v2pMap_.find(reg); - reg = (it == v2pMap_.end() ? 0 : it->second); + if (MRegisterInfo::isVirtualRegister(reg)) { + reg = vrm_->getPhys(reg); } std::cerr << mri_->getName(reg) << '\n'; } } - void printFreeRegs(const char* const str, - const TargetRegisterClass* rc) const { - if (str) std::cerr << str << ':'; - for (TargetRegisterClass::iterator i = - rc->allocation_order_begin(*mf_); - i != rc->allocation_order_end(*mf_); ++i) { - unsigned reg = *i; - if (!regUse_[reg]) { - std::cerr << ' ' << mri_->getName(reg); - if (reserved_[reg]) std::cerr << "*"; - } - } - std::cerr << '\n'; - } +// void verifyAssignment() const { +// for (Virt2PhysMap::const_iterator i = v2pMap_.begin(), +// e = v2pMap_.end(); i != e; ++i) +// for (Virt2PhysMap::const_iterator i2 = next(i); i2 != e; ++i2) +// if (MRegisterInfo::isVirtualRegister(i->second) && +// (i->second == i2->second || +// mri_->areAliases(i->second, i2->second))) { +// const LiveIntervals::Interval +// &in = li_->getInterval(i->second), +// &in2 = li_->getInterval(i2->second); +// if (in.overlaps(in2)) { +// std::cerr << in << " overlaps " << in2 << '\n'; +// assert(0); +// } +// } +// } }; } +void RA::releaseMemory() +{ + unhandled_.clear(); + active_.clear(); + inactive_.clear(); + fixed_.clear(); + handled_.clear(); +} + bool RA::runOnMachineFunction(MachineFunction &fn) { mf_ = &fn; tm_ = &fn.getTarget(); mri_ = tm_->getRegisterInfo(); + li_ = &getAnalysis(); + if (!prt_.get()) prt_.reset(new PhysRegTracker(*mri_)); + vrm_.reset(new VirtRegMap(*mf_)); + if (!spiller_.get()) spiller_.reset(createSpiller()); - initIntervalSets(getAnalysis().getIntervals()); + initIntervalSets(li_->getIntervals()); - v2pMap_.clear(); - v2ssMap_.clear(); - memset(regUse_, 0, sizeof(regUse_)); - memset(regUseBackup_, 0, sizeof(regUseBackup_)); - - // FIXME: this will work only for the X86 backend. I need to - // device an algorthm to select the minimal (considering register - // aliasing) number of temp registers to reserve so that we have 2 - // registers for each register class available. - - // reserve R8: CH, CL - // R16: CX, DI, - // R32: ECX, EDI, - // RFP: FP5, FP6 - reserved_.assign(MRegisterInfo::FirstVirtualRegister, false); - reserved_[ 8] = true; /* CH */ - reserved_[ 9] = true; /* CL */ - reserved_[10] = true; /* CX */ - reserved_[12] = true; /* DI */ - reserved_[18] = true; /* ECX */ - reserved_[19] = true; /* EDI */ - reserved_[28] = true; /* FP5 */ - reserved_[29] = true; /* FP6 */ + linearScan(); - // linear scan algorithm + spiller_->runOnMachineFunction(*mf_, *vrm_); - DEBUG(printIntervals("\tunhandled", unhandled_.begin(), unhandled_.end())); - DEBUG(printIntervals("\tfixed", fixed_.begin(), fixed_.end())); - DEBUG(printIntervals("\tactive", active_.begin(), active_.end())); - DEBUG(printIntervals("\tinactive", inactive_.begin(), inactive_.end())); + return true; +} + +void RA::linearScan() +{ + // linear scan algorithm + DEBUG(std::cerr << "********** LINEAR SCAN **********\n"); + DEBUG(std::cerr << "********** Function: " + << mf_->getFunction()->getName() << '\n'); + + DEBUG(printIntervals("unhandled", unhandled_.begin(), unhandled_.end())); + DEBUG(printIntervals("fixed", fixed_.begin(), fixed_.end())); + DEBUG(printIntervals("active", active_.begin(), active_.end())); + DEBUG(printIntervals("inactive", inactive_.begin(), inactive_.end())); while (!unhandled_.empty() || !fixed_.empty()) { // pick the interval with the earliest start point IntervalPtrs::value_type cur; if (fixed_.empty()) { cur = unhandled_.front(); - unhandled_.erase(unhandled_.begin()); + unhandled_.pop_front(); } else if (unhandled_.empty()) { cur = fixed_.front(); - fixed_.erase(fixed_.begin()); + fixed_.pop_front(); } else if (unhandled_.front()->start() < fixed_.front()->start()) { cur = unhandled_.front(); - unhandled_.erase(unhandled_.begin()); + unhandled_.pop_front(); } else { cur = fixed_.front(); - fixed_.erase(fixed_.begin()); + fixed_.pop_front(); } - DEBUG(std::cerr << *cur << '\n'); + DEBUG(std::cerr << "\n*** CURRENT ***: " << *cur << '\n'); processActiveIntervals(cur); processInactiveIntervals(cur); // if this register is fixed we are done - if (cur->reg < MRegisterInfo::FirstVirtualRegister) { - markPhysRegNotFree(cur->reg); + if (MRegisterInfo::isPhysicalRegister(cur->reg)) { + prt_->addRegUse(cur->reg); active_.push_back(cur); + handled_.push_back(cur); } // otherwise we are allocating a virtual register. try to find // a free physical register or spill an interval in order to // assign it one (we could spill the current though). else { - backupRegUse(); - - // for every interval in inactive we overlap with, mark the - // register as not free - for (IntervalPtrs::const_iterator i = inactive_.begin(), - e = inactive_.end(); i != e; ++i) { - unsigned reg = (*i)->reg; - if (reg >= MRegisterInfo::FirstVirtualRegister) - reg = v2pMap_[reg]; - - if (cur->overlaps(**i)) { - markPhysRegNotFree(reg); - } - } - - // for every interval in fixed we overlap with, - // mark the register as not free - for (IntervalPtrs::const_iterator i = fixed_.begin(), - e = fixed_.end(); i != e; ++i) { - assert((*i)->reg < MRegisterInfo::FirstVirtualRegister && - "virtual register interval in fixed set?"); - if (cur->overlaps(**i)) - markPhysRegNotFree((*i)->reg); - } - - DEBUG(std::cerr << "\tallocating current interval:\n"); - - unsigned physReg = getFreePhysReg(cur); - if (!physReg) { - assignStackSlotAtInterval(cur); - } - else { - restoreRegUse(); - assignVirt2PhysReg(cur->reg, physReg); - active_.push_back(cur); - } + assignRegOrStackSlotAtInterval(cur); } - DEBUG(printIntervals("\tactive", active_.begin(), active_.end())); - DEBUG(printIntervals("\tinactive", inactive_.begin(), inactive_.end())); } + DEBUG(printIntervals("active", active_.begin(), active_.end())); + DEBUG(printIntervals("inactive", inactive_.begin(), inactive_.end())); + // DEBUG(verifyAssignment()); + } // expire any remaining active intervals for (IntervalPtrs::iterator i = active_.begin(); i != active_.end(); ++i) { unsigned reg = (*i)->reg; - DEBUG(std::cerr << "\t\tinterval " << **i << " expired\n"); - if (reg >= MRegisterInfo::FirstVirtualRegister) { - reg = v2pMap_[reg]; - } - markPhysRegFree(reg); - } - active_.clear(); - inactive_.clear(); - - DEBUG(std::cerr << "finished register allocation\n"); - DEBUG(printVirt2PhysMap()); - - DEBUG(std::cerr << "Rewrite machine code:\n"); - for (currentMbb_ = mf_->begin(); currentMbb_ != mf_->end(); ++currentMbb_) { - instrAdded_ = 0; - - for (currentInstr_ = currentMbb_->begin(); - currentInstr_ != currentMbb_->end(); ++currentInstr_) { - - DEBUG(std::cerr << "\tinstruction: "; - (*currentInstr_)->print(std::cerr, *tm_);); - - // use our current mapping and actually replace and - // virtual register with its allocated physical registers - DEBUG(std::cerr << "\t\treplacing virtual registers with mapped " - "physical registers:\n"); - for (unsigned i = 0, e = (*currentInstr_)->getNumOperands(); - i != e; ++i) { - MachineOperand& op = (*currentInstr_)->getOperand(i); - if (op.isVirtualRegister()) { - unsigned virtReg = op.getAllocatedRegNum(); - unsigned physReg = v2pMap_[virtReg]; - if (physReg) { - DEBUG(std::cerr << "\t\t\t%reg" << virtReg - << " -> " << mri_->getName(physReg) << '\n'); - (*currentInstr_)->SetMachineOperandReg(i, physReg); - } - } - } - - DEBUG(std::cerr << "\t\tloading temporarily used operands to " - "registers:\n"); - for (unsigned i = 0, e = (*currentInstr_)->getNumOperands(); - i != e; ++i) { - MachineOperand& op = (*currentInstr_)->getOperand(i); - if (op.isVirtualRegister() && op.isUse() && !op.isDef()) { - unsigned virtReg = op.getAllocatedRegNum(); - unsigned physReg = v2pMap_[virtReg]; - if (!physReg) { - physReg = getFreeTempPhysReg(virtReg); - loadVirt2PhysReg(virtReg, physReg); - tempUseOperands_.push_back(virtReg); - } - (*currentInstr_)->SetMachineOperandReg(i, physReg); - } - } - - DEBUG(std::cerr << "\t\tclearing temporarily used operands:\n"); - for (unsigned i = 0, e = tempUseOperands_.size(); i != e; ++i) { - clearVirtReg(tempUseOperands_[i]); - } - tempUseOperands_.clear(); - - DEBUG(std::cerr << "\t\tassigning temporarily defined operands to " - "registers:\n"); - for (unsigned i = 0, e = (*currentInstr_)->getNumOperands(); - i != e; ++i) { - MachineOperand& op = (*currentInstr_)->getOperand(i); - if (op.isVirtualRegister() && op.isDef()) { - unsigned virtReg = op.getAllocatedRegNum(); - unsigned physReg = v2pMap_[virtReg]; - if (!physReg) { - physReg = getFreeTempPhysReg(virtReg); - } - if (op.isUse()) { // def and use - loadVirt2PhysReg(virtReg, physReg); - } - else { - assignVirt2PhysReg(virtReg, physReg); - } - tempDefOperands_.push_back(virtReg); - (*currentInstr_)->SetMachineOperandReg(i, physReg); - } - } - - DEBUG(std::cerr << "\t\tspilling temporarily defined operands " - "of this instruction:\n"); - ++currentInstr_; // we want to insert after this instruction - for (unsigned i = 0, e = tempDefOperands_.size(); i != e; ++i) { - spillVirtReg(tempDefOperands_[i]); - } - --currentInstr_; // restore currentInstr_ iterator - tempDefOperands_.clear(); - } + DEBUG(std::cerr << "\tinterval " << **i << " expired\n"); + if (MRegisterInfo::isVirtualRegister(reg)) + reg = vrm_->getPhys(reg); + prt_->delRegUse(reg); } - return true; + DEBUG(std::cerr << *vrm_); } -void RA::initIntervalSets(const LiveIntervals::Intervals& li) +void RA::initIntervalSets(LiveIntervals::Intervals& li) { assert(unhandled_.empty() && fixed_.empty() && active_.empty() && inactive_.empty() && "interval sets should be empty on initialization"); - for (LiveIntervals::Intervals::const_iterator i = li.begin(), e = li.end(); + for (LiveIntervals::Intervals::iterator i = li.begin(), e = li.end(); i != e; ++i) { - if (i->reg < MRegisterInfo::FirstVirtualRegister) + if (MRegisterInfo::isPhysicalRegister(i->reg)) fixed_.push_back(&*i); else unhandled_.push_back(&*i); @@ -432,20 +249,18 @@ // remove expired intervals if ((*i)->expiredAt(cur->start())) { DEBUG(std::cerr << "\t\tinterval " << **i << " expired\n"); - if (reg >= MRegisterInfo::FirstVirtualRegister) { - reg = v2pMap_[reg]; - } - markPhysRegFree(reg); + if (MRegisterInfo::isVirtualRegister(reg)) + reg = vrm_->getPhys(reg); + prt_->delRegUse(reg); // remove from active i = active_.erase(i); } // move inactive intervals to inactive list else if (!(*i)->liveAt(cur->start())) { - DEBUG(std::cerr << "\t\t\tinterval " << **i << " inactive\n"); - if (reg >= MRegisterInfo::FirstVirtualRegister) { - reg = v2pMap_[reg]; - } - markPhysRegFree(reg); + DEBUG(std::cerr << "\t\tinterval " << **i << " inactive\n"); + if (MRegisterInfo::isVirtualRegister(reg)) + reg = vrm_->getPhys(reg); + prt_->delRegUse(reg); // add to inactive inactive_.push_back(*i); // remove from active @@ -465,17 +280,16 @@ // remove expired intervals if ((*i)->expiredAt(cur->start())) { - DEBUG(std::cerr << "\t\t\tinterval " << **i << " expired\n"); + DEBUG(std::cerr << "\t\tinterval " << **i << " expired\n"); // remove from inactive i = inactive_.erase(i); } // move re-activated intervals in active list else if ((*i)->liveAt(cur->start())) { - DEBUG(std::cerr << "\t\t\tinterval " << **i << " active\n"); - if (reg >= MRegisterInfo::FirstVirtualRegister) { - reg = v2pMap_[reg]; - } - markPhysRegNotFree(reg); + DEBUG(std::cerr << "\t\tinterval " << **i << " active\n"); + if (MRegisterInfo::isVirtualRegister(reg)) + reg = vrm_->getPhys(reg); + prt_->addRegUse(reg); // add to active active_.push_back(*i); // remove from inactive @@ -487,281 +301,237 @@ } } -namespace { - template - void updateWeight(T rw[], int reg, T w) - { - if (rw[reg] == std::numeric_limits::max() || - w == std::numeric_limits::max()) - rw[reg] = std::numeric_limits::max(); - else - rw[reg] += w; - } +void RA::updateSpillWeights(unsigned reg, SpillWeights::value_type weight) +{ + spillWeights_[reg] += weight; + for (const unsigned* as = mri_->getAliasSet(reg); *as; ++as) + spillWeights_[*as] += weight; } -void RA::assignStackSlotAtInterval(IntervalPtrs::value_type cur) +void RA::assignRegOrStackSlotAtInterval(IntervalPtrs::value_type cur) { - DEBUG(std::cerr << "\t\tassigning stack slot at interval " - << *cur << ":\n"); + DEBUG(std::cerr << "\tallocating current interval: "); + + PhysRegTracker backupPrt = *prt_; - // set all weights to zero - float regWeight[MRegisterInfo::FirstVirtualRegister]; - for (unsigned i = 0; i < MRegisterInfo::FirstVirtualRegister; ++i) - regWeight[i] = 0.0F; + spillWeights_.assign(mri_->getNumRegs(), 0.0); - // for each interval in active that overlaps + // for each interval in active update spill weights for (IntervalPtrs::const_iterator i = active_.begin(), e = active_.end(); i != e; ++i) { - if (!cur->overlaps(**i)) - continue; - unsigned reg = (*i)->reg; - if (reg >= MRegisterInfo::FirstVirtualRegister) { - reg = v2pMap_[reg]; - } - updateWeight(regWeight, reg, (*i)->weight); - for (const unsigned* as = mri_->getAliasSet(reg); *as; ++as) - updateWeight(regWeight, *as, (*i)->weight); + if (MRegisterInfo::isVirtualRegister(reg)) + reg = vrm_->getPhys(reg); + updateSpillWeights(reg, (*i)->weight); } - // for each interval in inactive that overlaps + // for every interval in inactive we overlap with, mark the + // register as not free and update spill weights for (IntervalPtrs::const_iterator i = inactive_.begin(), e = inactive_.end(); i != e; ++i) { - if (!cur->overlaps(**i)) - continue; - - unsigned reg = (*i)->reg; - if (reg >= MRegisterInfo::FirstVirtualRegister) { - reg = v2pMap_[reg]; + if (cur->overlaps(**i)) { + unsigned reg = (*i)->reg; + if (MRegisterInfo::isVirtualRegister(reg)) + reg = vrm_->getPhys(reg); + prt_->addRegUse(reg); + updateSpillWeights(reg, (*i)->weight); } - updateWeight(regWeight, reg, (*i)->weight); - for (const unsigned* as = mri_->getAliasSet(reg); *as; ++as) - updateWeight(regWeight, *as, (*i)->weight); } - // for each fixed interval that overlaps - for (IntervalPtrs::const_iterator i = fixed_.begin(), e = fixed_.end(); - i != e; ++i) { - if (!cur->overlaps(**i)) - continue; + // for every interval in fixed we overlap with, + // mark the register as not free and update spill weights + for (IntervalPtrs::const_iterator i = fixed_.begin(), + e = fixed_.end(); i != e; ++i) { + if (cur->overlaps(**i)) { + unsigned reg = (*i)->reg; + prt_->addRegUse(reg); + updateSpillWeights(reg, (*i)->weight); + } + } - assert((*i)->reg < MRegisterInfo::FirstVirtualRegister && - "virtual register interval in fixed set?"); - updateWeight(regWeight, (*i)->reg, (*i)->weight); - for (const unsigned* as = mri_->getAliasSet((*i)->reg); *as; ++as) - updateWeight(regWeight, *as, (*i)->weight); + unsigned physReg = getFreePhysReg(cur); + // restore the physical register tracker + *prt_ = backupPrt; + // if we find a free register, we are done: assign this virtual to + // the free physical register and add this interval to the active + // list. + if (physReg) { + DEBUG(std::cerr << mri_->getName(physReg) << '\n'); + vrm_->assignVirt2Phys(cur->reg, physReg); + prt_->addRegUse(physReg); + active_.push_back(cur); + handled_.push_back(cur); + return; } + DEBUG(std::cerr << "no free registers\n"); + + DEBUG(std::cerr << "\tassigning stack slot at interval "<< *cur << ":\n"); - float minWeight = std::numeric_limits::max(); + float minWeight = std::numeric_limits::infinity(); unsigned minReg = 0; const TargetRegisterClass* rc = mf_->getSSARegMap()->getRegClass(cur->reg); for (TargetRegisterClass::iterator i = rc->allocation_order_begin(*mf_); i != rc->allocation_order_end(*mf_); ++i) { unsigned reg = *i; - if (!reserved_[reg] && minWeight > regWeight[reg]) { - minWeight = regWeight[reg]; + if (minWeight > spillWeights_[reg]) { + minWeight = spillWeights_[reg]; minReg = reg; } } + DEBUG(std::cerr << "\t\tregister with min weight: " + << mri_->getName(minReg) << " (" << minWeight << ")\n"); - if (cur->weight < minWeight) { - restoreRegUse(); - DEBUG(std::cerr << "\t\t\t\tspilling: " << *cur << '\n'); - assignVirt2StackSlot(cur->reg); - } - else { - DEBUG(std::cerr << "\t\t\t\tfreeing: " << mri_->getName(minReg) << '\n'); - std::set toSpill; - toSpill.insert(minReg); - for (const unsigned* as = mri_->getAliasSet(minReg); *as; ++as) - toSpill.insert(*as); - - std::vector spilled; - for (IntervalPtrs::iterator i = active_.begin(); - i != active_.end(); ) { - unsigned reg = (*i)->reg; - if (reg >= MRegisterInfo::FirstVirtualRegister && - toSpill.find(v2pMap_[reg]) != toSpill.end() && - cur->overlaps(**i)) { - spilled.push_back(v2pMap_[reg]); - DEBUG(std::cerr << "\t\t\t\tspilling : " << **i << '\n'); - assignVirt2StackSlot(reg); - i = active_.erase(i); + // if the current has the minimum weight, we need to modify it, + // push it back in unhandled and let the linear scan algorithm run + // again + if (cur->weight <= minWeight) { + DEBUG(std::cerr << "\t\t\tspilling(c): " << *cur << '\n';); + int slot = vrm_->assignVirt2StackSlot(cur->reg); + li_->updateSpilledInterval(*cur, *vrm_, slot); + + // if we didn't eliminate the interval find where to add it + // back to unhandled. We need to scan since unhandled are + // sorted on earliest start point and we may have changed our + // start point. + if (!cur->empty()) { + IntervalPtrs::iterator it = unhandled_.begin(); + while (it != unhandled_.end() && (*it)->start() < cur->start()) + ++it; + unhandled_.insert(it, cur); + } + return; + } + + // push the current interval back to unhandled since we are going + // to re-run at least this iteration. Since we didn't modify it it + // should go back right in the front of the list + unhandled_.push_front(cur); + + // otherwise we spill all intervals aliasing the register with + // minimum weight, rollback to the interval with the earliest + // start point and let the linear scan algorithm run again + assert(MRegisterInfo::isPhysicalRegister(minReg) && + "did not choose a register to spill?"); + std::vector toSpill(mri_->getNumRegs(), false); + toSpill[minReg] = true; + for (const unsigned* as = mri_->getAliasSet(minReg); *as; ++as) + toSpill[*as] = true; + unsigned earliestStart = cur->start(); + + for (IntervalPtrs::iterator i = active_.begin(); i != active_.end(); ++i) { + unsigned reg = (*i)->reg; + if (MRegisterInfo::isVirtualRegister(reg) && + toSpill[vrm_->getPhys(reg)] && + cur->overlaps(**i)) { + DEBUG(std::cerr << "\t\t\tspilling(a): " << **i << '\n'); + earliestStart = std::min(earliestStart, (*i)->start()); + int slot = vrm_->assignVirt2StackSlot((*i)->reg); + li_->updateSpilledInterval(**i, *vrm_, slot); + } + } + for (IntervalPtrs::iterator i = inactive_.begin(); + i != inactive_.end(); ++i) { + unsigned reg = (*i)->reg; + if (MRegisterInfo::isVirtualRegister(reg) && + toSpill[vrm_->getPhys(reg)] && + cur->overlaps(**i)) { + DEBUG(std::cerr << "\t\t\tspilling(i): " << **i << '\n'); + earliestStart = std::min(earliestStart, (*i)->start()); + int slot = vrm_->assignVirt2StackSlot((*i)->reg); + li_->updateSpilledInterval(**i, *vrm_, slot); + } + } + + DEBUG(std::cerr << "\t\trolling back to: " << earliestStart << '\n'); + // scan handled in reverse order and undo each one, restoring the + // state of unhandled and fixed + while (!handled_.empty()) { + IntervalPtrs::value_type i = handled_.back(); + // if this interval starts before t we are done + if (!i->empty() && i->start() < earliestStart) + break; + DEBUG(std::cerr << "\t\t\tundo changes for: " << *i << '\n'); + handled_.pop_back(); + IntervalPtrs::iterator it; + if ((it = find(active_.begin(), active_.end(), i)) != active_.end()) { + active_.erase(it); + if (MRegisterInfo::isPhysicalRegister(i->reg)) { + fixed_.push_front(i); + prt_->delRegUse(i->reg); } else { - ++i; + prt_->delRegUse(vrm_->getPhys(i->reg)); + vrm_->clearVirt(i->reg); + if (i->spilled()) { + if (!i->empty()) { + IntervalPtrs::iterator it = unhandled_.begin(); + while (it != unhandled_.end() && + (*it)->start() < i->start()) + ++it; + unhandled_.insert(it, i); + } + } + else + unhandled_.push_front(i); + } } - for (IntervalPtrs::iterator i = inactive_.begin(); - i != inactive_.end(); ) { - unsigned reg = (*i)->reg; - if (reg >= MRegisterInfo::FirstVirtualRegister && - toSpill.find(v2pMap_[reg]) != toSpill.end() && - cur->overlaps(**i)) { - DEBUG(std::cerr << "\t\t\t\tspilling : " << **i << '\n'); - assignVirt2StackSlot(reg); - i = inactive_.erase(i); + else if ((it = find(inactive_.begin(), inactive_.end(), i)) != inactive_.end()) { + inactive_.erase(it); + if (MRegisterInfo::isPhysicalRegister(i->reg)) + fixed_.push_front(i); + else { + vrm_->clearVirt(i->reg); + if (i->spilled()) { + if (!i->empty()) { + IntervalPtrs::iterator it = unhandled_.begin(); + while (it != unhandled_.end() && + (*it)->start() < i->start()) + ++it; + unhandled_.insert(it, i); + } + } + else + unhandled_.push_front(i); } + } + else { + if (MRegisterInfo::isPhysicalRegister(i->reg)) + fixed_.push_front(i); else { - ++i; + vrm_->clearVirt(i->reg); + unhandled_.push_front(i); } } - - unsigned physReg = getFreePhysReg(cur); - assert(physReg && "no free physical register after spill?"); - - restoreRegUse(); - for (unsigned i = 0; i < spilled.size(); ++i) - markPhysRegFree(spilled[i]); - - assignVirt2PhysReg(cur->reg, physReg); - active_.push_back(cur); } -} - -bool RA::physRegAvailable(unsigned physReg) -{ - assert(!reserved_[physReg] && - "cannot call this method with a reserved register"); - return !regUse_[physReg]; + // scan the rest and undo each interval that expired after t and + // insert it in active (the next iteration of the algorithm will + // put it in inactive if required) + IntervalPtrs::iterator i = handled_.begin(), e = handled_.end(); + for (; i != e; ++i) { + if (!(*i)->expiredAt(earliestStart) && (*i)->expiredAt(cur->start())) { + DEBUG(std::cerr << "\t\t\tundo changes for: " << **i << '\n'); + active_.push_back(*i); + if (MRegisterInfo::isPhysicalRegister((*i)->reg)) + prt_->addRegUse((*i)->reg); + else + prt_->addRegUse(vrm_->getPhys((*i)->reg)); + } + } } unsigned RA::getFreePhysReg(IntervalPtrs::value_type cur) { - DEBUG(std::cerr << "\t\tgetting free physical register: "); const TargetRegisterClass* rc = mf_->getSSARegMap()->getRegClass(cur->reg); for (TargetRegisterClass::iterator i = rc->allocation_order_begin(*mf_); i != rc->allocation_order_end(*mf_); ++i) { unsigned reg = *i; - if (!reserved_[reg] && !regUse_[reg]) { - DEBUG(std::cerr << mri_->getName(reg) << '\n'); - return reg; - } - } - - DEBUG(std::cerr << "no free register\n"); - return 0; -} - -bool RA::tempPhysRegAvailable(unsigned physReg) -{ - assert(reserved_[physReg] && - "cannot call this method with a not reserved temp register"); - - return !regUse_[physReg]; -} - -unsigned RA::getFreeTempPhysReg(unsigned virtReg) -{ - DEBUG(std::cerr << "\t\tgetting free temporary physical register: "); - - const TargetRegisterClass* rc = mf_->getSSARegMap()->getRegClass(virtReg); - // go in reverse allocation order for the temp registers - for (TargetRegisterClass::iterator i = rc->allocation_order_end(*mf_) - 1; - i != rc->allocation_order_begin(*mf_) - 1; --i) { - unsigned reg = *i; - if (reserved_[reg] && !regUse_[reg]) { - DEBUG(std::cerr << mri_->getName(reg) << '\n'); + if (prt_->isRegAvail(reg)) return reg; - } } - - assert(0 && "no free temporary physical register?"); return 0; -} - -void RA::assignVirt2PhysReg(unsigned virtReg, unsigned physReg) -{ - v2pMap_[virtReg] = physReg; - markPhysRegNotFree(physReg); -} - -void RA::clearVirtReg(unsigned virtReg) -{ - Virt2PhysMap::iterator it = v2pMap_.find(virtReg); - assert(it != v2pMap_.end() && - "attempting to clear a not allocated virtual register"); - unsigned physReg = it->second; - markPhysRegFree(physReg); - v2pMap_[virtReg] = 0; // this marks that this virtual register - // lives on the stack - DEBUG(std::cerr << "\t\t\tcleared register " << mri_->getName(physReg) - << "\n"); -} - -void RA::assignVirt2StackSlot(unsigned virtReg) -{ - const TargetRegisterClass* rc = mf_->getSSARegMap()->getRegClass(virtReg); - int frameIndex = mf_->getFrameInfo()->CreateStackObject(rc); - - bool inserted = v2ssMap_.insert(std::make_pair(virtReg, frameIndex)).second; - assert(inserted && - "attempt to assign stack slot to already assigned register?"); - // if the virtual register was previously assigned clear the mapping - // and free the virtual register - if (v2pMap_.find(virtReg) != v2pMap_.end()) { - clearVirtReg(virtReg); - } - else { - v2pMap_[virtReg] = 0; // this marks that this virtual register - // lives on the stack - } -} - -int RA::getStackSlot(unsigned virtReg) -{ - // use lower_bound so that we can do a possibly O(1) insert later - // if necessary - Virt2StackSlotMap::iterator it = v2ssMap_.find(virtReg); - assert(it != v2ssMap_.end() && - "attempt to get stack slot on register that does not live on the stack"); - return it->second; -} - -void RA::spillVirtReg(unsigned virtReg) -{ - DEBUG(std::cerr << "\t\t\tspilling register: " << virtReg); - const TargetRegisterClass* rc = mf_->getSSARegMap()->getRegClass(virtReg); - int frameIndex = getStackSlot(virtReg); - DEBUG(std::cerr << " to stack slot #" << frameIndex << '\n'); - ++numSpilled; - instrAdded_ += mri_->storeRegToStackSlot(*currentMbb_, currentInstr_, - v2pMap_[virtReg], frameIndex, rc); - clearVirtReg(virtReg); -} - -void RA::loadVirt2PhysReg(unsigned virtReg, unsigned physReg) -{ - DEBUG(std::cerr << "\t\t\tloading register: " << virtReg); - const TargetRegisterClass* rc = mf_->getSSARegMap()->getRegClass(virtReg); - int frameIndex = getStackSlot(virtReg); - DEBUG(std::cerr << " from stack slot #" << frameIndex << '\n'); - ++numReloaded; - instrAdded_ += mri_->loadRegFromStackSlot(*currentMbb_, currentInstr_, - physReg, frameIndex, rc); - assignVirt2PhysReg(virtReg, physReg); -} - -void RA::markPhysRegFree(unsigned physReg) -{ - assert(regUse_[physReg] != 0); - --regUse_[physReg]; - for (const unsigned* as = mri_->getAliasSet(physReg); *as; ++as) { - physReg = *as; - assert(regUse_[physReg] != 0); - --regUse_[physReg]; - } -} - -void RA::markPhysRegNotFree(unsigned physReg) -{ - ++regUse_[physReg]; - for (const unsigned* as = mri_->getAliasSet(physReg); *as; ++as) { - physReg = *as; - ++regUse_[physReg]; - } } FunctionPass* llvm::createLinearScanRegisterAllocator() { Index: llvm/lib/CodeGen/RegAllocLocal.cpp diff -u llvm/lib/CodeGen/RegAllocLocal.cpp:1.37 llvm/lib/CodeGen/RegAllocLocal.cpp:1.37.2.1 --- llvm/lib/CodeGen/RegAllocLocal.cpp:1.37 Tue Jan 13 00:24:30 2004 +++ llvm/lib/CodeGen/RegAllocLocal.cpp Mon Mar 1 17:58:13 2004 @@ -1,10 +1,10 @@ //===-- RegAllocLocal.cpp - A BasicBlock generic register allocator -------===// -// +// // The LLVM Compiler Infrastructure // // This file was developed by the LLVM research group and is distributed under // the University of Illinois Open Source License. See LICENSE.TXT for details. -// +// //===----------------------------------------------------------------------===// // // This register allocator allocates registers to a basic block at a time, @@ -23,17 +23,16 @@ #include "llvm/Target/TargetMachine.h" #include "Support/CommandLine.h" #include "Support/Debug.h" +#include "Support/DenseMap.h" #include "Support/Statistic.h" #include - -namespace llvm { +using namespace llvm; namespace { - Statistic<> NumSpilled ("ra-local", "Number of registers spilled"); - Statistic<> NumReloaded("ra-local", "Number of registers reloaded"); - cl::opt DisableKill("disable-kill", cl::Hidden, - cl::desc("Disable register kill in local-ra")); - + Statistic<> NumStores("ra-local", "Number of stores added"); + Statistic<> NumLoads ("ra-local", "Number of loads added"); + Statistic<> NumFolded("ra-local", "Number of loads/stores folded into " + "instructions"); class RA : public MachineFunctionPass { const TargetMachine *TM; MachineFunction *MF; @@ -46,16 +45,21 @@ // Virt2PhysRegMap - This map contains entries for each virtual register // that is currently available in a physical register. + DenseMap Virt2PhysRegMap; + + unsigned &getVirt2PhysRegMapSlot(unsigned VirtReg) { + return Virt2PhysRegMap[VirtReg]; + } + + // PhysRegsUsed - This array is effectively a map, containing entries for + // each physical register that currently has a value (ie, it is in + // Virt2PhysRegMap). The value mapped to is the virtual register + // corresponding to the physical register (the inverse of the + // Virt2PhysRegMap), or 0. The value is set to 0 if this register is pinned + // because it is used by a future instruction. If the entry for a physical + // register is -1, then the physical register is "not in the map". // - std::map Virt2PhysRegMap; - - // PhysRegsUsed - This map contains entries for each physical register that - // currently has a value (ie, it is in Virt2PhysRegMap). The value mapped - // to is the virtual register corresponding to the physical register (the - // inverse of the Virt2PhysRegMap), or 0. The value is set to 0 if this - // register is pinned because it is used by a future instruction. - // - std::map PhysRegsUsed; + std::vector PhysRegsUsed; // PhysRegsUseOrder - This contains a list of the physical registers that // currently have a virtual register value in them. This list provides an @@ -75,16 +79,16 @@ std::vector VirtRegModified; void markVirtRegModified(unsigned Reg, bool Val = true) { - assert(Reg >= MRegisterInfo::FirstVirtualRegister && "Illegal VirtReg!"); + assert(MRegisterInfo::isVirtualRegister(Reg) && "Illegal VirtReg!"); Reg -= MRegisterInfo::FirstVirtualRegister; if (VirtRegModified.size() <= Reg) VirtRegModified.resize(Reg+1); VirtRegModified[Reg] = Val; } bool isVirtRegModified(unsigned Reg) const { - assert(Reg >= MRegisterInfo::FirstVirtualRegister && "Illegal VirtReg!"); + assert(MRegisterInfo::isVirtualRegister(Reg) && "Illegal VirtReg!"); assert(Reg - MRegisterInfo::FirstVirtualRegister < VirtRegModified.size() - && "Illegal virtual register!"); + && "Illegal virtual register!"); return VirtRegModified[Reg - MRegisterInfo::FirstVirtualRegister]; } @@ -93,14 +97,14 @@ if (PhysRegsUseOrder.back() == Reg) return; // Already most recently used for (unsigned i = PhysRegsUseOrder.size(); i != 0; --i) - if (areRegsEqual(Reg, PhysRegsUseOrder[i-1])) { - unsigned RegMatch = PhysRegsUseOrder[i-1]; // remove from middle - PhysRegsUseOrder.erase(PhysRegsUseOrder.begin()+i-1); - // Add it to the end of the list - PhysRegsUseOrder.push_back(RegMatch); - if (RegMatch == Reg) - return; // Found an exact match, exit early - } + if (areRegsEqual(Reg, PhysRegsUseOrder[i-1])) { + unsigned RegMatch = PhysRegsUseOrder[i-1]; // remove from middle + PhysRegsUseOrder.erase(PhysRegsUseOrder.begin()+i-1); + // Add it to the end of the list + PhysRegsUseOrder.push_back(RegMatch); + if (RegMatch == Reg) + return; // Found an exact match, exit early + } } public: @@ -109,8 +113,7 @@ } virtual void getAnalysisUsage(AnalysisUsage &AU) const { - if (!DisableKill) - AU.addRequired(); + AU.addRequired(); AU.addRequiredID(PHIEliminationID); AU.addRequiredID(TwoAddressInstructionPassID); MachineFunctionPass::getAnalysisUsage(AU); @@ -150,7 +153,7 @@ /// the virtual register slot specified by VirtReg. It then updates the RA /// data structures to indicate the fact that PhysReg is now available. /// - void spillVirtReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator &I, + void spillVirtReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, unsigned VirtReg, unsigned PhysReg); /// spillPhysReg - This method spills the specified physical register into @@ -158,7 +161,7 @@ /// true, then the request is ignored if the physical register does not /// contain a virtual register. /// - void spillPhysReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator &I, + void spillPhysReg(MachineBasicBlock &MBB, MachineInstr *I, unsigned PhysReg, bool OnlyVirtRegs = false); /// assignVirtToPhysReg - This method updates local state so that we know @@ -172,7 +175,7 @@ /// the way or spilled to memory. /// void liberatePhysReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator &I, - unsigned PhysReg); + unsigned PhysReg); /// isPhysRegAvailable - Return true if the specified physical register is /// free and available for use. This also includes checking to see if @@ -184,22 +187,29 @@ /// specified register class. If not, return 0. /// unsigned getFreeReg(const TargetRegisterClass *RC); - + /// getReg - Find a physical register to hold the specified virtual /// register. If all compatible physical registers are used, this method /// spills the last used virtual register to the stack, and uses that /// register. /// - unsigned getReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator &I, - unsigned VirtReg); + unsigned getReg(MachineBasicBlock &MBB, MachineInstr *MI, + unsigned VirtReg); - /// reloadVirtReg - This method loads the specified virtual register into a - /// physical register, returning the physical register chosen. This updates - /// the regalloc data structures to reflect the fact that the virtual reg is - /// now alive in a physical register, and the previous one isn't. + /// reloadVirtReg - This method transforms the specified specified virtual + /// register use to refer to a physical register. This method may do this + /// in one of several ways: if the register is available in a physical + /// register already, it uses that physical register. If the value is not + /// in a physical register, and if there are physical registers available, + /// it loads it into a register. If register pressure is high, and it is + /// possible, it tries to fold the load of the virtual register into the + /// instruction itself. It avoids doing this if register pressure is low to + /// improve the chance that subsequent instructions can use the reloaded + /// value. This method returns the modified instruction. /// - unsigned reloadVirtReg(MachineBasicBlock &MBB, - MachineBasicBlock::iterator &I, unsigned VirtReg); + MachineInstr *reloadVirtReg(MachineBasicBlock &MBB, MachineInstr *MI, + unsigned OpNum); + void reloadPhysReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator &I, unsigned PhysReg); @@ -224,11 +234,11 @@ } -/// removePhysReg - This method marks the specified physical register as no +/// removePhysReg - This method marks the specified physical register as no /// longer being in use. /// void RA::removePhysReg(unsigned PhysReg) { - PhysRegsUsed.erase(PhysReg); // PhyReg no longer used + PhysRegsUsed[PhysReg] = -1; // PhyReg no longer used std::vector::iterator It = std::find(PhysRegsUseOrder.begin(), PhysRegsUseOrder.end(), PhysReg); @@ -241,9 +251,8 @@ /// virtual register slot specified by VirtReg. It then updates the RA data /// structures to indicate the fact that PhysReg is now available. /// -void RA::spillVirtReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator &I, +void RA::spillVirtReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, unsigned VirtReg, unsigned PhysReg) { - if (!VirtReg && DisableKill) return; assert(VirtReg && "Spilling a physical register is illegal!" " Must not have appropriate kill for the register or use exists beyond" " the intended one."); @@ -260,9 +269,10 @@ int FrameIndex = getStackSpaceFor(VirtReg, RC); DEBUG(std::cerr << " to stack slot #" << FrameIndex); RegInfo->storeRegToStackSlot(MBB, I, PhysReg, FrameIndex, RC); - ++NumSpilled; // Update statistics + ++NumStores; // Update statistics } - Virt2PhysRegMap.erase(VirtReg); // VirtReg no longer available + + getVirt2PhysRegMapSlot(VirtReg) = 0; // VirtReg no longer available DEBUG(std::cerr << "\n"); removePhysReg(PhysReg); @@ -274,22 +284,19 @@ /// then the request is ignored if the physical register does not contain a /// virtual register. /// -void RA::spillPhysReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator &I, +void RA::spillPhysReg(MachineBasicBlock &MBB, MachineInstr *I, unsigned PhysReg, bool OnlyVirtRegs) { - std::map::iterator PI = PhysRegsUsed.find(PhysReg); - if (PI != PhysRegsUsed.end()) { // Only spill it if it's used! - if (PI->second || !OnlyVirtRegs) - spillVirtReg(MBB, I, PI->second, PhysReg); + if (PhysRegsUsed[PhysReg] != -1) { // Only spill it if it's used! + if (PhysRegsUsed[PhysReg] || !OnlyVirtRegs) + spillVirtReg(MBB, I, PhysRegsUsed[PhysReg], PhysReg); } else { // If the selected register aliases any other registers, we must make // sure that one of the aliases isn't alive... for (const unsigned *AliasSet = RegInfo->getAliasSet(PhysReg); - *AliasSet; ++AliasSet) { - PI = PhysRegsUsed.find(*AliasSet); - if (PI != PhysRegsUsed.end()) // Spill aliased register... - if (PI->second || !OnlyVirtRegs) - spillVirtReg(MBB, I, PI->second, *AliasSet); - } + *AliasSet; ++AliasSet) + if (PhysRegsUsed[*AliasSet] != -1) // Spill aliased register... + if (PhysRegsUsed[*AliasSet] || !OnlyVirtRegs) + spillVirtReg(MBB, I, PhysRegsUsed[*AliasSet], *AliasSet); } } @@ -299,12 +306,11 @@ /// register must not be used for anything else when this is called. /// void RA::assignVirtToPhysReg(unsigned VirtReg, unsigned PhysReg) { - assert(PhysRegsUsed.find(PhysReg) == PhysRegsUsed.end() && - "Phys reg already assigned!"); + assert(PhysRegsUsed[PhysReg] == -1 && "Phys reg already assigned!"); // Update information to note the fact that this register was just used, and // it holds VirtReg. PhysRegsUsed[PhysReg] = VirtReg; - Virt2PhysRegMap[VirtReg] = PhysReg; + getVirt2PhysRegMapSlot(VirtReg) = PhysReg; PhysRegsUseOrder.push_back(PhysReg); // New use of PhysReg } @@ -314,13 +320,13 @@ /// registers are all free... /// bool RA::isPhysRegAvailable(unsigned PhysReg) const { - if (PhysRegsUsed.count(PhysReg)) return false; + if (PhysRegsUsed[PhysReg] != -1) return false; // If the selected register aliases any other allocated registers, it is // not free! for (const unsigned *AliasSet = RegInfo->getAliasSet(PhysReg); *AliasSet; ++AliasSet) - if (PhysRegsUsed.count(*AliasSet)) // Aliased register in use? + if (PhysRegsUsed[*AliasSet] != -1) // Aliased register in use? return false; // Can't use this reg then. return true; } @@ -349,7 +355,7 @@ /// or spilled to memory. /// void RA::liberatePhysReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator &I, - unsigned PhysReg) { + unsigned PhysReg) { // FIXME: This code checks to see if a register is available, but it really // wants to know if a reg is available BEFORE the instruction executes. If // called after killed operands are freed, it runs the risk of reallocating a @@ -360,9 +366,9 @@ // Check to see if the register is directly used, not indirectly used through // aliases. If aliased registers are the ones actually used, we cannot be // sure that we will be able to save the whole thing if we do a reg-reg copy. - std::map::iterator PRUI = PhysRegsUsed.find(PhysReg); - if (PRUI != PhysRegsUsed.end()) { - unsigned VirtReg = PRUI->second; // The virtual register held... + if (PhysRegsUsed[PhysReg] != -1) { + // The virtual register held... + unsigned VirtReg = PhysRegsUsed[PhysReg]->second; // Check to see if there is a compatible register available. If so, we can // move the value into the new register... @@ -371,12 +377,12 @@ if (unsigned NewReg = getFreeReg(RC)) { // Emit the code to copy the value... RegInfo->copyRegToReg(MBB, I, NewReg, PhysReg, RC); - + // Update our internal state to indicate that PhysReg is available and Reg // isn't. - Virt2PhysRegMap.erase(VirtReg); + getVirt2PhysRegMapSlot[VirtReg] = 0; removePhysReg(PhysReg); // Free the physreg - + // Move reference over to new register... assignVirtToPhysReg(VirtReg, NewReg); return; @@ -391,8 +397,8 @@ /// register. If all compatible physical registers are used, this method spills /// the last used virtual register to the stack, and uses that register. /// -unsigned RA::getReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator &I, - unsigned VirtReg) { +unsigned RA::getReg(MachineBasicBlock &MBB, MachineInstr *I, + unsigned VirtReg) { const TargetRegisterClass *RC = MF->getSSARegMap()->getRegClass(VirtReg); // First check to see if we have a free register of the requested type... @@ -408,13 +414,13 @@ for (unsigned i = 0; PhysReg == 0; ++i) { assert(i != PhysRegsUseOrder.size() && "Couldn't find a register of the appropriate class!"); - + unsigned R = PhysRegsUseOrder[i]; // We can only use this register if it holds a virtual register (ie, it // can be spilled). Do not use it if it is an explicitly allocated // physical register! - assert(PhysRegsUsed.count(R) && + assert(PhysRegsUsed[R] != -1 && "PhysReg in PhysRegsUseOrder, but is not allocated?"); if (PhysRegsUsed[R]) { // If the current register is compatible, use it. @@ -448,57 +454,87 @@ } -/// reloadVirtReg - This method loads the specified virtual register into a -/// physical register, returning the physical register chosen. This updates the -/// regalloc data structures to reflect the fact that the virtual reg is now -/// alive in a physical register, and the previous one isn't. +/// reloadVirtReg - This method transforms the specified specified virtual +/// register use to refer to a physical register. This method may do this in +/// one of several ways: if the register is available in a physical register +/// already, it uses that physical register. If the value is not in a physical +/// register, and if there are physical registers available, it loads it into a +/// register. If register pressure is high, and it is possible, it tries to +/// fold the load of the virtual register into the instruction itself. It +/// avoids doing this if register pressure is low to improve the chance that +/// subsequent instructions can use the reloaded value. This method returns the +/// modified instruction. /// -unsigned RA::reloadVirtReg(MachineBasicBlock &MBB, - MachineBasicBlock::iterator &I, - unsigned VirtReg) { - std::map::iterator It = Virt2PhysRegMap.find(VirtReg); - if (It != Virt2PhysRegMap.end()) { - MarkPhysRegRecentlyUsed(It->second); - return It->second; // Already have this value available! +MachineInstr *RA::reloadVirtReg(MachineBasicBlock &MBB, MachineInstr *MI, + unsigned OpNum) { + unsigned VirtReg = MI->getOperand(OpNum).getReg(); + + // If the virtual register is already available, just update the instruction + // and return. + if (unsigned PR = getVirt2PhysRegMapSlot(VirtReg)) { + MarkPhysRegRecentlyUsed(PR); // Already have this value available! + MI->SetMachineOperandReg(OpNum, PR); // Assign the input register + return MI; } - unsigned PhysReg = getReg(MBB, I, VirtReg); - + // Otherwise, we need to fold it into the current instruction, or reload it. + // If we have registers available to hold the value, use them. const TargetRegisterClass *RC = MF->getSSARegMap()->getRegClass(VirtReg); + unsigned PhysReg = getFreeReg(RC); int FrameIndex = getStackSpaceFor(VirtReg, RC); + if (PhysReg) { // Register is available, allocate it! + assignVirtToPhysReg(VirtReg, PhysReg); + } else { // No registers available. + // If we can fold this spill into this instruction, do so now. + MachineBasicBlock::iterator MII = MI; + if (RegInfo->foldMemoryOperand(MII, OpNum, FrameIndex)) { + ++NumFolded; + // Since we changed the address of MI, make sure to update live variables + // to know that the new instruction has the properties of the old one. + LV->instructionChanged(MI, MII); + return MII; + } + + // It looks like we can't fold this virtual register load into this + // instruction. Force some poor hapless value out of the register file to + // make room for the new register, and reload it. + PhysReg = getReg(MBB, MI, VirtReg); + } + markVirtRegModified(VirtReg, false); // Note that this reg was just reloaded DEBUG(std::cerr << " Reloading %reg" << VirtReg << " into " << RegInfo->getName(PhysReg) << "\n"); // Add move instruction(s) - RegInfo->loadRegFromStackSlot(MBB, I, PhysReg, FrameIndex, RC); - ++NumReloaded; // Update statistics - return PhysReg; + RegInfo->loadRegFromStackSlot(MBB, MI, PhysReg, FrameIndex, RC); + ++NumLoads; // Update statistics + + MI->SetMachineOperandReg(OpNum, PhysReg); // Assign the input register + return MI; } void RA::AllocateBasicBlock(MachineBasicBlock &MBB) { // loop over each instruction - MachineBasicBlock::iterator I = MBB.begin(); - for (; I != MBB.end(); ++I) { - MachineInstr *MI = *I; + MachineBasicBlock::iterator MI = MBB.begin(); + for (; MI != MBB.end(); ++MI) { const TargetInstrDescriptor &TID = TM->getInstrInfo().get(MI->getOpcode()); DEBUG(std::cerr << "\nStarting RegAlloc of: " << *MI; std::cerr << " Regs have values: "; - for (std::map::const_iterator - I = PhysRegsUsed.begin(), E = PhysRegsUsed.end(); I != E; ++I) - std::cerr << "[" << RegInfo->getName(I->first) - << ",%reg" << I->second << "] "; + for (unsigned i = 0; i != RegInfo->getNumRegs(); ++i) + if (PhysRegsUsed[i] != -1) + std::cerr << "[" << RegInfo->getName(i) + << ",%reg" << PhysRegsUsed[i] << "] "; std::cerr << "\n"); // Loop over the implicit uses, making sure that they are at the head of the // use order list, so they don't get reallocated. for (const unsigned *ImplicitUses = TID.ImplicitUses; *ImplicitUses; ++ImplicitUses) - MarkPhysRegRecentlyUsed(*ImplicitUses); + MarkPhysRegRecentlyUsed(*ImplicitUses); // Get the used operands into registers. This has the potential to spill // incoming values if we are out of registers. Note that we completely @@ -506,67 +542,66 @@ // physical register is referenced by the instruction, that it is guaranteed // to be live-in, or the input is badly hosed. // - for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) - if (MI->getOperand(i).isUse() && - !MI->getOperand(i).isDef() && - MI->getOperand(i).isVirtualRegister()){ - unsigned VirtSrcReg = MI->getOperand(i).getAllocatedRegNum(); - unsigned PhysSrcReg = reloadVirtReg(MBB, I, VirtSrcReg); - MI->SetMachineOperandReg(i, PhysSrcReg); // Assign the input register + for (unsigned i = 0; i != MI->getNumOperands(); ++i) { + MachineOperand& MO = MI->getOperand(i); + // here we are looking for only used operands (never def&use) + if (!MO.isDef() && MO.isRegister() && MO.getReg() && + MRegisterInfo::isVirtualRegister(MO.getReg())) + MI = reloadVirtReg(MBB, MI, i); + } + + // If this instruction is the last user of anything in registers, kill the + // value, freeing the register being used, so it doesn't need to be + // spilled to memory. + // + for (LiveVariables::killed_iterator KI = LV->killed_begin(MI), + KE = LV->killed_end(MI); KI != KE; ++KI) { + unsigned VirtReg = KI->second; + unsigned PhysReg = VirtReg; + if (MRegisterInfo::isVirtualRegister(VirtReg)) { + // If the virtual register was never materialized into a register, it + // might not be in the map, but it won't hurt to zero it out anyway. + unsigned &PhysRegSlot = getVirt2PhysRegMapSlot(VirtReg); + PhysReg = PhysRegSlot; + PhysRegSlot = 0; } - - if (!DisableKill) { - // If this instruction is the last user of anything in registers, kill the - // value, freeing the register being used, so it doesn't need to be - // spilled to memory. - // - for (LiveVariables::killed_iterator KI = LV->killed_begin(MI), - KE = LV->killed_end(MI); KI != KE; ++KI) { - unsigned VirtReg = KI->second; - unsigned PhysReg = VirtReg; - if (VirtReg >= MRegisterInfo::FirstVirtualRegister) { - std::map::iterator I = - Virt2PhysRegMap.find(VirtReg); - assert(I != Virt2PhysRegMap.end()); - PhysReg = I->second; - Virt2PhysRegMap.erase(I); - } - if (PhysReg) { - DEBUG(std::cerr << " Last use of " << RegInfo->getName(PhysReg) - << "[%reg" << VirtReg <<"], removing it from live set\n"); - removePhysReg(PhysReg); - } + if (PhysReg) { + DEBUG(std::cerr << " Last use of " << RegInfo->getName(PhysReg) + << "[%reg" << VirtReg <<"], removing it from live set\n"); + removePhysReg(PhysReg); } } // Loop over all of the operands of the instruction, spilling registers that // are defined, and marking explicit destinations in the PhysRegsUsed map. - for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) - if (MI->getOperand(i).isDef() && - MI->getOperand(i).isPhysicalRegister()) { - unsigned Reg = MI->getOperand(i).getAllocatedRegNum(); - spillPhysReg(MBB, I, Reg, true); // Spill any existing value in the reg + for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { + MachineOperand& MO = MI->getOperand(i); + if (MO.isDef() && MO.isRegister() && MO.getReg() && + MRegisterInfo::isPhysicalRegister(MO.getReg())) { + unsigned Reg = MO.getReg(); + spillPhysReg(MBB, MI, Reg, true); // Spill any existing value in the reg PhysRegsUsed[Reg] = 0; // It is free and reserved now PhysRegsUseOrder.push_back(Reg); for (const unsigned *AliasSet = RegInfo->getAliasSet(Reg); *AliasSet; ++AliasSet) { - PhysRegsUseOrder.push_back(*AliasSet); - PhysRegsUsed[*AliasSet] = 0; // It is free and reserved now + PhysRegsUseOrder.push_back(*AliasSet); + PhysRegsUsed[*AliasSet] = 0; // It is free and reserved now } } + } // Loop over the implicit defs, spilling them as well. for (const unsigned *ImplicitDefs = TID.ImplicitDefs; *ImplicitDefs; ++ImplicitDefs) { unsigned Reg = *ImplicitDefs; - spillPhysReg(MBB, I, Reg); + spillPhysReg(MBB, MI, Reg, true); PhysRegsUseOrder.push_back(Reg); PhysRegsUsed[Reg] = 0; // It is free and reserved now for (const unsigned *AliasSet = RegInfo->getAliasSet(Reg); *AliasSet; ++AliasSet) { - PhysRegsUseOrder.push_back(*AliasSet); - PhysRegsUsed[*AliasSet] = 0; // It is free and reserved now + PhysRegsUseOrder.push_back(*AliasSet); + PhysRegsUsed[*AliasSet] = 0; // It is free and reserved now } } @@ -575,71 +610,65 @@ // implicit defs and assign them to a register, spilling incoming values if // we need to scavenge a register. // - for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) - if (MI->getOperand(i).isDef() && - MI->getOperand(i).isVirtualRegister()) { - unsigned DestVirtReg = MI->getOperand(i).getAllocatedRegNum(); + for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { + MachineOperand& MO = MI->getOperand(i); + if (MO.isDef() && MO.isRegister() && MO.getReg() && + MRegisterInfo::isVirtualRegister(MO.getReg())) { + unsigned DestVirtReg = MO.getReg(); unsigned DestPhysReg; // If DestVirtReg already has a value, use it. - std::map::iterator DestI = - Virt2PhysRegMap.find(DestVirtReg); - if (DestI != Virt2PhysRegMap.end()) { - DestPhysReg = DestI->second; - } - else { - DestPhysReg = getReg(MBB, I, DestVirtReg); - } + if (!(DestPhysReg = getVirt2PhysRegMapSlot(DestVirtReg))) + DestPhysReg = getReg(MBB, MI, DestVirtReg); markVirtRegModified(DestVirtReg); MI->SetMachineOperandReg(i, DestPhysReg); // Assign the output register } + } - if (!DisableKill) { - // If this instruction defines any registers that are immediately dead, - // kill them now. - // - for (LiveVariables::killed_iterator KI = LV->dead_begin(MI), - KE = LV->dead_end(MI); KI != KE; ++KI) { - unsigned VirtReg = KI->second; - unsigned PhysReg = VirtReg; - if (VirtReg >= MRegisterInfo::FirstVirtualRegister) { - std::map::iterator I = - Virt2PhysRegMap.find(VirtReg); - assert(I != Virt2PhysRegMap.end()); - PhysReg = I->second; - Virt2PhysRegMap.erase(I); - } + // If this instruction defines any registers that are immediately dead, + // kill them now. + // + for (LiveVariables::killed_iterator KI = LV->dead_begin(MI), + KE = LV->dead_end(MI); KI != KE; ++KI) { + unsigned VirtReg = KI->second; + unsigned PhysReg = VirtReg; + if (MRegisterInfo::isVirtualRegister(VirtReg)) { + unsigned &PhysRegSlot = getVirt2PhysRegMapSlot(VirtReg); + PhysReg = PhysRegSlot; + assert(PhysReg != 0); + PhysRegSlot = 0; + } - if (PhysReg) { - DEBUG(std::cerr << " Register " << RegInfo->getName(PhysReg) - << " [%reg" << VirtReg - << "] is never used, removing it frame live list\n"); - removePhysReg(PhysReg); - } + if (PhysReg) { + DEBUG(std::cerr << " Register " << RegInfo->getName(PhysReg) + << " [%reg" << VirtReg + << "] is never used, removing it frame live list\n"); + removePhysReg(PhysReg); } } } - // Rewind the iterator to point to the first flow control instruction... - const TargetInstrInfo &TII = TM->getInstrInfo(); - I = MBB.end(); - while (I != MBB.begin() && TII.isTerminatorInstr((*(I-1))->getOpcode())) - --I; + MI = MBB.getFirstTerminator(); // Spill all physical registers holding virtual registers now. - while (!PhysRegsUsed.empty()) - if (unsigned VirtReg = PhysRegsUsed.begin()->second) - spillVirtReg(MBB, I, VirtReg, PhysRegsUsed.begin()->first); - else - removePhysReg(PhysRegsUsed.begin()->first); - - for (std::map::iterator I = Virt2PhysRegMap.begin(), - E = Virt2PhysRegMap.end(); I != E; ++I) - std::cerr << "Register still mapped: " << I->first << " -> " - << I->second << "\n"; + for (unsigned i = 0, e = RegInfo->getNumRegs(); i != e; ++i) + if (PhysRegsUsed[i] != -1) + if (unsigned VirtReg = PhysRegsUsed[i]) + spillVirtReg(MBB, MI, VirtReg, i); + else + removePhysReg(i); + +#ifndef NDEBUG + bool AllOk = true; + for (unsigned i = MRegisterInfo::FirstVirtualRegister, + e = MF->getSSARegMap()->getLastVirtReg(); i <= e; ++i) + if (unsigned PR = Virt2PhysRegMap[i]) { + std::cerr << "Register still mapped: " << i << " -> " << PR << "\n"; + AllOk = false; + } + assert(AllOk && "Virtual registers still in phys regs?"); +#endif - assert(Virt2PhysRegMap.empty() && "Virtual registers still in phys regs?"); - // Clear any physical register which appear live at the end of the basic // block, but which do not hold any virtual registers. e.g., the stack // pointer. @@ -654,9 +683,13 @@ MF = &Fn; TM = &Fn.getTarget(); RegInfo = TM->getRegisterInfo(); + LV = &getAnalysis(); - if (!DisableKill) - LV = &getAnalysis(); + PhysRegsUsed.assign(RegInfo->getNumRegs(), -1); + + // initialize the virtual->physical register map to have a 'null' + // mapping for all virtual registers + Virt2PhysRegMap.grow(MF->getSSARegMap()->getLastVirtReg()); // Loop over all of the basic blocks, eliminating virtual register references for (MachineFunction::iterator MBB = Fn.begin(), MBBe = Fn.end(); @@ -664,12 +697,12 @@ AllocateBasicBlock(*MBB); StackSlotForVirtReg.clear(); + PhysRegsUsed.clear(); VirtRegModified.clear(); + Virt2PhysRegMap.clear(); return true; } -FunctionPass *createLocalRegisterAllocator() { +FunctionPass *llvm::createLocalRegisterAllocator() { return new RA(); } - -} // End llvm namespace Index: llvm/lib/CodeGen/RegAllocSimple.cpp diff -u llvm/lib/CodeGen/RegAllocSimple.cpp:1.47 llvm/lib/CodeGen/RegAllocSimple.cpp:1.47.2.1 --- llvm/lib/CodeGen/RegAllocSimple.cpp:1.47 Sun Dec 14 07:24:16 2003 +++ llvm/lib/CodeGen/RegAllocSimple.cpp Mon Mar 1 17:58:13 2004 @@ -24,13 +24,13 @@ #include "llvm/Target/TargetMachine.h" #include "Support/Debug.h" #include "Support/Statistic.h" +#include "Support/STLExtras.h" #include - -namespace llvm { +using namespace llvm; namespace { - Statistic<> NumSpilled ("ra-simple", "Number of registers spilled"); - Statistic<> NumReloaded("ra-simple", "Number of registers reloaded"); + Statistic<> NumStores("ra-simple", "Number of stores added"); + Statistic<> NumLoads ("ra-simple", "Number of loads added"); class RegAllocSimple : public MachineFunctionPass { MachineFunction *MF; @@ -79,10 +79,10 @@ /// Moves value from memory into that register unsigned reloadVirtReg(MachineBasicBlock &MBB, - MachineBasicBlock::iterator &I, unsigned VirtReg); + MachineBasicBlock::iterator I, unsigned VirtReg); /// Saves reg value on the stack (maps virtual register to stack value) - void spillVirtReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator &I, + void spillVirtReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, unsigned VirtReg, unsigned PhysReg); }; @@ -124,39 +124,37 @@ } unsigned RegAllocSimple::reloadVirtReg(MachineBasicBlock &MBB, - MachineBasicBlock::iterator &I, + MachineBasicBlock::iterator I, unsigned VirtReg) { const TargetRegisterClass* RC = MF->getSSARegMap()->getRegClass(VirtReg); int FrameIdx = getStackSpaceFor(VirtReg, RC); unsigned PhysReg = getFreeReg(VirtReg); // Add move instruction(s) - ++NumReloaded; + ++NumLoads; RegInfo->loadRegFromStackSlot(MBB, I, PhysReg, FrameIdx, RC); return PhysReg; } void RegAllocSimple::spillVirtReg(MachineBasicBlock &MBB, - MachineBasicBlock::iterator &I, + MachineBasicBlock::iterator I, unsigned VirtReg, unsigned PhysReg) { const TargetRegisterClass* RC = MF->getSSARegMap()->getRegClass(VirtReg); int FrameIdx = getStackSpaceFor(VirtReg, RC); // Add move instruction(s) - ++NumSpilled; + ++NumStores; RegInfo->storeRegToStackSlot(MBB, I, PhysReg, FrameIdx, RC); } void RegAllocSimple::AllocateBasicBlock(MachineBasicBlock &MBB) { // loop over each instruction - for (MachineBasicBlock::iterator I = MBB.begin(); I != MBB.end(); ++I) { + for (MachineBasicBlock::iterator MI = MBB.begin(); MI != MBB.end(); ++MI) { // Made to combat the incorrect allocation of r2 = add r1, r1 std::map Virt2PhysRegMap; - MachineInstr *MI = *I; - - RegsUsed.resize(MRegisterInfo::FirstVirtualRegister); + RegsUsed.resize(RegInfo->getNumRegs()); // a preliminary pass that will invalidate any registers that // are used by the instruction (including implicit uses) @@ -174,8 +172,8 @@ for (int i = MI->getNumOperands() - 1; i >= 0; --i) { MachineOperand &op = MI->getOperand(i); - if (op.isVirtualRegister()) { - unsigned virtualReg = (unsigned) op.getAllocatedRegNum(); + if (op.isRegister() && MRegisterInfo::isVirtualRegister(op.getReg())) { + unsigned virtualReg = (unsigned) op.getReg(); DEBUG(std::cerr << "op: " << op << "\n"); DEBUG(std::cerr << "\t inst[" << i << "]: "; MI->print(std::cerr, *TM)); @@ -185,29 +183,31 @@ unsigned physReg = Virt2PhysRegMap[virtualReg]; if (physReg == 0) { if (op.isDef()) { - if (TM->getInstrInfo().isTwoAddrInstr(MI->getOpcode()) && i == 0) { + if (!TM->getInstrInfo().isTwoAddrInstr(MI->getOpcode()) || i) { + physReg = getFreeReg(virtualReg); + } else { // must be same register number as the first operand // This maps a = b + c into b += c, and saves b into a's spot assert(MI->getOperand(1).isRegister() && - MI->getOperand(1).getAllocatedRegNum() && + MI->getOperand(1).getReg() && MI->getOperand(1).isUse() && "Two address instruction invalid!"); - physReg = MI->getOperand(1).getAllocatedRegNum(); - } else { - physReg = getFreeReg(virtualReg); + physReg = MI->getOperand(1).getReg(); + spillVirtReg(MBB, next(MI), virtualReg, physReg); + MI->getOperand(1).setDef(); + MI->RemoveOperand(0); + break; // This is the last operand to process } - ++I; - spillVirtReg(MBB, I, virtualReg, physReg); - --I; + spillVirtReg(MBB, next(MI), virtualReg, physReg); } else { - physReg = reloadVirtReg(MBB, I, virtualReg); + physReg = reloadVirtReg(MBB, MI, virtualReg); Virt2PhysRegMap[virtualReg] = physReg; } } MI->SetMachineOperandReg(i, physReg); DEBUG(std::cerr << "virt: " << virtualReg << - ", phys: " << op.getAllocatedRegNum() << "\n"); + ", phys: " << op.getReg() << "\n"); } } RegClassIdx.clear(); @@ -233,8 +233,6 @@ return true; } -FunctionPass *createSimpleRegisterAllocator() { +FunctionPass *llvm::createSimpleRegisterAllocator() { return new RegAllocSimple(); } - -} // End llvm namespace Index: llvm/lib/CodeGen/TwoAddressInstructionPass.cpp diff -u llvm/lib/CodeGen/TwoAddressInstructionPass.cpp:1.6 llvm/lib/CodeGen/TwoAddressInstructionPass.cpp:1.6.2.1 --- llvm/lib/CodeGen/TwoAddressInstructionPass.cpp:1.6 Sun Jan 11 03:18:43 2004 +++ llvm/lib/CodeGen/TwoAddressInstructionPass.cpp Mon Mar 1 17:58:13 2004 @@ -16,53 +16,49 @@ // to: // // A = B -// A = A op C +// A op= C +// +// Note that if a register allocator chooses to use this pass, that it +// has to be capable of handling the non-SSA nature of these rewritten +// virtual registers. +// +// It is also worth noting that the duplicate operand of the two +// address instruction is removed. // //===----------------------------------------------------------------------===// #define DEBUG_TYPE "twoaddrinstr" #include "llvm/Function.h" +#include "llvm/CodeGen/Passes.h" #include "llvm/CodeGen/LiveVariables.h" -#include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineInstr.h" -#include "llvm/CodeGen/Passes.h" #include "llvm/CodeGen/SSARegMap.h" #include "llvm/Target/MRegisterInfo.h" #include "llvm/Target/TargetInstrInfo.h" #include "llvm/Target/TargetMachine.h" -#include "llvm/Target/TargetRegInfo.h" #include "Support/Debug.h" #include "Support/Statistic.h" #include "Support/STLExtras.h" #include - using namespace llvm; namespace { - class TwoAddressInstructionPass : public MachineFunctionPass - { - private: - MachineFunction* mf_; - const TargetMachine* tm_; - const MRegisterInfo* mri_; - LiveVariables* lv_; + Statistic<> numTwoAddressInstrs("twoaddressinstruction", + "Number of two-address instructions"); + Statistic<> numInstrsAdded("twoaddressinstruction", + "Number of instructions added"); - public: + struct TwoAddressInstructionPass : public MachineFunctionPass + { virtual void getAnalysisUsage(AnalysisUsage &AU) const; - private: /// runOnMachineFunction - pass entry point bool runOnMachineFunction(MachineFunction&); }; RegisterPass X( "twoaddressinstruction", "Two-Address instruction pass"); - - Statistic<> numTwoAddressInstrs("twoaddressinstruction", - "Number of two-address instructions"); - Statistic<> numInstrsAdded("twoaddressinstruction", - "Number of instructions added"); }; const PassInfo *llvm::TwoAddressInstructionPassID = X.getPassInfo(); @@ -70,101 +66,113 @@ void TwoAddressInstructionPass::getAnalysisUsage(AnalysisUsage &AU) const { AU.addPreserved(); - AU.addRequired(); AU.addPreservedID(PHIEliminationID); - AU.addRequiredID(PHIEliminationID); MachineFunctionPass::getAnalysisUsage(AU); } /// runOnMachineFunction - Reduce two-address instructions to two -/// operands +/// operands. /// -bool TwoAddressInstructionPass::runOnMachineFunction(MachineFunction &fn) { +bool TwoAddressInstructionPass::runOnMachineFunction(MachineFunction &MF) { DEBUG(std::cerr << "Machine Function\n"); - mf_ = &fn; - tm_ = &fn.getTarget(); - mri_ = tm_->getRegisterInfo(); - lv_ = &getAnalysis(); - - const TargetInstrInfo& tii = tm_->getInstrInfo(); + const TargetMachine &TM = MF.getTarget(); + const MRegisterInfo &MRI = *TM.getRegisterInfo(); + const TargetInstrInfo &TII = TM.getInstrInfo(); + LiveVariables* LV = getAnalysisToUpdate(); + + bool MadeChange = false; + + DEBUG(std::cerr << "********** REWRITING TWO-ADDR INSTRS **********\n"); + DEBUG(std::cerr << "********** Function: " + << MF.getFunction()->getName() << '\n'); - for (MachineFunction::iterator mbbi = mf_->begin(), mbbe = mf_->end(); + for (MachineFunction::iterator mbbi = MF.begin(), mbbe = MF.end(); mbbi != mbbe; ++mbbi) { - for (MachineBasicBlock::iterator mii = mbbi->begin(); - mii != mbbi->end(); ++mii) { - MachineInstr* mi = *mii; - + for (MachineBasicBlock::iterator mi = mbbi->begin(), me = mbbi->end(); + mi != me; ++mi) { unsigned opcode = mi->getOpcode(); + // ignore if it is not a two-address instruction - if (!tii.isTwoAddrInstr(opcode)) + if (!TII.isTwoAddrInstr(opcode)) continue; ++numTwoAddressInstrs; - DEBUG(std::cerr << "\tinstruction: "; mi->print(std::cerr, *tm_)); - - // we have nothing to do if the two operands are the same - if (mi->getOperand(0).getAllocatedRegNum() == - mi->getOperand(1).getAllocatedRegNum()) - continue; + DEBUG(std::cerr << '\t'; mi->print(std::cerr, TM)); assert(mi->getOperand(1).isRegister() && - mi->getOperand(1).getAllocatedRegNum() && + mi->getOperand(1).getReg() && mi->getOperand(1).isUse() && "two address instruction invalid"); - // rewrite: - // a = b op c - // to: - // a = b - // a = a op c - unsigned regA = mi->getOperand(0).getAllocatedRegNum(); - unsigned regB = mi->getOperand(1).getAllocatedRegNum(); - - assert(regA >= MRegisterInfo::FirstVirtualRegister && - regB >= MRegisterInfo::FirstVirtualRegister && - "cannot update physical register live information"); - - // first make sure we do not have a use of a in the - // instruction (a = b + a for example) because our - // transofrmation will not work. This should never occur - // because of SSA. - for (unsigned i = 1; i < mi->getNumOperands(); ++i) { - assert(!mi->getOperand(i).isRegister() || - mi->getOperand(i).getAllocatedRegNum() != (int)regA); + // if the two operands are the same we just remove the use + // and mark the def as def&use + if (mi->getOperand(0).getReg() == + mi->getOperand(1).getReg()) { } + else { + MadeChange = true; - const TargetRegisterClass* rc = - mf_->getSSARegMap()->getRegClass(regA); - numInstrsAdded += mri_->copyRegToReg(*mbbi, mii, regA, regB, rc); - - MachineInstr* prevMi = *(mii - 1); - DEBUG(std::cerr << "\t\tadded instruction: "; - prevMi->print(std::cerr, *tm_)); - - // update live variables for regA - LiveVariables::VarInfo& varInfo = lv_->getVarInfo(regA); - varInfo.DefInst = prevMi; - - // update live variables for regB - if (lv_->removeVirtualRegisterKilled(regB, &*mbbi, mi)) - lv_->addVirtualRegisterKilled(regB, &*mbbi, prevMi); - - if (lv_->removeVirtualRegisterDead(regB, &*mbbi, mi)) - lv_->addVirtualRegisterDead(regB, &*mbbi, prevMi); - - // replace all occurences of regB with regA - for (unsigned i = 1; i < mi->getNumOperands(); ++i) { - if (mi->getOperand(i).isRegister() && - mi->getOperand(i).getReg() == regB) - mi->SetMachineOperandReg(i, regA); + // rewrite: + // a = b op c + // to: + // a = b + // a = a op c + unsigned regA = mi->getOperand(0).getReg(); + unsigned regB = mi->getOperand(1).getReg(); + + assert(MRegisterInfo::isVirtualRegister(regA) && + MRegisterInfo::isVirtualRegister(regB) && + "cannot update physical register live information"); + + // first make sure we do not have a use of a in the + // instruction (a = b + a for example) because our + // transformation will not work. This should never occur + // because we are in SSA form. + for (unsigned i = 1; i != mi->getNumOperands(); ++i) + assert(!mi->getOperand(i).isRegister() || + mi->getOperand(i).getReg() != regA); + + const TargetRegisterClass* rc = + MF.getSSARegMap()->getRegClass(regA); + unsigned Added = MRI.copyRegToReg(*mbbi, mi, regA, regB, rc); + numInstrsAdded += Added; + + MachineBasicBlock::iterator prevMi = prior(mi); + DEBUG(std::cerr << "\t\tprepend:\t"; + prevMi->print(std::cerr, TM)); + + if (LV) { + // update live variables for regA + assert(Added == 1 && + "Cannot handle multi-instruction copies yet!"); + LiveVariables::VarInfo& varInfo = LV->getVarInfo(regA); + varInfo.DefInst = prevMi; + + // update live variables for regB + if (LV->removeVirtualRegisterKilled(regB, &*mbbi, mi)) + LV->addVirtualRegisterKilled(regB, &*mbbi, prevMi); + + if (LV->removeVirtualRegisterDead(regB, &*mbbi, mi)) + LV->addVirtualRegisterDead(regB, &*mbbi, prevMi); + } + + // replace all occurences of regB with regA + for (unsigned i = 1, e = mi->getNumOperands(); i != e; ++i) { + if (mi->getOperand(i).isRegister() && + mi->getOperand(i).getReg() == regB) + mi->SetMachineOperandReg(i, regA); + } } - DEBUG(std::cerr << "\t\tmodified original to: "; - mi->print(std::cerr, *tm_)); - assert(mi->getOperand(0).getAllocatedRegNum() == - mi->getOperand(1).getAllocatedRegNum()); + + assert(mi->getOperand(0).isDef()); + mi->getOperand(0).setUse(); + mi->RemoveOperand(1); + + DEBUG(std::cerr << "\t\trewrite to:\t"; + mi->print(std::cerr, TM)); } } - return numInstrsAdded != 0; + return MadeChange; } From brukman at cs.uiuc.edu Mon Mar 1 18:06:54 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Mar 1 18:06:54 2004 Subject: [llvm-commits] [parallel] CVS: llvm/runtime/libpng/contrib/msvctest/README.txt msvctest.dsp msvctest.dsw Message-ID: <200403012358.RAA04303@zion.cs.uiuc.edu> Changes in directory llvm/runtime/libpng/contrib/msvctest: README.txt added (r1.1.2.1) msvctest.dsp added (r1.1.2.1) msvctest.dsw added (r1.1.2.1) --- Log message: Merge from trunk --- Diffs of the changes: (+298 -0) Index: llvm/runtime/libpng/contrib/msvctest/README.txt diff -c /dev/null llvm/runtime/libpng/contrib/msvctest/README.txt:1.1.2.1 *** /dev/null Mon Mar 1 17:58:55 2004 --- llvm/runtime/libpng/contrib/msvctest/README.txt Mon Mar 1 17:58:45 2004 *************** *** 0 **** --- 1,22 ---- + Microsoft Developer Studio Build File, Format Version 6.00 for + msvctest + + Assumes that libpng DLLs and LIBs are in ..\..\projects\msvc\win32\libpng + Assumes that zlib DLLs and LIBs are in ..\..\projects\msvc\win32\zlib + + To build: + + 1) On the main menu Select "Build|Set Active configuration". + Choose the configuration that corresponds to the library you want to test. + This library must have been built using the libpng MS project located in + the "mscv" subdirectory. + + 2) Select "Build|Clean" + + 3) Select "Build|Rebuild All" + + 4) The test results should appear in the "Build" pane of the Output Window. + + + Simon-Pierre Cadieux + Methodex Computer Systems Inc. Index: llvm/runtime/libpng/contrib/msvctest/msvctest.dsp diff -c /dev/null llvm/runtime/libpng/contrib/msvctest/msvctest.dsp:1.1.2.1 *** /dev/null Mon Mar 1 17:58:55 2004 --- llvm/runtime/libpng/contrib/msvctest/msvctest.dsp Mon Mar 1 17:58:45 2004 *************** *** 0 **** --- 1,247 ---- + # Microsoft Developer Studio Project File - Name="msvctest" - Package Owner=<4> + # Microsoft Developer Studio Generated Build File, Format Version 6.00 + # ** DO NOT EDIT ** + + # TARGTYPE "Win32 (x86) Console Application" 0x0103 + + CFG=msvctest - Win32 Debug DLL + !MESSAGE This is not a valid makefile. To build this project using NMAKE, + !MESSAGE use the Export Makefile command and run + !MESSAGE + !MESSAGE NMAKE /f "msvctest.mak". + !MESSAGE + !MESSAGE You can specify a configuration when running NMAKE + !MESSAGE by defining the macro CFG on the command line. For example: + !MESSAGE + !MESSAGE NMAKE /f "msvctest.mak" CFG="msvctest - Win32 Debug DLL" + !MESSAGE + !MESSAGE Possible choices for configuration are: + !MESSAGE + !MESSAGE "msvctest - Win32 DLL" (based on "Win32 (x86) Console Application") + !MESSAGE "msvctest - Win32 Debug DLL" (based on "Win32 (x86) Console Application") + !MESSAGE "msvctest - Win32 ASM DLL" (based on "Win32 (x86) Console Application") + !MESSAGE "msvctest - Win32 Debug ASM DLL" (based on "Win32 (x86) Console Application") + !MESSAGE "msvctest - Win32 LIB" (based on "Win32 (x86) Console Application") + !MESSAGE "msvctest - Win32 Debug LIB" (based on "Win32 (x86) Console Application") + !MESSAGE + + # Begin Project + # PROP AllowPerConfigDependencies 0 + # PROP Scc_ProjName "" + # PROP Scc_LocalPath "" + CPP=cl.exe + RSC=rc.exe + + !IF "$(CFG)" == "msvctest - Win32 DLL" + + # PROP BASE Use_MFC 0 + # PROP BASE Use_Debug_Libraries 0 + # PROP BASE Output_Dir "dll" + # PROP BASE Intermediate_Dir "dll" + # PROP BASE Target_Dir "" + # PROP Use_MFC 0 + # PROP Use_Debug_Libraries 0 + # PROP Output_Dir "dll" + # PROP Intermediate_Dir "dll" + # PROP Ignore_Export_Lib 0 + # PROP Target_Dir "" + # ADD BASE CPP /nologo /W3 /O1 /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /FD /c + # ADD CPP /nologo /MD /W3 /O1 /I "..\..\..\zlib" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "PNG_DLL" /D "PNG_NO_STDIO" /D "PNG_NO_GLOBAL_ARRAYS" /FD /c + # ADD BASE RSC /l 0x409 /d "NDEBUG" + # ADD RSC /l 0x409 /d "NDEBUG" + BSC32=bscmake.exe + # ADD BASE BSC32 /nologo + # ADD BSC32 /nologo + LINK32=link.exe + # ADD BASE LINK32 /nologo /subsystem:console /machine:I386 + # ADD LINK32 ..\..\projects\msvc\win32\libpng\dll\libpng13.lib /nologo /subsystem:console /machine:I386 + # Begin Special Build Tool + OutDir=.\dll + SOURCE="$(InputPath)" + PostBuild_Desc=[Run Test] + PostBuild_Cmds=set path=..\..\projects\msvc\win32\libpng\dll;..\..\projects\msvc\win32\zlib\dll; $(outdir)\msvctest.exe ..\..\pngtest.png + # End Special Build Tool + + !ELSEIF "$(CFG)" == "msvctest - Win32 Debug DLL" + + # PROP BASE Use_MFC 0 + # PROP BASE Use_Debug_Libraries 1 + # PROP BASE Output_Dir "dll_dbg" + # PROP BASE Intermediate_Dir "dll_dbg" + # PROP BASE Target_Dir "" + # PROP Use_MFC 0 + # PROP Use_Debug_Libraries 1 + # PROP Output_Dir "dll_dbg" + # PROP Intermediate_Dir "dll_dbg" + # PROP Ignore_Export_Lib 0 + # PROP Target_Dir "" + # ADD BASE CPP /nologo /W3 /Zi /Od /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c + # ADD CPP /nologo /MDd /W3 /Zi /Od /I "..\..\..\zlib" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "PNG_DLL" /D "PNG_NO_STDIO" /D "PNG_NO_GLOBAL_ARRAYS" /FD /GZ /c + # ADD BASE RSC /l 0x409 /d "_DEBUG" + # ADD RSC /l 0x409 /d "_DEBUG" + BSC32=bscmake.exe + # ADD BASE BSC32 /nologo + # ADD BSC32 /nologo + LINK32=link.exe + # ADD BASE LINK32 /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept + # ADD LINK32 ..\..\projects\msvc\win32\libpng\dll_dbg\libpng13d.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept + # Begin Special Build Tool + OutDir=.\dll_dbg + SOURCE="$(InputPath)" + PostBuild_Desc=[Run Test] + PostBuild_Cmds=set path=..\..\projects\msvc\win32\libpng\dll_dbg;..\..\projects\msvc\win32\zlib\dll_dbg; $(outdir)\msvctest.exe ..\..\pngtest.png + # End Special Build Tool + + !ELSEIF "$(CFG)" == "msvctest - Win32 ASM DLL" + + # PROP BASE Use_MFC 0 + # PROP BASE Use_Debug_Libraries 0 + # PROP BASE Output_Dir "dll_asm" + # PROP BASE Intermediate_Dir "dll_asm" + # PROP BASE Target_Dir "" + # PROP Use_MFC 0 + # PROP Use_Debug_Libraries 0 + # PROP Output_Dir "dll_asm" + # PROP Intermediate_Dir "dll_asm" + # PROP Ignore_Export_Lib 0 + # PROP Target_Dir "" + # ADD BASE CPP /nologo /W3 /O1 /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /FD /c + # ADD CPP /nologo /MD /W3 /O1 /I "..\..\..\zlib" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "PNG_DLL" /D "PNG_NO_STDIO" /D "PNG_NO_GLOBAL_ARRAYS" /FD /c + # ADD BASE RSC /l 0x409 /d "NDEBUG" + # ADD RSC /l 0x409 /d "NDEBUG" + BSC32=bscmake.exe + # ADD BASE BSC32 /nologo + # ADD BSC32 /nologo + LINK32=link.exe + # ADD BASE LINK32 /nologo /subsystem:console /machine:I386 + # ADD LINK32 ..\..\projects\msvc\win32\libpng\dll_asm\libpng13a.lib /nologo /subsystem:console /machine:I386 + # Begin Special Build Tool + OutDir=.\dll_asm + SOURCE="$(InputPath)" + PostBuild_Desc=[Run Test] + PostBuild_Cmds=set path=..\..\projects\msvc\win32\libpng\dll_asm;..\..\projects\msvc\win32\zlib\dll_asm; $(outdir)\msvctest.exe ..\..\pngtest.png + # End Special Build Tool + + !ELSEIF "$(CFG)" == "msvctest - Win32 Debug ASM DLL" + + # PROP BASE Use_MFC 0 + # PROP BASE Use_Debug_Libraries 1 + # PROP BASE Output_Dir "dll_dbga" + # PROP BASE Intermediate_Dir "dll_dbga" + # PROP BASE Target_Dir "" + # PROP Use_MFC 0 + # PROP Use_Debug_Libraries 1 + # PROP Output_Dir "dll_dbga" + # PROP Intermediate_Dir "dll_dbga" + # PROP Ignore_Export_Lib 0 + # PROP Target_Dir "" + # ADD BASE CPP /nologo /W3 /Zi /Od /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c + # ADD CPP /nologo /MDd /W3 /Zi /Od /I "..\..\..\zlib" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "PNG_DLL" /D "PNG_NO_STDIO" /D "PNG_NO_GLOBAL_ARRAYS" /FD /GZ /c + # ADD BASE RSC /l 0x409 /d "_DEBUG" + # ADD RSC /l 0x409 /d "_DEBUG" + BSC32=bscmake.exe + # ADD BASE BSC32 /nologo + # ADD BSC32 /nologo + LINK32=link.exe + # ADD BASE LINK32 /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept + # ADD LINK32 ..\..\projects\msvc\win32\libpng\dll_dbga\libpng13b.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept + # Begin Special Build Tool + OutDir=.\dll_dbga + SOURCE="$(InputPath)" + PostBuild_Desc=[Run Test] + PostBuild_Cmds=set path=..\..\projects\msvc\win32\libpng\dll_dbga;..\..\projects\msvc\win32\zlib\dll_dbga; $(outdir)\msvctest.exe ..\..\pngtest.png + # End Special Build Tool + + !ELSEIF "$(CFG)" == "msvctest - Win32 LIB" + + # PROP BASE Use_MFC 0 + # PROP BASE Use_Debug_Libraries 0 + # PROP BASE Output_Dir "lib" + # PROP BASE Intermediate_Dir "lib" + # PROP BASE Target_Dir "" + # PROP Use_MFC 0 + # PROP Use_Debug_Libraries 0 + # PROP Output_Dir "lib" + # PROP Intermediate_Dir "lib" + # PROP Ignore_Export_Lib 0 + # PROP Target_Dir "" + # ADD BASE CPP /nologo /W3 /O1 /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /FD /c + # ADD CPP /nologo /W3 /O1 /I "..\..\..\zlib" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /FD /c + # ADD BASE RSC /l 0x409 /d "NDEBUG" + # ADD RSC /l 0x409 /d "NDEBUG" + BSC32=bscmake.exe + # ADD BASE BSC32 /nologo + # ADD BSC32 /nologo + LINK32=link.exe + # ADD BASE LINK32 /nologo /subsystem:console /machine:I386 + # ADD LINK32 ..\..\projects\msvc\win32\libpng\lib\libpng.lib /nologo /subsystem:console /machine:I386 + # Begin Special Build Tool + OutDir=.\lib + SOURCE="$(InputPath)" + PostBuild_Desc=[Run Test] + PostBuild_Cmds=$(outdir)\msvctest.exe ..\..\pngtest.png + # End Special Build Tool + + !ELSEIF "$(CFG)" == "msvctest - Win32 Debug LIB" + + # PROP BASE Use_MFC 0 + # PROP BASE Use_Debug_Libraries 1 + # PROP BASE Output_Dir "lib_dbg" + # PROP BASE Intermediate_Dir "lib_dbg" + # PROP BASE Target_Dir "" + # PROP Use_MFC 0 + # PROP Use_Debug_Libraries 1 + # PROP Output_Dir "lib_dbg" + # PROP Intermediate_Dir "lib_dbg" + # PROP Ignore_Export_Lib 0 + # PROP Target_Dir "" + # ADD BASE CPP /nologo /W3 /Zi /Od /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c + # ADD CPP /nologo /W3 /Zi /Od /I "..\..\..\zlib" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c + # ADD BASE RSC /l 0x409 /d "_DEBUG" + # ADD RSC /l 0x409 /d "_DEBUG" + BSC32=bscmake.exe + # ADD BASE BSC32 /nologo + # ADD BSC32 /nologo + LINK32=link.exe + # ADD BASE LINK32 /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept + # ADD LINK32 ..\..\projects\msvc\win32\libpng\lib_dbg\libpng.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept + # Begin Special Build Tool + OutDir=.\lib_dbg + SOURCE="$(InputPath)" + PostBuild_Desc=[Run Test] + PostBuild_Cmds=$(outdir)\msvctest.exe ..\..\pngtest.png + # End Special Build Tool + + !ENDIF + + # Begin Target + + # Name "msvctest - Win32 DLL" + # Name "msvctest - Win32 Debug DLL" + # Name "msvctest - Win32 ASM DLL" + # Name "msvctest - Win32 Debug ASM DLL" + # Name "msvctest - Win32 LIB" + # Name "msvctest - Win32 Debug LIB" + # Begin Group "Source Files" + + # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" + # Begin Source File + + SOURCE=..\..\pngtest.c + # End Source File + # Begin Source File + + SOURCE=.\README.txt + # PROP Exclude_From_Build 1 + # End Source File + # End Group + # Begin Group "Header Files" + + # PROP Default_Filter "h;hpp;hxx;hm;inl" + # End Group + # Begin Group "Resource Files" + + # PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" + # End Group + # End Target + # End Project Index: llvm/runtime/libpng/contrib/msvctest/msvctest.dsw diff -c /dev/null llvm/runtime/libpng/contrib/msvctest/msvctest.dsw:1.1.2.1 *** /dev/null Mon Mar 1 17:58:55 2004 --- llvm/runtime/libpng/contrib/msvctest/msvctest.dsw Mon Mar 1 17:58:45 2004 *************** *** 0 **** --- 1,29 ---- + Microsoft Developer Studio Workspace File, Format Version 6.00 + # WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + + ############################################################################### + + Project: "msvctest"=.\msvctest.dsp - Package Owner=<4> + + Package=<5> + {{{ + }}} + + Package=<4> + {{{ + }}} + + ############################################################################### + + Global: + + Package=<5> + {{{ + }}} + + Package=<3> + {{{ + }}} + + ############################################################################### + From brukman at cs.uiuc.edu Mon Mar 1 18:07:11 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Mar 1 18:07:11 2004 Subject: [llvm-commits] [parallel] CVS: llvm/runtime/libpng/projects/beos/x86-shared.proj x86-shared.txt x86-static.proj x86-static.txt Message-ID: <200403012358.RAA04416@zion.cs.uiuc.edu> Changes in directory llvm/runtime/libpng/projects/beos: x86-shared.proj added (r1.1.2.1) x86-shared.txt added (r1.1.2.1) x86-static.proj added (r1.1.2.1) x86-static.txt added (r1.1.2.1) --- Log message: Merge from trunk --- Diffs of the changes: (+44 -0) Index: llvm/runtime/libpng/projects/beos/x86-shared.proj Index: llvm/runtime/libpng/projects/beos/x86-shared.txt diff -c /dev/null llvm/runtime/libpng/projects/beos/x86-shared.txt:1.1.2.1 *** /dev/null Mon Mar 1 17:58:56 2004 --- llvm/runtime/libpng/projects/beos/x86-shared.txt Mon Mar 1 17:58:45 2004 *************** *** 0 **** --- 1,22 ---- + This project builds a shared library version of libpng on x86 BeOS. + + It defines PNG_USE_PNGGCCRD, which activates the assembly code in + pnggccrd.c; this hasn't been extensively tested on BeOS. + + To install: + + 1) build + + Note: As of version 1.0.10, you'll get a fair number of warnings when + you compile pnggccrd.c. As far as I know, these are harmless, + but it would be better if someone fixed them. + + 2) copy and png.h, pngconf.h somewhere; /boot/home/config/include (which + you'll have to make) is a good choice + + 3) copy libpng.so to /boot/home/config/lib + + 4) build your libpng.so applications (remember to include libz.a as + well when you link) + + - Chris Herborth, March 27, 2001 Index: llvm/runtime/libpng/projects/beos/x86-static.proj Index: llvm/runtime/libpng/projects/beos/x86-static.txt diff -c /dev/null llvm/runtime/libpng/projects/beos/x86-static.txt:1.1.2.1 *** /dev/null Mon Mar 1 17:58:56 2004 --- llvm/runtime/libpng/projects/beos/x86-static.txt Mon Mar 1 17:58:45 2004 *************** *** 0 **** --- 1,22 ---- + This project builds a static library version of libpng on x86 BeOS. + + It defines PNG_USE_PNGGCCRD, which activates the assembly code in + pnggccrd.c; this hasn't been extensively tested on BeOS. + + To install: + + 1) build + + Note: As of version 1.0.10, you'll get a fair number of warnings when + you compile pnggccrd.c. As far as I know, these are harmless, + but it would be better if someone fixed them. + + 2) copy and png.h, pngconf.h somewhere; /boot/home/config/include (which + you'll have to make) is a good choice + + 3) copy libpng.a to /boot/home/config/lib + + 4) build your libpng.a applications (remember to include libz.a as + well when you link) + + - Chris Herborth, March 27, 2001 From brukman at cs.uiuc.edu Mon Mar 1 18:07:29 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Mar 1 18:07:29 2004 Subject: [llvm-commits] [parallel] CVS: llvm/runtime/libpng/contrib/pngminus/README makefile.std makefile.tc3 makevms.com png2pnm.bat png2pnm.c png2pnm.sh pngminus.bat pngminus.sh pnm2png.bat pnm2png.c pnm2png.sh Message-ID: <200403012358.RAA04408@zion.cs.uiuc.edu> Changes in directory llvm/runtime/libpng/contrib/pngminus: README added (r1.1.2.1) makefile.std added (r1.1.2.1) makefile.tc3 added (r1.1.2.1) makevms.com added (r1.1.2.1) png2pnm.bat added (r1.1.2.1) png2pnm.c added (r1.1.2.1) png2pnm.sh added (r1.1.2.1) pngminus.bat added (r1.1.2.1) pngminus.sh added (r1.1.2.1) pnm2png.bat added (r1.1.2.1) pnm2png.c added (r1.1.2.1) pnm2png.sh added (r1.1.2.1) --- Log message: Merge from trunk --- Diffs of the changes: (+1483 -0) Index: llvm/runtime/libpng/contrib/pngminus/README diff -c /dev/null llvm/runtime/libpng/contrib/pngminus/README:1.1.2.1 *** /dev/null Mon Mar 1 17:58:55 2004 --- llvm/runtime/libpng/contrib/pngminus/README Mon Mar 1 17:58:45 2004 *************** *** 0 **** --- 1,153 ---- + PngMinus + -------- + (copyright Willem van Schaik, 1999) + + + License + ------- + + Permission to use, copy, modify, and distribute this software and + its documentation for any purpose and without fee is hereby granted, + provided that the above copyright notice appear in all copies and + that both that copyright notice and this permission notice appear in + supporting documentation. This software is provided "as is" without + express or implied warranty. + + + Some history + ------------ + Soon after the creation of PNG in 1995, the need was felt for a set of + pnmtopng / pngtopnm utilities. Independantly Alexander Lehmann and I + (Willem van Schaik) started such a project. Luckily we discovered this + and merged the two together into pnmtopng.tar.gz, which is available + from a/o ftp://swrinde.nde.swri.edu/pub/png/. + + These two utilities have many, many options and make use of most of the + features of PNG, like gamma, alpha, sbit, text-chunks, etc. This makes + the utilities quite complex and by now not anymore very maintainable. + When we wrote these programs, libpng was still in an early stage. + Therefore, lots of the functionality that we put in our software can now + be done using transform-functions in libpng. + + Finally, to compile these programs, you need to have installed and + compiled three libraries: libpng, zlib and netpbm. Especially the latter + makes the whole setup a bit bulky. But that's unavoidable given the many + features of pnmtopng. + + + What now + -------- + At this moment libpng is in a very stable state and can do much of the + work done in pnmtopng. Also, pnmtopng needs to be upgraded to the new + interface of libpng. Hence, it is time for a rewrite from the ground up + of pnmtopng and pngtopnm. This will happen in the near future (stay + tuned). The new package will get a different name to distinguish it from + the old one: PngPlus. + + To experiment a bit with the new interface of libpng, I started off with + a small prototype that contains only the basic functionality. It doesn't + have any of the options to read or write special chunks and it will do + no gamma correction. But this makes it also a simple program that is + quite easy to understand and can serve well as a template for other + software developments. (By now there are of course a couple of programs, + like Greg Roelofs' rpng/wpng, that can be used just as good.) + + + Can and can not + --------------- + As this is the small brother of the future PngPlus, I called this fellow + PngMinus. Because I started this development in good-old Turbo-C, I + avoided the use the netpbm library, which requires DOS extenders. Again, + another reason to call it PngMinus (minus netpbm :-). So, part of the + program are some elementary routines to read / write pgm- and ppm-files. + It does not read b&w pbm-files. + + The downside of this approach is that you can not use them on images + that require blocks of memory bigger than 64k (the DOS version). For + larger images you will get an out-of-memory error. + + As said before, PngMinus doesn't correct for gamma. When reading + png-files you can do this just as well by piping the output of png2pnm + to pnmgamma, one of the standard PbmPlus tools. This same scenario will + most probably also be followed in the full-blown future PngPlus, with + the addition of course of the possibility to create gamma-chunks when + writing png-files. + + On the other hand it supports alpha-channels. When reading a png-image + you can write the alpha-channel into a pgm-file. And when creating an + RGB+A png-image, you just combine a ppm-file with a corresponding + pgm-file containing the alpha-channel. When reading, transparency chunks + are converted into an alpha-channel and from there on treated the same + way. + + Finally you can opt for writing ascii or binary pgm- and ppm-files. When + the bit-depth is 16, the format will always be ascii. + + + Using it + -------- + To distinguish them from pnmtopng and PngPlus, the utilities are named + png2pnm and pnm2png (2 instead of to). The input- and output-files can + be given as parameters or through redirection. Therefore the programs + can be part of a pipe. + + To list the options type "png2pnm -h" or "pnm2png -h". + + + Just like Scandinavian furniture + -------------------------------- + You have to put it together yourself. I did test the software under + MS-DOS with Turbo-C 3.0 and under RedHat Linux 4.2 with gcc. In both + cases I used libpng-1.0.4 and zlib-1.1.3. Later versions should be OK, + however some older libpng versions have a bug in pngmem.c when using + Turbo-C 3.0 (see below). + + You can build it using one of the two makefiles (make -f makefile.###) + or use the batch/script files pngminus.bat / pngminus.sh. This assumes + that you have built the libraries in ../libpng and ../zlib. Using Linux, + make sure that you have built libpng with makefile.std and not + makefile.linux (also called .lnx in earlier versions of libpng). The + latter creates a .so shared-library, while the PngMinus makefile assumes + a normal .a static library. + + If you create a ../pngsuite directory and then store the basn####.png + files from PngSuite (http://www.schaik.com/pngsuite/) in there, you can + test in one go the proper functioning of PngMinus, see png2pnm.bat and + pnm2png.bat (or the .sh versions). + + + Warranty + ------- + Please, remember that this was just a small experiment to learn a few + things. It will have many unforeseen features . Who said bugs? Use + it when you are in need for something simple or when you want to start + developing your own stuff. + + + The Turbo bug + ------------- + ** pngmem.old + hptr = (png_byte huge *)((long)(hptr) & 0xfffffff0L); + hptr += 16L; + ** pngmem.c + hptr = (png_byte huge *)((long)(hptr) & 0xfffffff0L); + hptr = hptr + 16L; + ** + + ** pngmem.old + png_ptr->offset_table_ptr[i] = (png_bytep)hptr; + hptr += (png_uint_32)65536L; + ** pngmem.c + png_ptr->offset_table_ptr[i] = (png_bytep)hptr; + hptr = hptr + 65536L; + ** + + + The end + ------- + Willem van Schaik + mailto:willem at schaik.com + http://www.schaik.com/png/ + ------- + Oct 1999 + Index: llvm/runtime/libpng/contrib/pngminus/makefile.std diff -c /dev/null llvm/runtime/libpng/contrib/pngminus/makefile.std:1.1.2.1 *** /dev/null Mon Mar 1 17:58:55 2004 --- llvm/runtime/libpng/contrib/pngminus/makefile.std Mon Mar 1 17:58:45 2004 *************** *** 0 **** --- 1,65 ---- + # Makefile for PngMinus (png2pnm and pnm2png) + # Linux / Unix + + #CC=cc + CC=gcc + LD=$(CC) + + RM=rm -f + + #PNGPATH = /usr/local + #PNGINC = -I$(PNGPATH)/include/libpng12 + #PNGLIB = -L$(PNGPATH)/lib -lpng12 + #PNGLIBS = $(PNGPATH)/lib/libpng12.a + PNGINC = -I../.. + PNGLIB = -L../.. -lpng + PNGLIBS = ../../libpng.a + + #ZPATH = /usr/local + #ZINC = -I$(ZPATH)/include + #ZLIB = -L$(ZPATH)/lib -lz + #ZLIBS = $(ZPATH)/lib/libz.a + ZINC = -I../../../zlib + ZLIB = -L../../../zlib -lz + ZLIBS = ../../../zlib/libz.a + + CFLAGS=-O3 $(PNGINC) $(ZINC) + LDFLAGS=$(PNGLIB) $(ZLIB) + LDFLAGSS=$(PNGLIBS) $(ZLIBS) + C=.c + O=.o + L=.a + E= + + # dependencies + + #all: png2pnm$(E) pnm2png$(E) + all: png2pnm$(E) pnm2png$(E) png2pnm-static$(E) pnm2png-static$(E) + + png2pnm$(O): png2pnm$(C) + $(CC) -c $(CFLAGS) png2pnm$(C) + + png2pnm$(E): png2pnm$(O) + $(LD) -o png2pnm$(E) png2pnm$(O) $(LDFLAGS) -lm + + png2pnm-static$(E): png2pnm$(O) + $(LD) -o png2pnm-static$(E) png2pnm$(O) $(LDFLAGSS) -lm + + pnm2png$(O): pnm2png$(C) + $(CC) -c $(CFLAGS) pnm2png$(C) + + pnm2png$(E): pnm2png$(O) + $(LD) -o pnm2png$(E) pnm2png$(O) $(LDFLAGS) -lm + + pnm2png-static$(E): pnm2png$(O) + $(LD) -o pnm2png-static$(E) pnm2png$(O) $(LDFLAGSS) -lm + + clean: + $(RM) png2pnm$(O) + $(RM) pnm2png$(O) + $(RM) png2pnm$(E) + $(RM) pnm2png$(E) + $(RM) png2pnm-static$(E) + $(RM) pnm2png-static$(E) + + # End of makefile for png2pnm / pnm2png Index: llvm/runtime/libpng/contrib/pngminus/makefile.tc3 diff -c /dev/null llvm/runtime/libpng/contrib/pngminus/makefile.tc3:1.1.2.1 *** /dev/null Mon Mar 1 17:58:55 2004 --- llvm/runtime/libpng/contrib/pngminus/makefile.tc3 Mon Mar 1 17:58:45 2004 *************** *** 0 **** --- 1,38 ---- + # Makefile for PngMinus (png2pnm and pnm2png) + # TurboC++ 3.0 + + CC=tcc -Ic:\tc3\inc + LD=tcc -Lc:\tc3\lib + LB=tlib + RM=del + CP=copy + MODEL=l + CCFLAGS=-O -m$(MODEL) -I..\libpng -I..\zlib + LDFLAGS=-m$(MODEL) -L..\libpng -L..\zlib + C=.c + O=.obj + L=.lib + E=.exe + + # dependencies + + all: png2pnm$(E) pnm2png$(E) + + png2pnm$(O): png2pnm$(C) + $(CC) -c $(CCFLAGS) png2pnm$(C) + + png2pnm$(E): png2pnm$(O) + $(LD) $(LDFLAGS) png2pnm$(O) libpng$(L) zlib$(L) + + pnm2png$(O): pnm2png$(C) + $(CC) -c $(CCFLAGS) pnm2png$(C) + + pnm2png$(E): pnm2png$(O) + $(LD) $(LDFLAGS) pnm2png$(O) libpng$(L) zlib$(L) + + clean: + $(RM) *$(O) + $(RM) *$(E) + + # End of makefile for png2pnm / pnm2png + Index: llvm/runtime/libpng/contrib/pngminus/makevms.com diff -c /dev/null llvm/runtime/libpng/contrib/pngminus/makevms.com:1.1.2.1 *** /dev/null Mon Mar 1 17:58:55 2004 --- llvm/runtime/libpng/contrib/pngminus/makevms.com Mon Mar 1 17:58:45 2004 *************** *** 0 **** --- 1,92 ---- + $!------------------------------------------------------------------------------ + $! make Contrib programs of libpng under OpenVMS + $! + $! + $! Look for the compiler used + $! + $ zlibsrc = "[---.zlib]" + $ ccopt="/include=(''zlibsrc',[--])" + $ if f$getsyi("HW_MODEL").ge.1024 + $ then + $ ccopt = "/prefix=all"+ccopt + $ comp = "__decc__=1" + $ if f$trnlnm("SYS").eqs."" then define sys sys$library: + $ else + $ if f$search("SYS$SYSTEM:DECC$COMPILER.EXE").eqs."" + $ then + $ if f$trnlnm("SYS").eqs."" then define sys sys$library: + $ if f$search("SYS$SYSTEM:VAXC.EXE").eqs."" + $ then + $ comp = "__gcc__=1" + $ CC :== GCC + $ else + $ comp = "__vaxc__=1" + $ endif + $ else + $ if f$trnlnm("SYS").eqs."" then define sys decc$library_include: + $ ccopt = "/decc/prefix=all"+ccopt + $ comp = "__decc__=1" + $ endif + $ endif + $ open/write lopt lib.opt + $ write lopt "[--]libpng.olb/lib" + $ write lopt "''zlibsrc'libz.olb/lib" + $ close lopt + $ open/write xopt x11.opt + $ write xopt "sys$library:decw$xlibshr.exe/share" + $ close xopt + $ write sys$output "Compiling PNG contrib programs ..." + $ write sys$output "Building pnm2png..." + $ CALL MAKE pnm2png.OBJ "cc ''CCOPT' pnm2png" - + pnm2png.c + $ call make pnm2png.exe - + "LINK pnm2png,lib.opt/opt" - + pnm2png.obj + $ write sys$output "Building png2pnm..." + $ CALL MAKE png2pnm.OBJ "cc ''CCOPT' png2pnm" - + png2pnm.c + $ call make png2pnm.exe - + "LINK png2pnm,lib.opt/opt" - + png2pnm.obj + $ exit + $! + $! + $MAKE: SUBROUTINE !SUBROUTINE TO CHECK DEPENDENCIES + $ V = 'F$Verify(0) + $! P1 = What we are trying to make + $! P2 = Command to make it + $! P3 - P8 What it depends on + $ + $ If F$Search(P1) .Eqs. "" Then Goto Makeit + $ Time = F$CvTime(F$File(P1,"RDT")) + $arg=3 + $Loop: + $ Argument = P'arg + $ If Argument .Eqs. "" Then Goto Exit + $ El=0 + $Loop2: + $ File = F$Element(El," ",Argument) + $ If File .Eqs. " " Then Goto Endl + $ AFile = "" + $Loop3: + $ OFile = AFile + $ AFile = F$Search(File) + $ If AFile .Eqs. "" .Or. AFile .Eqs. OFile Then Goto NextEl + $ If F$CvTime(F$File(AFile,"RDT")) .Ges. Time Then Goto Makeit + $ Goto Loop3 + $NextEL: + $ El = El + 1 + $ Goto Loop2 + $EndL: + $ arg=arg+1 + $ If arg .Le. 8 Then Goto Loop + $ Goto Exit + $ + $Makeit: + $ VV=F$VERIFY(0) + $ write sys$output P2 + $ 'P2 + $ VV='F$Verify(VV) + $Exit: + $ If V Then Set Verify + $ENDSUBROUTINE Index: llvm/runtime/libpng/contrib/pngminus/png2pnm.bat diff -c /dev/null llvm/runtime/libpng/contrib/pngminus/png2pnm.bat:1.1.2.1 *** /dev/null Mon Mar 1 17:58:55 2004 --- llvm/runtime/libpng/contrib/pngminus/png2pnm.bat Mon Mar 1 17:58:45 2004 *************** *** 0 **** --- 1,41 ---- + REM -- grayscale + png2pnm.exe -noraw ..\pngsuite\basn0g01.png basn0g01.pgm + png2pnm.exe -noraw ..\pngsuite\basn0g02.png basn0g02.pgm + png2pnm.exe -noraw ..\pngsuite\basn0g04.png basn0g04.pgm + png2pnm.exe -noraw ..\pngsuite\basn0g08.png basn0g08.pgm + png2pnm.exe -noraw ..\pngsuite\basn0g16.png basn0g16.pgm + REM -- full-color + png2pnm.exe -noraw ..\pngsuite\basn2c08.png basn2c08.ppm + png2pnm.exe -noraw ..\pngsuite\basn2c16.png basn2c16.ppm + REM -- palletted + png2pnm.exe -noraw ..\pngsuite\basn3p01.png basn3p01.ppm + png2pnm.exe -noraw ..\pngsuite\basn3p02.png basn3p02.ppm + png2pnm.exe -noraw ..\pngsuite\basn3p04.png basn3p04.ppm + png2pnm.exe -noraw ..\pngsuite\basn3p08.png basn3p08.ppm + REM -- gray with alpha-channel + png2pnm.exe -noraw ..\pngsuite\basn4a08.png basn4a08.pgm + png2pnm.exe -noraw ..\pngsuite\basn4a16.png basn4a16.pgm + REM -- color with alpha-channel + png2pnm.exe -noraw -alpha basn6a08.pgm ..\pngsuite\basn6a08.png basn6a08.ppm + png2pnm.exe -noraw -alpha basn6a16.pgm ..\pngsuite\basn6a16.png basn6a16.ppm + REM -- grayscale + png2pnm.exe -raw ..\pngsuite\basn0g01.png rawn0g01.pgm + png2pnm.exe -raw ..\pngsuite\basn0g02.png rawn0g02.pgm + png2pnm.exe -raw ..\pngsuite\basn0g04.png rawn0g04.pgm + png2pnm.exe -raw ..\pngsuite\basn0g08.png rawn0g08.pgm + png2pnm.exe -raw ..\pngsuite\basn0g16.png rawn0g16.pgm + REM -- full-color + png2pnm.exe -raw ..\pngsuite\basn2c08.png rawn2c08.ppm + png2pnm.exe -raw ..\pngsuite\basn2c16.png rawn2c16.ppm + REM -- palletted + png2pnm.exe -raw ..\pngsuite\basn3p01.png rawn3p01.ppm + png2pnm.exe -raw ..\pngsuite\basn3p02.png rawn3p02.ppm + png2pnm.exe -raw ..\pngsuite\basn3p04.png rawn3p04.ppm + png2pnm.exe -raw ..\pngsuite\basn3p08.png rawn3p08.ppm + REM -- gray with alpha-channel + png2pnm.exe -raw ..\pngsuite\basn4a08.png rawn4a08.pgm + png2pnm.exe -raw ..\pngsuite\basn4a16.png rawn4a16.pgm + REM -- color with alpha-channel + png2pnm.exe -noraw -alpha rawn6a08.pgm ..\pngsuite\basn6a08.png rawn6a08.ppm + png2pnm.exe -noraw -alpha rawn6a16.pgm ..\pngsuite\basn6a16.png rawn6a16.ppm + Index: llvm/runtime/libpng/contrib/pngminus/png2pnm.c diff -c /dev/null llvm/runtime/libpng/contrib/pngminus/png2pnm.c:1.1.2.1 *** /dev/null Mon Mar 1 17:58:55 2004 --- llvm/runtime/libpng/contrib/pngminus/png2pnm.c Mon Mar 1 17:58:45 2004 *************** *** 0 **** --- 1,430 ---- + /* + * png2pnm.c --- conversion from PNG-file to PGM/PPM-file + * copyright (C) 1999 by Willem van Schaik + * + * version 1.0 - 1999.10.15 - First version. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear in + * supporting documentation. This software is provided "as is" without + * express or implied warranty. + */ + + #include + #include + #ifdef __TURBOC__ + #include + #include + #endif + + #ifndef BOOL + #define BOOL unsigned char + #endif + #ifndef TRUE + #define TRUE (BOOL) 1 + #endif + #ifndef FALSE + #define FALSE (BOOL) 0 + #endif + + #ifdef __TURBOC__ + #define STDIN 0 + #define STDOUT 1 + #define STDERR 2 + #endif + + /* to make png2pnm verbose so we can find problems (needs to be before png.h) */ + #ifndef PNG_DEBUG + #define PNG_DEBUG 0 + #endif + + #include "png.h" + + /* Define png_jmpbuf() in case we are using a pre-1.0.6 version of libpng */ + #ifndef png_jmpbuf + # define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf) + #endif + + /* function prototypes */ + + int main (int argc, char *argv[]); + void usage (); + BOOL png2pnm (FILE *png_file, FILE *pnm_file, FILE *alpha_file, BOOL raw, BOOL alpha); + + /* + * main + */ + + int main(int argc, char *argv[]) + { + FILE *fp_rd = stdin; + FILE *fp_wr = stdout; + FILE *fp_al = NULL; + BOOL raw = TRUE; + BOOL alpha = FALSE; + int argi; + + for (argi = 1; argi < argc; argi++) + { + if (argv[argi][0] == '-') + { + switch (argv[argi][1]) + { + case 'n': + raw = FALSE; + break; + case 'r': + raw = TRUE; + break; + case 'a': + alpha = TRUE; + argi++; + if ((fp_al = fopen (argv[argi], "wb")) == NULL) + { + fprintf (stderr, "PNM2PNG\n"); + fprintf (stderr, "Error: can not create alpha-channel file %s\n", argv[argi]); + exit (1); + } + break; + case 'h': + case '?': + usage(); + exit(0); + break; + default: + fprintf (stderr, "PNG2PNM\n"); + fprintf (stderr, "Error: unknown option %s\n", argv[argi]); + usage(); + exit(1); + break; + } /* end switch */ + } + else if (fp_rd == stdin) + { + if ((fp_rd = fopen (argv[argi], "rb")) == NULL) + { + fprintf (stderr, "PNG2PNM\n"); + fprintf (stderr, "Error: file %s does not exist\n", argv[argi]); + exit (1); + } + } + else if (fp_wr == stdout) + { + if ((fp_wr = fopen (argv[argi], "wb")) == NULL) + { + fprintf (stderr, "PNG2PNM\n"); + fprintf (stderr, "Error: can not create file %s\n", argv[argi]); + exit (1); + } + } + else + { + fprintf (stderr, "PNG2PNM\n"); + fprintf (stderr, "Error: too many parameters\n"); + usage(); + exit(1); + } + } /* end for */ + + #ifdef __TURBOC__ + /* set stdin/stdout if required to binary */ + if (fp_rd == stdin) + { + setmode (STDIN, O_BINARY); + } + if ((raw) && (fp_wr == stdout)) + { + setmode (STDOUT, O_BINARY); + } + #endif + + /* call the conversion program itself */ + if (png2pnm (fp_rd, fp_wr, fp_al, raw, alpha) == FALSE) + { + fprintf (stderr, "PNG2PNM\n"); + fprintf (stderr, "Error: unsuccessful convertion of PNG-image\n"); + exit(1); + } + + /* close input file */ + fclose (fp_rd); + /* close output file */ + fclose (fp_wr); + /* close alpha file */ + if (alpha) + fclose (fp_al); + + return 0; + } + + /* + * usage + */ + + void usage() + { + fprintf (stderr, "PNG2PNM\n"); + fprintf (stderr, " by Willem van Schaik, 1999\n"); + #ifdef __TURBOC__ + fprintf (stderr, " for Turbo-C and Borland-C compilers\n"); + #else + fprintf (stderr, " for Linux (and Unix) compilers\n"); + #endif + fprintf (stderr, "Usage: png2pnm [options] .png [.pnm]\n"); + fprintf (stderr, " or: ... | png2pnm [options]\n"); + fprintf (stderr, "Options:\n"); + fprintf (stderr, " -r[aw] write pnm-file in binary format (P4/P5/P6) (default)\n"); + fprintf (stderr, " -n[oraw] write pnm-file in ascii format (P1/P2/P3)\n"); + fprintf (stderr, " -a[lpha] .pgm write PNG alpha channel as pgm-file\n"); + fprintf (stderr, " -h | -? print this help-information\n"); + } + + /* + * png2pnm + */ + + BOOL png2pnm (FILE *png_file, FILE *pnm_file, FILE *alpha_file, BOOL raw, BOOL alpha) + { + png_struct *png_ptr = NULL; + png_info *info_ptr = NULL; + png_byte buf[8]; + png_byte *png_pixels = NULL; + png_byte **row_pointers = NULL; + png_byte *pix_ptr = NULL; + png_uint_32 row_bytes; + + png_uint_32 width; + png_uint_32 height; + int bit_depth; + int channels; + int color_type; + int alpha_present; + int row, col; + int ret; + int i; + long dep_16; + + /* read and check signature in PNG file */ + ret = fread (buf, 1, 8, png_file); + if (ret != 8) + return FALSE; + + ret = png_check_sig (buf, 8); + if (!ret) + return FALSE; + + /* create png and info structures */ + + png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, + NULL, NULL, NULL); + if (!png_ptr) + return FALSE; /* out of memory */ + + info_ptr = png_create_info_struct (png_ptr); + if (!info_ptr) + { + png_destroy_read_struct (&png_ptr, NULL, NULL); + return FALSE; /* out of memory */ + } + + if (setjmp (png_jmpbuf(png_ptr))) + { + png_destroy_read_struct (&png_ptr, &info_ptr, NULL); + return FALSE; + } + + /* set up the input control for C streams */ + png_init_io (png_ptr, png_file); + png_set_sig_bytes (png_ptr, 8); /* we already read the 8 signature bytes */ + + /* read the file information */ + png_read_info (png_ptr, info_ptr); + + /* get size and bit-depth of the PNG-image */ + png_get_IHDR (png_ptr, info_ptr, + &width, &height, &bit_depth, &color_type, + NULL, NULL, NULL); + + /* set-up the transformations */ + + /* transform paletted images into full-color rgb */ + if (color_type == PNG_COLOR_TYPE_PALETTE) + png_set_expand (png_ptr); + /* expand images to bit-depth 8 (only applicable for grayscale images) */ + if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) + png_set_expand (png_ptr); + /* transform transparency maps into full alpha-channel */ + if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS)) + png_set_expand (png_ptr); + + #ifdef NJET + /* downgrade 16-bit images to 8 bit */ + if (bit_depth == 16) + png_set_strip_16 (png_ptr); + /* transform grayscale images into full-color */ + if (color_type == PNG_COLOR_TYPE_GRAY || + color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + png_set_gray_to_rgb (png_ptr); + /* only if file has a file gamma, we do a correction */ + if (png_get_gAMA (png_ptr, info_ptr, &file_gamma)) + png_set_gamma (png_ptr, (double) 2.2, file_gamma); + #endif + + /* all transformations have been registered; now update info_ptr data, + * get rowbytes and channels, and allocate image memory */ + + png_read_update_info (png_ptr, info_ptr); + + /* get the new color-type and bit-depth (after expansion/stripping) */ + png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, + NULL, NULL, NULL); + + /* check for 16-bit files */ + if (bit_depth == 16) + { + raw = FALSE; + #ifdef __TURBOC__ + pnm_file->flags &= ~((unsigned) _F_BIN); + #endif + } + + /* calculate new number of channels and store alpha-presence */ + if (color_type == PNG_COLOR_TYPE_GRAY) + channels = 1; + else if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + channels = 2; + else if (color_type == PNG_COLOR_TYPE_RGB) + channels = 3; + else if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) + channels = 4; + else + channels = 0; /* should never happen */ + alpha_present = (channels - 1) % 2; + + /* check if alpha is expected to be present in file */ + if (alpha && !alpha_present) + { + fprintf (stderr, "PNG2PNM\n"); + fprintf (stderr, "Error: PNG-file doesn't contain alpha channel\n"); + exit (1); + } + + /* row_bytes is the width x number of channels x (bit-depth / 8) */ + row_bytes = png_get_rowbytes (png_ptr, info_ptr); + + if ((png_pixels = (png_byte *) malloc (row_bytes * height * sizeof (png_byte))) == NULL) { + png_destroy_read_struct (&png_ptr, &info_ptr, NULL); + return FALSE; + } + + if ((row_pointers = (png_byte **) malloc (height * sizeof (png_bytep))) == NULL) + { + png_destroy_read_struct (&png_ptr, &info_ptr, NULL); + free (png_pixels); + png_pixels = NULL; + return FALSE; + } + + /* set the individual row_pointers to point at the correct offsets */ + for (i = 0; i < (height); i++) + row_pointers[i] = png_pixels + i * row_bytes; + + /* now we can go ahead and just read the whole image */ + png_read_image (png_ptr, row_pointers); + + /* read rest of file, and get additional chunks in info_ptr - REQUIRED */ + png_read_end (png_ptr, info_ptr); + + /* clean up after the read, and free any memory allocated - REQUIRED */ + png_destroy_read_struct (&png_ptr, &info_ptr, (png_infopp) NULL); + + /* write header of PNM file */ + + if ((color_type == PNG_COLOR_TYPE_GRAY) || + (color_type == PNG_COLOR_TYPE_GRAY_ALPHA)) + { + fprintf (pnm_file, "%s\n", (raw) ? "P5" : "P2"); + fprintf (pnm_file, "%d %d\n", (int) width, (int) height); + fprintf (pnm_file, "%ld\n", ((1L << (int) bit_depth) - 1L)); + } + else if ((color_type == PNG_COLOR_TYPE_RGB) || + (color_type == PNG_COLOR_TYPE_RGB_ALPHA)) + { + fprintf (pnm_file, "%s\n", (raw) ? "P6" : "P3"); + fprintf (pnm_file, "%d %d\n", (int) width, (int) height); + fprintf (pnm_file, "%ld\n", ((1L << (int) bit_depth) - 1L)); + } + + /* write header of PGM file with alpha channel */ + + if ((alpha) && + ((color_type == PNG_COLOR_TYPE_GRAY_ALPHA) || + (color_type == PNG_COLOR_TYPE_RGB_ALPHA))) + { + fprintf (alpha_file, "%s\n", (raw) ? "P5" : "P2"); + fprintf (alpha_file, "%d %d\n", (int) width, (int) height); + fprintf (alpha_file, "%ld\n", ((1L << (int) bit_depth) - 1L)); + } + + /* write data to PNM file */ + pix_ptr = png_pixels; + + for (row = 0; row < height; row++) + { + for (col = 0; col < width; col++) + { + for (i = 0; i < (channels - alpha_present); i++) + { + if (raw) + fputc ((int) *pix_ptr++ , pnm_file); + else + if (bit_depth == 16){ + dep_16 = (long) *pix_ptr++; + fprintf (pnm_file, "%ld ", (dep_16 << 8) + ((long) *pix_ptr++)); + } + else + fprintf (pnm_file, "%ld ", (long) *pix_ptr++); + } + if (alpha_present) + { + if (!alpha) + { + pix_ptr++; /* alpha */ + if (bit_depth == 16) + pix_ptr++; + } + else /* output alpha-channel as pgm file */ + { + if (raw) + fputc ((int) *pix_ptr++ , alpha_file); + else + if (bit_depth == 16){ + dep_16 = (long) *pix_ptr++; + fprintf (alpha_file, "%ld ", (dep_16 << 8) + (long) *pix_ptr++); + } + else + fprintf (alpha_file, "%ld ", (long) *pix_ptr++); + } + } /* if alpha_present */ + + if (!raw) + if (col % 4 == 3) + fprintf (pnm_file, "\n"); + } /* end for col */ + + if (!raw) + if (col % 4 != 0) + fprintf (pnm_file, "\n"); + } /* end for row */ + + if (row_pointers != (unsigned char**) NULL) + free (row_pointers); + if (png_pixels != (unsigned char*) NULL) + free (png_pixels); + + return TRUE; + + } /* end of source */ + Index: llvm/runtime/libpng/contrib/pngminus/png2pnm.sh diff -c /dev/null llvm/runtime/libpng/contrib/pngminus/png2pnm.sh:1.1.2.1 *** /dev/null Mon Mar 1 17:58:55 2004 --- llvm/runtime/libpng/contrib/pngminus/png2pnm.sh Mon Mar 1 17:58:45 2004 *************** *** 0 **** --- 1,41 ---- + # -- grayscale + ./png2pnm -noraw ../pngsuite/basn0g01.png basn0g01.pgm + ./png2pnm -noraw ../pngsuite/basn0g02.png basn0g02.pgm + ./png2pnm -noraw ../pngsuite/basn0g04.png basn0g04.pgm + ./png2pnm -noraw ../pngsuite/basn0g08.png basn0g08.pgm + ./png2pnm -noraw ../pngsuite/basn0g16.png basn0g16.pgm + # -- full-color + ./png2pnm -noraw ../pngsuite/basn2c08.png basn2c08.ppm + ./png2pnm -noraw ../pngsuite/basn2c16.png basn2c16.ppm + # -- palletted + ./png2pnm -noraw ../pngsuite/basn3p01.png basn3p01.ppm + ./png2pnm -noraw ../pngsuite/basn3p02.png basn3p02.ppm + ./png2pnm -noraw ../pngsuite/basn3p04.png basn3p04.ppm + ./png2pnm -noraw ../pngsuite/basn3p08.png basn3p08.ppm + # -- gray with alpha-channel + ./png2pnm -noraw ../pngsuite/basn4a08.png basn4a08.pgm + ./png2pnm -noraw ../pngsuite/basn4a16.png basn4a16.pgm + # -- color with alpha-channel + ./png2pnm -noraw -alpha basn6a08.pgm ../pngsuite/basn6a08.png basn6a08.ppm + ./png2pnm -noraw -alpha basn6a16.pgm ../pngsuite/basn6a16.png basn6a16.ppm + # -- grayscale + ./png2pnm -raw ../pngsuite/basn0g01.png rawn0g01.pgm + ./png2pnm -raw ../pngsuite/basn0g02.png rawn0g02.pgm + ./png2pnm -raw ../pngsuite/basn0g04.png rawn0g04.pgm + ./png2pnm -raw ../pngsuite/basn0g08.png rawn0g08.pgm + ./png2pnm -raw ../pngsuite/basn0g16.png rawn0g16.pgm + # -- full-color + ./png2pnm -raw ../pngsuite/basn2c08.png rawn2c08.ppm + ./png2pnm -raw ../pngsuite/basn2c16.png rawn2c16.ppm + # -- palletted + ./png2pnm -raw ../pngsuite/basn3p01.png rawn3p01.ppm + ./png2pnm -raw ../pngsuite/basn3p02.png rawn3p02.ppm + ./png2pnm -raw ../pngsuite/basn3p04.png rawn3p04.ppm + ./png2pnm -raw ../pngsuite/basn3p08.png rawn3p08.ppm + # -- gray with alpha-channel + ./png2pnm -raw ../pngsuite/basn4a08.png rawn4a08.pgm + ./png2pnm -raw ../pngsuite/basn4a16.png rawn4a16.pgm + # -- color with alpha-channel + ./png2pnm -noraw -alpha rawn6a08.pgm ../pngsuite/basn6a08.png rawn6a08.ppm + ./png2pnm -noraw -alpha rawn6a16.pgm ../pngsuite/basn6a16.png rawn6a16.ppm + Index: llvm/runtime/libpng/contrib/pngminus/pngminus.bat diff -c /dev/null llvm/runtime/libpng/contrib/pngminus/pngminus.bat:1.1.2.1 *** /dev/null Mon Mar 1 17:58:55 2004 --- llvm/runtime/libpng/contrib/pngminus/pngminus.bat Mon Mar 1 17:58:45 2004 *************** *** 0 **** --- 1,4 ---- + make -f makefile.tc3 + call png2pnm.bat + call pnm2png.bat + Index: llvm/runtime/libpng/contrib/pngminus/pngminus.sh diff -c /dev/null llvm/runtime/libpng/contrib/pngminus/pngminus.sh:1.1.2.1 *** /dev/null Mon Mar 1 17:58:55 2004 --- llvm/runtime/libpng/contrib/pngminus/pngminus.sh Mon Mar 1 17:58:45 2004 *************** *** 0 **** --- 1,4 ---- + make -f makefile.std + sh png2pnm.sh + sh pnm2png.sh + Index: llvm/runtime/libpng/contrib/pngminus/pnm2png.bat diff -c /dev/null llvm/runtime/libpng/contrib/pngminus/pnm2png.bat:1.1.2.1 *** /dev/null Mon Mar 1 17:58:56 2004 --- llvm/runtime/libpng/contrib/pngminus/pnm2png.bat Mon Mar 1 17:58:45 2004 *************** *** 0 **** --- 1,41 ---- + REM -- grayscale + pnm2png.exe basn0g01.pgm basn0g01.png + pnm2png.exe basn0g02.pgm basn0g02.png + pnm2png.exe basn0g04.pgm basn0g04.png + pnm2png.exe basn0g08.pgm basn0g08.png + pnm2png.exe basn0g16.pgm basn0g16.png + REM -- full-color + pnm2png.exe basn2c08.ppm basn2c08.png + pnm2png.exe basn2c16.ppm basn2c16.png + REM -- palletted + pnm2png.exe basn3p01.ppm basn3p01.png + pnm2png.exe basn3p02.ppm basn3p02.png + pnm2png.exe basn3p04.ppm basn3p04.png + pnm2png.exe basn3p08.ppm basn3p08.png + REM -- gray with alpha-channel + pnm2png.exe -alpha basn6a08.pgm basn4a08.pgm basn4a08.png + pnm2png.exe -alpha basn6a16.pgm basn4a16.pgm basn4a16.png + REM -- color with alpha-channel + pnm2png.exe -alpha basn6a08.pgm basn6a08.ppm basn6a08.png + pnm2png.exe -alpha basn6a16.pgm basn6a16.ppm basn6a16.png + REM -- grayscale + pnm2png.exe rawn0g01.pgm rawn0g01.png + pnm2png.exe rawn0g02.pgm rawn0g02.png + pnm2png.exe rawn0g04.pgm rawn0g04.png + pnm2png.exe rawn0g08.pgm rawn0g08.png + pnm2png.exe rawn0g16.pgm rawn0g16.png + REM -- full-color + pnm2png.exe rawn2c08.ppm rawn2c08.png + pnm2png.exe rawn2c16.ppm rawn2c16.png + REM -- palletted + pnm2png.exe rawn3p01.ppm rawn3p01.png + pnm2png.exe rawn3p02.ppm rawn3p02.png + pnm2png.exe rawn3p04.ppm rawn3p04.png + pnm2png.exe rawn3p08.ppm rawn3p08.png + REM -- gray with alpha-channel + pnm2png.exe -alpha rawn6a08.pgm rawn4a08.pgm rawn4a08.png + pnm2png.exe -alpha rawn6a16.pgm rawn4a16.pgm rawn4a16.png + REM -- color with alpha-channel + pnm2png.exe -alpha rawn6a08.pgm rawn6a08.ppm rawn6a08.png + pnm2png.exe -alpha rawn6a16.pgm rawn6a16.ppm rawn6a16.png + Index: llvm/runtime/libpng/contrib/pngminus/pnm2png.c diff -c /dev/null llvm/runtime/libpng/contrib/pngminus/pnm2png.c:1.1.2.1 *** /dev/null Mon Mar 1 17:58:56 2004 --- llvm/runtime/libpng/contrib/pngminus/pnm2png.c Mon Mar 1 17:58:45 2004 *************** *** 0 **** --- 1,533 ---- + /* + * pnm2png.c --- conversion from PBM/PGM/PPM-file to PNG-file + * copyright (C) 1999 by Willem van Schaik + * + * version 1.0 - 1999.10.15 - First version. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear in + * supporting documentation. This software is provided "as is" without + * express or implied warranty. + */ + + #include + #include + #ifdef __TURBOC__ + #include + #include + #endif + + #ifndef BOOL + #define BOOL unsigned char + #endif + #ifndef TRUE + #define TRUE (BOOL) 1 + #endif + #ifndef FALSE + #define FALSE (BOOL) 0 + #endif + + #define STDIN 0 + #define STDOUT 1 + #define STDERR 2 + + /* to make pnm2png verbose so we can find problems (needs to be before png.h) */ + #ifndef PNG_DEBUG + #define PNG_DEBUG 0 + #endif + + #include "png.h" + + /* Define png_jmpbuf() in case we are using a pre-1.0.6 version of libpng */ + #ifndef png_jmpbuf + # define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf) + #endif + + /* function prototypes */ + + int main (int argc, char *argv[]); + void usage (); + BOOL pnm2png (FILE *pnm_file, FILE *png_file, FILE *alpha_file, BOOL interlace, BOOL alpha); + void get_token(FILE *pnm_file, char *token); + png_uint_32 get_data (FILE *pnm_file, int depth); + png_uint_32 get_value (FILE *pnm_file, int depth); + + /* + * main + */ + + int main(int argc, char *argv[]) + { + FILE *fp_rd = stdin; + FILE *fp_al = NULL; + FILE *fp_wr = stdout; + BOOL interlace = FALSE; + BOOL alpha = FALSE; + int argi; + + for (argi = 1; argi < argc; argi++) + { + if (argv[argi][0] == '-') + { + switch (argv[argi][1]) + { + case 'i': + interlace = TRUE; + break; + case 'a': + alpha = TRUE; + argi++; + if ((fp_al = fopen (argv[argi], "rb")) == NULL) + { + fprintf (stderr, "PNM2PNG\n"); + fprintf (stderr, "Error: alpha-channel file %s does not exist\n", + argv[argi]); + exit (1); + } + break; + case 'h': + case '?': + usage(); + exit(0); + break; + default: + fprintf (stderr, "PNM2PNG\n"); + fprintf (stderr, "Error: unknown option %s\n", argv[argi]); + usage(); + exit(1); + break; + } /* end switch */ + } + else if (fp_rd == stdin) + { + if ((fp_rd = fopen (argv[argi], "rb")) == NULL) + { + fprintf (stderr, "PNM2PNG\n"); + fprintf (stderr, "Error: file %s does not exist\n", argv[argi]); + exit (1); + } + } + else if (fp_wr == stdout) + { + if ((fp_wr = fopen (argv[argi], "wb")) == NULL) + { + fprintf (stderr, "PNM2PNG\n"); + fprintf (stderr, "Error: can not create PNG-file %s\n", argv[argi]); + exit (1); + } + } + else + { + fprintf (stderr, "PNM2PNG\n"); + fprintf (stderr, "Error: too many parameters\n"); + usage(); + exit (1); + } + } /* end for */ + + #ifdef __TURBOC__ + /* set stdin/stdout to binary, we're reading the PNM always! in binary format */ + if (fp_rd == stdin) + { + setmode (STDIN, O_BINARY); + } + if (fp_wr == stdout) + { + setmode (STDOUT, O_BINARY); + } + #endif + + /* call the conversion program itself */ + if (pnm2png (fp_rd, fp_wr, fp_al, interlace, alpha) == FALSE) + { + fprintf (stderr, "PNM2PNG\n"); + fprintf (stderr, "Error: unsuccessful converting to PNG-image\n"); + exit (1); + } + + /* close input file */ + fclose (fp_rd); + /* close output file */ + fclose (fp_wr); + /* close alpha file */ + if (alpha) + fclose (fp_al); + + return 0; + } + + /* + * usage + */ + + void usage() + { + fprintf (stderr, "PNM2PNG\n"); + fprintf (stderr, " by Willem van Schaik, 1999\n"); + #ifdef __TURBOC__ + fprintf (stderr, " for Turbo-C and Borland-C compilers\n"); + #else + fprintf (stderr, " for Linux (and Unix) compilers\n"); + #endif + fprintf (stderr, "Usage: pnm2png [options] . [.png]\n"); + fprintf (stderr, " or: ... | pnm2png [options]\n"); + fprintf (stderr, "Options:\n"); + fprintf (stderr, " -i[nterlace] write png-file with interlacing on\n"); + fprintf (stderr, " -a[lpha] .pgm read PNG alpha channel as pgm-file\n"); + fprintf (stderr, " -h | -? print this help-information\n"); + } + + /* + * pnm2png + */ + + BOOL pnm2png (FILE *pnm_file, FILE *png_file, FILE *alpha_file, BOOL interlace, BOOL alpha) + { + png_struct *png_ptr = NULL; + png_info *info_ptr = NULL; + png_byte *png_pixels = NULL; + png_byte **row_pointers = NULL; + png_byte *pix_ptr = NULL; + png_uint_32 row_bytes; + + char type_token[16]; + char width_token[16]; + char height_token[16]; + char maxval_token[16]; + int color_type; + png_uint_32 width, alpha_width; + png_uint_32 height, alpha_height; + png_uint_32 maxval; + int bit_depth = 0; + int channels; + int alpha_depth = 0; + int alpha_present; + int row, col; + BOOL raw, alpha_raw = FALSE; + png_uint_32 tmp16; + int i; + + /* read header of PNM file */ + + get_token(pnm_file, type_token); + if (type_token[0] != 'P') + { + return FALSE; + } + else if ((type_token[1] == '1') || (type_token[1] == '4')) + { + raw = (type_token[1] == '4'); + color_type = PNG_COLOR_TYPE_GRAY; + bit_depth = 1; + } + else if ((type_token[1] == '2') || (type_token[1] == '5')) + { + raw = (type_token[1] == '5'); + color_type = PNG_COLOR_TYPE_GRAY; + get_token(pnm_file, width_token); + sscanf (width_token, "%lu", &width); + get_token(pnm_file, height_token); + sscanf (height_token, "%lu", &height); + get_token(pnm_file, maxval_token); + sscanf (maxval_token, "%lu", &maxval); + if (maxval <= 1) + bit_depth = 1; + else if (maxval <= 3) + bit_depth = 2; + else if (maxval <= 15) + bit_depth = 4; + else if (maxval <= 255) + bit_depth = 8; + else /* if (maxval <= 65535) */ + bit_depth = 16; + } + else if ((type_token[1] == '3') || (type_token[1] == '6')) + { + raw = (type_token[1] == '6'); + color_type = PNG_COLOR_TYPE_RGB; + get_token(pnm_file, width_token); + sscanf (width_token, "%lu", &width); + get_token(pnm_file, height_token); + sscanf (height_token, "%lu", &height); + get_token(pnm_file, maxval_token); + sscanf (maxval_token, "%lu", &maxval); + if (maxval <= 1) + bit_depth = 1; + else if (maxval <= 3) + bit_depth = 2; + else if (maxval <= 15) + bit_depth = 4; + else if (maxval <= 255) + bit_depth = 8; + else /* if (maxval <= 65535) */ + bit_depth = 16; + } + else + { + return FALSE; + } + + /* read header of PGM file with alpha channel */ + + if (alpha) + { + if (color_type == PNG_COLOR_TYPE_GRAY) + color_type = PNG_COLOR_TYPE_GRAY_ALPHA; + if (color_type == PNG_COLOR_TYPE_RGB) + color_type = PNG_COLOR_TYPE_RGB_ALPHA; + + get_token(alpha_file, type_token); + if (type_token[0] != 'P') + { + return FALSE; + } + else if ((type_token[1] == '2') || (type_token[1] == '5')) + { + alpha_raw = (type_token[1] == '5'); + get_token(alpha_file, width_token); + sscanf (width_token, "%lu", &alpha_width); + if (alpha_width != width) + return FALSE; + get_token(alpha_file, height_token); + sscanf (height_token, "%lu", &alpha_height); + if (alpha_height != height) + return FALSE; + get_token(alpha_file, maxval_token); + sscanf (maxval_token, "%lu", &maxval); + if (maxval <= 1) + alpha_depth = 1; + else if (maxval <= 3) + alpha_depth = 2; + else if (maxval <= 15) + alpha_depth = 4; + else if (maxval <= 255) + alpha_depth = 8; + else /* if (maxval <= 65535) */ + alpha_depth = 16; + if (alpha_depth != bit_depth) + return FALSE; + } + else + { + return FALSE; + } + } /* end if alpha */ + + /* calculate the number of channels and store alpha-presence */ + if (color_type == PNG_COLOR_TYPE_GRAY) + channels = 1; + else if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + channels = 2; + else if (color_type == PNG_COLOR_TYPE_RGB) + channels = 3; + else if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) + channels = 4; + else + channels = 0; /* should not happen */ + + alpha_present = (channels - 1) % 2; + + /* row_bytes is the width x number of channels x (bit-depth / 8) */ + row_bytes = width * channels * ((bit_depth <= 8) ? 1 : 2); + + if ((png_pixels = (png_byte *) malloc (row_bytes * height * sizeof (png_byte))) == NULL) + return FALSE; + + /* read data from PNM file */ + pix_ptr = png_pixels; + + for (row = 0; row < height; row++) + { + for (col = 0; col < width; col++) + { + for (i = 0; i < (channels - alpha_present); i++) + { + if (raw) + *pix_ptr++ = get_data (pnm_file, bit_depth); + else + if (bit_depth <= 8) + *pix_ptr++ = get_value (pnm_file, bit_depth); + else + { + tmp16 = get_value (pnm_file, bit_depth); + *pix_ptr = (png_byte) ((tmp16 >> 8) & 0xFF); + pix_ptr++; + *pix_ptr = (png_byte) (tmp16 & 0xFF); + pix_ptr++; + } + } + + if (alpha) /* read alpha-channel from pgm file */ + { + if (alpha_raw) + *pix_ptr++ = get_data (alpha_file, alpha_depth); + else + if (alpha_depth <= 8) + *pix_ptr++ = get_value (alpha_file, bit_depth); + else + { + tmp16 = get_value (alpha_file, bit_depth); + *pix_ptr++ = (png_byte) ((tmp16 >> 8) & 0xFF); + *pix_ptr++ = (png_byte) (tmp16 & 0xFF); + } + } /* if alpha */ + + } /* end for col */ + } /* end for row */ + + /* prepare the standard PNG structures */ + png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (!png_ptr) + { + return FALSE; + } + info_ptr = png_create_info_struct (png_ptr); + if (!info_ptr) + { + png_destroy_write_struct (&png_ptr, (png_infopp) NULL); + return FALSE; + } + + /* setjmp() must be called in every function that calls a PNG-reading libpng function */ + if (setjmp (png_jmpbuf(png_ptr))) + { + png_destroy_write_struct (&png_ptr, (png_infopp) NULL); + return FALSE; + } + + /* initialize the png structure */ + png_init_io (png_ptr, png_file); + + /* we're going to write more or less the same PNG as the input file */ + png_set_IHDR (png_ptr, info_ptr, width, height, bit_depth, color_type, + (!interlace) ? PNG_INTERLACE_NONE : PNG_INTERLACE_ADAM7, + PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + + /* write the file header information */ + png_write_info (png_ptr, info_ptr); + + /* if needed we will allocate memory for an new array of row-pointers */ + if (row_pointers == (unsigned char**) NULL) + { + if ((row_pointers = (png_byte **) malloc (height * sizeof (png_bytep))) == NULL) + { + png_destroy_write_struct (&png_ptr, (png_infopp) NULL); + return FALSE; + } + } + + /* set the individual row_pointers to point at the correct offsets */ + for (i = 0; i < (height); i++) + row_pointers[i] = png_pixels + i * row_bytes; + + /* write out the entire image data in one call */ + png_write_image (png_ptr, row_pointers); + + /* write the additional chuncks to the PNG file (not really needed) */ + png_write_end (png_ptr, info_ptr); + + /* clean up after the write, and free any memory allocated */ + png_destroy_write_struct (&png_ptr, (png_infopp) NULL); + + if (row_pointers != (unsigned char**) NULL) + free (row_pointers); + if (png_pixels != (unsigned char*) NULL) + free (png_pixels); + + return TRUE; + } /* end of pnm2png */ + + /* + * get_token() - gets the first string after whitespace + */ + + void get_token(FILE *pnm_file, char *token) + { + int i = 0; + + /* remove white-space */ + do + { + token[i] = (unsigned char) fgetc (pnm_file); + } + while ((token[i] == '\n') || (token[i] == '\r') || (token[i] == ' ')); + + /* read string */ + do + { + i++; + token[i] = (unsigned char) fgetc (pnm_file); + } + while ((token[i] != '\n') && (token[i] != '\r') && (token[i] != ' ')); + + token[i] = '\0'; + + return; + } + + /* + * get_data() - takes first byte and converts into next pixel value, + * taking as much bits as defined by bit-depth and + * using the bit-depth to fill up a byte (0Ah -> AAh) + */ + + png_uint_32 get_data (FILE *pnm_file, int depth) + { + static int bits_left = 0; + static int old_value = 0; + static int mask = 0; + int i; + png_uint_32 ret_value; + + if (mask == 0) + for (i = 0; i < depth; i++) + mask = (mask >> 1) | 0x80; + + if (bits_left <= 0) + { + old_value = fgetc (pnm_file); + bits_left = 8; + } + + ret_value = old_value & mask; + for (i = 1; i < (8 / depth); i++) + ret_value = ret_value || (ret_value >> depth); + + old_value = (old_value << depth) & 0xFF; + bits_left -= depth; + + return ret_value; + } + + /* + * get_value() - takes first (numeric) string and converts into number, + * using the bit-depth to fill up a byte (0Ah -> AAh) + */ + + png_uint_32 get_value (FILE *pnm_file, int depth) + { + static png_uint_32 mask = 0; + png_byte token[16]; + png_uint_32 ret_value; + int i = 0; + + if (mask == 0) + for (i = 0; i < depth; i++) + mask = (mask << 1) | 0x01; + + get_token (pnm_file, (char *) token); + sscanf ((const char *) token, "%lu", &ret_value); + + ret_value &= mask; + + if (depth < 8) + for (i = 0; i < (8 / depth); i++) + ret_value = (ret_value << depth) || ret_value; + + return ret_value; + } + + /* end of source */ + Index: llvm/runtime/libpng/contrib/pngminus/pnm2png.sh diff -c /dev/null llvm/runtime/libpng/contrib/pngminus/pnm2png.sh:1.1.2.1 *** /dev/null Mon Mar 1 17:58:56 2004 --- llvm/runtime/libpng/contrib/pngminus/pnm2png.sh Mon Mar 1 17:58:45 2004 *************** *** 0 **** --- 1,41 ---- + # -- grayscale + ./pnm2png basn0g01.pgm basn0g01.png + ./pnm2png basn0g02.pgm basn0g02.png + ./pnm2png basn0g04.pgm basn0g04.png + ./pnm2png basn0g08.pgm basn0g08.png + ./pnm2png basn0g16.pgm basn0g16.png + # -- full-color + ./pnm2png basn2c08.ppm basn2c08.png + ./pnm2png basn2c16.ppm basn2c16.png + # -- palletted + ./pnm2png basn3p01.ppm basn3p01.png + ./pnm2png basn3p02.ppm basn3p02.png + ./pnm2png basn3p04.ppm basn3p04.png + ./pnm2png basn3p08.ppm basn3p08.png + # -- gray with alpha-channel + ./pnm2png -alpha basn6a08.pgm basn4a08.pgm basn4a08.png + ./pnm2png -alpha basn6a16.pgm basn4a16.pgm basn4a16.png + # -- color with alpha-channel + ./pnm2png -alpha basn6a08.pgm basn6a08.ppm basn6a08.png + ./pnm2png -alpha basn6a16.pgm basn6a16.ppm basn6a16.png + # -- grayscale + ./pnm2png rawn0g01.pgm rawn0g01.png + ./pnm2png rawn0g02.pgm rawn0g02.png + ./pnm2png rawn0g04.pgm rawn0g04.png + ./pnm2png rawn0g08.pgm rawn0g08.png + ./pnm2png rawn0g16.pgm rawn0g16.png + # -- full-color + ./pnm2png rawn2c08.ppm rawn2c08.png + ./pnm2png rawn2c16.ppm rawn2c16.png + # -- palletted + ./pnm2png rawn3p01.ppm rawn3p01.png + ./pnm2png rawn3p02.ppm rawn3p02.png + ./pnm2png rawn3p04.ppm rawn3p04.png + ./pnm2png rawn3p08.ppm rawn3p08.png + # -- gray with alpha-channel + ./pnm2png -alpha rawn6a08.pgm rawn4a08.pgm rawn4a08.png + ./pnm2png -alpha rawn6a16.pgm rawn4a16.pgm rawn4a16.png + # -- color with alpha-channel + ./pnm2png -alpha rawn6a08.pgm rawn6a08.ppm rawn6a08.png + ./pnm2png -alpha rawn6a16.pgm rawn6a16.ppm rawn6a16.png + From brukman at cs.uiuc.edu Mon Mar 1 18:07:48 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Mar 1 18:07:48 2004 Subject: [llvm-commits] [parallel] CVS: llvm/runtime/libpng/projects/netware.txt wince.txt Message-ID: <200403012358.RAA04423@zion.cs.uiuc.edu> Changes in directory llvm/runtime/libpng/projects: netware.txt added (r1.1.2.1) wince.txt added (r1.1.2.1) --- Log message: Merge from trunk --- Diffs of the changes: (+12 -0) Index: llvm/runtime/libpng/projects/netware.txt diff -c /dev/null llvm/runtime/libpng/projects/netware.txt:1.1.2.1 *** /dev/null Mon Mar 1 17:58:56 2004 --- llvm/runtime/libpng/projects/netware.txt Mon Mar 1 17:58:45 2004 *************** *** 0 **** --- 1,6 ---- + A set of project files is available for Netware. Get + libpng-1.2.5-project-netware.zip from a libpng distribution + site such as http://libpng.sourceforge.net + + Put the zip file in this directory (projects) and then run + "unzip -a libpng-1.2.5-project-netware.zip" Index: llvm/runtime/libpng/projects/wince.txt diff -c /dev/null llvm/runtime/libpng/projects/wince.txt:1.1.2.1 *** /dev/null Mon Mar 1 17:58:56 2004 --- llvm/runtime/libpng/projects/wince.txt Mon Mar 1 17:58:45 2004 *************** *** 0 **** --- 1,6 ---- + A set of project files is available for WinCE. Get + libpng-1.2.5-project-wince.zip from a libpng distribution + site such as http://libpng.sourceforge.net + + Put the zip file in this directory (projects) and then run + "unzip -a libpng-1.2.5-project-wince.zip" From brukman at cs.uiuc.edu Mon Mar 1 18:08:05 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Mar 1 18:08:05 2004 Subject: [llvm-commits] [parallel] CVS: llvm/runtime/libpng/contrib/pngsuite/README basn0g01.png basn0g02.png basn0g04.png basn0g08.png basn0g16.png basn2c08.png basn2c16.png basn3p01.png basn3p02.png basn3p04.png basn3p08.png basn4a08.png basn4a16.png basn6a08.png basn6a16.png Message-ID: <200403012358.RAA04492@zion.cs.uiuc.edu> Changes in directory llvm/runtime/libpng/contrib/pngsuite: README added (r1.1.2.1) basn0g01.png added (r1.1.2.1) basn0g02.png added (r1.1.2.1) basn0g04.png added (r1.1.2.1) basn0g08.png added (r1.1.2.1) basn0g16.png added (r1.1.2.1) basn2c08.png added (r1.1.2.1) basn2c16.png added (r1.1.2.1) basn3p01.png added (r1.1.2.1) basn3p02.png added (r1.1.2.1) basn3p04.png added (r1.1.2.1) basn3p08.png added (r1.1.2.1) basn4a08.png added (r1.1.2.1) basn4a16.png added (r1.1.2.1) basn6a08.png added (r1.1.2.1) basn6a16.png added (r1.1.2.1) --- Log message: Merge from trunk --- Diffs of the changes: (+85 -0) Index: llvm/runtime/libpng/contrib/pngsuite/README diff -c /dev/null llvm/runtime/libpng/contrib/pngsuite/README:1.1.2.1 *** /dev/null Mon Mar 1 17:58:55 2004 --- llvm/runtime/libpng/contrib/pngsuite/README Mon Mar 1 17:58:45 2004 *************** *** 0 **** --- 1,85 ---- + + pngsuite + -------- + (c) Willem van Schaik, 1999 + + Permission to use, copy, and distribute these images for any purpose and + without fee is hereby granted. + + These 15 images are part of the much larger PngSuite test-set of + images, available for developers of PNG supporting software. The + complete set, available at http:/www.schaik.com/pngsuite/, contains + a variety of images to test interlacing, gamma settings, ancillary + chunks, etc. + + The images in this directory represent the basic PNG color-types: + grayscale (1-16 bit deep), full color (8 or 16 bit), paletted + (1-8 bit) and grayscale or color images with alpha channel. You + can use them to test the proper functioning of PNG software. + + filename depth type + ------------ ------ -------------- + basn0g01.png 1-bit grayscale + basn0g02.png 2-bit grayscale + basn0g04.png 4-bit grayscale + basn0g08.png 8-bit grayscale + basn0g16.png 16-bit grayscale + basn2c08.png 8-bit truecolor + basn2c16.png 16-bit truecolor + basn3p01.png 1-bit paletted + basn3p02.png 2-bit paletted + basn3p04.png 4-bit paletted + basn3p08.png 8-bit paletted + basn4a08.png 8-bit gray with alpha + basn4a16.png 16-bit gray with alpha + basn6a08.png 8-bit RGBA + basn6a16.png 16-bit RGBA + + Here is the correct result of typing "pngtest -m *.png" in + this directory: + + Testing basn0g01.png: PASS (524 zero samples) + Filter 0 was used 32 times + Testing basn0g02.png: PASS (448 zero samples) + Filter 0 was used 32 times + Testing basn0g04.png: PASS (520 zero samples) + Filter 0 was used 32 times + Testing basn0g08.png: PASS (3 zero samples) + Filter 1 was used 9 times + Filter 4 was used 23 times + Testing basn0g16.png: PASS (1 zero samples) + Filter 1 was used 1 times + Filter 2 was used 31 times + Testing basn2c08.png: PASS (6 zero samples) + Filter 1 was used 5 times + Filter 4 was used 27 times + Testing basn2c16.png: PASS (592 zero samples) + Filter 1 was used 1 times + Filter 4 was used 31 times + Testing basn3p01.png: PASS (512 zero samples) + Filter 0 was used 32 times + Testing basn3p02.png: PASS (448 zero samples) + Filter 0 was used 32 times + Testing basn3p04.png: PASS (544 zero samples) + Filter 0 was used 32 times + Testing basn3p08.png: PASS (4 zero samples) + Filter 0 was used 32 times + Testing basn4a08.png: PASS (32 zero samples) + Filter 1 was used 1 times + Filter 4 was used 31 times + Testing basn4a16.png: PASS (64 zero samples) + Filter 0 was used 1 times + Filter 1 was used 2 times + Filter 2 was used 1 times + Filter 4 was used 28 times + Testing basn6a08.png: PASS (160 zero samples) + Filter 1 was used 1 times + Filter 4 was used 31 times + Testing basn6a16.png: PASS (1072 zero samples) + Filter 1 was used 4 times + Filter 4 was used 28 times + libpng passes test + + Willem van Schaik + + October 1999 Index: llvm/runtime/libpng/contrib/pngsuite/basn0g01.png Index: llvm/runtime/libpng/contrib/pngsuite/basn0g02.png Index: llvm/runtime/libpng/contrib/pngsuite/basn0g04.png Index: llvm/runtime/libpng/contrib/pngsuite/basn0g08.png Index: llvm/runtime/libpng/contrib/pngsuite/basn0g16.png Index: llvm/runtime/libpng/contrib/pngsuite/basn2c08.png Index: llvm/runtime/libpng/contrib/pngsuite/basn2c16.png Index: llvm/runtime/libpng/contrib/pngsuite/basn3p01.png Index: llvm/runtime/libpng/contrib/pngsuite/basn3p02.png Index: llvm/runtime/libpng/contrib/pngsuite/basn3p04.png Index: llvm/runtime/libpng/contrib/pngsuite/basn3p08.png Index: llvm/runtime/libpng/contrib/pngsuite/basn4a08.png Index: llvm/runtime/libpng/contrib/pngsuite/basn4a16.png Index: llvm/runtime/libpng/contrib/pngsuite/basn6a08.png Index: llvm/runtime/libpng/contrib/pngsuite/basn6a16.png From brukman at cs.uiuc.edu Mon Mar 1 18:08:24 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Mar 1 18:08:24 2004 Subject: [llvm-commits] [parallel] CVS: llvm/runtime/libpng/contrib/visupng/PngFile.c PngFile.h README.txt VisualPng.c VisualPng.dsp VisualPng.dsw VisualPng.ico VisualPng.png VisualPng.rc cexcept.h resource.h Message-ID: <200403012358.RAA04506@zion.cs.uiuc.edu> Changes in directory llvm/runtime/libpng/contrib/visupng: PngFile.c added (r1.1.2.1) PngFile.h added (r1.1.2.1) README.txt added (r1.1.2.1) VisualPng.c added (r1.1.2.1) VisualPng.dsp added (r1.1.2.1) VisualPng.dsw added (r1.1.2.1) VisualPng.ico added (r1.1.2.1) VisualPng.png added (r1.1.2.1) VisualPng.rc added (r1.1.2.1) cexcept.h added (r1.1.2.1) resource.h added (r1.1.2.1) --- Log message: Merge from trunk --- Diffs of the changes: (+2156 -0) Index: llvm/runtime/libpng/contrib/visupng/PngFile.c diff -c /dev/null llvm/runtime/libpng/contrib/visupng/PngFile.c:1.1.2.1 *** /dev/null Mon Mar 1 17:58:56 2004 --- llvm/runtime/libpng/contrib/visupng/PngFile.c Mon Mar 1 17:58:45 2004 *************** *** 0 **** --- 1,439 ---- + //------------------------------------- + // PNGFILE.C -- Image File Functions + //------------------------------------- + + // Copyright 2000, Willem van Schaik. For conditions of distribution and + // use, see the copyright/license/disclaimer notice in png.h + + #include + #include + #include + #include + + #include "png.h" + #include "pngfile.h" + #include "cexcept.h" + + define_exception_type(const char *); + extern struct exception_context the_exception_context[1]; + struct exception_context the_exception_context[1]; + png_const_charp msg; + + static OPENFILENAME ofn; + + static png_structp png_ptr = NULL; + static png_infop info_ptr = NULL; + + + // cexcept interface + + static void + png_cexcept_error(png_structp png_ptr, png_const_charp msg) + { + if(png_ptr) + ; + #ifndef PNG_NO_CONSOLE_IO + fprintf(stderr, "libpng error: %s\n", msg); + #endif + { + Throw msg; + } + } + + // Windows open-file functions + + void PngFileInitialize (HWND hwnd) + { + static TCHAR szFilter[] = TEXT ("PNG Files (*.PNG)\0*.png\0") + TEXT ("All Files (*.*)\0*.*\0\0"); + + ofn.lStructSize = sizeof (OPENFILENAME); + ofn.hwndOwner = hwnd; + ofn.hInstance = NULL; + ofn.lpstrFilter = szFilter; + ofn.lpstrCustomFilter = NULL; + ofn.nMaxCustFilter = 0; + ofn.nFilterIndex = 0; + ofn.lpstrFile = NULL; // Set in Open and Close functions + ofn.nMaxFile = MAX_PATH; + ofn.lpstrFileTitle = NULL; // Set in Open and Close functions + ofn.nMaxFileTitle = MAX_PATH; + ofn.lpstrInitialDir = NULL; + ofn.lpstrTitle = NULL; + ofn.Flags = 0; // Set in Open and Close functions + ofn.nFileOffset = 0; + ofn.nFileExtension = 0; + ofn.lpstrDefExt = TEXT ("png"); + ofn.lCustData = 0; + ofn.lpfnHook = NULL; + ofn.lpTemplateName = NULL; + } + + BOOL PngFileOpenDlg (HWND hwnd, PTSTR pstrFileName, PTSTR pstrTitleName) + { + ofn.hwndOwner = hwnd; + ofn.lpstrFile = pstrFileName; + ofn.lpstrFileTitle = pstrTitleName; + ofn.Flags = OFN_HIDEREADONLY; + + return GetOpenFileName (&ofn); + } + + BOOL PngFileSaveDlg (HWND hwnd, PTSTR pstrFileName, PTSTR pstrTitleName) + { + ofn.hwndOwner = hwnd; + ofn.lpstrFile = pstrFileName; + ofn.lpstrFileTitle = pstrTitleName; + ofn.Flags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT; + + return GetSaveFileName (&ofn); + } + + // PNG image handler functions + + BOOL PngLoadImage (PTSTR pstrFileName, png_byte **ppbImageData, + int *piWidth, int *piHeight, int *piChannels, png_color *pBkgColor) + { + static FILE *pfFile; + png_byte pbSig[8]; + int iBitDepth; + int iColorType; + double dGamma; + png_color_16 *pBackground; + png_uint_32 ulChannels; + png_uint_32 ulRowBytes; + png_byte *pbImageData = *ppbImageData; + static png_byte **ppbRowPointers = NULL; + int i; + + // open the PNG input file + + if (!pstrFileName) + { + *ppbImageData = pbImageData = NULL; + return FALSE; + } + + if (!(pfFile = fopen(pstrFileName, "rb"))) + { + *ppbImageData = pbImageData = NULL; + return FALSE; + } + + // first check the eight byte PNG signature + + fread(pbSig, 1, 8, pfFile); + if (!png_check_sig(pbSig, 8)) + { + *ppbImageData = pbImageData = NULL; + return FALSE; + } + + // create the two png(-info) structures + + png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, + (png_error_ptr)png_cexcept_error, (png_error_ptr)NULL); + if (!png_ptr) + { + *ppbImageData = pbImageData = NULL; + return FALSE; + } + + info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) + { + png_destroy_read_struct(&png_ptr, NULL, NULL); + *ppbImageData = pbImageData = NULL; + return FALSE; + } + + Try + { + + // initialize the png structure + + #if !defined(PNG_NO_STDIO) + png_init_io(png_ptr, pfFile); + #else + png_set_read_fn(png_ptr, (png_voidp)pfFile, png_read_data); + #endif + + png_set_sig_bytes(png_ptr, 8); + + // read all PNG info up to image data + + png_read_info(png_ptr, info_ptr); + + // get width, height, bit-depth and color-type + + png_get_IHDR(png_ptr, info_ptr, piWidth, piHeight, &iBitDepth, + &iColorType, NULL, NULL, NULL); + + // expand images of all color-type and bit-depth to 3x8 bit RGB images + // let the library process things like alpha, transparency, background + + if (iBitDepth == 16) + png_set_strip_16(png_ptr); + if (iColorType == PNG_COLOR_TYPE_PALETTE) + png_set_expand(png_ptr); + if (iBitDepth < 8) + png_set_expand(png_ptr); + if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) + png_set_expand(png_ptr); + if (iColorType == PNG_COLOR_TYPE_GRAY || + iColorType == PNG_COLOR_TYPE_GRAY_ALPHA) + png_set_gray_to_rgb(png_ptr); + + // set the background color to draw transparent and alpha images over. + if (png_get_bKGD(png_ptr, info_ptr, &pBackground)) + { + png_set_background(png_ptr, pBackground, PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); + pBkgColor->red = (byte) pBackground->red; + pBkgColor->green = (byte) pBackground->green; + pBkgColor->blue = (byte) pBackground->blue; + } + else + { + pBkgColor = NULL; + } + + // if required set gamma conversion + if (png_get_gAMA(png_ptr, info_ptr, &dGamma)) + png_set_gamma(png_ptr, (double) 2.2, dGamma); + + // after the transformations have been registered update info_ptr data + + png_read_update_info(png_ptr, info_ptr); + + // get again width, height and the new bit-depth and color-type + + png_get_IHDR(png_ptr, info_ptr, piWidth, piHeight, &iBitDepth, + &iColorType, NULL, NULL, NULL); + + + // row_bytes is the width x number of channels + + ulRowBytes = png_get_rowbytes(png_ptr, info_ptr); + ulChannels = png_get_channels(png_ptr, info_ptr); + + *piChannels = ulChannels; + + // now we can allocate memory to store the image + + if (pbImageData) + { + free (pbImageData); + pbImageData = NULL; + } + if ((pbImageData = (png_byte *) malloc(ulRowBytes * (*piHeight) + * sizeof(png_byte))) == NULL) + { + png_error(png_ptr, "Visual PNG: out of memory"); + } + *ppbImageData = pbImageData; + + // and allocate memory for an array of row-pointers + + if ((ppbRowPointers = (png_bytepp) malloc((*piHeight) + * sizeof(png_bytep))) == NULL) + { + png_error(png_ptr, "Visual PNG: out of memory"); + } + + // set the individual row-pointers to point at the correct offsets + + for (i = 0; i < (*piHeight); i++) + ppbRowPointers[i] = pbImageData + i * ulRowBytes; + + // now we can go ahead and just read the whole image + + png_read_image(png_ptr, ppbRowPointers); + + // read the additional chunks in the PNG file (not really needed) + + png_read_end(png_ptr, NULL); + + // and we're done + + free (ppbRowPointers); + ppbRowPointers = NULL; + + // yepp, done + } + + Catch (msg) + { + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + + *ppbImageData = pbImageData = NULL; + + if(ppbRowPointers) + free (ppbRowPointers); + + fclose(pfFile); + + return FALSE; + } + + fclose (pfFile); + + return TRUE; + } + + + BOOL PngSaveImage (PTSTR pstrFileName, png_byte *pDiData, + int iWidth, int iHeight, png_color bkgColor) + { + const int ciBitDepth = 8; + const int ciChannels = 3; + + static FILE *pfFile; + png_uint_32 ulRowBytes; + static png_byte **ppbRowPointers = NULL; + int i; + + // open the PNG output file + + if (!pstrFileName) + return FALSE; + + if (!(pfFile = fopen(pstrFileName, "wb"))) + return FALSE; + + // prepare the standard PNG structures + + png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, + (png_error_ptr)png_cexcept_error, (png_error_ptr)NULL); + if (!png_ptr) + { + fclose(pfFile); + return FALSE; + } + + info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) { + fclose(pfFile); + png_destroy_write_struct(&png_ptr, (png_infopp) NULL); + return FALSE; + } + + Try + { + // initialize the png structure + + #if !defined(PNG_NO_STDIO) + png_init_io(png_ptr, pfFile); + #else + png_set_write_fn(png_ptr, (png_voidp)pfFile, png_write_data, png_flush); + #endif + + // we're going to write a very simple 3x8 bit RGB image + + png_set_IHDR(png_ptr, info_ptr, iWidth, iHeight, ciBitDepth, + PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, + PNG_FILTER_TYPE_BASE); + + // write the file header information + + png_write_info(png_ptr, info_ptr); + + // swap the BGR pixels in the DiData structure to RGB + + png_set_bgr(png_ptr); + + // row_bytes is the width x number of channels + + ulRowBytes = iWidth * ciChannels; + + // we can allocate memory for an array of row-pointers + + if ((ppbRowPointers = (png_bytepp) malloc(iHeight * sizeof(png_bytep))) == NULL) + Throw "Visualpng: Out of memory"; + + // set the individual row-pointers to point at the correct offsets + + for (i = 0; i < iHeight; i++) + ppbRowPointers[i] = pDiData + i * (((ulRowBytes + 3) >> 2) << 2); + + // write out the entire image data in one call + + png_write_image (png_ptr, ppbRowPointers); + + // write the additional chunks to the PNG file (not really needed) + + png_write_end(png_ptr, info_ptr); + + // and we're done + + free (ppbRowPointers); + ppbRowPointers = NULL; + + // clean up after the write, and free any memory allocated + + png_destroy_write_struct(&png_ptr, (png_infopp) NULL); + + // yepp, done + } + + Catch (msg) + { + png_destroy_write_struct(&png_ptr, (png_infopp) NULL); + + if(ppbRowPointers) + free (ppbRowPointers); + + fclose(pfFile); + + return FALSE; + } + + fclose (pfFile); + + return TRUE; + } + + #ifdef PNG_NO_STDIO + + static void + png_read_data(png_structp png_ptr, png_bytep data, png_size_t length) + { + png_size_t check; + + /* fread() returns 0 on error, so it is OK to store this in a png_size_t + * instead of an int, which is what fread() actually returns. + */ + check = (png_size_t)fread(data, (png_size_t)1, length, + (FILE *)png_ptr->io_ptr); + + if (check != length) + { + png_error(png_ptr, "Read Error"); + } + } + + static void + png_write_data(png_structp png_ptr, png_bytep data, png_size_t length) + { + png_uint_32 check; + + check = fwrite(data, 1, length, (FILE *)(png_ptr->io_ptr)); + if (check != length) + { + png_error(png_ptr, "Write Error"); + } + } + + static void + png_flush(png_structp png_ptr) + { + FILE *io_ptr; + io_ptr = (FILE *)CVT_PTR((png_ptr->io_ptr)); + if (io_ptr != NULL) + fflush(io_ptr); + } + + #endif + + //----------------- + // end of source + //----------------- Index: llvm/runtime/libpng/contrib/visupng/PngFile.h diff -c /dev/null llvm/runtime/libpng/contrib/visupng/PngFile.h:1.1.2.1 *** /dev/null Mon Mar 1 17:58:56 2004 --- llvm/runtime/libpng/contrib/visupng/PngFile.h Mon Mar 1 17:58:45 2004 *************** *** 0 **** --- 1,27 ---- + //------------------------------------------ + // PNGFILE.H -- Header File for pngfile.c + //------------------------------------------ + + // Copyright 2000, Willem van Schaik. For conditions of distribution and + // use, see the copyright/license/disclaimer notice in png.h + + #include + #include + #include + #include + + void PngFileInitialize (HWND hwnd) ; + BOOL PngFileOpenDlg (HWND hwnd, PTSTR pstrFileName, PTSTR pstrTitleName) ; + BOOL PngFileSaveDlg (HWND hwnd, PTSTR pstrFileName, PTSTR pstrTitleName) ; + + BOOL PngLoadImage (PTSTR pstrFileName, png_byte **ppbImageData, + int *piWidth, int *piHeight, int *piChannels, png_color *pBkgColor); + BOOL PngSaveImage (PTSTR pstrFileName, png_byte *pDiData, + int iWidth, int iHeight, png_color BkgColor); + + #if defined(PNG_NO_STDIO) + static void png_read_data(png_structp png_ptr, png_bytep data, png_size_t length); + static void png_write_data(png_structp png_ptr, png_bytep data, png_size_t length); + static void png_flush(png_structp png_ptr); + #endif + Index: llvm/runtime/libpng/contrib/visupng/README.txt diff -c /dev/null llvm/runtime/libpng/contrib/visupng/README.txt:1.1.2.1 *** /dev/null Mon Mar 1 17:58:56 2004 --- llvm/runtime/libpng/contrib/visupng/README.txt Mon Mar 1 17:58:45 2004 *************** *** 0 **** --- 1,58 ---- + Microsoft Developer Studio Build File, Format Version 6.00 for VisualPng + ------------------------------------------------------------------------ + + Copyright 2000, Willem van Schaik. For conditions of distribution and + use, see the copyright/license/disclaimer notice in png.h + + As a PNG .dll demo VisualPng is finished. More features would only hinder + the program's objective. However, further extensions (like support for other + graphics formats) are in development. To get these, or for pre-compiled + binaries, go to "http://www.schaik.com/png/visualpng.html". + + ------------------------------------------------------------------------ + + Assumes that + + libpng DLLs and LIBs are in ..\..\projects\msvc\win32\libpng + zlib DLLs and LIBs are in ..\..\projects\msvc\win32\zlib + libpng header files are in ..\..\..\libpng + zlib header files are in ..\..\..\zlib + the pngsuite images are in ..\pngsuite + + To build: + + 1) On the main menu Select "Build|Set Active configuration". + Choose the configuration that corresponds to the library you want to test. + This library must have been built using the libpng MS project located in + the "..\..\mscv" subdirectory. + + 2) Select "Build|Clean" + + 3) Select "Build|Rebuild All" + + 4) After compiling and linking VisualPng will be started to view an image + from the PngSuite directory. Press Ctrl-N (and Ctrl-V) for other images. + + + To install: + + When distributing VisualPng (or a further development) the following options + are available: + + 1) Build the program with the configuration "Win32 LIB" and you only need to + include the executable from the ./lib directory in your distribution. + + 2) Build the program with the configuration "Win32 DLL" and you need to put + in your distribution the executable from the ./dll directory and the dll's + libpng1.dll, zlib.dll and msvcrt.dll. These need to be in the user's PATH. + + + Willem van Schaik + Calgary, June 6th 2000 + + P.S. VisualPng was written based on preliminary work of: + + - Simon-Pierre Cadieux + - Glenn Randers-Pehrson + - Greg Roelofs + Index: llvm/runtime/libpng/contrib/visupng/VisualPng.c diff -c /dev/null llvm/runtime/libpng/contrib/visupng/VisualPng.c:1.1.2.1 *** /dev/null Mon Mar 1 17:58:56 2004 --- llvm/runtime/libpng/contrib/visupng/VisualPng.c Mon Mar 1 17:58:45 2004 *************** *** 0 **** --- 1,961 ---- + //------------------------------------ + // VisualPng.C -- Shows a PNG image + //------------------------------------ + + // Copyright 2000, Willem van Schaik. For conditions of distribution and + // use, see the copyright/license/disclaimer notice in png.h + + // switches + + // defines + + #define PROGNAME "VisualPng" + #define LONGNAME "Win32 Viewer for PNG-files" + #define VERSION "1.0 of 2000 June 07" + + // constants + + #define MARGIN 8 + + // standard includes + + #include + #include + #include + #include + + // application includes + + #include "png.h" + #include "pngfile.h" + #include "resource.h" + + // macros + + // function prototypes + + LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM); + BOOL CALLBACK AboutDlgProc (HWND, UINT, WPARAM, LPARAM) ; + + BOOL CenterAbout (HWND hwndChild, HWND hwndParent); + + BOOL BuildPngList (PTSTR pstrPathName, TCHAR **ppFileList, int *pFileCount, + int *pFileIndex); + + BOOL SearchPngList (TCHAR *pFileList, int FileCount, int *pFileIndex, + PTSTR pstrPrevName, PTSTR pstrNextName); + + BOOL LoadImageFile(HWND hwnd, PTSTR pstrPathName, + png_byte **ppbImage, int *pxImgSize, int *pyImgSize, int *piChannels, + png_color *pBkgColor); + + BOOL DisplayImage (HWND hwnd, BYTE **ppDib, + BYTE **ppDiData, int cxWinSize, int cyWinSize, + BYTE *pbImage, int cxImgSize, int cyImgSize, int cImgChannels, + BOOL bStretched); + + BOOL InitBitmap ( + BYTE *pDiData, int cxWinSize, int cyWinSize); + + BOOL FillBitmap ( + BYTE *pDiData, int cxWinSize, int cyWinSize, + BYTE *pbImage, int cxImgSize, int cyImgSize, int cImgChannels, + BOOL bStretched); + + // a few global variables + + static char *szProgName = PROGNAME; + static char *szAppName = LONGNAME; + static char *szIconName = PROGNAME; + static char szCmdFileName [MAX_PATH]; + + // MAIN routine + + int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, + PSTR szCmdLine, int iCmdShow) + { + HACCEL hAccel; + HWND hwnd; + MSG msg; + WNDCLASS wndclass; + int ixBorders, iyBorders; + + wndclass.style = CS_HREDRAW | CS_VREDRAW; + wndclass.lpfnWndProc = WndProc; + wndclass.cbClsExtra = 0; + wndclass.cbWndExtra = 0; + wndclass.hInstance = hInstance; + wndclass.hIcon = LoadIcon (hInstance, szIconName) ; + wndclass.hCursor = LoadCursor (NULL, IDC_ARROW); + wndclass.hbrBackground = NULL; // (HBRUSH) GetStockObject (GRAY_BRUSH); + wndclass.lpszMenuName = szProgName; + wndclass.lpszClassName = szProgName; + + if (!RegisterClass (&wndclass)) + { + MessageBox (NULL, TEXT ("Error: this program requires Windows NT!"), + szProgName, MB_ICONERROR); + return 0; + } + + // if filename given on commandline, store it + if ((szCmdLine != NULL) && (*szCmdLine != '\0')) + if (szCmdLine[0] == '"') + strncpy (szCmdFileName, szCmdLine + 1, strlen(szCmdLine) - 2); + else + strcpy (szCmdFileName, szCmdLine); + else + strcpy (szCmdFileName, ""); + + // calculate size of window-borders + ixBorders = 2 * (GetSystemMetrics (SM_CXBORDER) + + GetSystemMetrics (SM_CXDLGFRAME)); + iyBorders = 2 * (GetSystemMetrics (SM_CYBORDER) + + GetSystemMetrics (SM_CYDLGFRAME)) + + GetSystemMetrics (SM_CYCAPTION) + + GetSystemMetrics (SM_CYMENUSIZE) + + 1; /* WvS: don't ask me why? */ + + hwnd = CreateWindow (szProgName, szAppName, + WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, CW_USEDEFAULT, + 512 + 2 * MARGIN + ixBorders, 384 + 2 * MARGIN + iyBorders, + // CW_USEDEFAULT, CW_USEDEFAULT, + NULL, NULL, hInstance, NULL); + + ShowWindow (hwnd, iCmdShow); + UpdateWindow (hwnd); + + hAccel = LoadAccelerators (hInstance, szProgName); + + while (GetMessage (&msg, NULL, 0, 0)) + { + if (!TranslateAccelerator (hwnd, hAccel, &msg)) + { + TranslateMessage (&msg); + DispatchMessage (&msg); + } + } + return msg.wParam; + } + + LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, + LPARAM lParam) + { + static HINSTANCE hInstance ; + static HDC hdc; + static PAINTSTRUCT ps; + static HMENU hMenu; + + static BITMAPFILEHEADER *pbmfh; + static BITMAPINFOHEADER *pbmih; + static BYTE *pbImage; + static int cxWinSize, cyWinSize; + static int cxImgSize, cyImgSize; + static int cImgChannels; + static png_color bkgColor = {127, 127, 127}; + + static BOOL bStretched = TRUE; + + static BYTE *pDib = NULL; + static BYTE *pDiData = NULL; + + static TCHAR szImgPathName [MAX_PATH]; + static TCHAR szTitleName [MAX_PATH]; + + static TCHAR *pPngFileList = NULL; + static int iPngFileCount; + static int iPngFileIndex; + + BOOL bOk; + + switch (message) + { + case WM_CREATE: + hInstance = ((LPCREATESTRUCT) lParam)->hInstance ; + PngFileInitialize (hwnd); + + strcpy (szImgPathName, ""); + + // in case we process file given on command-line + + if (szCmdFileName[0] != '\0') + { + strcpy (szImgPathName, szCmdFileName); + + // read the other png-files in the directory for later + // next/previous commands + + BuildPngList (szImgPathName, &pPngFileList, &iPngFileCount, + &iPngFileIndex); + + // load the image from file + + if (!LoadImageFile (hwnd, szImgPathName, + &pbImage, &cxImgSize, &cyImgSize, &cImgChannels, &bkgColor)) + return 0; + + // invalidate the client area for later update + + InvalidateRect (hwnd, NULL, TRUE); + + // display the PNG into the DIBitmap + + DisplayImage (hwnd, &pDib, &pDiData, cxWinSize, cyWinSize, + pbImage, cxImgSize, cyImgSize, cImgChannels, bStretched); + } + + return 0; + + case WM_SIZE: + cxWinSize = LOWORD (lParam); + cyWinSize = HIWORD (lParam); + + // invalidate the client area for later update + + InvalidateRect (hwnd, NULL, TRUE); + + // display the PNG into the DIBitmap + + DisplayImage (hwnd, &pDib, &pDiData, cxWinSize, cyWinSize, + pbImage, cxImgSize, cyImgSize, cImgChannels, bStretched); + + return 0; + + case WM_INITMENUPOPUP: + hMenu = GetMenu (hwnd); + + if (pbImage) + EnableMenuItem (hMenu, IDM_FILE_SAVE, MF_ENABLED); + else + EnableMenuItem (hMenu, IDM_FILE_SAVE, MF_GRAYED); + + return 0; + + case WM_COMMAND: + hMenu = GetMenu (hwnd); + + switch (LOWORD (wParam)) + { + case IDM_FILE_OPEN: + + // show the File Open dialog box + + if (!PngFileOpenDlg (hwnd, szImgPathName, szTitleName)) + return 0; + + // read the other png-files in the directory for later + // next/previous commands + + BuildPngList (szImgPathName, &pPngFileList, &iPngFileCount, + &iPngFileIndex); + + // load the image from file + + if (!LoadImageFile (hwnd, szImgPathName, + &pbImage, &cxImgSize, &cyImgSize, &cImgChannels, &bkgColor)) + return 0; + + // invalidate the client area for later update + + InvalidateRect (hwnd, NULL, TRUE); + + // display the PNG into the DIBitmap + + DisplayImage (hwnd, &pDib, &pDiData, cxWinSize, cyWinSize, + pbImage, cxImgSize, cyImgSize, cImgChannels, bStretched); + + return 0; + + case IDM_FILE_SAVE: + + // show the File Save dialog box + + if (!PngFileSaveDlg (hwnd, szImgPathName, szTitleName)) + return 0; + + // save the PNG to a disk file + + SetCursor (LoadCursor (NULL, IDC_WAIT)); + ShowCursor (TRUE); + + bOk = PngSaveImage (szImgPathName, pDiData, cxWinSize, cyWinSize, + bkgColor); + + ShowCursor (FALSE); + SetCursor (LoadCursor (NULL, IDC_ARROW)); + + if (!bOk) + MessageBox (hwnd, TEXT ("Error in saving the PNG image"), + szProgName, MB_ICONEXCLAMATION | MB_OK); + return 0; + + case IDM_FILE_NEXT: + + // read next entry in the directory + + if (SearchPngList (pPngFileList, iPngFileCount, &iPngFileIndex, + NULL, szImgPathName)) + { + if (strcmp (szImgPathName, "") == 0) + return 0; + + // load the image from file + + if (!LoadImageFile (hwnd, szImgPathName, &pbImage, + &cxImgSize, &cyImgSize, &cImgChannels, &bkgColor)) + return 0; + + // invalidate the client area for later update + + InvalidateRect (hwnd, NULL, TRUE); + + // display the PNG into the DIBitmap + + DisplayImage (hwnd, &pDib, &pDiData, cxWinSize, cyWinSize, + pbImage, cxImgSize, cyImgSize, cImgChannels, bStretched); + } + + return 0; + + case IDM_FILE_PREVIOUS: + + // read previous entry in the directory + + if (SearchPngList (pPngFileList, iPngFileCount, &iPngFileIndex, + szImgPathName, NULL)) + { + + if (strcmp (szImgPathName, "") == 0) + return 0; + + // load the image from file + + if (!LoadImageFile (hwnd, szImgPathName, &pbImage, &cxImgSize, + &cyImgSize, &cImgChannels, &bkgColor)) + return 0; + + // invalidate the client area for later update + + InvalidateRect (hwnd, NULL, TRUE); + + // display the PNG into the DIBitmap + + DisplayImage (hwnd, &pDib, &pDiData, cxWinSize, cyWinSize, + pbImage, cxImgSize, cyImgSize, cImgChannels, bStretched); + } + + return 0; + + case IDM_FILE_EXIT: + + // more cleanup needed... + + // free image buffer + + if (pDib != NULL) + { + free (pDib); + pDib = NULL; + } + + // free file-list + + if (pPngFileList != NULL) + { + free (pPngFileList); + pPngFileList = NULL; + } + + // let's go ... + + exit (0); + + return 0; + + case IDM_OPTIONS_STRETCH: + bStretched = !bStretched; + if (bStretched) + CheckMenuItem (hMenu, IDM_OPTIONS_STRETCH, MF_CHECKED); + else + CheckMenuItem (hMenu, IDM_OPTIONS_STRETCH, MF_UNCHECKED); + + // invalidate the client area for later update + + InvalidateRect (hwnd, NULL, TRUE); + + // display the PNG into the DIBitmap + + DisplayImage (hwnd, &pDib, &pDiData, cxWinSize, cyWinSize, + pbImage, cxImgSize, cyImgSize, cImgChannels, bStretched); + + return 0; + + case IDM_HELP_ABOUT: + DialogBox (hInstance, TEXT ("AboutBox"), hwnd, AboutDlgProc) ; + return 0; + + } // end switch + + break; + + case WM_PAINT: + hdc = BeginPaint (hwnd, &ps); + + if (pDib) + SetDIBitsToDevice (hdc, 0, 0, cxWinSize, cyWinSize, 0, 0, + 0, cyWinSize, pDiData, (BITMAPINFO *) pDib, DIB_RGB_COLORS); + + EndPaint (hwnd, &ps); + return 0; + + case WM_DESTROY: + if (pbmfh) + { + free (pbmfh); + pbmfh = NULL; + } + + PostQuitMessage (0); + return 0; + } + + return DefWindowProc (hwnd, message, wParam, lParam); + } + + BOOL CALLBACK AboutDlgProc (HWND hDlg, UINT message, + WPARAM wParam, LPARAM lParam) + { + switch (message) + { + case WM_INITDIALOG : + ShowWindow (hDlg, SW_HIDE); + CenterAbout (hDlg, GetWindow (hDlg, GW_OWNER)); + ShowWindow (hDlg, SW_SHOW); + return TRUE ; + + case WM_COMMAND : + switch (LOWORD (wParam)) + { + case IDOK : + case IDCANCEL : + EndDialog (hDlg, 0) ; + return TRUE ; + } + break ; + } + return FALSE ; + } + + //--------------- + // CenterAbout + //--------------- + + BOOL CenterAbout (HWND hwndChild, HWND hwndParent) + { + RECT rChild, rParent, rWorkArea; + int wChild, hChild, wParent, hParent; + int xNew, yNew; + BOOL bResult; + + // Get the Height and Width of the child window + GetWindowRect (hwndChild, &rChild); + wChild = rChild.right - rChild.left; + hChild = rChild.bottom - rChild.top; + + // Get the Height and Width of the parent window + GetWindowRect (hwndParent, &rParent); + wParent = rParent.right - rParent.left; + hParent = rParent.bottom - rParent.top; + + // Get the limits of the 'workarea' + bResult = SystemParametersInfo( + SPI_GETWORKAREA, // system parameter to query or set + sizeof(RECT), + &rWorkArea, + 0); + if (!bResult) { + rWorkArea.left = rWorkArea.top = 0; + rWorkArea.right = GetSystemMetrics(SM_CXSCREEN); + rWorkArea.bottom = GetSystemMetrics(SM_CYSCREEN); + } + + // Calculate new X position, then adjust for workarea + xNew = rParent.left + ((wParent - wChild) /2); + if (xNew < rWorkArea.left) { + xNew = rWorkArea.left; + } else if ((xNew+wChild) > rWorkArea.right) { + xNew = rWorkArea.right - wChild; + } + + // Calculate new Y position, then adjust for workarea + yNew = rParent.top + ((hParent - hChild) /2); + if (yNew < rWorkArea.top) { + yNew = rWorkArea.top; + } else if ((yNew+hChild) > rWorkArea.bottom) { + yNew = rWorkArea.bottom - hChild; + } + + // Set it, and return + return SetWindowPos (hwndChild, NULL, xNew, yNew, 0, 0, SWP_NOSIZE | + SWP_NOZORDER); + } + + //---------------- + // BuildPngList + //---------------- + + BOOL BuildPngList (PTSTR pstrPathName, TCHAR **ppFileList, int *pFileCount, + int *pFileIndex) + { + static TCHAR szImgPathName [MAX_PATH]; + static TCHAR szImgFileName [MAX_PATH]; + static TCHAR szImgFindName [MAX_PATH]; + + WIN32_FIND_DATA finddata; + HANDLE hFind; + + static TCHAR szTmp [MAX_PATH]; + BOOL bOk; + int i, ii; + int j, jj; + + // free previous file-list + + if (*ppFileList != NULL) + { + free (*ppFileList); + *ppFileList = NULL; + } + + // extract foldername, filename and search-name + + strcpy (szImgPathName, pstrPathName); + strcpy (szImgFileName, strrchr (pstrPathName, '\\') + 1); + + strcpy (szImgFindName, szImgPathName); + *(strrchr (szImgFindName, '\\') + 1) = '\0'; + strcat (szImgFindName, "*.png"); + + // first cycle: count number of files in directory for memory allocation + + *pFileCount = 0; + + hFind = FindFirstFile(szImgFindName, &finddata); + bOk = (hFind != (HANDLE) -1); + + while (bOk) + { + *pFileCount += 1; + bOk = FindNextFile(hFind, &finddata); + } + FindClose(hFind); + + // allocation memory for file-list + + *ppFileList = (TCHAR *) malloc (*pFileCount * MAX_PATH); + + // second cycle: read directory and store filenames in file-list + + hFind = FindFirstFile(szImgFindName, &finddata); + bOk = (hFind != (HANDLE) -1); + + i = 0; + ii = 0; + while (bOk) + { + strcpy (*ppFileList + ii, szImgPathName); + strcpy (strrchr(*ppFileList + ii, '\\') + 1, finddata.cFileName); + + if (strcmp(pstrPathName, *ppFileList + ii) == 0) + *pFileIndex = i; + + ii += MAX_PATH; + i++; + + bOk = FindNextFile(hFind, &finddata); + } + FindClose(hFind); + + // finally we must sort the file-list + + for (i = 0; i < *pFileCount - 1; i++) + { + ii = i * MAX_PATH; + for (j = i+1; j < *pFileCount; j++) + { + jj = j * MAX_PATH; + if (strcmp (*ppFileList + ii, *ppFileList + jj) > 0) + { + strcpy (szTmp, *ppFileList + jj); + strcpy (*ppFileList + jj, *ppFileList + ii); + strcpy (*ppFileList + ii, szTmp); + + // check if this was the current image that we moved + + if (*pFileIndex == i) + *pFileIndex = j; + else + if (*pFileIndex == j) + *pFileIndex = i; + } + } + } + + return TRUE; + } + + //---------------- + // SearchPngList + //---------------- + + BOOL SearchPngList ( + TCHAR *pFileList, int FileCount, int *pFileIndex, + PTSTR pstrPrevName, PTSTR pstrNextName) + { + if (FileCount > 0) + { + // get previous entry + + if (pstrPrevName != NULL) + { + if (*pFileIndex > 0) + *pFileIndex -= 1; + else + *pFileIndex = FileCount - 1; + + strcpy (pstrPrevName, pFileList + (*pFileIndex * MAX_PATH)); + } + + // get next entry + + if (pstrNextName != NULL) + { + if (*pFileIndex < FileCount - 1) + *pFileIndex += 1; + else + *pFileIndex = 0; + + strcpy (pstrNextName, pFileList + (*pFileIndex * MAX_PATH)); + } + + return TRUE; + } + else + { + return FALSE; + } + } + + //----------------- + // LoadImageFile + //----------------- + + BOOL LoadImageFile (HWND hwnd, PTSTR pstrPathName, + png_byte **ppbImage, int *pxImgSize, int *pyImgSize, + int *piChannels, png_color *pBkgColor) + { + static TCHAR szTmp [MAX_PATH]; + + // if there's an existing PNG, free the memory + + if (*ppbImage) + { + free (*ppbImage); + *ppbImage = NULL; + } + + // Load the entire PNG into memory + + SetCursor (LoadCursor (NULL, IDC_WAIT)); + ShowCursor (TRUE); + + PngLoadImage (pstrPathName, ppbImage, pxImgSize, pyImgSize, piChannels, + pBkgColor); + + ShowCursor (FALSE); + SetCursor (LoadCursor (NULL, IDC_ARROW)); + + if (*ppbImage != NULL) + { + sprintf (szTmp, "VisualPng - %s", strrchr(pstrPathName, '\\') + 1); + SetWindowText (hwnd, szTmp); + } + else + { + MessageBox (hwnd, TEXT ("Error in loading the PNG image"), + szProgName, MB_ICONEXCLAMATION | MB_OK); + return FALSE; + } + + return TRUE; + } + + //---------------- + // DisplayImage + //---------------- + + BOOL DisplayImage (HWND hwnd, BYTE **ppDib, + BYTE **ppDiData, int cxWinSize, int cyWinSize, + BYTE *pbImage, int cxImgSize, int cyImgSize, int cImgChannels, + BOOL bStretched) + { + BYTE *pDib = *ppDib; + BYTE *pDiData = *ppDiData; + // BITMAPFILEHEADER *pbmfh; + BITMAPINFOHEADER *pbmih; + WORD wDIRowBytes; + png_color bkgBlack = {0, 0, 0}; + png_color bkgGray = {127, 127, 127}; + png_color bkgWhite = {255, 255, 255}; + + // allocate memory for the Device Independant bitmap + + wDIRowBytes = (WORD) ((3 * cxWinSize + 3L) >> 2) << 2; + + if (pDib) + { + free (pDib); + pDib = NULL; + } + + if (!(pDib = (BYTE *) malloc (sizeof(BITMAPINFOHEADER) + + wDIRowBytes * cyWinSize))) + { + MessageBox (hwnd, TEXT ("Error in displaying the PNG image"), + szProgName, MB_ICONEXCLAMATION | MB_OK); + *ppDib = pDib = NULL; + return FALSE; + } + *ppDib = pDib; + memset (pDib, 0, sizeof(BITMAPINFOHEADER)); + + // initialize the dib-structure + + pbmih = (BITMAPINFOHEADER *) pDib; + pbmih->biSize = sizeof(BITMAPINFOHEADER); + pbmih->biWidth = cxWinSize; + pbmih->biHeight = -((long) cyWinSize); + pbmih->biPlanes = 1; + pbmih->biBitCount = 24; + pbmih->biCompression = 0; + pDiData = pDib + sizeof(BITMAPINFOHEADER); + *ppDiData = pDiData; + + // first fill bitmap with gray and image border + + InitBitmap (pDiData, cxWinSize, cyWinSize); + + // then fill bitmap with image + + if (pbImage) + { + FillBitmap ( + pDiData, cxWinSize, cyWinSize, + pbImage, cxImgSize, cyImgSize, cImgChannels, + bStretched); + } + + return TRUE; + } + + //-------------- + // InitBitmap + //-------------- + + BOOL InitBitmap (BYTE *pDiData, int cxWinSize, int cyWinSize) + { + BYTE *dst; + int x, y, col; + + // initialize the background with gray + + dst = pDiData; + for (y = 0; y < cyWinSize; y++) + { + col = 0; + for (x = 0; x < cxWinSize; x++) + { + // fill with GRAY + *dst++ = 127; + *dst++ = 127; + *dst++ = 127; + col += 3; + } + // rows start on 4 byte boundaries + while ((col % 4) != 0) + { + dst++; + col++; + } + } + + return TRUE; + } + + //-------------- + // FillBitmap + //-------------- + + BOOL FillBitmap ( + BYTE *pDiData, int cxWinSize, int cyWinSize, + BYTE *pbImage, int cxImgSize, int cyImgSize, int cImgChannels, + BOOL bStretched) + { + BYTE *pStretchedImage; + BYTE *pImg; + BYTE *src, *dst; + BYTE r, g, b, a; + const int cDIChannels = 3; + WORD wImgRowBytes; + WORD wDIRowBytes; + int cxNewSize, cyNewSize; + int cxImgPos, cyImgPos; + int xImg, yImg; + int xWin, yWin; + int xOld, yOld; + int xNew, yNew; + + if (bStretched) + { + cxNewSize = cxWinSize - 2 * MARGIN; + cyNewSize = cyWinSize - 2 * MARGIN; + + // stretch the image to it's window determined size + + // the following two are the same, but the first has side-effects + // because of rounding + // if ((cyNewSize / cxNewSize) > (cyImgSize / cxImgSize)) + if ((cyNewSize * cxImgSize) > (cyImgSize * cxNewSize)) + { + cyNewSize = cxNewSize * cyImgSize / cxImgSize; + cxImgPos = MARGIN; + cyImgPos = (cyWinSize - cyNewSize) / 2; + } + else + { + cxNewSize = cyNewSize * cxImgSize / cyImgSize; + cyImgPos = MARGIN; + cxImgPos = (cxWinSize - cxNewSize) / 2; + } + + pStretchedImage = malloc (cImgChannels * cxNewSize * cyNewSize); + pImg = pStretchedImage; + + for (yNew = 0; yNew < cyNewSize; yNew++) + { + yOld = yNew * cyImgSize / cyNewSize; + for (xNew = 0; xNew < cxNewSize; xNew++) + { + xOld = xNew * cxImgSize / cxNewSize; + + r = *(pbImage + cImgChannels * ((yOld * cxImgSize) + xOld) + 0); + g = *(pbImage + cImgChannels * ((yOld * cxImgSize) + xOld) + 1); + b = *(pbImage + cImgChannels * ((yOld * cxImgSize) + xOld) + 2); + *pImg++ = r; + *pImg++ = g; + *pImg++ = b; + if (cImgChannels == 4) + { + a = *(pbImage + cImgChannels * ((yOld * cxImgSize) + xOld) + + 3); + *pImg++ = a; + } + } + } + + // calculate row-bytes + + wImgRowBytes = cImgChannels * cxNewSize; + wDIRowBytes = (WORD) ((cDIChannels * cxWinSize + 3L) >> 2) << 2; + + // copy image to screen + + for (yImg = 0, yWin = cyImgPos; yImg < cyNewSize; yImg++, yWin++) + { + if (yWin >= cyWinSize - cyImgPos) + break; + src = pStretchedImage + yImg * wImgRowBytes; + dst = pDiData + yWin * wDIRowBytes + cxImgPos * cDIChannels; + + for (xImg = 0, xWin = cxImgPos; xImg < cxNewSize; xImg++, xWin++) + { + if (xWin >= cxWinSize - cxImgPos) + break; + r = *src++; + g = *src++; + b = *src++; + *dst++ = b; /* note the reverse order */ + *dst++ = g; + *dst++ = r; + if (cImgChannels == 4) + { + a = *src++; + } + } + } + + // free memory + + if (pStretchedImage != NULL) + { + free (pStretchedImage); + pStretchedImage = NULL; + } + + } + + // process the image not-stretched + + else + { + // calculate the central position + + cxImgPos = (cxWinSize - cxImgSize) / 2; + cyImgPos = (cyWinSize - cyImgSize) / 2; + + // check for image larger than window + + if (cxImgPos < MARGIN) + cxImgPos = MARGIN; + if (cyImgPos < MARGIN) + cyImgPos = MARGIN; + + // calculate both row-bytes + + wImgRowBytes = cImgChannels * cxImgSize; + wDIRowBytes = (WORD) ((cDIChannels * cxWinSize + 3L) >> 2) << 2; + + // copy image to screen + + for (yImg = 0, yWin = cyImgPos; yImg < cyImgSize; yImg++, yWin++) + { + if (yWin >= cyWinSize - MARGIN) + break; + src = pbImage + yImg * wImgRowBytes; + dst = pDiData + yWin * wDIRowBytes + cxImgPos * cDIChannels; + + for (xImg = 0, xWin = cxImgPos; xImg < cxImgSize; xImg++, xWin++) + { + if (xWin >= cxWinSize - MARGIN) + break; + r = *src++; + g = *src++; + b = *src++; + *dst++ = b; /* note the reverse order */ + *dst++ = g; + *dst++ = r; + if (cImgChannels == 4) + { + a = *src++; + } + } + } + } + + return TRUE; + } + + //----------------- + // end of source + //----------------- Index: llvm/runtime/libpng/contrib/visupng/VisualPng.dsp diff -c /dev/null llvm/runtime/libpng/contrib/visupng/VisualPng.dsp:1.1.2.1 *** /dev/null Mon Mar 1 17:58:56 2004 --- llvm/runtime/libpng/contrib/visupng/VisualPng.dsp Mon Mar 1 17:58:45 2004 *************** *** 0 **** --- 1,223 ---- + # Microsoft Developer Studio Project File - Name="VisualPng" - Package Owner=<4> + # Microsoft Developer Studio Generated Build File, Format Version 6.00 + + # Copyright 2000, Willem van Schaik. For conditions of distribution and + # use, see the copyright/license/disclaimer notice in png.h + + # ** DO NOT EDIT ** + + # TARGTYPE "Win32 (x86) Application" 0x0101 + + CFG=VisualPng - Win32 Debug LIB + !MESSAGE This is not a valid makefile. To build this project using NMAKE, + !MESSAGE use the Export Makefile command and run + !MESSAGE + !MESSAGE NMAKE /f "VisualPng.mak". + !MESSAGE + !MESSAGE You can specify a configuration when running NMAKE + !MESSAGE by defining the macro CFG on the command line. For example: + !MESSAGE + !MESSAGE NMAKE /f "VisualPng.mak" CFG="VisualPng - Win32 Debug LIB" + !MESSAGE + !MESSAGE Possible choices for configuration are: + !MESSAGE + !MESSAGE "VisualPng - Win32 DLL" (based on "Win32 (x86) Application") + !MESSAGE "VisualPng - Win32 Debug DLL" (based on "Win32 (x86) Application") + !MESSAGE "VisualPng - Win32 LIB" (based on "Win32 (x86) Application") + !MESSAGE "VisualPng - Win32 Debug LIB" (based on "Win32 (x86) Application") + !MESSAGE + + # Begin Project + # PROP AllowPerConfigDependencies 0 + # PROP Scc_ProjName "" + # PROP Scc_LocalPath "" + CPP=cl.exe + MTL=midl.exe + RSC=rc.exe + + !IF "$(CFG)" == "VisualPng - Win32 DLL" + + # PROP BASE Use_MFC 0 + # PROP BASE Use_Debug_Libraries 0 + # PROP BASE Output_Dir "VisualPng___Win32_DLL" + # PROP BASE Intermediate_Dir "VisualPng___Win32_DLL" + # PROP BASE Target_Dir "" + # PROP Use_MFC 0 + # PROP Use_Debug_Libraries 0 + # PROP Output_Dir "dll" + # PROP Intermediate_Dir "dll" + # PROP Ignore_Export_Lib 0 + # PROP Target_Dir "" + # ADD BASE CPP /nologo /W3 /GX /O2 /I "libpng" /I "zlib" /D "PNG_USE_DLL" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c + # ADD CPP /nologo /W3 /GX /O2 /I "..\..\..\libpng" /I "..\..\..\zlib" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "PNG_USE_DLL" /D "PNG_NO_STDIO" /D "PNG_NO_GLOBAL_ARRAYS" /FD /c + # SUBTRACT CPP /YX + # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 + # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 + # ADD BASE RSC /l 0x409 /d "NDEBUG" + # ADD RSC /l 0x409 /d "NDEBUG" + BSC32=bscmake.exe + # ADD BASE BSC32 /nologo + # ADD BSC32 /nologo + LINK32=link.exe + # ADD BASE LINK32 libpng13.lib zlibd.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 /libpath:"libpng" /libpath:"zlib" + # ADD LINK32 libpng13.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 /libpath:"..\..\projects\msvc\win32\libpng\dll" + # Begin Special Build Tool + OutDir=.\dll + SOURCE="$(InputPath)" + PostBuild_Cmds=set path=..\..\projects\msvc\win32\libpng\dll;..\..\projects\msvc\win32\zlib\dll; $(outdir)\VisualPng.exe ..\..\contrib\pngsuite\basn6a16.png + # End Special Build Tool + + !ELSEIF "$(CFG)" == "VisualPng - Win32 Debug DLL" + + # PROP BASE Use_MFC 0 + # PROP BASE Use_Debug_Libraries 1 + # PROP BASE Output_Dir "VisualPng___Win32_Debug_DLL" + # PROP BASE Intermediate_Dir "VisualPng___Win32_Debug_DLL" + # PROP BASE Ignore_Export_Lib 0 + # PROP BASE Target_Dir "" + # PROP Use_MFC 0 + # PROP Use_Debug_Libraries 1 + # PROP Output_Dir "dll_dbg" + # PROP Intermediate_Dir "dll_dbg" + # PROP Ignore_Export_Lib 0 + # PROP Target_Dir "" + # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /I "libpng" /I "zlib" /D "PNG_USE_DLL" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c + # ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\..\..\libpng" /I "..\..\..\zlib" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "PNG_USE_DLL" /D "PNG_NO_STDIO" /D "PNG_NO_GLOBAL_ARRAYS" /FD /GZ /c + # SUBTRACT CPP /YX + # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 + # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 + # ADD BASE RSC /l 0x409 /d "_DEBUG" + # ADD RSC /l 0x409 /d "_DEBUG" + BSC32=bscmake.exe + # ADD BASE BSC32 /nologo + # ADD BSC32 /nologo + LINK32=link.exe + # ADD BASE LINK32 libpng13.lib zlibd.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /nodefaultlib:"libc" /pdbtype:sept /libpath:"libpng" /libpath:"zlib" + # SUBTRACT BASE LINK32 /nodefaultlib + # ADD LINK32 libpng13d.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /nodefaultlib:"libc" /pdbtype:sept /libpath:"..\..\projects\msvc\win32\libpng\dll_dbg" + # SUBTRACT LINK32 /nodefaultlib + # Begin Special Build Tool + OutDir=.\dll_dbg + SOURCE="$(InputPath)" + PostBuild_Cmds=set path=..\..\projects\msvc\win32\libpng\dll_dbg;..\..\projects\msvc\win32\zlib\dll_dbg; $(outdir)\VisualPng.exe ..\..\contrib\pngsuite\basn6a16.png + # End Special Build Tool + + !ELSEIF "$(CFG)" == "VisualPng - Win32 LIB" + + # PROP BASE Use_MFC 0 + # PROP BASE Use_Debug_Libraries 0 + # PROP BASE Output_Dir "VisualPng___Win32_LIB" + # PROP BASE Intermediate_Dir "VisualPng___Win32_LIB" + # PROP BASE Ignore_Export_Lib 0 + # PROP BASE Target_Dir "" + # PROP Use_MFC 0 + # PROP Use_Debug_Libraries 0 + # PROP Output_Dir "lib" + # PROP Intermediate_Dir "lib" + # PROP Ignore_Export_Lib 0 + # PROP Target_Dir "" + # ADD BASE CPP /nologo /W3 /GX /O2 /I "..\..\..\libpng" /I "..\..\..\zlib" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "PNG_USE_DLL" /D "PNG_NO_STDIO" /D "PNG_NO_GLOBAL_ARRAYS" /FD /c + # SUBTRACT BASE CPP /YX + # ADD CPP /nologo /W3 /GX /O2 /I "..\..\..\libpng" /I "..\..\..\zlib" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "PNG_NO_STDIO" /D "PNG_NO_GLOBAL_ARRAYS" /FD /c + # SUBTRACT CPP /YX + # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 + # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 + # ADD BASE RSC /l 0x409 /d "NDEBUG" + # ADD RSC /l 0x409 /d "NDEBUG" + BSC32=bscmake.exe + # ADD BASE BSC32 /nologo + # ADD BSC32 /nologo + LINK32=link.exe + # ADD BASE LINK32 libpng13.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 /libpath:"..\..\projects\msvc\win32\libpng\dll" + # ADD LINK32 libpng.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 /libpath:"..\..\projects\msvc\win32\libpng\lib" + # Begin Special Build Tool + OutDir=.\lib + SOURCE="$(InputPath)" + PostBuild_Cmds=$(outdir)\VisualPng.exe ..\..\contrib\pngsuite\basn6a16.png + # End Special Build Tool + + !ELSEIF "$(CFG)" == "VisualPng - Win32 Debug LIB" + + # PROP BASE Use_MFC 0 + # PROP BASE Use_Debug_Libraries 1 + # PROP BASE Output_Dir "VisualPng___Win32_Debug_LIB" + # PROP BASE Intermediate_Dir "VisualPng___Win32_Debug_LIB" + # PROP BASE Ignore_Export_Lib 0 + # PROP BASE Target_Dir "" + # PROP Use_MFC 0 + # PROP Use_Debug_Libraries 1 + # PROP Output_Dir "lib_dbg" + # PROP Intermediate_Dir "lib_dbg" + # PROP Ignore_Export_Lib 0 + # PROP Target_Dir "" +